Invoke when creating any new entity, resource, or endpoint group (e.g. 'add tags', 'create a bookmarks table', 'I need CRUD for X'). Generates model, schemas, router, and tests.
$ARGUMENTSPropose a set of fields (names, types, relationships, constraints) for the resource based on its name and the existing codebase context. Present the proposal to the user for approval before writing any code.
Derive names from $ARGUMENTS (singular, e.g. "tag"): PascalCase for class, plural snake_case for table/router/test file.
Read these files for patterns before generating code:
backend/app/models.py — model conventionsbackend/app/schemas.py — schema conventionsbackend/app/routers/reviews.py — router conventionsbackend/tests/test_reviews.py — test conventionsbackend/app/models.pybackend/app/schemas.pybackend/app/routers/<table>.py with POST, GET list (paginated), GET by id, PUT, DELETEapp.include_router() in backend/app/main.pybackend/tests/test_<table>.py — 8 tests: create, list, get, get-404, update, update-404, delete, delete-404cd backend && python -m pytest tests/test_<table>.py -v — all must passAll models must use soft delete instead of hard delete:
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None, index=True) to every modeldeleted_at = datetime.utcnow() instead of db.delete()where(Model.deleted_at.is_(None)) — list, get-by-id, and any relationship joinsdeleted_atdeleted_at set (not physically removed), and verify GET returns 404default=datetime.utcnow — no parens, it's a function referencecascade="all, delete-orphan" on parent relationship — required for delete to workForeignKey("table.id", ondelete="CASCADE") with index=True on every FK columnmodel_config = {"from_attributes": True} on response/list schemas only, not on createscalar_one_or_none() for single lookups, scalars().all() for listsselectinload() for any relationship accessed in the responseoffset/limit pagination, never unboundedapp.routers.<table>.func), not definition pathconftest.py fixtures (client, setup_db) — no extra setupcomment_count) go in the list endpoint builder, not the model