- 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
17 KiB
17 KiB
Вводная часть
Веб‑приложение, в котором авторизованный пользователь выбирает стек (HTML/CSS/JS/Web basics) и уровень (базовый/начинающий), получает тест из 10 или 20 теоретических вопросов, сгенерированных LLM, отвечает, а в конце видит результат с разбором ошибок.
Минимальный MVP
Регистрация / логин / выход
✅ Подтверждение email
✅ Восстановление пароля
✅ Профиль (никнейм, страна)
✅ Создание теста (стек + уровень + количество вопросов)
✅ Прохождение теста (вопросы, таймер, прогресс)
✅ Результаты (балл, разбор, объяснения)
✅ Базовая история (последние 10 тестов)
✅ LLM генерация вопросов + fallback на банк
✅ Минимальная админка (QA очередь вопросов)
Максимальный MVP (целевое состояние продукта)
Это не то, что делаем сейчас — это то, к чему ведём. Все решения в коде, БД и архитектуре принимаем с оглядкой на эту картину.
Пользователи и роли
Guest → видит лендинг, описание тарифов, примеры вопросов
Free → базовый функционал, 5 тестов/день, 3 стека
Pro → полный функционал, безлимит, все стеки
Admin → модерация контента, управление пользователями
Модули и их максимальный объём
Auth
✅ Email + пароль
✅ Подтверждение email
✅ Восстановление пароля
✅ OAuth (GitHub + Google)
✅ 2FA (TOTP: Google Authenticator)
✅ Управление сессиями (список устройств, logout везде)
Профиль
✅ Никнейм, аватар, страна, город
✅ Уровень (jun/mid/sen — самооценка)
✅ Статистика на странице профиля
✅ Публичный профиль (по username)
✅ Приватность (скрыть из рейтингов)
Тестирование
✅ Стеки: 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
Результаты и аналитика
✅ Итоговый экран (балл, время, статус)
✅ Детальный разбор (вопрос → ответ → объяснение)
✅ История всех попыток (фильтры, поиск)
✅ Статистика по темам (% правильных)
✅ График прогресса по времени
✅ Слабые места + LLM-рекомендации (Pro)
✅ Экспорт истории в CSV (Pro)
Рейтинги (Pro)
✅ Глобальный лидерборд (Top 100)
✅ Рейтинг по стекам
✅ Сезонный рейтинг (ежемесячный)
✅ Позиция пользователя (даже вне Top 100)
✅ Бейджи и достижения
✅ Архив сезонов
Подписка и биллинг
✅ Free план (всегда)
✅ Pro: 699₽/мес или 6999₽/год
✅ Пробный период 5 дней (с привязкой карты)
✅ Автопродление / отмена
✅ ЮKassa (основной провайдер)
✅ CloudPayments (резервный)
✅ Региональные цены (Казахстан, Беларусь, Закавказье)
✅ Промокоды и скидки
✅ История платежей в ЛК
Уведомления
✅ Email: verify, reset, trial, billing
✅ In-app баннеры и тосты
✅ Telegram-бот (Phase 3)
✅ Push-уведомления (Phase 3)
Контент / LLM
✅ Генерация вопросов по стеку/уровню/типу
✅ Проверка short text через LLM
✅ Подсказки (один наводящий вопрос)
✅ LLM-рекомендации по слабым местам
✅ Мультимодельная оркестрация (local + cloud fallback)
✅ Банк вопросов с QA-циклом
✅ Кэш и переиспользование вопросов
Админка
✅ QA очередь вопросов (approve/reject/edit)
✅ Управление пользователями (бан, сброс лимитов)
✅ Просмотр жалоб на вопросы
✅ Операционная панель (метрики, ошибки)
✅ Управление промокодами
✅ Прогрев кэша вопросов
Полная схема данных (ориентир)
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 (промокоды)
Что закладываем архитектурно с первого дня
Это принципы, не обсуждаемые при написании любого кода:
1. user.plan всегда читается из БД через subscription middleware
→ никогда не хардкодить права в контроллерах
2. Вопросы копируются в test_questions при старте теста (снепшот)
→ никогда не читать question_bank "живьём" во время теста
3. Все LLM-вызовы только через LlmService
→ остальной код не знает какая модель работает
4. Все внешние события (webhooks, LLM) валидируются по JSON-схеме
→ никогда не доверять внешним данным без валидации
5. Все проверки прав и лимитов только на backend
→ frontend только отображает состояние
6. Все даты хранятся в UTC
→ конвертация в часовой пояс только на фронте
7. Все конфигурации через env переменные
→ никаких хардкодов в коде
Фазы разработки
MVP 0 (сейчас)
└── Auth + Test (2 стека) + Results + Базовая история
Phase 1 (платный запуск)
└── Все стеки + Подписка + Trial + Лимиты FREE/PRO
Phase 2 (рост)
└── Рейтинги + Аналитика Pro + 2FA + OAuth + Multiple select + Short text
Phase 3 (зрелость)
└── Код-задачи + Бесконечный режим + Telegram + Достижения + Региональные цены
Фиксируем в docs-репо
# architecture/decisions/001-max-mvp-scope.md
## Контекст
Определяем максимальный целевой объём продукта,
чтобы архитектурные решения MVP не конфликтовали
с будущим функционалом.
## Решение
[ссылка на этот документ]
## Последствия
- Схема БД создаётся с заделом на все фазы
- LLM-слой абстрагирован с первого дня
- Subscription middleware существует с первого дня
(даже когда все пользователи Free)
Структура репозиториев
samreshu-backend (Node.js + TS + API)
samreshu-frontend (React + TS + Vite)
samreshu-shared (общие TS-типы/интерфейсы)
samreshu-docs (документация, ADR, прогресс)
Структура samreshu-docs
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 # Как поднять проект локально
Окружение разработчика
Базовые требования
Node.js >= 20 LTS (через nvm)
npm >= 10
Git >= 2.40
Docker + Docker Compose (для локальной БД и Redis)
VS Code (рекомендован, настройки в репо)
.nvmrc (в корне каждого репо)
20
Backend: вспомогательные инструменты
1. ESLint
npm install -D \
eslint \
@eslint/js \
typescript-eslint \
eslint-plugin-import \
eslint-plugin-security \
eslint-config-prettier
// 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
npm install -D prettier
// .prettierrc
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"endOfLine": "lf"
}
// .prettierignore
dist/
node_modules/
*.sql
3. Husky + lint-staged (проверки перед коммитом)
npm install -D husky lint-staged
npx husky init
// package.json
{
"lint-staged": {
"*.{ts,js}": ["eslint --fix", "prettier --write"],
"*.{json,md}": ["prettier --write"]
}
}
# .husky/pre-commit
npx lint-staged
4. Commitlint (единый стиль коммитов)
npm install -D @commitlint/cli @commitlint/config-conventional
// commitlint.config.ts
export default {
extends: ['@commitlint/config-conventional'],
}
# .husky/commit-msg
npx --no -- commitlint --edit $1
Формат коммитов:
feat: добавить генерацию вопросов через LLM
fix: исправить подсчёт результатов теста
chore: обновить зависимости
docs: добавить описание LLM-модуля
refactor: переработать subscription middleware
test: добавить тесты для auth сервиса
5. TypeScript (строгий режим)
// 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 (тесты)
npm install -D vitest @vitest/coverage-v8
// 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: вспомогательные инструменты
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 (общий для всех репо)
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: рекомендуемые расширения
// .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"
]
}
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.preferences.importModuleSpecifier": "non-relative"
}
Итог: что фиксируем в docs-репо прямо сейчас
# principles/code-style.md
- Язык кода: английский (переменные, функции, комментарии)
- Язык коммитов: английский (conventional commits)
- Язык документации: русский
- Форматтер: Prettier (конфиг в репо — не обсуждается)
- Линтер: ESLint strict + security plugin
- Тесты: Vitest, минимум 70% покрытие на сервисном слое
- any в TypeScript: запрещён (только через явный комментарий с обоснованием)
- console.log в коде: запрещён в prod (только через logger)