@deployxai/dxc 0.1.0
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/README.md +131 -0
- package/dist/chunks/chunk-I6VZLNRZ.js +2118 -0
- package/dist/chunks/chunk-XIHX5YAF.js +16391 -0
- package/dist/chunks/knowledge-Q6MHPG6I.js +1248 -0
- package/dist/chunks/monitor-VPRVRQIS.js +694 -0
- package/dist/index.js +32367 -0
- package/docs/00-project-context.md +125 -0
- package/docs/01-north-star-architecture.md +234 -0
- package/docs/02-mvp-technical-design.md +553 -0
- package/docs/03-domain-state-api.md +599 -0
- package/docs/04-security-and-operations.md +413 -0
- package/docs/05-delivery-plan.md +407 -0
- package/docs/README.md +44 -0
- package/docs/decisions/0001-initial-architecture.md +57 -0
- package/docs/decisions/0002-mongodb-environment-boundary.md +42 -0
- package/docs/decisions/0003-staged-production-topology.md +33 -0
- package/docs/decisions/0004-local-first-agent-research-runtime.md +71 -0
- package/docs/decisions/0005-official-skill-orchestration-and-local-content-memory.md +97 -0
- package/docs/decisions/0006-separate-wechat-user-login-from-account-authorization.md +87 -0
- package/docs/decisions/0007-explicit-personal-wechat-start.md +67 -0
- package/docs/decisions/0008-end-to-end-content-workflow-continuity.md +115 -0
- package/docs/decisions/0009-privileged-multitenant-draft-scheduling.md +36 -0
- package/docs/decisions/0009-versioned-cloud-template-catalog.md +39 -0
- package/docs/eight-stage-implementation-audit.md +62 -0
- package/docs/first-user-guide.md +187 -0
- package/docs/history/content-forge-prd-v0.2-summary.md +81 -0
- package/docs/local-development.md +511 -0
- package/docs/references/aliyun-oss-production-setup.md +89 -0
- package/docs/references/legacy-content-to-wechat-contract.md +223 -0
- package/docs/references/renderer-compatibility-report.md +68 -0
- package/docs/references/source-inventory.md +179 -0
- package/docs/references/wechat-renderer-platform-validation.md +92 -0
- package/docs/references/wechat-third-party-platform-setup.md +159 -0
- package/docs/references/wechat-website-login-setup.md +137 -0
- package/docs/references/wemd-template-attribution.md +25 -0
- package/docs/research-monitoring-design.md +235 -0
- package/docs/todo-preview-local-first.md +31 -0
- package/docs/workbuddy-first-user-runbook.md +246 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-b-research-analyst/SKILL.md +230 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-c-outline-architect/SKILL.md +194 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-d-content-writer/SKILL.md +296 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-e-visual-designer/SKILL.md +268 -0
- package/package.json +25 -0
- package/skills/dxc-article-outline/SKILL.md +82 -0
- package/skills/dxc-article-outline/agents/openai.yaml +6 -0
- package/skills/dxc-article-outline/references/outline-methods.md +38 -0
- package/skills/dxc-article-write/SKILL.md +85 -0
- package/skills/dxc-article-write/agents/openai.yaml +6 -0
- package/skills/dxc-article-write/references/writing-methods.md +42 -0
- package/skills/dxc-content-brief/SKILL.md +81 -0
- package/skills/dxc-content-brief/agents/openai.yaml +6 -0
- package/skills/dxc-content-brief/references/brief-method.md +34 -0
- package/skills/dxc-content-review/SKILL.md +84 -0
- package/skills/dxc-content-review/agents/openai.yaml +6 -0
- package/skills/dxc-content-review/references/review-checklist.md +35 -0
- package/skills/dxc-content-workflow/SKILL.md +190 -0
- package/skills/dxc-content-workflow/agents/openai.yaml +6 -0
- package/skills/dxc-content-workflow/references/catalog.json +136 -0
- package/skills/dxc-content-workflow/references/onboarding-questions.md +107 -0
- package/skills/dxc-content-workflow/references/stage-contract.md +70 -0
- package/skills/dxc-research/SKILL.md +110 -0
- package/skills/dxc-research/agents/openai.yaml +6 -0
- package/skills/dxc-research/references/research-method.md +53 -0
- package/skills/dxc-title-write/SKILL.md +112 -0
- package/skills/dxc-title-write/agents/openai.yaml +6 -0
- package/skills/dxc-title-write/references/title-methods.md +26 -0
- package/skills/dxc-visual-plan/SKILL.md +119 -0
- package/skills/dxc-visual-plan/agents/openai.yaml +6 -0
- package/skills/dxc-visual-plan/references/visual-methods.md +35 -0
- package/skills/dxc-wechat-publisher/SKILL.md +157 -0
- package/skills/dxc-wechat-publisher/agents/openai.yaml +6 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
# 本地开发
|
|
2
|
+
|
|
3
|
+
更新日期:2026-07-29
|
|
4
|
+
|
|
5
|
+
本文描述工程骨架、本地渲染与内容记忆、九个官方 Skill、个人微信首次注册/登录、公众号
|
|
6
|
+
绑定、通用文章上传/云端预览/确认和草稿回读闭环。默认配置不连接 MongoDB、不读取微信
|
|
7
|
+
或支付密钥、不访问任何服务器,也不包含部署命令;只有显式启用
|
|
8
|
+
`DXC_WECHAT_MODE=fake|live` 才初始化微信模块,个人登录还需单独启用
|
|
9
|
+
`DXC_WECHAT_LOGIN_MODE=fake|live`。通用发布还要求 Server 与 Worker 使用同一对象存储。
|
|
10
|
+
|
|
11
|
+
## 1. 环境要求
|
|
12
|
+
|
|
13
|
+
- Node.js 24 LTS;
|
|
14
|
+
- pnpm 11;
|
|
15
|
+
- macOS、Windows 或 Linux。
|
|
16
|
+
|
|
17
|
+
仓库通过 `.node-version`、`.nvmrc`、根 `package.json` 的 `engines` 和 `packageManager` 固定版本边界。先确认环境:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
node --version
|
|
21
|
+
pnpm --version
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Node 主版本应为 `24`,pnpm 主版本应为 `11`。
|
|
25
|
+
|
|
26
|
+
## 2. 安装与完整验证
|
|
27
|
+
|
|
28
|
+
全新检出后,在仓库根目录执行:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
pnpm install --frozen-lockfile
|
|
32
|
+
pnpm check
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`pnpm check` 依次执行格式检查、lint、严格类型检查、构建和 Vitest 测试。依赖锁文件必须提交,不使用生产数据库或任何外部服务完成这些测试。
|
|
36
|
+
|
|
37
|
+
可单独执行:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
pnpm format:check
|
|
41
|
+
pnpm lint
|
|
42
|
+
pnpm typecheck
|
|
43
|
+
pnpm test
|
|
44
|
+
pnpm build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 3. 本地环境文件
|
|
48
|
+
|
|
49
|
+
macOS/Linux:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
cp .env.example .env.local
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Windows PowerShell:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
Copy-Item .env.example .env.local
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
基础运行配置:
|
|
62
|
+
|
|
63
|
+
| 变量 | 用途 |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `DXC_ENV` | `development`、`test` 或 `production` |
|
|
66
|
+
| `DXC_LOG_LEVEL` | Pino 日志级别 |
|
|
67
|
+
| `DXC_SERVER_HOST` | Server 监听地址 |
|
|
68
|
+
| `DXC_SERVER_PORT` | Server 监听端口 |
|
|
69
|
+
| `DXC_WECHAT_MODE` | `disabled`、`fake` 或 `live` |
|
|
70
|
+
| `DXC_WECHAT_LOGIN_MODE` | 个人微信网站登录;`disabled`、`fake` 或 `live` |
|
|
71
|
+
| `DXC_OBJECT_STORAGE_MODE` | `disabled`、本地开发 `filesystem` 或共享 `s3` |
|
|
72
|
+
| `DXC_OBJECT_STORAGE_DIRECTORY` | 仅开发用的绝对目录;production(生产)模式禁止 |
|
|
73
|
+
|
|
74
|
+
缺失或非法配置会让 Server/Worker 快速失败。错误只列出变量名,不输出变量值。`.env.local` 已被 Git 忽略;真实第三方平台值只能放在本地安全环境或后续密钥管理服务。
|
|
75
|
+
|
|
76
|
+
`fake`/`live` 模式还会校验 Mongo、公开基址、DxC 加密 Key;第三方平台 `live` 模式额外校验 Component AppID/AppSecret、Token、EncodingAESKey 和微信 API 安全材料。个人登录 `live` 模式只额外校验独立网站应用的 AppID/AppSecret。两条链路的变量和 URL 分别见 [微信第三方平台授权绑定配置](references/wechat-third-party-platform-setup.md) 与 [微信网站应用登录配置](references/wechat-website-login-setup.md)。
|
|
77
|
+
|
|
78
|
+
本机通用发布使用:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
DXC_OBJECT_STORAGE_MODE=filesystem
|
|
82
|
+
DXC_OBJECT_STORAGE_DIRECTORY=/absolute/path/to/local-dxc-objects
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
生产 Server/Worker 分离时,两者必须使用相同的 `s3` endpoint、private bucket、region、
|
|
86
|
+
prefix 和受控访问凭据。生产配置禁止 `filesystem`;对象存储访问密钥不得进入 Git 或
|
|
87
|
+
日志。
|
|
88
|
+
|
|
89
|
+
多租户草稿 Worker 额外要求:
|
|
90
|
+
|
|
91
|
+
| 变量 | 用途 |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `DXC_MONGODB_URI` | 本地 Docker MongoDB 连接;生产值不得用于本地开发 |
|
|
94
|
+
| `DXC_MONGODB_DATABASE` | 独立数据库,生产固定为 `dxc` |
|
|
95
|
+
| `DXC_ENCRYPTION_KEY_BASE64` | 解密已授权公众号 Token 的 32 字节应用密钥 |
|
|
96
|
+
| `DXC_WECHAT_COMPONENT_APP_ID` | 第三方平台 Component AppID |
|
|
97
|
+
| `DXC_WECHAT_COMPONENT_APP_SECRET` | 获取 Component Token 的平台密钥 |
|
|
98
|
+
| `DXC_WECHAT_LOGIN_APP_ID` | 独立网站应用 AppID;不复用 Component AppID |
|
|
99
|
+
| `DXC_WECHAT_LOGIN_APP_SECRET` | 独立网站应用 AppSecret;只由 Server 使用 |
|
|
100
|
+
| `DXC_WECHAT_API_AES_KEY_BASE64` | 微信 API 安全配置中的 32 字节对称密钥 |
|
|
101
|
+
| `DXC_WECHAT_API_AES_KEY_SERIAL` | 上述对称密钥序列号 |
|
|
102
|
+
| `DXC_WECHAT_API_RSA_PRIVATE_KEY_FILE` | 应用 RSA 私钥的绝对文件路径 |
|
|
103
|
+
| `DXC_WECHAT_API_RSA_PRIVATE_KEY_SERIAL` | 应用非对称密钥编号;不是 AES 密钥或平台证书编号 |
|
|
104
|
+
| `DXC_WECHAT_API_PLATFORM_CERTIFICATE_FILE` | 微信平台证书的绝对文件路径 |
|
|
105
|
+
| `DXC_WECHAT_API_PLATFORM_CERTIFICATE_SERIAL` | 微信平台证书序列号 |
|
|
106
|
+
|
|
107
|
+
`DXC_WECHAT_COMPONENT_TOKEN` 和 `DXC_WECHAT_ENCODING_AES_KEY` 保护第三方平台事件回调;`DXC_WECHAT_API_*` 保护 Worker 发出的微信 API 请求和微信响应;`DXC_WECHAT_LOGIN_*` 只用于个人网站登录 OAuth。三组材料用途不同,不能混用。Worker 从队列领取所有租户的任务,但每次读取授权、快照、封面与状态转移仍使用任务自带的 `tenantId`,并同时绑定具体 `accountId`;`.env.example` 只给出安全占位符;私钥和平台证书必须放在 Git 之外、仅运行用户可读的文件中。
|
|
108
|
+
|
|
109
|
+
## 4. CLI
|
|
110
|
+
|
|
111
|
+
先构建,再运行:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
pnpm build
|
|
115
|
+
pnpm dxc version --json
|
|
116
|
+
pnpm dxc doctor --json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`dxc doctor` 检查 Node.js 24 和当前目录读写权限。JSON 结果写入 stdout;面向人的提示写入 stderr。CLI 的 `bin` 使用同一个 Node 入口,由 pnpm/npm 在 POSIX 与 Windows 上分别生成对应 shim(启动包装)。
|
|
120
|
+
|
|
121
|
+
生成并隔离安装与 npm 发布形态相同的本地包:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
pnpm package:cli
|
|
125
|
+
npm install -g .artifacts/deployxai-dxc-0.1.0.tgz
|
|
126
|
+
dxc skills install --target workbuddy
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
包内包含经过 bundle(打包)的 CLI、两个本地语义运行依赖和九个官方 Skill。当前没有
|
|
130
|
+
发布到 npm;正式发布后才使用 `npm install -g @deployxai/dxc@0.1.0`。安装 Skill 默认
|
|
131
|
+
保留已有同名目录,只有显式 `--force` 才做原子替换。完整首位用户步骤见
|
|
132
|
+
[第一个真实用户指南](first-user-guide.md)。
|
|
133
|
+
|
|
134
|
+
### 4.1 创作画像与总控 Skill
|
|
135
|
+
|
|
136
|
+
唯一公开入口仍是 `skills/dxc-content-workflow`;九个官方 Skill 一次安装:
|
|
137
|
+
|
|
138
|
+
- `dxc-content-workflow@0.6.0`:唯一隐式入口、项目恢复、知识库引导与自动线性编排;
|
|
139
|
+
- `dxc-research@0.1.0`:四类输入归一、本地知识召回、公开研究和角度候选;
|
|
140
|
+
- `dxc-content-brief@0.1.0`:九字段命题和必要时的立场选择;
|
|
141
|
+
- `dxc-article-outline@0.1.0`:可解析大纲和下游标记;
|
|
142
|
+
- `dxc-article-write@0.1.0`:可发布正文和最终正文确认;
|
|
143
|
+
- `dxc-title-write@0.3.0`:标题生成、筛选和确认;
|
|
144
|
+
- `dxc-visual-plan@0.3.0`:经授权的 Agent 图片生成、本地素材选择和真实文件交接;
|
|
145
|
+
- `dxc-content-review@0.3.0`:事实、标题承诺、真实视觉素材和交付边界审校;
|
|
146
|
+
- `dxc-wechat-publisher@0.5.0`:素材上传、右侧云端预览、确认和公众号草稿交付。
|
|
147
|
+
|
|
148
|
+
除总控外的步骤都设置 `allow_implicit_invocation: false`。用户说“写一篇文章”或“继续
|
|
149
|
+
《某篇文章》”即可触发总控,不必知道或逐个调用下游 Skill。
|
|
150
|
+
|
|
151
|
+
首次使用先查看:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
pnpm dxc profile status --json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
若 `configured` 为 `false`,按 [首次创作偏好问卷](../skills/dxc-content-workflow/references/onboarding-questions.md) 生成输入文件,再保存:
|
|
158
|
+
|
|
159
|
+
```text
|
|
160
|
+
pnpm dxc profile save --input <answers.json> --json
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
画像保存在 `~/.dxc/content-profile.json`;目录权限 `0700`、文件权限 `0600`。输入只包含选择题 ID、选项 ID 和可选备注,不包含账号或平台凭据。没有独立“安装 Skill”;
|
|
164
|
+
CLI 的 `skills install` 只是确定性的文件分发命令。
|
|
165
|
+
|
|
166
|
+
### 4.2 内容项目和统一检查点
|
|
167
|
+
|
|
168
|
+
初始化并读取项目:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
pnpm dxc project init --directory <directory> --title "<title>" \
|
|
172
|
+
[--knowledge <history-files...>] --json
|
|
173
|
+
pnpm dxc project resolve [<title-or-project-id>] [--directory <directory>] --json
|
|
174
|
+
pnpm dxc project status --directory <directory> --json
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
项目包含 `dxc.project.json`、`artifacts/`、`assets/` 和 `.dxc/checkpoints/`。八类产物固定为 `research`、`brief`、`outline`、`article`、`titles`、`visual-plan`、`quality-review`、`delivery`。所有步骤复用同一个命令,例如:
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
pnpm dxc project checkpoint research \
|
|
181
|
+
--directory <directory> \
|
|
182
|
+
--status awaiting-user \
|
|
183
|
+
--skill dxc-research \
|
|
184
|
+
--skill-version 0.1.0 \
|
|
185
|
+
--summary "研究产物已经生成并等待用户决定来源范围" \
|
|
186
|
+
--waiting-for "是否确认当前研究来源范围?" \
|
|
187
|
+
--execution-location local-device \
|
|
188
|
+
--data-transit local-only \
|
|
189
|
+
--json
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
checkpoint v3 记录实际 `inputs`、声明或已生成的 `outputs`、`metadata.summary`、
|
|
193
|
+
`waitingFor` 和结构化 `confirmationBinding`。有上游输入时使用
|
|
194
|
+
`--inputs research,brief`;第一阶段可以省略。`awaiting-user`/`completed` 必须存在
|
|
195
|
+
对应输出。CLI 不只检查非空,还会解析阶段 frontmatter,核对固定 Skill 版本、项目、
|
|
196
|
+
实际输入哈希和阶段字段;视觉阶段会检查真实图片。普通内部步骤直接写 `completed`
|
|
197
|
+
即可自动继续;真实用户决策在回答后写
|
|
198
|
+
`--confirm --confirmed-by <actor>`,交付阶段再用
|
|
199
|
+
`--confirmation-snapshot <snapshot-sha256>` 绑定权威渲染快照。缺少确认时命令保留
|
|
200
|
+
`awaiting-user` 并返回 guidance(引导)。输入或输出产物随后变化会在
|
|
201
|
+
`project status` 中显示 `stale`,总控 Skill 从最早失效阶段重新执行。
|
|
202
|
+
|
|
203
|
+
`project init`、对显式目录执行的 `project status` 和 checkpoint 更新都会把项目标题、
|
|
204
|
+
ID、绝对目录和更新时间登记到权限为 `0600` 的 `~/.dxc/content-projects.json`。
|
|
205
|
+
因此升级前已有项目只要按路径读取一次,也能进入新索引。`project resolve` 只读取该索引
|
|
206
|
+
和当前目录,不保存正文、不扫描其他目录;一个标题匹配多个项目时返回 `multiple`,由
|
|
207
|
+
用户选择。
|
|
208
|
+
|
|
209
|
+
当前 catalog(目录)把八个步骤全部标为 `available`,表示可调用;另用
|
|
210
|
+
`implementationLevel`、`verificationLevel` 和 `knownGaps` 声明实现深度。已有正文用户
|
|
211
|
+
仍可把标准 `article` 产物记录为自动 `completed`,并把当前路线确实不需要的前置步骤
|
|
212
|
+
写为 `skipped`,但不得冒充对应专家 Skill 已运行。
|
|
213
|
+
|
|
214
|
+
### 4.3 本地历史文章知识库
|
|
215
|
+
|
|
216
|
+
只导入用户明确选择的 Markdown/文本文件:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
pnpm dxc knowledge status --json
|
|
220
|
+
pnpm dxc knowledge import <article-1.md> <article-2.md> --json
|
|
221
|
+
pnpm dxc knowledge search "创业低谷中的真实教训" --mode hybrid --limit 8 --json
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
用户不需要每次显式要求搜索。总控进入研究、Brief、大纲或正文阶段时,会先检查本地
|
|
225
|
+
知识库,并由对应 Skill 按当前目标自动调用 hybrid 查询;知识库为空时正常继续。
|
|
226
|
+
`project init` 同时返回文章数、`ready|import-recommended` 和可执行建议;用户可以在
|
|
227
|
+
初始化命令直接传入 `--knowledge`,也可以明确选择稍后导入或跳过。
|
|
228
|
+
|
|
229
|
+
首次语义导入/搜索会把固定 revision 的 `bge-small-zh-v1.5` q8 模型下载到 `~/.dxc/models/`,模型权重约 24 MB;下载请求不包含文章正文。模型文件有固定 SHA-256,下载后校验,不接受同名但内容变化的权重。CLI 使用 Tokenizers.js 与 ONNX Runtime Web 的单线程 WASM 执行器,不安装体积更大的多平台原生推理包。文章、分段、哈希、FTS5 和 512 维向量保存在 `~/.dxc/content-memory.sqlite`,主文件权限 `0600`。CLI 不自动扫描目录,不在结构化结果中返回绝对源路径,也不把历史全文同步到 DxC Cloud。
|
|
230
|
+
|
|
231
|
+
无网络且用户明确接受只做字面检索时可以:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
pnpm dxc knowledge import <article.md> --lexical-only --json
|
|
235
|
+
pnpm dxc knowledge search "原句关键词" --mode lexical --json
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
对缺少向量的数据库执行 `hybrid` 或 `semantic` 会返回 `DXC_KNOWLEDGE_SEMANTIC_NOT_READY`,不会静默退化。单篇删除:
|
|
239
|
+
|
|
240
|
+
```text
|
|
241
|
+
pnpm dxc knowledge remove <article-id> --json
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
该命令同时删除文章分段、FTS5 行和向量。召回结果只给有界片段及文章/分段 ID、章节和哈希;若 Agent 把片段放入对话,宿主或模型提供方仍可能按自身政策处理该片段。
|
|
245
|
+
|
|
246
|
+
自动化测试注入假嵌入器,不下载模型;本轮另用隔离 `/tmp` 缓存完成一次真实 q8 模型探针,结束后已清理缓存。
|
|
247
|
+
|
|
248
|
+
### 4.4 微信与设备命令
|
|
249
|
+
|
|
250
|
+
推荐首次入口:
|
|
251
|
+
|
|
252
|
+
```text
|
|
253
|
+
pnpm dxc setup --server http://127.0.0.1:3000
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
它先检查已有设备会话;没有时启动个人微信 `start`,已关联身份恢复原 owner,未关联
|
|
257
|
+
身份则在明确提示后创建新 owner。随后若账号列表为空,再进入公众号管理员第三方平台
|
|
258
|
+
授权。已有状态不会重复扫码。
|
|
259
|
+
|
|
260
|
+
个人身份命令:
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
pnpm dxc auth start --server http://127.0.0.1:3000
|
|
264
|
+
pnpm dxc auth link-wechat --server http://127.0.0.1:3000
|
|
265
|
+
pnpm dxc auth login --server http://127.0.0.1:3000
|
|
266
|
+
pnpm dxc auth status
|
|
267
|
+
pnpm dxc auth logout
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`start` 是显式的登录或首次注册;`link-wechat` 只由当前有效 owner 设备发起,用于兼容
|
|
271
|
+
此前已存在但尚未关联个人微信的租户;严格的 `login` 只接受已经关联的个人微信,不会
|
|
272
|
+
创建第二个租户。同一新微信并发 `start` 收敛到相同候选 owner,不留下随机孤立租户。
|
|
273
|
+
固定入口为 `/auth/wechat/login`,固定回调为 `/callbacks/wechat/login`,与公众号第三方
|
|
274
|
+
平台授权完全分离。
|
|
275
|
+
|
|
276
|
+
微信公众号授权命令:
|
|
277
|
+
|
|
278
|
+
```text
|
|
279
|
+
pnpm dxc wechat connect --server http://127.0.0.1:3000
|
|
280
|
+
pnpm dxc wechat accounts
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
远端 API 基址必须使用 HTTPS;HTTP 只允许 `localhost`、`127.0.0.0/8` 和 `::1` 回环地址,带用户名/密码、查询参数或 fragment(片段)的基址会在读取或发送本地凭据前被拒绝。`--server` 与 `DXC_API_BASE_URL` 使用同一校验。
|
|
284
|
+
已有设备会话再次执行 `dxc wechat connect` 时,如果没有显式传入 `--server` 且没有设置
|
|
285
|
+
`DXC_API_BASE_URL`,CLI 会复用会话中保存的 API 基址,不会退回本机开发地址。
|
|
286
|
+
如果当前内容空间已经绑定公众号,该命令直接显示现有账号并成功退出,不要求重复扫码;
|
|
287
|
+
用户明确要新增公众号或重新授权时才使用 `dxc wechat connect --force`。
|
|
288
|
+
|
|
289
|
+
这些扫码命令默认打开系统浏览器并等待结果;`--no-open` 只显示授权 URL。首次连接或新设备登录会在本机生成 Ed25519 设备密钥、候选 24 小时访问 Token 和候选 30 天刷新 Token;持钥签名同时覆盖短时挑战和两个候选 Token 哈希。默认设备私钥保存在 `~/.dxc/device-identity.json`,会话保存在 `~/.dxc/wechat-session.json`;目录权限为 `0700`、文件权限为 `0600`。CLI 读取时拒绝符号链接、非普通文件、其他用户所有的文件和向组/其他用户开放的权限,并复核私钥、公钥与指纹一致;CLI、API 和日志都不输出私钥或 Token。
|
|
290
|
+
|
|
291
|
+
访问 Token 到期时,CLI 用刷新 Token + Ed25519 签名轮换下一组访问/刷新 Token;服务端只存哈希。同一 `rotationId` 可恢复响应丢失,待提交的下一组凭据也先写进同一个 `0600` 会话文件。旧设备会话没有刷新凭据时,可在访问 Token 仍有效时通过 `link-wechat` 自动登记;系统钥匙串适配仍是后续工作。
|
|
292
|
+
|
|
293
|
+
同一设备新增公众号时复用现有设备会话。新的授权轮询 Token 只可查询该授权会话,不会覆盖或获得设备权限。一个公众号已属于其他租户时,Server 返回冲突,不迁移账号;已有身份租户不允许新设备仅凭公众号扫码取得 owner 权限。旧版 `wechat_authorization_sessions` Token 不再提供查询兼容;`connect` 只识别字段恰为 `apiBaseUrl + clientToken` 的旧 CLI 会话文件,把它当作“尚未连接”并在新扫码成功后原子覆盖,绝不发送旧 Token。其他 CLI 命令和任何非精确旧格式仍拒绝该文件。
|
|
294
|
+
|
|
295
|
+
`dxc auth logout` 会撤销当前设备会话。由该设备发起但尚未完成的新增公众号授权在调用微信前、交换结果写入前和 `AUTHORIZED` 恢复前都会重新核对设备 ID、用户、租户、有效期和撤销状态;注销后会话进入 `FAILED`,不得继续持久化账号或 access/refresh token。
|
|
296
|
+
|
|
297
|
+
身份版本首次连接 Mongo 时会执行范围严格的索引迁移:除了原有授权 session 迁移,还会只删除精确匹配的“每租户一个活动设备”临时唯一索引,改为多设备查询索引;只删除精确匹配的旧 `device_sessions.expiresAt` TTL,回填 `cleanupAt = refreshExpiresAt ?? expiresAt` 后建立新 TTL。partial/sparse/collation/hidden(部分/稀疏/排序规则/隐藏)等未知或自定义索引不会被删除。首次公众号 bootstrap 通过租户文档上的原子设备指纹认领继续保证只有一个设备能接管旧单账号租户;个人登录路径才允许第二设备。升级前仍需备份并在本地副本执行 `DXC_TEST_MONGODB_URI=... pnpm test:integration:mongodb` 复验迁移。
|
|
298
|
+
|
|
299
|
+
正文图片版本还会把 `publishing_articles` 的唯一性从
|
|
300
|
+
`tenantId + sourceHash + coverHash` 升级为再包含 `assetManifestHash`。启动迁移只删除
|
|
301
|
+
名称、三字段顺序、唯一性和无自定义选项都精确匹配的旧自动索引;自定义名称或
|
|
302
|
+
partial/sparse/collation/hidden 索引全部保留。生产执行仍必须获得部署写授权并先在本地
|
|
303
|
+
副本复验。
|
|
304
|
+
|
|
305
|
+
设备绑定挑战初始有效 10 分钟,但在创建微信授权会话时会原子延长到同一个 15 分钟授权入口截止时间,因此第 10–15 分钟完成扫码仍有效。微信授权码成功交换并加密后,会先把绑定会话延长到 24 小时恢复截止时间,再写入 `AUTHORIZED` 检查点;该窗口只用于服务崩溃后完成已确认结果的幂等投影,不延长微信授权入口,也不允许在过期后重新消费授权码。
|
|
306
|
+
|
|
307
|
+
## 5. API Server
|
|
308
|
+
|
|
309
|
+
创建 `.env.local` 后运行:
|
|
310
|
+
|
|
311
|
+
```text
|
|
312
|
+
pnpm dev:server
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
另一个终端核验:
|
|
316
|
+
|
|
317
|
+
```text
|
|
318
|
+
curl http://127.0.0.1:3000/health/live
|
|
319
|
+
curl http://127.0.0.1:3000/health/ready
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
响应分别为:
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{"status":"ok"}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{"status":"ready","checks":{"configuration":"ok"}}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
健康接口只返回分类状态,不返回监听地址、端口、环境变量值或未来的连接信息。
|
|
333
|
+
|
|
334
|
+
## 6. Worker
|
|
335
|
+
|
|
336
|
+
创建 `.env.local` 后运行:
|
|
337
|
+
|
|
338
|
+
```text
|
|
339
|
+
pnpm dev:worker
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
`pnpm dev:worker` 仍是无副作用的 P1 运行骨架:只验证公共配置、输出经过脱敏的结构化启动日志,并等待 `SIGINT`/`SIGTERM` 后退出。
|
|
343
|
+
|
|
344
|
+
微信草稿 Worker 使用独立入口:
|
|
345
|
+
|
|
346
|
+
```text
|
|
347
|
+
pnpm exec tsx --env-file-if-exists=.env.local apps/worker/src/wechat-draft.ts
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
它通过 Worker 内部特权调度仓储跨租户原子领取通用草稿意图,再兼容领取固定测试意图,
|
|
351
|
+
且是唯一允许调用微信素材和草稿 API 的进程。任务领取后,授权、快照、素材、状态转移
|
|
352
|
+
和审计仍必须显式使用任务自带的 `tenantId`。通用路径要求
|
|
353
|
+
`DXC_OBJECT_STORAGE_MODE` 不是 `disabled`,并与 Server 指向同一存储。必须先由 CLI
|
|
354
|
+
展示不可变快照并取得用户明确确认;不要在未确认时直接写 Mongo 或启动真实副作用测试。
|
|
355
|
+
|
|
356
|
+
## 7. 日志安全基线
|
|
357
|
+
|
|
358
|
+
Server 和 Worker 共用 `@dxc/security`:
|
|
359
|
+
|
|
360
|
+
- Pino JSON 结构化日志;
|
|
361
|
+
- 按字段路径移除 token、cookie、Authorization、password 等值;
|
|
362
|
+
- 按值模式过滤 Bearer、带口令 Mongo URI、预签名 URL、私钥块和本地绝对路径;
|
|
363
|
+
- 异常对象在序列化前清洗。
|
|
364
|
+
|
|
365
|
+
日志中仍不得主动传入文章正文、完整回调、支付通知、Agent 对话或任何真实凭据。脱敏是最后防线,不是记录敏感数据的许可。
|
|
366
|
+
|
|
367
|
+
## 8. 本地渲染包
|
|
368
|
+
|
|
369
|
+
`packages/renderer-wechat` 提供纯本地、无网络副作用的:
|
|
370
|
+
|
|
371
|
+
- frontmatter / 文章包运行时校验;
|
|
372
|
+
- `wechat-minimal@1` 与固定云端模板目录的 token 渲染;
|
|
373
|
+
- HTML allowlist 清洗;
|
|
374
|
+
- 结构化预检;
|
|
375
|
+
- `sourceHash` / `htmlHash`;
|
|
376
|
+
- `fixtures/renderer` 黄金样例。
|
|
377
|
+
|
|
378
|
+
运行全部检查即可验证:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
pnpm check
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
120 字摘要和 20,000 字 HTML 当前仍是旧工具兼容限制,不是本轮重新确认的微信官方结论。平台实测状态见 [渲染兼容性报告](references/renderer-compatibility-report.md)。
|
|
385
|
+
|
|
386
|
+
## 9. 微信授权本地测试
|
|
387
|
+
|
|
388
|
+
`DXC_WECHAT_MODE=fake` 与 `DXC_WECHAT_LOGIN_MODE=fake` 使用本地 Mongo 和假微信适配器验证:
|
|
389
|
+
|
|
390
|
+
- 授权会话和一次性 `state`;
|
|
391
|
+
- 授权回跳;
|
|
392
|
+
- ID 3/11 权限检查;
|
|
393
|
+
- Token AES-256-GCM 加密持久化;
|
|
394
|
+
- CLI 账号与草稿能力查询。
|
|
395
|
+
- 当前 owner 关联个人微信;
|
|
396
|
+
- 第二设备登录同一 owner/租户;
|
|
397
|
+
- 24 小时访问 Token 与 30 天刷新凭据轮换。
|
|
398
|
+
|
|
399
|
+
完整步骤见 [微信第三方平台授权绑定配置](references/wechat-third-party-platform-setup.md) 和 [微信网站应用登录配置](references/wechat-website-login-setup.md)。自动化测试不会请求真实微信,也不会连接生产数据库。
|
|
400
|
+
|
|
401
|
+
需要复验草稿意图的 Mongo 仓储时,只允许连接本机 Mongo,并由测试创建、删除随机隔离的 `dxc_test_*` 数据库:
|
|
402
|
+
|
|
403
|
+
```text
|
|
404
|
+
DXC_TEST_MONGODB_URI=mongodb://127.0.0.1:27017 pnpm test:integration:mongodb
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## 10. 通用文章预览与草稿
|
|
408
|
+
|
|
409
|
+
在 fake(假服务)或经过单独授权的真实环境中:
|
|
410
|
+
|
|
411
|
+
```text
|
|
412
|
+
pnpm dxc wechat accounts
|
|
413
|
+
pnpm dxc wechat draft preview \
|
|
414
|
+
--article <article.md> \
|
|
415
|
+
--assets-directory <local-images> \
|
|
416
|
+
--cover <cover.png-or-jpeg-or-auto> \
|
|
417
|
+
--account <account-id> \
|
|
418
|
+
--title "<已确认标题>"
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
返回的 `preview.url`、`snapshot.id` 和 `snapshot.snapshotHash` 绑定同一不可变 HTML、
|
|
422
|
+
正文图片清单、封面、metadata、模板和渲染器版本;响应还返回
|
|
423
|
+
`createdAt/expiresAt/expiresInSeconds`。Agent 读取 URL 后应立即用宿主右侧内置浏览器
|
|
424
|
+
展示,不在对话或项目产物中输出链接。
|
|
425
|
+
链接过期时运行
|
|
426
|
+
`pnpm dxc wechat draft preview-refresh --snapshot <snapshot-id> --snapshot-hash <snapshot-hash>`
|
|
427
|
+
只重建短时链接。打开云端预览并明确确认公众号和快照后,才运行:
|
|
428
|
+
|
|
429
|
+
```text
|
|
430
|
+
pnpm dxc wechat draft create \
|
|
431
|
+
--account <account-id> \
|
|
432
|
+
--snapshot <snapshot-id> \
|
|
433
|
+
--snapshot-hash <snapshot-hash> \
|
|
434
|
+
--idempotency-key <stable-key> \
|
|
435
|
+
--confirm
|
|
436
|
+
pnpm dxc wechat draft status <intent-id>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
当前接受 `.md`/`.markdown` 与显式本地 PNG/JPEG 正文图片/封面。素材目录不递归,
|
|
440
|
+
不会扫描未指定目录;正文图片单张小于 1 MiB、最多 20 张,封面不超过 5 MiB。缺少
|
|
441
|
+
内容封面时命令停止并提示返回视觉阶段生成或选择素材。草稿响应返回中文标签、说明、
|
|
442
|
+
下一步和建议查询秒数;内部英文状态不面向用户展示。成功终态必须带微信 MediaID 和
|
|
443
|
+
标题/作者/摘要/最终正文回读结果;未确认状态不盲目重试。完整交互和交付产物格式见
|
|
444
|
+
`skills/dxc-wechat-publisher/SKILL.md`。
|
|
445
|
+
|
|
446
|
+
## 11. 保留的固定受控草稿联调
|
|
447
|
+
|
|
448
|
+
真实联调每次只选择一个公众号,并固定使用仓库内的测试文章和封面:
|
|
449
|
+
|
|
450
|
+
```text
|
|
451
|
+
pnpm dxc wechat accounts
|
|
452
|
+
pnpm dxc wechat draft smoke-preview --account <account-id>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
先核对输出中的账号、标题、作者、摘要、封面哈希、封面标签和渲染版本,并将 `snapshot.snapshotHash` 作为下面的 `<snapshot-hash>`。该哈希同时绑定正文、标题、作者、摘要、评论开关、模板、渲染器版本和实际封面文件字节。用户明确确认后,使用唯一且可复用的幂等键提交:
|
|
456
|
+
|
|
457
|
+
```text
|
|
458
|
+
pnpm dxc wechat draft smoke-create \
|
|
459
|
+
--account <account-id> \
|
|
460
|
+
--snapshot <snapshot-hash> \
|
|
461
|
+
--idempotency-key <stable-key> \
|
|
462
|
+
--confirm
|
|
463
|
+
pnpm dxc wechat draft smoke-status <intent-id>
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
成功必须以 `draft/get` 回读为准。状态为 `ASSET_UPLOAD_UNVERIFIED` 或 `CREATED_UNVERIFIED` 时不要再次提交或更换幂等键,应先去公众号后台人工核对素材/草稿;只有能够证明微信没有完成对应副作用时,才能另行决定是否重建。
|
|
467
|
+
|
|
468
|
+
2026-07-26 的真实联调确认,该账号对作者“DeployX 内容工作台”返回 `45110 author size out of limit`,尽管其字符数未超过当日官方文档描述的 16 字。固定联调文章现使用作者 `DxC`;作者变化会生成新的 `snapshotHash`,必须重新执行 `smoke-preview` 并确认。Mongo 仓储仅会为同一租户、同一账号且 `coverHash` 相同的新联调意图复用此前已确认上传成功的固定封面 MediaID。历史记录缺少 `coverHash` 时不得通配复用;真实恢复只能在核对原封面字节后精确回填,并写入审计事件。
|
|
469
|
+
|
|
470
|
+
第三方平台开启“全部 API 加密及签名校验”时,只能对真实端点已支持的调用启用安全协议。永久素材上传是 `multipart/form-data`,按微信规则不支持正文加密;真实平台进一步证明该二进制上传端点不能携带 API 安全头。规则于 2026-07-26 通过官方契约和真实平台响应核验:
|
|
471
|
+
|
|
472
|
+
- `api_component_token`、`api_create_preauthcode`、`api_query_auth`、`api_get_authorizer_info` 和 `api_authorizer_token` 使用普通 HTTPS JSON;
|
|
473
|
+
- `draft/add` 和 `draft/get` 使用第三方平台 Component AppID 签名和加密;
|
|
474
|
+
- `material/add_material` 使用普通 HTTPS multipart,不发送或要求 `Wechatmp-*`;完整文件和 boundary(边界)仍按标准表单上传;
|
|
475
|
+
- `media/uploadimg` 按 2026-07-30 官方端点契约使用普通 HTTPS multipart,返回的 HTTPS
|
|
476
|
+
URL 只替换当前快照中匹配的正文逻辑路径;假服务测试已通过,真实公众号验证仍是
|
|
477
|
+
生产闸门;
|
|
478
|
+
- RSA 请求只发送 `Wechatmp-AppId`、`Wechatmp-TimeStamp` 和 `Wechatmp-Signature`,不发送 `Wechatmp-Serial`;
|
|
479
|
+
- 应用非对称密钥编号只保留在本地受控配置;API AES 序列号只进入 AAD;微信响应中的 `Wechatmp-Serial` 用于识别平台证书。
|
|
480
|
+
|
|
481
|
+
2026-07-26 现场使用同一 authorizer access token 探测 `batchget_material`:authorizer AppID 身份返回无签名 `40237`,Component AppID 身份返回可验签、可解密成功响应。因此 URL 中虽是 authorizer access token,安全请求头、AAD、加密字段和签名基串仍必须统一使用 Component AppID。同日对 `material/add_material` 发送必定无效的空文件、零填充文件和截断 PNG:完整含零字节正文签名返回 `40234`,首个零字节前缀签名返回 `40097`;完全不带安全头的同一截断 PNG 返回 `40113` 文件类型错误,证明普通 multipart 能进入正确解析路径。两次有效 PNG 的签名上传也都返回 `40097`,随后只读 `batchget_material` 对账确认素材总数仍为 165、同名新增为 0。对于仍使用安全模式的端点,完全无安全响应头的明文 `40230`–`40240` 只按错误码记录为确定性拒绝;其他无签名整数错误码只作为不可验证诊断后缀保留,不得据此改变状态或盲目重试副作用。无签名成功或非 JSON 响应仍按不可验证处理。
|
|
482
|
+
|
|
483
|
+
- [微信 API 签名加密指南](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html)
|
|
484
|
+
- [新增永久素材](https://developers.weixin.qq.com/doc/service/api/material/permanent/api_addmaterial)
|
|
485
|
+
- [上传图文消息内图片](https://developers.weixin.qq.com/doc/service/api/material/permanent/api_uploadimg)
|
|
486
|
+
- [新增草稿](https://developers.weixin.qq.com/doc/service/api/draftbox/draftmanage/api_draft_add)
|
|
487
|
+
- [获取草稿](https://developers.weixin.qq.com/doc/service/api/draftbox/draftmanage/api_getdraft)
|
|
488
|
+
|
|
489
|
+
真实联调会写入目标公众号草稿箱,只能在用户明确授权、出口 IP 已列入白名单且安全配置完整时执行。它不发布、不群发,也不触发支付。
|
|
490
|
+
|
|
491
|
+
## 12. 当前未实现
|
|
492
|
+
|
|
493
|
+
当前仍不包含:
|
|
494
|
+
|
|
495
|
+
- 带 lease/heartbeat/退避的通用多租户 Mongo Job 和完整 P3;对象存储端口、内存/
|
|
496
|
+
本地/S3 适配器和首位用户 Mongo 原子领取已实现;
|
|
497
|
+
- 正文图片裁切/压缩、真实平台 `media/uploadimg` 验证和完整 P5;显式图片上传、URL
|
|
498
|
+
替换、兜底封面、本地/云端预览和确认已实现;
|
|
499
|
+
- 自动 reconciliation(核验补偿)、稳定微信错误码全集和完整 P6;首位用户通用封面/
|
|
500
|
+
草稿/回读已实现;
|
|
501
|
+
- 素材上传不确定结果的自动对账、审计 outbox(发件箱)投影和自动下载新平台证书;
|
|
502
|
+
- 系统凭据存储、团队身份、非微信登录方式和设备管理界面;
|
|
503
|
+
- SkillPay、微信支付、订单和权益;
|
|
504
|
+
- DxC 内置第三方图片生成服务;研究、Brief、大纲、正文、视觉生产和审校 Skills 已
|
|
505
|
+
实现,宿主生成图片仍要求用户授权对应数据传输;
|
|
506
|
+
- MCP、通用 Agent 框架或 Web 工作台;
|
|
507
|
+
- 容器化和通用生产部署自动化;现有 PM2/Nginx 配置只服务于受控验证切片。
|
|
508
|
+
|
|
509
|
+
当前代码达到首位用户的最小可用闭环;生产是否可用只由对应版本的部署后验证和真实
|
|
510
|
+
首位用户验收决定。它不代表完整 P3/P4/P5/P6 或商业 P7 已关闭,其余能力仍按
|
|
511
|
+
`docs/05-delivery-plan.md` 的验收闸门进入。
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# 阿里云 OSS 生产配置
|
|
2
|
+
|
|
3
|
+
核验日期:2026-07-27
|
|
4
|
+
|
|
5
|
+
DxC 生产使用独立的阿里云 OSS 私有 bucket,不复用其他产品的 bucket、RAM 用户或
|
|
6
|
+
AccessKey。`alivps` 和 `worker_vps` 位于华南 1(深圳),因此选择 `cn-shenzhen`
|
|
7
|
+
并使用内网 S3 兼容 endpoint。
|
|
8
|
+
|
|
9
|
+
## Bucket
|
|
10
|
+
|
|
11
|
+
控制台创建参数:
|
|
12
|
+
|
|
13
|
+
| 字段 | 值 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| 地域 | 华南 1(深圳) |
|
|
16
|
+
| 存储类型 | 标准存储 |
|
|
17
|
+
| 读写权限 | 私有 |
|
|
18
|
+
| 阻止公共访问 | 开启 |
|
|
19
|
+
| 服务端加密 | SSE-OSS / AES-256 |
|
|
20
|
+
| 版本控制 | 首版关闭 |
|
|
21
|
+
| CORS | 不配置 |
|
|
22
|
+
| 传输加速 | 关闭 |
|
|
23
|
+
|
|
24
|
+
bucket 名必须全局唯一,例如 `dxc-prod-content-<account-suffix>`。创建后不要把真实名称、
|
|
25
|
+
AccessKey 或 Secret 写入 Git、文档、聊天或日志。
|
|
26
|
+
|
|
27
|
+
## RAM 最小权限
|
|
28
|
+
|
|
29
|
+
创建 DxC 专用 RAM 用户,只把以下策略中的 `<DXC_BUCKET>` 替换为实际 bucket 名。应用
|
|
30
|
+
只访问 `dxc/` 前缀,不需要列举 bucket、修改 ACL、生命周期、加密或删除 bucket。
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"Version": "1",
|
|
35
|
+
"Statement": [
|
|
36
|
+
{
|
|
37
|
+
"Effect": "Allow",
|
|
38
|
+
"Action": [
|
|
39
|
+
"oss:GetObject",
|
|
40
|
+
"oss:PutObject",
|
|
41
|
+
"oss:DeleteObject"
|
|
42
|
+
],
|
|
43
|
+
"Resource": "acs:oss:*:*:<DXC_BUCKET>/dxc/*"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
创建 AccessKey 后,只写入本地 `.env.local` 和服务器 `0600` 环境文件。不要在聊天中
|
|
50
|
+
发送。
|
|
51
|
+
|
|
52
|
+
## DxC 环境
|
|
53
|
+
|
|
54
|
+
```dotenv
|
|
55
|
+
DXC_OBJECT_STORAGE_MODE=s3
|
|
56
|
+
DXC_OBJECT_STORAGE_ENDPOINT=https://s3.oss-cn-shenzhen-internal.aliyuncs.com
|
|
57
|
+
DXC_OBJECT_STORAGE_BUCKET=<DXC_BUCKET>
|
|
58
|
+
DXC_OBJECT_STORAGE_REGION=cn-shenzhen
|
|
59
|
+
DXC_OBJECT_STORAGE_ACCESS_KEY_ID=<DXC_RAM_ACCESS_KEY_ID>
|
|
60
|
+
DXC_OBJECT_STORAGE_SECRET_ACCESS_KEY=<DXC_RAM_ACCESS_KEY_SECRET>
|
|
61
|
+
DXC_OBJECT_STORAGE_PREFIX=dxc
|
|
62
|
+
DXC_OBJECT_STORAGE_FORCE_PATH_STYLE=false
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
OSS 的 S3 兼容接口只支持虚拟主机风格,因此必须设置
|
|
66
|
+
`DXC_OBJECT_STORAGE_FORCE_PATH_STYLE=false`。DxC 还把 AWS SDK 的请求/响应 checksum
|
|
67
|
+
(校验和)模式固定为 `WHEN_REQUIRED`,避免生成 OSS 不支持的默认分块编码。
|
|
68
|
+
|
|
69
|
+
## 发布验证
|
|
70
|
+
|
|
71
|
+
部署前用与生产相同的构建产物和环境分别从 Server、Worker 执行:
|
|
72
|
+
|
|
73
|
+
1. 上传随机、无敏感内容的探针对象;
|
|
74
|
+
2. `HeadObject` 验证大小和类型;
|
|
75
|
+
3. `GetObject` 验证字节一致;
|
|
76
|
+
4. 删除对象;
|
|
77
|
+
5. 再次 `HeadObject` 确认不存在。
|
|
78
|
+
|
|
79
|
+
探针必须位于 `dxc/health/`,执行后清理。浏览器上传和预览都经过 DxC Server,因此
|
|
80
|
+
bucket 不需要公共读、CORS 或公网预签名上传。
|
|
81
|
+
|
|
82
|
+
## 官方来源
|
|
83
|
+
|
|
84
|
+
- [OSS 与 Amazon S3 兼容性](https://help.aliyun.com/zh/oss/developer-reference/compatibility-with-amazon-s3)
|
|
85
|
+
- [使用 AWS SDK 访问 OSS](https://help.aliyun.com/en/oss/developer-reference/use-aws-sdks-to-access-oss)
|
|
86
|
+
- [RAM Policy 示例和最小权限](https://help.aliyun.com/en/oss/user-guide/ram-policy/)
|
|
87
|
+
- [Bucket ACL](https://help.aliyun.com/zh/oss/user-guide/oss-bucket-acl)
|
|
88
|
+
- [阻止公共访问](https://help.aliyun.com/zh/oss/user-guide/block-public-access)
|
|
89
|
+
- [Bucket 服务端加密](https://help.aliyun.com/zh/oss/developer-reference/bucket-encryption)
|