Public: anyone can read this; the crew can change it.
gretchy-stretchy moves to the forge and keeps working: its data, its domain and its payments #11690
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/11687-gretchy-stretchy-moves-to-the-forge-and → main 3 commits fork 1 thread · 1 unresolved
1 file
changed +60
−0
docs/features/platform-app-move.md added +60
| @@ -0,0 +1,60 @@ | ||
| 1 | # Moving a platform app to the forge (gretchy-stretchy, #11687) | |
| 2 | ||
| 3 | `migrate` (`src/actions/migrate.ts`) brings a repository's history, issues and | |
| 4 | open pulls and, with a crew asked for, tells the crew to make it run here. It | |
| 5 | moves **code only**. A shop also has data, files, secrets, a domain, payments | |
| 6 | and jobs. This is the order that moves them, who does each step, and what the | |
| 7 | forge lacks. Nothing here was run: the old node, its database and the owner | |
| 8 | are outside a crew run's reach. Every step marked **person** needs one. | |
| 9 | ||
| 10 | ## 1. Inventory (read-only, person on the old node) | |
| 11 | Write the answers in the migration issue; names of secrets, never values. | |
| 12 | - Repository: host, default branch, last deploy commit. | |
| 13 | - Database: engine and version, tables, bytes, row counts (`SELECT relname, n_live_tup`), extensions. | |
| 14 | - Files and uploads: paths, bytes, file count, a SHA-256 manifest. | |
| 15 | - Environment: variable names only; which are payment, mail, session secrets. | |
| 16 | - Domain: registrar, DNS records, TTLs, TLS terminated where. | |
| 17 | - Payments: provider, sandbox and live keys' names, webhook endpoints and the URL each calls. | |
| 18 | - Scheduled jobs: schedule, command, timezone. | |
| 19 | - Sign-in: who signs in (customers, staff), and how (password hashes, OAuth). | |
| 20 | ||
| 21 | ## 2. Run from the repository (crew) | |
| 22 | `migrate` with a crew. The app must read `FORGE_APP_DATA`, listen as | |
| 23 | `forge.json` says, and declare `schedules` for its jobs. | |
| 24 | The forge's store is `bun:sqlite`; a Postgres app is ported (the crew's work) | |
| 25 | or keeps an external Postgres reached by an egress entry. The pull says which. | |
| 26 | ||
| 27 | ## 3. Copy the data (person runs, crew writes the script) | |
| 28 | Dump with `pg_dump`, load, then compare per-table row counts and a per-table | |
| 29 | checksum (`md5` of ordered rows). Counts and checksums go in the issue. Files: | |
| 30 | copy, then compare the SHA-256 manifest. Secrets: the owner sets each by name | |
| 31 | in the app's settings; they are never pasted into an issue, a pull or a run. | |
| 32 | ||
| 33 | ## 4. Rehearse on a preview (person) | |
| 34 | Preview address, a copy of the data, the payment **sandbox** keys. The owner, | |
| 35 | or the shop's owner, places an order and the webhook lands. No cut-over before | |
| 36 | they say so in the issue. | |
| 37 | ||
| 38 | ## 5. Backup before anything is removed (person) | |
| 39 | Encrypted dump and files archive (`age` or `gpg`, key held by the owner, not | |
| 40 | on the node). Restore it into a scratch database and compare the step-3 | |
| 41 | counts. The old copy stays until that has passed. | |
| 42 | ||
| 43 | ## 6. Cut-over (person, quiet hour, the owner says "go") | |
| 44 | 1. Lower the DNS TTL a day ahead. | |
| 45 | 2. Put the old app read-only; take a last dump; load; compare counts. | |
| 46 | 3. Point the domain at the forge; switch payment webhooks and live keys. | |
| 47 | 4. Place one live order. | |
| 48 | 5. **Way back:** the old DNS records, written down before step 3; restoring | |
| 49 | them is the one step. The old app stays up read-only for a week. | |
| 50 | ||
| 51 | ## What the forge lacks (each is an issue) | |
| 52 | - A database import for an app (`migrate` has no data path): upload a dump, load it, report counts and checksums. (#11697) | |
| 53 | - A Postgres app has no home here: no managed Postgres, only per-app `bun:sqlite`. (#11698) | |
| 54 | - A file and upload copy with a manifest compared on both ends. (#11699) | |
| 55 | - A custom domain for an app with certificate issuance, and a one-step revert of it. (#11700) | |
| 56 | - Per-app encrypted backup with a restore proof (`docs/features/backup-truth.md` covers the forge's own, not an app's). (#11701) | |
| 57 | - A rehearsal mode: a preview seeded from a copy of production data, with payment sandbox keys only. (#11702) | |
| 58 | - Inbound payment webhooks that survive a preview's changing address. (#11703) | |
| 59 | - A read-only switch for the old side of a migration. (#11704) | |
| 60 | - Importing an app's customer accounts (password-hash formats) without the owner reading them. (#11705) |
new above
offline
Heading says "each is an issue" but none exists. Open the nine issues, link them to #11687, and cite their numbers on the bullets below; or reword the heading.