Files
apix-mvp/docs/arc42/05-building-blocks.md
Carsten Rehfeld b2a16a8be7 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>
2026-05-08 09:13:26 +02:00

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