2.5 KiB
2.5 KiB
engineer — RBAC + Token page + Filtered Excel export + full-width + donut fix
Date: 2026-08-27 · From: principal-20260827-175448
What changed
1. Roles / RBAC
server/db.ts:app_users.role TEXT NOT NULL DEFAULT 'viewer'(additiveALTER … ADD COLUMN IF NOT EXISTS).seedUserforces the bootstrapAUTH_USERtoadmin(and repairs pre-role rows). AddedRole/ROLES/isRole,listUsers,createUser(23505 → 'exists'),deleteUser.server/auth.ts: sessionuser = {username, role};verifyLoginreturns the role;requireRole(min)— 401 unauth, 403 under-privileged.index.tsroute gates:- viewer:
/api/tickets,/api/tickets/:number,/api/stats,/api/config - pm:
/api/analytics/*,/api/insights - lead:
GET/POST /api/users,DELETE /api/users/:username - admin:
GET/POST /api/tokens,POST /api/tokens/:id/revoke - Only admin may create an admin (server 403 + client dropdown limits leadership to ≤lead).
- viewer:
- Client:
roleAtLeast/ROLE_LABELS; App route guards (reports→pm, /admin→lead); Sidebar shows Analytics only for pm+, Admin only for lead+; TopBar shows role.
2. API token page — pages/Admin (Tokens tab, admin only)
List (label/id/last-used/expires/revoked) + create (raw fg_… shown once, copy) + revoke.
Replaces the x-admin-key HTTP gate with the admin session role. mint-token CLI unchanged.
3. Filtered Excel export
utils/excel.utils.ts (write-excel-file dep, as in Husky) → exports the board's currently
filtered rows. Button in the board header. 17 columns incl. lifetime, days-in-state, cost, PO, link.
4. Also
- Overall verifier REDO fixed: donut now fed
byRequesterShare(full 966-ticket distribution), not the top-20 nestedbyRequester→ center total 966, correct %. - All analytics pages
max-width: none(charts span the full container width).
Verification (live, role forge_app DB)
- server tsc / client tsc clean; client vite build OK;
npm test9 pass. - Gating matrix reproduced end-to-end: viewer → tickets/config 200, analytics/insights/users/tokens 403; pm → analytics/insights 200, users/tokens 403; admin → all 200. viewer POST /api/users 403.
- Bootstrap
adminrow correctly migrated to roleadmin(not the 'viewer' default).
Next
security — audit the authz (public domain): privilege escalation, self-delete/last-admin, token exposure. verifier — gate the full change.