• /api/admin/* accepted only the T6 ADMIN_PASSWORD cookie until now —
    MVCP M.1/M.10's stated rule is users.role='admin' + a real session, and
    M.2's credit_ledger needs a real admin identity to attribute manual
    balance corrections to. isAdminAuthed() now accepts either path (the
    ADMIN_PASSWORD channel stays as a fallback so nobody's locked out
    before any role='admin' account exists by hand — dev-plan-4.md T30's
    explicit requirement). New POST /api/admin/credit/adjust wraps the
    new creditLedger.adjust() (db.js), which — unlike spend/refund — takes
    either sign of delta and records actorUserId (null over the legacy
    ADMIN_PASSWORD channel, which has no per-admin identity to attribute
    to).
    
    credit_ledger's actorUserId column needed an idempotent ALTER TABLE
    guard (no migration framework exists anywhere in this project) since
    the table's CREATE TABLE IF NOT EXISTS already shipped in T23 without
    it. Also switched db.js to WAL journal mode — surfaced by two processes
    legitimately touching the same data.sqlite at once in this session
    (the long-running server + a test run) hitting "database is locked" on
    the default rollback-journal mode; worth having before this bites in
    production too, not just to unblock local test runs.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011DUiYs6UjxDMkfvnjtsKFo
    yibo authored
     
    Browse File »
  • Single shared password (.env ADMIN_PASSWORD) + in-memory HttpOnly
    session cookie, no accounts/roles — MVCP M.1/M.10's real account
    system supersedes this in period 3. Covers the existing
    /api/admin/library/* routes (previously unauthenticated, see
    architecture.md 1.2's tech-debt note) plus the new upload endpoint.
    
    admin.html gets a fetch() interceptor that redirects to the new
    admin-login.html on any 401 from /api/admin/*, rather than patching
    every call site.
    yibo authored
     
    Browse File »