Merge pull request #388 from trails-cool/stigi/archive-staging-environments-spec

Archive staging-environments change; update local-dev spec
This commit is contained in:
Ullrich Schäfer 2026-05-17 20:46:07 +02:00 committed by GitHub
commit 6c3f8a3c38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 81 additions and 10 deletions

View file

@ -8,7 +8,7 @@
- [x] 2.1 Create `infrastructure/docker-compose.staging.yml` with staging journal (port 3100), planner (port 3101), memory limits (256MB), and `trails_staging` database URL
- [x] 2.2 Create `infrastructure/staging.env.template` documenting required staging environment variables (DOMAIN, DATABASE_URL, JWT_SECRET, SESSION_SECRET)
- [x] 2.3 Add a shared Docker network (`trails-shared`) to production `docker-compose.yml` so staging can reach BRouter and PostgreSQL
- [ ] 2.4 Verify staging containers start with `docker compose -f docker-compose.staging.yml -p trails-staging up -d` on the server
- [x] 2.4 Verify staging containers start with `docker compose -f docker-compose.staging.yml -p trails-staging up -d` on the server
## 3. Caddy Wildcard Routing
@ -16,7 +16,7 @@
- [x] 3.2 Add `planner.staging.trails.cool` site block proxying to planner on port 3101
- [x] 3.3 Add `import sites/*.caddyfile` to the main Caddyfile so per-PR site blocks can be dropped in and picked up on reload
- [x] 3.4 Define the per-PR Caddyfile snippet template the cd-staging workflow writes for each preview (host = `pr-<N>.staging.trails.cool`, upstream = `host.docker.internal:<port>`, port = `3200 + 2N`)
- [ ] 3.5 Reload Caddy and verify staging routes work with `curl -sf https://staging.trails.cool/api/health`
- [x] 3.5 Reload Caddy and verify staging routes work with `curl -sf https://staging.trails.cool/api/health`
## 4. GitHub Actions Workflow
@ -30,7 +30,7 @@
- [x] 5.1 Create a scheduled cleanup job (weekly cron in GitHub Actions or pg-boss on the server) that lists running `trails-pr-*` containers, checks PR status via `gh pr view`, and tears down orphans
- [x] 5.2 Add memory limits (`deploy.resources.limits.memory: 256m`) to staging containers in the compose override
- [ ] 5.3 Test full lifecycle: open a test PR → verify preview deploys → push a commit → verify preview updates → close PR → verify teardown
- [x] 5.3 Test full lifecycle: open a test PR → verify preview deploys → push a commit → verify preview updates → close PR → verify teardown
## 6. Documentation

View file

@ -1,12 +1,12 @@
## Why
There is no staging environment — production is the only deployed instance. Infra
changes (Prometheus alerts, Caddy config, Grafana dashboards) go straight to prod
with no way to validate them locally first. Meanwhile, CI E2E tests skip ~15 of
20 tests because there is no PostgreSQL service in the workflow, and BRouter was
only recently added to CI with manual setup instead of reusing the dev compose
file. The existing `docker-compose.dev.yml` covers PostgreSQL and BRouter but
nothing else from the production stack.
Infra changes (Prometheus alerts, Caddy config, Grafana dashboards) can only be
validated against staging or production — there is no way to test them locally
first. Meanwhile, CI E2E tests skip ~15 of 20 tests because there is no
PostgreSQL service in the workflow, and BRouter was only recently added to CI
with manual setup instead of reusing the dev compose file. The existing
`docker-compose.dev.yml` covers PostgreSQL and BRouter but nothing else from the
production stack.
## What Changes

View file

@ -2,6 +2,18 @@
One-command local development setup with PostgreSQL, BRouter, automatic schema migration, and segment downloading.
## When to Use Local vs. Staging
| Scenario | Use |
|----------|-----|
| Everyday development, unit tests, E2E tests | Local (`pnpm dev:full`) |
| Sharing a work-in-progress with reviewers | PR preview (`pr-<N>.staging.trails.cool`) |
| Testing against production-like infra (Caddy TLS, Docker networking) | Staging (`staging.trails.cool`) |
| Wahoo OAuth callback testing | Local with `HTTPS=1` (see CLAUDE.md) |
| ActivityPub federation testing | Staging (requires real HTTPS + public domain) |
The Planner, Journal, PostgreSQL, and BRouter all run locally. The local stack is the default for all development work. Staging is not a replacement for local dev — it is a pre-merge verification surface and a way to share work without merging first.
## Requirements
### Requirement: One-command dev startup

View file

@ -0,0 +1,59 @@
## Purpose
Production-like staging and ephemeral PR preview environments running alongside production on the flagship server, enabling integration testing before merge and live URL sharing with reviewers.
## Requirements
### Requirement: Persistent staging instance
A persistent staging instance SHALL run at `staging.trails.cool` (journal) and `planner.staging.trails.cool` (planner), auto-deploying from main on every push.
#### Scenario: Deploy staging on main push
- **WHEN** a commit is pushed to main that changes `apps/` or `packages/`
- **THEN** the staging journal and planner containers are rebuilt and redeployed with the latest main
#### Scenario: Staging uses isolated database
- **WHEN** the staging instance is running
- **THEN** it uses the `trails_staging` database, separate from the production `trails` database
#### Scenario: Staging is accessible
- **WHEN** a user navigates to `https://staging.trails.cool`
- **THEN** they see the journal app served over HTTPS with a valid TLS certificate
### Requirement: PR preview environments
Ephemeral preview environments SHALL be created for each PR that changes app or package code.
#### Scenario: Preview created on PR open
- **WHEN** a PR is opened that changes files in `apps/` or `packages/`
- **THEN** a preview environment is deployed at `pr-<number>.staging.trails.cool` within 5 minutes
- **AND** a comment is posted on the PR with the preview URL
#### Scenario: Preview updated on PR push
- **WHEN** new commits are pushed to a PR branch with an active preview
- **THEN** the preview containers are rebuilt and redeployed with the latest branch code
#### Scenario: Preview torn down on PR close
- **WHEN** a PR is merged or closed
- **THEN** its preview containers are stopped and removed
- **AND** its database (`trails_pr_<number>`) is dropped
#### Scenario: Preview database isolation
- **WHEN** a PR preview is running
- **THEN** it uses a dedicated database `trails_pr_<number>` with schema applied via Drizzle Kit push
### Requirement: PR preview cleanup
A scheduled cleanup job SHALL remove orphaned preview resources from closed PRs.
#### Scenario: Stale preview cleanup
- **WHEN** the cleanup job runs
- **THEN** any preview containers or databases belonging to closed/merged PRs are removed
### Requirement: Resource limits
Staging and preview containers SHALL have resource limits to protect production.
#### Scenario: Memory limits enforced
- **WHEN** a staging or preview container is running
- **THEN** it has a memory limit of 256MB per app container
#### Scenario: Concurrent preview limit
- **WHEN** more than 3 PR previews are active
- **THEN** the oldest preview is torn down before the new one is created