@cogito.ai/cli 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +1 -1
- package/dist/templates/web-nextjs/apps/docs/.source/server.ts +20 -11
- package/dist/templates/web-nextjs/apps/docs/content/docs/meta.json +1 -1
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/alipay.mdx +276 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/deployment.mdx +32 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/drizzle.mdx +18 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/getting-started.mdx +98 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/meta.json +13 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/stripe.mdx +18 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/supabase.mdx +130 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/troubleshooting.mdx +87 -0
- package/dist/templates/web-nextjs/apps/docs/content/docs/template/wechat-pay.mdx +318 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +1 -1
- package/dist/templates/web-nextjs/apps/web/src/app/docs/page.tsx +5 -0
- package/dist/templates/web-nextjs/pnpm-workspace.yaml +7 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -868,7 +868,7 @@ var package_default;
|
|
|
868
868
|
var init_package = __esm(() => {
|
|
869
869
|
package_default = {
|
|
870
870
|
name: "@cogito.ai/cli",
|
|
871
|
-
version: "0.4.
|
|
871
|
+
version: "0.4.5",
|
|
872
872
|
type: "module",
|
|
873
873
|
description: "AgentDock CLI – scaffold projects for humans and AI agents",
|
|
874
874
|
publishConfig: {
|
|
@@ -7,6 +7,6 @@ const create = browser<typeof Config, import("fumadocs-mdx/runtime/types").Inter
|
|
|
7
7
|
}
|
|
8
8
|
}>();
|
|
9
9
|
const browserCollections = {
|
|
10
|
-
docs: create.doc("docs", {"index.mdx": () => import("../content/docs/index.mdx?collection=docs"), "changelog/index.mdx": () => import("../content/docs/changelog/index.mdx?collection=docs"), "
|
|
10
|
+
docs: create.doc("docs", {"index.mdx": () => import("../content/docs/index.mdx?collection=docs"), "changelog/index.mdx": () => import("../content/docs/changelog/index.mdx?collection=docs"), "decisions/turbo-package-manager.mdx": () => import("../content/docs/decisions/turbo-package-manager.mdx?collection=docs"), "roadmap/index.mdx": () => import("../content/docs/roadmap/index.mdx?collection=docs"), "template/alipay.mdx": () => import("../content/docs/template/alipay.mdx?collection=docs"), "template/deployment.mdx": () => import("../content/docs/template/deployment.mdx?collection=docs"), "template/drizzle.mdx": () => import("../content/docs/template/drizzle.mdx?collection=docs"), "template/getting-started.mdx": () => import("../content/docs/template/getting-started.mdx?collection=docs"), "template/stripe.mdx": () => import("../content/docs/template/stripe.mdx?collection=docs"), "template/supabase.mdx": () => import("../content/docs/template/supabase.mdx?collection=docs"), "template/troubleshooting.mdx": () => import("../content/docs/template/troubleshooting.mdx?collection=docs"), "template/wechat-pay.mdx": () => import("../content/docs/template/wechat-pay.mdx?collection=docs"), "features/auth.mdx": () => import("../content/docs/features/auth.mdx?collection=docs"), "features/hello.mdx": () => import("../content/docs/features/hello.mdx?collection=docs"), }),
|
|
11
11
|
};
|
|
12
12
|
export default browserCollections;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
2
|
+
import * as __fd_glob_19 from "../content/docs/features/hello.mdx?collection=docs"
|
|
3
|
+
import * as __fd_glob_18 from "../content/docs/features/auth.mdx?collection=docs"
|
|
4
|
+
import * as __fd_glob_17 from "../content/docs/template/wechat-pay.mdx?collection=docs"
|
|
5
|
+
import * as __fd_glob_16 from "../content/docs/template/troubleshooting.mdx?collection=docs"
|
|
6
|
+
import * as __fd_glob_15 from "../content/docs/template/supabase.mdx?collection=docs"
|
|
7
|
+
import * as __fd_glob_14 from "../content/docs/template/stripe.mdx?collection=docs"
|
|
8
|
+
import * as __fd_glob_13 from "../content/docs/template/getting-started.mdx?collection=docs"
|
|
9
|
+
import * as __fd_glob_12 from "../content/docs/template/drizzle.mdx?collection=docs"
|
|
10
|
+
import * as __fd_glob_11 from "../content/docs/template/deployment.mdx?collection=docs"
|
|
11
|
+
import * as __fd_glob_10 from "../content/docs/template/alipay.mdx?collection=docs"
|
|
12
|
+
import * as __fd_glob_9 from "../content/docs/roadmap/index.mdx?collection=docs"
|
|
13
|
+
import * as __fd_glob_8 from "../content/docs/decisions/turbo-package-manager.mdx?collection=docs"
|
|
14
|
+
import * as __fd_glob_7 from "../content/docs/changelog/index.mdx?collection=docs"
|
|
15
|
+
import * as __fd_glob_6 from "../content/docs/index.mdx?collection=docs"
|
|
16
|
+
import { default as __fd_glob_5 } from "../content/docs/roadmap/meta.json?collection=docs"
|
|
17
|
+
import { default as __fd_glob_4 } from "../content/docs/template/meta.json?collection=docs"
|
|
18
|
+
import { default as __fd_glob_3 } from "../content/docs/changelog/meta.json?collection=docs"
|
|
19
|
+
import { default as __fd_glob_2 } from "../content/docs/features/meta.json?collection=docs"
|
|
20
|
+
import { default as __fd_glob_1 } from "../content/docs/decisions/meta.json?collection=docs"
|
|
12
21
|
import { default as __fd_glob_0 } from "../content/docs/meta.json?collection=docs"
|
|
13
22
|
import { server } from 'fumadocs-mdx/runtime/server';
|
|
14
23
|
import type * as Config from '../source.config';
|
|
@@ -18,4 +27,4 @@ const create = server<typeof Config, import("fumadocs-mdx/runtime/types").Intern
|
|
|
18
27
|
}
|
|
19
28
|
}>({"doc":{"passthroughs":["extractedReferences"]}});
|
|
20
29
|
|
|
21
|
-
export const docs = await create.docs("docs", "content/docs", {"meta.json": __fd_glob_0, "
|
|
30
|
+
export const docs = await create.docs("docs", "content/docs", {"meta.json": __fd_glob_0, "decisions/meta.json": __fd_glob_1, "features/meta.json": __fd_glob_2, "changelog/meta.json": __fd_glob_3, "template/meta.json": __fd_glob_4, "roadmap/meta.json": __fd_glob_5, }, {"index.mdx": __fd_glob_6, "changelog/index.mdx": __fd_glob_7, "decisions/turbo-package-manager.mdx": __fd_glob_8, "roadmap/index.mdx": __fd_glob_9, "template/alipay.mdx": __fd_glob_10, "template/deployment.mdx": __fd_glob_11, "template/drizzle.mdx": __fd_glob_12, "template/getting-started.mdx": __fd_glob_13, "template/stripe.mdx": __fd_glob_14, "template/supabase.mdx": __fd_glob_15, "template/troubleshooting.mdx": __fd_glob_16, "template/wechat-pay.mdx": __fd_glob_17, "features/auth.mdx": __fd_glob_18, "features/hello.mdx": __fd_glob_19, });
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 支付:支付宝
|
|
3
|
+
description: 支付宝支付集成指南,包括架构、配置、安全和使用方法。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 概述
|
|
7
|
+
|
|
8
|
+
本项目集成了 **支付宝** 支付方式,支持电脑网站支付(PC Web)场景。
|
|
9
|
+
|
|
10
|
+
## 技术架构
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
14
|
+
│ 用户浏览器 │
|
|
15
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
16
|
+
│ │ 选择商品 │ -> │ 创建订单 │ -> │ 跳转支付 │ │
|
|
17
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
18
|
+
└─────────────────────────────────────────────────────────────┘
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
22
|
+
│ Next.js 应用 (Server) │
|
|
23
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
24
|
+
│ │ /api/pay │ │ 签名/验签 │ │ 回调处理 │ │
|
|
25
|
+
│ │ /api/notify │ │ │ │ │ │
|
|
26
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
27
|
+
└─────────────────────────────────────────────────────────────┘
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
┌────────────────┐
|
|
31
|
+
│ 支付宝网关 │
|
|
32
|
+
│ (openapi.alipay.com) │
|
|
33
|
+
└────────────────┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 时序图
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
用户 前端页面 Next.js API 支付宝网关
|
|
40
|
+
│ │ │ │
|
|
41
|
+
│ 1.选择商品 │ │ │
|
|
42
|
+
│─────────────>│ │ │
|
|
43
|
+
│ │ 2.POST /create │ │
|
|
44
|
+
│ │─────────────────>│ │
|
|
45
|
+
│ │ │ 3.创建订单 │
|
|
46
|
+
│ │ │─────────────────>│
|
|
47
|
+
│ │ │ 4.返回支付链接 │
|
|
48
|
+
│ │ │<─────────────────│
|
|
49
|
+
│ 5.返回支付URL│ │ │
|
|
50
|
+
│<─────────────│ │ │
|
|
51
|
+
│ 6.跳转支付宝 │ │ │
|
|
52
|
+
│─────────────────────────────────────────────────>│
|
|
53
|
+
│ 7.完成支付 │ │ │
|
|
54
|
+
│<─────────────────────────────────────────────────│
|
|
55
|
+
│ │ │ 8.异步通知 │
|
|
56
|
+
│ │ │<─────────────────│
|
|
57
|
+
│ │ │ 9.验签+更新状态 │
|
|
58
|
+
│ │ │ │
|
|
59
|
+
│ 10.跳转成功页│ │ │
|
|
60
|
+
│<─────────────│ │ │
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 前置条件
|
|
64
|
+
|
|
65
|
+
### 支付宝开放平台账号
|
|
66
|
+
|
|
67
|
+
1. 注册 [支付宝开放平台](https://open.alipay.com/) 账号
|
|
68
|
+
2. 创建应用,获取 **APPID**
|
|
69
|
+
3. 生成并配置 **公钥和私钥**
|
|
70
|
+
|
|
71
|
+
### 必要配置
|
|
72
|
+
|
|
73
|
+
| 配置项 | 说明 | 获取位置 |
|
|
74
|
+
|--------|------|----------|
|
|
75
|
+
| `ALIPAY_APP_ID` | 应用 APPID | 支付宝开放平台 → 应用详情 |
|
|
76
|
+
| `ALIPAY_PRIVATE_KEY` | 应用私钥 | 密钥工具生成 |
|
|
77
|
+
| `ALIPAY_PUBLIC_KEY` | 应用公钥 | 密钥工具生成 |
|
|
78
|
+
| `ALIPAY_GATEWAY_URL` | 网关地址 | `https://openapi.alipay.com/gateway.do` |
|
|
79
|
+
|
|
80
|
+
## 开发环境配置
|
|
81
|
+
|
|
82
|
+
### 1. 配置环境变量
|
|
83
|
+
|
|
84
|
+
在 `.env.local` 中添加:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
ALIPAY_APP_ID=your-app-id
|
|
88
|
+
ALIPAY_PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----
|
|
89
|
+
ALIPAY_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
|
|
90
|
+
ALIPAY_GATEWAY_URL=https://openapi.alipay.com/gateway.do
|
|
91
|
+
ALIPAY_NOTIFY_URL=https://your-domain.com/api/payments/alipay/notify
|
|
92
|
+
ALIPAY_RETURN_URL=https://your-domain.com/payment/success
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> **注意**: 私钥包含换行符,使用 `\n` 转义。
|
|
96
|
+
|
|
97
|
+
### 2. 生成密钥对
|
|
98
|
+
|
|
99
|
+
使用支付宝提供的 [密钥工具](https://opendocs.alipay.com/common/02khje) 生成 RSA2 密钥对:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# 工具下载
|
|
103
|
+
https://ides.alipay.com/static/Alipaykeytool.dmg
|
|
104
|
+
|
|
105
|
+
# 选择 "RSA2" 和 "PKCS1" 格式
|
|
106
|
+
# 保存私钥和公钥
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. 配置支付宝公钥
|
|
110
|
+
|
|
111
|
+
在支付宝开放平台 → 应用详情 → 开发设置 → 接口加签方式 中:
|
|
112
|
+
|
|
113
|
+
1. 上传你的应用公钥
|
|
114
|
+
2. 获取支付宝公钥(用于回调验签)
|
|
115
|
+
|
|
116
|
+
## 生产环境配置
|
|
117
|
+
|
|
118
|
+
### 服务器要求
|
|
119
|
+
|
|
120
|
+
- 公网可访问的 HTTPS 地址
|
|
121
|
+
- 支持接收 POST 请求的回调接口
|
|
122
|
+
|
|
123
|
+
### 回调地址配置
|
|
124
|
+
|
|
125
|
+
在支付宝开放平台 → 应用详情 → 开发设置 中配置:
|
|
126
|
+
|
|
127
|
+
| 配置项 | 值 |
|
|
128
|
+
|--------|-----|
|
|
129
|
+
| 授权回调地址 | `https://your-domain.com/api/payments/alipay/return` |
|
|
130
|
+
| 异步通知地址 | `https://your-domain.com/api/payments/alipay/notify` |
|
|
131
|
+
|
|
132
|
+
## API 路由
|
|
133
|
+
|
|
134
|
+
### 创建支付订单
|
|
135
|
+
|
|
136
|
+
```http
|
|
137
|
+
POST /api/payments/alipay/create
|
|
138
|
+
Content-Type: application/json
|
|
139
|
+
|
|
140
|
+
{
|
|
141
|
+
"orderId": "ORDER_123456",
|
|
142
|
+
"amount": 99.99,
|
|
143
|
+
"subject": "商品名称",
|
|
144
|
+
"body": "商品描述"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**响应:**
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"success": true,
|
|
153
|
+
"data": {
|
|
154
|
+
"paymentUrl": "https://openapi.alipay.com/gateway.do?..."
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 支付回调通知
|
|
160
|
+
|
|
161
|
+
```http
|
|
162
|
+
POST /api/payments/alipay/notify
|
|
163
|
+
Content-Type: application/x-www-form-urlencoded
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
支付宝会发送以下参数:
|
|
167
|
+
|
|
168
|
+
| 参数 | 说明 |
|
|
169
|
+
|------|------|
|
|
170
|
+
| `out_trade_no` | 商户订单号 |
|
|
171
|
+
| `trade_no` | 支付宝交易号 |
|
|
172
|
+
| `trade_status` | 交易状态(TRADE_SUCCESS 表示成功) |
|
|
173
|
+
| `total_amount` | 订单金额 |
|
|
174
|
+
| `sign` | 签名 |
|
|
175
|
+
|
|
176
|
+
### 查询订单状态
|
|
177
|
+
|
|
178
|
+
```http
|
|
179
|
+
GET /api/payments/alipay/query?outTradeNo=ORDER_123456
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 安全注意事项
|
|
183
|
+
|
|
184
|
+
### 签名验证
|
|
185
|
+
|
|
186
|
+
**务必验证支付宝回调的签名**,防止伪造通知:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { verifyAlipaySignature } from '@/lib/alipay'
|
|
190
|
+
|
|
191
|
+
// 回调处理
|
|
192
|
+
export async function POST(request: Request) {
|
|
193
|
+
const formData = await request.formData()
|
|
194
|
+
const params = Object.fromEntries(formData)
|
|
195
|
+
|
|
196
|
+
// 1. 验证签名
|
|
197
|
+
const isValid = verifyAlipaySignature(params)
|
|
198
|
+
if (!isValid) {
|
|
199
|
+
return new Response('Invalid signature', { status: 400 })
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 2. 更新订单状态
|
|
203
|
+
// ...
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 安全最佳实践
|
|
208
|
+
|
|
209
|
+
| 风险 | 防护措施 |
|
|
210
|
+
|------|----------|
|
|
211
|
+
| 回调伪造 | 严格验证签名 |
|
|
212
|
+
| 金额篡改 | 比对数据库订单金额与回调金额 |
|
|
213
|
+
| 重复通知 | 使用幂等性处理(out_trade_no 去重) |
|
|
214
|
+
| 密钥泄露 | 私钥仅存储在服务器端,绝不暴露到客户端 |
|
|
215
|
+
| 中间人攻击 | 使用 HTTPS 传输 |
|
|
216
|
+
|
|
217
|
+
### 幂等性处理
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
// 使用数据库唯一约束防止重复处理
|
|
221
|
+
await db.payments.updateOne(
|
|
222
|
+
{ outTradeNo: params.out_trade_no, status: { $ne: 'PAID' } },
|
|
223
|
+
{ $set: { status: 'PAID', tradeNo: params.trade_no } }
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 开发环境调试
|
|
228
|
+
|
|
229
|
+
### 沙箱环境
|
|
230
|
+
|
|
231
|
+
支付宝提供沙箱环境用于开发测试:
|
|
232
|
+
|
|
233
|
+
1. 登录 [支付宝开放平台](https://open.alipay.com/)
|
|
234
|
+
2. 进入 **沙箱** 页面
|
|
235
|
+
3. 获取沙箱 APPID 和密钥
|
|
236
|
+
4. 修改环境变量为沙箱配置:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
ALIPAY_GATEWAY_URL=https://openapi.alipaydev.com/gateway.do
|
|
240
|
+
ALIPAY_APP_ID=your-sandbox-app-id
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 调试工具
|
|
244
|
+
|
|
245
|
+
- [支付宝沙箱环境](https://open.alipay.com/platform/appDaily.htm?tab=account)
|
|
246
|
+
- [在线签名校验工具](https://opendocs.alipay.com/common/02maie)
|
|
247
|
+
|
|
248
|
+
## 支付宝支付 FAQs
|
|
249
|
+
|
|
250
|
+
**Q: 支付回调收不到怎么办?**
|
|
251
|
+
|
|
252
|
+
A: 检查以下几点:
|
|
253
|
+
1. 服务器是否公网可访问
|
|
254
|
+
2. 回调地址是否正确配置在支付宝开放平台
|
|
255
|
+
3. 是否使用 HTTPS(支付宝要求)
|
|
256
|
+
4. 服务器防火墙是否放行
|
|
257
|
+
|
|
258
|
+
**Q: 签名验证失败?**
|
|
259
|
+
|
|
260
|
+
A: 常见原因:
|
|
261
|
+
1. 公私钥不匹配
|
|
262
|
+
2. 编码格式错误(应为 UTF-8)
|
|
263
|
+
3. 公钥/私钥格式错误(应为 PKCS1 格式)
|
|
264
|
+
|
|
265
|
+
**Q: 如何测试支付流程?**
|
|
266
|
+
|
|
267
|
+
A: 使用支付宝沙箱环境 + 沙箱账号登录 [沙箱版支付宝 APP](https://open.alipay.com/platform/appDaily.htm?tab=tool)。
|
|
268
|
+
|
|
269
|
+
## 相关资源
|
|
270
|
+
|
|
271
|
+
- [支付宝开放平台](https://open.alipay.com/)
|
|
272
|
+
- [支付宝电脑网站支付文档](https://opendocs.alipay.com/open/270/105899)
|
|
273
|
+
- [支付宝沙箱环境](https://open.alipay.com/platform/appDaily.htm)
|
|
274
|
+
- [密钥工具下载](https://opendocs.alipay.com/common/02khje)
|
|
275
|
+
- [签名校验工具](https://opendocs.alipay.com/common/02maie)
|
|
276
|
+
- [异步通知说明](https://opendocs.alipay.com/open/270/105902)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 项目部署
|
|
3
|
+
description: 如何将 web-nextjs 模板项目部署到生产环境。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 概述
|
|
7
|
+
|
|
8
|
+
本章将介绍如何将 web-nextjs 模板项目部署到生产环境。
|
|
9
|
+
|
|
10
|
+
> **占位章节**。后续我们会结合 CLI 部署到我们自己的部署平台 Dokploy。
|
|
11
|
+
|
|
12
|
+
## 部署选项
|
|
13
|
+
|
|
14
|
+
### 1. Vercel
|
|
15
|
+
|
|
16
|
+
Vercel 是 Next.js 的原生部署平台,支持一键部署。
|
|
17
|
+
|
|
18
|
+
### 2. Dokploy
|
|
19
|
+
|
|
20
|
+
我们将通过 AgentDock CLI 集成 Dokploy 平台,实现一键部署。
|
|
21
|
+
|
|
22
|
+
## 环境变量
|
|
23
|
+
|
|
24
|
+
生产环境需要配置以下环境变量:
|
|
25
|
+
|
|
26
|
+
- `NEXT_PUBLIC_SUPABASE_URL`
|
|
27
|
+
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
|
28
|
+
- `SUPABASE_SERVICE_ROLE_KEY`
|
|
29
|
+
|
|
30
|
+
## 即将推出
|
|
31
|
+
|
|
32
|
+
本章内容正在完善中,敬请期待。
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 开始使用
|
|
3
|
+
description: 如何初始化、开发和部署 web-nextjs 模板项目。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 环境要求
|
|
7
|
+
|
|
8
|
+
- **Node.js**: >= 18
|
|
9
|
+
- **pnpm**: >= 9
|
|
10
|
+
- **Git**
|
|
11
|
+
|
|
12
|
+
## 通过 CLI 初始化项目
|
|
13
|
+
|
|
14
|
+
使用 AgentDock CLI 创建新项目:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @cogito.ai/agentdock-cli create my-project
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
选择 **web-nextjs** 模板,CLI 会自动完成以下操作:
|
|
21
|
+
|
|
22
|
+
1. 克隆模板代码
|
|
23
|
+
2. 安装依赖 (`pnpm install`)
|
|
24
|
+
3. 复制环境变量配置文件 (`.env.local`)
|
|
25
|
+
|
|
26
|
+
## 本地开发
|
|
27
|
+
|
|
28
|
+
### 安装依赖
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 启动开发服务器
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm dev
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
这会同时启动:
|
|
41
|
+
- **Web 应用**: http://localhost:3000
|
|
42
|
+
- **文档站点**: http://localhost:3001
|
|
43
|
+
|
|
44
|
+
### 构建生产版本
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm build
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 运行测试
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm test # 运行单元测试
|
|
54
|
+
pnpm check-types # TypeScript 类型检查
|
|
55
|
+
pnpm lint # ESLint 代码检查
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 项目结构
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
my-project/
|
|
62
|
+
├── apps/
|
|
63
|
+
│ ├── web/ # Next.js 主应用
|
|
64
|
+
│ └── docs/ # Fumadocs 文档站点
|
|
65
|
+
├── packages/ # 共享包
|
|
66
|
+
├── supabase/ # 数据库迁移
|
|
67
|
+
└── scripts/ # 自动化脚本
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 关键配置
|
|
71
|
+
|
|
72
|
+
### 环境变量
|
|
73
|
+
|
|
74
|
+
复制 `.env.local.example` 到 `.env.local`,并填写以下配置:
|
|
75
|
+
|
|
76
|
+
| 变量 | 说明 | 获取方式 |
|
|
77
|
+
|------|------|----------|
|
|
78
|
+
| `NEXT_PUBLIC_SUPABASE_URL` | Supabase 项目 URL | Supabase Dashboard → Project Settings → API |
|
|
79
|
+
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase 匿名密钥 | Supabase Dashboard → Project Settings → API |
|
|
80
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase 服务角色密钥 | Supabase Dashboard → Project Settings → API |
|
|
81
|
+
|
|
82
|
+
### pnpm 工作区
|
|
83
|
+
|
|
84
|
+
项目使用 pnpm workspace 管理 monorepo:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
# pnpm-workspace.yaml
|
|
88
|
+
packages:
|
|
89
|
+
- 'apps/*'
|
|
90
|
+
- 'packages/*'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 下一步
|
|
94
|
+
|
|
95
|
+
- [数据层:Supabase](/docs/template/supabase)
|
|
96
|
+
- [数据层:Drizzle](/docs/template/drizzle)
|
|
97
|
+
- [支付:支付宝](/docs/template/alipay)
|
|
98
|
+
- [支付:微信支付](/docs/template/wechat-pay)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 数据层:Supabase
|
|
3
|
+
description: 如何在开发环境和生产环境中使用 Supabase,包括数据表设计、类型安全和最佳实践。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 概述
|
|
7
|
+
|
|
8
|
+
本项目使用 **Supabase** 作为后端数据库和身份验证服务。Supabase 提供了 PostgreSQL 数据库、自动生成的 REST API、实时订阅和身份验证功能。
|
|
9
|
+
|
|
10
|
+
## 开发环境配置
|
|
11
|
+
|
|
12
|
+
### 本地 Supabase CLI
|
|
13
|
+
|
|
14
|
+
1. **安装 Supabase CLI**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add -g supabase
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. **登录 Supabase**
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
supabase login
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. **启动本地 Supabase 实例**
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
supabase start
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
本地开发时,Supabase 服务运行在:
|
|
33
|
+
- **Studio UI**: http://localhost:54323
|
|
34
|
+
- **API URL**: http://localhost:54321
|
|
35
|
+
- **数据库**: postgresql://postgres:postgres@localhost:54322/postgres
|
|
36
|
+
|
|
37
|
+
### 环境变量
|
|
38
|
+
|
|
39
|
+
在 `.env.local` 中配置本地 Supabase:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
|
43
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-local-anon-key
|
|
44
|
+
SUPABASE_SERVICE_ROLE_KEY=your-local-service-role-key
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> 运行 `supabase status` 获取本地密钥。
|
|
48
|
+
|
|
49
|
+
## 生产环境配置
|
|
50
|
+
|
|
51
|
+
1. 在 [Supabase Dashboard](https://supabase.com/dashboard) 创建新项目
|
|
52
|
+
2. 获取项目 URL 和 API 密钥
|
|
53
|
+
3. 更新生产环境变量
|
|
54
|
+
|
|
55
|
+
## 数据表设计
|
|
56
|
+
|
|
57
|
+
项目包含以下核心数据表(通过迁移脚本管理):
|
|
58
|
+
|
|
59
|
+
| 表名 | 说明 |
|
|
60
|
+
|------|------|
|
|
61
|
+
| `profiles` | 用户资料扩展 |
|
|
62
|
+
| `subscriptions` | 订阅信息 |
|
|
63
|
+
| `payments` | 支付记录 |
|
|
64
|
+
|
|
65
|
+
### 运行迁移
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# 本地
|
|
69
|
+
supabase migration up
|
|
70
|
+
|
|
71
|
+
# 生产
|
|
72
|
+
supabase migration up --linked
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 类型安全
|
|
76
|
+
|
|
77
|
+
项目使用 **Supabase 类型生成** 确保数据库查询的类型安全:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { createClient } from '@supabase/supabase-js'
|
|
81
|
+
import type { Database } from './supabase/types'
|
|
82
|
+
|
|
83
|
+
const supabase = createClient<Database>(url, key)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
运行以下命令生成类型:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
supabase gen types typescript --project-id your-project-id --schema public > src/lib/supabase/types.ts
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 安全最佳实践
|
|
93
|
+
|
|
94
|
+
### 行级安全策略 (RLS)
|
|
95
|
+
|
|
96
|
+
所有表默认启用 RLS,确保用户只能访问自己的数据:
|
|
97
|
+
|
|
98
|
+
```sql
|
|
99
|
+
CREATE POLICY "Users can only access their own data"
|
|
100
|
+
ON profiles FOR ALL
|
|
101
|
+
TO authenticated
|
|
102
|
+
USING (auth.uid() = user_id);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 服务角色密钥
|
|
106
|
+
|
|
107
|
+
- **仅在服务器端**使用 `SUPABASE_SERVICE_ROLE_KEY`
|
|
108
|
+
- **绝不在客户端**暴露服务角色密钥
|
|
109
|
+
- 使用 `@supabase/ssr` 包管理会话
|
|
110
|
+
|
|
111
|
+
## 开发调试
|
|
112
|
+
|
|
113
|
+
### 查看数据库
|
|
114
|
+
|
|
115
|
+
通过 Supabase Studio 访问本地数据库:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
supabase studio
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 日志和监控
|
|
122
|
+
|
|
123
|
+
- 本地:http://localhost:54323/project/default/logs/explorer
|
|
124
|
+
- 生产:Supabase Dashboard → Logs
|
|
125
|
+
|
|
126
|
+
## 相关资源
|
|
127
|
+
|
|
128
|
+
- [Supabase 官方文档](https://supabase.com/docs)
|
|
129
|
+
- [Supabase JavaScript 客户端](https://supabase.com/docs/reference/javascript)
|
|
130
|
+
- [PostgreSQL 文档](https://www.postgresql.org/docs/)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 故障排查
|
|
3
|
+
description: 常见问题及解决方案。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 常见问题
|
|
7
|
+
|
|
8
|
+
### pnpm install 失败
|
|
9
|
+
|
|
10
|
+
**问题**: 运行 `pnpm install` 时出现 `ERR_PNPM_IGNORED_BUILDS` 错误。
|
|
11
|
+
|
|
12
|
+
**解决方案**:
|
|
13
|
+
- 运行 `pnpm approve-builds` 批准构建脚本
|
|
14
|
+
- 或者检查 `pnpm-workspace.yaml` 中的 `onlyBuiltDependencies` 配置
|
|
15
|
+
|
|
16
|
+
### 类型检查失败
|
|
17
|
+
|
|
18
|
+
**问题**: `pnpm check-types` 报错。
|
|
19
|
+
|
|
20
|
+
**解决方案**:
|
|
21
|
+
- 确保 `.env.local` 文件存在
|
|
22
|
+
- 运行 `pnpm build` 更新 `.source/` 文件
|
|
23
|
+
|
|
24
|
+
### 文档站点 404
|
|
25
|
+
|
|
26
|
+
**问题**: 访问 `/docs` 返回 404。
|
|
27
|
+
|
|
28
|
+
**解决方案**:
|
|
29
|
+
- 确保 docs 应用已启动(`pnpm --filter @cogito.ai/docs dev`)
|
|
30
|
+
- 检查 `.source/` 文件是否已生成
|
|
31
|
+
|
|
32
|
+
### 支付回调收不到
|
|
33
|
+
|
|
34
|
+
**问题**: 支付宝/微信支付回调通知收不到。
|
|
35
|
+
|
|
36
|
+
**解决方案**:
|
|
37
|
+
- 确保服务器公网可访问
|
|
38
|
+
- 检查回调地址配置是否正确
|
|
39
|
+
- 确认使用 HTTPS 协议
|
|
40
|
+
- 查看服务器防火墙设置
|
|
41
|
+
|
|
42
|
+
### 数据库连接失败
|
|
43
|
+
|
|
44
|
+
**问题**: 无法连接 Supabase 数据库。
|
|
45
|
+
|
|
46
|
+
**解决方案**:
|
|
47
|
+
- 检查 `.env.local` 中的 Supabase URL 和密钥
|
|
48
|
+
- 确保本地 Supabase 实例已启动(`supabase start`)
|
|
49
|
+
- 验证网络连接
|
|
50
|
+
|
|
51
|
+
## 调试技巧
|
|
52
|
+
|
|
53
|
+
### 查看日志
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Web 应用日志
|
|
57
|
+
pnpm --filter @cogito.ai/web dev
|
|
58
|
+
|
|
59
|
+
# 文档站点日志
|
|
60
|
+
pnpm --filter @cogito.ai/docs dev
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 清理缓存
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 删除 node_modules 和 lockfile
|
|
67
|
+
rm -rf node_modules pnpm-lock.yaml
|
|
68
|
+
|
|
69
|
+
# 重新安装依赖
|
|
70
|
+
pnpm install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 检查环境变量
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# 确认 .env.local 存在
|
|
77
|
+
cat .env.local
|
|
78
|
+
|
|
79
|
+
# 确认变量已加载
|
|
80
|
+
node -e "console.log(process.env.NEXT_PUBLIC_SUPABASE_URL)"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 获取帮助
|
|
84
|
+
|
|
85
|
+
- [AgentDock GitHub Issues](https://github.com/your-org/agentdock/issues)
|
|
86
|
+
- [Next.js 文档](https://nextjs.org/docs)
|
|
87
|
+
- [Supabase 文档](https://supabase.com/docs)
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 支付:微信支付
|
|
3
|
+
description: 微信支付集成指南,包括架构、配置、安全和使用方法。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 概述
|
|
7
|
+
|
|
8
|
+
本项目集成了 **微信支付**(WeChat Pay),支持 Native 支付(扫码支付)和 JSAPI 支付(公众号/小程序内支付)场景。
|
|
9
|
+
|
|
10
|
+
## 技术架构
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
14
|
+
│ 用户浏览器 │
|
|
15
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
16
|
+
│ │ 选择商品 │ -> │ 创建订单 │ -> │ 扫码/调起支付 │ │
|
|
17
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
18
|
+
└─────────────────────────────────────────────────────────────┘
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
22
|
+
│ Next.js 应用 (Server) │
|
|
23
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
24
|
+
│ │ /api/pay │ │ 签名/验签 │ │ 回调处理 │ │
|
|
25
|
+
│ │ /api/notify │ │ │ │ │ │
|
|
26
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
27
|
+
└─────────────────────────────────────────────────────────────┘
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
┌────────────────┐
|
|
31
|
+
│ 微信支付网关 │
|
|
32
|
+
│ (api.mch.weixin.qq.com) │
|
|
33
|
+
└────────────────┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 时序图
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
用户 前端页面 Next.js API 微信支付网关
|
|
40
|
+
│ │ │ │
|
|
41
|
+
│ 1.选择商品 │ │ │
|
|
42
|
+
│─────────────>│ │ │
|
|
43
|
+
│ │ 2.POST /create │ │
|
|
44
|
+
│ │─────────────────>│ │
|
|
45
|
+
│ │ │ 3.统一下单 │
|
|
46
|
+
│ │ │─────────────────>│
|
|
47
|
+
│ │ │ 4.返回 prepay_id│
|
|
48
|
+
│ │ │<─────────────────│
|
|
49
|
+
│ 5.返回支付参数│ │ │
|
|
50
|
+
│<─────────────│ │ │
|
|
51
|
+
│ 6.调起微信支付│ │ │
|
|
52
|
+
│─────────────────────────────────────────────────>│
|
|
53
|
+
│ 7.支付成功 │ │ │
|
|
54
|
+
│<─────────────────────────────────────────────────│
|
|
55
|
+
│ │ │ 8.异步通知 │
|
|
56
|
+
│ │ │<─────────────────│
|
|
57
|
+
│ │ │ 9.验签+更新状态 │
|
|
58
|
+
│ │ │ │
|
|
59
|
+
│ 10.跳转成功页│ │ │
|
|
60
|
+
│<─────────────│ │ │
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 前置条件
|
|
64
|
+
|
|
65
|
+
### 微信支付商户账号
|
|
66
|
+
|
|
67
|
+
1. 注册 [微信支付商户平台](https://pay.weixin.qq.com/) 账号
|
|
68
|
+
2. 完成商户认证,获取 **商户号 (mch_id)**
|
|
69
|
+
3. 申请 **API 证书** 和 **APIv3 密钥**
|
|
70
|
+
|
|
71
|
+
### 必要配置
|
|
72
|
+
|
|
73
|
+
| 配置项 | 说明 | 获取位置 |
|
|
74
|
+
|--------|------|----------|
|
|
75
|
+
| `WECHAT_PAY_MCH_ID` | 商户号 | 微信支付商户平台 → 账户中心 |
|
|
76
|
+
| `WECHAT_PAY_APP_ID` | 应用 APPID | 微信开放平台/公众号平台 |
|
|
77
|
+
| `WECHAT_PAY_API_V3_KEY` | APIv3 密钥 | 微信支付商户平台 → 账户中心 → API安全 |
|
|
78
|
+
| `WECHAT_PAY_CERT_SERIAL_NO` | 证书序列号 | 商户平台 → API安全 → 管理证书 |
|
|
79
|
+
| `WECHAT_PAY_PRIVATE_KEY` | 商户私钥 | 下载的 apiclient_key.pem |
|
|
80
|
+
|
|
81
|
+
## 开发环境配置
|
|
82
|
+
|
|
83
|
+
### 1. 配置环境变量
|
|
84
|
+
|
|
85
|
+
在 `.env.local` 中添加:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
WECHAT_PAY_MCH_ID=your-mch-id
|
|
89
|
+
WECHAT_PAY_APP_ID=your-app-id
|
|
90
|
+
WECHAT_PAY_API_V3_KEY=your-api-v3-key
|
|
91
|
+
WECHAT_PAY_CERT_SERIAL_NO=your-cert-serial-no
|
|
92
|
+
WECHAT_PAY_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----
|
|
93
|
+
WECHAT_PAY_NOTIFY_URL=https://your-domain.com/api/payments/wechat/notify
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> **注意**: 私钥包含换行符,使用 `\n` 转义。
|
|
97
|
+
|
|
98
|
+
### 2. 下载 API 证书
|
|
99
|
+
|
|
100
|
+
1. 登录 [微信支付商户平台](https://pay.weixin.qq.com/)
|
|
101
|
+
2. 进入 **账户中心 → API安全 → 申请API证书**
|
|
102
|
+
3. 下载证书文件(`apiclient_cert.pem` 和 `apiclient_key.pem`)
|
|
103
|
+
|
|
104
|
+
### 3. 设置 APIv3 密钥
|
|
105
|
+
|
|
106
|
+
在商户平台 → 账户中心 → API安全 → 设置 APIv3 密钥:
|
|
107
|
+
|
|
108
|
+
1. 点击"设置密钥"
|
|
109
|
+
2. 使用随机字符串生成器生成 32 位密钥
|
|
110
|
+
3. 保存密钥(只会显示一次)
|
|
111
|
+
|
|
112
|
+
## 生产环境配置
|
|
113
|
+
|
|
114
|
+
### 服务器要求
|
|
115
|
+
|
|
116
|
+
- 公网可访问的 HTTPS 地址
|
|
117
|
+
- 支持接收 POST 请求的回调接口
|
|
118
|
+
- 服务器时间与微信服务器时间误差不超过 5 分钟
|
|
119
|
+
|
|
120
|
+
### 回调地址配置
|
|
121
|
+
|
|
122
|
+
在商户平台 → 产品中心 → 开发配置 中配置:
|
|
123
|
+
|
|
124
|
+
| 配置项 | 值 |
|
|
125
|
+
|--------|-----|
|
|
126
|
+
| 回调通知地址 | `https://your-domain.com/api/payments/wechat/notify` |
|
|
127
|
+
|
|
128
|
+
## API 路由
|
|
129
|
+
|
|
130
|
+
### 创建支付订单
|
|
131
|
+
|
|
132
|
+
```http
|
|
133
|
+
POST /api/payments/wechat/create
|
|
134
|
+
Content-Type: application/json
|
|
135
|
+
|
|
136
|
+
{
|
|
137
|
+
"orderId": "ORDER_123456",
|
|
138
|
+
"amount": 99.99,
|
|
139
|
+
"description": "商品描述",
|
|
140
|
+
"openid": "user-openid" // JSAPI 支付需要
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**响应:**
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"success": true,
|
|
149
|
+
"data": {
|
|
150
|
+
"prepayId": "wx20240101120000...",
|
|
151
|
+
"appId": "wx...",
|
|
152
|
+
"timeStamp": "1704096000",
|
|
153
|
+
"nonceStr": "...",
|
|
154
|
+
"package": "prepay_id=wx...",
|
|
155
|
+
"signType": "RSA",
|
|
156
|
+
"paySign": "..."
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 支付回调通知
|
|
162
|
+
|
|
163
|
+
```http
|
|
164
|
+
POST /api/payments/wechat/notify
|
|
165
|
+
Content-Type: application/json
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
微信支付回调请求头包含 `Wechatpay-Serial` 和 `Wechatpay-Signature`:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
export async function POST(request: Request) {
|
|
172
|
+
const body = await request.text()
|
|
173
|
+
const signature = request.headers.get('Wechatpay-Signature')
|
|
174
|
+
const serial = request.headers.get('Wechatpay-Serial')
|
|
175
|
+
|
|
176
|
+
// 1. 验证签名
|
|
177
|
+
const isValid = await verifyWechatSignature(body, signature, serial)
|
|
178
|
+
if (!isValid) {
|
|
179
|
+
return new Response('Invalid signature', { status: 400 })
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 2. 解密回调数据
|
|
183
|
+
const data = JSON.parse(body)
|
|
184
|
+
const decrypted = await decryptWechatPayload(data)
|
|
185
|
+
|
|
186
|
+
// 3. 更新订单状态
|
|
187
|
+
// ...
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 查询订单状态
|
|
192
|
+
|
|
193
|
+
```http
|
|
194
|
+
GET /api/payments/wechat/query?outTradeNo=ORDER_123456
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 安全注意事项
|
|
198
|
+
|
|
199
|
+
### 签名验证
|
|
200
|
+
|
|
201
|
+
微信支付使用 **RSA 签名** 和 **AES 加密**,必须严格验证:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { verifyWechatSignature, decryptWechatPayload } from '@/lib/wechat-pay'
|
|
205
|
+
|
|
206
|
+
export async function POST(request: Request) {
|
|
207
|
+
const body = await request.text()
|
|
208
|
+
const signature = request.headers.get('Wechatpay-Signature')
|
|
209
|
+
|
|
210
|
+
// 1. 验证签名
|
|
211
|
+
const isValid = await verifyWechatSignature(body, signature)
|
|
212
|
+
if (!isValid) {
|
|
213
|
+
return new Response('Invalid signature', { status: 400 })
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 2. 解密回调数据
|
|
217
|
+
const data = JSON.parse(body)
|
|
218
|
+
const decrypted = await decryptWechatPayload(data)
|
|
219
|
+
|
|
220
|
+
// 3. 验证金额(防止篡改)
|
|
221
|
+
const order = await db.payments.findOne({ outTradeNo: decrypted.out_trade_no })
|
|
222
|
+
if (order.amount !== decrypted.amount.total) {
|
|
223
|
+
return new Response('Amount mismatch', { status: 400 })
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 4. 更新订单状态
|
|
227
|
+
// ...
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 安全最佳实践
|
|
232
|
+
|
|
233
|
+
| 风险 | 防护措施 |
|
|
234
|
+
|------|----------|
|
|
235
|
+
| 回调伪造 | 严格验证签名和证书序列号 |
|
|
236
|
+
| 金额篡改 | 比对数据库订单金额与回调金额 |
|
|
237
|
+
| 重复通知 | 使用幂等性处理(out_trade_no 去重) |
|
|
238
|
+
| 密钥泄露 | 私钥仅存储在服务器端 |
|
|
239
|
+
| 中间人攻击 | 使用 HTTPS 传输 |
|
|
240
|
+
| 时间戳重放 | 检查时间戳是否在合理范围内(5分钟) |
|
|
241
|
+
|
|
242
|
+
### 幂等性处理
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
// 使用数据库唯一约束防止重复处理
|
|
246
|
+
await db.payments.updateOne(
|
|
247
|
+
{ outTradeNo: decrypted.out_trade_no, status: { $ne: 'PAID' } },
|
|
248
|
+
{
|
|
249
|
+
$set: {
|
|
250
|
+
status: 'PAID',
|
|
251
|
+
transactionId: decrypted.transaction_id
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## 开发环境调试
|
|
258
|
+
|
|
259
|
+
### 沙箱环境
|
|
260
|
+
|
|
261
|
+
微信支付提供沙箱环境用于开发测试:
|
|
262
|
+
|
|
263
|
+
1. 登录 [微信支付商户平台](https://pay.weixin.qq.com/)
|
|
264
|
+
2. 进入 **产品中心 → 开发配置 → 沙箱**
|
|
265
|
+
3. 获取沙箱 API 密钥
|
|
266
|
+
4. 修改环境变量为沙箱配置:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
WECHAT_PAY_GATEWAY_URL=https://api.mch.weixin.qq.com/sandboxnew
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 调试工具
|
|
273
|
+
|
|
274
|
+
- [微信支付开发者工具](https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/Android_JDk.html)
|
|
275
|
+
- [签名调试工具](https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay6_0.shtml)
|
|
276
|
+
|
|
277
|
+
## 微信支付 FAQs
|
|
278
|
+
|
|
279
|
+
**Q: 回调通知收不到?**
|
|
280
|
+
|
|
281
|
+
A: 检查以下几点:
|
|
282
|
+
1. 服务器是否公网可访问
|
|
283
|
+
2. 回调地址是否正确配置在商户平台
|
|
284
|
+
3. 是否使用 HTTPS(微信要求)
|
|
285
|
+
4. 服务器时间是否准确(误差不超过5分钟)
|
|
286
|
+
5. 防火墙是否放行
|
|
287
|
+
|
|
288
|
+
**Q: 签名验证失败?**
|
|
289
|
+
|
|
290
|
+
A: 常见原因:
|
|
291
|
+
1. APIv3 密钥错误
|
|
292
|
+
2. 私钥格式错误(应为 PKCS#8 格式)
|
|
293
|
+
3. 时间戳误差超过 5 分钟
|
|
294
|
+
4. 请求体编码错误(应为 UTF-8)
|
|
295
|
+
|
|
296
|
+
**Q: 如何测试支付流程?**
|
|
297
|
+
|
|
298
|
+
A: 使用微信支付沙箱环境:
|
|
299
|
+
1. 在商户平台启用沙箱模式
|
|
300
|
+
2. 使用沙箱 API 密钥
|
|
301
|
+
3. 使用 [微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html) 模拟支付
|
|
302
|
+
|
|
303
|
+
**Q: 如何获取用户的 OpenID?**
|
|
304
|
+
|
|
305
|
+
A: 对于 JSAPI 支付,需要通过 OAuth 授权获取用户 OpenID:
|
|
306
|
+
1. 引导用户访问微信 OAuth 授权链接
|
|
307
|
+
2. 用户授权后,微信会重定向到回调地址并附带 `code`
|
|
308
|
+
3. 使用 `code` 换取 `openid`
|
|
309
|
+
|
|
310
|
+
## 相关资源
|
|
311
|
+
|
|
312
|
+
- [微信支付商户平台](https://pay.weixin.qq.com/)
|
|
313
|
+
- [微信支付开发文档](https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml)
|
|
314
|
+
- [Native 支付文档](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml)
|
|
315
|
+
- [JSAPI 支付文档](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml)
|
|
316
|
+
- [微信支付沙箱环境](https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay7_0.shtml)
|
|
317
|
+
- [APIv3 签名指南](https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml)
|
|
318
|
+
- [回调通知说明](https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml)
|
|
@@ -4,7 +4,7 @@ import { NextIntlClientProvider } from 'next-intl'
|
|
|
4
4
|
import { getMessages } from 'next-intl/server'
|
|
5
5
|
import { notFound } from 'next/navigation'
|
|
6
6
|
import { Toaster } from '@/components/ui/sonner'
|
|
7
|
-
import { ThemeProvider } from '
|
|
7
|
+
import { ThemeProvider } from '@/components/providers/theme-provider'
|
|
8
8
|
import { isLocale } from '@/i18n/config'
|
|
9
9
|
import './globals.css'
|
|
10
10
|
|
|
@@ -8,11 +8,10 @@ allowBuilds:
|
|
|
8
8
|
esbuild: set this to true or false
|
|
9
9
|
msw: set this to true or false
|
|
10
10
|
sharp: set this to true or false
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- sharp
|
|
11
|
+
onlyBuiltDependencies:
|
|
12
|
+
- '@fission-ai/openspec'
|
|
13
|
+
- '@parcel/watcher'
|
|
14
|
+
- '@swc/core'
|
|
15
|
+
- esbuild
|
|
16
|
+
- msw
|
|
17
|
+
- sharp
|