Skip to content

Design Decisions

stdOWL edited this page Jun 22, 2026 · 1 revision

Design Decisions and Trade-offs

Why the project is built the way it is. (AI_USAGE.md in the repo has the full phase-by-phase record.)

Decision Why Trade-off / note
WebFlux + Kotlin coroutines Non-blocking reactive stack; suspend handlers read like synchronous code Reactive learning curve; blocking work (BCrypt) must be pushed off the event loop
JWT, login-only Stateless auth, no session store; accounts are seeded (no self-registration by design) No token revocation before expiry (deferred)
Token-bucket rate limiting Smooths bursts, caps the sustained rate; pluggable in-memory / Redis Behind a proxy, accurate per-client limiting needs the real client IP — see Rate Limiting
R2DBC + H2, Flyway over JDBC Reactive DB access; one tool owns schema + seed H2 in-memory → data resets, single instance; Postgres is the scale-out path
DB-trigger audit trail Can't be bypassed by the app path; Envers is JPA-only (N/A on R2DBC) H2 delete-attribution caveat — see Data Migrations and Auditing
SPA served from the backend One origin, one container, no CORS between UI and API UI + API release together; the image build includes a Node stage
Cloud Run over GKE Scale-to-zero, ~$0 idle, no cluster to operate Single instance with in-memory data; a managed DB is needed to scale out
Keyless CI (WIF) No long-lived service-account keys stored in GitHub One-time Workload Identity setup

Known limitations

  • In-memory H2 → single instance; data resets on restart.
  • Rate limiting behind Cloud Run is coarse unless the real client IP is wired in (Troubleshooting).
  • No JWT revocation before expiry.

Clone this wiki locally