刘光辉
15 小时以前 34981c30a78e8bbd7791131059a9210f9928b62c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# docker-compose / start-all.sh 环境变量模板
#
# ══ 用法 ══
#
#   任何环境(开发本机/测试服务器/交付):cp .env.example .env,按下面的【场景】改值。
#   compose 自动读仓库根 .env;start-all.sh 启动时会加载全部 KEY=VALUE。.env 不入库。
#
#   切客户库 = 手改 .env 的 4 个键(§1 坐标 2 个 + §2/§3 密码 2 个)。改完必须重启
#   (Druid 池在启动时定死,配置不热改),并先跑 ./docker/preflight.sh 防连错库:
#       容器栈:docker compose up -d --force-recreate
#       宿主栈:./start-all.sh stop && ./start-all.sh
#
#   各客户 PG 实例坐标与真实密码总表:.env.tencent(gitignored,本文件不放任何真实
#   密码;同事需要连 CVM 时找 yangsui 单独拿对应客户段)。
#
# ══ 场景速查:数据库连哪 × 服务怎么跑,两维正交、自由组合 ══
#
#   ── 维度一:数据库坐标(只动 §1-§3 的 4 个键)────────────────────────────
#
#   | 数据库            | CUSTOMER_DB_HOST/PORT   | 两对 DB 密码(§2 §3)    |
#   |-------------------|-------------------------|--------------------------|
#   | 本机容器 PG(默认)| cx-postgres / 5432      | 默认值即可(出厂密码)    |
#   | 本机自装 PG       | 127.0.0.1 / 自装端口     | 自装库的真实密码          |
#
#   业务库 jnpf_init 与流程引擎库 jnpf_flow 都由这组坐标推导,必然同源(§3 红线)。
#
#   Redis 同样三档(§5 的 JNPF_REDIS_HOST/PORT/PASSWORD 三键,全不设 = 本机容器 cx-redis
#   零配置)。CVM 每客户一实例,端口 16431+N 与 PG 15431+N 尾数对齐:
#   客户A YOUR_DB_HOST:16432 | 客户B YOUR_DB_HOST:16433(密码在 .env.tencent 对应客户段)。
#   切 CVM 客户时 PG 4 键 + Redis 3 键一起改,对照 .env.tencent 整段抄。
#
#   ── 维度二:服务怎么跑 ──────────────────────────────────────────────────
#
#   | 跑法                       | 要求                                          |
#   |----------------------------|-----------------------------------------------|
#   | 全栈容器 docker compose up | .env 原样即用,无额外要求                      |
#   | 宿主 ./start-all.sh        | /etc/hosts 需下面 5 条 cx-*;cx-postgres 坐标 |
#   |(基础设施仍跑容器)         | 会自动翻译成宿主发布端口 127.0.0.1:5433        |
#
#   宿主跑法的 /etc/hosts(一次性,原理见 docs/docker-compose-guide.md §3):
#       127.0.0.1 cx-infra cx-redis cx-flow-engine
#
#   ── redis 想用宿主自装的(不跑 Redis 容器)──────────────────────────────
#   同时支持宿主 ./start-all.sh 和 Docker 业务容器时,按 §5 分别设置宿主/容器坐标:
#   宿主 JVM 用 127.0.0.1,容器用 cx-infra(compose 已映射到 host-gateway)。
#   requirepass 必须与 §5 的 JNPF_REDIS_PASSWORD 相同。
#   ⚠️ 流程引擎 cx-flow-engine 没有自装形态,任何跑法都要起它的容器。
#   (RocketMQ 已于 2026-08-10 移除,事件总线改走 Redis pub/sub,见补丁 #10)
#
#   ── 测试环境(192.168.21.151) 额外改 ─────────────────────────────────────
#   数据库 = CVM 客户A那档;域名四键必设 http://192.168.21.151(§7);
#   COMPOSE_FILE 用 testenv 组合(§9);其余键沿用默认(是服务器自己的本机栈)。
#
#   ── OnlyOffice 文档在线编辑 ─────────────────────────────────────────────
#   §6 一节,只有 ONLYOFFICE_JWT_SECRET 必填(缺了 compose 直接报错起不来),
#   其余 10 个键都有默认值 = 本机 compose 形态。交付环境务必换掉这个 secret:
#   回调端点匿名可达,它是唯一的安全边界。
 
 
# ════════════════════════════════════════════════════════════════════════════
# 1. 客户坐标(唯一开关:业务库 jnpf_init 与引擎库 jnpf_flow 都由它推导,必然同源)
# ════════════════════════════════════════════════════════════════════════════
# 本机 = compose 栈内的 cx-postgres。宿主 java -jar(start-all.sh)会自动把
# cx-postgres:5432 翻译成 127.0.0.1:5433(宿主发布端口),无需另配。
# 测试/CVM:改成 YOUR_DB_HOST / 15432(客户A);客户2 客户B 15433;客户N 15431+N。
CUSTOMER_DB_HOST=cx-postgres
CUSTOMER_DB_PORT=5432
 
# 栈内 PG 开关,必须与上面这对坐标配套(cx-postgres 收在 localdb profile 内,默认不启动):
#   CUSTOMER_DB_HOST=cx-postgres      → 保留本行,compose 才会起 cx-postgres 容器
#   CUSTOMER_DB_HOST=YOUR_DB_HOST  → 注释掉本行,本机不起 PG(起了也没人连,纯占内存,
#                                        还会因 external 卷 postgres_pgdata 不存在把整栈拦下)
# 两者不配套时 preflight 会直接报错,不会让你带着错配起栈。
COMPOSE_PROFILES=localdb
 
 
# ════════════════════════════════════════════════════════════════════════════
# 2. 业务库凭据(须与目标 PG 实例的真实角色密码一致)
# ════════════════════════════════════════════════════════════════════════════
# 默认值 = 本机容器 PG 出厂密码(install.sh 建库时写入),本机场景不用改。
# 切 CVM 时必须换成 .env.tencent 对应客户段的真实密码(沿用默认会认证失败)。
JNPF_APP_DB_USER=jnpf_app
JNPF_APP_DB_PASSWORD=jnpf_app_2026
 
 
# ════════════════════════════════════════════════════════════════════════════
# 3. 流程引擎库凭据
# ════════════════════════════════════════════════════════════════════════════
# 地址由 §1 客户坐标自动推导,与业务库结构性同源。
# 🔴 绝对不要设 JNPF_FLOW_DB_URL 来指引擎库!它是整串覆盖的逃生口,会把引擎库与
#    业务库拆成两个来源(半切)——2026-08-03 事故:49 个流程模板 44 个报「找不到流程
#    模板」。见 docs/adr-multi-customer-db-isolation.md §4。
JNPF_FLOW_DB_USER=jnpf_flow_app
JNPF_FLOW_DB_PASSWORD=jnpf_flow_app_2026
#JNPF_FLOW_DB_URL=jdbc:postgresql://YOUR_DB_HOST:15432/jnpf_flow
 
 
# ════════════════════════════════════════════════════════════════════════════
# 4. 本机栈私有(跟「连哪个客户」无关,是这台机器自己容器栈的设置)
# ════════════════════════════════════════════════════════════════════════════
# 两角色的 PG 连接数配额(供 create-app-roles.sh;防单角色占满连接槽饿死流程引擎,L029)。
# 多客户实例(max_conn=150):120/20;客户1老实例(400):350/35;交付单环境(200):150/30。
# 铁律:两者之和 < max_connections − 3。未设时脚本内置默认 150/30。
JNPF_APP_CONN_LIMIT=120
JNPF_FLOW_CONN_LIMIT=20
# PG 超级用户密码(仅运维用;只在 initdb 全新数据卷时写入,既有卷改密须 ALTER USER)
JNPF_PG_PASSWORD=jnpf_pg_2026
 
 
# ════════════════════════════════════════════════════════════════════════════
# 5. Redis
# ════════════════════════════════════════════════════════════════════════════
# cx-redis 的 requirepass;业务侧经 compose / start-all 透传(datasource.yaml 占位符),
# 改这里即全局轮换。
JNPF_REDIS_PASSWORD=jnpf_redis_2026
# Redis 坐标(datasource.yaml 占位符;与 PG 的 CUSTOMER_DB_HOST/PORT 同构)。
# 不设 = 本机/交付形态(栈内 cx-redis:6379)。指 CVM 共享实例时解开并按客户改:
# 客户A 16432 / 客户B 16433(端口 16431+N),密码同时换成 .env.tencent 对应客户段的值。
#JNPF_REDIS_HOST=YOUR_DB_HOST
#JNPF_REDIS_PORT=16432
# 宿主自装 Redis、且业务可能在宿主和 Docker 两种形态运行时使用下面四行:
# JNPF_REDIS_HOST/PORT 供 ./start-all.sh;JNPF_DOCKER_REDIS_HOST/PORT 仅由 compose 注入容器。
#JNPF_REDIS_HOST=127.0.0.1
#JNPF_REDIS_PORT=6379
#JNPF_DOCKER_REDIS_HOST=cx-infra
#JNPF_DOCKER_REDIS_PORT=6379
 
 
# ════════════════════════════════════════════════════════════════════════════
# 6. OnlyOffice Document Server(Office 文档在线预览/编辑)
# ════════════════════════════════════════════════════════════════════════════
# 消费方两侧:cx-onlyoffice 容器(DS 本体)+ cx-biz-common 的 onlyoffice 能力模块
# (经 config/shared/jnpf-biz-common.yaml 的占位符)。方案见 tasks/onlyoffice-integration-plan.md。
# 本节只有 JWT_SECRET 必填,其余全部有默认值 = 本机 compose 形态,cp 即用。
 
# ── 必填:DS 与后端之间的唯一信任凭据 ──
# 两侧必须同值:
#   - cx-onlyoffice 容器:作为 JWT_SECRET 环境变量注入(docker-compose.yml)
#   - cx-biz-common:经 config/shared/jnpf-biz-common.yaml 的 onlyoffice.jwt-secret 占位符消费
# 后端用它签发编辑器 config,DS 用它签发保存回调;不一致的表现是编辑器一直转圈
# 或回调静默失败,且两侧日志都不明显——改这里即全局轮换,改完两个容器都要重启。
# 🔴 回调路径 /api/biz/onlyoffice/callback 已进网关白名单(平台补丁 #9),该端点
#    匿名可达,这个 secret 是它唯一的安全边界,交付环境务必换成随机值。
ONLYOFFICE_JWT_SECRET=onlyoffice_jwt_2026
 
# ── 四个地址键:每个都是**某一方的视角**,别混着填 ──
# 容器栈(docker compose):四个全不设即可,默认值就是本机形态。
# 宿主栈(./start-all.sh):脚本已自动 export 下面 3 个 host.docker.internal 形态的值
#   (DS 在容器里、网关和后端在宿主上),一般不用在 .env 里设;显式设了则以 .env 为准。
#
#   键                          | 视角     | 容器栈默认            | 宿主栈(start-all.sh 自动值)
#   ----------------------------|---------|----------------------|------------------------------
#   ONLYOFFICE_DS_PUBLIC_URL    | 浏览器   | http://localhost:20000 | 同左(override 发布的端口)
#   ONLYOFFICE_FILE_FETCH_BASE_URL | DS   | http://cx-gateway:30000 | http://host.docker.internal:30000
#   ONLYOFFICE_CALLBACK_BASE_URL   | DS   | http://cx-gateway:30000 | http://host.docker.internal:30000
#   ONLYOFFICE_DS_INTERNAL_URL     | 后端 | http://cx-onlyoffice    | http://localhost:20000
#
# 浏览器视角:加载编辑器 api.js 的地址。容器名浏览器解析不了,本机走 override 发布的 20000。
# 交付环境改为 Nginx 反代的 https://<域名>/onlyoffice(方案 §8.4,与 §7 域名四键配套改)。
#ONLYOFFICE_DS_PUBLIC_URL=http://localhost:20000
# DS 视角:DS 回源拉原始文档。/api/file/Image/** 在网关白名单内,DS 无登录态靠 securityKey 取件。
#ONLYOFFICE_FILE_FETCH_BASE_URL=http://cx-gateway:30000
# DS 视角:DS 保存回调。必须经网关——直连 30015 按 L042 会被 inner-auth 拒。
#ONLYOFFICE_CALLBACK_BASE_URL=http://cx-gateway:30000
# 后端视角:后端反向拉取 DS 产物。回调里 DS 给的 url 是它自己视角的主机名,后端不一定直连得到,
# 配了本项就只保留其 path+query 换到这个主机上;留空则原样使用 DS 给的 url。
#ONLYOFFICE_DS_INTERNAL_URL=http://cx-onlyoffice
 
# ── 编辑行为开关 ──
# 编辑锁的心跳超时(分钟)。锁正常由 status 2/4 回调释放,本项是浏览器崩溃等异常场景的
# 兜底,否则文档会永久锁死。
#ONLYOFFICE_LOCK_TIMEOUT_MINUTES=30
# 编辑器里是否给下载/打印入口,默认全关。
# ⚠️ 只收界面入口,**不是安全边界**:知道 URL 的人照样能经 /api/file/Image/** 把原文件拉走。
#ONLYOFFICE_ALLOW_DOWNLOAD=false
#ONLYOFFICE_ALLOW_PRINT=false
# 未登记 bizModule 时是否一律只读。默认 false(放行编辑 + 一条 warn),兼容不传 bizModule 的
# 既有调用方。🔴 该登记的都登记完之后应当置 true——否则「漏登记」的表现是悄悄放行编辑,
# 而不是能被人发现的报错。登记表在 config/shared/jnpf-biz-common.yaml 的 edit-permission.modules。
#ONLYOFFICE_EDIT_PERMISSION_STRICT=false
 
# ── ELN 模板标注插件 ──
# 公网基础地址(浏览器视角,DS 从这里加载插件资源)+ 发布版本(对应不可变发布目录)。
#ONLYOFFICE_PLUGIN_PUBLIC_BASE_URL=http://localhost:4173/onlyoffice-plugins
#ONLYOFFICE_PLUGIN_RELEASE=0.1.0-dev
 
 
# ════════════════════════════════════════════════════════════════════════════
# 7. 域名四键(L023 双消费方:须浏览器可达且容器内可达)
# ════════════════════════════════════════════════════════════════════════════
# 本机不设(config/shared/system-config.yaml 内置默认即本机形态)。
# 测试环境必设为服务器实际地址,例如:
#JNPF_API_DOMAIN=http://192.168.21.151
#JNPF_APP_DOMAIN=http://192.168.21.151/
#JNPF_FLOW_DOMAIN=http://cx-flow-engine:31000
#JNPF_FRONT_DOMAIN=http://192.168.21.151/
 
 
# ════════════════════════════════════════════════════════════════════════════
# 8. 文件存储与日志落盘
# ════════════════════════════════════════════════════════════════════════════
# ── 业务文件(附件/图片/导出件)──
# 宿主侧文件根目录(compose 挂载用);Mac 默认 /Users/Shared,可不设。
# 业务进程读的是 JNPF_FILE_DIR(resources.yaml);容器内固定 /data/jnpf-files/。
# Win/Linux 按各自习惯改,例如 JNPF_DATA_DIR=D:/jnpf-data 或 /data/jnpf。
#JNPF_DATA_DIR=/Users/Shared
#JNPF_FILE_DIR=/Users/Shared/
 
# ── DMS SeaweedFS(S3 兼容接口,独立于现有 MinIO 配置)──
# 只有 DMS 专用上传接口会显式选择 seaweedfs-1,不会改变 default-platform。
#SEAWEEDFS_ENABLED=false
#SEAWEEDFS_ACCESS_KEY=change-me
#SEAWEEDFS_SECRET_KEY=change-me
#SEAWEEDFS_ENDPOINT=http://127.0.0.1:8333/
#SEAWEEDFS_BUCKET_NAME=jnpf-dms
#SEAWEEDFS_BASE_PATH=dms/
 
# ── 应用日志(2026-08-11 起已 bind mount 出容器)──
# 🔴 两个变量别搞混,后缀 _HOST 的才是你要改的那个:
#
#   变量                | 在哪一侧   | 值            | 谁消费
#   --------------------|-----------|---------------|--------------------------------
#   JNPF_LOG_DIR_HOST   | 宿主机 ★  | 默认 ./logs   | docker-compose.yml 的 volumes 源
#   JNPF_LOG_DIR        | 容器内    | /data/jnpf-logs | logger.yaml 的 log.path(compose 已固定,不用改)
#
#   docker-compose.yml 里那行挂载长这样:
#       - ${JNPF_LOG_DIR_HOST:-./logs}:/data/jnpf-logs
#         └── 宿主机目录 ────────────┘ └─ 容器内目录 ─┘
#
# 各服务自动写 <宿主目录>/<服务名>/log_{error,warn,info,debug,total}.log,
# 直接 tail -f logs/jnpf-lims/log_error.log 即可,容器重建/删除都不丢。
# 按天+按大小双维度滚动(logback SizeAndTimeBasedRollingPolicy:跨天或满 10MB 即切,
# 归档进 <服务名>/{error,warn,info,total}/YYYY-MM-DD/ 子目录,保留 7 天),归档同样在宿主上。
#
# 交付/测试环境建议指到数据盘,别让日志堆在部署目录里(下面是**宿主机**路径):
#JNPF_LOG_DIR_HOST=/var/log/jnpf
# ⚠️ Linux 上该目录由容器内 root 创建,非 root 用户读日志需要 sudo。
 
 
# ════════════════════════════════════════════════════════════════════════════
# 9. Compose / 构建
# ════════════════════════════════════════════════════════════════════════════
# 全栈统一产品版本:自建镜像 tag 随此值走,发版=改这一个值;未设默认 1.0.0
#CX_VERSION=1.0.0
# 测试环境(基线 + testenv;Windows 分隔符默认分号):
#COMPOSE_FILE=docker-compose.yml;docker-compose.testenv.yml
# 交付/生产(只用基线,排除 override 的本地调试端口发布):
#COMPOSE_FILE=docker-compose.yml
# 访问不了 Docker Hub 时解开,SWR 国内源(开发机同样适用,2026-08-10 换机实证:
# 不解开则 cx-web 构建报 auth.docker.io i/o timeout,业务镜像的 JRE 基底同理):
#BASE_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/bellsoft/liberica-openjre-rocky:21
# nginx 基底两种写法二选一:
#   ① 短名(推荐,同 cx-redis 待遇)——由 make pull-infra 从 SWR retag,
#      必须经 make images/pull-infra,否则 docker 会去 docker.io 找不存在的 library/cx-nginx
#NGINX_BASE_IMAGE=cx-nginx:1.27-alpine
#   ② SWR 长名(不依赖 retag,任何 docker compose build 都能用)
#NGINX_BASE_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27-alpine