Find a file
nns 58038c9cf7
Some checks failed
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 45s
CI / Web (React + Vite) (push) Successful in 39s
Docker API / Build + push API (push) Successful in 46s
Docker Web / Build + push Web (push) Successful in 30s
Docker API / Deploy API on stage (push) Failing after 36s
Docker Web / Deploy Web on stage (push) Successful in 11s
feat(directories): двухуровневые справочники Группы и Ед.измерения (системные + tenant)
Концепция: ProductGroup и UnitOfMeasure становятся двухуровневыми
справочниками. Системные эталонные записи (OrganizationId=NULL,
управляются SuperAdmin'ом) видны всем tenant'ам как «Эталон»
и read-only. Tenant'овские (OrganizationId=<orgId>) — обычная изоляция,
полный CRUD у админа орги.

Архитектура:
- IOptionalTenantEntity { Guid? OrganizationId } — новый интерфейс
  в Domain/Common. ProductGroup и UnitOfMeasure отнаследованы от
  Entity и реализуют его.
- AppDbContext.ApplyOptionalTenantFilter<T>: query-filter для
  IOptionalTenantEntity пропускает запись с OrganizationId=NULL для
  всех tenant'ов + tenant'овские по выбранной orgId. SuperAdmin без
  override видит всё, в override — только NULL+своё.
- StampTenant: при Add для IOptionalTenantEntity — null оставляется
  если SuperAdmin без override (системная), иначе подставляется
  tenant.OrganizationId.
- Миграция Phase4d_OptionalTenantOnDirectories: ALTER COLUMN
  OrganizationId DROP NOT NULL на product_groups и units_of_measure.
  Existing данные FOOD MARKET (11 групп, 5 единиц) сохраняются как
  tenant'овские — additive change, ничего не теряется.
- DTO: UnitOfMeasureDto и ProductGroupDto получили nullable
  OrganizationId; фронт читает его для показа badge «Эталон».
- Защита мутаций: PUT/DELETE контроллеры теперь возвращают Forbid()
  если запись OrganizationId=null и юзер не SuperAdmin (только
  суперадмин может править/удалять системные).

Frontend:
- Badge «Эталон» (indigo) рядом с именем системной записи в обеих
  страницах.
- Клик по строке системной записи → alert «Изменения недоступны…».
- SuperAdmin sidebar: новые пункты «Группы (эталон)» (FolderTree)
  и «Ед. измерения (эталон)» (Ruler) под «Справочники». Страницы
  реиспользуют существующие компоненты — для SuperAdmin без override
  фильтр возвращает все записи, что в Phase 4+ можно ужесточить
  отдельным эндпоинтом «только системные» (?orgId=null).

Decision (нонстоп-выбор по ТЗ): nullable OrganizationId через
IOptionalTenantEntity, не sentinel Guid.Empty — чище, безопаснее,
ясная семантика. Существующие группы FOOD MARKET НЕ мигрированы в
системные (как просил юзер) — пусть SuperAdmin сам создаст эталоны.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:20:47 +05:00
.claude feat: strict MoySklad schema — реплика потерянного f7087e9 2026-04-23 17:32:02 +05:00
.forgejo/workflows chore: remove one-shot ping workflow 2026-04-25 23:43:18 +05:00
.github/workflows.disabled ci: disable .github/workflows — Forgejo Actions is the primary CI now 2026-04-23 17:10:22 +05:00
deploy feat(bridge): /quiet и /loud команды для управления PreToolUse прогресс-лентой 2026-04-26 14:59:05 +05:00
docs docs: audit of our domain entities vs. live MoySklad API 2026-04-23 12:57:06 +05:00
src feat(directories): двухуровневые справочники Группы и Ед.измерения (системные + tenant) 2026-04-26 16:20:47 +05:00
.editorconfig Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
.gitattributes Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
.gitignore fix(auth): return 401 instead of 302 for API challenges; persist dev signing key across restarts 2026-04-21 21:42:53 +05:00
.nvmrc Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
CLAUDE.md Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
Directory.Build.props Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
Directory.Packages.props Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
food-market.sln Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
global.json Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
README.md Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00

food-market

Аналог системы МойСклад для розничной торговли в Казахстане.

Состав системы

  • Сервер (ASP.NET Core 8 + PostgreSQL) — мультитенантный API, web-админка на React
  • Web-админка (React 18 + Vite + shadcn/ui) — управление магазином, справочниками, документами, отчётами
  • Кассовая программа (WPF на .NET 8) — офлайн-работоспособная касса для Windows 10+, синхронизируется с сервером, работает с весами (Масса-К в первую очередь)

Структура репозитория

food-market/
├── src/
│   ├── food-market.domain/          # доменные сущности, enum'ы, события
│   ├── food-market.application/     # use cases (MediatR), DTO, интерфейсы
│   ├── food-market.infrastructure/  # EF Core, PostgreSQL, внешние сервисы
│   ├── food-market.api/             # ASP.NET Core + OpenIddict + SignalR
│   ├── food-market.web/             # React + Vite + shadcn/ui (SPA)
│   ├── food-market.shared/          # DTO-контракты сервер ↔ POS
│   ├── food-market.pos.core/        # логика POS (независима от UI)
│   └── food-market.pos/             # WPF + .NET 8 кассовая программа
├── tests/
├── deploy/
│   ├── docker-compose.yml           # PostgreSQL для локальной разработки
│   └── Dockerfile.api
└── docs/

Именование

  • Папки, проекты, csproj, docker-образы, URL — lowercase: food-market, food-market.api
  • C# namespacefoodmarket.Api, foodmarket.Domain (lowercase root; C# не допускает дефис в идентификаторах)
  • Отображаемое имя в UI — "Food Market"

Стек

Сервер

  • .NET 8 LTS (до ноября 2026), ASP.NET Core Minimal APIs + Controllers
  • EF Core 8 + Npgsql + PostgreSQL 16
  • OpenIddict 5 (OAuth2/OIDC — password + refresh tokens)
  • MediatR + FluentValidation (CQRS-lite)
  • SignalR (real-time синхронизация)
  • Hangfire (фоновые задачи)
  • Serilog (структурированное логирование)

Web

  • React 18 + Vite + TypeScript
  • shadcn/ui + Tailwind CSS
  • TanStack Query + TanStack Table
  • AG Grid Community (для тяжёлых grid'ов)
  • Recharts / Tremor (графики)
  • react-hook-form + Zod

POS

  • .NET 8 WPF, Windows 10+
  • CommunityToolkit.Mvvm (source-generated MVVM)
  • SQLite (локальная БД)
  • Refit + Polly (API-клиент с retry)
  • System.IO.Ports (драйверы весов: Масса-К и др.)

Мультитенантность

Каждая сущность имеет OrganizationId. Пользователь scoped к организации. EF Core query filter автоматически изолирует данные между тенантами.

Локальная разработка

# Поднять PostgreSQL
cd deploy && docker compose up -d

# Мигрировать БД
cd src/food-market.api && dotnet ef database update

# Запустить API
dotnet run --project src/food-market.api

# Запустить Web
cd src/food-market.web && pnpm install && pnpm dev

Статус

🚧 Phase 0: фундамент (scaffolding, auth, multi-tenancy)