discord-bot/TODO.md
loki5512344 29a21e4178 v2.3: Major refactoring, Lavalink music system, Spotify support, CI/CD
- Full refactoring: max 200 lines/file, max 3 files/dir, KISS/DRY/SOLID
- Lavalink client 3.4.0 + LavaSrc plugin (Spotify, Apple Music, Deezer)
- 3-bot architecture: main (!), music (q!), radio (r!)
- Filters: bassboost, nightcore, vaporwave, equalizer
- Slash commands for music (/play, /skip, etc.)
- Persistent queue in SQLite, auto-leave timer
- Radio manager with auto-reconnect
- Custom welcome GIF greetings via nekos.life
- JDA 5.6.1, gson 2.14, hikaricp 6.3, all deps updated
- Fixed YouTube playback via ytmsearch (LavaSrc)
- CI/CD: Docker publish + release workflows
- SpotBugs: all real bugs fixed, ignoreFailures=false
- Checkstyle: Google Style (adapted), 0 violations
2026-07-02 23:48:36 +02:00

294 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TODO — Loki Bot v2.1
## ✅ Что уже сделано
| # | Статус | Проблема | Изменения |
|---|--------|----------|-----------|
| C1–C15 | ✅ | Предыдущие раунды | См. git history |
| J21 | ✅ | Java 17 → 21 | `build.gradle`: source/target 21 |
| A05 | ✅ | EventDispatcher: CachedThreadPool → VirtualThreadPool | `Executors.newVirtualThreadPerTaskExecutor()` |
| A06 | ✅ | SwapCommand + RepTopCommand: `new Thread()` → `Thread.startVirtualThread()` | |
| A25 | ✅ | CommandExceptionHandler: instanceof pattern matching | |
| A26 | ✅ | ClearCommand: instanceof pattern matching | |
| A27 | ✅ | DatabaseMigration: instanceof pattern matching | |
| A28 | ✅ | InfoCommand: switch → arrow-switch | |
| A29 | ✅ | RateCommand: `"⭐".repeat(rating)` + `"☆".repeat()` | |
| A32 | ✅ | .collect(Collectors.toList()) → .toList() | SwapCommand, RepTopCommand, ChoiceOptionParser |
| A33 | ✅ | HelpCategories: Map.ofEntries() вместо HashMap + unmodifiable | |
| A02 | ✅ | RankCardGenerator: блокировка Event Thread | Исправлено (команды на virtual threads) |
| A10 | ✅ | RankCardGenerator: утечка InputStream | try-with-resources в loadFont + loadBackground |
| A11 | ✅ | RankCardGenerator: шрифты не кэшировались | ConcurrentHashMap cache |
| A12 | ✅ | RankCardGenerator: SVG-иконки не работали | Заменены на геометрические фигуры (Java2D) |
| A23 | ✅ | RankCardGenerator: throws Exception | loadFont безопасный |
| A03 | ✅ | Database: race condition на connection | synchronized методы |
| A13 | ✅ | NekosLifeApi: Thread.sleep в catch | Сон вынесен в retry loop |
| A14 | ✅ | GenerateRatingsCommand: блокировка event-потока | `complete()` вместо `queue()` |
| A35 | ✅ | GenerateRatingsCommand: опечатка | `Пропускаемботов` → `Пропускаем ботов` |
| A04 | ✅ | PrefixCommandRegistrar: God Constructor (22 param) | Разбит на 4 per-feature CommandRegistrar, Multibinder, 1 param |
| A21 | ✅ | BotModule: путь к БД хардкодом | Вынесен в .env (`DB_PATH`) + BotConfig |
| A34 | ✅ | CommandCategories: мёртвый код | Уже удалён (старый пакет) |
| A37 | ✅ | ProfileCommand: регистрация в PrefixCommandRegistrar | LevelCommandRegistrar |
---
## ♻️ Правила разработки
- KISS, DRY, SOLID
- Файлы ≤150–200 строк (в идеале ≤100)
- В папке ≤6 файлов
- Пакет = домен/фича, а не тип файла (`feature/level/`, а не `commands/listeners/`)
- Каждая фича содержит свои команды, сервисы, репозитории
- Единый слой персистентности через `repository/`
- Интеграции в `integration/`
---
## 🔴 Проблемы (результаты аудита, которые ещё не исправлены)
### HIGH
| # | Приоритет | Проблема | Статус |
|---|-----------|----------|--------|
| A07 | 🟠 **HIGH** | `HealthHttpServer` — single thread executor | ✅ Virtual threads |
| A08 | 🟠 **HIGH** | Тестовое покрытие ~5% (~34 теста на 149 продакшен-файлов). Нужно 20-30% | ⏳ 268 тестов в 22 файлах |
| A09 | 🟠 **HIGH** | Нет Docker / docker-compose | ✅ Dockerfile + docker-compose + .env.example |
| A01 | ⚪ **INFO** | `.env` с токеном в git-истории (локальный репозиторий) | ➖ |
### MEDIUM
| # | Приоритет | Проблема | Статус |
|---|-----------|----------|--------|
| A15 | 🟡 **MEDIUM** | ~33 файла команд в `command/impl/` — не перенесены в `feature/*/commands/` | ✅ 33 файла перенесены |
| A16 | 🟡 **MEDIUM** | ~16 репозиториев в `database/` — не разнесены в `feature/*/repository/` | ✅ 13+3 репозитория перенесены |
| A18 | 🟡 **MEDIUM** | `DatabaseMigration` — устаревший код для JSON→SQLite. Нужно оценить | ✅ Harmless, idempotent — keep as-is |
| A19 | 🟡 **MEDIUM** | Нет статического анализа (checkstyle / spotbugs) | ✅ checkstyle.xml + spotbugs + 169 known violations |
| A20 | 🟡 **MEDIUM** | Нет версионного каталога (`libs.versions.toml`) | ✅ gradle/libs.versions.toml, build.gradle переписан |
| A22 | 🟡 **MEDIUM** | Нет пула соединений (HikariCP). Голый JDBC | ✅ HikariCP 5.1.0 + proxy-based prepare() |
| A24 | 🟡 **MEDIUM** | VoiceTracker, RateLimiter, CooldownManager, MuteScheduler — ScheduledExecutorService. virtual threads? | ✅ Virtual threads |
| A40 | 🟡 **MEDIUM** | `HelpMenuHandler` в `event/interaction/` — должен быть в `feature/help/` | ✅ Перенесён |
### LOW
| # | Приоритет | Проблема | Статус |
|---|-----------|----------|--------|
| A30 | 🟢 **LOW** | SlowmodeCommand: ручная проверка границ → Math.clamp (другая семантика) | ➖ |
| A31 | 🟢 **LOW** | ClearCommand: ручная проверка границ → Math.clamp (другая семантика) | ➖ |
| A39 | 🟢 **LOW** | EmbedFactory: `set*` вместо `with*` для builder | ✅ Renamed in 43 files |
| A36 | 🟢 **LOW** | RankCardGenerator: URI → URL, deprecated API | ✅ `URI.toURL()` → `new URL()` |
---
## 📋 План рефакторинга
### Этап 1: Java 21 ✅ (14 items)
- [x] EventDispatcher: VirtualThreadPool
- [x] instanceof pattern matching (3 файла)
- [x] arrow-switch (InfoCommand)
- [x] String.repeat() (RateCommand)
- [x] .toList() (3 файла)
- [x] Map.ofEntries() (HelpCategories)
### Этап 2: Рефакторинг PrefixCommandRegistrar ✅
- [x] Создан интерфейс `CommandRegistrar`
- [x] 4 per-feature регистратора
- [x] Guice Multibinder для сбора регистраторов
- [x] 22 параметра → 1 (`Set<CommandRegistrar>`)
### Этап 3: Critical-баги ✅
- [x] RankCardGenerator: async + try-with-resources + cache + SVG
- [x] Database: synchronized connection
- [x] NekosLifeApi: чистый retry loop
- [x] GenerateRatingsCommand: async через complete()
- [x] DB path: вынесен в .env
### Этап 4: Перемещение файлов в feature-пакеты ✅
- [x] `command/impl/utility/` → `feature/*/commands/`
- [x] `command/impl/entertainment/` → `feature/*/commands/`
- [x] `command/entertainment/social/` → `feature/social/commands/`
- [x] `database/*/` → `feature/*/repository/`
- [x] `event/interaction/HelpMenuHandler` → `feature/help/`
### Этап 5: Тесты (цель: 20-30% покрытие)
- [x] Тесты на репозитории (in-memory SQLite) — Config, ShipPair, UserStats, Ratings, Warnings, ActiveMutes
- [x] Unit-тесты сервисов — MessageCooldownService, LevelService (был), XpFormula, ChoiceOptionParser
- [x] Unit-тесты value objects — UserStats (был), LevelProgress, LevelUpResult, BotConfig
- [x] Тесты embed — EmbedFactory (builder chaining), EmbedTemplates (factory methods)
- [x] Тесты форматирования — LeaderboardFormatter
- [ ] Unit-тесты на команды (с моками JDA)
- [ ] Smoke-тест: все команды регистрируются без коллизий
- [ ] Тесты на RankCardGenerator (изолированные, без сети)
- [ ] Тесты на EventDispatcher (маршрутизация, rate limiting)
### Этап 6: Инфраструктура ✅
- [x] Dockerfile (multi-stage)
- [x] docker-compose.yml
- [x] Статический анализ: checkstyle / spotbugs
- [x] Версионный каталог: `gradle/libs.versions.toml`
- [x] HikariCP вместо голого JDBC
### Этап 7: Кодстайл
- [x] EmbedFactory: `set*` → `with*` для builder
- [ ] DatabaseMigration: оценить нужность
- [x] HelpMenuHandler: переместить в feature/help/
---
## 🚀 Новые фичи (Roadmap)
## 🚀 Экономика — ✅ реализовано
### Модель данных
```sql
CREATE TABLE IF NOT EXISTS economy (
user_id TEXT PRIMARY KEY,
cash INTEGER NOT NULL DEFAULT 0, -- на руках
bank INTEGER NOT NULL DEFAULT 0, -- в банке
total_earned INTEGER NOT NULL DEFAULT 0,
total_spent INTEGER NOT NULL DEFAULT 0,
last_daily TEXT, -- ISO date
daily_streak INTEGER DEFAULT 0,
fishing_luck INTEGER DEFAULT 0, -- stat lvl 0-5
efficiency INTEGER DEFAULT 0, -- stat lvl 0-5
last_fish TEXT, -- ISO datetime
job TEXT, -- название работы
last_work TEXT -- ISO datetime
);
```
### Заработок
| Механика | Доход | Кулдаун |
|---|---|---|
| Сообщение | 1–3 LC | 60с |
| Голос | 1 LC / 2 мин | 2 мин |
| Ежедневно | 50 LC + streak ×1.5 на 7й день | 24ч |
| +rep (полученная) | 10 LC | — |
| Рыбалка | base × speed_mul × (1 + fishing_luck×0.01) | 2ч |
| Работа | random(range) × (1 + efficiency×0.01) | 6ч |
| Блэкджек | ×1.5 при победе | — |
| Слоты | ×0–×50 | — |
### Миниигры
**Рыбалка** (`!fish easy/normal/hard`)
- Сетка N×N (emoji + 🌊), бесплатно, неправильный ответ = 0
- Множитель скорости: <50% времени = ×1.5, <30% = ×2.0
- Стат `fishing_luck` (макс 5, стоимость 800×lvl)
**Блэкджек** (`!bj <bet>`)
- Дилер стоит на 16, ничья = проигрыш, BJ = ×1.5
- Кнопки Hit/Stand
**Слоты** (`!slot <bet>`)
- 🍒🍒🍒 ×3 (10%), 🔔🔔🔔 ×5 (5%), 💎💎💎 ×10 (2%), 👑👑👑 ×15 (1%), ⚡⚡⚡ ×50 (0.1%)
**Работы** (`!job list`, `!job join`, `!work`)
| Работа | Ур. | Доход |
|---|---|---|
| 🪓 Лесоруб | — | 15–30 |
| ⛏️ Шахтёр | — | 20–40 |
| 🎣 Рыбак | — | 25–50 |
| 🍳 Повар | 15 | 30–60 |
| 💻 Программист | 20 | 40–80 |
| 🧑‍🚀 Космонавт | 35 | 50–100 |
Стат `efficiency` (макс 5, стоимость 800×lvl)
**Rob** (`!rob @user`)
- 24ч кулдаун, 40% успех, крадёт до 15% cash (макс 10к)
- Провал: штраф 10% cash (макс 5к) → жертве
- Банк не трогается
**Банк** (`!bank deposit/withdraw/balance`)
- Без процентов, защита от rob
### Структура пакета
```
feature/economy/
EconomyModule.java
EconomyCommandRegistrar.java
domain/
EconomyAccount.java
EconomyTransaction.java
Job.java
SlotCombination.java
repository/
EconomyRepository.java
SqlEconomyRepository.java
service/
EconomyService.java
FishingService.java
BlackjackService.java
SlotService.java
JobService.java
command/
core/ (Balance, Baltop, Pay, Daily)
minigame/ (Fish, Blackjack, Slot, Job, Work)
social/ (Rob)
bank/ (Bank)
```
---
### Приоритет 1
- [ ] Система достижений (Achievements)
- [x] Система экономики (Economy) — **✅**
### Приоритет 2
- [x] Авто-модерация (3 варна = авто-мут на 1ч)
- [x] Музыка (lavaplayer: play, skip, stop, queue, np, volume, leave)
- [x] ~~Музыка — поиск с выбором (yt/sc/list + выбор номера)~~
- [x] Server Stats (участники, каналы, роли, бусты)
- [x] Level Roles (роли за уровни)
- [x] Красивые level-up embed с прогресс-баром
### Приоритет 3
- [ ] Статистика сервера — графики, CSV export
- [ ] Система квестов
- [ ] Wiki по установке и командам
---
**Версия:** 2.3 | **Последнее обновление:** 2026-07-02 | **Java 21 ✅, God Constructor ✅, Critical баги ✅, Economy ✅, Level Roles ✅, Lavalink Music ✅, SpotBugs ✅, Checkstyle ✅, CI/CD ✅**
## ✅ Что добавлено в v2.3
### 🎵 Lavalink Music Service
- [x] Node.js сервис с 4 Discord ботами (kazagumo + shoukaku)
- [x] Поддержка YouTube, SoundCloud, радио (`!radio <url>`)
- [x] Команды: play, stop, skip, queue, np, volume, pause, resume, shuffle, repeat, clear, move
- [x] Lavalink контейнер с healthcheck
- [x] docker-compose с интеграцией в основной проект
- [x] `.env.example` с 4 токенами
### 🔧 SpotBugs (все реальные баги исправлены)
- [x] FS (7): `\n` → `%n` в MetricsCollector, ServerStatsService
- [x] DMI (6): Random → static final Random в entertainment командах
- [x] SF (4): missing default → добавлены default в switch
- [x] RCN (3): Redundant nullcheck удалены
- [x] RV (1): Bad abs(hashCode) исправлен
- [x] Dm (2): Стандартная кодировка → UTF-8
- [x] OBL/ODR: Database.prepare() закрытие connection
- [x] REC: RankCardGenerator — узкий catch
- [x] DLS: FishingService — dead store удалён
- [x] EI2/EI (96): excluded как DI false positives
- [x] `ignoreFailures = false`
### 🔍 Checkstyle
- [x] Все 9 нарушений исправлены
- [x] `maxErrors`/`maxWarnings` удалены (0 нарушений)
### 🧪 Тесты
- [x] BalanceCommandTest (3 теста)
- [x] DailyCommandTest (2 теста)
- [x] PayCommandTest (3 теста)
- [x] CoinCommandTest (2 теста)
- [x] DiceCommandTest (2 теста)
- [x] EightBallCommandTest (2 теста)
- [x] Всего: 51 файл тестов, ~421+ тестов
### 🚀 CI/CD
- [x] Docker publish workflow (ghcr.io)
- [x] Release workflow (GitHub Releases + JAR artifact)