chore: scaffold olsitec-foundation mono-repo
Repo topology, baseline overlay, planning docs (PLAN-001/002), ADR-004/005, and the bootstrap/packages/documentation skeleton. Implementation (T00+) not started. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
f18676e6b3
22 changed files with 1174 additions and 0 deletions
|
|
@ -0,0 +1,69 @@
|
|||
# ADR-004 — Layered Platform: `olsitec-foundation` Is a K8s-Free Layer 0
|
||||
|
||||
**Date**: 2026-06-30
|
||||
**Status**: Accepted
|
||||
|
||||
## Context
|
||||
|
||||
We are building `olsitec-foundation` — the permanent, self-hosting technical foundation
|
||||
("the egg") for every future Olsitec product. Vision and detailed strategy:
|
||||
- [PLAN-001-forgejo.md](../PLAN-001-forgejo.md) (vision)
|
||||
- [PLAN-002-foundation-implementation.md](../PLAN-002-foundation-implementation.md) (strategy)
|
||||
|
||||
PLAN-001 proposed deploying Forgejo **onto the existing Kubernetes cluster** via ArgoCD + Helm.
|
||||
But Kubernetes, ArgoCD, cert-manager and External Secrets Operator are themselves part of the
|
||||
platform the foundation is meant to *hatch*. A foundation that runs on them creates an
|
||||
unrecoverable circular dependency: disaster-recovery-from-nothing would first require rebuilding
|
||||
K8s+ArgoCD+ESO, which need git + an OCI registry + a secret store — which *are* the foundation.
|
||||
|
||||
## Decision
|
||||
|
||||
**Layer the platform.**
|
||||
|
||||
- **Layer 0 — `olsitec-foundation` (the egg):** Forgejo (+ Actions + OCI/npm registry),
|
||||
PostgreSQL, HashiCorp Vault, RustFS (S3), and a reverse proxy (Caddy) run as **plain OCI
|
||||
containers on a single VM**, orchestrated by a **single Pulumi project** using the
|
||||
`@pulumi/docker` provider over SSH. **No Kubernetes, no ArgoCD, no Helm at Layer 0.**
|
||||
- **Layer 1+ — everything else** (the existing olsicloud4 K8s platform, ArgoCD, Authentik,
|
||||
Grafana/Prometheus, Longhorn, Renovate, internal PKI): a **consumer** of Layer 0. Its source
|
||||
repos live in foundation-Forgejo, its CI runs in foundation-Actions, its images/charts in
|
||||
foundation's registry, its secrets in foundation's Vault.
|
||||
|
||||
Ratified sub-decisions:
|
||||
1. **Vault unseal:** Shamir + passphrase-gated unseal helper (no external KMS, no SaaS).
|
||||
2. **Object storage:** RustFS is the primary Layer-0 S3; the offsite backup replica is **non-RustFS**
|
||||
so RustFS is never the only copy.
|
||||
3. **Offsite backup:** a second **self-hosted** location (different failure domain, no SaaS).
|
||||
|
||||
The single external secret is the master passphrase (`PULUMI_CONFIG_PASSPHRASE`, passphrase
|
||||
secrets provider). Everything else is derived or generated by `@pulumi/random` into Vault
|
||||
(consistent with [ADR-002](ADR_002_pulumi_credential_lifecycle.md)).
|
||||
|
||||
## Consequences
|
||||
|
||||
**Easier**:
|
||||
- DR-from-nothing is genuinely `{VM + repo + passphrase}` — no prerequisite platform to rebuild.
|
||||
- Reuses existing Olsitec tooling: `pulumi/modules/docker` (Docker-over-SSH) and the
|
||||
`olsitec-core/run.sh` Vault-init→capture-keys→passphrase-encrypted-config pattern.
|
||||
- Minimal moving parts at the root; the egg stays boring and inspectable.
|
||||
|
||||
**Harder**:
|
||||
- Layer 0 is a single VM (SPOF) — mitigated by tested offsite DR (≤1h target), not HA.
|
||||
- ADR-002's `Pulumi → Vault → ESO → K8s Secret` chain applies only at Layer 1; Layer 0 consumers
|
||||
are containers that read from Vault/rendered config directly.
|
||||
- Vault reboots require the passphrase for the unseal helper (auto-unseal deferred to Layer 1).
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- **Forgejo on the existing K8s cluster (PLAN-001 literal):** rejected — circular DR dependency;
|
||||
the egg cannot run on the chicken.
|
||||
- **Hybrid (bare Docker now, K8s-HA-ready later):** folded in — PLAN-001's K8s HA topology is
|
||||
retained as the documented *future* HA path for Forgejo (PLAN-002 §8), not the bootstrap substrate.
|
||||
- **MinIO/Garage instead of RustFS at Layer 0:** rejected for now — RustFS matches the existing
|
||||
credential flag; the S3 boundary keeps it replaceable if RustFS underperforms.
|
||||
|
||||
## Confidence
|
||||
|
||||
**High** — verified against existing source (`pulumi/modules/docker`, `pulumi/olsitec-core/run.sh`,
|
||||
`002_platform_architecture.md`) and ratified by the product owner on 2026-06-30. The one Medium-
|
||||
confidence area is RustFS production-readiness as primary S3 (flagged for later second-opinion).
|
||||
60
documentation/decisions/ADR_005_repo_topology.md
Normal file
60
documentation/decisions/ADR_005_repo_topology.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# ADR-005 — `olsitec-foundation` Repository Topology & Module Distribution
|
||||
|
||||
**Date**: 2026-06-30
|
||||
**Status**: Accepted
|
||||
|
||||
## Context
|
||||
|
||||
`~/work/olsitec-foundation` is the home for the foundation platform. We must decide repo boundaries:
|
||||
what is one mono-repo vs. separate repos, where shared Pulumi modules live, and how they are consumed
|
||||
both at day-zero (no registry yet) and in steady state (by downstream projects). Constraints:
|
||||
- The egg must be recoverable from `{VM + repo + passphrase}` (PLAN-002 §6) → favours **few repos**.
|
||||
- Shared modules must be **independently consumable** by other projects, hosted via the foundation →
|
||||
favours **independent versioning/publishing**.
|
||||
- The module registry is itself part of what the foundation builds → **day-zero registry paradox**.
|
||||
|
||||
## Decision
|
||||
|
||||
**Two git repositories under a non-git workspace root.**
|
||||
|
||||
1. **`foundation/` — a mono-repo** (Bun workspaces) containing `bootstrap/` (the egg Pulumi project),
|
||||
`packages/pulumi-*` (shared modules), and `documentation/`. This is the DR unit.
|
||||
2. **`ai-baseline/` — a single small repo** for the cross-project agentic workflow pattern
|
||||
(ADR-003), re-homed from gitlab.com to foundation-Forgejo.
|
||||
|
||||
Downstream consumer projects (the K8s platform, products) stay **outside** this workspace and consume
|
||||
the foundation's **published** packages.
|
||||
|
||||
**Module lifecycle:** Vendor (copy into `packages/`, consumed locally via Bun workspace) → Publish
|
||||
(`@olsitec/pulumi-*` to the foundation npm registry once it exists) → Consume (downstream switches
|
||||
imports to the published versions; old `olsicloud4/pulumi/modules/*` frozen then removed).
|
||||
|
||||
## Consequences
|
||||
|
||||
**Easier**:
|
||||
- Day-zero needs no registry: `bootstrap/` resolves modules from `packages/*` on disk (resolves the
|
||||
registry paradox, PLAN-002 §5.2).
|
||||
- DR = one clone of `foundation` → egg + exact module sources together.
|
||||
- Shared modules still get independent semver + publishing (semantic-release-monorepo, Conventional
|
||||
Commits — see memory `olsitec-charts-conventional-commits`), so downstream pins versions.
|
||||
- `ai-baseline` stays light and on its own cadence for all projects.
|
||||
|
||||
**Harder**:
|
||||
- A mono-repo needs workspace tooling (Bun workspaces) and per-package release config.
|
||||
- Two consumption paths for a module during transition (local workspace for the egg, published
|
||||
registry for downstream) — must be documented per package.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- **One giant mono-repo** (foundation + ai-baseline + everything): rejected — couples the
|
||||
every-project baseline to the platform's weight and release cadence.
|
||||
- **Polyrepo** (each module its own repo): rejected — day-zero would need to clone N repos before the
|
||||
registry exists; DR friction; over-fragmentation at this scale.
|
||||
- **Keep modules in olsicloud4, reference from there**: rejected — the foundation must own its inputs
|
||||
for DR-from-nothing; it cannot depend on a Layer-1 repo.
|
||||
|
||||
## Confidence
|
||||
|
||||
**High** — directly addresses the registry bootstrap paradox and the user's stated intent (vendor a
|
||||
copy now, host via the foundation later, downstream switches to the foundation-hosted module).
|
||||
Companion: [000_TOPOLOGY.md](../000_TOPOLOGY.md).
|
||||
Loading…
Add table
Add a link
Reference in a new issue