# 🔥 Критичные исправления для завершения этапов 1-6 **Приоритет:** ВЫСОКИЙ **Блокирует:** Компиляцию проекта (88 ошибок) --- ## 1. ❌ Исправить SoftDeleteMixin **Файл:** `lib/database/daos/mixins/soft_delete_mixin.dart` **Проблема:** Метод `table.companion()` не существует в Drift **Текущий код (строки 40-44):** ```dart .write( table.companion( isDeleted: const Value(true), deletedAt: Value(now), updatedAt: Value(now), ) as UpdateCompanion, ); ``` **Исправление:** Нужно создавать Companion вручную для каждой таблицы. SoftDeleteMixin не может быть универсальным для создания Companion. **Решение А (рекомендуемое):** Упростить миксин - убрать методы softDelete() и restore(), оставить только selectActive() и getActiveById() **Решение Б:** В каждом DAO реализовывать softDelete() вручную --- ## 2. ❌ Исправить WordStatisticsDao **Файл:** `lib/database/daos/word_statistics_dao.dart` ### Проблема 2.1: Метод update() конфликтует с базовым (строка 55) **Текущий код:** ```dart Future update({ required String id, required int correctAnswers, required int incorrectAnswers, required DateTime lastReviewed, }) async { ``` **Исправление:** Переименовать метод ```dart Future updateStatistics({ required String id, required int correctAnswers, required int incorrectAnswers, required DateTime lastReviewed, }) async { ``` ### Проблема 2.2: Неверные типы в create() (строки 42-45) **Текущий код:** ```dart correctAnswers: correctAnswers, incorrectAnswers: incorrectAnswers, mastery: mastery, lastReviewed: Value(lastReviewed), ``` **Исправление:** ```dart correctAnswers: Value(correctAnswers), incorrectAnswers: Value(incorrectAnswers), mastery: Value(mastery), lastReviewed: Value(PgDateTime(lastReviewed)), ``` ### Проблема 2.3: Ошибки в вызове update (строки 64-71) **Текущий код:** ```dart await (update(wordStatistics)..where((w) => w.id.equals(id))) .write( WordStatisticsCompanion( correctAnswers: Value(correctAnswers), incorrectAnswers: Value(incorrectAnswers), mastery: Value(mastery), lastReviewed: Value(lastReviewed), updatedAt: Value(DateTime.now()), ), ); ``` **Исправление:** ```dart await (update(wordStatistics)..where((w) => w.id.equals(id))) .write( WordStatisticsCompanion( correctAnswers: Value(correctAnswers), incorrectAnswers: Value(incorrectAnswers), mastery: Value(mastery), lastReviewed: Value(PgDateTime(lastReviewed)), updatedAt: Value(PgDateTime(DateTime.now())), ), ); ``` ### Проблема 2.4: Обновить вызовы метода update **Файл:** `lib/statistics/word_statistics_manager.dart` (строка 45) **Текущий код:** ```dart await _db.wordStatisticsDao.update( id: existing.id, correctAnswers: newCorrect, incorrectAnswers: newIncorrect, lastReviewed: DateTime.now(), ); ``` **Исправление:** ```dart await _db.wordStatisticsDao.updateStatistics( id: existing.id, correctAnswers: newCorrect, incorrectAnswers: newIncorrect, lastReviewed: DateTime.now(), ); ``` --- ## 3. ❌ Исправить AuditLogs.tableName **Файл:** `lib/database/tables/audit.dart` **Проблема:** tableName должен возвращать String?, а не Column **Текущий код (строка 21):** ```dart TextColumn get tableName => text()(); ``` **Исправление:** Переименовать поле, чтобы не конфликтовать с Table.tableName ```dart TextColumn get table => text()(); ``` **Также нужно обновить:** - `lib/database/daos/audit_dao.dart` - заменить `tableName` на `table` во всех местах --- ## 4. ❌ Удалить использование card.packId ### 4.1 Файл: `lib/api/v2/admin_cards_api_v2.dart` **Места использования:** - Строка 101: `'packId': card.packId,` - Строка 164: `'packId': card.packId,` - Строка 263: `'packId': card.packId ?? '',` - Строка 280: `packId: requestData['packId'],` - Строка 311: `'packId': card.packId,` **Решение:** 1. Для чтения packId: получить через JOIN с CardPackCards 2. Для записи packId: использовать CardPackCards.insert **Пример исправления (для чтения):** ```dart // Вместо: 'packId': card.packId, // Использовать: final packs = await _db.packDao.getPacksForCard(card.id); 'packId': packs.isNotEmpty ? packs.first.id : null, ``` **Нужно добавить метод в PackDao:** ```dart Future> getPacksForCard(String cardId) async { final query = select(cardPacks).join([ innerJoin( cardPackCards, cardPackCards.packId.equalsExp(cardPacks.id), ), ])..where(cardPackCards.cardId.equals(cardId)); final rows = await query.get(); return rows.map((row) => row.readTable(cardPacks)).toList(); } ``` ### 4.2 Файл: `lib/api/v2/telegram_bot_api_v2.dart` **Место использования:** - Строка 83: `'packId': card.packId,` **Исправление:** Аналогично - использовать JOIN через CardPackCards --- ## 5. ❌ Исправить DateTime → PgDateTime **Затронутые файлы (найдено анализатором):** 1. `lib/database/daos/discount_dao.dart:83` - updatedAt 2. `lib/database/daos/discount_dao.dart:110` - updatedAt 3. `lib/database/daos/promo_code_dao.dart:125` - updatedAt 4. `lib/database/daos/promo_code_dao.dart:135` - updatedAt 5. `lib/database/daos/test_dao.dart:99` - updatedAt 6. `lib/database/daos/user_dao.dart:210, 219, 230, 282, 300` - различные поля **Общее правило исправления:** ```dart // Было: updatedAt: Value(DateTime.now()), // Стало: updatedAt: Value(PgDateTime(DateTime.now())), ``` **Автоматизация:** Можно использовать поиск и замену: ``` Найти: Value\(DateTime\.now\(\)\) Заменить: Value(PgDateTime(DateTime.now())) ``` --- ## 6. ❌ Реализовать недостающие методы ### 6.1 UserDao.deleteToken() **Файл:** `lib/database/daos/user_dao.dart` **Использование:** - `lib/user/user_manager_drift.dart:51` - `lib/user/user_manager_drift.dart:72` **Добавить метод:** ```dart /// Удалить токен Future deleteToken(String token) async { await (delete(tokens)..where((t) => t.token.equals(token))).go(); } ``` ### 6.2 UserDao.deleteExpiredRefreshTokens() **Файл:** `lib/database/daos/user_dao.dart` **Использование:** - `lib/api/v2/jwt_service.dart:281` **Добавить метод:** ```dart /// Удалить истекшие refresh токены Future deleteExpiredRefreshTokens() async { final now = PgDateTime(DateTime.now()); await (delete(refreshTokens) ..where((rt) => rt.expiresAt.isSmallerThanValue(now)) ).go(); } ``` ### 6.3 DiscountDao.deleteCampaign() **Файл:** `lib/database/daos/discount_dao.dart` **Использование:** - `lib/discounts/discounts_manager.dart:161` **Добавить метод:** ```dart /// Удалить кампанию (soft delete) Future deleteCampaign(String campaignId) async { await (update(discountCampaigns) ..where((c) => c.id.equals(campaignId))) .write(DiscountCampaignsCompanion( isDeleted: const Value(true), deletedAt: Value(PgDateTime(DateTime.now())), updatedAt: Value(PgDateTime(DateTime.now())), )); } ``` ### 6.4 PaymentDao.countPaymentsByUserId() - дубликат **Файл:** `lib/database/daos/payment_dao.dart` **Проблема:** Метод определен дважды (строки 96 и 164) **Исправление:** Удалить одно из определений --- ## 7. ❌ Исправить card_pack_drift_extension.dart **Файл:** `lib/packs/card_pack_drift_extension.dart:86` **Проблема:** Используется несуществующий параметр `packId` в GameCardsCompanion **Текущий код:** ```dart packId: Value(pack.id), ``` **Исправление:** Удалить эту строку (packId больше нет в GameCards) --- ## Порядок выполнения исправлений ### Фаза 1: Простые исправления (30 минут) 1. ✅ Исправить AuditLogs.tableName → table 2. ✅ Исправить DateTime → PgDateTime (массовая замена) 3. ✅ Удалить дубликат метода в PaymentDao 4. ✅ Удалить packId из card_pack_drift_extension.dart ### Фаза 2: Методы DAO (30 минут) 5. ✅ Добавить deleteToken() в UserDao 6. ✅ Добавить deleteExpiredRefreshTokens() в UserDao 7. ✅ Добавить deleteCampaign() в DiscountDao ### Фаза 3: WordStatisticsDao (20 минут) 8. ✅ Переименовать update() → updateStatistics() 9. ✅ Исправить типы в create() 10. ✅ Обновить вызовы в WordStatisticsManager ### Фаза 4: SoftDeleteMixin (30 минут) 11. ✅ Упростить миксин (убрать softDelete и restore) 12. ✅ Или реализовать softDelete вручную в PaymentDao, StatisticsDao ### Фаза 5: card.packId (1 час) 13. ✅ Добавить getPacksForCard() в PackDao 14. ✅ Исправить admin_cards_api_v2.dart (5 мест) 15. ✅ Исправить telegram_bot_api_v2.dart (1 место) ### Фаза 6: Проверка (30 минут) 16. ✅ Запустить `dart analyze` 17. ✅ Запустить `dart run build_runner build` 18. ✅ Проверить что нет ошибок --- ## После исправлений После всех исправлений: 1. ✅ Запустить компиляцию: `dart analyze` 2. ✅ Убедиться что 0 ошибок 3. ✅ Запустить build_runner: `dart run build_runner build --delete-conflicting-outputs` 4. ✅ Проверить что backend запускается: `dart run bin/server.dart` 5. ✅ Запустить тесты: `dart test` Только после этого можно переходить к **Этапу 7: Тестирование**. --- ## Оценка времени - **Фаза 1-3 (простые):** ~1.5 часа - **Фаза 4-5 (сложные):** ~1.5 часа - **Фаза 6 (проверка):** ~0.5 часа **Итого:** ~3.5 часа работы После этого этапы 1-6 будут завершены на **100%**.