think
16px
820px

Completion notes — console self-service + accounts + triage (2026-07-08)

Spec: specs/2026-07-08-console-selfservice-accounts-design.md · Plan: plans/2026-07-08-console-selfservice-accounts.md
Batch: #2 persona editors, #3 schema browser, #5 per-account history, #8 password lifecycle, #7 vuln triage. Deployed build 1e46549; every feature verified live on staging.

#3 Schema browser ✅

/admin/internal/schema (nav "Skema DB") — DB selector → table list with tested client-side filter over the agent's existing /databases endpoints. UI-only as scoped.

#2 Persona editors ✅

  • Public (/admin/public/persona): persona_preamble (≤4000) added to both orchestrator-config copies; compose prepends it to the system prompt (base grounding rules stay authoritative). Applies on the next turn — config loads per request.
  • Internal (/admin/internal/persona): dash/persona.py (+apply_persona, tested by file-path loader) + app/persona_admin.py GET/PUT — PUT saves /data/persona.json atomically and hot-swaps dash/reasoning_dash/public_dash instructions live (reload-schema mechanism). Proxy route is guarded + audited. Live-verified: PUT → GET roundtrip on the deployed agent, then reverted to empty.
  • Compose fix ridealong: agents now mount named …-agent-data:/data volumes — persona.json and the pre-existing provider.json survive container recreates (latent loss-on-recreate fixed). Verified mounted in the deployed container.

#5 Per-account chat history ✅

ThreadStore (PUBLIC_DB: public_threads + public_thread_messages); /api/orchestrate tees event: content deltas when a valid Akun cookie is present and records the turn fire-and-forget (never blocks/fails the stream — tested incl. throw case); /api/threads/doc (+/[id]) serve the account's own threads with ownership enforced, legacy RAG passthrough for cookie-less callers. Tamu unchanged. Live-verified: register → chat → thread listed → detail returns user+assistant messages.

#8 Password lifecycle ✅ (transport-free scope)

  • Self-service POST /api/auth/change-password (session cookie + current password; token_version++; cookie re-issued). Sidebar Akun footer now shows the real account (replaces the hardcoded "Budi Santoso" fixture) with "Ubah sandi" dialog + "Keluar".
  • Staff reset: /admin/shared/public-users (nav "Pengguna Publik") — list, reset to a show-once temp password, disable/enable; PublicAccountAdminStore reads the shared /data/public.sqlite (same cross-app data-file pattern as orchestrator config; no cross-import); mutations guarded + audited.
  • Live-verified: change-password → old password 401, new 200. Email-based forgot-password still blocked on transport (documented).

#7 Vuln triage ✅ (registry-audit scope; reconcile Dependabot UI after push)

  • JS workspace: 22 → 0 known vulns. vitest 2→3 (+@vitest/coverage-v8) cleared the critical (vitest UI arbitrary file read) — all 164 tests pass on v3; pnpm-workspace.yaml overrides: pin dompurify ≥3.4.9, postcss ≥8.5.10, vite ≥6.4.3, esbuild ≥0.25.0. (Gotcha: pnpm 11 ignores pnpm.overrides in package.json — overrides live in pnpm-workspace.yaml.)
  • Python (agents): 51 → 19. Nine same-major pin bumps (python-multipart 0.0.31 — parses our /runs forms; pyjwt 2.13, cryptography 46.0.7, urllib3 2.7, gitpython 3.1.50, idna 3.15, pygments 2.20, python-dotenv 1.2.2, pydantic-settings 2.14.2). Deferred with reasons: starlette 1.x (major, fastapi-0.128-coupled), cryptography 48.x (major), pytest 9 (dev-only), agno CVE-2026-10105 (no fix released — re-check on agno upgrade), pip/setuptools (scratch-venv tooling, not shipped; image installs via uv). In-image pytest green on the new pins.

Verification

pnpm check green (typecheck ×6, 164 JS tests, conventions OK); agent suites green on pinned venv and in-image at ship; mirrors byte-identical (incl. requirements.txt). Deployed via build-and-ship (rsync absent in this container → tar-over-ssh equivalent) + compose up; all containers healthy; live smoke covered every feature (see per-item notes). New admin pages 307-gated (not 404). Smoke accounts/threads cleaned up.