Developer guide¶
This guide gets a new developer productive on the TaskTree backend. It describes how the system is built — the layers, the data model, the moving parts — and links to the Architecture Decision Records that explain why each choice was made.
Audience and scope
These pages document design and architecture. They're public, so they deliberately contain no secrets, credentials, or environment-specific identifiers — those live in the operator's internal notes and in Azure Key Vault, never here. See ADR 0040 for the boundary.
What TaskTree is, in one paragraph¶
A self-hosted project-management tool for engineering R&D teams. A FastAPI + PostgreSQL backend serves a React + TypeScript single-page app that renders the same task data as a canvas tree and a filterable list, kept in sync across clients in real time. It runs as a Microsoft Teams tab with Entra ID single sign-on, hosted on Azure. Roughly ten users per workspace, hundreds of tasks, one project per deployment-grown-to-many.
The stack¶
| Layer | Technology |
|---|---|
| Backend | Python 3.12, FastAPI, SQLAlchemy (sync), Alembic |
| Database | PostgreSQL 16 |
| Frontend | React 18, TypeScript, Vite, React Flow (canvas), TanStack Table (list) |
| Auth | Pluggable provider — local-dev for development, Entra ID for production |
| Real-time | Server-Sent Events, in-process broadcaster |
| Hosting | Azure App Service + Azure Database for PostgreSQL Flexible Server + Static Web Apps |
Read these pages in order¶
If you're onboarding, this is a sensible path:
- Architecture — the layers, the request lifecycle, how a write flows end to end.
- Data model — tasks, the tree, dependencies, projects, memberships, the audit log.
- API surface — the
/api/v1shape, conventions, and the error/conflict contract. - Authentication & authorization — the provider abstraction and per-project roles.
- Real-time sync — the SSE broadcaster, event payloads, catch-up, and the single-worker constraint.
- Concurrency & conflicts — last-write-wins with field-aware 409s.
- Migrations & schema — the Alembic workflow and the
native_enumgotcha. - Telemetry & observability — Application Insights wiring, with privacy filtering.
- Testing — the test layout, fixtures, and the coverage gate.
- Local development & contributing — get it running, and the Definition of Done.
How decisions are recorded¶
Every significant architectural choice is captured as an Architecture Decision Record (ADR) — a short Context / Decision / Consequences document, written before the code that implements it. ADRs are append-only history; they're not edited after they land. The pages here link to the relevant ADR for the reasoning behind each design. The ADRs themselves live in the repository under docs/adr/.
The golden rules¶
A handful of conventions run through the whole codebase. They're worth internalising early:
- Sync, not async. Endpoints are plain
def, notasync def— the one exception is the SSE stream. (ADR 0009) - The database is the only durable store. No
localStorage, no in-memory state that matters across a restart. - ADR-first. Structural decisions get an ADR before the code.
- A change isn't done until lint, typecheck, and tests pass — and tests ship in the same change as the code they cover. See Contributing.