This commit is contained in:
Dmitry 2025-11-20 23:38:19 +03:00
parent 73055ccf2e
commit 185278c016
20 changed files with 55 additions and 10042 deletions

View file

@ -1,106 +0,0 @@
# Mnemo Cards Deployment Guide
This guide describes how to deploy the Mnemo Cards project (Backend + Web App) using the CI/CD scripts.
## Overview
The deployment strategy is designed to optimize resource usage:
- **Backend**: Built directly on the server (saves bandwidth, ensures environment compatibility).
- **Web App**: Built on the client (your machine), then static files are transferred to the server (saves server RAM).
## Prerequisites
1. **SSH Access**: You must have SSH access to the server `147.45.152.129` as `root`.
- Ensure your public SSH key is added to `~/.ssh/authorized_keys` on the server.
- You can verify access by running: `ssh root@147.45.152.129`
2. **Flutter Installed**: You need Flutter installed on your local machine to build the web app.
3. **Rsync**: Ensure `rsync` is installed on your local machine (usually pre-installed on macOS/Linux).
## Project Structure
- `deploy_all.sh`: Master script to trigger deployments.
- `mnemo_cards_web_v2/deploy.sh`: Script to build and deploy the web app.
- `tools/deploy/backend/deploy_remote.sh`: Script to trigger the backend build on the server.
- `tools/deploy/web-app/config.sh`: Configuration for web deployment (server IP, paths, ports).
## Forgejo CI/CD Setup
The project includes a workflow `.forgejo/workflows/deploy.yaml` to automate deployment via Forgejo Actions.
### Why SSH?
Even though Forgejo runs on the same server, the Actions runner usually executes jobs inside isolated Docker containers (like `ubuntu-latest`). To modify files or restart services on the **host** machine (the server itself), the runner needs to "break out" of the container. We use SSH for this because it's secure and standard.
### Secrets Configuration
To enable the workflow, go to your repository on Forgejo: **Settings -> Actions -> Secrets** and add the following:
| Secret Name | Value | Description |
|-------------|-------|-------------|
| `SSH_HOST` | `147.45.152.129` | The public IP of your server. |
| `SSH_USER` | `root` | The user to log in as (must have permissions to restart services). |
| `SSH_KEY` | *(Your Private Key)* | The content of your private SSH key (e.g., `~/.ssh/id_rsa`). |
> **Tip**: You can generate a new key pair specifically for CI/CD if you prefer not to use your personal one:
> `ssh-keygen -t ed25519 -C "ci-cd"`
> Then add the public key to `~/.ssh/authorized_keys` on the server.
### Runner Installation (Reference)
The Forgejo runner (`act_runner`) has been installed on the server to execute the workflows.
- **Service**: `act_runner.service`
- **User**: `root` (required for Docker/SSH access)
- **Config**: Registered with tag `ubuntu-latest` to match the workflow.
If you ever need to restart it:
```bash
systemctl restart act_runner
```
## How to Deploy
### Option 1: Via Forgejo UI (Recommended)
1. Go to your repository in Forgejo.
2. Click on the **Actions** tab.
3. Select **Deploy Mnemo Cards** from the left sidebar.
4. Click the **Run workflow** button (dropdown).
5. Select the branch (usually `master`) and click **Run workflow**.
### Option 2: Via Command Line (Manual)
If you want to run scripts manually without Forgejo Actions:
#### Full Deployment (Backend + Web)
To deploy both the backend and the web application, run:
```bash
./deploy_all.sh
```
### 2. Web Only Deployment
If you only made changes to the frontend:
```bash
./deploy_all.sh --web-only
```
### 3. Backend Only Deployment
If you only made changes to the backend:
```bash
./deploy_all.sh --backend-only
```
## Troubleshooting
- **Permission Denied (SSH)**: Check your SSH keys. Ensure you can login to `root@147.45.152.129` without a password prompt (using keys).
- **Build Failed (Web)**: Run `flutter doctor` to ensure your local environment is correct. Try running `flutter build web --release` manually in `mnemo_cards_web_v2` to see detailed errors.
- **Backend Not Restarting**: SSH into the server and check logs: `journalctl -u mnemo_cards_server -f`.
- **Port Conflicts**: The web app is configured to talk to the API on standard HTTPS port `443` via `https://api.mnemo-cards.online`. nginx handles SSL termination and proxies to backend on port `8081`.
## Configuration
To change server IP, ports, or paths, edit:
- `tools/deploy/web-app/config.sh`
- `tools/deploy/backend/deploy_remote.sh`

View file

@ -6,6 +6,8 @@ const _publicAuthPaths = {
'/auth/oauth/google', '/auth/oauth/google',
'/auth/oauth/telegram', '/auth/oauth/telegram',
'/auth/telegram/generate-code', // Bot endpoint for generating codes '/auth/telegram/generate-code', // Bot endpoint for generating codes
'/auth/telegram/web-code', // Web app endpoint for creating auth codes
'/auth/telegram/claim-code', // Bot endpoint for claiming web codes
'/auth/refresh', '/auth/refresh',
'/tests', '/tests',
'/test', '/test',
@ -46,6 +48,11 @@ Middleware authorizeV2(UserManager userManager, JwtService jwtService) {
// Auth endpoints in public list are accessible without token // Auth endpoints in public list are accessible without token
return await innerHandler(request); return await innerHandler(request);
} }
// Check for dynamic auth paths (e.g., /auth/telegram/code-status/<code>)
if (normalizedPath.startsWith('/auth/telegram/code-status/')) {
// Code status endpoint is public (used before authentication)
return await innerHandler(request);
}
} }
final isStrictAuthPath = final isStrictAuthPath =

View file

@ -1,87 +0,0 @@
# API v2 Migration Guide
## Status: In Progress
The web app is being migrated to use API v2 exclusively. API v2 provides:
- Standard OAuth2/JWT Bearer token authentication
- RESTful endpoint patterns
- Better error handling with standard HTTP status codes
- Token refresh mechanism
## Backend Implementation Status
### ✅ Completed
- [x] Created `AuthApiV2` with OAuth2 endpoints
- [x] Created `JwtService` for token generation/verification
- [x] Created `authorizeV2` middleware for Bearer token auth
- [x] Created `PacksApiV2` basic structure
- [x] Mounted v2 APIs at `/api/v2` path
- [x] Separated v1 and v2 authorization middleware
### ⚠️ Needs Completion
- [ ] Fix JwtService HMAC-SHA256 implementation (use proper crypto library)
- [ ] Complete PacksApiV2 endpoints implementation
- [ ] Implement TestsApiV2
- [ ] Implement GamesApiV2
- [ ] Implement PurchasesApiV2
- [ ] Implement SubscriptionsApiV2
- [ ] Implement PromocodesApiV2
- [ ] Add comprehensive error responses
- [ ] Add API documentation (OpenAPI/Swagger)
## Web App Implementation Status
### ✅ Completed
- [x] Created `ApiConfigV2` with all v2 endpoints
- [x] Created `HttpRepositoryV2` with Bearer token auth
- [x] Updated `StorageModule` to use HttpRepositoryV2
- [x] Updated `AuthService` to use HttpRepositoryV2
- [x] Updated dependency injection to use v2
### ⚠️ Needs Completion
- [x] Update `GamesManager` to use HttpRepositoryV2
- [x] Update `TestManager` to use HttpRepositoryV2
- [ ] Update `StatisticsService` to use HttpRepositoryV2
- [x] Update `SubscriptionService` to use HttpRepositoryV2
- [x] Update `PromocodeService` to use HttpRepositoryV2
- [ ] Update `PackProgressService` to use HttpRepositoryV2
- [ ] Write unit tests for HttpRepositoryV2
- [ ] Update integration tests
## Backend Endpoints
### Authentication (`/api/v2/auth`)
- `POST /api/v2/auth/oauth/google` - Google OAuth
- `POST /api/v2/auth/refresh` - Refresh access token
- `GET /api/v2/auth/me` - Get current user
- `POST /api/v2/auth/logout` - Logout
### Packs (`/api/v2/packs`)
- `GET /api/v2/packs` - List packs (with pagination)
- `GET /api/v2/packs/{packId}` - Get pack details
- `GET /api/v2/packs/{packId}/cards` - Get pack cards
- `GET /api/v2/packs/{packId}/cards/{cardId}/image` - Get card image
- `GET /api/v2/packs/{packId}/tests` - Get pack tests
### Tests (`/api/v2/tests`)
- `GET /api/v2/tests/{testId}` - Get test
- `POST /api/v2/tests/{testId}/results` - Submit results
- `GET /api/v2/tests/{testId}/history` - Get attempt history
## Migration Steps
1. **Backend**: Complete JWT implementation and all v2 endpoints
2. **Web App**: Update all services to use HttpRepositoryV2
3. **Testing**: Write comprehensive tests for v2 endpoints
4. **Deployment**: Deploy backend v2 endpoints
5. **Verification**: Test end-to-end with web app
6. **Deprecation**: Mark v1 APIs as deprecated (keep for mobile app)
## Next Steps
1. Fix JWT service to use proper crypto library
2. Complete backend v2 endpoint implementations
3. Update web app services to use HttpRepositoryV2 methods
4. Write tests
5. Deploy and verify

View file

@ -1,318 +0,0 @@
# План реализации чата в mnemo_cards_web_v2
## 📋 Обзор
Добавление функциональности чата для общения пользователя с LLM через сервер. Поддержка текста и аудио сообщений (включая голосовые).
**Дата создания:** November 8, 2025
**Приоритет:** HIGH
**Оценка времени:** 60-80 часов
**Архитектура:** Clean Architecture, yx_scope/yx_state
---
## 🎯 Цели проекта
1. **Чат с LLM** - Общение пользователя с ИИ через сервер
2. **Поддержка медиа** - Текст и аудио (включая голосовые сообщения)
3. **Чистая архитектура** - Соблюдение паттернов проекта
4. **Адаптивный UI** - Работа на всех устройствах
5. **Реактивное состояние** - State management через yx_state
---
## 📁 Архитектурный обзор
### Clean Architecture слои:
```
├── domain/
│ ├── models/ # ChatMessage, AudioMessage, ChatSession
│ ├── services/ # ChatService, AudioService
│ └── state/ # ChatStateManager
├── presentation/
│ ├── pages/ # ChatPage
│ └── widgets/ # MessageBubble, AudioPlayer, etc.
└── di/
└── user_scope/
└── modules/ # ChatModule
```
---
## 📋 Детальный план реализации
### Фаза 1: Инфраструктура и модели данных (12-16 часов)
#### 1.1 Модели данных (4-6 часов)
- **ChatMessage** - Базовое сообщение чата
- **AudioMessage** - Аудио сообщение с метаданными
- **ChatSession** - Сессия чата
- **ChatParticipant** - Участник (пользователь/ассистент)
- **MessageStatus** - Статусы сообщений (отправлено, доставлено, ошибка)
#### 1.2 HTTP интеграция (4-6 часов)
- Расширение `HttpRepositoryV2` методами чата:
- `POST /api/v2/chat/messages` - Отправка текстового сообщения
- `POST /api/v2/chat/audio` - Отправка аудио сообщения
- `GET /api/v2/chat/messages/{sessionId}` - Получение истории
- `POST /api/v2/chat/sessions` - Создание сессии
- Обработка ошибок и таймаутов
#### 1.3 State management (4-4 часов)
- **ChatStateManager** - Управление состоянием чата
- Состояния: loading, loaded, error
- Реактивные обновления сообщений
- Управление активной сессией
### Фаза 2: Сервисы и бизнес-логика (16-20 часов)
#### 2.1 ChatService (6-8 часов)
- Отправка текстовых сообщений
- Получение ответов от LLM
- Управление сессиями чата
- Кэширование сообщений
- Обработка ошибок сети
#### 2.2 AudioService (6-8 часов)
- Запись аудио через Web Audio API
- Воспроизведение аудио сообщений
- Конвертация форматов (WebM/WAV → подходящий для сервера)
- Управление микрофоном (разрешения, состояние)
- Обработка голосовых команд
#### 2.3 DI интеграция (4-4 часов)
- **ChatModule** - Модуль для UserScope
- Регистрация сервисов в контейнере
- Зависимости: HttpRepositoryV2, AudioService
### Фаза 3: UI компоненты (20-24 часов)
#### 3.1 Базовые компоненты чата (8-10 часов)
- **MessageBubble** - Пузырь сообщения (текст/аудио)
- **MessageList** - Список сообщений с виртуализацией
- **ChatInput** - Поле ввода с прикреплением файлов
- **AudioRecorder** - Кнопка записи голосовых сообщений
- **AudioPlayer** - Воспроизведение аудио сообщений
#### 3.2 ChatPage (8-10 часов)
- Основная страница чата
- AppBar с информацией о сессии
- Сообщения + input внизу
- Обработка состояний загрузки/ошибок
- Адаптивный layout (мобильный/десктоп)
#### 3.3 Навигация и роутинг (4-4 часов)
- Добавление маршрута `/chat` в AppRouter
- Кнопка чата в bottom navigation или sidebar
- Переход к чату из других страниц
### Фаза 4: Аудио функциональность (8-12 часов)
#### 4.1 Запись аудио (4-6 часов)
- Web Audio API интеграция
- MediaRecorder для захвата
- Визуализация уровня звука
- Обработка разрешений микрофона
- Отправка на сервер
#### 4.2 Воспроизведение аудио (4-6 часов)
- HTML5 Audio для воспроизведения
- Кастомные контролы (play/pause/progress)
- Обработка ошибок загрузки
- Кэширование аудио файлов
### Фаза 5: Интеграция и полировка (8-12 часов)
#### 5.1 Backend endpoints (4-6 часов)
- Реализация серверных эндпоинтов
- Интеграция с LLM API
- Обработка аудио файлов
- Хранение истории чата
#### 5.2 Тестирование и QA (4-6 часов)
- Unit тесты для всех сервисов
- Widget тесты для UI компонентов
- Интеграционные тесты
- Тестирование аудио функциональности
- Кросс-браузерная совместимость
---
## 🔧 Технические решения
### Аудио обработка
```dart
// Web Audio API для записи
final stream = await navigator.mediaDevices.getUserMedia({'audio': true});
final recorder = MediaRecorder(stream);
// Конвертация для отправки
final audioBlob = await recorder.stop();
final audioFile = File.fromRawPath(audioBlob);
```
### State management
```dart
@freezed
class ChatState with _$ChatState {
const factory ChatState.loading() = ChatStateLoading;
const factory ChatState.loaded({
required List<ChatMessage> messages,
required ChatSession session,
}) = ChatStateLoaded;
const factory ChatState.error(String message) = ChatStateError;
}
```
### HTTP интеграция
```dart
// Отправка сообщения
final response = await _httpRepository.sendMessage(
sessionId: session.id,
content: message.text,
type: MessageType.text,
);
// Получение ответа
final llmResponse = ChatMessage.fromJson(response.data);
```
---
## 📱 UI/UX требования
### Адаптивный дизайн
- **Мобильный**: Полноэкранный чат, клавиатура поверх
- **Десктоп**: Sidebar или отдельное окно
- **Планшет**: Оптимизированный layout
### Аудио UX
- Визуальная обратная связь при записи
- Волновая форма для аудио сообщений
- Длительность и размер файла
- Возможность отмены записи
### Сообщения
- Разные стили для пользователя/ассистента
- Статусы доставки
- Тайминги сообщений
- Поддержка markdown в ответах LLM
---
## 🧪 Тестирование
### Unit тесты
- ChatService: отправка/получение сообщений
- AudioService: запись/воспроизведение
- ChatStateManager: state transitions
- Модели: сериализация/десериализация
### Widget тесты
- MessageBubble: рендеринг разных типов
- ChatInput: ввод текста и аудио
- MessageList: виртуализация и скролл
### Интеграционные тесты
- Полный флоу отправки сообщения
- Аудио запись и отправка
- Обработка ошибок сети
---
## 🚀 Roadmap реализации
### Неделя 1-2: Фаза 1 (Инфраструктура)
- День 1-2: Модели данных
- День 3-4: HTTP интеграция
- День 5: State management
- День 6-7: DI и модули
### Неделя 3-4: Фаза 2 (Сервисы)
- День 8-10: ChatService
- День 11-13: AudioService
- День 14: Интеграция сервисов
### Неделя 5-6: Фаза 3 (UI)
- День 15-18: UI компоненты
- День 19-21: ChatPage
- День 22: Навигация
### Неделя 7-8: Фаза 4-5 (Аудио + Полировка)
- День 23-25: Аудио функциональность
- День 26-28: Backend интеграция
- День 29-30: Тестирование
- День 31-32: Финальная полировка
---
## 📊 Критерии приемки
### Функциональные требования
- ✅ Отправка текстовых сообщений
- ✅ Получение ответов от LLM
- ✅ Запись голосовых сообщений
- ✅ Воспроизведение аудио ответов
- ✅ История сообщений сохраняется
- ✅ Обработка ошибок сети
### Нефункциональные требования
- ✅ Адаптивный дизайн (мобильный/десктоп)
- ✅ Производительность (виртуализация списка)
- ✅ Доступность (WCAG 2.1 AA)
- ✅ Безопасность (HTTPS, валидация данных)
### Качество кода
- ✅ 80%+ тестового покрытия
- ✅ Соблюдение clean architecture
- ✅ Type-safe код (freezed)
- ✅ Документация всех публичных API
---
## 🔄 Зависимости и риски
### Внешние зависимости
- **Backend API**: Эндпоинты чата должны быть готовы
- **LLM интеграция**: Доступ к модели ИИ
- **Web Audio API**: Поддержка в целевых браузерах
### Технические риски
- **Аудио совместимость**: Разные браузеры поддерживают разные кодеки
- **Производительность**: Большие аудио файлы
- **Сетевая надежность**: Обработка обрывов соединения
### МитIGATION стратегии
- Progressive enhancement для аудио
- Offline-first подход для сообщений
- Graceful degradation при ошибках
---
## 📈 Метрики успеха
### Технические метрики
- **Время ответа**: <2s для текстовых сообщений
- **Аудио качество**: 128kbps минимум
- **Test coverage**: >80%
- **Bundle size**: <500KB дополнительно
### Пользовательские метрики
- **Сообщения/сессия**: Среднее количество сообщений
- **Время сессии**: Среднее время использования чата
- **Аудио использование**: Процент голосовых сообщений
---
## 📋 Следующие шаги
1. **Создать todo-список** для фазы 1
2. **Начать с моделей данных** (ChatMessage, AudioMessage)
3. **Реализовать HTTP интеграцию** в HttpRepositoryV2
4. **Создать ChatStateManager** с базовым состоянием
5. **Написать unit тесты** для первых компонентов
---
**Статус плана:** ✅ Готов к реализации
**Следующий шаг:** Создание todo-списка и начало фазы 1

View file

@ -1,137 +0,0 @@
# Решение CORS Error
## Что такое CORS?
CORS (Cross-Origin Resource Sharing) - это механизм безопасности браузера, который блокирует запросы между разными доменами/портами.
## Проблема
При разработке:
- **Frontend** (Flutter Web) работает на `http://localhost:xxxxx` (случайный порт)
- **Backend** работает на `http://localhost:8000`
- Браузер блокирует запросы между этими портами
## Решение
### 1. ✅ Backend настроен (исправлено 19 окт 2025)
В файле `mnemo_cards_backend/lib/api/mnemo_shelf.dart` добавлена правильная CORS конфигурация:
```dart
final corsConfig = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS',
'Access-Control-Allow-Headers': 'Origin, Content-Type, Accept, Authorization, user_token, request_token, app_version',
'Access-Control-Expose-Headers': 'Authorization',
'Access-Control-Max-Age': '86400',
};
```
**⚠️ ВАЖНО:** CORS middleware должен быть **ПЕРВЫМ** в pipeline, иначе preflight запросы (OPTIONS) будут блокироваться авторизацией:
```dart
final handler = Pipeline()
.addMiddleware(corsHeaders(headers: corsConfig)) // ← CORS ПЕРВЫМ!
.addMiddleware(logRequests(logger: logger('app')))
.addMiddleware(appAuthorize(getIt.get<UserManager>()))
.addHandler(rootRouter);
```
Это позволяет:
- ✅ Принимать запросы с любого origin (`*`)
- ✅ Разрешает все необходимые HTTP методы
- ✅ Разрешает кастомные заголовки (`user_token`, `request_token`, `app_version`)
- ✅ Разрешает читать заголовок `Authorization` в ответе
- ✅ OPTIONS запросы обрабатываются до проверки авторизации
### 2. 🚀 Запуск Backend
Используйте скрипт для запуска backend в режиме разработки:
```bash
cd /Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_backend
./run_dev.sh
```
Backend будет доступен на `http://localhost:8000`
### 3. 🌐 Запуск Frontend
В отдельном терминале запустите веб-версию:
```bash
cd /Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_web_v2
flutter run -d chrome
```
### 4. ✔️ Проверка
После запуска обоих сервисов:
1. Откройте DevTools в Chrome (F12)
2. Перейдите на вкладку Network
3. Проверьте что запросы к `/packs/previews`, `/games` и т.д. успешны
4. В заголовках ответа должны быть CORS заголовки
## Альтернативные решения (если не помогло)
### Вариант 1: Отключить web security в Chrome (только для разработки!)
```bash
# macOS
open -n -a "Google Chrome" --args --user-data-dir="/tmp/chrome_dev_session" --disable-web-security
# Linux
google-chrome --disable-web-security --user-data-dir="/tmp/chrome_dev_session"
```
⚠️ **Внимание**: Это небезопасно! Используйте только для разработки.
### Вариант 2: Использовать Flutter с --web-port
Запускайте Flutter на фиксированном порту:
```bash
flutter run -d chrome --web-port=8080
```
### Вариант 3: Production CORS (для деплоя)
Для production версии:
1. **Backend** уже настроен с правильными CORS настройками ✅
2. **Frontend** использует `https://api.mnemo-cards.online` (nginx:443) ✅
3. **Nginx** настроен без конфликтующих COEP/COOP headers ✅
Текущая конфигурация позволяет:
- ✅ Запросы с `mnemo-cards.online` на `https://api.mnemo-cards.online`
- ✅ Все необходимые HTTP методы и headers
- ✅ Preflight OPTIONS запросы
## Диагностика
Если CORS ошибка все еще возникает:
1. **Проверьте что backend запущен**:
```bash
curl http://localhost:8000/games
```
2. **Проверьте CORS заголовки**:
```bash
curl -H "Origin: http://localhost:8080" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS --verbose http://localhost:8000/games
```
3. **Посмотрите логи backend** - там будут видны все входящие запросы
4. **Проверьте что ApiConfig использует правильный URL**:
```dart
// В lib/domain/config/api_config.dart
static const String baseUrl = 'http://localhost:8000';
```
## Полезные ссылки
- [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
- [shelf_cors_headers package](https://pub.dev/packages/shelf_cors_headers)
- [Flutter Web: CORS](https://docs.flutter.dev/platform-integration/web/building#handling-cors-errors-only-applicable-to-web)

View file

@ -1,601 +0,0 @@
# План адаптации дизайна веб-приложения mnemo_cards_web_v2
**Цель**: Адаптировать дизайн веб-приложения `mnemo_cards_web_v2`, чтобы он был визуально похож на мобильное приложение `mnemo_cards`.
**Дата создания**: 19 октября 2025
**Статус**: План
---
## 📊 Анализ текущего состояния
### Мобильное приложение (mnemo_cards)
**Ключевые особенности дизайна:**
1. **Цветовая схема**:
- Черно-белая основа (black/white primary)
- Кастомные акцентные цвета: peach, golden, green
- Специальные цвета: progressBlue, menuBlue, backgroundBlue, borderGray
- Использует MaterialColor для создания палитр
2. **Типографика**:
- Шрифт: `Nunito`
- Все тексты жирные: `FontWeight.w700` для всех стилей
- Использует flutter_screenutil для адаптивных размеров
3. **Карточки паков**:
- Горизонтальная компоновка (Row)
- Изображение слева (квадратное, равно высоте карточки)
- Информация справа (title, subtitle, количество карточек)
- Граница с цветом пака (`border: Border.all(color: pack.color)`)
- Скругленные углы (12.0)
- Прозрачный фон карточки
- Высота: ~110.h
4. **UI компоненты**:
- RefreshIndicator с кастомным цветом
- Простые границы и минималистичный дизайн
- Иконки из webp файлов
- Loading состояния с изображениями (cerdo/luna)
5. **Профиль**:
- UserStatistics виджет со списком слов
- Прогресс-бары для каждого слова
- SimpleTile компоненты с Divider'ами
- Золотой цвет для выученных слов
### Веб-приложение (mnemo_cards_web_v2)
**Текущий дизайн:**
1. **Цветовая схема**:
- Material 3 с синим seedColor
- Стандартная палитра Material
- Отсутствуют кастомные акцентные цвета
2. **Типографика**:
- Шрифт: `Nunito`
- Стандартные весы шрифтов Material
3. **Карточки паков**:
- Вертикальная компоновка (Column)
- Изображение сверху (AspectRatio 16:9)
- Информация снизу
- Стандартные Material Card с elevation
- Hero анимация ✅
4. **UI компоненты**:
- Material 3 компоненты
- Shimmer loading states ✅
- Современный responsive дизайн ✅
5. **Профиль**:
- Продвинутый дизайн со статистикой
- StatsCard компоненты
- SimpleChart для графиков
- Settings card с темной темой
---
## 🎯 Этапы адаптации
### Этап 1: Обновление цветовой схемы и темизации
**Приоритет**: 🔴 Высокий
**Время**: 2-3 часа
**Сложность**: Средняя
#### Задачи:
1. **Создать файл с цветовыми константами** (`lib/presentation/theme/app_colors.dart`):
```dart
// Точные цвета из мобильного приложения
const Color peach = Color(0xffffc994);
const Color golden = Color(0xffffea00);
const Color green = Color(0xff3d5309);
const Color greenAccent = Color(0xff688d11);
const Color black = Color(0xff000000);
const Color white = Color(0xffffffff);
const Color progressBlue = Color(0xff8CCBFF);
const Color menuBlue = Color(0xff99C4E9);
const Color backgroundBlue = Color(0xFFf0f0f0);
const Color testBlue = Color(0xffD0EAFF);
const Color borderGray = Color(0xffABABAB);
```
2. **Обновить `app_theme.dart`**:
- Изменить ColorScheme на черно-белую основу
- Светлая тема:
- primary: MaterialColor(0xFF000000, colorMap)
- surface: white
- onSurface: black
- secondary: green
- Темная тема:
- primary: MaterialColor(0xFFFFFFFF, whiteColorMap)
- surface: black
- onSurface: white
- secondary: lightBlue
3. **Обновить TextTheme**:
- Установить `FontWeight.w700` для всех стилей текста
- Сохранить Nunito шрифт
4. **Обновить компонентные темы**:
- AppBarTheme: иконки с primary цветом
- CardTheme: скругление 12.0, минимальная elevation
- ButtonTheme: жирные тексты
**Файлы для изменения**:
- ✏️ `lib/presentation/theme/app_theme.dart`
- `lib/presentation/theme/app_colors.dart`
---
### Этап 2: Адаптация карточек паков (PackCard)
**Приоритет**: 🔴 Высокий
**Время**: 3-4 часа
**Сложность**: Высокая
#### Задачи:
1. **Изменить компоновку PackCard на горизонтальную**:
- Изменить Column на Row
- Левая часть: квадратное изображение (height = width)
- Правая часть: информация о паке
2. **Обновить стиль карточки**:
- Удалить elevation из Card
- Добавить Border.all с цветом пака
- Сделать фон прозрачным или белым
- Скругление: 12.0
3. **Добавить парсинг цвета пака**:
- Использовать `pack.color?.asColor` из мобильного приложения
- Создать extension для ColorDto
4. **Обновить информацию в карточке**:
- Жирный большой заголовок
- Subtitle светлее
- Иконка карточек с количеством
- Индикатор загрузки (опционально)
5. **Адаптировать высоту**:
- Фиксированная высота ~110-120px
- Квадратное изображение слева
**Файлы для изменения**:
- ✏️ `lib/presentation/widgets/pack_card.dart`
- `lib/utils/color_extension.dart` (для парсинга цветов)
**Визуальный пример**:
```
┌─────────────────────────────────────────┐
│ ┌─────┐ │
│ │ │ Pack Title (bold, large) │
│ │ IMG │ Pack Subtitle (light) │
│ │ │ 🃏 42 cards │
│ └─────┘ │
└─────────────────────────────────────────┘
```
---
### Этап 3: Адаптация HomePage (список паков)
**Приоритет**: 🟡 Средний
**Время**: 2 часа
**Сложность**: Низкая
#### Задачи:
1. **Изменить layout с GridView на ListView**:
- Вертикальный список карточек
- Padding: 8.0
2. **Обновить RefreshIndicator**:
- Кастомные цвета (использовать цвет первого пака или primary)
- displacement: 20
3. **Обновить Loading состояние**:
- Опционально: добавить изображение (cerdo/luna) вместо shimmer
- Или оставить shimmer, но адаптировать под горизонтальную карточку
4. **Обновить Search bar**:
- Сделать более минималистичным
- Убрать излишнюю стилизацию
**Файлы для изменения**:
- ✏️ `lib/presentation/pages/home/home_page.dart`
- ✏️ `lib/presentation/widgets/loading/pack_card_shimmer.dart`
---
### Этап 4: Адаптация GamesPage и GameCard
**Приоритет**: 🟡 Средний
**Время**: 2-3 часа
**Сложность**: Средняя
#### Задачи:
1. **Обновить GameCard под стиль мобильного**:
- Возможно также сделать горизонтальную компоновку
- Или оставить вертикальную, но обновить стили
- Добавить границы с цветом игры
- Использовать кастомные цвета
2. **Обновить GamesPage**:
- Изменить layout (Grid или List в зависимости от выбора)
- Обновить RefreshIndicator
- Адаптировать Loading состояния
3. **Обновить shimmer для GameCard**
**Файлы для изменения**:
- ✏️ `lib/presentation/widgets/game_card.dart`
- ✏️ `lib/presentation/pages/games/games_page.dart`
- ✏️ `lib/presentation/widgets/loading/game_card_shimmer.dart`
---
### Этап 5: Адаптация ProfilePage
**Приоритет**: 🟢 Низкий
**Время**: 3-4 часа
**Сложность**: Средняя
#### Задачи:
1. **Упростить дизайн профиля**:
- Убрать или упростить статистические карточки
- Добавить UserStatistics компонент (или его аналог)
- Использовать SimpleTile стиль с Divider'ами
2. **Обновить статистику**:
- Показывать список изученных слов с прогрессом
- Использовать HorizontalProgressWidget
- Золотой цвет для выученных слов
3. **Обновить Settings секцию**:
- Более простой стиль с dividers
- Минималистичные иконки
4. **Обновить logout кнопку**:
- Более простой стиль
**Файлы для изменения**:
- ✏️ `lib/presentation/pages/profile/profile_page.dart`
- ✏️ `lib/presentation/widgets/stats_card.dart` (упростить или удалить)
- `lib/presentation/widgets/simple_tile.dart` (создать)
- `lib/presentation/widgets/horizontal_progress.dart` (создать)
---
### Этап 6: Адаптация PackDetailsPage
**Приоритет**: 🟢 Низкий
**Время**: 2 часа
**Сложность**: Низкая
#### Задачи:
1. **Упростить дизайн деталей пака**:
- Убрать излишнюю стилизацию
- Использовать границы вместо elevation
- Адаптировать под минималистичный стиль
2. **Обновить список карточек**:
- Более простой стиль ListTile
- Границы вместо карточек
**Файлы для изменения**:
- ✏️ `lib/presentation/pages/pack_details/pack_details_page.dart`
---
### Этап 7: Адаптация общих компонентов
**Приоритет**: 🟡 Средний
**Время**: 2-3 часа
**Сложность**: Низкая
#### Задачи:
1. **Обновить MainShell** (нижняя навигация):
- Адаптировать стили под новую тему
- Проверить цвета иконок
2. **Обновить AuthPage**:
- Упростить дизайн кнопок
- Использовать новую цветовую схему
3. **Обновить ErrorView и LoadingView**:
- Адаптировать под новую тему
- Опционально: добавить кастомные изображения для ошибок
4. **Создать общие утилиты**:
- ColorExtension для парсинга ColorDto
- Дополнительные helper'ы
**Файлы для изменения**:
- ✏️ `lib/presentation/widgets/main_shell.dart`
- ✏️ `lib/presentation/pages/auth/auth_page.dart`
- ✏️ `lib/presentation/widgets/error_view.dart`
- ✏️ `lib/presentation/widgets/loading_view.dart`
- `lib/utils/color_extension.dart`
---
### Этап 8: Адаптация для responsive дизайна
**Приоритет**: 🟢 Низкий
**Время**: 2-3 часа
**Сложность**: Средняя
#### Задачи:
1. **Обновить Responsive утилиты**:
- Адаптировать под новые размеры карточек
- Убедиться, что горизонтальные карточки хорошо смотрятся на разных экранах
2. **Тестирование на разных разрешениях**:
- Mobile (узкий экран)
- Tablet (средний экран)
- Desktop (широкий экран)
3. **Адаптация максимальной ширины контента**:
- Убедиться, что карточки не слишком широкие на больших экранах
**Файлы для изменения**:
- ✏️ `lib/utils/responsive.dart`
- ✏️ Все страницы с использованием responsive логики
---
### Этап 9: Финальная полировка и тестирование
**Приоритет**: 🔴 Высокий
**Время**: 2-3 часа
**Сложность**: Низкая
#### Задачи:
1. **Проверка консистентности**:
- Все цвета соответствуют мобильному приложению
- Все шрифты жирные где нужно
- Все границы используют правильные цвета
2. **Темная тема**:
- Проверить, что темная тема работает корректно
- Адаптировать все компоненты под темную тему
3. **Accessibility**:
- Проверить контрастность цветов
- Обновить Semantics labels если нужно
4. **Тестирование**:
- Визуальное тестирование всех экранов
- Проверка анимаций и переходов
- Unit тесты для новых компонентов
5. **Документация**:
- Обновить README с информацией о дизайне
- Создать DESIGN_GUIDE.md с примерами компонентов
**Файлы для проверки**:
- Все обновленные файлы
- Тесты
---
## 📁 Структура новых файлов
```
lib/
├── presentation/
│ ├── theme/
│ │ ├── app_theme.dart ✏️ Обновить
│ │ └── app_colors.dart Создать
│ ├── widgets/
│ │ ├── pack_card.dart ✏️ Полностью переделать
│ │ ├── game_card.dart ✏️ Обновить
│ │ ├── simple_tile.dart Создать
│ │ ├── horizontal_progress.dart Создать
│ │ └── loading/
│ │ ├── pack_card_shimmer.dart ✏️ Обновить под горизонтальную карточку
│ │ └── game_card_shimmer.dart ✏️ Обновить
│ └── pages/
│ ├── home/
│ │ └── home_page.dart ✏️ Изменить layout
│ ├── games/
│ │ └── games_page.dart ✏️ Обновить стили
│ ├── profile/
│ │ └── profile_page.dart ✏️ Упростить дизайн
│ └── pack_details/
│ └── pack_details_page.dart ✏️ Упростить
├── utils/
│ └── color_extension.dart Создать
└── assets/ Опционально
└── images/
├── cerdo.webp Копировать из мобильного
└── luna.webp Копировать из мобильного
```
---
## 🎨 Ключевые изменения дизайна
### До и После:
#### 1. Цветовая схема
**До**: Material 3 синяя палитра
**После**: Черно-белая основа с акцентными цветами (golden, green, peach)
#### 2. Карточки паков
**До**: Вертикальные карточки с изображением 16:9 сверху
**После**: Горизонтальные карточки с квадратным изображением слева и границей цвета пака
#### 3. Типографика
**До**: Стандартные веса шрифтов Material
**После**: Все тексты жирные (FontWeight.w700)
#### 4. UI компоненты
**До**: Material 3 elevation, стандартные карточки
**После**: Минималистичный дизайн с границами, без elevation
#### 5. Профиль
**До**: Продвинутая статистика с графиками и карточками
**После**: Простой список слов с прогрессом, SimpleTile компоненты
---
## ⚠️ Важные замечания
1. **Сохранить функциональность**:
- Все существующие функции должны работать
- Hero анимации сохранить
- RefreshIndicator сохранить
2. **Responsive дизайн**:
- Убедиться, что горизонтальные карточки хорошо смотрятся на всех экранах
- На очень узких экранах возможно нужно адаптировать размеры
3. **Тестирование**:
- Обновить тесты для новых компонентов
- Проверить, что старые тесты проходят
4. **Темная тема**:
- Особое внимание к темной теме
- Проверить контрастность
5. **Assets**:
- Возможно понадобится скопировать иконки из мобильного приложения
- Добавить cerdo.webp и luna.webp для loading состояний
---
## 📊 Приоритизация этапов
### Критический путь (начать с этого):
1. **Этап 1**: Цветовая схема и темизация
2. **Этап 2**: Адаптация PackCard (самое заметное изменение)
3. **Этап 3**: Адаптация HomePage
### Средний приоритет:
4. **Этап 4**: GamesPage и GameCard
5. **Этап 7**: Общие компоненты
6. **Этап 5**: ProfilePage
### Низкий приоритет (можно отложить):
7. **Этап 6**: PackDetailsPage
8. **Этап 8**: Responsive адаптация
9. **Этап 9**: Финальная полировка
---
## 🚀 Порядок выполнения
### День 1 (4-5 часов):
- Этап 1: Цветовая схема (2-3 часа)
- Этап 2: PackCard начать (2 часа)
### День 2 (4-5 часов):
- Этап 2: PackCard завершить (2 часа)
- Этап 3: HomePage (2 часа)
- Тестирование (1 час)
### День 3 (4-5 часов):
- Этап 4: GamesPage (2-3 часа)
- Этап 7: Общие компоненты (2 часа)
### День 4 (3-4 часа):
- Этап 5: ProfilePage (3 часа)
- Этап 6: PackDetailsPage (1 час)
### День 5 (2-3 часа):
- Этап 8: Responsive (2 часа)
- Этап 9: Финальная полировка (1 час)
**Общее время**: 17-22 часа работы
---
## 📝 Чек-лист выполнения
### Этап 1: Цветовая схема
- [ ] Создан app_colors.dart с константами
- [ ] Обновлен app_theme.dart (светлая тема)
- [ ] Обновлен app_theme.dart (темная тема)
- [ ] Все тексты жирные (FontWeight.w700)
- [ ] Проверено на обоих темах
### Этап 2: PackCard
- [ ] Изменена компоновка на горизонтальную
- [ ] Добавлена граница с цветом пака
- [ ] Создан ColorExtension для парсинга
- [ ] Обновлена информация в карточке
- [ ] Hero анимация работает
### Этап 3: HomePage
- [ ] Изменен GridView на ListView
- [ ] Обновлен RefreshIndicator
- [ ] Обновлен PackCardShimmer
- [ ] Проверена прокрутка и загрузка
### Этап 4: GamesPage
- [ ] Обновлен GameCard
- [ ] Обновлен GamesPage layout
- [ ] Обновлен GameCardShimmer
- [ ] Проверена функциональность
### Этап 5: ProfilePage
- [ ] Упрощен дизайн
- [ ] Создан SimpleTile компонент
- [ ] Создан HorizontalProgress (опционально)
- [ ] Обновлена статистика
### Этап 6: PackDetailsPage
- [ ] Упрощен дизайн
- [ ] Обновлен список карточек
- [ ] Проверена функциональность
### Этап 7: Общие компоненты
- [ ] Обновлен MainShell
- [ ] Обновлен AuthPage
- [ ] Обновлены ErrorView/LoadingView
- [ ] Созданы утилиты
### Этап 8: Responsive
- [ ] Проверено на mobile
- [ ] Проверено на tablet
- [ ] Проверено на desktop
- [ ] Адаптированы размеры
### Этап 9: Финальная полировка
- [ ] Проверена консистентность
- [ ] Проверена темная тема
- [ ] Проверена accessibility
- [ ] Все тесты проходят
- [ ] Обновлена документация
---
## 🎯 Ожидаемый результат
После выполнения всех этапов веб-приложение `mnemo_cards_web_v2` будет визуально похоже на мобильное приложение `mnemo_cards`:
- ✅ Идентичная цветовая схема (черно-белая с акцентами)
- ✅ Жирные шрифты Nunito
- ✅ Горизонтальные карточки паков с границами
- ✅ Минималистичный дизайн без лишних elevation
- ✅ Упрощенный профиль со статистикой
- ✅ Консистентный UI на всех экранах
- ✅ Работающая темная тема
- ✅ Сохраненная функциональность (авторизация, навигация, загрузка данных)
---
**Автор плана**: AI Assistant
**Дата**: 19 октября 2025
**Версия**: 1.0

View file

@ -1,233 +0,0 @@
# Прогресс адаптации дизайна
**Дата**: 19 октября 2025
**Статус**: В процессе
---
## ✅ Выполнено
### 🎨 Этап 1: Цветовая схема и темизация (ЗАВЕРШЕНО)
**Создано:**
- ✅ `lib/presentation/theme/app_colors.dart` - цветовые константы из мобильного приложения
- Peach, golden, green, progressBlue, borderGray и др.
- MaterialColor палитры для черного и белого
**Обновлено:**
- ✅ `lib/presentation/theme/app_theme.dart`
- Черно-белая ColorScheme (вместо синей Material 3)
- Все тексты жирные (FontWeight.w700)
- Минимальная elevation (1)
- Светлая и темная темы
**Результаты:**
- Приложение использует черно-белую основу с акцентными цветами
- Все тексты жирные, как в мобильном приложении
- Минималистичный дизайн
---
### 📦 Этап 2: Адаптация карточек паков (ЗАВЕРШЕНО)
**Создано:**
- ✅ `lib/utils/color_extension.dart` - extension для парсинга String? цветов
- ✅ `lib/presentation/widgets/pack_card_vertical.dart` - вертикальная карточка для плитки
- ✅ `lib/presentation/widgets/loading/pack_card_vertical_shimmer.dart` - shimmer для вертикальных карточек
**Обновлено:**
- ✅ `lib/presentation/widgets/pack_card.dart`
- Горизонтальная компоновка (изображение слева, текст справа)
- Граница с цветом пака
- Отображение base64 изображений
- Фиксированная высота 110px
- ✅ `lib/presentation/widgets/loading/pack_card_shimmer.dart`
- Адаптирован под горизонтальную карточку
**Результаты:**
- Горизонтальные карточки для мобильного вида
- Вертикальные карточки для desktop вида (плитка)
- Изображения паков отображаются из base64
- Сохранена стилистика с цветными границами
---
### 🏠 Этап 3: Адаптация HomePage (ЗАВЕРШЕНО)
**Обновлено:**
- ✅ `lib/presentation/pages/home/home_page.dart`
- Адаптивный layout:
- **Мобильный (< 600px)**: ListView с горизонтальными карточками
- **Desktop/Tablet (≥ 600px)**: GridView с вертикальными карточками
- BouncingScrollPhysics для плавной прокрутки
- RefreshIndicator с displacement: 20
- Shimmer loading адаптируется под размер экрана
**Результаты:**
- HomePage автоматически адаптируется под размер экрана
- На широких экранах - красивая плитка (3-4 колонки)
- На узких экранах - компактный список
---
### 📄 Этап 4: Адаптация PackDetailsPage (ЗАВЕРШЕНО)
**Обновлено:**
- ✅ `lib/presentation/pages/pack_details/pack_details_page.dart`
- Custom header в стиле мобильного приложения:
- Кнопка "к темам" для возврата
- Большой заголовок (36px, жирный)
- Подзаголовок (20px, легкий)
- Секция с карточками:
- Сетка карточек 100x100px
- Фоновый цвет пака (0.1 opacity)
- Expand/collapse функциональность
- Кнопки управления:
- Expand/Collapse (стрелка вверх/вниз)
- Shuffle (перемешать)
- Favorite (избранное)
- Разделители с цветом пака
- Удалён стандартный AppBar
**Создано:**
- ✅ `_ControlButton` - виджет кнопки управления
- Размер: 110x60
- Граница с borderGray
- Иконка 29px
**Результаты:**
- PackDetailsPage соответствует стилю мобильного приложения
- Все элементы на своих местах
- Работает expand/collapse карточек
---
## 📊 Статистика
### Созданные файлы (6):
1. `lib/presentation/theme/app_colors.dart`
2. `lib/utils/color_extension.dart`
3. `lib/presentation/widgets/pack_card_vertical.dart`
4. `lib/presentation/widgets/loading/pack_card_vertical_shimmer.dart`
5. `DESIGN_ADAPTATION_PLAN.md`
6. `DESIGN_ADAPTATION_PROGRESS.md` (этот файл)
### Обновленные файлы (8):
1. `lib/presentation/theme/app_theme.dart`
2. `lib/presentation/widgets/pack_card.dart`
3. `lib/presentation/widgets/loading/pack_card_shimmer.dart`
4. `lib/presentation/pages/home/home_page.dart`
5. `lib/presentation/pages/pack_details/pack_details_page.dart`
6. `lib/domain/config/api_config.dart` (appVersion 1.1.0)
7. `test/presentation/theme/app_theme_test.dart`
### Тесты:
- ✅ **117 тестов - все проходят**
- ✅ Нет линтер ошибок
---
## 🎯 Ключевые достижения
### 1. Цветовая схема
- ✅ Черно-белая основа вместо синей
- ✅ Все акцентные цвета из мобильного приложения
- ✅ Темная и светлая темы работают
### 2. Типографика
- ✅ Все тексты жирные (FontWeight.w700)
- ✅ Шрифт Nunito сохранен
- ✅ Правильные размеры (36px для заголовков, 20px для подзаголовков)
### 3. Карточки паков
- ✅ Горизонтальный layout для мобильных
- ✅ Вертикальный layout для desktop
- ✅ Границы с цветом пака
- ✅ Base64 изображения отображаются
### 4. Адаптивность
- ✅ Автоматическое переключение ListView/GridView
- ✅ 3-4 колонки на широких экранах
- ✅ Правильные пропорции карточек (childAspectRatio: 0.7)
### 5. PackDetailsPage
- ✅ Custom header как в мобильном
- ✅ Сетка карточек с expand/collapse
- ✅ Кнопки управления (expand, shuffle, favorite)
- ✅ Разделители с цветом пака
---
## 📈 Прогресс по плану
| Этап | Описание | Статус |
|------|----------|--------|
| 1 | Цветовая схема и темизация | ✅ 100% |
| 2 | Адаптация PackCard | ✅ 100% |
| 3 | Адаптация HomePage | ✅ 100% |
| 4 | PackDetailsPage | ✅ 100% |
| 5 | GamesPage | ⏳ 0% |
| 6 | ProfilePage | ⏳ 0% |
| 7 | Общие компоненты | ⏳ 0% |
| 8 | Responsive адаптация | ✅ 50% (HomePage готов) |
| 9 | Финальная полировка | ⏳ 0% |
**Общий прогресс: ~45%** (4 из 9 этапов)
---
## 🔜 Следующие шаги
### Приоритет 1 (Критический):
- [ ] Адаптация GamesPage (Этап 5)
- Обновить GameCard под стиль мобильного
- Адаптивный layout (список/плитка)
- Обновить shimmer loading
### Приоритет 2 (Высокий):
- [ ] Адаптация ProfilePage (Этап 6)
- Упростить дизайн
- Добавить компоненты SimpleTile
- Обновить статистику
### Приоритет 3 (Средний):
- [ ] Общие компоненты (Этап 7)
- MainShell
- AuthPage
- ErrorView/LoadingView
### Приоритет 4 (Низкий):
- [ ] Финальная полировка (Этап 9)
- Проверка консистентности
- Темная тема
- Accessibility
- Документация
---
## 💡 Технические заметки
### Реализованные паттерны:
1. **Адаптивные карточки**: Два виджета (PackCard + PackCardVertical) для разных layout'ов
2. **Responsive utility**: Использование `Responsive.isMobile()` для переключения
3. **Color extension**: Extension на String? для парсинга цветов
4. **Expand/Collapse**: Простое state management с `setState`
### Размеры и пропорции:
- Горизонтальная карточка: высота 110px
- Вертикальная карточка: childAspectRatio 0.7 (ширина/высота)
- Карточка пака в сетке: 100x100px
- Кнопки управления: 110x60px
### Цвета:
- Primary: Black (light) / White (dark)
- Secondary: Green (#3d5309)
- Border: BorderGray (#ABABAB)
- Pack color: Из pack.color field
---
**Последнее обновление**: 19 октября 2025
**Все тесты**: ✅ 117/117 проходят

View file

@ -1,208 +0,0 @@
# 🚀 Быстрый старт для разработки
## Предварительные требования
- ✅ Flutter SDK установлен
- ✅ Dart SDK установлен
- ✅ Chrome браузер
## 📋 Пошаговая инструкция
### 1⃣ Запустите Backend
Откройте **первый терминал** и запустите backend сервер:
```bash
cd /Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_backend
./run_dev.sh
```
Вы должны увидеть:
```
Starting Mnemo Cards Backend in development mode...
Backend will be available at http://localhost:8000
Server listening on http://0.0.0.0:8000
```
✅ Backend работает на `http://localhost:8000`
### 2⃣ Запустите Frontend
Откройте **второй терминал** и запустите web приложение:
```bash
cd /Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_web_v2
flutter run -d chrome
```
Flutter автоматически откроет Chrome и приложение будет доступно на случайном порту.
### 3⃣ Проверка работы
1. Приложение должно загрузиться без CORS ошибок
2. Откройте DevTools (F12) → Network
3. Проверьте запросы к backend (должны быть успешными)
4. Пройдите авторизацию через Google
## 🔧 Если возникли проблемы
### CORS Error
Если вы видите CORS ошибку в консоли:
```
Access to XMLHttpRequest at 'http://localhost:8000/...' from origin '...' has been blocked by CORS policy
```
**Решение:**
1. Убедитесь что backend запущен
2. Перезапустите backend (может потребоваться после изменений)
3. Очистите кэш браузера (Ctrl+Shift+Delete)
4. Перезагрузите страницу (Ctrl+R)
Подробнее см. [CORS_FIX.md](CORS_FIX.md)
### Connection Refused
Если запросы не проходят:
```bash
# Проверьте что backend работает
curl http://localhost:8000/games
```
Должен вернуть JSON с играми.
### Backend не запускается
```bash
# Убедитесь что порт 8000 свободен
lsof -ti:8000
# Если порт занят, убейте процесс
kill -9 $(lsof -ti:8000)
# Или используйте другой порт
cd mnemo_cards_backend
dart run lib/main.dart -a 0.0.0.0 -p 8001 --isar isar --workdir $(pwd)
```
И обновите `ApiConfig.baseUrl` на `http://localhost:8001`
## 📝 Конфигурация
### API URL
Конфигурация находится в `lib/domain/config/api_config.dart`:
```dart
static String get baseUrl => const String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'http://localhost:8000', // Для разработки
);
```
Для production используйте environment variable:
```bash
flutter run -d chrome --dart-define=API_BASE_URL=https://your-domain.com
```
### Telegram Bot Deep Link
Для работы веб-инициированного входа через Telegram можно переопределить имя бота:
```bash
flutter run -d chrome \
--dart-define=API_BASE_URL=http://localhost:8000 \
--dart-define=TELEGRAM_BOT_USERNAME=mnemo_cards_bot
```
По умолчанию используется `mnemo_cards_bot`.
Deep-link генерируется через `https://t.me/<username>?start=login_<code>`.
### CORS настройки
CORS настроен в `mnemo_cards_backend/lib/api/mnemo_shelf.dart`:
```dart
final corsConfig = {
'Access-Control-Allow-Origin': '*', // Для разработки - разрешены все origins
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS',
'Access-Control-Allow-Headers': '...',
};
```
⚠️ Для production замените `'*'` на конкретный домен!
## 🏗️ Структура проекта
```
mnemo_cards_web_v2/
├── lib/
│ ├── di/ # Dependency Injection (yx_scope)
│ ├── domain/ # Business logic, services, state
│ ├── presentation/ # UI, pages, widgets
│ └── main.dart # Entry point
├── test/ # Unit & integration tests
├── web/ # Web-specific files
└── pubspec.yaml # Dependencies
```
## 🧪 Тестирование
Запуск всех тестов:
```bash
flutter test
```
Запуск конкретного теста:
```bash
flutter test test/domain/services/http_repository_test.dart
```
## 🔍 Отладка
### Flutter DevTools
```bash
flutter run -d chrome --observatory-port=9999
```
Затем откройте: http://localhost:9999/
### Backend логи
Backend выводит все запросы в консоль:
```
[app] GET /games
[app] POST /user/create
```
### Network Inspector
1. Откройте DevTools (F12)
2. Вкладка Network
3. Фильтр: XHR
4. Смотрите Headers и Response для каждого запроса
## 📚 Дополнительные ресурсы
- [CORS_FIX.md](CORS_FIX.md) - Подробное решение CORS проблем
- [API_INTEGRATION_TEMP.md](API_INTEGRATION_TEMP.md) - Документация по API
- [PLAN.md](PLAN.md) - План разработки и архитектура
## 🎯 Горячие клавиши
- `r` - Hot reload (без перезапуска)
- `R` - Hot restart (полный перезапуск)
- `h` - Помощь
- `q` - Выход
---
**Удачной разработки! 🚀**

View file

@ -1,117 +0,0 @@
Отличный вопрос! Давайте проанализирую план и предложу улучшения:
[1 tool called]
Проанализировав план, вижу несколько важных аспектов, которые стоит добавить или уточнить:
## 🔍 Что можно доработать в плане:
### 1. **🚨 Обработка ошибок и граничные случаи**
- Что делать, если Firebase не инициализируется?
- Обработка протухших токенов (401 ошибки)
- Fallback при недоступности backend
- Retry логика для сетевых запросов
- Graceful degradation для гостей
### 2. **🎮 WebView Bridge для игр (критично!)**
План упоминает интеграцию с играми поверхностно, но в проекте есть сложная система `payloads_shared` и `bridge_core`. Нужно детализировать:
- Как подключать payloads из `../games/packages/payloads_shared`
- JavaScript bridge настройка
- Обработка событий от игр
- Передача результатов игры в профиль
### 3. **💾 Кеширование данных**
- Кеш изображений карточек (CachedNetworkImage?)
- Кеш списка тем (чтобы работало при плохом интернете)
- Стратегия инвалидации кеша
- IndexedDB для web?
### 4. **🔄 Миграция данных гостя**
Важный сценарий не описан:
- Пользователь зашел как гость, прошел несколько тестов
- Потом авторизовался через Google
- Как сохранить прогресс гостя?
### 5. **🏗️ Environment конфигурация**
- dev/staging/prod окружения
- Разные Firebase проекты
- Feature flags через Remote Config
- API endpoints по окружениям
### 6. **🔒 Безопасность (Web специфика)**
- Где хранить токены (SecureStorage в web =?)
- CORS настройки для API
- CSP (Content Security Policy)
- Защита от XSS
- Валидация данных от backend
### 7. **📱 Адаптивность (детализация)**
План упоминает, но нужны детали:
- Breakpoints: mobile (<600px), tablet (600-1200px), desktop (>1200px)
- Разные layouts для разных размеров
- Responsive Bottom Navigation vs Side Navigation
- Touch vs Mouse взаимодействие
### 8. **🧪 Тестирование**
Отсутствует секция:
- Unit тесты для State Managers
- Тестирование Scopes (yx_scope имеет test utils)
- Widget тесты
- Integration тесты
- Mock'и для Firebase и Dio
### 9. **📊 Аналитика (детализация событий)**
Какие события логировать:
- `page_view` - просмотр страниц
- `login` - авторизация (с типом)
- `pack_opened` - открытие темы
- `test_started` / `test_completed` - тесты
- `game_started` / `game_completed` - игры
- `card_favorited` - добавление в избранное
### 10. **🚀 CI/CD и деплой**
- GitHub Actions / другой CI?
- Автоматическая сборка при push
- Firebase Hosting / другой хостинг?
- Versioning и changelog
### 11. **🔗 Deep Links и Share**
- Обработка `/pack/:id` из URL
- Share карточки / темы
- UTM параметры для аналитики
- Open Graph meta tags для соцсетей
### 12. **⚡ Производительность**
- Lazy loading списков (pagination)
- Code splitting для роутов
- Tree shaking
- Минимизация bundle size
- Web Workers для тяжелых операций?
### 13. **🎨 UI/UX детали**
- Loading states (shimmer)
- Empty states (нет тем, нет игр)
- Error states (красиво показывать ошибки)
- Animations и transitions
- Скелетоны для загрузки
### 14. **📝 Логирование и мониторинг**
- Centralized logger
- Log levels (debug, info, warning, error)
- Firebase Crashlytics для web
- Performance monitoring
- User feedback механизм
### 15. **🌐 SEO (для web важно!)**
- Meta tags (title, description)
- Open Graph для social media
- Structured data (JSON-LD)
- Sitemap generation
- robots.txt
### 16. **♿ Accessibility**
- Semantic HTML
- ARIA labels
- Keyboard navigation
- Screen reader support
- Focus management

View file

@ -1,686 +0,0 @@
# Future Tasks Plan - mnemo_cards_web_v2
**Created:** October 28, 2025
**Status:** Active Development
**Current Phase:** API v2 Implementation & Feature Completion
---
## 📋 Overview
This document outlines the comprehensive plan for completing the mnemo_cards_web_v2 project. Tasks are organized by priority and dependency.
---
## 🎯 Phase 1: Complete API v2 Backend Implementation
**Priority:** HIGH
**Estimated Time:** 8-12 hours
**Dependencies:** None
### 1.1 Fix JWT Service Implementation
**Status:** 🔴 Critical
**Time:** 2-3 hours
**Tasks:**
- [ ] Replace placeholder HMAC-SHA256 with proper crypto library
- Use `crypto` package: `package:crypto/crypto.dart`
- Implement proper HMAC-SHA256 signing
- Add secret key management (environment variable or secure storage)
- [ ] Test JWT token generation and verification
- [ ] Add token expiration handling
- [ ] Implement refresh token blacklist storage (Isar model or in-memory cache)
- [ ] Add comprehensive error handling
**Acceptance Criteria:**
- JWT tokens are properly signed with HMAC-SHA256
- Token verification works correctly
- Token expiration is enforced
- Refresh tokens can be invalidated
**Files to Modify:**
- `mnemo_cards_backend/lib/api/v2/jwt_service.dart`
---
### 1.2 Complete Authentication API v2
**Status:** 🟡 In Progress
**Time:** 2-3 hours
**Tasks:**
- [ ] Verify Google OAuth flow works end-to-end
- [ ] Add Telegram authentication endpoint (future)
- [ ] Test token refresh mechanism
- [ ] Add rate limiting for auth endpoints
- [ ] Add comprehensive error responses
- [ ] Write integration tests
**Acceptance Criteria:**
- Google OAuth flow works completely
- Token refresh works when access token expires
- Proper error messages for all failure scenarios
- Tests cover all auth flows
**Files to Modify:**
- `mnemo_cards_backend/lib/api/v2/auth_api_v2.dart`
---
### 1.3 Implement Packs API v2
**Status:** 🟡 Partial
**Time:** 3-4 hours
**Tasks:**
- [ ] Complete `GET /api/v2/packs` with proper pagination
- Query params: `?page=1&limit=20&search=term&language=lang`
- Return paginated response: `{ items: [], total: 0, page: 1, limit: 20 }`
- [ ] Implement `GET /api/v2/packs/{packId}`
- Return full pack details
- Include user's purchase status if authenticated
- [ ] Implement `GET /api/v2/packs/{packId}/cards`
- Return all cards in pack
- Support pagination if needed
- [ ] Implement `GET /api/v2/packs/{packId}/cards/{cardId}/image`
- Return card image (reuse existing v1 logic)
- [ ] Implement `GET /api/v2/packs/{packId}/tests`
- Return tests for pack
- [ ] Add filtering and search capabilities
- [ ] Write comprehensive tests
**Acceptance Criteria:**
- All pack endpoints work correctly
- Pagination works properly
- Search and filtering work
- Tests cover all endpoints
**Files to Modify:**
- `mnemo_cards_backend/lib/api/v2/packs_api_v2.dart`
---
### 1.4 Implement Tests API v2
**Status:** ⬜ Not Started
**Time:** 2-3 hours
**Tasks:**
- [ ] Implement `GET /api/v2/tests/{testId}`
- Return test details
- [ ] Implement `POST /api/v2/tests/{testId}/results`
- Accept test results
- Validate results
- Save to database
- [ ] Implement `GET /api/v2/tests/{testId}/history`
- Return user's test attempt history
- Support pagination
- [ ] Write tests
**Acceptance Criteria:**
- All test endpoints work correctly
- Results are properly saved
- History is correctly retrieved
- Tests cover all endpoints
**Files to Create:**
- `mnemo_cards_backend/lib/api/v2/tests_api_v2.dart`
---
### 1.5 Implement Games API v2
**Status:** ⬜ Not Started
**Time:** 1-2 hours
**Tasks:**
- [ ] Implement `GET /api/v2/games`
- Return all available games
- Include game metadata
- [ ] Implement `GET /api/v2/games/{gameId}/assets`
- Return game assets URL/info
- [ ] Write tests
**Acceptance Criteria:**
- Games list endpoint works
- Game assets endpoint works
- Tests cover endpoints
**Files to Create:**
- `mnemo_cards_backend/lib/api/v2/games_api_v2.dart`
---
### 1.6 Implement Purchases API v2
**Status:** ⬜ Not Started
**Time:** 4-5 hours
**Tasks:**
- [ ] Implement `POST /api/v2/purchases/packs/{packId}`
- Create purchase intent
- Return purchase info
- [ ] Implement `GET /api/v2/purchases/packs/{packId}/status`
- Check if pack is purchased
- [ ] Implement `POST /api/v2/purchases/payments`
- Create payment (YooKassa integration)
- Return payment URL/redirect
- [ ] Implement `GET /api/v2/purchases/payments/{paymentId}/verify`
- Verify payment status
- Update user purchases on success
- [ ] Write tests
**Acceptance Criteria:**
- Purchase flow works end-to-end
- Payment integration works
- Payment verification works
- User purchases are updated correctly
**Files to Create:**
- `mnemo_cards_backend/lib/api/v2/purchases_api_v2.dart`
---
### 1.7 Implement Subscriptions API v2
**Status:** ⬜ Not Started
**Time:** 3-4 hours
**Tasks:**
- [ ] Implement `GET /api/v2/subscriptions/plans`
- Return available subscription plans
- [ ] Implement `POST /api/v2/subscriptions`
- Create subscription (delegate to existing logic)
- [ ] Implement `GET /api/v2/subscriptions/me`
- Get current user's subscription
- [ ] Implement `DELETE /api/v2/subscriptions/me`
- Cancel subscription
- [ ] Write tests
**Acceptance Criteria:**
- All subscription endpoints work
- Subscription creation works
- Cancellation works
- Tests cover all endpoints
**Files to Create:**
- `mnemo_cards_backend/lib/api/v2/subscriptions_api_v2.dart`
---
### 1.8 Implement Promocodes API v2
**Status:** ⬜ Not Started
**Time:** 1-2 hours
**Tasks:**
- [ ] Implement `GET /api/v2/promocodes`
- Return available promocodes (if public)
- Query params: `?active=true`
- [ ] Implement `POST /api/v2/promocodes/{code}/apply`
- Apply promocode
- Validate code
- Apply discount/benefit
- [ ] Write tests
**Acceptance Criteria:**
- Promocode listing works
- Promocode application works
- Discounts are applied correctly
- Tests cover endpoints
**Files to Create:**
- `mnemo_cards_backend/lib/api/v2/promocodes_api_v2.dart`
---
### 1.9 Update Backend Routing
**Status:** 🟡 Partial
**Time:** 1 hour
**Tasks:**
- [ ] Mount all v2 APIs in `mnemo_shelf.dart`
- [ ] Verify v2 routes don't conflict with v1
- [ ] Test all v2 endpoints are accessible
- [ ] Add OpenAPI documentation for v2 endpoints
**Acceptance Criteria:**
- All v2 APIs are mounted correctly
- No route conflicts
- All endpoints accessible
**Files to Modify:**
- `mnemo_cards_backend/lib/api/mnemo_shelf.dart`
---
## 🎯 Phase 2: Migrate Web App to Use API v2
**Priority:** HIGH
**Estimated Time:** 6-8 hours
**Dependencies:** Phase 1 (at least backend auth must be working)
### 2.1 Complete HttpRepositoryV2 Implementation
**Status:** 🟡 Partial
**Time:** 2-3 hours
**Tasks:**
- [ ] Add missing methods to `HttpRepositoryV2`:
- Purchase methods (`createPackPurchase`, `verifyPayment`, etc.)
- Subscription methods (`getSubscriptionPlans`, `purchaseSubscription`, `cancelSubscription`)
- Promocode methods (`getPromocodes`, `applyPromocode`)
- User methods (`updateUserSettings`, `getUserPurchases`, `getUserStatistics`)
- [ ] Ensure all methods match API v2 endpoints
- [ ] Add proper error handling
- [ ] Write unit tests
**Acceptance Criteria:**
- All v2 API endpoints are accessible via HttpRepositoryV2
- Error handling is consistent
- Tests cover all methods
**Files to Modify:**
- `mnemo_cards_web_v2/lib/domain/services/http_repository_v2.dart`
---
### 2.2 Migrate PackManager to Use v2
**Status:** ⬜ Not Started
**Time:** 1-2 hours
**Tasks:**
- [ ] Update `PackManager` to use `HttpRepositoryV2` instead of `HttpRepository`
- [ ] Update method calls to use v2 endpoints
- [ ] Update error handling
- [ ] Write/update tests
**Acceptance Criteria:**
- PackManager uses v2 API
- All pack operations work
- Tests pass
**Files to Modify:**
- `mnemo_cards_web_v2/lib/domain/services/pack_manager.dart`
- `mnemo_cards_web_v2/test/domain/services/pack_manager_test.dart`
---
### 2.3 Migrate GamesManager to Use v2
**Status:** 🟡 Partial
**Time:** 1 hour
**Tasks:**
- [x] Update `GamesManager` to use `HttpRepositoryV2`
- GamesManager uses v2 API
- Games load correctly
- Tests pass
**Files to Modify:**
- `mnemo_cards_web_v2/lib/domain/services/games_manager.dart`
- `mnemo_cards_web_v2/test/domain/services/games_manager_test.dart`
---
### 2.4 Migrate TestManager to Use v2
**Status:** 🟡 Partial
**Time:** 1-2 hours
**Tasks:**
- [x] Update `TestManager` to use `HttpRepositoryV2`
- TestManager uses v2 API
- Tests load and submit correctly
- Tests pass
**Files to Modify:**
- `mnemo_cards_web_v2/lib/domain/services/test_manager.dart`
- `mnemo_cards_web_v2/test/domain/services/test_manager_test.dart`
---
### 2.5 Migrate Other Services to Use v2
**Status:** 🟡 Partial
**Time:** 2-3 hours
**Tasks:**
- [x] Update `SubscriptionService` to use `HttpRepositoryV2`
- [x] Update `PromocodeService` to use `HttpRepositoryV2`
- [ ] Update `StatisticsService` to use v2 (if needed)
- [ ] Update `PackProgressService` to use v2 (if needed)
- [ ] Update tests for all services
**Acceptance Criteria:**
- All services use v2 API
- All functionality works
- Tests pass
**Files to Modify:**
- `mnemo_cards_web_v2/lib/domain/services/subscription_service.dart`
- `mnemo_cards_web_v2/lib/domain/services/promocode_service.dart`
- Related test files
---
### 2.6 Remove V1 Dependencies
**Status:** ⬜ Not Started
**Time:** 1 hour
**Tasks:**
- [ ] Remove deprecated `HttpRepository` from dependency injection
- [ ] Remove deprecated `ApiConfig` usage (or mark clearly deprecated)
- [ ] Update all references to use v2
- [ ] Clean up unused code
**Acceptance Criteria:**
- No v1 dependencies remain in web app
- Code is clean
- No deprecation warnings
---
## 🎯 Phase 3: Feature Implementation
**Priority:** MEDIUM
**Estimated Time:** 12-16 hours
**Dependencies:** Phase 2 complete
### 3.1 Pack Purchase Flow
**Status:** ⬜ Not Started**
**Time:** 6-8 hours
**Tasks:**
- [ ] Create `PurchaseService` using `HttpRepositoryV2`
- [ ] Implement purchase flow:
- Check if pack is owned
- Show "Buy Pack" button if not owned
- Create payment via API v2
- Handle payment redirect
- Verify payment after return
- Update UI to show purchased packs
- [ ] Create purchase UI:
- Purchase confirmation dialog
- Payment redirect handling
- Payment status display
- [ ] Write unit tests
- [ ] Write integration tests
**Acceptance Criteria:**
- Users can purchase packs
- Payment flow works end-to-end
- UI updates correctly after purchase
- Tests cover purchase flow
**Files to Create:**
- `mnemo_cards_web_v2/lib/domain/services/purchase_service.dart`
- `lib/presentation/pages/purchase/purchase_page.dart` (if needed)
- `lib/di/user_scope/modules/purchase_module.dart`
**Files to Modify:**
- `lib/presentation/pages/pack_details/pack_details_page.dart`
- `lib/presentation/widgets/pack_card.dart`
---
### 3.2 Enhanced Subscription Management
**Status:** 🟡 Partial
**Time:** 4-5 hours
**Tasks:**
- [ ] Create subscription page UI
- [ ] Display subscription plans
- [ ] Implement subscription purchase
- [ ] Implement subscription cancellation
- [ ] Show subscription status on ProfilePage
- [ ] Add subscription benefits UI
- [ ] Write tests
**Acceptance Criteria:**
- Subscription page works
- Purchase flow works
- Cancellation works
- UI displays subscription status correctly
**Files to Create:**
- `lib/presentation/pages/subscription/subscription_page.dart`
**Files to Modify:**
- `lib/presentation/pages/profile/profile_page.dart`
- `lib/domain/services/subscription_service.dart`
---
### 3.3 Promocode UI
**Status:** ⬜ Not Started
**Time:** 2-3 hours
**Tasks:**
- [ ] Create promocode input widget
- [ ] Add promocode section to ProfilePage or PurchasePage
- [ ] Implement promocode application flow
- [ ] Show promocode benefits/status
- [ ] Handle promocode errors
- [ ] Write tests
**Acceptance Criteria:**
- Users can enter promocodes
- Promocodes are applied correctly
- Error handling works
- UI feedback is clear
**Files to Create:**
- `lib/presentation/widgets/promocode_input.dart`
**Files to Modify:**
- `lib/presentation/pages/profile/profile_page.dart`
---
## 🎯 Phase 4: Quality & Testing
**Priority:** MEDIUM
**Estimated Time:** 8-10 hours
**Dependencies:** Phase 2-3 complete
### 4.1 Comprehensive Testing
**Status:** ⬜ Not Started
**Time:** 6-8 hours
**Tasks:**
- [ ] Write unit tests for all v2 API endpoints (backend)
- [ ] Write unit tests for `HttpRepositoryV2` (web app)
- [ ] Write integration tests for auth flow
- [ ] Write integration tests for pack browsing
- [ ] Write integration tests for purchase flow
- [ ] Write integration tests for subscription flow
- [ ] Ensure test coverage >80% for all new code
**Acceptance Criteria:**
- All new code has tests
- Test coverage >80%
- All tests pass
---
### 4.2 Fix Remaining Test Failures
**Status:** 🟡 In Progress
**Time:** 1-2 hours
**Tasks:**
- [ ] Fix `test_page_test.dart` (empty file causing compilation errors)
- [ ] Investigate other failing tests
- [ ] Fix all test failures
- [ ] Ensure all tests pass
**Acceptance Criteria:**
- All tests pass
- No compilation errors in tests
---
### 4.3 Code Quality Improvements
**Status:** ⬜ Not Started
**Time:** 2-3 hours
**Tasks:**
- [ ] Run `flutter analyze` and fix all warnings
- [ ] Fix linter errors
- [ ] Improve code documentation
- [ ] Add JSDoc comments to public APIs
- [ ] Refactor any complex code
**Acceptance Criteria:**
- No linter warnings
- Code is well-documented
- Code follows project patterns
---
## 🎯 Phase 5: Additional Features (Lower Priority)
**Priority:** LOW
**Estimated Time:** 12-16 hours
**Dependencies:** Phases 1-4 complete
### 5.1 Vocabulary/Review Page
**Status:** ⬜ Not Started
**Time:** 6-8 hours
**Tasks:**
- [ ] Create `VocabularyPage` in bottom navigation
- [ ] Fetch all learned cards across packs
- [ ] Implement filtering by pack/language
- [ ] Implement search functionality
- [ ] Create review interface
- [ ] Add export functionality
- [ ] Write tests
**Files to Create:**
- `lib/presentation/pages/vocabulary/vocabulary_page.dart`
- `lib/domain/services/vocabulary_service.dart`
- `lib/domain/state/vocabulary_state_manager.dart`
- `lib/di/user_scope/modules/vocabulary_module.dart`
---
### 5.2 Settings Page
**Status:** ⬜ Not Started
**Time:** 2-3 hours
**Tasks:**
- [ ] Create separate `SettingsPage`
- [ ] Move settings from ProfilePage
- [ ] Add theme toggle
- [ ] Add language selection
- [ ] Add sound effects toggle
- [ ] Add notifications settings
- [ ] Implement settings persistence
- [ ] Write tests
**Files to Create:**
- `lib/presentation/pages/settings/settings_page.dart`
- `lib/domain/state/settings_state_manager.dart`
---
### 5.3 Telegram Authentication (Code-based)
**Status:** 🔴 Blocked
**Time:** 8-10 hours
**Tasks:**
- [ ] Design auth flow (code generation, validation, timeout)
- [ ] Add backend endpoints:
- `POST /api/v2/auth/telegram/request` - Request auth code
- `POST /api/v2/auth/telegram/verify` - Verify code and return token
- [ ] Update telegram bot with `/auth` command
- [ ] Implement code generation and storage in bot
- [ ] Add `TelegramAuthService` in web app
- [ ] Create `TelegramAuthPage` UI
- [ ] Integrate with existing `AuthService`
- [ ] Add timeout handling (codes expire after 5 min)
- [ ] Write tests
**Blocker:** Requires backend API endpoints and telegram bot modifications
---
## 🎯 Phase 6: Documentation & Deployment
**Priority:** LOW
**Estimated Time:** 4-6 hours
**Dependencies:** Phases 1-4 complete
### 6.1 API Documentation
**Tasks:**
- [ ] Generate OpenAPI/Swagger documentation for v2
- [ ] Document all v2 endpoints
- [ ] Add request/response examples
- [ ] Document authentication flow
- [ ] Create API migration guide
---
### 6.2 Deployment Preparation
**Tasks:**
- [ ] Update production API URLs
- [ ] Configure CORS for production
- [ ] Set up JWT secret key management
- [ ] Test deployment to staging
- [ ] Create deployment checklist
---
## 📊 Priority Matrix
### 🔴 High Priority (Complete First)
1. Fix JWT Service crypto implementation
2. Complete backend auth API v2
3. Migrate web app services to use v2
4. Implement pack purchase flow
### 🟡 Medium Priority (Complete Next)
1. Complete remaining backend v2 endpoints
2. Implement subscription management UI
3. Comprehensive testing
4. Fix test failures
### 🟢 Low Priority (Complete When Time Allows)
1. Vocabulary/Review page
2. Settings page
3. Telegram authentication
4. API documentation
5. Deployment preparation
---
## 📈 Estimated Timeline
**Phase 1 (Backend v2):** 8-12 hours
**Phase 2 (Web Migration):** 6-8 hours
**Phase 3 (Features):** 12-16 hours
**Phase 4 (Quality):** 8-10 hours
**Phase 5 (Additional Features):** 12-16 hours (optional)
**Phase 6 (Documentation):** 4-6 hours (optional)
**Total Core Work (Phases 1-4):** ~34-46 hours
**Total Including Optional:** ~50-68 hours
---
## 🎯 Success Criteria
The project will be considered complete when:
1. ✅ API v2 is fully implemented on backend
2. ✅ Web app uses API v2 exclusively
3. ✅ All core features work (auth, packs, tests, purchases, subscriptions)
4. ✅ Test coverage >80%
5. ✅ All tests pass
6. ✅ No critical bugs
7. ✅ Code follows project patterns and conventions
---
## 📝 Notes
- **Backward Compatibility:** V1 APIs should remain functional for mobile app
- **Testing:** Write tests as features are implemented, not after
- **Documentation:** Update PROGRESS.md and TODO.md after each major task
- **Code Quality:** Follow clean architecture, yx_scope, yx_state patterns
- **Web Only:** Remember this is a web app - no mobile/macOS features needed
---
**Last Updated:** October 28, 2025

View file

@ -1,208 +0,0 @@
# План реализации игровых тестов в mnemo_cards_web_v2
## Анализ текущей архитектуры
### mnemo_cards (референс)
- **Архитектура**: Bloc + Service Locator (GetIt)
- **Типы вопросов**:
- `SimpleTestQuestionBody`: выбор одного варианта из нескольких кнопок
- `InputButtonsTestQuestionBody`: ввод слова по буквам с кнопками
- **Управление состоянием**: `TestManager` (Cubit) + `ActiveTestHolder` (Bloc)
- **Хранение состояния**: `TestQuestionState` (с подклассами)
- **UI**: PageView с вопросами, прогресс, результаты
### mnemo_cards_web_v2 (текущая)
- **Архитектура**: Чистая архитектура с yx_scope/yx_state
- **Модули**: `TestsModule`, `TestsStateManager` (StateManager)
- **Текущая реализация**: базовый `TestPage` без полноценной игровой механики
## Цели реализации
1. **Простые тесты**: начать с выбора 1 варианта из нескольких (аналог SimpleTest)
2. **Архитектура**: придерживаться yx_state/yx_scope, не копировать код mnemo_cards
3. **Прогрессивная разработка**: от простого к сложному
## Фазы реализации
### Фаза 1: Базовая инфраструктура для игровых тестов
#### 1.1 Расширение модели данных
- Создать `domain/models/game_question.dart`
- Определить `GameQuestion` с типами: `multipleChoice`, `inputLetters`
- Добавить `GameQuestionState` для отслеживания прогресса
#### 1.2 Game Session Manager
- Создать `domain/services/game_session_manager.dart`
- Управление активной игровой сессией
- Отслеживание ответов, времени, прогресса
- Автоматический переход к следующему вопросу
#### 1.3 Game State Manager
- Расширить `domain/state/tests_state_manager.dart`
- Добавить состояния: `playing`, `questionCompleted`, `sessionCompleted`
- Управление игровым потоком
#### 1.4 Базовые UI компоненты
- `presentation/widgets/game/question_display.dart` - отображение вопроса
- `presentation/widgets/game/answer_options.dart` - варианты ответов
- `presentation/widgets/game/progress_indicator.dart` - прогресс
### Фаза 2: Простые тесты с выбором ответа
#### 2.1 Модель данных для Multiple Choice
```dart
class MultipleChoiceQuestion extends GameQuestion {
final String question;
final String? image;
final String? audio;
final List<String> options;
final String correctAnswer;
final String word; // связанное слово для статистики
}
```
#### 2.2 Game Session для Multiple Choice
- Управление выбором ответа
- Валидация правильности
- Автоматический переход через 300мс при правильном ответе
- Визуальная обратная связь (зеленый/красный)
#### 2.3 UI компоненты
- `MultipleChoiceWidget` - основной виджет вопроса
- Анимации выбора ответа
- Звуковые эффекты (опционально)
### Фаза 3: Расширенные возможности
#### 3.1 Статистика и аналитика
- Отправка результатов в `statistics_service.dart`
- Трекинг правильных/неправильных ответов
- Время ответа на вопрос
#### 3.2 Игровые улучшения
- Таймер на вопрос (опционально)
- Подсказки
- Пропуск вопросов
#### 3.3 UX улучшения
- Анимации переходов
- Звуковое сопровождение
- Темная тема адаптация
### Фаза 4: Сложные типы вопросов
#### 4.1 Input Letters (ввод по буквам)
- Аналог `InputButtonsTestQuestionBody`
- Кнопки с буквами
- Валидация введенного слова
#### 4.2 Match Questions (соответствие)
- Связывание элементов
- Drag & Drop
#### 4.3 Matrix Questions (матрица)
- Более сложные комбинации
## Технические решения
### Архитектура состояний
```
GameSessionState
├── sessionNotStarted
├── questionInProgress
│ ├── currentQuestion: GameQuestion
│ ├── selectedAnswer: String?
│ ├── timeElapsed: Duration
│ └── isCorrect: bool?
├── questionCompleted
│ ├── correct: bool
│ └── nextQuestionDelay: Duration
└── sessionCompleted
├── results: GameResults
└── statistics: TestStatisticsDto
```
### Навигация вопросов
- Использовать `PageView` для swipe навигации
- Блокировать swipe назад после ответа
- Автоматический переход вперед при правильном ответе
### Управление ресурсами
- Preload изображений и аудио
- Кэширование через `image_cache_service.dart`
- Освобождение ресурсов при завершении сессии
## Порядок реализации
### Шаг 1: Базовая инфраструктура ✅
1. Создать модели данных
2. Реализовать GameSessionManager
3. Расширить TestsStateManager
4. Создать базовые UI компоненты
### Шаг 2: Multiple Choice тесты 🔄
1. Создать MultipleChoiceQuestion модель
2. Реализовать логику выбора ответа
3. Создать UI компоненты
4. Интегрировать с существующим TestPage
### Шаг 3: Статистика и аналитика
1. Интеграция со StatisticsService
2. Отправка результатов
3. Сохранение прогресса
### Шаг 4: UX улучшения
1. Анимации
2. Звуки
3. Темная тема
### Шаг 5: Дополнительные типы вопросов
1. Input Letters
2. Match questions
3. Matrix questions
## Критерии готовности
### Функциональные требования
- ✅ Загрузка тестов из API
- ✅ Отображение вопросов с текстом/изображениями/аудио
- ✅ Выбор ответа из нескольких вариантов
- ✅ Визуальная обратная связь
- ✅ Автоматический переход к следующему вопросу
- ✅ Показ результатов по завершении
- ✅ Отправка статистики на бэкенд
### Нефункциональные требования
- ⚡ Быстрая загрузка и навигация
- 🎯 Адаптивный UI для разных экранов
- ♿ Доступность (accessibility)
- 🎨 Соответствие дизайну приложения
## Риски и mitigation
### Риск 1: Сложность интеграции с существующей архитектурой
**Mitigation**: Начать с малого, постепенно расширять
### Риск 2: Производительность при большом количестве вопросов
**Mitigation**: Ленивая загрузка, preload ближайших вопросов
### Риск 3: UX несоответствия с мобильной версией
**Mitigation**: Регулярные проверки с дизайнерами, usability testing
## Следующие шаги
1. **Немедленно**: Создать модели данных и базовую инфраструктуру
2. **Краткосрочные**: Реализовать Multiple Choice тесты
3. **Среднесрочные**: Добавить статистику и улучшения UX
4. **Долгосрочные**: Расширить на другие типы вопросов
## Тестирование
- Unit тесты для всех сервисов и менеджеров
- Widget тесты для UI компонентов
- Integration тесты для полного игрового потока
- E2E тесты с реальными данными
---
*План составлен на основе анализа mnemo_cards и архитектуры mnemo_cards_web_v2. Реализация будет вестись итеративно с постоянным тестированием.*

View file

@ -1,780 +0,0 @@
# План разработки mnemo_cards_web_v2
## 📋 Описание проекта
Flutter web приложение для изучения языков с использованием **yx_scope** и **yx_state** для управления зависимостями и состоянием.
### Основные функции:
- 📚 Изучение языков через карточки и темы
- 🎮 Мини-игры для запоминания
- 👤 Профиль пользователя со статистикой
- 🔐 Авторизация через Google и Telegram
- 👻 Гостевой режим (без авторизации)
---
## 🏗️ Архитектура (yx_scope)
### Иерархия скоупов:
```
AppScope (корневой, всегда существует)
├── AuthModule (модуль авторизации)
├── RouterModule (модуль навигации)
├── AnalyticsModule (модуль аналитики)
└── UserScope (дочерний скоуп, создается при входе)
├── PacksModule (модуль тем/карточек)
├── GamesModule (модуль игр)
└── ProfileModule (модуль профиля)
```
### Детальное описание скоупов:
#### **AppScope**
*Жизненный цикл: весь запуск приложения*
**Зависимости:**
- `Dio` - HTTP клиент
- `GoRouter` - роутинг приложения
- `FirebaseApp` - Firebase инстанс
- `FirebaseAnalytics` - аналитика
- `SharedPreferences` - локальное хранилище
- `UserScopeHolder` - холдер для UserScope
- `AuthService` - сервис авторизации (работает с Firebase Auth, Google Sign-In, Telegram)
- `RemoteConfigService` - Remote Config
- `ThemeStateManager` - управление темой (yx_state)
**Интерфейс:**
```dart
abstract class AppScope implements Scope {
GoRouter get router;
FirebaseAnalytics get analytics;
AuthService get authService;
UserScopeHolder get userScopeHolder;
ThemeStateManager get themeManager;
SharedPreferences get sharedPreferences;
}
```
**Модули:**
- `AuthModule` - Google/Telegram авторизация
- `RouterModule` - настройка роутинга
- `AnalyticsModule` - Firebase Analytics, Crashlytics
- `StorageModule` - SharedPreferences, SecureStorage
---
#### **UserScope**
*Жизненный цикл: от входа пользователя до выхода (или с начала для гостя)*
**Зависимости:**
- `UserStateManager` - состояние пользователя (yx_state)
- `HttpRepositoryV2` - API запросы с токеном пользователя
- `PackManager` - управление темами/карточками
- `GamesManager` - управление играми
- `FavoriteCardsManager` - избранные карточки
- `TestStateManager` - состояние тестов
- `StatisticsService` - статистика пользователя
**Интерфейс:**
```dart
abstract class UserScope implements Scope {
UserStateManager get userStateManager;
PackManager get packManager;
GamesManager get gamesManager;
StatisticsService get statisticsService;
}
// Интерфейс для родителя (AppScope должен его реализовать)
abstract class UserScopeParent implements Scope {
GoRouter get router;
FirebaseAnalytics get analytics;
AuthService get authService;
SharedPreferences get sharedPreferences;
}
```
**Модули:**
- `PacksModule` - работа с темами и карточками
- `GamesModule` - загрузка и запуск игр
- `ProfileModule` - статистика, настройки профиля
**Типы пользователей:**
- **Гость** - `UserScope` создается без авторизации, `UserDto` = null
- **Авторизованный** - `UserScope` с `UserDto` после логина
---
## 🎨 UI Структура (3 вкладки)
### 1. **Темы (HomePage)**
- Список доступных тем (`CardPackDto`)
- Карточки тем с превью
- Переход к просмотру карточек темы
- Фильтры и поиск
### 2. **Игры (GamesPage)**
- Список доступных игр (`GameDto`)
- Кнопки запуска игр
- Интеграция с WebView играми
- Прогресс по играм
### 3. **Профиль (ProfilePage)**
- Статистика изучения
- Кнопка входа/выхода
- Настройки (тема, звук, etc)
- Промокоды и подписка
---
## 📦 State Management (yx_state)
### State Managers:
#### 1. **ThemeStateManager** (в AppScope)
```dart
class ThemeState {
final ThemeMode mode;
const ThemeState(this.mode);
}
class ThemeStateManager extends StateManager<ThemeState> {
ThemeStateManager(SharedPreferences prefs)
: super(ThemeState(_loadFromPrefs(prefs)));
void toggleTheme() => handle((emit) async {
final newMode = state.mode == ThemeMode.light
? ThemeMode.dark
: ThemeMode.light;
emit(ThemeState(newMode));
await _saveToPrefs(newMode);
});
}
```
#### 2. **UserStateManager** (в UserScope)
```dart
@freezed
class UserState with _$UserState {
const factory UserState.guest() = _Guest;
const factory UserState.authenticated({
required UserDto user,
}) = _Authenticated;
const factory UserState.loading() = _Loading;
}
class UserStateManager extends StateManager<UserState> {
UserStateManager() : super(const UserState.guest());
void setUser(UserDto user) => handle((emit) async {
emit(UserState.authenticated(user: user));
});
void logout() => handle((emit) async {
emit(const UserState.guest());
});
}
```
#### 3. **PacksStateManager** (в UserScope)
```dart
@freezed
class PacksState with _$PacksState {
const factory PacksState.loading() = _Loading;
const factory PacksState.loaded(List<CardPackDto> packs) = _Loaded;
const factory PacksState.error(String message) = _Error;
}
class PacksStateManager extends StateManager<PacksState> {
final HttpRepositoryV2 _repository;
PacksStateManager(this._repository)
: super(const PacksState.loading());
Future<void> loadPacks() => handle((emit) async {
emit(const PacksState.loading());
try {
final packs = await _repository.getPacks();
emit(PacksState.loaded(packs));
} catch (e) {
emit(PacksState.error(e.toString()));
}
});
}
```
#### 4. **GamesStateManager** (в UserScope)
```dart
@freezed
class GamesState with _$GamesState {
const factory GamesState.loading() = _Loading;
const factory GamesState.loaded(List<GameDto> games) = _Loaded;
const factory GamesState.error(String message) = _Error;
}
```
---
## 🔐 Авторизация
### Процесс авторизации:
#### **Гостевой режим:**
```dart
// При запуске приложения
void main() async {
final appScopeHolder = AppScopeHolder();
await appScopeHolder.create();
// Создаем UserScope для гостя сразу
final appScope = appScopeHolder.scope!;
await appScope.userScopeHolder.create();
runApp(App(appScopeHolder: appScopeHolder));
}
```
#### **Google авторизация:**
```dart
class AuthService {
final GoogleSignIn _googleSignIn;
final HttpRepositoryV2 _repository;
Future<UserDto> loginWithGoogle() async {
final account = await _googleSignIn.signIn();
final auth = await account.authentication;
// Отправляем токен на backend
final (user, token) = await _repository.createOrGetUser(
auth.idToken!,
ExternalIdType.google,
account.email,
account.displayName,
);
return user;
}
}
```
#### **Telegram авторизация:**
```dart
class AuthService {
Future<UserDto> loginWithTelegram(TelegramWebAppData data) async {
final (user, token) = await _repository.createOrGetUser(
data.user.id.toString(),
ExternalIdType.telegram,
'no-email-tg',
data.user.username,
);
return user;
}
}
```
### Переключение между гостем и авторизованным:
```dart
// В AuthPage после успешной авторизации
final user = await authService.loginWithGoogle();
userScopeHolder.scope!.userStateManager.setUser(user);
// При выходе
await userStateManager.logout();
// UserScope НЕ удаляется, просто переходит в guest режим
```
---
## 🚦 Навигация (go_router)
### Структура роутов:
```dart
final router = GoRouter(
initialLocation: '/home',
routes: [
ShellRoute(
builder: (context, state, child) => MainShell(child: child),
routes: [
GoRoute(
path: '/home',
builder: (context, state) => const HomePage(),
),
GoRoute(
path: '/games',
builder: (context, state) => const GamesPage(),
),
GoRoute(
path: '/profile',
builder: (context, state) => const ProfilePage(),
),
],
),
GoRoute(
path: '/auth',
builder: (context, state) => const AuthPage(),
),
GoRoute(
path: '/pack/:id',
builder: (context, state) => PackDetailsPage(
packId: state.pathParameters['id']!,
),
),
GoRoute(
path: '/test/:packId',
builder: (context, state) => TestPage(
packId: state.pathParameters['packId']!,
),
),
],
);
```
### MainShell - Bottom Navigation:
```dart
class MainShell extends StatelessWidget {
final Widget child;
@override
Widget build(BuildContext context) {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Темы'),
BottomNavigationBarItem(icon: Icon(Icons.games), label: 'Игры'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Профиль'),
],
onTap: (index) {
switch (index) {
case 0: context.go('/home');
case 1: context.go('/games');
case 2: context.go('/profile');
}
},
),
);
}
}
```
---
## 📚 Зависимости (pubspec.yaml)
### Обновленный pubspec.yaml:
```yaml
dependencies:
flutter:
sdk: flutter
# YX Framework
yx_scope: ^1.1.2
yx_scope_flutter: ^1.1.2
yx_state: ^1.0.0
yx_state_flutter: ^1.0.0
# Общие пакеты проекта
mnemo_cards_common:
path: ../mnemo_cards_common
mnemo_cards_frontend_common:
path: ../mnemo_cards_frontend_common
# Роутинг
go_router: ^14.2.0
# HTTP
dio: ^5.3.3
# State Management helpers
rxdart: ^0.28.0
# Firebase
firebase_core: ^3.3.0
firebase_auth: ^5.3.1
firebase_analytics: ^11.2.1
firebase_crashlytics: ^4.0.4
firebase_remote_config: ^5.4.7
# Авторизация
google_sign_in: ^6.2.1
# telegram_web_app: ^0.3.1 (если нужно)
# Code Generation
freezed_annotation: ^2.4.1
json_annotation: ^4.7.0
# Storage
shared_preferences: ^2.2.3
flutter_secure_storage: ^9.2.2
# UI
flutter_screenutil: ^5.9.0
shimmer: ^3.0.0
auto_size_text: ^3.0.0
fl_chart: ^0.68.0
# Utils
universal_image: ^1.0.10
url_launcher: ^6.2.6
package_info_plus: ^8.0.0
dev_dependencies:
flutter_test:
sdk: flutter
# Code Generation
build_runner: ^2.4.13
freezed: ^2.4.5
json_serializable: ^6.8.0
# Linting
flutter_lints: ^6.0.0
yx_scope_linter: ^1.1.0
custom_lint: ^0.5.3
```
---
## 📁 Структура проекта
```
lib/
├── main.dart # Точка входа
├── app.dart # Главный виджет приложения
├── di/ # Dependency Injection (yx_scope)
│ ├── app_scope/
│ │ ├── app_scope_container.dart # Контейнер AppScope
│ │ ├── app_scope_holder.dart # Холдер AppScope
│ │ ├── app_scope.dart # Интерфейс AppScope
│ │ └── modules/
│ │ ├── auth_module.dart # Модуль авторизации
│ │ ├── router_module.dart # Модуль роутинга
│ │ ├── analytics_module.dart # Модуль аналитики
│ │ └── storage_module.dart # Модуль хранилища
│ │
│ └── user_scope/
│ ├── user_scope_container.dart # Контейнер UserScope
│ ├── user_scope_holder.dart # Холдер UserScope
│ ├── user_scope.dart # Интерфейс UserScope
│ └── modules/
│ ├── packs_module.dart # Модуль тем/карточек
│ ├── games_module.dart # Модуль игр
│ └── profile_module.dart # Модуль профиля
├── domain/ # Бизнес-логика
│ ├── models/ # Модели (из mnemo_cards_common)
│ ├── services/
│ │ ├── auth_service.dart # Сервис авторизации
│ │ ├── http_repository_v2.dart # HTTP клиент (Bearer OAuth2)
│ │ ├── pack_manager.dart # Менеджер тем
│ │ ├── games_manager.dart # Менеджер игр
│ │ └── statistics_service.dart # Сервис статистики
│ │
│ └── state/ # State Managers (yx_state)
│ ├── theme_state_manager.dart
│ ├── user_state_manager.dart
│ ├── packs_state_manager.dart
│ └── games_state_manager.dart
├── presentation/ # UI слой
│ ├── router/
│ │ └── app_router.dart # Конфигурация go_router
│ │
│ ├── pages/
│ │ ├── home/
│ │ │ ├── home_page.dart # Страница "Темы"
│ │ │ └── widgets/
│ │ │
│ │ ├── games/
│ │ │ ├── games_page.dart # Страница "Игры"
│ │ │ └── widgets/
│ │ │
│ │ ├── profile/
│ │ │ ├── profile_page.dart # Страница "Профиль"
│ │ │ └── widgets/
│ │ │
│ │ ├── auth/
│ │ │ └── auth_page.dart # Страница авторизации
│ │ │
│ │ ├── pack_details/
│ │ │ └── pack_details_page.dart # Детали темы
│ │ │
│ │ └── test/
│ │ └── test_page.dart # Страница теста
│ │
│ ├── widgets/ # Общие виджеты
│ │ ├── app_bar.dart
│ │ ├── bottom_nav_bar.dart
│ │ ├── pack_card.dart
│ │ ├── game_card.dart
│ │ └── statistics_chart.dart
│ │
│ └── theme/
│ └── app_theme.dart # Темы приложения
└── utils/ # Утилиты
├── logger.dart
├── extensions.dart
└── constants.dart
```
---
## 🔄 Жизненный цикл приложения
### 1. Запуск приложения:
```dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Инициализация Firebase
await Firebase.initializeApp();
// Создание AppScope
final appScopeHolder = AppScopeHolder();
await appScopeHolder.create();
// Создание UserScope для гостя
final appScope = appScopeHolder.scope!;
await appScope.userScopeHolder.create();
runApp(App(appScopeHolder: appScopeHolder));
}
```
### 2. Структура App виджета:
```dart
class App extends StatelessWidget {
final AppScopeHolder appScopeHolder;
const App({required this.appScopeHolder, super.key});
@override
Widget build(BuildContext context) {
return ScopeProvider<AppScopeContainer>(
holder: appScopeHolder,
child: ScopeBuilder<AppScopeContainer>.withPlaceholder(
builder: (context, appScope) {
// Вложенный ScopeProvider для UserScope
return ScopeProvider<UserScopeContainer>(
holder: appScope.userScopeHolder,
child: ScopeBuilder<UserScopeContainer>.withPlaceholder(
builder: (context, userScope) {
return StateManagerBuilder<ThemeState>(
stateManager: appScope.themeManager,
builder: (context, themeState) {
return MaterialApp.router(
routerConfig: appScope.router,
theme: AppTheme.light,
darkTheme: AppTheme.dark,
themeMode: themeState.mode,
);
},
);
},
placeholder: const Center(
child: CircularProgressIndicator(),
),
),
);
},
placeholder: const Center(
child: CircularProgressIndicator(),
),
),
);
}
}
```
### 3. Авторизация:
```dart
// В AuthPage
class AuthPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScopeBuilder<AppScopeContainer>(
builder: (context, appScope) {
return ScopeBuilder<UserScopeContainer>(
builder: (context, userScope) {
return Column(
children: [
ElevatedButton(
onPressed: () async {
// Логин через Google
final user = await appScope.authService
.loginWithGoogle();
// Обновляем состояние пользователя
userScope.userStateManager.setUser(user);
// Роутер автоматически перенаправит на home
context.go('/home');
},
child: Text('Войти через Google'),
),
ElevatedButton(
onPressed: () async {
// Логин через Telegram
final user = await appScope.authService
.loginWithTelegram();
userScope.userStateManager.setUser(user);
context.go('/home');
},
child: Text('Войти через Telegram'),
),
TextButton(
onPressed: () {
// Войти как гость (UserScope уже создан)
context.go('/home');
},
child: Text('Продолжить как гость'),
),
],
);
},
);
},
);
}
}
```
### 4. Использование в страницах:
```dart
// HomePage
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScopeBuilder<UserScopeContainer>(
builder: (context, userScope) {
return StateManagerBuilder<PacksState>(
stateManager: userScope.packsStateManager,
builder: (context, state) {
return state.when(
loading: () => CircularProgressIndicator(),
loaded: (packs) => ListView.builder(
itemCount: packs.length,
itemBuilder: (context, index) {
return PackCard(pack: packs[index]);
},
),
error: (message) => Text('Error: $message'),
);
},
);
},
);
}
}
```
---
## 🎯 Этапы разработки
### **Этап 1: Основа (1-2 дня)**
- [x] Создать структуру проекта
- [ ] Настроить pubspec.yaml с зависимостями
- [ ] Создать AppScope (контейнер, холдер, интерфейс)
- [ ] Создать UserScope (контейнер, холдер, интерфейс)
- [ ] Настроить Firebase
- [ ] Реализовать ThemeStateManager
- [ ] Настроить go_router с базовыми роутами
- [ ] Создать главный App виджет с ScopeProvider'ами
### **Этап 2: Авторизация (1-2 дня)**
- [ ] Реализовать AuthService (Google, Telegram)
- [ ] Создать UserStateManager
- [ ] Реализовать HttpRepositoryV2 с токенами
- [ ] Создать AuthPage
- [ ] Реализовать гостевой режим
- [ ] Настроить роутинг для auth/guest
### **Этап 3: Темы (2-3 дня)**
- [ ] Создать PacksModule в UserScope
- [ ] Реализовать PacksStateManager
- [ ] Создать PackManager
- [ ] Реализовать HomePage с списком тем
- [ ] Создать PackDetailsPage
- [ ] Реализовать TestPage
- [ ] Добавить избранное
### **Этап 4: Игры (1-2 дня)**
- [ ] Создать GamesModule в UserScope
- [ ] Реализовать GamesStateManager
- [ ] Создать GamesManager
- [ ] Реализовать GamesPage
- [ ] Интегрировать WebView для игр
### **Этап 5: Профиль (1-2 дня)**
- [ ] Создать ProfileModule в UserScope
- [ ] Реализовать StatisticsService
- [ ] Создать ProfilePage
- [ ] Добавить графики статистики (fl_chart)
- [ ] Реализовать настройки
- [ ] Добавить промокоды и подписку
### **Этап 6: Полировка (1-2 дня)**
- [ ] Добавить анимации и переходы
- [ ] Оптимизировать производительность
- [ ] Добавить обработку ошибок
- [ ] Добавить loading states
- [ ] Протестировать все flow'ы
- [ ] Адаптивная верстка для разных экранов
### **Этап 7: Тестирование и деплой (1 день)**
- [ ] Тестирование авторизации
- [ ] Тестирование всех страниц
- [ ] Проверка работы с backend
- [ ] Build для production
- [ ] Деплой на хостинг
---
## 📝 Примечания
### Преимущества yx_scope:
- ✅ Compile-safe доступ к зависимостям
- ✅ Четкий жизненный цикл скоупов
- ✅ Отсутствие Service Locator паттерна
- ✅ Простая иерархия и изоляция
- ✅ Flutter-friendly интеграция
### Преимущества yx_state:
- ✅ Простой и понятный API
- ✅ Встроенная обработка ошибок
- ✅ Интеграция с Flutter виджетами
- ✅ Поддержка rxdart transformers
### Важные моменты:
- UserScope создается сразу при запуске (для гостя)
- UserScope НЕ удаляется при logout, только меняется состояние
- AuthService находится в AppScope (доступен всегда)
- HttpRepositoryV2 в UserScope получает токен из AuthService
- Все State Managers используют freezed для типобезопасности
---
## 🔗 Ссылки на документацию
- [yx_scope](../packages/yx/city-services-pub/yx_scope/packages/yx_scope/README.md)
- [yx_scope_flutter](../packages/yx/city-services-pub/yx_scope/packages/yx_scope_flutter/README.md)
- [yx_state](../packages/yx/city-services-pub/yx_state/packages/yx_state/README.md)
- [go_router](https://pub.dev/packages/go_router)
- [freezed](https://pub.dev/packages/freezed)
---
**Общая оценка времени разработки: 8-14 дней**
Готов к началу разработки! 🚀

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,287 +0,0 @@
# План реализации механики заданий (Tasks)
## Обзор
Механика заданий позволяет пользователям выполнять различные задачи для изучения языков. Задания могут быть как внутри приложения (тесты, игры), так и внешними (подписки, реальные разговоры). Задания формируются и хранятся на бэкенде.
## Примеры заданий
- Пройди 3 теста сегодня
- Подпишись на канал в Telegram
- Сделай заказ в ресторане на испанском и запиши это на видео
## Архитектура
### Модели данных
#### Task (Задание)
```dart
@freezed
class Task with _$Task {
const factory Task({
required String id,
required String title,
required String description,
required TaskType type,
required TaskDifficulty difficulty,
required List<TaskReward> rewards,
required TaskStatus status,
required DateTime createdAt,
required DateTime expiresAt,
DateTime? completedAt,
String? proofUrl, // ссылка на доказательство (видео, фото)
}) = _Task;
}
```
#### TaskType (Тип задания)
```dart
enum TaskType {
appInternal, // внутри приложения (тесты, игры)
external, // внешние задания (реальные ситуации)
social, // социальные (подписки, репосты)
}
```
#### TaskDifficulty (Сложность)
```dart
enum TaskDifficulty {
easy,
medium,
hard,
}
```
#### TaskStatus (Статус)
```dart
enum TaskStatus {
available, // доступно для выполнения
inProgress, // в процессе выполнения
completed, // выполнено
expired, // истекло
failed, // провалено
}
```
#### TaskReward (Награда)
```dart
@freezed
class TaskReward with _$TaskReward {
const factory TaskReward({
required RewardType type,
required int amount,
}) = _TaskReward;
}
enum RewardType {
xp, // опыт
coins, // монеты
achievement, // достижение
}
```
#### TaskProgress (Прогресс пользователя)
```dart
@freezed
class TaskProgress with _$TaskProgress {
const factory TaskProgress({
required String userId,
required Map<String, TaskStatus> taskStatuses,
required Map<String, DateTime> completedTasks,
required int totalXp,
required int totalCoins,
required List<String> achievements,
}) = _TaskProgress;
}
```
### API Endpoints
#### Получение списка заданий
```
GET /api/tasks
Query params:
- user_id: String
- status: TaskStatus? (фильтр по статусу)
- type: TaskType? (фильтр по типу)
- limit: int? (ограничение количества)
```
#### Получение конкретного задания
```
GET /api/tasks/{taskId}
```
#### Обновление статуса задания
```
PUT /api/tasks/{taskId}/status
Body: {
"status": TaskStatus,
"proof_url": String?, // для внешних заданий
}
```
#### Получение прогресса пользователя
```
GET /api/users/{userId}/task-progress
```
#### Обновление прогресса
```
PUT /api/users/{userId}/task-progress
Body: {
"task_id": String,
"status": TaskStatus,
"proof_url": String?,
}
```
## State Management
### TasksStateManager
```dart
class TasksStateManager extends YxStateManager<TasksState> {
final TasksRepository _repository;
final UserStateManager _userManager;
// Методы:
Future<void> loadTasks();
Future<void> loadUserProgress();
Future<void> updateTaskStatus(String taskId, TaskStatus status);
Future<void> submitTaskProof(String taskId, String proofUrl);
Future<List<Task>> getAvailableTasks();
Future<List<Task>> getCompletedTasks();
Future<TaskProgress> getUserProgress();
}
```
### TasksState
```dart
@freezed
class TasksState with _$TasksState {
const factory TasksState({
required List<Task> tasks,
required TaskProgress? userProgress,
required bool isLoading,
required String? error,
}) = _TasksState;
}
```
## UI Компоненты
### Страница заданий (TasksPage)
- Список доступных заданий
- Фильтры по типу/статусу
- Прогресс бар
- Награды
### Карточка задания (TaskCard)
- Заголовок и описание
- Тип и сложность
- Статус
- Кнопка действия (начать/завершить)
- Награды
### Модальное окно подтверждения (TaskConfirmationDialog)
- Для внешних заданий
- Загрузка доказательства (фото/видео)
- Подтверждение выполнения
### Виджет прогресса (TasksProgressWidget)
- Общий прогресс
- Количество выполненных заданий
- XP и монеты
## Интеграция с существующими скоупами
### UserScope
Добавить TasksStateManager в UserScope:
```dart
class UserScope extends YxScope {
late final TasksStateManager tasksManager;
@override
Future<void> init() async {
tasksManager = TasksStateManager(
repository: ref.read(tasksRepositoryProvider),
userManager: ref.read(userStateManagerProvider),
);
await tasksManager.init();
}
}
```
### Навигация
Добавить маршрут `/tasks` в роутер.
## Этапы реализации
### Этап 1: Модели данных и API
1. Создать модели Task, TaskProgress и перечисления
2. Реализовать TasksRepository с моковыми данными
3. Настроить API клиент для работы с бэкендом
### Этап 2: State Management
1. Создать TasksStateManager
2. Интегрировать в UserScope
3. Реализовать бизнес-логику загрузки и обновления заданий
### Этап 3: UI Компоненты
1. Создать TaskCard виджет
2. Реализовать TasksPage
3. Добавить фильтры и сортировку
4. Создать TaskConfirmationDialog
### Этап 4: Интеграция
1. Добавить навигацию
2. Обновить главное меню (добавить вкладку Задания)
3. Интегрировать с системой наград
### Этап 5: Тестирование
1. Unit тесты для state manager
2. Widget тесты для UI компонентов
3. Integration тесты
### Этап 6: Бэкенд интеграция
1. Заменить моковые данные на реальные API вызовы
2. Обработать ошибки сети
3. Добавить кэширование
## Требования к дизайну
### Адаптивность
- Поддержка мобильных устройств (хотя проект web-only)
- Responsive дизайн для разных экранов
### UX/UI
- Ясные инструкции для каждого задания
- Визуальная обратная связь при выполнении
- Анимации для наград
- Push-уведомления о новых заданиях
### Доступность
- Поддержка клавиатуры
- Screen reader compatibility
- Высокий контраст
## Метрики и аналитика
- Количество выполненных заданий
- Время выполнения заданий
- Популярность типов заданий
- Конверсия в повторные использования
## Безопасность
- Валидация proof_url на клиенте
- Проверка на бэкенде
- Защита от спама (rate limiting)
- Модерация контента для пользовательских доказательств
## Будущие улучшения
1. **Персонализация**: Задания на основе прогресса пользователя
2. **Социальные фичи**: Совместные задания, лидерборды
3. **Геймификация**: Серии заданий, достижения
4. **AI генерация**: Автоматическое создание заданий
5. **Мобильная интеграция**: QR-коды для внешних заданий

View file

@ -1,709 +0,0 @@
# TODO - mnemo_cards_web_v2
## Status: Active Development
**Last Updated:** November 8, 2025
---
## 🔥 Bug Fixes & Maintenance
### PURCHASE-1: Purchase Page Loading Issue - FIXED ✅
**Priority:** HIGH
**Status:** ✅ COMPLETED
**Time Spent:** 2 hours
**Date Fixed:** November 8, 2025
**Issue:** Purchase page (`/purchase/5`) was not loading due to JSON deserialization problems.
**Root Cause:**
- Constructor `CardPackBuyDto` incorrectly marked nullable fields as required
- UI method `_buildItem` used `item.toString()` which doesn't work for polymorphic Item subclasses
**Solution Applied:**
- Fixed `CardPackBuyDto` constructor to properly handle nullable fields
- Implemented type-safe rendering for different Item types (TextItem, SpacerItem, ButtonItem)
- Added proper spacing and visual elements for each item type
**Result:** Purchase page now loads correctly and displays pack information properly.
---
## 🔥 New Features
### TASKS-1: Tasks System Implementation - PHASE 1 COMPLETE ✅
**Priority:** HIGH
**Status:** ✅ Phase 1 Complete, Ready for Phase 2
**Estimated Time:** 40-60 hours total
**Plan Document:** `TASKS_PLAN.md`
**Goal:** Реализовать механику заданий для mnemo_cards_web_v2 - систему заданий, которые пользователь выполняет как в приложении, так и в реальном мире.
**Current Phase:** Phase 1 (Frontend Infrastructure) - Complete ✅
**Completed in Phase 1:**
- ✅ Created comprehensive task data models (Task, TaskProgress, TaskReward, enums)
- ✅ Implemented TasksRepository with mock data for development
- ✅ Created TasksStateManager with full state management using yx_state
- ✅ Added TasksModule to UserScope with proper dependency injection
- ✅ Built TaskCard widget with rewards display and action buttons
- ✅ Implemented TasksPage with filtering, tabs, and search functionality
- ✅ Added navigation route `/tasks` and updated bottom navigation
- ✅ Updated MainShell to include "Задания" tab
- ✅ Integrated with existing yx_scope/yx_state architecture
- ✅ Created unit tests for all components
**Next Actions:**
- [ ] Phase 2: Backend Integration (API endpoints, real data) - 12-16 hours
- [ ] Phase 3: Advanced Features (task creation, admin panel) - 8-12 hours
- [ ] Phase 4: Polish & Analytics (animations, tracking) - 8-12 hours
- [ ] Phase 5: Testing & Deployment (integration tests, production) - 8-12 hours
See `TASKS_PLAN.md` for complete breakdown.
---
### CHAT-1: Chat Module Implementation - MODULARIZATION COMPLETE ✅
**Priority:** HIGH
**Status:** ✅ Modularization Complete, Ready for Phase 2
**Estimated Time:** 60-80 hours total
**Plan Document:** `CHAT_PLAN.md`
**Goal:** Реализовать функциональность чата для общения пользователя с LLM через сервер, поддерживая текст и аудио сообщения.
**Current Phase:** Phase 1 (Infrastructure) - Complete ✅
**Completed:**
- ✅ **Modularization**: Created separate `mnemo_cards_chat` Flutter package
- ✅ **Architecture**: Clean architecture with ChatRepository interface for loose coupling
- ✅ **Models**: Comprehensive data models (ChatMessage, AudioMessage, ChatSession, ChatParticipant)
- ✅ **Services**: ChatService with business logic and ChatRepository abstraction
- ✅ **State Management**: Simplified ChatStateManager with manual state classes
- ✅ **DI Integration**: ChatModule for yx_scope integration in main application
- ✅ **Code Generation**: All freezed/json_serializable generation working
- ✅ **Compilation**: Module compiles successfully and integrates cleanly
**Next Actions:**
- [ ] Phase 2: UI Components (MessageBubble, ChatInput, AudioRecorder, ChatPage) - 16-20 hours
- [ ] Phase 3: Audio Functionality (recording, playback, Web Audio API) - 12-16 hours
- [ ] Phase 4: Integration & Polish (navigation, error handling, theming) - 8-12 hours
- [ ] Phase 5: Backend Integration & Testing (API endpoints, LLM integration) - 8-12 hours
See `CHAT_PLAN.md` for complete breakdown.
### GT-1: Game Tests Implementation - PLANNING COMPLETE ✅
**Priority:** HIGH
**Status:** 🟡 Planning Complete, Ready to Start
**Estimated Time:** 40-60 hours total
**Plan Document:** `GAME_TESTS_IMPLEMENTATION_PLAN.md`
**Goal:** Реализовать систему игровых тестов в mnemo_cards_web_v2, начиная с простых тестов с выбором 1 варианта из нескольких, с соблюдением архитектуры yx_scope/yx_state.
**Current Phase:** Planning Complete
**Current Phase:** Phase 4 Complete ✅ - UX Improvements FINISHED
**Status:** ✅ **GAME SYSTEM WITH ENHANCED UX READY**
**Successfully Implemented:**
- [x] Phase 1: Basic Infrastructure ✅
- [x] Phase 2: Multiple Choice Tests ✅
- [x] Phase 4: UX Improvements (animations, sounds, theming) ✅
- [x] Phase 5: Advanced Question Types ✅
**Question Types Available:**
- [x] **Multiple Choice** - Fully implemented and working
- [x] **Input Letters** - Fully implemented and working
- [x] **Match** - UI ready, waiting for backend support
- [x] **Matrix** - UI ready, waiting for backend support
**UX Enhancements Added:**
- [x] **Sound Effects** - Complete audio feedback system
- [x] **Animations** - Smooth transitions and visual feedback
- [x] **Dark Theme** - Full compatibility with light/dark themes
- [x] **Performance** - Optimized animations and resource usage
**Remaining Phases (Optional):**
- [ ] Phase 3: Statistics & Analytics (results submission) - 4-6 hours
**Game System is Production Ready!** 🎮✨
See `GAME_TESTS_IMPLEMENTATION_PLAN.md` for complete breakdown.
---
### STAT-1: Statistics System Upgrade - PLANNING COMPLETE ✅
**Priority:** HIGH
**Status:** 🟡 Planning Complete, Ready to Start
**Estimated Time:** 111-144 hours total
**Plan Document:** `STATISTICS_UPGRADE_PLAN.md`
**Goal:** Расширить систему сбора и отображения статистики пользователя для создания детализированной страницы профиля с красивым UI и настройками приложения.
**Current Phase:** Phase 1 - Backend Models and DTOs
**Next Actions:**
- [ ] Phase 1.1: Расширить модели данных (4-6 hours)
- [ ] Phase 1.2: Создать новые API endpoints (8-10 hours)
- [ ] Phase 2.2: Переписать StatisticsService (4-5 hours)
- [ ] Phase 3.1: Редизайн ProfilePage (12-15 hours)
- [ ] Phase 4.1: Создать Settings Page (10-12 hours)
See `STATISTICS_UPGRADE_PLAN.md` for complete breakdown.
---
## 🔴 Critical Issues
### CI-1: Fix Telegram Package Compilation Errors ✅ COMPLETE
**Priority:** HIGH
**Status:** ✅ Complete
**Problem:** `telegram_web_app-0.3.3` package has compilation errors with `JSExportedDartFunction` type
**Impact:** Tests cannot run, app may not compile
**Solution:** Either update package version, remove dependency, or add conditional compilation
---
### CI-2: Card Images Not Displaying ✅ COMPLETE
**Priority:** HIGH
**Status:** ✅ Complete
**Date Fixed:** December 19, 2024
**Problem:** Card word images not showing in packs
**Impact:** Users cannot see card images in pack lists, details, or card viewer
**Root Cause:** Frontend using deprecated `ApiConfig` generating wrong v1 API URLs instead of v2
**Solution:**
- Updated all frontend widgets to use `ApiConfigV2.getCardImageUrl()`
- Modified backend to allow public image access for enabled packs
- Added proper validation (pack exists, enabled, card belongs to pack)
- Enhanced error handling in backend endpoint
**Files Fixed:**
- `lib/presentation/widgets/pack_card_item.dart`
- `lib/presentation/widgets/card_flipper/card_flipper.dart`
- `lib/presentation/widgets/card_viewer.dart`
- `lib/presentation/pages/pack_details/pack_details_page.dart`
- `mnemo_cards_backend/lib/api/v2/packs_api_v2.dart`
**Tests Added:**
- `mnemo_cards_backend/test/api/v2/packs_api_v2_test.dart` (6 new tests) ✅
---
### CI-3: Fix Failing Tests (24 failures)
**Priority:** MEDIUM
**Status:** 🟡 In Progress
**Problem:** 24 tests are failing (177 passing)
**Impact:** Mostly empty test files causing compilation errors
**Action:** Fix test_page_test.dart empty file, investigate other failures
**Notes:** Lower priority - most failures are from empty test files
---
## 🟡 Backend Integration Tasks
### BI-0: API v2 Backend Implementation ✅ PHASE 1.2 COMPLETE
**Priority:** HIGH
**Status:** Phase 1.2 Complete (Auth API)
**Latest Update:** October 29, 2025
**Phase 1.1 - JWT Service ✅ COMPLETE:**
- ✅ Fixed JWT crypto implementation with proper HMAC-SHA256
- ✅ Created RefreshTokenModel Isar model for token storage
- ✅ Implemented token storage, blacklisting, and cleanup methods
- ✅ Written comprehensive unit tests (15 tests, all passing)
**Phase 1.2 - Authentication API v2 ✅ COMPLETE:**
- ✅ Google OAuth flow implemented and tested
- ✅ Token refresh mechanism implemented and tested
- ✅ Logout endpoint with refresh token blacklisting
- ✅ Get current user endpoint
- ✅ Comprehensive integration tests (12 tests, all passing)
- ✅ Improved error handling and error responses
- ✅ Updated HttpRepositoryV2 logout to send refresh token
**Next Steps (Phase 1.3):**
- ⬜ Implement Packs API v2 with pagination and filtering
- ⬜ Implement Tests API v2
- ⬜ Implement remaining v2 APIs (Games, Purchases, Subscriptions, Promocodes)
**Files Created/Modified:**
- `mnemo_cards_backend/lib/api/v2/auth_api_v2.dart`
- `mnemo_cards_backend/lib/api/v2/jwt_service.dart`
- `mnemo_cards_backend/test/api/v2/auth_api_v2_test.dart` ✅ (12 tests)
- `mnemo_cards_backend/test/api/v2/jwt_service_test.dart` ✅ (15 tests)
- `mnemo_cards_web_v2/lib/domain/services/http_repository_v2.dart`
---
### BI-1: Card Flipping Functionality ✅ COMPLETE
**Priority:** MEDIUM
**Status:** ✅ Complete
**Estimated Time:** 0 hours (already implemented)
**Description:** Card flipping functionality is already fully implemented
**Verification:**
- ✅ CardFlipper widget exists and works
- ✅ Card flip UI with animations implemented
- ✅ Progress tracking implemented
- ✅ Integration with PackDetailsPage complete
**Files Verified:**
- `lib/presentation/widgets/card_flipper/card_flipper.dart`
- `lib/domain/services/card_flipper_service.dart`
- `lib/di/user_scope/modules/card_flipper_module.dart`
---
### BI-2: Pack Purchase Functionality ✅ COMPLETE
**Priority:** MEDIUM
**Status:** ✅ Complete
**Date Completed:** November 8, 2025
**Time Spent:** 5 hours
**Description:** Implement pack purchase flow with payment integration
- **Progress:**
- [x] Implemented API v2 client helpers and `PurchasesService` with DI wiring
- [x] Added unit tests validating service → repository delegation
- [x] Created `PurchaseStateManager` with freezed states
- [x] Created `PurchasePage` with YooKassa payment integration
- [x] Added purchase module to DI
- [x] Added purchase route to app_router
- [x] Wrote comprehensive unit tests for state manager
**Features Implemented:**
- [x] Purchase page UI with pack preview
- [x] YooKassa payment integration
- [x] Payment URL launching
- [x] Payment verification dialog
- [x] Success/error states handling
- [x] Purchase state management with yx_state
- [x] Purchase module with DI wiring
**API Endpoints Used:**
- GET `/api/v2/packs/{packId}/buy` - Get purchase page info ✅
- POST `/api/v2/purchases/packs/{packId}` - Create pack purchase intent ✅
- POST `/api/v2/purchases/payments` - Create YooKassa payment ✅
- GET `/api/v2/purchases/payments/{paymentId}/verify` - Verify payment status ✅
**Files Created/Updated:**
- `lib/domain/models/purchase_models.dart`
- `lib/domain/services/http_repository_v2.dart`
- `lib/domain/services/purchases_service.dart`
- `lib/domain/state/purchase_state_manager.dart` ✅ (NEW)
- `lib/di/user_scope/modules/purchase_module.dart` ✅ (NEW)
- `lib/di/user_scope/modules/purchases_module.dart`
- `lib/di/user_scope/user_scope.dart`
- `lib/di/user_scope/user_scope_container.dart`
- `lib/presentation/pages/purchase/purchase_page.dart` ✅ (NEW)
- `lib/presentation/router/app_router.dart`
- `test/domain/services/purchases_service_test.dart`
- `test/domain/state/purchase_state_manager_test.dart` ✅ (NEW)
---
### BI-2B: Pack Purchase Status Check ✅ COMPLETE
**Priority:** HIGH
**Status:** ✅ Complete
**Date Completed:** November 8, 2025
**Time Spent:** 2 hours
**Description:** Modify PackDetailsPage to check pack purchase status and redirect to purchase page if pack is not purchased.
**Features Implemented:**
- [x] Updated PackDetailsPage to use `GetCardPackResponse` union type
- [x] Added purchase status check in `_loadPack()` method
- [x] Implemented automatic redirect to `/purchase/:packId` for unpurchased packs
- [x] Maintained proper loading and error states
- [x] Updated all methods to handle `CardPackDto` type casting
- [x] Verified app compiles successfully with new logic
**Technical Implementation:**
- [x] Response type checking: `packResponse.responseType == GetCardPackResponseType.buy`
- [x] Automatic redirect: `context.push('/purchase/${widget.packId}');` for unpurchased packs
- [x] Type safety: Proper `as CardPackDto` casting after purchase verification
- [x] Backward compatibility: All existing functionality preserved for purchased packs
**User Experience:**
- [x] Unpurchased packs: Direct redirect to purchase page (no details shown)
- [x] Purchased packs: Full pack details page with all features
- [x] Error states: Proper error handling for network issues
- [x] Loading states: Smooth loading experience maintained
**Files Modified:**
- `lib/presentation/pages/pack_details/pack_details_page.dart`
---
### BI-2A: Ads Reward Unlock Flow ✅ COMPLETE
**Priority:** HIGH
**Status:** ✅ Complete - Real Adsgram Integration
**Date Completed:** November 8, 2025
**Time Spent:** 6 hours
**Description:** Allow users to unlock specific packs/products on the web by watching a rewarded ad, similar to the mobile experience.
**Progress:**
- [x] Implemented AdsRewardService, AdsRewardStateManager, and user scope module with unit tests
- [x] Added animated shuffle transitions for pack card grid/list views
- [x] Created AdsRewardButton widget with state management integration
- [x] Integrated AdsRewardButton into pack_details_page.dart
- [x] Added Adsgram SDK integration for rewarded ads
- [x] Added loading, success, and error states to UI
- [x] Wrote widget tests for AdsRewardButton
**Features Implemented:**
- [x] Detect packs eligible for ad unlock and surface CTA in UI
- [x] Integrate Adsgram rewarded ad web SDK with proper lifecycle handling
- [x] Track ad playback state, completion, and failure
- [x] Call `/ads/product/acquire/<key>` upon rewarded completion and refresh user entitlements
- [x] Provide user feedback (loading, success, retry prompts)
- [x] Emit analytics events for impressions, completions, failures
- [x] Added Adsgram block ID configuration (16505)
- [x] Implemented reward callback endpoint `/adsgram/reward?userId=[userId]`
- [x] JavaScript interop with bidirectional callbacks
- [x] Real Adsgram SDK integration (no simulation)
- [x] Enhanced web/foos.js with callback system
**API Endpoints Used:**
- POST `/ads/product/acquire/<key>` - Grant product after rewarded ad ✅
- GET `/api/v2/packs/{packId}/buy` - Check ad availability ✅
- GET `/api/v2/adsgram/reward?userId={userId}` - Adsgram reward callback ✅
**Files Created/Updated:**
- `lib/presentation/widgets/ads_reward_button.dart` ✅ (NEW)
- `lib/domain/config/api_config_v2.dart` ✅ (ads config)
- `lib/presentation/pages/pack_details/pack_details_page.dart` ✅ (integration)
- `pubspec.yaml` ✅ (adsgram dependency)
- `test/presentation/widgets/ads_reward_button_test.dart` ✅ (NEW)
---
### BI-3: Subscription Management
**Priority:** MEDIUM
**Status:** 🟡 Partial (SubscriptionService exists)
**Estimated Time:** 4-6 hours
**Description:** Complete subscription purchase and management
**Features Needed:**
- [ ] Subscription page UI
- [ ] View available subscription plans
- [ ] Purchase subscription
- [ ] Cancel subscription
- [ ] Show subscription status on ProfilePage
**API Endpoints:**
- GET `/subscription/page` - Get subscription info ✅ (implemented)
- POST `/subscription/add` - Purchase subscription ✅ (implemented)
- POST `/subscription/delete/<id>` - Cancel subscription
**Files to Create:**
- `lib/presentation/pages/subscription/subscription_page.dart`
- Update `subscription_service.dart` with cancel method
- Add route to `app_router.dart`
---
### BI-4: Vocabulary/Review Page
**Priority:** LOW
**Status:** ⬜ Not Started
**Estimated Time:** 6-8 hours
**Description:** Create vocabulary page to review all learned words across packs
**Features Needed:**
- [ ] VocabularyPage in bottom navigation
- [ ] Display all learned cards
- [ ] Filter by pack, language
- [ ] Search functionality
- [ ] Review cards
- [ ] Export vocabulary
**API Endpoints:**
- GET `/cards` - Fetch all cards
- GET `/user/data` - Get user's learning progress
**Files to Create:**
- `lib/presentation/pages/vocabulary/vocabulary_page.dart`
- `lib/domain/services/vocabulary_service.dart`
- `lib/domain/state/vocabulary_state_manager.dart`
- `lib/di/user_scope/modules/vocabulary_module.dart`
---
### BI-5: Promocode Functionality
**Priority:** LOW
**Status:** 🟡 Partial (Service migrated; awaiting UI)
**Estimated Time:** 3-4 hours
**Description:** UI for entering and applying promocodes
**Features Needed:**
- [ ] Promocode input field on ProfilePage or PurchasePage
- [ ] Apply promocode
- [ ] Show promocode benefits
- [ ] Validate promocode
**API Endpoints:**
- POST `/user/promocode` - Apply promocode ✅ (implemented)
- GET `/promocode/list` - List available promocodes ✅ (implemented)
**Files to Create:**
- `lib/presentation/widgets/promocode_input.dart`
- Update `promocode_service.dart` UI integration
---
### BI-6: Settings Page
**Priority:** LOW
**Status:** ⬜ Not Started
**Estimated Time:** 2-3 hours
**Description:** Separate settings page (currently settings are in ProfilePage)
**Features Needed:**
- [ ] Separate SettingsPage
- [ ] Theme toggle
- [ ] Language selection
- [ ] Sound effects toggle
- [ ] Notifications settings
- [ ] Account settings
**API Endpoints:**
- POST `/user/settings` - Update user settings
**Files to Create:**
- `lib/presentation/pages/settings/settings_page.dart`
- `lib/domain/state/settings_state_manager.dart`
---
### BI-7: Card Images Display ✅ COMPLETE
**Priority:** HIGH
**Status:** ✅ Complete
**Estimated Time:** 0 hours (already implemented)
**Description:** Display card images in PackDetailsPage and CardFlipper
**Features Needed:**
- [x] Fetch card images from backend (using Image.network with ApiConfig.getCardImageUrl)
- [x] Display in card list (PackDetailsPage._buildCardImage)
- [x] Display in card viewer (CardViewer._buildImage)
- [x] Display in card flipper (CardFlipper._buildImage)
**Notes:** Card images are already fully implemented using Image.network. Flutter handles caching automatically. No additional work needed.
---
### BI-8: Card Flipper Responsive Layout ✅ COMPLETE
**Priority:** MEDIUM
**Status:** ✅ Complete
**Estimated Time:** 2 hours
**Description:** Align web CardFlipper experience with mobile adaptive behavior by introducing responsive layouts while preserving existing state and animations.
**Features Delivered:**
- [x] Breakpoint resolver (compact / medium / expanded) via `LayoutBuilder`
- [x] Adaptive card sizing that respects viewport height and width
- [x] Responsive progress indicator and control clusters per breakpoint
- [x] Optional `stateManagerOverride` parameter for isolated widget testing
- [x] Widget tests covering compact, tablet, wide desktop, and tall desktop scenarios
**Notes:** No backend changes required. Verify new widget tests in `card_flipper_responsive_test.dart` during CI.
---
### BI-9: Card Viewer Study Flow ✅ COMPLETE
**Priority:** MEDIUM
**Status:** ✅ Complete
**Estimated Time:** 2 hours
**Description:** Launch fullscreen study mode directly from pack card taps, mirroring mobile UX without redundant controls.
**Features Delivered:**
- [x] Removed dedicated “Изучение” CTA from pack controls
- [x] Routed taps through `CardViewer` with ordered card lists (shuffle + favorites aware)
- [x] Started study at tapped card index with consistent navigation
- [x] Added widget tests covering initial index, swiping order, and flip interaction
**Notes:** Learning progress marking remains handled externally via `_markCardLearned`. Future enhancements can add per-card callbacks if needed.
---
### BI-10: Pack Details Shuffle Animation ✅ COMPLETE
**Priority:** LOW
**Status:** ✅ Complete
**Estimated Time:** 1 hour
**Description:** Make pack card shuffling feel responsive and delightful with animated transitions and control feedback.
**Features Delivered:**
- [x] Added reusable `ShuffleAnimatedSwitcher` for fade + scale transitions across grid/list shuffles
- [x] Highlighted shuffle control with active state styling and `AnimatedRotation` feedback
- [x] Animated card reordering with movement-aware wrappers plus widget/unit coverage
**Notes:** Animation is triggered whenever shuffle/favorites state changes via `_shuffleAnimationKey`. Scroll position resets intentionally to showcase rearranged cards.
---
## 🟢 Quality & Testing Tasks
### QT-1: Increase Test Coverage
**Priority:** MEDIUM
**Status:** 🔴 In Progress
**Progress:** ~70% coverage
**Areas Needing Tests:**
- [ ] pack_progress_service_test.dart
- [ ] promocode_service_test.dart (partial)
- [ ] subscription_service_test.dart (partial)
- [ ] card_flipper_service_test.dart
- [ ] All new pages
---
### QT-2: Fix Linter Issues
**Priority:** LOW
**Status:** ⬜ Not Started
**Action:** Run `flutter analyze` and fix all warnings
---
### QT-3: Integration Tests
**Priority:** LOW
**Status:** ⬜ Not Started
**Tests Needed:**
- [ ] Full auth flow
- [ ] Pack browsing and purchase
- [ ] Test taking flow
- [ ] Card learning flow
---
## 🚫 Blocked/Deferred Tasks
### BD-1: Telegram Authentication ✅ COMPLETE
**Priority:** MEDIUM
**Status:** ✅ Complete
**Completion Date:** November 8, 2025
**Outcome:** Web-initiated Telegram login bridge with 5-minute codes, bot claims, and improved web UI.
**Highlights:**
- Implemented backend `/auth/telegram/web-code`, `/claim-code`, and `/code-status/{code}` endpoints
- Updated Telegram bot to accept `login_<code>` payloads and keep `/code` fallback
- Added web login UI for code generation, bot deep-link, status polling, and auto-login
- Created unit tests for auth service helpers and code status parsing
---
### UI-1: PackTip Support Implementation ✅ COMPLETE
**Priority:** MEDIUM
**Status:** ✅ Complete
**Estimated Time:** 3 hours
**Actual Time:** 5 hours
**Description:** Add support for CardPackPreviewDto.tip field to display small icons or badges in corners or right side of pack cards, adapting PackTip functionality from mobile app to web version for both horizontal and vertical card layouts.
**Completed Tasks:**
- ✅ Created PackTipExt extension for PackTip.build() method
- ✅ Implemented support for all PackTipType variants (asset, base64, text, unknown)
- ✅ Added _buildPackTip() method to PackCard widget (horizontal layout)
- ✅ Added _buildPackTip() method to PackCardVertical widget (vertical layout)
- ✅ Implemented support for all PackTipPosition values (topRight, bottomRight, fullRight)
- ✅ Adapted fullRight positioning: right side for horizontal, bottom banner for vertical cards
- ✅ Refactored both card layouts to use Stack for tip overlays
- ✅ Added proper theming and error handling
- ✅ Verified build success and code quality
**Files Created/Modified:**
- `lib/utils/pack_tip_extension.dart` - PackTipExt extension
- `lib/presentation/widgets/pack_card.dart` - PackTip integration for horizontal cards
- `lib/presentation/widgets/pack_card_vertical.dart` - PackTip integration for vertical cards
**Technical Details:**
- Extension pattern for clean PackTip rendering
- Stack-based overlay system for tip positioning on both card types
- Adaptive positioning logic for horizontal vs vertical layouts
- Full compatibility with mobile PackTip system
- Type-safe implementation with proper error handling
**Next Steps:**
- Test with real backend PackTip data
- Monitor performance with multiple tips
- Consider animation enhancements
---
### BD-2: API v2 Implementation 🔄 IN PROGRESS
**Priority:** HIGH
**Status:** 🟡 In Progress
**Estimated Time:** 34-46 hours for core work
**Description:** Implement API v2 with OAuth2/JWT, RESTful patterns, and versioning
**Current Status:**
- ✅ Backend: AuthApiV2, JwtService, authorizeV2 middleware created
- ✅ Web: ApiConfigV2, HttpRepositoryV2 created
- ✅ AuthService migrated to use v2
- ⚠️ Backend: JWT crypto needs proper implementation
- ⚠️ Backend: Remaining v2 endpoints need implementation
- ⚠️ Web: Remaining services need migration to v2
**See:** `FUTURE_TASKS_PLAN.md` for detailed breakdown
---
## 📊 Progress Summary
**Total Tasks:** 18
**Completed:** 1
**In Progress:** 2
**Not Started:** 13
**Blocked/Deferred:** 2
**Priority Breakdown:**
- 🔴 HIGH: 5 tasks
- 🟡 MEDIUM: 7 tasks
- 🟢 LOW: 5 tasks
---
## 🎯 Recommended Next Steps (See FUTURE_TASKS_PLAN.md for details)
### Immediate Priority (Phase 1 - Backend v2)
1. **Fix JWT Service** - Use proper crypto library for HMAC-SHA256
2. **Complete Auth API v2** - Test and verify Google OAuth flow
3. **Implement Packs API v2** - Complete all pack endpoints
4. **Implement Tests API v2** - Complete test endpoints
5. **Implement remaining v2 APIs** - Games, Purchases, Subscriptions, Promocodes
### Next Priority (Phase 2 - Web Migration)
1. **Complete HttpRepositoryV2** - Add all missing methods
2. **Migrate PackManager** - Update to use v2
3. **Migrate remaining services** - GamesManager, TestManager, etc.
4. **Remove v1 dependencies** - Clean up deprecated code
### After Migration (Phase 3 - Features)
1. **Pack Purchase Flow** - Implement purchase UI and flow
2. **Subscription Management** - Complete subscription UI
3. **Promocode UI** - Add promocode input and application
**For complete detailed plan, see:** `FUTURE_TASKS_PLAN.md`
---
**Note:** Tasks are prioritized based on:
- User impact
- Technical dependencies
- Development effort
- Backend availability

View file

@ -1,291 +0,0 @@
# 🔧 Устранение неполадок (Troubleshooting)
## 404 Error на `/packs/previews`
### Симптомы
```
GET http://localhost:8000/packs/previews 404 (Not Found)
```
### Причины и решения
#### 1⃣ Backend запущен старой версией
**Проверка:**
```bash
curl http://localhost:8000/packs/previews -H "app_version: 1.1.0"
# Если возвращает: {"detail":"Not Found"}
```
**Решение:**
```bash
cd mnemo_cards_backend
./restart_dev.sh
```
Или вручную:
```bash
# Остановить старый процесс
kill -9 $(lsof -ti:8000)
# Запустить заново
./run_dev.sh
```
#### 2⃣ Backend не запущен
**Проверка:**
```bash
lsof -ti:8000
# Если ничего не выводит - backend не запущен
```
**Решение:**
```bash
cd mnemo_cards_backend
./run_dev.sh
```
#### 3⃣ Неправильный порт в frontend
**Проверка:**
Откройте `mnemo_cards_web_v2/lib/domain/config/api_config.dart`:
```dart
static String get baseUrl => const String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'http://localhost:8000', // ← Должен быть 8000
);
```
**Решение:**
Если порт неправильный, исправьте и перезапустите Flutter:
```bash
# Ctrl+C чтобы остановить
flutter run -d chrome
```
#### 4⃣ Generated код устарел
**Проверка:**
Если вы изменяли `@Route` аннотации в backend
**Решение:**
```bash
cd mnemo_cards_backend
dart run build_runner build --delete-conflicting-outputs
./run_dev.sh
```
---
## CORS Error
### Симптомы
```
Access to XMLHttpRequest at 'http://localhost:8000/...' from origin '...'
has been blocked by CORS policy
```
**См. [CORS_FIX.md](CORS_FIX.md) для подробного решения**
**Быстрое решение:**
1. Убедитесь что backend запущен с новой версией (с CORS настройками)
2. Перезапустите backend: `./restart_dev.sh`
3. Очистите кэш браузера: Ctrl+Shift+Delete
4. Перезагрузите страницу: Ctrl+R
---
## Проблемы с авторизацией
### Симптомы
```
GET http://localhost:8000/pack/123 401 (Unauthorized)
```
### Причины
Некоторые endpoints требуют авторизации:
- `/pack/:id` - требует user_token
- `/packs/actions` - требует user_token
- `/user` - требует user_token
Endpoints БЕЗ авторизации:
- ✅ `/packs/previews` - доступен всем
- ✅ `/games` - доступен всем
- ✅ `/user/create` - для создания пользователя
### Решение
1. Пройдите авторизацию через Google Sign-In
2. Token должен автоматически сохраниться
3. Все последующие запросы будут включать token
**Проверка token:**
Откройте DevTools → Application → Local Storage → Shared Preferences
Должен быть ключ `auth_token`
---
## Backend не стартует
### Симптом 1: Port already in use
```
SocketException: Failed to create server socket (OS Error: Address already in use)
```
**Решение:**
```bash
# Найти и убить процесс на порту 8000
kill -9 $(lsof -ti:8000)
# Или использовать другой порт
dart run lib/main.dart -p 8001 --isar isar --workdir $(pwd)
```
### Симптом 2: Isar database locked
```
IsarError: Database is already open in another instance
```
**Решение:**
```bash
# Закрыть все процессы использующие Isar
pkill -f dart
# Удалить lock файл
rm -rf isar/*.lock
# Перезапустить
./run_dev.sh
```
### Симптом 3: Missing dependencies
```
Error: Could not resolve the package 'some_package'
```
**Решение:**
```bash
dart pub get
./run_dev.sh
```
---
## Flutter Web не запускается
### Симптом 1: Chrome not found
**Решение:**
```bash
# Укажите путь к Chrome
export CHROME_EXECUTABLE="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
flutter run -d chrome
```
### Симптом 2: Build failed
**Решение:**
```bash
flutter clean
flutter pub get
flutter run -d chrome
```
---
## Диагностические команды
### Проверить backend
```bash
# Запущен ли backend
lsof -ti:8000
# Доступен ли API
curl http://localhost:8000/games
# Проверить CORS
curl -X OPTIONS -H "Origin: http://localhost:8080" http://localhost:8000/games -v
```
### Проверить frontend config
```bash
# Показать текущий API URL
grep -A2 "baseUrl" mnemo_cards_web_v2/lib/domain/config/api_config.dart
```
### Логи backend
Backend выводит все запросы в консоль:
```
[app] GET /packs/previews
[app] POST /user/create
```
Смотрите терминал где запущен `./run_dev.sh`
### Логи frontend
Откройте DevTools (F12) → Console
Все HTTP ошибки будут показаны там
---
## Полезные скрипты
### Backend
```bash
cd mnemo_cards_backend
# Запуск
./run_dev.sh
# Перезапуск с регенерацией кода
./restart_dev.sh
# Тестирование API
./test_api.sh
```
### Frontend
```bash
cd mnemo_cards_web_v2
# Запуск
flutter run -d chrome
# Тесты
flutter test
# Анализ кода
flutter analyze
```
---
## Еще помогает?
1. ✅ Перезагрузите IDE (Cursor/VS Code)
2. ✅ Перезагрузите терминалы
3. ✅ Очистите кэш Flutter: `flutter clean`
4. ✅ Обновите зависимости: `flutter pub get`
5. ✅ Проверьте что используете правильную ветку git
6. ✅ Проверьте `.gitignore` - может файлы не закоммичены
---
## Дополнительные ресурсы
- [QUICK_START.md](QUICK_START.md) - Быстрый старт
- [DEV_SETUP.md](DEV_SETUP.md) - Инструкция по разработке
- [CORS_FIX.md](CORS_FIX.md) - Решение CORS проблем
- [API_INTEGRATION_TEMP.md](API_INTEGRATION_TEMP.md) - API документация
---
**Если ничего не помогло - создайте issue с:**
1. Версия Flutter (`flutter --version`)
2. Версия Dart (`dart --version`)
3. OS версия
4. Полный текст ошибки
5. Логи backend и frontend

View file

@ -1,168 +0,0 @@
# Backend Integration Work - Complete
**Date:** October 28, 2025
**Project:** mnemo_cards_web_v2
**Objective:** Integrate backend with web app
---
## ✅ Completed Tasks
### Task 1: Pack Images Display (100% Complete)
**What Was Done:**
- Created `ImageCacheService` for caching decoded base64 images
- Created `ImageCacheModule` and integrated into UserScope
- Updated `PackCard` widget to display cached pack cover images
- Updated `PackDetailsHeader` to display cached pack icons
- Maintained Hero animations for smooth transitions
- Graceful fallback to placeholder icons for missing images
**Results:**
- ✅ 15 comprehensive unit tests written and passing
- ✅ Zero linter errors
- ✅ Clean architecture maintained
- ✅ Performance optimized with caching
**Files Created:**
- `lib/domain/services/image_cache_service.dart`
- `lib/di/user_scope/modules/image_cache_module.dart`
- `test/domain/services/image_cache_service_test.dart`
**Files Modified:**
- `lib/di/user_scope/user_scope.dart`
- `lib/di/user_scope/user_scope_container.dart`
- `lib/presentation/widgets/pack_card.dart`
- `lib/presentation/widgets/pack_details_header.dart`
---
### Task 2: Tests Functionality Verification (100% Complete)
**What Was Done:**
- Verified `TestManager` service integration with `HttpRepository`
- Wrote 6 comprehensive unit tests for TestManager
- Verified full test flow: PackDetailsPage → TestPage
- Confirmed test loading, taking, completing, and result display
- Verified statistics submission to backend
- Confirmed progress tracking during tests
**Results:**
- ✅ 6 comprehensive unit tests written and passing
- ✅ All acceptance criteria met
- ✅ No navigation or state management issues
- ✅ Clean code with proper error handling
**Files Created:**
- `test/domain/services/test_manager_test.dart`
**Files Verified:**
- `lib/domain/services/test_manager.dart`
- `lib/presentation/pages/test/test_page.dart`
- `lib/presentation/pages/pack_details/pack_details_page.dart`
---
## ❌ Deferred Tasks
### Task 3: Telegram Code-Based Authentication
**Status:** BLOCKED
**Reason:** Requires backend API endpoints that don't currently exist
**What Would Be Needed:**
- Backend endpoints: `/auth/telegram/request`, `/auth/telegram/verify`
- Telegram bot modifications to handle `/auth` command
- Code generation and storage mechanism
- Code timeout and validation logic
**Decision:** Deferred until backend team can implement required endpoints
---
### Task 4: API v2 Design
**Status:** DEFERRED
**Reason:** Major refactoring outside current scope
**What Would Be Needed:**
- Migration from custom auth to standard OAuth2/JWT
- RESTful API patterns
- API versioning strategy
- Comprehensive backend refactoring
**Decision:** Deferred as this requires major backend architectural changes
---
## 📊 Overall Impact
### Tests Added
- **ImageCacheService:** 15 tests
- **TestManager:** 6 tests
- **Total New Tests:** 21 tests
- **All Tests Passing:** 134/134 ✅
### Code Quality
- ✅ Zero linter errors introduced
- ✅ Clean architecture maintained throughout
- ✅ Follows yx_scope and yx_state patterns
- ✅ Comprehensive error handling
### Progress
- **Before:** ~85% complete (Stage 6)
- **After:** ~88% complete (Stage 6+ with backend integration)
- **Improvement:** +3% overall progress
---
## 🎯 Acceptance Checklist
- [x] Builds successfully
- [x] Linters/type checks pass
- [x] All existing tests pass
- [x] New tests cover new behavior
- [x] PROGRESS.md updated
- [x] Tasks.md updated
- [x] workflow_state.md updated
- [x] Clean architecture maintained
- [x] No breaking changes introduced
---
## 📝 Notes for Future Work
1. **Pack Images:**
- Images load from base64 in API responses (CardPackPreviewDto.imageBase64)
- Cached using ImageCacheService (similar to mobile app's ImagesHolder)
- Consider adding image preloading for better UX
2. **Tests Functionality:**
- Currently uses simplified statistics (AllWordsStatisticsDto.empty())
- Consider enhancing to capture detailed word-level statistics
- Test results history view could be added as enhancement
3. **Telegram Auth:**
- Requires backend API development
- Bot modifications needed
- Consider security implications of code-based auth
4. **API v2:**
- Major refactoring project
- Should involve full backend team
- Consider gradual migration strategy
---
## ✨ Conclusion
Successfully completed 2 of 2 achievable tasks without backend modifications. The web app now:
- ✅ Displays pack cover images with caching
- ✅ Has fully functional and tested test-taking flow
- ✅ Maintains clean architecture and code quality
- ✅ Has 21 new passing tests
Tasks 3 and 4 are properly documented and deferred pending backend support.
**Work Status:** COMPLETE ✅

View file

@ -61,23 +61,54 @@ class HttpRepositoryV2 {
(uri != null && uri.path.endsWith(ApiConfigV2.authRefresh)); (uri != null && uri.path.endsWith(ApiConfigV2.authRefresh));
} }
/// Check if the request path is a public auth endpoint (doesn't require token)
bool _isPublicAuthRequest(String path, Uri? uri) {
// Normalize path - remove /api/v2 prefix if present
String normalizedPath = uri?.path ?? path;
if (normalizedPath.startsWith('/api/v2')) {
normalizedPath = normalizedPath.substring('/api/v2'.length);
}
// Ensure path starts with /
if (!normalizedPath.startsWith('/')) {
normalizedPath = '/$normalizedPath';
}
// Check exact matches
if (normalizedPath == ApiConfigV2.authGoogle ||
normalizedPath == ApiConfigV2.authTelegram ||
normalizedPath == ApiConfigV2.authTelegramWebCode ||
normalizedPath == ApiConfigV2.authRefresh) {
return true;
}
// Check dynamic paths (e.g., /auth/telegram/code-status/<code>)
if (normalizedPath.startsWith('/auth/telegram/code-status/')) {
return true;
}
return false;
}
void _setupInterceptors() { void _setupInterceptors() {
_dio.interceptors.add( _dio.interceptors.add(
InterceptorsWrapper( InterceptorsWrapper(
onRequest: (options, handler) async { onRequest: (options, handler) async {
// Check if this is a refresh token request - skip auth for it // Check if this is a refresh token request - skip auth for it
final isRefreshRequest = _isRefreshRequest(options.path, options.uri); final isRefreshRequest = _isRefreshRequest(options.path, options.uri);
// Check if this is a public auth endpoint - skip auth for it
final isPublicAuthRequest = _isPublicAuthRequest(options.path, options.uri);
// Add Bearer token for authenticated requests (except refresh) // Add Bearer token for authenticated requests (except refresh and public auth endpoints)
if (!isRefreshRequest) { if (!isRefreshRequest && !isPublicAuthRequest) {
final token = await getAccessToken(); final token = await getAccessToken();
if (token != null) { if (token != null) {
options.headers['Authorization'] = 'Bearer $token'; options.headers['Authorization'] = 'Bearer $token';
} }
} }
// Skip verbose logging for refresh requests to reduce spam // Skip verbose logging for refresh and public auth requests to reduce spam
if (!isRefreshRequest) { if (!isRefreshRequest && !isPublicAuthRequest) {
log( log(
'API v2 Request: ${options.method} ${options.path}\n' 'API v2 Request: ${options.method} ${options.path}\n'
'Headers: ${options.headers.containsKey('Authorization') ? 'Bearer token present' : 'No auth'}', 'Headers: ${options.headers.containsKey('Authorization') ? 'Bearer token present' : 'No auth'}',
@ -88,13 +119,17 @@ class HttpRepositoryV2 {
return handler.next(options); return handler.next(options);
}, },
onResponse: (response, handler) { onResponse: (response, handler) {
// Skip verbose logging for refresh requests to reduce spam // Skip verbose logging for refresh and public auth requests to reduce spam
final isRefreshRequest = _isRefreshRequest( final isRefreshRequest = _isRefreshRequest(
response.requestOptions.path, response.requestOptions.path,
response.requestOptions.uri, response.requestOptions.uri,
); );
final isPublicAuthRequest = _isPublicAuthRequest(
response.requestOptions.path,
response.requestOptions.uri,
);
if (!isRefreshRequest) { if (!isRefreshRequest && !isPublicAuthRequest) {
log( log(
'API v2 Response: ${response.statusCode} ${response.requestOptions.path}', 'API v2 Response: ${response.statusCode} ${response.requestOptions.path}',
name: 'HttpRepositoryV2', name: 'HttpRepositoryV2',
@ -108,6 +143,10 @@ class HttpRepositoryV2 {
requestPath, requestPath,
error.requestOptions.uri, error.requestOptions.uri,
); );
final isPublicAuthRequest = _isPublicAuthRequest(
requestPath,
error.requestOptions.uri,
);
// Check if we've already attempted refresh for this request // Check if we've already attempted refresh for this request
final hasAttemptedRefresh = final hasAttemptedRefresh =
@ -116,9 +155,11 @@ class HttpRepositoryV2 {
// Handle 401 Unauthorized - try to refresh token // Handle 401 Unauthorized - try to refresh token
// But don't try to refresh if: // But don't try to refresh if:
// 1. This IS the refresh request itself // 1. This IS the refresh request itself
// 2. We've already attempted refresh for this request (prevent infinite loops) // 2. This IS a public auth endpoint (shouldn't need token)
// 3. We've already attempted refresh for this request (prevent infinite loops)
if (error.response?.statusCode == 401 && if (error.response?.statusCode == 401 &&
!isRefreshRequest && !isRefreshRequest &&
!isPublicAuthRequest &&
!hasAttemptedRefresh) { !hasAttemptedRefresh) {
// Mark this request as having attempted refresh // Mark this request as having attempted refresh
error.requestOptions.extra[_refreshAttemptedKey] = true; error.requestOptions.extra[_refreshAttemptedKey] = true;