215 lines
4.8 KiB
Markdown
215 lines
4.8 KiB
Markdown
# Billing + Credits Architecture v1
|
|
|
|
## 1. System boundary
|
|
|
|
Separate billing orchestration from plugin runtime.
|
|
|
|
1. `Payment System` (e.g. Paymenter):
|
|
- plans, checkout, invoices, payments
|
|
2. `Management Cloud / Credits Service`:
|
|
- authoritative credit ledger
|
|
- entitlement state
|
|
- grant workflows
|
|
- treasury + funding automation
|
|
3. `NuQloud plugin + broker`:
|
|
- checks credits/entitlements before write operations
|
|
- records consumption/refunds via management APIs
|
|
|
|
Nextcloud app should not integrate directly with payment webhooks.
|
|
|
|
## 2. Data model (minimum)
|
|
|
|
## 2.1 Ledger entries
|
|
|
|
`ledger_entries`
|
|
|
|
1. `id`
|
|
2. `instance_id`
|
|
3. `type` (`grant|purchase|consume|refund|adjustment`)
|
|
4. `credits_delta` (signed integer)
|
|
5. `qort_amount` (nullable decimal, reference only)
|
|
6. `ref` (idempotency key)
|
|
7. `metadata` (JSON)
|
|
8. `created_at`
|
|
|
|
Constraint:
|
|
|
|
1. unique index on `(instance_id, type, ref)`
|
|
|
|
## 2.2 Balances
|
|
|
|
`instance_balances`
|
|
|
|
1. `instance_id` (PK)
|
|
2. `credits_balance`
|
|
3. `updated_at`
|
|
|
|
## 2.3 Entitlements
|
|
|
|
`instance_entitlements`
|
|
|
|
1. `instance_id` (PK)
|
|
2. `plan`
|
|
3. `follower_count`
|
|
4. `capacity_gb`
|
|
5. `status` (`active|past_due|suspended|cancelled`)
|
|
6. `period_end`
|
|
7. `updated_at`
|
|
|
|
## 2.4 Grants
|
|
|
|
`intro_grants`
|
|
|
|
1. `instance_id` (unique)
|
|
2. `status` (`pending|approved|rejected|completed`)
|
|
3. `requested_at`
|
|
4. `approved_by`
|
|
5. `approved_at`
|
|
6. `grant_credits`
|
|
7. `ref` (request id / tx id)
|
|
|
|
## 3. API contract (minimum)
|
|
|
|
## 3.1 Billing webhook ingest
|
|
|
|
`POST /billing/webhook/paymenter`
|
|
|
|
1. Verify signature/HMAC.
|
|
2. Extract `instance_id` from trusted metadata.
|
|
3. Write idempotent purchase ledger entry.
|
|
4. Update entitlement state.
|
|
5. Trigger async funding/reconciliation job.
|
|
|
|
## 3.2 Balance + entitlement read
|
|
|
|
1. `GET /instances/{id}/billing/summary`
|
|
2. Returns:
|
|
- balance
|
|
- plan
|
|
- capacity
|
|
- follower targets
|
|
- status
|
|
|
|
## 3.3 Consumption
|
|
|
|
`POST /instances/{id}/credits/consume`
|
|
|
|
1. Input:
|
|
- `cost_credits`
|
|
- `ref` (publish operation id)
|
|
- `metadata`
|
|
2. Behavior:
|
|
- atomic check and decrement
|
|
- idempotent by `ref`
|
|
|
|
## 3.4 Refund
|
|
|
|
`POST /instances/{id}/credits/refund`
|
|
|
|
1. Input:
|
|
- `credits`
|
|
- `ref` (failed operation id)
|
|
2. Behavior:
|
|
- idempotent compensation entry
|
|
|
|
## 3.5 Intro grant request/approval
|
|
|
|
1. `POST /instances/{id}/grants/intro/request`
|
|
2. `POST /instances/{id}/grants/intro/approve`
|
|
3. `POST /instances/{id}/grants/intro/reject`
|
|
|
|
Guardrails:
|
|
|
|
1. One grant ever per instance.
|
|
2. Approval role required.
|
|
3. Fixed max grant size.
|
|
|
|
## 3.6 Product catalog discovery
|
|
|
|
`POST /api/sovereign/v1/billing/catalog`
|
|
|
|
1. Accepts instance-scoped request plus optional `categoryId`.
|
|
2. Returns canonical catalog contract `sc.billing.catalog.v1`.
|
|
3. Includes normalized `subscriptions[]` and `addons[]` for UI rendering.
|
|
4. Enables adding/changing purchasable products without plugin updates.
|
|
|
|
## 4. Publish-time flow
|
|
|
|
1. Plugin/broker receives write request.
|
|
2. Determine cost in credits.
|
|
3. Call consume endpoint with operation ref.
|
|
4. Attempt write/publish.
|
|
5. On success: done.
|
|
6. On failure: call refund endpoint.
|
|
|
|
Requirements:
|
|
|
|
1. operation ref must be globally unique.
|
|
2. no duplicate charges on retries.
|
|
|
|
## 5. Funding and reconciliation
|
|
|
|
Optional treasury automation keeps publishing identity funded against outstanding credit liabilities.
|
|
|
|
Reconciliation job:
|
|
|
|
1. compute required funding from credit liability + safety buffer.
|
|
2. compare to instance publishing-wallet balance.
|
|
3. queue transfer if below threshold.
|
|
4. store tx hash and reconciliation ref.
|
|
|
|
## 6. Idempotency and concurrency
|
|
|
|
Non-negotiable:
|
|
|
|
1. webhook ingest idempotent.
|
|
2. consume/refund idempotent.
|
|
3. atomic balance updates (transaction/row lock).
|
|
4. no negative balance race conditions.
|
|
|
|
## 7. Failure modes + handling
|
|
|
|
1. Duplicate webhook:
|
|
- ignored by unique `(instance_id,type,ref)`
|
|
2. Payment metadata missing instance_id:
|
|
- reject and quarantine event
|
|
3. Publish fails after consume:
|
|
- refund by same operation ref
|
|
4. Entitlement expired:
|
|
- block guaranteed-replication features; keep clear error state
|
|
|
|
## 8. Operational controls
|
|
|
|
1. Admin override endpoint for adjustments with audit trail.
|
|
2. Export ledger CSV/JSON for audit.
|
|
3. Alerting for:
|
|
- low balance
|
|
- funding failures
|
|
- degraded replication below plan target
|
|
|
|
## 9. Security controls
|
|
|
|
1. Verify payment webhooks cryptographically.
|
|
2. Restrict webhook endpoint exposure.
|
|
3. Separate service credentials for:
|
|
- payment ingest
|
|
- ledger mutation
|
|
- read-only dashboard queries
|
|
4. Redact sensitive fields in logs.
|
|
|
|
## 10. Implementation phases
|
|
|
|
1. Phase 1:
|
|
- ledger + balances + entitlements schema
|
|
- summary/read API
|
|
2. Phase 2:
|
|
- consume/refund idempotent endpoints
|
|
- broker integration
|
|
3. Phase 3:
|
|
- payment webhook ingest + entitlement update
|
|
4. Phase 4:
|
|
- intro grant workflow
|
|
- reconciliation/funding jobs
|
|
5. Phase 5:
|
|
- dashboards, exports, alerts
|