DashboardView ("میز کار"): Rebuilt from scratch with a new structure, distinct from the old card+grid layout but visually aligned with HomeView (same blurred bar, @ink/@wine palette, staged reveal animation on mount):
Single hero card (ink→wine gradient) showing balance, gold/fiat debt, and identity — no quick-action icons inside it anymore.
Live gold rate folded into a slim inline row at the bottom instead of a titled section.
Iterated shadow/spacing on the hero card per feedback (softer, less clipped).
DialogVant / DialogVantOneButton (shared modal components, used in 7+ call sites: Dashboard, Cart, SingleProduct, Register, App): Replaced Vant's default dialog chrome with the app's own rounded-card language — circular icon badge for the illustration, pill-shaped primary/secondary buttons. No call-site markup changed.
LoginView: Rebuilt from scratch — full-bleed dark hero (brand + step copy) overlapped by a floating white form sheet, animated crossfade transition between the mobile-number and OTP steps, same staged entrance animation as Home/Dashboard. All auth logic (API check, OTP stub, session login) unchanged.
Three real bugs found and fixed while wiring up product images end-to-end:
1. src/prisma/migrate.ts only discovered flat prisma/migrations/<name>.sql
files, never Prisma's own folder-per-migration layout
(<timestamp>_<name>/migration.sql). Every migration created the normal
way (via 'prisma migrate dev') was silently skipped; only a hand-added
flat duplicate (prisma/migrations/0001_init.sql, now removed) ever ran.
This meant schema.prisma had drifted well ahead of what any real deploy
database actually had (missing columns on City, Customer, Branch,
Product, several new tables). Fixed to discover both layouts; the
drift is closed with a new 20260914165255_sync_schema_drift migration.
2. Neither nginx.conf (production) nor vite.config.ts (dev) proxied
/uploads/ to the API — only /api/. UploadedFile/ProductImage URLs
(/uploads/<file>, served by main.ts's useStaticAssets OUTSIDE the /api
prefix) 404'd through both. Both now proxy /uploads/ the same way /api/
already was.
3. docker-compose.yml's api service had no volume for storage/uploads, so
every uploaded file — and by extension every ProductImage row pointing
at one — was lost on the next container recreate/redeploy. Added a
named volume.
Also: main.ts's static file serving now sets Content-Type: image/avif
explicitly (serve-static's bundled mime table predates .avif and served it
as application/octet-stream; browsers rendered it anyway by sniffing, but
a stricter client would not have).
Product photos: copied 15 real jewelry photos into the uploads volume,
registered them as UploadedFile rows, and assigned each of the 5 existing
Product rows a randomly picked one (duplicates allowed, per request),
replacing their /img/no-items.png placeholder ProductImage row. Verified
end-to-end in a real browser against the real containerized API+DB: logged
in, opened the admin product list, confirmed all 5 rows render their photo
(naturalWidth/Height populated, network 200s, no console errors).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>