# CRUD Template ## Summary Every resource follows the same four-file slice. Repetition is intentional: it makes the codebase predictable and generatable. --- ## The slice ``` domain// models.py # pure Pydantic model (no DB fields) ports/ db.py # document model + repository factory service.py # service class + factory converters.py # (optional) transforms ``` ## models.py A framework-free Pydantic model describing the business shape. ```python class Item(BaseModel): name: str quantity: int = 0 ``` ## ports/db.py The persistence model extends the business model and adds database concerns. The repository factory selects the right repository flavour. ```python class ItemDocument(Item, BaseDocument): # BaseDocument adds id/created_at/... pass def create_item_repo(*, owner_repo=None) -> ItemRepository: return repo_factory( collection="items", document=ItemDocument, populate_rules=[PopulateRule(field="owner", collection="users")], cache=None, # or a CachedBaseRepository config ) ``` ## ports/service.py The service is built through the DI library, injecting the repository. The generic CRUD base provides `create/read/update/patch/delete/search/...`. ```python class ItemService(CrudsServiceAdaptor[Item, ItemDocument]): model = Item schema = ItemDocument def get_item_service(repo) -> ItemService: return build(ItemService, instances={"repo": repo}) ``` ## Naming conventions | Concept | Convention | |---|---| | collection | plural snake case (`items`) | | document | `Document` | | repository factory | `create__repo` | | service | `Service` | | service factory | `get__service` | | resource key | `_svc` | | operationId | `list_items`, `create_item`, ... | ## Optional files - `converters.py` — pure functions mapping between domain types. - `ports/enrichment.py` — adapts a pipeline into an async callable the service can invoke (used when a resource is populated by a pipeline).