A teaching platform: a complete example of taking a service from code to an operated system -- tested, containerized, monitored, documented. "Done" means operable, not "the endpoint returns 200".
The process is part of the product: decisions live in RFCs and ADRs, conventions in the engineering principles, and every change follows them. The polyglot platform is built: five runtimes (Python, JS, Go, Rust, Kotlin) with contract-first gRPC, shaped load generation, three-layer monitoring, and a static reports UI -- delivered through RFC-0001 and RFC-0002 (with RFC-0000 as the baseline). The next arc is the deployment and operability platform -- RFC-0003: the same system on Kubernetes (Kind) with Helm and the Gateway API, beside the compose stack -- and after it an authentication capstone (a future RFC-0004) that rides on that platform.
devops-demo/
├── .github/ # Workflows, PR/issue templates, Renovate config
├── deploy/
│ └── compose/
│ └── docker-compose.yml # Main Docker Compose configuration
│
├── docs/ # Documentation (see index below)
│ ├── adr/ # Architecture Decision Records
│ ├── rfc/ # Request for Comments -- design documents
│ ├── exercises/ # Student exercises
│ └── runbooks/ # Alert runbooks (meaning, triage, remediation)
│
├── loadgen/ # k6 scenarios + Dockerfile (RFC-0001 D4, ADR-0006)
│ ├── scenarios/ # main.js (long-running) + incident.js (make incident)
│ └── lib/ # env parsing + shared-profile stage scheduling
│
├── loadprofile/ # Shared load-shape definition (RFC-0001 D5, ADR-0003)
│ └── parity/ # Golden-file cross-language parity test + goldens
│
├── observability/ # Observability configuration
│ ├── prometheus.yml # Prometheus configuration
│ ├── prometheus_slo_rules.yml # SLO recording rules
│ ├── prometheus_alerts.yml # Alerting rules
│ ├── blackbox/ # blackbox_exporter config (synthetic profile)
│ ├── grafana/ # Dashboards (JSON) + provisioning
│ ├── loki/ # Loki configuration
│ └── alloy/ # Grafana Alloy configuration
│
├── proto/ # buf module -- cross-service gRPC contract (ADR-0002)
│ ├── buf.yaml # Module config: lint rules, breaking-change category
│ └── devopsdemo/items/v1/ # devopsdemo.items.v1: ItemService (backend serves)
│
├── scripts/ # Doctor, toolchain drift gate, make target logic (ADR-0019)
├── services/ # Self-contained services (own Dockerfile,
│ ├── backend/ # Makefile, tests, README each)
│ ├── frontend/
│ ├── analytics/ # Go analytics service (analytics profile)
│ ├── canary/ # Rust synthetic-journey canary (synthetic profile)
│ ├── reports/ # Kotlin/Spring Boot reports service (reports profile)
│ └── reports-ui/ # Caddy static SPA over the reports API (reports-ui profile)
│
├── .devcontainer/ # Devcontainer / GitHub Codespaces setup
├── .env.example # Compose overrides template (see local-setup)
├── .mise.toml # Pinned toolchain versions (source of truth)
├── AGENTS.md # Canonical instructions for AI coding agents
├── LICENSE # MIT
├── Makefile # Single operational entry point (make help)
├── README.md # This file
└── SECURITY.md # How to report a vulnerability
Two things this repo does not install for you: Docker (with Compose v2)
and mise. Everything else -- Python, Node, Go,
Rust, buf, k6, the JDK, Gradle -- is pinned in .mise.toml and installed by
mise in one step:
curl https://mise.run | sh # if you do not have it yet
mise install # installs every pinned version
eval "$(mise activate zsh)" # add to your shell rc (bash: activate bash)Using mise is not mandatory -- any other way to provide the same pinned
versions works, and make doctor checks versions, not how you got them.
It is simply the shortest path, and the one the pins are written for.
Then verify everything with one command -- it checks tools, versions, the Docker daemon, and resources, names anything missing, and tells you how to fix it:
make doctorMinimum: Docker with Compose v2, GNU Make, 2 GB free RAM, 3 GB free disk.
-
Start everything
make up
-
Seed initial data (could be done multiple times)
make seed
-
Seed 90 days of analytics history (RFC-0001 Phase 5 D5; needs the
analyticsprofile up first)make up-full make seed-history
-
Workshop mode: all profiles at
DEMO_TIME_SCALE=24(one profile-day compresses to 1 wall-clock hour, RFC-0001 D5) -- seed at the same scale or loadgen's scale guard refuses to start against the mismatched seed marker (no marker yet or analytics absent: it continues)make up-workshop DEMO_TIME_SCALE=24 SEED_DAYS=3 make seed-history
See Exercise 05 for what to do with it.
After successful startup, all services will be available at the following URLs:
| Service | URL | Credentials | Description |
|---|---|---|---|
| Frontend | http://localhost:8080 | - | React application with CRUD interface for managing items |
| API | http://localhost:8000 | - | FastAPI REST API server |
| API (gRPC) | localhost:50051 | - | ItemService (ListItems, GetItemStats, WatchItemEvents) -- backend serves, analytics dials |
| API Documentation | http://localhost:8000/docs | - | Swagger UI with interactive API documentation |
| ReDoc | http://localhost:8000/redoc | - | Alternative API documentation in ReDoc format |
| Grafana | http://localhost:3000 | admin/admin | Dashboards for metrics and logs visualization |
| Prometheus | http://localhost:9090 | - | UI for viewing and querying metrics |
| Loki | http://localhost:3100 | - | API for accessing logs |
| Postgres Exporter | http://localhost:9187 | - | PostgreSQL metrics in Prometheus format |
| cAdvisor | http://localhost:8081 | - | Container and resource metrics |
| Alertmanager | http://localhost:9093 | - | Alert routing, grouping, silencing, inhibition |
| Mailpit | http://localhost:8025 | - | Visible alert receiver: SMTP sink + web UI for notifications |
| Canary | http://localhost:8085 | - | Synthetic-journey canary (synthetic profile) |
| Analytics API | http://localhost:8082 | - | Event ingestion + read API (items, stats, seed-marker) (analytics profile) |
| Reports API | http://localhost:8083 | - | Kotlin/Spring Boot reports service: async XLSX/PDF/CSV engine (reports profile) |
| Reports UI | http://localhost:8084 | - | Static SPA over the reports API, served by Caddy (reports-ui profile) |
For the full command list run make help.
- Prerequisites -- required knowledge and learning resources
- Local setup -- development environment, dependencies, Docker
- Architecture -- system components and how they connect
- Observability -- metrics, logs, dashboards, SLOs
- Database and data -- schema, migrations, seeding
- Running tests -- unit and integration tests
- Troubleshooting -- common issues and solutions
- Engineering principles -- how and why we build this way; RFC/ADR lifecycle, change workflow, testing philosophy
- RFCs -- design documents; start with RFC-0001 (the polyglot platform), then RFC-0002 (the reports UI, a sibling RFC) and RFC-0003 (Kubernetes on Kind, a second deployment target)
- ADRs -- one durable decision per file, extracted from the RFCs; immutable once accepted
- CI/CD architecture -- pipeline topology, gates, releases, branch protection
- Contributing -- practical guide: commits, hooks, linting, tests
- AGENTS.md -- canonical instructions for AI coding agents
- Security policy -- how to report a vulnerability, scope notes for the intentional local-stack defaults
- Exercises -- structured assignments with difficulty levels; new exercise sets arrive with each platform phase
- Course -- semester guide for teaching or self-studying the
platform phase by phase: run current
main, read how it grew via the tags
This project is intended for educational purposes and licensed under the MIT License -- see the LICENSE file for details.