01 — ARCHITECTURE
Depends on: 00_MASTER.md · Next: 02_TECH_STACK.md
1. Philosophy
Module-centric, not page-centric. Every feature owns its vertical slice. Adding a tool never edits core.
Request → Nginx → Next.js / API → API SDK → REST /v1 → Service → Prisma → MariaDB
↓
Redis/Valkey (cache/session/rate-limit — optional)
2. C4 Container Diagram
C4Container
title YAS.SH V3 — Containers
Person(user, "User", "Creates & clicks links")
Person(admin, "Admin", "Moderates")
Container(web, "Web", "Next.js 16", "Marketing, blog, dashboard, docs")
Container(api, "API", "Hono / Next Routes", "REST /v1, redirect, auth")
ContainerDb(db, "Database", "MariaDB 11", "Links, clicks, users, audit")
Container(cache, "Cache/Queue", "Valkey/Redis + pg-boss", "Sessions, rate-limit")
Container(search, "Search", "DB Full-Text", "Blog search (Meilisearch later)")
Container(s3, "Storage", "R2/S3", "Images, backups")
Rel(user, web, "HTTPS")
Rel(web, api, "HTTPS /v1 + SDK")
Rel(api, db, "Prisma")
Rel(api, cache, "session/rate-limit")
Rel(api, s3, "files")
3. Monorepo Layout (Implemented)
yas-enterprise-v3/
├── apps/
│ ├── web/ # Next.js 16 App Router
│ │ ├── app/
│ │ │ ├── (marketing)/ # /, /pricing, /features, /tools
│ │ │ ├── (app)/ # /dashboard, /links, /analytics
│ │ │ ├── blog/ # /blog/[slug] from content collections
│ │ │ ├── docs/ # /docs/* (Stripe-like)
│ │ │ ├── api/ # Route Handlers if API colocated (Option A)
│ │ │ └── [code]/ # Redirect route (edge-optimizable)
│ │ ├── components/
│ │ └── content/ # MDX blog when colocated
│ └── api/ # Standalone API (Option B — Hono)
│ ├── src/modules/ # Re-exports from /modules
│ └── src/index.ts
├── modules/ # ← SOURCE OF TRUTH FOR FEATURES
│ ├── links/
│ │ ├── module.json # Manifest (see 06_MODULE_SYSTEM.md)
│ │ ├── schema.prisma # Prisma fragment (merged)
│ │ ├── routes.ts # Route registration
│ │ ├── api.ts # Hono/Next handlers + validation
│ │ ├── permissions.ts # RBAC matrix
│ │ ├── menu.ts # Nav registration
│ │ ├── ui/ # React components for this module
│ │ ├── docs.md # Module documentation
│ │ └── tests/ # unit + integration
│ ├── qr/
│ ├── analytics/
│ ├── blog/
│ ├── bio/
│ └── tools/ # Each tool = module
│ ├── password/
│ ├── utm/
│ └── base64/
├── packages/
│ ├── database/ # Prisma schema (merged), migrations, seeds
│ ├── ui/ # Design system (see 05_UI_UX.md)
│ ├── config/ # plans.ts, env.ts, tsconfig, eslint
│ └── security/ # isPrivateIP, validateUrl, rate-limit, crypto
├── blog/ # Alternative location for MDX (if not in apps/web)
├── docker/ # Dockerfiles + compose.yml + compose.prod.yml
├── nginx/ # nginx.conf + prod hardened
├── scripts/ # smoke.sh, security-smoke.sh, deps-check.sh
└── docs/ # This spec
Rule: /modules/* is auto-scanned at build. No manual import list.
4. Layering Rules
| Layer | May import | May NOT import |
|---|---|---|
apps/web UI |
packages/ui, modules/*/ui, packages/config, API SDK |
packages/database directly |
apps/api |
packages/database, packages/security, modules/*/api |
UI components |
modules/*/ui |
packages/ui, packages/config |
packages/database |
modules/*/api |
packages/database, packages/security |
UI |
packages/* |
Nothing app-specific | apps/*, modules/* |
Frontend → API SDK → REST → Service → DB. Never UI → DB.
5. Module Auto-Discovery
At build: scripts/generate-modules.js scans modules/*/module.json and generates:
apps/web/app/(app)/nav.ts(sidebar)apps/api/src/routes.ts(mount)packages/config/plans.tsvalidationdocssidebar
Adding a module = create folder + module.json → run pnpm gen:modules.
6. Naming Conventions
- Files:
kebab-case(link-analytics.tsx) - Components:
PascalCase(LinkTable) - DB tables:
snake_case(click_events), Prisma modelsPascalCase - API routes:
/v1/{resource}kebab, cursor pagination?cursor=...&limit=20 - Env vars:
UPPER_SNAKE(DATABASE_URL,REDIS_URL) - Commits: Conventional Commits (
feat(links): add expiry)
7. Shared Config
- TypeScript strict:
strict + noUncheckedIndexedAccess + exactOptionalPropertyTypes pnpm-workspace.yamlwithcatalog:for pinned versions.npmrc→engine-strict=true, save-exact=true, minimumReleaseAge=1440packages/configexports:plans.ts(single source for limits),env.ts(Zod boot validation)
8. State & Data Flow
- Server state: TanStack Query (or SWR) via API SDK
- Form state: React Hook Form + Zod resolver
- URL state: Search params for filters/pagination (shareable)
- Cache: API SDK handles
stale-while-revalidate, Redis caches redirects
9. Scaling Strategy
- Phase 1: Single Next.js (web+api together) — no Redis
- Phase 2: Split API to Hono on Fly/Coolify, add Valkey for rate-limit
- Phase 3: Add
pg-bossfor jobs (no BullMQ yet) - Future: Meilisearch, dedicated worker service, Kubernetes — only when metrics justify
Do not over-provision in Phase 1.
Next: 02_TECH_STACK.md — exact versions and governance.