Status

Ảnh chụp tiến độ hiện tại của codebase so với ROADMAP. File này được cập nhật mỗi đợt làm việc; lịch sử chi tiết nằm trong git log.

Cập nhật lần cuối: 29/07/2026


Đang ở đâu

Phase 2 — Pro modules (đang chạy; Phase 1 core đã xong).

Đã xong

  • Repo Next.js 16 + TypeScript + Tailwind 4, CI (lint + typecheck + build)
  • Typed env bằng Zod — fail fast lúc boot (src/lib/env.ts)
  • PaymentProvider interface gateway-agnostic (src/lib/payments/types.ts)
  • Mock provider (dev/CI không cần sandbox)
  • VNPay adapter đầy đủ quirk (×100, HMAC-SHA512 sort+encode, GMT+7, JSON RspCode)
  • Chuẩn hoá docs: VISION / ROADMAP / STATUS / GLOSSARY / architecture / engineering / legal
  • LICENSE thương mại + script chèn copyright header tự động (scripts/add-headers.ts)

Đã xong (Phase 1)

  • MoMo adapter (chữ ký thứ tự cố định, IPN 204)
  • ZaloPay adapter (app_trans_id prefix ngày GMT+7, MAC key2)
  • Prisma schema: User / Order / Payment (dedupe IPN theo gatewayTxnId)
  • NextAuth v5: credentials + Google conditional (Zalo OAuth → Phase 2) + API đăng ký
  • Checkout flow end-to-end: tạo đơn → payUrl → IPN idempotent (đối chiếu tiền, chống double-credit) → return page
  • Trang mock-checkout giả lập cổng thanh toán
  • Test tay end-to-end với mock provider: thành công / thất bại / retry IPN / chữ ký sai / lệch tiền

Đã xong (Phase 2 — đợt 1)

  • Trang đăng nhập/đăng ký UI + session trên trang chủ (cookie tên riêng phostack.session-token — tránh đụng cookie authjs của app localhost khác)
  • Stripe adapter (Checkout Session qua REST, webhook verify chữ ký trên raw body, VND zero-decimal)
  • VietQR: lib build URL ảnh QR + trang demo /vietqr
  • E-invoice NĐ70: InvoiceProvider + mock + SInvoice/meInvoice adapter; model Invoice (1 đơn ↔ 1 hoá đơn); API /api/invoices/issue idempotent, chặn lệch tiền, chỉ phát hành đơn PAID — test E2E với mock
  • Zalo ZNS: NotificationProvider + mock + ZNS adapter; API /api/notifications/send (yêu cầu đăng nhập)
  • Multi-tenant + RBAC: Workspace/Membership (OWNER/ADMIN/MEMBER), helpers requireWorkspaceRole chống IDOR (non-member nhận 404 như workspace không tồn tại) — test E2E 200/401/404
  • Admin panel /admin (gate User.isAdmin): bảng đơn + tổng thu
  • Email transactional: EmailProvider + mock + Resend adapter (REST)
  • Dữ liệu 34 tỉnh thành sau sáp nhập 2025 (NQ 202/2025/QH15) + resolveProvince tra tên cũ→mới (migrate địa chỉ) + API /api/vn/provinces
  • Zalo OAuth: flow tự viết (/api/auth/zalo/start + /callback, PKCE S256, state cookie) bàn giao session cho NextAuth qua one-time login token (5 phút, dùng 1 lần) — vì OAuth v4 của Zalo phi chuẩn, không dùng được provider Auth.js. Đã smoke test token 1 lần/reuse-fail; login thật cần app Zalo + redirect_uri khai báo

Đã xong (Phase 2 — đợt 2)

  • Unit tests (Vitest, 43 test): tự ký payload verify chữ ký cả 4 cổng thật + mock (VNPay sort+encode, MoMo thứ tự cố định, ZaloPay key1/key2, Stripe raw body + tolerance), lineTotals VAT, resolveProvince — yarn test, chạy trong CI
  • Seed: yarn db:seed (admin) + yarn db:seed:demo (24 đơn đủ cổng/trạng thái, 3 khách, workspace, hoá đơn — an toàn chạy lại)
  • UI quản lý workspace /workspaces: list + form tạo (tự gợi ý slug từ tên có dấu)
  • Admin: filter theo trạng thái/cổng qua searchParams (không client JS)

Đã xong (Phase 2 — đợt 3: lớp trình diễn)

  • /store: trang bán license PhoStack chạy trên chính hạ tầng của nó — 3 gói → checkout (nhận sẵn amount/description) → cổng → IPN → xuất hoá đơn điện tử ngay trên trang kết quả (dogfooding trọn luồng kinh doanh)
  • /dev: Dev console — trạng thái từng module (Thật/Mock/Tắt theo env) + IPN log 10 giao dịch gần nhất kèm payload gốc
  • /docs: docs site render bộ markdown trong app (react-markdown + GFM + typography), sidebar curated, rewrite link nội bộ, chặn path traversal

Đã xong (Phase 2 — đợt 4)

  • i18n vi/en không dependency: dictionary typed cùng shape (en: typeof vi — thiếu key là typecheck fail), locale qua cookie (mặc định vi), switcher VI/EN trên header (server action), html lang theo locale. Toàn bộ UI song ngữ; docs content giữ tiếng Việt (selling point). Client components nhận locale prop + import từ i18n/dictionaries (client-safe, không next/headers)

Đã xong (Phase 2 — đợt 5)

  • Docs song ngữ: bộ dịch tiếng Anh đầy đủ 10 tài liệu trong docs/en/ (mirror cây VI); bản VI là canonical, bản EN ghi rõ là courtesy translation. Trang /docs chọn theo locale — EN thiếu bản dịch thì fallback bản VI kèm thông báo. Quy tắc "sửa doc là sửa cả 2 ngôn ngữ" ghi trong ENGINEERING-STANDARDS

Đã xong (Phase 2 — đợt 6: hoàn thiện tài khoản)

  • /account: sửa tên, đổi mật khẩu (verify mật khẩu hiện tại), lịch sử đơn; email header → link account
  • /admin/users: bảng khách hàng (đơn/tổng chi/vai trò), cấp/gỡ admin qua server action (không tự gỡ mình)
  • Gate /admin chuyên nghiệp: khách → redirect login; non-admin → 403 sạch (gợi ý SQL chỉ ở dev)
  • Nav lọc theo quyền (public/auth/admin); docs kỹ thuật (Quickstart/Deployment/Architecture/Engineering) khoá sau đăng nhập — docs marketing (Vision/Roadmap/Legal…) vẫn public, sidebar hiện 🔒

Đã xong (Phase 3 — đợt 1: hạ tầng kinh doanh)

  • Module Lead/Booking (29/07/2026) cho topology 3 instance (phostack.com hub → saas-demo → hq): model Lead (DEMO_BOOKING/PREORDER/CONTACT, pipeline NEW→CONTACTED→CONVERTED/CLOSED, tier, source); endpoint public POST /api/leads (CORS allowlist chỉ phostack.com, honeypot nuốt bot lặng lẽ, Zod limit chặt); /admin/leads pipeline view + server action đổi trạng thái; doanh thu 6 tháng gần nhất trên /admin — API E2E test đủ 5 case (preflight 204, 2 lead thật 201, honeypot fake-201 không lưu, email sai 400)
  • phostack.com thành site công ty (29/07/2026): bỏ landing tĩnh 1 sản phẩm, dựng Next.js app riêng (repo phostack/website) — trang chủ công ty + catalogue sản phẩm trong src/data/products.ts (thêm starter mới = thêm 1 object, /products/[slug] tự có) + about + contact; lead gửi qua server action nên trình duyệt không chạm HQ, không còn CORS. Deploy Vercel (phostack-web), Cloudflare chỉ giữ DNS — hết upload tay
  • APP_MODE=hq (29/07/2026): cùng source SaaS Kit chạy được như backend kinh doanh riêng tư — chưa đăng nhập là đẩy về /login, / vào thẳng /admin, tắt tự đăng ký; chỉ /api/auth/*, /api/payments/ipn/*, /api/leads còn mở. Verify local đủ 2 chiều (khách bị chặn, admin vào được, lead vẫn nhận)
  • Form book demo/pre-order thật trên landing (thay mailto): POST JSON tới https://hq.phostack.com/api/leads, fallback mở mailto nếu HQ chưa sống; CTA bảng giá tự điền type/tier

Đã xong (Phase 3 — đợt 2: lên sóng thật)

  • Topology 3 instance chạy production (29/07/2026) — verify bằng dữ liệu thật, không phải bằng UI:
    • phostack.com → Vercel phostack-web (site công ty, Next.js, catalogue sản phẩm data-driven)
    • saas-demo.phostack.com → Vercel phostack-saas-demo (demo công khai, DB Neon riêng)
    • hq.phostack.com → Vercel phostack-hq với APP_MODE=hq, DB Neon riêng — chưa đăng nhập là đẩy /login (đã đo //store đều 307), tài khoản admin seed bằng mật khẩu sinh ngẫu nhiên
    • Lead thật đi trọn đường: form trên phostack.com → server action → HQ → bảng Lead → hiện trong /admin/leads (source ghi đúng phostack.com/contact); request giả danh Origin: evil.com bị chặn 403
    • DNS: 4 bản ghi CNAME tại Cloudflare, tất cả DNS only (proxy cam gây lỗi SSL 525 — đã gặp và sửa)
  • Bổ sung bảng Lead cho DB demo (tạo trước khi có model này nên thiếu)
  • Chuyển middleware.tsproxy.ts theo convention Next 16 (Middleware đã deprecated)
  • Dọn workspace: repo thật về đúng ~/Projects/phostack/saas-kit (trước đó tồn tại 2 bản clone, bản trong workspace là bản cũ)

Còn lại để chốt hạ tầng

  • Đặt phostack.com làm Primary trong Vercel (hiện apex 308 sang www)
  • APP_URL của demo → https://saas-demo.phostack.com + đổi IPN URL VNPay tương ứng
  • Cloudflare Email Routing cho hello@phostack.com — hiện chưa có MX, thư khách gửi tới địa chỉ in trên website đang bị trả về

Đang làm / còn lại (Phase 2)

  • VNPay sandbox verify với hệ thống thật (29/07/2026): tạo đơn qua sandbox → thanh toán thẻ test NCB → replay bộ tham số có chữ ký thật của VNPay vào IPN handler → chữ ký HMAC-SHA512 verify pass, đơn PAID, amount ×100 chia lại đúng; retry idempotent (1 Payment duy nhất); sửa amount sau khi ký → RspCode 97. IPN server-to-server thật đã verify (29/07/2026) sau khi deploy Vercel + cấu hình IPN URL tại sandbox.vnpayment.vn/vnpaygw-sit-testing/ipn: đơn trên demo cloud tự chuyển PAID qua IPN VNPay gọi thẳng vào /api/payments/ipn/vnpay (txn 15639474, payload lưu trong Payment.rawIpn) — VNPay xong trọn vẹn end-to-end
  • Test MoMo/ZaloPay sandbox end-to-end (cần tài khoản sandbox)
  • SInvoice/meInvoice: verify payload với tài khoản T-VAN thật — adapter viết theo docs công khai, CHƯA chạy với môi trường thật
  • ZNS: vòng đời token production (access token ~25h, refresh token dùng 1 lần → cần cron refresh + lưu DB; hiện nhận token qua env)
  • Zalo OAuth: test end-to-end với app Zalo thật (flow + token đã smoke test nội bộ)
  • Metadata title các trang còn tĩnh tiếng Việt — chuyển generateMetadata theo locale nếu cần SEO song ngữ

Rủi ro đang theo dõi

Rủi roẢnh hưởngỨng phó
Sandbox MoMo không ổn địnhChậm verify adapterMock-first; chỉ test sandbox ở bước cuối
NextAuth v5 còn betaAPI có thể đổiPin version trong lockfile; wrap sau facade riêng
Nghị định hướng dẫn NĐ70 thay đổi chi tiết kỹ thuậtAdapter e-invoice phải sửaĐây chính là giá trị bán — quy trình theo dõi trong LEGAL-FRAMEWORK