Use SPA root for the return-to-ops nav and proxy /admin-api in Vite dev so super-admin API calls work locally.
Co-authored-by: Cursor <cursoragent@cursor.com>
New pages under /ops/admin: Summary dashboard, Users (list + edit +
recharge + create), LLM provider keys management, Billing ledger and
usage records.
Shared AuthContext (lib/auth.tsx) fetches /auth/status once and
supplies user/role to RequireOps, RequireAdmin, and OpsLayout.
OpsLayout shows a ⚙ 超管 nav link for admins. RequireOps now grants
admin users access without an extra ops-role probe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Carve the platform super-admin API (/admin-api) and plaza operations console
API (/api/ops/v1) out of the public server.mjs into their own process, so the
user-facing fleet can no longer be taken down or scaled by back-office traffic.
Architecture (split-ready, single process for now):
- admin-routes.mjs: createAdminApi / createOpsApi route factories (DI, single
source of truth; the route logic moved verbatim out of server.mjs).
- admin-bootstrap.mjs: lean service container (user-auth, LLM providers, minimal
plaza graph) with no user-facing daemons.
- admin-server.mjs: standalone entry with a console registry. ADMIN_CONSOLES
selects which consoles a process mounts (default both), so splitting into two
processes later is a config change, not a code change.
- admin-guard.mjs (+ tests): per-console host / IP-CIDR allowlists, letting the
super-admin surface be locked down harder than moderation.
server.mjs no longer serves or mounts either surface. user-auth.mjs gains
pagination on listUsers/listUsageRecords/listBillingLedger to back the admin
dashboards. dev.mjs launches memind_adm; the ops SPA proxies /api to it while
/auth stays on the portal. Sessions are read from the shared cookie
(H5_COOKIE_DOMAIN=.tkmind.cn); login stays on the main domain.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore.
Co-authored-by: Cursor <cursoragent@cursor.com>