docs: refresh project documentation
Some checks failed
Some checks failed
This commit is contained in:
parent
c062850e83
commit
117f182851
16
AGENTS.md
16
AGENTS.md
@ -2,7 +2,7 @@
|
||||
|
||||
## Репозиторий
|
||||
|
||||
npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/frontend` (React + Vite).
|
||||
npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/frontend` (React + Vite), `apps/docs` (Docusaurus).
|
||||
|
||||
## Обязательный подход к разработке
|
||||
|
||||
@ -16,13 +16,18 @@ npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/fr
|
||||
|---|---|
|
||||
| `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 lint` | ESLint только для бэкенда |
|
||||
| `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`
|
||||
|
||||
## Переменные окружения
|
||||
@ -46,7 +51,7 @@ npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/fr
|
||||
## Архитектура
|
||||
|
||||
- **Бэкенд** — единственный клиент MOEX. Фронтенд никогда не обращается к MOEX напрямую.
|
||||
- Feature-модули: `PrismaModule` (глобальный), `MoexClientModule` (глобальный), `CacheModule` (глобальный), `AuthModule`, `SharesModule`, `BondsModule`, `SecuritiesModule`, `CandlesModule`, `HealthModule`.
|
||||
- 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()` для открытых эндпоинтов).
|
||||
@ -70,5 +75,6 @@ npm workspaces монорепозиторий: `apps/backend` (NestJS), `apps/fr
|
||||
- Prettier: одинарные кавычки, trailing commas, printWidth 100, точки с запятой.
|
||||
- Бэкенд: `const`, PascalCase для модулей/контроллеров/сервисов, DTO в `dto/` внутри каждого модуля.
|
||||
- Бэкенд использует SWC через `unplugin-swc` (vitest config).
|
||||
- Тесты фронтенда отсутствуют.
|
||||
- CI/CD в репозитории нет.
|
||||
- Тесты фронтенда есть: Vitest + Testing Library + MSW.
|
||||
- CI находится в `.gitea/workflows/ci.yml`.
|
||||
- Pre-commit checks настроены через Husky и lint-staged.
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
- **Backend:** NestJS, TypeScript, OpenAPI (Swagger)
|
||||
- **Frontend:** React, TypeScript, Vite, TanStack Query, lightweight-charts
|
||||
- **Docs:** Docusaurus
|
||||
- **Infrastructure:** Docker, docker-compose
|
||||
|
||||
## Quick Start
|
||||
@ -36,6 +37,13 @@ docker compose up --build
|
||||
|
||||
```bash
|
||||
npm run test:backend
|
||||
npm run test:frontend
|
||||
```
|
||||
|
||||
Live MOEX integration checks are opt-in:
|
||||
|
||||
```bash
|
||||
npm run test:integration -w apps/backend
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
@ -44,6 +52,7 @@ npm run test:backend
|
||||
apps/
|
||||
backend/ — NestJS API (single point of access to MOEX ISS)
|
||||
frontend/ — React SPA with Vite
|
||||
docs/ — Docusaurus documentation site
|
||||
docs/
|
||||
architecture/ — ADR documents and diagrams
|
||||
openapi/ — OpenAPI specification
|
||||
|
||||
@ -130,6 +130,25 @@
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /securities/screener`
|
||||
|
||||
Скринер ценных бумаг по параметрам цены, объёма, доходности, дюрации, купона и срока погашения.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Param | Type | Required | Description |
|
||||
|---|---|---|---|
|
||||
| `type` | enum | yes | `share` или `bond` |
|
||||
| `priceMin`, `priceMax` | number | no | Диапазон цены |
|
||||
| `volumeMin` | number | no | Минимальный объём |
|
||||
| `yieldMin`, `yieldMax` | number | no | Диапазон доходности облигаций |
|
||||
| `durationMin`, `durationMax` | number | no | Диапазон дюрации |
|
||||
| `sortBy` | string | no | Поле сортировки |
|
||||
| `sortOrder` | enum | no | `asc` или `desc` |
|
||||
| `page`, `pageSize` | integer | no | Пагинация |
|
||||
|
||||
**Response:** `{ data: { items, total, page, pageSize, totalPages }, meta }`.
|
||||
|
||||
## Shares
|
||||
|
||||
### `GET /securities/shares/:secid`
|
||||
@ -354,3 +373,22 @@
|
||||
"meta": { "fromCache": false, "cachedAt": null }
|
||||
}
|
||||
```
|
||||
|
||||
## Portfolios
|
||||
|
||||
Все portfolio endpoints защищены JWT и возвращают envelope `{ data, meta }`.
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|---|---|---|
|
||||
| `/api/v1/portfolios` | GET | Список портфелей пользователя |
|
||||
| `/api/v1/portfolios` | POST | Создать портфель |
|
||||
| `/api/v1/portfolios/:id` | GET | Детали портфеля с позициями и текущими ценами |
|
||||
| `/api/v1/portfolios/:id` | PATCH | Обновить портфель |
|
||||
| `/api/v1/portfolios/:id` | DELETE | Удалить портфель |
|
||||
| `/api/v1/portfolios/:id/positions` | POST | Добавить позицию |
|
||||
| `/api/v1/portfolios/:id/positions/:positionId` | PATCH | Обновить позицию |
|
||||
| `/api/v1/portfolios/:id/positions/:positionId` | DELETE | Удалить позицию |
|
||||
| `/api/v1/portfolios/:id/analytics` | GET | Аналитика портфеля и PnL |
|
||||
|
||||
`DELETE` endpoints возвращают `{ data: null, meta }`, что отражено в OpenAPI schema и frontend
|
||||
codegen types.
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Portfolio Module
|
||||
|
||||
The Portfolio module allows users to create and manage virtual investment portfolios for tracking purposes.
|
||||
Portfolio module позволяет пользователям создавать и вести виртуальные инвестиционные портфели для
|
||||
аналитики и отслеживания позиций.
|
||||
|
||||
## Overview
|
||||
|
||||
@ -10,19 +11,19 @@ The Portfolio module allows users to create and manage virtual investment portfo
|
||||
|
||||
## API Endpoints
|
||||
|
||||
All endpoints require JWT authentication (`JwtAuthGuard`).
|
||||
Все endpoints требуют JWT authentication (`JwtAuthGuard`).
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|---|---|---|
|
||||
| `/api/v1/portfolios` | GET | List user's portfolios |
|
||||
| `/api/v1/portfolios` | POST | Create portfolio |
|
||||
| `/api/v1/portfolios/:id` | GET | Portfolio detail with enriched positions and analytics summary |
|
||||
| `/api/v1/portfolios/:id/analytics` | GET | Detailed portfolio analytics with PnL |
|
||||
| `/api/v1/portfolios/:id/patch` | PATCH | Update portfolio (name, description, currency) |
|
||||
| `/api/v1/portfolios/:id` | DELETE | Delete portfolio (cascade deletes positions) |
|
||||
| `/api/v1/portfolios/:id/positions` | POST | Add position (accepts buyPrice, buyDate) |
|
||||
| `/api/v1/portfolios/:id/positions/:posId` | PATCH | Update position (quantity, buyPrice, buyDate, notes) |
|
||||
| `/api/v1/portfolios/:id/positions/:posId` | DELETE | Remove position |
|
||||
| `/api/v1/portfolios` | GET | Список портфелей пользователя |
|
||||
| `/api/v1/portfolios` | POST | Создать портфель |
|
||||
| `/api/v1/portfolios/:id` | GET | Детали портфеля с обогащёнными позициями и analytics summary |
|
||||
| `/api/v1/portfolios/:id/analytics` | GET | Детальная аналитика портфеля и PnL |
|
||||
| `/api/v1/portfolios/:id` | PATCH | Обновить портфель (name, description, currency) |
|
||||
| `/api/v1/portfolios/:id` | DELETE | Удалить портфель вместе с позициями |
|
||||
| `/api/v1/portfolios/:id/positions` | POST | Добавить позицию (buyPrice, buyDate, notes, tags) |
|
||||
| `/api/v1/portfolios/:id/positions/:positionId` | PATCH | Обновить позицию |
|
||||
| `/api/v1/portfolios/:id/positions/:positionId` | DELETE | Удалить позицию |
|
||||
|
||||
## Domain Model
|
||||
|
||||
|
||||
@ -24,6 +24,19 @@ openapi-typescript http://localhost:3000/api/docs-json -o src/api/types.ts
|
||||
### Output
|
||||
|
||||
- `apps/frontend/src/api/types.ts` — сгенерированные типы `paths` и `operations`
|
||||
- `docs/openapi/openapi.yaml` — статический snapshot Swagger JSON для ревью и документации
|
||||
|
||||
### Verify Artifacts
|
||||
|
||||
После регенерации OpenAPI artifacts запустите:
|
||||
|
||||
```bash
|
||||
npm run test -w apps/backend -- src/openapi-artifacts.spec.ts
|
||||
```
|
||||
|
||||
Тест проверяет, что checked-in frontend types и YAML содержат актуальные auth, screener и portfolio
|
||||
paths, не содержат локальный alternate port и сохраняют важные schema metadata для nullable полей,
|
||||
array enum tags и typed response envelopes.
|
||||
|
||||
### Manual Types
|
||||
|
||||
|
||||
@ -5,13 +5,16 @@
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `npm run dev:backend` | Запуск NestJS в режиме watch на :3000 |
|
||||
| `npm run dev:frontend` | Vite dev-сервер на :5173, проксирует `/api` → :3000 |
|
||||
| `npm run dev:frontend` | Vite dev-сервер на `:5173`, проксирует `/api` на backend |
|
||||
| `npm run dev:docs` | Docusaurus dev-сервер документации |
|
||||
| `npm run build:backend` | `nest build` |
|
||||
| `npm run build:frontend` | `tsc -b && vite build` (в две фазы) |
|
||||
| `npm run test:backend` | `vitest run` (SWC, не ts-jest) |
|
||||
| `npm run lint` | ESLint только для бэкенда |
|
||||
| `npm run build:frontend` | `tsc -b && vite build` |
|
||||
| `npm run build:docs` | `docusaurus build` |
|
||||
| `npm run test:backend` | Offline backend unit tests через Vitest |
|
||||
| `npm run test:frontend` | Frontend tests через Vitest + Testing Library |
|
||||
| `npm run lint` | ESLint для backend и frontend |
|
||||
| `npm run format` | Prettier для всех `*.{ts,tsx}` |
|
||||
| `npm run format:check` | Prettier check для всех `*.{ts,tsx}` |
|
||||
| `npm run format:check` | Проверка Prettier для всех `*.{ts,tsx}` |
|
||||
|
||||
## Backend Workspace
|
||||
|
||||
@ -23,6 +26,7 @@
|
||||
| `npm run lint -w apps/backend` | ESLint для `{src,test}/**/*.ts` |
|
||||
| `npm run test -w apps/backend` | `vitest run` |
|
||||
| `npm run test:watch -w apps/backend` | `vitest` |
|
||||
| `npm run test:integration -w apps/backend` | Opt-in live MOEX integration tests, требуется network access |
|
||||
|
||||
## Frontend Workspace
|
||||
|
||||
@ -32,6 +36,16 @@
|
||||
| `npm run build -w apps/frontend` | `tsc -b && vite build` |
|
||||
| `npm run preview -w apps/frontend` | `vite preview` |
|
||||
| `npm run codegen -w apps/frontend` | `openapi-typescript` из Swagger → `src/api/types.ts` |
|
||||
| `npm run lint -w apps/frontend` | ESLint для `src/**/*.{ts,tsx}` |
|
||||
| `npm run test -w apps/frontend` | Frontend Vitest suite |
|
||||
|
||||
## Docs Workspace
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `npm run dev -w apps/docs` | Docusaurus dev-server |
|
||||
| `npm run build -w apps/docs` | Production build документации |
|
||||
| `npm run serve -w apps/docs` | Локальная проверка production build |
|
||||
|
||||
## Single Test
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ Prettier (`.prettierrc`):
|
||||
|
||||
## Linting
|
||||
|
||||
ESLint только для бэкенда (`apps/backend`).
|
||||
ESLint запускается для backend (`apps/backend`) и frontend (`apps/frontend`).
|
||||
|
||||
Плагины:
|
||||
- `@typescript-eslint/eslint-plugin`
|
||||
|
||||
@ -39,4 +39,25 @@ npm run test:watch -w apps/backend
|
||||
|
||||
## Frontend Tests
|
||||
|
||||
Фронтенд-тесты отсутствуют.
|
||||
Фреймворк: **Vitest 4** + **React Testing Library** + **MSW**.
|
||||
|
||||
Запуск:
|
||||
|
||||
```bash
|
||||
npm run test:frontend
|
||||
# или
|
||||
npm run test -w apps/frontend
|
||||
```
|
||||
|
||||
Тесты покрывают API-клиент, auth context, hooks, базовые pages и shared components.
|
||||
|
||||
## Live MOEX Integration Tests
|
||||
|
||||
Live MOEX checks вынесены из default backend suite.
|
||||
|
||||
```bash
|
||||
npm run test:integration -w apps/backend
|
||||
```
|
||||
|
||||
Эта команда opt-in: она требует network access и может падать при недоступности MOEX или сетевых
|
||||
ограничениях окружения.
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
async function request<T>(
|
||||
path: string,
|
||||
params?: Record<string, string>,
|
||||
options?: { method?: string; body?: unknown; skipAuth?: boolean },
|
||||
): Promise<{ data: T; meta: ApiResponseMeta }>
|
||||
```
|
||||
|
||||
@ -20,7 +21,14 @@ async function request<T>(
|
||||
| Function | Method | Path |
|
||||
|---|---|---|
|
||||
| `getHealth()` | GET | `/api/v1/health` |
|
||||
| `register(data)` | POST | `/api/v1/auth/register` |
|
||||
| `login(data)` | POST | `/api/v1/auth/login` |
|
||||
| `refresh()` | POST | `/api/v1/auth/refresh` |
|
||||
| `logout()` | POST | `/api/v1/auth/logout` |
|
||||
| `getProfile()` / `getMe()` | GET | `/api/v1/auth/me` |
|
||||
| `updateProfile(data)` | PATCH | `/api/v1/auth/me` |
|
||||
| `searchSecurities(q, type?, limit?)` | GET | `/api/v1/securities/search` |
|
||||
| `screenSecurities(query)` / `getScreenerResults(query)` | GET | `/api/v1/securities/screener` |
|
||||
| `getShare(secid)` | GET | `/api/v1/securities/shares/:secid` |
|
||||
| `getShareMarketData(secid)` | GET | `/api/v1/securities/shares/:secid/marketdata` |
|
||||
| `getShareDividends(secid)` | GET | `/api/v1/securities/shares/:secid/dividends` |
|
||||
@ -30,6 +38,15 @@ async function request<T>(
|
||||
| `getBondHistory(secid, from, till)` | GET | `/api/v1/securities/bonds/:secid/history` |
|
||||
| `getShareCandles(secid, interval, from, till)` | GET | `/api/v1/securities/shares/:secid/candles` |
|
||||
| `getBondCandles(secid, interval, from, till)` | GET | `/api/v1/securities/bonds/:secid/candles` |
|
||||
| `getPortfolios()` | GET | `/api/v1/portfolios` |
|
||||
| `createPortfolio(data)` | POST | `/api/v1/portfolios` |
|
||||
| `getPortfolio(id)` | GET | `/api/v1/portfolios/:id` |
|
||||
| `updatePortfolio(id, data)` | PATCH | `/api/v1/portfolios/:id` |
|
||||
| `deletePortfolio(id)` | DELETE | `/api/v1/portfolios/:id` |
|
||||
| `addPosition(portfolioId, data)` | POST | `/api/v1/portfolios/:id/positions` |
|
||||
| `updatePosition(portfolioId, positionId, data)` | PATCH | `/api/v1/portfolios/:id/positions/:positionId` |
|
||||
| `removePosition(portfolioId, positionId)` | DELETE | `/api/v1/portfolios/:id/positions/:positionId` |
|
||||
| `getPortfolioAnalytics(portfolioId)` | GET | `/api/v1/portfolios/:id/analytics` |
|
||||
|
||||
## Types
|
||||
|
||||
@ -41,5 +58,8 @@ async function request<T>(
|
||||
- `BondResponse` — спецификация облигации + `BondMarketData`
|
||||
- `CandleItem`, `DividendItem`, `ShareHistoryItem`, `BondHistoryItem`
|
||||
- `SearchResultItem`, `HealthResponse`
|
||||
- `UserResponse`, `AuthResponse`
|
||||
- `Portfolio`, `PortfolioDetail`, `Position`, `PortfolioSummary`, `AnalyticsResponse`
|
||||
- `ScreenerItem`, `ScreenerResult`
|
||||
|
||||
Codegen-типы из OpenAPI в `api/types.ts` (генерируются через `npm run codegen`).
|
||||
|
||||
@ -9,6 +9,7 @@ React SPA, собранная с Vite.
|
||||
- TanStack Query v5
|
||||
- lightweight-charts v4
|
||||
- openapi-fetch (с рукописными типами `responses.ts`)
|
||||
- Vitest + Testing Library + MSW
|
||||
- Vite 5
|
||||
|
||||
## Source Layout
|
||||
@ -19,10 +20,22 @@ apps/frontend/src/
|
||||
├── App.tsx # BrowserRouter
|
||||
├── routes.tsx # Маршруты
|
||||
├── api/
|
||||
│ ├── auth.ts # Auth API helpers
|
||||
│ ├── client.ts # HTTP-клиент (fetch)
|
||||
│ ├── portfolio.ts # Portfolio API helpers
|
||||
│ ├── responses.ts # Типы ответов (ручные)
|
||||
│ ├── screener.ts # Screener API helpers
|
||||
│ └── types.ts # Типы из openapi-typescript
|
||||
├── context/
|
||||
│ └── AuthContext.tsx
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts
|
||||
│ ├── usePortfolio.ts
|
||||
│ ├── usePortfolioAnalytics.ts
|
||||
│ ├── usePortfolioMutations.ts
|
||||
│ ├── usePortfolios.ts
|
||||
│ ├── usePositionMutations.ts
|
||||
│ ├── useScreener.ts
|
||||
│ ├── useSearch.ts
|
||||
│ ├── useStock.ts
|
||||
│ ├── useStockCandles.ts
|
||||
@ -31,14 +44,24 @@ apps/frontend/src/
|
||||
│ └── useBondCandles.ts
|
||||
├── components/
|
||||
│ ├── Layout.tsx
|
||||
│ ├── ProtectedRoute.tsx
|
||||
│ ├── SearchBar.tsx
|
||||
│ ├── PriceChart.tsx
|
||||
│ ├── StockDetails.tsx
|
||||
│ └── BondDetails.tsx
|
||||
│ ├── BondDetails.tsx
|
||||
│ └── portfolios/
|
||||
├── pages/
|
||||
│ ├── HomePage.tsx
|
||||
│ ├── StockPage.tsx
|
||||
│ └── BondPage.tsx
|
||||
│ ├── BondPage.tsx
|
||||
│ ├── LoginPage.tsx
|
||||
│ ├── RegisterPage.tsx
|
||||
│ ├── ProfilePage.tsx
|
||||
│ ├── portfolios/
|
||||
│ └── screener/
|
||||
├── test/
|
||||
│ ├── handlers.ts # MSW handlers
|
||||
│ └── test-utils.tsx
|
||||
└── styles.css
|
||||
```
|
||||
|
||||
|
||||
@ -2,11 +2,17 @@
|
||||
|
||||
Определены в `apps/frontend/src/routes.tsx`.
|
||||
|
||||
| Path | Component | Description |
|
||||
|---|---|---|
|
||||
| `/` | `HomePage` | Главная страница с приветствием |
|
||||
| `/stocks/:secid` | `StockPage` | Страница акции |
|
||||
| `/bonds/:secid` | `BondPage` | Страница облигации |
|
||||
| Path | Component | Access | Description |
|
||||
|---|---|---|---|
|
||||
| `/` | `HomePage` | Public | Главная страница |
|
||||
| `/stocks/:secid` | `StockPage` | Public | Страница акции |
|
||||
| `/bonds/:secid` | `BondPage` | Public | Страница облигации |
|
||||
| `/screener` | `ScreenerPage` | Public | Скринер ценных бумаг |
|
||||
| `/login` | `LoginPage` | Public | Вход |
|
||||
| `/register` | `RegisterPage` | Public | Регистрация |
|
||||
| `/profile` | `ProfilePage` | Protected | Профиль текущего пользователя |
|
||||
| `/portfolios` | `PortfoliosListPage` | Protected | Список портфелей |
|
||||
| `/portfolios/:id` | `PortfolioDetailPage` | Protected | Детальная страница портфеля |
|
||||
|
||||
Все страницы обёрнуты в `Layout`, который содержит:
|
||||
|
||||
@ -22,6 +28,33 @@
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/stocks/:secid" element={<StockPage />} />
|
||||
<Route path="/bonds/:secid" element={<BondPage />} />
|
||||
<Route path="/screener" element={<ScreenerPage />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route
|
||||
path="/profile"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<ProfilePage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/portfolios"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<PortfoliosListPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/portfolios/:id"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<PortfolioDetailPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
</Routes>
|
||||
```
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
---
|
||||
slug: /
|
||||
---
|
||||
|
||||
# MoexVibe
|
||||
|
||||
Веб-приложение для анализа ценных бумаг Московской биржи (MOEX).
|
||||
@ -15,7 +19,8 @@
|
||||
moex-vibe/
|
||||
├── apps/
|
||||
│ ├── backend/ # NestJS API (единственная точка доступа к MOEX)
|
||||
│ └── frontend/ # React SPA
|
||||
│ ├── frontend/ # React SPA
|
||||
│ └── docs/ # Docusaurus documentation site
|
||||
├── docs/
|
||||
│ ├── architecture/ # ADR и диаграммы
|
||||
│ ├── openapi/ # OpenAPI-спецификация
|
||||
@ -31,6 +36,6 @@ moex-vibe/
|
||||
## Key Principles
|
||||
|
||||
- Backend — единственный клиент MOEX. Frontend никогда не обращается к MOEX напрямую.
|
||||
- npm workspaces монорепозиторий: `apps/backend` и `apps/frontend`.
|
||||
- npm workspaces монорепозиторий: `apps/backend`, `apps/frontend` и `apps/docs`.
|
||||
- Глобальный префикс API: `/api/v1`. Swagger: `/api/docs`.
|
||||
- Ответы API обёрнуты в `{ data: T, meta: { fromCache, cachedAt } }`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user