CI/CD & Release Management
This page sets the global rules for how we build, test, tag, and ship Otherwhere from a single monorepo. It complements:
Objectives
- Speed with safety. Every change runs fast checks; blocker issues stop deploys early.
- Independent surfaces, shared truth. Docs, Server, Mobile release separately, but share types (DTOs), error codes, and OpenAPI.
- Predictable rollbacks. Every release has a simple, documented undo path.
Environments & Branching
| Env | Source | Purpose |
|---|---|---|
| Local | dev machines | Fast iteration, full stack locally (docker-compose) |
| Preview | PR branches | Auto previews for docs; optional server staging |
| Staging | main (gated) | Smoke tests + manual QA |
| Prod | main tags | Live users |
Branching model: trunk-based. Short-lived feature branches → PR → main. Tags cut per surface.
Versioning & Tagging
We version per surface (independent cadence):
- Server:
server-vMAJOR.MINOR.PATCH(e.g.,server-v0.5.1) - Mobile (iOS):
mobile-vMAJOR.MINOR.PATCH(paired with CFBundleShortVersion) - Docs: date-based or semver (e.g.,
docs-2025-01-12)
Use Conventional Commits to auto-generate release notes. Optionally manage via Changesets if we publish packages later.
Pipelines (global policy)
All pipelines follow the same stages with surface-specific steps.
Common checks (all surfaces)
- Typecheck: TS strict.
- Lint & format: ESLint + Prettier.
- Unit tests: fast suite (services, utilities).
- Security:
npm audit(low noise), Dependabot weekly. - License policy: denylist for problematic licenses.
Server-specific
- Integration tests: Fastify
inject()routes + minimal WS tests. - OpenAPI: generate from Zod on build; publish artifact.
- Container: Docker build + scan (low/medium warnings allowed, block on high/critical).
- DB migrations: forward‑compatible + idempotent; run before deploy; guard rails (readiness probe, p95 watch).
Mobile-specific
- Detox/unit: light unit tests + lint.
- EAS build: production profile; submit to TestFlight for
main. - Version bump: auto if
feat:commits present (Changesets optional).
Docs-specific
- Build Docusaurus: link checks off; mermaid enabled.
- Preview: PR previews for reviewer sign‑off.
Gates & Policies
Hard gates (deployment blocks):
- Unit/integration tests failing.
- Server: OpenAPI generation fails or endpoint breaking changes (openapi-diff) without
BREAKING OKlabel. - Security: critical vulnerabilities in container scan.
- Migrations are not idempotent (smoke script fails).
Soft gates (warn, allow override by maintainer):
- p95 latency regression in staging smoke > 20% vs last tag.
- Coverage drop > 2% (server services/tests).
Feature flags
- New capabilities ship flagged off by default.
- Rollout via progressive flags; keep kill switch per module (
story,reveal,intents).
Artifacts & Provenance
- Server: Docker image
ghcr.io/yourorg/otherwhere-server:<git-sha>; SBOM attached if available. - OpenAPI:
server/openapi/openapi.jsonuploaded as build artifact and copied intoapps/docs/static/api/. - Mobile: EAS build link +
.ipamanaged by Expo. - Docs: static
build/directory for Cloudflare Pages.
Each release stores: commit SHA, tag, changelog, artifact URLs, and checksums.
Release Procedures
Server (to Prod)
- Merge to
main→ CI runs tests/builds image. - Run migrations against prod DB (idempotent).
- Deploy image → health checks (readiness + p95 guard).
- Flip feature flags if applicable.
- Tag
server-vX.Y.Z; publish release notes.
Rollback: redeploy previous image tag; if migration had data changes, run safe down script (only if pre‑approved) or toggle flags off.
Mobile (to TestFlight)
- Merge to
main→ EAS build and submit. - Internal testers verify smoke (sign‑in, feed load, story start).
- Promote build to external/TestFlight testers; later, App Store release.
Rollback: revert build channel to previous release; increment hotfix version if needed.
Docs (to Pages)
- On changes to
apps/docs/**, build and publish (Direct Git or GH Action). - PRs always publish preview URLs for review.
Rollback: choose previous Pages build; instant.
Path‑filtered Workflows (summary)
| Change path | Pipeline | Target |
|---|---|---|
apps/docs/** | Docs Pages | Cloudflare Pages |
server/**, packages/shared-types/** | Server container | Fly/Render/ECS (prod) |
apps/mobile/**, packages/shared-types/** | Mobile iOS (EAS) | TestFlight |
Example: Monorepo CI Overview (Mermaid)
Secrets & Config
- Secret source: Doppler/SSM/1Password; injected via CI env vars.
- Do not commit secrets. Provide
.env.exampleonly. - Config parsing: Zod in
server/src/config/env.ts(fail‑fast, human errors surfaced early).
Observability & Post‑deploy
- Logs: Pino JSON + request ID; redact PII.
- Metrics: HTTP p95/p99, queue depth, job failure rate, WS connections; dashboards in Grafana/Metabase.
- Tracing: OTEL spans around request lifecycle, S3 I/O, BullMQ jobs.
- Post‑deploy smoke:
server/scripts/smoke.tscreates user → avatar job → story start → intent propose → WS ping.
Checklists
PR checklist
- Zod schemas updated (and OpenAPI regenerates)
- Unit/integration tests updated
- Telemetry events added
- Docs updated (if endpoints/flows changed)
- Feature flags default set
- Rollback plan noted
Release checklist (server)
- Migrations safe & applied
- Health checks green
- Flags adjusted
- Tag created + notes published
Release checklist (mobile)
- Build passes, installs on 2 devices
- Sign‑in, feed, story, WS smoke pass
- Testers notified
FAQ
Q: Why independent versions?
A: Server and Mobile ship at different cadences; tags track each safely. Shared DTOs sit in packages/shared-types and are validated by OpenAPI.
Q: What about Android?
A: Mirror the iOS pipeline (EAS Android) under a separate path filter when we open that target.
Q: Can we pause all deploys fast?
A: Yes—set repo‑wide required status checks to "failed" via a temporary CI job or flip a global DEPLOY_BLOCK=true in CI context.