Update TODO: detailed refactoring plan with proper priorities and XP formula fix

This commit is contained in:
loki5512344 2026-05-11 14:15:09 +02:00
parent 64a8928d41
commit 17f979b5d3

248
TODO.md
View file

@ -174,108 +174,181 @@ src/main/java/creator/loki/
└── BotModule └── BotModule
``` ```
### План действий (приоритеты): ### План действий (этапы):
#### Высокий приоритет (делаем сейчас): #### Этап 1: Фундамент (делаем первым)
**1. Удалить ненужное** **1. Создать repository/ (средний → высокий приоритет)**
- [x] Удалить `command/slash/` (дубликаты) - [ ] Создать `repository/`
- [x] Удалить `audio/` (TTS не работает) - [ ] Создать интерфейс `repository/UserStatsRepository.java`
- [x] Удалить `TtsCommand.java` - [ ] Создать `repository/impl/`
- [ ] Удалить `SwapCommand.java` - [ ] Создать `repository/impl/JsonUserStatsRepository.java` (обёртка над JsonDataStore)
- [ ] Удалить все импорты AudioManager - [ ] Создать интерфейс `repository/GuildConfigRepository.java`
- [ ] Рефакторить `database/ConfigRepository` → использовать интерфейс
**2. Реорганизовать util/ (мусорная корзина)** **2. Реорганизовать util/ (мусорная корзина)**
- [ ] Создать `core/security/` - [ ] Создать `core/security/`
- [ ] Переместить `CooldownManager` → `core/security/` - [ ] Переместить `util/CooldownManager` → `core/security/CooldownManager`
- [ ] Переместить `GlobalRateLimiter` → `core/security/` - [ ] Переместить `util/GlobalRateLimiter` → `core/security/RateLimiter`
- [ ] Создать `integration/nekos/` - [ ] Создать `integration/nekos/`
- [ ] Переместить `NekosLifeApi` → `integration/nekos/` - [ ] Переместить `util/NekosLifeApi` → `integration/nekos/NekosLifeApi`
- [ ] Удалить пустую папку `util/` - [ ] Удалить пустую папку `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/`
- [ ] Создать `feature/level/domain/` для доменных объектов - [ ] Создать `feature/level/domain/`
- [ ] Создать `feature/level/service/` для сервисов - [ ] Создать `feature/level/domain/XpFormula.java`:
- [ ] Создать `feature/level/repository/` для интерфейсов ```java
- [ ] **Рефакторинг LevelSystem (God Class 5/10):** public class XpFormula {
- [ ] Вынести `LevelUpResult` в `feature/level/domain/LevelUpResult.java` private static final int XP_PER_LEVEL = 200;
- [ ] Вынести `LevelProgress` в `feature/level/domain/LevelProgress.java`
- [ ] Создать `feature/level/domain/XpFormula.java` (инкапсуляция математики) // Исправленная формула: 200 * n * (n+1) / 2
- [ ] Создать `feature/level/repository/UserStatsRepository.java` (интерфейс) public int getTotalXPForLevel(int level) {
- [ ] Создать `feature/level/repository/JsonUserStatsRepository.java` (реализация) return XP_PER_LEVEL * level * (level + 1) / 2;
- [ ] Создать `feature/level/service/LeaderboardService.java` (топы и агрегации) }
- [ ] Исправить формулу: 100 vs 200 (рассогласование в коде)
- [ ] Убрать `messageTimestamps` ConcurrentHashMap, использовать `UserStats.lastMessageTime` // Обратная формула с использованием XP_PER_LEVEL
- [ ] Рефакторить `LevelSystem` → `feature/level/service/LevelService.java` public int calculateLevel(int xp) {
- [ ] **Рефакторинг UserStats (анемичная модель 6/10):** double discriminant = 1 + 8.0 * xp / XP_PER_LEVEL;
- [ ] Сделать immutable (убрать сеттеры) return (int) Math.floor((-1 + Math.sqrt(discriminant)) / 2.0);
- [ ] Добавить методы `addXP()`, `recordMessage()`, `addVoiceTime()` }
- [ ] Добавить `getLevel(XpFormula)` вместо внешних вычислений }
- [ ] Добавить `equals()` и `hashCode()` ```
- [ ] Переименовать `incrementMessages()` → `recordMessage(long timestamp)` - [ ] Вынести `LevelUpResult` из `LevelSystem` → `feature/level/domain/LevelUpResult.java`
- [ ] Переместить `level/LevelSystem` → `feature/level/service/LevelService.java` - [ ] Вынести `LevelProgress` из `LevelSystem` → `feature/level/domain/LevelProgress.java`
- [ ] Переместить `level/UserStats` → `feature/level/domain/UserStats.java` - [ ] Переместить `level/UserStats` → `feature/level/domain/UserStats.java`
- [ ] Переместить `profile/LevelUtils` → `feature/level/` (если нужен) - [ ] **НЕ делать immutable сейчас** (Gson требует сеттеры, сделаем после Repository)
- [ ] Переместить `command/impl/stats/RankCommand` → `feature/level/` - [ ] Добавить `equals()` и `hashCode()` в `UserStats`
- [ ] Переместить `command/impl/stats/StatsCommand` → `feature/level/` - [ ] Переименовать `incrementMessages()` → `recordMessage(long timestamp)`
- [ ] Переместить `listener/LevelUpNotifier` → `feature/level/`
- [ ] Переместить `listener/VoiceTracker` → `feature/level/`
- [ ] Удалить пустую папку `level/`
**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<UserStats>`
- [ ] Рефакторить `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/` - [ ] Создать `feature/voice/`
- [ ] Переместить `voice/*` → `feature/voice/` - [ ] Переместить `voice/VoiceChannelManager` → `feature/voice/`
- [ ] Переместить `voice/VoiceChannelData` → `feature/voice/`
- [ ] Переместить `voice/VoicePreset` → `feature/voice/`
- [ ] Переместить `command/impl/setup/VoiceSetupCommand` → `feature/voice/` - [ ] Переместить `command/impl/setup/VoiceSetupCommand` → `feature/voice/`
- [ ] Переместить `listener/VoiceChannelListener` → `feature/voice/` - [ ] Переместить `listener/VoiceChannelListener` → `feature/voice/`
- [ ] Переместить `listener/VoiceButtonHandler` → `feature/voice/` - [ ] Переместить `listener/VoiceButtonHandler` → `feature/voice/`
- [ ] Удалить пустую папку `voice/` - [ ] Удалить пустую папку `voice/`
- [ ] Обновить импорты
**5. Создать feature/counter/ (счетчик)** **8. Создать feature/counter/ (счетчик участников)**
- [ ] Создать `feature/counter/` - [ ] Создать `feature/counter/`
- [ ] Переместить `counter/*` → `feature/counter/` - [ ] Переместить `counter/CounterManager` → `feature/counter/`
- [ ] Переместить `counter/DailyStats` → `feature/counter/`
- [ ] Переместить `command/impl/setup/CounterSetupCommand` → `feature/counter/` - [ ] Переместить `command/impl/setup/CounterSetupCommand` → `feature/counter/`
- [ ] Переместить `listener/MemberCounterListener` → `feature/counter/` - [ ] Переместить `listener/MemberCounterListener` → `feature/counter/`
- [ ] Удалить пустую папку `counter/` - [ ] Удалить пустую папку `counter/`
- [ ] Обновить импорты
**6. Создать feature/role/ (кастомные роли)** **9. Создать feature/role/ (кастомные роли)**
- [ ] Создать `feature/role/` - [ ] Создать `feature/role/`
- [ ] Переместить `role/CustomRoleManager` → `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/` - [ ] Удалить пустые папки `role/` и `command/impl/roles/`
- [ ] Обновить импорты
#### Средний приоритет (потом): **10. Создать feature/reputation/ (система репутации)**
**7. Создать feature/reputation/**
- [ ] Создать `feature/reputation/` - [ ] Создать `feature/reputation/`
- [ ] Создать `ReputationService` (вынести логику из команд) - [ ] Создать `feature/reputation/ReputationService.java` (вынести логику из команд)
- [ ] Переместить `command/impl/stats/RepCommand` → `feature/reputation/` - [ ] Переместить `command/impl/stats/RepCommand` → `feature/reputation/`
- [ ] Переместить `command/impl/stats/MinusRepCommand` → `feature/reputation/` - [ ] Переместить `command/impl/stats/MinusRepCommand` → `feature/reputation/`
- [ ] Переместить `command/impl/stats/RepTopCommand` → `feature/reputation/` - [ ] Переместить `command/impl/stats/RepTopCommand` → `feature/reputation/`
- [ ] Рефакторить команды: использовать `ReputationService`
- [ ] Обновить импорты
**8. Создать feature/leaderboard/** **11. Создать feature/leaderboard/ (таблица лидеров)**
- [ ] Создать `feature/leaderboard/` - [ ] Создать `feature/leaderboard/`
- [ ] Переместить `command/impl/stats/leaderboard/*` → `feature/leaderboard/` - [ ] Переместить `command/impl/stats/leaderboard/NewLeaderboardCommand` → `feature/leaderboard/LeaderboardCommand`
- [ ] Создать `LeaderboardService` - [ ] Переместить `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/` - [ ] Удалить пустую папку `command/impl/stats/`
- [ ] Обновить импорты
**9. Реорганизовать profile/** **12. Создать feature/profile/ (профили пользователей)**
- [ ] Создать `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/` - [ ] Переместить `command/impl/utility/ProfileCommand` → `feature/profile/`
- [ ] Создать `ProfileEmbedFactory` (вынести из команды) - [ ] Создать `feature/profile/ProfileEmbedFactory.java` (вынести из команды)
- [ ] Удалить пустую папку `profile/` - [ ] Удалить пустую папку `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/` - [ ] Создать `event/`
- [ ] Переместить `listener/ReadyListener` → `event/` - [ ] Создать `event/gateway/` (JDA Gateway events)
- [ ] Переместить `listener/MessageListener` → `event/` - [ ] Переместить `listener/ReadyListener` → `event/gateway/`
- [ ] Переместить `listener/SlashCommandListener` → `event/` - [ ] Переместить `listener/MessageListener` → `event/gateway/`
- [ ] Переместить `listener/HelpMenuHandler` → `event/` - [ ] Создать `event/gateway/GuildListener.java` (member join/leave + moderation)
- [ ] Переместить `listener/ModerationLogger` → `event/` - [ ] Переместить `listener/ModerationLogger` → `event/gateway/GuildListener` (или отдельно)
- [ ] Создать `event/interaction/` (Button/Menu interactions)
- [ ] Переместить `listener/SlashCommandListener` → `event/interaction/`
- [ ] Переместить `listener/HelpMenuHandler` → `event/interaction/`
- [ ] Удалить пустую папку `listener/` - [ ] Удалить пустую папку `listener/`
- [ ] Обновить импорты
**11. Реорганизовать core/** **15. Реорганизовать core/**
- [ ] Создать `core/registry/` - [ ] Создать `core/registry/`
- [ ] Переместить `core/CommandRegistry` → `core/registry/` - [ ] Переместить `core/CommandRegistry` → `core/registry/`
- [ ] Переместить `core/SlashCommandRegistry` → `core/registry/` - [ ] Переместить `core/SlashCommandRegistry` → `core/registry/`
@ -283,27 +356,50 @@ src/main/java/creator/loki/
- [ ] Переместить `core/SlashCommandRegistrar` → `core/registry/` - [ ] Переместить `core/SlashCommandRegistrar` → `core/registry/`
- [ ] Создать `core/exception/` - [ ] Создать `core/exception/`
- [ ] Переместить `exception/CommandExceptionHandler` → `core/exception/` - [ ] Переместить `exception/CommandExceptionHandler` → `core/exception/`
- [ ] Переместить `exception/CommandException` → `command/` - [ ] Переместить `exception/CommandException` → `command/CommandException`
- [ ] Удалить пустую папку `exception/` - [ ] Удалить пустую папку `exception/`
- [ ] Обновить импорты
**12. Реорганизовать command/** **16. Почистить command/**
- [ ] Переименовать `command/impl/entertainment/interaction/` → `command/entertainment/social/` - [ ] Переименовать `command/impl/entertainment/interaction/` → `command/entertainment/social/`
- [ ] Переместить `command/impl/utility/MetricsCommand` → `command/system/` - [ ] Удалить `command/impl/setup/` (команды перенесены в feature/)
- [ ] Переместить `command/impl/setup/LogSetupCommand` → `event/` (или удалить setup/) - [ ] Удалить `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. Обновить документацию** #### Этап 5: Финальная полировка (опционально)
- [ ] Обновить FEATURES.md (убрать TTS)
- [ ] Обновить README.md (новая структура) **18. UserStats immutable (после Repository)**
- [ ] Добавить ARCHITECTURE.md (описание доменов) - [ ] Создать `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 строк
- [ ] Запустить бота и протестировать основные команды
--- ---