Files
samreshu_docs/intro.md
Anton 99cd8ae727 docs: add full project documentation
- Architecture: overview, 7 ADR, tech stack
- Principles: code-style, git-workflow, security
- API contracts: auth, profile, tests, admin endpoints
- Database schema: tables, relationships, indexes
- LLM strategy: prompts, fallback, validation, Qwen 2.5 14B
- Onboarding: setup, Docker, .env template
- Progress: roadmap, changelog
- Agents: context, backend instructions

Made-with: Cursor
2026-03-04 12:07:17 +03:00

574 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Вводная часть
Веб‑приложение, в котором авторизованный пользователь выбирает стек (HTML/CSS/JS/Web basics) и уровень (базовый/начинающий), получает тест из 10 или 20 теоретических вопросов, сгенерированных LLM, отвечает, а в конце видит результат с разбором ошибок.
## Минимальный MVP
Регистрация / логин / выход
```text
✅ Подтверждение email
✅ Восстановление пароля
✅ Профиль (никнейм, страна)
✅ Создание теста (стек + уровень + количество вопросов)
✅ Прохождение теста (вопросы, таймер, прогресс)
✅ Результаты (балл, разбор, объяснения)
✅ Базовая история (последние 10 тестов)
✅ LLM генерация вопросов + fallback на банк
✅ Минимальная админка (QA очередь вопросов)
```
## Максимальный MVP (целевое состояние продукта)
Это не то, что делаем сейчас — это то, к чему ведём. Все решения в коде, БД и архитектуре принимаем с оглядкой на эту картину.
### Пользователи и роли
```text
Guest → видит лендинг, описание тарифов, примеры вопросов
Free → базовый функционал, 5 тестов/день, 3 стека
Pro → полный функционал, безлимит, все стеки
Admin → модерация контента, управление пользователями
```
### Модули и их максимальный объём
#### Auth
```text
✅ Email + пароль
✅ Подтверждение email
✅ Восстановление пароля
✅ OAuth (GitHub + Google)
✅ 2FA (TOTP: Google Authenticator)
✅ Управление сессиями (список устройств, logout везде)
```
#### Профиль
```text
✅ Никнейм, аватар, страна, город
✅ Уровень (jun/mid/sen — самооценка)
✅ Статистика на странице профиля
✅ Публичный профиль (по username)
✅ Приватность (скрыть из рейтингов)
```
#### Тестирование
```text
✅ Стеки: HTML, CSS, JS, TS, React, Vue, Node.js, Git, Web basics
✅ Уровни: Базовый, Начинающий, Средний, Продвинутый, Эксперт
✅ Типы вопросов:
- Single choice
- Multiple select
- True/False
- Short text (LLM-верификация)
- Code reading (что выведет код) ← Phase 3
- Bug fixing (найди ошибку) ← Phase 3
✅ Режимы:
- Фиксированный (10/20/30 вопросов)
- Бесконечный (только Pro)
- Марафон (100 вопросов, только Pro) ← Phase 3
✅ Таймер (на весь тест или на вопрос)
✅ Подсказки (Pro, 1 на вопрос)
✅ Пауза теста (сохранение прогресса) ← Phase 2
```
#### Результаты и аналитика
```text
✅ Итоговый экран (балл, время, статус)
✅ Детальный разбор (вопрос → ответ → объяснение)
✅ История всех попыток (фильтры, поиск)
✅ Статистика по темам (% правильных)
✅ График прогресса по времени
✅ Слабые места + LLM-рекомендации (Pro)
✅ Экспорт истории в CSV (Pro)
```
#### Рейтинги (Pro)
```text
✅ Глобальный лидерборд (Top 100)
✅ Рейтинг по стекам
✅ Сезонный рейтинг (ежемесячный)
✅ Позиция пользователя (даже вне Top 100)
✅ Бейджи и достижения
✅ Архив сезонов
```
#### Подписка и биллинг
```text
✅ Free план (всегда)
✅ Pro: 699₽/мес или 6999₽/год
✅ Пробный период 5 дней (с привязкой карты)
✅ Автопродление / отмена
✅ ЮKassa (основной провайдер)
✅ CloudPayments (резервный)
✅ Региональные цены (Казахстан, Беларусь, Закавказье)
✅ Промокоды и скидки
✅ История платежей в ЛК
```
#### Уведомления
```text
✅ Email: verify, reset, trial, billing
✅ In-app баннеры и тосты
✅ Telegram-бот (Phase 3)
✅ Push-уведомления (Phase 3)
```
#### Контент / LLM
```text
✅ Генерация вопросов по стеку/уровню/типу
✅ Проверка short text через LLM
✅ Подсказки (один наводящий вопрос)
✅ LLM-рекомендации по слабым местам
✅ Мультимодельная оркестрация (local + cloud fallback)
✅ Банк вопросов с QA-циклом
✅ Кэш и переиспользование вопросов
```
#### Админка
```text
✅ QA очередь вопросов (approve/reject/edit)
✅ Управление пользователями (бан, сброс лимитов)
✅ Просмотр жалоб на вопросы
✅ Операционная панель (метрики, ошибки)
✅ Управление промокодами
✅ Прогрев кэша вопросов
```
***
### Полная схема данных (ориентир)
```text
users
├── subscriptions (план, статус, даты)
├── sessions (устройства, refresh токены)
├── oauth_accounts (GitHub/Google)
├── totp_secrets (2FA)
├── tests
│ └── test_questions (снепшот вопросов)
├── user_stats (агрегаты по темам)
├── user_achievements (бейджи)
└── user_question_log (какие вопросы видел, когда)
question_bank
├── question_cache_meta (LLM метаданные)
└── question_reports (жалобы)
payments
└── payment_events (webhook лог)
audit_logs (действия админов)
notifications_log (история отправок)
promo_codes (промокоды)
```
***
### Что закладываем архитектурно с первого дня
Это **принципы, не обсуждаемые** при написании любого кода:
```text
1. user.plan всегда читается из БД через subscription middleware
→ никогда не хардкодить права в контроллерах
2. Вопросы копируются в test_questions при старте теста (снепшот)
→ никогда не читать question_bank "живьём" во время теста
3. Все LLM-вызовы только через LlmService
→ остальной код не знает какая модель работает
4. Все внешние события (webhooks, LLM) валидируются по JSON-схеме
→ никогда не доверять внешним данным без валидации
5. Все проверки прав и лимитов только на backend
→ frontend только отображает состояние
6. Все даты хранятся в UTC
→ конвертация в часовой пояс только на фронте
7. Все конфигурации через env переменные
→ никаких хардкодов в коде
```
***
### Фазы разработки
```text
MVP 0 (сейчас)
└── Auth + Test (2 стека) + Results + Базовая история
Phase 1 (платный запуск)
└── Все стеки + Подписка + Trial + Лимиты FREE/PRO
Phase 2 (рост)
└── Рейтинги + Аналитика Pro + 2FA + OAuth + Multiple select + Short text
Phase 3 (зрелость)
└── Код-задачи + Бесконечный режим + Telegram + Достижения + Региональные цены
```
***
### Фиксируем в docs-репо
```markdown
# architecture/decisions/001-max-mvp-scope.md
## Контекст
Определяем максимальный целевой объём продукта,
чтобы архитектурные решения MVP не конфликтовали
с будущим функционалом.
## Решение
[ссылка на этот документ]
## Последствия
- Схема БД создаётся с заделом на все фазы
- LLM-слой абстрагирован с первого дня
- Subscription middleware существует с первого дня
(даже когда все пользователи Free)
```
***
## Структура репозиториев
```text
samreshu-backend (Node.js + TS + API)
samreshu-frontend (React + TS + Vite)
samreshu-shared (общие TS-типы/интерфейсы)
samreshu-docs (документация, ADR, прогресс)
```
### Структура samreshu-docs
```text
samreshu-docs/
├── README.md # Навигация по доке
├── architecture/
│ ├── overview.md # Общая архитектура
│ ├── decisions/ # ADR
│ │ ├── 001-monorepo-vs-polyrepo.md
│ │ ├── 002-postgresql-provider.md
│ │ ├── 003-llm-abstraction.md
│ │ └── ...
│ └── diagrams/ # Схемы (Mermaid / draw.io)
├── principles/
│ ├── code-style.md # Соглашения по коду
│ ├── git-workflow.md # Ветки, коммиты, PR
│ └── security.md # Базовые правила безопасности
├── api/
│ └── openapi.yaml # Контракт API (или ссылка)
├── database/
│ └── schema.md # Описание таблиц и связей
├── progress/
│ ├── roadmap.md # Что планируем
│ └── changelog.md # Что сделали
└── onboarding/
└── setup.md # Как поднять проект локально
```
***
## Окружение разработчика
### Базовые требования
```text
Node.js >= 20 LTS (через nvm)
npm >= 10
Git >= 2.40
Docker + Docker Compose (для локальной БД и Redis)
VS Code (рекомендован, настройки в репо)
```
### .nvmrc (в корне каждого репо)
```text
20
```
***
## Backend: вспомогательные инструменты
### 1. ESLint
```bash
npm install -D \
eslint \
@eslint/js \
typescript-eslint \
eslint-plugin-import \
eslint-plugin-security \
eslint-config-prettier
```
```ts
// eslint.config.ts (flat config, актуальный формат ESLint 9+)
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import security from 'eslint-plugin-security'
import importPlugin from 'eslint-plugin-import'
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommended,
{
plugins: { security, import: importPlugin },
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'warn',
'security/detect-object-injection': 'warn',
'import/order': ['error', { 'newlines-between': 'always' }],
'no-console': 'warn',
}
}
)
```
***
### 2. Prettier
```bash
npm install -D prettier
```
```json
// .prettierrc
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"endOfLine": "lf"
}
```
```text
// .prettierignore
dist/
node_modules/
*.sql
```
***
### 3. Husky + lint-staged (проверки перед коммитом)
```bash
npm install -D husky lint-staged
npx husky init
```
```json
// package.json
{
"lint-staged": {
"*.{ts,js}": ["eslint --fix", "prettier --write"],
"*.{json,md}": ["prettier --write"]
}
}
```
```bash
# .husky/pre-commit
npx lint-staged
```
***
### 4. Commitlint (единый стиль коммитов)
```bash
npm install -D @commitlint/cli @commitlint/config-conventional
```
```ts
// commitlint.config.ts
export default {
extends: ['@commitlint/config-conventional'],
}
```
```bash
# .husky/commit-msg
npx --no -- commitlint --edit $1
```
**Формат коммитов:**
```text
feat: добавить генерацию вопросов через LLM
fix: исправить подсчёт результатов теста
chore: обновить зависимости
docs: добавить описание LLM-модуля
refactor: переработать subscription middleware
test: добавить тесты для auth сервиса
```
***
### 5. TypeScript (строгий режим)
```json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": "src",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
```
***
### 6. Vitest (тесты)
```bash
npm install -D vitest @vitest/coverage-v8
```
```ts
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
coverage: {
provider: 'v8',
reporter: ['text', 'lcov'],
thresholds: { lines: 70 }, // минимальное покрытие MVP
}
}
})
```
***
## Frontend: вспомогательные инструменты
```bash
npm install -D \
eslint \
typescript-eslint \
eslint-plugin-react \
eslint-plugin-react-hooks \
eslint-plugin-jsx-a11y \
prettier \
husky \
lint-staged \
@commitlint/cli \
@commitlint/config-conventional \
vitest \
@testing-library/react \
@testing-library/user-event
```
**Отличия от backend:**
- `eslint-plugin-react-hooks` — обязателен, ловит типичные ошибки с хуками
- `eslint-plugin-jsx-a11y` — базовая доступность (a11y) прямо в линтере
- `@testing-library/react` вместо чистого vitest для компонентов
***
## .editorconfig (общий для всех репо)
```ini
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
```
***
## VS Code: рекомендуемые расширения
```json
// .vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"prisma.prisma",
"bradlc.vscode-tailwindcss",
"eamodio.gitlens",
"streetsidesoftware.code-spell-checker-russian",
"usernamehw.errorlens",
"ms-azuretools.vscode-docker",
"mikestead.dotenv"
]
}
```
```json
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.preferences.importModuleSpecifier": "non-relative"
}
```
***
## Итог: что фиксируем в docs-репо прямо сейчас
```markdown
# principles/code-style.md
- Язык кода: английский (переменные, функции, комментарии)
- Язык коммитов: английский (conventional commits)
- Язык документации: русский
- Форматтер: Prettier (конфиг в репо — не обсуждается)
- Линтер: ESLint strict + security plugin
- Тесты: Vitest, минимум 70% покрытие на сервисном слое
- any в TypeScript: запрещён (только через явный комментарий с обоснованием)
- console.log в коде: запрещён в prod (только через logger)
```