13 KiB
13 KiB
Indexium — TODO / Roadmap
Сервис: асинхронный событийный индексатор модов Minecraft поверх GitHub Releases CDN. Бэкенд не хранит тяжёлые артефакты, только метаданные + индексация + быстрый JSON API.
Правила проекта (обязательно к соблюдению)
Эти правила — не чекбоксы, а инварианты. Любой PR, нарушающий их, не принимается.
1. KISS — Keep It Simple, Stupid
- Выбирай самое простое решение, которое закрывает задачу. Никаких абстракций «на будущее» (YAGNI).
- Один модуль — одна ответственность. Если не можешь объяснить функцию в одном предложении — дроби.
- Предпочитай явный код неявной магии (никаких макросов ради макросов).
2. DRY — Don't Repeat Yourself
- Повтор >2 раз → выноси в функцию/модуль. Но не DRY ради DRY: дублирование лучше неправильной абстракции.
- Общие типы/утилиты — в
common/shared, доменная логика — в своём модуле.
3. SOLID (применительно к Rust)
- S — один файл/модуль = одна причина для изменений (см. лимиты ниже).
- O — открыт для расширения через трейты, закрыт для модификации (feature-flag, а не
ifна типы). - L — любой
impl Traitдолжен заменять другой без поломки контракта. - I — узкие трейты лучше жирных (
Readable,ValidatableвместоGodService). - D — зависимость от абстракций (
PgPoolчерезAppState, а не глобаль).
4. Лимиты структуры (жёстко)
- Макс 250 строк на файл — если больше, дроби файл на подмодули.
- Макс 4 файла на папку — если больше, вводи подпапки по домену (
api/mods/,worker/parsers/). - Исключение:
mod.rs/lib.rsне считаются, но должны быть тонкими реэкспортами. - CI будет ругаться (
cargo clippy+ кастомный скриптscripts/check-limits.sh).
5. Дополнительные инварианты
- Чистота ошибок: никаких
unwrap()/expect()внеmain.rsи тестов. ВездеResult+thiserror/anyhow. - Типы вместо строк:
Slug,GameVersion,Loader— newtype, а неString. - Миграции только вперёд: никаких
DROPбез ADR и бэкапа. Каждая миграция — идемпотентна (IF NOT EXISTS). - Логика без сайд-эффектов: парсеры/валидаторы — чистые функции, I/O только на границах (handler/worker).
- Документация рядом с кодом: публичная функция без
///— не готова к мерджу. - Тест на каждый баг: регрессия покрывается тестом до фикса.
Легенда статусов
[ ]— не начато[~]— в процессе[x]— готово[!]— заблокировано / требует решения
Phase 0 — Фундамент монорепо (Текущий приоритет)
- Объединить
indexium-backend+indexium-frontendв один git-монорепо (корень/) - Настроить корневой
.gitignore+ локальные.gitignore - Создать структуру
docs/и заполнить базовую архитектуру - Создать
todo.mdиREADME.mdв корне + прописать правила KISS/DRY/SOLID и лимиты файлов - Первая миграция
20260906000000_init_schema.sql(mods, mod_versions, GIN индексы) - Базовый
src/main.rs(Axum + SQLx + CORS + /health + миграции при старте) - Настройка
.env/.env.example(DATABASE_URL, SERVER_PORT) - Добавить
docker-compose.yml(Postgres + Redis/Valkey) для локальной разработки - Добавить
Makefile/justfileс командамиdev,migrate,lint,test - Настроить CI (GitHub Actions):
cargo clippy + test,svelte-check,sqlx migrate check - Скрипт
scripts/check-limits.sh— проверка 250 строк / 4 файла на папку
Phase 1 — Backend Core (Rust / Axum)
1.1 Инфраструктура
config— загрузка.env(DATABASE_URL, REDIS_URL, GITHUB_APP_ID, WEBHOOK_SECRET) — база вmain.rsчерезdotenvydb— пулsqlx::PgPool, миграции (sqlx::migrate!), health-check/healthtracing— структурированные логи (EnvFilter + fmt layer)- Axum роутер:
GET /health, CORS (5173), TraceLayer
1.2 Схема БД (PostgreSQL + FTS + pg_trgm)
- Миграция
20260906000000_init_schema.sql— таблицыmods,mod_versions+GIN (game_versions, loaders) - Миграция
002_fts—search_vector,pg_trgm, триггер (см.docs/database-schema.md) - Таблица
authors+webhook_deliveries(идемпотентность) - Сиды / фикстуры для локального дев-окружения
1.3 Webhook Ingestion API
POST /api/v1/webhooks/github— проверкаX-Hub-Signature-256(HMAC SHA-256)- Валидация эвента
release.published/release.released, идемпотентность поdelivery_id - Пуш задачи в очередь (Redis Streams) + ответ
202 Accepted< 50ms - Тест на replay-атаку и неверную подпись
1.4 Async Worker / Indexer
- Консьюмер очереди (tokio task)
- Скачивание через HTTP Range Request — чтение только ZIP central directory
.jar - Парсинг
fabric.mod.json/quilt.mod.json/neoforge.mods.toml/mcmod.info - Валидация:
mod_id,version,game_versions,loaders, иконка - SHA-256 сверка (если приложен
.sha256), отбраковка битого артефакта - Бейсик malware-скан: поиск
Runtime.exec,URLClassLoader, сетевых вызовов в<clinit> - Сохранение в
mod_versions, инвалидация Redis-кэша
1.5 Public REST API (Read-Heavy, Cache-First)
GET /api/v1/mods?query=&gameVersion=&loader=&page=&limit=— FTS + фильтры, кэш Redis 60sGET /api/v1/mods/:slug— карточка мода + список версийGET /api/v1/mods/:slug/versions/:version— детали версии +download_url(прямая CDN ссылка GitHub)- Пагинация cursor/offset, ETag,
Cache-Control - Rate limiting (tower_governor / redis-cell)
1.6 Auth & Profiles (см. docs/auth-profiles.md, adr/004)
- GitHub OAuth 2.0 (read:user, user:email) + JWT httpOnly — вход для авторов (MVP)
- PAT
personal_access_tokens(hash, scopes, expires) —POST /auth/tokensдля CLI/лаунчеров (MVP) POST /api/v1/mods/import— импорт репозитория (проверка LICENSE + public + манифест)- Профили
/u/:login,/org/:login— кэш ISR, sponsors, verified badge, SVG/v1/badges/:slug/*.svg(MVP) - Star/Follow
stars,follows(с фильтром game_version/loader) — in-app уведомления (MVP-лайт) - Device Flow RFC8628 (
/oauth/device/code→/activate) — спроектировать, реализация Phase 2 - Discord linked_accounts + бот роли Verified Modder — Phase 2
- Установка Webhook'а через GitHub App API (автоматически) — миграция с OAuth на App в Phase 2
Phase 2 — Frontend (SvelteKit) + Social
- Дизайн-система: Tailwind / UnoCSS + токены
- Страницы:
/(поиск + фильтры),/mod/[slug],/mods/import,/u/[login],/org/[login],/activate(device flow) - Компоненты:
ModCard,VersionTable,SearchBar,LoaderBadge,ProfileHeader,SponsorsBar - Клиент API (
src/lib/api.ts) — типизированные fetch-обёртки - SSR + кэширование, skeletons, error boundaries
- SEO / OpenGraph для карточек модов
- Collections / Modlists
collections,collection_stars+ экспорт?format=prism|packwiz(Phase 2 хит) - Activity Feed — лента по подпискам (releases + collections + stars)
- Org/Teams —
/org/:loginагрегатор,role=maintainer - Геймификация —
badges(Early Adopter, Bug Hunter, Veteran) + Showcase SVG
Phase 3 — Поиск, качество данных и аналитика (см. docs/analytics.md, adr/005)
- PostgreSQL FTS (
to_tsvector+ts_rank) поname,summary,README pg_trgmдля неточных совпадений / опечаток- Опционально:
pgvectorдля семантического поиска по описанию (эмбеддинги README) - Админ-панель / ручная модерация, флаг
verified/suspicious - Indexium Analytics (bStats аналог):
- Миграция
20260907000000_telemetry.sql(mod_telemetry_pings,mod_daily_stats,analytics_salts) POST /api/v1/analytics/submit(gzip, валидация, daily_salt hash, Redis 1/15мин, без IP)- Крон агрегация
COUNT(DISTINCT server_hash)→mod_daily_stats+ TTL 30д GET /mods/:slug/analytics?range=30d+GET /badges/:slug/servers.svg+sort=active_servers- Легковесный Java/Kotlin SDK
dev.indexium:analytics(MIT, SimplePie, opt-out флаг)
- Миграция
Phase 4 — Надёжность и ограничения GitHub
- GitHub App Install token — 5k-12.5k RPH вместо 60 RPH анонимных
- Прямые редиректы на
objects.githubusercontent.com— не проксировать трафик - Retry + exponential backoff, DLQ для воркера
- Метрики: Prometheus /
tracing+ Grafana, алерты на lag очереди
Phase 5 — Деплой и эксплуатации
- Dockerfile multi-stage для backend (distroless / alpine)
- Dockerfile для frontend (adapter-node / adapter-static)
docker-compose.prod.yml/ Fly.io / Railway / Hetzner- Бэкапы Postgres (PITR), миграции в CI
- Документация деплоя (
docs/deployment.md)
Phase 6 — Расширения (Backlog)
- Поддержка CurseForge / Modrinth как доп. источников (опционально)
- Webhooks для лаунчеров (подписка на обновления мода)
- CLI для авторов (
indexium publish) - Аналитика рантайма — аналог bStats (спроектирована, см. docs/analytics.md) → реализация в Phase 3
- Аналитика скачиваний (агрегация без хранения персоналки)
Ближайшие 3 шага (Next Actions)
docker-compose.yml+ первая миграция SQLPOST /webhooks/githubс HMAC-проверкой и заглушкой очереди (in-memory channel)GET /mods— мок-данные из БД + подключение фронта
Как отмечать прогресс
- При завершении задачи ставь
[x]и добавляй ссылку на PR/коммит:[x] Задача (#12) - Если задача блочится — ставь
[!]и опиши блокер в комментарии ниже.
Блокеры / Вопросы
- Выбрать окончательно очередь:
Redis StreamsvsNATS JetStreamvspg-queueна старте?- Рекомендация: стартовать с
Redis(уже нужен как кэш) → мигрировать на NATS если нужен strict ordering.
- Рекомендация: стартовать с
- Где хостить Postgres на старте — Supabase / Neon / self-hosted?