Skip to main content

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

EnvSourcePurpose
Localdev machinesFast iteration, full stack locally (docker-compose)
PreviewPR branchesAuto previews for docs; optional server staging
Stagingmain (gated)Smoke tests + manual QA
Prodmain tagsLive 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 OK label.
  • 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.json uploaded as build artifact and copied into apps/docs/static/api/.
  • Mobile: EAS build link + .ipa managed 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)

  1. Merge to main → CI runs tests/builds image.
  2. Run migrations against prod DB (idempotent).
  3. Deploy image → health checks (readiness + p95 guard).
  4. Flip feature flags if applicable.
  5. 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)

  1. Merge to main → EAS build and submit.
  2. Internal testers verify smoke (sign‑in, feed load, story start).
  3. 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)

  1. On changes to apps/docs/**, build and publish (Direct Git or GH Action).
  2. PRs always publish preview URLs for review.

Rollback: choose previous Pages build; instant.


Path‑filtered Workflows (summary)

Change pathPipelineTarget
apps/docs/**Docs PagesCloudflare Pages
server/**, packages/shared-types/**Server containerFly/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.example only.
  • 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.ts creates 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.