This commit is contained in:
parent
1dc27a6e9b
commit
a95308762f
354
AGENTS.md
354
AGENTS.md
@ -1,21 +1,56 @@
|
||||
# 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.
|
||||
- **Superpowers**: использовать релевантные Skills при старте задачи. Обычно: brainstorming для уточнения дизайна, systematic-debugging для багов, test-driven-development для feature/bugfix, writing-plans/executing-plans для крупных многошаговых работ, frontend-design для UI, requesting-code-review перед завершением крупных изменений.
|
||||
- **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).
|
||||
|
||||
## Структура документации
|
||||
### Структура документации
|
||||
|
||||
```text
|
||||
docs/
|
||||
@ -36,20 +71,23 @@ docs/
|
||||
|
||||
```
|
||||
|
||||
## Назначение документов
|
||||
### inbox.md
|
||||
Полный набор `spec.md`, `plan.md` и `tasks.md` обязателен для новых фич. Исторические feature-каталоги могут быть неполными: отсутствующие артефакты не требуется восстанавливать задним числом, если это не нужно для текущего изменения.
|
||||
|
||||
### Назначение документов
|
||||
|
||||
#### inbox.md
|
||||
|
||||
Содержит идеи и мысли, которые появились во время работы над проектом.
|
||||
|
||||
Записи в inbox не являются требованиями и не должны реализовываться напрямую.
|
||||
|
||||
### roadmap.md
|
||||
#### roadmap.md
|
||||
|
||||
Содержит список запланированных эпиков и фич.
|
||||
|
||||
Наличие задачи в 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 контракты
|
||||
- потоки данных
|
||||
- технический подход
|
||||
|
||||
### features/{feature-name}/tasks.md
|
||||
#### features/{feature-name}/tasks.md
|
||||
|
||||
Содержит список задач для реализации.
|
||||
|
||||
Задачи должны быть:
|
||||
|
||||
- небольшими
|
||||
- конкретными
|
||||
- независимыми по возможности
|
||||
|
||||
### Правила разработки
|
||||
|
||||
## Правила разработки
|
||||
#### Правило 1
|
||||
|
||||
|
||||
### Правило 1
|
||||
|
||||
Нельзя начинать реализацию без спецификации.
|
||||
Нельзя начинать реализацию новой фичи без спецификации.
|
||||
|
||||
Если спецификации нет:
|
||||
|
||||
@ -109,28 +148,23 @@ docs/
|
||||
- Уточнить требования.
|
||||
- Только после этого переходить к реализации.
|
||||
|
||||
### Правило 2
|
||||
#### Правило 2
|
||||
|
||||
Реализация должна соответствовать spec.md.
|
||||
|
||||
Если в процессе разработки выясняется, что требования неполные или ошибочные:
|
||||
|
||||
Не изменять поведение системы молча.
|
||||
- Не изменять поведение системы молча.
|
||||
- Сначала обновить spec.md и plan.md.
|
||||
- И только потом продолжать реализацию.
|
||||
|
||||
Сначала обновить:
|
||||
- spec.md
|
||||
- plan.md
|
||||
|
||||
И только потом продолжать реализацию.
|
||||
|
||||
### Правило 3
|
||||
#### Правило 3
|
||||
|
||||
Спецификация является источником истины.
|
||||
|
||||
Если plan.md противоречит spec.md:
|
||||
Приоритет имеет spec.md.
|
||||
Если plan.md противоречит spec.md — приоритет имеет spec.md.
|
||||
|
||||
### Правило 4
|
||||
#### Правило 4
|
||||
|
||||
Не добавлять функциональность, которая отсутствует в спецификации.
|
||||
|
||||
@ -139,65 +173,71 @@ docs/
|
||||
- обновить спецификацию;
|
||||
- либо создать новую фичу.
|
||||
|
||||
### Правило 5
|
||||
#### Правило 5
|
||||
|
||||
Исправления ошибок можно выполнять напрямую.
|
||||
Исправления ошибок можно выполнять напрямую. Новая функциональность должна проходить через спецификацию.
|
||||
|
||||
Новая функциональность должна проходить через спецификацию.
|
||||
#### Определение бага
|
||||
|
||||
Баг — это поведение системы, противоречащее спецификации, acceptance criteria, API-контракту, зафиксированному тестами поведению или подтверждённому архитектурному инварианту.
|
||||
|
||||
## Процесс работы над фичей
|
||||
Если желаемое поведение нигде не зафиксировано и не следует из существующего контракта или инварианта — это отсутствующая функциональность (new feature), а не баг.
|
||||
|
||||
При реализации фичи необходимо:
|
||||
Классификация:
|
||||
|
||||
1) Ознакомиться с эпиком, если он существует.
|
||||
2) Прочитать spec.md.
|
||||
3) Прочитать plan.md.
|
||||
4) Прочитать tasks.md.
|
||||
5) Выполнять задачи последовательно.
|
||||
6) Отмечать выполненные задачи.
|
||||
7) Обновлять plan.md при изменении технических решений.
|
||||
8) Обновлять spec.md при изменении требований.
|
||||
- **Есть зафиксированный контракт, поведение не соответствует** → баг (можно чинить напрямую, Правило 5)
|
||||
- **Нет зафиксированного контракта, требуется новое поведение** → новая фича (нужна спецификация)
|
||||
- **Spec есть, но в нём неопределённость** → сначала уточнить spec, потом решать, баг это или фича
|
||||
|
||||
## Работа с новыми идеями
|
||||
### Процесс работы над фичей
|
||||
|
||||
При реализации новой фичи необходимо:
|
||||
|
||||
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
|
||||
- История операций
|
||||
- Пагинация истории операций
|
||||
- Фильтрация истории операций
|
||||
- Экспорт истории операций
|
||||
|
||||
Все перечисленные возможности относятся к одному эпику.
|
||||
├── История операций
|
||||
├── Пагинация истории операций
|
||||
├── Фильтрация истории операций
|
||||
└── Экспорт истории операций
|
||||
```
|
||||
|
||||
Новый эпик создаётся только при появлении новой продуктовой возможности или нового домена.
|
||||
|
||||
## Поддержание документации
|
||||
### Поддержание документации
|
||||
|
||||
Документация должна соответствовать текущему состоянию проекта.
|
||||
|
||||
После значимых изменений необходимо обновлять:
|
||||
|
||||
- spec.md
|
||||
- plan.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 фичи.
|
||||
3. plan.md фичи.
|
||||
4. ADR.
|
||||
@ -236,70 +289,133 @@ Portfolio Dashboard
|
||||
|
||||
roadmap.md и inbox.md никогда не являются основанием для реализации функциональности.
|
||||
|
||||
## Git workflow
|
||||
### Git workflow
|
||||
|
||||
- Для каждой самостоятельной фичи создавать отдельную feature branch и вести разработку внутри неё.
|
||||
- Имя ветки по умолчанию начинать с `codex/`, если пользователь не попросил другой префикс.
|
||||
- Не смешивать независимые фичи в одной ветке. Небольшие связанные 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).
|
||||
- ADR для опубликованной документации находятся в `apps/docs/docs/adr/`.
|
||||
- OpenAPI source of truth — live Swagger JSON бэкенда на `/api/docs-json`; frontend generated types находятся в `apps/frontend/src/api/types.ts`.
|
||||
|
||||
## Команды
|
||||
### Definition of Done (DoD)
|
||||
|
||||
| Команда | Что делает |
|
||||
|---|---|
|
||||
| `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` |
|
||||
- Все acceptance criteria реализованы
|
||||
- Тесты проходят
|
||||
- Lint проходит
|
||||
- Для новой фичи созданы и обновлены spec/plan/tasks; для исторической фичи обновлены существующие и необходимые для текущего изменения артефакты
|
||||
- Документация обновлена
|
||||
- Нет TODO без согласования
|
||||
|
||||
Live MOEX integration tests opt-in: `npm run test:integration -w apps/backend`.
|
||||
---
|
||||
|
||||
Один тест: `npx vitest run path/to/test.spec.ts -w apps/backend`
|
||||
## Технические регламенты
|
||||
|
||||
## Переменные окружения
|
||||
### Правила тестирования
|
||||
|
||||
| Переменная | По умолчанию | Описание |
|
||||
|---|---|---|
|
||||
| `PORT` | 3000 | Порт бэкенда |
|
||||
| `MOEX_BASE_URL` | `https://iss.moex.com/iss` | Endpoint 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` | `''` | Server-side токен 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` | Metadata приложения для 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 | 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 результатов поиска (с) |
|
||||
| `CACHE_DIVIDENDS_TTL` | 86400 | TTL дивидендных данных (с) |
|
||||
| `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 |
|
||||
- Для новой бизнес-логики → обязательны unit-тесты
|
||||
- Для API-контрактов → интеграционные тесты
|
||||
- Не мокать собственный код без необходимости
|
||||
- В unit-тестах мокать внешние API (MOEX, T-Bank) и Prisma
|
||||
- При исправлении бага — сначала падающий тест (TDD)
|
||||
- Тесты писать рядом с основным кодом
|
||||
|
||||
### Работа с миграциями Prisma
|
||||
|
||||
- Никогда не редактировать файлы в `prisma/migrations/` вручную
|
||||
- После изменения `schema.prisma` → `npm exec -w apps/backend -- prisma migrate dev --name <name>`
|
||||
- Изменять существующие миграции допустимо только до их публикации/мержа. После мержа создавать новую миграцию
|
||||
- Всегда запускать `npm exec -w apps/backend -- prisma generate` после изменения схемы
|
||||
|
||||
### Правила рефакторинга
|
||||
|
||||
- Не выполнять крупный рефакторинг вне рамок задачи
|
||||
- Допустимы: локальные улучшения, устранение техдолга рядом с изменяемым кодом, исправление архитектурных нарушений
|
||||
- Запрещено: менять структуру проекта без ADR, переписывать модули без отдельной задачи
|
||||
- Крупный рефакторинг требует отдельного эпика/фичи + ADR
|
||||
|
||||
### Политики безопасности
|
||||
|
||||
- Запрещено логировать токены, пароли, секреты
|
||||
- Не отключать 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 напрямую.
|
||||
- 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 открыт).
|
||||
- In-memory кеш через `@nestjs/cache-manager`. Путь миграции на Redis описан (см. ADR-002).
|
||||
- Аутентификация: 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 } }`.
|
||||
- Алиасы: `@/*` → `src/*` в обоих пакетах.
|
||||
|
||||
## Фронтенд
|
||||
### Фронтенд
|
||||
|
||||
- React 18 + react-router-dom v6 + TanStack Query v5.
|
||||
- `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]`, и т.д.
|
||||
- CSS через `styles.css` (CSS custom properties, без CSS-in-JS или Tailwind).
|
||||
|
||||
## Стиль кода
|
||||
### Стиль кода
|
||||
|
||||
- Prettier: одинарные кавычки, trailing commas, printWidth 100, точки с запятой.
|
||||
- Бэкенд: `const`, PascalCase для модулей/контроллеров/сервисов, DTO в `dto/` внутри каждого модуля.
|
||||
|
||||
138
README.md
138
README.md
@ -2,60 +2,154 @@
|
||||
|
||||
Веб-приложение для анализа ценных бумаг Московской биржи (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
|
||||
# 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
|
||||
|
||||
# Start frontend (http://localhost:5173)
|
||||
# Запуск фронтенда (http://localhost:5173)
|
||||
npm run dev:frontend
|
||||
```
|
||||
|
||||
Swagger UI: http://localhost:3000/api/docs
|
||||
|
||||
---
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
- Frontend: http://localhost:80
|
||||
- Backend: http://localhost:3000
|
||||
- Фронтенд: http://localhost:80
|
||||
- Бэкенд: http://localhost:3000
|
||||
|
||||
## Tests
|
||||
---
|
||||
|
||||
## Тестирование
|
||||
|
||||
```bash
|
||||
npm run test:backend
|
||||
npm run test:frontend
|
||||
```
|
||||
|
||||
Live MOEX integration checks are opt-in:
|
||||
Интеграционные тесты с MOEX — опциональны:
|
||||
|
||||
```bash
|
||||
npm run test:integration -w apps/backend
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
---
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
apps/
|
||||
backend/ — NestJS API (single point of access to MOEX ISS)
|
||||
frontend/ — React SPA with Vite
|
||||
docs/ — Docusaurus documentation site
|
||||
backend/ — NestJS API, единая точка доступа к MOEX ISS
|
||||
frontend/ — React SPA на Vite
|
||||
docs/ — сайт документации Docusaurus
|
||||
docs/
|
||||
features/ — SDD feature specifications and implementation plans
|
||||
epics/ — product epics
|
||||
inbox.md — captured ideas and follow-ups
|
||||
roadmap.md — planned epics and features
|
||||
features/ — спецификации и планы реализации (SDD)
|
||||
epics/ — продуктовые эпики
|
||||
inbox.md — идеи и заметки
|
||||
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