Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .claude/skills/add-endpoint/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: add-endpoint
description: Step-by-step recipes for adding an endpoint or modifying the schema in this repo
---

# Endpoint and schema recipes

**Add an endpoint**: Add Pydantic model in `models/` if the request/response
Comment thread
coderabbitai[bot] marked this conversation as resolved.
shape is new β†’ add async service method in `services/` with error handling and
rollback β†’ add route in `routes/` with `Depends(generate_async_session)` β†’
add tests following the naming pattern β†’ run pre-commit checks.

**Modify schema**: Update `schemas/player_schema.py` β†’ run
`uv run alembic revision --autogenerate -m "description"` to generate a
migration β†’ review and adjust the generated file in `alembic/versions/` β†’
run `uv run alembic upgrade head` β†’ update `models/player_model.py` if the
API shape changes β†’ update services and tests β†’ run `pytest`.
13 changes: 13 additions & 0 deletions .claude/skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: create-issue
description: Feature and bug GitHub Issue templates for this repo's Spec-Driven Development workflow
---

# Create an issue

Spec-Driven Development (SDD): discuss in Plan mode first, create a GitHub
Issue as the spec artifact, then implement. Always offer to draft an issue
before writing code.

- Feature (`enhancement`): Problem β†’ Proposed Solution β†’ Acceptance Criteria β†’ References
- Bug (`bug`): Description β†’ Steps to Reproduce β†’ Expected/Actual Behavior β†’ Environment
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,21 @@ This project uses famous football coaches as release codenames, following an A-Z
- ADR-0011: Use Coach-Themed Semantic Versioning
- ADR-0012: Adopt AI-Assisted Development Workflow
- ADR-0013: Adopt Spec-Driven Development (SDD)
- `.claude/skills/create-issue/SKILL.md` and `.claude/skills/add-endpoint/SKILL.md`:
extracted from `CLAUDE.md` as on-demand skills, so the SDD issue templates and
the endpoint/schema-change recipes load only when invoked instead of every
session; each starts with a top-level heading per `markdownlint` MD041

### Changed

- `CLAUDE.md`: trimmed the Tech Stack list, plain directory tree, and Overview
prose (all reconstructable from `pyproject.toml` and `ls`); moved "Creating
Issues" and "Key workflows" to on-demand skills; `Releases` section now
points to `CHANGELOG.md`'s coach table as the single source instead of
duplicating it; removed the "Pre-commit Checks" section and the Quick Start
linting commands, both already covered by `.claude/commands/pre-commit.md`;
removed the "Line length" / "Import order" bullets, already enforced by
`.flake8` and Black config
- `CLAUDE.md`: fix stale `docker-compose.yml` reference to `compose.yaml`; add
`rest/` and `gunicorn.conf.py` to Structure section; condense "Creating
Issues" templates from 18 lines to 4 lines; remove redundant commit format
Expand Down
95 changes: 17 additions & 78 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,16 @@
## Claude Code

- Run `/pre-commit` to execute the full pre-commit checklist for this project.

## Overview

REST API for managing football players built with Python and FastAPI. Implements
async CRUD operations with SQLAlchemy 2.0 (async), SQLite, Pydantic validation,
and in-memory caching.

## Tech Stack

- **Language**: Python 3.13
- **Framework**: FastAPI + Uvicorn
- **ORM**: SQLAlchemy 2.0 (async) + aiosqlite
- **Database**: SQLite (local/test), PostgreSQL-compatible
- **Migrations**: Alembic (async, `render_as_batch=True`)
- **Validation**: Pydantic
- **Caching**: aiocache (in-memory, 10-minute TTL)
- **Testing**: pytest + pytest-cov + httpx
- **Linting/Formatting**: Flake8 + Black
- **Containerization**: Docker
- Run `/pre-release` before tagging a release.
- See `.claude/skills/create-issue/SKILL.md` for the SDD issue workflow, and
`.claude/skills/add-endpoint/SKILL.md` for the endpoint/schema workflows.

## Structure

```text
main.py β€” application entry point: FastAPI setup, router registration
alembic.ini β€” Alembic configuration (sqlalchemy.url set dynamically)
alembic/ β€” Alembic migration environment and version scripts
routes/ β€” HTTP route definitions, caching + dependency injection [HTTP layer]
services/ β€” async business logic [business layer]
schemas/ β€” SQLAlchemy ORM models (database schema) [data layer]
databases/ β€” async SQLAlchemy session setup + get_database_url()
models/ β€” Pydantic models for request/response validation
scripts/ β€” shell scripts for Docker (entrypoint.sh, healthcheck.sh)
tools/ β€” legacy standalone seed scripts (superseded by Alembic migrations)
rest/ β€” HTTP request file (players.rest) for manual API testing
gunicorn.conf.py β€” production WSGI worker config (used by Docker entrypoint)
tests/ β€” pytest integration tests
```

**Layer rule**: `Routes β†’ Services β†’ SQLAlchemy β†’ SQLite`. Routes handle HTTP
concerns only; business logic belongs in services. Never skip a layer.
`tools/` is legacy (superseded by Alembic migrations); `gunicorn.conf.py` is
used by the Docker entrypoint.

## Coding Guidelines

Expand Down Expand Up @@ -71,8 +41,6 @@ concerns only; business logic belongs in services. Never skip a layer.
validation returns 422 (not 400); squad number mismatch on PUT returns 400
(not 422 β€” it is a semantic error, not a validation failure)
- **Logging**: `logging` module only; never `print()`
- **Line length**: 88; complexity ≀ 10
- **Import order**: stdlib β†’ third-party β†’ local
- **Tests**: integration tests against the real SQLite DB (seeded via
Alembic migrations) via `TestClient` β€” no mocking. Naming pattern
`test_request_{method}_{resource}_{context}_response_{outcome}`;
Expand Down Expand Up @@ -106,10 +74,6 @@ uv run uvicorn main:app --reload --port 9000 # http://localhost:9000/docs
uv run pytest # run tests
uv run pytest --cov=./ --cov-report=term # with coverage (target >=80%)

# Linting and formatting
uv run flake8 .
uv run black --check .

# Migration workflow
uv run alembic upgrade head # apply all pending migrations
uv run alembic downgrade -1 # roll back last migration
Expand All @@ -120,18 +84,6 @@ docker compose up
docker compose down -v
```

### Pre-commit Checks

1. Update `CHANGELOG.md` `[Unreleased]` section (Added / Changed / Fixed /
Removed)
2. `uv run flake8 .` β€” must pass
3. `uv run black --check .` β€” must pass
4. `uv run pytest` β€” all tests must pass
5. `uv run pytest --cov=./ --cov-report=term` β€” coverage must be β‰₯80%
6. Commit message follows Conventional Commits format (enforced by commitlint)
7. If this commit introduces or changes an architectural decision, update
`CLAUDE.md` and create or amend the relevant ADR in `docs/adr/`

### Commits

Format: `type(scope): description (#issue)` β€” max 80 chars
Expand All @@ -141,16 +93,9 @@ Example: `feat(api): add player stats endpoint (#42)`
### Releases

Tags follow the format `v{MAJOR}.{MINOR}.{PATCH}-{COACH}` (e.g.
`v2.0.0-capello`). The CD pipeline validates the coach name against a fixed
list (A–Z):

```
ancelotti bielsa capello delbosque eriksson ferguson guardiola heynckes
inzaghi klopp kovac low mourinho nagelsmann ottmar pochettino queiroz
ranieri simeone tuchel unai vangaal wenger xavi yozhef zeman
```

Never suggest a release tag with a coach name not on this list.
`v2.0.0-capello`). Valid coach names (A–Z) are maintained in `CHANGELOG.md`'s
naming-convention table β€” the same table `/pre-release` reads. Never suggest
a release tag with a coach name not in that table.

## Agent Mode

Expand Down Expand Up @@ -190,25 +135,19 @@ Never suggest a release tag with a coach name not on this list.

### Creating Issues

Spec-Driven Development (SDD): discuss in Plan mode first, create a GitHub Issue as the spec artifact, then implement. Always offer to draft an issue before writing code.

- Feature (`enhancement`): Problem β†’ Proposed Solution β†’ Acceptance Criteria β†’ References
- Bug (`bug`): Description β†’ Steps to Reproduce β†’ Expected/Actual Behavior β†’ Environment
Spec-Driven Development (SDD): discuss in Plan mode first, create a GitHub
Issue as the spec artifact, then implement. Always offer to draft an issue
before writing code. See `.claude/skills/create-issue/SKILL.md` for the
feature/bug issue templates.

### Key workflows

**Add an endpoint**: Add Pydantic model in `models/` if the request/response
shape is new β†’ add async service method in `services/` with error handling and
rollback β†’ add route in `routes/` with `Depends(generate_async_session)` β†’
add tests following the naming pattern β†’ run pre-commit checks.

**Modify schema**: Update `schemas/player_schema.py` β†’ run
`uv run alembic revision --autogenerate -m "description"` to generate a
migration β†’ review and adjust the generated file in `alembic/versions/` β†’
run `uv run alembic upgrade head` β†’ update `models/player_model.py` if the
API shape changes β†’ update services and tests β†’ run `pytest`.
See `.claude/skills/add-endpoint/SKILL.md` for the "add an endpoint" and
"modify schema" recipes.

**After completing work**: Propose a branch name and commit message for user approval. Do not create a branch, commit, or push until the user explicitly confirms.
**After completing work**: Propose a branch name and commit message for user
approval. Do not create a branch, commit, or push until the user explicitly
confirms.

## Invariants (never change without explicit discussion)

Expand Down