feat: audit log and settings admin pages (PH6.3) #77

Merged
bart merged 3 commits from feature/web-audit-settings into main 2026-09-11 13:20:04 +00:00
Collaborator

Description

Admins (and planners, read-only) can now browse the audit trail and admins can edit runtime settings from the app itself, instead of neither page existing yet.

The audit page lists every recorded change - who did it, to what, when and why - and lets you filter by entity, entity id, actor and date range, with a details view showing the before/after values for a given entry. The settings page lists the app's runtime settings and lets an admin edit one in place; every save requires a short reason, which is recorded in the audit trail alongside the change itself, the same way every other change in the system already works.

Closes #44. Row PH6.3 in docs/12-implementation-plan.md.

Type of Change

  • New feature
  • Bug fix
  • Refactor / cleanup (no behaviour change)
  • Documentation
  • Chore / build / CI
  • Breaking change

Breaking Changes

None.

Test Plan

Tests green: backend (ruff, mypy --strict, pytest unit + integration against a real Postgres) and frontend (ng lint, ng test, ng build, i18n parity check) all pass.

Checklist

  • Conventional commit(s), one logical change per commit
  • Tests added/updated and passing
  • docs/ updated for any behavioural change (ADR added if a prior decision was reversed)
  • No hard deletes; no direct status updates outside polaris.domain
  • No business logic in routers/components
  • Migration included if the schema changed (one per PR max, reversible downgrade)
  • No new dependency without a reason in the commit body

Additional Context

  • Settings only supports editing an existing setting's value - there is no way to create a brand new setting key through the API or UI, matching how the settings catalogue is meant to be seeded, not invented on the fly.
  • The settings list currently shows every row on one page rather than paginating, since the whole catalogue is expected to stay small.
  • One small, isolated touch to frontend/eslint.config.js outside this ticket's own paths: it now excludes the generated, git-ignored API client types directory from linting, since this is the first feature to actually generate and import it.

🤖 Generated with Claude Code

https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM

## Description Admins (and planners, read-only) can now browse the audit trail and admins can edit runtime settings from the app itself, instead of neither page existing yet. The audit page lists every recorded change - who did it, to what, when and why - and lets you filter by entity, entity id, actor and date range, with a details view showing the before/after values for a given entry. The settings page lists the app's runtime settings and lets an admin edit one in place; every save requires a short reason, which is recorded in the audit trail alongside the change itself, the same way every other change in the system already works. ## Related Issues Closes #44. Row PH6.3 in docs/12-implementation-plan.md. ## Type of Change - [x] New feature - [ ] Bug fix - [ ] Refactor / cleanup (no behaviour change) - [ ] Documentation - [ ] Chore / build / CI - [ ] Breaking change ## Breaking Changes None. ## Test Plan Tests green: backend (ruff, mypy --strict, pytest unit + integration against a real Postgres) and frontend (ng lint, ng test, ng build, i18n parity check) all pass. ## Checklist - [x] Conventional commit(s), one logical change per commit - [x] Tests added/updated and passing - [x] `docs/` updated for any behavioural change (ADR added if a prior decision was reversed) - [x] No hard deletes; no direct status updates outside `polaris.domain` - [x] No business logic in routers/components - [ ] Migration included if the schema changed (one per PR max, reversible downgrade) - [x] No new dependency without a reason in the commit body ## Additional Context - Settings only supports editing an existing setting's value - there is no way to create a brand new setting key through the API or UI, matching how the settings catalogue is meant to be seeded, not invented on the fly. - The settings list currently shows every row on one page rather than paginating, since the whole catalogue is expected to stay small. - One small, isolated touch to `frontend/eslint.config.js` outside this ticket's own paths: it now excludes the generated, git-ignored API client types directory from linting, since this is the first feature to actually generate and import it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Replace the 501 stubs with real implementations: the audit endpoint is
paginated and filterable by entity, entity id, actor and period; the
settings endpoint requires admin plus a non-empty reason on writes and
applies changes through new polaris.domain.audit/settings services (hard
rule #3), backed by new polaris.db.repositories.audit/settings
implementations of the repository protocols those services define for
themselves, following the domain/tasks.py + db/repositories/task.py
precedent from PH0.3.

Adjust the shared 501-stub test file to drop the audit/settings
assertions that are no longer true now that those endpoints do real work;
their role-check and behaviour tests move to dedicated
audit_test.py/settings_test.py files.

Closes #44
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Alias the polaris.domain imports instead of renaming the route handler
functions, so FastAPI's default operationId (derived from the function
name) stays list_audit_log/get_settings/update_settings, matching the
PH1.7 stub contract the frontend's generated client already expects.

Regenerate backend/openapi.json: the new page/size query params on
GET /audit and the required X-Reason header on PUT /settings weren't on
the 501 stub's spec (its handler never read them), everything else is
unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Build P13 (audit log: filterable/paginated table with a before/after
details dialog) and P14 (settings: list + edit-in-place with a required
reason) against the real GET /audit and GET/PUT /settings endpoints,
replacing the NotBuiltPage placeholders. Each page gets its own
signalStoreFeature-composed store (audit.store.ts = withFilters() +
withEntries(), settings.store.ts = withList() + withSave()), following
the notifications store's worked slice-composition example, provided
per-route rather than providedIn: 'root' since this is page-scoped state.
DTOs are generated types from core/api/generated/schema.d.ts (npm run
api:gen against backend/openapi.json), never hand-written. Both features
add nl/en i18n with full key parity.

Add one deliberate, isolated touch to eslint.config.js (outside this
ticket's owned paths) to stop the generated, git-ignored
core/api/generated/** directory from being linted as hand-written
source: this is the first feature to actually generate and import it, so
the gap only surfaces now.

Closes #44
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
bart merged commit e33a54d897 into main 2026-09-11 13:20:04 +00:00
bart deleted branch feature/web-audit-settings 2026-09-11 13:20:04 +00:00
Sign in to join this conversation.
No description provided.