Files
eryao/.trellis/tasks/archive/05-11-creem-payment-integration/prd.md
T

141 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PRD: CREEM Web Payment Integration
## Background
iOS App 路线已放弃,需改用 CREEM (Merchant of Record) 进行 Web 端支付。现有 Apple IAP 代码保留但不再活跃使用。
## Goals
1. Web 端用户可通过 CREEM 托管支付页购买积分
2. 商品价格从 CREEM API 动态获取,不在本地硬编码
3. 支付成功后通过 webhook 自动发放积分
4. 保留现有 Apple IAP 架构,不破坏
## CREEM Product Mapping
| 内部 product_code | CREEM Product ID | 积分 |
|---|---|---|
| new_user_pack | prod_2x9LzVlR3ot1HLgbIZALPd | 60 |
| starter_pack | prod_697ay0pXFXrBYEVC7HS0MR | 100 |
| popular_pack | prod_5ivxlPnZWN6dIhnOxctThy | 210 |
| premium_pack | prod_2L13k70jlpPYkdHhexHP2s | 415 |
### Pricing Notes
- CREEM 最低支持 $1.00,因此新人专享包价格从原 $0.99 调整为 $1.00
- 价格由 CREEM Dashboard 管理,后端通过 API 动态获取,不硬编码在 mapping.yaml 中
- mapping.yaml 只存储: creem_product_id, credits, type, sort_order, enabled
## Architecture
### Payment Flow
```
Frontend Backend CREEM
| | |
|-- GET /packages ---->| |
| |-- GET /products ---->|
| |<-- products list ----|
|<-- packages+prices --| |
| | |
|-- POST /checkout --->| |
| |-- POST /checkouts -->|
| |<-- checkout_url -----|
|<-- checkout_url -----| |
| | |
|-- redirect to CREEM checkout page --------->|
| | |
| |<-- webhook ----------|
| | (checkout.completed)
| | verify signature
| | grant credits |
| | |
|-- success_url -------| |
```
### API Endpoints
| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | `/api/v1/payments/creem/checkouts` | User | Create checkout session, return checkout_url |
| POST | `/api/v1/payments/creem/webhook` | None | CREEM callback (verify signature) |
### Existing Endpoint Changes
| Method | Endpoint | Change |
|--------|----------|--------|
| GET | `/api/v1/points/packages` | Add `priceCents` and `currency` fields from CREEM API |
## Implementation Details
### Phase 1: Backend Infrastructure
1. **settings.py** - Add `CreemSettings` (api_key, webhook_secret, base_url, success_url)
2. **creem_client.py** - HTTP client for CREEM API (get_products, create_checkout)
3. **models/creem_transaction.py** - New DB table for CREEM transactions
4. **alembic migration** - Create `creem_transactions` table
5. **repository.py** - Add CREEM transaction CRUD methods
### Phase 2: Backend Business Logic
6. **creem_service.py** - Checkout creation + webhook handling
7. **service.py** - Update `ProductMapping` to include `creem_product_id`
8. **schemas.py** - Add `CreateCheckoutRequest/Response`, update `PackageInfo` with price fields
9. **dependencies.py** - Add `get_creem_service` DI
10. **router.py** - Add 2 new CREEM endpoints
11. **points/service.py** - `get_available_packages` merges CREEM product prices
### Phase 3: Frontend
12. **api.ts** - Add `createCheckout()` function and types
13. **StorePage.tsx** - Use dynamic price from API, add buy button that redirects to checkout_url
## DB Schema: creem_transactions
| Column | Type | Description |
|--------|------|-------------|
| id | UUID PK | |
| user_id | UUID FK | |
| product_code | String(32) | Internal product code |
| creem_product_id | String(128) | CREEM product ID |
| checkout_id | String(128) UNIQUE | CREEM checkout session ID |
| order_id | String(128) nullable | CREEM order ID |
| customer_id | String(128) nullable | CREEM customer ID |
| status | enum(pending, completed, failed, refunded) | |
| credits | BigInt | Points to grant |
| amount_cents | BigInt | Payment amount in cents |
| currency | String(8) | Currency code |
| creem_payload | JSONB | Full CREEM webhook payload |
| ledger_event_id | String(128) nullable | Points ledger event ID |
| created_at, updated_at | Timestamp | |
## Environment Variables
```bash
ERYAO_CREEM_API_KEY= # CREEM API key
ERYAO_CREEM_WEBHOOK_SECRET= # Webhook signature verification secret (先占位,实现后配置)
ERYAO_CREEM_BASE_URL=https://test-api.creem.io # test or production
ERYAO_CREEM_SUCCESS_URL=https://yourdomain.com/store?payment=success # 支付成功跳转URL
```
## Frontend Behavior
1. 支付成功后跳转到 `ERYAO_CREEM_SUCCESS_URL`
2. 前端检测 URL 参数 `?payment=success`,显示成功提示并刷新积分
3. 价格从后端 API 动态获取,不再使用翻译文件中的硬编码价格
4. 翻译文件保留:套餐名称、描述、badge 文字(如"限购一次"、"推荐"
## Security
- Webhook must verify `creem-signature` HMAC-SHA256 header
- API key never exposed to frontend
- Checkout idempotency: prevent duplicate credit grants via checkout_id unique constraint
- Starter pack eligibility check shared with Apple IAP logic
## Out of Scope
- CREEM subscription management (one-time purchases only)
- CREEM license keys
- Removing Apple IAP code (preserved for potential future use)
- Customer portal integration