[Arch] main.py is a 1,553-line god module with no router split #50

Closed
opened 2026-07-01 07:26:27 +02:00 by bullitt · 1 comment
Owner

Severity: High | Category: Architecture

52 @app.* route handlers live in one flat file (grep -c "^@app\." main.py → 52); zero APIRouter/include_router usage anywhere.

Problem: No structural boundary between shipment CRUD, admin, auth, settings, scrapers. Hard to reason about locally; concentrates merge conflicts.

Recommendation: Split into APIRouter modules by resource (routers/shipments.py, routers/settings.py, routers/admin.py, routers/auth.py, routers/scrapers.py), mounted via app.include_router(...). Pure mechanical extraction.

Refactoring safety: tests/test_api.py + tests/test_multiuser.py already cover most routes end-to-end.

Full detail: docs/architecture-review.md § C, Finding "main.py is a 1,553-line god module..."

**Severity:** High | **Category:** Architecture 52 `@app.*` route handlers live in one flat file (`grep -c "^@app\." main.py` → 52); zero `APIRouter`/`include_router` usage anywhere. **Problem:** No structural boundary between shipment CRUD, admin, auth, settings, scrapers. Hard to reason about locally; concentrates merge conflicts. **Recommendation:** Split into `APIRouter` modules by resource (`routers/shipments.py`, `routers/settings.py`, `routers/admin.py`, `routers/auth.py`, `routers/scrapers.py`), mounted via `app.include_router(...)`. Pure mechanical extraction. **Refactoring safety:** `tests/test_api.py` + `tests/test_multiuser.py` already cover most routes end-to-end. Full detail: `docs/architecture-review.md` § C, Finding "main.py is a 1,553-line god module..."
Author
Owner

Fixed on branch architecture-rework, commits 933e290, 430d744, 1a6ff16, de06465: split main.py's 52 route handlers into routers/admin.py, routers/auth.py, routers/settings.py, routers/scrapers.py, routers/shipments.py, mounted via app.include_router(). main.py shrinks from 1,553 lines / 52 routes to 630 lines / 5 core routes (/ingest, /health, /metrics, /api/releases, /api/stats) plus middleware, startup/shutdown, the exception handler, and shared singletons.

Routers needing main.py's shared state (scheduler, notifiers, rate limiters) use import main and only read main.xxx inside function bodies, deferring attribute access to request time — main.py includes the routers after all its own singletons/helpers are defined, so this avoids a circular import without needing a separate app-state module. Caught and fixed one real test-visibility regression along the way: a router importing scrape_single directly (instead of via main.scrape_single) broke tests patching main.scrape_single. Full suite: 259 passed at completion.

Fixed on branch `architecture-rework`, commits 933e290, 430d744, 1a6ff16, de06465: split main.py's 52 route handlers into `routers/admin.py`, `routers/auth.py`, `routers/settings.py`, `routers/scrapers.py`, `routers/shipments.py`, mounted via `app.include_router()`. main.py shrinks from 1,553 lines / 52 routes to 630 lines / 5 core routes (`/ingest`, `/health`, `/metrics`, `/api/releases`, `/api/stats`) plus middleware, startup/shutdown, the exception handler, and shared singletons. Routers needing main.py's shared state (scheduler, notifiers, rate limiters) use `import main` and only read `main.xxx` inside function bodies, deferring attribute access to request time — main.py includes the routers after all its own singletons/helpers are defined, so this avoids a circular import without needing a separate app-state module. Caught and fixed one real test-visibility regression along the way: a router importing `scrape_single` directly (instead of via `main.scrape_single`) broke tests patching `main.scrape_single`. Full suite: 259 passed at completion.
Sign in to join this conversation.
No labels
arch
harness
security
ux
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bullitt/trackbox#50
No description provided.