think
16px
820px

Console self-service + account lifecycle + security triage (2026-07-08)

Batch picked by Efran from the readiness ranking: **#2 persona editors,

3 schema browser, #5 per-account chat history, #8 password reset, #7

Dependabot triage**. (#1 feedback loop, #4 knowledge backup, #6 error
monitoring stay on the roadmap as next-up.)

#3 — DB schema browser (/admin/internal/schema) — UI-only

Backends exist (/api/admin/databases, /api/admin/databases/[name]/tables;
agent returns {databases:[{name,description}]} / {database,tables:[]}).
Page: DB selector → table list with client-side search (hundreds of tables).
Tested pure helper filterTables(tables, q). AdminRail INTERNAL entry
"Skema DB". Read-only; no new backend.

#2 — Persona editors

Public surface (/admin/public/persona): new persona_preamble: string
(default "", max 4000 chars) on BOTH Config copies (public-web
orchestrator/config.ts + internal-web orchestrator-config.ts — the files
document they must stay in sync). compose.ts prepends it to SYSTEM_COMPOSE
when set (buildMessages gains optional persona arg; orchestrate passes
cfg.persona_preamble). Editor page PUTs through the existing
/api/admin/orchestrator route. Empty string ⇒ byte-identical behavior.

Internal agent (/admin/internal/persona): mirrors the provider-admin
pattern. New light dash/persona.py (file-path testable): load_persona()
reads PERSONA_CONFIG_PATH (default /data/persona.json, {"persona": str};
missing/invalid ⇒ ""). agents.py prepends persona to
_EFFECTIVE_INSTRUCTIONS at build. New app/persona_admin.py (mirrored ×2):
GET /persona, PUT /persona (≤8000 chars) — saves atomically then hot-swaps
dash.instructions / public_dash.instructions / reasoning_dash.instructions
live (same mechanism as /provider/reload-schema). internal-web proxy
/api/admin/agent-persona (GET; PUT = requireMutationSession + audit row).
Compose: agents gain named volumes (…-agent-data:/data) so persona.json
and the pre-existing provider.json survive recreates (today they don't —
latent bug fixed by this).

#5 — Per-account chat history (Akun)

Public chat runs through the in-app orchestrator; the old /api/threads/doc
(doc-RAG /sessions) doesn't see those turns at all. New app-local
ThreadStore (better-sqlite3 on PUBLIC_DB): public_threads(id=sessionId, user_email, title, created_at, updated_at) +
public_thread_messages(thread_id, role, content, created_at).

  • /api/orchestrate route: when a valid Akun cookie is present, tee the SSE
    stream — accumulate event: content deltas; on done, persist user +
    assistant messages fire-and-forget (never blocks/fails the stream). Tamu ⇒
    no persistence, zero behavior change.
  • /api/threads/doc GET: Akun cookie ⇒ list own threads from ThreadStore
    (Thread {id,q,when,mode:'doc'}); no cookie ⇒ legacy upstream passthrough.
  • /api/threads/doc/[id] GET: Akun-owned thread ⇒ its messages (shape matched
    to the sidebar's history loader); not owned/absent ⇒ 404.

#8 — Password lifecycle (no email transport — email reset stays blocked)

  • Self-service change (public-web): POST /api/auth/change-password
    {currentPassword, newPassword≥8} — requires valid session cookie AND
    current-password verify; PublicUserStore.resetPassword (new; bcrypt +
    token_version++) then re-issues the cookie with the new tv. Sidebar Akun
    section gains "Ubah kata sandi" dialog.
  • Admin reset (internal-web): staff console manages public accounts —
    /admin/shared/public-users page + /api/admin/public-users (GET list) +
    [id] PATCH {action: reset_password|disable|enable}; reset generates a
    temp password shown once to the admin. App-local PublicAccountAdminStore
    reads the SAME /data/public.sqlite (both webs mount ahu-shared_policy-data
    at /data — verified). Mutations: requireMutationSession + audit rows
    (mandate). No cross-app import.

#7 — Dependency vuln triage (91 Dependabot: 4 critical, 33 high)

No gh/PAT in this environment ⇒ triage via pnpm audit (registry advisories)
for the JS workspace + pip-audit against both agents' requirements.txt.
Fix criticals/highs that are non-breaking bumps (direct bumps or pnpm
overrides); re-run suites; report what remains (major-version/breaking ones
deferred with reasons). GitHub's alert list can be reconciled from the
Dependabot UI afterward.

Constraints

Boundary (no cross-app imports; data-file sharing via the shared volume is the
established staff/public pattern), mandate (admin mutations =
requireMutationSession + audit), mirrors byte-identical, TDD, pnpm check +
agent pytest green, deploy via build-and-ship → staging, verify live.