feat(pitch-deck): admin UI for investor + financial-model management #3
Reference in New Issue
Block a user
Delete Branch "feature/pitch-admin-ui"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds a full admin dashboard at
/pitch-adminso the founders can invite investors, see who's logged in and what they viewed, edit investor profiles, resend magic links, revoke access, manage admin accounts, and edit financial-model defaults — all with full audit attribution.Auth model
pitch_adminstable with bcrypt passwords (cost 12) andpitch_admin_sessionswith single-active-session enforcementpitch_admin_sessioncookie + JWT withpitch-adminaudience claim (so an investor JWT can never be mistaken for an admin one)lib/admin-auth.tsmirrorslib/auth.ts(bcryptjs, jose, single-session, getAdminFromCookie)requireAdmin(request)API guard returns admin row OR 401 NextResponseAuthorization: Bearer $PITCH_ADMIN_SECRETcurl access still works on/api/admin/*(logged as actor='cli')Audit attribution
pitch_audit_logsextended withadmin_id(actor) andtarget_investor_id(target)logAuditaccepts trailingadminId+targetInvestorIdparamslogAdminAuditwrapper for admin-initiated eventsNew audit actions:
admin_login_success,admin_login_failed,admin_logout,investor_invited,magic_link_resent,investor_edited,investor_revoked(existing, now attributed),admin_created,admin_edited,admin_deactivated,scenario_edited,assumption_editedAPI surface
New (
/api/admin-auth/*): login, logout, meNew (
/api/admin/*): dashboard, investors/[id] GET+PATCH, investors/[id]/resend, admins GET+POST, admins/[id] PATCH, fm/scenarios GET, fm/scenarios/[id] PATCH, fm/assumptions/[id] PATCHMigrated to
requireAdmin: invite, investors (list), revoke, audit-logs (now supports actor_type, admin_id, target_investor_id, since/until filters)Frontend
/pitch-admin/login— email + password form (separate layout, bypasses the authed shell)/pitch-admin/(authed)/...— route group with sharedAdminShell(sidebar + topbar, dark theme matching the pitch deck)Bootstrap
pitch-deck/scripts/create-admin.ts(npm run admin:create -- --email=... --name=... --password=...). Idempotent: existing admin gets password updated. Also reads fromPITCH_ADMIN_BOOTSTRAP_*env vars for non-interactive use.Files
bcryptjs+@types/bcryptjs+tsx(dev)Test plan
002_admin_users.sqlagainst PostgreSQLnpm run admin:create -- --email=ben@breakpilot.ai --name='Benjamin' --password='...'/pitch-admin/login, enter credentials → redirected to dashboard with KPIs/pitch-admin/investors/new→ magic link email arrives/pitch-admin/audit→ rowinvestor_invitedwith admin_id + target_investor_id populated/pitch-admin, "Active 7d" goes upinvestor_editedwith before/after diffmagic_link_resentrevoked, audit row attributed to adminassumption_editedwith before/after valueBearer $PITCH_ADMIN_SECRETon/api/admin/invitestill works/auth→/unaffected (no regression)🤖 Generated with Claude Code
Adds /pitch-admin dashboard with real admin accounts (bcrypt) and full audit attribution for every state-changing action. Backend: - pitch_admins + pitch_admin_sessions tables (migration 002) - pitch_audit_logs.admin_id + target_investor_id columns - lib/admin-auth.ts: bcryptjs hashing, single-session enforcement, jose JWT with 'pitch-admin' audience claim, requireAdmin guard - logAudit extended to accept admin_id and target_investor_id - middleware.ts: gates /pitch-admin/* and /api/admin/* on the admin cookie (with bearer-secret fallback for CLI compatibility) - 14 API routes under /api/admin-auth and /api/admin (login, logout, me, dashboard, investors[id] CRUD + resend, admins CRUD, fm scenarios + assumptions PATCH) - Existing /api/admin/{invite,investors,revoke,audit-logs} migrated to requireAdmin and now log with admin_id + target_investor_id - scripts/create-admin.ts CLI bootstrap (npm run admin:create) Frontend: - /pitch-admin/login + /pitch-admin/(authed) route group - AdminShell with sidebar nav + StatCard + AuditLogTable components - Dashboard with KPIs, recent logins, recent activity - Investors list with search/filter + resend/revoke inline actions - Investor detail with inline edit + per-investor audit timeline - Audit log viewer with actor/action/date filters + pagination - Financial model scenario list + per-scenario assumption editor (categorized, inline edit, before/after diff in audit) - Admins management (add, deactivate, reset password) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>