# 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 \ --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 для соответствия их логике.