Files
wiggleverse-ecomm/docs/BOOTSTRAP.md
T
ben.stull 4bb9763633
ci / check (pull_request) Has been cancelled
ci / check (push) Has been cancelled
docs(slice-4): record the first PPE bootstrap rehearsal (PUC-11, 2026-06-11) — green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:54:47 -07:00

5.6 KiB

Bootstrapping ecomm

Bringing an environment from empty persistence to "first merchant, first storefront" through the product flows alone (SD-0001 BUC-5). Empty is a working state (INV-1): the app applies its own schema migrations at startup; there is no seed step.

This document grows per environment. SLICE-1 shipped the localhost section; SLICE-4 adds pre-production (PPE). The production section lands with the prod stand-up.

Localhost

Prerequisites

  • Docker (Desktop or Engine) with Compose v2 — the one external prerequisite. The dev datastore is a single PostgreSQL container; the app itself runs natively for a fast dev loop (D-7).
  • Python 3.13 and Node 20+ on your PATH. scripts/dev.sh creates the backend venv and installs frontend deps on first run.

Bring-up

From a clean checkout:

scripts/dev.sh

This:

  1. starts the dev Postgres container and waits for it to report healthy (the script owns the container's lifecycle);
  2. creates the backend virtualenv and installs dependencies (first run only);
  3. installs the frontend's npm dependencies (first run only);
  4. runs the FastAPI backend on :8000 — which connects to the empty database and applies all pending migrations itself (INV-7) — and the Vite dev server on :5173, proxying /api to the backend.

Press Ctrl-C to stop the backend and Vite. The database container keeps running.

Verify

curl http://localhost:8000/healthz

Expected: {"status":"ok"} (HTTP 200) — the process is up, the database is reachable, and migrations are current. Open http://localhost:5173 to see the app shell.

Reset to empty (rehearse the bootstrap)

docker compose down -v

This removes the container and its named volume, returning persistence to empty. The next scripts/dev.sh re-migrates from scratch — exactly the day-one state every environment starts from (BUC-5a).

Configuration

scripts/dev.sh sets ECOMM_DATABASE_URL to the local compose DSN (postgresql://ecomm:ecomm@localhost:5432/ecomm). No deployment shape is baked into the app (INV-8); deployed environments supply this and other config from Secret Manager (see PPE below).

Pre-production (PPE)

PPE is stood up and deployed through the launch-app / flotilla-core suite only (handbook §8.5 — provisioning is an operator-run gesture). The app's deployment record is deployment.toml at this repo's root; flotilla-core consumes it.

One-time provisioning (operator-run, in order)

  1. Cloud foundationscaffold-gcp-project: the GCP project, its dedicated --no-activate gcloud config, billing, core APIs, ADC quota pin.
  2. Managed databaseprovision-datastore (launch-app §6.6a, built for ecomm's D-7/D-8): Cloud SQL for PostgreSQL 16, private-IP-only, automated backups + point-in-time recovery; writes the full DSN to Secret Manager as <project>/ecomm-ppe-database-url. Bound on the deployment record as ECOMM_DATABASE_URL.
  3. Secrets (references only — bytes go in via stdin, never through a session): ECOMM_SESSION_SECRET (fresh random), ECOMM_SMTP_PASSWORD (the shared Wiggleverse relay credential), and flotilla's own Gitea read token for this private repo.
  4. VM + edgeprovision-vm: the e2-micro, IAP-only SSH, nginx + Cloudflare origin TLS, the systemd unit, DNS for ecomm-ppe.wiggleverse.org.
  5. Deployment recordflotilla-core deployment scaffold ecomm … -o deployment.toml, validate, commit it here, deployment import --reconcile.

Deploy

Each release is a git tag v<VERSION> matching the repo-root VERSION file (the pin). The one gesture, from the flotilla-core repo's venv:

CLOUDSDK_ACTIVE_CONFIG_NAME=ecomm .venv/bin/flotilla-core deploy ecomm

Nine phases, fail-stop; it ends by polling https://ecomm-ppe.wiggleverse.org/healthz and requiring status == "ok" and version == <target>. Watch it yourself the same way:

curl https://ecomm-ppe.wiggleverse.org/healthz

Configuration surface (PPE values)

Env var Kind Value
ECOMM_DATABASE_URL secret ref <project>/ecomm-ppe-database-url (from provision-datastore)
ECOMM_SESSION_SECRET secret ref <project>/ecomm-ppe-session-secret
ECOMM_SMTP_PASSWORD secret ref the shared Wiggleverse relay credential
ECOMM_MAILER overlay smtp
ECOMM_COOKIE_SECURE overlay 1
ECOMM_SMTP_HOST / _PORT / _USER / _FROM overlay the relay coordinates (non-secret)

The rehearsal (PUC-11)

From empty persistence: the deploy migrates the schema at startup (INV-7); then a real sign-up → one-time code arriving by real email → create storefront → admin, through the public flows alone. Record each rehearsal here when it happens.

Rehearsals:

  • 2026-06-11 — PPE first bootstrap (v0.4.0, session 0024): First-ever ecomm deploy (flotilla-core deploy ecomm, 9/9 phases green, deploys.id=40) onto a freshly provisioned environment — project wiggleverse-ecomm, Cloud SQL ecomm-ppe-pg (provisioned by launch-app provision-datastore, first run), VM ecomm-ppe. The app self-migrated the empty database at startup; the operator then walked sign-up → real emailed code (Gmail relay) → create storefront → honestly-empty admin in a browser, through the public flows alone. Findings captured: OTC email branding (#16); identity should outgrow ecomm (engineering#49/#50).

Production

Lands with the prod stand-up — the identical gesture on a prod deployment record (BUC-5a): same provisioning skills, same deploy, same rehearsal.