Files
home-network-k3s/docs/00-vision-and-scope.md
T
jakman85andClaude Opus 4.8 a2cbdf656d Resolve OQ-1/2/3, refine OQ-4: single ExpressVPN gateway, single WAN, external media
Operator answers folded into the specs:
- OQ-3 VPN: ExpressVPN, cluster-controlled SINGLE shared in-cluster tunnel
  (OpenVPN UDP / non-TCP), rules enforced outside the service. New ADR-0012
  supersedes ADR-0008 (Gluetun-sidecar default dropped). Central kill-switch.
- OQ-1 WAN/edge: one commercial WAN, no multi-ISP plans; dumb SOHO edge (no
  VLAN/VPN/services). Multi-WAN out of scope; segmentation + VPN in-cluster;
  edge = NAT + manual port-forward. Gateway VIP resolved to Cilium L2
  announcement. T-3.3 marked won't-do.
- OQ-2 storage: bulk media lives outside the cluster (backing TBD, non-blocking)
  via a 'bulk' external-mount indirection; Plex metadata DB stays on Longhorn.
  Split out a separate OQ-BKP for the off-cluster DR backup target (Phase 4).
- OQ-4 refined: wildcard record covers reachability but NOT ACME DNS-01 (needs
  TXT-write access) and does not match *.home.* depth. Still OPEN: Cloudflare
  API token (Option A) vs acme-dns delegation (Option B). T-2.4/T-2.5 blocked.

Updated: docs 00,01,03,04,08,09; ADR-0008/0012 + index; task board.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-15 23:00:11 -05:00

205 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 00 — Vision & Scope
## Vision
Build a home platform that behaves like a small private cloud. An operator declares a service — a
container app *or* a virtual machine — in git, and the platform provisions it, secures it, exposes
it under a trusted TLS URL, routes its traffic on the correct WAN, protects its data, updates it
automatically, and reports on its health. Onboarding a new service is a pull request against a
catalog, not a weekend of manual work.
The platform is delivered in two stages:
- **dev/test** on local KVMs — the active build target, used to prove viability.
- **prod** on 3 mini-PCs — the eventual home, designed for now but not built on yet.
## Personas
- **Operator (primary user)**: runs the home network; wants to onboard/offboard services with
minimal ceremony and zero data loss.
- **Platform (the system)**: reconciles declared state, enforces isolation and egress policy,
renews certificates, updates workloads, and raises alerts.
- **Implementation agents**: the AI teams building the platform from this spec.
## In scope
- A k3s-based platform with distributed storage (Longhorn) across 3 nodes.
- Container workloads (PaaS) and VM workloads (IaaS) through one Kubernetes surface.
- GitOps delivery, automated updates, trusted TLS, DNS, ingress.
- Network isolation (default-deny east-west) and multi-WAN egress including VPN routing.
- Observability with email + dashboard alerting.
- A command-and-control web UI at the root of `home.keithjackson.dev`.
- The initial service catalog (13 services, see [`13-service-catalog.md`](13-service-catalog.md)).
## Out of scope (for now)
- Building on production mini-PC hardware (design-only until the roadmap flips it to active).
- Multi-tenant / multi-operator RBAC beyond a single operator + platform automation.
- Public multi-user SaaS concerns (billing, per-tenant isolation beyond network policy).
- Non-`keithjackson.dev` domains.
## The domain & DNS model
- Public apex `*.keithjackson.dev` is available and its records resolve to the network's public IP.
- All platform services live under `*.home.keithjackson.dev`.
- Each service is reachable at `<service>.home.keithjackson.dev` (e.g. `plex.home.keithjackson.dev`).
- The **root** `home.keithjackson.dev` serves the **Command & Control (C2) center** UI.
## Requirements (stable IDs)
Requirement IDs are stable references used across ADRs, specs, the task board, and PRs. `MUST` is
mandatory; `SHOULD` is strongly preferred and requires an ADR to deviate.
### Platform & API surface — `R-PLAT-*`
- **R-PLAT-01** — The platform MUST run on k3s across 3 nodes with production-grade HA control plane
in prod; dev/test MAY run fewer nodes but MUST exercise the same multi-node topology.
- **R-PLAT-02** — Container workloads MUST be onboarded and managed declaratively via the Kubernetes
API, `kubectl`-class CLI, and YAML.
- **R-PLAT-03** — Virtual-machine workloads MUST be created, managed, and destroyed through the
*same* Kubernetes API/CLI/YAML surface as containers (no separate hypervisor management plane for
application VMs).
- **R-PLAT-04** — The platform MUST support create / destroy / rebuild of any workload on demand.
### GitOps & delivery — `R-GITOPS-*`
- **R-GITOPS-01** — All application and platform desired state MUST be defined in git and reconciled
automatically (pull-based GitOps).
- **R-GITOPS-02** — Onboarding a new service MUST be expressible as a change to a versioned catalog
in git.
- **R-GITOPS-03** — The system MUST detect and correct drift between git and cluster state.
### Networking, isolation & egress — `R-NET-*`
- **R-NET-01** — East-west traffic between services MUST be **denied by default**; communication is
allowed only by explicit, port-level configuration (firewall-like).
- **R-NET-02** — Allow rules MUST be declarative, reviewable in git, and scoped per source →
destination → port/protocol.
- **R-NET-03** — Networks MUST be configurable and isolatable (segments/namespaces with enforced
boundaries).
- **R-NET-04** — The platform MUST support **multiple egress paths** selected by routing rules. Per
OQ-1 the environment has **one physical commercial WAN and no multi-ISP plans**, so this is
realized as two paths — the local `internet` path and the in-cluster `vpn` path — not multi-ISP
routing. Physical multi-WAN (multiple ISP uplinks) is **out of scope** unless a future ADR reopens
it.
- **R-NET-05** — A service MUST be able to declare its **egress class**: `internet` (standard local
network/internet) or `vpn` (routed through a custom VPN connection). VPN routing MUST be enforced
**outside the service** (a single shared in-cluster gateway), so a service cannot leak by
misconfiguration (ADR-0012, OQ-3).
- **R-NET-06** — VPN-class egress MUST enforce a **kill-switch**: if the VPN tunnel is down, the
service MUST NOT leak traffic to the standard internet.
- **R-NET-07** — Egress class MUST be a declarative property of the service, changeable via GitOps
without re-architecting the workload.
### Storage & state — `R-STATE-*`
- **R-STATE-01** — Stateful data MUST survive destroy/rebuild of the workload (PaaS and IaaS).
- **R-STATE-02** — Persistent storage MUST be distributed/replicated across the 3 nodes (Longhorn)
so a single node loss does not lose data.
- **R-STATE-03** — The platform MUST provide scheduled backups to an **off-cluster** target and a
tested restore path (disaster recovery).
- **R-STATE-04** — Bulk media storage (Plex library) MUST have a capacity strategy distinct from
replicated app-config storage (replicating multi-TB media 3× is out of scope; see ADR-0003).
### Automated updates — `R-UPD-*`
- **R-UPD-01** — Services MUST update to the latest **stable** versions on a schedule.
- **R-UPD-02** — Updates MUST require **no human, no AI, and no hand-authored GitOps change** to
occur. Automation controllers acting on declarative policy are the permitted mechanism.
- **R-UPD-03** — Update policy MUST be per-service configurable (cadence, stability channel,
pin/hold, auto-rollback on failed health).
### TLS & certificates — `R-TLS-*`
- **R-TLS-01** — Every externally reachable service MUST present TLS from a **credible, trusted,
non-self-signed** authority.
- **R-TLS-02** — Certificates MUST be automatically **issued, renewed, and revoked** without manual
steps.
- **R-TLS-03** — Certificate issuance MUST work for internal-only services (no requirement to expose
a service publicly just to validate a certificate).
### DNS & ingress — `R-DNS-*`
- **R-DNS-01** — Services MUST be reachable at `<service>.home.keithjackson.dev`.
- **R-DNS-02** — DNS records MUST be managed automatically from declared service intent.
- **R-DNS-03** — Internal clients MUST resolve service names correctly (split-horizon where public
and internal answers differ).
### Observability & alerting — `R-OBS-*`
- **R-OBS-01** — Services MUST be monitored (metrics, logs, health).
- **R-OBS-02** — Issues MUST be reported by **email**.
- **R-OBS-03** — Issues and health MUST be visible on **dashboards**.
- **R-OBS-04** — The platform MUST alert on its own health (nodes, storage, GitOps reconciliation,
certificate expiry, VPN tunnel state, backup success).
### Command & control — `R-C2-*`
- **R-C2-01** — The root `home.keithjackson.dev` MUST serve a UI that surfaces the services running
in the cluster and links to them.
- **R-C2-02** — The C2 UI MUST surface platform health (cluster, storage, GitOps, alerts) and
provide controlled operational actions where safe.
### Security & secrets — `R-SEC-*`
- **R-SEC-01** — Secrets MUST NOT be stored in plaintext in git; they MUST be encrypted at rest in
the repo and decrypted only in-cluster.
- **R-SEC-02** — The platform MUST follow least-privilege for workload identities and network reach.
- **R-SEC-03** — All the above properties MUST be demonstrable/auditable (an operator can prove
isolation, egress path, cert validity, and backup integrity).
### Environments — `R-ENV-*`
- **R-ENV-01** — dev/test MUST be provisioned as local KVMs via IaC: created, baselined, cluster-
joined, and managed as code.
- **R-ENV-02** — The same GitOps configuration MUST promote from dev/test to prod with only
environment-scoped overrides.
- **R-ENV-03** — prod is a 3× mini-PC bare-metal k3s cluster with local storage; it MUST NOT be an
active development surface until the roadmap declares it ready.
### Conformance testing & governance — `R-TEST-*`
- **R-TEST-01** — Every requirement MUST be verified by **automated, behavior-based tests**
(Given/When/Then style) that assert observable system behavior, not implementation internals.
- **R-TEST-02** — Tests MUST be **reproducible**: deterministic, hermetic (create and tear down
their own fixtures), version-pinned, and runnable by a single command locally and in CI against
any conforming cluster, producing machine-readable, requirement-tagged results.
- **R-TEST-03** — A **conformance suite** MUST gate delivery: merges are blocked unless the tests
for the touched requirements pass, and phase exits are blocked unless the phase's full suite
passes. "Demonstrated" means "the automated test passes," never a manual one-off.
- **R-TEST-04** — Tests MUST be **traceable**: each test declares the requirement ID(s) it verifies,
and a coverage report maps every `R-*` requirement to its verifying test(s). Uncovered
requirements are a gap to close, not an acceptable state.
- **R-TEST-05** — Safety-critical behaviors (default-deny, VPN kill-switch, data-survival on
rebuild, DR restore, auto-rollback) MUST be verified by **fault-injection** behavior tests that
prove fail-closed / no-data-loss outcomes, not merely happy-path checks.
- **R-TEST-06 (governance)** — **AI agents MUST NOT modify the specifications** (this `docs/` tree,
the requirements, or accepted ADRs). Specs are changed only by the human operator/architect.
Agents that find a spec wrong, blocking, ambiguous, or missing MUST **stop and escalate** and MAY
draft a proposal, but MUST NOT self-approve or merge a spec/ADR change (see
[`AGENTS.md`](../AGENTS.md) §2 and §11).
## Acceptance philosophy
Each requirement class maps to an **automated, reproducible, behavior-based conformance test** in
dev/test (`R-TEST-*`). "Done" means *the conformance test for the touched requirements passes* — a
green, reproducible result traced to requirement IDs — never "manifest merged" and never a manual
demonstration. The testing approach is specified in
[`docs/14-testing-and-conformance.md`](14-testing-and-conformance.md) and
[ADR-0010](../decisions/adr-0010-conformance-testing.md); the gate checklist lives in
[`agents/definition-of-done.md`](../agents/definition-of-done.md).
**Governance:** the specifications are human-owned and **immutable to agents** (R-TEST-06). Agents
implement against the spec and prove conformance with tests; they never edit the spec to fit the
implementation.
## Open questions
### Resolved (2026-08-15)
- **OQ-1 (WAN / edge)** — **RESOLVED**: one commercial WAN, no multi-ISP plans; dumb SOHO edge (no
VLAN/VPN/services). All segmentation + VPN in-cluster; edge does NAT + port-forward only. Physical
multi-WAN out of scope. See [`03`](03-networking-isolation-and-egress.md), [`09`](09-dns-and-ingress.md).
- **OQ-2 (bulk media)** — **RESOLVED (deferred backing)**: Plex bulk media lives **outside the
cluster**; the specific backing is **TBD later** and does not block the core platform. Plex's
metadata DB still lives on replicated Longhorn. The **off-cluster DR backup target** (for app
config, Nextcloud, Gitea, etc.) remains to be chosen at Phase 4. See [`04`](04-storage-and-state.md).
- **OQ-3 (VPN)** — **RESOLVED**: **ExpressVPN**, cluster-provisioned, **single shared in-cluster
tunnel**, **non-TCP** (OpenVPN UDP / Lightway-UDP), rules enforced outside the service
(ADR-0012). See [`03`](03-networking-isolation-and-egress.md).
### Still open
- **OQ-4 (TLS/DNS challenge access)**: Cloudflare already has a wildcard `*.keithjackson.dev` → public
IP (covers reachability), but **ACME DNS-01 needs write access** to create `_acme-challenge` TXT
records, and `*.keithjackson.dev` does **not** match the two-label-deep `*.home.keithjackson.dev`.
Decide the challenge mechanism: **(a)** a scoped Cloudflare **API token** (Zone·DNS·Edit) → fully
automated DNS-01 + ExternalDNS, or **(b)** **acme-dns delegation** (one-time `_acme-challenge`
CNAME edit, then no standing Cloudflare credential). See [`08`](08-tls-and-certificates.md).