Files
jellybit/CLAUDE.md
T
avandClaude Opus 4.8 6d801ed03b Беклог: перенос в Tududi как единственный источник
Задачи беклога перенесены в Tududi (проект jellybit) с приоритетами и
описанием. Файл docs/backlog.md удалён; CLAUDE.md указывает на Tududi как
единственный источник. Живые ссылки в спеках на backlog.md переписаны на
отсылку к задаче в беклоге (Tududi).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 14:55:53 +03:00

10 KiB
Raw Blame History

CLAUDE.md

Памятка для работы над jellybit. Перед задачей прочитай также README.md, BRIEF.md и docs/specs/architecture.md. Разработка идёт по Spec Driven Development через OpenSpec — см. раздел ниже.

Что это

Связующий сервис qBittorrent ↔ Jellyfin: принимает торрент + контекст, качает, распознаёт фильм/сериал (LLM + контекст + опц. метабазы) и раскладывает файлы для Jellyfin хардлинками. Деплоится на домашний медиа-сервер umbar (/home/av/projects/private/umbar) — туда копируется готовый бинарь.

Стек и принципы

  • Go, один статический бинарь (CGO_ENABLED=0). Почему — см. ADR-2026-06-13-go-single-binary.
  • SQLite как хранилище (чистый Go-драйвер modernc.org/sqlite).
  • Конфигурация — TOML. Логи — структурированный JSON (log/slog).
  • Хардлинки, источник не трогаем — qBittorrent продолжает раздачу, диск не дублируется.
  • Единое ядро, тонкие транспорты — вся логика приёма в use-case Ingest; HTTP API, веб-UI и Telegram — лишь обёртки над ним.
  • Минимум компонентов — в духе umbar, без зоопарка сервисов. Внешние базы метаданных (TMDB/TVDB) опциональны, включаются конфигом.

Инварианты (безопасность данных)

  • Источник неприкосновенен: только mkdir / link(2) / unlink своих ссылок; никогда не трогаем файлы под paths.downloads.
  • Целевой путь санитизируется и проверяется, что он строго под paths.movies/series (защита от traversal); существующее не перезаписываем.
  • Выход LLM недоверенный — безопасность на валидации пути, не на промпте. Авто-раскладка только при подтверждённом матче в базе.
  • Секреты не попадают в логи — пароли qBittorrent, API-ключи LLM/метабаз, auth-заголовки. Подробнее — docs/conventions/logging.md.
  • Запуск: контейнер под 1000:1000, в общей docker-сети (адресация по именам), mount /srv/media (единая песочница) + data-том для SQLite/конфига.

Spec Driven Development (OpenSpec)

Изменения ведём через OpenSpec (CLI openspec, v1.x). Сначала спецификация — потом код.

  • openspec/specs/<capability>/spec.mdактуальные capability-спеки: что система делает сейчас. Capability — это поведение/домен (ingest, recognition, file-layout, review, notifications), а не пакет кода.
  • openspec/changes/<id>/ — предлагаемое изменение: proposal.md (зачем и что), design.md (как, для нетривиальных), дельта-спеки (ADDED/ MODIFIED/REMOVED Requirements), tasks.md (шаги). После реализации change архивируется в openspec/changes/archive/, дельты вливаются в openspec/specs/.
  • openspec/config.yaml — язык и правила оформления спек (читай перед написанием).

Поток работы — через слэш-команды opsx:* (канонический набор, его поддерживает openspec update): opsx:explore (продумать), opsx:propose (завести change), opsx:apply (реализовать tasks), opsx:sync/opsx:archive (влить и архивировать). Skills openspec-* — то же, но предыдущего поколения; для новой работы используем opsx:*.

Правила спек:

  • Каждое ### Requirement ОБЯЗАНО содержать литерал SHALL или MUST — иначе openspec validate падает.
  • Структурные заголовки и ключевые слова — английские (### Requirement:, #### Scenario:, GIVEN/WHEN/THEN, RFC 2119), остальной текст — русский.
  • Сценарии — в формате GIVEN/WHEN/THEN.
  • openspec validate --strict перед коммитом change.

Ревью (процесс, не артефакт): нетривиальная задача — два чекпоинта (ревью дизайна после design/specs, ДО кода; ревью кода после apply, до archive); тривиальная — одного прохода по коду достаточно.

Миграция: capabilities постепенно переносятся из docs/specs/ в OpenSpec (пилот — ingest). До переноса источник истины по теме — соответствующий файл в docs/specs/; перенесённое живёт в openspec/specs/.

Прочая документация

  • docs/specs/живые спецификации целевого состояния (архитектурный обзор + ещё не перенесённые в OpenSpec темы). Меняем по мере развития, держим в соответствии с кодом.
  • docs/adr/неизменяемый журнал решений, пишется постфактум, хранит почему. Правила — docs/adr/README.md.
  • docs/drafts/ — черновики: планы, идеи, ещё не принятые решения. Не источник истины.

Задачи и беклог

  • Единственный источник беклога — Tududi, проект jellybit (MCP-сервер tududi, project_id 14). Там задачи с приоритетами (высокий/средний/ низкий) и описанием (контекст, принятые решения, ссылки на спеки/ADR/ черновики в теле задачи). Ищи, заводи и закрывай задачи через MCP-инструменты tududi (list_tasks, create_task, update_task, complete_task, search).
  • Спекулятивные задачи (ещё без решения «делаем») помечены префиксом [идея] в названии — их сперва прорабатываем.
  • Отдельного файла-беклога в репозитории больше нет: docs/backlog.md перенесён в Tududi. Старая версия при необходимости доступна в истории git.

Язык

  • Документация, комментарии, сообщения коммитов — русский.
  • Код и идентификаторы — английский.

Команды

Запуск через Task (task --list — полный список):

  • task setup — установка тулинга (golangci-lint + git-хуки lefthook)
  • task run — локальный запуск (go run ./cmd/jellybit --config ./config.toml)
  • task build — статический бинарь linux/amd64 для сервера
  • task test / task lint — тесты и golangci-lint
  • task tidygo mod tidy
  • task image — docker-образ из готового бинаря

Module path — git.vakhrushev.me/av/jellybit. Go 1.26, CGO_ENABLED=0. Стек: chi, sqlx + modernc.org/sqlite, goose (миграции), pelletier/go-toml/v2, log/slog.

Конвенции кода

  • Раскладка: cmd/jellybit (точка входа) + internal/<пакет> по компонентам из architecture.md.
  • Ошибки — stdlib, обёртка с контекстом (fmt.Errorf("...: %w", err)), проверка через errors.Is/errors.As, трансляция на внешней границе: docs/conventions/errors.md.
  • Логирование только через slog, без fmt.Println — уровни, обязательные поля и что не логировать см. docs/conventions/logging.md.
  • Конфигурация — только TOML; секреты рендерит деплой (Ansible+Vault) в файл (config.toml не коммитится, 0600), не в env; валидация на старте: docs/conventions/config.md.
  • Время — всегда с явным TZ (сервер в Europe/Moscow).
  • Идентификаторы — TEXT ULID (lowercase) через internal/ident, без числовых AUTOINCREMENT; внешние id валидируются ident.Parse на границе: docs/conventions/database.md.
  • Миграции БД (goose, internal/store/migrations; SQL для DDL, Go — когда нужен код) — при изменении структуры (таблица/столбец/индекс/связь) в том же change обновляем ER-схему docs/specs/database.md.
  • Веб-UI на htmx — единый партиал = страница = фрагмент, ветвление по isHTMX, деградация без JS, ошибка на htmx-пути = 200 + фрагмент, самозавершающийся поллинг: docs/conventions/web-ui.md.

Кросс-каттинг конвенции (как пишем код, а не что система делает) живут в docs/conventions/ и не переносятся в OpenSpec.