Marginalia
Library management system
A library system prototype to practice modelling a real domain end to end — cataloguing, patrons, and circulation. It has a staff console for the desk and a public catalogue (OPAC) for patrons.
Features
Staff console
The operational side: catalogue records, the circulation desk, and the hold shelf.
- Circulation desk — check out, return, and renew; load a patron; work the hold shelf.
- Catalog — the Work → Manifestation → Item tree, with availability derived from loans and holds.
- Records — register and edit patrons; move items through repair, lost, and withdrawn.

Public catalogue (OPAC)
What a patron sees: search the catalogue, place holds, and check their own account.
- Browse — search by title, author, or ISBN; filter by material type.
- Holds — reserve an edition and see your place in the queue.
- My library — current loans with due dates, and holds with their pickup dates.

More screens




Domain
The catalogue follows the FRBR model.
Work → Manifestation → Item
A Work has editions (Manifestations), and each edition has physical copies (Items). A copy's availability isn't stored — it's worked out from its state, its loans, and its holds.
Cards, categories, and policy
A patron has a category and a card that can expire; a suspended or expired card can't borrow. Loan periods and limits come from a policy keyed by category and material type, not hard-coded into the entities.
Loans and holds
Check out, return, and renew, with due dates. Holds queue per edition, go to the shelf when a copy comes back, and expire if nobody picks them up — swept on a schedule.
Demos


Clean Architecture
The code follows Clean Architecture — dependencies point inward. The domain and application layers import no web or database library, and a test enforces that.
flowchart LR
SPA["React SPA (staff + OPAC)"] -->|HTTP, same origin| IF["Interface: routers, schemas"]
IF --> APP["Application: use cases"]
APP --> DOM["Domain: entities, policy, services"]
APP --> PORTS["Repository ports"]
INFRA["Infrastructure: SQLAlchemy, Alembic"] -. implements .-> PORTS
INFRA --> DB[("SQLite / Postgres")]
- DomainEntities, the loan policy, and domain services. Plain Python, no framework.
- ApplicationUse cases over repository ports.
- InterfaceFastAPI routers, Pydantic schemas, and the React SPA.
- InfrastructureSQLAlchemy repositories and Alembic migrations.
How it's built
- Spec first — every requirement in SPEC.md is traced to the test that verifies it.
- Tests — unit and integration in pytest, end-to-end in Playwright.
- Decisions written down — ADRs for the bibliographic model, the loan aggregate, and so on.
- CI on every PR — the test suites, a Storybook build, and ruff.
- Migrations — Alembic owns the schema; the app migrates on startup.