This commit is contained in:
parent
1dc27a6e9b
commit
a95308762f
354
AGENTS.md
354
AGENTS.md
@ -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
138
README.md
@ -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
32
apps/backend/.env.example
Normal 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
|
||||||
Loading…
x
Reference in New Issue
Block a user