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",
|
"name": "audit-and-optimize-web-performance",
|
||||||
"title": "Audit and optimize web performance",
|
"title": "Audit and optimize web performance",
|
||||||
"description": "",
|
"description": "",
|
||||||
"status": "in_progress",
|
"status": "completed",
|
||||||
"dev_type": null,
|
"dev_type": null,
|
||||||
"scope": null,
|
"scope": null,
|
||||||
"package": null,
|
"package": null,
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"creator": "zl-q",
|
"creator": "zl-q",
|
||||||
"assignee": "zl-q",
|
"assignee": "zl-q",
|
||||||
"createdAt": "2026-05-10",
|
"createdAt": "2026-05-10",
|
||||||
"completedAt": null,
|
"completedAt": "2026-05-11",
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"base_branch": "dev",
|
"base_branch": "dev",
|
||||||
"worktree_path": null,
|
"worktree_path": null,
|
||||||
Reference in New Issue
Block a user