CI/CD Pipeline Guide
Last Updated: 2026-01-14
Status: ✅ Active
Overview
Lantern uses GitHub Actions for continuous integration and continuous deployment (CI/CD). This ensures code quality, automated testing, and streamlined deployments to development and production environments.
Table of Contents
- Implementation Summary
- Workflows
- Branch Strategy
- Environment Variables
- Deployment Process
- Status Checks
- Troubleshooting
- Maintenance
Implementation Summary
What Was Implemented
A complete CI/CD pipeline using GitHub Actions that automates:
- Code Quality Checks - Linting, formatting, building, and testing
- Security Scanning - npm audit and CodeQL vulnerability detection
- Firestore Validation - Ensures indexes are valid before deployment
- Automated Deployments - Deploys to dev and prod environments
- Discord Notifications - Team alerts for deployment status
Files Added
GitHub Actions Workflows (4 files):
.github/workflows/ci.yml- Main CI pipeline (runs on every commit and PR).github/workflows/deploy-dev.yml- Development deployment (triggers ondevbranch).github/workflows/deploy-prod.yml- Production deployment (triggers onmainbranch).github/workflows/codeql.yml- Security scanning (runs on push, PR, and weekly)
Documentation:
docs/engineering/deployment/CICD_GUIDE.md- Complete reference guide (this file)docs/engineering/deployment/CICD_QUICK_SETUP.md- Step-by-step setup checklistdocs/engineering/deployment/BRANCH_PROTECTION_SETUP.md- Branch protection guidedocs/worklog/CICD_IMPLEMENTATION_COMPLETE.md- Implementation worklog entry
Cost Impact
- GitHub Actions: ~300-400 minutes/month (free tier includes 2,000/month)
- Cloudflare Pages: Unlimited deployments on free tier
- Firebase: Rules/indexes deployment is free
- Total Cost: $0
Workflows
1. CI Workflow (.github/workflows/ci.yml)
Triggers:
- Push to
mainordevbranches - Pull requests to
mainordevbranches
Jobs:
Lint
- Runs ESLint on all JavaScript/JSX files
- Checks code formatting with Prettier
- Required to pass for merge
Build
- Builds the web application
- Builds Storybook component library
- Builds VitePress documentation
- Uploads build artifacts for review
- Required to pass for merge
Test
- Runs Vitest unit tests with coverage
- Uploads coverage reports to Codecov
- Required to pass for merge
Security
- Runs
npm auditon main dependencies - Runs
npm auditon Discord bot dependencies - Checks for known vulnerabilities
- Non-blocking but generates warnings
Validate Firestore Indexes
- Validates
firestore.indexes.jsonexists and is valid JSON - Warns about manual index deployment requirements
- Required to pass for merge
All Checks Complete
- Aggregates all job results
- Provides clear pass/fail status
- Required to pass for merge
Concurrency:
Cancels in-progress runs for the same workflow on the same PR/branch to save resources.
2. Deploy to Development (.github/workflows/deploy-dev.yml)
Triggers:
- Automatically after CI workflow completes successfully on
devbranch - Uses
workflow_runtrigger to ensure CI checks pass before deployment
Pre-deployment Checks:
- ✅ CI Success Check: Verifies CI workflow completed successfully
- ❌ Fail if CI Failed: Blocks deployment if CI checks did not pass
- Purpose: Prevents deploying broken, untested, or insecure code
Jobs:
Check CI Success
- Runs only if CI workflow passed all checks
- Gates all deployment jobs
- Required to pass before any deployment occurs
Deploy App
- Builds application with dev Firebase config
- Deploys to Cloudflare Pages (
lantern-app-devproject) - Live URL: dev.ourlantern.app
- Depends on: CI success check
Deploy Storybook
- Builds Storybook component library
- Deploys to Cloudflare Pages (
lantern-storybook-devproject) - Live URL: storybook.dev.ourlantern.app
- Depends on: CI success check
Deploy Docs
- Builds VitePress documentation
- Deploys to Cloudflare Pages (
lantern-docs-devproject) - Live URL: docs.dev.ourlantern.app
- Depends on: CI success check
Deploy Firebase Rules
- Deploys Firestore security rules to
lantern-app-dev - Deploys Firestore indexes to
lantern-app-dev - Deploys Cloud Storage rules to
lantern-app-dev - Depends on: CI success check
Notify Discord
- Sends deployment status to Discord webhook
- Includes deployment results for all services
- Provides direct links to deployed environments
- Critical: If Discord notification fails, the entire deployment fails
- Prevents losing commit notification history
- Ensures audit trail is maintained
- Common failure causes: invalid webhook, character encoding issues
- Deployment can be retried to send the notification
3. Deploy to Production (.github/workflows/deploy-prod.yml)
Triggers:
- Automatically after CI workflow completes successfully on
mainbranch - Manual workflow dispatch (for emergency deployments)
- Uses
workflow_runtrigger to ensure CI checks pass before deployment
Pre-deployment Checks:
- ✅ CI Success Check: Verifies CI workflow completed successfully (automatic deploys only)
- ❌ Fail if CI Failed: Blocks deployment if CI checks did not pass (automatic deploys only)
- ✅ Verify Deployment: Ensures deployment is from
mainbranch only - Purpose: Prevents deploying broken, untested, or insecure code to production
Environment: Uses GitHub production environment with protection rules
Jobs:
Check CI Success
- Runs only if CI workflow passed all checks (automatic deploys)
- Gates all deployment jobs
- Skipped for manual emergency deployments
- Required to pass before any automatic deployment occurs
Verify Deployment
- Ensures deployment is from
mainbranch only - Logs manual deployment triggers
- Depends on: CI success check (for automatic deploys)
Deploy App
- Builds application with production Firebase config
- Deploys to Cloudflare Pages (
lantern-appproject) - Live URL: ourlantern.app
Deploy Storybook
- Builds Storybook component library
- Deploys to Cloudflare Pages (
lantern-storybookproject) - Live URL: storybook.ourlantern.app
Deploy Docs
- Builds VitePress documentation
- Deploys to Cloudflare Pages (
lantern-docsproject) - Live URL: docs.ourlantern.app
Deploy Firebase Rules
- Deploys Firestore security rules to
lantern-app-prod - Deploys Firestore indexes to
lantern-app-prod - Deploys Cloud Storage rules to
lantern-app-prod
Notify Discord
- Sends deployment status to Discord webhook
- Critical: If Discord notification fails, the entire deployment fails
- Prevents losing commit notification history
- Ensures audit trail is maintained
- Common failure causes: invalid webhook, character encoding issues
- Deployment can be retried to send the notification
- Alerts team on deployment failures with exit code 1
4. CodeQL Security Scan (.github/workflows/codeql.yml)
Triggers:
- Push to
mainordevbranches - Pull requests to
mainordevbranches - Scheduled: Every Monday at 6:30 AM UTC
Jobs:
Analyze Code
- Scans JavaScript/JSX code for security vulnerabilities
- Uses
security-extendedandsecurity-and-qualityquery suites - Uploads results to GitHub Security tab
- Non-blocking but generates alerts for review
Permissions:
Requires security-events: write to upload scan results
5. Discord Notification (.github/workflows/discord-notify.yml)
Triggers:
- Push to
mainordevbranches
Jobs:
Notify
- Sends commit notifications to Discord
- Includes commit messages, authors, and links
- Color-coded by branch (main = green, dev = blue)
- Smart recovery: Tracks posted commits and automatically retries missed ones on next push
- If notification fails, commit is logged for retry
- Next push includes any previously failed commits
- Ensures complete audit trail even if Discord is temporarily down
How missed commit recovery works:
- Each successful Discord notification is recorded
- If notification fails, commit is marked for retry
- Next successful push automatically includes missed commits with a note
- You'll never lose commit history even if Discord API is temporarily down
CI/CD Workflow Dependencies
How Deployments Depend on CI
To prevent deploying broken code, our deployment workflows use GitHub's workflow_run trigger:
Flow:
Push to dev/main
↓
CI Workflow runs (lint, build, test, security, indexes)
↓
├─ ✅ CI Passes → Deployment workflow triggers
│ └─ Check CI Success job gates deployment
│ └─ All deployment jobs proceed
│
└─ ❌ CI Fails → Deployment workflow triggers
└─ Fail if CI Failed job runs
└─ Deployment blocked with exit 1Key Benefits:
- Zero risk of deploying untested code: Deployments only occur after all CI checks pass
- Automatic blocking: No manual intervention needed; failed CI = no deployment
- Clear feedback: Deployment logs show exactly why deployment was blocked
- Emergency override: Manual deployments can bypass CI (use with extreme caution)
Technical Implementation:
- Deployment workflows use
on: workflow_runinstead ofon: push workflows: ["CI"]specifies dependency on CI workflowtypes: [completed]triggers after CI finishes (success or failure)if: github.event.workflow_run.conclusion == 'success'gates deployment jobs- Failed CI causes
fail-if-ci-failedjob to exit with code 1
Important Notes:
- Automatic deploys: CI must pass before deployment runs
- Manual deploys (prod only): Can bypass CI check for emergencies
- Both dev and prod: Protected against deploying broken code
- Cloudflare Pages: While Cloudflare may auto-deploy on push, our GitHub Actions workflow enforces the CI gate before triggering deployment
Cloudflare Pages Configuration
Automatic Deployment Settings
⚠️ CRITICAL: Cloudflare Pages must be configured to disable automatic deployments and instead rely on GitHub Actions workflow triggers.
Why? Cloudflare's automatic deployment feature watches for push events directly and deploys immediately, bypassing our CI/CD gates. This means broken code could be deployed to production without passing tests.
Setup Instructions
For both lantern-app-dev and lantern-app-prod projects:
Go to Cloudflare Pages project settings
- Navigate to Cloudflare Dashboard
- Select your project (e.g.,
lantern-app-dev) - Click Settings → Builds & deployments
Disable Automatic Deployments
- Under "Automatic deployments," toggle OFF
- This prevents Cloudflare from auto-deploying on every push
Verify GitHub Integration is Active
- Ensure the GitHub integration shows your repository is connected
- GitHub Actions workflows will now trigger deployments after CI passes
Result
After disabling automatic deployments:
- ✅ Push to
dev→ CI workflow runs - ✅ CI completes → Deployment workflow triggers (via
workflow_run) - ✅ Deployment gates check CI status
- ✅ Only if CI passed: Cloudflare deployment proceeds via GitHub Actions
- ❌ If CI failed: Deployment is blocked automatically
This ensures zero risk of deploying untested code.
Troubleshooting Cloudflare Deployments
If deployments aren't triggering after disabling automatic deployments:
- Verify GitHub integration is still active - Go to project settings and confirm the connection
- Check workflow run logs - Look at
.github/workflows/deploy-dev.ymlexecution - Confirm CI workflow completed - The deployment workflow only triggers after CI finishes
- Check branch name - Deployments only trigger on
devandmainbranches
Branch Strategy
main (production)
↑
└── dev (development/staging)
↑
└── feature/my-feature
└── fix/bug-fix
└── copilot/ai-featureRules
- Feature branches: All new work starts in a feature branch from
dev - Development: Merge features →
devfor testing and QA - Production: Merge
dev→mainfor production releases - Never commit directly to
main(enforced by branch protection)
Workflow
Create feature branch from
dev:bashgit checkout dev git pull origin dev git checkout -b feature/my-featureMake changes, commit, and push:
bashgit add . git commit -m "Add my feature" git push origin feature/my-featureOpen pull request to
devbranchCI runs automatically on PR:
- ✅ Lint
- ✅ Build
- ✅ Test
- ✅ Security
- ✅ Validate Firestore indexes
After PR approval and merge to
dev:- ✅ Auto-deploys to dev environment
When ready for production, merge
dev→main:- ✅ Auto-deploys to production
Environment Variables
Required GitHub Secrets
Set these in Settings → Secrets and variables → Actions → Repository secrets:
Firebase Configuration (Development)
VITE_FIREBASE_API_KEY_DEV
VITE_FIREBASE_AUTH_DOMAIN_DEV
VITE_FIREBASE_PROJECT_ID_DEV
VITE_FIREBASE_STORAGE_BUCKET_DEV
VITE_FIREBASE_MESSAGING_SENDER_ID_DEV
VITE_FIREBASE_APP_ID_DEVFirebase Configuration (Production)
VITE_FIREBASE_API_KEY_PROD
VITE_FIREBASE_AUTH_DOMAIN_PROD
VITE_FIREBASE_PROJECT_ID_PROD
VITE_FIREBASE_STORAGE_BUCKET_PROD
VITE_FIREBASE_MESSAGING_SENDER_ID_PROD
VITE_FIREBASE_APP_ID_PRODCloudflare
CLOUDFLARE_API_TOKEN # API token with Pages:Edit permissions
CLOUDFLARE_ACCOUNT_ID # Account ID from Cloudflare dashboardFirebase CLI
FIREBASE_TOKEN # Firebase CI token (run: firebase login:ci)Discord
DISCORD_WEBHOOK_COMMITS # Discord webhook for commit notifications (#commits channel)
DISCORD_WEBHOOK_DEV_DEPLOY # Discord webhook for dev deployments (#deployments channel)
DISCORD_WEBHOOK_PROD_DEPLOY # Discord webhook for prod deployments (#deployments channel)Note: See DISCORD_WEBHOOK_SETUP.md for detailed webhook configuration instructions.
Optional
CODECOV_TOKEN # Codecov token for coverage reportsEnvironment Detection
The application automatically detects the environment:
- Local:
VITE_APP_ENV=local(or not set) - Development:
VITE_APP_ENV=development - Production:
VITE_APP_ENV=production
This controls which Firebase project is used and which features are enabled.
Deployment Process
Automatic Deployments
Development
- Merge PR to
devbranch - CI runs and validates
- On success, deployment workflow triggers
- All services deploy to dev environment
- Discord notification sent
Production
- Merge
devtomainbranch (via PR) - CI runs and validates
- On success, deployment workflow triggers
- All services deploy to production
- Discord notification sent
- Manual approval required (if environment protection is enabled)
Manual Deployments
Emergency Production Deploy
Use GitHub Actions UI:
- Go to Actions tab
- Select Deploy to Production workflow
- Click Run workflow
- Select
mainbranch - Optionally skip tests (emergency only)
- Click Run workflow
⚠️ Use manual deployments only for emergencies!
Rollback Procedure
If a bad deployment goes live:
Immediate rollback:
bashgit checkout main git revert <bad-commit-sha> git push origin mainThis triggers a new production deployment with the revert.
Or revert to previous commit:
bashgit checkout main git reset --hard <previous-good-commit> git push --force origin main⚠️ Force push requires temporarily disabling branch protection
Cloudflare Pages rollback:
- Go to Cloudflare Pages dashboard
- Select project (e.g.,
lantern-app) - Go to Deployments
- Find previous working deployment
- Click Rollback to this deployment
Status Checks
Required Status Checks (Branch Protection)
To enable branch protection on main and dev:
Go to Settings → Branches
Add branch protection rule for
main:- ✅ Require a pull request before merging
- ✅ Require approvals (at least 1)
- ✅ Dismiss stale pull request approvals when new commits are pushed
- ✅ Require status checks to pass before merging
- ✅
lint - ✅
build - ✅
test - ✅
validate-firestore-indexes - ✅
all-checks-complete
- ✅
- ✅ Require conversation resolution before merging
- ✅ Do not allow bypassing the above settings
Repeat for
devbranch
Result: PRs cannot be merged if CI fails
Troubleshooting
Build Failures
Lint Errors
Error: ESLint found issuesFix:
npm run lint:fix
npm run formatBuild Errors
Error: Vite build failedFix:
- Check for TypeScript/JavaScript errors in code
- Verify all imports are correct
- Check environment variables are set in GitHub Secrets
Test Failures
Error: Tests failedFix:
- Run tests locally:
npm test - Fix failing tests
- Ensure Firebase environment variables are set
Deployment Failures
Cloudflare API Error
Error: Unauthorized (403)Fix:
- Verify
CLOUDFLARE_API_TOKENis set and valid - Ensure token has
Pages:Editpermissions - Check
CLOUDFLARE_ACCOUNT_IDis correct
Firebase Deployment Error
Error: HTTP Error: 401, UnauthorizedFix:
- Regenerate Firebase token:
firebase login:ci - Update
FIREBASE_TOKENsecret in GitHub
Discord Notification Failure
Error: Webhook URL invalid
Error: Character encoding issuesFix:
- Verify
DISCORD_WEBHOOK_COMMITS,DISCORD_WEBHOOK_DEV_DEPLOY,DISCORD_WEBHOOK_PROD_DEPLOYare set and valid - Check Discord server settings
- Recreate webhook if necessary
- Important: Discord notification failures will retry automatically on next push
- The commit is logged for automatic retry
- Next successful push will include the missed commit(s)
- Ensures complete audit trail even if Discord is temporarily down
Why notifications are critical:
- Discord notifications provide an audit trail of all commits and deployments
- Missed notifications are automatically tracked and retried
- You'll never lose commit history due to temporary Discord downtime
- If notifications consistently fail, investigate the webhook configuration
Manual recovery if needed:
# View the artifact containing missed commits
# In GitHub Actions, check "discord-posted-commits-log" artifact
# It contains all successfully posted commit SHAs
# These commits will automatically be included in the next push notificationFirestore Index Issues
Index Not Found Error
Error: The query requires an indexFix:
- Firestore Console will suggest the exact index needed
- Add to
firestore.indexes.json:json{ "collectionGroup": "collectionName", "queryScope": "COLLECTION", "fields": [ {"fieldPath": "field1", "order": "ASCENDING"}, {"fieldPath": "field2", "order": "DESCENDING"} ] } - Deploy manually:bash
firebase deploy --only firestore:indexes --project lantern-app-dev firebase deploy --only firestore:indexes --project lantern-app-prod
⚠️ IMPORTANT: Indexes must exist in BOTH dev and prod projects!
Discord Bot Integration Issues
If Discord notifications fail after deployments:
- Verify webhook URLs are set and valid:
DISCORD_WEBHOOK_COMMITS(for commit notifications)DISCORD_WEBHOOK_DEV_DEPLOY(for dev deployments)DISCORD_WEBHOOK_PROD_DEPLOY(for prod deployments)
- Verify webhooks still exist in Discord server
- Test webhook manually:bash
curl -X POST $DISCORD_WEBHOOK_COMMITS \ -H "Content-Type: application/json" \ -d '{"content": "Test message"}' - If webhook is deleted, recreate and update secret (see DISCORD_WEBHOOK_SETUP.md)
Note: Discord bot deployment is separate (Railway). See DISCORD_BOT_DEPLOYMENT.md.
Maintenance
Regular Tasks
Weekly
- ✅ Review CodeQL security scan results
- ✅ Check for npm audit warnings
Monthly
- ✅ Update dependencies:
npm update - ✅ Review and update Firestore indexes
- ✅ Verify all deployments are healthy
Quarterly
- ✅ Rotate Firebase tokens
- ✅ Rotate Cloudflare API tokens
- ✅ Review and optimize CI/CD workflows
- ✅ Update GitHub Actions versions
Updating Workflows
To update a workflow:
- Edit workflow file in
.github/workflows/ - Commit to feature branch
- Test with a PR to
dev - Verify workflow runs correctly
- Merge to
dev, thenmain
⚠️ Test workflow changes in dev before merging to main!
Adding New Secrets
- Go to Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
SECRET_NAME - Value:
secret_value - Click Add secret
- Update workflow file to use
\$\{\{ secrets.SECRET_NAME \}\}
Monitoring
GitHub Actions
- View workflow runs: Actions tab
- View logs: Click on workflow run → Click on job
- Download artifacts: Scroll to bottom of job logs
Codecov
- View coverage reports: codecov.io/gh/cattreedev/lantern_app
CodeQL
- View security alerts: Security tab → Code scanning alerts
Best Practices
For Developers
Always create feature branches from
devbashgit checkout dev git pull origin dev git checkout -b feature/my-featureRun checks locally before pushing
bashnpm run lint npm run format:check npm run build npm testKeep commits small and focused
- One feature/fix per commit
- Write clear commit messages
Update CHANGELOG.md
- Add entry under
[Unreleased]section - Follow Keep a Changelog format
- Add entry under
Test in dev before merging to main
- Merge to
devfirst - Verify deployment works
- Then merge
dev→main
- Merge to
For Maintainers
Review all PRs thoroughly
- Check CI passes
- Review code changes
- Test locally if needed
Monitor deployments
- Check Discord notifications
- Verify deployed sites work
- Watch for errors in logs
Keep secrets up to date
- Rotate tokens regularly
- Update when they expire
- Document changes
Maintain Firestore indexes
- Keep
firestore.indexes.jsonin sync with queries - Deploy indexes to both dev and prod
- Monitor index creation status in Firebase Console
- Keep
See Also
- Deployment Overview - General deployment guide
- App Deployment - Cloudflare Pages setup
- Discord Bot Deployment - Railway setup
- Contributing Guide - Contribution guidelines
- Security Architecture - Security setup
Quick Reference
Commands
# Run CI checks locally
npm run lint # ESLint
npm run format:check # Prettier
npm run build # Build app
npm test # Run tests
# Deploy Firebase rules manually
firebase deploy --only firestore:rules --project lantern-app-dev
firebase deploy --only firestore:indexes --project lantern-app-dev
# Generate Firebase CI token
firebase login:ciURLs
- Dev App: dev.ourlantern.app
- Prod App: ourlantern.app
- Dev Storybook: storybook.dev.ourlantern.app
- Prod Storybook: storybook.ourlantern.app
- Dev Docs: docs.dev.ourlantern.app
- Prod Docs: docs.ourlantern.app
Workflow Status
Check status: github.com/cattreedev/lantern_app/actions