Data Model: UnivaPay Card Payment Integration (MVP)
Data Model: UnivaPay Card Payment Integration (MVP)
Draft for planning — final schema is decided in /speckit-plan. Based on the old
docs/univaPayment/ schema, adjusted for the MVP scope (manual registration, no auto-onboarding).
1. user_payment_univapays (new table — one row per supplier)
Stores the supplier’s UnivaPay connection. Mirrors the role of
user_payment_settings.stripe_connect_id in the Stripe flow.
| Column | Type | Notes |
|---|---|---|
id |
bigint PK | |
user_id |
FK users | UNIQUE — one connection per supplier |
store_id |
string(64) | UnivaPay store UUID; candidate for auto-retrieval from the token |
api_key |
string(512) | The app token (JWT) — store-type token |
secret_key |
string(512) | Encrypted at rest; never returned to the frontend; never re-displayed |
webhook_auth_token |
string(64) nullable | auth_token Yoyacoo generated/displayed for the supplier’s webhook; used for inbound webhook verification (per-store, unlike Stripe’s global env secret) |
charges_enabled |
boolean | Whether UnivaPay reports the store ready for charges |
status |
enum | not_connected / connected / unavailable (spec FR-003) |
mode |
enum | test / live — which token was registered (FR-015 separation) |
timestamps |
2. orders (modify)
| Column | Type | Notes |
|---|---|---|
univapay_charge_id |
string(64) nullable | Charge UUID returned when the charge is created; used to look up applications from refund_finished / cancel_finished webhooks (charge_id) and for refund/cancel API calls |
univapay_status |
string nullable | Last known charge status (successful / failed / canceled …) — optional; application status remains the source of truth |
3. Service payment methods (modify ServicePaymentMethod / related settings)
| Concept | Notes |
|---|---|
univapay payment type |
Allow selecting “Card Payment (UnivaPay)” per service (spec FR-005/FR-006) |
univapay_installment_enabled |
boolean — installment ON/OFF only (spec FR-014); count selection happens in the UnivaPay inline form |
4. Webhook idempotency record (new, small)
| Column | Type | Notes |
|---|---|---|
id |
bigint PK | |
webhook_event_id |
string(64) UNIQUE | Top-level webhook event id — the idempotency key (replays skip) |
payload_hash / raw payload |
Audit/logging | |
processed_at |
datetime |
Alternative: reuse the existing failed/log tables per codebase conventions — decided in planning.
Relationships
User 1──1 UserPaymentUnivapay (per-supplier credentials + status)
Order N──1 User (application paid via Order.univapay_charge_id)
Order 1──1 WebhookEventLog (optional; webhook replay guard, keyed by webhook_event_id)
Service N──M PaymentMethod (per-service enablement incl. univapay + installment flag)