4.6 KiB
4.6 KiB
Architecture Decision Records
Each file records one decision that was expensive to make and would be expensive to reverse. The purpose is not documentation for its own sake — it is so that in a year, when someone asks "why is money an integer?" or "why doesn't the admin just query the database?", the answer is written down along with what was rejected and why.
An ADR is immutable once accepted. If a decision changes, add a new ADR that supersedes it.
| ADR | Decision | Status |
|---|---|---|
| 0001 | Monorepo with pnpm workspaces and Turborepo | Accepted |
| 0002 | Modular monolith, not microservices | Accepted |
| 0003 | Product and ProductVariant as separate entities | Accepted |
| 0004 | The admin dashboard has no database access | Accepted |
| 0005 | URI-based API versioning | Accepted |
| 0006 | Zod schemas shared between API and frontends | Accepted |
| 0007 | RBAC permissions instead of role checks | Accepted |
| 0008 | Short access tokens, rotating refresh tokens, separate audiences | Accepted |
| 0009 | Media in S3-compatible storage, metadata in PostgreSQL | Accepted |
| 0010 | Redis is a cache and an ephemeral store, never a system of record | Accepted |
| 0011 | Money as integer minor units | Accepted |
| 0012 | PostgreSQL full-text search before a dedicated search engine | Accepted |
| 0013 | Content translations in typed tables, UI strings in message catalogs | Accepted |
| 0014 | A denormalised price/stock projection on Product | Accepted |
| 0015 | Frontends reach the API through their own origin | Accepted |
| 0016 | Option values are retained when variants reference them | Accepted |
| 0017 | shadcn/ui for infrastructure, hand-built for brand | Accepted |
Decisions deliberately NOT recorded yet
These are open and should become ADRs when the need is real, not before:
- Payment provider abstraction shape (VNPay / MoMo / ZaloPay / COD) — write it when the second provider is integrated, not the first. One provider does not reveal the right abstraction.
- Whether a third locale ever ships, and whether localised pathnames
(
/vi/san-pham/...) are worth the routing complexity on top of localised slugs. - Facet counts for sport and gender, which need
unnest()over the array columns — worth doing when a UI displays them. - Shipping-rate provider integration.
- Whether guest carts ever get promoted to PostgreSQL before sign-in.
- Multi-warehouse allocation strategy. The schema supports it; the policy does not exist yet.
- i18n / multi-currency rollout.
- Read replicas and connection pooling (PgBouncer) — a scaling decision that needs real traffic numbers to make well.