Files
vmall/docs/architecture.md
T

2.7 KiB

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/