Skip to content

Modular Monolith Contract

Module Isolation Model

A module is a business capability with internal files: - api.py - service.py - repo.py - schemas.py - models.py - deps.py

Each module owns its own behavior and data access rules.

Allowed Imports

  • module -> itself
  • module -> racerapi.core.*
  • module -> racerapi.shared.*

Forbidden Imports

  • module -> another module (for example users -> auth)

Example Layout

src/racerapi/modules/
  users/
  health/

Example of Correct Internal Use

# users/service.py
from racerapi.modules.users.repo import UserRepo

Example of Forbidden Coupling

# forbidden: users/service.py
from racerapi.modules.health.service import HealthService

Why This Matters

Direct cross-module imports create hidden dependency graphs that eventually block independent extraction and safe refactoring.

DO

  • Communicate across modules via API boundaries or explicit shared abstractions in core/shared.
  • Keep module-local invariants inside service layer.

DON'T

  • Import another module because “it is easy right now”.
  • Put domain logic in shared helpers.

Common Mistakes

  • Building a "shared business utils" file that contains domain behavior.
  • Copying repo queries between modules instead of creating module-owned queries.

When to Break the Rule

Only for controlled migrations where temporary adapters exist with: - TODO + owner + removal date, - test coverage proving behavior, - architecture review approval.