All checks were successful
- Add type query param to GET /accounts/:accountId/positions endpoint - Backend filters T-Bank portfolio positions by instrument type before pagination - Each instrument type (share, bond, etf, fund) has its own frontend table with independent cursor-based pagination and skeleton loading - Groups with no positions are automatically hidden - Cache key includes type for correct per-type caching - Remove centralized positions pagination state from BrokerAccountDetailPage - 94 backend tests / 112 frontend tests pass
106 lines
8.6 KiB
Markdown
106 lines
8.6 KiB
Markdown
# MoexVibe — Инструкция для агента
|
||
|
||
## Репозиторий
|
||
|
||
npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/frontend` (React + Vite), `apps/docs` (Docusaurus).
|
||
|
||
## Обязательный подход к разработке
|
||
|
||
- **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 в браузере.
|
||
|
||
## Git workflow
|
||
|
||
- Для каждой самостоятельной фичи создавать отдельную feature branch и вести разработку внутри неё.
|
||
- Имя ветки по умолчанию начинать с `codex/`, если пользователь не попросил другой префикс.
|
||
- Не смешивать независимые фичи в одной ветке. Небольшие связанные docs/chore/test-правки можно держать в той же ветке, если они относятся к текущей задаче.
|
||
|
||
## Документация и SDD-артефакты
|
||
|
||
- `apps/docs` — единственная опубликованная человекочитаемая документация проекта (Docusaurus).
|
||
- Root `docs` хранит только согласованные SDD-спецификации в `docs/superpowers/specs/`.
|
||
- Все SDD spec-файлы в `docs/superpowers/specs/` пишутся на русском языке; англоязычные термины допустимы для API, кода, протоколов и официальных названий.
|
||
- ADR для опубликованной документации находятся в `apps/docs/docs/adr/`.
|
||
- OpenAPI source of truth — live Swagger JSON бэкенда на `/api/docs-json`; frontend generated types находятся в `apps/frontend/src/api/types.ts`.
|
||
- Superpowers plans и временные execution logs не коммитить по умолчанию. Если нужен план для ревью, держать его кратким и переносить устойчивые решения в spec/ADR/docs.
|
||
|
||
## Команды
|
||
|
||
| Команда | Что делает |
|
||
|---|---|
|
||
| `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` |
|
||
|
||
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 для T-Bank |
|
||
| `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 |
|
||
|
||
## Архитектура
|
||
|
||
- **Бэкенд** — единственный клиент MOEX. Фронтенд никогда не обращается к MOEX напрямую.
|
||
- Feature-модули: `PrismaModule` (глобальный), `MoexClientModule` (глобальный), `CacheModule` (глобальный), `AuthModule`, `SharesModule`, `BondsModule`, `SecuritiesModule`, `CandlesModule`, `PortfolioModule`, `HealthModule`.
|
||
- `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()` для открытых эндпоинтов).
|
||
- БД: SQLite через Prisma ORM. Prisma client используется из `@prisma/client`; схема и миграции находятся в `apps/backend/prisma/`.
|
||
- Глобальный префикс NestJS: `/api/v1`. Swagger: `/api/docs`.
|
||
- Глобальный ValidationPipe (`transform: true, whitelist: true`), `HttpExceptionFilter`, `TransformInterceptor`, middleware логирования запросов.
|
||
- Ответы API обёрнуты в `{ data: T, meta: { fromCache, cachedAt } }`.
|
||
- Алиасы: `@/*` → `src/*` в обоих пакетах.
|
||
|
||
## Фронтенд
|
||
|
||
- React 18 + react-router-dom v6 + TanStack Query v5.
|
||
- `lightweight-charts` v4 для графиков цен.
|
||
- `openapi-fetch` + рукописные типы `responses.ts` (не полностью codegen'овые).
|
||
- TanStack Query по умолчанию: `staleTime: 900s`, `retry: 2`, `refetchOnWindowFocus: false`.
|
||
- Конвенция ключей запросов: `['stock', secid]`, `['securities', 'search', query]`, и т.д.
|
||
- CSS через `styles.css` (CSS custom properties, без CSS-in-JS или Tailwind).
|
||
|
||
## Стиль кода
|
||
|
||
- Prettier: одинарные кавычки, trailing commas, printWidth 100, точки с запятой.
|
||
- Бэкенд: `const`, PascalCase для модулей/контроллеров/сервисов, DTO в `dto/` внутри каждого модуля.
|
||
- Бэкенд использует SWC через `unplugin-swc` (vitest config).
|
||
- Тесты фронтенда есть: Vitest + Testing Library + MSW.
|
||
- CI находится в `.gitea/workflows/ci.yml`.
|
||
- Pre-commit checks настроены через Husky и lint-staged.
|