sdlc-hub/CLAUDE.md
2026-10-24 03:39:39 +04:00

10 KiB
Raw Blame History

jira-hub

Что это

Хаб моста Jira для АРМ КА: единственный источник истины по задачам проектов-меток Jira-проекта AURORA на Mac mini (192.168.0.106) и Markdown-копии вики Eva по проектам (модуль wiki). Хранит зеркало задач, служебные заметки и очередь команд в SQLite, отдаёт HTTP API в локальной сети (агенту на виртуалке jira-agent и интерфейсам) и MCP-сервер для Claude. Главный сценарий: из чата поставить пакет команд, агент на виртуалке выполняет их в Jira по правилу «проверь, потом сделай» и возвращает состояние задач в зеркало. Спеки: openspec/specs/; активные change — openspec/changes/ (кроме archive/).

Стек и ограничения

  • Веб-приложение — web/ (React 19 + TypeScript + Vite, TanStack Query, Vitest, Playwright; Node 24, npm); сборка в src/jira_hub/web/app/ не в git.
  • Python 3.13 от uv (.python-version, tool.uv.python-preference = "only-managed": системный Python miniconda несёт SQLite 3.51.1 с взаимной блокировкой, O-14 #29), uv, hatchling, pytest; HTTP на stdlib (http.server), БД — SQLite (stdlib), MCP — пакет mcp (закреплён <2, рулинг R-10).
  • Хаб не знает пароль Jira и не ходит в Jira: учётные данные и сеть до Jira только у агента.
  • Зеркало задач пишет только mirror.apply_state по загрузке состояния от агента (POST /agent/state); правки идут командами через очередь.
  • Хаб не создаёт команды сам: повтор после failed — новая команда по запросу человека/интерфейса. Команду, выданную агенту и оставшуюся без отчёта, хаб довыдаёт при следующем claim (до 3 выдач, затем failed).
  • Данные: ~/.local/share/jira-hub/ (JIRA_HUB_HOME): hub.sqlite (зеркало, очередь, журнал изменений issue_change), backups/, release/<модуль>/ (опубликованная версия агента модуля), files/ (файлы вложений по sha256, уборка через 30 дней), downloads/ (копии вложений для MCP <id>/<имя>, у wiki wiki-<id>/<имя>, уборка 30 дней), wiki/<метка>/ (Markdown-копия вики проекта: index.md в каталоге страницы, _tree.json); каталог данных, backups/, release/<модуль>/, files/, downloads/ и wiki/ — права 0700. Порт по умолчанию 8790.
  • Статические токены (в таблице setting): клиентский — всё, кроме /agent/*; по одному токену агента на модуль (jira, wiki) — только /agent/* и только маршруты своего модуля. Токен Eva в хабе не хранится.

Архитектура

  • src/jira_hub/core/ — ядро: db, settings, projects, queue (механика очереди), files, api (HTTP, CORE_ROUTES + маршруты модулей в ROUTES, фоновый tick), relay, release, client, mcp (каркас MCP), cli; контракт модуля Module/CommandHooks — core/modules.py, реестр — core/registry.py.
  • src/jira_hub/modules/jira/ — модуль jira: schema, mirror, history, attachments, fetch, commands, refresh, projects, hooks (смысл типов команд для очереди), api, mcp, settings, importer/cli. Входная точка — MODULE в modules/jira/__init__.py.
  • src/jira_hub/modules/wiki/ — модуль wiki: schema, settings, paths, projects (поле wiki_root), commands (wiki_sync, wiki_fetch и хуки очереди), convert (HTML → Markdown), stage, sync, search (FTS5), attachments, tick, api, mcp. Входная точка — MODULE в modules/wiki/__init__.py.
  • Граница: ядро не импортирует модули (кроме ленивого импорта в registry.py и шагах миграций db.py), типы команд и термины модулей (jira, wiki, eva) живут в модуле, новые имена в ядре — без названий модулей; проверяют test_core_imports, test_core_has_no_jira_terms, test_core_has_no_module_terms в tests/test_registry.py. Меток-исключений нет.
  • Цепочка ядра: db ← settings, projects ← queue ← api ← cli; files ← queue, api; реле relay — поток в serve; backup вызывается из api и из db. Модуль jira: hooks → commands/mirror/history/refresh/attachments/fetch → core.
  • Веб: оболочка и общее — web/src/{shell,ui,api,projects,auth,styles}, модули — web/src/modules/<имя>/ (контракт HubModule в modules/types.ts, список — modules/index.ts); модуль jira — страницы доски, задач и ленты; модуль wiki (web/src/modules/wiki/) — страница «Вики» (/app/wiki?project=<метка>).
  • Подробная карта модулей и границ — ARCHITECTURE.md.

Команды

  • uv run pytest — весь набор тестов. Зелёным считается только весь набор.
  • uv sync — установка окружения.
  • uv run jira-hub init --config PATH [--force] — настройки проекта из config.example.json, создание токенов.
  • uv run jira-hub serve [--host] [--port] — локальный запуск хаба.
  • Веб-приложение — http://127.0.0.1:8790/app/ (доска — /app/board?project=<метка>, задачи — /app/issues?project=<метка>, лента изменений — /app/feed?project=<метка>; вход по клиентскому токену); / и /links перенаправляют на доску.
  • make web — сборка приложения (после git pull на Mac mini, до перезапуска хаба); make check — pytest + lint и тесты фронта; cd web && npm run dev — разработка с прокси на тестовый хаб bash web/scripts/test-hub.sh (:8791); cd web && npm run e2e — Playwright; cd web && npm run golden — перегенерировать эталоны доски из links.html@3931a88 (только при смене фикстур).
  • uv run jira-hub import FOLDER — импорт CSV-пакета admin/jira-sync; uv run jira-hub mcp [модуль] [--project <метка>] — MCP модуля по stdio (по умолчанию jira; jira-hub mcp wiki — сервер jira-hub-wiki; с привязкой сессии к проекту); uv run jira-hub tokens — показать токены (клиентский и по агенту на модуль).
  • uv run jira-hub agent publish [--module jira|wiki] PATH — опубликовать версию агента модуля для самообновления (только вверх; по умолчанию jira; публикация лежит в release/<модуль>/).

Тесты

  • Golden-тесты: tests/fixtures/<name>.* + эталон <name>.expected.*. Внешние сервисы в тестах мокаются.
  • SQLite в памяти или во временном JIRA_HUB_HOME (tmp_path); API поднимается на порту 0 в отдельном потоке. Jira и агент в тестах не участвуют.
  • Соединение SQLite в тесте — через фикстуру open_db (tests/conftest.py) или фикстуру conn модуля, иначе с явным close(): pyproject.toml (filterwarnings) делает незакрытое соединение ошибкой набора.
  • Фронт: golden-эталоны доски — web/src/modules/jira/board/__fixtures__/*.expected.json (их пишет web/scripts/golden-from-links.ts из старой страницы); тесты рядом с кодом *.test.ts(x); e2e — web/e2e/ на тестовом хабе.

Первая подсистема

Очередь команд (core/queue.py, Task 5): пакеты, порядок (batch.created_at, seq), одна команда в полёте, временные ключи new:<n>, подтверждение по состоянию зеркала. Остальное (API, MCP, импорт) надстраивается над ней.

OpenSpec и superpowers

  • Вход в любую задачу — superpowers:brainstorming. Skills openspec-propose и openspec-explore сами по себе не запускать.
  • Когда brainstorming классифицировал задачу как architectural, структуру change создать через openspec new change <id> (или /opsx:propose <id>), а содержимое proposal.md, specs/ и design.md написать по итогам brainstorming. tasks.md из OpenSpec не заполнять — задачи живут в плане superpowers.
  • /opsx:apply не использовать: исполнение идёт через writing-plans и SDD/executing-plans.
  • openspec archive <id> — после merge PR, как часть чеклиста закрытия.
  • Хук require-plan защищает любой каталог src/ на любой глубине. Если код лежит иначе — перечислить каталоги (префиксы от корня, по одному в строке) в .claude/code-paths.