mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
ci(deploy): establish staged Dokploy promotion
This commit is contained in:
1 parent
2dad7aa352
commit
a455325147
14 files changed
+199
-310
No files matched your search
@@ -0,0 +1,44 @@
|
||||
# Backend deployment and branching
|
||||
|
||||
Dokploy deploys the standalone backend directly from GitHub. GitHub Actions is
|
||||
the verification gate; it does not hold a broad Dokploy API credential and does
|
||||
not deploy the retired Supabase data plane.
|
||||
|
||||
## Branch contract
|
||||
|
||||
| Branch | Purpose | Dokploy target | Public API |
|
||||
|---|---|---|---|
|
||||
| feature branches | isolated reviewed work | none | none |
|
||||
| `staging` | integrated release candidate | `backend-staging` | `https://api.preprod.sauci.app` |
|
||||
| `main` | production promotion | `backend-production` | `https://api.sauci.app` |
|
||||
| `master` | frozen legacy default | none | none |
|
||||
|
||||
Normal feature pull requests target `staging`. After CI and authenticated staging
|
||||
acceptance pass, open a promotion pull request from `staging` to `main`. Do not
|
||||
add production-only commits to `main`: production should run the exact commit
|
||||
already exercised in staging. Direct pushes to either deployment branch are for
|
||||
explicit incident recovery only.
|
||||
|
||||
Each Dokploy Compose application is connected to `jjbrunton/Sauci`, watches its
|
||||
single branch with push-triggered automatic deployment, and uses
|
||||
`infra/backend/compose.production.yaml`. The Compose file deliberately has no
|
||||
top-level project name so Dokploy assigns different project names, networks, and
|
||||
named volumes to staging and production. Never point both applications at the
|
||||
same PostgreSQL or media volume.
|
||||
|
||||
## Promotion checks
|
||||
|
||||
1. GitHub `Verify / static` and `Verify / backend-integration` succeed for the
|
||||
candidate commit.
|
||||
2. The Dokploy deployment for `staging` reports success; `/health/live` and
|
||||
`/health/ready` return 200 over valid TLS.
|
||||
3. An unauthenticated protected request returns 401, proving the public route is
|
||||
not bypassing authentication.
|
||||
4. The mobile app signs in through non-production Supabase Auth and reads real
|
||||
migrated content from `https://api.preprod.sauci.app`.
|
||||
5. Promote the exact `staging` commit to `main` and verify the production health,
|
||||
TLS, and authentication boundary independently.
|
||||
|
||||
Health proves infrastructure, not customer-data cutover. The App Store build
|
||||
must not be released against production until the controlled final sync and the
|
||||
checks in [backend-cutover.md](backend-cutover.md) are complete.
|
||||
@@ -1,26 +1,35 @@
|
||||
# Database migration safety
|
||||
|
||||
All schema changes are versioned local files under `apps/supabase/migrations/`.
|
||||
The standalone PostgreSQL schema is owned by ordered SQL files under
|
||||
`apps/api/drizzle/`. Hosted Supabase owns Auth only; its legacy product-data
|
||||
migrations and Edge Functions are retained as cutover history and are not a
|
||||
deployment target.
|
||||
|
||||
## Required workflow
|
||||
|
||||
1. `npm run db:migration:new -- <descriptive_name>`
|
||||
2. Edit the generated local migration.
|
||||
3. Prefer idempotent SQL where semantics permit it.
|
||||
4. `npm run db:reset` against local Supabase.
|
||||
5. Run `npm run test:supabase` and affected application checks.
|
||||
6. Commit the migration with dependent code and types.
|
||||
1. Add the next ordered SQL migration under `apps/api/drizzle/`.
|
||||
2. Keep application, repository, shared-contract, and client changes in the same
|
||||
reviewed change where the schema contract requires them.
|
||||
3. Run `npm run verify:full` against the dedicated loopback PostgreSQL service.
|
||||
4. Run `infra/backend/verify-production.sh` for container and migration startup.
|
||||
5. Merge to `staging`; the Dokploy migration service applies the committed files
|
||||
under an advisory lock before the API receives traffic.
|
||||
6. Prove staging health and affected authenticated behavior before promoting the
|
||||
exact commit from `staging` to `main`.
|
||||
|
||||
## Forbidden paths
|
||||
## Safety invariants
|
||||
|
||||
- Never call a remote `apply_migration` MCP tool.
|
||||
- Never execute DDL through MCP SQL execution.
|
||||
- MCP SQL execution is read-only `SELECT` use only.
|
||||
- Never insert migration history manually except an explicitly approved repair.
|
||||
- Never hardcode a production URL in a migration or cron definition.
|
||||
- Never point local integration tests, reset commands, or disposable verification
|
||||
at a remote database.
|
||||
- Never deploy `apps/supabase/migrations` or `apps/supabase/functions` as part of
|
||||
the standalone backend release.
|
||||
- Never execute DDL through MCP or provider SQL tools.
|
||||
- Never edit migration history already applied to a persistent environment; add
|
||||
a forward migration.
|
||||
- Back up PostgreSQL and private media together before a destructive production
|
||||
migration or data import, and prove restore separately.
|
||||
- A failed migration must block API startup. Do not bypass the one-shot `migrate`
|
||||
service to force new code against an old schema.
|
||||
|
||||
CI deploys committed migrations and Edge Functions to non-production after relevant
|
||||
pushes. Production promotion is a manual workflow dispatch. Terraform is applied
|
||||
only when files under `terraform/` change, or when `deploy_infrastructure` is
|
||||
explicitly selected during a manual deployment. Local verification must not link a
|
||||
remote project.
|
||||
Production data cutover has additional stop-source, final-sync, parity, legacy
|
||||
media, and authenticated-mobile checks in [backend-cutover.md](backend-cutover.md).
|
||||
Reference in new issue
Block a user