Files
backend/.ai/conventions/data.md
T
ksv741 e3ecb8c15e
Backend verify / commits (pull_request) Successful in 1m29s
Backend verify / security (pull_request) Successful in 1m5s
Backend verify / verify (pull_request) Successful in 6m13s
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 1m11s
Backend verify / verify (push) Failing after 7m34s
refactor: enforce repository boundary in application (WealthLedger/backend#171)
2026-11-04 22:29:01 +03:00

85 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<T>`, `GenericRepository<T>` и 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).