Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6181e52
docs: add audit log module design spec
antosubash May 27, 2026
74c0507
docs: add audit log module implementation plan
antosubash May 27, 2026
491337a
feat(db): add AuditRecord dataclass and collect_audit_records diff logic
antosubash May 27, 2026
24ac63b
feat(db): wire audit callback into DatabaseState and before_flush lis…
antosubash May 27, 2026
99f1ae1
feat(audit_log): scaffold module package with constants and host wiring
antosubash May 27, 2026
0cf6fa6
feat(audit_log): add AuditEntry model and DTO schemas
antosubash May 27, 2026
12cf80b
feat(audit_log): add capture callback
antosubash May 27, 2026
946ea98
feat(audit_log): add service layer and deps
antosubash May 27, 2026
16c0ff7
feat(audit_log): add API and Inertia view endpoints
antosubash May 27, 2026
be5b081
feat(audit_log): add AuditLogModule with lifecycle hooks
antosubash May 27, 2026
4d38868
feat(audit_log): add i18n locale strings
antosubash May 27, 2026
6dcd2a2
feat(audit_log): add Browse.tsx page with filters, pagination, and ch…
antosubash May 27, 2026
eb427fd
test(audit_log): add integration tests for capture, API filtering, an…
antosubash May 27, 2026
15b7c64
migration(audit_log): add audit_log_audit_entry table
antosubash May 27, 2026
97623f8
chore: regenerate i18n and package-lock with audit_log module
antosubash May 27, 2026
4625aed
fix(audit_log): use datetime-local inputs and preserve page_size in n…
antosubash May 27, 2026
1a27147
fix(test): ensure test_filter_by_action is non-vacuous
antosubash May 27, 2026
d7493ba
fix(audit_log): deterministic pagination, error-resilient capture, en…
antosubash May 27, 2026
6420101
fix(db): correctly classify soft-deleted entities and exclude SoftDel…
antosubash May 27, 2026
22c6c5d
fix(audit_log): gracefully handle invalid query params in view endpoint
antosubash May 27, 2026
c7192e9
fix(db): two-phase audit capture resolves DB-assigned integer PKs
antosubash May 28, 2026
13d43a1
chore(audit_log): format files, fix frozenset typing, add e2e specs
antosubash May 28, 2026
96b24d1
chore: add QA report and verification screenshots
antosubash May 28, 2026
3a25897
style(audit_log): align Browse page layout with other module pages
antosubash May 28, 2026
88e40ee
fix(audit_log): satisfy CI checks for the layout pass
antosubash May 28, 2026
54d913d
fix(audit_log): inline useT in ChangesList to satisfy TS strict typing
antosubash May 28, 2026
b3e91e2
fix(ci): unblock PR checks
antosubash May 28, 2026
fe7c124
ci(e2e): include AuditLog in SM_MODULES_ENABLED allowlist
antosubash May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -149,7 +149,7 @@ jobs:
SM_USERS_BOOTSTRAP_PASSWORD: admin
# Exclude Keycloak module — SM020 prevents both users and keycloak
# from running simultaneously. E2E tests use the users module.
SM_MODULES_ENABLED: '["Auth","Users","Dashboard","Permissions","Settings","BackgroundTasks","FileStorage","FeatureFlags"]'
SM_MODULES_ENABLED: '["Auth","Users","Dashboard","Permissions","Settings","BackgroundTasks","FileStorage","FeatureFlags","AuditLog"]'
E2E_BASE_URL: http://localhost:8000
steps:
- uses: actions/checkout@v6
Expand Down
83 changes: 83 additions & 0 deletions .qa/reports/qa-report-iteration-1.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
# QA Report: Audit Log Module
**Date:** 2026-05-28
**Tester:** Claude QA (Senior)
**Target:** http://localhost:8000/audit_log
**Depth:** normal
**Iteration:** 1 of 3

## Summary
| Category | Passed | Failed | Skipped |
|----------|--------|--------|---------|
| Happy Path | 8 | 2 | 0 |
| Form Validation | — | — | — (agent timed out) |
| Error States | 11 | 6 | 0 |
| **Total** | **19** | **8** | **0** |

## Critical Issues (P0)
None.

## Major Issues (P1)

### BUG-001: Invalid query params render raw JSON validation errors
- **Severity:** P1 (4 instances: ES-005, ES-006, ES-007, ES-008)
- **Steps to reproduce:** Navigate to /audit_log?page_size=0 or /audit_log?page=-1 or /audit_log?page=abc or /audit_log?page_size=500
- **Expected:** Graceful fallback — clamp to defaults or show user-friendly error page
- **Actual:** Raw FastAPI JSON validation error shown as entire page content: `{"detail":[{"type":"greater_than_equal",...}]}`
- **Root cause:** Inertia view endpoint uses `Query(ge=1, le=200)` constraints which raise `RequestValidationError` — no handler converts these to Inertia-friendly responses
- **Fix hint:** Add a `RequestValidationError` exception handler in the view that either clamps to defaults or renders an Inertia error page. Could be framework-level (benefits all modules).

## Minor Issues (P2)

### BUG-002: Setting entity_id is empty string for integer-PK entities
- **Severity:** P2
- **Steps to reproduce:** Create a Setting via POST /api/settings/, then check the audit log for that Setting's "Created" entry
- **Expected:** entity_id shows the Setting's actual ID (e.g., "1")
- **Actual:** entity_id is "" (empty string) — the entity column shows "Setting" with no ID
- **Root cause:** Known limitation — `_entity_pk_str` runs during before_flush when integer PKs haven't been assigned yet. UUID PKs work fine.
- **Fix hint:** Architectural change needed — move to after_flush or accept as known limitation for integer-PK models.

## Observations (P3)

### OBS-001: Sidebar "Audit Log" link has no active/highlighted state
- **Severity:** P3
- **Details:** All sidebar links share identical CSS classes regardless of current page. No `aria-current="page"` is set. This is a framework-wide issue affecting all modules, not specific to Audit Log.

### OBS-002: Entity Type dropdown opens on Tab focus
- **Severity:** P3
- **Details:** The Radix Select component's Entity Type dropdown auto-opens when receiving Tab focus, potentially trapping keyboard navigation. This is a known Radix UI behavior.

### OBS-003: Out-of-range page shows empty state without context
- **Severity:** P3
- **Details:** /audit_log?page=999 shows "No audit entries" empty state. Could show "Page out of range" or redirect to last valid page.

### OBS-004: Form validation agent timed out
- **Details:** The form validation agent stalled while testing datetime-local inputs (likely Playwright interaction complexity with date pickers). Core form validation was partially covered by other agents.

## Passed Tests

<details>
<summary>Click to expand (19 tests passed)</summary>

| # | Category | Scenario | Result |
|---|----------|----------|--------|
| 1 | Happy Path | Page loads with data | PASS |
| 2 | Happy Path | Filter by Entity Type | PASS |
| 3 | Happy Path | Filter by Action | PASS |
| 4 | Happy Path | Filter by User ID | PASS |
| 5 | Happy Path | Clear filters | PASS |
| 6 | Happy Path | Pagination (Next/Previous) | PASS |
| 7 | Happy Path | New entity generates audit entry | PASS |
| 8 | Happy Path | Empty state display | PASS |
| 9 | Error States | Empty state for zero results | PASS |
| 10 | Error States | URL-based filter preselection | PASS |
| 11 | Error States | page_size=5 via URL | PASS |
| 12 | Error States | Browser back preserves state | PASS |
| 13 | Error States | Page refresh preserves filters | PASS |
| 14 | Error States | Enter key submits filter form | PASS |
| 15 | Error States | Rapid Apply clicks (5x) | PASS |
| 16 | Error States | Unauthenticated redirect to login | PASS |
| 17 | Error States | API endpoint returns JSON | PASS |
| 18 | Error States | API returns 401 unauthenticated | PASS |
| 19 | Error States | XSS in params safely handled | PASS |

</details>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added.qa/screenshots/iteration-1/99-fix-verify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified.verify/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading