Update TODO: detailed refactoring plan with proper priorities and XP formula fix
This commit is contained in:
parent
64a8928d41
commit
17f979b5d3
1 changed files with 172 additions and 76 deletions
250
TODO.md
250
TODO.md
|
|
@ -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` (инкапсуляция математики)
|
|
||||||
- [ ] Создать `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`
|
|
||||||
- [ ] Переместить `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/`
|
|
||||||
|
|
||||||
**4. Создать feature/voice/ (голосовые каналы)**
|
// Исправленная формула: 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`
|
||||||
|
- [ ] **НЕ делать immutable сейчас** (Gson требует сеттеры, сделаем после Repository)
|
||||||
|
- [ ] Добавить `equals()` и `hashCode()` в `UserStats`
|
||||||
|
- [ ] Переименовать `incrementMessages()` → `recordMessage(long timestamp)`
|
||||||
|
|
||||||
|
**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 строк
|
||||||
|
- [ ] Запустить бота и протестировать основные команды
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue