gendesign/CLAUDE.md
lekss361 7c43bc5496
feat(infra): auto-apply data/sql/*.sql migrations in deploy pipeline (#150) (#151)
* fix(frontend): apiFetchWithStatus body stream double-read crash

Per user report 2026-05-14: 'Failed to execute text on Response: body stream
already read' при analyze с non-JSON error response.

apiFetchWithStatus делал .json() (consumes stream), потом .text() в catch
(FAILS — stream already consumed). Fetch API: body — ReadableStream,
consumable один раз.

Fix: read text() once → JSON.parse on string. На fail (HTML / non-JSON)
оборачиваем в {detail: rawText}. Никаких double-reads.

Site-finder cad search больше не крашится на error pages.

* feat(infra): auto-apply data/sql/*.sql migrations in deploy pipeline (#150)

Закрывает root cause production 500 на /api/v1/admin/site-finder/weight-profiles
(а также 2 unapplied migrations: #89/#91).

## Why это нужно

После audit обнаружили что:
- backend/alembic/versions/ пустой (Alembic configured но не используется)
- deploy.yml не имеет migration step
- 47+ raw SQL files накопилось без auto-apply
- 3 файла unapplied: 87 (engineering), 89 (drop brin), 90 (weight profiles)

User report: GET weight-profiles → 500 потому что user_weight_profiles
table не существует на prod.

## Changes

### deploy.yml +39 lines
- Path trigger расширен на data/sql/*.sql
- New step 'Apply DB migrations' между compose pull и compose up -d:
  - Idempotent CREATE TABLE _schema_migrations
  - Loop по data/sql/*.sql sorted → skip applied → psql with ON_ERROR_STOP=on
  - Record applied filename в tracking table
  - Exit 1 на failure → containers НЕ обновляются (no partial state)

### NN collision fix
- 87_engineering_networks_191fz.sql → 91_engineering_networks_191fz.sql
  (collision с 87_on_demand_indexes.sql, мой renumber 85→87 был неудачным)

### CLAUDE.md +32 lines
- Subsection 'Auto-apply' под Migration pattern
- Bootstrap procedure docs
- Idempotency requirement
- Failure recovery

### scripts/bootstrap_schema_migrations.sh +100 lines
- One-time seed _schema_migrations с 48 already-applied files
- 3 файла intentionally NOT seeded: 89/90/91 (auto-apply на first deploy)
- Usage docs + verification query

## Vault

domains/infra/Runbook_Auto_Apply_Migrations.md NEW
infra-MOC.md updated

## Required manual steps ДО merge

1. SSH gendesign (tunnel)
2. POSTGRES creds export
3. bash scripts/bootstrap_schema_migrations.sh — seed 48 already-applied files
4. Verify: SELECT COUNT(*) FROM _schema_migrations → 48
5. После merge → first deploy auto-apply #89/#90/#91 → 500 closes

Closes #150

---------

Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-15 08:06:54 +03:00

36 KiB
Raw Blame History

Instructions for Claude — GenDesign

Эти инструкции читаются автоматически при старте сессии Claude Code в этом репозитории. Они описывают: что за проект, как работать с кодом и инфрой, какие правила и какие "грабли" не наступать. Источник истины для бизнес-знания — Obsidian vault (см. ниже), а этот файл — про сам процесс разработки.


⚠️ TL;DR — обязательно прочитай первым

  1. Все memory / knowledge только в Obsidian vault obsidian.gendsgn.ru (CouchDB) ↔ C:\Users\user\Documents\gendesign-memory (mirror). Доступ через mcp__obsidian__* tools. Для анализа любой задачи и записи любой документации / решения / research — используй ТОЛЬКО vault.

  2. НЕ читай и НЕ пиши в legacy JSONL knowledge graph (memory/memory-gendesign.jsonl) — он deprecated. Файл оставлен в репе как историчекий снапшот, но не отражает текущее состояние.

  3. НЕ создавай новые .md файлы в docs/, notes/, wiki/ репозитория — knowledge живёт только в vault. Исключения для репа: README.md, CLAUDE.md, docs/*-strategy.md (исторические снапшоты бизнес-плана), inline-комментарии в коде.

  4. Workflow для новой задачи:

    1. obsidian_simple_search "<keyword>"  → найди MOC / related entities
    2. obsidian_get_file_contents для нужных → подгрузи контекст
    3. Делай работу в коде
    4. По итогу: append observation / create entity в vault через
       obsidian_patch_content / obsidian_append_content / Write (filesystem fallback)
    
  5. Branch + PR workflow обязательно — никаких direct push в main. Создаю feature branch (feat/... / fix/... / refactor/... / docs/... / chore/...), коммичу туда, push branch, gh pr create, отдаю URL пользователю. Merge только по явному approval. См. секцию "Git workflow".

  6. No --no-verify / --force / --amend — pre-commit hooks обязательны, force-push запрещён.


Project at a glance

GenDesign — две продуктовые линии: Site Finder (AI-подбор инвест-участков)

  • Generative Design (автогенерация концепций застройки) для девелоперов РФ. Регион Discovery — Свердловская обл. (ЕКБ, ПЗЗ, МСК-66). Live на https://gendsgn.ru/.

Tech stack

Слой Stack
Backend Python 3.12, FastAPI, SQLAlchemy 2.0, GeoAlchemy2, Pydantic v2, Celery + Redis, httpx, Shapely 2, scikit-learn
DB PostgreSQL 16 + PostGIS 3.4 (partitioned rosreestr_deals, GIST на geom, ~50 предметных таблиц)
Frontend Next.js 15 (app router), React 19, TypeScript 5, Tailwind 4, TanStack Query, Leaflet/Mapbox, ECharts
Export WeasyPrint (PDF), ezdxf (DXF), openpyxl (Excel)
Tooling uv (Python deps), ruff, mypy strict (selective), pytest, pre-commit, prettier
Deploy Beget VPS · GitHub Actions → GHCR → SSH → docker-compose · Caddy auto-TLS
Knowledge Obsidian vault на obsidian.gendsgn.ru (Self-hosted LiveSync + CouchDB)

Repository layout

backend/                 FastAPI + Celery (services, scrapers, workers, api/v1/*)
frontend/                Next.js (app router; analytics, admin, concept, site-finder)
data/sql/                ETL артефакты + миграции схемы (numbered NN_*.sql)
ops/                     backup.sh + deploy скрипты
scripts/                 утилиты (migrate_kg_to_obsidian.py, setup-couchdb.sh, etc)
docs/                    стратегические снапшоты (источник истины — Obsidian)
memory/                  legacy JSONL knowledge graph (deprecated)
docker-compose.prod.yml      main стек (backend, frontend, postgres, redis, worker, beat, caddy)
docker-compose.obsidian.yml  obsidian-стек (CouchDB) — деплоится отдельно
.github/workflows/
  deploy.yml             main stack (триггер: backend/**, frontend/**, Caddyfile)
  deploy-obsidian.yml    obsidian stack (триггер: docker-compose.obsidian.yml, scripts/setup-couchdb.sh)

Where knowledge lives — read THIS first

Obsidian vault на obsidian.gendsgn.ru — единственный source of truth для бизнес-знания (268+ entities + relations). Локальная папка vault'а: C:\Users\user\Documents\gendesign-memory.

Структура vault:

  • meta/ — Project_GenDesign, TechStack, NorthStar + setup guides (00_credentials, 01_connect_devices, 02_claude_usage, 03_obsidian_plugins, 04_mcp_obsidian_setup)
  • domains/{domrf,cadastre,rosreestr,analytics,ui,api,geo,infra,sitefinder}/
  • code/{modules,schemas,patterns,hooks,tasks}/
  • decisions/ fixes/ sessions/ sprints/ events/ research/ sources/ feedback/ github/ limitations/
  • MOC.md (Map of Content) в каждой папке + 00_index.md в корне vault'а

MCP для доступа к vault: mcp__obsidian__* tools (см. meta/02_claude_usage.md):

  • obsidian_simple_search — BM25 fulltext (Obsidian syntax: tag:#x, path:, ["yaml"])
  • obsidian_get_file_contents / obsidian_batch_get_file_contents
  • obsidian_list_files_in_dir
  • obsidian_patch_content (под heading) / obsidian_append_content
  • obsidian_complex_search (JsonLogic)

При работе над задачей: сначала obsidian_simple_search по ключевому слову → найди MOC или related entity → читай target файл. Это в 5-10 раз дешевле по токенам чем Grep + Read по всему репо.

Setup & dev commands

# Локально (Docker Desktop + Node 20 + uv):
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env
docker compose up -d --build
curl http://localhost:8000/health   # → {"status":"ok","environment":"dev"}

# Backend dev (без Docker):
cd backend && uv sync
uv run uvicorn app.main:app --reload

# Frontend dev:
cd frontend && npm install && npm run dev

# Migrations (Alembic — стандартный путь):
make migration NAME=add_foo_column
# или сырой SQL (data/sql/NN_xxx.sql) — для DDL артефактов которые
# не сделаны Alembic'ом (большие views, материализации, partitions).

# Tests:
cd backend && uv run pytest
cd frontend && npm test

# Lint + typecheck (запускается в pre-commit, но можно явно):
cd backend && uv run --no-project --with ruff ruff check app/
cd backend && uv run mypy app/services/generative app/services/site_finder/scorer
cd frontend && npx tsc --noEmit -p tsconfig.json
cd frontend && npm run lint

# Codegen TS типов из Pydantic OpenAPI:
cd frontend && npm run codegen

Code style & conventions

Python (backend)

  • Line length 100 (ruff)
  • Ruff rules: E F I B UP N RUF ASYNC; ignored RUF001/002/003 (Cyrillic в комментариях — нормально)
  • mypy strict только для app.services.generative.* и app.services.site_finder.scorer (см. Validation_Findings_Apr25 entity в vault)
  • psycopg v3 only (psycopg[binary]>=3.2.0) — НЕ психcopg2 (его нет в зависимостях; импорт упадёт ModuleNotFoundError). Для bulk INSERT use cur.executemany() или COPY, НЕ execute_values.
  • Type hints везде, Any — только обоснованно
  • Docstrings на русском OK (но без emoji-spam), bullet-факты предпочтительнее художественного описания
  • Async: FastAPI handlers — async def, Celery tasks — def (Celery sync)
  • Tests: pytest + asyncio_mode = auto

Frontend (TS/React)

  • Prettier + ESLint (запускается в pre-commit)
  • React 19 + Next 15 app router (НЕ pages router)
  • TanStack Query для data-fetching, без useEffect для HTTP
  • TS strict, никаких any; для unknown shape → unknown + narrow
  • Styling: Tailwind 4 утилитарные классы, inline styles только для динамики
  • TanStack Query keys как массивы: ["scrape-logs", scraperType, runIdFilter]

SQL

  • Файлы в data/sql/ именуются NN_topic.sql (NN = sequential int, e.g. 78_drop_use_rosreestr2coord.sql)
  • BEGIN ... COMMIT для DDL чтобы атомарно
  • IF EXISTS / IF NOT EXISTS для идемпотентности
  • Комментарии в начале файла: контекст + порядок применения + dependencies
  • View'ы пересоздаются CREATE OR REPLACE VIEW
  • Колонки удаляются ALTER TABLE ... DROP COLUMN IF EXISTS (после удаления зависимостей)

Git workflow — BRANCH + PR mandatory

Workflow (НИКАКОГО direct push в main)

1. Создаём feature branch:    git checkout -b feat/foo-bar
2. Commits на этой ветке:      git commit -m "..."
3. Push branch:                git push -u origin feat/foo-bar
4. Создаём PR:                 gh pr create --title "..." --body "..."
5. Show PR URL пользователю → ждём review
6. Пользователь комментирует / approves
7. После approval — пользователь merge'ит (или я merge'у после явного "merge it")
8. Удаляем branch после merge

Branches

  • main — protected, никаких direct push. Только через PR merge.
  • Feature branches: feat/short-description / fix/short-description / refactor/... / docs/... / chore/...
  • Trunk-based, мелкие PR'ы (1-2 файла или 1 концептуальное изменение)

Commit messages (на feature branch)

  • Imperative mood: "fix worker crash" не "fixed worker crash"
  • Длинный prefix: feat(scope): ..., fix(scope): ..., refactor(scope): ..., docs(scope): ..., chore: ...
  • Body — почему, не что (что видно в diff)
  • Атомарные коммиты — один логический шаг = один коммит
  • НЕ добавлять Co-Authored-By: Claude ... (per feedback rule)

PR

  • Title: краткое описание изменения (под 70 символов)
  • Body должен содержать:
    • ## Summary — 1-3 bullet'a что изменилось
    • ## Test plan — что проверить пользователю / какие команды smoke test'а
    • Cross-refs: Closes #N, Relates to #N, ссылка на vault entity
  • gh pr create с --title + --body (через HEREDOC чтобы preserve formatting)
  • После создания — вернуть PR URL пользователю, ждать его approval
  • Squash on merge — PR в main объединяется одним коммитом через squash (предпочтительно gh pr merge --squash).

Code review pipeline

Worker (backend/frontend/database/devops) пишет код на feature branch
  ↓
Main session делает commit на feature branch (worker'у запрещено git commit)
  ↓
[опционально] code-reviewer agent делает review
  ↓ если ✅
git push -u origin feat/branch
  ↓
gh pr create  →  PR URL пользователю
  ↓
User approves / requests changes
  ↓
Если changes — main session делает fixup commits на той же branch + push
  ↓
По явному "merge it" / "approved" от user → gh pr merge --squash

Critical workflow rules (НЕ нарушать)

  1. НИКОГДА не пуш напрямую в main. Только через PR merge.
  2. Worker-agents (backend/frontend/devops/database) НЕ делают git commit сами. Они оставляют изменения staged — main session коммитит на feature branch.
  3. Никогда не используй --no-verify / --no-edit / --amend — pre-commit hooks обязательны. Если hook падает — fix root cause, не bypass.
  4. Никогда не пуш с --force ни в main ни в feature branch без approval.
  5. Merge PR только по approval. Approval сигналы:
    • Human user всегда валиден: "merge it" / "ok merge" / "approved" / "залей" / "мердж"
    • Auto-review bot LGTM = approval, НО с ограничениями (см. "Auto-merge scope" ниже). Bot LGTM валиден только если SHA marker в теле комментария совпадает с current PR HEAD SHA — иначе это устаревший approval до fixup-push.
  6. Auto-merge scope (где боту разрешено self-merge без человека):
    • Разрешено (PR diff целиком в этих путях):
      • CLAUDE.md, README.md, docs/** (документация / правила)
      • frontend/src/app/** UI-only changes без новых API endpoints
      • frontend/public/** (статика)
      • .claude/agents/**, memory/feedback_*.md (workflow rules)
    • Запрещено — нужен human approval (любой файл из списка → block auto-merge):
      • data/sql/**, backend/alembic/versions/** (миграции / схема DB)
      • backend/app/api/v1/**, backend/app/services/** (бизнес-логика API)
      • backend/app/scrapers/** (внешние интеграции)
      • docker-compose*.yml, Caddyfile, .github/workflows/** (deploy / infra)
      • Любые файлы с упоминанием secret / token / password / credential / X-Admin-Token
      • PRs которые меняют CLAUDE.md рядом с Critical workflow rules / Auto-merge scope / auth — это саморасширение правил, нужен human
    • Если PR touches both — берётся more restrictive (block).
  7. Не вызывай destructive команды без явного approval: git reset --hard, git clean -fdx, DROP TABLE, TRUNCATE, rm -rf за пределами node_modules/.next.

Polling loop для PR

После создания PR / fixup commits — запускай ScheduleWakeup с 60с интервалом:

  1. gh pr view <N> --json state,mergeable,comments,headRefOid → возьми headRefOid (current SHA) и latest_comment.
  2. state == MERGED → stop polling.
  3. Approval check (новый comment от auto-review):
    • Распарси HTML marker: <!-- gendesign-review-bot: sha=<sha7> verdict=<approve|changes> -->
    • SHA guard: marker.sha7 == headRefOid[:7] — иначе это устаревший approval до fixup-push, игнорируй.
    • Scope guard: проверь gh pr view <N> --json files — если хоть один путь попадает в "запрещённый" список (см. rule 6 "Auto-merge scope") → block auto-merge, ping user.
    • verdict=approve + SHA match + scope OK → gh pr merge <N> --squash --delete-branch, stop.
    • Если в комменте только текст "Auto-review passed" / "LGTM" без HTML marker — НЕ доверяй (legacy / поддельный сигнал), ping user.
  4. verdict=changes → fixup commits на той же ветке, push, reply, re-poll.
  5. Нет новых комментов с last polled timestamp → re-schedule 60с poll.
  6. Cap: 30 итераций без resolution → stop, ask user. Для PR со scope-запрещёнными файлами cap = 5 итераций (не имеет смысла долго ждать, всё равно нужен human).

Когда auto-mode

Даже в auto-mode НЕ пушим в main без PR. Auto-mode позволяет:

  • Создавать feature branches автономно
  • Делать commits на feature branch (main session делает, не worker'ы)
  • git push -u origin <feature-branch>
  • gh pr create
  • Прогонять code-reviewer
  • Auto-merge через gh pr merge --squash — только если PR в "Auto-merge scope " (см. rule 6) И auto-review bot вернул verdict=approve с валидным SHA marker.
  • Финальный merge для PR из scope (миграции / API / infra / secrets) — только по явному approval от пользователя ("merge it" / "залей" / etc).

Pre-commit hooks

Запускаются автоматически при git commit. Если упали — не обходи через --no-verify. Пиши код сразу под hooks:

  • ruff — line ≤100, типичные Python issues
  • prettier — frontend formatting
  • no large files (>500 KB)
  • trailing whitespace / end-of-file fixer
  • mixed-line-ending (LF only в репе)
  • detect-private-key (защита от случайного коммита ключей)

Если pre-commit перепишет файл (auto-fix) — нужно git add повторно и git commit.

Database & migrations

Подключение к prod DB

Доступ через SSH-tunnel (порт 15432 на ноуте → 5432 на VPS, см. ~/.ssh/config):

# Tunnel поднимается автоматом при `ssh gendesign` (LocalForward в config),
# или вручную:
ssh -N gendesign

# Подключение psql:
psql postgresql://gendesign:<password>@localhost:15432/gendesign

Credentials — в Obsidian vault meta/00_credentials.md (НЕ в этом файле, НЕ в коммитах!).

Migration pattern

  1. Alembic migrations для prod schema changes (backend/alembic/versions/).
  2. Raw SQL artifacts (data/sql/NN_xxx.sql) для:
    • Bootstrap / dev seed
    • Большие view с UNION
    • Material partitions / GIST индексы
    • Удалить колонку с CASCADE-зависимостями

Auto-apply (data/sql/*.sql → prod)

data/sql/NN_*.sql миграции применяются автоматически через deploy.yml после compose pull и до compose up -d. Tracking через _schema_migrations table в prod DB — каждый файл применяется ровно один раз, в порядке sort (NN order).

При добавлении новой миграции:

  1. Создаёшь data/sql/NN_xxx.sql (NN — следующий sequential номер)
  2. Открываешь PR — merge автоматически триггерит deploy
  3. Deploy auto-apply этого файла + любых других pending

Bootstrap (one-time): до первого auto-deploy после merge PR #150 — запустить ./scripts/bootstrap_schema_migrations.sh на prod вручную (через SSH tunnel) чтобы seed tracking table с уже-applied файлами. Иначе auto-deploy попытается применить все 88 исторических файлов, многие не idempotent.

Idempotency: каждый новый .sql файл должен быть idempotent (IF NOT EXISTS, ON CONFLICT DO NOTHING, CREATE OR REPLACE VIEW) — на случай частичного применения или ручного ре-apply.

Если auto-apply падает: deploy завершится с ошибкой (exit 1). Containers не обновятся. Диагностика: посмотреть GitHub Actions log шага "Apply DB migrations". Ручной fix: psql -f data/sql/NN_xxx.sql через SSH tunnel, затем вручную INSERT INTO _schema_migrations (filename) VALUES ('NN_xxx.sql') ON CONFLICT DO NOTHING;, затем rerun workflow.

Applying migrations к prod

Order matters:

  1. Apply migration first (SQL → prod) — теперь auto через deploy.yml
  2. Deploy backend code that matches new schema
  3. Никогда наоборот — иначе deployed code напорется на старую/новую несовместимую схему

Если миграция меняет существующие FK / column type / drop column — read-then-write дискретно: верифицируй на staging, имей rollback ready.

Postgres MCP

Доступ из Claude к prod DB через mcp__postgres-gendesign__* tools (после SSH tunnel). Для прод-чтения нужен explicit approval — safety guard для production reads.

Deploy

GitHub Actions:

  • .github/workflows/deploy.yml — main: build & push backend (lean + worker-with-chromium) + frontend → SSH → compose pull && up -d + caddy reload + /health check
  • .github/workflows/deploy-obsidian.yml — obsidian: SSH compose up -d для couchdb + idempotent scripts/setup-couchdb.sh bootstrap

Триггеры по path:

  • Push в backend/**, frontend/**, Caddyfile, docker-compose.prod.yml, data/sql/*.sqldeploy.yml
  • Push в docker-compose.obsidian.yml, scripts/setup-couchdb.sh, docs/obsidian-livesync.mddeploy-obsidian.yml
  • Push только в docs/** (не из триггеров выше) — деплоев не вызывает

Sentry release tracking: SENTRY_RELEASE=$IMAGE_TAG пишется в backend/.env.runtime на VPS через sed (НЕ полная перезапись файла — там user-managed COUCHDB_PASSWORD и пр.).

Specialized subagents

В .claude/agents/ лежит 6 subagent'ов — 4 worker'a + 2 read-only (analyst, reviewer). Каждый имеет:

  • Свой context window (не засоряет main session)
  • Restricted tool set (не делает что-то вне его scope)
  • Pre-loaded knowledge о доменных конвенциях

Workers (4) — пишут код

Agent Когда использовать
backend-engineer (blue) Работа в backend/app/ — FastAPI, Celery, scrapers, services, ETL
frontend-engineer (green) Работа в frontend/ — Next.js pages, components, hooks, admin UI
devops-engineer (orange) docker-compose*.yml, Caddyfile, .github/workflows/, deploy issues, SSH operations
database-expert (purple) data/sql/NN_*.sql migrations, Alembic, EXPLAIN ANALYZE, index design, schema changes

Read-only (2) — не пишут код

Agent Когда использовать
tech-analyst (yellow) Нечёткий запрос ("надо ускорить", "что чинить дальше"), cross-domain задачи (2+ слоя), рефакторинг-разборы, аудит. Возвращает план, main session раздаёт worker'ам.
code-reviewer (red) Review ПОСЛЕ worker'а ДО git push. Проверяет: security (secrets, SQL injection, auth bypass), correctness (edge cases, transactions, idempotency), performance (N+1, индексы, re-renders), conventions (ruff/prettier/CLAUDE.md), arch (DRY, dead code). Возвращает verdict /⚠️/.

Routing rules

  • Тривиальная задача (typo, rename, обновить one-liner) — main session сам, без делегирования
  • Single-domain task с чёткими шагами → один соответствующий worker через Agent(subagent_type="backend-engineer", ...)
  • Нечёткая задача / cross-domain (2+ слоя)сначала tech-analyst → план → main session раздаёт worker'ам по плану
  • После worker'а перед push критичных измененийcode-reviewer → если блок → вернуть worker'у. Опционально для тривиальных.
  • Pure exploration (поиск файлов / понимание структуры) — встроенный Explore (Haiku, дёшево)
  • Crisis fix (горящий prod баг) — пропускаешь tech-analyst и code-reviewer, идёшь напрямую к worker'у

Cross-domain pattern (рекомендуемый)

Для задач затрагивающих 2+ слоя:

User request
  ↓
tech-analyst → структурированный план: Шаг 1 (database-expert) → Шаг 2 (backend-engineer) → Шаг 3 (frontend-engineer)
  ↓
Main session (ты) показывает план пользователю → получает approval
  ↓
Main session запускает worker'ов в order'е (по dependencies)
  ↓
Каждый worker возвращает summary → main session собирает в финальный отчёт

Что считается "max 4 worker agents"

По best practices (Anthropic, community) — больше 4 worker-агентов снижает productivity (классификация "кто что делает" становится сложнее). У нас 4 worker'а + 2 read-only (tech-analyst планирует, code-reviewer проверяет) — read-only не считаются worker'ами.

Code-reviewer workflow

User request → tech-analyst (если cross-domain)
  ↓
Main session creates feature branch (git checkout -b feat/...)
  ↓
Worker (backend/frontend/devops/database) пишет код (staged changes)
  ↓
**code-reviewer** проверяет staged changes:
  • ✅ APPROVE → main session коммитит на feature branch
  • ⚠️ MINOR → main session решает (или коммитит, или возвращает worker'у)
  • ❌ MAJOR → BLOCK, возвращает worker'у на исправление
  ↓
Loop until ✅ → git push -u origin <feature-branch>
  ↓
gh pr create → отдаём PR URL пользователю
  ↓
По явному "merge it" / "approved" → gh pr merge --squash --delete-branch

Используй code-reviewer для:

  • Backend endpoints (auth, SQL injection vector)
  • DB migrations (idempotency, индексы)
  • Production deploys (compose changes, secrets)
  • Изменения в job_settings / async tasks (race conditions)

Можно пропустить для:

  • UI-only style/cosmetic
  • Documentation
  • Frontend type tweaks
  • Trivial fixes (typo, rename)

Subagents не могут спавнить друг друга

Только main session может вызывать subagents через Agent tool. Если worker обнаружил что нужна работа из чужого scope — возвращает control в main session, main делегирует следующему.

When working on a task

1. Understand context — ВСЕГДА vault-first

  • Прочитай user request один раз
  • mcp__obsidian__obsidian_simple_search "<keyword>" — обязательный первый шаг для нетривиальной задачи. Найди MOC + related entities.
  • Открой связанный MOC.md (например domains/domrf/domrf-MOC.md для DOM.РФ работы) — он покажет relevant entities
  • Если в vault'е есть fixes/Bug_X.md про похожую проблему — обязательно прочитай
  • НЕ ищи в memory/memory-gendesign.jsonl — он deprecated, состояние не отражает

2. Plan, then act

  • Для нетривиальных задач (>3 файла или >50 строк) — сначала набросай план (или используй Plan subagent), потом выполняй
  • Для тривиальных (typo, mass-rename, обновить deps) — сразу делай

3. Verify locally

  • ruff + tsc + ast.parse() где применимо
  • Не пиши тесты пока user не попросил, НО не ломай существующие
  • Pre-commit hooks упадут на CI → проверь локально через pre-commit run --all-files если делал большие изменения

4. Communicate

  • Не объясняй очевидное (если правил один файл — не нужен абзац summary)
  • Для каждого fix: что было сломано, что починил, что осталось проверить пользователю
  • Если изменения в нескольких репо/системах — финальный bullet-list "Что осталось у тебя"

5. Commit message

  • Когда задача готова — напиши сообщение коммита в чат (не коммить сам)
  • Conventional commits style + краткое описание зачем

6. Update vault (важно!)

Для нетривиальных изменений — обнови vault:

  • Bug fix → создай или обнови fixes/Bug_<short_name>.md с root cause + fix
  • ADR / architectural decision → создай decisions/<Name>.md
  • Новый scraper / endpoint / module → создай entity в domains/<area>/ или code/modules/
  • Гайд по операционной задачеrunbooks/ (или в meta/0X_*.md если про сам repo / workflow)
  • Session log (опционально для большой работы): sessions/Session_<date>_<topic>.md

Используй mcp__obsidian__obsidian_append_content для добавления observation в existing entity, либо Write напрямую в C:\Users\user\Documents\gendesign-memory\<path>/<File>.md (LiveSync запушит в CouchDB через ~60 сек).

Common pitfalls (learned the hard way)

Worker crash на старте

  • Скорее всего import error — pyproject.toml имеет dep, но uv.lock ещё не обновлён
  • Fix: cd backend && uv lock → коммит lock-файла → push → CI пересобирает image

psycopg2 ImportError

  • В проекте только psycopg v3. Если видишь import psycopg2 — порти.
  • psycopg2.extras.execute_valuescur.executemany() (v3 pipeline mode справится)

Caddy не подхватывает Caddyfile после up -d

  • Caddyfile bind-mounted — нужен явный caddy reload
  • deploy.yml это делает после compose up -d

git pull на VPS перетирает локальные правки

  • deploy.yml использует git reset --hard origin/main — любые ручные правки в /opt/gendesign будут стёрты
  • .env-файлы выживают (они в .gitignore)

docker compose restart не перечитывает env_file

  • После правки .env: up -d --force-recreate --no-deps <service>

Frontend build хочет TS-типы которых нет

  • npm run codegen обновляет src/types/openapi.ts из live OpenAPI schema backend'а
  • Если backend меняется → нужно перегенерить TS типы

NSPD WAF / rate limiting

  • Используй rosreestr2coord lib (v5+), НЕ свой urllib
  • Rate limit делается worker'ом (time.sleep(rate_ms / 1000)), НЕ библиотекой (в v5 убрали delay параметр)

CouchDB / LiveSync — данные не появляются в Obsidian

  • Local vault на ноуте — single source of write
  • Если LiveSync не запушил после изменения → команда Self-hosted LiveSync: Replicate now
  • Если file body пустой → Verify and repair all files → Apply Remote (см. 04_mcp_obsidian_setup.md)

git status показывает trailing-whitespace / line-ending warnings

  • Это от core.autocrlf на Windows. Pre-commit mixed-line-ending hook fix'ит автоматом.

Don't do these (no exceptions)

Knowledge / memory

  • Читать или писать в memory/memory-gendesign.jsonl — он deprecated. Knowledge только в Obsidian vault.
  • Создавать новые .md для knowledge вне vault'а — никаких docs/research/*.md, notes/, wiki/ etc. Всё что про предметную область → vault.
  • Использовать aim_memory_* MCP tools (старая knowledge-graph MCP server'а нет, поэтому даже не пытайся).
  • Удалять MOC.md файлы в vault'е — они нужны для навигации.
  • Писать новые сущности в old/ папку vault'а — это архив legacy paths.

Code / git

  • Direct push в main — только через PR. Все изменения на feature branch → gh pr create → user approval → merge. См. "Git workflow".
  • Merge PR без явного user approval ("merge it" / "approved" / "ok merge").
  • --no-verify, --amend, --no-edit, --no-gpg-sign — обходить hooks/signing нельзя.
  • git push --force ни в main ни в feature branch без approval.
  • Hardcode credentials в код / в коммиты. Используй os.environ.get() + .env/.env.runtime.
  • print(...) для логирования в prod-коде — использовать logger.info/warning/error.
  • Catching Exception без re-raise или явного логирования (silent failures).
  • Использовать requests напрямую — есть httpx в стеке.
  • Импортировать psycopg2 — в проекте только psycopg v3.

Schema / migrations

  • Запускать миграции на prod без понимания зависимостей (views на колонки, FK).
  • Менять categorize_v2 в scripts/migrate_kg_to_obsidian.py без сопутствующей миграции (path scheme должен оставаться backwards-compatible).
  • DROP TABLE / TRUNCATE без явного approval пользователя.

Token efficiency tips для Claude

  • Не читай 00_index.md → каждый entity по списку — это 268 read'ов, ~500K токенов. Иди через MOC + tags.
  • grep -l (или Grep с output_mode: files_with_matches) дешевле полного content reading.
  • Один obsidian_simple_search часто заменяет 3-5 Read + parse.
  • При write — обновляй MOC.md только если структурное изменение (новый entity, переименование, удаление). Append observation в existing entity не требует MOC update.
  • Когда видишь много [[wiki-links]]НЕ читай каждый, спроси у user'а что именно интересует.

Project-specific knowledge to load on first read

При старте новой задачи в этом репо — first principles в vault'е:

  • meta/02_claude_usage.md — этот гайд (источник истины — vault'овая копия)
  • meta/00_credentials.md — secrets (когда нужны для debug-задач)
  • decisions/ папка — почему мы делаем так а не иначе (ADR-style)
  • fixes/ папка — что уже ломалось и как чинили
  • limitations/ папка — что НЕ работает / не реализовано

Для специфичной работы — открывай MOC по релевантному домену (domains/<area>/<area>-MOC.md).


Maintenance: этот файл обновляется когда:

  • Меняется tech stack (миграция фреймворка / DB)
  • Появляются новые workflow rules (новые hooks, новые workflow в CI)
  • Команда сталкивается с recurring pitfall → запиши его в "Common pitfalls"
  • Меняется структура vault'а / MOC scheme

Не превращай в новеллу — держи функциональный, action-oriented, без воды.