Appearance
SDD-001 — Platform Architecture
Nguyên tắc: One World, One Learner, One Platform. Nemo12 là distributed education platform về business capability, unified learner system về technology.
1. High-Level
text
nemo12.com ── Cloudflare Edge (WAF, DDoS, rate limit, bot)
│
├─ apps (Vite/React SPA + assets-on-Worker): web, learn, marlins, mentors, admin, docs(VitePress)
│
└─ api.nemo12.com ── Hono on Workers (modular monolith)
├─ D1 `nemo12-platform` (id f4275a70-66fa-4746-8292-40f96a7ed288) — system of record
├─ R2 `nemo12-content` — heavy assets/media
├─ KV `nemo12-config` (id f08c239409404bfe82b5aad303de362d) — config/flags/manifests cache
├─ Queues `nemo12-events` (+ `nemo12-events-dlq`) — async fan-out
├─ Workflows — durable multi-step processes
└─ AI Gateway `nemo12` — mọi AI request (bắt buộc, không bypass)Tài nguyên trên account Cloudflare ff302e77218f9616c3baaf01db59d64e, zone nemo12.com (id 09caf325ee80eca4743957e03b655867). Tạo ngày 2026-08-13.
2. Modular Monolith (REQ-PLT-02)
Bounded modules trong một Worker api (tách service chỉ khi có lý do scale/security rõ):
text
identity · family · learner · school · enrollment · learning · assessment
evidence · recommendation · mentor · community/interaction · content · media
ai · notification · admissionsMỗi module: thư mục riêng trong workers/api/src/modules/, export router Hono + event handlers; không import chéo internals (chỉ qua public interface của module).
3. Cloudflare Services (REQ-PLT-01)
| Nhu cầu | Dịch vụ | Quy tắc |
|---|---|---|
| Compute | Workers | Hono, TypeScript |
| Relational | D1 | Một database nemo12-platform; school phân biệt bằng school_id/program_id, không tách DB theo school (ADR-002) |
| Heavy content | R2 | metadata ở D1, D1 chỉ giữ content_ref (SDD-004, SDD-009) |
| Cache/config | KV | không chứa learner state quan trọng |
| Async | Queues | batching, retry, DLQ (SDD-006 §5) |
| Durable process | Workflows | diagnosis, evaluation, recalculation… |
| AI | AI Gateway nemo12 | logging, caching, rate-limit; cấm direct provider call và cấm "probe-then-fallback" kiểu chuyenchon (RISK-022) |
| API edge | API Shield/Gateway (khi bật) + code-level hardening | method/path allowlist, body cap (kế thừa pattern sutucon shared/gateway.ts) |
4. Frontend (REQ-PLT-05, REQ-BRD-01, REQ-SCH-01)
text
apps/
├── web/ nemo12.com (+ www) — public, 6 school pages /turtle…/whale, SEO+OG
├── learn/ learn.nemo12.com — Nemos; school = route context (/turtle, /shark…)
├── marlins/ marlins.nemo12.com — parents
├── mentors/ mentors.nemo12.com — Dolphins (build sau, thứ 4)
├── admin/ admin.nemo12.com — internal, sau Cloudflare Access (build cuối)
└── docs/ docs.nemo12.com — VitePress, render docs/ canonical (sau Access)- Vite + React + TypeScript, Cloudflare Vite plugin; deploy dạng Worker với static assets (không dùng Pages — hợp nhất một mô hình deploy).
- School không có app riêng — chỉ là route/theme context (REQ-SCH-01).
@latestkhi cài, lock trong lockfile (Vite 8.x, Tailwind v4, shadcn CLI mới nhất).
5. API (REQ-PLT-04, REQ-PLT-10)
- Base:
https://api.nemo12.com/v1/— resources:/learners /families /invitations /enrollments /evidence /assessments /recommendations /learning /content /media /interactions /notifications. - Contract OpenAPI sinh từ code (
@hono/zod-openapi): mọi route bắt buộc có zod schema (fix RISK-024 — sutucon hand-maintained openapi).GET /v1/openapi.jsonpublic. - API-first cho mobile: không logic nào chỉ nằm trong web app; response envelope
{data}/{error:{code,message}}theo error taxonomy SDD-006 §11. - Versioning:
/v1ổn định; breaking change →/v2song song (REQ-NFR-10).
6. Identity, Auth & Access (REQ-ACC-*, REQ-SEC-05)
Parent-first (Q-006):
text
Parent bấm "Đăng nhập với Google" (Google Identity Services, id_token)
→ api verify id_token (aud = GOOGLE_CLIENT_ID, email_verified)
→ chưa có user? tạo `users` + `families` + membership 'owner' (tự động, không form)
→ session: token opaque 32B, lưu sha256(token), cookie `nemo12_session`
Domain=.nemo12.com HttpOnly Secure SameSite=Lax, Max-Age 30d, CÓ rotation khi refresh- GSI id_token flow → không cần Google client secret (kế thừa sutucon, RISK-021 tránh được).
GOOGLE_CLIENT_IDlà var công khai. - Invite flow: parent tạo invitation (email hoặc link + mã) → learner login Google qua link → account learner tạo + gắn
family_id+guardianlinks. Learner không qua invite = không enroll được (REQ-ACC-03). - Mobile (REQ-ACC-06): cùng endpoint đổi id_token → session token, client mobile giữ token trong secure storage, gửi qua
Authorization: Bearer— cookie và bearer song song. - RBAC: bảng
role_assignments(user_id, role, scope) — roleslearner|guardian|mentor|staff|admin; mọi authorization ở backend, theo quan hệ family/assignment (REQ-SEC-02). - Cloudflare Access bảo vệ
admin.+docs.(+ staging). Cấu hình Zero Trust: app per hostname, policy = email domain/list; audience + team domain đặt qua env var, cấm hardcode (REQ-SEC-06, fix RISK-013). Trạng thái 2026-08-13: chưa bật được qua API token hiện có — cần làm trên dashboard; admin/docs không deploy public cho tới khi Access bật.
7. Data Layer (REQ-ACC-04, REQ-PLT-11)
- Canonical identity:
users.id(UUIDv7),learners.idriêng (một user có thể là learner; guardian liên kết quaguardians/family_members). Email chỉ là thuộc tính đăng nhập — cấm làm khóa dữ liệu (fix RISK-001 owner_key=email của chuyenchon). - Core tables (migration 0001):
users, families, family_members, learners, guardians, invitations, sessions, auth_identities, role_assignments, audit_log. - Domain tables theo SDD-002/003/004/005/009.
- Migrations: một sequence duy nhất
migrations/ở root monorepo, áp bằngwrangler d1 migrations apply nemo12-platform; idempotent khi có thể; cấm DML destructive trộn DDL; cấm nhiều thư mục migration trỏ cùng DB (fix RISK-004/005 của cả 2 legacy). - Timestamps: TEXT ISO-8601 UTC (SQLite), tên cột
*_at.
8. Events & AI plumbing (REQ-PLT-03, REQ-PLT-09)
- Domain events chuẩn:
{event_id, idempotency_key, type, occurred_at, producer, version, payload}— publish sau commit, quanemo12-events; consumer idempotent; quá retry → DLQ. - Catalog khởi điểm:
UserCreated, FamilyCreated, LearnerInvited, LearnerJoined, EnrollmentCreated, EvidenceRecorded, AssessmentCompleted, SkillMasteryChanged, RecommendationGenerated, LearningExperienceCompleted, MentorInteractionRecorded, ParentObservationRecorded, CommentCreated, MediaUploaded, MediaModerated. - AI: một module
ai/duy nhất gọi AI Gatewaynemo12; ghi{model, prompt_version, input_ref, output, confidence, evaluation_state}cho mọi output quan trọng (REQ-INT-14). Prompt registry versioned trong repo (packages/ai/prompts/). Provider mặc định: Workers AI (llama) cho tác vụ rẻ, có thể route Claude qua Gateway cho đánh giá chất lượng cao (Q-020 tự quyết — xem open-questions).
9. Monorepo (REQ-PLT-07)
text
nemo12/
├── apps/{web,learn,marlins,mentors,admin,docs}
├── workers/api # Hono modular monolith
├── workers/consumers # queue consumers (tách khi cần)
├── packages/{design-system,domain,database,events,ai,auth,shared}
├── migrations/ # một sequence duy nhất cho nemo12-platform
└── docs/ # canonical documentation (REQ-PLT-08)npm workspaces (Node 22). CI: GitHub Actions per-path (kế thừa mô hình 2 legacy repo — đã chạy ổn), deploy bằng wrangler deploy với CLOUDFLARE_API_TOKEN secret.
10. Documentation plane (REQ-PLT-08)
docs/ = canonical duy nhất; VitePress render tại apps/docs; frontmatter machine-readable (conventions.md); CI check broken links + trace closure (QG-001).
11. Configuration rules (REQ-SEC-06)
Cấm hardcode: domain names, school ids, owner emails, Access audiences, upstream URLs — tất cả qua vars/secrets trong wrangler config + packages/shared/config. (Fix RISK-013/016/023 — hai legacy hardcode domain ở 45+ và ~30 files.)
Trace
| REQ | Mục |
|---|---|
| REQ-PLT-01..05,07,08,10,11 | §1–§5, §7, §9, §10 |
| REQ-ACC-01..06 | §6 |
| REQ-BRD-01/02 | §4 |
| REQ-SCH-01 | §4 |
| REQ-SEC-05/06, REQ-MEN-01 | §6, §11 |