Skip to main content

CI/CD Pipeline

CI/CD Pipeline

Project: {{PROJECT_NAME}}Drop Version: {{VERSION}}0.1.0 Date: {{DATE}}2026-02-23 Author: {{AUTHOR}}Platform Architect (AI) Status: Draft | In Review | Approved Reviewers: {{REVIEWERS}}Alem Bašić (CEO)

Document History

Version Date Author Changes
0.1 {{DATE}}2026-02-23 {{AUTHOR}}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: {{PLATFORM}}GitHub Actions (.github/workflows/ci.yml) Container Registry: {{REGISTRY}}AWS ECR (324480209768.dkr.ecr.eu-west-1.amazonaws.com/drop-web) Deployment Target:Target (production): {{DEPLOY_TARGET}}AWS App Runner (eu-west-1) Deployment Target (staging): Fly.io (Stockholm, region arn) Strategy: {{STRATEGY}}Rolling (App Runner managed)


2. Pipeline Overview

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

    subgraph CI[CI ["CI — runs on every push/PR"]
        LINT[Lint1. &lint-and-typecheck\nnpm Format]run TEST_UNIT[Unitlint\ntsc Tests]--noEmit]
        TEST_INT[IntegrationTEST[2. Tests]test\nvitest SAST[SAST Scan]
        SCA[Dependency Scan]run]
        BUILD[Build3. Artifact]build\nnext build]
        E2E[4. e2e\nPlaywright\nuser-flows + full-flows]
        DOCKER[5. docker-build\ndocker build -t drop-app:ci]
    end

    subgraph CD_DEV[CD_STG ["CD Staging Dev Auto-Deploy"manual"]
        DEPLOY_DEV[DeploySTG[fly todeploy\nFly.io Dev]
        SMOKE_DEV[Smoke Tests]Stockholm]
    end

    subgraph CD_STAGING[CD_PROD ["CD — Staging (auto on main)"]
        DEPLOY_STG[Deploy to Staging]
        TEST_E2E[E2E Tests]
        PERF[Performance Tests]
    end

    subgraph CD_PROD["CDProductionProductionpending (manual gate)"implementation"]
        APPROVAL[Manual Approval]Approval\nvia DEPLOY_PROD[DeployGitHub toEnvironments]
        Production]PROD[aws SMOKE_PROD[Smoke Tests]
        MONITOR[Verify Monitoring]apprunner\nstart-deployment]
    end

    PR --> LINT
    MERGE --> LINT
    LINT --> TEST_UNITTEST
    TEST_UNIT --> TEST_INT
    TEST_INT --> SAST
    SAST --> SCA
    SCALINT --> BUILD
    MERGETEST --> CD_DEVE2E
    BUILD --> DEPLOY_DEVE2E
    DEPLOY_DEVE2E --> SMOKE_DEVDOCKER
    SMOKE_DEVDOCKER --> DEPLOY_STGSTG
    DEPLOY_STG --> TEST_E2E
    TEST_E2E --> PERF
    PERFDOCKER --> APPROVAL
    APPROVAL --> DEPLOY_PROD
    DEPLOY_PROD --> SMOKE_PROD
    SMOKE_PROD --> MONITORPROD

3. Source Control Configuration

3.1 Branching Strategy

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

Branch Purpose Naming Convention Lifetime
main Production-ready code fixed Permanent
developIntegration branchfixedPermanent
feature/* New features feature/{{TICKET}}-description Until merged
fix/* Bug fixes fix/{{TICKET}}-description Until merged
hotfix/* Production hotfixes hotfix/{{TICKET}}-descriptionUntil merged
release/*Release preparationrelease/v{{VERSION}} Until merged

3.2 Branch Protection Rules

Protected Branches: main, develop

1 e2e,
Rule maindevelop
Require PR Yes Yes
Required approvals {{APPROVALS}} 1(Alem Bašić)
Dismiss stale reviewsYes Yes
Require status checks Yes Yes
Required checks lint,lint-and-typecheck, unit-tests,test, integration-tests,build, sast lint, unit-testsdocker-build
Require up-to-date Yes No
Allow force push No No
Allow deletionsNo No

3.3 Code Review Requirements

  • Minimum {{APPROVALS}}1 approval(s)approval required before merge
  • At least one approval from aAlem code ownerBašić (seeor CODEOWNERS)delegated lead)
  • All review comments must be resolved before merge
  • Review turnaround SLA: {{REVIEW_SLA}}24 business hours
  • Auto-assign reviewers via: {{ASSIGN_MECHANISM}}

4. Build Stage

4.1 Build Tool & Configuration

Parameter Value
Build Tool {{BUILD_TOOL}}npm (Node.js 22)
Install Commandnpm ci (requires python3, make, g++ for better-sqlite3 native deps)
Build Command {{BUILD_CMD}}npm run build (Next.js standalone output)
Artifact Type {{ARTIFACT}}Docker image (multi-stage: deps → builder → runner)
Artifact Naming {{REGISTRY}}/{{IMAGE_NAME}}:{{TAG_STRATEGY}}324480209768.dkr.ecr.eu-west-1.amazonaws.com/drop-web:<git-sha>
Tag Strategy git-sha for PRs,CI semverbuilds, semantic version for releases
Base Imagenode:22-alpine
Production Image Usernextjs (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-${{OS} hashFiles('package-lock.json') }-{{LOCKFILE_HASH}} node-modules-{{OS}}-linux-
Docker build layers BuildKit layer cache via buildx-{{DOCKERFILE_HASH}}cache-from: type=gha buildx-
Test resultstest-results-{{COMMIT_SHA}}N/A

4.3 Artifact Generation

Artifact Storage Retention Signed
Docker image {{REGISTRY}}AWS ECR drop-web repository 90 days (non-prod)prod tags), Forever (prodrelease tags) {{SIGNING}}No (planned)
TestPlaywright reportsHTML report CIGitHub Actions artifact storageplaywright-report/ 307 days No
SBOMQA report (qa-report.html) {{SBOM_STORAGE}}GitHub Actions artifact 1 yearYes
Coverage report{{COVERAGE_STORAGE}}307 days No

5. Test Stages

5.1 Unit Tests

Parameter Value
Framework {{UNIT_FRAMEWORK}}Vitest 4.0.18
Command {{UNIT_CMD}}npm test (runs vitest run)
Test filestests/**/*.test.ts
Setuptests/setup.ts — sets NODE_ENV=test, in-memory databases
Coverage Tool {{COVERAGE_TOOL}}TBD — not yet configured
Coverage Gate TBD {{COVERAGE_GATE}}% lines,requires coverage {{BRANCH_GATE}}% branchesconfiguration
Failure Action Block PR merge (CI job 2 test must pass)

5.2 Integration Tests

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

5.3 E2E Tests

Parameter Value
Framework {{E2E_FRAMEWORK}}Playwright 1.58.2
Command {{E2E_CMD}}npx playwright test user-flows full-flows
BrowserChromium only (installed in CI via npx playwright install chromium)
Environment StagingProduction build running locally (npm run build && npm run start)
Parallelization {{E2E_SHARDS}}1 shardsworker (serial — rate limiter is shared state)
Retries2 (CI)
Timeout30,000ms
Base URLhttp://localhost:3000
Test suitesuser-flows.spec.ts, full-flows.spec.ts, input-chaos.spec.ts (depends on user-flows)
ArtifactsPlaywright HTML report + qa-report.html uploaded to GitHub Actions
Failure Action Block stagingdocker-build promotionjob

5.4 Security Scanning

Scan Type Tool CommandStatus Gate
SAST {{SAST_TOOL}}TBD — not yet implemented {{SAST_CMD}}Pending Block on HIGH/CRITICAL
SCA (dependencies) {{SCA_TOOL}}npm audit — not yet in CI {{SCA_CMD}}Pending Block on CRITICAL
Container scan {{CONTAINER_SCAN}}TBD (Trivy planned) {{CONTAINER_SCAN_CMD}}Pending Block on CRITICAL
Secret scanning {{SECRET_SCAN}}GitHub native secret scanning {{SECRET_SCAN_CMD}}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

TypeScript
Tool Purpose Command Auto-fix
{{LINTER}}ESLint 9 Code linting {{LINT_CMD}}npm run lint PR comment
{{FORMATTER}} Code formatting{{FMT_CMD}}Auto-commit or fail
{{TYPE_CHECK}}5 Type checking {{TYPE_CMD}}npx tsc --noEmit No

6. Deploy Stages

6.1 Deployment Strategy

Strategy: {{DEPLOY_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.

RollingApp Runner Deployment:

  • BatchTrigger: size:aws {{BATCH_SIZE}}%apprunner ofstart-deployment instances
  • (currently
  • Pause between batches: {{PAUSE}}minmanual)
  • Health checkcheck: wait:GET {{HEALTH_WAIT}}s/api/health every 30s
  • RollbackAuto-rollback: trigger:App Runner reverts if new deployment fails health checkchecks
  • failure
  • Deployment time: ~3-5 minutes

Canary DeploymentStaging (ifFly.io) used):Deployment:

  • InitialCommand: canaryfly weight:deploy {{CANARY_INITIAL}}%(manual)
  • Increment:Region: {{CANARY_INCREMENT}}%arn every {{CANARY_INTERVAL}}min(Stockholm)
  • PromotionAuto-scale: criteria:Scales errorto rate0 <when {{ERROR_THRESHOLD}}%,idle, p99 < {{LATENCY_THRESHOLD}}ms
  • Rollback trigger: automaticauto-starts on threshold breachrequest

6.2 Environment Promotion

PR Branch → DevCI (auto) → Staging (automanual onfly main merge)deploy) → Production (manual approval)apprunner start-deployment)
Alem
Promotion Trigger Gate Approver
DevStaging Merge to develop / PRManual All CI checks pass Automatic
→ StagingMerge to mainAll CI + Dev smoke testsAutomaticBašić
→ Production Tag v*.*.*Manual All testsCI + manualstaging approvalverification {{PROD_APPROVER}}Alem Bašić

6.3 Approval Gates

Production Approval Required: Yes (manual) Approvers: {{PROD_APPROVERS}}Alem Bašić (atsole leastapprover {{APPROVAL_COUNT}}during required)MVP phase) Approval Window: {{APPROVAL_WINDOW}}hNo automated timeout (pipelinemanual cancels after timeout)process) Emergency Override: {{EMERGENCY_OVERRIDE}}Direct aws apprunner start-deployment via AWS Console (Alem only)

6.4 Feature Flags Integration

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

FlagDevStagingProduction
NEXT_PUBLIC_FF_VIRTUAL_CARDSfalsefalsefalse
NEXT_PUBLIC_FF_PHYSICAL_CARDSfalsefalsefalse
NEXT_PUBLIC_FF_CARD_DETAILSfalsefalsefalse
NEXT_PUBLIC_FF_CARD_FREEZEfalsefalsefalse
NEXT_PUBLIC_FF_CARD_PINfalsefalsefalse
NEXT_PUBLIC_FF_SPENDING_LIMITSfalsefalsefalse
NEXT_PUBLIC_FF_NOTIFICATIONStruetruetrue
NEXT_PUBLIC_FF_MERCHANT_DASHBOARDtruetruetrue

Flag Validation:Note: FeatureFlags flagsare validatedbaked in stagingat beforebuild productiontime deployby KillNext.js. Switch:Changing Alla flag requires a new featuresbuild behindand flags for first {{FF_PERIOD}} daysdeployment.


7. Post-Deploy

7.1 Smoke Tests

HTTP
Check Expected Timeout
Health endpoint GET /api/health HTTP 200200, "status":"ok" 10s
DB connectivity (via health endpoint)"db": {"status":"pass"}15s
Auth endpoint reachableGET /api/auth/me HTTP 401 (no cookie) 10s
DatabaseLanding connectionpage Healthy 15s
Cache connectionHealthy200 10s
Critical user journeySuccess60s

Smoke test timeout: {{SMOKE_TIMEOUT}}2 min total On failure: Auto-Manual rollback triggeredvia App Runner console (revert to previous deployment)

7.2 Monitoring Verification

After each deployment, verify via BetterStack and Slack:

Metric Threshold Check Duration
ErrorBetterStack ratehealth monitor < {{ERROR_RATE}}%UP 5 min post-deploy
P99Error latencyspike detection <No {{P99}}msalerts in Slack #drop-ops 510 min post-deploy
CPUApp utilizationRunner service status < {{CPU}}%RUNNING 5 minImmediate
MemoryRDS utilizationconnection <Healthy {{MEM}}%(via /api/health) 5 minImmediate

7.3 Rollback Triggers

Automatic rollback triggers:

  • SmokeApp testRunner failure
  • Error rate > {{AUTO_ROLLBACK_ERROR}}% for {{AUTO_ROLLBACK_DURATION}}min post-deploy
  • Healthhealth check failure onduring {{HEALTH_FAIL_THRESHOLD}}%deployment of(App instancesRunner native)
  • BetterStack detects downtime → Slack alert → manual investigation

Manual rollback:

See
# rollback-plan.md

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: {{CONFIG_PATH}} .github/workflows/ci.yml

Key environment variables injected by CI:

roleforECRpushand
Variable Source Purpose
REGISTRY_TOKENJWT_SECRET {{SECRET_STORE}}GitHub Actions Secret ContainerBuild-time registryplaceholder auth(required by Next.js build)
DEPLOY_KEYAWS_ROLE_ARN {{SECRET_STORE}}GitHub Actions Secret DeploymentOIDC credentials
SENTRY_DSN {{SECRET_STORE}} ErrorApp trackingRunner deploy
SLACK_WEBHOOK {{SECRET_STORE}}GitHub Actions Secret NotificationsBuild notifications

9. Secret Injection Strategy

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

GitHubOIDC+AWS
Secret Type Storage Injection Method Rotation
Registry credentials (ECR) {{STORAGE}} {{METHOD}} {{ROTATION}}
Cloud credentials{{STORAGE}}IAM OIDC /token Workload Identityassumed role Per-job (ephemeral)
App secrets (JWT_SECRET, DATABASE_URL) {{STORAGE}}AWS Secrets Manager {{METHOD}}App Runner environment from Secrets Manager {{ROTATION}}90 days
Slack webhookGitHub Actions SecretEnv var injectionOn compromise

OIDC Preferred: CloudGitHub credentialsActions injected viauses OIDC to assume AWS IAM role — no long-lived AWS keys stored in CIGitHub.


10. Pipeline Metrics

Metric Target Current
Build duration (P50) < {{BUILD_TARGET}}5 min TBD
TestE2E test duration (P50) < {{TEST_TARGET}}10 min TBD
Total pipeline duration < {{TOTAL_TARGET}}20 min TBD
Deploy frequency {{DEPLOY_FREQ}}On-demand TBD
Lead time for changes < {{LEAD_TIME}}1 hour TBD
Change failure rate < {{FAILURE_RATE}}%10% TBD
MTTR < {{MTTR}}30 min TBD


Approval

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