b2a16a8be7
- 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>
4.8 KiB
4.8 KiB
arc42, status
| arc42 | status |
|---|---|
| 5 — Building Block View | stub |
5.1 Level 1 — Maven Module Structure
@startuml modules
skinparam packageStyle rectangle
package "apix-common\n(plain Java 21 library)" as common {
component [OLevel\nLivenessStatus\nBsmPayload\nServiceSummaryDto\nVerificationResult] as dtos
}
package "apix-verification\n(plain Java 21 library)" as verification {
component [O1DnsVerifier\nO2GleifVerifier\nO2OpenCorporatesVerifier\nO3HygieneVerifier\nSanctionsScreener\nVerificationPipeline] as verifiers
}
package "apix-registry\n(Quarkus 3.x app)" as registry {
component [IndexResource\nServiceResource\nRegisterResource] as res
component [RegistryService\nVerificationOrchestrator] as svc
component [ServiceRecord\nServiceRepository] as repo
component [Liquibase\nmigrations] as lb
}
package "apix-spider\n(Quarkus 3.x app)" as spider {
component [SpiderScheduler\nLivenessFetcher\nLivenessEvaluator\nOpenApiParser\nMcpParser] as spider_core
component [SpiderServiceView\nSpiderRepository] as spider_repo
}
package "apix-portal\n(Quarkus 3.x app)" as portal {
component [PortalResource\nAdminResource\nRegistryClient] as portal_res
component [Qute templates] as templates
}
verification ..> common : depends on
registry ..> common : depends on
registry ..> verification : depends on
spider ..> common : depends on
portal ..> common : depends on
@enduml
5.2 Level 1 — Deployment View (Docker Compose)
@startuml deploy_l1
package "Docker Compose — Hetzner CX22" {
component [Caddy\n:80 / :443] as caddy
component [apix-registry\n:8180 (internal)] as registry
component [apix-spider\n:8082 (internal only)] as spider
component [apix-portal\n:8081 (internal)] as portal
database [PostgreSQL 16\n:5432 (internal)] as db
}
cloud Internet
Internet --> caddy : HTTPS
caddy --> registry : /api/*
caddy --> portal : /*
registry --> db : Hibernate ORM (Liquibase owner)
spider --> db : Hibernate ORM (Liquibase disabled)
portal --> registry : REST Client (HTTP internal)
spider --> [External Services] : liveness checks (HTTPS)
@enduml
5.3 Level 2 — apix-registry Internals
@startuml level2_registry
package "apix-registry" {
component [IndexResource] as r_index
component [ServiceResource] as r_svc
component [RegisterResource] as r_reg
component [RegistryService] as svc
component [VerificationOrchestrator] as orch
component [ServiceRepository\n(Panache)] as repo
component [Bean Validation\n(@Valid on JAX-RS)] as val
}
r_index --> svc
r_svc --> svc
r_reg --> val
r_reg --> svc
r_reg --> orch
svc --> repo
orch --> [VerificationPipeline\n(apix-verification)]
orch --> repo : persist VerificationResult
@enduml
5.4 Level 2 — apix-spider Internals
@startuml level2_spider
package "apix-spider" {
component [SpiderScheduler\n@Scheduled(every=15m)] as sched
component [LivenessFetcher\n@RestClient\n@RunOnVirtualThread] as fetcher
component [LivenessEvaluator\n(pure logic)] as eval
component [OpenApiParser] as oa
component [McpParser] as mcp
component [SpiderRepository\n(Panache)] as repo
}
sched --> repo : load services due for check
sched --> fetcher : dispatch per service
fetcher --> eval : HTTP status + response_ms
fetcher --> oa : spec URL
fetcher --> mcp : MCP URL
eval --> repo : write LivenessStatus
oa --> repo : write spec validation result
mcp --> repo : write spec validation result
@enduml
5.5 Component Responsibility Table
| Module / Component | Type | Responsibility |
|---|---|---|
apix-common |
Plain Java library | Shared enums and DTOs; no framework dependency; used by all modules |
apix-verification |
Plain Java library | O-level elevation pipeline; pure logic + external HTTP/DNS calls via java.net.http; no Quarkus context |
apix-registry |
Quarkus app | REST API (HATEOAS); BSM registration + validation; capability search; schema owner (Liquibase) |
apix-spider |
Quarkus app | Scheduled liveness checks; OpenAPI/MCP spec verification; writes liveness metrics to DB; independent lifecycle |
apix-portal |
Quarkus app | Human-readable web portal (HTMX + Qute); registration form; admin O-level view; calls registry via REST Client |
VerificationOrchestrator |
CDI bean (registry) | Bridge between Quarkus config injection and the plain-Java VerificationPipeline; persists results |
LivenessEvaluator |
Plain class (spider) | Pure function: HTTP status + response time → LivenessStatus; no I/O; testable without Quarkus |
ServiceRecord |
Panache entity (registry) | Full entity — all columns; schema owner |
SpiderServiceView |
Panache entity (spider) | Read/write subset of services table — only liveness columns; does not run migrations |
| PostgreSQL | Database | Single shared instance; registry owns schema; spider and portal are consumers |