ERP (Bookkeeping) Example
The ERP example is a full, domain-driven reference application that demonstrates HyperAdmin in a realistic multi-module setup. It is the recommended starting point for adopters building admin interfaces over relational data.
Source: examples/erp/
What it demonstrates
- Multi-module auto-discovery — each domain (
contacts,sales,purchases,accounting) is a standalone Python package;Admin(discover_apps=[...])wires them all automatically. - Relational data — invoices belong to contacts, invoice items belong to invoices, journal lines belong to journal entries. HyperAdmin handles all FK list/detail views out of the box.
- Built-in RBAC —
hyperadmin.authis added as a discovered app; aSessionAuthBackendandModelPermissionCheckerguard every route. - Custom report — the Annual Profit & Loss view shows how to add a custom FastAPI router and Jinja2 template that integrate with the admin sidebar and base layout.
- Large seed dataset — 100 contacts, 500+ invoices, 800+ bills give meaningful pagination, search, and sort behaviour under realistic load.
Modules
| Module | Key Models | Description |
|---|---|---|
contacts |
Contact |
Customers and suppliers |
sales |
Invoice, InvoiceItem |
Customer invoices with line items |
purchases |
Bill, BillItem |
Supplier bills with line items |
accounting |
Account, JournalEntry, JournalLine |
Chart of accounts, double-entry ledger |
auth |
User, Group, Permission |
Built-in HyperAdmin RBAC |
Quick start
Docker (zero setup)
docker compose -f examples/erp/docker-compose.yml up --build
Open http://localhost:8000/admin — login admin / admin.
Local (uv)
uv sync --all-extras
uv run fastapi dev examples/erp/main.py
Open http://127.0.0.1:8000/admin — login admin / admin.
Seed command
The database is seeded automatically on first start. To reseed from scratch:
rm erp.db
uv run fastapi dev examples/erp/main.py
Key files
| File | Purpose |
|---|---|
main.py |
FastAPI app, Admin wiring, lifespan seeding |
db.py |
Async SQLite engine |
seed.py |
Faker-based seed script (contacts, invoices, bills, accounts) |
*/models.py |
SQLModel table definitions per module |
*/admin.py |
ModelAdmin registrations per module |
reports/views.py |
Custom Annual P&L FastAPI router |
templates/reports/profit_loss.html |
Custom Jinja2 report template |
Custom P&L report
The report extends HyperAdmin with a plain FastAPI APIRouter:
# examples/erp/main.py (excerpt)
app.include_router(reports_router)
admin.templates.env.globals["nav_items"].append(
{"name": "Profit & Loss Report", "url": "/reports/profit-loss", "icon": "ha-icon-chart"}
)
The template at templates/reports/profit_loss.html extends {% extends "base.html" %} so it
inherits the sidebar, header, and HTMX bindings without any extra setup.
Visit /admin/reports/profit-loss?year=2024 (or leave year blank for the current year).
Next: Frontend Overview