Перейти к содержанию

02. Карта модулей src/*

Краткая карта всех подкаталогов src/ Payment Manager, их ответственности и зависимостей между собой. Используется как точка входа в детальные документы по каждому модулю (../modules/*.md).

Назначение

src/ Payment Manager состоит из 14 подкаталогов плюс двух корневых файлов (server.ts — точка сборки Fastify; migrate.ts — CLI для миграций Drizzle). Каждый подкаталог отвечает за один аспект платёжной обработки и имеет ограниченный набор зависимостей: верхние слои (HTTP, оркестрация) опираются на нижние (ledger, shared), но не наоборот.

Этот документ описывает топологию: какие модули используют какие. Все детали (DTO, ключи Redis, формат событий) — в соответствующих ../modules/*.md.

Диаграмма зависимостей

flowchart TD
  server[server.ts<br/>Fastify wiring]

  subgraph HTTP[HTTP layer]
    admin[admin/]
    auth[auth/]
    policies[policies/]
    intent_http[intent/<br/>handler · quote · confirm · cancel]
  end

  subgraph Orchestration[Оркестрация]
    intent_core[intent/<br/>router · step-registry · operation-registry]
    channels[channels/]
    optypes[operation-types/]
  end

  subgraph Domain[Доменные сервисы]
    ledger[ledger/]
    limits[limits/]
    accounts[accounts/]
    rule[rule-engine/]
    psp[psp/]
  end

  subgraph Async[Асинхронная обработка]
    workers[workers/]
    jobs[jobs/]
  end

  shared[shared/<br/>db · redis · schema · errors · logger]

  server --> HTTP
  server --> workers

  intent_http --> intent_core
  intent_http --> auth
  intent_core --> channels
  intent_core --> optypes
  channels --> ledger
  channels --> psp
  optypes --> ledger
  optypes --> limits
  optypes --> rule
  optypes --> accounts

  policies --> shared
  admin --> shared
  auth --> shared

  workers --> ledger
  workers --> psp
  workers --> jobs
  jobs --> shared

  HTTP --> shared
  Orchestration --> shared
  Domain --> shared
  Async --> shared

Стрелка A --> B читается как «A импортирует из B». Все модули в конечном счёте упираются в shared/ (БД, Redis, схема, ошибки, конфиг, логгер).

Таблица модулей

Каталог Ответственность Документ
accounts/ Резолверы TigerBeetle-аккаунтов по имени/роли; обёртки над pm.tb_account_map. ../modules/ledger.md
admin/ HTTP-роуты для административных операций: health, debug-level, fee-rules. ../api/admin.md
auth/ HMAC-плагин Fastify (X-Service-Id / X-Timestamp / X-Signature), проверка service_key. TODO: ../modules/auth.md
channels/ Реализации каналов исполнения: INTERNAL_P2P, IPPS_TRANSFER, MERCHANT_INVOICE, SERVICE_TRANSFER, ADMIN и т.д. Каждый канал — это объект TwoPhaseChannel со steps reserve/commit/cancel/expire. TODO: ../modules/channels.md
intent/ Точка входа платежей. HTTP-обработчики (handler.ts, quote.ts, confirm-handler.ts, cancel-handler.ts), резолвер канала (router.ts), реестры (step-registry.ts, operation-registry.ts), запись событий, публикация статусов. TODO: ../modules/intent.md
jobs/ Описание фоновых job-ов (типы, payload-ы, статусы) для воркеров. ../modules/workers.md
ledger/ Единственная точка доступа к TigerBeetle: createAccounts, createTransfers, lookupAccounts. HTTP-роуты /accounts/*. TODO: ../modules/ledger.md
limits/ Расчёт и проверка лимитов (per-tx, daily, monthly). check-limits.ts, evaluate-policy.ts. TODO: ../modules/limits.md
operation-types/ Каталог operationType (P2P_TRANSFER, IPPS_WITHDRAWAL, THAI_QR_PAY, MERCHANT_PAYMENT, INVOICE_PAYMENT, SERVICE_DEPOSIT, ADMIN_TRANSFER и т.д.). Каждый тип задаёт: какой канал использует, какие fee-rule-ы, какие limit-ы. TODO: ../modules/operation-types.md
policies/ HTTP-роуты для step-up auth policies (см. docs/AUTH-POLICIES.md). TODO: ../modules/policies.md
psp/ Интеграция с PSP-провайдерами (IPPS-драйвер, очередь psp_tx_map). Phase 1 — in-process worker. TODO: ../modules/psp.md
rule-engine/ Калькулятор комиссий по правилам из pm.fee_rule: fee-calculator.ts, контекст и сплиты. TODO: ../modules/rule-engine.md
shared/ Общая инфраструктура: db.ts (Drizzle), redis.ts, schema.ts, errors.ts, logger.ts, config.ts, утилиты подписей. TODO: ../modules/shared.md
workers/ Фоновые воркеры (OutboxWorker, expiry, psp-worker). Запускаются ролью процесса в server.ts. TODO: ../modules/workers.md

Корневые файлы:

  • src/server.ts — собирает Fastify, регистрирует плагины (hmac, swagger, helmet, cors), монтирует роуты из admin/, auth/, ledger/, intent/, policies/. Стартует воркеры по роли (api / worker / psp-worker).
  • src/migrate.ts — CLI-точка для drizzle-kit migrate. Не часть рантайма.

Особенности именования (ловушки)

В кодовой базе несколько мест, где имена пересекаются с близкими, но не идентичными понятиями. Эти ловушки чаще всего ловят новых разработчиков и при review/grep-навигации.

  1. src/intent/router.ts — это resolveChannel(), а НЕ HTTP-routes. Файл экспортирует чистую функцию, которая по operationType и контексту возвращает имя канала (INTERNAL_P2P, IPPS_TRANSFER, …). HTTP-роуты /intents, /intents/quote, /intents/:id/confirm, /intents/:id/cancel регистрируются отдельными файлами: src/intent/handler.ts, src/intent/quote.ts, src/intent/confirm-handler.ts, src/intent/cancel-handler.ts. Не путать с Fastify-роутером.

  2. Канал ADMIN ≠ operationType ADMIN_TRANSFER. channels/admin*.ts (если/когда появится) реализует механику административных переводов; operation-types/admin-transfer.ts — конкретный operationType, который использует этот канал, но имеет собственные лимиты и проверки. В аналитике и логах оба значения попадают в разные поля (channel vs operation_type).

  3. Канал SERVICE_TRANSFER ≠ operationType SERVICE_DEPOSIT. Канал SERVICE_TRANSFER — это механика перевода между service- и user-аккаунтами. SERVICE_DEPOSIT — это operationType «зачисление от сервиса пользователю», который выполняется через канал SERVICE_TRANSFER. Один канал может обслуживать несколько operationType.

  4. Канал IPPS_TRANSFER ≠ operationTypes IPPS_WITHDRAWAL / THAI_QR_PAY. IPPS_TRANSFER — единый канал интеграции с IPPS PSP. На него маршрутизируются разные operationType: вывод средств (IPPS_WITHDRAWAL) и оплата по QR (THAI_QR_PAY). Они отличаются по комиссиям, лимитам и способу заполнения PSP-payload-а, но используют одну и ту же reserve/commit/cancel-механику в канале.

  5. operation-registry vs step-registry в src/intent/. operation-registry.ts — реестр operationType (что разрешено, какие политики применяются). step-registry.ts — реестр каналов и проверка isTwoPhase(). Это разные реестры с разной семантикой; легко перепутать при grep.

  6. accounts/ vs ledger/accounts.ts. src/accounts/ — высокоуровневые резолверы (по userId, по роли, по merchantId). src/ledger/accounts.ts — низкоуровневые обёртки над TigerBeetle SDK (getAccountByName, getAccountByTbId). Обращайтесь к accounts/; в ledger/ лазьте только если нужен прямой TB-lookup.

  7. shared/schema.ts — это Drizzle-схема pm.*, НЕ Zod-схемы. Zod-схемы DTO лежат рядом с роутами (например, src/intent/operation-type.ts экспортирует BaseIntentBody). Не путать с типами Drizzle-таблиц.

Детализация по слоям

HTTP-слой (точка входа всех внешних вызовов)

Все внешние клиенты (Auth Center, nginx-proxy для Flutter, admin panel, mini-app backends) попадают в PM через Fastify-роуты. Маршрутизация по файлам:

  • intent/handler.tsPOST /intents (создание платёжного intent, главный endpoint).
  • intent/quote.tsPOST /intents/quote (расчёт комиссии без фиксации).
  • intent/confirm-handler.tsPOST /intents/:id/confirm (commit для двухфазных каналов).
  • intent/cancel-handler.tsPOST /intents/:id/cancel (откат reserved-intent-а).
  • ledger/routes.tsGET /accounts/balance, GET /accounts/history и другие read-only-обёртки над TB.
  • admin/health.tsGET /health, GET /ready.
  • admin/debug-level.ts — управление log-level на лету.
  • admin/fee-rules.ts — CRUD над pm.fee_rule.
  • policies/routes.ts — CRUD над pm.auth_policy.

Все эти роуты проходят через auth/hmacPlugin.ts — глобальный preHandler, который валидирует подпись и кладёт serviceId в request.requestContext. Исключения — health-endpoint-ы.

Оркестрация (intent → channel → operation-type)

При входящем POST /intents поток такой:

  1. handler.ts парсит DTO (BaseIntentBody + специфичный для operationType discriminator).
  2. operation-registry.ts подтверждает, что operationType разрешён для данного serviceId.
  3. router.ts (resolveChannel) по operationType и контексту выбирает канал.
  4. step-registry.ts отдаёт реализацию канала (объект TwoPhaseChannel).
  5. Канал из channels/ исполняет reserve() (pending TB-transfer), при необходимости публикует job в psp/ или Redis.
  6. intent-events.ts записывает событие в pm.intent_event и публикует в Redis (intent.{id}).

Доменный слой (без HTTP, чистая логика)

  • ledger/ — единственная обёртка над TigerBeetle SDK. Никакой другой каталог не должен импортировать tigerbeetle-node напрямую.
  • accounts/ — резолверы «по смыслу» (userId, merchantId, роль), трансляция в TB account_id через pm.tb_account_map.
  • limits/ — реализация per-tx / daily / monthly лимитов. Читает pm.limit_policy, считает текущее окно по pm.intent.
  • rule-engine/ — fee-калькулятор. Принимает RuleContext, возвращает ResolvedFeeSplit (кому сколько и куда).
  • psp/ — драйверы PSP. В Phase 1 — IPPS in-process worker через psp_tx_map. В Phase 2B будет вынесен в отдельный сервис через Redis Streams.

Асинхронный слой

  • workers/ — long-running процессы:
  • OutboxWorker — публикует pending-события из pm.outbox.
  • ExpiryWorker — отменяет просроченные reserved-intent-ы.
  • PspWorker — Phase 1 IPPS-исполнитель (polling psp_tx_map через FOR UPDATE SKIP LOCKED).
  • jobs/ — типы job-ов (payload-схемы, статусы). workers/ опирается на эти типы.

Запуск воркеров определяется переменной окружения / argv role: server.ts стартует либо HTTP-сервер (api), либо воркеры (worker / psp-worker).

Связь с другими документами