platform/CLAUDE.md
Bart Van Geyt fe4cbbe36a Phase 4: provisioning CLI (heleosctl)
Python control-panel package driving the full provisioning flow from a
site's site.yaml (docs/05):

- provision: ZFS web dataset + ownership, per-site DB + least-priv user,
  generated .env encrypted to secrets.enc.yaml (SOPS/age), render the
  profile templates + persist site.yaml, per-customer chrooted SFTP
  account, docker compose up.
- deprovision (gated: data destroyed only with --purge, after a final
  backup), backup (ZFS snapshot + mariadb-dump), restore (rollback +
  import), render (preview), list.

Design: one command/file runner with a real --dry-run (prints every
action, redacts secrets); idempotent steps; Config + Site validation
mirroring docs/03; passwords never logged.

Modules: cli, config, naming, context, render, runner, zfs, database,
secrets, sftp, compose, provision, backup. Plus pyproject (heleosctl
entry point), config.example.yaml, an example site, and a README.

Tests: 22 pure-logic unit tests (naming, config validation, template
render across all profiles + db on/off) — all passing. Full provision and
deprovision verified end-to-end in --dry-run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:18:36 +02:00

4 KiB
Raw Blame History

CLAUDE.md — heleosv2 platform

Multi-tenant web hosting platform: container-per-site + ZFS-dataset-per-site, CLI-driven provisioning, decoupled per-site backup/restore. Single bare-metal host, Docker Compose per site, no orchestrator.

Read docs/ first — it is the source of truth. Start with docs/00-roadmap.md. This file is just the orientation map so a fresh session gets up to speed cheaply.

Core philosophy

  1. The customer is the boundary — isolation, backup, restore align on it.
  2. Two levels: a customer owns many sites. Isolation/containers/DB/network are per site; grouping (one SFTP login, recursive backup, billing) is per customer. See docs/03-naming-conventions.md.
  3. Containers isolate, they don't secure by themselves — non-root FPM, read-only rootfs, per-site networks, egress filtering, least-priv DB users.
  4. Each backup stream matches its change pattern — web files via ZFS snapshot/send; DB via automysqlbackup + rsync; logs via Loki. Never fold the DB dump into the web dataset (it bloats every incremental).
  5. CLI/templates before UI. Prove the platform, then wrap it in a panel.

Status

  • Phase 0 — design docs, ADRs, scaffold (docs/)
  • Phase 1 — host baseline Ansible (platform-infra/ansible/)
  • Phase 2 — platform services (Traefik, MariaDB, Forgejo) in platform-infra/stacks/
  • Phase 3 — site templates & base images in site-templates/
  • Phase 4 — provisioning CLI heleosctl in control-panel/ (provision/deprovision/list/render/backup/restore; --dry-run; 22 tests)
  • 🚧 Phase 5 — backup/DR automation (ZFS snapshot/send + automysqlbackup jobs, offsite, restore drill)
  • Phases 68 — observability, migration, panel

Phase 4 follow-ups (not yet done)

  • reconfigure + rotate-secret commands; git-commit of deployments/ on provision; php-fpm umask for two-way SFTP editing (see control-panel/README.md).

Repo map

Path Purpose
docs/ Architecture, ADRs, runbooks, conventions (authoritative).
platform-infra/ansible/ Phase 1 host baseline (ZFS, Docker, firewall, SSH).
platform-infra/stacks/ Phase 2 base compose projects (Traefik/MariaDB/Forgejo).
site-templates/ Dockerfiles + per-profile compose templates (Phase 3).
deployments/ Rendered per-site configs <customer>/<site>/ (GitOps state).
control-panel/ Provisioning CLI (Phase 4), panel later.

Naming quick-ref (see docs/03)

  • customer + site ids; slug = <customer>-<site> (Docker/DB key).
  • ZFS: tank/customers/<customer>/<site>/web; platform on tank/platform/*.
  • DB: db_<customer>_<site> + user u_<customer>_<site> on shared MariaDB.
  • Networks: shared proxy (edge) + platform (DB); per-site <slug>_net.

Common commands

# Phase 1 — host baseline (from platform-infra/ansible, against the VM)
ansible-galaxy collection install -r requirements.yml
ansible-playbook site.yml            # tags: base|zfs|docker|firewall|ssh

# Phase 2 — platform services (on the host, once Phase 1 is applied)
platform-infra/stacks/bootstrap-networks.sh
cd platform-infra/stacks/<svc> && cp .env.example .env && docker compose up -d

Working agreements

  • Docs are source of truth. When a design decision changes, update the relevant docs/ file and add/adjust an ADR in docs/adr/.
  • Never commit plaintext secrets. Only *.enc.* (SOPS/age) are allowed; .env is git-ignored (.env.example is committed). See .gitignore.
  • Line endings: LF for scripts/Dockerfiles/YAML (enforced by .gitattributes) — these run on Linux.
  • Commit per phase/step with a descriptive message; the repo is the memory.
  • Environment is Windows (authoring) → Linux host (runtime). Prefer the Bash tool for POSIX one-offs.