Refactor: remove TTS system, slash commands folder, reorganize stats leaderboard

This commit is contained in:
loki5512344 2026-05-11 14:12:30 +02:00
parent f43db6a527
commit 64a8928d41
29 changed files with 313 additions and 1764 deletions

309
TODO.md
View file

@ -1,6 +1,313 @@
# TODO - План реализации функций
## 🎯 Основные задачи
## Правила разработки
### Архитектура и код:
- KISS, DRY, SOLID принципы
- Файлы максимум 150-200 строк, стараться делать 100 строк
- В одной папке не больше 6 файлов
- Не создавать новые MD файлы без необходимости
- Разделение по доменам, а не по типам артефактов
### Принципы структуры:
- Пакет = домен/фича, а не тип файла (не "команды/листенеры", а "profile/level/voice")
- Каждая фича содержит свои команды, сервисы, репозитории
- Единый слой персистентности через repository/
- Интеграции в отдельном пакете integration/
---
## Рефакторинг структуры проекта
### Целевая оценка: 7/10
**Проблемы:**
1. `util/` - мусорная корзина (CooldownManager, RateLimiter, NekosLifeApi)
2. Два механизма персистентности (data/ и database/) без абстракции
3. `command/impl/entertainment/` - 23 файла в одном пакете
4. `exception/` - избыточный пакет для 2 файлов
5. `embed/` - presentation layer оторван от domain
6. `listener/` - смешаны разные ответственности
7. Техническое разделение вместо доменного
8. **LevelSystem - God Class (5/10):**
- Нарушение SRP: хранение + кэширование + формулы + лидерборды + прогресс-бары
- Прямая зависимость от JsonDataStore (нет интерфейса Repository)
- O(n) на каждое сообщение (читает/пишет весь JSON)
- Кэш messageTimestamps не персистентный (теряется при рестарте)
- Рассогласование формул: комментарий говорит 200, код использует 100
- LevelUpResult и LevelProgress - вложенные классы вместо отдельных
- getAllStats() возвращает mutable map (можно сломать консистентность)
9. **UserStats - анемичная модель (6/10):**
- Сеттеры позволяют нарушить инварианты (setLevel(999) без XP)
- incrementMessages() скрыто меняет lastMessageTime (side effect)
- Поля lastMessageTime и lastVoiceJoin не используются системой
- Нет equals/hashCode для использования в коллекциях
### Целевая структура (по доменам):
```
src/main/java/creator/loki/
├── App.java # Точка входа (временно, потом в bootstrap/)
│
├── core/ # Ядро системы
│ ├── BotInitializer
│ ├── EventDispatcher
│ ├── registry/ # Регистрация команд
│ │ ├── CommandRegistry
│ │ ├── SlashCommandRegistry
│ │ ├── PrefixCommandRegistrar
│ │ └── SlashCommandRegistrar
│ ├── security/ # Безопасность и ограничения
│ │ ├── RateLimiter # (из util/)
│ │ └── CooldownManager # (из util/)
│ └── exception/ # Глобальная обработка ошибок
│ └── CommandExceptionHandler
│
├── command/ # Базовые интерфейсы команд
│ ├── Command.java
│ ├── CommandContext.java
│ ├── CommandException.java # (из exception/)
│ ├── SlashCommand.java
│ ├── moderation/ # Модерация (3 файла)
│ │ ├── BanCommand
│ │ ├── KickCommand
│ │ └── ClearCommand
│ ├── entertainment/ # Развлечения
│ │ ├── games/ # Игры (12 файлов)
│ │ └── social/ # Взаимодействия (11 файлов)
│ ├── utility/ # Утилиты (5 файлов)
│ │ ├── HelpCommand
│ │ ├── PingCommand
│ │ ├── InfoCommand
│ │ ├── AvatarCommand
│ │ └── PollCommand
│ └── system/ # Системные команды
│ └── MetricsCommand # (из utility/)
│
├── feature/ # Крупные фичи/домены
│ ├── level/ # Система уровней
│ │ ├── LevelSystem
│ │ ├── UserStats
│ │ ├── LevelUtils # (из profile/)
│ │ ├── RankCommand # (из command/stats/)
│ │ ├── StatsCommand # (из command/stats/)
│ │ ├── LevelUpNotifier # (из listener/)
│ │ └── VoiceTracker # (из listener/)
│ │
│ ├── profile/ # Профили пользователей
│ │ ├── ProfileService
│ │ ├── ProfileGenerator
│ │ ├── ProfileData
│ │ ├── ProfileCommand # (из command/utility/)
│ │ └── ProfileEmbedFactory # (из embed/)
│ │
│ ├── reputation/ # Система репутации
│ │ ├── ReputationService # (логика из RepCommand)
│ │ ├── RepCommand # (из command/stats/)
│ │ ├── MinusRepCommand # (из command/stats/)
│ │ └── RepTopCommand # (из command/stats/)
│ │
│ ├── leaderboard/ # Таблица лидеров
│ │ ├── LeaderboardCommand # (NewLeaderboardCommand)
│ │ ├── LeaderboardService # (логика из команды)
│ │ ├── LeaderboardFormatter
│ │ ├── LeaderboardButtons
│ │ └── LeaderboardButtonListener
│ │
│ ├── voice/ # Личные голосовые каналы
│ │ ├── VoiceChannelManager
│ │ ├── VoiceChannelData
│ │ ├── VoicePreset
│ │ ├── VoiceSetupCommand # (из command/setup/)
│ │ ├── VoiceChannelListener # (из listener/)
│ │ └── VoiceButtonHandler # (из listener/)
│ │
│ ├── counter/ # Счетчик участников
│ │ ├── CounterManager
│ │ ├── DailyStats
│ │ ├── CounterSetupCommand # (из command/setup/)
│ │ └── MemberCounterListener # (из listener/)
│ │
│ └── role/ # Кастомные роли
│ ├── CustomRoleManager
│ ├── CreateRoleCommand # (из command/roles/)
│ ├── DeleteRoleCommand # (из command/roles/)
│ ├── EditRoleCommand # (из command/roles/)
│ ├── MyRolesCommand # (из command/roles/)
│ └── RoleCommandValidator # (из command/roles/)
│
├── event/ # Обработчики событий Discord
│ ├── ReadyListener # (из listener/)
│ ├── MessageListener # (из listener/)
│ ├── SlashCommandListener # (из listener/)
│ ├── HelpMenuHandler # (из listener/)
│ └── ModerationLogger # (из listener/)
│
├── repository/ # Единый слой данных
│ ├── UserRepository # Интерфейс
│ ├── GuildConfigRepository # Интерфейс
│ └── impl/
│ ├── JsonUserRepository # (из data/)
│ └── SqliteConfigRepository # (из database/)
│
├── database/ # Инфраструктура БД
│ ├── Database
│ ├── DatabaseSchema
│ └── DatabaseMigration
│
├── integration/ # Внешние API
│ └── nekos/
│ └── NekosLifeApi # (из util/)
│
├── config/ # Конфигурация
│ ├── BotConfig
│ └── ConfigLoader
│
├── embed/ # Общие шаблоны embed
│ ├── EmbedFactory
│ └── EmbedTemplates
│
├── metrics/ # Метрики
│ └── MetricsCollector
│
└── di/ # Dependency Injection
└── BotModule
```
### План действий (приоритеты):
#### Высокий приоритет (делаем сейчас):
**1. Удалить ненужное**
- [x] Удалить `command/slash/` (дубликаты)
- [x] Удалить `audio/` (TTS не работает)
- [x] Удалить `TtsCommand.java`
- [ ] Удалить `SwapCommand.java`
- [ ] Удалить все импорты AudioManager
**2. Реорганизовать util/ (мусорная корзина)**
- [ ] Создать `core/security/`
- [ ] Переместить `CooldownManager` → `core/security/`
- [ ] Переместить `GlobalRateLimiter` → `core/security/`
- [ ] Создать `integration/nekos/`
- [ ] Переместить `NekosLifeApi` → `integration/nekos/`
- [ ] Удалить пустую папку `util/`
**3. Создать feature/level/ (система уровней)**
- [ ] Создать `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`
- [ ] Переместить `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/ (голосовые каналы)**
- [ ] Создать `feature/voice/`
- [ ] Переместить `voice/*` → `feature/voice/`
- [ ] Переместить `command/impl/setup/VoiceSetupCommand` → `feature/voice/`
- [ ] Переместить `listener/VoiceChannelListener` → `feature/voice/`
- [ ] Переместить `listener/VoiceButtonHandler` → `feature/voice/`
- [ ] Удалить пустую папку `voice/`
**5. Создать feature/counter/ (счетчик)**
- [ ] Создать `feature/counter/`
- [ ] Переместить `counter/*` → `feature/counter/`
- [ ] Переместить `command/impl/setup/CounterSetupCommand` → `feature/counter/`
- [ ] Переместить `listener/MemberCounterListener` → `feature/counter/`
- [ ] Удалить пустую папку `counter/`
**6. Создать feature/role/ (кастомные роли)**
- [ ] Создать `feature/role/`
- [ ] Переместить `role/CustomRoleManager` → `feature/role/`
- [ ] Переместить `command/impl/roles/*` → `feature/role/`
- [ ] Удалить пустые папки `role/` и `command/impl/roles/`
#### Средний приоритет (потом):
**7. Создать feature/reputation/**
- [ ] Создать `feature/reputation/`
- [ ] Создать `ReputationService` (вынести логику из команд)
- [ ] Переместить `command/impl/stats/RepCommand` → `feature/reputation/`
- [ ] Переместить `command/impl/stats/MinusRepCommand` → `feature/reputation/`
- [ ] Переместить `command/impl/stats/RepTopCommand` → `feature/reputation/`
**8. Создать feature/leaderboard/**
- [ ] Создать `feature/leaderboard/`
- [ ] Переместить `command/impl/stats/leaderboard/*` → `feature/leaderboard/`
- [ ] Создать `LeaderboardService`
- [ ] Удалить пустую папку `command/impl/stats/`
**9. Реорганизовать profile/**
- [ ] Создать `feature/profile/`
- [ ] Переместить `profile/*` → `feature/profile/`
- [ ] Переместить `command/impl/utility/ProfileCommand` → `feature/profile/`
- [ ] Создать `ProfileEmbedFactory` (вынести из команды)
- [ ] Удалить пустую папку `profile/`
**10. Реорганизовать event/ (listener)**
- [ ] Создать `event/`
- [ ] Переместить `listener/ReadyListener` → `event/`
- [ ] Переместить `listener/MessageListener` → `event/`
- [ ] Переместить `listener/SlashCommandListener` → `event/`
- [ ] Переместить `listener/HelpMenuHandler` → `event/`
- [ ] Переместить `listener/ModerationLogger` → `event/`
- [ ] Удалить пустую папку `listener/`
**11. Реорганизовать core/**
- [ ] Создать `core/registry/`
- [ ] Переместить `core/CommandRegistry` → `core/registry/`
- [ ] Переместить `core/SlashCommandRegistry` → `core/registry/`
- [ ] Переместить `core/PrefixCommandRegistrar` → `core/registry/`
- [ ] Переместить `core/SlashCommandRegistrar` → `core/registry/`
- [ ] Создать `core/exception/`
- [ ] Переместить `exception/CommandExceptionHandler` → `core/exception/`
- [ ] Переместить `exception/CommandException` → `command/`
- [ ] Удалить пустую папку `exception/`
**12. Реорганизовать command/**
- [ ] Переименовать `command/impl/entertainment/interaction/` → `command/entertainment/social/`
- [ ] Переместить `command/impl/utility/MetricsCommand` → `command/system/`
- [ ] Переместить `command/impl/setup/LogSetupCommand` → `event/` (или удалить setup/)
#### Низкий приоритет (опционально):
**13. Создать repository/ (единый слой данных)**
- [ ] Создать `repository/`
- [ ] Создать интерфейсы `UserRepository`, `GuildConfigRepository`
- [ ] Создать `repository/impl/`
- [ ] Рефакторить `data/JsonDataStore` → `repository/impl/`
- [ ] Рефакторить `database/ConfigRepository` → `repository/impl/`
**14. Обновить документацию**
- [ ] Обновить FEATURES.md (убрать TTS)
- [ ] Обновить README.md (новая структура)
- [ ] Добавить ARCHITECTURE.md (описание доменов)
---
## Основные задачи
### 1. ⚡ Переделать систему опыта (XP System Rework)