tillerhand 3.42.1 → 3.47.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/.claude/agents/board-chair.md +20 -20
- package/.claude/agents/code-reviewer.md +20 -20
- package/.claude/agents/council-advisor.md +14 -14
- package/.claude/agents/security-auditor.md +30 -30
- package/.claude/agents/test-writer.md +22 -21
- package/.claude/board/board-ai.md +25 -25
- package/.claude/board/board-api.md +25 -25
- package/.claude/board/board-architect.md +28 -28
- package/.claude/board/board-devops.md +25 -25
- package/.claude/board/board-mobile.md +25 -25
- package/.claude/board/board-performance.md +24 -24
- package/.claude/board/board-privacy.md +25 -25
- package/.claude/board/board-product.md +26 -26
- package/.claude/board/board-qa.md +28 -28
- package/.claude/board/board-ux.md +26 -26
- package/.claude/board/council.md +76 -76
- package/.claude/board/rules.md +61 -61
- package/.claude/claude-security-guidance.md +10 -10
- package/.claude/commands/adopt.md +70 -69
- package/.claude/commands/ask-mode.md +9 -9
- package/.claude/commands/board.md +15 -15
- package/.claude/commands/build.md +47 -47
- package/.claude/commands/dashboard.md +17 -17
- package/.claude/commands/design.md +31 -31
- package/.claude/commands/findings-all.md +14 -14
- package/.claude/commands/findings-business.md +7 -7
- package/.claude/commands/findings-legal.md +7 -7
- package/.claude/commands/findings-perf.md +7 -7
- package/.claude/commands/findings-security.md +9 -9
- package/.claude/commands/findings-tech.md +7 -7
- package/.claude/commands/findings-ux.md +7 -7
- package/.claude/commands/fix-bug.md +15 -15
- package/.claude/commands/freeze.md +8 -8
- package/.claude/commands/handoff.md +38 -38
- package/.claude/commands/kit-update.md +17 -14
- package/.claude/commands/language.md +13 -0
- package/.claude/commands/maintain.md +19 -19
- package/.claude/commands/plan-task.md +32 -32
- package/.claude/commands/qa.md +17 -17
- package/.claude/commands/release.md +40 -40
- package/.claude/commands/research.md +31 -31
- package/.claude/commands/retro.md +32 -32
- package/.claude/commands/review-changes.md +15 -15
- package/.claude/commands/rollback.md +24 -24
- package/.claude/commands/start.md +116 -113
- package/.claude/commands/tools.md +11 -11
- package/.claude/commands/user-feedback.md +11 -11
- package/.claude/commands/wrap-up.md +18 -18
- package/.claude/findings/lenses/business.md +24 -24
- package/.claude/findings/lenses/legal.md +29 -29
- package/.claude/findings/lenses/perf.md +19 -19
- package/.claude/findings/lenses/security.md +30 -30
- package/.claude/findings/lenses/tech.md +23 -23
- package/.claude/findings/lenses/ux.md +19 -19
- package/.claude/findings/protocol.md +54 -54
- package/.claude/findings/report-template.md +30 -30
- package/.claude/hooks/budget.mjs +7 -7
- package/.claude/hooks/checkpoint.mjs +12 -12
- package/.claude/hooks/commit-gate.mjs +50 -34
- package/.claude/hooks/cost.mjs +2 -2
- package/.claude/hooks/council.mjs +3 -3
- package/.claude/hooks/dashboard-data.mjs +3 -2
- package/.claude/hooks/dashboard.mjs +164 -149
- package/.claude/hooks/destructive-guard.mjs +74 -64
- package/.claude/hooks/edit-rounds.mjs +3 -3
- package/.claude/hooks/flow.mjs +10 -10
- package/.claude/hooks/freeze-guard.mjs +27 -23
- package/.claude/hooks/gate.mjs +25 -25
- package/.claude/hooks/guard-secrets.mjs +11 -11
- package/.claude/hooks/lang.mjs +114 -0
- package/.claude/hooks/messages.mjs +495 -0
- package/.claude/hooks/models.mjs +14 -11
- package/.claude/hooks/notify.mjs +3 -2
- package/.claude/hooks/package-gate.mjs +17 -15
- package/.claude/hooks/plugins-sync.mjs +9 -9
- package/.claude/hooks/prefs.mjs +19 -19
- package/.claude/hooks/preview.mjs +11 -11
- package/.claude/hooks/progress.mjs +14 -14
- package/.claude/hooks/qa-report.mjs +11 -10
- package/.claude/hooks/reminder.mjs +6 -3
- package/.claude/hooks/session-start.mjs +23 -17
- package/.claude/hooks/shared.mjs +1 -1
- package/.claude/hooks/status-read.mjs +5 -4
- package/.claude/hooks/statusline.mjs +14 -11
- package/.claude/hooks/structure-guard.mjs +9 -9
- package/.claude/hooks/test-guard.mjs +61 -20
- package/.claude/hooks/tools.mjs +28 -29
- package/.claude/hooks/usage.mjs +18 -15
- package/.claude/output-styles/anlatici.md +28 -28
- package/.claude/security-patterns.json +3 -3
- package/.claude/settings.json +6 -0
- package/.claude/skills/logo-design/SKILL.md +42 -42
- package/.claude/skills/motion-video/SKILL.md +52 -52
- package/.claude/skills/source-research/SKILL.md +35 -35
- package/.claude/skills/ui-motion/SKILL.md +38 -38
- package/.github/workflows/kit-tests.yml +7 -7
- package/.github/workflows/npm-publish.yml +16 -16
- package/AGENTS.md +56 -56
- package/CHANGELOG.md +7 -7
- package/CLAUDE.md +5 -5
- package/README.md +199 -172
- package/README.tr.md +292 -0
- package/docs/architecture/overview.md +31 -31
- package/docs/architecture/stack.md +2 -2
- package/docs/archive/README.md +4 -4
- package/docs/decisions/adr-template.md +14 -14
- package/docs/decisions/log.md +10 -10
- package/docs/findings/README.md +13 -13
- package/docs/findings/config.md +13 -13
- package/docs/legal/privacy-kvkk.md +1 -1
- package/docs/operations/accounts.md +25 -25
- package/docs/operations/deploy-setup.md +64 -64
- package/docs/operations/feature-flags.md +17 -17
- package/docs/operations/maintenance.md +48 -48
- package/docs/operations/release-checklist.md +61 -61
- package/docs/operations/spend-alarms.md +28 -28
- package/docs/product/feedback.md +9 -8
- package/docs/product/glossary.md +16 -16
- package/docs/product/launch.md +28 -28
- package/docs/product/prd.md +43 -42
- package/docs/product/roadmap.md +31 -30
- package/docs/product/specs/_template.md +13 -12
- package/docs/product/unit-economics.md +23 -22
- package/docs/quality/metrics.md +14 -14
- package/docs/quality/retros.md +11 -11
- package/docs/quality/test-plan.md +48 -48
- package/docs/security/checklist.md +57 -57
- package/docs/workflow/board.md +7 -7
- package/docs/workflow/cost-log.md +4 -4
- package/docs/workflow/decision-protocol.md +70 -70
- package/docs/workflow/learning.md +4 -4
- package/docs/workflow/mcp-catalog.md +31 -31
- package/docs/workflow/models.md +35 -35
- package/docs/workflow/progress.md +7 -7
- package/docs/workflow/skills.md +108 -108
- package/docs/workflow/usage-limits.md +62 -62
- package/kit/CHANGELOG.md +879 -839
- package/kit/VERSION +1 -1
- package/kit/guide.html +713 -477
- package/kit/guide.tr.html +1328 -0
- package/kit/kit.mjs +56 -54
- package/kit/project/README.md +29 -29
- package/kit/project/gitignore +12 -12
- package/kit/templates/addons/ai/.env.example.append +5 -5
- package/kit/templates/addons/ai/ai/evals/README.md +11 -11
- package/kit/templates/addons/ai/ai/evals/cases.jsonl +2 -2
- package/kit/templates/addons/ai/ai/prompts/README.md +8 -8
- package/kit/templates/addons/ai/docs/ai/guide.md +56 -56
- package/kit/templates/backend/.claude/hooks/format.mjs +1 -1
- package/kit/templates/backend/.claude/structure.json +1 -1
- package/kit/templates/backend/.env.example +6 -6
- package/kit/templates/backend/.github/dependabot.yml +1 -1
- package/kit/templates/backend/.github/workflows/ci.yml +13 -13
- package/kit/templates/backend/.github/workflows/claude-ci-fix.yml +19 -19
- package/kit/templates/backend/.github/workflows/claude-maintenance.yml +18 -18
- package/kit/templates/backend/.github/workflows/live-monitoring.yml +14 -14
- package/kit/templates/backend/.pre-commit-config.yaml +3 -3
- package/kit/templates/backend/docs/architecture/stack.md +98 -98
- package/kit/templates/backend/docs/architecture/structure.md +34 -34
- package/kit/templates/mobile/.claude/structure.json +1 -1
- package/kit/templates/mobile/.env.example +6 -6
- package/kit/templates/mobile/.github/dependabot.yml +2 -2
- package/kit/templates/mobile/.github/workflows/ci.yml +18 -18
- package/kit/templates/mobile/.github/workflows/claude-ci-fix.yml +19 -19
- package/kit/templates/mobile/.github/workflows/claude-maintenance.yml +18 -18
- package/kit/templates/mobile/.gitignore.append +2 -2
- package/kit/templates/mobile/docs/architecture/stack.md +113 -113
- package/kit/templates/mobile/docs/architecture/structure.md +33 -33
- package/kit/templates/mobile/docs/design/design-guide.md +37 -37
- package/kit/templates/mobile/tests/security/rls.mjs +22 -22
- package/kit/templates/web-saas/.claude/structure.json +1 -1
- package/kit/templates/web-saas/.env.example +11 -11
- package/kit/templates/web-saas/.github/dependabot.yml +3 -3
- package/kit/templates/web-saas/.github/workflows/ci.yml +20 -20
- package/kit/templates/web-saas/.github/workflows/claude-ci-fix.yml +19 -19
- package/kit/templates/web-saas/.github/workflows/claude-maintenance.yml +18 -18
- package/kit/templates/web-saas/.github/workflows/live-monitoring.yml +12 -12
- package/kit/templates/web-saas/docs/architecture/stack.md +116 -116
- package/kit/templates/web-saas/docs/architecture/structure.md +44 -44
- package/kit/templates/web-saas/docs/design/design-guide.md +38 -38
- package/kit/templates/web-saas/tests/live/smoke.spec.ts +4 -4
- package/kit/templates/web-saas/tests/security/rls.mjs +22 -22
- package/kit/tools/codex/.codex/hooks.json +1 -1
- package/package.json +2 -2
- package/README.en.md +0 -267
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
# Stack: Backend / API /
|
|
1
|
+
# Stack: Backend / API / Automation
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> This file is loaded into the AI every session. If the project makes a different choice, update this file
|
|
4
|
+
> and write the reason to `docs/decisions/log.md`.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Decision points
|
|
7
7
|
|
|
8
|
-
`/start`
|
|
8
|
+
`/start` asks these decisions in order (`docs/workflow/decision-protocol.md`). For each decision, offer the 2-4 options that fit this project best. The **recommended** label is the default, but if another option fits the PRD better, recommend that one and say why. A claim that can change (price, free tier, limit) with a `(kaynak: <adres>, YYYY-AA-GG)` note newer than 90 days is not researched again.
|
|
9
9
|
|
|
10
|
-
| # |
|
|
10
|
+
| # | Decision | Options (when each is better) |
|
|
11
11
|
|---|---|---|
|
|
12
|
-
| 1 |
|
|
13
|
-
| 2 |
|
|
14
|
-
| 3 | ORM /
|
|
15
|
-
| 4 |
|
|
16
|
-
| 5 |
|
|
17
|
-
| 6 | API
|
|
18
|
-
| 7 |
|
|
19
|
-
| 8 |
|
|
20
|
-
| 9 |
|
|
21
|
-
| 10 |
|
|
12
|
+
| 1 | Language and framework | **Python + FastAPI** (recommended: AI/data work, fast development, automatic OpenAPI docs) · Node.js + TypeScript + Hono/Fastify (same language as the frontend, shared types) · Go (high performance, single binary, low memory) · Django (ready-made admin panel, large monolith) |
|
|
13
|
+
| 2 | Database | **PostgreSQL** (recommended: fits everything, JSON support) · SQLite / Turso (single server, small scale, zero operations) · MongoDB (schemaless documents, variable structure) |
|
|
14
|
+
| 3 | ORM / queries | **SQLAlchemy 2 + Alembic** (Python) · SQLModel (one model with Pydantic, simpler) · If Node is chosen: Drizzle (recommended) / Prisma |
|
|
15
|
+
| 4 | Authentication | **An external provider's JWT** (Supabase Auth / Clerk; you do not write user management) · API key (service to service, B2B API) · Your own session/JWT (full control; the security burden is yours) |
|
|
16
|
+
| 5 | Background jobs | **Platform cron** (recommended for simple scheduled jobs) · ARQ / Celery + Redis (queue, retries, heavy work) · Temporal / Inngest (multi-step, long-running workflows) · None |
|
|
17
|
+
| 6 | API style | **REST + OpenAPI** (recommended) · GraphQL (many different clients, flexible queries) · tRPC (TypeScript clients only) |
|
|
18
|
+
| 7 | Hosting | **Railway** (recommended: easiest, Postgres included; no free permanent tier, Hobby is 5 dollars a month and includes 5 dollars of usage (kaynak: https://docs.railway.com/pricing/plans, 2026-10-26)) · Fly.io (region close to users, scaling) · Render · Google Cloud Run (pay per request, scales to zero) · VPS + Coolify (fixed cost, maintenance is yours) |
|
|
19
|
+
| 8 | Package management | **uv** (recommended for Python: very fast, lock file) · Poetry |
|
|
20
|
+
| 9 | Observability | **Sentry + structured logs** (Better Stack / Axiom) · OpenTelemetry (distributed services) |
|
|
21
|
+
| 10 | Testing | **pytest + httpx** (recommended) · If Node is chosen: Vitest + supertest |
|
|
22
22
|
|
|
23
23
|
## Seçilen teknolojiler
|
|
24
24
|
|
|
25
|
-
> `/start`
|
|
26
|
-
>
|
|
25
|
+
> Filled in by `/start` Step 4 from the decision points. The table below is the **recommended** stack and counts as a proposal until approved.
|
|
26
|
+
> If the choice differs, rewrite this file's commands, folder, rules, verification and checks sections to match.
|
|
27
27
|
|
|
28
|
-
|
|
|
28
|
+
| Layer | Choice | Note |
|
|
29
29
|
|---|---|---|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
30
|
+
| Language | Python 3.12+ | Alternative: Node.js + TypeScript (Hono/Fastify + Drizzle) |
|
|
31
|
+
| Package management | uv | `uv add`, not `pip install` |
|
|
32
32
|
| API | FastAPI + Pydantic v2 | |
|
|
33
|
-
|
|
|
34
|
-
| DB | PostgreSQL + SQLAlchemy 2 (
|
|
33
|
+
| Settings | pydantic-settings | All config comes from environment variables |
|
|
34
|
+
| DB | PostgreSQL + SQLAlchemy 2 (or SQLModel) | |
|
|
35
35
|
| Migration | Alembic | |
|
|
36
|
-
|
|
|
36
|
+
| Background jobs | Cron (platform) / ARQ / Celery | Only as needed; cron is enough for simple jobs |
|
|
37
37
|
| Lint + format | Ruff | |
|
|
38
38
|
| Test | pytest + httpx | |
|
|
39
|
-
|
|
|
39
|
+
| Packaging | Docker | |
|
|
40
40
|
| Hosting | Railway / Fly.io / Render | |
|
|
41
|
-
|
|
|
42
|
-
| Cron
|
|
41
|
+
| Error tracking | Sentry | |
|
|
42
|
+
| Cron monitoring | Healthchecks.io (dead man's switch) | Alarm if a job does not run |
|
|
43
43
|
|
|
44
|
-
## Komutlar
|
|
44
|
+
## Komutlar (commands)
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
uv sync #
|
|
48
|
-
uv run fastapi dev app/main.py #
|
|
47
|
+
uv sync # install dependencies
|
|
48
|
+
uv run fastapi dev app/main.py # development
|
|
49
49
|
uv run pytest # test
|
|
50
50
|
uv run ruff check . # lint
|
|
51
51
|
uv run ruff format . # format
|
|
52
|
-
uv run alembic revision --autogenerate -m "[ad]" # migration
|
|
53
|
-
uv run alembic upgrade head #
|
|
54
|
-
uv run --with pip-audit pip-audit #
|
|
52
|
+
uv run alembic revision --autogenerate -m "[ad]" # create a migration (always read the output)
|
|
53
|
+
uv run alembic upgrade head # apply migrations
|
|
54
|
+
uv run --with pip-audit pip-audit # dependency vulnerabilities
|
|
55
55
|
docker build -t [ad] . && docker run --env-file .env -p 8000:8000 [ad]
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
##
|
|
58
|
+
## Folder structure
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Feature-based structure and rules: `docs/architecture/structure.md`. Map: `.claude/structure.json` (writing outside it is asked about, CI checks it).
|
|
61
61
|
```
|
|
62
62
|
app/
|
|
63
|
-
├── main.py #
|
|
63
|
+
├── main.py # app, router registration, /health
|
|
64
64
|
├── config.py # pydantic-settings
|
|
65
|
-
├── core/ #
|
|
65
|
+
├── core/ # database session, security, logging, error handlers, shared dependencies
|
|
66
66
|
├── features/
|
|
67
|
-
│ └──
|
|
68
|
-
│ ├── router.py # HTTP
|
|
69
|
-
│ ├── service.py #
|
|
70
|
-
│ ├── repository.py #
|
|
67
|
+
│ └── <feature>/ # e.g. invoice/
|
|
68
|
+
│ ├── router.py # HTTP endpoints (thin)
|
|
69
|
+
│ ├── service.py # business logic
|
|
70
|
+
│ ├── repository.py # database access
|
|
71
71
|
│ ├── models.py # SQLAlchemy modelleri
|
|
72
|
-
│ ├── schemas.py # Pydantic
|
|
72
|
+
│ ├── schemas.py # Pydantic input/output schemas
|
|
73
73
|
│ ├── dependencies.py
|
|
74
74
|
│ └── exceptions.py
|
|
75
|
-
├── shared/ #
|
|
76
|
-
└── jobs/ #
|
|
75
|
+
├── shared/ # helpers used by more than one feature
|
|
76
|
+
└── jobs/ # scheduled and background jobs (idempotent)
|
|
77
77
|
alembic/ # migration'lar
|
|
78
78
|
tests/
|
|
79
|
-
├──
|
|
80
|
-
└── live/ #
|
|
79
|
+
├── <feature>/ # tests by feature (test_O_01_1_... kabul testleri dahil)
|
|
80
|
+
└── live/ # live monitoring tests
|
|
81
81
|
Dockerfile pyproject.toml uv.lock
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
##
|
|
84
|
+
## Coding rules
|
|
85
85
|
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
- **
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
- `/health`
|
|
94
|
-
-
|
|
95
|
-
-
|
|
86
|
+
- Keep the router thin; business logic goes in `services/`.
|
|
87
|
+
- Every endpoint has a Pydantic input schema; the response has a schema too (internal fields must not leak).
|
|
88
|
+
- Use a consistent error format: `{"error": {"code": "...", "message": "..."}}`.
|
|
89
|
+
- Pagination is required on list endpoints.
|
|
90
|
+
- **An explicit timeout on every external call** (`requests` has no default timeout, so a request can hang forever) and, where needed, retry with backoff.
|
|
91
|
+
- Jobs are **idempotent**: running twice does no harm.
|
|
92
|
+
- Logs are structured (JSON) and include the request id; they contain no personal data or secrets.
|
|
93
|
+
- `/health` endpoint: the app + the DB connection.
|
|
94
|
+
- Review migrations by hand; `autogenerate` does not catch everything correctly.
|
|
95
|
+
- Do not use a synchronous, blocking library in an async endpoint.
|
|
96
96
|
|
|
97
|
-
##
|
|
97
|
+
## Verification (evidence before a task is done)
|
|
98
98
|
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
- Migration: `alembic upgrade head` → `alembic downgrade -1` → `alembic upgrade head`
|
|
99
|
+
- Endpoint: run the server, then use `curl -i` (or httpx) for the main scenario + an unauthorized request + invalid input. Show the request and the response.
|
|
100
|
+
- Job/cron: trigger the job by hand once, show the log and its effect in the DB; run it twice and show it is idempotent.
|
|
101
|
+
- Migration: `alembic upgrade head` → `alembic downgrade -1` → `alembic upgrade head` passes cleanly.
|
|
102
102
|
|
|
103
|
-
##
|
|
103
|
+
## Automatic checks
|
|
104
104
|
|
|
105
|
-
|
|
|
105
|
+
| Layer | What it does | Setup |
|
|
106
106
|
|---|---|---|
|
|
107
|
-
| Claude
|
|
108
|
-
| Pre-commit | Ruff +
|
|
109
|
-
| CI (+ Semgrep,
|
|
110
|
-
| Dependabot |
|
|
111
|
-
| MCP |
|
|
107
|
+
| Claude hooks | Block writing secrets; format `.py` files with Ruff and feed lint errors back to the AI | Ready (`.claude/settings.json`). Needs Node.js |
|
|
108
|
+
| Pre-commit | Ruff + secret scan, before commit | `uvx pre-commit install` (once) |
|
|
109
|
+
| CI (+ Semgrep, duplicate code, complexity budget) | Lint, format, migration, test, vulnerability scan, Docker build, gitleaks, complexity budget on changed files (function complexity 15, function 80, file 400 lines; `node .claude/hooks/budget.mjs --check`) | `.github/workflows/ci.yml` is ready; push to GitHub |
|
|
110
|
+
| Dependabot | Weekly dependency PRs | `.github/dependabot.yml` is ready |
|
|
111
|
+
| MCP | Read errors in Sentry (`/maintain`) | `.mcp.json` is ready; sign in to Sentry on first use |
|
|
112
112
|
|
|
113
|
-
##
|
|
113
|
+
## Acceptance tests and feature flags
|
|
114
114
|
|
|
115
|
-
**
|
|
115
|
+
**Acceptance tests** (`docs/quality/test-plan.md` §1a): The test function name carries the criterion id (`test_O_01_1_...`). The dashboard reads the JUnit report:
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
118
|
uv run pytest --junitxml=test-results/junit.xml
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
**Feature flags** (`docs/operations/feature-flags.md`): An emergency shutoff must not need a redeploy. Use a `feature_flags` table in the database (`ad`, `acik`, `yuzde`, `guncellendi`) + a 60 s in-process cache. Reading happens in one place: `app/services/bayrak.py` → `bayrak_acik("ad", kullanici_id)`. Changing a flag is done through an admin endpoint or SQL and is logged.
|
|
122
122
|
|
|
123
|
-
##
|
|
123
|
+
## Common AI mistakes (watch for these)
|
|
124
124
|
|
|
125
|
-
-
|
|
126
|
-
- Pydantic v1
|
|
127
|
-
-
|
|
128
|
-
- CORS
|
|
129
|
-
-
|
|
130
|
-
- DB
|
|
125
|
+
- Writing a machine-specific absolute path into code, a test or a setting (`C:\Users\<ad>\…`, `/home/<ad>/…`, the full path of the project folder): it does not work on another machine. Derive the path with `Path(__file__).parent`, a root from settings, or `tmp_path` in a test. The deterministic gate catches this.
|
|
126
|
+
- Mixing Pydantic v1 syntax (`class Config`, `.dict()`) with v2.
|
|
127
|
+
- Not setting a timeout on an external API call, swallowing the error (`except: pass`).
|
|
128
|
+
- Opening CORS with `allow_origins=["*"]` together with credentials.
|
|
129
|
+
- Writing a cron job inside the server as `while True: sleep` (lost on restart, cannot be monitored).
|
|
130
|
+
- Not closing the DB session, exhausting the connection pool.
|
|
131
131
|
|
|
132
|
-
##
|
|
132
|
+
## Security (extra)
|
|
133
133
|
|
|
134
|
-
- [ ]
|
|
135
|
-
- [ ] Rate limit (slowapi
|
|
136
|
-
- [ ]
|
|
137
|
-
- [ ] CORS
|
|
138
|
-
- [ ] Docker
|
|
134
|
+
- [ ] Authentication: JWT verification (signature + expiry + issuer) or an API key (stored hashed).
|
|
135
|
+
- [ ] Rate limit (slowapi or reverse proxy).
|
|
136
|
+
- [ ] `/docs` and `/openapi.json` are off or protected in prod.
|
|
137
|
+
- [ ] CORS allowlist.
|
|
138
|
+
- [ ] The Docker image runs as a non-root user, and the image has no `.env`.
|
|
139
139
|
|
|
140
|
-
##
|
|
140
|
+
## Go live (extra)
|
|
141
141
|
|
|
142
|
-
- [ ] Dockerfile:
|
|
143
|
-
- [ ]
|
|
144
|
-
- [ ] Migration
|
|
145
|
-
- [ ]
|
|
146
|
-
- [ ]
|
|
147
|
-
- [ ]
|
|
148
|
-
- [ ] Log
|
|
149
|
-
- [ ]
|
|
150
|
-
- [ ]
|
|
142
|
+
- [ ] Dockerfile: multi-stage, non-root user, `HEALTHCHECK`
|
|
143
|
+
- [ ] The platform health check points to `/health`
|
|
144
|
+
- [ ] Migration runs automatically or in a controlled way at the deploy step (before the app)
|
|
145
|
+
- [ ] Environment variables are on the platform; `DEBUG` is off
|
|
146
|
+
- [ ] Resource limits (memory/CPU) and automatic restart
|
|
147
|
+
- [ ] Every cron job pings Healthchecks.io; an alarm fires if it does not
|
|
148
|
+
- [ ] Log retention and search (platform logs or Better Stack/Axiom)
|
|
149
|
+
- [ ] A simple load trial (`hey`, `k6`): no errors at 3 times the expected traffic
|
|
150
|
+
- [ ] Response time target: p95 < 500 ms (main endpoints)
|
|
151
151
|
|
|
152
|
-
##
|
|
152
|
+
## Maintenance (extra)
|
|
153
153
|
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
154
|
+
- Weekly: did the cron jobs succeed, is the queue backing up, the 5xx rate.
|
|
155
|
+
- Monthly: `uv lock --upgrade` + tests, `uv run --with pip-audit pip-audit`, slow queries (`pg_stat_statements`).
|
|
156
|
+
- Quarterly: major versions of Python and core libraries, Docker base image update, DB index and size review.
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Project structure: Backend (FastAPI)
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> This file is the human-readable description of the `.claude/structure.json` map; update both together.
|
|
4
|
+
> Following the structure is mandatory: the hook checks at write time, CI on every PR, the board Architect and `/findings-tech` also check.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Code
|
|
7
7
|
|
|
8
8
|
```
|
|
9
9
|
app/
|
|
10
|
-
├── main.py #
|
|
10
|
+
├── main.py # app, router registrations, /health
|
|
11
11
|
├── config.py # pydantic-settings
|
|
12
|
-
├── core/ #
|
|
12
|
+
├── core/ # database session, security, logging, error handlers, common dependencies
|
|
13
13
|
├── features/
|
|
14
|
-
│ └──
|
|
15
|
-
│ ├── router.py # HTTP
|
|
16
|
-
│ ├── service.py #
|
|
17
|
-
│ ├── repository.py #
|
|
18
|
-
│ ├── models.py # SQLAlchemy
|
|
19
|
-
│ ├── schemas.py # Pydantic
|
|
14
|
+
│ └── <feature>/ # e.g. invoice/
|
|
15
|
+
│ ├── router.py # HTTP endpoints (thin)
|
|
16
|
+
│ ├── service.py # business logic
|
|
17
|
+
│ ├── repository.py # database access
|
|
18
|
+
│ ├── models.py # SQLAlchemy models
|
|
19
|
+
│ ├── schemas.py # Pydantic input/output schemas
|
|
20
20
|
│ ├── dependencies.py
|
|
21
21
|
│ └── exceptions.py
|
|
22
|
-
├── shared/ #
|
|
23
|
-
└── jobs/ #
|
|
24
|
-
alembic/ #
|
|
22
|
+
├── shared/ # helpers used by more than one feature
|
|
23
|
+
└── jobs/ # scheduled and background jobs (idempotent)
|
|
24
|
+
alembic/ # migrations
|
|
25
25
|
tests/
|
|
26
|
-
├──
|
|
27
|
-
└── live/ #
|
|
26
|
+
├── <feature>/ # tests by feature (including test_O_01_1_... acceptance tests)
|
|
27
|
+
└── live/ # live monitoring tests
|
|
28
28
|
Dockerfile pyproject.toml uv.lock
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Common to every project
|
|
32
32
|
|
|
33
33
|
```
|
|
34
34
|
.
|
|
35
|
-
├── .claude/ # Claude Code:
|
|
36
|
-
├── .github/ # CI, Dependabot,
|
|
35
|
+
├── .claude/ # Claude Code: commands, agents, hooks, board, findings, structure.json
|
|
36
|
+
├── .github/ # CI, Dependabot, cloud agents
|
|
37
37
|
├── docs/
|
|
38
38
|
│ ├── product/ # prd, roadmap, glossary, launch, feedback, unit-economics
|
|
39
|
-
│ ├── architecture/ # overview, stack, structure (
|
|
40
|
-
│ ├── design/ # design-guide (
|
|
41
|
-
│ ├── decisions/ # log.md (
|
|
39
|
+
│ ├── architecture/ # overview, stack, structure (this file)
|
|
40
|
+
│ ├── design/ # design-guide (if there is an interface)
|
|
41
|
+
│ ├── decisions/ # log.md (decision log) + adr-NNNN-*.md (detailed decisions)
|
|
42
42
|
│ ├── quality/ # test-plan, metrics, retros
|
|
43
43
|
│ ├── security/ # checklist
|
|
44
44
|
│ ├── legal/ # privacy-kvkk
|
|
45
45
|
│ ├── operations/ # release-checklist, maintenance, accounts, feature-flags
|
|
46
46
|
│ ├── workflow/ # progress, decision-protocol, skills, board, usage-limits, cost-log
|
|
47
|
-
│ ├── findings/ # /findings-*
|
|
48
|
-
│ └── archive/ #
|
|
49
|
-
├── sandbox/ #
|
|
47
|
+
│ ├── findings/ # /findings-* reports (type/date.md, latest.md)
|
|
48
|
+
│ └── archive/ # documents that are no longer valid but kept
|
|
49
|
+
├── sandbox/ # trials, exploration code, temporary scripts (not committed to git)
|
|
50
50
|
├── AGENTS.md CLAUDE.md README.md CHANGELOG.md
|
|
51
51
|
└── .env.example
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
##
|
|
54
|
+
## Rules
|
|
55
55
|
|
|
56
|
-
1. **
|
|
57
|
-
2.
|
|
58
|
-
3.
|
|
59
|
-
4. **
|
|
60
|
-
5. **
|
|
61
|
-
6. **
|
|
62
|
-
7. **
|
|
56
|
+
1. **A new file goes to its place in the map.** Writing outside the `.claude/structure.json` map is asked about; clutter patterns (`*.bak`, `*-old.*`, `* copy*`, `temp/`, `deneme*`) are blocked. CI checks the whole repo on every PR.
|
|
57
|
+
2. **By feature.** Everything that belongs to a feature (component, logic, test) lives under `features/<feature>/`. When two features start using the same code, it moves to the shared layer (`components/`, `lib/`, `shared/`).
|
|
58
|
+
3. **Features do not reach into each other.** `features/a` does not import another feature's internal files; it uses only what that feature exposes through its `index` file.
|
|
59
|
+
4. **Naming:** Folders and files use `kebab-case`. React component files may be `PascalCase.tsx`; Python modules use `snake_case.py`. A feature folder name is singular and in English (`invoice`, `customer`).
|
|
60
|
+
5. **Temporary and unrelated work** goes under `sandbox/`. If something useful comes out of it, it moves to the right place; `sandbox/` is cleaned regularly.
|
|
61
|
+
6. **Old documents** are not deleted; they move under `docs/archive/`, with a line at the top saying why they were archived.
|
|
62
|
+
7. **Changing the map** (a new top-level folder, a new layer) is a `teknik` decision: ask the user, record it under `docs/decisions/`, then update `.claude/structure.json` and this file.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "Mobile (Expo Router, by feature). New files are written only to places that match these patterns; changing them is a technical decision. Details: docs/architecture/structure.md",
|
|
3
3
|
"allow": [
|
|
4
4
|
"README.md",
|
|
5
5
|
"CHANGELOG.md",
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
# EXPO_PUBLIC_
|
|
4
|
-
#
|
|
1
|
+
# This file is committed; DO NOT WRITE REAL VALUES. Copy: cp .env.example .env
|
|
2
|
+
# Local values come only from the DEVELOPMENT (dev) project. Production values live only in EAS environment variables; they never reach this machine or the AI environment.
|
|
3
|
+
# Variables starting with EXPO_PUBLIC_ are embedded in the app bundle = public.
|
|
4
|
+
# Anything that needs a secret key runs on the server (Supabase Edge Function / backend).
|
|
5
5
|
|
|
6
6
|
EXPO_PUBLIC_API_URL=
|
|
7
7
|
EXPO_PUBLIC_SUPABASE_URL=
|
|
8
|
-
EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY= # sb_publishable_… (
|
|
8
|
+
EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY= # sb_publishable_… (the secret key never goes into the app)
|
|
9
9
|
EXPO_PUBLIC_REVENUECAT_IOS_KEY=
|
|
10
10
|
EXPO_PUBLIC_REVENUECAT_ANDROID_KEY=
|
|
11
11
|
EXPO_PUBLIC_SENTRY_DSN=
|
|
12
12
|
|
|
13
|
-
#
|
|
13
|
+
# Build/EAS side only (not bundled in the app; add to EAS Secrets too)
|
|
14
14
|
SENTRY_AUTH_TOKEN=
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# Expo SDK
|
|
2
|
-
#
|
|
1
|
+
# Packages tied to the Expo SDK are updated with 'npx expo install --fix', not with Dependabot.
|
|
2
|
+
# For security updates: GitHub > Settings > Code security > Dependabot security updates: On.
|
|
3
3
|
version: 2
|
|
4
4
|
updates:
|
|
5
5
|
- package-ecosystem: npm
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Runs on every push and PR. The build (EAS) is not done here; it is done on EAS.
|
|
2
2
|
name: CI
|
|
3
3
|
|
|
4
4
|
on:
|
|
@@ -6,7 +6,7 @@ on:
|
|
|
6
6
|
branches: [main]
|
|
7
7
|
pull_request:
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Jobs only read the repo; a hijacked step must not be able to write to the repo with the token
|
|
10
10
|
permissions:
|
|
11
11
|
contents: read
|
|
12
12
|
|
|
@@ -23,16 +23,16 @@ jobs:
|
|
|
23
23
|
- run: npx expo lint
|
|
24
24
|
- run: npx tsc --noEmit
|
|
25
25
|
- run: npm run --if-present test
|
|
26
|
-
- name: SDK
|
|
26
|
+
- name: SDK compatibility
|
|
27
27
|
run: npx expo-doctor
|
|
28
|
-
- name:
|
|
28
|
+
- name: Dependency vulnerabilities (high and above)
|
|
29
29
|
run: npm audit --audit-level=high --omit=dev
|
|
30
30
|
|
|
31
31
|
structure:
|
|
32
32
|
runs-on: ubuntu-latest
|
|
33
33
|
steps:
|
|
34
34
|
- uses: actions/checkout@v7
|
|
35
|
-
- name:
|
|
35
|
+
- name: Folder structure (.claude/structure.json)
|
|
36
36
|
run: node .claude/hooks/structure-guard.mjs --check
|
|
37
37
|
|
|
38
38
|
karmasiklik:
|
|
@@ -40,14 +40,14 @@ jobs:
|
|
|
40
40
|
steps:
|
|
41
41
|
- uses: actions/checkout@v7
|
|
42
42
|
with:
|
|
43
|
-
fetch-depth: 0 # base commit
|
|
44
|
-
- name:
|
|
43
|
+
fetch-depth: 0 # to compare with the base commit
|
|
44
|
+
- name: Complexity budget (changed files; function complexity 15, function 80, file 400 lines)
|
|
45
45
|
env:
|
|
46
46
|
BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
|
|
47
47
|
run: node .claude/hooks/budget.mjs --check --base "$BASE"
|
|
48
48
|
|
|
49
|
-
# RLS
|
|
50
|
-
# Supabase
|
|
49
|
+
# RLS adversarial test: an empty local Supabase starts inside CI and the migrations are applied. No secrets needed; it does not touch dev or prod.
|
|
50
|
+
# If Supabase is not used (no supabase/config.toml), the steps are skipped.
|
|
51
51
|
rls:
|
|
52
52
|
runs-on: ubuntu-latest
|
|
53
53
|
steps:
|
|
@@ -59,13 +59,13 @@ jobs:
|
|
|
59
59
|
cache: npm
|
|
60
60
|
- if: hashFiles('supabase/config.toml') != ''
|
|
61
61
|
run: npm ci
|
|
62
|
-
- name:
|
|
62
|
+
- name: Local Supabase
|
|
63
63
|
if: hashFiles('supabase/config.toml') != ''
|
|
64
64
|
run: npx -y supabase@2.120.0 start -x studio,imgproxy,edge-runtime,logflare,vector,realtime,storage-api,supavisor,postgres-meta
|
|
65
|
-
- name: RLS
|
|
65
|
+
- name: RLS adversarial test (anonymous and second user)
|
|
66
66
|
if: hashFiles('supabase/config.toml') != ''
|
|
67
67
|
run: |
|
|
68
|
-
#
|
|
68
|
+
# Only the needed keys are taken; the output is not run as a shell command
|
|
69
69
|
anahtarlar=$(npx -y supabase@2.120.0 status -o env | grep -E '^(API_URL|ANON_KEY|SERVICE_ROLE_KEY|DB_URL|PUBLISHABLE_KEY|SECRET_KEY)=')
|
|
70
70
|
while IFS="=" read -r ad deger; do deger="${deger%\"}"; export "$ad=${deger#\"}"; done <<< "$anahtarlar"
|
|
71
71
|
node --test tests/security/rls.mjs
|
|
@@ -76,29 +76,29 @@ jobs:
|
|
|
76
76
|
image: semgrep/semgrep
|
|
77
77
|
steps:
|
|
78
78
|
- uses: actions/checkout@v7
|
|
79
|
-
- name:
|
|
79
|
+
- name: Static security analysis (high severity findings stop CI)
|
|
80
80
|
run: semgrep scan --config p/default --config p/owasp-top-ten --severity ERROR --error
|
|
81
81
|
|
|
82
82
|
kopya-kod:
|
|
83
83
|
runs-on: ubuntu-latest
|
|
84
84
|
steps:
|
|
85
85
|
- uses: actions/checkout@v7
|
|
86
|
-
- name:
|
|
86
|
+
- name: Duplicate code ratio (threshold 5%)
|
|
87
87
|
run: npx --yes jscpd@4 --threshold 5 --silent --ignore "**/node_modules/**,**/.next/**,**/dist/**,**/build/**,**/.venv/**,**/coverage/**,**/.expo/**" .
|
|
88
88
|
|
|
89
89
|
sir-taramasi:
|
|
90
90
|
runs-on: ubuntu-latest
|
|
91
|
-
# gitleaks
|
|
91
|
+
# gitleaks reads the commit list on a PR (pulls/{n}/commits); in a private repo this gives 403 without this permission
|
|
92
92
|
permissions:
|
|
93
93
|
contents: read
|
|
94
94
|
pull-requests: read
|
|
95
95
|
steps:
|
|
96
96
|
- uses: actions/checkout@v7
|
|
97
97
|
with:
|
|
98
|
-
fetch-depth: 0 #
|
|
99
|
-
#
|
|
98
|
+
fetch-depth: 0 # the whole history is scanned
|
|
99
|
+
# Free on a personal account; an organization repo needs the GITLEAKS_LICENSE secret
|
|
100
100
|
- uses: gitleaks/gitleaks-action@v3
|
|
101
101
|
env:
|
|
102
102
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
103
|
-
#
|
|
103
|
+
# The token is read-only: PR comments are off, a leak turns the job red
|
|
104
104
|
GITLEAKS_ENABLE_COMMENTS: "false"
|