@allbluecn/admin-app 0.3.2 → 0.3.3

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 (198) hide show
  1. package/package.json +19 -17
  2. package/src/components/admin/admin-user-menu.tsx +4 -4
  3. package/src/components/admin/developer-log.tsx +16 -32
  4. package/src/components/ai-memory/memory-facts-panel.tsx +30 -70
  5. package/src/components/ai-prompts/preview-panel.tsx +1 -1
  6. package/src/components/ai-prompts/prompt-editor.tsx +8 -9
  7. package/src/components/ai-prompts/prompt-table.tsx +6 -6
  8. package/src/components/ai-prompts/section-editor.tsx +3 -3
  9. package/src/components/ai-prompts/variable-panel.tsx +2 -2
  10. package/src/components/ai-prompts/version-history.tsx +21 -41
  11. package/src/components/ai-provider/model-list-editor.tsx +2 -3
  12. package/src/components/ai-provider/provider-form.tsx +7 -7
  13. package/src/components/ai-provider/provider-table.tsx +17 -40
  14. package/src/components/auth/admin-login-form.tsx +7 -7
  15. package/src/components/auth/icon-input.tsx +2 -2
  16. package/src/components/auth/password-input.tsx +2 -2
  17. package/src/components/component/component-form-dialog.tsx +10 -18
  18. package/src/components/component/component-import-dialog.tsx +6 -6
  19. package/src/components/component/component-preview.tsx +311 -0
  20. package/src/components/component/component-table.tsx +3 -3
  21. package/src/components/dependency/changelog-dialog.tsx +2 -2
  22. package/src/components/dependency/columns.tsx +3 -3
  23. package/src/components/dependency/dependency-table.tsx +7 -7
  24. package/src/components/dependency/edit-dialog.tsx +8 -8
  25. package/src/components/invitations/invitations-page.tsx +26 -49
  26. package/src/components/knowledge-public/bookmark-form-dialog.tsx +6 -6
  27. package/src/components/knowledge-public/compliance-form-dialog.tsx +6 -6
  28. package/src/components/knowledge-public/legal-form-dialog.tsx +7 -7
  29. package/src/components/layout/sidebar-02/app-sidebar.tsx +1 -2
  30. package/src/components/layout/sidebar-02/index.tsx +1 -1
  31. package/src/components/layout/sidebar-02/nav-main.tsx +2 -3
  32. package/src/components/layout/sidebar-02/nav-notifications.tsx +3 -3
  33. package/src/components/market/columns.tsx +4 -4
  34. package/src/components/market/market-app-form.tsx +6 -7
  35. package/src/components/market/market-app-list.tsx +14 -29
  36. package/src/components/monitoring/error-list.tsx +2 -2
  37. package/src/components/monitoring/metrics-stats.tsx +1 -1
  38. package/src/components/monitoring/request-log-table.tsx +2 -2
  39. package/src/components/oauth-providers/provider-page.tsx +20 -38
  40. package/src/components/permissions/assign-dialog.tsx +135 -0
  41. package/src/components/permissions/create-role-dialog.tsx +135 -0
  42. package/src/components/permissions/types.ts +49 -0
  43. package/src/components/user/columns.tsx +6 -6
  44. package/src/components/user/settings-activity-log.tsx +7 -7
  45. package/src/components/user/settings-profile/avatar-uploader.tsx +118 -0
  46. package/src/components/user/settings-profile/social-links.tsx +63 -0
  47. package/src/components/user/settings-profile.tsx +26 -125
  48. package/src/components/user/user-create-dialog.tsx +6 -6
  49. package/src/components/user/user-detail/error-boundary.tsx +19 -0
  50. package/src/components/user/user-detail/user-detail-dialogs.tsx +203 -0
  51. package/src/components/user/user-filters.tsx +4 -4
  52. package/src/lib/auth/page-gate.ts +28 -0
  53. package/src/lib/auth.config.ts +25 -9
  54. package/src/lib/i18n/detect.ts +1 -1
  55. package/src/lib/loader-serial.ts +14 -0
  56. package/src/providers/index.tsx +1 -1
  57. package/src/routeTree.gen.ts +67 -78
  58. package/src/routes/__root.tsx +4 -4
  59. package/src/routes/_nav/audit/route.lazy.tsx +1 -2
  60. package/src/routes/_nav/compliance/route.lazy.tsx +5 -3
  61. package/src/routes/_nav/components/route.lazy.tsx +14 -34
  62. package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +18 -38
  63. package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +18 -38
  64. package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +6 -6
  65. package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +3 -3
  66. package/src/routes/_nav/licenses/new/route.lazy.tsx +5 -5
  67. package/src/routes/_nav/licenses/route.lazy.tsx +1 -1
  68. package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +2 -2
  69. package/src/routes/_nav/monitoring/errors/route.lazy.tsx +10 -10
  70. package/src/routes/_nav/monitoring/errors/route.tsx +7 -0
  71. package/src/routes/_nav/monitoring/health/route.lazy.tsx +13 -15
  72. package/src/routes/_nav/monitoring/health/route.tsx +14 -0
  73. package/src/routes/_nav/monitoring/logs/route.lazy.tsx +24 -9
  74. package/src/routes/_nav/monitoring/logs/route.tsx +13 -0
  75. package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +12 -14
  76. package/src/routes/_nav/monitoring/metrics/route.tsx +7 -0
  77. package/src/routes/_nav/monitoring/overview/route.lazy.tsx +14 -13
  78. package/src/routes/_nav/monitoring/overview/route.tsx +17 -0
  79. package/src/routes/_nav/monitoring/route.lazy.tsx +6 -6
  80. package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +2 -2
  81. package/src/routes/_nav/permissions/route.lazy.tsx +21 -311
  82. package/src/routes/_nav/permissions/route.tsx +1 -1
  83. package/src/routes/_nav/route.tsx +5 -13
  84. package/src/routes/_nav/sso/route.lazy.tsx +2 -3
  85. package/src/routes/_nav/users/$userId/route.lazy.tsx +91 -156
  86. package/src/routes/_nav/users/-components/users-table.tsx +1 -1
  87. package/src/routes/_nav/users/route.lazy.tsx +1 -1
  88. package/src/routes/login/route.lazy.tsx +1 -1
  89. package/src/routes/setup/route.lazy.tsx +2 -2
  90. package/src/server/__tests__/admin-billing.test.ts +191 -16
  91. package/src/server/__tests__/compliance.test.ts +44 -7
  92. package/src/server/__tests__/permissions.test.ts +10 -5
  93. package/src/server/__tests__/prompt-defaults.test.ts +3 -3
  94. package/src/server/admin-ai-alerts.ts +2 -1
  95. package/src/server/admin-ai-usage.ts +2 -1
  96. package/src/server/ai-memory/store.ts +6 -2
  97. package/src/server/{serverFns/ai-prompts → ai-prompts}/prompt-defaults.ts +5 -3
  98. package/src/server/{serverFns/dependency → dependency}/helpers.ts +4 -3
  99. package/src/server/knowledge-public/github-sync.ts +2 -1
  100. package/src/server/license-issue.ts +2 -1
  101. package/src/server/middlewares/auth-rate-limit.ts +117 -0
  102. package/src/server/observability/health-check.ts +4 -1
  103. package/src/server/observability/metrics.ts +17 -15
  104. package/src/server/observability/request-middleware.ts +2 -1
  105. package/src/server/observability/timing.ts +14 -16
  106. package/src/server/serverFns/admin-billing.ts +107 -12
  107. package/src/server/serverFns/ai-memory/list-users.ts +2 -1
  108. package/src/server/serverFns/ai-prompts/activate.ts +2 -1
  109. package/src/server/serverFns/ai-prompts/get.ts +3 -2
  110. package/src/server/serverFns/ai-prompts/list.ts +3 -2
  111. package/src/server/serverFns/ai-prompts/rollback.ts +3 -1
  112. package/src/server/serverFns/ai-prompts/save.ts +5 -3
  113. package/src/server/serverFns/ai-provider/create.ts +4 -1
  114. package/src/server/serverFns/ai-provider/delete.ts +4 -1
  115. package/src/server/serverFns/ai-provider/get.ts +4 -1
  116. package/src/server/serverFns/ai-provider/list.ts +28 -1
  117. package/src/server/serverFns/ai-provider/seed-from-seed.ts +2 -1
  118. package/src/server/serverFns/ai-provider/update.ts +4 -1
  119. package/src/server/serverFns/anyhub/market.ts +8 -1
  120. package/src/server/serverFns/audit.ts +14 -1
  121. package/src/server/serverFns/auth/setup.ts +3 -1
  122. package/src/server/serverFns/compliance.ts +32 -3
  123. package/src/server/serverFns/components/import.ts +69 -14
  124. package/src/server/serverFns/components/list.ts +4 -1
  125. package/src/server/serverFns/components/mutations.ts +9 -1
  126. package/src/server/serverFns/dependency/list.ts +28 -5
  127. package/src/server/serverFns/dependency/sync.ts +7 -2
  128. package/src/server/serverFns/dependency/update.ts +4 -1
  129. package/src/server/serverFns/developer-log-auto-generate.ts +63 -32
  130. package/src/server/serverFns/developer-logs.ts +5 -1
  131. package/src/server/serverFns/invitations.ts +7 -1
  132. package/src/server/serverFns/knowledge-public/bookmarks/create.ts +2 -1
  133. package/src/server/serverFns/knowledge-public/bookmarks/delete.ts +2 -1
  134. package/src/server/serverFns/knowledge-public/bookmarks/detail.ts +2 -1
  135. package/src/server/serverFns/knowledge-public/bookmarks/list.ts +2 -1
  136. package/src/server/serverFns/knowledge-public/bookmarks/sync-all-github.ts +2 -1
  137. package/src/server/serverFns/knowledge-public/bookmarks/update.ts +2 -1
  138. package/src/server/serverFns/knowledge-public/compliance/create.ts +2 -1
  139. package/src/server/serverFns/knowledge-public/compliance/delete.ts +2 -1
  140. package/src/server/serverFns/knowledge-public/compliance/detail.ts +2 -1
  141. package/src/server/serverFns/knowledge-public/compliance/list.ts +2 -1
  142. package/src/server/serverFns/knowledge-public/compliance/update.ts +2 -1
  143. package/src/server/serverFns/knowledge-public/legal/create.ts +2 -1
  144. package/src/server/serverFns/knowledge-public/legal/delete.ts +2 -1
  145. package/src/server/serverFns/knowledge-public/legal/detail.ts +2 -1
  146. package/src/server/serverFns/knowledge-public/legal/list.ts +2 -1
  147. package/src/server/serverFns/knowledge-public/legal/update.ts +2 -1
  148. package/src/server/serverFns/licenses.ts +8 -2
  149. package/src/server/serverFns/monitoring/get-errors.ts +2 -1
  150. package/src/server/serverFns/monitoring/get-health.ts +2 -1
  151. package/src/server/serverFns/monitoring/get-metrics.ts +2 -1
  152. package/src/server/serverFns/monitoring/get-request-logs.ts +2 -1
  153. package/src/server/serverFns/monitoring/report-error.ts +2 -1
  154. package/src/server/serverFns/monitoring/reset.ts +2 -1
  155. package/src/server/serverFns/oauth-providers.ts +4 -1
  156. package/src/server/serverFns/permissions.ts +18 -11
  157. package/src/server/serverFns/sentry/config.ts +11 -8
  158. package/src/server/serverFns/sso-config.ts +17 -2
  159. package/src/server/serverFns/user/create.ts +6 -1
  160. package/src/server/serverFns/user/delete.ts +6 -1
  161. package/src/server/serverFns/user/detail.ts +5 -2
  162. package/src/server/serverFns/user/list.ts +19 -4
  163. package/src/server/serverFns/user/reset-password.ts +10 -2
  164. package/src/server/serverFns/user/update-role.ts +10 -2
  165. package/src/server/serverFns/user/update-status.ts +10 -2
  166. package/src/styles/globals.css +4 -0
  167. package/src/components/data-table/data-table-pagination.tsx +0 -112
  168. package/src/components/data-table/data-table.tsx +0 -218
  169. package/src/components/data-table/table-detail-layout.tsx +0 -98
  170. package/src/components/ui/alert-dialog.tsx +0 -187
  171. package/src/components/ui/alert.tsx +0 -75
  172. package/src/components/ui/avatar.tsx +0 -106
  173. package/src/components/ui/badge.tsx +0 -51
  174. package/src/components/ui/button.tsx +0 -57
  175. package/src/components/ui/card.tsx +0 -102
  176. package/src/components/ui/checkbox.tsx +0 -28
  177. package/src/components/ui/collapsible.tsx +0 -19
  178. package/src/components/ui/dialog.tsx +0 -155
  179. package/src/components/ui/dropdown-menu.tsx +0 -267
  180. package/src/components/ui/field.tsx +0 -236
  181. package/src/components/ui/input-group.tsx +0 -158
  182. package/src/components/ui/input.tsx +0 -19
  183. package/src/components/ui/label.tsx +0 -17
  184. package/src/components/ui/pagination.tsx +0 -130
  185. package/src/components/ui/select.tsx +0 -234
  186. package/src/components/ui/separator.tsx +0 -22
  187. package/src/components/ui/sheet.tsx +0 -135
  188. package/src/components/ui/sidebar.tsx +0 -721
  189. package/src/components/ui/skeleton.tsx +0 -13
  190. package/src/components/ui/switch.tsx +0 -29
  191. package/src/components/ui/table.tsx +0 -115
  192. package/src/components/ui/textarea.tsx +0 -17
  193. package/src/components/ui/toast.tsx +0 -282
  194. package/src/components/ui/tooltip.tsx +0 -63
  195. package/src/hooks/use-mobile.ts +0 -19
  196. package/src/lib/avatar.ts +0 -41
  197. /package/src/routes/{api.auth.$.ts → api/auth/$.ts} +0 -0
  198. /package/src/routes/{api.sentry-test.ts → api/sentry-test.ts} +0 -0
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { z } from 'zod'
20
- import { prisma } from '@allbluecn/database'
20
+ import { getPrisma } from '@allbluecn/database/get-prisma'
21
21
  import { requireAdmin } from '@/server/auth-helpers'
22
22
 
23
23
  const listSubscriptionsInput = z.object({
@@ -31,11 +31,17 @@ const listSubscriptionsInput = z.object({
31
31
  export const listAllSubscriptionsFn = createServerFn({ method: 'GET' })
32
32
  .validator(listSubscriptionsInput)
33
33
  .handler(async ({ data }) => {
34
+ const prisma = await getPrisma()
34
35
  await requireAdmin()
35
36
 
36
37
  const where: any = {}
37
38
  if (data.search) {
38
- where.OR = [{ workspace: { name: { contains: data.search } } }]
39
+ // 修复:Subscription 无 workspace 关系(OSS schema 订阅挂在 userId 上),
40
+ // 检索走 user name/email;原 `workspace.name contains` 会 PrismaClientValidationError
41
+ where.OR = [
42
+ { user: { name: { contains: data.search } } },
43
+ { user: { email: { contains: data.search } } },
44
+ ]
39
45
  }
40
46
  if (data.plan) {
41
47
  where.planId = data.plan
@@ -44,32 +50,76 @@ export const listAllSubscriptionsFn = createServerFn({ method: 'GET' })
44
50
  where.status = data.status
45
51
  }
46
52
 
47
- const [items, total] = await Promise.all([
53
+ // DB-05:include 全行(含 provider 凭据 id 等)改白名单 select。
54
+ // 响应 shape 保持消费方键位不变:workspace.name 由 user 映射、seats 由
55
+ // plan.maxSeats + addonSeats 计算(schema 注释的实际上限口径)。
56
+ const [subs, total] = await Promise.all([
48
57
  prisma.subscription.findMany({
49
58
  where,
50
- include: { plan: true, workspace: true },
51
59
  orderBy: { createdAt: 'desc' },
52
60
  skip: (data.page - 1) * data.pageSize,
53
61
  take: data.pageSize,
62
+ select: {
63
+ id: true,
64
+ status: true,
65
+ addonSeats: true,
66
+ currentPeriodEnd: true,
67
+ plan: { select: { name: true, maxSeats: true } },
68
+ user: { select: { name: true, email: true } },
69
+ },
54
70
  }),
55
71
  prisma.subscription.count({ where }),
56
72
  ])
57
73
 
74
+ const items = subs.map((s) => ({
75
+ id: s.id,
76
+ workspace: { name: s.user?.name ?? s.user?.email ?? null },
77
+ plan: { name: s.plan?.name ?? null },
78
+ status: s.status,
79
+ seats: (s.plan?.maxSeats ?? 0) + s.addonSeats,
80
+ currentPeriodEnd: s.currentPeriodEnd,
81
+ }))
82
+
58
83
  return { items, total, page: data.page, pageSize: data.pageSize }
59
84
  })
60
85
 
61
86
  export const getSubscriptionDetailFn = createServerFn({ method: 'GET' })
62
87
  .validator(z.object({ subscriptionId: z.string() }))
63
88
  .handler(async ({ data }) => {
89
+ const prisma = await getPrisma()
64
90
  await requireAdmin()
65
- return prisma.subscription.findUnique({
91
+ const detail = await prisma.subscription.findUnique({
66
92
  where: { id: data.subscriptionId },
67
- include: {
68
- plan: true,
69
- workspace: true,
70
- invoices: { orderBy: { createdAt: 'desc' } },
93
+ select: {
94
+ id: true,
95
+ status: true,
96
+ addonSeats: true,
97
+ currentPeriodStart: true,
98
+ currentPeriodEnd: true,
99
+ providerSubscriptionId: true,
100
+ plan: { select: { id: true, name: true, displayName: true, maxSeats: true } },
101
+ user: { select: { id: true, name: true, email: true } },
102
+ invoices: {
103
+ orderBy: { createdAt: 'desc' },
104
+ select: {
105
+ id: true,
106
+ status: true,
107
+ currency: true,
108
+ amountDue: true,
109
+ periodStart: true,
110
+ periodEnd: true,
111
+ createdAt: true,
112
+ },
113
+ },
71
114
  },
72
115
  })
116
+ if (!detail) return null
117
+ // 同 listAllSubscriptionsFn:workspace/seats 由 user/plan+addonSeats 映射,键位不变
118
+ return {
119
+ ...detail,
120
+ workspace: { name: detail.user?.name ?? detail.user?.email ?? null },
121
+ seats: (detail.plan?.maxSeats ?? 0) + detail.addonSeats,
122
+ }
73
123
  })
74
124
 
75
125
  export const listAllInvoicesFn = createServerFn({ method: 'GET' })
@@ -77,18 +127,63 @@ export const listAllInvoicesFn = createServerFn({ method: 'GET' })
77
127
  z.object({
78
128
  page: z.number().default(1),
79
129
  pageSize: z.number().default(20),
130
+ // DB-02:补 where 参数化(status 过滤;UI 暂无筛选器,默认不过滤——
131
+ // 账单审计要求全量分页可见,避免默认隐藏历史发票)
132
+ status: z.string().optional(),
80
133
  }),
81
134
  )
82
135
  .handler(async ({ data }) => {
136
+ const prisma = await getPrisma()
83
137
  await requireAdmin()
84
- const [items, total] = await Promise.all([
138
+ const where: any = {}
139
+ if (data.status) {
140
+ where.status = data.status
141
+ }
142
+ // DB-05:白名单 select;workspace.name 由 subscription.user 映射(键位不变)
143
+ const [rows, total] = await Promise.all([
85
144
  prisma.invoice.findMany({
145
+ where,
86
146
  orderBy: { createdAt: 'desc' },
87
- include: { subscription: { include: { workspace: true, plan: true } } },
88
147
  skip: (data.page - 1) * data.pageSize,
89
148
  take: data.pageSize,
149
+ select: {
150
+ id: true,
151
+ status: true,
152
+ currency: true,
153
+ amountDue: true,
154
+ amountPaid: true,
155
+ periodStart: true,
156
+ periodEnd: true,
157
+ createdAt: true,
158
+ subscription: {
159
+ select: {
160
+ id: true,
161
+ plan: { select: { name: true } },
162
+ user: { select: { name: true, email: true } },
163
+ },
164
+ },
165
+ },
90
166
  }),
91
- prisma.invoice.count(),
167
+ prisma.invoice.count({ where }),
92
168
  ])
169
+ const items = rows.map((inv) => ({
170
+ id: inv.id,
171
+ status: inv.status,
172
+ currency: inv.currency,
173
+ amountDue: inv.amountDue,
174
+ periodStart: inv.periodStart,
175
+ periodEnd: inv.periodEnd,
176
+ createdAt: inv.createdAt,
177
+ subscription: inv.subscription
178
+ ? {
179
+ id: inv.subscription.id,
180
+ workspace: {
181
+ name:
182
+ inv.subscription.user?.name ?? inv.subscription.user?.email ?? null,
183
+ },
184
+ plan: { name: inv.subscription.plan?.name ?? null },
185
+ }
186
+ : null,
187
+ }))
93
188
  return { items, total, page: data.page, pageSize: data.pageSize }
94
189
  })
@@ -18,13 +18,14 @@
18
18
  // apps/admin/src/server/serverFns/ai-memory/list-users.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import { requireAdmin } from "../../auth-helpers"
23
23
 
24
24
  /** 列出可查询的用户(admin 按 userId 查记忆事实的前置选择) */
25
25
  export const listMemoryUsersFn = createServerFn({ method: "GET" })
26
26
  .validator(z.object({}))
27
27
  .handler(async () => {
28
+ const prisma = await getPrisma()
28
29
  await requireAdmin()
29
30
  const users = await prisma.user.findMany({
30
31
  orderBy: [{ username: "asc" }],
@@ -18,7 +18,7 @@
18
18
  // apps/admin/src/server/serverFns/ai-prompts/activate.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import { requireAdmin } from "../../auth-helpers"
23
23
 
24
24
  const activateSchema = z.object({
@@ -30,6 +30,7 @@ const activateSchema = z.object({
30
30
  export const activatePromptTemplateFn = createServerFn({ method: "POST" })
31
31
  .validator(activateSchema)
32
32
  .handler(async ({ data }) => {
33
+ const prisma = await getPrisma()
33
34
  const session = await requireAdmin()
34
35
  const updatedBy = session.user?.id ?? null
35
36
  const existing = await prisma.systemPromptTemplate.findUnique({
@@ -18,13 +18,13 @@
18
18
  // apps/admin/src/server/serverFns/ai-prompts/get.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import type {
23
23
  SystemPromptSectionDTO,
24
24
  SystemPromptTemplateDTO,
25
25
  } from "@allbluecn/kernel"
26
26
  import { requireAdmin } from "../../auth-helpers"
27
- import { backfillMissingPromptTemplates } from "./prompt-defaults"
27
+ import { backfillMissingPromptTemplates } from "@/server/ai-prompts/prompt-defaults"
28
28
 
29
29
  const getInput = z.object({ key: z.string() })
30
30
 
@@ -40,6 +40,7 @@ export interface PromptVersionSummary {
40
40
  export const getPromptTemplateFn = createServerFn({ method: "GET" })
41
41
  .validator(getInput)
42
42
  .handler(async ({ data }) => {
43
+ const prisma = await getPrisma()
43
44
  await requireAdmin()
44
45
  await backfillMissingPromptTemplates()
45
46
  const template = await prisma.systemPromptTemplate.findUnique({
@@ -18,15 +18,16 @@
18
18
  // apps/admin/src/server/serverFns/ai-prompts/list.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import { requireAdmin } from "../../auth-helpers"
23
- import { backfillMissingPromptTemplates } from "./prompt-defaults"
23
+ import { backfillMissingPromptTemplates } from "@/server/ai-prompts/prompt-defaults"
24
24
 
25
25
  /** 列出提示词模板(列表页只取轻量字段,详情经 get 加载) */
26
26
  export const listPromptTemplatesFn = createServerFn({ method: "GET" })
27
27
  .validator(z.object({}))
28
28
  .handler(
29
29
  async () => {
30
+ const prisma = await getPrisma()
30
31
  await requireAdmin()
31
32
  await backfillMissingPromptTemplates()
32
33
  const templates = await prisma.systemPromptTemplate.findMany({
@@ -18,7 +18,8 @@
18
18
  // apps/admin/src/server/serverFns/ai-prompts/rollback.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma, Prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
+ import type { Prisma } from "@allbluecn/database"
22
23
  import type {
23
24
  PromptVariableDefDTO,
24
25
  SystemPromptSectionDTO,
@@ -39,6 +40,7 @@ function toJson(value: unknown): Prisma.InputJsonValue {
39
40
  export const rollbackPromptTemplateFn = createServerFn({ method: "POST" })
40
41
  .validator(rollbackSchema)
41
42
  .handler(async ({ data }) => {
43
+ const prisma = await getPrisma()
42
44
  const session = await requireAdmin()
43
45
  const updatedBy = session.user?.id ?? null
44
46
  return prisma.$transaction(async (tx) => {
@@ -18,11 +18,12 @@
18
18
  // apps/admin/src/server/serverFns/ai-prompts/save.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma, Prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
+ import type { Prisma } from "@allbluecn/database"
22
23
  import { requireAdmin } from "../../auth-helpers"
23
24
  import { promptSectionSchema, promptVariableSchema } from "./prompt-schemas"
24
- import { getPromptDefinition } from "@allbluecn/web-app/ai-gateway/prompts/definitions"
25
- import { BACKFILL_SNAPSHOT_NOTE } from "./prompt-defaults"
25
+ import { getPromptDefinition } from "@allbluecn/kernel"
26
+ import { BACKFILL_SNAPSHOT_NOTE } from "@/server/ai-prompts/prompt-defaults"
26
27
 
27
28
  const saveSchema = z.object({
28
29
  key: z.string(),
@@ -42,6 +43,7 @@ function toJson(value: unknown): Prisma.InputJsonValue {
42
43
  export const savePromptTemplateFn = createServerFn({ method: "POST" })
43
44
  .validator(saveSchema)
44
45
  .handler(async ({ data }) => {
46
+ const prisma = await getPrisma()
45
47
  const session = await requireAdmin()
46
48
  const updatedBy = session.user?.id ?? null
47
49
  return prisma.$transaction(async (tx) => {
@@ -18,11 +18,12 @@
18
18
  // apps/admin/src/server/serverFns/ai-provider/create.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import {
23
23
  ADAPTER_KIND_VALUES,
24
24
  PROVIDER_CATEGORY_VALUES,
25
25
  } from "@allbluecn/kernel"
26
+ import { requireAdmin } from "@/server/auth-helpers"
26
27
 
27
28
  const modelSchema = z.object({
28
29
  id: z.string().min(1),
@@ -62,6 +63,8 @@ const createInput = z.object({
62
63
  export const createAiProviderAdminFn = createServerFn({ method: "POST" })
63
64
  .validator(createInput)
64
65
  .handler(async ({ data }) => {
66
+ const prisma = await getPrisma()
67
+ await requireAdmin()
65
68
  const exists = await prisma.aiProvider.findUnique({
66
69
  where: { providerId: data.providerId },
67
70
  })
@@ -18,11 +18,14 @@
18
18
  // apps/admin/src/server/serverFns/ai-provider/delete.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
+ import { requireAdmin } from "@/server/auth-helpers"
22
23
 
23
24
  export const deleteAiProviderAdminFn = createServerFn({ method: "POST" })
24
25
  .validator(z.object({ id: z.string() }))
25
26
  .handler(async ({ data }) => {
27
+ const prisma = await getPrisma()
28
+ await requireAdmin()
26
29
  const provider = await prisma.aiProvider.findUnique({
27
30
  where: { id: data.id },
28
31
  select: { providerId: true },
@@ -18,12 +18,15 @@
18
18
  // apps/admin/src/server/serverFns/ai-provider/get.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import type { AiProviderMeta } from "@allbluecn/kernel"
23
+ import { requireAdmin } from "@/server/auth-helpers"
23
24
 
24
25
  export const getAiProviderAdminFn = createServerFn({ method: "GET" })
25
26
  .validator(z.object({ id: z.string() }))
26
27
  .handler(async ({ data }) => {
28
+ const prisma = await getPrisma()
29
+ await requireAdmin()
27
30
  const p = await prisma.aiProvider.findUnique({ where: { id: data.id } })
28
31
  if (!p) throw new Error("未找到服务商")
29
32
  return {
@@ -18,8 +18,9 @@
18
18
  // apps/admin/src/server/serverFns/ai-provider/list.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import type { AiProviderRow } from "@allbluecn/kernel"
23
+ import { requireAdmin } from "@/server/auth-helpers"
23
24
 
24
25
  const listInput = z.object({
25
26
  search: z.string().optional(),
@@ -31,6 +32,8 @@ const listInput = z.object({
31
32
  export const listAiProvidersAdminFn = createServerFn({ method: "GET" })
32
33
  .validator(listInput)
33
34
  .handler(async ({ data }) => {
35
+ const prisma = await getPrisma()
36
+ await requireAdmin()
34
37
  const where: {
35
38
  OR?: Array<Record<string, unknown>>
36
39
  enabled?: boolean
@@ -46,9 +49,33 @@ export const listAiProvidersAdminFn = createServerFn({ method: "GET" })
46
49
  if (data.enabled !== undefined) where.enabled = data.enabled
47
50
  if (data.category) where.category = data.category
48
51
 
52
+ // DB-05:白名单 select——消费方 AiProviderRow 映射用到全部列,显式列出防
53
+ // 未来新增敏感列被整行外泄
49
54
  const providers = await prisma.aiProvider.findMany({
50
55
  where,
51
56
  orderBy: [{ sortOrder: "asc" }, { createdAt: "asc" }],
57
+ select: {
58
+ id: true,
59
+ providerId: true,
60
+ displayName: true,
61
+ brandName: true,
62
+ description: true,
63
+ category: true,
64
+ adapterKind: true,
65
+ defaultBaseUrl: true,
66
+ keyUrl: true,
67
+ docsUrl: true,
68
+ keyPlaceholder: true,
69
+ iconSlug: true,
70
+ brandColor: true,
71
+ badge: true,
72
+ isLocal: true,
73
+ enabled: true,
74
+ models: true,
75
+ sortOrder: true,
76
+ createdAt: true,
77
+ updatedAt: true,
78
+ },
52
79
  })
53
80
 
54
81
  const providerIds = providers.map((p) => p.providerId)
@@ -18,13 +18,14 @@
18
18
  // apps/admin/src/server/serverFns/ai-provider/seed-from-seed.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import { SEED_AI_PROVIDERS } from "@allbluecn/kernel"
23
23
  import { requireAdmin } from "../../auth-helpers"
24
24
 
25
25
  export const seedFromSeedFn = createServerFn({ method: "POST" })
26
26
  .validator(z.object({}))
27
27
  .handler(async () => {
28
+ const prisma = await getPrisma()
28
29
  await requireAdmin()
29
30
  const created: string[] = []
30
31
  const skipped: string[] = []
@@ -18,11 +18,12 @@
18
18
  // apps/admin/src/server/serverFns/ai-provider/update.ts
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { z } from "zod"
21
- import { prisma } from "@allbluecn/database"
21
+ import { getPrisma } from "@allbluecn/database/get-prisma"
22
22
  import {
23
23
  ADAPTER_KIND_VALUES,
24
24
  PROVIDER_CATEGORY_VALUES,
25
25
  } from "@allbluecn/kernel"
26
+ import { requireAdmin } from "@/server/auth-helpers"
26
27
 
27
28
  const modelSchema = z.object({
28
29
  id: z.string().min(1),
@@ -55,6 +56,8 @@ const updateInput = z.object({
55
56
  export const updateAiProviderAdminFn = createServerFn({ method: "POST" })
56
57
  .validator(updateInput)
57
58
  .handler(async ({ data }) => {
59
+ const prisma = await getPrisma()
60
+ await requireAdmin()
58
61
  const { id, ...rest } = data
59
62
  const update: Record<string, unknown> = {}
60
63
  for (const [k, v] of Object.entries(rest)) {
@@ -17,7 +17,8 @@
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { z } from 'zod'
20
- import { prisma } from '@allbluecn/database'
20
+ import { getPrisma } from '@allbluecn/database/get-prisma'
21
+ import { requireAdmin } from '@/server/auth-helpers'
21
22
 
22
23
  const listInput = z.object({
23
24
  page: z.number().default(1),
@@ -29,6 +30,8 @@ const listInput = z.object({
29
30
  export const listMarketAppsFn = createServerFn({ method: 'GET' })
30
31
  .validator(listInput)
31
32
  .handler(async ({ data }) => {
33
+ const prisma = await getPrisma()
34
+ await requireAdmin()
32
35
  const { page, pageSize, search, category } = data
33
36
  const where: any = {}
34
37
  if (search) where.name = { contains: search, mode: 'insensitive' }
@@ -52,6 +55,8 @@ const updateInput = z.object({
52
55
  export const updateMarketAppFn = createServerFn({ method: 'POST' })
53
56
  .validator(updateInput)
54
57
  .handler(async ({ data }) => {
58
+ const prisma = await getPrisma()
59
+ await requireAdmin()
55
60
  const { id, ...update } = data
56
61
  return prisma.anyHubMarketApp.update({ where: { id }, data: update })
57
62
  })
@@ -59,6 +64,8 @@ export const updateMarketAppFn = createServerFn({ method: 'POST' })
59
64
  export const deleteMarketAppFn = createServerFn({ method: 'POST' })
60
65
  .validator(z.object({ id: z.string() }))
61
66
  .handler(async ({ data }) => {
67
+ const prisma = await getPrisma()
68
+ await requireAdmin()
62
69
  await prisma.anyHubMarketApp.delete({ where: { id: data.id } })
63
70
  return { success: true }
64
71
  })
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { z } from 'zod'
20
- import { prisma } from '@allbluecn/database'
20
+ import { getPrisma } from '@allbluecn/database/get-prisma'
21
21
  import { requireAdmin } from '@/server/auth-helpers'
22
22
  import { requireFeature } from '@/server/entitlements'
23
23
 
@@ -34,6 +34,7 @@ const querySchema = z.object({
34
34
  export const queryAuditLogsFn = createServerFn({ method: 'GET' })
35
35
  .validator(querySchema)
36
36
  .handler(async ({ data }) => {
37
+ const prisma = await getPrisma()
37
38
  await requireAdmin()
38
39
  await requireFeature(undefined, 'audit')
39
40
  const where: any = {
@@ -50,6 +51,18 @@ export const queryAuditLogsFn = createServerFn({ method: 'GET' })
50
51
  orderBy: { createdAt: 'desc' },
51
52
  skip: (data.page - 1) * data.pageSize,
52
53
  take: data.pageSize,
54
+ // DB-05:metadata Json 载荷列表页不渲染,白名单排除
55
+ select: {
56
+ id: true,
57
+ workspaceId: true,
58
+ userId: true,
59
+ action: true,
60
+ resourceType: true,
61
+ resourceId: true,
62
+ ip: true,
63
+ userAgent: true,
64
+ createdAt: true,
65
+ },
53
66
  }),
54
67
  prisma.auditLog.count({ where }),
55
68
  ])
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { z } from 'zod'
20
- import { prisma } from '@allbluecn/database'
20
+ import { getPrisma } from '@allbluecn/database/get-prisma'
21
21
  import bcrypt from 'bcryptjs'
22
22
  import { getRandomConfig, presetBgColors } from '@/components/settings/avatar/avatar-config'
23
23
 
@@ -28,6 +28,7 @@ function pickBgColor(seed: string) {
28
28
  }
29
29
 
30
30
  export const checkAdminExistsFn = createServerFn({ method: 'GET' }).handler(async () => {
31
+ const prisma = await getPrisma()
31
32
  const count = await prisma.user.count({
32
33
  where: { role: { in: ['ADMIN', 'SUPER_ADMIN'] } },
33
34
  })
@@ -43,6 +44,7 @@ const setupSchema = z.object({
43
44
  export const setupAdminFn = createServerFn({ method: 'POST' })
44
45
  .validator(setupSchema)
45
46
  .handler(async ({ data }) => {
47
+ const prisma = await getPrisma()
46
48
  const count = await prisma.user.count({
47
49
  where: { role: 'SUPER_ADMIN' },
48
50
  })
@@ -18,14 +18,23 @@
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { getRequest } from '@tanstack/react-start/server'
20
20
  import { z } from 'zod'
21
- import { prisma } from '@allbluecn/database'
21
+ import { getPrisma } from '@allbluecn/database/get-prisma'
22
22
  import { getProService } from '@/server/pro-services'
23
23
  import { requireAdmin } from '@/server/auth-helpers'
24
24
  import { requireFeature } from '@/server/entitlements'
25
25
 
26
26
  export const listComplianceExportsFn = createServerFn({ method: 'GET' })
27
- .validator(z.object({ page: z.number().default(1), pageSize: z.number().default(20) }))
27
+ .validator(
28
+ z.object({
29
+ page: z.number().default(1),
30
+ pageSize: z.number().default(20),
31
+ // DB-02:where 参数化(status 过滤);UI 暂无筛选器,默认不过滤——
32
+ // 合规任务列表含已过期项的状态呈现,默认隐藏会破坏审计可见性
33
+ status: z.string().optional(),
34
+ }),
35
+ )
28
36
  .handler(async ({ data }) => {
37
+ const prisma = await getPrisma()
29
38
  const request = getRequest()
30
39
  await requireAdmin()
31
40
  await requireFeature(request, 'compliance')
@@ -33,13 +42,31 @@ export const listComplianceExportsFn = createServerFn({ method: 'GET' })
33
42
  if (compliance) {
34
43
  return compliance.listJobs({ page: data.page, pageSize: data.pageSize })
35
44
  }
45
+ const where: any = {}
46
+ if (data.status) {
47
+ where.status = data.status
48
+ }
49
+ // DB-05:content(导出负载,可极大)与 downloadUrl/completedAt 列表页不消费,
50
+ // 白名单排除;下载走 /api/compliance-download/:id,不需要 downloadUrl
36
51
  const [items, total] = await Promise.all([
37
52
  prisma.complianceExport.findMany({
53
+ where,
38
54
  orderBy: { createdAt: 'desc' },
39
55
  skip: (data.page - 1) * data.pageSize,
40
56
  take: data.pageSize,
57
+ select: {
58
+ id: true,
59
+ type: true,
60
+ scope: true,
61
+ targetId: true,
62
+ status: true,
63
+ expiresAt: true,
64
+ error: true,
65
+ requestedBy: true,
66
+ createdAt: true,
67
+ },
41
68
  }),
42
- prisma.complianceExport.count(),
69
+ prisma.complianceExport.count({ where }),
43
70
  ])
44
71
  return { items, total }
45
72
  })
@@ -54,6 +81,7 @@ export const createComplianceExportFn = createServerFn({ method: 'POST' })
54
81
  }),
55
82
  )
56
83
  .handler(async ({ data }) => {
84
+ const prisma = await getPrisma()
57
85
  const request = getRequest()
58
86
  await requireAdmin()
59
87
  await requireFeature(request, 'compliance')
@@ -70,6 +98,7 @@ export const createComplianceExportFn = createServerFn({ method: 'POST' })
70
98
  export const executeComplianceJobFn = createServerFn({ method: 'POST' })
71
99
  .validator(z.object({ jobId: z.string() }))
72
100
  .handler(async ({ data }) => {
101
+ const prisma = await getPrisma()
73
102
  const request = getRequest()
74
103
  await requireAdmin()
75
104
  await requireFeature(request, 'compliance')