chore(activity-log): scaffold feature plan and phase subplans
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# Phase 4: REST API — query / filter / export / settings / clear
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
|
||||
Expose the audit log over the REST API: a filtered, keyset-paginated list endpoint; a
|
||||
streaming CSV/JSON export honoring the same filters; retention settings get/update; and a
|
||||
destructive clear. Apply the project's auth posture (stricter auth on export + clear).
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] `server/src/ledgrab/api/schemas/activity_log.py` (Pydantic):
|
||||
- `ActivityLogEntryResponse` (matches the frozen Phase 2 entry dict shape).
|
||||
- `ActivityLogPageResponse` { `entries: list[...]`, `next_before_seq: int | None`,
|
||||
`total: int` (optional/over filters), `has_more: bool` }.
|
||||
- `ActivityLogSettingsResponse` / `UpdateActivityLogSettingsRequest`
|
||||
(`enabled`, `max_days`, `max_entries`) with validation bounds.
|
||||
- [ ] `server/src/ledgrab/api/routes/activity_log.py` — `APIRouter(prefix="/api/v1/activity-log")`:
|
||||
- `GET ""` — list. Query params: `categories`, `severities`, `actor`, `entity_type`,
|
||||
`entity_id`, `since`/`until` (ISO), `q` (free-text), `before_seq` (cursor), `limit`
|
||||
(default 50, capped e.g. 200). `AuthRequired`. Maps params → `ActivityLogFilters`,
|
||||
calls `repo.query(...)`, returns page envelope.
|
||||
- `GET "/export"` — streaming export. Same filters; `format=csv|json`. Uses
|
||||
`StreamingResponse` over `repo.iter_export(...)`. **`require_authenticated()`** (may
|
||||
contain IPs/labels). Sets `Content-Disposition` with a timestamped filename.
|
||||
- `GET "/settings"` / `PUT "/settings"` — retention settings via the retention engine.
|
||||
`AuthRequired`; updates apply immediately.
|
||||
- `DELETE ""` — clear all entries. **`require_authenticated()`**. The clear is itself
|
||||
audited (recorder records a `system`/`activity_log_cleared` entry AFTER the wipe, so the
|
||||
log shows who cleared it and when).
|
||||
- Register the router in `server/src/ledgrab/api/__init__.py` (aggregator).
|
||||
- [ ] API tests `server/tests/api/routes/test_activity_log_api.py`:
|
||||
- list returns entries; each filter narrows results; `before_seq` cursor paginates without
|
||||
overlap/gaps; `limit` cap enforced;
|
||||
- export CSV and JSON both stream and honor filters; export requires authentication
|
||||
(401 for loopback-anonymous when keys configured);
|
||||
- settings get/update round-trip + validation rejects out-of-range;
|
||||
- clear empties the log, requires auth, and leaves exactly one post-clear audit entry.
|
||||
|
||||
## Files to Modify/Create
|
||||
|
||||
- `server/src/ledgrab/api/schemas/activity_log.py` — new
|
||||
- `server/src/ledgrab/api/routes/activity_log.py` — new
|
||||
- `server/src/ledgrab/api/__init__.py` — modify: register router
|
||||
- `server/tests/api/routes/test_activity_log_api.py` — new
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- List is filterable on every dimension and keyset-paginated (stable, no dupes/gaps).
|
||||
- Export streams CSV + JSON, honors filters, and requires authentication.
|
||||
- Settings get/update works and validates bounds; changes take effect immediately.
|
||||
- Clear requires authentication and is itself audited.
|
||||
- New + existing tests green; `ruff` clean.
|
||||
|
||||
## Notes
|
||||
|
||||
- Auth helpers: `AuthRequired` dependency for normal endpoints; `require_authenticated()` for
|
||||
export + clear (pattern: backup download / secret reveal). See `api/auth.py` + `server/CLAUDE.md`.
|
||||
- Follow the existing route/schema conventions (one schema file per entity, router registered
|
||||
in `api/__init__.py`). Reference `api/routes/backup.py` for settings-style GET/PUT + a
|
||||
`StreamingResponse`/download pattern.
|
||||
- Reuse the entry→dict serializer from Phase 2 to keep the response shape single-sourced.
|
||||
- Backup/restore: no `STORE_MAP` change needed — backup is whole-DB; the table is auto-covered.
|
||||
|
||||
## Review Checklist
|
||||
|
||||
- [ ] All tasks completed
|
||||
- [ ] Code follows project conventions (router registration, schema-per-entity, auth posture)
|
||||
- [ ] No unintended side effects
|
||||
- [ ] Build passes (ruff + pytest)
|
||||
- [ ] Tests pass (new + existing)
|
||||
|
||||
## Handoff to Next Phase
|
||||
|
||||
<!-- Filled in by the implementer: exact endpoint paths, query-param names, page-envelope
|
||||
field names, and settings field bounds — Phase 5/6 frontend consumes these verbatim. -->
|
||||
Reference in New Issue
Block a user