@gadmin2n/schematics 0.0.87 → 0.0.89

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.
Files changed (99) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/.dockerignore +16 -2
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.codegen +40 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.server +76 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.web +53 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/Jenkinsfile +219 -33
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/compose-ctl.sh +250 -0
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +4 -1
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/dev/postgres/init.sql +12 -0
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.md +170 -0
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.yml +254 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +8 -7
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/lib/page-helpers.ts +1 -1
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/prismaModels.ts +1 -1
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/agenda.seed.ts +39 -0
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/audit.seed.ts +40 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/bootstrap.ts +56 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/canvas.seed.ts +39 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/{scripts/sync-data-mngt-pages.ts → seed/data-mngt.seed.ts} +36 -20
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/game.seed.ts +44 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +30 -6
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permission.seed.ts +130 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-event-trigger.ts +60 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +11 -25
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +108 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/main.ts +1 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.controller.spec.ts +31 -2
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.spec.ts +31 -2
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.service.spec.ts +41 -57
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.spec.ts +31 -2
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.service.spec.ts +309 -1
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.spec.ts +31 -2
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.service.spec.ts +315 -1
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.spec.ts +31 -2
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.service.spec.ts +312 -2
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.spec.ts +31 -2
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.service.spec.ts +317 -1
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.spec.ts +31 -2
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.service.spec.ts +309 -1
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.spec.ts +31 -2
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.service.spec.ts +299 -1
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.spec.ts +31 -2
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.service.spec.ts +307 -1
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.spec.ts +31 -2
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.spec.ts +309 -1
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +205 -0
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.ts +116 -0
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.spec.ts +158 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +110 -1
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/webhook-signature.util.spec.ts +79 -0
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/webhook-signature.util.ts +54 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +34 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +457 -0
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +241 -4
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +34 -2
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +24 -30
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.spec.ts +34 -2
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +36 -36
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.spec.ts +34 -2
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.service.spec.ts +48 -24
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/README.md +312 -3
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/TODO.md +152 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/.dockerignore +12 -0
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/Dockerfile +79 -0
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/GRACEFUL-DEPLOYMENT.md +270 -0
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/index.ts +1 -1
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/reporting.ts +23 -0
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/index.ts +70 -5
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/outbox-poller.ts +246 -90
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/cron-trigger-workflow.test.ts +20 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/workflows/dsl-workflow.ts +96 -8
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/web/nginx.conf +74 -0
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/ElementInspector.tsx +18 -0
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/promptGenerator.ts +1 -1
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/form.tsx +1 -1
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +3 -3
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +3 -3
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +4 -1
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasEditPage.tsx +9 -0
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +156 -139
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasPage.tsx +14 -2
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasToolbar.tsx +62 -0
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/PublishModal.tsx +4 -6
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasApi.ts +18 -27
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasDefaults.ts +32 -11
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/demos.ts +48 -61
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas-page/index.tsx +3 -6
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +16 -16
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +28 -35
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +34 -3
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +1 -1
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +1 -1
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd.css +6 -0
  93. package/package.json +1 -1
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile +0 -63
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/sync-resources.ts +0 -100
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permissions.ts +0 -302
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.spec.ts +0 -20
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/sql/create-event-trigger.sql +0 -87
  99. /package/dist/lib/application/files/gadmin2-game-angle-demo/{GRACEFUL-DEPLOYMENT.md → server/GRACEFUL-DEPLOYMENT.md} +0 -0
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env bash
2
+ # compose-ctl.sh — gadmin 本地全栈 docker-compose 控制脚本
3
+ #
4
+ # 用法见 `./compose-ctl.sh -h`
5
+
6
+ set -euo pipefail
7
+ cd "$(dirname "$0")"
8
+
9
+ # ─── 项目命名(pod / 镜像 prefix 都用这个) ─────────────────────
10
+ # PROJECT_NAME 默认取项目目录的 basename,例如本项目为 "gadmin-test"。
11
+ # - 镜像: <PROJECT_NAME>-{codegen,web,nest-server,temporal-worker}:local
12
+ # - pod : <PROJECT_NAME>-pod (仅 podman-compose 有 pod 概念)
13
+ # 通过 export COMPOSE_PROJECT_NAME 让 docker-compose.yml 中的
14
+ # ${COMPOSE_PROJECT_NAME} 变量插值到正确的值。
15
+ PROJECT_NAME="$(basename "$(pwd)")"
16
+ export COMPOSE_PROJECT_NAME="$PROJECT_NAME"
17
+ POD_NAME="${PROJECT_NAME}-pod"
18
+ CODEGEN_IMAGE="${PROJECT_NAME}-codegen:local"
19
+
20
+ # ─── 最低推荐版本(低于会打 warning 但仍尝试执行) ──────────────
21
+ MIN_DOCKER="20.10"
22
+ MIN_DOCKER_COMPOSE_V2="2.0.0"
23
+ MIN_DOCKER_COMPOSE_V1="1.29.0"
24
+ MIN_PODMAN="4.0.0"
25
+ MIN_PODMAN_COMPOSE="1.0.7"
26
+
27
+ # 从命令输出中抽取第一个 X.Y(.Z) 形式的版本号
28
+ extract_semver() {
29
+ printf '%s' "$1" | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -n1
30
+ }
31
+
32
+ # version_lt "1.0.6" "1.0.7" → 0 (true) 当 $1 < $2
33
+ version_lt() {
34
+ [ "$1" = "$2" ] && return 1
35
+ [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]
36
+ }
37
+
38
+ warn_if_old() {
39
+ local name="$1" actual="$2" minimum="$3"
40
+ if [ -z "$actual" ]; then
41
+ echo "[compose-ctl] WARN: 无法检测 $name 版本(最低推荐 $minimum)" >&2
42
+ return
43
+ fi
44
+ if version_lt "$actual" "$minimum"; then
45
+ echo "[compose-ctl] WARN: $name $actual < 最低推荐 $minimum" >&2
46
+ echo "[compose-ctl] 可能症状:profiles 不生效 / service_completed_successfully 被忽略 /" >&2
47
+ echo "[compose-ctl] depends_on 顺序错乱 / 多阶段构建失败。建议升级。" >&2
48
+ fi
49
+ }
50
+
51
+ # ─── 运行时探测 ─────────────────────────────────────────────────
52
+ # shell alias (alias docker=podman) 不会传到 bash 脚本里,所以这里要自己找。
53
+ # DOCKER_CLI / COMPOSE_CLI 用数组以支持 "docker compose" 这种带空格的命令。
54
+ DOCKER_CLI=()
55
+ COMPOSE_CLI=()
56
+ DOCKER_VER=""
57
+ COMPOSE_VER=""
58
+ COMPOSE_KIND="" # 用于挑选最低推荐版本
59
+
60
+ detect_runtime() {
61
+ if command -v docker >/dev/null 2>&1; then
62
+ DOCKER_CLI=(docker)
63
+ DOCKER_VER=$(extract_semver "$(docker --version 2>/dev/null)")
64
+ if docker compose version >/dev/null 2>&1; then
65
+ COMPOSE_CLI=(docker compose)
66
+ COMPOSE_VER=$(extract_semver "$(docker compose version 2>/dev/null)")
67
+ COMPOSE_KIND="docker-compose-v2"
68
+ elif command -v docker-compose >/dev/null 2>&1; then
69
+ COMPOSE_CLI=(docker-compose)
70
+ COMPOSE_VER=$(extract_semver "$(docker-compose --version 2>/dev/null)")
71
+ # v2 standalone 的版本号也是 2.x,v1 是 1.x
72
+ case "$COMPOSE_VER" in
73
+ 2.*) COMPOSE_KIND="docker-compose-v2" ;;
74
+ *) COMPOSE_KIND="docker-compose-v1" ;;
75
+ esac
76
+ fi
77
+ elif command -v podman >/dev/null 2>&1; then
78
+ DOCKER_CLI=(podman)
79
+ DOCKER_VER=$(extract_semver "$(podman --version 2>/dev/null)")
80
+ if command -v podman-compose >/dev/null 2>&1; then
81
+ COMPOSE_CLI=(podman-compose)
82
+ COMPOSE_VER=$(extract_semver "$(podman-compose --version 2>/dev/null | head -n1)")
83
+ COMPOSE_KIND="podman-compose"
84
+ elif command -v docker-compose >/dev/null 2>&1; then
85
+ COMPOSE_CLI=(docker-compose)
86
+ COMPOSE_VER=$(extract_semver "$(docker-compose --version 2>/dev/null)")
87
+ case "$COMPOSE_VER" in
88
+ 2.*) COMPOSE_KIND="docker-compose-v2" ;;
89
+ *) COMPOSE_KIND="docker-compose-v1" ;;
90
+ esac
91
+ fi
92
+ fi
93
+
94
+ if [ ${#DOCKER_CLI[@]} -eq 0 ]; then
95
+ echo "ERROR: 未找到 docker 或 podman" >&2
96
+ echo "提示:alias docker=podman 不会传到 bash 脚本,需要真实安装 docker 或 podman 二进制" >&2
97
+ exit 127
98
+ fi
99
+ if [ ${#COMPOSE_CLI[@]} -eq 0 ]; then
100
+ echo "ERROR: 找到了 ${DOCKER_CLI[*]} 但没找到 compose 命令" >&2
101
+ echo "提示:装 docker-compose 或 podman-compose" >&2
102
+ exit 127
103
+ fi
104
+
105
+ echo "[compose-ctl] runtime: ${DOCKER_CLI[*]} ${DOCKER_VER:-?} | compose: ${COMPOSE_CLI[*]} ${COMPOSE_VER:-?}"
106
+
107
+ # podman-compose 1.0.7+ 支持 --in-pod=NAME,让所有服务跑在同一个自定义命名 pod 里。
108
+ # docker-compose 没有 pod 概念,跳过。
109
+ COMPOSE_GLOBAL_ARGS=()
110
+ if [ "$COMPOSE_KIND" = "podman-compose" ]; then
111
+ COMPOSE_GLOBAL_ARGS+=(--in-pod="$POD_NAME")
112
+ fi
113
+
114
+ # 版本检查(只 warn 不 fail)
115
+ case "${DOCKER_CLI[0]}" in
116
+ docker) warn_if_old "docker" "$DOCKER_VER" "$MIN_DOCKER" ;;
117
+ podman) warn_if_old "podman" "$DOCKER_VER" "$MIN_PODMAN" ;;
118
+ esac
119
+ case "$COMPOSE_KIND" in
120
+ docker-compose-v2) warn_if_old "docker compose" "$COMPOSE_VER" "$MIN_DOCKER_COMPOSE_V2" ;;
121
+ docker-compose-v1) warn_if_old "docker-compose" "$COMPOSE_VER" "$MIN_DOCKER_COMPOSE_V1" ;;
122
+ podman-compose) warn_if_old "podman-compose" "$COMPOSE_VER" "$MIN_PODMAN_COMPOSE" ;;
123
+ esac
124
+ }
125
+
126
+ print_help() {
127
+ cat <<'EOF'
128
+ compose-ctl.sh — gadmin-test 本地全栈 docker-compose 控制脚本
129
+
130
+ 用法:
131
+ ./compose-ctl.sh [up] 起服务(默认)。codegen 镜像不存在才构建,否则跳过。
132
+ ./compose-ctl.sh --rebuild 强制重建 codegen 后起服务。
133
+ config/ui/** 或 config/prisma/** 改动后用。
134
+ ./compose-ctl.sh --reset 清数据卷 + 重建 codegen + 起服务(核武器)。
135
+ 业务数据、temporal 历史全部清空,回到种子数据状态。
136
+ ./compose-ctl.sh --down 停服务(保留数据)。
137
+ ./compose-ctl.sh -h, --help 显示本帮助。
138
+
139
+ 运行时:
140
+ 脚本会自动探测 docker / podman,自动选择 compose 命令。
141
+ 优先级: docker compose > docker-compose > podman-compose
142
+
143
+ 最低推荐版本(低于会打 warning,不阻断执行):
144
+ docker >= 20.10
145
+ docker compose v2 >= 2.0 (插件形式 / 独立 v2 二进制)
146
+ docker-compose v1 >= 1.29 (legacy)
147
+ podman >= 4.0
148
+ podman-compose >= 1.0.7
149
+
150
+ 示例:
151
+ 首次拉代码后: ./compose-ctl.sh
152
+ 改了 prisma: ./compose-ctl.sh --rebuild
153
+ 数据库脏了: ./compose-ctl.sh --reset
154
+ 下班关掉: ./compose-ctl.sh --down
155
+ EOF
156
+ }
157
+
158
+ print_post_up_guide() {
159
+ cat <<'EOF'
160
+
161
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
162
+ 服务已启动 ✓ 首次启动需等 30~60s 让 temporal-server 完成 schema 初始化
163
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
164
+
165
+ 访问入口:
166
+ Web 前端 http://localhost:3000
167
+ Server API http://localhost:8000 (健康检查 /health/live)
168
+ Temporal Web UI http://localhost:8080
169
+ Temporal gRPC localhost:7233 (worker / @temporalio/client)
170
+ PostgreSQL localhost:5432 (用户 kavenma / 密码 kavenma)
171
+
172
+ 库划分 (PG 内):
173
+ gadmin_demo 业务库 (server + worker, Prisma 管理)
174
+ temporal Temporal 元数据库
175
+ temporal_visibility Temporal Visibility 库 (PG-only)
176
+
177
+ 常用命令:
178
+ 查看所有服务状态 docker compose ps
179
+ 跟某个服务日志 docker compose logs -f <service>
180
+ (service: postgres / temporal-server / temporal-ui /
181
+ temporal-worker / server / server-init / web)
182
+ 跟全部日志 docker compose logs -f
183
+ 重启某服务 docker compose restart <service>
184
+ 进容器排查 docker compose exec <service> sh
185
+
186
+ 停止 / 重置:
187
+ 停服务 (保留数据) ./compose-ctl.sh --down
188
+ config 改了重建 ./compose-ctl.sh --rebuild
189
+ 清空数据回到种子状态 ./compose-ctl.sh --reset
190
+
191
+ 提示:
192
+ · 前端开发请用 cd web && yarn dev (本 compose 的 web 是 nginx 静态镜像,无热更新)
193
+ · server-init 是一次性容器,跑完 push:db + seed 后退出 (Exited 0) 是正常的
194
+ EOF
195
+ }
196
+
197
+ build_codegen() {
198
+ echo "[compose-ctl] building codegen image ($CODEGEN_IMAGE) ..."
199
+ "${COMPOSE_CLI[@]}" "${COMPOSE_GLOBAL_ARGS[@]}" --profile codegen build codegen
200
+ }
201
+
202
+ up_services() {
203
+ echo "[compose-ctl] starting services (project=$PROJECT_NAME, pod=$POD_NAME) ..."
204
+ "${COMPOSE_CLI[@]}" "${COMPOSE_GLOBAL_ARGS[@]}" up -d --build
205
+ print_post_up_guide
206
+ }
207
+
208
+ # ─── main ──────────────────────────────────────────────────────
209
+ # 帮助命令不需要运行时,先处理
210
+ case "${1:-up}" in
211
+ -h|--help)
212
+ print_help
213
+ exit 0
214
+ ;;
215
+ esac
216
+
217
+ detect_runtime
218
+
219
+ case "${1:-up}" in
220
+ up)
221
+ if "${DOCKER_CLI[@]}" image inspect "$CODEGEN_IMAGE" >/dev/null 2>&1; then
222
+ echo "[compose-ctl] codegen image exists, skip build (use --rebuild to force)"
223
+ else
224
+ build_codegen
225
+ fi
226
+ up_services
227
+ ;;
228
+ --rebuild|-r)
229
+ build_codegen
230
+ # podman-compose 1.x 不会因镜像 ID 变化自动重建容器(docker-compose v2 会)。
231
+ # --rebuild 既然是为"改了配置/Dockerfile/代码"准备的,强制 recreate 才能让新镜像生效。
232
+ echo "[compose-ctl] (rebuild) force-recreating containers ..."
233
+ "${COMPOSE_CLI[@]}" "${COMPOSE_GLOBAL_ARGS[@]}" up -d --build --force-recreate
234
+ print_post_up_guide
235
+ ;;
236
+ --reset)
237
+ "${COMPOSE_CLI[@]}" "${COMPOSE_GLOBAL_ARGS[@]}" down -v
238
+ build_codegen
239
+ up_services
240
+ ;;
241
+ --down)
242
+ "${COMPOSE_CLI[@]}" "${COMPOSE_GLOBAL_ARGS[@]}" down
243
+ ;;
244
+ *)
245
+ echo "unknown option: $1" >&2
246
+ echo "" >&2
247
+ print_help >&2
248
+ exit 1
249
+ ;;
250
+ esac
@@ -76,6 +76,7 @@ model WorkflowInstance {
76
76
  context Json?
77
77
  result Json?
78
78
  temporalRunId String? @db.VarChar(128) @map("temporal_run_id") // Temporal workflow run ID
79
+ sourceOutboxId BigInt? @map("source_outbox_id") // 触发本实例的 outbox 行 id;与 workflowId 组合后唯一,用于 outbox-poller 的幂等 upsert,避免崩溃恢复时产生重复 instance 行
79
80
  startedAt DateTime? @map("started_at")
80
81
  finishedAt DateTime? @map("finished_at")
81
82
  creator String @default("") @db.VarChar(128) @map("creator")
@@ -85,6 +86,7 @@ model WorkflowInstance {
85
86
  workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
86
87
  nodeExecutions WorkflowNodeExecution[]
87
88
 
89
+ @@unique([workflowId, sourceOutboxId], map: "uk_wi_workflow_outbox") // 一个 outbox 事件对一个 workflow 至多一条 instance(NULL 不参与唯一性,正常 execute / cron / webhook 不受影响)
88
90
  @@index([workflowId], map: "idx_wi_workflow_id")
89
91
  @@index([status], map: "idx_wi_status")
90
92
  @@map("t_workflow_instance")
@@ -166,6 +168,7 @@ model WorkflowEventOutbox {
166
168
  retryCount Int @default(0) @map("retry_count") // 处理失败重试次数
167
169
  lastError String? @db.Text @map("last_error") // 最近一次失败的错误信息
168
170
 
169
- @@index([createdAt], map: "idx_outbox_created_at")
171
+ // 注意:未处理事件的部分索引 idx_outbox_unprocessed 由 seed/workflow-event-trigger.ts 维护
172
+ // (Prisma schema 不支持 WHERE 子句的 partial index)
170
173
  @@map("t_workflow_event_outbox")
171
174
  }
@@ -0,0 +1,12 @@
1
+ -- Bootstrap databases on first postgres container start.
2
+ -- Runs once: only when the named volume `pgdata` is empty.
3
+ -- Reset with `docker compose down -v` to re-run.
4
+ --
5
+ -- Three databases created here:
6
+ -- gadmin_demo -> server + worker business data (Prisma)
7
+ -- temporal -> Temporal Server default schema (auto-setup populates tables)
8
+ -- temporal_visibility -> Temporal Server visibility schema (PG-only, no ES locally)
9
+
10
+ CREATE DATABASE gadmin_demo;
11
+ CREATE DATABASE temporal;
12
+ CREATE DATABASE temporal_visibility;
@@ -0,0 +1,170 @@
1
+ # 本地联调环境(docker-compose)
2
+
3
+ 一行命令起一整套服务用于本地集成验证:PostgreSQL + Temporal Server + Temporal Web UI + NestJS Server + Temporal Worker + Web 前端。
4
+
5
+ > 生产部署走 K8s(参考 `docs/temporal-server-argocd.md`)。本环境**只**用于本地联调与端到端集成验证。
6
+
7
+ ## 启动 / 停止
8
+
9
+ **推荐:用 `./compose-ctl.sh` 一键起,不用记 codegen 那一步。**
10
+
11
+ ```bash
12
+ # 起所有服务(codegen 镜像不存在才构建,否则跳过)
13
+ ./compose-ctl.sh
14
+
15
+ # 改了 config/ui/** 或 config/prisma/** 后,强制重建 codegen
16
+ ./compose-ctl.sh --rebuild
17
+
18
+ # 完全重置:清数据卷 + 重建 codegen + 起服务(首启会重新初始化 schema/seed)
19
+ ./compose-ctl.sh --reset
20
+
21
+ # 停服务(保留数据)
22
+ ./compose-ctl.sh --down
23
+ ```
24
+
25
+ 如果想用原生 `docker compose` 命令(脚本就是这两步的封装):
26
+
27
+ ```bash
28
+ # 起所有服务(后台)
29
+ docker compose up -d
30
+
31
+ # 跟日志(按 Ctrl+C 退出,服务继续运行)
32
+ docker compose logs -f
33
+
34
+ # 停服务(保留数据)
35
+ docker compose down
36
+
37
+ # 完全重置(连数据卷一起删,下次首启会重新初始化 schema)
38
+ docker compose down -v
39
+
40
+ # 重建某个镜像(改了 Dockerfile / 源码后)
41
+ docker compose build server
42
+ docker compose up -d server
43
+
44
+ # 改了 config/ui/** 或 config/prisma/** 后,必须先 rebuild codegen 中间镜像
45
+ docker compose --profile codegen build codegen
46
+ docker compose build server web # 让 server/web 拉到新的生成代码
47
+ docker compose up -d server web
48
+ ```
49
+
50
+ ## 访问入口
51
+
52
+ | 服务 | 地址 | 说明 |
53
+ |------|------|------|
54
+ | Web 前端 | http://localhost:3000 | 生产 nginx 镜像,**不支持热更新** |
55
+ | Server API | http://localhost:8000 | NestJS,健康检查 `/health/live` |
56
+ | Temporal Web UI | http://localhost:8080 | Workflow 可视化 |
57
+ | Temporal gRPC | `localhost:7233` | Worker / `@temporalio/client` 连这里 |
58
+ | PostgreSQL | `localhost:5432` | 用户 `kavenma` / 密码 `kavenma` |
59
+
60
+ 库划分:
61
+
62
+ - `gadmin_demo` —— 业务库(server + worker 共用,Prisma 管理)
63
+ - `temporal` —— Temporal 元数据库(auto-setup 自动建表)
64
+ - `temporal_visibility` —— Temporal Visibility 库(PG-only,本地不开 ES)
65
+
66
+ ## 与 `temporal/docker-compose.yml` 的区别
67
+
68
+ | 文件 | 内容 | 用途 |
69
+ |------|------|------|
70
+ | `docker-compose.yml`(本目录) | **完整**栈:PG + Temporal + Server + Worker + Web | 端到端集成验证 |
71
+ | `temporal/docker-compose.yml` | 只有 Temporal Server + UI(连 host PG) | 只想跑 Temporal、复用本机 PG 时使用 |
72
+
73
+ 两个文件互不干扰,可单独使用。
74
+
75
+ ## 前端开发态:不要用本 compose
76
+
77
+ 本 compose 里的 `web` service 是 `nginx + 编译后静态文件`,改前端代码不会热更新。日常前端开发请:
78
+
79
+ ```bash
80
+ cd web
81
+ yarn dev # Vite dev server,端口 5173,自带 HMR
82
+ ```
83
+
84
+ 让 Vite dev server 反代到本 compose 起的 `server`(http://localhost:8000)。
85
+
86
+ 后端开发同理:可以选择只起 `postgres` + `temporal-server` 这两个外部依赖:
87
+
88
+ ```bash
89
+ docker compose up -d postgres temporal-server temporal-ui
90
+ cd server && yarn start:dev
91
+ ```
92
+
93
+ ## 启动顺序(depends_on + healthcheck)
94
+
95
+ ```
96
+ postgres (healthy: pg_isready)
97
+ ├─> server-init (一次性容器:prisma db push + seed → exit 0)
98
+ │ ├─> server (启动 API)
99
+ │ └─> temporal-worker (并需 temporal-server healthy)
100
+ └─> temporal-server (healthy: temporal operator cluster health)
101
+ ├─> temporal-ui
102
+ └─> temporal-worker
103
+ server (started)
104
+ └─> web
105
+ ```
106
+
107
+ 首次启动 Temporal 需要跑 schema 初始化(约 30~60s),期间 `temporal-server` 会处于 `starting`,依赖它的 worker 会等待。
108
+
109
+ `server-init` 跑完 `prisma db push` + `seed` 就退出,`docker compose ps` 里它显示 `Exited (0)` 是正常的,不是故障 —— 见"常见问题"。
110
+
111
+ ## 常见问题
112
+
113
+ ### 端口冲突
114
+
115
+ ```bash
116
+ # 看占用:
117
+ lsof -iTCP:3000 -sTCP:LISTEN
118
+ lsof -iTCP:5432 -sTCP:LISTEN
119
+ lsof -iTCP:7233 -sTCP:LISTEN
120
+ lsof -iTCP:8000 -sTCP:LISTEN
121
+ lsof -iTCP:8080 -sTCP:LISTEN
122
+ ```
123
+
124
+ 如本机已有 PG 在 5432,可临时把 `docker-compose.yml` 里 postgres 的 ports 改成 `"5433:5432"`,并把 server / worker 的 `DATABASE_URL` host 改回 `postgres`(容器内通信不变,宿主机端口不影响 docker 网络)。
125
+
126
+ ### `server-init` 显示 `Exited (0)` 是 bug 吗?
127
+
128
+ **不是。** `server-init` 是一次性容器,启动后跑 `prisma db push` 同步业务表结构,再跑 `seed` 灌默认数据,跑完就退出 ——`docker compose ps` 里看到状态 `Exited (0)` 即代表初始化成功。`server` / `temporal-worker` 在 `depends_on` 里声明了 `condition: service_completed_successfully` 等它跑完。
129
+
130
+ > ⚠️ **podman-compose 1.x 注意**:实测对 `service_completed_successfully` 的支持不完整,`up -d` 时不会真的等 init 退出就启动 server/worker。NestJS 启动时不立即查表所以一般没问题,但严格的串行保证没了。真 docker-compose v2 没这问题。
131
+
132
+ 要看它做了什么:
133
+
134
+ ```bash
135
+ docker compose logs server-init
136
+ ```
137
+
138
+ 如果状态是 `Exited (1)` 或更高,说明 push:db 或 seed 失败了,server / worker 不会启动。看日志排错后用 `docker compose up -d server-init` 重跑(幂等)。
139
+
140
+ ### Temporal schema 初始化失败
141
+
142
+ ```bash
143
+ docker compose logs temporal-server | grep -i schema
144
+ ```
145
+
146
+ 最常见原因是 PG 没就绪 server 就启动了。`docker compose down -v` 重置后再 `up -d` 通常解决。
147
+
148
+ ### Server 启动后访问 401 / Cookie 失效
149
+
150
+ server 镜像里 `TAIHU_*` 用的是 `server/.env` 默认值,对应太湖测试账号。如需走真实账号,先 `docker compose down`,把对应变量加到 shell 环境(或新建项目根 `.env` 文件,compose 会自动读取)后重启。
151
+
152
+ ### 重置数据库(清空所有业务数据)
153
+
154
+ ```bash
155
+ ./compose-ctl.sh --reset
156
+ # 等 temporal-server 重新做 schema setup(看日志 `temporal-server` 里出现 "Temporal server started")
157
+ # server-init 会自动重跑 push:db + seed,业务库回到种子数据状态
158
+ ```
159
+
160
+ ## 用到的镜像
161
+
162
+ | 镜像 | 版本 | 来源 |
163
+ |------|------|------|
164
+ | `postgres` | 15-alpine | docker hub 官方 |
165
+ | `temporalio/auto-setup` | 1.29.6.1 | Docker Hub 上 auto-setup 当前最新(生产 Server 是 1.31.0,auto-setup tag 通常滞后;schema 兼容) |
166
+ | `temporalio/ui` | latest | 仅 UI,跨版本兼容性好 |
167
+ | `gadmin2-codegen:local` | 本地 build | `Dockerfile.codegen`,仅做 `gadmin2 g prisma`,被 server/web 镜像通过 `FROM ${CODEGEN_IMAGE}` 引用;同时被 `server-init` 直接复用其全量依赖 |
168
+ | `gadmin-server` | 本地 build | `Dockerfile.server`,build context = 项目根,依赖 codegen 镜像 |
169
+ | `gadmin-temporal-worker` | 本地 build | `temporal/worker/Dockerfile` |
170
+ | `gadmin-web` | 本地 build | `Dockerfile.web`,nginx 静态镜像,依赖 codegen 镜像 |