Architecture Overview¶
Hiroba is an internal platform engineering framework built on Crossplane v2 (infrastructure orchestration) and CDK8s (type-safe manifest generation for XRDs and Compositions). All reconciliation logic lives in a single Go composition function; TypeScript packages only describe APIs.
The Orchestrator (ADR 007)¶
function-platform is a single Crossplane composition function that dispatches on
the composite resource's apiVersion/kind. Every product — primitive or stack —
ships:
- an XRD (
apiextensions.crossplane.io/v2,scope: Namespaced), and - a thin Pipeline Composition with one step: invoke
function-platform.
Provider branching, profile defaults, hierarchical composition, and readiness live
in the Go handlers (functions/platform/handlers/), not in Composition files.
packages/<product>/src/xrd.ts -> XRD + thin Composition (cdk8s synth)
functions/platform/handlers/ -> one handler per kind, registered in cmd/main.go
contract/contract.json -> single source of truth (ADR 009), codegen to TS + Go
Products¶
Primitives (this repo):
- PostgresInstance:
spec.provider:cnpg(CloudNativePG, default) oraws(RDS). - ObjectBucket:
spec.provider:garage(default) oraws(S3).
Observability (consumer repo, ADR 010):
- ObservabilityStack: KRO
ResourceGraphDefinitionthat consumesPostgresInstanceandObjectBucketprimitives and emits ArgoCD Applications for Grafana, Loki, Mimir/Prometheus, and in-cluster Alloy. - ObservabilityAgent: KRO
ResourceGraphDefinitionthat deploys a remote Grafana Alloy agent in a client cluster, pushing logs/metrics to a management-plane stack over mTLS withX-Scope-OrgIDtenancy.
Stacks are GitOps-managed: ArgoCD syncs the Helm charts, and per-client value overrides live in the consumer repo. Primitives remain reconciled by the orchestrator.
Crossplane v2 Contract Notes¶
- No XR connection secrets. v2 drops
connectionSecretKeys; function-returned connection details for child XRs are not persisted. The public contract isstatus:phase,endpoint,connectionSecretRef(pointing at the provider-native secret, e.g. the CNPG operator's<name>-pg-app). - Explicit readiness. Pipeline composed resources are unready unless the
function says otherwise; handlers derive readiness from the observed resource's
Readycondition or a healthystatus.phase. - Namespaced provider configs. Composed managed resources reference
<team>-<provider>ProviderConfigs in the XR namespace (e.g.team-api-helm,team-api-aws).
Dependency Gate¶
The orchestrator fails fast when a required operator is missing. contract/contract.json
declares required CRDs per XR kind and provider (dependencies); before dispatching
to a handler, the function verifies those CRDs are installed (discovery API, 60s
cache). A missing dependency aborts the reconcile with a fatal, client-actionable
error naming the CRDs and the operator to install — installing operators stays the
platform operator's responsibility, and the error is visible via
kubectl describe <xr>. Outside a cluster (render, tests) the check is a no-op.
Provider & Profile Defaults¶
Precedence: spec.* override > function env config (PLATFORM_DEFAULT_*) >
contract default. Profile (development|staging|production) supplies defaults for
instance class, HA, backups, and deletion policy per the contract.
Repository Layout¶
hiroba/
├── contract/ # contract.json + codegen
├── functions/platform/# Go orchestrator (handlers, registry, provider config)
├── packages/ # shared lib + primitives (XRDs via cdk8s)
├── stacks/ # KRO ResourceGraphDefinitions for product stacks
├── consumer-sdk/ # Developer-facing typed constructs
├── infrastructure/ # Control-plane manifests (providers)
├── scripts/ # e2e-setup.sh, team-setup.sh, render-validate.sh
├── examples/ # Example consumer projects
└── docs/ # Documentation + ADRs
Design Principles¶
- One reconciliation brain: all logic in the orchestrator; TS describes APIs only.
- Status is the contract: deterministic names + status fields, not secrets.
- Profile-driven defaults: development/staging/production encode sensible defaults.
- Escape hatch: every Helm-backed module accepts
spec.values(chart defaults < user values < platform wiring). - Schema-first guardrails: XRD schemas enforce structure; the contract codegen keeps TS and Go in lockstep.