Back to Software Engineering & Delivery Mastery Series

Part 42: Hands-On Projects & Capstone Exercises

May 14, 2026 Wasil Zafar 50 min read

You have learned the theory across 41 parts. Now it is time to build. This capstone provides 5 hands-on projects of increasing complexity — from a personal CI/CD pipeline to a full delivery lifecycle simulation — designed to solidify your skills and build your portfolio.

Table of Contents

  1. Introduction
  2. Project 1: Personal CI/CD Pipeline
  3. Project 2: Microservices Delivery Platform
  4. Project 3: Supply Chain Security Audit
  5. Project 4: DORA Metrics Dashboard
  6. Project 5: Full Delivery Lifecycle
  7. Evaluation Rubric
  8. Portfolio Presentation
  9. Recommended Reading
  10. Series Conclusion

Introduction

Theory without practice is philosophy. Practice without theory is guesswork. Over 41 parts, you have built a comprehensive mental model of modern software delivery — from SDLC fundamentals through CI/CD pipelines, testing strategies, security practices, observability, and team dynamics. Now it is time to build.

This capstone presents 5 projects of increasing complexity. Each project integrates concepts from multiple parts of the series, requires hands-on tool usage, and produces a tangible artifact you can showcase in your portfolio. They are designed to be completed in order, each building on skills developed in the previous project.

How to Approach These Projects: Do not just read through them. Build them. Create real repositories, write real code, deploy real pipelines. The gap between "I understand CI/CD" and "I have built a CI/CD pipeline from scratch" is enormous — and visible to hiring managers.
Project Difficulty Time Estimate Key Series Parts
1. Personal CI/CD Pipeline Beginner 1–2 days Parts 9, 14, 15
2. Microservices Delivery Platform Intermediate 3–5 days Parts 16, 20, 27
3. Supply Chain Security Audit Intermediate 2–3 days Parts 13, 23, 24
4. DORA Metrics Dashboard Advanced 5–7 days Parts 25, 26, 15
5. Full Delivery Lifecycle Advanced 2–4 weeks Entire series

Project 1: Personal CI/CD Pipeline (Beginner)

Build a complete CI/CD pipeline for a simple web application. This project covers the fundamentals: version control, automated testing, continuous integration, and automated deployment.

Requirements

  • A Git repository on GitHub containing a simple web application (static site, React app, or Python Flask app)
  • Automated unit tests (minimum 10 tests with 80%+ coverage)
  • A GitHub Actions workflow that: lints code, runs tests, builds the application, and deploys to GitHub Pages
  • Branch protection rules requiring CI to pass before merge
  • A README with architecture diagram and setup instructions
Project 1: CI/CD Pipeline Architecture
flowchart LR
    A["Developer\nPush to branch"] --> B["GitHub Actions\nTrigger"]
    B --> C["Lint\n(ESLint/Flake8)"]
    C --> D["Unit Tests\n(Jest/Pytest)"]
    D --> E["Build\n(npm build/Docker)"]
    E --> F{"Tests Pass?"}
    F -->|Yes| G["Deploy to\nGitHub Pages"]
    F -->|No| H["Notify Developer\n(PR Comment)"]
    G --> I["Live Site\n✓ Deployed"]
                            

Implementation Guide

# Step 1: Create project structure
mkdir my-cicd-project && cd my-cicd-project
git init

# Step 2: Initialize a simple Node.js application
npm init -y
npm install --save-dev jest eslint

# Step 3: Create source and test files
mkdir src tests
cat > src/calculator.js << 'EOF'
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) {
    if (b === 0) throw new Error('Division by zero');
    return a / b;
}
module.exports = { add, subtract, multiply, divide };
EOF

# Step 4: Create test file
cat > tests/calculator.test.js << 'EOF'
const { add, subtract, multiply, divide } = require('../src/calculator');

test('adds 1 + 2 to equal 3', () => expect(add(1, 2)).toBe(3));
test('subtracts 5 - 3 to equal 2', () => expect(subtract(5, 3)).toBe(2));
test('multiplies 3 * 4 to equal 12', () => expect(multiply(3, 4)).toBe(12));
test('divides 10 / 2 to equal 5', () => expect(divide(10, 2)).toBe(5));
test('throws on division by zero', () => {
    expect(() => divide(10, 0)).toThrow('Division by zero');
});
EOF
# .github/workflows/ci.yml — GitHub Actions Pipeline
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npx eslint src/ --ext .js

      - name: Run tests with coverage
        run: npx jest --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80}}'

  deploy:
    needs: lint-and-test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    permissions:
      pages: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: npm run build
      - name: Deploy to GitHub Pages
        uses: actions/deploy-pages@v4

Project 2: Microservices Delivery Platform (Intermediate)

Build a 3-service application with independent CI/CD pipelines, contract testing between services, and a blue-green deployment simulation. This project teaches you how to manage multiple deployable units with interdependencies.

Architecture

Project 2: Microservices Architecture
flowchart TD
    subgraph "API Gateway"
        GW["Nginx\nReverse Proxy\nPort 80"]
    end
    subgraph "Service A: Users"
        A["User Service\n(Python Flask)\nPort 5001"]
        ADB["PostgreSQL\n(Users DB)"]
    end
    subgraph "Service B: Orders"
        B["Order Service\n(Node.js Express)\nPort 5002"]
        BDB["PostgreSQL\n(Orders DB)"]
    end
    subgraph "Service C: Notifications"
        C["Notification Service\n(Python FastAPI)\nPort 5003"]
        CQ["Redis\n(Message Queue)"]
    end
    GW --> A
    GW --> B
    GW --> C
    A --> ADB
    B --> BDB
    B --> A
    B --> CQ
    CQ --> C
                            

Requirements

  • 3 services in separate directories, each with its own Dockerfile and CI pipeline
  • Docker Compose for local development (all services + databases + message queue)
  • Contract tests between Service B (Orders) and Service A (Users) using Pact or schema validation
  • Blue-green deployment simulation using Docker Compose profiles or Nginx upstream switching
  • Health check endpoints on all services (/health)
  • Integration test suite that validates cross-service interactions

Implementation Guide

# docker-compose.yml — Multi-service local environment
version: '3.8'

services:
  gateway:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - user-service
      - order-service
      - notification-service

  user-service:
    build: ./services/users
    ports:
      - "5001:5001"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@users-db:5432/users
    depends_on:
      - users-db
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
      interval: 10s
      timeout: 5s
      retries: 3

  order-service:
    build: ./services/orders
    ports:
      - "5002:5002"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@orders-db:5432/orders
      - USER_SERVICE_URL=http://user-service:5001
      - REDIS_URL=redis://redis:6379
    depends_on:
      - orders-db
      - redis
      - user-service

  notification-service:
    build: ./services/notifications
    ports:
      - "5003:5003"
    environment:
      - REDIS_URL=redis://redis:6379

  users-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: users
      POSTGRES_PASSWORD: postgres

  orders-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: orders
      POSTGRES_PASSWORD: postgres

  redis:
    image: redis:7-alpine
# Blue-Green Deployment Simulation
# Deploy new version alongside existing one

# Step 1: Build new version
docker build -t order-service:v2 ./services/orders

# Step 2: Start new version on different port (green)
docker run -d --name order-green -p 5012:5002 order-service:v2

# Step 3: Run smoke tests against green
curl -f http://localhost:5012/health || exit 1

# Step 4: Switch traffic (update Nginx upstream)
sed -i 's/order-service:5002/order-green:5002/' nginx.conf
docker exec gateway nginx -s reload

# Step 5: Verify and drain old (blue) instance
sleep 10
docker stop order-blue && docker rm order-blue
echo "Blue-green deployment complete!"

Project 3: Supply Chain Security Audit (Intermediate)

Audit an open-source project's software supply chain. Generate a Software Bill of Materials (SBOM), scan for vulnerabilities, check SLSA compliance, and sign artifacts. This project builds practical security skills that are increasingly required in enterprise environments.

Scope & Tools

Task Tool Output
Generate SBOM Syft CycloneDX/SPDX JSON file
Vulnerability scanning Trivy / Grype Vulnerability report (JSON + table)
License compliance Syft + custom script License inventory with risk flags
Container scanning Trivy OS + library vulnerability report
Artifact signing Cosign (Sigstore) Signed container image with verification
SLSA assessment slsa-verifier SLSA level determination

Implementation Guide

# Supply Chain Security Audit — Complete Workflow

# Step 1: Generate SBOM from a container image
syft packages alpine:3.19 -o cyclonedx-json > sbom.json
echo "SBOM generated: $(cat sbom.json | jq '.components | length') components found"

# Step 2: Scan SBOM for vulnerabilities
grype sbom:sbom.json --output table
grype sbom:sbom.json --output json > vulnerabilities.json

# Step 3: Scan container image directly with Trivy
trivy image --severity HIGH,CRITICAL --format json \
    --output trivy-report.json alpine:3.19

# Step 4: Check license compliance
syft packages alpine:3.19 -o json | \
    jq '[.artifacts[].licenses[]?.value] | group_by(.) | map({license: .[0], count: length}) | sort_by(-.count)' \
    > license-inventory.json

# Step 5: Sign a container image with Cosign
cosign sign --key cosign.key myregistry/myapp:v1.0.0

# Step 6: Verify the signature
cosign verify --key cosign.pub myregistry/myapp:v1.0.0
Deliverable

Security Audit Report

Your final deliverable is a structured security audit report containing: (1) Executive summary with risk score, (2) SBOM inventory with component count and dependency depth, (3) Vulnerability findings ranked by CVSS score with remediation recommendations, (4) License compliance matrix with GPL/copyleft risk flags, (5) SLSA compliance assessment with current level and gaps to next level, (6) Signed artifact verification proof. Present this as a Markdown document with embedded JSON snippets.

SBOM Supply Chain SLSA

Project 4: DORA Metrics Dashboard (Advanced)

Build a dashboard that measures all four DORA metrics from real GitHub or GitLab data. This project requires API integration, data processing, time-series calculations, and data visualisation.

The Four Metrics

  • Deployment Frequency: How often does your team deploy to production?
  • Lead Time for Changes: How long from commit to production?
  • Change Failure Rate: What percentage of deployments cause an incident?
  • Time to Restore Service: How quickly do you recover from failures?

Implementation Guide

# DORA Metrics Calculator — Core Logic
import requests
from datetime import datetime, timedelta
from typing import Dict, List

def calculate_deployment_frequency(
    deployments: List[Dict], period_days: int = 30
) -> Dict:
    """Calculate deployment frequency over a period.

    Args:
        deployments: List of deployment events with 'timestamp' field
        period_days: Number of days to analyze

    Returns:
        Dict with frequency metrics and DORA classification
    """
    cutoff = datetime.now() - timedelta(days=period_days)
    recent = [d for d in deployments
              if datetime.fromisoformat(d['timestamp']) > cutoff]

    total = len(recent)
    per_day = total / period_days
    per_week = per_day * 7

    # DORA classification
    if per_day >= 1:
        classification = "Elite"
    elif per_week >= 1:
        classification = "High"
    elif total >= 1:  # At least once per month
        classification = "Medium"
    else:
        classification = "Low"

    return {
        "total_deployments": total,
        "per_day": round(per_day, 2),
        "per_week": round(per_week, 2),
        "classification": classification,
        "period_days": period_days
    }

def calculate_lead_time(
    pull_requests: List[Dict]
) -> Dict:
    """Calculate lead time for changes (PR merge to deploy).

    Args:
        pull_requests: List of PRs with 'created_at' and 'deployed_at'

    Returns:
        Dict with lead time statistics and DORA classification
    """
    lead_times = []
    for pr in pull_requests:
        if pr.get('deployed_at'):
            created = datetime.fromisoformat(pr['created_at'])
            deployed = datetime.fromisoformat(pr['deployed_at'])
            hours = (deployed - created).total_seconds() / 3600
            lead_times.append(hours)

    if not lead_times:
        return {"error": "No data available"}

    median_hours = sorted(lead_times)[len(lead_times) // 2]

    if median_hours < 24:
        classification = "Elite"
    elif median_hours < 168:  # 1 week
        classification = "High"
    elif median_hours < 720:  # 1 month
        classification = "Medium"
    else:
        classification = "Low"

    return {
        "median_hours": round(median_hours, 1),
        "mean_hours": round(sum(lead_times) / len(lead_times), 1),
        "p95_hours": round(sorted(lead_times)[int(len(lead_times) * 0.95)], 1),
        "sample_size": len(lead_times),
        "classification": classification
    }

# Example usage
sample_deploys = [
    {"timestamp": "2026-05-14T10:00:00", "version": "v1.2.3"},
    {"timestamp": "2026-05-13T14:30:00", "version": "v1.2.2"},
    {"timestamp": "2026-05-12T09:15:00", "version": "v1.2.1"},
]

result = calculate_deployment_frequency(sample_deploys, period_days=7)
print(f"Deployment Frequency: {result['per_week']}/week")
print(f"DORA Classification: {result['classification']}")

Project 5: Full Delivery Lifecycle (Advanced)

The ultimate capstone: build an application end-to-end through the complete delivery lifecycle. This is a multi-week project, ideally done with a team of 2–4 people, covering every stage from requirements through production monitoring.

Project 5: Full Delivery Lifecycle
flowchart TD
    A["Phase 1: Requirements\n& Architecture"] --> B["Phase 2: Implementation\n& Testing"]
    B --> C["Phase 3: CI/CD Pipeline\n& Deployment"]
    C --> D["Phase 4: Observability\n& Monitoring"]
    D --> E["Phase 5: Incident Response\n& Improvement"]
    E --> F["Phase 6: Documentation\n& Presentation"]

    A ---|"ADRs, User Stories\nC4 Diagrams"| A
    B ---|"TDD, Contract Tests\nCode Review"| B
    C ---|"GitHub Actions\nDocker, K8s"| C
    D ---|"Metrics, Logs, Traces\nSLOs, Alerts"| D
    E ---|"Chaos Engineering\nPostmortems"| E
    F ---|"README, Runbook\nDemo Video"| F
                            

Project Phases

Phase 1: Requirements & Architecture (Days 1–3)

  • Write 5–10 user stories with acceptance criteria
  • Create Architecture Decision Records (ADRs) for key technology choices
  • Draw C4 diagrams (Context, Container, Component levels)
  • Define API contracts (OpenAPI spec)
  • Define SLOs (Service Level Objectives) for your system

Phase 2: Implementation & Testing (Days 4–10)

  • Implement using TDD — write tests first, then code
  • Minimum 85% code coverage
  • Contract tests between services (if multi-service)
  • Code review process (even if solo — review your own PRs with a checklist)
  • Security scanning integrated from day 1 (SAST with Semgrep)

Phase 3: CI/CD Pipeline & Deployment (Days 11–14)

  • Multi-stage CI pipeline: lint → test → security scan → build → deploy
  • Container-based deployment (Docker + orchestration)
  • Blue-green or canary deployment strategy
  • Automated rollback on health check failure
  • Environment promotion: dev → staging → production

Phase 4: Observability & Monitoring (Days 15–18)

  • Structured logging (JSON format, correlation IDs)
  • Metrics collection (application and infrastructure)
  • Distributed tracing (if multi-service)
  • SLO-based alerting (alert on SLO burn rate, not individual metrics)
  • Dashboard showing key health indicators

Phase 5: Incident Response & Improvement (Days 19–21)

  • Simulate an incident (inject a failure, observe detection and response)
  • Write a blameless postmortem for the simulated incident
  • Implement at least one improvement from the postmortem
  • Run a simple chaos experiment (kill a container, observe recovery)

Phase 6: Documentation & Presentation (Days 22–28)

  • Comprehensive README with quick start instructions
  • Runbook for common operational procedures
  • Architecture diagram with deployment topology
  • 5-minute demo video or recorded walkthrough
Capstone Challenge

The 42-Part Integration Challenge

For maximum portfolio impact, annotate your Project 5 with references to which series part taught each technique you used. For example: "Branch protection (Part 9: Git Workflows)", "Contract testing (Part 20: Testing Strategies)", "SLO-based alerting (Part 26: Observability)". This demonstrates both technical skill AND systematic learning — a combination that stands out in interviews.

Portfolio Integration Career

Evaluation Rubric

Use this rubric to self-assess each project. Each dimension is scored 1–5:

Dimension 1 (Minimal) 3 (Competent) 5 (Excellent)
Functionality Partially works, manual steps required Works end-to-end with minor issues Robust, handles edge cases, zero manual steps
Automation Some scripts, mostly manual CI/CD pipeline, automated tests Full automation including deployment, rollback, and monitoring
Security No security considerations Dependency scanning, basic SAST SBOM, signed artifacts, SLSA compliance, security gates in CI
Documentation Minimal README Good README, architecture diagram README, ADRs, runbook, API docs, demo video
Observability Console logs only Structured logs, basic metrics Logs + metrics + traces, SLO dashboards, alerting

Portfolio Presentation

These projects are most valuable when they are visible. Here is how to showcase them effectively:

GitHub Profile Optimisation

  • Pin your best repositories: Pin Project 4 (DORA Dashboard) and Project 5 (Full Lifecycle) to your profile
  • Write compelling READMEs: Start with a one-sentence summary, then architecture diagram, then "Quick Start" instructions that work in under 2 minutes
  • Use topics/tags: Add tags like ci-cd, devops, github-actions, docker, dora-metrics
  • Show green squares: Regular commits demonstrate sustained engagement

Architecture Diagrams

  • Include Mermaid diagrams in your README (GitHub renders them natively)
  • Create C4 diagrams for complex projects (Context, Container, Component)
  • Add deployment topology diagrams showing infrastructure

Demo Recordings

  • Record a 3–5 minute walkthrough of your CI/CD pipeline in action
  • Show a deployment happening: push commit → CI runs → deploy → verify
  • Demonstrate a failure scenario and automated recovery
  • Tools: asciinema (terminal recording), Loom (screen + voice), or OBS Studio
# Record a terminal session with asciinema
# Install: brew install asciinema (macOS) or pip install asciinema

# Start recording
asciinema rec demo.cast --title "CI/CD Pipeline Demo"

# ... run your commands (push, wait for CI, deploy) ...

# Stop recording (Ctrl+D or 'exit')
# Upload to asciinema.org or embed in README
asciinema upload demo.cast

Recommended Reading

To continue your journey beyond this series, these books represent the definitive works in software delivery engineering:

Book Authors Key Topics
Accelerate Nicole Forsgren, Jez Humble, Gene Kim DORA metrics, scientific evidence for DevOps practices, capabilities that drive performance
Continuous Delivery Jez Humble, David Farley Deployment pipelines, configuration management, release strategies, build automation
The Phoenix Project Gene Kim, Kevin Behr, George Spafford DevOps transformation narrative, Theory of Constraints applied to IT, the Three Ways
Team Topologies Matthew Skelton, Manuel Pais Four team types, interaction modes, Conway's Law, cognitive load, fast flow of change
Release It! (2nd ed.) Michael Nygard Production readiness, stability patterns, capacity planning, chaos engineering
Site Reliability Engineering Betsy Beyer, Chris Jones, et al. (Google) SLOs/SLIs/SLAs, error budgets, toil reduction, incident management, on-call practices
Reading Order Suggestion: Start with The Phoenix Project (narrative, easy read) → Accelerate (research backing) → Continuous Delivery (technical depth) → Team Topologies (organisational design) → Release It! (production wisdom) → SRE Book (operational excellence).

Series Conclusion

You have completed the Software Engineering & Delivery Mastery series — 42 parts spanning the entire landscape of modern software delivery. Let us recap the journey:

  • Parts 1–5: Mental models, SDLC, Agile methodologies, and process frameworks
  • Parts 6–10: Version control, Git workflows, branching strategies, and code review
  • Parts 11–15: CI/CD pipelines, build systems, artifact management, and deployment automation
  • Parts 16–20: Containerisation, orchestration, testing strategies, and quality assurance
  • Parts 21–25: Security, compliance, supply chain integrity, and DORA metrics
  • Parts 26–30: Observability, incident management, SRE practices, and chaos engineering
  • Parts 31–35: Infrastructure as Code, platform engineering, and developer experience
  • Parts 36–39: Advanced testing, AI/ML delivery, and emerging practices
  • Parts 40–42: LEAN thinking, team dynamics, and hands-on capstone projects
The Continuous Learning Mindset: Software delivery is a field that evolves rapidly. The tools will change. The platforms will change. But the principles — automation, reproducibility, fast feedback, safe deployments, continuous improvement — are timeless. You now have the mental models to evaluate any new tool, practice, or methodology against these principles.

The most important thing you can do now is build. Start with Project 1. Iterate. Ship something imperfect and improve it. That is, after all, the essence of continuous delivery — and the essence of engineering itself.

Thank you for following this series. Now go deliver something extraordinary.