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

Обзор архитектуры OneWallet

OneWallet — e-money кошелёк для Таиланда (регулятор Bank of Thailand, валюта THB). Это верхнеуровневая карта системы для разработчиков: какие сервисы есть, как они связаны и где искать детали.

На какие вопросы отвечает

  • Из каких сервисов состоит платформа и какие у них версии и порты?
  • Как запрос от приложения доходит до денег (кто кого вызывает)?
  • Кто имеет право писать в TigerBeetle, а кто только читает?
  • Сколько баз/схем у нас и как они изолированы?
  • Где читать про платежи, безопасность, хранилище, деплой?

Топология

graph TD
  loop[one_loop_app<br/>Flutter consumer]
  merch[one_merchant_app<br/>Flutter merchant]
  loop --> nginx
  merch --> nginx
  nginx[nginx ingress<br/>service-id: nginx-gateway<br/>HMAC-signer]
  nginx -->|/api/pm/* balance,history| PM
  nginx -->|остальное| AC
  AC[Auth Center<br/>Serverpod 3.4.8<br/>JWT KYC PII Mini-App]
  PM[Payment Manager<br/>Node 22 Fastify 5.8.5]
  AC -->|POST /intents HMAC| PM
  PM -->|pub/sub intent.id| AC
  AC -->|streamStatus| loop
  PM -->|write only| TB[(TigerBeetle 0.17.4<br/>ledger)]
  admin[admin-panel<br/>SvelteKit 2 + Svelte 5] -->|read-only| TB
  PM <--> VK[(Valkey<br/>Redis-совм.)]
  PM -->|Phase 1 in-process<br/>psp-worker IPPS| PSP[PSP / IPPS]
  PM --> PG[(PostgreSQL 17<br/>public / pm / blog)]
  AC --> PG

nginx не в docker-compose — это хостовой/отдельный ingress. Он подписывает запросы к PM как nginx-gateway. Внешние PSP-адаптеры на Redis Streams (Phase 2B) пока не реализованы: IPPS работает in-process внутри PM (psp-worker, таблица psp_tx_map, FOR UPDATE SKIP LOCKED).

Сервисы, версии и порты

Порты из projects/deploy/docker-compose.*.yml (внешний→внутренний).

Сервис Стек Порт
core (Auth Center + Flutter web) Serverpod 3.4.8 (Dart) 8090→8080 (RPC), 8081 (insights), 8082 (web)
payment-manager Node 22 + Fastify 5.8.5 + Drizzle 0.45.2 3099→3000
admin-panel SvelteKit 2 + Svelte 5 + TS + Tailwind v4 3200→3000
one_blog SvelteKit + Drizzle 3201→3000
kyc-service Node + BullMQ 3003
notifications-service Node + firebase-admin — (worker)
tigerbeetle TigerBeetle 0.17.4 3000 (internal)
postgres PostgreSQL 17 5432
valkey Valkey (Redis-совм.) 6379
garage (S3) dxflrs/garage v2.2.0 3900 (S3), 3902, 3903
garage-ui 2080

Профили compose: core, pm, kyc, s3, compreface. Redis DB: 0 = PM, 4 = Notifications, 9 = KYC. Подробнее — 07-deployment.md.

Базы данных: три схемы в одной PostgreSQL

Схема Владелец Миграции
public.* Auth Center (Serverpod) serverpod generate + --apply-migrations
pm.* Payment Manager drizzle-kit migrate
blog.* one_blog drizzle-kit migrate

Никто не пишет в чужую схему. Cross-schema чтение — только через views в public: v_user_tb_accounts, v_tx_history, v_blog_category, v_blog_location, v_blog_post (сгенерированы как Serverpod-модели, напр. onewallet_base_server/lib/src/generated/v_tx_history.dart). Детали — 03-data-and-schemas.md и ADR ../adr/0003-schema-separation.md.

Как это работает: пример P2P-перевода

INTERNAL P2P проходит синхронно в одном HTTP-запросе:

  1. Flutter → nginx → Auth Center.
  2. Auth Center подписывает HMAC и делает POST /intents с operationType=P2P_TRANSFER (канал INTERNAL_P2P резолвится роутером по operationType+amount, в запросе не передаётся).
  3. PM прогоняет intent CREATED → … → SETTLED синхронно (settleSync), пишет two-phase pending/post в TigerBeetle (инвариант transit.balance = 0), trace_id = intent_id.
  4. PM публикует статус в intent.{id} (Valkey pub/sub) → Auth Center → streamStatus во Flutter.

Внешние PSP-каналы возвращают на AUTHORIZED с requiresMonitoring=true, финал приходит асинхронно через тот же pub/sub. Полный конечный автомат intent (9 состояний) и 11 operationType — в 04-payments-and-ledger.md.

HMAC между сервисами

Единая схема (источник: projects/payment-manager/src/auth/hmac.ts). Заголовки X-Service-Id, X-Timestamp, X-Signature; подпись:

sig = HMAC-SHA256(secret, `${timestamp}\n${METHOD}\n${PATH}\n${sha256(body)}`)

Окно ±60 с, сравнение timing-safe. Деталь и список endpoint'ов — 05-security-and-auth.md, ADR ../adr/0002-single-hmac-auth.md.

Куда дальше

ADR (решения): ../adr/0001-tigerbeetle-ledger.md, ../adr/0002-single-hmac-auth.md, ../adr/0003-schema-separation.md, ../adr/0004-single-intent-api.md, ../adr/0005-pii-encryption.md, ../adr/0006-clients-and-appid.md.

Бизнес-контекст: ../business/01-what-is-onewallet.md. Контракт PM (канонический): ../../projects/payment-manager/PASSPORT.md.