1.4 Data Models

Черновик модели данных платформы PSP Aggregator для backend: таблицы, enum, связи и JSON-схема атрибутов оффера.

Черновик модели данных платформы PSP Aggregator для backend: таблицы, enum, связи и JSON-схема атрибутов оффера.

[!WARNING] Черновик (Draft). Документ предназначен для расширения и детализации backend-командой. Бизнес-правила — в Core и User Stories, этот файл их не заменяет.

1. ER-диаграмма

erDiagram
    USERS ||--o{ DEALS : "creates/owns"
    PROVIDERS ||--o{ OFFERS : "has"
    OFFERS ||--o{ DEAL_ITEMS : "included in"
    DEALS ||--|{ DEAL_ITEMS : "contains"
    DEALS ||--o{ DEAL_EVENTS : "logs"

    USERS {
        uuid id PK
        enum role "SuperAdmin, Admin, Agent, Merchant"
        string email "UNIQUE"
        string password_hash
        string company_name
        enum status "Pending, Active, Blocked, Inactive, Rejected"
        uuid invited_by_agent_id FK "Nullable"
        string client_alias "Nullable"
        timestamp created_at
    }
    PROVIDERS {
        uuid id PK
        string real_name
        text description
        jsonb integration_methods
        string support_contacts
        enum status "Active, Paused"
        timestamp created_at
    }
    OFFERS {
        uuid id PK
        uuid provider_id FK
        string alias "Public Name"
        decimal raw_rate
        decimal platform_margin
        jsonb attributes
        enum status "Active, Paused"
        uuid created_by FK "Admin ID"
    }
    DEALS {
        uuid id PK
        uuid initiator_id FK "Agent/Admin/Merchant"
        uuid merchant_id FK "Nullable"
        enum source "Inbound, Agent_Outbound, Admin_Outbound"
        enum status "Draft, Negotiation, Agreed, Declined, Revoked, Terminated, Archived"
        uuid assignee_id FK "Nullable"
        string merchant_name_brand
        string merchant_country
        string merchant_currency
        uuid chosen_provider_id FK "Set when Agreed"
        timestamp expires_at
        timestamp created_at
    }
    DEAL_EVENTS {
        uuid id PK
        uuid deal_id FK
        uuid actor_id FK
        enum event_type "Status_Change, Margin_Update, Special_Terms_Request, Note_Added"
        jsonb payload
        text comment
        string field_reference "[Post-MVP]"
        timestamp created_at
    }
    DEAL_ITEMS {
        uuid id PK
        uuid deal_id FK
        uuid offer_id FK
        uuid provider_id FK
        decimal agent_margin
        decimal raw_rate_snapshot
        decimal platform_margin_snapshot
        decimal final_fee_snapshot
    }

2. Описание таблиц

2.1 users (Пользователи)

Единая таблица для SuperAdmin, Admin, агентов и мерчантов. Провайдер в эту таблицу не входит.

  • id (UUID): уникальный идентификатор.
  • role (Enum): SuperAdmin, Admin, Agent, Merchant. У записи в Pending роль ещё не назначена.
  • email (String): уникальный ключ (UNIQUE).
  • company_name (String): официальное название компании при регистрации.
  • status (Enum): Pending, Active, Blocked, Inactive, Rejected. Новые регистрации попадают в Pending до обработки SuperAdmin.
  • invited_by_agent_id (UUID, FK, Nullable): ID агента, который привёл мерчанта. В MVP = NULL (приглашает SuperAdmin). [Post-MVP].
  • client_alias (String, Nullable): псевдоним мерчанта. [Post-MVP].

2.2 providers (Провайдеры)

Системная таблица платежных систем. Скрыта от агентов и мерчантов.

  • id (UUID): уникальный идентификатор.
  • real_name (String): настоящее имя платежной системы.
  • status (Enum): Active или Paused. Пауза каскадно паузит связанные офферы.

2.3 offers (Офферы каталога)

Публичные тарифы, которые Admin / SuperAdmin создают на базе провайдеров.

  • id (UUID): уникальный идентификатор.
  • provider_id (UUID, FK): ссылка на провайдера.
  • alias (String): публичный псевдоним для каталога (например Card-EU-01).
  • raw_rate (Decimal): Raw Provider Rate.
  • platform_margin (Decimal): Platform Margin.
  • attributes (JSONB): характеристики оффера (см. схему ниже).
  • status (Enum): Active или Paused.

2.4 deals (Сделки / тикеты)

Главная бизнес-сущность. Ticket-based: итерации внутри одного тикета.

  • id (UUID): уникальный идентификатор (используется для Secure-ссылки).
  • initiator_id (UUID, FK): кто создал сделку.
  • merchant_id (UUID, FK, Nullable): мерчант. Пусто, пока мерчант ещё не зарегистрирован.
  • source (Enum): Inbound, Agent_Outbound, Admin_Outbound.
  • status (Enum): Draft, Negotiation, Agreed, Declined, Revoked, Terminated, Archived. Истечение срока Secure-ссылки → Revoked.
  • assignee_id (UUID, FK, Nullable): на ком сейчас мяч (Assignee). Agent, Admin или Merchant.
  • merchant_name_brand (String): название бренда, если merchant_id ещё неизвестен.
  • merchant_country / merchant_currency: гео-данные мерчанта для аналитики.
  • chosen_provider_id (UUID, FK): заполняется только при переходе в Agreed.
  • expires_at (Timestamp): срок жизни текущей Secure-ссылки (1 неделя с момента отправки).

2.5 deal_events (Журнал событий / Audit Trail)

Лента изменений тикета и текстовых обоснований.

  • id (UUID): уникальный идентификатор события.
  • deal_id (UUID, FK): ссылка на сделку.
  • actor_id (UUID, FK): пользователь, совершивший действие.
  • event_type (Enum): Status_Change, Margin_Update, Special_Terms_Request, Note_Added.
  • payload (JSONB): детали изменения (например старая маржа → новая).
  • comment (Text, Nullable): текстовое обоснование. В MVP — к кнопке Request Special Terms.
  • field_reference (String, Nullable): [Post-MVP] указатель на поле для точечного торга.

2.6 deal_items (Элементы сделки)

Связь сделки с офферами и снимки цены.

  • id (UUID): уникальный идентификатор элемента.
  • deal_id (UUID, FK): ссылка на сделку (Proposal).
  • offer_id (UUID, FK): ссылка на оффер.
  • agent_margin (Decimal): Agent Margin на момент сборки.
  • raw_rate_snapshot / platform_margin_snapshot / final_fee_snapshot (Decimal): замороженные Raw Provider Rate, Platform Margin и Total Fee.

3. Структура атрибутов оффера (JSONB Schema)

Поле attributes в offers хранит конфигурацию условий. Типизация нужна для динамической формы оффера и фильтров каталога.

{
  "general": {
    "regions": ["Africa", "Europe"],
    "countries": ["DE", "NO", "FI", "KE"],
    "authorization_currencies": ["EUR", "KES", "NGN", "JPY"],
    "traffic_type": ["Trusted", "Untrusted", "FTD/STD", "with KYC"],
    "integration_types": ["Hosted", "API", "H2H"]
  },
  "payin": {
    "methods": ["Visa/MC", "M-Pesa", "OpenBanking"],
    "commission": "3.2% min 0.20 EUR",
    "limits": {
      "min": "1 KES",
      "max": "122500 KES"
    },
    "kyc_conditions": "499 EUR (w/o KYC), 15 000 EUR (with KYC)"
  },
  "payout": {
    "methods": ["Airtel money", "OpenBanking"],
    "commission": "2% + 0.30 EUR",
    "limits": {
      "min": "10 KES",
      "max": "250000 KES"
    },
    "kyc_conditions": "Особые условия, если есть"
  },
  "settlement": {
    "currencies": ["USDT", "USDC"],
    "commission": "1.5%",
    "terms": "T+1, twice a week",
    "min_amount": "5000 USDC",
    "exchange_rate": "Provider exchange rate",
    "destination": "Kraken или внешний кошелек"
  },
  "fees_and_holds": {
    "rolling_reserve": "10% / 180 дней",
    "refund_fee": "1 EUR",
    "chargeback_fee": "80 EUR"
  },
  "additional": {
    "special_requirements": "URL, KYB обязательны",
    "user_flow": "видео-флоу, редирект",
    "notes": "Любая другая важная информация"
  }
}

Провайдер (providers) может хранить приватные атрибуты в похожем JSON (SLA, имена менеджеров, доступы к API). Они не наследуются в оффер и скрыты ото всех, кроме Admin / SuperAdmin.

4. Связанные документы