Phased delivery from a clean Pi to a working classroom module. Each phase has a single goal, hard exit criteria, and an estimated effort. Effort is expressed in focused half-days (≈4 hours) for a single developer.
Don’t skip phases. Don’t merge two phases. The point of the gates is to keep the platform stable as it grows.
| Goal | A stable, portable touchscreen Pi that boots reliably on USB-C battery. |
| Effort | 1–2 half-days. |
| Runbook | hardware-runbook.md. |
Exit criteria — every box in hardware-runbook.md §10 is ticked.
| Goal | All platform services come up with docker compose up -d on the Pi. |
| Effort | 2–3 half-days. |
Tasks:
rpi-iot-platform/docker-compose.yml with services: mosquitto,
node-red, api, ai, frontend. arm64 only.infra/ configs (Mosquitto with auth enabled, Node-RED with
default settings, nginx for the Vue build).services/api/ with FastAPI + a single /health route + SQLAlchemy +
Alembic skeleton (no business endpoints yet).services/ai/ with FastAPI + a single /health route + the echo
provider (Claude wired up but disabled until Phase 6).frontend/ with a Vite + Vue 3 + Tailwind app showing a placeholder home
page..env.example committed; real .env ignored.scripts/bootstrap-pi.sh installs Docker + Compose plugin on a fresh Pi.Exit criteria:
docker compose ps shows all five services healthy.http://<pi>/ loads the Vue placeholder.http://<pi>:1880/ shows Node-RED.mosquitto_pub / mosquitto_sub round-trips a message between two
laptops on the LAN with auth.curl http://<pi>:8000/health and :8001/health return {"status":"ok"}.| Goal | The bus is real: a test sensor publishes, the API stores, the dashboard renders. |
| Effort | 1–2 half-days. |
Tasks:
services/api/app/mqtt/.
Subscribes to +/sensor/+/+ with QoS 0; parses the v1 envelope; calls
ReadingsRepository.append.scripts/publish-test-sensor.py — a small async publisher that emits
fake temperature/humidity at 1 Hz. Used for demos and CI.flows/core.json with debug nodes for system/# and
+/sensor/+/+. Imported once, exported on change.SensorCard.vue on the home page wired to a WebSocket
from FastAPI that pushes the latest reading per sensor.Exit criteria:
publish-test-sensor.py from a laptop causes the Pi’s home
screen card to update within 1 second.| Goal | Every reading is durable; the schema in database-design.md is real. |
| Effort | 1–2 half-days. |
Tasks:
0001_initial covering all tables in
database-design.md §2.devices, sensors, readings, system_logs (the rest
come with later phases).sensor_readings older than 30 days./api/sensors, /api/sensors/{id}/readings?limit=... endpoints.Exit criteria:
/api/sensors lists every sensor that has ever published.system_logs.| Goal | A polished Vue touchscreen UI that’s pleasant to use in front of a class. |
| Effort | 3–4 half-days. |
Tasks:
SensorCard, ModuleTile, LineChart (Chart.js or
ECharts; pick one and live with it), MqttActivity, SettingsView./, /modules, /settings, /about.Exit criteria:
| Goal | The “Explain” button on a sensor card calls Claude Haiku, shows a 2–3 sentence answer, and logs the prompt/response. |
| Effort | 1–2 half-days. |
| Design doc | ai-integration.md. |
Tasks:
services/ai/ with FastAPI, the anthropic SDK, a tiny retry helper,
and prompt caching on the system block.prompts/explain-sensor-v1.md. Validate at boot.POST /ai/explain on the AI service.POST /api/ai/explain on the main API: looks up the latest
reading for the given sensor_id and forwards to the AI service.AiExplainer.vue on each sensor card: tap → call → render the text.ai_prompts and ai_responses on every call,
success or failure./settings: weekly tally of input/output tokens.Exit criteria:
ANTHROPIC_API_KEY unset, the platform falls back to the deterministic
stub and the UI shows a banner — no crashes.ai_prompts / ai_responses and is visible in the
cost view.| Goal | A complete teachable module that a Year 7 class can use end-to-end. |
| Effort | 3–4 half-days. |
Tasks:
modules/classroom-sensor-hub/module.yaml manifest. Picked up at boot.mqtt-microbit
bridge) committed under modules/classroom-sensor-hub/microbit/..../esp32/.modules/classroom-sensor-hub/README.md.Exit criteria:
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Power bank causes under-voltage warnings under load | Medium | Display flicker, SD corruption | Test in Phase 1 §6; reject inadequate banks early. |
| SQLite WAL corruption on hard power-off | Low | Data loss | WAL + synchronous=NORMAL; document the trade-off; nightly DB snapshot to a second file in data/sqlite/backups/. |
| Anthropic API outage in a live lesson | Low | “Explain” stops working | echo provider fallback + visible UI banner; lessons don’t depend on AI as the critical path. |
| Wi-Fi unreliable in the classroom | Medium | No MQTT from Micro:bits | Pi can run a local Wi-Fi hotspot mode (Phase 5 stretch), Micro:bits join the Pi directly. |
| Scope creep (more modules, more features) | High | v1 never ships | Each module is post-Phase-7. No new ADRs without explicit review. |
| Vendor lock-in on Claude | Low | Cost / availability | Acceptable for v1; AI is a single, isolated service so swapping vendors later is a contained change. |
To make these explicit so they don’t drift in: