Update pricing UX, billing flows, and API rules
This commit is contained in:
195
app/dewemoji-billing-integration-plan.md
Normal file
195
app/dewemoji-billing-integration-plan.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# Dewemoji Billing Integration Plan (QRIS + PayPal)
|
||||
|
||||
This document outlines a proper, production-grade billing flow for Dewemoji using **QRIS (Pakasir)** and **PayPal Subscriptions**, including webhooks, retries, and license activation.
|
||||
|
||||
---
|
||||
|
||||
## 1) Goals
|
||||
|
||||
- Replace primitive payment links with real provider integrations.
|
||||
- Support **subscription** billing (monthly/annual) and **one-time lifetime**.
|
||||
- Activate or revoke licenses based on webhook-confirmed payments.
|
||||
- Log all webhook events and payment activity for audit.
|
||||
|
||||
---
|
||||
|
||||
## 2) Data Model
|
||||
|
||||
### `orders` (new)
|
||||
|
||||
Acts as the primary record of what the user is buying. Payments link back to orders.
|
||||
|
||||
- `id`
|
||||
- `user_id`
|
||||
- `plan_code`
|
||||
- `type` (`one_time`, `subscription`)
|
||||
- `currency` (`IDR`, `USD`)
|
||||
- `amount`
|
||||
- `status` (`pending`, `paid`, `failed`, `expired`, `refunded`)
|
||||
- `provider` (`qris`, `paypal`)
|
||||
- `provider_ref`
|
||||
- `created_at`, `updated_at`
|
||||
|
||||
### `payments` (new)
|
||||
|
||||
- `id`
|
||||
- `user_id`
|
||||
- `order_id`
|
||||
- `provider` (`qris`, `paypal`)
|
||||
- `type` (`one_time`, `subscription`)
|
||||
- `plan_code` (`personal_monthly`, `personal_annual`, `personal_lifetime`)
|
||||
- `currency` (`IDR`, `USD`)
|
||||
- `amount`
|
||||
- `status` (`pending`, `paid`, `failed`, `expired`, `refunded`)
|
||||
- `provider_ref` (invoice_id / order_id / subscription_id)
|
||||
- `raw_payload` (json)
|
||||
- `created_at`, `updated_at`
|
||||
|
||||
### `subscriptions` (existing)
|
||||
Extend with:
|
||||
- `provider`
|
||||
- `provider_ref`
|
||||
- `status` (`active`, `pending`, `canceled`, `expired`)
|
||||
- `started_at`, `expires_at`, `canceled_at`
|
||||
- `next_renewal_at` (optional)
|
||||
|
||||
### `webhook_events` (existing)
|
||||
Continue to log inbound payloads and processing status:
|
||||
- `provider`, `event_type`, `status`, `payload`, `received_at`, `processed_at`, `error_message`
|
||||
|
||||
---
|
||||
|
||||
## 3) Payment Flow (User Journey)
|
||||
|
||||
### Pricing Page (Frontend)
|
||||
|
||||
Each plan shows:
|
||||
- **Primary currency** (based on geo + user toggle)
|
||||
- **Two payment buttons** (real provider flow):
|
||||
- **QRIS (IDR)** → subscription or one-time
|
||||
- **PayPal (USD)** → subscription or one-time
|
||||
|
||||
### Backend Endpoints
|
||||
|
||||
#### QRIS (Pakasir)
|
||||
- `POST /billing/qris/create`
|
||||
- Creates invoice via Pakasir API
|
||||
- Stores `payments` with `pending`
|
||||
- Returns QR payment URL or QR code data
|
||||
- `GET /billing/qris/return` (optional)
|
||||
- Shows “pending / processing” state
|
||||
|
||||
#### PayPal Subscriptions
|
||||
- `POST /billing/paypal/create`
|
||||
- Creates PayPal subscription
|
||||
- Stores `payments` with `pending`
|
||||
- Returns approval URL
|
||||
- `GET /billing/paypal/return`
|
||||
- Shows “pending / processing” state
|
||||
|
||||
---
|
||||
|
||||
## 4) Webhook Processing (Critical)
|
||||
|
||||
Webhook endpoint:
|
||||
```
|
||||
POST /webhooks/{provider}
|
||||
```
|
||||
|
||||
Store inbound payloads in `webhook_events`, then process async (queue).
|
||||
|
||||
### PayPal Events
|
||||
- `BILLING.SUBSCRIPTION.ACTIVATED` → mark subscription active, set `users.tier = personal`
|
||||
- `BILLING.SUBSCRIPTION.CANCELLED` → mark subscription canceled
|
||||
- `PAYMENT.SALE.COMPLETED` → mark payment paid
|
||||
- `PAYMENT.SALE.DENIED` → mark payment failed
|
||||
|
||||
### Pakasir / QRIS Events
|
||||
- `payment.paid` → mark payment paid, grant access
|
||||
- `payment.expired` → mark payment failed/expired
|
||||
|
||||
---
|
||||
|
||||
## 5) License Activation Rules
|
||||
|
||||
When a payment or subscription is confirmed:
|
||||
- Create or update a `subscriptions` record
|
||||
- Set `users.tier = personal`
|
||||
- Store provider refs (`provider_ref`)
|
||||
- Log admin audit record
|
||||
|
||||
When revoked/expired:
|
||||
- Update `subscriptions.status`
|
||||
- Downgrade user if no active subscription remains
|
||||
|
||||
### Renewal Logic (QRIS manual renew)
|
||||
|
||||
- **If still active:** extend from current `expires_at`
|
||||
- `expires_at = expires_at + duration`
|
||||
- **If expired:** start from now
|
||||
- `expires_at = now + duration`
|
||||
|
||||
---
|
||||
|
||||
## 6) Admin Dashboard Enhancements
|
||||
|
||||
Add or extend:
|
||||
- **Payments list** (new screen)
|
||||
- filter by provider/status/currency
|
||||
- show raw provider ref
|
||||
- **Subscriptions list** (already exists)
|
||||
- show provider + status
|
||||
- **Webhook events** (already exists)
|
||||
- replay capability
|
||||
|
||||
---
|
||||
|
||||
## 7) Security & Reliability
|
||||
|
||||
- Validate webhook signatures (PayPal + Pakasir)
|
||||
- Reject duplicate events (idempotency)
|
||||
- Use queues for webhook processing
|
||||
- Log all webhook failures
|
||||
|
||||
---
|
||||
|
||||
## 8) Required Inputs (From Owner)
|
||||
|
||||
Before implementation:
|
||||
|
||||
1. **Pakasir API docs** (create invoice, webhook payload format)
|
||||
2. **PayPal API credentials** (client_id, secret, webhook signing key)
|
||||
3. Confirm **plans & pricing**:
|
||||
- Monthly
|
||||
- Annual
|
||||
- Lifetime
|
||||
|
||||
---
|
||||
|
||||
## 9) Implementation Phases
|
||||
|
||||
**Phase 1 — Schema + Core Models**
|
||||
- Add `orders` table
|
||||
- Add `payments` table (link to orders)
|
||||
- Extend `subscriptions`
|
||||
- Update webhook model if needed
|
||||
|
||||
**Phase 2 — Provider APIs**
|
||||
- Pakasir invoice create
|
||||
- PayPal subscription create
|
||||
|
||||
**Phase 3 — Webhooks**
|
||||
- Save raw events
|
||||
- Process via queue + idempotency
|
||||
|
||||
**Phase 4 — UI**
|
||||
- Pricing page buttons → real flows
|
||||
- Admin payment + subscription tools
|
||||
|
||||
---
|
||||
|
||||
## 10) Notes
|
||||
|
||||
- This plan assumes **proper subscription lifecycle** with webhooks.
|
||||
- PayPal.me / static links are **not sufficient** for subscriptions.
|
||||
- All access control must be tied to **confirmed payment status**.
|
||||
Reference in New Issue
Block a user