d3ro-voice/docs/map/08-admin-console.md
Yun Chan e87ce63440 docs: record Wave 3 surface consolidation and fold NAS-only whisper into compose
- docs/REFACTOR_WAVE3_REPORT.md and the Wave 3 policy: canonical map,
  production changes, verification and remaining external steps.
- Gap backlog: GAP-BILL-01 resolved; new GAP-BILL-02 (Payple renewal never ran,
  Payple client key never set), GAP-WEB-01 (tunnel host for /app), GAP-OPS-01
  (NAS compose/.env drift), GAP-CI-01, GAP-I18N-02, GAP-TEAM-02.
- design.md: hero loop decision (numbers taken from the app capsule), pricing
  mismatch closed; feature catalog SHELL-11 updated.
- docs/map, release guide and mobile release docs no longer describe the
  deleted wwwroot, binaries, Dockerfile.admin, NAS site copy or .github CI.
- docker-compose.nas.yml gains the d3ro-whisper service that only existed in
  the NAS copy, so the repository file is the complete definition.
- refactor-wave skill: Wave 3 index and lessons P10-P12.
2026-09-26 16:02:44 +09:00

5.7 KiB

08 — Admin Console (Next.js) Map

Surface: apps/admin Stack: Next.js 16 App Router + MUI (@d3ro/ui theme) + Supabase service role + .NET proxy Role: back office CRM/ops — users, subscriptions, models, usage, audit, releases, ads


1. Route tree (src/app/)

Public

Route Purpose
/login Email/password → /api/auth/login; Google OAuth via Supabase → /auth/callback; maps error keys
/unauthorized 403 screen
/auth/callback OAuth code → session exchange

Protected (admin) (guarded by (admin)/layout.tsx → requireManager())

Route Purpose
/ Dashboard: backend stats, node health, MRR/ARR/active subscriptions (Supabase), recent errors
/pipelines AI/voice pipeline telemetry; explicit "unavailable" card when no measured data
/models LLM model + STT provider manager (presets, CRUD, test)
/releases Forgejo live release hub (assets, platforms, sizes, downloads, SHA-256)
/users User directory: search + tier/role filters
/users/[id] User 360: profile, subscription, 30-day usage, role change (admin+), payment history
/subscriptions Subscription ops list + filters; license issuer (super_admin)
/subscriptions/new Grant VIP subscription (admin+)
/subscriptions/[id] Subscription detail: edit (manager+) / delete (admin+)
/ads Ad mediation console (10 networks, all fail_closed) + reward stats
/support Stub — explicit "not configured" panel
/usage Combined LLM + STT usage/cost analytics
/audit-log Supabase audit log list + target filter + pagination
/audit-log/[id] Audit detail with before/after diff

2. API route handlers (src/app/api/)

Route Methods Behavior
/api/auth/login POST Validate body, reject honeypot trap, in-memory rate limit/lockout, proxy to .NET /api/auth/login (7s timeout, HTTPS in prod), validate token/role/email/expiry, sign HMAC session cookie d3ro_admin_session
/api/auth/logout POST/GET Clear cookie; GET redirects /login
/api/admin/backend/[...segments] GET/POST/PUT/DELETE Allow-list proxy to .NET /api/admin/*; required role by path; same-origin for non-GET; ≤64KB; UUID idempotency-key for mutations
/api/admin/license POST Same-origin + requireVerifiedBackendSession('super_admin'); sign Ed25519 key with ADMIN_LICENSE_PRIVATE_KEY (@d3ro/core/utils/crypto-license); best-effort audit
/api/admin/supabase/[operation] GET/POST/PATCH/DELETE admin-users, admin-subscriptions, admin-payments via RPCs; strict allow-lists; Payple live history returns 501
/auth/callback GET Supabase OAuth exchange

3. Libraries (src/lib/)

File Purpose
admin-session.ts Session types, secret validation (≥32 bytes), strict cookie parse, adminCookieSecure() escape hatch
security.ts server-only HMAC-SHA256 sign/verify, in-memory rate limit/lockout, runtime security validation
admin-guard.ts RSC guards requireManager/requireAdmin/requireSuperAdmin, role helpers
edge-session.ts Edge-runtime HMAC verify via WebCrypto (used by proxy.ts)
backend-session.ts requireApiServerOrigin, requireVerifiedBackendSession(minRole) (verifies cookie + .NET /api/auth/me), fetchAdminBackend
api-server.ts server-only data access to .NET backend (stats, users, endpoints, usage reports)
backend-admin-client.ts client CRUD for model/STT endpoints with auto idempotency keys
admin-api.ts client callAdminApi for Supabase admin operations
supabase-admin.ts service-role client, actor resolution RPC, product user fetch
supabase-browser.ts / supabase-server.ts client/server Supabase wrappers
ad-monetization.ts MEDIATION_ROSTER (fail_closed) + ad reward stats
subscription-metrics.ts MRR/ARR/active/tier breakdown
audit-sanitize.ts recursive redaction of sensitive keys in audit snapshots
forgejo-releases.ts Forgejo release feed parser (RELEASE_REPO_URL)
console-theme.ts design tokens + MUI style presets

Root files: instrumentation.ts (startup security validation), proxy.ts (edge middleware: public paths, auth redirect, security headers), robots.ts (disallow all).


4. Components (src/components/)

admin-sidebar (nav island: Core Platform / Customer & Revenue / Intelligence & Security), unavailable-admin-panel (reusable "NOT CONNECTED", no sample data), audit-diff-viewer, payment-history, subscription-form, role-change-dialog + role-change-button, memo-dialog, license-issuer-button + license-issuer-dialog, checksum-copy, charts (dau-chart, feature-usage-chart, top-users-chart).


5. Admin status summary

  • Dashboard, models, releases, users, subscriptions, usage, audit log, ads: implemented against real backend/Supabase data.
  • Security: HMAC signed sessions, RSC + edge guards, rate limit/lockout, honeypot, strict origin/allow-list, no-store, robots disallow, audit redaction. Red-team scenarios were exercised (see memory/project_status.md).
  • Explicit fail-closed / not-configured states (by design, not bugs):
    • /support stub — no ticket/SLA/diagnostics contract.
    • /ads — all 10 networks fail_closed; no live bids.
    • admin-payments Payple live history → 501.
    • UnavailableAdminPanel whenever Supabase env absent; writes disabled, no sample metrics.
    • /pipelines and dashboard node/error sections render only measured data.
  • Deploy: apps/admin/Dockerfile → GHCR + NAS compose; the duplicate root Dockerfile.admin was deleted 2026-09-26 (Wave 3, cd9d199) since apps/admin/Dockerfile is the one actually used. GitLab admin NAS deploy job disabled.