Component Concept
A Runtime Component is the deployable unit of the Arda system — the artifact that gets built, versioned, and shipped into a Partition. A Component packages one or more Modules and provisions or binds the resources those Modules declare. The Component sits on an axis that is orthogonal to the functional hierarchy: a Component is never part of a functional URL or any name a Module exposes. Moving a Module between Components is a re-packaging operation; it does not change any Module’s name, contract, or URL.
For the orthogonal axis itself — the System / Domain / Module / Service / Endpoint hierarchy — see Functional Decomposition. For the Module-side view of the declare/provide pattern described here, see Module Concept.
What a Component is
Section titled “What a Component is”A Component is, concretely:
- A Docker image built from a single Kotlin/JVM (or other-stack) source tree, tagged with the Component’s own version.
- A Helm chart describing the K8s resources the Component needs to run in a Partition: Deployment, Service, Ingress, ExternalSecrets, ServiceAccount, RBAC.
- A CloudFormation stack provisioning the cloud-side resources the Component depends on: an IAM role for the pod, an API Gateway integration, an ExternalSecrets
SecretStore, the per-Component RDS server, and the per-Module schemas, secrets, and route resources the Component packages. - One
Main.kt(the Kotlin entry point) that wires up the Modules the Component packages, passing each Module the Component-level configuration it needs to resolve its declared resources.
The current Arda system packages its functional Modules into two backend Components:
operations— a multi-Module monolith hosting the Procurement, Reference Data, Resources, and Shop Access Domains (Order, Item, Business Affiliate, Kanban, PDF Render, Email, plus the embedded Facility / Station / Batch supporting Modules).accounts-component— the identity-and-access component hosting Tenant, User Account, AgentFor, and Invitation under the System Domain.
A third Component, arda-frontend-app, is a Next.js application deployed via AWS Amplify; it consumes the backend Components’ APIs through a BFF layer.
Component identity and configuration footprint
Section titled “Component identity and configuration footprint”A Component carries configuration of its own, separate from what its Modules declare. The configuration covers the Component’s identity and the shared infrastructure the Component provisions for its Modules.
Identity lives in the component { ... } top-level block of application.conf:
| Field | Purpose |
|---|---|
name | The Component’s canonical name (operations, accounts, …). |
version | The Component’s artifact version. |
title | Human-readable label used in OpenAPI titles and operational tooling. |
description | Free-text description. |
baseUrl | The gateway URL where the Component is mounted; set at deployment time. Carries scheme + host + optional port; the System root for every URL the Component’s modules expose. |
Component-level infrastructure — the Ktor server (ktor), the database connection pool (dataSource.pool), AWS SDK settings (aws), and authentication infrastructure (auth — JWT issuers, client IDs, bearer API key) — currently live at the file root, not under component { ... }. A future revision will move them under the component block as component.ktor, component.infrastructure.*, and component.authentication. That restructure is deferred because it touches every Module’s deployment shape and can land independently of the canonical adoption.
The full per-block reference, including the path-derived module-identity mechanism, lives in application.conf Structure. That pattern doc is the engineering reference; this page covers the role the Component plays.
Equivalent surface presence:
- Helm Values —
values.yamlcarries the Component’s deploy-time concerns at the file root (image identity, ServiceAccount, IRSA role ARN, compute config including HPA, networking, feature flags) plus two flat maps (apis:anddatabases:) iterated by the chart templates. Per-Component, not per-Module. - CloudFormation — one stack per Component. Stack-level resources (provisioned by the Component, used by every Module it packages) include the IAM role for the pod, the API Gateway integration, the ExternalSecrets
SecretStore, and the per-Component RDS server. Per-Module resources (DB schemas, ExternalSecret entries, API Gateway routes, per-Module IAM policy statements) inherit the Component-level inputs.
The declare / provide / bind pattern
Section titled “The declare / provide / bind pattern”The Component’s central architectural role is to make the Modules it packages runnable. The mechanism is an inversion-of-control pattern split across the two axes:
- A Module declares the resources it requires using logical names —
dataSource.name = "email_db",secrets.postmark-account-token,servers.postmark.baseUrl. The Module’s code never sees a concrete URI, ARN, or mount path; it consumes logical references that the runtime resolves at start-up. - A Component provides the concrete provisioning context — the database server URI plus the connection pool, the ExternalSecrets store that turns each
ExternalSecret:*reference into a K8s Secret mounted at the right path, the HTTP-client defaults (TLS config, retry policy) that turn aservers.postmarkdeclaration into a configured client. - Bindings happen at two times:
- Deploy time — the Helm template iterates the
apis:anddatabases:maps invalues.yaml, combines them with the Component’s file-root infrastructure blocks, and produces K8s resources: ExternalSecret manifests with the rightremoteRefand mount paths; ConfigMaps with per-Module HOCON overlays; Ingress paths from each Module’s compoundapis.<key>.name; Deployment env vars carrying the JDBC URL composed from the DB-server URI plus the Module’s declared schema name. - Init time — the Component’s
Main.ktcalls each Module’sApplication.{module}(...)entry function, passing the resolvedModuleConfig(derived from the canonical lookup pathmodules.<version>.<domain>.<module>) plus references to the shared infrastructure (DB connection, secret-store, JWT validator). The Module’s Kotlin code then wires its Services using these bindings.
- Deploy time — the Helm template iterates the
The split keeps Module code testable (Modules depend on logical names only — no AWS-account IDs, no Partition URIs) and keeps Components portable (a Component can swap underlying infrastructure — different DB engine, different secret store, different observability backend — without touching any Module’s code).
Orthogonality — Components never appear in functional names
Section titled “Orthogonality — Components never appear in functional names”The orthogonality rule has concrete implications across every surface:
- URLs: Functional URLs are
/v{module-version}/{domain}/{module}/{service}/{endpoint}/{routes+}. No segment carries the Component name. A client calling/v1/shop-access/email/jobcannot tell from the URL whether the email Module is packaged inoperations,accounts-component, or a hypothetical future Component dedicated to email. - OpenAPI titles and Swagger UI: the per-Endpoint OpenAPI document’s
info.titleand the catalog’s section heading name the Module / Service / Endpoint, not the Component. - In-pod logging and Sentry tags: the Component name appears in operational metadata (Sentry environment tag, log lines emitted by the Component itself) but not in any field a Module exposes through its contract.
- Component-level operational concerns (such as the OAM cross-cutting route
/operations/oam/{proxy+}or/accounts/oam/{proxy+}) do carry the Component name as a URL prefix because they are Component-level, not Module-level — they describe the running Component itself, not its packaged functional content. These routes are deliberately kept outside the canonical functional URL formula.
When a Module is moved from one Component to another (e.g. the email Module spinning out from operations into its own dedicated Component), the migration changes the deployment topology — the K8s Deployment, the Helm chart, the CFN stack, the Docker image — but every URL, OpenAPI title, and Endpoint identifier the Module exposes stays exactly the same.
Relationship to the Runtime Viewpoint
Section titled “Relationship to the Runtime Viewpoint”In the Runtime Viewpoint hierarchy Platform → Infrastructure → Partition → Component → Resource, the Component is the smallest independently-deployed unit. A Component is deployed into one or more Partitions (typically all four Application Runtime partitions: Alpha002-dev, Alpha002-stage, Alpha001-demo, Alpha001-prod); within each Partition, the Component’s K8s Deployment runs against the Partition’s compute and network resources, talking to the Partition’s RDS server and Secrets Manager.
See Platform Structure for the per-Partition layout and naming conventions.
Related Pages
Section titled “Related Pages”- Functional Decomposition — The functional hierarchy that Components are orthogonal to; the canonical URL formula and per-surface naming rules.
- Module Concept — The Module-side view of the declare/provide pattern, cohesion and encapsulation, and inter-Module interaction mechanisms.
- Platform Structure — The Runtime Viewpoint hierarchy and the per-Partition layout in which Components run.
- Repository Catalog — The source repositories that build into Components.
Copyright: © Arda Systems 2025-2026, All rights reserved