# Backend data ## Ownership и выбор операции PrismaService — существующий shared DB provider с lifecycle приложения. `prisma/schema.prisma` и migrations владеют persistence; `generated/prisma` создаётся Prisma и не редактируется вручную. Конфигурация URL находится в `prisma.config.ts`/validated environment; SQLite — текущая локальная база. | Ситуация | Решение | | --- | --- | | Данные для use case | Concrete repository; use case не импортирует PrismaService/Prisma и не строит queries | | Несколько записей обязаны выполниться вместе | Database transaction вокруг инварианта | | Конкурентная смена одного значения | Atomic conditional update/constraint с проверкой результата | | Независимые reads | Не добавляй transaction ради внешнего вида | | Общая persistence abstraction | Только при реальной общей ответственности; generic repository для одной Prisma реализации не нужен | Размещение repository определяется [Architecture](../architecture.md): в слоистом module это `infrastructure/`. Repository — конкретный класс `*.repository.ts` у business owner, без обязательных interface/port/adapter. Он владеет queries, includes/filtering, DB mapping и согласованным чтением. Суффиксы `*.persistence.ts`, `*.store.ts`, `*.dao.ts` для той же роли не используем. Nest module регистрирует repository приватно. Новые business decisions (можно ли менять архивную карту, допустим ли перевод) принадлежат application/domain; repository сохраняет persistence и ownership ограничения. Existing checks/HTTP helpers в BankCardsRepository — migration candidate, не повод дублировать их при новом use case или разрывать transaction. `BaseRepository`, `GenericRepository` и RepositoryFactory поверх Prisma не нужны без отдельной общей ответственности. `BankCardsRepository.summaryData` проверяет владельца карты и получает операции с категориями в одной read transaction. `GetBankSummaryUseCase` выбирает период, вызывает repository, затем чистый `bankSummary` и формирует ответ. Prisma records не становятся domain entities: расчёт получает только нужные ему значения. Application-код не импортирует PrismaService и не строит Prisma queries. Репозиторий владеет запросом и CAS-проверкой результата, а application — правилами и формированием ответа. Типы Prisma допустимы только в type-only импортах для существующей транзакционной границы. Не создавай обёртку на каждый вызов Prisma без текущего потребителя. `BankCardsRepository.write` сохраняет retry/transaction boundary для банковских записей; callback с transaction client — локальная техническая граница, не API для domain. Выбирай только нужные данные, сохраняй user/account ownership в запросах и application checks. Предварительный lookup не заменяет unique constraint при race. Пример: AuthRepository преобразует P2002 в результат регистрации и выполняет conditional `updateMany` для refresh rotation; AuthService сохраняет HTTP error contract. Сначала пойми invariant; не копируй его flow в другой use case. Transaction не охватывает сетевой T-Bank вызов как будто это одна atomic DB операция. Планируй порядок и compensation по текущей задаче; не удерживай DB lock во время retry внешней сети. Access/cache generation semantics — у [T-Bank integration](integrations.md#retry-cache-и-protocol). ## Деньги и точность Для денежных значений используй existing decimal helpers и строковый wire value, не JS floating-point арифметику для сумм. Currency — отдельная часть Money; разные валюты не складываются без явно заданного conversion contract. Источник формы — `src/common/money.types.ts`; пример точной арифметики: [decimal.ts](../../src/common/decimal.ts). Форматирование ответа не меняет доменную семантику и точность расчёта. ## Schema и migration Сначала определи, какие существующие данные/consumers должны сохраниться. Миграцию проверяй на disposable копии с representative existing data; generated client обновляй из schema. Не переписывай уже применённую migration ради нового состояния и не выполняй reset/drop реальной базы как шаг верификации. Для destructive или compatibility-sensitive изменения подготовь backup/restore, переход и проверку отката до его применения. SQLite/local MVP не означает disposable data. **Безопасный путь:** additive изменение, заполнение/проверка данных и только затем удаление прежней формы, если задача этого требует. Примеры schema/migrations: [Prisma source](../../prisma/schema.prisma). SQLite — embedded storage текущего приложения; файл БД и encryption key требуют согласованного backup/restore. ## Проверка `npx prisma validate`; после schema change `npx prisma generate` и `npm run typecheck:app`. Invariants/atomicity/migration safety требуют tests на соответствующей boundary: mock Prisma не доказывает реальную transaction. Выбор integration/e2e и известные ограничения — в [Testing](testing.md).