chore(task): archive 05-10-audit-and-optimize-web-performance
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
# 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
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
"name": "audit-and-optimize-web-performance",
|
||||
"title": "Audit and optimize web performance",
|
||||
"description": "",
|
||||
"status": "in_progress",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
@@ -11,7 +11,7 @@
|
||||
"creator": "zl-q",
|
||||
"assignee": "zl-q",
|
||||
"createdAt": "2026-05-10",
|
||||
"completedAt": null,
|
||||
"completedAt": "2026-05-11",
|
||||
"branch": null,
|
||||
"base_branch": "dev",
|
||||
"worktree_path": null,
|
||||
Reference in New Issue
Block a user