[AZ-529] [AZ-530] Cycle-2 documentation refresh

Refreshes _docs/02_document/ to reflect the cycle-2 auth-modernization
+ CMMC hardening landings (AZ-531..AZ-538). Authoritative source for
the ripple set is ripple_log_cycle2.md.

Covered:
- architecture.md (section 1 rewritten, ADRs 6-9 added)
- data_model.md (sessions, audit_events, user columns, migrations)
- system-flows.md (F1 rewritten; F11-F17 added; F2/F7/F9 minor)
- module-layout.md (cycle-2 sub-component table)
- diagrams/flows/flow_login.md (dual-token + MFA)
- components/{01_data_layer,03_auth_and_security,05_admin_api}
- modules/ (12 new, 8 modified — full Argon2id/ES256/MFA/refresh
  /mission/session/audit/jwks rollup)
- tests/{blackbox,security,traceability-matrix}

Step 13 (Update Docs) output for cycle 2.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-14 09:22:53 +03:00
parent c2c659ef62
commit a77b3f8a59
35 changed files with 3624 additions and 468 deletions
@@ -0,0 +1,73 @@
# Module: Azaion.Common.Entities.AuditEvent
## Purpose
Append-only audit row for security-relevant events: login outcomes, lockouts, and the MFA enrollment / login lifecycle. Drives both the per-account sliding-window rate limit (AZ-537) and the human-readable security trail.
> Added in cycle 2 (2026-05-14). Initial event types from AZ-537 (login_failed / login_success / login_lockout); MFA event types added by AZ-534 in the same cycle.
## Public Interface
### AuditEvent
| Property | Type | Description |
|----------|------|-------------|
| `Id` | `long` | DB-assigned identity. |
| `EventType` | `string` | One of `AuditEventTypes`. |
| `OccurredAt` | `DateTime` | `now()` at insert. |
| `Email` | `string?` | Normalised lowercase. NULL for system events without a subject. |
| `Ip` | `string?` | Caller IP from `HttpContext.Connection.RemoteIpAddress`. NULL for background tasks. |
| `Metadata` | `string?` | Reserved for future structured payload. Not used today. |
### AuditEventTypes (constants)
| Value | When |
|-------|------|
| `login_failed` | Wrong password, locked account, or rate-limit reject. |
| `login_lockout` | Account just hit `MaxAttempts` and was locked. |
| `login_success` | Password verified, MFA not required. |
| `mfa_enroll` | `/users/me/mfa/enroll` succeeded. |
| `mfa_confirm` | `/users/me/mfa/confirm` succeeded; MFA now active. |
| `mfa_disable` | `/users/me/mfa/disable` succeeded. |
| `mfa_login_success` | `/login/mfa` succeeded with TOTP. |
| `mfa_login_failed` | `/login/mfa` rejected (bad TOTP and bad recovery code). |
| `mfa_recovery_used` | `/login/mfa` succeeded with a recovery code (also burns the code). |
## Internal Logic
None — pure data class. All write/read logic lives in `AuditLog`.
## Dependencies
None.
## Consumers
- `AuditLog` — produces every row; reads via `CountRecentFailedLogins`.
- `AzaionDb.AuditEvents``ITable<AuditEvent>` access.
- `AzaionDbSchemaHolder` — maps `AuditEvent` to the `audit_events` table.
## Data Models
Maps to PostgreSQL table `audit_events` (defined in `env/db/07_auth_lockout_and_audit.sql`).
Columns: `id (bigserial PK)`, `event_type (varchar(64))`, `occurred_at (timestamp default now())`, `email (varchar(160) NULL)`, `ip (varchar(64) NULL)`, `metadata (text NULL)`.
Index: `audit_events_event_type_email_idx (event_type, email, occurred_at DESC)` — supports the per-account sliding-window failed-login count in O(window-rows).
## Configuration
None.
## External Integrations
None.
## Security
- Append-only by convention — `azaion_admin` only has `INSERT, SELECT` on the table.
- Stores PII (email, IP); access is gated to `azaion_admin` and `azaion_reader` only. No public endpoint surfaces audit rows.
- The table backs CMMC AC.L2-3.1.8 ("limit unsuccessful logon attempts") — tampering with it bypasses the rate limit + lockout enforcement.
## Tests
Indirectly tested via `RateLimitLockoutTests`, `MfaEnrollmentTests`, `MfaLoginTests` (assertions on the resulting `audit_events` rows).