08 — Form Specifications (Audit Module)
Every form field field-by-field. The Audit module has one form: the filter bar. There are no mutation forms — the module is append-only read (
audit.controller.ts:17), so no create/update/delete DTOs exist. Validation mirrors the absence of server-side DTOs:AuditController.query()takes raw query params with defaults (audit.controller.ts:19-25) — there is noAuditQueryDto, hence no class-validator rules; the client self-validates.
1. Audit Filter Form (non-mandatory, all fields optional)
| # | Field | Control | Query param | Server handling | Client UX / validation |
|---|---|---|---|---|---|
| 1 | Action | AppDropdown (searchable, free list) | action | optional string → filter.action (audit.controller.ts:22,27) | values = distinct actions from data; free text allowed (enum is open — audit.handler.ts:36) |
| 2 | Entity type | AppDropdown (searchable) | entityType | optional string → filter.entityType (audit.controller.ts:23,28) | exact match against entityType; helper note: rarely populated by emitters (OQ-1) |
| 3 | Actor | AppDropdown/AppTextField | actorId | optional string → filter.actorId (audit.controller.ts:24,29) | exact actorId string; name→id resolution (proposed) via users module |
| 4 | Page | implicit | page | default 1, cast Number(page) (audit.controller.ts:20,31) | client keeps internally; non-numeric → server CastError → 400 (http-exception.filter.ts:47-55) |
| 5 | Limit | implicit | limit | default 50, cast Number(limit) (audit.controller.ts:20,32) | client uses 50; unbounded server-side (no max clamp, OQ-7) |
| 6 | Date range | (planned) — no from/to params exist | — | — | blueprint promises date-range querying (AUDITING.md:86) — backend (planned) |
| 7 | Search q | (planned) | — | — | shared convention q (00-shared/07 §5) not supported by this controller |
| 8 | Sort | none (fixed) | — | — | always occurredAt desc (audit-log.repository.ts:23); sort param unsupported |
Filter combination rule (server): all present filters AND-combined into one Mongo
filter object, always merged with the tenant scope:
{ tenantId, action?, entityType?, actorId? } (audit.controller.ts:26-29,
audit.service.ts:45-48).
Form-level rules:
- Submitting a filter → reset
page=1→ reload; no debounce needed (explicit dropdown selection, not keystrokes); actor text field debounce 300 ms (AppSearchBardefault). - "Clear filters" resets all three fields + page.
- Double-submit: dropdowns single-select, no pending overlap; Load-more disabled while a request is in flight.
- Optimistic: none — filter changes always hit the server (list is server-paginated).
- Error priority (client, 00-shared/06 §5): 400/404 → keep filters, snackbar; 429 →
countdown; 5xx →
AppErrorState; 401 → session flow.
Empty-result copy: "No activity matches these filters" + Clear filters (not an error —
total === 0 is a valid success state).