From 05aa57c880bce10bedfadc51360dd527ddb15866 Mon Sep 17 00:00:00 2001 From: Justin Paul Date: Sun, 20 Sep 2026 22:43:33 -0400 Subject: [PATCH] docs(deploy): add deploy/README.md and record the live instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The deploy/ directory had no entry point: how to stand the stack up lived only in comments inside docker-compose.yml, and the maintainer's own instance (provenance.paul.farm) was written down nowhere in the repo — it had to be rediscovered from an unrelated repo's research log. Add deploy/README.md covering the run/build commands, the LAN-push / FQDN-pull registry split, the env-driven site address, and the Watchtower + one-shot-migrate caveat, plus a "maintainer's instance" section with the URL, host, ingress and deploy path. Cross-reference it from CLAUDE.md. Also note the live instance reports "env":"development" — its .env never set APP_ENV=production. Informational only (app_env gates no behavior), but .env.example now says to set it on a real deployment. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BeRh7Vwq8j9s6jshaMUNCd Signed-off-by: Justin Paul --- CLAUDE.md | 4 +++- deploy/.env.example | 2 ++ deploy/README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 deploy/README.md diff --git a/CLAUDE.md b/CLAUDE.md index 917537c..7f8dfed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,7 +41,7 @@ Pick libraries consistent with this stack. If you introduce a significant depend / # docs and project meta (this file, README, LICENSE, COC, CONTRIBUTING) /docs # PRD.md, ARCHITECTURE.md /backend # FastAPI service (uv-managed). app/{api/v1, services (+ privacy engine), repositories, models, schemas, integrations (auth, mailer, objectstore, models = pluggable LLM/embedding providers), core}; migrations/ = Alembic -/deploy # docker-compose.yml (+ docker-compose.dev.yml), Caddyfile, .env.example, backup.sh + BACKUP.md (one-command pg_dump + MinIO backup) — the self-host stack +/deploy # README.md (how to run it + the live instance), docker-compose.yml (+ docker-compose.dev.yml), Caddyfile, .env.example, backup.sh + BACKUP.md (one-command pg_dump + MinIO backup) — the self-host stack /.gitea/workflows # Gitea Actions CI (build images → Gitea registry) /frontend # Next.js (App Router, TS, Tailwind, shadcn-style UI). app/ pages, lib/api generated OpenAPI client, components/ui ``` @@ -113,6 +113,8 @@ Wordmark is a serif (heritage register); UI body/secondary text is a humanist sa Maintainer: **Justin Paul** (`justin@jpaul.io`). This deployment targets a home lab: Authentik at `auth.jpaul.io` for auth, `mail.jpaul.io` for SMTP, behind Caddy + Cloudflare Tunnel. +The maintainer's live instance is **** (host `192.168.0.2`, owner account `justin@jpaul.me`) — see [deploy/README.md](deploy/README.md) for its specifics. The code itself hard-codes no hostname; the site address is env-driven. + ## Open questions (don't assume answers) Parked in PRD §11 and ARCHITECTURE §14: telemetry (opt-in anonymous vs none), embeddings provider for matching, DNA as future-phase vs permanent non-goal, native mobile timing, hosted-SaaS model, queue backend default (Postgres vs Redis), and PostGIS adoption. If a task depends on one of these, surface the dependency instead of picking silently. diff --git a/deploy/.env.example b/deploy/.env.example index 0c40d98..2bafe66 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -2,6 +2,8 @@ # Everything is twelve-factor; no endpoints or secrets live in code. # --- Core --- +# development | production. Set to `production` on a real deployment — it is +# reported by /health and the owner /admin surface. APP_ENV=development # Instance owner / operator. The account(s) whose email is named here get diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..3431c89 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,48 @@ +# Deploying Provenance + +This directory is the self-host stack: `docker-compose.yml` (Postgres + MinIO + +Caddy + backend + worker + frontend, with a one-shot Alembic `migrate` job), +`Caddyfile` for the edge, `.env.example` for configuration, and `backup.sh` / +[BACKUP.md](BACKUP.md) for backup and restore. + +## Run it + +```bash +cp .env.example .env # fill in secrets, OWNER_EMAIL, APP_ENV=production +docker compose up -d # pulls backend/frontend images from git.jpaul.io +``` + +Images are **pulled** from the public `git.jpaul.io` registry (CI pushes them to +the LAN endpoint `192.168.0.2:1234`; see CLAUDE.md). To build locally instead, +layer the dev override: + +```bash +docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build +``` + +Caddy's site address is env-driven (`PROVENANCE_SITE_ADDRESS`): `:80` for plain +HTTP behind a tunnel or for `http://localhost`, or a domain for automatic HTTPS. +Nothing in this repo hard-codes a hostname. + +Note that a Watchtower image swap recreates only the long-running containers, +not the one-shot `migrate` job — pair auto-deploys with a `docker compose up` +so migrations re-run. + +## The maintainer's instance + +Justin's own deployment — the one holding the Paul/Reier family tree: + +| | | +|---|---| +| **URL** | | +| **Host** | `192.168.0.2` (the fleet host; also the LAN registry endpoint) | +| **Ingress** | Cloudflare Tunnel → `caddy:80`; Cloudflare terminates TLS, so `PROVENANCE_SITE_ADDRESS` stays `:80` | +| **Owner account** | `justin@jpaul.me` | +| **Deploys** | CI builds on merge to `main`; the host's global Watchtower swaps the `test-main` images | + +Health check (no auth): `curl https://provenance.paul.farm/health`. + +Known drift: that endpoint currently reports `"env":"development"` — the host's +`.env` never set `APP_ENV=production`. It is informational only (`app_env` is +reported by `/health` and `/api/v1/admin`; it gates no behavior), but it should +be corrected on the host. -- 2.54.0