Skip to main content

CI/CD Pipeline

CI/CD Pipeline

Project: Drop Version: 0.1.0 Date: 2026-02-23 Author: Platform Architect (AI) Status: In Review Reviewers: Alem Bašić (CEO)

Document History

Version Date Author Changes
0.1 2026-02-23 Platform Architect (AI) Initial draft from source code analysis

1. Overview

Drop uses GitHub Actions for CI with a 5-job pipeline covering lint, typecheck, unit tests, E2E tests, and Docker build. The CD (automated deployment) pipeline to AWS App Runner is tracked as a pending item — currently CI builds but does not deploy automatically. Staging deployment is manual via fly deploy to Fly.io (Stockholm).

CI/CD Platform: GitHub Actions (.github/workflows/ci.yml) Container Registry: AWS ECR (324480209768.dkr.ecr.eu-west-1.amazonaws.com/drop-web) Deployment Target (production): AWS App Runner (eu-west-1) Deployment Target (staging): Fly.io (Stockholm, region arn) Strategy: Rolling (App Runner managed)


2. Pipeline Overview

flowchart LR
    subgraph Source
        PR[Pull Request\nto main/master]
        MERGE[Push to\nmain/master]
    end

    subgraph CI ["CI — runs on every push/PR"]
        LINT[1. lint-and-typecheck\nnpm run lint\ntsc --noEmit]
        TEST[2. test\nvitest run]
        BUILD[3. build\nnext build]
        E2E[4. e2e\nPlaywright\nuser-flows + full-flows]
        DOCKER[5. docker-build\ndocker build -t drop-app:ci]
    end

    subgraph CD_STG ["CD Staging — manual"]
        STG[fly deploy\nFly.io Stockholm]
    end

    subgraph CD_PROD ["CD Production — pending implementation"]
        APPROVAL[Manual Approval\nvia GitHub Environments]
        PROD[aws apprunner\nstart-deployment]
    end

    PR --> LINT
    MERGE --> LINT
    LINT --> TEST
    LINT --> BUILD
    TEST --> E2E
    BUILD --> E2E
    E2E --> DOCKER
    DOCKER --> STG
    DOCKER --> APPROVAL
    APPROVAL --> PROD

3. Source Control Configuration

3.1 Branching Strategy

Strategy: GitHub Flow (feature branches off main, PR into main)

Branch Purpose Naming Convention Lifetime
main Production-ready code fixed Permanent
feature/* New features feature/description Until merged
fix/* Bug fixes fix/description Until merged
hotfix/* Production hotfixes hotfix/description Until merged

3.2 Branch Protection Rules

Protected Branches: main

Rule main
Require PR Yes
Required approvals 1 (Alem Bašić)
Dismiss stale reviews Yes
Require status checks Yes
Required checks lint-and-typecheck, test, build, e2e, docker-build
Require up-to-date Yes
Allow force push No
Allow deletions No

3.3 Code Review Requirements

  • Minimum 1 approval required before merge
  • At least one approval from Alem Bašić (or delegated lead)
  • All review comments must be resolved before merge
  • Review turnaround SLA: 24 business hours

4. Build Stage

4.1 Build Tool & Configuration

Parameter Value
Build Tool npm (Node.js 22)
Install Command npm ci (requires python3, make, g++ for better-sqlite3 native deps)
Build Command npm run build (Next.js standalone output)
Artifact Type Docker image (multi-stage: deps → builder → runner)
Artifact Naming 324480209768.dkr.ecr.eu-west-1.amazonaws.com/drop-web:<git-sha>
Tag Strategy git-sha for CI builds, semantic version for releases
Base Image node:22-alpine
Production Image User nextjs (UID 1001, non-root)

Multi-stage build:

Stage 1: deps     — npm ci + native dependencies
Stage 2: builder  — npm run build (Next.js standalone)
Stage 3: runner   — minimal image, copies only public/ + .next/standalone/ + .next/static/

4.2 Dependency Caching

Cache Key Restore Keys
Node modules node-modules-linux-${{ hashFiles('package-lock.json') }} node-modules-linux-
Docker build layers BuildKit layer cache via cache-from: type=gha

4.3 Artifact Generation

Artifact Storage Retention Signed
Docker image AWS ECR drop-web repository 90 days (non-prod tags), Forever (release tags) No (planned)
Playwright HTML report GitHub Actions artifact playwright-report/ 7 days No
QA report (qa-report.html) GitHub Actions artifact 7 days No

5. Test Stages

5.1 Unit Tests

Parameter Value
Framework Vitest 4.0.18
Command npm test (runs vitest run)
Test files tests/**/*.test.ts
Setup tests/setup.ts — sets NODE_ENV=test, in-memory databases
Coverage Tool TBD — not yet configured
Coverage Gate TBD — requires coverage configuration
Failure Action Block PR merge (CI job 2 test must pass)

5.2 Integration Tests

Parameter Value
Framework Vitest (same runner as unit tests)
Command npm test
Dependencies SQLite in-memory (no external services needed)
Failure Action Block PR merge

5.3 E2E Tests

Parameter Value
Framework Playwright 1.58.2
Command npx playwright test user-flows full-flows
Browser Chromium only (installed in CI via npx playwright install chromium)
Environment Production build running locally (npm run build && npm run start)
Parallelization 1 worker (serial — rate limiter is shared state)
Retries 2 (CI)
Timeout 30,000ms
Base URL http://localhost:3000
Test suites user-flows.spec.ts, full-flows.spec.ts, input-chaos.spec.ts (depends on user-flows)
Artifacts Playwright HTML report + qa-report.html uploaded to GitHub Actions
Failure Action Block docker-build job

5.4 Security Scanning

Scan Type Tool Status Gate
SAST TBD — not yet implemented Pending Block on HIGH/CRITICAL
SCA (dependencies) npm audit — not yet in CI Pending Block on CRITICAL
Container scan TBD (Trivy planned) Pending Block on CRITICAL
Secret scanning GitHub native secret scanning Enabled via GitHub Block on any finding

Note: Security scanning tracked in security/hardening-checklist.md. npm audit and Snyk integration are pending.

5.5 Linting & Formatting

Tool Purpose Command Auto-fix
ESLint 9 Code linting npm run lint PR comment
TypeScript 5 Type checking npx tsc --noEmit No

6. Deploy Stages

6.1 Deployment Strategy

Strategy: Rolling (App Runner managed)

App Runner handles deployment atomically — new container version deployed, health checks verified, traffic shifted. No blue-green or canary at this stage.

App Runner Deployment:

  • Trigger: aws apprunner start-deployment (currently manual)
  • Health check: GET /api/health every 30s
  • Auto-rollback: App Runner reverts if new deployment fails health checks
  • Deployment time: ~3-5 minutes

Staging (Fly.io) Deployment:

  • Command: fly deploy (manual)
  • Region: arn (Stockholm)
  • Auto-scale: Scales to 0 when idle, auto-starts on request

6.2 Environment Promotion

PR Branch → CI (auto) → Staging (manual fly deploy) → Production (manual apprunner start-deployment)
Promotion Trigger Gate Approver
→ Staging Manual All CI checks pass Alem Bašić
→ Production Manual All CI + staging verification Alem Bašić

6.3 Approval Gates

Production Approval Required: Yes (manual) Approvers: Alem Bašić (sole approver during MVP phase) Approval Window: No automated timeout (manual process) Emergency Override: Direct aws apprunner start-deployment via AWS Console (Alem only)

6.4 Feature Flags Integration

Feature Flag Tool: Environment variables (build-time via Next.js NEXT_PUBLIC_FF_* pattern)

Flag Dev Staging Production
NEXT_PUBLIC_FF_VIRTUAL_CARDS false false false
NEXT_PUBLIC_FF_PHYSICAL_CARDS false false false
NEXT_PUBLIC_FF_CARD_DETAILS false false false
NEXT_PUBLIC_FF_CARD_FREEZE false false false
NEXT_PUBLIC_FF_CARD_PIN false false false
NEXT_PUBLIC_FF_SPENDING_LIMITS false false false
NEXT_PUBLIC_FF_NOTIFICATIONS true true true
NEXT_PUBLIC_FF_MERCHANT_DASHBOARD true true true

Note: Flags are baked in at build time by Next.js. Changing a flag requires a new build and deployment.


7. Post-Deploy

7.1 Smoke Tests

Check Expected Timeout
Health endpoint GET /api/health HTTP 200, "status":"ok" 10s
DB connectivity (via health endpoint) "db": {"status":"pass"} 15s
Auth endpoint GET /api/auth/me HTTP 401 (no cookie) 10s
Landing page HTTP 200 10s

Smoke test timeout: 2 min total On failure: Manual rollback via App Runner console (revert to previous deployment)

7.2 Monitoring Verification

After each deployment, verify via BetterStack and Slack:

Metric Threshold Check Duration
BetterStack health monitor UP 5 min post-deploy
Error spike detection No alerts in Slack #drop-ops 10 min post-deploy
App Runner service status RUNNING Immediate
RDS connection Healthy (via /api/health) Immediate

7.3 Rollback Triggers

Automatic rollback triggers:

  • App Runner health check failure during deployment (App Runner native)
  • BetterStack detects downtime → Slack alert → manual investigation

Manual rollback:

# Rollback via AWS CLI (revert to previous ECR image)
aws apprunner start-deployment \
  --service-arn arn:aws:apprunner:eu-west-1:324480209768:service/drop-web/8e45b0d335304487a1880f4e32d6aeec \
  --region eu-west-1

8. Pipeline Configuration Reference

Config File Location: .github/workflows/ci.yml

Key environment variables injected by CI:

Variable Source Purpose
JWT_SECRET GitHub Actions Secret Build-time placeholder (required by Next.js build)
AWS_ROLE_ARN GitHub Actions Secret OIDC role for ECR push and App Runner deploy
SLACK_WEBHOOK GitHub Actions Secret Build notifications

9. Secret Injection Strategy

Strategy: GitHub Actions Secrets for CI variables; AWS Secrets Manager for runtime application secrets.

Secret Type Storage Injection Method Rotation
Registry credentials (ECR) GitHub OIDC + AWS IAM OIDC token → assumed role Per-job (ephemeral)
App secrets (JWT_SECRET, DATABASE_URL) AWS Secrets Manager App Runner environment from Secrets Manager 90 days
Slack webhook GitHub Actions Secret Env var injection On compromise

OIDC Preferred: GitHub Actions uses OIDC to assume AWS IAM role — no long-lived AWS keys stored in GitHub.


10. Pipeline Metrics

Metric Target Current
Build duration (P50) < 5 min TBD
E2E test duration (P50) < 10 min TBD
Total pipeline duration < 20 min TBD
Deploy frequency On-demand TBD
Lead time for changes < 1 hour TBD
Change failure rate < 10% TBD
MTTR < 30 min TBD


Approval

Role Name Date Signature
Author Platform Architect (AI) 2026-02-23
Reviewer
Approver Alem Bašić