Commit 38bbaaa
authored
feat(admin): /admin/database 页面嵌入 pgAdmin iframe (#301)
* feat(admin): /admin/database 页面嵌入 pgAdmin iframe
管理员用一个主站入口进 pgAdmin 做备份/恢复/查表/跑 SQL,不再打开
api.involutionhell.com:8082 这种裸页面。pgAdmin 本身的 UI 风格跟主站不搭,
但用户明确说"管理员不配享受好 UI",优先接通能力。
- 新增 app/admin/database/page.tsx:AdminGuard 兜底权限,iframe src 走
https://api.involutionhell.com/admin/pgadmin/(可由 NEXT_PUBLIC_PGADMIN_URL 覆盖)
- /admin 首页加"数据库管理"入口卡片
真实的权限/流量控制在后端 compose + Caddy 那边(见 involutionhell-backend#12):
Caddy 反向代理 /admin/pgadmin/* 到 127.0.0.1:8082,剥 X-Frame-Options,
下发 CSP frame-ancestors 放行 involutionhell.com 主域。
* feat(chat): onFinish 改 fetch 后端 /api/chat/sessions/save,不再直连 Prisma
背景:Neon → 自建 Docker PG 迁移后,前端 Prisma 还指向 Neon,AI 对话持久
化会写进旧库,和后端读自建 PG 分叉出脏数据。方案 A:把 chat + message 写
入挪到后端统一走,前端 onFinish 只发一次 HTTP。
- 删掉 import { prisma } from "@/lib/db",运行时再无 Prisma 依赖
- onFinish 原来三次 prisma 调用(chat upsert + user 消息 + assistant 消息)
合并成一次 fetch(BACKEND_URL + "/api/chat/sessions/save")
- 后端接口匿名允许,登录时通过 satoken header 关联 userId,行为语义和原
Prisma 版完全一致(匿名写 userId=NULL,登录补挂 userId)
- BACKEND_URL 未配或后端返回非 2xx 时 console.warn 不抛错,保持
"持久化失败不阻塞对话流式返回"的原语义
Vercel AI SDK 流式路径(streamText / convertToModelMessages 等)完全未动,
前端 UX 无感知。
配套后端 PR:InvolutionHell/involutionhell-backend#13
* refactor(admin): /admin/database 去掉 iframe,改新标签打开 pgAdmin
iframe 嵌入两种嵌法都是坑:
- 跨域嵌:pgAdmin session/CSRF cookie 走 SameSite=Lax,子域 iframe POST
不带 cookie,登录永远报 "CSRF session token is missing"
- 同源代理嵌:pgAdmin 会发绝对 URL 的重定向(host 是容器自己以为的值),
浏览器跟着跳到 http://localhost:8082 变成 ERR_CONNECTION_REFUSED
管理员不高频用数据库,没必要为了 UI 嵌在主站里搭这些管道。改成一个大按钮,
target=_blank 打开 pgAdmin 自己的页面——cookie / CSRF 都在它自己域里,
一切正常工作。
同步删掉上一版临时加的 Next.js /admin/pgadmin/:path* rewrite。
* feat(auth): 登录成功同步 satoken 到 .involutionhell.com cookie
配合后端 /api/admin/pgadmin-check 和 Caddy forward_auth 的整条链:用户直连
api.involutionhell.com/admin/pgadmin/* 时浏览器不会主动发 satoken header,
必须靠 cookie 自动携带。
- 新加 syncTokenCookie(token):登录 / 刷新有效 session / 登出全部打点
localhost 域不写 Domain(浏览器默认绑当前 host);
生产写 Domain=.involutionhell.com 让主域 + 所有子域共享
SameSite=Lax 刚好够——顶层导航 / 子资源 GET 都会带;跨站 POST 不带但我们
也不需要(pgAdmin 的 CSRF 有自己的 cookie)
Max-Age=2592000 与 sa-token.timeout 保持一致
- token 无效 / 登出时清掉 cookie,避免 stale 身份残留
服务端配套:InvolutionHell/involutionhell-backend#12
* feat(admin/database): hostname=localhost 时按钮自动指本地 pgAdmin
开发时访问 localhost:3010/admin/database 点按钮会直接打 prod
api.involutionhell.com,需要 cookie 但 localhost 登录时 cookie 写不到
.involutionhell.com 域,只能卡 401。
改成客户端挂载后读 window.location.hostname:
- localhost / 127.0.0.1 → http://localhost:8082/admin/pgadmin/
(要求开发者先 ssh -L 8082:127.0.0.1:8082 server 引端口)
- 其他 → 原来的公网 URL(走 Caddy forward_auth 链)
NEXT_PUBLIC_PGADMIN_URL 仍然最高优先级,想覆盖任何时候都能覆盖。
useEffect 里 setState 走 Promise.resolve 异步化,绕开 React
"cascading renders" lint 规则。1 parent 6a72d76 commit 38bbaaa
4 files changed
Lines changed: 218 additions & 47 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
52 | 58 | | |
53 | 59 | | |
54 | 60 | | |
| |||
88 | 94 | | |
89 | 95 | | |
90 | 96 | | |
91 | | - | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
92 | 100 | | |
93 | 101 | | |
94 | 102 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | 1 | | |
3 | 2 | | |
4 | 3 | | |
| |||
187 | 186 | | |
188 | 187 | | |
189 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
190 | 192 | | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
198 | | - | |
199 | | - | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
207 | 200 | | |
208 | | - | |
209 | | - | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
210 | 204 | | |
211 | 205 | | |
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 | | - | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
237 | 230 | | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
238 | 236 | | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
239 | 242 | | |
240 | 243 | | |
241 | 244 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 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 | + | |
39 | 70 | | |
40 | 71 | | |
41 | 72 | | |
| |||
63 | 94 | | |
64 | 95 | | |
65 | 96 | | |
66 | | - | |
| 97 | + | |
67 | 98 | | |
| 99 | + | |
68 | 100 | | |
69 | 101 | | |
70 | 102 | | |
| |||
87 | 119 | | |
88 | 120 | | |
89 | 121 | | |
| 122 | + | |
| 123 | + | |
90 | 124 | | |
91 | | - | |
| 125 | + | |
92 | 126 | | |
| 127 | + | |
93 | 128 | | |
94 | 129 | | |
95 | 130 | | |
| |||
110 | 145 | | |
111 | 146 | | |
112 | 147 | | |
| 148 | + | |
113 | 149 | | |
114 | 150 | | |
115 | 151 | | |
| |||
0 commit comments