Living architecture/ops ledger. Each entry: Decision · Why · Status. Dates
absolute. Read this first when changing servers, forking, or revisiting a choice —
it captures the why, not just the what. Specs hold the detail
(docs/superpowers/specs/); this is the index of intent.
Last updated: 2026-06-25.
- Multi-host group model, one repo. · Groups (Dev, Support, Monitoring) each
deploy to their own host; one repo,
deploy/<group>/per host. · Why: clean isolation, independent cadence, each host self-contained. · Locked. - Cloud = AWS Lightsail; region us-east-1. · Why: flat price incl. transfer, simpler than EC2. · Locked (pivot from EC2 — see Pivots).
- Provision via AWS CLI script (
infra/scripts/), no OpenTofu. · Why: cheaper/ simpler for a personal box; reproducible without IaC. · Locked. - Host sizes: Dev 16 GB
xlarge_2_0, Support 8 GBlarge_2_0, Monitoring TBD. · Why: Plane's stack is heavy (~11 containers); Support is light. · Locked. - 4 GB swap per host. · Why: safety net on an 8/16 GB box, not headroom. · Locked.
- Data on a separate Lightsail block disk at
/data. · Why: survives instance recreation (instance = cattle, disk = pet). · Locked. - No backups. · Why: accepted risk for a personal dev platform; block disk is the only durability. · Locked (accepted risk).
- Secrets in
deploy/<group>/.envon host,chmod 600, gitignored. No SSM. · Why: simple; Lightsail has no IAM instance role anyway. · Locked.
- Dev: Forgejo (git), Mattermost (chat), Plane (project mgmt). · Built, merged (PR #1).
- Support: Planka (kanban), Chatwoot (helpdesk). · Spec done.
- Admin: Twenty CRM (shared Postgres
twenty+ own Redis). · Why: CRM on the standard Postgres; build/host decided in its own brainstorm. · Backlog. - Monitoring: Beszel (lightweight server monitoring) — confirmed. Hub uses its own SQLite/PocketBase store (no shared Postgres); agents per host (cross-host deferred). · Built (local).
- Overlay official image: Forgejo, Mattermost, Planka (branding only). · Why: no code changes → cheap updates. · Locked.
- Fork from source: Plane, Chatwoot. · Why: we modify their code (Plane customizations; Chatwoot += Kanban + features). · Locked.
- Fork images → GHCR, built off-host, host pulls. · Why: Lightsail has no IAM role (ECR painful); building Plane/Chatwoot on host risks OOM. · Locked (pivot from ECR).
- Fork layout: submodule
apps/<app>/upstream, long-livedcode42branch,CHANGES.mddivergence log. · Why: diffable, rebasable against upstream. · Locked.
- One shared Postgres per host; one DB per app; reporting DB via
postgres_fdw. · Why: single backing service; apps stay attached resources; Plane's bundledplane-dbdropped. · Locked. - Curated read-only
reportingviews, never raw app tables. · Why: app schemas change between versions and lack external-facing RLS; views are the stable seam. · Locked. - PostgREST over
reporting+ read-only roles (bi_reader,authenticator); Adminer as SQL explorer. · Why: auto REST API for BI; Supabase Studio dropped (too heavy). · Locked. - Per-group reporting (each host runs its own Postgres+FDW+PostgREST). · Why: keeps N2 — no Postgres exposed between hosts. Cross-host BI deferred. · Locked.
- Metabase/Superset deferred (read-only role left ready). · Deferred.
- Auth A1 — each app its own login, no SSO. · Why: fewest moving parts to start. · Locked.
- Network N2 — Caddy is the only public ingress (80/443, auto-TLS); SSH 22 owner-IP only; Postgres/PostgREST/Adminer publish no host port (SSH tunnel). · Why: minimal attack surface; BI never public. · Locked.
- Domains on
code42.dev: Devgit./chat./plane.; Supportboard.(Planka) /support.(Chatwoot). · Locked. - Ingress = Caddy, not Traefik. · Why: our per-host set is small and static
(3–5 subdomains), so Traefik's dynamic discovery adds little. Caddy gives a single
readable Caddyfile, zero-config auto-TLS, an offline
caddy validatelint step, and — key — no Docker socket (Traefik's Docker provider needsdocker.sock= root-equivalent, against N2's minimal surface; avoiding it via file-provider or a socket-proxy negates Traefik's main benefit). · Locked. · Reconsider if: forward-auth SSO (Authelia/Authentik middleware), many dynamic/autoscaling services, or Traefik middlewares (rate-limit/headers) become needed.
- Layout:
infra/(provisioning) ·apps/<app>/(shared per-app contexts) ·deploy/<group>/(compose + .env per host). · Why: provisioning, the app library, and per-host composition change for different reasons. · Locked. DATA_ROOTenv for dev/prod parity (/dataon VPS,<repo>/.datalocal). · Why: same compose everywhere, no per-env edits. · Locked.- Local dev via Colima (not Docker Desktop); VPS uses Docker. · Why: user preference; amd64-only images (Mattermost) cross-built with buildx on the arm64 dev box. · Locked.
- Tests =
Makefile+test/(lint + live smoke; HTTP via curl sidecar). · Why: infra needs lint+smoke, not unit tests; sidecar because app images lack curl. · Locked.
- Chatwoot fork = add Kanban + product features. · Locked.
- WhatsApp = Cloud API (Meta official). · Why: ToS-safe, no extra container, webhook via Caddy; avoids ban risk of unofficial bridges (Evolution API). · Locked.
- Chatwoot attachments = MinIO (own container, bucket
chatwoot, S3 Active Storage). · Why: decouples storage from disk, ready for scale/S3 backup. · Locked. - Chatwoot needs own Redis (Sidekiq) + shared Postgres
chatwootDB. · Locked.
- Node TUI installer (
bin/install,installer/). ·@clack/prompts+picocolors; modos Local e Remoto (SSH). Reusa Makefile/compose/scripts por baixo; gera o.envpor grupo (segredos viacrypto.randomBytes, pergunta só os externos). · Why: alinhar com os outros CLIs Node do ecossistema; um onboarding guiado em cima da base bash existente. · Active. - SSH por shell-out atrás de interface (
installer/src/ssh.js). ·ssh/scp/rsyncdo sistema; troca futura paranode-ssh/ssh2fica isolada nesse módulo. · Active. - Multi-provider provisioning REABERTO. · O instalador provisiona em Lightsail (AWS CLI, mantém o script atual), EC2 (OpenTofu), Vultr (OpenTofu), ou usa um host existente. · Why: flexibilidade de provider/região/custo e portabilidade pedida pelo usuário (2026-06-28). · Supersede parcialmente "no OpenTofu / Lightsail-only": OpenTofu volta apenas para as trilhas EC2/Vultr; Lightsail segue via AWS CLI. · Active.
- EC2/Vultr v1:
/datano root volume (sem disco-pet separado). · Why: evita o problema de nomeação de device em instâncias nitro e mantém o sistema funcionando primeiro; o modelo "disco=pet" do Lightsail vira evolução futura. · Active (aceito como simplificação v1).
- EC2 + OpenTofu → Lightsail + AWS CLI script. · Cheaper, simpler, no IaC. · Reaberto em 2026-06-28 para multi-provider — ver "Provisioning & installer".
- ECR → GHCR for fork images. · Lightsail has no IAM instance role.
- Support apps: same Dev host (phase 2) → separate 8 GB host (own group). · Cleaner isolation; per-group reporting.
- Dev host 8 GB → 16 GB. · Plane's self-host stack grew (admin, live, RabbitMQ; ~11 containers).
- Supabase-as-shared-DB idea → shared Postgres + curated
reportingviews. · Exposing app tables raw via PostgREST is brittle + insecure.
- Chatwoot Kanban feature design — detailed once the base Chatwoot is up.
- Admin group (Twenty CRM) — own brainstorm: build (overlay vs fork), host size, Redis sizing. Backlog.
- Remote Beszel agents on the Dev/Support/Admin hosts — cross-host; deferred.
- Cross-host BI (Dev+Support correlation) — deferred; default per-group, revisit when a concrete need appears.