UI for Admin — Overview
A back-office Web UI for 4D operations staff to interact with the Guinness Admin API (api-admin).
Purpose
- CRUD for admin accounts, organizations, projects, and app users
- Authentication (login, forgot password, password reset, profile retrieval)
- Access control based on roles (RBAC)
Scope
Included
- Full authentication flow (
/auth/login,/auth/logout,/auth/forgot_password,/auth/reset_password,/auth/me) - List, detail, create, edit, soft-delete, and hard-delete for
/admins,/organizations,/projects, and/users - Screen and button guards based on role flags (
admin_access,organization_access,project_access,user_access)
Not included
Backend Contract
- API source:
GenAI-Guinness-backend/apps/admin - OpenAPI 3.1 spec:
/api/v1/doc(JSON) - Swagger UI:
/api/v1/docs - Version: v1 (
/api/v1prefix)
Authentication
Pattern: httpOnly Cookie + stateless Next.js proxy.
Rationale:
- JWT is inaccessible from JavaScript (XSS resistance)
- No session state on the Next.js side keeps horizontal scaling simple
SameSite=Lax+ same-origin proxy prevents CSRF
Cookies set by Next.js:
| Cookie | Attributes | TTL |
|---|---|---|
admin_token |
httpOnly, Secure, SameSite=Lax | ~15 minutes |
admin_refresh_token |
httpOnly, Secure, SameSite=Lax | Long-lived (per backend configuration) |
Authentication Flow
| Flow | Behavior |
|---|---|
| Login | Form → Next.js /api/auth/login → Admin API /auth/login → Sets two cookies → Returns only { user } to the browser (no token returned) → Primes the TanStack Query auth/me cache |
| Authenticated requests | Browser /api/proxy/<path> → Proxy reads cookie → Forwards to Admin API with Authorization: Bearer header |
| Token refresh on 401 | Proxy calls /auth/refresh (with refresh cookie attached) → On success, updates the admin_token cookie and replays the original request. The browser-side fetcher coalesces concurrent 401s into a single refresh Promise (only one refresh occurs per burst) |
| Logout | Next.js /api/auth/logout → Admin API /auth/logout (deletes the server-side session row) → Clears both cookies |
| Forgot password / reset | No session required. The Next.js route passes the request straight through to the Admin API |
Rejected Approaches (with Rationale)
- Storing JWT in localStorage / sessionStorage — XSS risk; accessible from JavaScript
- In-memory only (lost on reload / silent refresh is complex)
- NextAuth — Conflicts with the backend session
- Amplify Auth SDK — Goes directly to Cognito, bypassing the Admin API's session table and DB-based RBAC
Backend Verification Items
- Exact path and request/response shape of the refresh endpoint (
routes/v1/auth.tshas arefreshTokenRouteimport, but details are unconfirmed) - Whether refresh token rotation is in use, and whether a grace window exists for old tokens immediately after rotation
- Migration plan for the response envelope (
{ success, data }vs. legacy format) — affects the fetcher normalization layer
RBAC
The Admin API assigns each administrator a set of role flags:
admin_accessorganization_accessproject_accessuser_access
Each flag carries an AccessLevel (NONE / READ / READ_WRITE). The UI enforces guards at three layers:
middleware.ts(edge) — Checks for theadmin_tokencookie. Redirects to/loginif absent(authenticated)/layout.tsx(Server Component) — Fetches/auth/meand injects{ user, role }into children via a Provider. If required layout-level flags are belowREAD, returns 404- Per page / button — Hides or disables buttons and UI elements using
useCan(flag, level)
Page Structure (Key Screens)
| Route | Required Role | Feature |
|---|---|---|
/login |
None | Login |
/forgot-password, /reset-password |
None | Password reset flow |
/admins |
admin_access >= READ |
Admin list |
/admins/[id] |
admin_access >= READ |
Admin detail & edit (buttons shown with READ_WRITE) |
/organizations |
organization_access >= READ |
Organization list |
/organizations/[id] |
organization_access >= READ |
Organization detail & edit |
/projects |
project_access >= READ |
Project list (filter by organization_id, pagination, sorting) |
/projects/[id] |
project_access >= READ |
Project detail & edit |
/users |
user_access >= READ |
App user list |
/users/[id] |
user_access >= READ |
App user detail & edit |
/profile |
Authenticated | Own profile (/auth/me), password change |
Actors
Related Documents
- API for Admin — Backend side
- Tech Stack — List of adopted technologies
- Directory Structure — Layer structure and request flow
- Setup — Orval configuration and fetcher
- Coding Rules — Validation and implementation conventions