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)
Этап 2: Рефакторинг PrefixCommandRegistrar ✅
Этап 3: Critical-баги ✅
Этап 4: Перемещение файлов в feature-пакеты ✅
Этап 5: Тесты (цель: 20-30% покрытие)
Тесты на репозитории (in-memory SQLite) — Config, ShipPair, UserStats, Ratings, Warnings, ActiveMutes
Unit-тесты сервисов — MessageCooldownService, LevelService (был), XpFormula, ChoiceOptionParser
Unit-тесты value objects — UserStats (был), LevelProgress, LevelUpResult, BotConfig
Тесты embed — EmbedFactory (builder chaining), EmbedTemplates (factory methods)
Тесты форматирования — LeaderboardFormatter
Unit-тесты на команды (с моками JDA)
Smoke-тест: все команды регистрируются без коллизий
Тесты на RankCardGenerator (изолированные, без сети)
Тесты на EventDispatcher (маршрутизация, rate limiting)
Этап 6: Инфраструктура ✅
Этап 7: Кодстайл
🚀 Новые фичи (Roadmap)
🚀 Экономика — ✅ реализовано
Модель данных
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
Приоритет 2
Приоритет 3
🔴 Результаты аудита KISS/DRY/SOLID (2026-07-04)
DRY — дублирование кода (критично)
#
Что дублируется
Где
Сколько раз
Статус
D1
getDeterministicValue() — целиком
GayCommand, FatCommand, IqCommand, PpCommand, BoykisserCommand, MustacheCommand, RateCommand
7
✅ RatingService
D2
Cooldown check boilerplate (5 строк)
В с е entertainment команды
10+
✅ RatingService
D3
trunc() / err() helpers
MuteCommand, WarnCommand, SwapAndCaseCommand, UnmuteCommand, PunishCommand
5
✅ ModerationHelper
D4
Voice connect retry loop (цикл 10× 200ms)
PlayCommand, RadioManager
2
D5
RatingConfig — 6 методов с идентичной структурой
RatingConfig.java
6
D6
Social команды (hug/kiss/slap/poke/tickle/cuddle/feed/pat) — шаблон
10 файлов
10
SOLID
#
Нарушение
Файл
Описание
S1
SRP
BotModule.java
Биндит всё приложение
S2
SRP
SwapAndCaseCommand.java
Две разные команды в одном файле
S3
SRP
BotInitializer.java
Инициализирует 3 JDA, Lavalink, mutes, counters, health
S4
SRP
ShutdownManager.java
9 зависимостей в конструкторе
S5
SRP
PlayCommand.java
execute() на 145 строк
S6
OCP
Meter-команды (gay/fat/iq/pp)
Добавить новую = копировать 90 строк
S7
DIP
MuteCommand, WarnCommand
>5 конкретных репозиториев вместо интерфейсов
Файлы >150 строк
#
Файл
Строк
F1
PlayCommand.java
219
F2
QueueSlashHandler.java
207
F3
MusicBotControlHandler.java
207
F4
QueueCommands.java
207
F5
TrackScheduler.java
202
F6
MuteCommand.java
199
F7
ModerationLogger.java
199
F8
FeatureTables.java
193
F9
DatabaseMigration.java
193
F10
VoiceChannelManager.java
187
F11
ServerStatsService.java
187
F12
VoiceSetupPrefixCommand.java
183
F13
RadioManager.java
182
F14
MetricsCollector.java
182
F15
WarnCommand.java
184
F16
BotInitializer.java
182
F17
SlashHandler's (Queue/Filter)
>100
F18
GenerateRatingsCommand.java
172
F19
BlackjackService.java
172
F20
SqlEconomyRepository.java
169
F21
GuildMusicManager.java
167
F22
ProfileCommand/RankCardGen
>150
>3 файла в папке
#
Папка
Файлов
P1
feature/entertainment/commands/
15
P2
feature/social/commands/
10
P3
feature/economy/command/minigame/
7
P4
feature/level/ (все субпапки)
21
P5
feature/moderation/ (все субпакеты)
18
P6
feature/music/ (все субпакеты)
22
P7
feature/voice/ (все субпакеты)
12
Нет тестов
#
Фича
Файлов
T1
music
20+
T2
voice
12
T3
social
10
T4
role
9
T5
radio
5
T6
reputation
4
T7
counter
7
T8
admin
1
T9
help
2
T10
utility
2
T11
welcome
2
T12
profile
5
T13
serverstats
1
📋 План рефакторинга (KISS/DRY/SOLID)
Этап 8: Убить дублирование (DRY) — в процессе
Этап 9: SOLID
Этап 10: Файлы ≤150 строк
Этап 11: ≤6 файлов в папке
Этап 12: Тесты
Техдолг (баги)
Версия: 2.3 | Последнее обновление: 2026-07-04 | Java 21 ✅ , God Constructor ✅ , Critical баги ✅ , Economy ✅ , Level Roles ✅ , Lavalink Music ✅ , SpotBugs ✅ , Checkstyle ✅ , CI/CD ✅
✅ Что добавлено в v2.3
🎵 Lavalink Music Service
Node.js сервис с 4 Discord ботами (kazagumo + shoukaku)
Поддержка YouTube, SoundCloud, радио (!radio <url>)
Команды: play, stop, skip, queue, np, volume, pause, resume, shuffle, repeat, clear, move
Lavalink контейнер с healthcheck
docker-compose с интеграцией в основной проект
.env.example с 4 токенами
🔧 SpotBugs (все реальные баги исправлены)
🔍 Checkstyle
🧪 Тесты
🚀 CI/CD