Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
1c6c0be
docs: spec design SOMA Python template v2
vianneybacoup May 5, 2026
4a4c3db
feat: phase A - cookiecutter scaffolding + minimal generated project
vianneybacoup May 5, 2026
5ad178c
feat: phase B+D1 - clean architecture skeleton + custom lints
vianneybacoup May 5, 2026
ac329a1
feat: phase C+D2 - reference feature, fakes, hardened ruff/ty config
vianneybacoup May 5, 2026
4651e63
feat: phase E+F - prod Dockerfile, devcontainer stack, Helm chart
vianneybacoup May 5, 2026
c810474
feat: phase G+H - CI workflows + Claude Code integration
vianneybacoup May 5, 2026
72a4da5
feat: phase I+K - documentation, ADRs, template repo CI
vianneybacoup May 5, 2026
f2511c2
feat: base classes + use case instrumentation wrapper
vianneybacoup May 6, 2026
557b83e
feat: tier 1 — initial migration, health probe split, conftest fixtures
vianneybacoup May 6, 2026
b22f03e
feat: tier 2 — middleware stack, graceful shutdown, image supply chain
vianneybacoup May 6, 2026
35bb5b4
feat: add justfile + install just in devcontainer
vianneybacoup May 6, 2026
7d1d489
feat: conditional OpenAPI export + TypeScript SDK generation
vianneybacoup May 6, 2026
122fb1b
feat: mermaid diagrams + transaction boundary + outbox pattern stub
vianneybacoup May 6, 2026
d8cd549
feat: tier 5 polish — LICENSE, CODEOWNERS, SECURITY.md
vianneybacoup May 6, 2026
8ff96e2
refactor: drop ci-conventional-commits + remove cron from ci-mutation
vianneybacoup May 6, 2026
434490e
feat: ty strict + prometheus /metrics + adding-a-new-abstraction skill
vianneybacoup May 6, 2026
832e49e
docs: README section for removing the User reference feature
vianneybacoup May 6, 2026
af5143c
refactor: split conftests per layer + add SqlAlchemyUserRepository in…
vianneybacoup May 6, 2026
e28c716
refactor: replace 'aggregate' with 'entity' in docs and skills
vianneybacoup May 6, 2026
080640c
fix: devcontainer image tags + bake just into the dev image + gracefu…
vianneybacoup May 7, 2026
60aec04
fix: integration tests in the devcontainer — Docker outside of Docker…
vianneybacoup May 7, 2026
f7fb06c
fix(devcontainer): set moby=false on docker-outside-of-docker Feature
vianneybacoup May 7, 2026
9fdc621
fix(tests): silence SAWarning by using create_savepoint in pg_session
vianneybacoup May 7, 2026
bd6f30c
docs(skills): pass 1 — onboarding-soma + tdd-workflow + writing-tests…
vianneybacoup May 7, 2026
8dc3e69
docs(skills): pass 2 — clean-architecture-layers + writing-domain-cod…
vianneybacoup May 7, 2026
c8ded0a
docs(skills): pass 3 — adding-a-use-case + adding-a-domain-exception …
vianneybacoup May 10, 2026
7d56573
docs(skills): pass 4 (tactical) — di / transactions-and-events / db-a…
vianneybacoup May 10, 2026
8cfc604
docs(skills): pass 5 (quality) — reviewing-a-pr-soma-style
vianneybacoup May 10, 2026
e612f30
feat: Introduce new agents and skills for orchestrating feature devel…
vianneybacoup May 12, 2026
806e84c
feat(events): wire in-process handler registry for the outbox relay
vianneybacoup May 12, 2026
09fdce4
feat(auth): bearer-JWT scaffold with HS256 default and JWKS swap path
vianneybacoup May 12, 2026
c800e89
feat(outbox): retry backoff + dead-letter + dedicated relay Deployment
vianneybacoup May 12, 2026
459cdb3
feat(helm): PrometheusRule with outbox + API + relay alerts
vianneybacoup May 12, 2026
9f0854f
feat(idempotency): client-retry safety via Idempotency-Key middleware
vianneybacoup May 12, 2026
c85995f
docs(runbooks): ship backups + disaster-recovery playbooks
vianneybacoup May 12, 2026
0ff8bde
docs(skills): event-sourcing-pattern skill + bootstrapper agent
vianneybacoup May 12, 2026
fc3d7d3
feat(agents): feature-level builders for business-intent prompts
vianneybacoup May 12, 2026
1c2881a
docs(validation): TODO API walkthrough plan for end-to-end template test
vianneybacoup May 12, 2026
f1c4ef8
docs(validation): align walkthrough plan with feature-level builders
vianneybacoup May 18, 2026
a66dfef
feat(skills): pivot to outside-in TDD
vianneybacoup May 19, 2026
4342393
fix(devcontainer): auto-configure docker.sock access on plain compose up
vianneybacoup May 19, 2026
fa02b38
docs(skill): strip pre-design from enrichment pattern
vianneybacoup May 19, 2026
f7845cf
chore(claude): remove 8 custom sub-agents
vianneybacoup May 20, 2026
0c1322c
refactor(skills): bundle three core skills as comprehensive references
vianneybacoup May 20, 2026
40a1e24
feat(skills): add building-a-feature as end-to-end feature runbook
vianneybacoup May 20, 2026
a3c5931
chore(skills): remove 12 absorbed and dropped skills
vianneybacoup May 20, 2026
6dec683
refactor(template): rewire CLAUDE.md, hooks, bake test, spec and cros…
vianneybacoup May 20, 2026
371fe12
docs(validation): TodoList walkthrough — Phase 1 and 2 report
vianneybacoup May 20, 2026
785db98
docs(validation): walkthrough followups backlog (P0/P1/P2)
vianneybacoup May 20, 2026
17579f2
fix(template): correct mutmut config (lists + also_copy)
vianneybacoup May 20, 2026
71c5c34
fix(template): import all ORM models in models/__init__.py
vianneybacoup May 20, 2026
a5bad00
fix(template): make ``just lint`` pass out of the box on baked projects
vianneybacoup May 20, 2026
c115663
docs(skill): clarify that idempotency replay is not testable via e2e
vianneybacoup May 20, 2026
0cf2a07
fix(template): align initial migrations with what the models declare
vianneybacoup May 20, 2026
be438e4
feat(template): add ``just devcontainer-reset`` recipe
vianneybacoup May 20, 2026
e2c23cd
docs(validation): mark all P0 items resolved in the followups backlog
vianneybacoup May 20, 2026
7c07a67
docs(skill): harden the "no domain pre-decision" rule in the plan
vianneybacoup May 20, 2026
6ea6798
docs(skill): add "Aggregates with nested children" persistence pattern
vianneybacoup May 20, 2026
31b1af5
docs(skill): add "kill the obvious mutmut survivors" checklist
vianneybacoup May 20, 2026
c92623d
docs(validation): mark P1 items resolved (only sub-agent decision left)
vianneybacoup May 20, 2026
5eafa19
docs(skill,validation): document Phase 3 auth findings
vianneybacoup May 20, 2026
f4363a2
docs(readme): document non-interactive cookiecutter usage with overrides
vianneybacoup May 21, 2026
0b64d88
docs(skill): make "one test == one assert == one reason to fail" prom…
vianneybacoup May 21, 2026
4341aae
feat(auth): expose 'name' claim on CurrentUser
vianneybacoup May 21, 2026
2ca0d2d
feat(template): replace POST /v1/users with SSO auto-provisioning
vianneybacoup May 21, 2026
b8918f1
feat(template): declare HTTPBearer Security scheme for Swagger UI
vianneybacoup May 21, 2026
1af0acc
feat(template): full OAuth2 Authorization Code flow in Swagger UI
vianneybacoup May 21, 2026
4671587
chore(helm): wire SWAGGER_OAUTH2_* env vars into the chart
vianneybacoup May 21, 2026
6c70878
chore(helm): expose 8 missing env vars (db pool, request limits, idem…
vianneybacoup May 21, 2026
33dbad3
docs(template): align skill + doc references with the SSO User reference
vianneybacoup May 21, 2026
983f7d5
feat(hooks): auto-run ruff check --fix + ruff format on every Edit/Write
vianneybacoup May 21, 2026
40e7b35
docs(skill): canonical pattern for testing external HTTP adapters (re…
vianneybacoup May 21, 2026
f3e063b
test(auth): cover RS256/JWKS path + name claim; embark respx as dev dep
vianneybacoup May 21, 2026
c951e0c
chore(template): drop 'none' from database menu, keep defensive pre_g…
vianneybacoup May 21, 2026
e94b5da
chore: remove docs/superpowers/ — design rationale now lives in git h…
vianneybacoup May 21, 2026
c4011fb
chore: remove docs/validation/ — walkthrough findings already actioned
vianneybacoup May 21, 2026
f8d0303
chore(template): make cookiecutter prompts non-technical and conseque…
vianneybacoup May 27, 2026
4064dba
fix(template): retry alembic migrate to absorb first-boot DNS race
vianneybacoup May 27, 2026
0b91b33
fix(devcontainer): drop static host port bindings, lean on VS Code's …
vianneybacoup May 27, 2026
650b893
test(template): enforce one-assert-per-test across the reference suite
vianneybacoup May 27, 2026
cf95c4e
test(template): one-assert-per-test in outbox relay + idempotency suites
vianneybacoup May 27, 2026
6dea2a8
fix(template): bump pydantic + switch devcontainer to uv-managed Pyth…
vianneybacoup May 27, 2026
3607240
chore(template): drop dead include_cli cookiecutter option
vianneybacoup May 27, 2026
8fbe8ce
chore(template): commit per post_gen step, faster bake, tighter dev loop
vianneybacoup May 29, 2026
6b16e40
feat(devcontainer): ship local Keycloak for oauth2_auth_code projects
vianneybacoup May 29, 2026
ce6f96b
refactor(tests): wire e2e on real adapters, reserve Fakes for unit
vianneybacoup May 29, 2026
9bd392f
chore(template): squash alembic versions + tighten skills doctrine
vianneybacoup May 29, 2026
866b6f1
chore(template): drop no_float_in_domain lint and its references
vianneybacoup May 29, 2026
bd87900
docs: reword building a feature skill
vianneybacoup Jun 1, 2026
cf9f53b
fix(ci): silence S607/S603 in bake tests' subprocess.run calls
vianneybacoup Jun 1, 2026
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
32 changes: 0 additions & 32 deletions .github/workflows/ci-quality.yml

This file was deleted.

31 changes: 31 additions & 0 deletions .github/workflows/ci-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI Template

on:
pull_request:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
bake-smoke:
name: bake (3 combos, smoke)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v7
with: { enable-caching: true }
- run: uv sync --group dev
- run: uv run pytest -m unit -v
- run: uv run ruff check hooks/ tests/

bake-integration:
name: bake + ruff + custom lints + pytest unit on baked project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v7
with: { enable-caching: true }
- run: uv sync --group dev
- run: uv run pytest -m integration -v
53 changes: 0 additions & 53 deletions .github/workflows/soma-quality.yml

This file was deleted.

7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,10 @@ Thumbs.db
.env
.env.*
!.env.example

# Cookiecutter local bake outputs
/tmp-bake/
/.bake/
# Locally baked test projects (any baked project living at the repo root).
# Keep them out of version control so devs can experiment freely.
/toto/
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Pre-commit for the template repo itself.
# The heavy guardrails (custom lints, ty, pytest, mutmut) live inside the
# generated project at {{cookiecutter.project_slug}}/.pre-commit-config.yaml.
# Cookiecutter-templated files contain Jinja syntax that breaks YAML/TOML
# parsers, so we exclude that whole directory from syntactic checks.

exclude: '^\{\{cookiecutter\.project_slug\}\}/'

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
Expand All @@ -8,6 +16,7 @@ repos:
- id: check-toml
- id: detect-private-key
- id: check-added-large-files
- id: check-merge-conflict

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.0
Expand Down
79 changes: 0 additions & 79 deletions AGENTS.md

This file was deleted.

48 changes: 48 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# dev-soma-template — Repo IA Rules

> This file governs **AI editing of the template itself**.
> The generated projects ship their own `CLAUDE.md` inside `{{cookiecutter.project_slug}}/CLAUDE.md`.

## What this repo is

A **Cookiecutter** that generates SOMA Python services. Output = a project with FastAPI + Clean Architecture + observability + Helm + multi-layer guardrails (Claude skills, hooks, pre-commit, CI).

The design rationale lives in the git history (commit messages are the source of truth for "why"). Each generated project ships its own `docs/architecture.md` and `docs/adr/`.

## Repo layout

```
.
├── cookiecutter.json # template variables
├── hooks/ # pre/post_gen_project Python hooks
├── tests/ # pytest-cookies bake tests of the template
└── {{cookiecutter.project_slug}}/ # the generated project (see its own CLAUDE.md)
```

## Hard rules for AI editors

1. **Two roots, two pyprojects, two CLAUDE.md** — never confuse them:
- root `pyproject.toml` = template tooling (cookiecutter, pytest, pytest-cookies, ruff)
- `{{cookiecutter.project_slug}}/pyproject.toml` = generated project deps (FastAPI, SQLAlchemy, etc.)
2. **Never** edit `{{cookiecutter.project_slug}}/` files to fix a generated-project bug discovered downstream — fix at the template level so the next bake inherits the fix.
3. **Cookiecutter templating syntax** uses `{{ cookiecutter.<var> }}`. Be careful when editing JSON/YAML files: Jinja braces inside JSON strings need to remain valid Jinja, not break JSON parsing.
4. **Bake tests are the contract** — adding a feature without updating `tests/test_template_bake.py` is a regression.
5. **Conventional commits** required. Branches: `feat/*`, `fix/*`, `docs/*`, `refactor/*`, `chore/*`. PRs must pass all CI checks.

## Editing workflow

1. Edit either the template machinery (root) **or** the generated project skeleton (`{{cookiecutter.project_slug}}/`) — rarely both in the same change.
2. Run bake tests locally: `uv run pytest`.
3. Write the commit message so it captures the *why* of the change (it's the long-term decision record).

## Commands

```bash
uv sync # install template tooling
uv run pytest # run bake tests
uv run cookiecutter . --no-input -o /tmp # bake with default values for manual inspection
uv run ruff check hooks/ tests/ # only on the template machinery — see note below
uv run ruff format hooks/ tests/
```

**Note on ruff paths**: `uv run ruff check .` fails because ruff walks into `{{cookiecutter.project_slug}}/` and tries to parse the Jinja-templated `pyproject.toml` as a nested config. Always pass explicit paths (`hooks/`, `tests/`) at the template root. Pre-commit handles this transparently via its `exclude` regex.
91 changes: 70 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,91 @@
# [NOM DU PROJET]
# dev-soma-template

> Template SOMA — remplacer ce fichier par la documentation du projet.
A **Cookiecutter** template that generates state-of-the-art SOMA Python services.

## Description
What you get out-of-the-box:

[Description du projet en 2-3 phrases]
- **FastAPI 0.115+** + **SQLAlchemy 2.0 async** + **asyncpg** + **Alembic**
- **Clean Architecture** (Uncle Bob strict): `domain` / `application` / `infrastructure` / `presentation`
- **uv** + **ruff** (extended ruleset) + **ty** (Astral type checker) + **mutmut** (mutation testing)
- **OpenTelemetry** auto-switching between console and OTLP exporters
- **structlog** with technical (JSON) and human-readable formats
- **Devcontainer** with full local stack (Postgres + Jaeger + OTel collector)
- **Helm chart** with multi-environment values, schema validation, migrations job
- **Multi-layer guardrails** preventing convention drift: Claude Code skills + hooks, pre-commit, git hooks, CI

## Stack
## Generate a new project

- Python 3.13
- [Framework principal]
- [Autres dépendances clés]

## Installation
### Interactive (recommended for first use)

```bash
# Installer les dépendances
uv sync
# Install cookiecutter (one-time, globally or via pipx/uvx)
uvx cookiecutter gh:soma-smart/dev-soma-template

# Installer le hook de commit (conventional commits)
bash /chemin/vers/doc-soma-manifest/templates/install-hooks.sh
# Or from a local clone
git clone git@github.com:soma-smart/dev-soma-template.git
uvx cookiecutter ./dev-soma-template
```

## Lancer le projet
### Non-interactive (CI, scripts, repeat bakes)

`cookiecutter` accepts overrides as positional `key=value` arguments
**after** the template path. Combine with `--no-input` to skip every
prompt and `-o <path>` to control the output directory:

```bash
[commandes pour démarrer le projet]
uvx cookiecutter ./dev-soma-template --no-input \
-o /tmp/out \
project_name="Billing API" \
database=postgres \
include_helm=yes
```

## Tests
Any variable not passed on the CLI uses its default from `cookiecutter.json`.
For larger configs, point `--config-file <path>` at a YAML file with a
`default_context:` mapping.

### Variables

You will be prompted for:

| Variable | Default | Description |
| ---------------------- | --------------------- | --------------------------------------------------- |
| `project_name` | `My SOMA Service` | Human-readable project name |
| `project_slug` | derived from name | Folder + repo slug (`kebab-case`) |
| `package_name` | derived from slug | Importable Python package (`snake_case`) |
| `project_description` | | One-liner |
| `author_name` | `SOMA` | |
| `author_email` | `team@soma-smart.com` | |
| `python_version` | `3.13` | `3.13` or `3.14` |
| `database` | `postgres` | `postgres` (full) or `sqlite` (light) |
| `include_helm` | `yes` | Ship a Helm chart |
| `include_otel` | `yes` | Wire OpenTelemetry instrumentations |
| `license` | `proprietary` | `proprietary`, `MIT`, `Apache-2.0` |

After generation, the post-hook automatically:

1. `git init` + initial commit
2. `uv sync --group dev`
3. `cp .env.example .env`
4. `pre-commit install` (commit-msg + pre-push hooks)

## Develop on the template itself

```bash
uv run pytest
uv sync # template tooling
uv run pytest # bake tests (pytest-cookies)
uv run cookiecutter . --no-input -o /tmp/out # smoke-bake with defaults
uv run ruff check . && uv run ruff format .
```

## Linter
Bake with custom values for manual inspection — same positional
`key=value` syntax as the user-facing flow above:

```bash
uv run ruff check .
uv run ruff format .
uv run cookiecutter . --no-input -o /tmp/out \
project_name="Smoke Bake" \
database=sqlite \
include_helm=no
```

See [`CLAUDE.md`](CLAUDE.md) for AI-assisted editing rules.
Loading
Loading