6 Commits
Author SHA1 Message Date
tiennm99 4e59b0d03e ci: run on Node 24 and align types with the runtime
The runner already defaults to Node 24 and local dev is on v24.14.0, while CI
pinned 22 and @types/node was still ^22 — so the type definitions described an
older runtime than anything actually running.

- CI node-version 22 -> 24
- @types/node ^22 -> ^24 (matches the runtime major; the newer ^26 line targets
  Node 26, which we don't run)
- declare engines.node >=24 so local, CI, and Vercel resolve the same major

All six CI gates pass locally on Node 24: secret-leak, format:check, test (97),
lint, typecheck, build.
2026-07-25 15:57:10 +07:00
tiennm99 f0faece37b ci: bump actions to latest stable majors
Clears the "Node.js 20 is deprecated / being forced to run on Node.js 24"
warning by moving off the v4 actions:

- actions/checkout v4 -> v7
- actions/setup-node v4 -> v7
- pnpm/action-setup v4 -> v6

Kept pnpm/action-setup ahead of setup-node (its `cache: pnpm` needs pnpm on
PATH first) and noted why; pnpm version still comes from the packageManager
field in package.json.
2026-07-25 15:48:53 +07:00
tiennm99 5ddf11ac4a test: add Vitest unit + Playwright E2E suites (PLAN §7)
The repo had zero tests despite PLAN §7 mandating them.

- 97 unit tests over the pure logic: checkup/customer/catalog/template Zod
  schemas, parseNum, computeAge, and invoice math
- extracted lib/billing/totals.ts (sumLineTotals/formatVnd) so invoice math is
  testable, and refactored the invoice route + dashboard to use it
- 16 Playwright smoke tests that need no database: auth gates redirect to
  sign-in, VI-default rendering, password-reveal toggle, /en locale, 404
- playwright.config passes placeholder env inline via webServer.env so no
  env file is ever needed; pnpm test wired into CI (E2E stays local)

tests/e2e/README.md documents the seeded-data prerequisites for the full
queue -> checkup -> prescription -> paid -> invoice happy path, which is
blocked on a provisioned Supabase project rather than faked with skipped tests.
2026-07-25 15:16:48 +07:00
tiennm99 d578e71266 ci: use package manager pnpm version 2026-05-27 23:19:44 +07:00
tiennm99 eeda68c34a chore(ci): add NEXT_PUBLIC_*=sb_secret_* leak guard
Defense-in-depth check that fails the build (and the local pre-push
workflow) if a server secret value is assigned to a NEXT_PUBLIC_*
variable — those get bundled into the browser by Next.js.

- scripts/check-no-secret-leak.mjs: git grep for the assignment shape,
  excluding lockfiles and the script itself
- package.json: pnpm check:no-secret-leak
- .github/workflows/ci.yml: run the guard right after install, before
  format/lint/typecheck/build
- docs/threat-model.md: close the last Unresolved item
2026-05-25 16:19:43 +07:00
tiennm99 b88147059e feat: scaffold Phase 0 foundation (Next.js 16 + Tailwind v4 + Supabase/Upstash)
Initial code drop for the BSK educational rewrite. Repo previously held only
docs (PLAN.md, README, NOTICE, LICENSE, RESEARCH_REPORT). This commit lands
the App Router shell, i18n route group, and shared-infra factories per the
Phase 0 plan.

Scaffold:
- Next.js 16 + React 19 + TypeScript 5.9, App Router, Turbopack defaults
- Tailwind v4 via @tailwindcss/postcss with CSS-first @theme block
- shadcn/ui CLI v4 (components.json + cn helper); components install lazily
- next-intl v4 with vi default + en fallback; async-params-aware routing
- proxy.ts (Next 16's renamed middleware) wired to next-intl
- lib/supabase/{server,client,admin,session}.ts on @supabase/ssr, schema-scoped
  to 'bsk', async cookies(), server factory unsafe inside 'use cache'
- lib/upstash.ts: prefixed cache helpers and Ratelimit v2, QStash signature
  verifier; future code cannot write unprefixed Redis keys
- lib/env/{client,server}.ts split so the secret key types stay server-side
- ESLint flat config (eslint-config-next/core-web-vitals + typescript +
  prettier), Prettier with tailwindcss plugin, .npmrc + pnpm-workspace.yaml
  for pnpm 11 native-build approval
- CI runs format:check, lint, typecheck, build on PR with dummy env

PLAN.md updates:
- §1 reconciled to TypeScript 5.9 (TS 6 is GA but lacks ecosystem support)
- §3.1 notes middleware → proxy file rename and removal of `next lint`

All four gates pass locally: format:check, lint, typecheck, build (SSG for
/vi and /en, Proxy detected). Code-reviewer findings applied: env split,
session helper renamed and docstring fixed, cache.set/del types tightened,
prettierignore scope reduced, bilingual GlobalNotFound, explanatory comments
on no-op layouts and duplicate setRequestLocale.

Deferred to Phase 1: wiring updateSupabaseSession into proxy.ts (needs auth
flow first), schema migrations, sign-in form.
2026-05-25 10:58:04 +07:00