Commit Graph
2 Commits
Author SHA1 Message Date
tiennm99 9afd68a741 feat(phase-1): role-gated app shell + dashboard placeholder
- app/[locale]/(app)/layout.tsx: Server gate — getServerSession()
  redirects unauth users (defense in depth) and signs out + redirects
  the authed-but-no-role edge case. Renders AppShell with user/role/locale.
- app/[locale]/(app)/admin/layout.tsx: second gate via requireRole;
  non-admin → /[locale]/dashboard (not 404 — avoids confirming routes).
- app/[locale]/(app)/dashboard/page.tsx: placeholder showing email +
  role badge.
- lib/auth/role-menu.ts: ROLE_MENU mapping per AppRole → MenuItem[]
  with href + i18n labelKey + lucide icon.
- lib/auth/require-role.ts: server helper for the admin gate.
- components/app-shell/{app-shell,sidebar,sign-out-button,locale-switcher}.tsx:
  Server-rendered shell + sidebar that reads ROLE_MENU[role]; client
  locale switcher (native <select> fallback) and sign-out (<form action>
  with useFormStatus pending UX).
- components/ui/{badge,separator}.tsx: shadcn primitives.
- messages/{vi,en}.json: nav.*, app.*, dashboard.* keys (parity).

Gating chain: proxy.ts redirects unauth → /sign-in for /dashboard +
/admin prefixes; (app) layout enforces session+role; (app)/admin layout
additionally enforces role === 'admin'.
2026-05-25 17:53:44 +07:00
tiennm99 8265942101 feat(phase-1): sign-in page + form (RHF + useActionState + shadcn)
- app/[locale]/(auth)/layout.tsx: centered card layout for unauth routes
- app/[locale]/(auth)/sign-in/page.tsx: Server Component, redirects
  authed users to dashboard, renders SignInForm
- app/[locale]/(auth)/sign-in/sign-in-form.tsx: Client form with RHF
  (zodResolver, mode onBlur) + useActionState(signInAction). Form root
  is <form action={dispatchAction}>. Server fieldErrors sync into RHF
  via useEffect for consistent inline UX. aria-invalid/aria-describedby
  set for accessibility.
- app/[locale]/layout.tsx: mounts <Toaster richColors position="top-right" />
  inside NextIntlClientProvider
- components/ui/{button,input,label,sonner}.tsx: shadcn primitives
  installed via shadcn CLI v4 (Tailwind v4 CSS-first)
- messages/{vi,en}.json: title + subtitle keys under auth.signIn

Scope honored: no next= plumbing, no rate-limit i18n keys (both cut from
phase 03), no unenrolledError key (action uses invalidCredentials for
both wrong-password and unenrolled paths per enumeration defense).
2026-05-25 17:42:13 +07:00