create-rigel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/cli.js +122 -0
- package/package.json +47 -0
- package/templates/express/.claude/CLAUDE.md +114 -0
- package/templates/express/.claude/agents/arch-validator.md +85 -0
- package/templates/express/.claude/agents/db-optimizer.md +72 -0
- package/templates/express/.claude/agents/doc-gardener.md +67 -0
- package/templates/express/.claude/agents/garbage-collector.md +94 -0
- package/templates/express/.claude/agents/gate-checker.md +176 -0
- package/templates/express/.claude/agents/reviewer.md +84 -0
- package/templates/express/.claude/agents/security-auditor.md +82 -0
- package/templates/express/.claude/hooks/post-write.sh +93 -0
- package/templates/express/.claude/rules/api.md +149 -0
- package/templates/express/.claude/rules/architecture.md +78 -0
- package/templates/express/.claude/rules/database.md +104 -0
- package/templates/express/.claude/rules/jobs.md +81 -0
- package/templates/express/.claude/rules/security.md +92 -0
- package/templates/express/.claude/rules/testing.md +97 -0
- package/templates/express/.claude/settings.json +35 -0
- package/templates/express/.claude/skills/00-infra-setup/SKILL.md +479 -0
- package/templates/express/.claude/skills/01-write-roadmap/SKILL.md +72 -0
- package/templates/express/.claude/skills/02-write-spec/SKILL.md +119 -0
- package/templates/express/.claude/skills/03-write-plan/SKILL.md +124 -0
- package/templates/express/.claude/skills/04-build-layer/SKILL.md +216 -0
- package/templates/express/.claude/skills/05-validate-layer/SKILL.md +43 -0
- package/templates/express/.claude/skills/06-push-layer/SKILL.md +59 -0
- package/templates/express/.claude/skills/07-layer-check/SKILL.md +62 -0
- package/templates/express/.claude/skills/08-garbage-collect/SKILL.md +86 -0
- package/templates/express/.claude/skills/09-doc-garden/SKILL.md +64 -0
- package/templates/express/.claude/skills/10-db-optimize/SKILL.md +96 -0
- package/templates/express/.claude/skills/11-load-test/SKILL.md +77 -0
- package/templates/express/.dockerignore +43 -0
- package/templates/express/.env.example +42 -0
- package/templates/express/.github/CODEOWNERS +22 -0
- package/templates/express/.github/dependabot.yml +48 -0
- package/templates/express/.github/pull_request_template.md +58 -0
- package/templates/express/.github/workflows/ci.yml +278 -0
- package/templates/express/.github/workflows/load-test.yml +41 -0
- package/templates/express/.gitleaks.toml +18 -0
- package/templates/express/.lintstagedrc.json +3 -0
- package/templates/express/.nvmrc +1 -0
- package/templates/express/.prettierrc +8 -0
- package/templates/express/.sequelizerc +8 -0
- package/templates/express/AGENTS.md +94 -0
- package/templates/express/ARCHITECTURE.md +161 -0
- package/templates/express/Dockerfile +40 -0
- package/templates/express/Makefile +79 -0
- package/templates/express/QUICKSTART.md +131 -0
- package/templates/express/docker-compose.yml +114 -0
- package/templates/express/docs/PLANS.md +111 -0
- package/templates/express/docs/QUALITY_SCORE.md +66 -0
- package/templates/express/docs/design-docs/core-beliefs.md +89 -0
- package/templates/express/docs/design-docs/decisions/ADR-000-infrastructure.md +70 -0
- package/templates/express/docs/design-docs/decisions/ADR-001-observability.md +82 -0
- package/templates/express/docs/design-docs/decisions/index.md +23 -0
- package/templates/express/docs/design-docs/index.md +11 -0
- package/templates/express/docs/design-docs/observability.md +194 -0
- package/templates/express/docs/design-docs/team-workflow.md +64 -0
- package/templates/express/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/express/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/express/docs/exec-plans/tech-debt-tracker.md +31 -0
- package/templates/express/docs/generated/.gitkeep +0 -0
- package/templates/express/docs/product-specs/ROADMAP.md +49 -0
- package/templates/express/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/express/docs/product-specs/index.md +21 -0
- package/templates/express/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/express/eslint.config.mjs +94 -0
- package/templates/express/gitignore +36 -0
- package/templates/express/infra/monitoring/alloy/config.alloy +59 -0
- package/templates/express/jest.config.ts +61 -0
- package/templates/express/package.json +45 -0
- package/templates/express/scripts/openapi.export.ts +77 -0
- package/templates/express/tests/architecture/isolation.test.ts +51 -0
- package/templates/express/tests/architecture/layers.test.ts +83 -0
- package/templates/express/tests/integration/health.test.ts +40 -0
- package/templates/express/tests/integration/isolation.test.template.ts +88 -0
- package/templates/express/tests/load/smoke.js +46 -0
- package/templates/express/tests/load/soak.js +45 -0
- package/templates/express/tests/load/stress.js +44 -0
- package/templates/express/tests/unit/utils/response.util.test.ts +53 -0
- package/templates/express/tsconfig.build.json +8 -0
- package/templates/express/tsconfig.json +20 -0
- package/templates/fastapi/.claude/CLAUDE.md +122 -0
- package/templates/fastapi/.claude/agents/arch-validator.md +64 -0
- package/templates/fastapi/.claude/agents/db-optimizer.md +59 -0
- package/templates/fastapi/.claude/agents/doc-gardener.md +55 -0
- package/templates/fastapi/.claude/agents/garbage-collector.md +74 -0
- package/templates/fastapi/.claude/agents/gate-checker.md +133 -0
- package/templates/fastapi/.claude/agents/reviewer.md +74 -0
- package/templates/fastapi/.claude/agents/security-auditor.md +69 -0
- package/templates/fastapi/.claude/hooks/post-write.sh +65 -0
- package/templates/fastapi/.claude/rules/api.md +119 -0
- package/templates/fastapi/.claude/rules/architecture.md +84 -0
- package/templates/fastapi/.claude/rules/database.md +153 -0
- package/templates/fastapi/.claude/rules/jobs.md +85 -0
- package/templates/fastapi/.claude/rules/security.md +102 -0
- package/templates/fastapi/.claude/rules/testing.md +207 -0
- package/templates/fastapi/.claude/settings.json +50 -0
- package/templates/fastapi/.claude/skills/00-infra-setup/SKILL.md +311 -0
- package/templates/fastapi/.claude/skills/01-write-roadmap/SKILL.md +61 -0
- package/templates/fastapi/.claude/skills/02-write-spec/SKILL.md +82 -0
- package/templates/fastapi/.claude/skills/03-write-plan/SKILL.md +83 -0
- package/templates/fastapi/.claude/skills/04-build-layer/SKILL.md +170 -0
- package/templates/fastapi/.claude/skills/05-validate-layer/SKILL.md +20 -0
- package/templates/fastapi/.claude/skills/06-push-layer/SKILL.md +31 -0
- package/templates/fastapi/.claude/skills/07-layer-check/SKILL.md +51 -0
- package/templates/fastapi/.claude/skills/08-garbage-collect/SKILL.md +47 -0
- package/templates/fastapi/.claude/skills/09-doc-garden/SKILL.md +9 -0
- package/templates/fastapi/.claude/skills/10-db-optimize/SKILL.md +53 -0
- package/templates/fastapi/.claude/skills/11-load-test/SKILL.md +81 -0
- package/templates/fastapi/.dockerignore +30 -0
- package/templates/fastapi/.github/dependabot.yml +24 -0
- package/templates/fastapi/AGENTS.md +87 -0
- package/templates/fastapi/ARCHITECTURE.md +141 -0
- package/templates/fastapi/Makefile +42 -0
- package/templates/fastapi/README.md +179 -0
- package/templates/fastapi/docs/PLANS.md +26 -0
- package/templates/fastapi/docs/QUALITY_SCORE.md +26 -0
- package/templates/fastapi/docs/design-docs/core-beliefs.md +46 -0
- package/templates/fastapi/docs/design-docs/decisions/ADR-000-infrastructure.md +79 -0
- package/templates/fastapi/docs/design-docs/decisions/index.md +7 -0
- package/templates/fastapi/docs/design-docs/index.md +9 -0
- package/templates/fastapi/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/fastapi/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/fastapi/docs/exec-plans/tech-debt-tracker.md +19 -0
- package/templates/fastapi/docs/generated/.gitkeep +0 -0
- package/templates/fastapi/docs/product-specs/ROADMAP.md +49 -0
- package/templates/fastapi/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/fastapi/docs/product-specs/index.md +18 -0
- package/templates/fastapi/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/fastapi/gitignore +46 -0
- package/templates/fastapi/scripts/gate.sh +68 -0
- package/templates/nestjs/.claude/CLAUDE.md +121 -0
- package/templates/nestjs/.claude/agents/db-optimizer.md +51 -0
- package/templates/nestjs/.claude/agents/doc-gardener.md +45 -0
- package/templates/nestjs/.claude/agents/garbage-collector.md +50 -0
- package/templates/nestjs/.claude/agents/gate-checker.md +127 -0
- package/templates/nestjs/.claude/agents/reviewer.md +68 -0
- package/templates/nestjs/.claude/agents/security-auditor.md +72 -0
- package/templates/nestjs/.claude/hooks/post-write.sh +91 -0
- package/templates/nestjs/.claude/rules/api.md +87 -0
- package/templates/nestjs/.claude/rules/architecture.md +104 -0
- package/templates/nestjs/.claude/rules/database.md +111 -0
- package/templates/nestjs/.claude/rules/security.md +110 -0
- package/templates/nestjs/.claude/rules/testing.md +145 -0
- package/templates/nestjs/.claude/settings.json +33 -0
- package/templates/nestjs/.claude/skills/00-infra-setup/SKILL.md +222 -0
- package/templates/nestjs/.claude/skills/01-write-spec/SKILL.md +25 -0
- package/templates/nestjs/.claude/skills/02-write-plan/SKILL.md +18 -0
- package/templates/nestjs/.claude/skills/03-build-layer/SKILL.md +242 -0
- package/templates/nestjs/.claude/skills/04-validate-layer/SKILL.md +4 -0
- package/templates/nestjs/.claude/skills/05-push-layer/SKILL.md +6 -0
- package/templates/nestjs/.claude/skills/06-layer-check/SKILL.md +12 -0
- package/templates/nestjs/.claude/skills/07-garbage-collect/SKILL.md +2 -0
- package/templates/nestjs/.claude/skills/08-doc-garden/SKILL.md +4 -0
- package/templates/nestjs/.claude/skills/09-api-sync/SKILL.md +36 -0
- package/templates/nestjs/.claude/skills/10-load-test/SKILL.md +29 -0
- package/templates/nestjs/.env.example +11 -0
- package/templates/nestjs/AGENTS.md +88 -0
- package/templates/nestjs/ARCHITECTURE.md +192 -0
- package/templates/nestjs/docs/PLANS.md +22 -0
- package/templates/nestjs/docs/QUALITY_SCORE.md +27 -0
- package/templates/nestjs/docs/design-docs/core-beliefs.md +18 -0
- package/templates/nestjs/docs/design-docs/decisions/ADR-000-infrastructure.md +58 -0
- package/templates/nestjs/docs/design-docs/decisions/index.md +7 -0
- package/templates/nestjs/docs/design-docs/index.md +7 -0
- package/templates/nestjs/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/nestjs/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/nestjs/docs/exec-plans/tech-debt-tracker.md +16 -0
- package/templates/nestjs/docs/generated/.gitkeep +0 -0
- package/templates/nestjs/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/nestjs/docs/product-specs/index.md +7 -0
- package/templates/nestjs/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/nestjs/gitignore +8 -0
- package/templates/nextjs/.claude/CLAUDE.md +139 -0
- package/templates/nextjs/.claude/agents/arch-validator.md +66 -0
- package/templates/nextjs/.claude/agents/contract-checker.md +78 -0
- package/templates/nextjs/.claude/agents/doc-gardener.md +52 -0
- package/templates/nextjs/.claude/agents/garbage-collector.md +61 -0
- package/templates/nextjs/.claude/agents/gate-checker.md +129 -0
- package/templates/nextjs/.claude/agents/perf-auditor.md +109 -0
- package/templates/nextjs/.claude/agents/reviewer.md +79 -0
- package/templates/nextjs/.claude/agents/security-auditor.md +50 -0
- package/templates/nextjs/.claude/hooks/post-write.sh +121 -0
- package/templates/nextjs/.claude/rules/api-contract.md +166 -0
- package/templates/nextjs/.claude/rules/architecture.md +99 -0
- package/templates/nextjs/.claude/rules/components.md +122 -0
- package/templates/nextjs/.claude/rules/security.md +122 -0
- package/templates/nextjs/.claude/rules/testing.md +187 -0
- package/templates/nextjs/.claude/scripts/infra-setup.sh +550 -0
- package/templates/nextjs/.claude/settings.json +33 -0
- package/templates/nextjs/.claude/skills/00-infra-setup/SKILL.md +471 -0
- package/templates/nextjs/.claude/skills/01-write-roadmap/SKILL.md +77 -0
- package/templates/nextjs/.claude/skills/02-write-spec/SKILL.md +78 -0
- package/templates/nextjs/.claude/skills/03-write-plan/SKILL.md +91 -0
- package/templates/nextjs/.claude/skills/04-build-layer/SKILL.md +141 -0
- package/templates/nextjs/.claude/skills/05-validate-layer/SKILL.md +13 -0
- package/templates/nextjs/.claude/skills/06-push-layer/SKILL.md +20 -0
- package/templates/nextjs/.claude/skills/07-layer-check/SKILL.md +28 -0
- package/templates/nextjs/.claude/skills/08-garbage-collect/SKILL.md +14 -0
- package/templates/nextjs/.claude/skills/09-doc-garden/SKILL.md +12 -0
- package/templates/nextjs/.claude/skills/10-api-sync/SKILL.md +50 -0
- package/templates/nextjs/.claude/skills/11-perf-budget/SKILL.md +51 -0
- package/templates/nextjs/.dockerignore +25 -0
- package/templates/nextjs/.gitattributes +10 -0
- package/templates/nextjs/.github/CODEOWNERS +24 -0
- package/templates/nextjs/.github/dependabot.yml +31 -0
- package/templates/nextjs/.github/pull_request_template.md +59 -0
- package/templates/nextjs/.github/workflows/ci.yml +143 -0
- package/templates/nextjs/.github/workflows/lighthouse.yml +54 -0
- package/templates/nextjs/.github/workflows/load-test.yml +54 -0
- package/templates/nextjs/.husky/pre-commit +1 -0
- package/templates/nextjs/.lintstagedrc.json +4 -0
- package/templates/nextjs/.mcp.json +8 -0
- package/templates/nextjs/.prettierignore +13 -0
- package/templates/nextjs/.prettierrc +9 -0
- package/templates/nextjs/AGENTS.md +88 -0
- package/templates/nextjs/ARCHITECTURE.md +165 -0
- package/templates/nextjs/Dockerfile +38 -0
- package/templates/nextjs/Makefile +50 -0
- package/templates/nextjs/QUICKSTART.md +128 -0
- package/templates/nextjs/docs/PLANS.md +23 -0
- package/templates/nextjs/docs/QUALITY_SCORE.md +27 -0
- package/templates/nextjs/docs/design-docs/core-beliefs.md +43 -0
- package/templates/nextjs/docs/design-docs/decisions/ADR-000-infrastructure.md +72 -0
- package/templates/nextjs/docs/design-docs/decisions/index.md +7 -0
- package/templates/nextjs/docs/design-docs/index.md +7 -0
- package/templates/nextjs/docs/design-docs/team-workflow.md +66 -0
- package/templates/nextjs/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/nextjs/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/nextjs/docs/exec-plans/tech-debt-tracker.md +19 -0
- package/templates/nextjs/docs/generated/.gitkeep +0 -0
- package/templates/nextjs/docs/product-specs/ROADMAP.md +59 -0
- package/templates/nextjs/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/nextjs/docs/product-specs/index.md +18 -0
- package/templates/nextjs/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/nextjs/eslint.config.mjs +150 -0
- package/templates/nextjs/gitignore +35 -0
- package/templates/nextjs/lighthouserc.js +37 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# AGENTS.md — Navigation Map
|
|
2
|
+
|
|
3
|
+
Stack: Python 3.14 · FastAPI 0.115 · SQLAlchemy 2 (async) · PostgreSQL · Redis · Celery · uv
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🗺️ Where Everything Lives
|
|
8
|
+
|
|
9
|
+
| What you need | Where |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Daily-driver commands | `Makefile` (`make bootstrap/dev/lint/test/gate/migrate/openapi`) |
|
|
12
|
+
| Runnable gate (same checks as gate-checker) | `scripts/gate.sh` (`make gate`) |
|
|
13
|
+
| Layer rules + dependency diagram | `ARCHITECTURE.md` |
|
|
14
|
+
| Engineering constitution (the WHY) | `docs/design-docs/core-beliefs.md` |
|
|
15
|
+
| Active execution plan | `docs/exec-plans/active/` |
|
|
16
|
+
| Completed plans (history) | `docs/exec-plans/completed/` |
|
|
17
|
+
| Product roadmap (epics → specs, dependency order) | `docs/product-specs/ROADMAP.md` |
|
|
18
|
+
| Product specs (draft) | `docs/product-specs/draft/` |
|
|
19
|
+
| Product specs (approved) | `docs/product-specs/ready/` |
|
|
20
|
+
| Architectural decisions (ADRs) | `docs/design-docs/decisions/` |
|
|
21
|
+
| Known tech debt | `docs/exec-plans/tech-debt-tracker.md` |
|
|
22
|
+
| Domain health grades | `docs/QUALITY_SCORE.md` |
|
|
23
|
+
| Plan format + lifecycle | `docs/PLANS.md` |
|
|
24
|
+
| Generated DB schema | `docs/generated/db-schema.md` |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ⚡ Slash Commands
|
|
29
|
+
|
|
30
|
+
| Command | What it does |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `/infra-setup` | Phase 0 — full infra scaffold (run once) |
|
|
33
|
+
| `/write-roadmap` | Turn a product brief into an ordered spec roadmap → `docs/product-specs/ROADMAP.md` |
|
|
34
|
+
| `/write-spec` | Write a product spec → `docs/product-specs/draft/` |
|
|
35
|
+
| `/write-plan` | Turn a READY spec into an execution plan |
|
|
36
|
+
| `/build-layer` | Build next unchecked layer from active plan + run gate |
|
|
37
|
+
| `/validate-layer` | Run gate check on current layer without building |
|
|
38
|
+
| `/push-layer` | Commit + push current layer with conventional message |
|
|
39
|
+
| `/layer-check` | Ad-hoc architecture violation scan |
|
|
40
|
+
| `/garbage-collect` | End-of-feature cleanup pass |
|
|
41
|
+
| `/doc-garden` | Scan + fix stale documentation |
|
|
42
|
+
| `/db-optimize` | EXPLAIN ANALYZE workflow for slow queries |
|
|
43
|
+
| `/load-test` | Run k6 smoke / stress / soak test |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 🤖 Agents
|
|
48
|
+
|
|
49
|
+
| Agent | When to use |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `gate-checker` | Called automatically by `/build-layer` — PASS/FAIL per layer |
|
|
52
|
+
| `reviewer` | Before opening a PR — full harness review |
|
|
53
|
+
| `arch-validator` | Deep import + layer compliance scan |
|
|
54
|
+
| `db-optimizer` | N+1, missing index, pagination audit on repo layer |
|
|
55
|
+
| `security-auditor` | OWASP Top 10 review — run before any auth/payment PR |
|
|
56
|
+
| `doc-gardener` | Use the `/doc-garden` skill |
|
|
57
|
+
| `garbage-collector` | Use the `/garbage-collect` skill |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## ✅ Non-Negotiable Invariants
|
|
62
|
+
|
|
63
|
+
- No `print()` → use `logger` from `src/providers/logger.py`
|
|
64
|
+
- No `os.environ` outside `src/config/settings.py`
|
|
65
|
+
- No raw dict cast on SQLAlchemy results → `Model.model_validate(row.__dict__)` only
|
|
66
|
+
- No file > 400 lines → split into focused modules
|
|
67
|
+
- No cross-layer imports → enforced by `ruff` + structural tests
|
|
68
|
+
- Every DB query result → `PydanticSchema.model_validate()`
|
|
69
|
+
- Every list endpoint → cursor-based pagination
|
|
70
|
+
- Every protected route → `Depends(require_auth)` as first dependency
|
|
71
|
+
- Every external call → `tenacity` retry + timeout
|
|
72
|
+
- All tests pass before `/push-layer`
|
|
73
|
+
- `raise HTTPException` only in runtime layer — never in service layer
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 🔁 The Flow
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
# Whole product (run once at the start):
|
|
81
|
+
/write-roadmap → human reviews ROADMAP → pick the walking-skeleton spec
|
|
82
|
+
|
|
83
|
+
# Every feature (repeat down the roadmap):
|
|
84
|
+
/write-spec (roadmap-guided) → human marks READY → /write-plan
|
|
85
|
+
→ /build-layer (repeats, gate-enforced)
|
|
86
|
+
→ /garbage-collect → plan closed
|
|
87
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# ARCHITECTURE.md — Layered Architecture
|
|
2
|
+
|
|
3
|
+
Stack: Python 3.14 · FastAPI 0.115 · SQLAlchemy 2 (async) · Alembic · PostgreSQL · Redis · Celery
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Dependency Layer Diagram
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌──────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Utils — stateless helpers, zero domain imports │
|
|
12
|
+
│ 100% test coverage required │
|
|
13
|
+
└───────────────────────┬──────────────────────────────────┘
|
|
14
|
+
│ (imported by all layers below)
|
|
15
|
+
┌───────────────────────▼──────────────────────────────────┐
|
|
16
|
+
│ │
|
|
17
|
+
│ Types ──► Config ──► Models ──► Repo │
|
|
18
|
+
│ │ │
|
|
19
|
+
│ ▼ │
|
|
20
|
+
│ Service │
|
|
21
|
+
│ │ │
|
|
22
|
+
│ ▼ │
|
|
23
|
+
│ Runtime { Routers · Workers } │
|
|
24
|
+
│ │
|
|
25
|
+
│ Providers (auth, logger, db session, redis, telemetry) │
|
|
26
|
+
│ └─ enter domain via FastAPI Depends() only │
|
|
27
|
+
│ │
|
|
28
|
+
└───────────────────────────────────────────────────────────┘
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Layer Definitions
|
|
34
|
+
|
|
35
|
+
### Types (`src/types/`)
|
|
36
|
+
- Pure Pydantic `BaseModel` schemas, enums, TypedDicts
|
|
37
|
+
- **Zero imports** from other layers
|
|
38
|
+
- **Zero logic** — only field definitions and validators
|
|
39
|
+
- Examples: `ApplicationStage`, `CreateApplicationInput`, `PageResult[T]`
|
|
40
|
+
|
|
41
|
+
### Config (`src/config/`)
|
|
42
|
+
- `pydantic-settings` `BaseSettings` — typed, validated on startup
|
|
43
|
+
- Imports: **Types only**
|
|
44
|
+
- `settings.py` raises `ValidationError` on bad env → process never starts
|
|
45
|
+
- Examples: `settings.py`, `constants.py`, `timeouts.py`
|
|
46
|
+
|
|
47
|
+
### Models (`src/models/`)
|
|
48
|
+
- SQLAlchemy 2 ORM model classes — schema only, no logic
|
|
49
|
+
- Imports: **Types, Config**
|
|
50
|
+
- All models: `__mapper_args__` soft delete pattern, `uuid7()` default on id
|
|
51
|
+
- Indexes defined in model `__table_args__`
|
|
52
|
+
- Examples: `user.py`, `application.py`
|
|
53
|
+
|
|
54
|
+
### Repo (`src/repo/`)
|
|
55
|
+
- Async DB access **and** outbound external-API gateways (`*_gateway.py`, httpx + tenacity). All output validated with Pydantic.
|
|
56
|
+
- This is the home for "external APIs go via Repo" — services never make inline HTTP calls.
|
|
57
|
+
- Imports: **Types, Config, Models**
|
|
58
|
+
- **Every** query/response result: `Schema.model_validate(row.__dict__)`
|
|
59
|
+
- All list methods: cursor-based pagination (`WHERE created_at < :cursor`)
|
|
60
|
+
- Ownership enforced: `WHERE id = :id AND user_id = :user_id`
|
|
61
|
+
- Examples: `user_repo.py`, `application_repo.py`
|
|
62
|
+
|
|
63
|
+
### Service (`src/services/`)
|
|
64
|
+
- Business logic and use-case orchestration
|
|
65
|
+
- Imports: **Types, Config, Repo**
|
|
66
|
+
- **No** `Request`, `HTTPException`, `fastapi` imports
|
|
67
|
+
- **No** inline HTTP calls — external APIs go via Repo
|
|
68
|
+
- `raise DomainError(...)` — never `raise HTTPException`
|
|
69
|
+
- Examples: `application_service.py`, `auth_service.py`
|
|
70
|
+
|
|
71
|
+
### Runtime (`src/runtime/`)
|
|
72
|
+
- FastAPI routers, Celery workers, CLI entry points
|
|
73
|
+
- Imports: **Types, Config, Repo, Service**
|
|
74
|
+
- Routes: `Depends(require_auth)` first, then validate, then service, then respond
|
|
75
|
+
- Thin layer — zero business logic
|
|
76
|
+
- Maps `DomainError` → `HTTPException` in exception handlers
|
|
77
|
+
- Examples: `routers/v1/applications.py`, `workers/reminder_worker.py`
|
|
78
|
+
|
|
79
|
+
### Providers (`src/providers/`)
|
|
80
|
+
- Cross-cutting: logger, db session factory, redis, auth, telemetry
|
|
81
|
+
- Injected via FastAPI `Depends()` — never imported directly by Service
|
|
82
|
+
- Examples: `logger.py`, `database.py`, `auth/jwt.py`
|
|
83
|
+
|
|
84
|
+
### Utils (`src/utils/`)
|
|
85
|
+
- Stateless helpers — **zero domain imports**
|
|
86
|
+
- **100% test coverage** required
|
|
87
|
+
- Examples: `retry.py`, `pagination.py`, `uuid_util.py`
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Allowed Imports (strict — ruff enforces)
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Types → (nothing)
|
|
95
|
+
Config → Types
|
|
96
|
+
Models → Types, Config
|
|
97
|
+
Repo → Types, Config, Models
|
|
98
|
+
Service → Types, Config, Repo
|
|
99
|
+
Runtime → Types, Config, Repo, Service
|
|
100
|
+
Utils → (nothing)
|
|
101
|
+
Providers → Types, Config only
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Forbidden:**
|
|
105
|
+
- Service importing `fastapi`, `HTTPException`, or anything from Runtime
|
|
106
|
+
- Repo containing business logic (if/else beyond null checks)
|
|
107
|
+
- Utils importing any domain layer
|
|
108
|
+
- Circular imports of any kind
|
|
109
|
+
- `os.environ` outside `src/config/settings.py`
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## File Size Limit
|
|
114
|
+
- **400 lines maximum** per file
|
|
115
|
+
- Enforced by: PostToolUse hook + gate-checker agent
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Naming Conventions
|
|
120
|
+
|
|
121
|
+
| Layer | Pattern | Example |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| Types | `*_schema.py` or `*_types.py` | `application_schema.py` |
|
|
124
|
+
| Config | `settings.py`, `constants.py` | `settings.py` |
|
|
125
|
+
| Models | `*.py` in `models/` | `application.py` |
|
|
126
|
+
| Repo | `*_repo.py` | `application_repo.py` |
|
|
127
|
+
| Service | `*_service.py` | `application_service.py` |
|
|
128
|
+
| Router | `*.py` in `routers/v1/` | `applications.py` |
|
|
129
|
+
| Worker | `*_worker.py` | `reminder_worker.py` |
|
|
130
|
+
| Utils | `*_util.py` | `retry_util.py` |
|
|
131
|
+
| Pydantic schemas | `PascalCase` | `ApplicationResponse` |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Mechanical Enforcement Stack
|
|
136
|
+
|
|
137
|
+
1. **ruff rules** — `no-os-environ`, `no-cross-layer-import`, `no-print`
|
|
138
|
+
2. **PostToolUse hooks** — fire on every file write (size, print, os.environ)
|
|
139
|
+
3. **Structural tests** — `tests/architecture/test_layers.py` — fails CI on violations
|
|
140
|
+
4. **gate-checker agent** — PASS required before every commit
|
|
141
|
+
5. **mypy** — strict type checking on every CI run
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Makefile — single-command developer experience for the FastAPI harness.
|
|
2
|
+
# Every command in the docs goes through a target here so humans and agents
|
|
3
|
+
# run the exact same thing. Generated/maintained alongside /infra-setup.
|
|
4
|
+
|
|
5
|
+
.PHONY: bootstrap dev lint format typecheck test gate migrate openapi up down lgtm
|
|
6
|
+
|
|
7
|
+
bootstrap: ## one-command setup: sync deps + install git hooks
|
|
8
|
+
uv sync && uv run pre-commit install
|
|
9
|
+
|
|
10
|
+
dev: ## run the API with autoreload
|
|
11
|
+
uv run uvicorn src.runtime.main:app --reload
|
|
12
|
+
|
|
13
|
+
lint: ## ruff lint
|
|
14
|
+
uv run ruff check src/ tests/
|
|
15
|
+
|
|
16
|
+
format: ## ruff format (writes)
|
|
17
|
+
uv run ruff format src/ tests/
|
|
18
|
+
|
|
19
|
+
typecheck: ## mypy strict
|
|
20
|
+
uv run mypy src/
|
|
21
|
+
|
|
22
|
+
test: ## full test suite + coverage
|
|
23
|
+
uv run pytest
|
|
24
|
+
|
|
25
|
+
gate: ## deterministic gate — same checks the gate-checker agent runs
|
|
26
|
+
bash scripts/gate.sh
|
|
27
|
+
|
|
28
|
+
migrate: ## apply migrations
|
|
29
|
+
uv run alembic upgrade head
|
|
30
|
+
|
|
31
|
+
openapi: ## export OpenAPI spec to openapi.json (loads .env if present so settings validate)
|
|
32
|
+
set -a; [ -f .env ] && . ./.env; set +a; \
|
|
33
|
+
uv run python -c "import json,sys; from src.runtime.main import app; json.dump(app.openapi(), sys.stdout)" > openapi.json
|
|
34
|
+
|
|
35
|
+
up: ## start local stack (app + postgres + redis)
|
|
36
|
+
docker compose up -d
|
|
37
|
+
|
|
38
|
+
down: ## stop local stack
|
|
39
|
+
docker compose down
|
|
40
|
+
|
|
41
|
+
lgtm: ## start local observability stack (Grafana/Loki/Tempo/Prometheus)
|
|
42
|
+
docker compose -f infra/monitoring/docker-compose.lgtm.yml up -d
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# FastAPI Agent Template
|
|
2
|
+
|
|
3
|
+
Production-ready FastAPI template with layered architecture, SQLAlchemy 2 async, OpenTelemetry, and full agent harness for spec → plan → build → test → deploy workflow.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Initialize new project
|
|
11
|
+
/infra-setup
|
|
12
|
+
|
|
13
|
+
# Plan a whole product (run before /write-spec)
|
|
14
|
+
/write-roadmap # → docs/product-specs/ROADMAP.md (brief → ordered, dependency-aware specs)
|
|
15
|
+
|
|
16
|
+
# Build a feature
|
|
17
|
+
/write-spec # → docs/product-specs/draft/ (roadmap-guided)
|
|
18
|
+
/write-plan # → docs/exec-plans/active/
|
|
19
|
+
/build-layer # → auto-build + gate + commit + push (one layer at a time)
|
|
20
|
+
|
|
21
|
+
# Quality gates
|
|
22
|
+
/validate-layer # Run gate without building
|
|
23
|
+
/layer-check # Ad-hoc architecture violation scan
|
|
24
|
+
/db-optimize # N+1 query detection, missing indexes
|
|
25
|
+
/load-test smoke # k6 performance test
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Stack
|
|
31
|
+
|
|
32
|
+
| Category | Packages |
|
|
33
|
+
|---|---|
|
|
34
|
+
| **Runtime** | Python 3.14, FastAPI 0.115, uvicorn[standard] 0.32 |
|
|
35
|
+
| **ORM** | SQLAlchemy 2 (async), Alembic, asyncpg |
|
|
36
|
+
| **Auth** | PyJWT[crypto] 2.9, pwdlib[argon2] 0.2, argon2-cffi |
|
|
37
|
+
| **Queue** | Celery 5, Redis 5 |
|
|
38
|
+
| **Logging** | structlog 24 |
|
|
39
|
+
| **Tracing** | opentelemetry-sdk, opentelemetry-instrumentation-fastapi, prometheus-fastapi-instrumentator |
|
|
40
|
+
| **Validation** | pydantic 2, pydantic-settings 2, email-validator |
|
|
41
|
+
| **HTTP Client** | httpx, tenacity |
|
|
42
|
+
| **Rate Limit** | slowapi, limits (Redis store) |
|
|
43
|
+
| **Testing** | pytest 8, pytest-asyncio, pytest-cov, httpx AsyncClient, factory-boy, faker |
|
|
44
|
+
| **Security** | bandit |
|
|
45
|
+
| **Tooling** | uv, ruff, mypy, pre-commit |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ✅ Key Features
|
|
50
|
+
|
|
51
|
+
- **Layered architecture** enforced by ruff + AST structural tests
|
|
52
|
+
- **Pydantic v2 validation** at every DB boundary (`model_validate` required)
|
|
53
|
+
- **Structured JSON logging** with PII redaction (structlog)
|
|
54
|
+
- **OpenTelemetry** instrumentation (FastAPI + SQLAlchemy)
|
|
55
|
+
- **Rate limiting** with Redis store (3 tiers: auth, public, user)
|
|
56
|
+
- **Cursor pagination** with opaque base64url tokens (no leaking impl details)
|
|
57
|
+
- **Response envelopes** standardized: `{ ok, data, meta }` success, `{ ok: false, error, meta }` errors
|
|
58
|
+
- **Security headers** middleware (7 headers: CSP, HSTS, X-Frame-Options, etc.)
|
|
59
|
+
- **GDPR deletion** utility (anonymize PII, hard-delete sensitive, keep audit)
|
|
60
|
+
- **Audit logging** utility (who, what, resource, timestamp)
|
|
61
|
+
- **Cross-user isolation** tests (404 not 403 — don't leak resource existence)
|
|
62
|
+
- **k6 load tests** (smoke + stress with P95/P99 budgets enforced in CI)
|
|
63
|
+
- **schemathesis** OpenAPI contract/fuzz tests against `/openapi.json`
|
|
64
|
+
- **Multi-stage Dockerfile** + `.dockerignore` (non-root user, HEALTHCHECK)
|
|
65
|
+
- **GitHub Actions CI** — parallel jobs: quality (ruff + mypy), test (pytest + schemathesis), security (bandit + pip-audit + gitleaks), image (Trivy scan + SBOM)
|
|
66
|
+
- **Dependabot** (uv + GitHub Actions + Docker)
|
|
67
|
+
- **Makefile** single-command DX (`make bootstrap/dev/lint/test/gate/migrate/openapi`) + runnable `scripts/gate.sh`
|
|
68
|
+
- **Agent-first workflow** (spec → plan → build loop with auto-gating)
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Why `>=` Version Bounds?
|
|
73
|
+
|
|
74
|
+
All dependencies use `>=` (no upper bounds):
|
|
75
|
+
|
|
76
|
+
```toml
|
|
77
|
+
fastapi = ">=0.115"
|
|
78
|
+
pydantic = ">=2.0"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Reasoning:**
|
|
82
|
+
|
|
83
|
+
- `uv.lock` pins exact versions for reproducible builds (lock file does the pinning)
|
|
84
|
+
- Upper bounds cause **dependency hell** in libraries (if lib A pins `pydantic<3` and lib B pins `pydantic<2.5`, they're incompatible)
|
|
85
|
+
- Security updates apply immediately via `uv sync --upgrade` (no waiting for maintainer to bump upper bound)
|
|
86
|
+
- Dependabot raises weekly PRs that bump `uv.lock` and re-run the full CI gate, so updates are reviewed, not blind
|
|
87
|
+
- Lockfile-first dependency management (pin the lock, range the manifest) is standard modern practice
|
|
88
|
+
|
|
89
|
+
This is the same strategy as Rust (Cargo.toml) and modern Python packaging (PEP 440 discourages upper bounds).
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Architecture Layers
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
src/
|
|
97
|
+
├── types/ # Domain exceptions, common types (no imports allowed)
|
|
98
|
+
├── config/ # Settings, constants, timeouts (pydantic-settings)
|
|
99
|
+
├── models/ # SQLAlchemy models (ORM only)
|
|
100
|
+
├── repo/ # DB queries, cursor pagination, ownership filters
|
|
101
|
+
├── services/ # Business logic (raise DomainError, never HTTPException)
|
|
102
|
+
├── utils/ # Pure functions (no domain imports)
|
|
103
|
+
├── providers/ # External integrations (DB, Redis, auth, logger, telemetry)
|
|
104
|
+
└── runtime/ # FastAPI routers, middleware, exception handlers
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Enforced by:**
|
|
108
|
+
|
|
109
|
+
- ruff import rules
|
|
110
|
+
- `tests/architecture/test_layers.py` (AST-based structural tests)
|
|
111
|
+
- post-write hook (catches `print()`, `os.environ`, HTTPException in services)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Project Files
|
|
116
|
+
|
|
117
|
+
| File | Purpose |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `ARCHITECTURE.md` | Layer rules + dependency graph |
|
|
120
|
+
| `AGENTS.md` | Navigation map for agents (which files do what) |
|
|
121
|
+
| `.claude/CLAUDE.md` | Agent entry point (read first on every session) |
|
|
122
|
+
| `.claude/rules/*.md` | Path-scoped rules (auto-injected based on file being edited) |
|
|
123
|
+
| `.claude/skills/*.md` | Slash commands (`/infra-setup`, `/build-layer`, etc.) |
|
|
124
|
+
| `docs/product-specs/ROADMAP.md` | Whole-product spec roadmap (epics, dependency order, walking skeleton) |
|
|
125
|
+
| `docs/exec-plans/active/` | Current execution plan (checked boxes = done) |
|
|
126
|
+
| `docs/design-docs/decisions/` | ADRs (Architecture Decision Records) |
|
|
127
|
+
| `docs/product-specs/ready/` | Approved specs ready for implementation |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## OpenAPI → Frontend Sync
|
|
132
|
+
|
|
133
|
+
FastAPI auto-generates OpenAPI spec at `GET /openapi.json`. To sync with frontend:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# 1. Export the OpenAPI spec (no running server needed)
|
|
137
|
+
make openapi # → openapi.json (app.openapi() dumped to file)
|
|
138
|
+
|
|
139
|
+
# 2. In frontend repo
|
|
140
|
+
/api-sync # generates TypeScript types from openapi.json
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This keeps frontend types in sync with backend contract.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Celery vs arq
|
|
148
|
+
|
|
149
|
+
Template uses **Celery 5** by default. Trade-offs:
|
|
150
|
+
|
|
151
|
+
| Feature | Celery | arq |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| **Async support** | Sync-first (requires `asyncio.run()` wrapper) | Native async |
|
|
154
|
+
| **Scheduling** | Beat (cron-like) | None (use external scheduler) |
|
|
155
|
+
| **Workflows** | Chain, chord, group primitives | Manual composition |
|
|
156
|
+
| **Ecosystem** | Large (flower, django-celery, etc.) | Small (Pydantic team only) |
|
|
157
|
+
| **Type safety** | Manual | Built-in (Pydantic v2) |
|
|
158
|
+
|
|
159
|
+
**When to use arq:** If you don't need beat scheduling or chord/chain and want native async + type safety, consider arq.
|
|
160
|
+
|
|
161
|
+
**Decision documented in:** `docs/design-docs/decisions/ADR-000-infrastructure.md` (scaffolded by `/infra-setup`)
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT (or your org's standard license)
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Contributing
|
|
172
|
+
|
|
173
|
+
This is a template repository. To update:
|
|
174
|
+
|
|
175
|
+
1. Edit `.claude/skills/*.md` (skill scaffolds)
|
|
176
|
+
2. Edit `.claude/rules/*.md` (path-scoped rules)
|
|
177
|
+
3. Edit `CLAUDE.md`, `ARCHITECTURE.md`, `AGENTS.md` (agent context)
|
|
178
|
+
4. Update `Verified:` headers on skills when libraries change
|
|
179
|
+
5. Run staleness detection: if `Verified:` date > 60 days, fetch current docs via `ctx7`
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# PLANS.md — Execution Plan Format
|
|
2
|
+
|
|
3
|
+
## Roadmap → Specs (the altitude above plans)
|
|
4
|
+
/write-roadmap creates → docs/product-specs/ROADMAP.md (epics → dependency-ordered specs).
|
|
5
|
+
The roadmap plans the SET of specs for a whole product; /write-spec then authors each one.
|
|
6
|
+
A single spec may span MULTIPLE plans — slice a big spec into shippable milestones, each its own
|
|
7
|
+
PLAN-XXX. The spec's `**Plan:**` field then lists them all (e.g. `PLAN-003, PLAN-007`).
|
|
8
|
+
|
|
9
|
+
## Lifecycle
|
|
10
|
+
/write-plan creates → docs/exec-plans/active/PLAN-XXX.md [IN_PROGRESS]
|
|
11
|
+
→ layers built one by one, checkboxes ticked
|
|
12
|
+
→ /garbage-collect closes → docs/exec-plans/completed/ [COMPLETE]
|
|
13
|
+
|
|
14
|
+
Plans are NEVER deleted. They are the project memory.
|
|
15
|
+
|
|
16
|
+
## Plan Template
|
|
17
|
+
See any file in docs/exec-plans/ for the full template.
|
|
18
|
+
|
|
19
|
+
## Escalation Rule
|
|
20
|
+
Escalate to human only when judgment is required:
|
|
21
|
+
- Ambiguous acceptance criteria
|
|
22
|
+
- Conflicting requirements
|
|
23
|
+
- Security decision with no established pattern
|
|
24
|
+
- Performance budget impossible without architecture change
|
|
25
|
+
|
|
26
|
+
Never escalate for: linter failures, test failures, technical unknowns — fix those.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# QUALITY_SCORE.md — Domain Health Grades
|
|
2
|
+
|
|
3
|
+
Updated by /garbage-collect after every feature.
|
|
4
|
+
|
|
5
|
+
## Grading Rubric
|
|
6
|
+
| Grade | Meaning |
|
|
7
|
+
|---|---|
|
|
8
|
+
| A | All invariants met, ≥ 90% coverage, zero known debt |
|
|
9
|
+
| B | Minor issues, ≥ 80% coverage, low-priority debt logged |
|
|
10
|
+
| C | Layer violation OR < 80% coverage OR unresolved medium debt |
|
|
11
|
+
| D | Multiple violations, < 70% coverage, active bugs |
|
|
12
|
+
| F | Blocking issues, data integrity risk, security concern |
|
|
13
|
+
|
|
14
|
+
## Architecture Health
|
|
15
|
+
| Check | Status |
|
|
16
|
+
|---|---|
|
|
17
|
+
| No circular imports | — |
|
|
18
|
+
| No files > 400 lines | — |
|
|
19
|
+
| No os.environ outside config | — |
|
|
20
|
+
| No print() in src/ | — |
|
|
21
|
+
| Utils: 100% test coverage | — |
|
|
22
|
+
|
|
23
|
+
## Domain Grades
|
|
24
|
+
| Domain | Grade | Coverage | Last Updated | Notes |
|
|
25
|
+
|---|---|---|---|---|
|
|
26
|
+
| *(no domains yet)* | — | — | — | — |
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Core Beliefs — The Engineering Constitution
|
|
2
|
+
|
|
3
|
+
Rules without reasons get bent under pressure.
|
|
4
|
+
This document explains the WHY behind every constraint in this harness.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. The Repo Is Reality
|
|
9
|
+
If a decision isn't written here, it doesn't exist. Verbal agreements and Slack messages are invisible to agents and future engineers.
|
|
10
|
+
**Consequence:** Every decision → ADR. Every product → ROADMAP.md. Every intent → spec. Every plan → PLAN-XXX.md.
|
|
11
|
+
|
|
12
|
+
## 2. Enforce Mechanically, Not Aspirationally
|
|
13
|
+
A ruff rule that blocks CI is worth ten documentation paragraphs. Agents respond to linter output.
|
|
14
|
+
**Consequence:** Every constraint is a ruff rule, a structural test, or a hook — not just a doc.
|
|
15
|
+
|
|
16
|
+
## 3. Agents Execute. Humans Steer.
|
|
17
|
+
Human attention is the scarcest resource. Optimize everything around preserving it.
|
|
18
|
+
**Consequence:** Maximum agent autonomy. Escalate only when judgment is needed.
|
|
19
|
+
|
|
20
|
+
## 4. Layers Protect Business Logic
|
|
21
|
+
Service layer is pure business logic. No HTTP, no FastAPI, no ORM models. It receives an injected `AsyncSession` and orchestrates repos — testable against a real test session, no web-layer mocks.
|
|
22
|
+
**Consequence:** `raise HTTPException` only in runtime. Services raise `DomainError`. ORM models and `session.add` live only in the repo layer.
|
|
23
|
+
|
|
24
|
+
## 5. External Data Is Adversarial Until Validated
|
|
25
|
+
SQLAlchemy row `__dict__` is untyped. Pydantic `model_validate()` is the gate.
|
|
26
|
+
**Consequence:** `Schema.model_validate(row.__dict__)` at every repo boundary. No raw dicts.
|
|
27
|
+
|
|
28
|
+
## 6. Observability Is Not Optional
|
|
29
|
+
Structured logs + traces are the only way to reproduce production bugs autonomously.
|
|
30
|
+
**Consequence:** structlog on every service boundary. OTel spans on every DB query.
|
|
31
|
+
|
|
32
|
+
## 7. Gate Before Commit — Always
|
|
33
|
+
Every layer gated before commit. Auto-fix enabled — no reason to leave violations in.
|
|
34
|
+
**Consequence:** gate-checker runs after every layer. PASS required before push.
|
|
35
|
+
|
|
36
|
+
## 8. Small, Boring, Legible
|
|
37
|
+
400 lines max. Well-known libraries. No premature abstraction.
|
|
38
|
+
**Consequence:** uv, FastAPI, SQLAlchemy — widely used, well-documented, excellent agent training data.
|
|
39
|
+
|
|
40
|
+
## 9. Technical Debt Is a High-Interest Loan
|
|
41
|
+
Log debt immediately. Pay it in small daily amounts.
|
|
42
|
+
**Consequence:** tech-debt-tracker.md updated after every feature. Garbage collect after every plan.
|
|
43
|
+
|
|
44
|
+
## 10. The Fix Is Never "Try Harder"
|
|
45
|
+
Repeated failures indicate a missing capability — tool, constraint, or abstraction.
|
|
46
|
+
**Consequence:** Diagnose → build the capability → solve permanently.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# ADR-000 — Infrastructure & Stack Choices
|
|
2
|
+
|
|
3
|
+
**Status:** ACCEPTED
|
|
4
|
+
**Date:** *(fill when /infra-setup is run)*
|
|
5
|
+
**Plan:** Phase 0
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
Starting a new Python backend project. Stack choices made here are expensive to change.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Decisions
|
|
15
|
+
|
|
16
|
+
### Runtime: Python 3.14 + FastAPI 0.115
|
|
17
|
+
- Python 3.14 is the latest stable (released Oct 2025) — improved performance, better typing
|
|
18
|
+
- FastAPI: async-native, auto OpenAPI, Pydantic v2 integration, best-in-class DX
|
|
19
|
+
- Alternatives rejected: Flask (no async-native), Django (too opinionated for API-only)
|
|
20
|
+
|
|
21
|
+
### ORM: SQLAlchemy 2 (async) + Alembic
|
|
22
|
+
- SQLAlchemy 2 has proper async support (not bolted on)
|
|
23
|
+
- `asyncpg` driver — fastest async PostgreSQL driver available
|
|
24
|
+
- Alembic is SQLAlchemy's own migration tool — tight integration
|
|
25
|
+
- Alternatives rejected: Tortoise ORM (less mature), SQLModel (thin wrapper, less control)
|
|
26
|
+
|
|
27
|
+
### Validation: Pydantic v2
|
|
28
|
+
- FastAPI's native schema layer — zero friction integration
|
|
29
|
+
- v2 is 5-17x faster than v1 (Rust core)
|
|
30
|
+
- Used at every external data boundary via `model_validate()`
|
|
31
|
+
|
|
32
|
+
### Auth: PyJWT[crypto] + pwdlib[argon2]
|
|
33
|
+
- PyJWT: FastAPI's official recommendation, actively maintained, RS256/HS256 support
|
|
34
|
+
- pwdlib (`PasswordHash.recommended()` → argon2id): created by the FastAPI Users maintainer, Python 3.13+ compatible
|
|
35
|
+
- argon2id: OWASP-recommended, winner of the Password Hashing Competition — GPU-resistant
|
|
36
|
+
- Alternatives rejected:
|
|
37
|
+
- python-jose (abandoned — last release 2023, open CVEs)
|
|
38
|
+
- passlib (BROKEN on Python 3.13+ — `crypt` module removed in 3.13)
|
|
39
|
+
- bcrypt directly (GPU-vulnerable vs argon2id)
|
|
40
|
+
|
|
41
|
+
### Queue: Celery 5 + Redis
|
|
42
|
+
- Most mature Python task queue — battle-tested at scale
|
|
43
|
+
- Redis broker: same Redis instance used for caching and rate limiting
|
|
44
|
+
- Alternatives considered: dramatiq (simpler but less ecosystem), RQ (less features)
|
|
45
|
+
|
|
46
|
+
### Logging: structlog 24
|
|
47
|
+
- Structured JSON logging — equivalent of pino for Python
|
|
48
|
+
- Built-in context binding, redaction, async support
|
|
49
|
+
- Alternatives rejected: loguru (less structured), standard logging (no structured output)
|
|
50
|
+
|
|
51
|
+
### Rate Limiting: slowapi + limits (Redis store)
|
|
52
|
+
- slowapi: FastAPI-native rate limiting via Depends()
|
|
53
|
+
- Redis store: distributed — works across multiple uvicorn workers
|
|
54
|
+
- Alternatives: custom middleware (more work, same result)
|
|
55
|
+
|
|
56
|
+
### Package Manager: uv
|
|
57
|
+
- 10-100x faster than pip
|
|
58
|
+
- Manages Python version + virtualenv + dependencies in one tool
|
|
59
|
+
- Replaces: pip, pip-tools, pyenv, virtualenv
|
|
60
|
+
- Lockfile (`uv.lock`) committed for reproducible installs
|
|
61
|
+
|
|
62
|
+
### Linter/Formatter: ruff
|
|
63
|
+
- Replaces: flake8 + black + isort + pyupgrade in one tool
|
|
64
|
+
- Written in Rust — 10-100x faster than alternatives
|
|
65
|
+
- Single config in `pyproject.toml`
|
|
66
|
+
|
|
67
|
+
### PgBouncer
|
|
68
|
+
- NOT in application code — infrastructure concern
|
|
69
|
+
- Uncomment in `docker-compose.yml` when concurrent users > 50
|
|
70
|
+
- App connects to PgBouncer (port 6432), PgBouncer connects to PostgreSQL
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Consequences
|
|
75
|
+
- FastAPI async: all DB calls must be `await session.execute(...)` — no sync ORM calls
|
|
76
|
+
- SQLAlchemy async: sessions are NOT thread-safe — inject via `Depends(get_session)`, never share
|
|
77
|
+
- Celery: sync tasks (Celery is sync by default) — use `asyncio.run()` inside tasks for async calls
|
|
78
|
+
- PyJWT: stateless tokens — revocation requires a Redis denylist check on every verify
|
|
79
|
+
- argon2id (pwdlib): intentionally slow — login endpoint will be slower than bcrypt (~200ms vs ~100ms)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Design Docs Index
|
|
2
|
+
|
|
3
|
+
| Document | Purpose |
|
|
4
|
+
|---|---|
|
|
5
|
+
| core-beliefs.md | Engineering constitution — WHY every rule exists |
|
|
6
|
+
| decisions/index.md | ADR registry |
|
|
7
|
+
| decisions/ADR-000-infrastructure.md | Stack choices and rationale |
|
|
8
|
+
|
|
9
|
+
Add a row here when creating a new design doc or ADR.
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Technical Debt Tracker
|
|
2
|
+
|
|
3
|
+
## Severity
|
|
4
|
+
| Level | Fix by |
|
|
5
|
+
|---|---|
|
|
6
|
+
| P0 | Immediately — security/data integrity |
|
|
7
|
+
| P1 | Within 2 sprints — blocks features |
|
|
8
|
+
| P2 | Within quarter — degrades quality |
|
|
9
|
+
| P3 | When in area — code smell |
|
|
10
|
+
|
|
11
|
+
## Open Debt
|
|
12
|
+
| ID | Severity | Area | Description | Created By | Date |
|
|
13
|
+
|---|---|---|---|---|---|
|
|
14
|
+
| *(none yet)* | — | — | — | — | — |
|
|
15
|
+
|
|
16
|
+
## Resolved Debt
|
|
17
|
+
| ID | Description | Resolved By | Date |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| *(none yet)* | — | — | — |
|
|
File without changes
|