HealthPulse Portal — Complete Capstone Project
*HealthPulse Inc.** is a healthcare technology startup that has built a patient portal as a **React/TypeScript single-page application**. The application allows patients to view appointments, lab results, medications, and communicate with their care team.
Currently, the development team **manually builds and deploys** the application by:
1. Running `npm run build` on a developer's laptop
2. SCP-ing the `dist/` folder to a single Nginx server
3. SSHing into the server and restarting Nginx
and hosted by their private server
https://healthpulse-capstone.vercel.app/
This process takes **45 minutes per deployment**, is error-prone, and has caused **3 production outages** in the last quarter from misconfigurations. There is **no testing in the pipeline**, **no code quality checks**, **no security scanning**, and **no monitoring**.
**HealthPulse Inc. has hired your DevOps team** to design and implement a complete CI/CD pipeline, multi-environment infrastructure, container orchestration, and observability platform on **AWS**.
---
## Application Details
| Item | Detail |
|------|--------|
| **App Name** | HealthPulse Portal |
| **Tech Stack** | React 18, TypeScript, Vite, shadcn/ui, Tailwind CSS |
| **Testing** | Vitest (unit), Playwright (e2e) |
| **Build Output** | Static files (`dist/`) served by Nginx |
| **Container** | Multi-stage Dockerfile (Node build → Nginx serve) |
| **Health Endpoint** | `GET /health` → `{"status":"healthy"}` |
Stack: React 18 + TypeScript + Vite + shadcn/ui + Tailwind CSS + Recharts
| New File | Purpose |
|---|---|
docs/mkdocs.yml | MkDocs config with Material theme, dark/light toggle, nav, extensions |
docs/Dockerfile | Multi-stage build (mkdocs-material → nginx:alpine) |
docs/docker-compose.yml | Prod on port 84 + live-reload dev mode on port 8084 |
docs/docs/index.md | Home page with project overview, team roster template |
docs/docs/architecture.md | ADR templates (CI/CD platform + container orchestration) |
docs/docs/environments.md | Environment matrix table (Dev/UAT/QA/Prod) |
docs/docs/runbooks.md | 4 runbook templates (deploy, rollback, scale, incident) |
docs/docs/pipeline.md | CI/CD pipeline stage docs with diagrams |
Summary Task A
TASK A: Documentation Platform (Docs-as-Code)
1. Set up MkDocs with Material theme inside the deployment repo
2. Create a docker-compose.yml to serve docs on port 84
3. Write initial documentation pages:
- Team roster and roles
- ADR: "Why we chose [Jenkins/GitLab/Azure DevOps]"
- Environment matrix (Dev/UAT/QA/Prod)
- Runbook template
4. Build docs via Docker (multi-stage: mkdocs build → nginx serve)
5. CI pipeline auto-builds docs site on push to /docs folder
Acceptance Criteria:
- Docs served on port 84 via Docker
- mkdocs.yml and all markdown files committed to Git
- Multi-stage Dockerfile builds and serves the docs
- 4 documentation pages created with real content
1. Live Reload Dev Mode
When writing documentation (editing the Markdown files), you need to see how their changes look in real-time. That's what dev mode does:
Student edits runbooks.md → saves file → browser auto-refreshes → sees updated page instantly
Without dev mode: Edit markdown → rebuild Docker image → restart container → refresh browser → check result. That's painful and slow.
With dev mode: MkDocs watches the files. The second you hit save, the browser updates automatically. It's the same concept as npm run dev for the React app — hot reload for docs.
In the docker-compose.yml, there are two services:
| Service | Port | Purpose |
|---|---|---|
docs-prod | 84 | Built static site served by Nginx (what users/team see) |
docs-dev | 8084 | Live preview with auto-refresh (only used while writing docs) |
Students use 8084 while writing, then build and deploy to 84 for production. It's a workflow thing — not two permanent servers.
2. Runbook Template
A runbook is an operational instruction manual — step-by-step procedures for when things happen in production. Think of it like a recipe book, but for servers.
Every real DevOps team has them. Eg When it's 2 AM and production is down, you don't want the on-call engineer guessing — you want them following a tested checklist.
Here's An Example of what the you would fill in as you complete the project:
RUNBOOK: Deploy New Version
═══════════════════════════
When to use: New release ready for production
Who can run: DevOps team lead
Steps:
1. Verify build passed in Jenkins → check #healthpulse-builds Slack
2. Confirm SonarQube quality gate passed
3. Approve deployment in pipeline (manual gate)
4. Monitor Datadog dashboard during rollout
5. Verify /health endpoint returns 200
6. If health check fails → pipeline auto-rolls back via Ansible
───────────────────────────
RUNBOOK: Rollback Production
════════════════════════════
When to use: Production deployment caused errors
Who can run: Any DevOps team member
Steps:
1. Run: ./scripts/k8s-manage.sh rollback
OR: Trigger Ansible Tower rollback job
2. Verify previous version is serving traffic
3. Check Datadog for error rate returning to normal
4. Post incident summary in wiki
───────────────────────────
RUNBOOK: Scale Application
══════════════════════════
When to use: High traffic / slow response times
Who can run: Any DevOps team member
Steps:
1. Check Datadog → confirm CPU/memory is the bottleneck
2. Run: REPLICAS=6 ./scripts/k8s-manage.sh scale
3. Monitor HPA: kubectl get hpa -n healthpulse-prod
4. Scale back down after traffic normalizeshealthpulse-docs/
├── mkdocs.yml # Site config + navigation
├── Dockerfile # Multi-stage build (mkdocs → nginx)
├── docker-compose.yml # Prod (port 84) + dev (port 8084)
└── docs/
├── index.md # Home — project overview, team roster, quick links
├── architecture.md # ADR templates (CI/CD choice, orchestration choice)
├── environments.md # Environment matrix (IPs, URLs, sizing)
├── pipeline.md # CI/CD pipeline stages and config
├── setup-template.md # Reusable template — copy for each tool install
├── runbooks.md # Deploy, rollback, scale, health check procedures
├── incidents.md # Incident log template — track issues + root causes
└── changelog.md # Weekly progress log — what was built, when, by whom
How Students Use It
| Page | When |
|---|---|
| Setup Template | Copy to setup-jenkins.md, setup-sonarqube.md, setup-artifactory.md, setup-ansible-tower.md, setup-datadog.md — one per tool they install. Documents every command they ran. |
| Runbooks | Fill in real commands and URLs as they complete Tasks F-H |
| Incident Log | Every time something breaks during the project, they log it |
| Changelog | Weekly entries tracking progress across all tasks |
| Architecture/Environments/Pipeline | Fill in as they make decisions and provision infrastructure |
One template, students create as many copies as they need. Keeps it simple.
TASK B: Version Control & Code Security
Plan & Code
App Name: Healthpulse
- WorkStation A- Team Pipeline Pirates - 3.15.209.165
- WorkStation B - Team DevopsAvengers - 3.143.221.53
- WorkStation C- Team Devius - 3.144.208.46
Create two repositories:
| Repository | Purpose | Access |
|---|---|---|
HealthPulse_App | Application source code | Developers |
HealthPulse_Deployment | IaC, Ansible, pipelines, scripts | DevOps team |
Implement GitFlow in the App repository:
main ─────────────────────────────────────────►
└── develop ─────────────────────────────────►
├── feature/login-page ──► (merge to develop)
├── feature/dashboard ───► (merge to develop)
└── release/1.0.0 ───────► (merge to main + develop)
B.3 — Repository Security (Layer 1 & Layer 3)
Repository security follows a defense-in-depth approach with 3 layers. In this task you set up Layer 1 (local hooks) and Layer 3 (branch protection). Layer 2 (gitleaks in the CI pipeline) comes later in Task F once the pipeline exists.
Layer 1 (this task): Local hooks → fast feedback for developers
Layer 2 (Task F): CI pipeline scan → server-side safety net
Layer 3 (this task): Branch protection → platform-enforced rules
Layer 1: Local Git Hooks (pre-commit + pre-push)
Install pre-commit and pre-push hooks so developers get early feedback when they accidentally commit secrets. Understand that developers can bypass these with --no-verify — that's why Layer 3 exists.
| Hook | Tool | Purpose |
|---|---|---|
| pre-commit | detect-secrets | Scans staged changes for secrets using entropy + pattern analysis |
| pre-push | custom script | Warns on direct push to main/develop |
Use the provided .pre-commit-config.yaml and scripts/setup-git-hooks.sh.
# Step 1: Install the pre-commit framework
curl -O https://raw.githubusercontent.com/princexav/security/refs/heads/main/.pre-commit-config.yaml
pip install pre-commit
# Step 2: Install hooks into the repo
pre-commit install
# Step 3: Test it — this should be BLOCKED
echo "AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" >> test.txt
git add test.txt && git commit -m "test secret"
# Expected: detect-secrets blocks the commit
# Step 4: Clean up
git checkout -- test.txt
# Step 5: Test the pre-push hook
git checkout main
git push origin main
# Expected: Warning message about direct push to protected branchKey lesson: Run
git commit --no-verify -m "test"and notice the hook is skipped entirely. This is why local hooks alone are NOT enough — you need Layer 3.
Layer 3: Branch Protection Rules (platform-level — cannot be bypassed)
Configure these in your Git hosting platform (GitHub / GitLab / Bitbucket). Unlike hooks, these are enforced by the server — no developer can skip them.
| Rule | Setting |
|---|---|
| Require pull request before merging | main and develop |
| Require at least 1 approval | main and develop |
| Do not allow bypassing the above | Even admins must follow the rules |
Note: The rule "Require CI status checks to pass" will be added in Task F once your pipeline is built. For now, configure the PR and approval requirements.
# Test it — this should be REJECTED by the platform
git checkout main
git commit --allow-empty -m "testing direct push"
git push origin main
# Expected: Rejected — branch protection requires a pull requestAcceptance Criteria:
- Both repos created with proper access controls
- GitFlow branching strategy demonstrated (main, develop, feature/, release/)
- SSH key authentication configured for repo access
-
pre-commit installruns successfully and hooks are active - Demonstrate: committing a fake AWS key is blocked by
detect-secrets - Demonstrate:
--no-verifybypasses the hook (explain why this matters) - Demonstrate: pre-push hook warns on direct push to
main - Branch protection rules configured on
mainanddevelop(screenshot required) - PR requires at least 1 approval before merge
- Direct push to
mainis rejected by the platform (not just the hook) - Document the security setup in your MkDocs wiki