d3ro-voice/docs/map/08-admin-console.md
Yun Chan c3ddd36c6f
Some checks failed
deploy-site / deploy (push) Failing after 40s
docs: record the 1.1.0 release and add the infrastructure map
Release notes for 1.1.0 were split between an Unreleased section and the
version section, so the published notes would have omitted the update-feed
and desktop changes. Everything shipping in this version now sits under one
`## [1.1.0]` heading.

`docs/map/` becomes the entry point for what infrastructure exists per
platform and how far each feature is developed, with a documented update
protocol so feature work and this map do not drift apart again. The release
guide now states that installer binaries live in the update feed rather than
the repository.
2026-09-16 23:27:52 +09:00

5.6 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.tsxrequireManager())

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: Dockerfile.admin / apps/admin/Dockerfile → GHCR + NAS compose; GitLab admin NAS deploy job disabled.