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
@@ -9,6 +9,7 @@ historical notes. Agents should load only the section relevant to their task.
|
||||
- [Local full-stack development](development/local-stack.md)
|
||||
- [Testing strategy](testing/strategy.md)
|
||||
- [Database migration safety](operations/database-migrations.md)
|
||||
- [Backend deployment and branching](operations/backend-deployments.md)
|
||||
- [Agent routing and effort](agents/routing.md)
|
||||
- [Learning promotion](agents/learnings.md)
|
||||
- [Authentication](authentication.md)
|
||||
|
||||
@@ -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).
|
||||
@@ -6,23 +6,25 @@ is proved through the real stack.
|
||||
## Gates
|
||||
|
||||
- `verify:fast`: invariant lint, workspace lint/typecheck, and unit tests.
|
||||
- `verify:full`: fast gate plus builds and local Supabase function tests when the
|
||||
required local tools are present.
|
||||
- `verify:full`: fast gate plus builds and standalone API/PostgreSQL integration
|
||||
tests against a loopback database.
|
||||
- `verify:e2e`: Playwright browser flows and native Maestro flows against an
|
||||
already-running local stack.
|
||||
- `verify`: full plus E2E; this is the pre-PR target.
|
||||
|
||||
CI runs deterministic checks on every pull request. Running-stack tests use a
|
||||
separate job because they require Docker/Supabase and produce traces,
|
||||
screenshots, and videos as artifacts.
|
||||
CI runs deterministic checks on every pull request and on pushes to `staging`
|
||||
and `main`. The backend integration job provisions disposable PostgreSQL and
|
||||
refuses non-loopback database URLs. User-facing browser/native acceptance remains
|
||||
a pre-promotion check because it requires running services and test identities.
|
||||
|
||||
## Test ownership
|
||||
|
||||
- Unit/component tests live with their workspace.
|
||||
- Supabase function integration tests live in `apps/supabase/tests`.
|
||||
- Standalone backend integration tests live in `apps/api/test`.
|
||||
- `apps/supabase/tests` cover the retired data plane and are not a deployment gate.
|
||||
- Cross-application browser tests live in `e2e`.
|
||||
- Native black-box flows live in `e2e/maestro`.
|
||||
|
||||
E2E must use local or sandbox endpoints. Tests refuse non-local Supabase URLs.
|
||||
Authentication is proved once through the public flow; reusable fixture sessions
|
||||
avoid repeating auth in unrelated scenarios.
|
||||
E2E product-data endpoints must be local or staging, never production. Local
|
||||
database tests refuse non-loopback URLs. Authenticated staging acceptance uses
|
||||
the designated non-production hosted Auth project and disposable fixture users.
|
||||
Reference in new issue
Block a user