New /admin/system panel (operations.md §Maintenance jobs): the maintenance
job list shows every registered job with truthful last-run data (new
Job.lastDurationMs recorded by the scheduler) and a manual trigger that
respects the run-mutex and is itself audit-logged; a backup card mirrors
the sidecar's status.json including the freshness verdict; an audit-log
viewer filters by actor, action, and time range with pagination; and a
storage overview lists the largest ponds. Auth events and admin actions
(grants, members, user/quota admin, plugins, settings, setup) now land in
a new audit_log table through a central AuditService — which keeps
emitting the established stdout log line — while content activity stays
log-only by design. All endpoints are Site-Admin-only; covered by API DB
tests and a Playwright pack in CI.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
Instance operators get basic user administration for support, abuse handling,
and GDPR groundwork (security.md §Privacy).
- api `admin/`: Site-Admin-gated `/admin/users` — a searchable, paginated list
(username, e-mail, status, role, pond count, last login) plus lifecycle
actions: disable/enable (a disabled user is logged out everywhere and login
is refused with the distinct `account_disabled`), resend verification, delete,
and grant/revoke Site Admin. Guards: you cannot act on your own account
(`cannot_modify_self`) and the last Site Admin cannot be dropped
(`last_site_admin`). Every action is audit-logged with the actor.
- `PseudonymizationService`: account deletion scrubs the PII, removes all login
identities + sessions, and trashes the personal pond — the kept row is what
authorship references, so shared content the user authored shows as "Deleted
user" (no orphaned/cascaded content).
- web: the Admin area gains a 'Users' surface — search, pagination, and the
actions (destructive ones behind an inline two-step confirm; self-actions
hidden). New `users` i18n namespace (de+en).
- tests: `user-admin.e2e.db.test.ts` (disable → logout + login blocked; delete
→ pseudonymized authorship + personal pond trashed + credentials gone; last
Site Admin and self protected; Site-Admin gating); a non-destructive browser
`admin-users` pack proving disable-in-UI blocks login and enable restores it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
Site Admins tune quotas per user and per pond on the three-level ladder
(pond override → user override → instance default, data-model.md §Quotas).
- api `admin/`: a `QuotaAdminService` + Site-Admin-gated endpoints under
`/admin/quotas` — look up a user (username/e-mail) or pond (slug), list every
quota's override / instance default / effective value (resolved through the
existing QuotaService, the single consumption path, so a change takes effect
immediately) plus current usage, and set/clear a per-subject override. Every
change is audit-logged. A pond's effective values resolve on its own override
then its owner's, matching the consumption checks.
- web: the Admin area gains a 'Quotas' surface — the instance defaults move
into a proper number-input form (was raw settings, #19), and a per-subject
panel looks a user/pond up, shows the ladder with usage, flags subjects over
their effective limit, and sets/clears overrides. New `quotas` i18n
namespace (de+en).
- tests: `quota-admin.e2e.db.test.ts` (override → effective changes at once and
QuotaService sees it; clear → falls back to the default; lookup; Site-Admin
gating); a browser `admin-quotas` pack proving an override raised in the UI
immediately lets a user create another shared pond (issue #22 consumption).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
Server halves of #17/#18/#19: PATCH /users/me and change-password
(verifies the current password, logs out every other session),
GET/DELETE /users/me/sessions with current-session flag and protection
against revoking oneself; InstanceSettingsService as a typed, cached,
Zod-validated registry over instance_settings (schema-default fallback
for invalid stored values, audit-logged writes) consumed by the signup
flow; /admin/settings behind the new SiteAdminGuard with strict
unknown-key rejection. SessionsService moves to its own module to keep
Auth/Users acyclic. Three new e2e suites bring the api to 42 tests.
Part of #17, #18, #19
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>