- 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.
91 lines
5.7 KiB
Markdown
91 lines
5.7 KiB
Markdown
# 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.
|