# VMall Architecture VMall is a B2B2C marketplace MVP: one Rust API serving three Nuxt 3 frontends, with all HTTP contracts centralized in a shared TypeScript package. ## Workspace layout ``` apps/ api/ Rust (crate vmall-api), port 8080 — the only backend mall/ Nuxt 3 shopper storefront (PC), port 3000 shop-admin/ Nuxt 3 merchant console, port 3001 admin/ Nuxt 3 platform console, port 3002 packages/ shared/ @vmall/shared — the ONLY API contract (types.ts + api.ts), en/zh locale packs, Tailwind v4 theme tokens ui/ @vmall/ui — shared Vue components (VBtn, VCard, VField, VInput, VTable, VPage, VPanel, VBadge, VAccentSwatch) openspec/ Spec-driven change management (specs/ = archived truth) docs/ Architecture, guidelines, code index ``` ## Request path ``` Browser ──► Nuxt (SSR + hydration) ──► $api plugin ──► vmall-api ──► Postgres │ │ │ └─► Redis (cache/sessions) └─ mock adapter fallback (mall only) ``` - Frontends never call `fetch` directly; they call the `ApiClient` from `@vmall/shared`, provided as `$api` by each app's `plugins/api.ts`. - The mall additionally composes a mock adapter (`apps/mall/mock/api.ts`) with per-domain live picks (`LIVE_PICKS` in `apps/mall/plugins/api.ts`), so any domain can roll back to deterministic fixtures via `NUXT_PUBLIC_LIVE_DOMAINS`. The consoles are always live. ## Roles and tenancy `platform_admin` (apps/admin), `shop_owner`/`shop_staff` (apps/shop-admin, scoped to their shop via `auth.own_shop()`), `customer` (apps/mall). Every protected route declares its roles; cross-shop access returns 404. ## Data rules that shape everything - **Money**: `i64` minor units + ISO currency code everywhere. No floats. The currency table carries the exponent (JPY=0); display goes through `formatMoney(minor, code, exponent, locale)`. - **User-facing content**: `{en, zh}` JSONB. - **State machines**: guarded `UPDATE … WHERE status = …`; zero rows → 409. - **Concurrent counters**: guarded `SET col = col - $q … AND col >= $q`; replenish with `col + n`, never read-then-write. - **Migrations**: `apps/api/migrations/`, append-only, run on boot. ## Where to look next - Backend conventions → `docs/backend-guidelines.md` - Frontend conventions → `docs/frontend-guidelines.md` - Run/develop/test → `docs/development.md` - Domain deep dives → `docs/domains/` - Find the file for a feature → `docs/code_index/index.md` - Normative behavior → `openspec/specs/`