HARRY-19 — Index dự án — 1 codebase, 5 lần nâng cấp
Index dự án — 1 codebase, 5 lần nâng cấp
Trang tổng hợp mọi dự án trong lộ trình. Spec chi tiết nằm trong từng giai đoạn; đây là nơi xem toàn cảnh, thứ tự phụ thuộc, và tiến độ.
Nguyên tắc xuyên suốt: không làm 5 dự án rời rạc. Bạn nâng cấp cùng một codebase qua từng giai đoạn. Đó là điều khiến portfolio của bạn khác với 500 repo "todo-app" khác trên GitHub — người phỏng vấn nhìn thấy một hệ thống tiến hoá có lịch sử git thật, không phải một bài tutorial chép lại.
Bản đồ
GĐ00 DSA & Complexity ──┐ nền học xen kẽ, áp dụng vào mọi dự án
GĐ01 Systems Foundation ─┘
DA0 Skeleton TS (GĐ02) ──┐
DA1 Todo API (GĐ04) ──┤ cùng một repo, nâng cấp dần
DA2 + Postgres/Prisma (GĐ05) ──┤
DA3 Mini SaaS API (GĐ06–GĐ21) ──┤ ← portfolio chính
DA4 Capstone DocuChat (GĐ22–GĐ25)──┘ ← sản phẩm hoàn chỉnhGĐ00–GĐ01 không tạo thêm project portfolio. Code thí nghiệm nằm cùng workspace học tập hoặc repo exercises riêng; DA0 bắt đầu ngay khi vào GĐ02. Không chờ giải hết DSA rồi mới build backend.
| # | Tên | Giai đoạn | Nền tảng | Sản phẩm giao |
|---|---|---|---|---|
| DA0 | Skeleton TypeScript | GĐ02 | — | Repo build & chạy được, lint + typecheck sạch |
| DA1 | Todo/Notes API | GĐ04 | DA0 | REST API + JWT + validation, deploy công khai |
| DA2 | Todo API trên Postgres | GĐ05 | DA1 | Prisma + migration + chứng minh fix N+1 |
| DA3 | Mini SaaS API | GĐ06–GĐ21 | DA2 | Portfolio chính: NestJS, auth, upload, jobs, search, test, Docker, CI, AWS, Cloudflare, K8s |
| DA4 | Capstone "DocuChat" | GĐ22–GĐ25 | DA3 | AI SaaS chạy thật: RAG + streaming + billing + quota + observability |
DA0 — Skeleton TypeScript · GĐ02
Mục tiêu. Dựng toolchain từ số 0, không copy template.
Giao được khi: npm run dev (watch), npm run build && npm start (bản build thật sự chạy), npm run lint, npm run typecheck — cả bốn đều sạch. Env validate bằng zod, fail-fast lúc boot. Debug VSCode dừng đúng dòng trong file .ts.
Cạm bẫy dễ vấp: alias chạy dev nhưng vỡ khi build → GĐ02 mục 4.
DA1 — Todo/Notes API · GĐ04
Mục tiêu. REST API hoàn chỉnh bằng Express, deploy lên internet.
Phạm vi: auth JWT (register/login), CRUD todos scoped theo user, pagination, validate bằng Zod → 422, error handler tập trung, deploy Railway/Render.
Điều quan trọng nhất phải làm đúng: thứ tự middleware trong app.ts — error handler luôn cuối cùng.
Spec đầy đủ: GĐ04 — Dự án 1.
DA2 — Todo API trên Postgres · GĐ05
Mục tiêu. Thay mảng in-memory bằng database thật.
Phạm vi: Prisma schema quan hệ 1-n, migration versioned commit vào git, seed idempotent, Redis cache-aside (tuỳ chọn), full-text search bằng tsvector → GĐ05 mục 14.
Sản phẩm giao đặc trưng: một commit "before/after" chứng minh bằng số rằng N+1 đã được sửa (đếm số query trước và sau). Đây là bằng chứng bạn hiểu ORM, không chỉ dùng ORM.
DA3 — Mini SaaS API · GĐ06 → GĐ21 ← portfolio chính
Dự án lớn nhất. Mười sáu giai đoạn cùng đổ vào đây, mỗi giai đoạn thêm một lớp.
Lớp 0 — NoSQL đúng chỗ (GĐ06)
Thêm một collection Mongo (activity_events) bên cạnh Postgres, có $jsonSchema validator, compound index theo quy tắc ESR, TTL index, một aggregation pipeline có số liệu explain trước/sau. README phải trả lời được: vì sao cái này ở Mongo mà orders ở Postgres.
Lớp 1 — Nền NestJS (GĐ07)
Auth đầy đủ (argon2, JWT access 15m + refresh 7d có rotation, refresh lưu hash, logout = revoke), RBAC bằng guard, OAuth Google/GitHub, ValidationPipe global, exception filter, interceptor, Prisma + repository, Swagger /docs, unit + e2e test.
Lớp 2 — Kiến trúc (GĐ08)
Refactor một module có nghiệp vụ thật sang domain/application/infrastructure, có lint rule chặn vi phạm quy tắc phụ thuộc, test domain chạy không cần DB. Giữ các module khác ở kiểu Nest thường và so sánh hai kiểu trong README.
Lớp 3 — API thực chiến (GĐ09)
Rate limit qua Redis, WebSocket, cache-aside, versioning API, cursor pagination có sort ghép + tie-breaker, idempotency key, webhook verify HMAC, structured logging + request id, health check, graceful shutdown.
Lớp 4 — Xử lý nền (GĐ10)
Worker process riêng, ba queue theo mức ưu tiên, outbox + relay SKIP LOCKED, handler idempotent có test, retry backoff + jitter, DLQ + trang quản trị, cronjob có tz tường minh, job rollup theo con trỏ, metric queue depth.
Lớp 5 — Search (GĐ11)
Meilisearch/Typesense/ES trong compose, đồng bộ qua outbox, filter tenant_id bắt buộc, facet, phân trang search_after, job đối soát + metric drift, số đo zero-result rate trước/sau.
Lớp 6 — File & Email (GĐ12)
Presigned URL upload 3 bước, validate magic bytes, xử lý ảnh trong worker, xoá mềm + job purge, email qua outbox có idempotency key, SPF/DKIM/DMARC thật, suppression list từ webhook bounce.
Lớp 7 — Testing (GĐ13)
Testcontainers, factory, ma trận authorization, test tenant isolation, test transaction rollback, MSW mock dịch vụ ngoài (có cả đường lỗi), k6 load test, CI gate.
Lớp 8 — Vòng đời dữ liệu (GĐ14)
Audit log bất biến, TIMESTAMPTZ toàn bộ + xử lý múi giờ đúng, tiền bằng số nguyên minor unit, CHECK constraint, retention + ẩn danh hoá, backup + restore drill thật, migration expand-contract không downtime.
Lớp 9 — DevOps (GĐ15)
Dockerfile multi-stage, docker-compose (app + worker + Postgres + Redis + search) chạy một lệnh, GitHub Actions CI/CD, deploy Railway/VPS/ECS, HTTPS, zero-downtime.
Lớp 10 — AWS (GĐ16)
Đưa API và data lên một lab AWS: EC2 chạy Docker, RDS private, S3 private với presigned upload, IAM role least-privilege, Lambda xử lý S3 event và CloudWatch logs/alarms. Vẽ VPC + Security Group trước khi tạo tài nguyên; dọn lab và kiểm tra chi phí sau khi học. Thực hành theo GĐ16 — AWS.
Lớp 11 — Cloudflare (GĐ17)
Tạo nhánh deploy edge cho API/file lab: Worker TypeScript, D1 cho metadata, R2 private cho object và Queue cho scan/xử lý nền. So sánh cùng luồng upload trên AWS; KV chỉ dùng cho cache/config đọc nhiều, còn Durable Objects là phần mở rộng khi cần điều phối trạng thái theo room/tenant. Làm staging riêng, kiểm tra authorization/log/chi phí rồi dọn resource. Thực hành theo GĐ17 — Cloudflare.
Lớp 12 — Kubernetes (GĐ18)
Cluster local kind/k3d, manifest đủ ba probe (liveness không chạm DB), resources + --max-old-space-size, preStop + grace period khớp job dài nhất, HPA + PDB, rollout dưới tải k6 với 0 request lỗi.
Lớp 13 — Ranh giới (GĐ19–GĐ20)
Kiểm toán timeout + idempotency, phân loại C-vs-L từng endpoint, distributed tracing xuyên queue, biến DA3 thành modular monolith có lint chặn import xuyên biên, tách đúng một service qua queue, contract test, và số đo trước/sau về chi phí của lần tách đó.
Spec gốc: GĐ07 — Dự án 3.
Tự chấm — DA3 đạt khi bạn trả lời được, có chỉ vào code:
- "Nếu refresh token của tôi bị đánh cắp thì sao?" → rotation phát hiện được, chỉ ra chỗ code.
- "User A có đọc được dữ liệu user B không?" → chỉ vào test chứng minh không, không phải chỉ vào câu
where. - "Webhook provider gửi lại lần hai thì sao?" → idempotency, chỉ vào test.
- "Worker chết giữa lúc chạy 10.000 job thì sao?" → chỉ vào lần thử nghiệm thật, không mất, không trùng.
- "Search index lệch với DB thì bao lâu bạn biết?" → chỉ vào metric drift và job đối soát.
- "Deploy lúc đang có traffic thì sao?" → graceful shutdown, có kết quả k6 chứng minh 0 lỗi.
- "Mất database lúc này thì bao lâu khôi phục?" → nói được con số RTO đo được từ lần diễn tập.
- "Vì sao anh không tách microservice?" → chỉ vào 4 phép thử ranh giới đã áp dụng và số đo chi phí.
DA4 — Capstone "DocuChat" · GĐ22 → GĐ25
Mục tiêu. AI SaaS chạy thật, có người trả tiền được.
Phạm vi: auth + org (tenant_id), Stripe Free/Pro + webhook, upload → ingestion pipeline (extract → chunk → embed → pgvector theo tenant), chat RAG streaming SSE có trích dẫn + nút Stop, quota + rate limit theo gói, cost tracking + dashboard + model routing, moderation + chống prompt injection + redact PII, Langfuse + Sentry + alert, deploy đầy đủ.
Lớp nền — GĐ21 (System Design): rà stateless, chạy 3 instance sau LB, PgBouncer, timeout + retry có jitter + circuit breaker cho LLM, load shedding, dashboard RED, và chạy k6 tới điểm gãy để tìm nút thắt thật.
Spec đầy đủ: GĐ25 — Capstone.
Thứ tự phụ thuộc — cái gì phải xong trước
GĐ02 → GĐ03 → GĐ04(DA1) → GĐ05(DA2) → GĐ07(DA3) → GĐ09 → GĐ10 → GĐ15 → GĐ16 AWS → GĐ17 Cloudflare
│ │ │ │
│ ▼ ▼ ▼
│ GĐ06 GĐ08 GĐ18 Kubernetes
│ │
│ GĐ11 (sau GĐ10) ▼
│ GĐ19 → GĐ20 → GĐ21
│ │
│ GĐ12, GĐ13, GĐ14 (song song được) │
│ └────────→ GĐ22 → GĐ23 → GĐ24 → GĐ25 ◄─────────────┘Ghi chú về thứ tự:
- GĐ12 / GĐ13 / GĐ14 học song song được — không phụ thuộc nhau. Nếu phải chọn một: GĐ13 (testing) trước, vì nó làm mọi giai đoạn sau an toàn hơn.
- GĐ11 (search) phải sau GĐ10 — đồng bộ index dùng lại outbox + worker.
- GĐ16 AWS theo sau GĐ15 DevOps — dùng Docker/CI đã học để hiểu đường deploy và quan sát backend trên cloud.
- GĐ17 Cloudflare theo sau AWS — so sánh Worker, bindings, R2, D1 và Queues với cách deploy/lưu trữ đã thực hành; dùng resource staging riêng.
- GĐ19 → GĐ20 → GĐ21 là một khối liền mạch. Học GĐ20 mà chưa có GĐ19 thì chỉ là sơ đồ hộp và mũi tên.
- GĐ21 học sau GĐ25 cũng được nếu bạn muốn có hệ thống thật mà mổ xẻ. Nhưng nếu đang chuẩn bị phỏng vấn, đọc khối GĐ19–GĐ20 sớm hơn — nó độc lập tương đối.
- GĐ22 có thể bắt đầu song song với GĐ12–13 nếu bạn nóng lòng chạm vào AI.
Theo dõi tiến độ
Đánh dấu khi giao được sản phẩm, không phải khi đọc xong tài liệu.
- [ ] GĐ00 foundation — hoàn thành bộ bài theo pattern + năm utilities có test
- [ ] GĐ01 foundation — hoàn thành tám thí nghiệm OS/Linux/DB/networking có kết quả đo
- [ ] DA0 — build + start chạy thật, lint/typecheck sạch
- [ ] DA1 — Todo API deploy công khai, có URL truy cập được
- [ ] DA2 — Postgres + migration, có bằng chứng số liệu fix N+1
- [ ] DA3 lớp 0 — collection Mongo có validator + index + số liệu explain
- [ ] DA3 lớp 1 — auth đầy đủ + RBAC + OAuth + Swagger
- [ ] DA3 lớp 2 — một module Clean Architecture + lint chặn vi phạm + so sánh trong README
- [ ] DA3 lớp 3 — rate limit + cache + cursor pagination + idempotency + observability
- [ ] DA3 lớp 4 — worker riêng + outbox + DLQ + cron; đã giết worker giữa 10k job và chứng minh không mất/không trùng
- [ ] DA3 lớp 5 — search chạy thật + job đối soát + số đo zero-result rate
- [ ] DA3 lớp 6 — upload presigned + email có SPF/DKIM/DMARC pass
- [ ] DA3 lớp 7 — Testcontainers + ma trận authz + k6 + CI gate
- [ ] DA3 lớp 8 — audit log + timezone + tiền + backup đã diễn tập restore
- [ ] DA3 lớp 9 — Docker + CI/CD + deploy
- [ ] DA3 lớp 10 — AWS lab: EC2 + RDS private + S3 presigned + IAM role + Lambda event + CloudWatch alarm
- [ ] DA3 lớp 11 — Cloudflare Worker + private R2 + D1 metadata + Queue consumer idempotent, deploy qua staging
- [ ] DA3 lớp 12 — K8s local, rollout dưới tải k6 với 0 lỗi
- [ ] DA3 lớp 13 — modular monolith có lint + tách 1 service + contract test + số đo chi phí
- [ ] DA4 — DocuChat chạy production, có người dùng thật (dù chỉ 5 người)
- [ ] DA4 + GĐ21 — chạy 3 instance, chịu được k6 tới điểm gãy đã biết
Vài lời về portfolio
Một dự án sâu > năm dự án nông. DA3 với lịch sử git 6 tháng, có test, có CI, có ADR ghi lại quyết định — mạnh hơn năm repo tutorial gộp lại.
README là thứ được đọc, không phải code. Trong README của DA3/DA4 phải có: kiến trúc (một sơ đồ), các quyết định và lý do (vì sao Postgres cho đơn hàng nhưng Mongo cho event log, vì sao modular monolith không phải microservice, vì sao Meilisearch không phải Elasticsearch), cách chạy local trong một lệnh, và những gì bạn cố ý chưa làm kèm lý do. Mục cuối cùng đó gây ấn tượng mạnh nhất — nó cho thấy bạn phân biệt được "chưa làm" và "không biết".
Giữ lại các commit "before/after". Commit fix N+1, commit thêm index kèm số liệu EXPLAIN, commit sửa lỗ authz do test bắt được, commit đo chi phí trước/sau khi tách service. Đó là bằng chứng về quá trình tư duy — thứ mà một repo hoàn hảo không có lịch sử không thể chứng minh.
