ADR-001: Adopt Eight-Pillar Monorepo Structure
Status
Accepted — pillar table amended (see Amendments below).
Date
2024-01-15
Context
We need an enterprise-grade learning lab that demonstrates real-world platform engineering practices across multiple domains: application development, infrastructure provisioning, CI/CD automation, observability, and governance. The repository must support multiple technology stacks (.NET, Spring Cloud, Python, Terraform) while maintaining clear domain boundaries, team ownership, and discoverability.
Key requirements:
- Multiple teams must be able to work independently on different domains.
- Changes to infrastructure should not require navigating through application code and vice versa.
- The structure must be intuitive for onboarding new engineers.
- CI/CD must support per-domain triggers to avoid unnecessary builds.
- Governance and standards must be co-located with the code they govern.
Decision
We adopt an eight-pillar monorepo structure where each pillar represents a distinct operational domain. Pillars are alphabetically prefixed with a single letter to enforce a consistent ordering:
| Pillar | Domain |
|---|---|
a-governance/ | Governance machinery (schemas, scripts, generated outputs, change records, policy exceptions) |
d-apps/ | Application code |
c-platform/ | Infrastructure as Code |
e-gitops/ | CI/CD and orchestration |
f-observability/ | Monitoring and alerting |
i-tooling/ | Developer utilities |
k-docs/ | Documentation, ADRs, and engineering standards (rendered via MkDocs) |
l-labs/ | R&D sandbox |
h-aiops/ | AIOps & intelligent operations |
Within each pillar, sub-directories use a two-digit numeric prefix (e.g., 01-python-samples/,
02-dotnet-FakeStoreIngestor/) for ordering and disambiguation.
Team ownership is enforced through GitHub CODEOWNERS, with each pillar or sub-path assigned to a specific team.
Consequences
Positive
- Clear domain boundaries. Each pillar has a well-defined scope, reducing the cognitive load of navigating the repository.
- Independent team ownership. CODEOWNERS and path-based CI triggers allow teams to work autonomously within their pillar.
- Discoverability. Alphabetical prefixes create a natural reading order. New contributors can quickly understand the repository layout.
- Monorepo benefits. Atomic cross-pillar changes are possible when needed (e.g., an application change paired with its Terraform module and CI workflow).
- Path-based CI. GitHub Actions path filters ensure that changes to one pillar do not trigger unrelated workflows, keeping CI fast.
Negative
- Risk of pillar sprawl. Without governance, teams may propose new pillars for every concern. Mitigation: new pillars require an ADR and platform-leads approval.
- Governance overhead. Maintaining CODEOWNERS, naming conventions, and standards across eight
pillars requires ongoing effort. Mitigation: the
a-governance/pillar centralizes governance. - Repository size. Over time, the monorepo may grow large. Mitigation: use
.gitattributesand sparse checkout for teams that only need specific pillars. - Cross-pillar dependencies. Changes that span multiple pillars require coordination between teams. Mitigation: prefer separate PRs per pillar; use cross-pillar PRs only when atomicity is required.
Alternatives Considered
Multi-Repository Architecture
Each pillar would be its own GitHub repository (e.g., archlab-services, archlab-platform,
archlab-observability).
Rejected because:
- Cross-repo coordination overhead is significant for a learning lab where patterns must be demonstrated end-to-end.
- Atomic changes across repos require complex tooling (e.g., multi-repo PRs).
- Onboarding is harder when code is scattered across multiple repositories.
- Shared CI/CD patterns are difficult to maintain consistently.
Flat Monorepo (No Pillar Structure)
All code in a single repository without domain-based top-level directories.
Rejected because:
- No domain boundaries leads to a sprawling, unorganized structure.
- CODEOWNERS assignments become difficult without clear path patterns.
- CI path filters are harder to define.
- New contributors have no mental model for navigating the repository.
Domain-Driven Directories Without Alphabetical Prefixes
Use descriptive names without letter prefixes (e.g., _meta/, services/, platform/).
Rejected because:
- File explorers and directory listings would display pillars in unpredictable order.
- The alphabetical prefix provides a stable, predictable ordering that aligns with operational dependency (governance before services, services before platform, etc.).
Amendments
- 2026-03-26 — ADR-005 added the
h-aiops/pillar as a ninth pillar dedicated to AIOps and intelligent operations. See ADR-005. - 2026-04-29 — ADRs and engineering standards relocated. ADR markdown files and the
standards/collection moved froma-governance/intok-docs/docs/so they render through the MkDocs site alongside the rest of the documentation. Thea-governance/pillar is now scoped to governance machinery — JSON Schemas, the component registry script, generated outputs (CODEOWNERS, Backstage catalog, components index), change records, and policy exceptions. The original spirit of the decision (centralized governance, single source of truth, CODEOWNERS routing) is unchanged; only the content map was redrawn.
Local graph
Linked from 3 notes
ADR-005: Adopt AIOps Pillar for Intelligent Operations
Accepted 2026-03-26 The Architect Learning Lab has mature observability (f-observability), tooling (i-tooling/srekit),
The Pillar Model
The monorepo is organized into nine alphabetically-prefixed pillars, each representing a distinct
01 — Platform Architecture
How the platform is built — views, planes, signals, and the decision record indexes.
Related notes
Signal Forge ADR-005: Separate collector configmaps per deployment mode
Keeps cloud and local Alloy collector configs in separate files rather than one conditional configmap, so each mode's exporters stay explicit and uncoupled.
Signal Forge ADR-003: Span metrics generated before tail sampling
Places the spanmetrics connector ahead of tail_sampling so RED metrics reflect all traffic instead of only the ~25% of traces that survive sampling.
Signal Forge ADR-002: SpanLink for async RabbitMQ propagation (not parent-child)
Uses a SpanLink, not a parent-child span relationship, to connect RabbitMQ consumer spans back to the producer span across async, retry-prone delivery.
Architecture Overview
Signal Forge's topology, service communication, trace propagation, and per-signal pipeline flow across local and Grafana Cloud deployment modes.