- Backend: validate display.currency against 10 supported ISO 4217 codes
(USD, GBP, EUR, CAD, AUD, JPY, CHF, MXN, BRL, INR); return 400 on
unsupported code with a clear message listing accepted values
- Frontend: useCurrency composable fetches rates from open.er-api.com
with 1-hour module-level cache and in-flight deduplication; falls back
to USD display on network failure
- Preferences store: adds display.currency with localStorage fallback for
anonymous users and localStorage-to-DB migration for newly logged-in users
- ListingCard: price and market price now convert from USD using live rates,
showing USD synchronously while rates load then updating reactively
- Settings UI: currency selector dropdown in Appearance section using
theme-aware CSS classes; available to all users (anon via localStorage,
logged-in via DB preference)
- Tests: 6 Python tests for the PATCH /api/preferences currency endpoint
(including ordering-safe fixture using patch.object on _LOCAL_SNIPE_DB);
14 Vitest tests for convertFromUSD, formatPrice, and formatPriceUSD
Phase 2 (snipe#4): after bulk-reporting sellers to eBay T&S, Snipe now
persists which sellers were reported so cards show a muted "Reported to
eBay" badge and users aren't prompted to re-report the same seller.
- migration 012 adds reported_sellers table (user DB, UNIQUE on seller)
- Store.mark_reported / list_reported methods
- POST /api/reported + GET /api/reported endpoints
- reported store (frontend) with optimistic update + server persistence
- reportSelected wires into store after opening eBay tabs
Phase 3 prep (snipe#4): community blocklist share toggle
- Settings > Community section: "Share blocklist with community" toggle
(visible only to signed-in cloud users, default OFF)
- Persisted as community.blocklist_share user preference
- Backend community signal publish now gated on opt-in preference;
privacy-by-architecture: sharing is explicit, never implicit
Replaces the Coming Soon placeholder. Clicking Details on any card opens
a full trust breakdown view:
- SVG score ring with composite score and colour-coded verdict label
- Auto-generated verdict text (identifies worst signals in plain English)
- Signal table with mini-bars: Feedback Volume/Ratio, Account Age,
Price vs Market, Category History — pending state shown for unresolved
- Red flag badges (hard vs soft) above the score ring
- Photo carousel with prev/next controls and img-error skip
- Seller panel (feedback count/ratio, account age, pending enrichment note)
- Block seller inline form wired to POST /api/blocklist
- Triple Red pulsing border easter egg carried over from card
- Not-found state for direct URL access (store cleared on refresh)
- Responsive: single-column layout on ≤640px
- ListingCard: adds Details RouterLink to price column
- search store: adds getListing(id) lookup helper
All error-red and success-green rgba values were using dark-mode hex values directly.
In light mode those tokens shift (error #f85149→#dc2626, success #3fb950→#16a34a),
so the hardcoded tints stayed wrong. Replaced with color-mix() so tints follow the token.
Also:
- Add missing --space-5 (1.25rem) to spacing scale in theme.css
- Add --color-accent (purple) token for csv_import badge; adapts dark/light
- Wire blocklist source badges to use --color-info/accent/success tokens
- api/main.py: GET /api/feedback/status + POST /api/feedback — creates
Forgejo issues; disabled (503) when FORGEJO_API_TOKEN unset, 403 in
demo mode; includes view, version, platform context in issue body
- FeedbackButton.vue: 2-step modal (type → review → submit); probes
/api/feedback/status on mount, stays hidden until confirmed enabled
- App.vue: mount FeedbackButton with current route name as view context;
import useRoute for reactive route name tracking
- .env.example: document FORGEJO_API_TOKEN / FORGEJO_REPO / FORGEJO_API_URL