Deployment Flow
This page describes the CI/CD pipeline and deployment strategy for peppercheck.
Branch Strategy
peppercheck uses a Release Branch Model:
main (always latest, no deploy on push)
|
+-- beta/v0.3 (cut from main when release is near)
| +-- push -> auto-deploy to all beta environments
| +-- v0.3.0 tag -> auto-deploy to all production environments
|
+-- hotfix flow:
1. fix PR -> main (squash merge)
2. cherry-pick to beta/v0.3
3. v0.3.1 tag on beta/v0.3
Trigger Mapping
| Trigger | Condition | Action |
|---|---|---|
PR to |
|
Flutter analyze + test |
PR to |
|
Supabase DB test + data check + dry-run |
PR to |
|
Webapp type-check + lint + prettier |
Push to |
always |
Deploy all components to beta |
|
always |
Deploy all components to production |
Deploy Order
-
Supabase DB migrations (
supabase db push) -
Supabase Edge Functions (
supabase functions deploy --use-api) -
Flutter Android build + distribute (parallel, after Supabase)
-
Webapp deploy via Cloudflare Workers (parallel, after Supabase)
DB migrations run first because Edge Functions and apps may depend on schema changes.
Supabase Deployment
Environments
| Environment | Project | Trigger |
|---|---|---|
Local |
|
manual |
Beta |
beta Supabase project |
Push to |
Production |
production Supabase project |
|
Deploy Steps
supabase link --project-ref $PROJECT_ID # connect to target project
supabase db push # apply pending migrations
supabase functions deploy --use-api # deploy all Edge Functions
The --use-api flag eliminates Docker dependency for faster CI deploys.
Edge Function Secrets
Runtime secrets are set per environment via CLI (managed manually, not via CI/CD):
supabase secrets set --project-ref <id> --env-file .env.beta
supabase secrets set --project-ref <id> --env-file .env.production
Production Safety
-
Beta environment is always deployed and validated first
-
supabase db push --dry-runruns in PR CI for migration changes -
Migrations use
IF EXISTS/IF NOT EXISTSguards -
Large table changes set
SET lock_timeout = '10s' -
Destructive changes are done in 2 phases across releases
-
Rollback is forward-only: create a new "undo" migration
Flutter Android Deployment
Environments
| Environment | Build | Entry Point | Distribution |
|---|---|---|---|
Beta |
APK (release) |
|
Firebase App Distribution |
Production |
AAB (release) |
|
Google Play Store (future) |
Build Environment
-
Runner:
ubuntu-latest(1x minute rate) -
Java: Temurin 17
-
Flutter: 3.38.3 (stable)
-
Caching: Flutter SDK + pub packages + Gradle
Webapp Deployment (Cloudflare Workers)
Workflow Files
.github/workflows/
├── ci-flutter.yml # PR: Flutter analyze + test
├── ci-supabase.yml # PR: DB test + data check + dry-run
├── ci-webapp.yml # PR: type-check + lint + prettier
├── deploy-beta.yml # beta/v* push: all components to beta
└── deploy-production.yml # v* tag: all components to production
Required GitHub Secrets
| Secret | Purpose |
|---|---|
|
Supabase CLI authentication |
|
Beta Supabase project ref |
|
Beta DB password |
|
Production Supabase project ref |
|
Production DB password |
|
Base64-encoded Android keystore |
|
Keystore store password |
|
Key password |
|
Key alias |
|
Firebase App ID |
|
Firebase service account JSON |
|
Cloudflare API token |
|
Cloudflare account ID |