Digital wallet и balance management¶
Раздел 05 · Редакционный стандарт
Тип материала — референсная архитектура. HYPOTHETICAL — схемы и операции. INFERENCE — инженерные рекомендации и критерии выбора. Внешние контракты ограничены источниками ниже.
Бизнес-задача¶
Разрешать конкурентный расход только в пределах доступных средств.
Требования¶
Отдельно учитывать booked, active holds и available. Чтение UI допускает явный stale marker. Spend требует текущей проверки.
Поток данных и владение состоянием¶
flowchart LR
A["Wallet API"] --> B["Spend service"]
B --> C["Ledger and holds DB"]
C --> D["Balance projection"]
D --> E["Reporting"]
Posted legs определяют booked. Holds уменьшают available. UI projection служит чтению.
Транзакционные границы¶
Под общей блокировкой позиции проверить лимит и создать hold. Capture атомарно уменьшает hold и пишет legs.
Порядок и идемпотентность¶
Capture и expiry конкурируют в одной области. Replay требует source revision и projection generation.
Нормальная последовательность¶
sequenceDiagram
participant A as Wallet API
participant B as Spend service
participant C as Ledger and holds DB
participant D as Balance projection
A->>B: Request debit against available funds
B->>C: Lock position and commit hold
C-->>B: Return hold ID and new revision
B->>D: Apply versioned balance update
Отказ и восстановление¶
sequenceDiagram
participant B as Spend service
participant C as Ledger and holds DB
participant E as Recovery operator
B->>C: Commit hold while projection event is delayed
Note over B,C: Outcome becomes uncertain
E->>C: Replay from ledger and active hold cut
E->>B: Resume from verified boundary
Два запроса могут увидеть одинаковый старый available. Повторить проверку под lock. После потери view восстановить позиции из истории.
Сверка¶
Пересчитать booked и holds на одном cut. Сверить остатки частично captured holds.
Гонка expiry и capture. Под одним guard прочитайте hold state и остаток. Если expiry первым зафиксировал release, поздний capture переводится в exception с проверкой PSP outcome. Если capture первым провёл сумму, expiry освобождает только оставшийся резерв. Rebuild использует snapshot ledger и hold state на одном cut. Теневая проекция не должна принимать live updates без generation fence.
Наблюдаемость¶
Старые holds, negative available, lag и mismatch.
Безопасность и применимость требований¶
Изолировать tenant и account. Аудировать инициатора release.
Альтернативы и trade-offs¶
Синхронная позиция ускоряет guard ценой contention. Async view масштабирует чтение.
Вопросы на собеседовании¶
Зачем освобождать hold при capture? Иначе available дважды учитывает один расход.