Skip to content

Repository files navigation

Monorepo Template by Atinary - PyCon Italy 2026

A minimal, opinionated template that mirrors the architecture introduced in the PyCon Italy 2026 talk Simplicity Scales - Rewriting to a Django Monolith and a Monorepo. Slides | Video recording (coming soon)

Layout

.
├── backend/                     # Python code: one folder per deployable unit
│   ├── django/                  # Django monolith — uv workspace
│   │   ├── apps/                # Django apps (notifications, ...)
│   │   ├── config/              # Django settings, Celery, ASGI, URLs
│   │   ├── compose.yaml         # postgres + redis + celery worker
│   │   ├── Dockerfile
│   │   ├── justfile             # setup / run / migrate / type-gen
│   │   └── pyproject.toml
│   ├── ml/                      # ML workspace — uv workspace
│   │   ├── algorithm/           # Toy optimisation algorithm package
│   │   ├── evaluation/          # Evaluation pipeline package
│   │   ├── Dockerfile           # Demonstrates packaging the algorithm as a container
│   │   ├── compose.yml
│   │   └── justfile
│   ├── util/                    # Shared Python utilities (logging, env, ...)
│   ├── typings/                 # Centralised type stubs for third-party libs
│   ├── pyproject.toml           # Shared ruff + basedpyright configuration
│   └── justfile                 # Cross-workspace lint / type / test
├── frontend/                    # Vite + React + TypeScript
├── infrastructure/              # OpenTofu / Terraform stub
├── generated/                   # OpenAPI / AsyncAPI schemas (gitignored — regenerated by `just generate_types`)
├── .github/
│   └── CODEOWNERS
├── justfile                     # Repo-wide entrypoint
└── README.md

Getting started

Requirements:

just setup           # set everything up (backend + frontend + pre-commit)
just backend run     # start Django + Celery worker + Postgres + Redis
just run             # start the frontend (Vite dev server on :5173)

The included demo: POST /api/notifications/ simulates an outgoing email. The request returns immediately; a Celery task picks the row up, sleeps a couple of seconds (where you'd call a real asynchronous task), and flips the status to SENT. The frontend polls every second so you can watch the state transition.

To run every quality gate across the monorepo:

just backend lint
just backend type
just backend test

Each command is also available inside an individual workspace (e.g. cd backend/django && just lint).

Why this layout?

See the talk for the long version. In short:

  1. One folder per language: backend/ for Python, frontend/ for TypeScript, infrastructure/ for IaC, generated/ for cross-language artefacts.
  2. One uv workspace per deployable unit (django, ml). The two never share a virtual environment, which keeps heavy ML dependencies out of the Django image.
  3. just as the single entrypoint — versions for ruff, pyright, and pytest are pinned once in backend/justfile and inherited by every sub-project.
  4. Local-first development: a single just setup boots Postgres, Redis and the Celery worker, so a single command brings up everything needed to exercise the async path end to end.
  5. Generated artefacts are derived state, not source — generated/ and the frontend's src/generated/ are gitignored. Both just setup and just generate_types regenerate them, so a fresh clone always rebuilds from the live Django schema rather than a stale committed snapshot.

License

MIT — feel free to use this as a starting point for your own project.

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages