@@ -47,6 +47,7 @@ Request → Routes → Services → SQLAlchemy → SQLite
4747```
4848
4949** Key Directories:**
50+
5051- ` routes/ ` - API endpoints (player_route.py, health_route.py)
5152- ` services/ ` - Business logic (player_service.py)
5253- ` models/ ` - Pydantic validation (camelCase JSON API)
@@ -56,6 +57,7 @@ Request → Routes → Services → SQLAlchemy → SQLite
5657- ` tests/ ` - pytest suite (test_main.py, conftest.py)
5758
5859** Config Files:**
60+
5961- ` .flake8 ` - Linter (max-line-length=88, complexity=10)
6062- ` pyproject.toml ` - Black formatter (line-length=88)
6163- ` .coveragerc ` - Coverage config (80% target)
@@ -65,6 +67,7 @@ Request → Routes → Services → SQLAlchemy → SQLite
6567## API Endpoints
6668
6769All async with ` AsyncSession ` injection:
70+
6871- ` POST /players/ ` → 201|409|422
6972- ` GET /players/ ` → 200 (cached 10min)
7073- ` GET /players/{player_id} ` → 200|404
@@ -78,11 +81,13 @@ JSON: camelCase (e.g., `squadNumber`, `firstName`)
7881## CI/CD
7982
8083** python-ci.yml** (push/PR to master):
84+
81851 . Lint: commitlint → ` flake8 . ` → ` black --check . `
82862 . Test: ` pytest -v ` → coverage
83873 . Upload to Codecov
8488
8589** python-cd.yml** (tags ` v*.*.*-* ` ):
90+
86911 . Validate semver + coach name
87922 . Run tests
88933 . Build Docker (amd64/arm64)
@@ -92,19 +97,22 @@ JSON: camelCase (e.g., `squadNumber`, `firstName`)
9297## Critical Patterns
9398
9499### Async Everywhere
100+
95101``` python
96102# Always use async/await
97103async def get_player (async_session : AsyncSession, player_id : int ):
98104 stmt = select(Player).where(Player.id == player_id)
99105 result = await async_session.execute(stmt)
100106 return result.scalar_one_or_none()
101107```
108+
102109- All routes: ` async def `
103110- Database: ` AsyncSession ` (never ` Session ` )
104111- Driver: ` aiosqlite ` (not ` sqlite3 ` )
105112- SQLAlchemy 2.0: ` select() ` (not ` session.query() ` )
106113
107114### camelCase API Contract
115+
108116``` python
109117class PlayerModel (BaseModel ):
110118 model_config = ConfigDict(alias_generator = to_camel)
@@ -113,14 +121,17 @@ class PlayerModel(BaseModel):
113121```
114122
115123### Database Schema Changes
124+
116125⚠️ No Alembic yet - manual process:
126+
1171271 . Update ` schemas/player_schema.py `
1181282 . Manually update ` storage/players-sqlite3.db ` (SQLite CLI/DB Browser)
1191293 . Preserve 26 players
1201304 . Update ` models/player_model.py ` if API changes
1211315 . Update services + tests
122132
123133### Caching
134+
124135- Key: ` "players" ` (hardcoded)
125136- TTL: 600s (10min)
126137- Cleared on POST/PUT/DELETE
@@ -160,18 +171,21 @@ curl http://localhost:9000/players # 200 OK
160171Integration tests follow an action-oriented pattern:
161172
162173** Pattern:**
163- ```
174+
175+ ``` text
164176test_request_{method}_{resource}_{param_or_context}_response_{outcome}
165177```
166178
167179** Components:**
180+
168181- ` method ` - HTTP verb: ` get ` , ` post ` , ` put ` , ` delete `
169182- ` resource ` - ` players ` (collection) or ` player ` (single resource)
170183- ` param_or_context ` - Request details: ` id_existing ` , ` squadnumber_nonexistent ` , ` body_empty `
171184- ` response ` - Literal separator
172185- ` outcome ` - What's asserted: ` status_ok ` , ` status_not_found ` , ` body_players ` , ` header_cache_miss `
173186
174187** Examples:**
188+
175189``` python
176190def test_request_get_players_response_status_ok (client ):
177191 """ GET /players/ returns 200 OK"""
@@ -184,6 +198,7 @@ def test_request_post_player_body_empty_response_status_unprocessable(client):
184198```
185199
186200** Docstrings:**
201+
187202- Single-line, concise descriptions
188203- Complements test name (doesn't repeat)
189204- No "Expected:" prefix (redundant)
@@ -195,12 +210,14 @@ Follow Conventional Commits format (enforced by commitlint in CI):
195210** Format:** ` type(scope): description (#issue) `
196211
197212** Rules:**
213+
198214- Max 80 characters
199215- Types: ` feat ` , ` fix ` , ` docs ` , ` test ` , ` refactor ` , ` chore ` , ` ci ` , ` perf ` , ` style ` , ` build `
200216- Scope: Optional (e.g., ` api ` , ` db ` , ` service ` , ` route ` )
201217- Issue number: Required suffix
202218
203219** Examples:**
220+
204221``` text
205222feat(api): add player stats endpoint (#42)
206223fix(db): resolve async session leak (#88)
0 commit comments