All checks were successful
CI / test-go-consent (push) Successful in 42s
CI / test-python-voice (push) Successful in 30s
CI / test-bqas (push) Successful in 30s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / Deploy (push) Successful in 2s
Adds /pitch-admin dashboard with real bcrypt admin accounts and full audit attribution for every state-changing action. - pitch_admins + pitch_admin_sessions tables (migration 002) - pitch_audit_logs.admin_id + target_investor_id columns - lib/admin-auth.ts: bcryptjs, single-session, jose JWT with audience claim - middleware.ts: two-cookie gating with bearer-secret CLI fallback - 14 new API routes (admin-auth, dashboard, investor detail/edit/resend, admins CRUD, fm scenarios + assumptions PATCH) - 9 admin pages: login, dashboard, investors list/new/[id], audit, financial-model list/[id], admins - Bootstrap CLI: npm run admin:create - 36 vitest tests covering auth, admin-auth, rate-limit primitives Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
41 lines
1.9 KiB
SQL
41 lines
1.9 KiB
SQL
-- =========================================================
|
|
-- Pitch Deck: Admin Users + Audit Log Extensions
|
|
-- =========================================================
|
|
|
|
-- Admin users (real accounts with bcrypt passwords)
|
|
CREATE TABLE IF NOT EXISTS pitch_admins (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
name VARCHAR(255) NOT NULL,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
last_login_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_pitch_admins_email ON pitch_admins(email);
|
|
CREATE INDEX IF NOT EXISTS idx_pitch_admins_active ON pitch_admins(is_active);
|
|
|
|
-- Admin sessions (mirrors pitch_sessions structure)
|
|
CREATE TABLE IF NOT EXISTS pitch_admin_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
admin_id UUID NOT NULL REFERENCES pitch_admins(id) ON DELETE CASCADE,
|
|
token_hash VARCHAR(128) NOT NULL,
|
|
ip_address INET,
|
|
user_agent TEXT,
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
revoked BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_pitch_admin_sessions_admin ON pitch_admin_sessions(admin_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pitch_admin_sessions_token ON pitch_admin_sessions(token_hash);
|
|
|
|
-- Extend audit log: track admin actor + target investor for admin actions
|
|
ALTER TABLE pitch_audit_logs
|
|
ADD COLUMN IF NOT EXISTS admin_id UUID REFERENCES pitch_admins(id) ON DELETE SET NULL;
|
|
ALTER TABLE pitch_audit_logs
|
|
ADD COLUMN IF NOT EXISTS target_investor_id UUID REFERENCES pitch_investors(id) ON DELETE SET NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pitch_audit_admin ON pitch_audit_logs(admin_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pitch_audit_target_investor ON pitch_audit_logs(target_investor_id);
|