@allbluecn/admin-app 0.3.1 → 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 (199) 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/paraglide/README.md +1 -1
  57. package/src/providers/index.tsx +1 -1
  58. package/src/routeTree.gen.ts +67 -78
  59. package/src/routes/__root.tsx +4 -4
  60. package/src/routes/_nav/audit/route.lazy.tsx +1 -2
  61. package/src/routes/_nav/compliance/route.lazy.tsx +5 -3
  62. package/src/routes/_nav/components/route.lazy.tsx +14 -34
  63. package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +18 -38
  64. package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +18 -38
  65. package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +6 -6
  66. package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +3 -3
  67. package/src/routes/_nav/licenses/new/route.lazy.tsx +5 -5
  68. package/src/routes/_nav/licenses/route.lazy.tsx +1 -1
  69. package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +2 -2
  70. package/src/routes/_nav/monitoring/errors/route.lazy.tsx +10 -10
  71. package/src/routes/_nav/monitoring/errors/route.tsx +7 -0
  72. package/src/routes/_nav/monitoring/health/route.lazy.tsx +13 -15
  73. package/src/routes/_nav/monitoring/health/route.tsx +14 -0
  74. package/src/routes/_nav/monitoring/logs/route.lazy.tsx +24 -9
  75. package/src/routes/_nav/monitoring/logs/route.tsx +13 -0
  76. package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +12 -14
  77. package/src/routes/_nav/monitoring/metrics/route.tsx +7 -0
  78. package/src/routes/_nav/monitoring/overview/route.lazy.tsx +14 -13
  79. package/src/routes/_nav/monitoring/overview/route.tsx +17 -0
  80. package/src/routes/_nav/monitoring/route.lazy.tsx +6 -6
  81. package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +2 -2
  82. package/src/routes/_nav/permissions/route.lazy.tsx +21 -311
  83. package/src/routes/_nav/permissions/route.tsx +1 -1
  84. package/src/routes/_nav/route.tsx +5 -13
  85. package/src/routes/_nav/sso/route.lazy.tsx +2 -3
  86. package/src/routes/_nav/users/$userId/route.lazy.tsx +91 -156
  87. package/src/routes/_nav/users/-components/users-table.tsx +1 -1
  88. package/src/routes/_nav/users/route.lazy.tsx +1 -1
  89. package/src/routes/login/route.lazy.tsx +1 -1
  90. package/src/routes/setup/route.lazy.tsx +2 -2
  91. package/src/server/__tests__/admin-billing.test.ts +191 -16
  92. package/src/server/__tests__/compliance.test.ts +44 -7
  93. package/src/server/__tests__/permissions.test.ts +10 -5
  94. package/src/server/__tests__/prompt-defaults.test.ts +3 -3
  95. package/src/server/admin-ai-alerts.ts +2 -1
  96. package/src/server/admin-ai-usage.ts +2 -1
  97. package/src/server/ai-memory/store.ts +6 -2
  98. package/src/server/{serverFns/ai-prompts → ai-prompts}/prompt-defaults.ts +5 -3
  99. package/src/server/{serverFns/dependency → dependency}/helpers.ts +4 -3
  100. package/src/server/knowledge-public/github-sync.ts +2 -1
  101. package/src/server/license-issue.ts +2 -1
  102. package/src/server/middlewares/auth-rate-limit.ts +117 -0
  103. package/src/server/observability/health-check.ts +4 -1
  104. package/src/server/observability/metrics.ts +17 -15
  105. package/src/server/observability/request-middleware.ts +2 -1
  106. package/src/server/observability/timing.ts +14 -16
  107. package/src/server/serverFns/admin-billing.ts +107 -12
  108. package/src/server/serverFns/ai-memory/list-users.ts +2 -1
  109. package/src/server/serverFns/ai-prompts/activate.ts +2 -1
  110. package/src/server/serverFns/ai-prompts/get.ts +3 -2
  111. package/src/server/serverFns/ai-prompts/list.ts +3 -2
  112. package/src/server/serverFns/ai-prompts/rollback.ts +3 -1
  113. package/src/server/serverFns/ai-prompts/save.ts +5 -3
  114. package/src/server/serverFns/ai-provider/create.ts +4 -1
  115. package/src/server/serverFns/ai-provider/delete.ts +4 -1
  116. package/src/server/serverFns/ai-provider/get.ts +4 -1
  117. package/src/server/serverFns/ai-provider/list.ts +28 -1
  118. package/src/server/serverFns/ai-provider/seed-from-seed.ts +2 -1
  119. package/src/server/serverFns/ai-provider/update.ts +4 -1
  120. package/src/server/serverFns/anyhub/market.ts +8 -1
  121. package/src/server/serverFns/audit.ts +14 -1
  122. package/src/server/serverFns/auth/setup.ts +3 -1
  123. package/src/server/serverFns/compliance.ts +32 -3
  124. package/src/server/serverFns/components/import.ts +69 -14
  125. package/src/server/serverFns/components/list.ts +4 -1
  126. package/src/server/serverFns/components/mutations.ts +9 -1
  127. package/src/server/serverFns/dependency/list.ts +28 -5
  128. package/src/server/serverFns/dependency/sync.ts +7 -2
  129. package/src/server/serverFns/dependency/update.ts +4 -1
  130. package/src/server/serverFns/developer-log-auto-generate.ts +63 -32
  131. package/src/server/serverFns/developer-logs.ts +5 -1
  132. package/src/server/serverFns/invitations.ts +7 -1
  133. package/src/server/serverFns/knowledge-public/bookmarks/create.ts +2 -1
  134. package/src/server/serverFns/knowledge-public/bookmarks/delete.ts +2 -1
  135. package/src/server/serverFns/knowledge-public/bookmarks/detail.ts +2 -1
  136. package/src/server/serverFns/knowledge-public/bookmarks/list.ts +2 -1
  137. package/src/server/serverFns/knowledge-public/bookmarks/sync-all-github.ts +2 -1
  138. package/src/server/serverFns/knowledge-public/bookmarks/update.ts +2 -1
  139. package/src/server/serverFns/knowledge-public/compliance/create.ts +2 -1
  140. package/src/server/serverFns/knowledge-public/compliance/delete.ts +2 -1
  141. package/src/server/serverFns/knowledge-public/compliance/detail.ts +2 -1
  142. package/src/server/serverFns/knowledge-public/compliance/list.ts +2 -1
  143. package/src/server/serverFns/knowledge-public/compliance/update.ts +2 -1
  144. package/src/server/serverFns/knowledge-public/legal/create.ts +2 -1
  145. package/src/server/serverFns/knowledge-public/legal/delete.ts +2 -1
  146. package/src/server/serverFns/knowledge-public/legal/detail.ts +2 -1
  147. package/src/server/serverFns/knowledge-public/legal/list.ts +2 -1
  148. package/src/server/serverFns/knowledge-public/legal/update.ts +2 -1
  149. package/src/server/serverFns/licenses.ts +8 -2
  150. package/src/server/serverFns/monitoring/get-errors.ts +2 -1
  151. package/src/server/serverFns/monitoring/get-health.ts +2 -1
  152. package/src/server/serverFns/monitoring/get-metrics.ts +2 -1
  153. package/src/server/serverFns/monitoring/get-request-logs.ts +2 -1
  154. package/src/server/serverFns/monitoring/report-error.ts +2 -1
  155. package/src/server/serverFns/monitoring/reset.ts +2 -1
  156. package/src/server/serverFns/oauth-providers.ts +4 -1
  157. package/src/server/serverFns/permissions.ts +18 -11
  158. package/src/server/serverFns/sentry/config.ts +11 -8
  159. package/src/server/serverFns/sso-config.ts +17 -2
  160. package/src/server/serverFns/user/create.ts +6 -1
  161. package/src/server/serverFns/user/delete.ts +6 -1
  162. package/src/server/serverFns/user/detail.ts +5 -2
  163. package/src/server/serverFns/user/list.ts +19 -4
  164. package/src/server/serverFns/user/reset-password.ts +10 -2
  165. package/src/server/serverFns/user/update-role.ts +10 -2
  166. package/src/server/serverFns/user/update-status.ts +10 -2
  167. package/src/styles/globals.css +4 -0
  168. package/src/components/data-table/data-table-pagination.tsx +0 -112
  169. package/src/components/data-table/data-table.tsx +0 -218
  170. package/src/components/data-table/table-detail-layout.tsx +0 -98
  171. package/src/components/ui/alert-dialog.tsx +0 -187
  172. package/src/components/ui/alert.tsx +0 -75
  173. package/src/components/ui/avatar.tsx +0 -106
  174. package/src/components/ui/badge.tsx +0 -51
  175. package/src/components/ui/button.tsx +0 -57
  176. package/src/components/ui/card.tsx +0 -102
  177. package/src/components/ui/checkbox.tsx +0 -28
  178. package/src/components/ui/collapsible.tsx +0 -19
  179. package/src/components/ui/dialog.tsx +0 -155
  180. package/src/components/ui/dropdown-menu.tsx +0 -267
  181. package/src/components/ui/field.tsx +0 -236
  182. package/src/components/ui/input-group.tsx +0 -158
  183. package/src/components/ui/input.tsx +0 -19
  184. package/src/components/ui/label.tsx +0 -17
  185. package/src/components/ui/pagination.tsx +0 -130
  186. package/src/components/ui/select.tsx +0 -234
  187. package/src/components/ui/separator.tsx +0 -22
  188. package/src/components/ui/sheet.tsx +0 -135
  189. package/src/components/ui/sidebar.tsx +0 -721
  190. package/src/components/ui/skeleton.tsx +0 -13
  191. package/src/components/ui/switch.tsx +0 -29
  192. package/src/components/ui/table.tsx +0 -115
  193. package/src/components/ui/textarea.tsx +0 -17
  194. package/src/components/ui/toast.tsx +0 -282
  195. package/src/components/ui/tooltip.tsx +0 -63
  196. package/src/hooks/use-mobile.ts +0 -19
  197. package/src/lib/avatar.ts +0 -41
  198. /package/src/routes/{api.auth.$.ts → api/auth/$.ts} +0 -0
  199. /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
  import { complianceCanonicalId } from '@/server/knowledge-public/canonical-id'
23
23
 
@@ -37,6 +37,7 @@ const createSchema = z.object({
37
37
  export const adminCreateComplianceFn = createServerFn({ method: 'POST' })
38
38
  .validator(createSchema)
39
39
  .handler(async ({ data }) => {
40
+ const prisma = await getPrisma()
40
41
  const session = await requireAdmin()
41
42
  return prisma.industryCompliance.create({
42
43
  data: {
@@ -17,12 +17,13 @@
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
  export const adminDeleteComplianceFn = createServerFn({ method: 'POST' })
24
24
  .validator(z.object({ id: z.string() }))
25
25
  .handler(async ({ data }) => {
26
+ const prisma = await getPrisma()
26
27
  await requireAdmin()
27
28
  const existing = await prisma.industryCompliance.findUnique({ where: { id: data.id } })
28
29
  if (!existing) throw new Error('未找到')
@@ -17,12 +17,13 @@
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
  export const adminGetComplianceDetailFn = createServerFn({ method: 'GET' })
24
24
  .validator(z.object({ id: z.string() }))
25
25
  .handler(async ({ data }) => {
26
+ const prisma = await getPrisma()
26
27
  await requireAdmin()
27
28
  const item = await prisma.industryCompliance.findFirst({
28
29
  where: { id: data.id, visibility: 'public', isDeleted: false },
@@ -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 listSchema = z.object({
@@ -31,6 +31,7 @@ const listSchema = z.object({
31
31
  export const adminListComplianceFn = createServerFn({ method: 'GET' })
32
32
  .validator(listSchema)
33
33
  .handler(async ({ data }) => {
34
+ const prisma = await getPrisma()
34
35
  await requireAdmin()
35
36
  const where: any = { visibility: 'public', isDeleted: false }
36
37
  if (data.search) {
@@ -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 { complianceCanonicalId } from '@/server/knowledge-public/canonical-id'
23
23
 
@@ -38,6 +38,7 @@ const updateSchema = z.object({
38
38
  export const adminUpdateComplianceFn = createServerFn({ method: 'POST' })
39
39
  .validator(updateSchema)
40
40
  .handler(async ({ data }) => {
41
+ const prisma = await getPrisma()
41
42
  await requireAdmin()
42
43
  const { id, code, ...rest } = data
43
44
  const existing = await prisma.industryCompliance.findUnique({ where: { id } })
@@ -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 { legalCanonicalId } from '@/server/knowledge-public/canonical-id'
23
23
 
@@ -39,6 +39,7 @@ const createSchema = z.object({
39
39
  export const adminCreateLegalFn = createServerFn({ method: 'POST' })
40
40
  .validator(createSchema)
41
41
  .handler(async ({ data }) => {
42
+ const prisma = await getPrisma()
42
43
  const session = await requireAdmin()
43
44
  return prisma.legalRegulation.create({
44
45
  data: {
@@ -17,12 +17,13 @@
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
  export const adminDeleteLegalFn = createServerFn({ method: 'POST' })
24
24
  .validator(z.object({ id: z.string() }))
25
25
  .handler(async ({ data }) => {
26
+ const prisma = await getPrisma()
26
27
  await requireAdmin()
27
28
  const existing = await prisma.legalRegulation.findUnique({ where: { id: data.id } })
28
29
  if (!existing) throw new Error('未找到')
@@ -17,12 +17,13 @@
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
  export const adminGetLegalDetailFn = createServerFn({ method: 'GET' })
24
24
  .validator(z.object({ id: z.string() }))
25
25
  .handler(async ({ data }) => {
26
+ const prisma = await getPrisma()
26
27
  await requireAdmin()
27
28
  const item = await prisma.legalRegulation.findFirst({
28
29
  where: { id: data.id, visibility: 'public', isDeleted: false },
@@ -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 listSchema = z.object({
@@ -31,6 +31,7 @@ const listSchema = z.object({
31
31
  export const adminListLegalFn = createServerFn({ method: 'GET' })
32
32
  .validator(listSchema)
33
33
  .handler(async ({ data }) => {
34
+ const prisma = await getPrisma()
34
35
  await requireAdmin()
35
36
  const where: any = { visibility: 'public', isDeleted: false }
36
37
  if (data.search) {
@@ -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 { legalCanonicalId } from '@/server/knowledge-public/canonical-id'
23
23
 
@@ -40,6 +40,7 @@ const updateSchema = z.object({
40
40
  export const adminUpdateLegalFn = createServerFn({ method: 'POST' })
41
41
  .validator(updateSchema)
42
42
  .handler(async ({ data }) => {
43
+ const prisma = await getPrisma()
43
44
  await requireAdmin()
44
45
  const { id, code, ...rest } = data
45
46
  const existing = await prisma.legalRegulation.findUnique({ where: { id } })
@@ -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 { issueLicense } from '@/server/license-issue'
23
23
 
@@ -30,6 +30,7 @@ const listSchema = z.object({
30
30
  export const listLicensesFn = createServerFn({ method: 'GET' })
31
31
  .validator(listSchema)
32
32
  .handler(async ({ data }) => {
33
+ const prisma = await getPrisma()
33
34
  await requireAdmin()
34
35
  const where: any = data.search
35
36
  ? {
@@ -57,6 +58,7 @@ export const listLicensesFn = createServerFn({ method: 'GET' })
57
58
  export const getLicenseDetailFn = createServerFn({ method: 'GET' })
58
59
  .validator(z.object({ licenseId: z.string() }))
59
60
  .handler(async ({ data }) => {
61
+ const prisma = await getPrisma()
60
62
  await requireAdmin()
61
63
  const license = await prisma.licenseKey.findUnique({
62
64
  where: { id: data.licenseId },
@@ -69,6 +71,7 @@ export const getLicenseDetailFn = createServerFn({ method: 'GET' })
69
71
  export const revokeLicenseFn = createServerFn({ method: 'POST' })
70
72
  .validator(z.object({ licenseId: z.string() }))
71
73
  .handler(async ({ data }) => {
74
+ const prisma = await getPrisma()
72
75
  await requireAdmin()
73
76
  await prisma.licenseKey.update({
74
77
  where: { id: data.licenseId },
@@ -89,4 +92,7 @@ export const issueLicenseFn = createServerFn({ method: 'POST' })
89
92
  expiresAt: z.string().datetime().nullable(),
90
93
  }),
91
94
  )
92
- .handler(async ({ data }) => issueLicense(data))
95
+ .handler(async ({ data }) => {
96
+ await requireAdmin()
97
+ return issueLicense(data)
98
+ })
@@ -16,11 +16,12 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
- import { prisma } from '@allbluecn/database'
19
+ import { getPrisma } from '@allbluecn/database/get-prisma'
20
20
  import { requireAdmin } from '@/server/auth-helpers'
21
21
 
22
22
  export const getErrors = createServerFn({ method: 'GET' })
23
23
  .handler(async () => {
24
+ const prisma = await getPrisma()
24
25
  await requireAdmin()
25
26
 
26
27
  const errors = await prisma.monitoringErrorReport.findMany({
@@ -16,12 +16,13 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
- import { prisma } from '@allbluecn/database'
19
+ import { getPrisma } from '@allbluecn/database/get-prisma'
20
20
  import { requireAdmin } from '@/server/auth-helpers'
21
21
  import { performHealthCheck } from '@/server/observability'
22
22
 
23
23
  export const getHealthStatus = createServerFn({ method: 'GET' })
24
24
  .handler(async () => {
25
+ const prisma = await getPrisma()
25
26
  await requireAdmin()
26
27
 
27
28
  const current = await performHealthCheck()
@@ -18,10 +18,11 @@
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { requireAdmin } from '@/server/auth-helpers'
20
20
  import { metrics } from '@/server/observability'
21
- import { prisma } from '@allbluecn/database'
21
+ import { getPrisma } from '@allbluecn/database/get-prisma'
22
22
 
23
23
  export const getMetrics = createServerFn({ method: 'GET' })
24
24
  .handler(async () => {
25
+ const prisma = await getPrisma()
25
26
  await requireAdmin()
26
27
 
27
28
  const memory = process.memoryUsage()
@@ -16,7 +16,7 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
- import { prisma } from '@allbluecn/database'
19
+ import { getPrisma } from '@allbluecn/database/get-prisma'
20
20
  import { requireAdmin } from '@/server/auth-helpers'
21
21
 
22
22
  type GetRequestLogsInput = {
@@ -37,6 +37,7 @@ const MONITORING_PREFIXES = [
37
37
  export const getRequestLogs = createServerFn({ method: 'GET' })
38
38
  .validator((data: GetRequestLogsInput) => data)
39
39
  .handler(async ({ data }) => {
40
+ const prisma = await getPrisma()
40
41
  await requireAdmin()
41
42
 
42
43
  const where: any = {}
@@ -16,7 +16,7 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
- import { prisma } from '@allbluecn/database'
19
+ import { getPrisma } from '@allbluecn/database/get-prisma'
20
20
  import { requireAdmin } from '@/server/auth-helpers'
21
21
 
22
22
  type ReportErrorInput = {
@@ -30,6 +30,7 @@ type ReportErrorInput = {
30
30
  export const reportClientError = createServerFn({ method: 'POST' })
31
31
  .validator((data: ReportErrorInput) => data)
32
32
  .handler(async ({ data }) => {
33
+ const prisma = await getPrisma()
33
34
  await requireAdmin()
34
35
 
35
36
  const key = `${data.errorName}:${data.errorMessage}`
@@ -18,7 +18,7 @@
18
18
  import { createServerFn } from '@tanstack/react-start'
19
19
  import { requireAdmin } from '@/server/auth-helpers'
20
20
  import { metrics, resetErrors } from '@/server/observability'
21
- import { prisma } from '@allbluecn/database'
21
+ import { getPrisma } from '@allbluecn/database/get-prisma'
22
22
 
23
23
  type ResetInput = {
24
24
  type: 'errors' | 'metrics' | 'request-logs' | 'health' | 'all'
@@ -28,6 +28,7 @@ type ResetInput = {
28
28
  export const resetMonitoring = createServerFn({ method: 'POST' })
29
29
  .validator((data: ResetInput) => data)
30
30
  .handler(async ({ data }) => {
31
+ const prisma = await getPrisma()
31
32
  await requireAdmin()
32
33
 
33
34
  const cutoff = data.days ? new Date(Date.now() - data.days * 86400000) : null
@@ -5,7 +5,7 @@
5
5
  // oauth-config 60s 缓存最长延迟 60s 生效(TTL 自然过期,符合 plan2 spec),无跨进程失效通道。
6
6
  import { createServerFn } from '@tanstack/react-start'
7
7
  import { z } from 'zod'
8
- import { prisma } from '@allbluecn/database'
8
+ import { getPrisma } from '@allbluecn/database/get-prisma'
9
9
  import { requireAdmin } from '@/server/auth-helpers'
10
10
  import { decryptSecret, encryptSecret } from '@allbluecn/kernel/crypto'
11
11
 
@@ -30,6 +30,7 @@ function hasGoogleEnvFallback(): boolean {
30
30
  export const listOAuthProvidersFn = createServerFn({ method: 'GET' })
31
31
  .validator(z.object({}))
32
32
  .handler(async (): Promise<{ providers: OAuthProviderView[] }> => {
33
+ const prisma = await getPrisma()
33
34
  await requireAdmin()
34
35
  const row = await prisma.oAuthProviderConfig.findUnique({
35
36
  where: { provider: PROVIDER_KEY },
@@ -69,6 +70,7 @@ export const saveOAuthProviderFn = createServerFn({ method: 'POST' })
69
70
  }),
70
71
  )
71
72
  .handler(async ({ data }) => {
73
+ const prisma = await getPrisma()
72
74
  await requireAdmin()
73
75
  const hasSecret = Boolean(data.clientSecret && data.clientSecret.length > 0)
74
76
  if (!hasSecret) {
@@ -148,6 +150,7 @@ export const testOAuthProviderFn = createServerFn({ method: 'POST' })
148
150
  export const deleteOAuthProviderFn = createServerFn({ method: 'POST' })
149
151
  .validator(z.object({ provider: z.literal('google') }))
150
152
  .handler(async ({ data }) => {
153
+ const prisma = await getPrisma()
151
154
  await requireAdmin()
152
155
  try {
153
156
  await prisma.oAuthProviderConfig.delete({ where: { provider: data.provider } })
@@ -1,6 +1,6 @@
1
1
  import { createServerFn } from '@tanstack/react-start'
2
2
  import { z } from 'zod'
3
- import { prisma } from '@allbluecn/database'
3
+ import { getPrisma } from '@allbluecn/database/get-prisma'
4
4
  import { requireAdmin } from '@/server/auth-helpers'
5
5
  import { requireFeature } from '@/server/entitlements'
6
6
  import { getProService } from '@/server/pro-services'
@@ -98,6 +98,7 @@ function buildSystemRolePresets(): SystemRolePreset[] {
98
98
  export const listRolesFn = createServerFn({ method: 'GET' })
99
99
  .validator(z.object({ workspaceId: z.string() }))
100
100
  .handler(async ({ data }) => {
101
+ const prisma = await getPrisma()
101
102
  await requireAdmin()
102
103
  await requireFeature(undefined, 'advancedPermissions')
103
104
 
@@ -106,16 +107,16 @@ export const listRolesFn = createServerFn({ method: 'GET' })
106
107
  })
107
108
  if (systemCount === 0 && getProService('permissions')) {
108
109
  const presets = buildSystemRolePresets()
109
- for (const preset of presets) {
110
- await prisma.customRole.create({
111
- data: {
112
- workspaceId: data.workspaceId,
113
- name: preset.name,
114
- permissions: preset.permissions as never,
115
- isSystem: true,
116
- },
117
- })
118
- }
110
+ // DB-01/DB-06:系统角色种子从逐 preset create(N 次查询)改为 1 次 createMany
111
+ // (创建行不被消费,ownerRole 仍按 name 回查,行为等价)。查询次数 before: N + 2 → after: 3
112
+ await prisma.customRole.createMany({
113
+ data: presets.map((preset) => ({
114
+ workspaceId: data.workspaceId,
115
+ name: preset.name,
116
+ permissions: preset.permissions as never,
117
+ isSystem: true,
118
+ })),
119
+ })
119
120
  const admins = await prisma.user.findMany({
120
121
  where: { role: 'ADMIN' },
121
122
  select: { id: true },
@@ -151,6 +152,7 @@ export const createRoleFn = createServerFn({ method: 'POST' })
151
152
  }),
152
153
  )
153
154
  .handler(async ({ data }) => {
155
+ const prisma = await getPrisma()
154
156
  await requireAdmin()
155
157
  await requireFeature(undefined, 'advancedPermissions')
156
158
  return prisma.customRole.create({
@@ -166,6 +168,7 @@ export const createRoleFn = createServerFn({ method: 'POST' })
166
168
  export const deleteRoleFn = createServerFn({ method: 'POST' })
167
169
  .validator(z.object({ roleId: z.string() }))
168
170
  .handler(async ({ data }) => {
171
+ const prisma = await getPrisma()
169
172
  await requireAdmin()
170
173
  await requireFeature(undefined, 'advancedPermissions')
171
174
  await prisma.customRole.delete({ where: { id: data.roleId } })
@@ -175,6 +178,7 @@ export const deleteRoleFn = createServerFn({ method: 'POST' })
175
178
  export const assignRoleFn = createServerFn({ method: 'POST' })
176
179
  .validator(z.object({ userId: z.string(), roleId: z.string() }))
177
180
  .handler(async ({ data }) => {
181
+ const prisma = await getPrisma()
178
182
  await requireAdmin()
179
183
  await requireFeature(undefined, 'advancedPermissions')
180
184
  await prisma.roleAssignment.create({ data: { userId: data.userId, roleId: data.roleId } })
@@ -184,6 +188,7 @@ export const assignRoleFn = createServerFn({ method: 'POST' })
184
188
  export const unassignRoleFn = createServerFn({ method: 'POST' })
185
189
  .validator(z.object({ assignmentId: z.string() }))
186
190
  .handler(async ({ data }) => {
191
+ const prisma = await getPrisma()
187
192
  await requireAdmin()
188
193
  await requireFeature(undefined, 'advancedPermissions')
189
194
  await prisma.roleAssignment.delete({ where: { id: data.assignmentId } })
@@ -193,6 +198,7 @@ export const unassignRoleFn = createServerFn({ method: 'POST' })
193
198
  export const listRoleAssignmentsFn = createServerFn({ method: 'GET' })
194
199
  .validator(z.object({ roleId: z.string() }))
195
200
  .handler(async ({ data }) => {
201
+ const prisma = await getPrisma()
196
202
  await requireAdmin()
197
203
  await requireFeature(undefined, 'advancedPermissions')
198
204
  return prisma.roleAssignment.findMany({
@@ -205,6 +211,7 @@ export const listRoleAssignmentsFn = createServerFn({ method: 'GET' })
205
211
  export const listWorkspacesFn = createServerFn({ method: 'GET' })
206
212
  .validator(z.object({}))
207
213
  .handler(async () => {
214
+ const prisma = await getPrisma()
208
215
  await requireAdmin()
209
216
  await requireFeature(undefined, 'advancedPermissions')
210
217
  return prisma.workspace.findMany({
@@ -16,7 +16,7 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createServerFn } from '@tanstack/react-start'
19
- import { prisma } from '@allbluecn/database'
19
+ import { getPrisma } from '@allbluecn/database/get-prisma'
20
20
  import { requireAdmin } from '@/server/auth-helpers'
21
21
 
22
22
  export type SentryConfig = {
@@ -28,6 +28,7 @@ export type SentryConfig = {
28
28
 
29
29
  export const getSentryConfig = createServerFn({ method: 'GET' })
30
30
  .handler(async () => {
31
+ const prisma = await getPrisma()
31
32
  await requireAdmin()
32
33
 
33
34
  const settings = await prisma.systemSetting.findMany({
@@ -47,6 +48,7 @@ export const getSentryConfig = createServerFn({ method: 'GET' })
47
48
  export const saveSentryConfig = createServerFn({ method: 'POST' })
48
49
  .validator((data: SentryConfig) => data)
49
50
  .handler(async ({ data }) => {
51
+ const prisma = await getPrisma()
50
52
  await requireAdmin()
51
53
 
52
54
  const entries: { key: string; value: string; category: string; desc: string }[] = [
@@ -56,13 +58,14 @@ export const saveSentryConfig = createServerFn({ method: 'POST' })
56
58
  { key: 'auth_token', value: data.authToken, category: 'sentry', desc: 'Sentry Auth Token(源码映射上传用)' },
57
59
  ]
58
60
 
59
- for (const entry of entries) {
60
- await prisma.systemSetting.upsert({
61
- where: { key: entry.key },
62
- create: entry,
63
- update: { value: entry.value },
64
- })
65
- }
61
+ // DB-01/DB-06:4 个配置项从逐条 upsert(4 次串行查询)改为事务内 deleteMany + createMany
62
+ // (2 次查询、原子提交)。key 全局唯一且仅 sentry 配置使用这 4 个裸键(其他配置均带命名空间前缀),
63
+ // 读取方均按 key→value 消费,重建行(新 id/createdAt)无行为影响。
64
+ // 查询次数 before: 4 → after: 2(事务内)
65
+ await prisma.$transaction([
66
+ prisma.systemSetting.deleteMany({ where: { key: { in: entries.map((entry) => entry.key) } } }),
67
+ prisma.systemSetting.createMany({ data: entries }),
68
+ ])
66
69
 
67
70
  return { ok: true }
68
71
  })
@@ -17,21 +17,33 @@
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
 
24
24
  export const listSsoProvidersFn = createServerFn({ method: 'GET' })
25
25
  .validator(z.object({ workspaceId: z.string().optional() }))
26
26
  .handler(async ({ data }) => {
27
+ const prisma = await getPrisma()
27
28
  await requireAdmin()
28
29
  await requireFeature(undefined, 'sso')
29
30
  const where: any = data.workspaceId ? { workspaceId: data.workspaceId } : {}
30
31
  const [items, total] = await Promise.all([
31
32
  prisma.ssoProvider.findMany({
32
33
  where,
33
- include: { _count: { select: { mappings: true } } },
34
34
  orderBy: { createdAt: 'desc' },
35
+ // DB-05:config Json 含 IdP client secret 等凭据,列表页不消费,白名单排除
36
+ select: {
37
+ id: true,
38
+ workspaceId: true,
39
+ type: true,
40
+ name: true,
41
+ domain: true,
42
+ enabled: true,
43
+ createdAt: true,
44
+ updatedAt: true,
45
+ _count: { select: { mappings: true } },
46
+ },
35
47
  }),
36
48
  prisma.ssoProvider.count({ where }),
37
49
  ])
@@ -49,6 +61,7 @@ export const createSsoProviderFn = createServerFn({ method: 'POST' })
49
61
  }),
50
62
  )
51
63
  .handler(async ({ data }) => {
64
+ const prisma = await getPrisma()
52
65
  await requireAdmin()
53
66
  await requireFeature(undefined, 'sso')
54
67
  return prisma.ssoProvider.create({
@@ -65,6 +78,7 @@ export const createSsoProviderFn = createServerFn({ method: 'POST' })
65
78
  export const deleteSsoProviderFn = createServerFn({ method: 'POST' })
66
79
  .validator(z.object({ providerId: z.string() }))
67
80
  .handler(async ({ data }) => {
81
+ const prisma = await getPrisma()
68
82
  await requireAdmin()
69
83
  await requireFeature(undefined, 'sso')
70
84
  await prisma.ssoProvider.delete({ where: { id: data.providerId } })
@@ -74,6 +88,7 @@ export const deleteSsoProviderFn = createServerFn({ method: 'POST' })
74
88
  export const toggleSsoProviderFn = createServerFn({ method: 'POST' })
75
89
  .validator(z.object({ providerId: z.string(), enabled: z.boolean() }))
76
90
  .handler(async ({ data }) => {
91
+ const prisma = await getPrisma()
77
92
  await requireAdmin()
78
93
  await requireFeature(undefined, 'sso')
79
94
  return prisma.ssoProvider.update({
@@ -17,8 +17,9 @@
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
+ import { requireAdmin } from '@/server/auth-helpers'
22
23
 
23
24
  const createInput = z.object({
24
25
  email: z.string().email(),
@@ -31,10 +32,14 @@ const createInput = z.object({
31
32
  export const createUserFn = createServerFn({ method: 'POST' })
32
33
  .validator(createInput)
33
34
  .handler(async ({ data }) => {
35
+ const prisma = await getPrisma()
36
+ await requireAdmin()
34
37
  const exists = await prisma.user.findUnique({ where: { email: data.email } })
35
38
  if (exists) throw new Error('Email already exists')
36
39
  const hashedPassword = await bcrypt.hash(data.password, 12)
37
40
  return prisma.user.create({
38
41
  data: { ...data, password: hashedPassword, username: data.name },
42
+ // 不回显 password 哈希
43
+ select: { id: true, email: true, username: true, role: true, status: true },
39
44
  })
40
45
  })
@@ -17,13 +17,18 @@
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
  export const deleteUserFn = createServerFn({ method: 'POST' })
23
24
  .validator(z.object({ userId: z.string() }))
24
25
  .handler(async ({ data }) => {
26
+ const prisma = await getPrisma()
27
+ await requireAdmin()
25
28
  return prisma.user.update({
26
29
  where: { id: data.userId },
27
30
  data: { status: 'INACTIVE' },
31
+ // 不回显 password 哈希
32
+ select: { id: true, email: true, username: true, role: true, status: true },
28
33
  })
29
34
  })
@@ -17,11 +17,14 @@
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
  export const getUserDetailFn = createServerFn({ method: 'GET' })
23
24
  .validator(z.object({ userId: z.string() }))
24
25
  .handler(async ({ data }) => {
26
+ const prisma = await getPrisma()
27
+ await requireAdmin()
25
28
  const user = await prisma.user.findUnique({
26
29
  where: { id: data.userId },
27
30
  select: {
@@ -36,7 +39,7 @@ export const getUserDetailFn = createServerFn({ method: 'GET' })
36
39
  createdAt: true,
37
40
  updatedAt: true,
38
41
  lastLoginAt: true,
39
- _count: { select: { prds: true, anyhubMarketApps: true, anyhubApps: true, reviews: true } },
42
+ _count: { select: { designs: true, anyhubMarketApps: true, anyhubApps: true, reviews: true } },
40
43
  loginLogs: { orderBy: { createdAt: 'desc' }, take: 20 },
41
44
  },
42
45
  })