diff --git a/packages/dashboard/index.html b/packages/dashboard/index.html
index 643bdd0..6b6146a 100644
--- a/packages/dashboard/index.html
+++ b/packages/dashboard/index.html
@@ -1866,20 +1866,24 @@ async function openTxDetail(id) {
if (iVer) verItems.push('✓ Image');
if (dVer) verItems.push('✓ Details');
if (fVer) {
- h += '
'
- + '
★ 100% VERIFIED'
- + '
–'
- + verItems.join('
·')
- + (t.fully_verified_at ? '
seit ' + fmtDate(t.fully_verified_at) + '' : '')
+ // Inside the green bar: all text must be white/light — not #2d6a4f (same as bg)
+ var fvItems = [];
+ if (pVer) fvItems.push('
✓ Price');
+ if (iVer) fvItems.push('
✓ Image');
+ if (dVer) fvItems.push('
✓ Details');
+ h += '
'
+ + '★ 100% VERIFIED'
+ + '–'
+ + fvItems.join('·')
+ + (t.fully_verified_at ? 'seit ' + fmtDate(t.fully_verified_at) + '' : '')
+ '
';
} else if (verItems.length > 0) {
+ // Partial verification on white background: dark green is fine here
h += '
'
+ verItems.join('·')
+ '
';
- } else {
- // No verification data yet — show neutral indicator
- h += '
Data not yet verified from official sources
';
}
+ // No verification → no badge. Never show unverified data as verified.
// Helper: render a spec section as a clean table (like Flexoptix spec tables)
function renderSpecTable(title, rows) {
@@ -1948,30 +1952,27 @@ async function openTxDetail(id) {
['Year Mainstream', t.year_mainstream],
]);
- // SPECIFICATION — Pricing (verified prices from DB)
- var prices = t.competitor_prices || [];
+ // SPECIFICATION — Pricing
+ // Rule: Only show prices that were scraped from a real URL within the last 30 days.
+ // Unverified / estimated prices are NOT shown — silence is better than wrong data.
+ var prices = (t.competitor_prices || []).filter(function(p) { return p.url && p.price > 0; });
if (prices.length > 0) {
h += '
Current Prices
';
h += '
';
prices.forEach(function(p) {
- var verBadge = p.is_verified
- ? '
✓ Verified'
- : '
unverified';
- var priceStr = p.currency + ' ' + parseFloat(p.price).toLocaleString('de-DE', {minimumFractionDigits:2,maximumFractionDigits:2});
- var dateStr = '
' + fmtDate(p.observed_at) + '';
- var urlLink = p.url ? '
↗' : '';
+ // Verified badge only if observed within 7 days AND has a real URL
+ var verBadge = p.is_verified === true
+ ? '
✓ Verified Price'
+ : ''; // No badge for older observations — not wrong, just not shown as verified
+ var priceStr = '
' + p.currency + '\u00a0' + parseFloat(p.price).toLocaleString('de-DE', {minimumFractionDigits:2,maximumFractionDigits:2}) + '';
+ var dateStr = '
Stand: ' + fmtDate(p.observed_at) + '';
+ var urlLink = '
↗ Quelle';
h += '
' + esc(p.vendor_name) + ''
- + '' + priceStr + verBadge + dateStr + urlLink + '
';
+ + '
' + priceStr + verBadge + dateStr + urlLink + '';
});
h += '
';
- } else {
- // Fallback: show MSRP/street from transceivers table if no price_observations
- h += renderSpecTable('Pricing', [
- ['MSRP', t.msrp_usd ? '$' + parseFloat(t.msrp_usd).toLocaleString() : null],
- ['Street Price', t.street_price_usd ? '$' + parseFloat(t.street_price_usd).toLocaleString() : null],
- ['Price Tier', t.price_tier],
- ]);
}
+ // No price_observations → show nothing. Never display estimated or unverifiable prices.
// Notes (scraped extra specs)
if (t.notes) {