# Data Model

This document defines the initial data model for Open Solar Payments. Field names are implementation guidance rather than a forced database schema.

## Core Entities

- PaymentRequest
- Invoice
- PaymentEvent
- Receipt
- Settlement
- ProviderAccount

## PaymentRequest

Represents the merchant-level request for payment. It may be connected to a quote, cart, order, installation deposit, or workorder balance.

```json
{
  "id": "payreq_123",
  "sourceType": "solar_quote",
  "sourceId": "quote_456",
  "customerRef": "customer_789",
  "merchantRef": "merchant_suntecorb",
  "status": "pending",
  "amountSats": 185000,
  "displayAmount": {
    "amount": 250000,
    "currency": "NGN"
  },
  "description": "Solar quote deposit for 5kVA inverter system",
  "expiresAt": "2026-07-01T12:00:00Z",
  "metadata": {
    "market": "Nigeria",
    "orderType": "deposit"
  },
  "createdAt": "2026-07-01T11:30:00Z",
  "updatedAt": "2026-07-01T11:30:00Z"
}
```

Recommended `sourceType` values:

```text
solar_quote
product_cart
component_order
installation_deposit
workorder_balance
service_fee
```

## Invoice

Represents the Bitcoin/Lightning invoice created through a backend provider.

```json
{
  "id": "inv_123",
  "paymentRequestId": "payreq_123",
  "provider": "btcpay",
  "providerInvoiceId": "btcpay_invoice_456",
  "status": "pending",
  "amountSats": 185000,
  "bolt11": "lnbc1850u1p...",
  "checkoutUrl": "https://pay.example.com/i/abc123",
  "expiresAt": "2026-07-01T12:00:00Z",
  "paidAt": null,
  "createdAt": "2026-07-01T11:31:00Z",
  "updatedAt": "2026-07-01T11:31:00Z"
}
```

## PaymentEvent

Stores normalized provider events for auditability and idempotency.

```json
{
  "id": "pevt_123",
  "provider": "btcpay",
  "providerEventId": "evt_123",
  "invoiceId": "inv_123",
  "paymentRequestId": "payreq_123",
  "eventType": "invoice_paid",
  "status": "processed",
  "amountSats": 185000,
  "receivedAt": "2026-07-01T11:42:00Z",
  "processedAt": "2026-07-01T11:42:02Z",
  "rawPayloadHash": "sha256:..."
}
```

The raw provider payload may be stored depending on privacy, security, and compliance requirements. If stored, it should be protected and not exposed in public examples.

## Receipt

Represents customer-visible proof of payment.

```json
{
  "id": "receipt_123",
  "receiptNumber": "OSP-2026-000001",
  "paymentRequestId": "payreq_123",
  "invoiceId": "inv_123",
  "sourceType": "solar_quote",
  "sourceId": "quote_456",
  "customerRef": "customer_789",
  "merchantRef": "merchant_suntecorb",
  "amountSats": 185000,
  "displayAmount": {
    "amount": 250000,
    "currency": "NGN"
  },
  "paidAt": "2026-07-01T11:42:00Z",
  "issuedAt": "2026-07-01T11:42:03Z"
}
```

## Settlement

Represents installer or internal reconciliation state connected to a workorder.

```json
{
  "id": "settlement_123",
  "workorderId": "workorder_456",
  "installerRef": "installer_789",
  "paymentRequestId": "payreq_123",
  "receiptId": "receipt_123",
  "settlementType": "installation_deposit",
  "status": "confirmed",
  "amountSats": 185000,
  "displayAmount": {
    "amount": 250000,
    "currency": "NGN"
  },
  "confirmedAt": "2026-07-01T11:42:03Z",
  "reconciledAt": null,
  "paidOutAt": null,
  "createdAt": "2026-07-01T11:42:03Z",
  "updatedAt": "2026-07-01T11:42:03Z"
}
```

Recommended `settlementType` values:

```text
installation_deposit
workorder_balance
installer_fee
merchant_fee
refund
```

## ProviderAccount

Represents configured backend details without exposing secrets in normal API responses.

```json
{
  "id": "provider_btcpay_main",
  "provider": "btcpay",
  "merchantRef": "merchant_suntecorb",
  "status": "active",
  "capabilities": [
    "lightning_invoice",
    "checkout_url",
    "webhook_events"
  ],
  "createdAt": "2026-07-01T10:00:00Z"
}
```

Secrets should live outside ordinary table fields where possible, or in encrypted storage:

```text
BTCPAY_API_KEY
BTCPAY_STORE_ID
BTCPAY_WEBHOOK_SECRET
BTCPAY_BASE_URL
```

## Suggested Indexes

```text
payment_requests.sourceType + payment_requests.sourceId
payment_requests.customerRef
payment_requests.status
invoices.provider + invoices.providerInvoiceId
invoices.paymentRequestId
payment_events.provider + payment_events.providerEventId
receipts.paymentRequestId
receipts.receiptNumber
settlements.workorderId
settlements.installerRef
settlements.status
```

## Audit Trail

Implementations should keep a compact event log for payment and settlement state changes:

```json
{
  "id": "audit_123",
  "entityType": "settlement",
  "entityId": "settlement_123",
  "fromStatus": "confirmed",
  "toStatus": "reconciled",
  "actorType": "admin",
  "actorRef": "admin_456",
  "reason": "Installer confirmed workorder completion",
  "createdAt": "2026-07-02T09:00:00Z"
}
```

## Data Portability

The module should make it easy to export:

- Payment requests
- Invoices
- Receipts
- Settlement records
- Payment event history

This supports the public-good goal: merchants should not be locked into one private marketplace to use Bitcoin/Lightning payment records.
