# Prisma и data layer

## Паспорт документа

- Статус документа: working reference
- Актуально на: 28 марта 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении архитектурных решений, data layer или frontend data patterns
- Область применения: архитектурные и интеграционные справочные документы проекта
- Связанные документы:
  - [Текущее состояние](../project/current-state.md)
  - [Карта API-маршрутов](./api-routes.md)
  - [Платформенный design](../../specs/qadam-platform/design.md)

## Цель документа

Этот документ описывает текущий Prisma-контур Qadam как инженерный источник истины по модели данных, миграциям, генерации клиента и operational-практикам работы с базой.

## 1. Краткий вывод

В проекте Prisma оформлен не как локальная зависимость `apps/api`, а как отдельный workspace-пакет `@repo/prisma`. Это правильная архитектура для монолитного backend-ядра:

- схема данных централизована;
- migrations и generated client лежат рядом;
- seed и селекты живут в одном пакете;
- API и другие backend-слои получают единый источник истины по данным.

Текущий Prisma-контур подходит проекту, но требует дальнейшей инженерной дисциплины:

- schema change должен всегда идти вместе с migration;
- generated client должен обновляться синхронно;
- нужно дожать документацию по данным и аналитике;
- нужно убрать legacy-ощущение, что data layer живёт только “внутри API”.

## 2. Структура пакета `@repo/prisma`

Ключевые файлы:

- `packages/prisma/schema.prisma`
- `packages/prisma/migrations/*`
- `packages/prisma/generated/prisma/*`
- `packages/prisma/seed.ts`
- `packages/prisma/selects/*`
- `packages/prisma/index.ts`
- `packages/prisma/client.ts`
- `packages/prisma/enums.ts`

Назначение:

- `schema.prisma` — каноническая модель данных;
- `migrations/` — история структурных изменений БД;
- `generated/prisma/` — сгенерированный Prisma Client;
- `seed.ts` — наполнение тестовыми и demo-данными;
- `selects/*` — общие безопасные выборки для reuse в backend;
- `index.ts`, `client.ts`, `enums.ts` — публичные точки экспорта пакета.

## 3. Генерация и сборка

Generator настроен так:

```prisma
generator client {
  provider = "prisma-client-js"
  output   = "./generated/prisma"
}
```

Это означает:

- generated client хранится внутри пакета, а не в `node_modules/.prisma`;
- backend импортирует клиента через workspace-путь;
- build становится воспроизводимым и прозрачным.

Основные команды:

- `pnpm --filter @repo/prisma generate`
- `pnpm --filter @repo/prisma build`
- `pnpm --filter @repo/prisma migrate:dev`
- `pnpm --filter @repo/prisma migrate:deploy`
- `pnpm --filter @repo/prisma seed`

## 4. Runtime-модель Prisma в API

`PrismaService` в `apps/api/src/prisma/prisma.service.ts` наследуется от `PrismaClient` и добавляет production-полезную обвязку:

- primary connection через `DATABASE_URL`;
- optional read replica через `DATABASE_REPLICA_URL`;
- метод `$replica()` для read-only операций;
- lifecycle hooks `onModuleInit` / `onModuleDestroy`;
- structured logging через `PinoLogger`;
- режим `SKIP_EXTERNAL_CONNECTIONS=true` для export/openapi-задач.

Это важная инженерная деталь: OpenAPI export и похожие offline-задачи не обязаны поднимать реальные DB/Redis connections.

## 5. Что находится в схеме данных

### 5.1 Аккаунты и роли

Схема покрывает:

- `Account`
- `Buyer`
- `Parent`
- `Student`
- `Seller`
- `School`
- `OnlineSchool`
- `IndividualContributor`
- `SellerStaff`
- `Admin`

То есть ролевая модель у проекта уже физически зашита на уровне схемы данных.

### 5.2 Центральная продуктовая сущность

Главная продуктовая сущность — `Item`.

С ней связаны:

- продавец;
- школа / online school;
- subject и location;
- лиды;
- отзывы;
- media;
- schedules;
- performer groups;
- special offers;
- moderation records.

Именно `Item` является центром buyer/seller/admin-потоков и основной точкой для дальнейшей аналитики.

### 5.3 Лиды и отзывы

Схема уже содержит:

- `Lead`
- `Review`
- их связи с buyer/seller/item

Это важно, потому что аналитика воронки и quality metrics уже может строиться поверх реальных сущностей, а не поверх временных event-only логов.

### 5.4 Admin и модерация

Для moderation слоя уже есть:

- `Admin`
- `AdminModeration`

Это создаёт основу для audit trail и дальнейшей операционной аналитики по модерации.

### 5.5 Аналитический append-only слой

В схеме есть `EventLog`.

Это не отдельная BI-схема, а operational analytics log в основном postgres-контуре. Он уже достаточен для:

- product event tracking;
- аудита действий;
- ручных выборок;
- будущего ETL в отдельную аналитическую систему.

## 6. Миграции

Сейчас в пакете уже есть migrations:

- `20260312231315_initial_schema`
- `20260315211735_add_event_log_table`

Это означает, что аналитический слой `EventLog` уже формально зафиксирован migration-историей, а не только кодом.

Operational-правило для production:

- schema change без migration недопустим;
- `migrate:deploy` выполняется до рестарта сервисов;
- факт отсутствия pending migrations должен проверяться в release-пакете.

## 7. Seed и demo-данные

`seed.ts` не ограничивается примитивными справочниками. Он создаёт:

- subjects;
- locations;
- продавцов разных типов;
- buyer/demo-данные;
- большой набор айтемов и связанных сущностей.

Практический смысл:

- локальная разработка быстрее стартует;
- buyer/seller/public flows можно быстро прогонять на наполненной БД;
- каталог и reference data не выглядят пустыми на dev/staging.

При этом seed не должен восприниматься как production migration-инструмент. Его задача — development/demo bootstrap.

## 8. Канонические правила работы с Prisma

1. Источник истины по структуре БД — только `packages/prisma/schema.prisma`.
2. Любое изменение схемы должно сопровождаться migration.
3. После schema change обязательно прогоняются `generate` и `build`.
4. Backend использует Prisma через `PrismaService`, а не создаёт новые `PrismaClient` в произвольных местах.
5. Frontend не должен тянуть Prisma runtime-код.
6. Общие enums и select helpers должны жить в `@repo/prisma`, а не дублироваться по проекту.

## 8.1 Правило идентификаторов для аналитического контура

Для аналитического слоя фиксируется отдельное обязательное правило, которое не меняет продуктовую Prisma-схему:

- в backend и operational PostgreSQL источником истины остаются внешние идентификаторы в текущем продуктово-сервисном формате;
- raw/staging слой аналитики принимает эти значения как есть и хранит их как внешние технические ключи `*_id_ext`;
- внутри аналитической БД любая сущность, которая попадает во внутренние join, факты и витрины, получает собственный surrogate key типа `bigint` (`*_id`);
- соответствие `*_id_ext <-> *_id` поддерживается через отдельный mapping-слой `1:1`;
- все внутренние join, агрегаты и витрины в аналитике строятся только по внутренним `bigint`, а `*_id_ext` остаётся ключом для загрузки, трассировки и сверки с продуктовым контуром.

Это означает, что backend не подстраивает продуктовую схему под аналитические `bigint`, а аналитический контур не использует внешние UUID/string идентификаторы как основной join key в своих heavy queries.

## 9. Текущие пробелы и риски

- В `package.json#prisma` используется deprecated-конфигурация seed; позже нужен переход на `prisma.config.ts`.
- Нет отдельного документа по retention/архивации для `EventLog`.
- Нет dedicated read-model / analytics mart поверх operational postgres.
- Нет formal data contract docs по ключевым таблицам уровня BI/аналитики.
- Нет автоматической проверки архитектурного правила “не создавать сырые PrismaClient вне `PrismaService`”.

## 10. Рекомендуемые следующие шаги

1. Зафиксировать канонический data contract для `Item`, `Lead`, `Review`, `EventLog`.
2. Документировать allowed read-path через `$replica()` и policy использования replica.
3. Перевести Prisma seed/config на актуальный формат перед Prisma 7.
4. Добавить отдельные интеграционные проверки на migrations и critical selects.
5. Дальше строить аналитику поверх уже существующего Prisma/EventLog контура, а не вводить параллельный data stack без необходимости.
