docs: improve AGENTS.md and README.md
All checks were successful
CI / ci (push) Successful in 3m20s

This commit is contained in:
Sergey Krylov 2026-06-19 08:24:54 +03:00
parent 1dc27a6e9b
commit a95308762f
3 changed files with 384 additions and 142 deletions

354
AGENTS.md
View File

@ -1,21 +1,56 @@
# MoexVibe — Инструкция для агента # MoexVibe — Инструкция для агента
## Репозиторий ## Содержание
npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/frontend` (React + Vite), `apps/docs` (Docusaurus). - [Обязательный подход к разработке](#обязательный-подход-к-разработке)
- [Процесс разработки](#процесс-разработки)
- [Структура документации](#структура-документации)
- [Назначение документов](#назначение-документов)
- [Правила разработки](#правила-разработки)
- [Определение бага](#определение-бага)
- [Процесс работы над фичей](#процесс-работы-над-фичей)
- [Работа с новыми идеями](#работа-с-новыми-идеями)
- [Работа с существующими фичами](#работа-с-существующими-фичами)
- [Поддержание документации](#поддержание-документации)
- [Поведение AI-агентов](#поведение-ai-агентов)
- [Anti-Loop: лимит на итерации](#anti-loop-лимит-на-итерации)
- [Приоритет источников информации](#приоритет-источников-информации)
- [Git workflow](#git-workflow)
- [Конвенция коммитов](#конвенция-коммитов)
- [Документация и SDD-артефакты](#документация-и-sdd-артефакты)
- [Definition of Done (DoD)](#definition-of-done-dod)
- [Технические регламенты](#технические-регламенты)
- [Правила тестирования](#правила-тестирования)
- [Работа с миграциями Prisma](#работа-с-миграциями-prisma)
- [Правила рефакторинга](#правила-рефакторинга)
- [Политики безопасности](#политики-безопасности)
- [ADR-процесс](#adr-процесс)
- [Правила обновления OpenAPI/типов](#правила-обновления-openapiтипов)
- [Цикл работы над API](#цикл-работы-над-api)
- [Инфраструктура проекта](#инфраструктура-проекта)
- [Команды](#команды)
- [Переменные окружения](#переменные-окружения)
- [Архитектура](#архитектура)
- [Бэкенд](#бэкенд)
- [Фронтенд](#фронтенд)
- [Стиль кода](#стиль-кода)
---
## Обязательный подход к разработке ## Обязательный подход к разработке
- **SDD (Specification-Driven Development)**: перед значимыми изменениями сначала зафиксировать спецификацию нужного масштаба — PRD/цели, доменную модель, ADR, API-контракт, frontend/backend architecture и этапы реализации. Для небольших maintenance-правок достаточно короткого обоснования и acceptance criteria. - **SDD (Specification-Driven Development)**: перед значимыми изменениями сначала зафиксировать спецификацию нужного масштаба — PRD/цели, доменную модель, ADR, API-контракт, frontend/backend architecture и этапы реализации. Для небольших maintenance-правок достаточно короткого обоснования и acceptance criteria.
- **Superpowers**: использовать релевантные Skills при старте задачи. Обычно: brainstorming для уточнения дизайна, systematic-debugging для багов, test-driven-development для feature/bugfix, writing-plans/executing-plans для крупных многошаговых работ, frontend-design для UI, requesting-code-review перед завершением крупных изменений. - **Superpowers**: использовать релевантные Skills при старте задачи. Обычно: brainstorming для уточнения дизайна, systematic-debugging для багов, test-driven-development для feature/bugfix, writing-plans/executing-plans для крупных многошаговых работ, frontend-design для UI, requesting-code-review перед завершением крупных изменений.
- **MCP-инструменты**: использовать MCP для анализа, дизайна, работы с API, генерации кода и проверки локального UI, когда это полезно задаче. - **MCP-инструменты**: использовать MCP для анализа, дизайна, работы с API, генерации кода и проверки локального UI, когда это полезно задаче.
- **Visual Companion**: при обсуждении дизайна UI (mockups, макеты, варианты внешнего вида) использовать visual companion в браузере. - **Visual Companion**: в ходе `brainstorming`, если предстоящие вопросы действительно требуют визуального представления (mockups, wireframes, диаграммы, сравнение вариантов), отдельным сообщением предложить пользователю [Visual Companion](https://github.com/obra/superpowers/blob/main/skills/brainstorming/visual-companion.md). Использовать его только после согласия пользователя и только для тех вопросов, которые понятнее показать, чем описать текстом. Visual Companion — инструмент, а не отдельный режим работы.
# Процесс разработки ---
## Процесс разработки
Проект использует подход Specification-Driven Development (SDD). Проект использует подход Specification-Driven Development (SDD).
## Структура документации ### Структура документации
```text ```text
docs/ docs/
@ -36,20 +71,23 @@ docs/
``` ```
## Назначение документов Полный набор `spec.md`, `plan.md` и `tasks.md` обязателен для новых фич. Исторические feature-каталоги могут быть неполными: отсутствующие артефакты не требуется восстанавливать задним числом, если это не нужно для текущего изменения.
### inbox.md
### Назначение документов
#### inbox.md
Содержит идеи и мысли, которые появились во время работы над проектом. Содержит идеи и мысли, которые появились во время работы над проектом.
Записи в inbox не являются требованиями и не должны реализовываться напрямую. Записи в inbox не являются требованиями и не должны реализовываться напрямую.
### roadmap.md #### roadmap.md
Содержит список запланированных эпиков и фич. Содержит список запланированных эпиков и фич.
Наличие задачи в roadmap не означает, что её нужно немедленно реализовать. Наличие задачи в roadmap не означает, что её нужно немедленно реализовать.
### research/ #### research/
Содержит результаты исследований и экспериментов. Содержит результаты исследований и экспериментов.
@ -57,17 +95,18 @@ docs/
Результаты исследований необходимо проверять перед реализацией. Результаты исследований необходимо проверять перед реализацией.
### epics/ #### epics/
Эпик представляет собой крупную продуктовую возможность или модуль. Эпик представляет собой крупную продуктовую возможность или модуль.
Эпик может состоять из нескольких фич. Эпик может состоять из нескольких фич.
### features/{feature-name}/spec.md #### features/{feature-name}/spec.md
Описывает ЧТО должно быть реализовано. Описывает **ЧТО** должно быть реализовано.
Спецификация должна содержать: Спецификация должна содержать:
- цель - цель
- требования - требования
- ограничения - ограничения
@ -75,32 +114,32 @@ docs/
Спецификация не должна содержать деталей реализации. Спецификация не должна содержать деталей реализации.
### features/{feature-name}/plan.md #### features/{feature-name}/plan.md
Описывает КАК будет реализована фича. Описывает **КАК** будет реализована фича.
План может содержать: План может содержать:
- архитектурные решения - архитектурные решения
- API контракты - API контракты
- потоки данных - потоки данных
- технический подход - технический подход
### features/{feature-name}/tasks.md #### features/{feature-name}/tasks.md
Содержит список задач для реализации. Содержит список задач для реализации.
Задачи должны быть: Задачи должны быть:
- небольшими - небольшими
- конкретными - конкретными
- независимыми по возможности - независимыми по возможности
### Правила разработки
## Правила разработки #### Правило 1
Нельзя начинать реализацию новой фичи без спецификации.
### Правило 1
Нельзя начинать реализацию без спецификации.
Если спецификации нет: Если спецификации нет:
@ -109,28 +148,23 @@ docs/
- Уточнить требования. - Уточнить требования.
- Только после этого переходить к реализации. - Только после этого переходить к реализации.
### Правило 2 #### Правило 2
Реализация должна соответствовать spec.md. Реализация должна соответствовать spec.md.
Если в процессе разработки выясняется, что требования неполные или ошибочные: Если в процессе разработки выясняется, что требования неполные или ошибочные:
Не изменять поведение системы молча. - Не изменять поведение системы молча.
- Сначала обновить spec.md и plan.md.
- И только потом продолжать реализацию.
Сначала обновить: #### Правило 3
- spec.md
- plan.md
И только потом продолжать реализацию.
### Правило 3
Спецификация является источником истины. Спецификация является источником истины.
Если plan.md противоречит spec.md: Если plan.md противоречит spec.md — приоритет имеет spec.md.
Приоритет имеет spec.md.
### Правило 4 #### Правило 4
Не добавлять функциональность, которая отсутствует в спецификации. Не добавлять функциональность, которая отсутствует в спецификации.
@ -139,65 +173,71 @@ docs/
- обновить спецификацию; - обновить спецификацию;
- либо создать новую фичу. - либо создать новую фичу.
### Правило 5 #### Правило 5
Исправления ошибок можно выполнять напрямую. Исправления ошибок можно выполнять напрямую. Новая функциональность должна проходить через спецификацию.
Новая функциональность должна проходить через спецификацию. #### Определение бага
Баг — это поведение системы, противоречащее спецификации, acceptance criteria, API-контракту, зафиксированному тестами поведению или подтверждённому архитектурному инварианту.
## Процесс работы над фичей Если желаемое поведение нигде не зафиксировано и не следует из существующего контракта или инварианта — это отсутствующая функциональность (new feature), а не баг.
При реализации фичи необходимо: Классификация:
1) Ознакомиться с эпиком, если он существует. - **Есть зафиксированный контракт, поведение не соответствует**баг (можно чинить напрямую, Правило 5)
2) Прочитать spec.md. - **Нет зафиксированного контракта, требуется новое поведение** → новая фича (нужна спецификация)
3) Прочитать plan.md. - **Spec есть, но в нём неопределённость** → сначала уточнить spec, потом решать, баг это или фича
4) Прочитать tasks.md.
5) Выполнять задачи последовательно.
6) Отмечать выполненные задачи.
7) Обновлять plan.md при изменении технических решений.
8) Обновлять spec.md при изменении требований.
## Работа с новыми идеями ### Процесс работы над фичей
При реализации новой фичи необходимо:
1. Ознакомиться с эпиком, если он существует.
2. Прочитать spec.md.
3. Прочитать plan.md.
4. Прочитать tasks.md.
5. Выполнять задачи последовательно.
6. Отмечать выполненные задачи.
7. Обновлять plan.md при изменении технических решений.
8. Обновлять spec.md при изменении требований.
Для исторической фичи сначала прочитать все имеющиеся артефакты. Отсутствие старого `plan.md` или `tasks.md` само по себе не блокирует maintenance или исправление бага и не требует создавать их задним числом. Для нового расширения такой фичи сначала подготовить недостающие артефакты в объёме текущего изменения.
### Работа с новыми идеями
Если во время реализации появилась новая идея: Если во время реализации появилась новая идея:
Не реализовывать её автоматически. Не реализовывать её автоматически. Необходимо определить, является ли она:
Необходимо определить, является ли она:
- багом; - багом;
- улучшением существующей функциональности; - улучшением существующей функциональности;
- новой фичей. - новой фичей.
Если это улучшение или новая фича: Если это улучшение или новая фича — добавить её в inbox.md или создать отдельную фичу.
Добавить её в: ### Работа с существующими фичами
- inbox.md
или создать отдельную фичу.
## Работа с существующими фичами
Улучшения существующей функциональности обычно остаются внутри текущего эпика. Улучшения существующей функциональности обычно остаются внутри текущего эпика.
Пример: Пример:
```
Portfolio Dashboard Portfolio Dashboard
- История операций ├── История операций
- Пагинация истории операций ├── Пагинация истории операций
- Фильтрация истории операций ├── Фильтрация истории операций
- Экспорт истории операций └── Экспорт истории операций
```
Все перечисленные возможности относятся к одному эпику.
Новый эпик создаётся только при появлении новой продуктовой возможности или нового домена. Новый эпик создаётся только при появлении новой продуктовой возможности или нового домена.
## Поддержание документации ### Поддержание документации
Документация должна соответствовать текущему состоянию проекта. Документация должна соответствовать текущему состоянию проекта.
После значимых изменений необходимо обновлять: После значимых изменений необходимо обновлять:
- spec.md - spec.md
- plan.md - plan.md
- tasks.md - tasks.md
@ -206,27 +246,40 @@ Portfolio Dashboard
Документация не должна отставать от реализации. Документация не должна отставать от реализации.
## Поведение AI-агентов ### Поведение AI-агентов
Перед написанием кода необходимо: Перед написанием кода необходимо:
1) Изучить спецификацию фичи.
2) Проверить полноту требований.
3) Найти неоднозначности и противоречия.
4) При необходимости запросить уточнения.
Запрещено: 1. Изучить спецификацию фичи.
2. Проверить полноту требований.
3. Найти неоднозначности и противоречия.
4. При необходимости запросить уточнения.
5. Перед началом реализации агент должен кратко подтвердить понимание задачи и спецификации (одним сообщением).
**Запрещено:**
- придумывать требования; - придумывать требования;
- додумывать поведение системы; - додумывать поведение системы;
- реализовывать неописанную функциональность. - реализовывать неописанную функциональность.
Если информации недостаточно: Если информации недостаточно — остановиться и запросить уточнение вместо того, чтобы делать предположения.
- Остановиться и запросить уточнение вместо того, чтобы делать предположения.
## Приоритет источников информации ### Anti-Loop: лимит на итерации
Если после 3 последовательных неудачных попыток исправить одну и ту же проблему в рамках одной гипотезы симптом не изменился — остановиться и запросить помощь у пользователя.
Правила:
- Каждая попытка = один цикл «сформулировал гипотезу → внёс изменение → проверил → тот же симптом сохранился»
- Сбор новой диагностической информации без изменения кода попыткой не считается
- Не начинать 4-ю попытку без явного указания пользователя
- При запросе помощи приложить: что пытался сделать, что пошло не так, последнее состояние кода/логов
### Приоритет источников информации
При возникновении противоречий использовать следующий порядок приоритетов: При возникновении противоречий использовать следующий порядок приоритетов:
1. Текущая задача пользователя. 1. Текущая задача пользователя (она может изменить требования, но соответствующие SDD-артефакты обновляются до реализации).
2. spec.md фичи. 2. spec.md фичи.
3. plan.md фичи. 3. plan.md фичи.
4. ADR. 4. ADR.
@ -236,70 +289,133 @@ Portfolio Dashboard
roadmap.md и inbox.md никогда не являются основанием для реализации функциональности. roadmap.md и inbox.md никогда не являются основанием для реализации функциональности.
## Git workflow ### Git workflow
- Для каждой самостоятельной фичи создавать отдельную feature branch и вести разработку внутри неё. - Для каждой самостоятельной фичи создавать отдельную feature branch и вести разработку внутри неё.
- Имя ветки по умолчанию начинать с `codex/`, если пользователь не попросил другой префикс. - Имя ветки по умолчанию начинать с `codex/`, если пользователь не попросил другой префикс.
- Не смешивать независимые фичи в одной ветке. Небольшие связанные docs/chore/test-правки можно держать в той же ветке, если они относятся к текущей задаче. - Не смешивать независимые фичи в одной ветке. Небольшие связанные docs/chore/test-правки можно держать в той же ветке, если они относятся к текущей задаче.
## Документация и SDD-артефакты ### Конвенция коммитов
Использовать [Conventional Commits](https://www.conventionalcommits.org/):
- `feat:` — новая функциональность
- `fix:` — исправление бага
- `chore:` — обслуживание (зависимости, конфиги, CI)
- `docs:` — документация
- `refactor:` — рефакторинг без изменения поведения
- `test:` — добавление или исправление тестов
- `style:` — форматирование, кодстайл (prettier)
- `perf:` — улучшение производительности
- `build:` — изменения сборки и зависимостей
- `ci:` — изменения CI/CD
Формат: `<тип>(<необязательный scope>): <краткое описание в настоящем времени>`
Примеры:
- `feat: add portfolio rebalancing endpoint`
- `fix: handle empty dividend list from MOEX`
- `docs: update API authentication section`
### Документация и SDD-артефакты
- `apps/docs` — единственная опубликованная человекочитаемая документация проекта (Docusaurus). - `apps/docs` — единственная опубликованная человекочитаемая документация проекта (Docusaurus).
- ADR для опубликованной документации находятся в `apps/docs/docs/adr/`. - ADR для опубликованной документации находятся в `apps/docs/docs/adr/`.
- OpenAPI source of truth — live Swagger JSON бэкенда на `/api/docs-json`; frontend generated types находятся в `apps/frontend/src/api/types.ts`. - OpenAPI source of truth — live Swagger JSON бэкенда на `/api/docs-json`; frontend generated types находятся в `apps/frontend/src/api/types.ts`.
## Команды ### Definition of Done (DoD)
| Команда | Что делает | - Все acceptance criteria реализованы
|---|---| - Тесты проходят
| `npm run dev:backend` | Запуск NestJS в режиме watch на :3000 | - Lint проходит
| `npm run dev:frontend` | Vite dev-сервер на :5173, проксирует `/api` → :3000 | - Для новой фичи созданы и обновлены spec/plan/tasks; для исторической фичи обновлены существующие и необходимые для текущего изменения артефакты
| `npm run dev:docs` | Docusaurus dev-сервер | - Документация обновлена
| `npm run build:backend` | `nest build` | - Нет TODO без согласования
| `npm run build:frontend` | `tsc -b && vite build` (в две фазы) |
| `npm run build:docs` | `docusaurus build` |
| `npm run test:backend` | `vitest run` (SWC, не ts-jest) |
| `npm run test:frontend` | Frontend Vitest suite |
| `npm run lint` | ESLint для backend и frontend |
| `npm run format` | Prettier для всех `*.{ts,tsx}` |
| `npm run codegen -w apps/frontend` | `openapi-typescript` из локального Swagger → `src/api/types.ts` |
Live MOEX integration tests opt-in: `npm run test:integration -w apps/backend`. ---
Один тест: `npx vitest run path/to/test.spec.ts -w apps/backend` ## Технические регламенты
## Переменные окружения ### Правила тестирования
| Переменная | По умолчанию | Описание | - Для новой бизнес-логики → обязательны unit-тесты
|---|---|---| - Для API-контрактов → интеграционные тесты
| `PORT` | 3000 | Порт бэкенда | - Не мокать собственный код без необходимости
| `MOEX_BASE_URL` | `https://iss.moex.com/iss` | Endpoint MOEX ISS | - В unit-тестах мокать внешние API (MOEX, T-Bank) и Prisma
| `MOEX_RATE_LIMIT` | 10 | Запросов/с к MOEX | - При исправлении бага — сначала падающий тест (TDD)
| `MOEX_CIRCUIT_BREAKER_THRESHOLD` | 5 | Количество ошибок до открытия circuit breaker | - Тесты писать рядом с основным кодом
| `MOEX_CIRCUIT_BREAKER_RESET_SECONDS` | 30 | Время до попытки закрыть circuit breaker |
| `T_BANK_TOKEN` | `''` | Server-side токен T-Bank Invest | ### Работа с миграциями Prisma
| `T_BANK_BASE_URL` | `invest-public-api.tbank.ru:443` | gRPC endpoint T-Bank Invest |
| `T_BANK_CA_CERT_PATH` | `''` | Путь к PEM root CA для gRPC TLS, если локальная сеть подменяет сертификаты | - Никогда не редактировать файлы в `prisma/migrations/` вручную
| `T_BANK_APP_NAME` | `ksv741.moex-vibe` | Metadata приложения для T-Bank | - После изменения `schema.prisma``npm exec -w apps/backend -- prisma migrate dev --name <name>`
| `T_BANK_RATE_LIMIT_PER_SECOND` | 5 | Rate limiter для OperationsService и UsersService (запросов/с) | - Изменять существующие миграции допустимо только до их публикации/мержа. После мержа создавать новую миграцию
| `T_BANK_INSTRUMENTS_RATE_LIMIT` | 20 | Rate limiter для InstrumentsService (запросов/с) | - Всегда запускать `npm exec -w apps/backend -- prisma generate` после изменения схемы
| `T_BANK_REQUEST_TIMEOUT_MS` | 10000 | Deadline gRPC-запроса (мс) |
| `CACHE_MARKET_DATA_TTL` | 900 | TTL рыночных данных (с) | ### Правила рефакторинга
| `CACHE_HISTORY_TTL` | 3600 | TTL истории (с) |
| `CACHE_CANDLES_TTL` | 3600 | TTL свечей (с) | - Не выполнять крупный рефакторинг вне рамок задачи
| `CACHE_SECURITY_TTL` | 86400 | TTL спецификации (с) | - Допустимы: локальные улучшения, устранение техдолга рядом с изменяемым кодом, исправление архитектурных нарушений
| `CACHE_SEARCH_TTL` | 3600 | TTL результатов поиска (с) | - Запрещено: менять структуру проекта без ADR, переписывать модули без отдельной задачи
| `CACHE_DIVIDENDS_TTL` | 86400 | TTL дивидендных данных (с) | - Крупный рефакторинг требует отдельного эпика/фичи + ADR
| `DATABASE_URL` | `file:./dev.db` | URL SQLite для Prisma |
| `JWT_SECRET` | `dev-jwt-secret-...` | Secret для access token | ### Политики безопасности
| `JWT_REFRESH_SECRET` | `dev-refresh-secret-...` | Secret для refresh token |
| `JWT_ACCESS_EXPIRES` | `15m` | TTL access token | - Запрещено логировать токены, пароли, секреты
| `JWT_REFRESH_EXPIRES` | `7d` | TTL refresh token | - Не отключать guard'ы
- Не хранить секреты в коде, не коммитить .env
- Использовать маскирование при выводе (например, `***`)
### ADR-процесс
- Создавать ADR при: выборе новой технологии, изменении архитектуры, изменении API-контрактов, изменении стратегии хранения данных
- ADR должен содержать: Контекст, Рассмотренные варианты, Решение, Последствия
### Правила обновления OpenAPI/типов
1. Обновить DTO/Controller на бэкенде
2. Обновить Swagger
3. Запустить `npm run codegen -w apps/frontend`
4. Использовать обновлённые типы из `src/api/types.ts`
5. Никогда не редактировать `types.ts` вручную
### Цикл работы над API
Стандартная процедура при любом изменении API-контракта:
1. **Бэкенд** — описать/обновить DTO и контроллер (NestJS)
2. **Swagger** — убедиться, что документация отдаётся корректно (`/api/docs-json`)
3. **Codegen**`npm run codegen -w apps/frontend` (генерирует `src/api/types.ts`)
4. **Фронтенд** — использовать обновлённые типы, адаптировать вызовы
5. **Проверка** — убедиться, что `npm run build` проходит в обоих пакетах
Обновление типов вручную (`types.ts`) запрещено — всегда через codegen.
---
## Инфраструктура проекта
### Команды
Основные команды проекта описаны в README.md.
Перед завершением задачи запускать тесты, lint и build затронутых пакетов.
### Переменные окружения
Основные настройки находятся в .env.
Полный список переменных описан в README.md.
---
## Архитектура ## Архитектура
### Бэкенд
- **Бэкенд** — единственный клиент MOEX. Фронтенд никогда не обращается к MOEX напрямую. - **Бэкенд** — единственный клиент MOEX. Фронтенд никогда не обращается к MOEX напрямую.
- Feature-модули: `PrismaModule` (глобальный), `MoexClientModule` (глобальный), `CacheModule` (глобальный), `AuthModule`, `SharesModule`, `BondsModule`, `SecuritiesModule`, `CandlesModule`, `PortfolioModule`, `HealthModule`. - Актуальная композиция backend-модулей определяется в `apps/backend/src/app.module.ts`; не дублировать динамический список модулей в инструкциях. Опубликованное описание архитектуры находится в `apps/docs/docs/backend/modules.md`.
- `MoexClientService` использует p-queue (rate limiter) + circuit breaker (5 ошибок → 30s открыт). - `MoexClientService` использует p-queue (rate limiter) + circuit breaker (5 ошибок → 30s открыт).
- In-memory кеш через `@nestjs/cache-manager`. Путь миграции на Redis описан (см. ADR-002). - In-memory кеш через `@nestjs/cache-manager`. Путь миграции на Redis описан (см. ADR-002).
- Аутентификация: JWT access token (15m, в памяти) + refresh token (7d, httpOnly cookie, bcrypt hash в БД). Глобальный `JwtAuthGuard` (`@Public()` для открытых эндпоинтов). - Аутентификация: JWT access token (15m, в памяти) + refresh token (7d, httpOnly cookie, bcrypt hash в БД). Глобальный `JwtAuthGuard` (`@Public()` для открытых эндпоинтов).
@ -309,7 +425,7 @@ Live MOEX integration tests opt-in: `npm run test:integration -w apps/backend`.
- Ответы API обёрнуты в `{ data: T, meta: { fromCache, cachedAt } }`. - Ответы API обёрнуты в `{ data: T, meta: { fromCache, cachedAt } }`.
- Алиасы: `@/*``src/*` в обоих пакетах. - Алиасы: `@/*``src/*` в обоих пакетах.
## Фронтенд ### Фронтенд
- React 18 + react-router-dom v6 + TanStack Query v5. - React 18 + react-router-dom v6 + TanStack Query v5.
- `lightweight-charts` v4 для графиков цен. - `lightweight-charts` v4 для графиков цен.
@ -318,7 +434,7 @@ Live MOEX integration tests opt-in: `npm run test:integration -w apps/backend`.
- Конвенция ключей запросов: `['stock', secid]`, `['securities', 'search', query]`, и т.д. - Конвенция ключей запросов: `['stock', secid]`, `['securities', 'search', query]`, и т.д.
- CSS через `styles.css` (CSS custom properties, без CSS-in-JS или Tailwind). - CSS через `styles.css` (CSS custom properties, без CSS-in-JS или Tailwind).
## Стиль кода ### Стиль кода
- Prettier: одинарные кавычки, trailing commas, printWidth 100, точки с запятой. - Prettier: одинарные кавычки, trailing commas, printWidth 100, точки с запятой.
- Бэкенд: `const`, PascalCase для модулей/контроллеров/сервисов, DTO в `dto/` внутри каждого модуля. - Бэкенд: `const`, PascalCase для модулей/контроллеров/сервисов, DTO в `dto/` внутри каждого модуля.

138
README.md
View File

@ -2,60 +2,154 @@
Веб-приложение для анализа ценных бумаг Московской биржи (MOEX). Веб-приложение для анализа ценных бумаг Московской биржи (MOEX).
## Tech Stack ## Содержание
- **Backend:** NestJS, TypeScript, OpenAPI (Swagger) - [О проекте](#о-проекте)
- **Frontend:** React, TypeScript, Vite, TanStack Query, lightweight-charts - [Стек технологий](#стек-технологий)
- **Docs:** Docusaurus - [Быстрый старт](#быстрый-старт)
- **Infrastructure:** Docker, docker-compose - [Docker](#docker)
- [Тестирование](#тестирование)
- [Структура проекта](#структура-проекта)
- [Команды](#команды)
- [Переменные окружения](#переменные-окружения)
## Quick Start ---
## О проекте
npm workspaces монорепозиторий:
| Пакет | Назначение |
| --------------- | -------------------------------------------------- |
| `apps/backend` | NestJS API (единственная точка доступа к MOEX ISS) |
| `apps/frontend` | React SPA на Vite |
| `apps/docs` | Сайт документации Docusaurus |
---
## Стек технологий
- **Бэкенд:** NestJS, TypeScript, OpenAPI (Swagger)
- **Фронтенд:** React, TypeScript, Vite, TanStack Query, lightweight-charts
- **Документация:** Docusaurus
- **Инфраструктура:** Docker, docker-compose
---
## Быстрый старт
```bash ```bash
# Install dependencies # Настройка локального окружения
npm install cp apps/backend/.env.example apps/backend/.env
# Start backend (http://localhost:3000) # Установка зависимостей и подготовка базы данных
npm install
npm exec -w apps/backend -- prisma migrate dev
# Запуск бэкенда (http://localhost:3000)
npm run dev:backend npm run dev:backend
# Start frontend (http://localhost:5173) # Запуск фронтенда (http://localhost:5173)
npm run dev:frontend npm run dev:frontend
``` ```
Swagger UI: http://localhost:3000/api/docs Swagger UI: http://localhost:3000/api/docs
---
## Docker ## Docker
```bash ```bash
docker compose up --build docker compose up --build
``` ```
- Frontend: http://localhost:80 - Фронтенд: http://localhost:80
- Backend: http://localhost:3000 - Бэкенд: http://localhost:3000
## Tests ---
## Тестирование
```bash ```bash
npm run test:backend npm run test:backend
npm run test:frontend npm run test:frontend
``` ```
Live MOEX integration checks are opt-in: Интеграционные тесты с MOEX — опциональны:
```bash ```bash
npm run test:integration -w apps/backend npm run test:integration -w apps/backend
``` ```
## Project Structure ---
## Структура проекта
``` ```
apps/ apps/
backend/ — NestJS API (single point of access to MOEX ISS) backend/ — NestJS API, единая точка доступа к MOEX ISS
frontend/ — React SPA with Vite frontend/ — React SPA на Vite
docs/ — Docusaurus documentation site docs/ — сайт документации Docusaurus
docs/ docs/
features/ — SDD feature specifications and implementation plans features/ — спецификации и планы реализации (SDD)
epics/ — product epics epics/ — продуктовые эпики
inbox.md — captured ideas and follow-ups inbox.md — идеи и заметки
roadmap.md — planned epics and features roadmap.md — запланированные эпики и фичи
``` ```
---
## Команды
| Команда | Что делает |
| ---------------------------------- | --------------------------------------------------------------------------- |
| `npm run dev:backend` | Запуск NestJS в режиме watch на :3000 |
| `npm run dev:frontend` | Vite dev-сервер на :5173, проксирует `/api` → :3000 |
| `npm run dev:docs` | Docusaurus dev-сервер |
| `npm run build:backend` | `nest build` |
| `npm run build:frontend` | `tsc -b && vite build` (в две фазы) |
| `npm run build:docs` | `docusaurus build` |
| `npm run test:backend` | `vitest run` (SWC, не ts-jest) |
| `npm run test:frontend` | Frontend Vitest suite |
| `npm run lint` | ESLint для backend и frontend |
| `npm run format` | Prettier для всех `*.{ts,tsx}` |
| `npm run codegen -w apps/frontend` | `openapi-typescript` из запущенного локального Swagger → `src/api/types.ts` |
Интеграционные тесты с MOEX: `npm run test:integration -w apps/backend`.
Один backend-тест: `npm exec -w apps/backend -- vitest run src/path/to/test.spec.ts`
---
## Переменные окружения
| Переменная | По умолчанию | Описание |
| ------------------------------------ | -------------------------------- | -------------------------------------------------------------- |
| `PORT` | 3000 | Порт бэкенда |
| `MOEX_BASE_URL` | `https://iss.moex.com/iss` | Адрес MOEX ISS |
| `MOEX_RATE_LIMIT` | 10 | Запросов/с к MOEX |
| `MOEX_CIRCUIT_BREAKER_THRESHOLD` | 5 | Ошибок до открытия circuit breaker |
| `MOEX_CIRCUIT_BREAKER_RESET_SECONDS` | 30 | Секунд до попытки закрыть circuit breaker |
| `T_BANK_TOKEN` | `''` | Токен T-Bank Invest (серверный) |
| `T_BANK_BASE_URL` | `invest-public-api.tbank.ru:443` | gRPC endpoint T-Bank Invest |
| `T_BANK_CA_CERT_PATH` | `''` | Путь к PEM root CA для gRPC TLS |
| `T_BANK_APP_NAME` | `ksv741.moex-vibe` | Имя приложения для T-Bank |
| `T_BANK_RATE_LIMIT_PER_SECOND` | 5 | Rate limiter для OperationsService и UsersService (запросов/с) |
| `T_BANK_INSTRUMENTS_RATE_LIMIT` | 20 | Rate limiter для InstrumentsService (запросов/с) |
| `T_BANK_REQUEST_TIMEOUT_MS` | 10000 | Таймаут gRPC-запроса (мс) |
| `CACHE_MARKET_DATA_TTL` | 900 | TTL рыночных данных (с) |
| `CACHE_HISTORY_TTL` | 3600 | TTL истории (с) |
| `CACHE_CANDLES_TTL` | 3600 | TTL свечей (с) |
| `CACHE_SECURITY_TTL` | 86400 | TTL спецификации (с) |
| `CACHE_SEARCH_TTL` | 3600 | TTL результатов поиска (с) |
| `CACHE_DIVIDENDS_TTL` | 86400 | TTL дивидендных данных (с) |
| `CACHE_TBANK_ACCOUNTS_TTL` | 3600 | TTL брокерских счетов T-Bank (с) |
| `CACHE_TBANK_PORTFOLIO_TTL` | 60 | TTL брокерского портфеля T-Bank (с) |
| `CACHE_TBANK_OPERATIONS_TTL` | 300 | TTL брокерских операций T-Bank (с) |
| `CACHE_TBANK_POSITIONS_TTL` | 60 | TTL брокерских позиций T-Bank (с) |
| `CACHE_TBANK_INSTRUMENT_TTL` | 86400 | TTL инструментов T-Bank (с) |
| `DATABASE_URL` | `file:./dev.db` | URL SQLite для Prisma |
| `JWT_SECRET` | `dev-jwt-secret-...` | Secret для access token |
| `JWT_REFRESH_SECRET` | `dev-refresh-secret-...` | Secret для refresh token |
| `JWT_ACCESS_EXPIRES` | `15m` | TTL access token |
| `JWT_REFRESH_EXPIRES` | `7d` | TTL refresh token |

32
apps/backend/.env.example Normal file
View File

@ -0,0 +1,32 @@
PORT=3000
DATABASE_URL=file:./dev.db
MOEX_BASE_URL=https://iss.moex.com/iss
MOEX_RATE_LIMIT=10
MOEX_CIRCUIT_BREAKER_THRESHOLD=5
MOEX_CIRCUIT_BREAKER_RESET_SECONDS=30
T_BANK_TOKEN=
T_BANK_BASE_URL=invest-public-api.tbank.ru:443
T_BANK_CA_CERT_PATH=
T_BANK_APP_NAME=ksv741.moex-vibe
T_BANK_RATE_LIMIT_PER_SECOND=5
T_BANK_INSTRUMENTS_RATE_LIMIT=20
T_BANK_REQUEST_TIMEOUT_MS=10000
CACHE_MARKET_DATA_TTL=900
CACHE_HISTORY_TTL=3600
CACHE_CANDLES_TTL=3600
CACHE_SECURITY_TTL=86400
CACHE_SEARCH_TTL=3600
CACHE_DIVIDENDS_TTL=86400
CACHE_TBANK_ACCOUNTS_TTL=3600
CACHE_TBANK_PORTFOLIO_TTL=60
CACHE_TBANK_OPERATIONS_TTL=300
CACHE_TBANK_POSITIONS_TTL=60
CACHE_TBANK_INSTRUMENT_TTL=86400
JWT_SECRET=dev-jwt-secret-change-in-production
JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production
JWT_ACCESS_EXPIRES=15m
JWT_REFRESH_EXPIRES=7d