Implement apix-registry with IoT sunset/decommission lifecycle and full BDD suite

- REST API: register, patch, O-level, replacements, history, search endpoints
- IoT lifecycle validations: future sunset, lock-before-release, sunset-passed-before-decommission
- DB schema: Liquibase changesets 001–008 (services, versions, replacements, sunset-at column)
- @ColumnTransformer(write="?::jsonb") on bsm_payload fields to avoid JDBC varchar→jsonb rejection
- Jandex plugin on apix-common + quarkus.index-dependency so @NotBlank validators resolve at runtime
- quarkus-logging-json extension added; quarkus.log.console.json=false is now a recognised key
- Fix requireSunsetBeforeLockRelease: Boolean.TRUE.equals instead of !Boolean.FALSE.equals (null guard)
- BDD suite: 27 scenarios / 213 steps across 5 feature files (sunset-lock, decommission, replacement, discovery, anonymity)
- Test infrastructure: JDBC TRUNCATE in @Before for DB isolation, Arc.container() for clock control — no test endpoints in production code
- sunsetAt truncated to microseconds in BDD steps to match Postgres timestamptz precision
- Cucumber step fixes: singular/plural candidate(s), lastResponse propagation in replacementsReturnsNCandidates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Carsten Rehfeld
2026-05-08 09:13:26 +02:00
commit b2a16a8be7
71 changed files with 5480 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
---
arc42: "4 — Solution Strategy"
status: stub
---
## 4.1 Technology Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Language + framework | Java 21 + Quarkus 3.x | Compile-time safety; purpose-built for microservices; GraalVM native image first-class (see ADR-001) |
| Production binary | GraalVM Native Image | ~5080MB RAM per service; ~100ms startup; fits Hetzner CX22 with headroom |
| Dev loop | `quarkus dev` (JVM mode) | Live reload + continuous testing; native build only for production image |
| Persistence | Hibernate ORM + Panache | Standard Quarkus persistence; Panache active record reduces boilerplate |
| BSM payload | PostgreSQL JSONB + `@JdbcTypeCode(SqlTypes.JSON)` | Flexible schema for optional BSM fields without a separate document store |
| Migrations | Liquibase | User's existing tool; first-class Quarkus extension; rollback + context support (see ADR-008) |
| Reverse proxy | Caddy | Auto-TLS with Let's Encrypt; minimal config (see ADR-003) |
| Portal rendering | HTMX + Qute | No JS build pipeline; type-safe templates (build-time error on missing variables); idiomatic Quarkus (see ADR-004) |
| Spider concurrency | Java 21 virtual threads (`@RunOnVirtualThread`) | Non-blocking HTTP checks without reactive programming complexity |
| HTTP client (Spider) | Quarkus REST Client Reactive | Declarative; integrates with Quarkus DI and fault tolerance extensions |
| Build tool | Maven 3.9 | Quarkus documentation is Maven-first; Quarkus Maven plugin handles native build |
| Testing | JUnit 5 + `@QuarkusTest` + RestAssured + WireMock | `@QuarkusTest` starts real application context; RestAssured for HTTP assertions; WireMock for external API mocks |
## 4.2 Architectural Patterns
| Pattern | Application |
|---|---|
| HATEOAS | `IndexResource` returns all navigation links; agents navigate from root without prior knowledge |
| Repository pattern | DB access in `ServiceRepository` (Panache); business logic in `RegistryService`; resources are thin |
| Compile-time DI | Quarkus CDI resolves all injection at build time; no runtime reflection surprises |
| Scheduler-based Spider | `@Scheduled(every="15m")` on `SpiderScheduler`; stateless per run; virtual threads for concurrent checks |
| Verification pipeline | Sequential O-level elevation (O-1 → sanctions → O-2 → O-3); each step is an independent CDI bean |
| API key on writes | Single shared key for MVP via custom Quarkus Security identity provider; per-registrant keys post-MVP |
| Fail-fast validation | BSM validated at boundary via Bean Validation (`@Valid` on JAX-RS resource); invalid BSM rejected with 400 + constraint violation details |
## 4.3 Quality Goal → Decision Mapping
| Quality Goal | Architecture Decision |
|---|---|
| Compile-time safety | Quarkus CDI + Bean Validation + Qute type-safe templates — errors at build time, not runtime |
| Queryability | HATEOAS root + capability search; JPQL + JSONB operator query in ServiceRepository |
| Liveness accuracy | SpiderScheduler every 15 min; `last_checked_at` + `uptime_30d_percent` exposed in response |
| Registration reliability | Idempotent `UPSERT` on endpoint URL; Liquibase migrations with rollback support |
| Security hygiene | HTTPS via Caddy; API key on write endpoints; no PII in logs; non-root container user |
| Solo maintainability | Docker Compose; `quarkus dev` for local loop; single JVM language across all services |
## 4.4 MVP Shortcuts (Accepted Technical Debt)
| Shortcut | Exit Path |
|---|---|
| O-4 / O-5 assigned manually | Accredited Verifier integration post-MVP |
| Single shared API key | Per-registrant key management + OAuth2 post-MVP |
| No rate limiting on read endpoints | Caddy rate_limit directive when traffic warrants |
| OpenAPI / MCP parsers validate presence only | Field-level spec comparison in Spider post-MVP |
| Single-region deployment | Hetzner multi-region + Managed Database post-funding |
| No billing | Commercial tier in Phase 2 |
| No CI/CD pipeline | GitHub Actions native build pipeline post-MVP |