From 17f979b5d344afac6003ca3aea86aa4f7d8dcf5a Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Mon, 11 May 2026 14:15:09 +0200 Subject: [PATCH] Update TODO: detailed refactoring plan with proper priorities and XP formula fix --- TODO.md | 248 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 172 insertions(+), 76 deletions(-) diff --git a/TODO.md b/TODO.md index 949b13d..57427f2 100644 --- a/TODO.md +++ b/TODO.md @@ -174,108 +174,181 @@ src/main/java/creator/loki/ └── BotModule ``` -### План действий (приоритеты): +### План действий (этапы): -#### Высокий приоритет (делаем сейчас): +#### Этап 1: Фундамент (делаем первым) -**1. Удалить ненужное** -- [x] Удалить `command/slash/` (дубликаты) -- [x] Удалить `audio/` (TTS не работает) -- [x] Удалить `TtsCommand.java` -- [ ] Удалить `SwapCommand.java` -- [ ] Удалить все импорты AudioManager +**1. Создать repository/ (средний → высокий приоритет)** +- [ ] Создать `repository/` +- [ ] Создать интерфейс `repository/UserStatsRepository.java` +- [ ] Создать `repository/impl/` +- [ ] Создать `repository/impl/JsonUserStatsRepository.java` (обёртка над JsonDataStore) +- [ ] Создать интерфейс `repository/GuildConfigRepository.java` +- [ ] Рефакторить `database/ConfigRepository` → использовать интерфейс **2. Реорганизовать util/ (мусорная корзина)** - [ ] Создать `core/security/` -- [ ] Переместить `CooldownManager` → `core/security/` -- [ ] Переместить `GlobalRateLimiter` → `core/security/` +- [ ] Переместить `util/CooldownManager` → `core/security/CooldownManager` +- [ ] Переместить `util/GlobalRateLimiter` → `core/security/RateLimiter` - [ ] Создать `integration/nekos/` -- [ ] Переместить `NekosLifeApi` → `integration/nekos/` +- [ ] Переместить `util/NekosLifeApi` → `integration/nekos/NekosLifeApi` - [ ] Удалить пустую папку `util/` +- [ ] Обновить все импорты -**3. Создать feature/level/ (система уровней)** +**3. Удалить импорты AudioManager** +- [ ] Удалить импорты из `core/BotInitializer` +- [ ] Удалить импорты из `core/PrefixCommandRegistrar` +- [ ] Удалить импорты из `core/SlashCommandRegistrar` +- [ ] Удалить параметры AudioManager из конструкторов +- [ ] Проверить компиляцию: `gradle build` + +--- + +#### Этап 2: feature/level/ (зависит от Этапа 1) + +**4. Создать feature/level/domain/** - [ ] Создать `feature/level/` -- [ ] Создать `feature/level/domain/` для доменных объектов -- [ ] Создать `feature/level/service/` для сервисов -- [ ] Создать `feature/level/repository/` для интерфейсов -- [ ] **Рефакторинг LevelSystem (God Class 5/10):** - - [ ] Вынести `LevelUpResult` в `feature/level/domain/LevelUpResult.java` - - [ ] Вынести `LevelProgress` в `feature/level/domain/LevelProgress.java` - - [ ] Создать `feature/level/domain/XpFormula.java` (инкапсуляция математики) - - [ ] Создать `feature/level/repository/UserStatsRepository.java` (интерфейс) - - [ ] Создать `feature/level/repository/JsonUserStatsRepository.java` (реализация) - - [ ] Создать `feature/level/service/LeaderboardService.java` (топы и агрегации) - - [ ] Исправить формулу: 100 vs 200 (рассогласование в коде) - - [ ] Убрать `messageTimestamps` ConcurrentHashMap, использовать `UserStats.lastMessageTime` - - [ ] Рефакторить `LevelSystem` → `feature/level/service/LevelService.java` -- [ ] **Рефакторинг UserStats (анемичная модель 6/10):** - - [ ] Сделать immutable (убрать сеттеры) - - [ ] Добавить методы `addXP()`, `recordMessage()`, `addVoiceTime()` - - [ ] Добавить `getLevel(XpFormula)` вместо внешних вычислений - - [ ] Добавить `equals()` и `hashCode()` - - [ ] Переименовать `incrementMessages()` → `recordMessage(long timestamp)` -- [ ] Переместить `level/LevelSystem` → `feature/level/service/LevelService.java` +- [ ] Создать `feature/level/domain/` +- [ ] Создать `feature/level/domain/XpFormula.java`: + ```java + public class XpFormula { + private static final int XP_PER_LEVEL = 200; + + // Исправленная формула: 200 * n * (n+1) / 2 + public int getTotalXPForLevel(int level) { + return XP_PER_LEVEL * level * (level + 1) / 2; + } + + // Обратная формула с использованием XP_PER_LEVEL + public int calculateLevel(int xp) { + double discriminant = 1 + 8.0 * xp / XP_PER_LEVEL; + return (int) Math.floor((-1 + Math.sqrt(discriminant)) / 2.0); + } + } + ``` +- [ ] Вынести `LevelUpResult` из `LevelSystem` → `feature/level/domain/LevelUpResult.java` +- [ ] Вынести `LevelProgress` из `LevelSystem` → `feature/level/domain/LevelProgress.java` - [ ] Переместить `level/UserStats` → `feature/level/domain/UserStats.java` -- [ ] Переместить `profile/LevelUtils` → `feature/level/` (если нужен) -- [ ] Переместить `command/impl/stats/RankCommand` → `feature/level/` -- [ ] Переместить `command/impl/stats/StatsCommand` → `feature/level/` -- [ ] Переместить `listener/LevelUpNotifier` → `feature/level/` -- [ ] Переместить `listener/VoiceTracker` → `feature/level/` -- [ ] Удалить пустую папку `level/` +- [ ] **НЕ делать immutable сейчас** (Gson требует сеттеры, сделаем после Repository) +- [ ] Добавить `equals()` и `hashCode()` в `UserStats` +- [ ] Переименовать `incrementMessages()` → `recordMessage(long timestamp)` -**4. Создать feature/voice/ (голосовые каналы)** +**5. Создать feature/level/service/** +- [ ] Создать `feature/level/service/` +- [ ] Создать `feature/level/service/MessageCooldownService.java`: + - Персистентный кулдаун через `UserStats.lastMessageTime` + - Убрать `ConcurrentHashMap messageTimestamps` +- [ ] Создать `feature/level/service/LeaderboardService.java`: + - Вынести методы `getTopByLevel`, `getTopByMessages`, `getTopByVoice` + - Обобщить через `Comparator` +- [ ] Рефакторить `level/LevelSystem` → `feature/level/service/LevelService.java`: + - Убрать God Class: только бизнес-логика начисления XP + - Использовать `UserStatsRepository` вместо `JsonDataStore` + - Использовать `XpFormula` для вычислений + - Использовать `MessageCooldownService` для кулдаунов + - Убрать методы лидерборда (в `LeaderboardService`) + - Убрать `getAllStats()` (в Repository) + +**6. Переместить команды и листенеры в feature/level/** +- [ ] Переместить `command/impl/stats/RankCommand` → `feature/level/RankCommand` +- [ ] Переместить `command/impl/stats/StatsCommand` → `feature/level/StatsCommand` +- [ ] Переместить `listener/LevelUpNotifier` → `feature/level/LevelUpNotifier` +- [ ] Переместить `listener/VoiceTracker` → `feature/level/VoiceTracker` +- [ ] Переместить `profile/LevelUtils` → `feature/level/LevelUtils` (если нужен) +- [ ] Удалить пустую папку `level/` +- [ ] Обновить все импорты +- [ ] Обновить `BotInitializer`, `BotModule`, `PrefixCommandRegistrar` + +--- + +#### Этап 3: Остальные feature/ (параллельно, независимо) + +**7. Создать feature/voice/ (голосовые каналы)** - [ ] Создать `feature/voice/` -- [ ] Переместить `voice/*` → `feature/voice/` +- [ ] Переместить `voice/VoiceChannelManager` → `feature/voice/` +- [ ] Переместить `voice/VoiceChannelData` → `feature/voice/` +- [ ] Переместить `voice/VoicePreset` → `feature/voice/` - [ ] Переместить `command/impl/setup/VoiceSetupCommand` → `feature/voice/` - [ ] Переместить `listener/VoiceChannelListener` → `feature/voice/` - [ ] Переместить `listener/VoiceButtonHandler` → `feature/voice/` - [ ] Удалить пустую папку `voice/` +- [ ] Обновить импорты -**5. Создать feature/counter/ (счетчик)** +**8. Создать feature/counter/ (счетчик участников)** - [ ] Создать `feature/counter/` -- [ ] Переместить `counter/*` → `feature/counter/` +- [ ] Переместить `counter/CounterManager` → `feature/counter/` +- [ ] Переместить `counter/DailyStats` → `feature/counter/` - [ ] Переместить `command/impl/setup/CounterSetupCommand` → `feature/counter/` - [ ] Переместить `listener/MemberCounterListener` → `feature/counter/` - [ ] Удалить пустую папку `counter/` +- [ ] Обновить импорты -**6. Создать feature/role/ (кастомные роли)** +**9. Создать feature/role/ (кастомные роли)** - [ ] Создать `feature/role/` - [ ] Переместить `role/CustomRoleManager` → `feature/role/` -- [ ] Переместить `command/impl/roles/*` → `feature/role/` +- [ ] Переместить `command/impl/roles/CreateRoleCommand` → `feature/role/` +- [ ] Переместить `command/impl/roles/DeleteRoleCommand` → `feature/role/` +- [ ] Переместить `command/impl/roles/EditRoleCommand` → `feature/role/` +- [ ] Переместить `command/impl/roles/MyRolesCommand` → `feature/role/` +- [ ] Переместить `command/impl/roles/RoleCommandValidator` → `feature/role/` - [ ] Удалить пустые папки `role/` и `command/impl/roles/` +- [ ] Обновить импорты -#### Средний приоритет (потом): - -**7. Создать feature/reputation/** +**10. Создать feature/reputation/ (система репутации)** - [ ] Создать `feature/reputation/` -- [ ] Создать `ReputationService` (вынести логику из команд) +- [ ] Создать `feature/reputation/ReputationService.java` (вынести логику из команд) - [ ] Переместить `command/impl/stats/RepCommand` → `feature/reputation/` - [ ] Переместить `command/impl/stats/MinusRepCommand` → `feature/reputation/` - [ ] Переместить `command/impl/stats/RepTopCommand` → `feature/reputation/` +- [ ] Рефакторить команды: использовать `ReputationService` +- [ ] Обновить импорты -**8. Создать feature/leaderboard/** +**11. Создать feature/leaderboard/ (таблица лидеров)** - [ ] Создать `feature/leaderboard/` -- [ ] Переместить `command/impl/stats/leaderboard/*` → `feature/leaderboard/` -- [ ] Создать `LeaderboardService` +- [ ] Переместить `command/impl/stats/leaderboard/NewLeaderboardCommand` → `feature/leaderboard/LeaderboardCommand` +- [ ] Переместить `command/impl/stats/leaderboard/LeaderboardFormatter` → `feature/leaderboard/` +- [ ] Переместить `command/impl/stats/leaderboard/LeaderboardButtons` → `feature/leaderboard/` +- [ ] Переместить `command/impl/stats/leaderboard/LeaderboardButtonListener` → `feature/leaderboard/` +- [ ] Создать `feature/leaderboard/LeaderboardService.java` (использовать из level/) - [ ] Удалить пустую папку `command/impl/stats/` +- [ ] Обновить импорты -**9. Реорганизовать profile/** +**12. Создать feature/profile/ (профили пользователей)** - [ ] Создать `feature/profile/` -- [ ] Переместить `profile/*` → `feature/profile/` +- [ ] Переместить `profile/ProfileService` → `feature/profile/` +- [ ] Переместить `profile/ProfileGenerator` → `feature/profile/` +- [ ] Переместить `profile/ProfileData` → `feature/profile/` - [ ] Переместить `command/impl/utility/ProfileCommand` → `feature/profile/` -- [ ] Создать `ProfileEmbedFactory` (вынести из команды) +- [ ] Создать `feature/profile/ProfileEmbedFactory.java` (вынести из команды) - [ ] Удалить пустую папку `profile/` +- [ ] Обновить импорты -**10. Реорганизовать event/ (listener)** +**13. Создать feature/metrics/ (метрики системы)** +- [ ] Создать `feature/metrics/` +- [ ] Переместить `metrics/MetricsCollector` → `feature/metrics/` +- [ ] Переместить `command/impl/utility/MetricsCommand` → `feature/metrics/` +- [ ] Создать `feature/metrics/MetricsService.java` (если нужна логика) +- [ ] Удалить пустую папку `metrics/` +- [ ] Обновить импорты + +--- + +#### Этап 4: Инфраструктура (после feature/) + +**14. Реорганизовать event/ (listener)** - [ ] Создать `event/` -- [ ] Переместить `listener/ReadyListener` → `event/` -- [ ] Переместить `listener/MessageListener` → `event/` -- [ ] Переместить `listener/SlashCommandListener` → `event/` -- [ ] Переместить `listener/HelpMenuHandler` → `event/` -- [ ] Переместить `listener/ModerationLogger` → `event/` +- [ ] Создать `event/gateway/` (JDA Gateway events) +- [ ] Переместить `listener/ReadyListener` → `event/gateway/` +- [ ] Переместить `listener/MessageListener` → `event/gateway/` +- [ ] Создать `event/gateway/GuildListener.java` (member join/leave + moderation) +- [ ] Переместить `listener/ModerationLogger` → `event/gateway/GuildListener` (или отдельно) +- [ ] Создать `event/interaction/` (Button/Menu interactions) +- [ ] Переместить `listener/SlashCommandListener` → `event/interaction/` +- [ ] Переместить `listener/HelpMenuHandler` → `event/interaction/` - [ ] Удалить пустую папку `listener/` +- [ ] Обновить импорты -**11. Реорганизовать core/** +**15. Реорганизовать core/** - [ ] Создать `core/registry/` - [ ] Переместить `core/CommandRegistry` → `core/registry/` - [ ] Переместить `core/SlashCommandRegistry` → `core/registry/` @@ -283,27 +356,50 @@ src/main/java/creator/loki/ - [ ] Переместить `core/SlashCommandRegistrar` → `core/registry/` - [ ] Создать `core/exception/` - [ ] Переместить `exception/CommandExceptionHandler` → `core/exception/` -- [ ] Переместить `exception/CommandException` → `command/` +- [ ] Переместить `exception/CommandException` → `command/CommandException` - [ ] Удалить пустую папку `exception/` +- [ ] Обновить импорты -**12. Реорганизовать command/** +**16. Почистить command/** - [ ] Переименовать `command/impl/entertainment/interaction/` → `command/entertainment/social/` -- [ ] Переместить `command/impl/utility/MetricsCommand` → `command/system/` -- [ ] Переместить `command/impl/setup/LogSetupCommand` → `event/` (или удалить setup/) +- [ ] Удалить `command/impl/setup/` (команды перенесены в feature/) +- [ ] Удалить `command/impl/utility/SwapCommand.java` (не используется) +- [ ] Оставить в `command/` только: + - Интерфейсы: `Command.java`, `CommandContext.java`, `SlashCommand.java`, `CommandException.java` + - `command/moderation/` (если не выносим в feature/) + - `command/entertainment/` (кросс-доменные развлечения) + - `command/utility/` (HelpCommand, PingCommand, InfoCommand, AvatarCommand, PollCommand) -#### Низкий приоритет (опционально): +**17. Вынести App.java из корня** +- [ ] Создать `bootstrap/` +- [ ] Создать `bootstrap/App.java` +- [ ] Переместить логику инициализации из корневого `App.java` +- [ ] Удалить корневой `App.java` +- [ ] Обновить `build.gradle` (mainClass) -**13. Создать repository/ (единый слой данных)** -- [ ] Создать `repository/` -- [ ] Создать интерфейсы `UserRepository`, `GuildConfigRepository` -- [ ] Создать `repository/impl/` -- [ ] Рефакторить `data/JsonDataStore` → `repository/impl/` -- [ ] Рефакторить `database/ConfigRepository` → `repository/impl/` +--- -**14. Обновить документацию** -- [ ] Обновить FEATURES.md (убрать TTS) -- [ ] Обновить README.md (новая структура) -- [ ] Добавить ARCHITECTURE.md (описание доменов) +#### Этап 5: Финальная полировка (опционально) + +**18. UserStats immutable (после Repository)** +- [ ] Создать `UserStats.Builder` +- [ ] Убрать public сеттеры (оставить package-private для Gson) +- [ ] Добавить методы `addXP()`, `recordMessage()`, `addVoiceTime()` +- [ ] Добавить `getLevel(XpFormula)` вместо внешних вычислений +- [ ] Обновить `JsonUserStatsRepository` для работы с immutable + +**19. Обновить документацию** +- [ ] Обновить `FEATURES.md` (убрать TTS, добавить новые фичи) +- [ ] Обновить `README.md` (новая структура проекта) +- [ ] Создать `ARCHITECTURE.md` (описание доменов и feature/) +- [ ] Обновить комментарии в коде + +**20. Финальная проверка** +- [ ] `gradle build` - компиляция без ошибок +- [ ] Проверить все импорты +- [ ] Проверить что нет папок с >6 файлами +- [ ] Проверить что нет файлов >200 строк +- [ ] Запустить бота и протестировать основные команды ---