Files
vmall/docs/architecture.md
T

64 lines
2.7 KiB
Markdown

# 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/`