What to build
Make the template easier to extend with another CRUD resource by documenting the concrete code paths that must be updated and by moving repeated API-test assertions into shared test utilities.
This is related to #25, but it is narrower: the focus here is resource extension, test reuse, integration-test prerequisites, and local command portability.
Verified repository evidence
- The only full resource slice is
Entity, spread across:
app/model/entity.py
app/io/entity.py
app/repository/entity.py
app/service/entity.py
app/routes/entity.py
tests/unit/io/test_entity.py
tests/unit/service/test_entity_service_behaviour.py
tests/integration/test_entities_api.py
- Resource registration is split across several files:
app/model/__init__.py imports and exports Entity.
alembic/env.py uses Base.metadata as Alembic target_metadata, so new SQLAlchemy models need to be imported into the model package before autogeneration can see them.
app/io/__init__.py re-exports entity schemas.
app/repository/__init__.py re-exports EntityRepository.
app/service/__init__.py defines service_dependency(...), creates get_entity_service, and exports both EntityService and get_entity_service.
app/routes/__init__.py mounts health_route on public_route and entity_route on auth-protected protected_route.
app/exceptions/__init__.py re-exports NoEntityFoundError.
- Protected integration tests rely on a marker:
tests/integration/conftest.py defines WithAuth = pytest.mark.with_auth.
- The
app_client fixture only injects the Bearer token when the current test has the with_auth marker.
tests/integration/test_entities_api.py uses @WithAuth for protected entity API tests.
- Integration tests require Docker/Testcontainers:
tests/integration/conftest.py starts PostgresContainer(image="postgres:18-alpine", ...).
pyproject.toml documents the integration marker, but README only shows make test and make test-cov.
- API response assertion helpers are local to
tests/integration/test_entities_api.py:
_assert_problem_details(...)
_assert_validation_problem(...)
_assert_unauthorized(...)
- Unit-test fixtures are inconsistent:
tests/unit/conftest.py provides mock_session and mock_entity_repository.
tests/unit/service/test_entity_service_behaviour.py defines local session and repository fixtures instead of using the shared fixture pattern.
- The
Makefile run target is POSIX-shell-specific:
- It uses
[ ! -f .env ], cp, and backslash continuations.
- README does not provide PowerShell-friendly equivalents for setup/run/test commands.
Acceptance criteria
Non-goals
- Do not add a second public endpoint just for demonstration; the existing health route already exercises the public router path.
- Do not change authentication behavior for the existing protected entity routes.
- Do not reduce the current integration coverage for entity CRUD, validation, authorization, pagination, missing records, or telemetry.
What to build
Make the template easier to extend with another CRUD resource by documenting the concrete code paths that must be updated and by moving repeated API-test assertions into shared test utilities.
This is related to #25, but it is narrower: the focus here is resource extension, test reuse, integration-test prerequisites, and local command portability.
Verified repository evidence
Entity, spread across:app/model/entity.pyapp/io/entity.pyapp/repository/entity.pyapp/service/entity.pyapp/routes/entity.pytests/unit/io/test_entity.pytests/unit/service/test_entity_service_behaviour.pytests/integration/test_entities_api.pyapp/model/__init__.pyimports and exportsEntity.alembic/env.pyusesBase.metadataas Alembictarget_metadata, so new SQLAlchemy models need to be imported into the model package before autogeneration can see them.app/io/__init__.pyre-exports entity schemas.app/repository/__init__.pyre-exportsEntityRepository.app/service/__init__.pydefinesservice_dependency(...), createsget_entity_service, and exports bothEntityServiceandget_entity_service.app/routes/__init__.pymountshealth_routeonpublic_routeandentity_routeon auth-protectedprotected_route.app/exceptions/__init__.pyre-exportsNoEntityFoundError.tests/integration/conftest.pydefinesWithAuth = pytest.mark.with_auth.app_clientfixture only injects the Bearer token when the current test has thewith_authmarker.tests/integration/test_entities_api.pyuses@WithAuthfor protected entity API tests.tests/integration/conftest.pystartsPostgresContainer(image="postgres:18-alpine", ...).pyproject.tomldocuments theintegrationmarker, but README only showsmake testandmake test-cov.tests/integration/test_entities_api.py:_assert_problem_details(...)_assert_validation_problem(...)_assert_unauthorized(...)tests/unit/conftest.pyprovidesmock_sessionandmock_entity_repository.tests/unit/service/test_entity_service_behaviour.pydefines localsessionandrepositoryfixtures instead of using the shared fixture pattern.Makefileruntarget is POSIX-shell-specific:[ ! -f .env ],cp, and backslash continuations.Acceptance criteria
CONTRIBUTING.md.app/model/__init__.pyso Alembic metadata includes the model.app/io/__init__.pyexport.app/repository/__init__.pyexport.get_*_service = service_dependency(...)wiring andapp/service/__init__.pyexport.app/routes/__init__.py.app/exceptions/__init__.pyexport when the resource needs a typed 404 or domain error.protected_route.public_route.uv run --group test pytest -m unituv run --group test pytest -m integration@WithAuthorpytest.mark.with_auth.uv run ruff check .uv run ty checktests/integration/test_entities_api.pyinto a reusable test helper module, for exampletests/helpers/api_assertions.pyortests/integration/helpers.py.mock_session/ repository fixture pattern in service tests, orMakefilerunbootstrap with a cross-platform helper script.uv run --group test pytest -m unituv run --group test pytest -m integrationwhen Docker is runninguv run ruff check .uv run ty checkNon-goals