- ui/handlers_accounts.go (handleIssueSystemToken): call
GetSystemToken before issuing; if one exists, call
RevokeToken(existing.JTI, "rotated") before TrackToken
and SetSystemToken for the new token; mirrors the pattern
in REST handleTokenIssue and gRPC IssueServiceToken
- db/db_test.go: TestSystemTokenRotationRevokesOld verifies
the full rotation flow: old JTI revoked with reason
"rotated", new JTI tracked and active, GetSystemToken
returns the new JTI
- AUDIT.md: mark F-16 as fixed
Security: without this fix an old system token remained valid
after rotation until its natural expiry, giving a leaked or
stolen old token extra lifetime. With the revocation the old
JTI is immediately marked in token_revocation so any validator
checking revocation status rejects it.
The package-level defaultRateLimiter drained its token bucket
across all test cases, causing later tests to hit ResourceExhausted.
Move rateLimiter from a package-level var to a *grpcRateLimiter field
on Server; New() allocates a fresh instance (10 req/s, burst 10) per
server. Each test's newTestEnv() constructs its own Server, so tests
no longer share limiter state.
Production behaviour is unchanged: a single Server is constructed at
startup and lives for the process lifetime.
- Introduced `web/templates/` for HTMX-fragmented pages (`dashboard`, `accounts`, `account_detail`, `error_fragment`, etc.).
- Implemented UI routes for account CRUD, audit log display, and login/logout with CSRF protection.
- Added `internal/ui/` package for handlers, CSRF manager, session validation, and token issuance.
- Updated documentation to include new UI features and templates directory structure.
- Security: Double-submit CSRF cookies, constant-time HMAC validation, login password/Argon2id re-verification at all steps to prevent bypass.