ADR-0004: Monorepo layout — apps, packages, infra, scripts, specs
Status: AcceptedDate: 2026-05-02Owner: @satyaContext
Section titled “Context”Treeper has three runtimes (Flutter mobile, NestJS API, Python workers) plus shared decisions and contracts. We can either:
- One repo per runtime (multi-repo).
- One repo for everything (monorepo).
For a small team, multi-repo means PRs cross repos for almost every change that touches a contract. Monorepo wins.
Decision
Section titled “Decision”A single Git repo with this layout:
treeper/├── apps/│ ├── mobile/ Flutter app│ ├── backend/ NestJS API│ └── workers/ Python (FastAPI)├── packages/ Shared TS types / contracts (planned)├── infra/│ ├── docker/ docker-compose for local dev│ └── coolify/ deploy templates├── scripts/ Cross-app helper scripts├── specs/ SDD source of truth├── PRODUCT.md└── README.mdTooling stays per-app (no Nx / Turborepo at v0). Each apps/* directory has
its own README with run / build / test commands.
Alternatives considered
Section titled “Alternatives considered”| Option | Why not |
|---|---|
| Multi-repo | Cross-repo PRs for contract changes; harder to enforce SDD link from PRs. |
| Nx / Turborepo / pnpm workspaces | Worth it once we have shared TS code; premature for three foreign runtimes. |
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- One PR can carry mobile + backend + worker + spec changes together.
- A single
specs/is the cross-runtime source of truth. docker compose upboots the whole backend stack from one place.
Negative / risks
Section titled “Negative / risks”- CI matrix gets bigger; we’ll need path-filtered jobs.
- Repo size grows over time (Flutter pub cache, etc.); manage with a strict
.gitignore.
Follow-ups
Section titled “Follow-ups”- Path-filtered CI when we start adding GitHub Actions.
- Add
packages/contracts/once the API surface is large enough that the mobile app benefits from a generated client.
References
Section titled “References”- README.md — full layout walk-through