You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: restructure the admin panel into six tabs, add read-only view-as
The admin panel was one page of stacked cards. It is now General / Apps / AI /
Config / Health / Enterprise, with the active tab in the URL so a tab is a
link you can send.
General — an About block (running version, latest release, public URL) and an
administrator access matrix showing, per person, whether their role grants
super access, admin-panel access and view-as. Plus the feature those columns
describe:
View as a user (read-only impersonation)
- A signed, short-lived cookie ticket carrying BOTH the actor and the target;
getCurrentDbUser resolves the target so every page renders exactly what that
person sees, with the real actor named in a permanent banner.
- Read-only by construction. requireWriter() is the new guard on every
mutating server action and refuses while a ticket is active; requirePermission
blocks writes too, with an explicit requirePermissionForRead opt-out for the
handful of permissioned reads. Writes are blocked by DEFAULT, so an action
added later is safe until someone says otherwise.
- Rails: only holders of the new system.impersonate permission may start one;
accounts with full access can never be viewed as (wearing an owner's session
is indistinguishable from being one); no nesting; no self-impersonation;
disabled accounts excluded; the ticket is bound to the actor's session, so
signing out ends it by construction; both start and stop are written to the
previously-unused audit_logs table.
Config — SMTP settings are now editable at runtime, stored encrypted in
app_settings and overriding the environment, with a test that actually sends a
message. States the honest limitation in the UI: magic-link sign-in reads its
providers at startup, so it picks these up on restart; app-sent mail uses a
per-send transport and applies immediately.
Health — an operational/degraded/outage rollup (datastores are load-bearing, a
dead worker is degraded not an outage), the web app's own uptime/memory, and
migration-state detection: applied migrations vs what the build ships, which
catches the deploy where the pre-deploy migration step didn't run. Verified the
query against a real Postgres 16 after running the actual migrator.
Enterprise — licence key stored encrypted, gating flagged features. Honest
copy: an honour-system switch on a self-hosted MIT product, not a
cryptographic lock, and nothing phones home.
AI — unchanged provider management; usage reporting added as coming-soon and
enterprise-gated, with an explicit note that nothing is metered today.
New tests cover ticket signing/expiry/tampering and every impersonation rail;
EXPECTED_MIGRATION_COUNT is asserted against the journal so adding a migration
without bumping it fails CI. 275 tests pass, typecheck and build green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018A8f7g1t5FMFkYgx12aiu9
0 commit comments