chore: init monorepo with GPL-3.0 license, docs, backend skeleton, frontend wiring
This commit is contained in:
commit
43cf0e277d
57 changed files with 5027 additions and 0 deletions
26
docs/adr/001-monorepo.md
Normal file
26
docs/adr/001-monorepo.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# ADR-001: Монорепо vs Полирепо
|
||||
|
||||
Дата: 2026-09-06
|
||||
Статус: Принято
|
||||
|
||||
## Контекст
|
||||
В корне два пакета: `indexium-backend` (Rust/Axum) и `indexium-frontend` (SvelteKit). Нужно решить как организовать git: один репозиторий на всё или два отдельных. Backend уже имел пустой `.git` без коммитов, фронт без гита.
|
||||
|
||||
## Рассмотренные варианты
|
||||
1. **Монорепо** — один `.git` в корне.
|
||||
2. **Полирепо** — два независимых репозитория.
|
||||
3. **Submodules** — корневой репо + сабмодули.
|
||||
|
||||
## Решение
|
||||
Выбрать **монорепо**. Удалить `indexium-backend/.git`, инициализировать `Indexium/.git` в корне. См. `docs/git-strategy.md`.
|
||||
|
||||
Причины: атомарные изменения API+UI, один CI, проще onboarding, нет нужды в разных релизных каденсах на старте.
|
||||
|
||||
## Последствия
|
||||
- Положительные: один clone, один PR для кросс-пакетных изменений, один issue tracker.
|
||||
- Отрицательные: при росте команды >10 может потребоваться разрезание (план через `git filter-repo`).
|
||||
- Submodules отклонены из-за сложности DX.
|
||||
|
||||
## Ссылки
|
||||
- `docs/git-strategy.md`
|
||||
- `todo.md` Phase 0
|
||||
26
docs/adr/002-async-indexer.md
Normal file
26
docs/adr/002-async-indexer.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# ADR-002: Асинхронный событийный индексатор поверх GitHub Releases
|
||||
|
||||
Дата: 2026-09-06
|
||||
Статус: Принято
|
||||
|
||||
## Контекст
|
||||
Нужен дешёвый и устойчивый к лимитам GitHub способ индексировать моды. Хранить `.jar` у себя дорого, проксировать трафик — упрёмся в bandwidth и rate limits.
|
||||
|
||||
## Решение
|
||||
Бэкенд не хранит артефакты. GitHub Releases CDN — источник правды для файлов. Мы только:
|
||||
- принимаем webhook `release.published` (HMAC + queue + 202),
|
||||
- воркер читает zip central directory через Range Request,
|
||||
- парсит манифест (`fabric.mod.json` и т.д.),
|
||||
- пишет метаданные в Postgres,
|
||||
- отдаёт прямые `download_url` на `objects.githubusercontent.com`.
|
||||
|
||||
Подробнее в `docs/architecture.md`.
|
||||
|
||||
## Последствия
|
||||
- Плюс: минимальный storage, нет egress costs, +5k–12.5k RPH через GitHub App.
|
||||
- Минус: зависимость от доступности GitHub CDN (приемлемо — моды и так там).
|
||||
- Вынесен malware-скан и SHA-256 сверка как обязательные.
|
||||
|
||||
## Альтернативы
|
||||
- Хранить файлы у себя (S3) — отклонено: дорого, дублирование.
|
||||
- Полный pull `.jar` на каждый релиз — отклонено: трафик, медленно.
|
||||
33
docs/adr/003-search-engine.md
Normal file
33
docs/adr/003-search-engine.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# ADR-003: Использование PostgreSQL FTS и pg_trgm вместо Meilisearch/Elasticsearch
|
||||
|
||||
Дата: 2026-09-06
|
||||
Статус: Принято
|
||||
|
||||
## Контекст
|
||||
Для поиска модов по названию, описанию и авторам требуется полнотекстовый поиск и устойчивость к опечаткам (fuzzy search). Введение отдельного движка поиска (Meilisearch, OpenSearch, Elasticsearch) усложняет инфраструктуру и увеличивает потребление RAM (ещё один сервис в `docker-compose`, отдельный индекс, синхронизация).
|
||||
|
||||
На MVP ожидается <50k модов, поисковый трафик <100 RPS, VPS за $5–10.
|
||||
|
||||
## Решение
|
||||
Использовать возможности PostgreSQL 16:
|
||||
- `tsvector` + `GIN`-индексы для ранжированного полнотекстового поиска (`to_tsvector`, `ts_rank`, `plainto_tsquery`).
|
||||
- Расширение `pg_trgm` для поиска с опечатками (Trigram Similarity, оператор `%`, `similarity()`).
|
||||
- Материализованный `search_vector` с триггером на `INSERT/UPDATE` (см. `docs/database-schema.md`).
|
||||
|
||||
Запрос: `search_vector @@ plainto_tsquery` + фильтр по `mod_versions` (`GIN (game_versions, loaders)`) + `ORDER BY ts_rank DESC` + fallback `similarity()` при 0 результатах.
|
||||
|
||||
## Последствия
|
||||
|
||||
- **Плюсы:** Нет дополнительных сервисов в `docker-compose`, экономия памяти (~0 доп. RAM vs +500MB–1GB у Meilisearch), атомарные транзакции при обновлении индекса (нет лагосинка), проще бэкапы.
|
||||
- **Минусы:** При объёме >500k записей или >500 RPS скорость FTS в Postgres начинает уступать специализированным движкам (latency >100ms, нет typo-tolerance из коробки как в Meilisearch).
|
||||
- **План миграции:** Если p95 latency поиска превысит 100ms (метрика в `tracing` + Grafana), вынести индекс в Meilisearch: добавить воркер-синк `mods` → Meilisearch, переключить `GET /mods` на Meilisearch с fallback на Postgres. Схема БД не меняется.
|
||||
|
||||
## Альтернативы (отклонены на MVP)
|
||||
|
||||
- **Meilisearch** — отличный typo-tolerance, но +1 сервис, нужен отдельный деплой и синк.
|
||||
- **Elasticsearch / OpenSearch** — оверхед по RAM/диску, нужен кластер даже для малого объёма.
|
||||
- **SQLite FTS** — не подходит, уже Postgres как основной.
|
||||
|
||||
## Ссылки
|
||||
- `docs/database-schema.md` — секция 2 (триггер `mods_search_vector_update`), секция 3 (примеры FTS + fuzzy).
|
||||
- `docs/architecture.md` — секция 4 (Поиск без Elasticsearch).
|
||||
37
docs/adr/004-auth-strategy.md
Normal file
37
docs/adr/004-auth-strategy.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# ADR-004: Стратегия авторизации и профилей — GitHub-only + PAT (+ Device Flow позже)
|
||||
|
||||
Дата: 2026-09-06
|
||||
Статус: Принято (MVP) / Запроектировано (Phase 2)
|
||||
|
||||
## Контекст
|
||||
Каталог open-source модов где 1 мод = 1 GitHub репо. Нужна минимальная, безопасная авторизация без паролей, но с поддержкой CLI/лаунчеров (Prism) и будущих Discord/коллекций. Пользователь предложил: GitHub App, PAT, Device Flow, Discord синк, дашборды, коллекции, геймификацию, SVG виджет.
|
||||
|
||||
## Решение
|
||||
|
||||
**MVP:**
|
||||
- Вход только GitHub OAuth (`read:user`, `user:email`), JWT httpOnly cookie, без паролей. Читатели — anonymous.
|
||||
- PAT с `SHA256` хранением и скоупами `read:mods|write:mods|webhooks:manage` для CI/лаунчеров.
|
||||
- `verified` бейдж если репо публичное + лицензия + GitHub App установлен.
|
||||
- Sponsors (GitHub/Patreon/Ko-fi) + star/follow (in-app) + SVG badges (`/v1/badges/:slug/downloads.svg`).
|
||||
|
||||
**Phase 2 (спроектировано, не кодим сейчас):**
|
||||
- Device Code Flow (RFC 8628) — Indexium как OAuth2 Provider для лаунчеров (`/oauth/device/code` → `/activate`).
|
||||
- Discord linked_account + бот роли `Verified Modder`.
|
||||
- Collections/Modlists с экспортом Prism/packwiz, Activity Feed, аналитика по версиям/лоадерам, PGP проверка.
|
||||
|
||||
**Backlog:** краш-логи, лидерборды, Profile README.
|
||||
|
||||
## Альтернативы
|
||||
- Google/email логин — отклонён для MVP (публикация всё равно требует GitHub, лишняя сложность).
|
||||
- Сразу Device Flow — отклонён ( +2 недели, PAT покрывает 80% кейсов).
|
||||
- Discord как логин — отклонён (только linked).
|
||||
|
||||
## Последствия
|
||||
- Плюс: минимум GDPR, нет паролей, доказуемое владение репо, CLI готов через PAT.
|
||||
- Минус: без GitHub аккаунта не опубликовать (осознанно, соответствует open-source философии).
|
||||
- Миграция: таблицы `personal_access_tokens`, `linked_accounts`, `oauth_clients/device_codes` добавятся без breaking change.
|
||||
|
||||
## Ссылки
|
||||
- `docs/auth-profiles.md` §7-10
|
||||
- `docs/catalog-philosophy.md`
|
||||
- `docs/api-spec.md` §Auth/Profiles
|
||||
29
docs/adr/005-analytics.md
Normal file
29
docs/adr/005-analytics.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# ADR-005: Собственный bStats-аналог для Indexium Analytics
|
||||
|
||||
Дата: 2026-09-06
|
||||
Статус: Принято (дизайн) / К реализации в Phase 3
|
||||
|
||||
## Контекст
|
||||
Скачивания накручиваются CI, нужна честная метрика популярности — активные установки в рантайме. bStats де-факто стандарт для Minecraft модов: lightweight SDK → POST gzip JSON → агрегация. Пользователь предложил полный дизайн с `server_uuid`, daily_salt, `mod_telemetry_pings` + `mod_daily_stats`, opt-out и сортировкой `active_servers`.
|
||||
|
||||
## Решение
|
||||
- **SDK:** MIT Java/Kotlin модуль `dev.indexium:analytics` ~15KB, `IndexiumMetrics(slug)` + `SimplePie`, уважает `-Dindexium.analytics.disable=true` и `config/indexium.json`.
|
||||
- **Ingestion:** `POST /api/v1/analytics/submit` (gzip, без IP логов) → валидация allow-list → `server_hash = sha256(uuid + daily_salt)` → Redis 1/15мин → `mod_telemetry_pings` (TTL 30d).
|
||||
- **Storage:** Postgres `mod_telemetry_pings` + `mod_daily_stats (breakdown_json)` + `analytics_salts`. Кроном `COUNT(DISTINCT server_hash)` раз в час. Хватает до 10M пингов/мес, далее TimescaleDB hypertable без смены схемы.
|
||||
- **Serving:** `GET /mods/:slug/analytics?range=7d|30d|90d` (кэш 5м), `GET /badges/:slug/servers.svg`, `GET /mods?sort=active_servers`.
|
||||
- **Приватность:** не храним IP, daily_salt ротация (не трекать сквозь дни), `custom_charts` ≤5 ключей, opt-out на клиенте.
|
||||
|
||||
## Альтернативы
|
||||
- Сторонний bStats.org — отклонён (внешняя зависимость, нет контроля, нет breakdown по нашим лоадерам).
|
||||
- ClickHouse сразу — отклонён (оверхед для MVP, Postgres хватает).
|
||||
- Хранить сырые пинги навсегда — отклонён (раздувание, достаточно daily агрегата).
|
||||
|
||||
## Последствия
|
||||
- Плюс: честная сортировка `active_servers`, графики для авторов, бейджи, без сторонних сервисов.
|
||||
- Минус: +2 таблицы, крон-агрегация, SDK нужно публиковать в Maven Central.
|
||||
- План: сначала Axum handler + агрегация, потом SDK (или наоборот — можно параллельно).
|
||||
|
||||
## Ссылки
|
||||
- `docs/analytics.md`
|
||||
- `docs/api-spec.md` §Analytics
|
||||
- `docs/database-schema.md` §3
|
||||
Loading…
Add table
Add a link
Reference in a new issue