Skip to content

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

  • End-user UI (design import, code generation, etc.) → ui-user
  • MCP server-related UI → mcp-v2

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/v1 prefix)

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

  1. Exact path and request/response shape of the refresh endpoint (routes/v1/auth.ts has a refreshTokenRoute import, but details are unconfirmed)
  2. Whether refresh token rotation is in use, and whether a grace window exists for old tokens immediately after rotation
  3. 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_access
  • organization_access
  • project_access
  • user_access

Each flag carries an AccessLevel (NONE / READ / READ_WRITE). The UI enforces guards at three layers:

  1. middleware.ts (edge) — Checks for the admin_token cookie. Redirects to /login if absent
  2. (authenticated)/layout.tsx (Server Component) — Fetches /auth/me and injects { user, role } into children via a Provider. If required layout-level flags are below READ, returns 404
  3. Per page / button — Hides or disables buttons and UI elements using useCan(flag, level)
{useCan('organization_access', 'READ_WRITE') && <CreateOrganizationButton />}

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

Operations Admin