- .NET 8 LTS solution with 7 projects (domain/application/infrastructure/api/shared/pos.core/pos[WPF]) - Central package management (Directory.Packages.props), .editorconfig, global.json pin to 8.0.417 - PostgreSQL 14 dev DB via existing brew service; food_market database created - ASP.NET Identity + OpenIddict 5 (password + refresh token flows) with ephemeral dev keys - EF Core 8 + Npgsql; multi-tenant query filter via reflection over ITenantEntity - Initial migration: 13 tables (Identity + OpenIddict + organizations) - AuthorizationController implements /connect/token; seeders create demo org + admin - Protected /api/me endpoint returns current user + org claims - React 19 + Vite 8 + Tailwind v4 SPA with TanStack Query, React Router 7 - Login flow with dev-admin placeholder, bearer interceptor + refresh token fallback - docs/architecture.md, CLAUDE.md, README.md Verified end-to-end: health check, password grant issues JWT with org_id, web app builds successfully (310 kB gzipped). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
102 lines
5.6 KiB
Markdown
102 lines
5.6 KiB
Markdown
# food-market — project guide for Claude
|
||
|
||
Аналог системы МойСклад для розничной торговли в Казахстане. Multi-tenant сервер + web-админка + Windows-касса.
|
||
|
||
## Naming
|
||
|
||
- **Брендинг lowercase везде:** папки, файлы, csproj, docker-образы, репо → `food-market`, `food-market.api`.
|
||
- **C# namespaces** — `foodmarket.Api`, `foodmarket.Domain`, `foodmarket.Infrastructure` и т.д. (C# не допускает дефис, поэтому `foodmarket` одним словом).
|
||
- **Отображаемое имя в UI** — "Food Market" или "food-market" в техн. контекстах.
|
||
|
||
## Стек
|
||
|
||
| Слой | Технология |
|
||
|---|---|
|
||
| Backend | .NET 8 LTS, ASP.NET Core, EF Core 8, PostgreSQL 14+ |
|
||
| Auth | OpenIddict 5 (password + refresh), ASP.NET Identity |
|
||
| Backend libs | MediatR, FluentValidation, Mapster (НЕ AutoMapper — тот стал платным + CVE), Serilog, Hangfire, SignalR |
|
||
| Web | React 19 + Vite + TypeScript 6, Tailwind CSS v4, shadcn/ui, TanStack Query, TanStack Table, AG Grid Community, react-hook-form + Zod |
|
||
| POS | WPF на .NET 8 (Windows 10+), CommunityToolkit.Mvvm, SQLite, Refit + Polly, System.IO.Ports для весов |
|
||
|
||
**Запрет на платные компоненты:** никаких Kendo UI, DevExpress, Syncfusion commercial, Telerik в новом коде. Если задача требует такой компонент — сначала спросить.
|
||
|
||
## Структура
|
||
|
||
```
|
||
food-market/
|
||
├── src/
|
||
│ ├── food-market.domain/ # чистые POCO, enum'ы, доменные события (никакого ASP.NET, EF)
|
||
│ ├── food-market.application/ # MediatR handlers, DTO, FluentValidation, интерфейсы
|
||
│ ├── food-market.infrastructure/ # EF Core, Identity, OpenIddict EF store, внешние сервисы
|
||
│ ├── food-market.api/ # ASP.NET Core, контроллеры, OpenIddict server
|
||
│ ├── food-market.web/ # React + Vite SPA
|
||
│ ├── food-market.shared/ # DTO-контракты сервер ↔ POS
|
||
│ ├── food-market.pos.core/ # логика POS (независима от UI)
|
||
│ └── food-market.pos/ # WPF (net8.0-windows, сборка возможна на macOS)
|
||
├── tests/
|
||
├── deploy/
|
||
│ └── docker-compose.yml # Postgres 16 для прод/Linux
|
||
├── docs/
|
||
└── food-market.sln
|
||
```
|
||
|
||
## Мультитенантность (важно)
|
||
|
||
Каждая доменная сущность реализует `ITenantEntity` (есть `OrganizationId`). `AppDbContext` применяет query filter автоматически через reflection — запросы видят только данные своей организации. `SuperAdmin` роль видит всё.
|
||
|
||
Tenant определяется из JWT claim `org_id`, который выдаётся при логине. См. `HttpContextTenantContext` в api.
|
||
|
||
**При создании новой сущности:**
|
||
1. Если данные относятся к магазину — наследовать от `TenantEntity`.
|
||
2. Если общие справочники (единицы измерения, страны) — от `Entity`.
|
||
3. Справочник организаций (`Organization`) — от `Entity` (сама по себе не tenant-scoped).
|
||
|
||
## БД для dev
|
||
|
||
Используется существующий **postgres@14** из brew (порт 5432). БД `food_market`, owner `nns`, пароль пустой.
|
||
|
||
Connection string в `appsettings.Development.json`. Для прода/Linux будет postgres@16 через `deploy/docker-compose.yml` (порт 5433 чтобы не конфликтовать).
|
||
|
||
**НЕ переключать systemwide postgres версию** — это сломает смежные проекты (calcman, purchase, makesales, food-market-server).
|
||
|
||
## Миграции EF Core
|
||
|
||
```bash
|
||
# Создать миграцию
|
||
dotnet ef migrations add <Name> \
|
||
--project src/food-market.infrastructure \
|
||
--startup-project src/food-market.api \
|
||
--output-dir Persistence/Migrations
|
||
|
||
# Применить
|
||
dotnet ef database update \
|
||
--project src/food-market.infrastructure \
|
||
--startup-project src/food-market.api
|
||
```
|
||
|
||
## Запуск dev
|
||
|
||
```bash
|
||
# API (http://localhost:5081)
|
||
ASPNETCORE_ENVIRONMENT=Development dotnet run --project src/food-market.api
|
||
|
||
# Web (http://localhost:5173)
|
||
cd src/food-market.web && pnpm dev
|
||
|
||
# Проверить здоровье
|
||
curl http://localhost:5081/health
|
||
|
||
# Получить токен (dev admin)
|
||
curl -X POST http://localhost:5081/connect/token \
|
||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
-d "grant_type=password&username=admin@food-market.local&password=Admin12345!&client_id=food-market-web&scope=openid profile email roles api"
|
||
```
|
||
|
||
## Соседние проекты (НЕ ломать)
|
||
|
||
В `~/Documents/devprojects/` есть: `food-market-server`, `food-market-app`, `calcman`, `purchase`, `makesales`. Любые изменения глобальных инструментов (nvm default, postgres CLI версия, .NET SDK) — только с подтверждения пользователя.
|
||
|
||
## Источник правды по функциональности
|
||
|
||
МойСклад API: `https://dev.moysklad.ru/doc/api/remap/1.2/`. Перед моделированием новых сущностей в Phase 1+ — подтягивать актуальные разделы через WebFetch для соответствия их логике.
|