# Deep Review — Phase 3: Семь измерений > Supporting reference. Применяй к файлам P0/P1 минимум, к P2/P3 — выборочно. ## A. Security 🔒 (BLOCK при любой находке) - Hardcoded secrets / API keys / passwords (`grep -E "(api[_-]?key|password|token|secret).*=.*['\"][a-zA-Z0-9]{16,}"` по diff) - SQL injection: f-string / `.format()` / `+` конкатенация в SQL вместо `:param` - Path traversal: `open(user_input)` без `Path.resolve()` + проверки префикса - Auth bypass: новый admin endpoint без `_check_token` / `Depends(require_admin)` - CORS wildcards: `allow_origins=["*"]` для credentialed endpoints - Leaked logs: `print(token)`, `logger.info(f"...{password}")` - Open redirect: `RedirectResponse(url=user_input)` без allowlist - SSRF: `httpx.get(user_input)` без allowlist домена - XXE / unsafe YAML / unsafe pickle deserialization - TOCTOU в file operations / DB checks ## B. Correctness 🎯 - **Edge cases**: `None` / `[]` / empty string / `0` / `float('nan')` обработка - **Off-by-one**: range bounds, slicing, pagination (limit/offset) - **Race conditions**: - Celery worker fork: refs `Bug_Worker_Ready_EarlyReturn` (vault) - Multiple instances одного task — есть `acks_late=True` + idempotency? - DB: `SELECT ... FOR UPDATE` где нужен row lock? - **Transaction symmetry**: каждый `BEGIN` → `COMMIT` или `ROLLBACK`? Nested `with db.begin()` корректны? - **Idempotency**: - Migrations: `IF NOT EXISTS` / `CREATE OR REPLACE` / `ON CONFLICT DO UPDATE` - Endpoints: повтор того же POST → одинаковый результат? - Scrapers: rerun → нет дубликатов в БД? - **Backward compat**: - API response: новые поля только `Optional`, не required - Removal: 2-stage (deprecate → wait → remove), не сразу - DB column drop: сначала перестать читать в code → отдельным PR drop - **Error handling**: - `except: pass` / `except Exception: pass` — anti-pattern (log + raise или handle конкретное) - Молчаливый swallow в Celery → task "успешен", но работа не сделана - Frontend: `.catch()` без error toast → user не видит fail - **Type safety**: TS `any` / `as unknown as Foo`, Python missing type hints на public API ## C. Performance ⚡ - **N+1 queries**: цикл с `db.execute(...)` или `await session.execute(...)` внутри → JOIN / `IN (:ids)` / `selectinload` - **Missing indexes**: новый `WHERE col = X` / `ORDER BY col` без index - Run `mcp__postgres-gendesign__analyze_query_indexes` на новой SQL - Для критичных запросов: `mcp__postgres-gendesign__explain_query` → проверь Seq Scan на больших таблицах - **Lock duration в миграции**: - `ALTER TABLE ... ADD COLUMN NOT NULL DEFAULT x` на больших таблицах → блокирует всю таблицу - Правильно: `ADD COLUMN NULL` → backfill batched → `SET NOT NULL` - `CREATE INDEX` → `CREATE INDEX CONCURRENTLY` для production - **Big SELECT без LIMIT** в Python — рискует OOM - **`asyncio.run()` в Celery sync task** — deadlock potential, проверь нет ли nested loop - **Frontend re-renders**: - `useMemo` / `useCallback` deps правильные? - `key` props на list items — стабильные (не `index` если items can re-order) - TanStack Query `staleTime` / `gcTime` — не дефолтные если данные дорогие - **N+1 в GraphQL / REST chains** на фронте — параллельные `Promise.all` или batch endpoint ## D. Project conventions 📋 Python (`.claude/rules/backend.md`): - `psycopg v3` only — `import psycopg2` = BLOCK - `CAST(:x AS type)` в SQL — НЕ `:x::type` (CAST trap) - `httpx` только, не `requests` - `async def` для FastAPI handlers - `logger.*` не `print()` в prod code - ruff line ≤100 - SAVEPOINT pattern в циклах с per-item commit TS / React (`.claude/rules/frontend.md` + `ui-tokens.md` + `ui-conventions.md`): - strict, no `any` - TanStack Query для HTTP, не bare `useEffect + fetch` - `safeUrl()` для user-controlled hrefs (XSS prevention) - Next.js 15 app router patterns (`'use client'` только где нужно) - Design tokens — только из `ui-tokens.md` списка (нет inline `#hex`) SQL (`.claude/rules/sql.md`): - `data/sql/NN_topic.sql` — numbered, sequential - `BEGIN; ... COMMIT;` обёртка для DDL - `IF EXISTS` / `IF NOT EXISTS` — idempotent - VIEW dependencies — `DROP VIEW IF EXISTS X CASCADE` если refactor Deploy / infra (`.claude/rules/deploy.md`): - `.env.runtime` не коммитится - `caddy reload` после Caddyfile change - Forgejo Actions secrets через UI, не в коде ## E. Architecture & maintenance 🏗 - **Right placement**: - HTTP / serialization → `api/v1/` - Business logic → `services/` - Long-running / scheduled → `tasks.py` (Celery) / `services//` - Не запихивай business logic в FastAPI handler - **DRY**: дубль логики в parcels.py vs analytics_queries.py vs services/? - **Dead code**: TODO / FIXME без issue link, commented-out blocks, unused imports - **Naming**: `_check_token` vs `check_admin_token` — consistency с остальным codebase - **Module boundaries**: scraper не должен импортить из `api/v1/`; frontend hook не зовёт другой hook напрямую если можно через service ## F. Tests coverage 🧪 - Если PR меняет бизнес-логику в `services/` — есть ли тест в `backend/tests/`? - Если added endpoint — есть ли smoke test? - Если fix bug — есть ли regression test покрывающий именно тот сценарий? - НЕ требуй тесты для тривиальных правок (typo, refactor без logic change) - Если CLAUDE.md / project явно говорит "не пиши тесты пока не попросят" — не настаивай ## G. Vault & decisions cross-check 📚 **Обязательный шаг для P0-P1 PR.** ``` mcp__obsidian__obsidian_simple_search "" mcp__obsidian__obsidian_simple_search "<имя функции / эндпоинта>" ``` Проверь: - [ ] `fixes/` — была ли уже эта же ошибка? Новый код не повторяет старый bug? - [ ] `decisions/` — есть ли архитектурный decision который этот PR нарушает? - [ ] `limitations/` — known issue который этот код должен учитывать? - [ ] `code/patterns/` — есть ли established pattern для этого типа изменения? Если PR fix bug — должна быть entry в `fixes/.md` (per CLAUDE.md rule #6). Если PR architectural change — должна быть entry в `decisions/.md`.