Skip to content

Commit 015bd69

Browse files
committed
docs: add deployment and operations guides
1 parent f10e51b commit 015bd69

3 files changed

Lines changed: 156 additions & 0 deletions

File tree

docs/current-deployment-setup.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Current deployment-relevant setup
2+
3+
This note is superseded by:
4+
5+
- [deployment.md](./deployment.md) — secrets, Supabase/Coolify provisioning, initial deploy
6+
- [operations.md](./operations.md) — routine deploy, rollback, rotation, outage checks
7+
8+
The explorer runs as Astro SSR (`@astrojs/node` standalone) from a root multi-stage `Dockerfile`, talks to managed Supabase PostgreSQL over verified TLS with a read-only runtime login, and exposes token-gated `/livez` and `/readyz` for Coolify health checks.

docs/deployment.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Deployment
2+
3+
Secret-free checklist for deploying the MoSA explorer with Coolify and managed Supabase.
4+
5+
Do not put passwords, tokens, certificates, or live connection strings in this repository.
6+
7+
## Required GitHub secrets (`production` environment)
8+
9+
| Secret | Purpose |
10+
|--------|---------|
11+
| `SUPABASE_ACCESS_TOKEN` | Supabase CLI authentication for `db push` |
12+
| `SUPABASE_PROJECT_ID` | Production project ref |
13+
| `SUPABASE_DB_PASSWORD` | Database password for migration apply |
14+
| `COOLIFY_DEPLOY_WEBHOOK` | Triggers a Coolify deploy for the app |
15+
| `COOLIFY_API_TOKEN` | Reserved for Coolify API use if needed later |
16+
| `PRODUCTION_URL` | Public URL used for post-deploy smoke tests |
17+
18+
## Required Coolify runtime secrets
19+
20+
| Variable | Notes |
21+
|----------|-------|
22+
| `DATABASE_URL` | Runtime login URL (literal if the password contains `$`) |
23+
| `DATABASE_SSL_CA` | Supabase CA certificate (multiline) |
24+
| `HEALTHCHECK_TOKEN` | Shared with Docker/`X-Health-Token` health checks |
25+
| `NODE_ENV` | `production` |
26+
| `DATABASE_POOL_SIZE` | Optional; default `5` |
27+
| `DATABASE_STATEMENT_TIMEOUT_MS` | Optional; default `5000` |
28+
29+
`HOST` defaults to `0.0.0.0` and `PORT` to `4321` in the image.
30+
31+
## Explorer environment variables
32+
33+
| Variable | Required in production | Notes |
34+
|----------|------------------------|-------|
35+
| `DATABASE_URL` | yes | Prefer over deprecated `LOCAL_DATABASE_URL` |
36+
| `DATABASE_SSL_CA` | yes | Verified TLS |
37+
| `HEALTHCHECK_TOKEN` | yes | Authorizes `/livez` and `/readyz` |
38+
| `DATABASE_POOL_SIZE` | no | Default `5` |
39+
| `DATABASE_STATEMENT_TIMEOUT_MS` | no | Default `5000` |
40+
| `LOCAL_DATABASE_URL` | no | Dev-only deprecated alias; ignored as production source |
41+
42+
Unauthorized health requests return `404` and do not query PostgreSQL. External uptime checks should hit a normal page (for example `/`), not `/readyz`.
43+
44+
## Managed Supabase provisioning checklist
45+
46+
1. Create one production project on PostgreSQL 17 in a region near the Coolify server.
47+
2. Confirm required extensions match local development (including `unaccent` in `extensions`).
48+
3. Apply migrations (`supabase db push` / CI deploy job). Do not load fixtures or `seed.sql`.
49+
4. Create login `explorer_runtime_production` outside Git:
50+
- generated password
51+
- `grant explorer_reader to explorer_runtime_production`
52+
- `alter role ... set default_transaction_read_only = on`
53+
- short `statement_timeout` and a small connection limit
54+
5. Build `DATABASE_URL` from that login.
55+
6. Disable the Data API. Leave Auth, Storage, Realtime, and Functions unused.
56+
7. Download the database CA certificate for `DATABASE_SSL_CA`.
57+
8. From the Coolify host, test connectivity:
58+
- prefer the direct PostgreSQL endpoint if outbound IPv6 works
59+
- otherwise Supavisor **session** mode on port `5432` (not transaction mode)
60+
9. Enable SSL enforcement after the verified-TLS test succeeds.
61+
10. Restrict network access to the Coolify egress address where practical.
62+
11. Confirm managed daily backups are active.
63+
64+
A staging project and PITR can wait until there is a demonstrated need.
65+
66+
## Coolify application checklist
67+
68+
1. Connect the private GitHub repository through the Coolify GitHub App.
69+
2. Create a Dockerfile application:
70+
- branch `main`
71+
- build pack Dockerfile
72+
- base directory `/`
73+
- Dockerfile `/Dockerfile`
74+
- internal port `4321`
75+
- no host port mapping
76+
- no persistent volume
77+
- rolling updates enabled
78+
- default container naming
79+
3. Configure the production domain and DNS.
80+
4. Set the runtime-only secrets listed above (not build variables).
81+
5. Point Coolify health checks at `/readyz` with header `X-Health-Token: <HEALTHCHECK_TOKEN>`.
82+
6. **Disable auto-deploy on push** so migrations always run before the new container ships.
83+
7. Perform the first deployment manually and verify it before relying on the GitHub deploy job.
84+
85+
## Initial deployment checklist
86+
87+
1. Apply all migrations to production and confirm with `supabase migration list`.
88+
2. Verify `explorer_runtime_production` can `SELECT` expected objects and cannot write or run DDL.
89+
3. Trigger the first Coolify deployment for the image built from this repository.
90+
4. Confirm:
91+
- container health passes
92+
- TLS certificate is issued for the domain
93+
- authorized `/livez` and `/readyz` succeed
94+
- representative explorer pages render
95+
- no secrets appear in build or application logs
96+
5. Point production DNS only after those checks pass.
97+
6. Enable or rely on the GitHub Actions `deploy` job on `main` (CI must pass `static`, `database`, and `docker` first).

docs/operations.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Operations
2+
3+
Short operational notes for the Coolify + managed Supabase explorer deployment. No live credentials belong in this file.
4+
5+
## Routine deployment
6+
7+
1. Merge to `main` only after CI passes (`static`, `database`, `docker`).
8+
2. The `deploy` job:
9+
- applies pending Supabase migrations with `supabase db push`
10+
- triggers the Coolify deploy webhook
11+
- retries `PRODUCTION_URL` for a bounded period
12+
3. Keep Coolify auto-deploy disabled so the app never ships before migrations.
13+
14+
Use expand/contract migrations so a successful migration remains compatible with both old and new containers during rolling updates.
15+
16+
## Application rollback
17+
18+
- Roll back the application by redeploying a previously successful Coolify deployment/version.
19+
- Do not roll back schema with reverse migrations.
20+
- If a release is bad only in the app layer, keep the newer compatible schema and ship an older image, or ship a forward fix.
21+
22+
## Forward-fixing failed database migrations
23+
24+
- Treat migrations as forward-only.
25+
- If `db push` fails, fix forward with a new migration and re-run deploy.
26+
- Do not hand-edit production schema outside the migration history.
27+
- If a migration applied but the app deploy failed, either complete the app deploy for that commit or ship a follow-up commit that is schema-compatible.
28+
29+
## Database credential rotation
30+
31+
1. Create a new password for `explorer_runtime_production` in the Supabase SQL editor or dashboard (outside Git).
32+
2. Update Coolify `DATABASE_URL` with the new password (literal value if it contains `$`).
33+
3. Redeploy or restart the Coolify application so new connections use the rotated secret.
34+
4. Confirm authorized `/readyz` and a normal page still succeed.
35+
5. Never commit passwords, paste them into migrations, or leave them in shell history files that are shared.
36+
37+
## Backups and logs
38+
39+
- **Backups:** use Supabase managed daily backups for the production project. Restore through the Supabase dashboard/support flow when needed.
40+
- **Application logs:** Coolify application logs for the explorer container.
41+
- **Migration / deploy logs:** GitHub Actions `deploy` job for the `production` environment.
42+
- **Database logs:** Supabase project logs.
43+
44+
## Basic outage checks
45+
46+
1. Is the Coolify application running and healthy?
47+
2. Does `PRODUCTION_URL` respond?
48+
3. Does authorized `/readyz` return `204`? (`X-Health-Token` header required; public callers should see `404`.)
49+
4. Is the Supabase project up? Can you connect with verified TLS from the Coolify host?
50+
5. Did the latest GitHub deploy job fail on migrations or on the smoke test?
51+
6. Were Coolify runtime secrets recently changed (`DATABASE_URL`, `DATABASE_SSL_CA`, `HEALTHCHECK_TOKEN`)?

0 commit comments

Comments
 (0)