01 schema overview
Обзор схемы pm.* PostgreSQL: 11 таблиц, их связи и конвенции хранения.
Назначение каталога¶
Каталог database/ — справочник по физической модели данных Payment Manager.
Вся информация PM хранится в собственной схеме PostgreSQL pm.*; схема public.* принадлежит Auth Center (Serverpod) и для PM доступна только на чтение через search_path=pm,public (см. CLAUDE.md).
Источник истины модели — src/shared/schema.ts (Drizzle ORM). DDL генерируется в каталог drizzle/migrations/ и применяется только через drizzle-kit migrate.
ER-диаграмма¶
Логические связи между таблицами по intent_id (UUID) не оформлены как FK в БД, но фактически держат всю цепочку платежа.
erDiagram
service_key ||--o{ intent : "service_id"
tb_account_map ||--o{ intent : "from_account_name / to_account_name"
tb_account_map ||--o{ tx_history : "account_name"
intent ||--o{ intent_event : "intent_id"
intent ||--o{ tx_history : "intent_id"
intent ||--o{ outbox_event : "intent_id"
intent ||--o| psp_tx_map : "intent_id (UNIQUE)"
payment_route }o--o{ intent : "operation_type + amount + channel"
fee_rule }o--o{ intent : "operation_type → pre/post fee"
limit_rule }o--o{ intent : "operation_type + channel + direction"
auth_policies }o--o{ intent : "scope (operationType:channel)"
service_key {
varchar service_id PK
jsonb permissions
boolean active
timestamptz created_at
}
tb_account_map {
serial id
varchar account_name PK
uuid tb_account_id UK
integer tb_ledger
varchar account_type
integer user_id
char currency
text ipps_wallet_id
}
intent {
uuid id PK
uuid idempotency_key
varchar service_id
integer user_id
varchar operation_type
varchar channel
varchar from_account_name
varchar to_account_name
bigint amount
varchar status
bigint pre_fee_amount
bigint post_fee_amount
uuid_array tb_transfer_ids
timestamptz expires_at
}
payment_route {
serial id PK
varchar operation_type
bigint amount_min
bigint amount_max
varchar channel
boolean active
}
fee_rule {
serial id PK
varchar name
varchar operation_type
text expression
char timing
integer priority
}
intent_event {
serial id PK
uuid intent_id
varchar status_from
varchar status_to
jsonb payload
}
tx_history {
serial id PK
uuid intent_id
integer user_id
varchar account_name
varchar direction
bigint amount
bigint fee_amount
jsonb attributes
}
outbox_event {
serial id PK
uuid intent_id
varchar action
varchar status
integer retry_count
}
psp_tx_map {
uuid id PK
uuid intent_id UK
text psp_name
text state
text query_rq_uid
text confirm_rq_uid
text leased_by
}
limit_rule {
serial id PK
varchar operation_type
varchar channel
varchar direction
varchar window
bigint amount_limit
integer count_limit
}
auth_policies {
bigserial id PK
varchar scope
jsonb condition
varchar required_step_up
integer priority
}
Список таблиц¶
| Таблица | Что хранит | Документ |
|---|---|---|
pm.intent |
Платёжное намерение — корневая сущность всей оркестрации | ./02-intent.md |
pm.tx_history |
Денежная история по account_name (DEBIT/CREDIT) |
./03-tx-history.md |
pm.payment_route |
Выбор канала по operationType + amount |
./04-payment-route.md |
pm.fee_rule |
Правила комиссий (PRE/POST), sandboxed JS-выражения | ./05-fee-rule.md |
pm.tb_account_map |
Маппинг account_name ↔ TigerBeetle account UUID + ledger |
./06-tb-account-map.md |
pm.psp_tx_map |
State-machine PSP-адаптера (IPPS; QP/WISE — заготовки) |
./07-psp-tx-map.md |
pm.auth_policies |
Политики step-up аутентификации (PIN/OTP/BIOMETRIC/KYC_UPLIFT) |
./08-auth-policies.md |
pm.outbox_event |
Очередь post_pending/void_pending для двухфазных TB-трансферов (OutboxWorker) |
./09-outbox-event.md |
pm.intent_event |
Аудит-лог переходов статусов intent и psp_tx_map |
./10-intent-event.md |
pm.service_key |
Регистрация сервисов-клиентов и их HMAC-разрешения | ./11-service-key.md |
pm.limit_rule |
Лимиты на операции (PER_TX/DAILY/MONTHLY) по сумме и счёту |
./12-limit-rule.md |
Конвенции¶
- Схема. Все таблицы — в
pm.*. Серверподовская схемаpublic.*для PM строго read-only. - Деньги. Суммы всегда
BIGINTв satang (минимальная единица THB, 1 THB = 100 satang). Поля:amount,pre_fee_amount,post_fee_amount,fee_amount,amount_min/amount_max,amount_limit. Никакихnumeric/floatдля денег. - Валюта.
currency—CHAR(3), по умолчанию'THB'. - Время. Все временные поля —
TIMESTAMPTZ(timestamp with time zone), по умолчаниюnow(). - Enum-литералы. Реализованы как
VARCHAR(N)+CHECK(а не PostgreSQLENUM), TypeScript-типы заданы через.$type<...>(). Полный перечень: см. экспортируемые алиасы (IntentStatus,PspState,TxDirection,OutboxAction,OutboxStatus,StepUpLevel,AccountType,PspName) вsrc/shared/schema.ts. - Идентификаторы. Бизнес-ключи (
intent.id,psp_tx_map.id,tb_account_map.tb_account_id) —UUID. Технические —SERIAL/BIGSERIAL. - Связи через
intent_id. FK наintent.idне объявлены в DDL, чтобы не блокировать запись событий при concurrent-обновлениях; целостность держится прикладным кодом и индексами (intent_event_intent_id_idx,tx_history_intent_id_idx,outbox_event_intent_id_idx,psp_tx_map.intent_id UNIQUE). - Каналы (
intent.channel). Реальные channel-имена изsrc/channels/*.ts:INTERNAL_P2P(синхронный settle),IPPS_TRANSFER,SERVICE_TRANSFER,ADMIN(служебные операции от админки),MERCHANT_INVOICE(двухфазный, черезTwoPhaseChannel). ПривязкаoperationType → channelопределяетсяpm.payment_route. ТипPspName(IPPS/QP/WISE) вpm.psp_tx_map.psp_name— это перечень PSP-адаптеров (сейчас активен толькоIPPS;QP/WISE— заготовки на будущее). - Статусы
intent.status. ТолькоCREATED, VALIDATED, AUTHORIZED, SETTLING, SETTLED, FAILED, MANUAL_REVIEW, CANCELED, EXPIRED.
Миграции¶
DDL и порядок применения миграций описаны в ./13-migrations.md. Все изменения схемы — только через drizzle-kit generate → review SQL → drizzle-kit migrate. Ручной DDL в pm.* запрещён (см. CLAUDE.md, раздел Critical Rules).