create-fullstack-scaffold 0.4.2 → 0.4.4

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 (156) hide show
  1. package/dist/cli/index.js +513 -122
  2. package/dist/cli/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/template/dist/cli/index.js +237 -94
  5. package/template/dist/cli/index.js.map +1 -1
  6. package/template/dist/client/admin.html +15 -10
  7. package/template/dist/client/assets/App-BpFUIC-5.js +114 -0
  8. package/template/dist/client/assets/{CartPage-DESSHkaG.js → CartPage-DgDZP-R5.js} +2 -2
  9. package/template/dist/client/assets/{CategoriesPage-DqLZ_Mom.js → CategoriesPage-fuYNiSmE.js} +2 -2
  10. package/template/dist/client/assets/ContentDetailPage-BvvFU1Mr.js +1 -0
  11. package/template/dist/client/assets/ContentListPage-ShPxo6WG.js +1 -0
  12. package/template/dist/client/assets/DashboardPage-C1rZzZo4.js +11 -0
  13. package/template/dist/client/assets/{DeveloperDashboardPage-Cum7zFwO.js → DeveloperDashboardPage-_WtmbVoA.js} +2 -2
  14. package/template/dist/client/assets/{EmptyState-BK7ttK8D.js → EmptyState-DEyOQjbY.js} +1 -1
  15. package/template/dist/client/assets/LoadingSpinner-BcHjaM1m.js +6 -0
  16. package/template/dist/client/assets/LoginPage-CjeQqDdO.js +1 -0
  17. package/template/dist/client/assets/LogoutOutlined-ColFAHdd.js +1 -0
  18. package/template/dist/client/assets/NotificationPage-DRkEv02s.js +1 -0
  19. package/template/dist/client/assets/OrdersPage-7I3vPWLP.js +11 -0
  20. package/template/dist/client/assets/{PluginDetailPage-Br24YS4P.js → PluginDetailPage-CWyxdVCg.js} +3 -13
  21. package/template/dist/client/assets/PluginsPage-DRgWLeJT.js +6 -0
  22. package/template/dist/client/assets/ProfilePage-2FFkaii8.js +16 -0
  23. package/template/dist/client/assets/PublishPage-DW7yvROx.js +1 -0
  24. package/template/dist/client/assets/{RegisterPage-rPFG4Sry.js → RegisterPage-Dvaf9b0e.js} +2 -2
  25. package/template/dist/client/assets/SaveOutlined-CLQ2tsSY.js +2 -0
  26. package/template/dist/client/assets/{SearchPage-DQl1U5Uy.js → SearchPage-DvnEyswS.js} +2 -2
  27. package/template/dist/client/assets/{SettingsPage-DaYE80wj.js → SettingsPage-IrU-L9Zr.js} +2 -2
  28. package/template/dist/client/assets/{StatusBadge-BJ3W2Zc7.js → StatusBadge-CG7wVqpu.js} +1 -1
  29. package/template/dist/client/assets/{TodoPage-zC5wWNBa.js → TodoPage-B7D-bl65.js} +3 -3
  30. package/template/dist/client/assets/TopicsPage-CYCNr-mn.js +6 -0
  31. package/template/dist/client/assets/{WebSocketPage-B4NLdz1w.js → WebSocketPage-CGEg6QJE.js} +2 -2
  32. package/template/dist/client/assets/{activity-B94BUAsD.js → activity-CgTz9Mrd.js} +1 -1
  33. package/template/dist/client/assets/admin-D2iHWNOg.js +1 -0
  34. package/template/dist/client/assets/api-request-DIJocPxr.js +356 -0
  35. package/template/dist/client/assets/{arrow-left-H5JH0iU1.js → arrow-left-DtLQ3tTk.js} +1 -1
  36. package/template/dist/client/assets/{chevron-down-DwRh_wjD.js → chevron-down-CpIAV_yr.js} +1 -1
  37. package/template/dist/client/assets/{chevron-right-CpIWaqAL.js → chevron-right-CnU7oPQs.js} +1 -1
  38. package/template/dist/client/assets/{circle-check-big-CSElLscG.js → circle-check-big-CrZdwS75.js} +1 -1
  39. package/template/dist/client/assets/{circle-x-CYxr4RAw.js → circle-x-CvN9r3fW.js} +1 -1
  40. package/template/dist/client/assets/{clock-BseUJ7ex.js → clock-CTeSZBiH.js} +1 -1
  41. package/template/dist/client/assets/{download-BsGC_Xhq.js → download-OSVfVuNV.js} +1 -1
  42. package/template/dist/client/assets/{external-link-UTDzdjq8.js → external-link-fBsuHMby.js} +1 -1
  43. package/template/dist/client/assets/{eye-nR10ui7i.js → eye-CwlZZEsj.js} +1 -1
  44. package/template/dist/client/assets/index-09IqiOaE.css +1 -0
  45. package/template/dist/client/assets/index-B3CRby6r.js +51 -0
  46. package/template/dist/client/assets/index-CC_zy73y.js +17 -0
  47. package/template/dist/client/assets/main-Cn4IDo2I.js +92 -0
  48. package/template/dist/client/assets/merchant-DDDN9bMu.js +40 -0
  49. package/template/dist/client/assets/{message-square-CwWGL-Bh.js → message-square-BRaZfgbJ.js} +1 -1
  50. package/template/dist/client/assets/pluginStore-DDsWJPe6.js +1 -0
  51. package/template/dist/client/assets/{plus-pZld_nUL.js → plus-DDZfPiDJ.js} +1 -1
  52. package/template/dist/client/assets/sse-client-DGQ072hl.js +64 -0
  53. package/template/dist/client/assets/star-C7tO6w4H.js +11 -0
  54. package/template/dist/client/assets/{tag-DsiUPF90.js → tag-DBfpQDuJ.js} +1 -1
  55. package/template/dist/client/assets/tenant-CizbLaLJ.js +1 -0
  56. package/template/dist/client/assets/{trash-2-DRblNbnA.js → trash-2-BP7fkd5b.js} +1 -1
  57. package/template/dist/client/assets/{triangle-alert-D1CLh-Vd.js → triangle-alert-CrOQEdJ2.js} +1 -1
  58. package/template/dist/client/assets/{wifi-BwXjnCqI.js → wifi-CwYSE0J4.js} +1 -1
  59. package/template/dist/client/assets/{x-BH2rJdFq.js → x-t615pnNR.js} +1 -1
  60. package/template/dist/client/content/index.html +5 -4
  61. package/template/dist/client/index.html +4 -3
  62. package/template/dist/client/merchant.html +18 -0
  63. package/template/dist/client/notifications/index.html +6 -5
  64. package/template/dist/client/tenant.html +18 -0
  65. package/template/dist/client/todos/index.html +6 -5
  66. package/template/dist/client/websocket/index.html +6 -5
  67. package/template/dist/cloudflare/chunk-HX7DVRDX.js +1 -0
  68. package/template/dist/cloudflare/{chunk-QBHAPWIA.js → chunk-IXJL2LE4.js} +1 -1
  69. package/template/dist/cloudflare/chunk-Q34AN3RF.js +14 -0
  70. package/template/dist/cloudflare/{chunk-BHPTQ4K2.js → chunk-ZAMVL4EG.js} +2 -2
  71. package/template/dist/cloudflare/cloudflare.js +35 -29
  72. package/template/dist/cloudflare/db-4AQOSFAX.js +1 -0
  73. package/template/dist/cloudflare/{migrator-2ZYYKNI5.js → migrator-TEPBVUFO.js} +1 -1
  74. package/template/dist/cloudflare/permission-service-impl-RE7NPW3Q.js +1 -0
  75. package/template/dist/cloudflare/schema-DVEMT3X2.js +1 -0
  76. package/template/dist/cloudflare/test-setup-Z2RYE5B4.js +265 -0
  77. package/template/dist/server/chunk-27SIJSPF.js +1 -0
  78. package/template/dist/server/chunk-37QNGBQU.js +1 -0
  79. package/template/dist/server/chunk-FIY4CGJJ.js +1 -0
  80. package/template/dist/server/chunk-HZUDBIT4.js +1 -0
  81. package/template/dist/server/chunk-I6OBDFDU.js +1 -0
  82. package/template/dist/server/chunk-JHNYLNG7.js +1 -0
  83. package/template/dist/server/chunk-MDOVVKKD.js +1 -0
  84. package/template/dist/server/chunk-NSOCT7E5.js +1 -0
  85. package/template/dist/server/chunk-OU5IGVVO.js +1 -0
  86. package/template/dist/server/chunk-OYCBNRMK.js +1 -0
  87. package/template/dist/server/chunk-P2RJNNGD.js +1 -0
  88. package/template/dist/server/chunk-UMAQLNPE.js +1 -0
  89. package/template/dist/server/chunk-XZZTSRSN.js +1 -0
  90. package/template/dist/server/content-service-5QVHDR5X.js +1 -0
  91. package/template/dist/server/db-FLI5L5DD.js +1 -0
  92. package/template/dist/server/dispute-service-E2FCYUEM.js +1 -0
  93. package/template/dist/server/init-72JXJV3I.js +46 -0
  94. package/template/dist/server/init-FWYXSKPX.js +46 -0
  95. package/template/dist/server/node.js +34 -28
  96. package/template/dist/server/order-service-TKGG5S5K.js +1 -0
  97. package/template/dist/server/permission-service-impl-M3AKEYNY.js +1 -0
  98. package/template/dist/server/schema-V4UG7HMU.js +1 -0
  99. package/template/dist/server/tenant-service-JG6UUWXQ.js +1 -0
  100. package/template/dist/server/tenant-service-XJWZSEDX.js +1 -0
  101. package/template/dist/{cloudflare/test-setup-NMZJZLRV.js → server/test-setup-VFOPBGYM.js} +83 -2
  102. package/template/dist/server/ticket-service-3RSW7V2Z.js +1 -0
  103. package/template/dist/server/todo-service-S6BGIO7D.js +1 -0
  104. package/template/package.json +1 -1
  105. package/template/src/client/App.tsx +3 -1
  106. package/template/src/client/pages/ContentListPage.tsx +36 -4
  107. package/template/src/client/pages/PluginsPage.tsx +112 -20
  108. package/template/src/client/pages/TodoPage.tsx +9 -1
  109. package/template/src/client/preset-ui-config.ts +79 -2
  110. package/template/src/merchant/pages/DisputesPage.tsx +11 -11
  111. package/template/src/merchant/pages/OrdersPage.tsx +4 -3
  112. package/template/src/merchant/pages/ProductsPage.tsx +2 -2
  113. package/template/src/merchant/stores/merchantStore.ts +11 -6
  114. package/template/src/server/db/init.ts +5 -253
  115. package/template/src/server/module-content/routes/topics-routes.ts +250 -0
  116. package/template/src/server/module-content/services/content-service.ts +1 -1
  117. package/template/src/server/module-plugin/services/plugin-seed-service.ts +623 -0
  118. package/template/src/server/module-tenant/routes/tenant-routes.ts +2 -2
  119. package/template/src/server/module-tenant/services/tenant-service.ts +63 -17
  120. package/template/src/server/module-todos/services/todo-service.ts +1 -1
  121. package/template/src/shared/modules/merchant/index.ts +9 -0
  122. package/template/src/shared/modules/merchant/schemas.ts +37 -0
  123. package/template/src/shared/modules/tenant/index.ts +2 -0
  124. package/template/src/shared/schemas/index.ts +27 -0
  125. package/template/src/tenant/layouts/Header.tsx +1 -1
  126. package/template/src/tenant/layouts/Sidebar.tsx +1 -1
  127. package/template/src/tenant/pages/SettingsPage.tsx +4 -8
  128. package/template/src/tenant/stores/tenantStore.ts +41 -302
  129. package/template/tsconfig.json +1 -0
  130. package/template/tsup.config.ts +11 -3
  131. package/template/dist/client/assets/ContentDetailPage-DdltMANL.js +0 -1
  132. package/template/dist/client/assets/ContentListPage-B63sUB6N.js +0 -1
  133. package/template/dist/client/assets/DashboardPage-tUMilc7Z.js +0 -11
  134. package/template/dist/client/assets/LoadingSpinner-DVYOLSRM.js +0 -6
  135. package/template/dist/client/assets/LoginPage-g9mSLIMC.js +0 -6
  136. package/template/dist/client/assets/NotificationPage-COTzp-HD.js +0 -1
  137. package/template/dist/client/assets/OrdersPage-BsPh4oEI.js +0 -11
  138. package/template/dist/client/assets/PluginsPage-BNtAe_yo.js +0 -6
  139. package/template/dist/client/assets/ProfilePage-dL_iSuZN.js +0 -16
  140. package/template/dist/client/assets/PublishPage-D96FnbLA.js +0 -1
  141. package/template/dist/client/assets/TopicsPage-DyLjZa4D.js +0 -6
  142. package/template/dist/client/assets/admin-Bh1vfz_L.js +0 -486
  143. package/template/dist/client/assets/index-1bA-ixFv.js +0 -114
  144. package/template/dist/client/assets/index-CWh3vXC_.css +0 -1
  145. package/template/dist/client/assets/main-DHnArIp_.js +0 -82
  146. package/template/dist/client/assets/pluginStore-XQfsm3iR.js +0 -1
  147. package/template/dist/client/content/content-1/index.html +0 -18
  148. package/template/dist/client/content/content-13/index.html +0 -18
  149. package/template/dist/client/content/content-14/index.html +0 -18
  150. package/template/dist/client/content/content-15/index.html +0 -18
  151. package/template/dist/client/content/content-19/index.html +0 -18
  152. package/template/dist/client/content/content-2/index.html +0 -18
  153. package/template/dist/client/content/content-20/index.html +0 -18
  154. package/template/dist/cloudflare/chunk-YY6FRMAQ.js +0 -14
  155. package/template/dist/cloudflare/db-7J42RQ3T.js +0 -1
  156. package/template/dist/cloudflare/permission-service-impl-TGXVSSSA.js +0 -1
@@ -14,8 +14,8 @@ export const ProductsPage: FC = () => {
14
14
  setLoading(true)
15
15
  try {
16
16
  const response = await fetch('/api/merchant/products')
17
- const result = await response.json()
18
- if (result.success) {
17
+ const result = (await response.json()) as { success?: boolean; data?: Product[] }
18
+ if (result.success === true && result.data) {
19
19
  setProducts(result.data)
20
20
  }
21
21
  } catch (error) {
@@ -13,6 +13,8 @@ interface MerchantState {
13
13
  stats: MerchantStats | null
14
14
  loading: boolean
15
15
  error: string | null
16
+ startLoading: (message?: string) => void
17
+ stopLoading: () => void
16
18
  checkAuth: () => Promise<void>
17
19
  login: (username: string, password: string) => Promise<void>
18
20
  logout: () => void
@@ -28,12 +30,15 @@ export const useMerchantStore = create<MerchantState>(set => ({
28
30
  loading: false,
29
31
  error: null,
30
32
 
33
+ startLoading: (_message?: string) => set({ loading: true }),
34
+ stopLoading: () => set({ loading: false }),
35
+
31
36
  checkAuth: async () => {
32
37
  set({ loading: true, error: null })
33
38
  try {
34
39
  const response = await fetch('/api/merchant/me')
35
- const result = await response.json()
36
- if (result.success) {
40
+ const result = (await response.json()) as { success?: boolean; data?: User }
41
+ if (result.success === true && result.data) {
37
42
  set({ user: result.data, isAuthenticated: true })
38
43
  } else {
39
44
  set({ user: null, isAuthenticated: false })
@@ -56,8 +61,8 @@ export const useMerchantStore = create<MerchantState>(set => ({
56
61
  },
57
62
  body: JSON.stringify({ username, password }),
58
63
  })
59
- const result = await response.json()
60
- if (result.success) {
64
+ const result = (await response.json()) as { success?: boolean; data?: User; error?: string }
65
+ if (result.success === true && result.data) {
61
66
  set({ user: result.data, isAuthenticated: true })
62
67
  } else {
63
68
  set({ error: result.error || 'Login failed' })
@@ -78,8 +83,8 @@ export const useMerchantStore = create<MerchantState>(set => ({
78
83
  set({ loading: true, error: null })
79
84
  try {
80
85
  const response = await fetch('/api/merchant/stats')
81
- const result = await response.json()
82
- if (result.success) {
86
+ const result = (await response.json()) as { success?: boolean; data?: MerchantStats }
87
+ if (result.success === true && result.data) {
83
88
  set({ stats: result.data })
84
89
  }
85
90
  } catch (error) {
@@ -363,8 +363,8 @@ async function seedDevelopersIfEmpty() {
363
363
 
364
364
  log.info({}, 'Seeding developers...')
365
365
 
366
- const demoPasswordHash = await hash('demo123')
367
- const adminPasswordHash = await hash('admin123')
366
+ const demoPasswordHash = await hash('demo123', 10)
367
+ const adminPasswordHash = await hash('admin123', 10)
368
368
 
369
369
  const sampleDevelopers = [
370
370
  {
@@ -372,7 +372,7 @@ async function seedDevelopersIfEmpty() {
372
372
  username: 'demo',
373
373
  email: 'demo@biomimic.app',
374
374
  passwordHash: demoPasswordHash,
375
- role: 'developer',
375
+ role: 'developer' as const,
376
376
  apiKey: generateUUID(),
377
377
  },
378
378
  {
@@ -380,7 +380,7 @@ async function seedDevelopersIfEmpty() {
380
380
  username: 'superadmin',
381
381
  email: 'admin@biomimic.app',
382
382
  passwordHash: adminPasswordHash,
383
- role: 'admin',
383
+ role: 'admin' as const,
384
384
  apiKey: generateUUID(),
385
385
  },
386
386
  ]
@@ -401,254 +401,6 @@ async function seedDevelopersIfEmpty() {
401
401
  }
402
402
  }
403
403
 
404
- async function seedPluginsIfEmpty() {
405
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic import for presets that may not have plugin module
406
- let plugins: any
407
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
408
- let pluginVersions: any
409
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
410
- let pluginCategories: any
411
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
412
- let pluginCategoryMappings: any
413
- try {
414
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
415
- const schema = (await import('./schema')) as Record<string, any>
416
- plugins = schema.plugins
417
- pluginVersions = schema.pluginVersions
418
- pluginCategories = schema.pluginCategories
419
- pluginCategoryMappings = schema.pluginCategoryMappings
420
- if (!plugins) return
421
- } catch {
422
- return
423
- }
424
-
425
- const db = await getDb()
426
-
427
- const existing = await db.select().from(plugins)
428
- if (existing.length > 0) return
429
-
430
- log.info({}, 'Seeding plugins...')
431
-
432
- const sampleCategories = [
433
- {
434
- id: generateUUID(),
435
- name: 'UI & Design',
436
- slug: 'ui-design',
437
- description: 'Visual customization and theming',
438
- icon: 'palette',
439
- sortOrder: 1,
440
- },
441
- {
442
- id: generateUUID(),
443
- name: 'Analytics',
444
- slug: 'analytics',
445
- description: 'Data tracking and reporting',
446
- icon: 'chart',
447
- sortOrder: 2,
448
- },
449
- {
450
- id: generateUUID(),
451
- name: 'SEO & Marketing',
452
- slug: 'seo-marketing',
453
- description: 'Search optimization and growth tools',
454
- icon: 'trending-up',
455
- sortOrder: 3,
456
- },
457
- {
458
- id: generateUUID(),
459
- name: 'Developer Tools',
460
- slug: 'developer-tools',
461
- description: 'Utilities for developers',
462
- icon: 'code',
463
- sortOrder: 4,
464
- },
465
- {
466
- id: generateUUID(),
467
- name: 'Integration',
468
- slug: 'integration',
469
- description: 'Third-party service integrations',
470
- icon: 'plug',
471
- sortOrder: 5,
472
- },
473
- ]
474
-
475
- await db.insert(pluginCategories).values(sampleCategories)
476
-
477
- const samplePlugins = [
478
- {
479
- id: generateUUID(),
480
- name: 'Theme Engine',
481
- slug: 'theme-engine',
482
- description:
483
- 'Advanced theming system with dark mode, custom color palettes, and responsive layout controls.',
484
- readme:
485
- '# Theme Engine\n\nA powerful theming plugin for customizing the look and feel of your application.',
486
- authorId: '1',
487
- authorName: 'superadmin',
488
- repositoryUrl: 'https://github.com/example/theme-engine',
489
- homepageUrl: 'https://theme-engine.example.com',
490
- license: 'MIT',
491
- version: '2.1.0',
492
- status: 'approved' as const,
493
- downloadCount: 1520,
494
- viewCount: 4320,
495
- featured: true,
496
- screenshotUrl: 'https://picsum.photos/seed/theme/800/400',
497
- tags: '["theme","dark-mode","customization"]',
498
- },
499
- {
500
- id: generateUUID(),
501
- slug: 'analytics-dashboard',
502
- name: 'Analytics Dashboard',
503
- description:
504
- 'Real-time analytics dashboard with charts, heatmaps, and user behavior tracking.',
505
- readme: '# Analytics Dashboard\n\nTrack user engagement and visualize data in real time.',
506
- authorId: '1',
507
- authorName: 'superadmin',
508
- repositoryUrl: 'https://github.com/example/analytics-dashboard',
509
- homepageUrl: 'https://analytics.example.com',
510
- license: 'Apache-2.0',
511
- version: '1.5.3',
512
- status: 'approved' as const,
513
- downloadCount: 980,
514
- viewCount: 2100,
515
- featured: true,
516
- screenshotUrl: 'https://picsum.photos/seed/analytics/800/400',
517
- tags: '["analytics","dashboard","charts"]',
518
- },
519
- {
520
- id: generateUUID(),
521
- slug: 'seo-optimizer',
522
- name: 'SEO Optimizer',
523
- description:
524
- 'Automated SEO optimization with meta tags, sitemap generation, and structured data support.',
525
- authorId: '2',
526
- authorName: 'customerservice',
527
- repositoryUrl: 'https://github.com/example/seo-optimizer',
528
- license: 'MIT',
529
- version: '1.2.0',
530
- status: 'approved' as const,
531
- downloadCount: 740,
532
- viewCount: 1800,
533
- featured: false,
534
- screenshotUrl: 'https://picsum.photos/seed/seo/800/400',
535
- tags: '["seo","meta","sitemap"]',
536
- },
537
- {
538
- id: generateUUID(),
539
- slug: 'api-toolkit',
540
- name: 'API Toolkit',
541
- description:
542
- 'Developer toolkit for building and testing REST APIs with auto-documentation and mock servers.',
543
- authorId: '2',
544
- authorName: 'customerservice',
545
- repositoryUrl: 'https://github.com/example/api-toolkit',
546
- homepageUrl: 'https://api-toolkit.example.com',
547
- license: 'MIT',
548
- version: '3.0.1',
549
- status: 'approved' as const,
550
- downloadCount: 2100,
551
- viewCount: 5600,
552
- featured: true,
553
- screenshotUrl: 'https://picsum.photos/seed/apitoolkit/800/400',
554
- tags: '["api","developer","testing","documentation"]',
555
- },
556
- {
557
- id: generateUUID(),
558
- slug: 'notification-hub',
559
- name: 'Notification Hub',
560
- description:
561
- 'Unified notification management supporting email, SMS, push, and in-app notifications.',
562
- authorId: '3',
563
- authorName: 'user1',
564
- repositoryUrl: 'https://github.com/example/notification-hub',
565
- license: 'ISC',
566
- version: '1.0.0',
567
- status: 'pending' as const,
568
- downloadCount: 0,
569
- viewCount: 50,
570
- featured: false,
571
- screenshotUrl: 'https://picsum.photos/seed/notify/800/400',
572
- tags: '["notification","email","push"]',
573
- },
574
- ]
575
-
576
- await db.insert(plugins).values(samplePlugins)
577
-
578
- const sampleVersions = [
579
- {
580
- id: generateUUID(),
581
- pluginId: samplePlugins[0].id,
582
- version: '2.1.0',
583
- changelog: 'Added responsive layout controls',
584
- status: 'approved' as const,
585
- },
586
- {
587
- id: generateUUID(),
588
- pluginId: samplePlugins[0].id,
589
- version: '2.0.0',
590
- changelog: 'Major rewrite with dark mode support',
591
- status: 'approved' as const,
592
- },
593
- {
594
- id: generateUUID(),
595
- pluginId: samplePlugins[1].id,
596
- version: '1.5.3',
597
- changelog: 'Fixed heatmap rendering',
598
- status: 'approved' as const,
599
- },
600
- {
601
- id: generateUUID(),
602
- pluginId: samplePlugins[1].id,
603
- version: '1.5.0',
604
- changelog: 'Added real-time tracking',
605
- status: 'approved' as const,
606
- },
607
- {
608
- id: generateUUID(),
609
- pluginId: samplePlugins[2].id,
610
- version: '1.2.0',
611
- changelog: 'Structured data support',
612
- status: 'approved' as const,
613
- },
614
- {
615
- id: generateUUID(),
616
- pluginId: samplePlugins[3].id,
617
- version: '3.0.1',
618
- changelog: 'Auto-documentation improvements',
619
- status: 'approved' as const,
620
- },
621
- {
622
- id: generateUUID(),
623
- pluginId: samplePlugins[3].id,
624
- version: '3.0.0',
625
- changelog: 'Major version with mock server',
626
- status: 'approved' as const,
627
- },
628
- {
629
- id: generateUUID(),
630
- pluginId: samplePlugins[4].id,
631
- version: '1.0.0',
632
- changelog: 'Initial release',
633
- status: 'pending' as const,
634
- },
635
- ]
636
-
637
- await db.insert(pluginVersions).values(sampleVersions)
638
-
639
- const sampleMappings = [
640
- { pluginId: samplePlugins[0].id, categoryId: sampleCategories[0].id },
641
- { pluginId: samplePlugins[1].id, categoryId: sampleCategories[1].id },
642
- { pluginId: samplePlugins[2].id, categoryId: sampleCategories[2].id },
643
- { pluginId: samplePlugins[3].id, categoryId: sampleCategories[3].id },
644
- { pluginId: samplePlugins[4].id, categoryId: sampleCategories[4].id },
645
- ]
646
-
647
- await db.insert(pluginCategoryMappings).values(sampleMappings)
648
-
649
- log.info({}, 'Plugin seeding complete!')
650
- }
651
-
652
404
  export async function initializeDatabase() {
653
405
  const db = await getDb()
654
406
 
@@ -705,7 +457,7 @@ export async function initializeDatabase() {
705
457
  () => import('../module-dispute/services/dispute-service').then(m => m.seedDisputesIfEmpty()),
706
458
  () => import('../module-content/services/content-service').then(m => m.seedContentsIfEmpty()),
707
459
  () => import('../module-tenant/services/tenant-service').then(m => m.seedTenantsIfEmpty()),
708
- () => seedPluginsIfEmpty(),
460
+ () => import('../module-plugin/services/plugin-seed-service').then(m => m.seedPluginsIfEmpty()),
709
461
  ]
710
462
  await Promise.all(moduleSeeders.map(fn => fn().catch(() => {})))
711
463
  log.info({}, 'Module data seeding complete!')
@@ -101,6 +101,256 @@ const MOCK_TOPICS = [
101
101
  author: { name: 'Emma Wilson', initials: 'EW' },
102
102
  createdAt: '12h ago',
103
103
  },
104
+ {
105
+ id: '7',
106
+ title: 'Optimizing React components with useMemo and useCallback',
107
+ excerpt:
108
+ 'Understanding when and how to use React hooks for performance optimization. Real-world examples and benchmarks showing measurable improvements.',
109
+ votes: 45,
110
+ replyCount: 15,
111
+ viewCount: 678,
112
+ status: 'discussion' as const,
113
+ tags: [
114
+ { label: 'React', color: 'bg-cyan-100 text-cyan-700' },
115
+ { label: 'Performance', color: 'bg-amber-100 text-amber-700' },
116
+ ],
117
+ author: { name: '张伟', initials: 'ZW' },
118
+ createdAt: '1d ago',
119
+ },
120
+ {
121
+ id: '8',
122
+ title: 'PostgreSQL query optimization for large datasets',
123
+ excerpt:
124
+ 'Strategies for handling millions of rows with efficient indexing, query planning, and materialized views. Includes EXPLAIN ANALYZE walkthrough.',
125
+ votes: 89,
126
+ replyCount: 23,
127
+ viewCount: 1567,
128
+ status: 'hot' as const,
129
+ tags: [
130
+ { label: 'PostgreSQL', color: 'bg-blue-100 text-blue-700' },
131
+ { label: 'Database', color: 'bg-indigo-100 text-indigo-700' },
132
+ { label: 'Performance', color: 'bg-amber-100 text-amber-700' },
133
+ ],
134
+ author: { name: 'Raj Sharma', initials: 'RS' },
135
+ createdAt: '1d ago',
136
+ },
137
+ {
138
+ id: '9',
139
+ title: 'Implementing JWT authentication with refresh tokens',
140
+ excerpt:
141
+ 'Secure authentication flow with JWT access tokens and refresh tokens. Best practices for token storage, rotation, and revocation.',
142
+ votes: 72,
143
+ replyCount: 18,
144
+ viewCount: 1245,
145
+ status: 'solved' as const,
146
+ tags: [
147
+ { label: 'Auth', color: 'bg-rose-100 text-rose-700' },
148
+ { label: 'Security', color: 'bg-red-100 text-red-700' },
149
+ { label: 'JWT', color: 'bg-pink-100 text-pink-700' },
150
+ ],
151
+ author: { name: '田中太郎', initials: 'TT' },
152
+ createdAt: '2d ago',
153
+ },
154
+ {
155
+ id: '10',
156
+ title: 'Building microservices with Docker and Kubernetes',
157
+ excerpt:
158
+ 'Complete guide to containerizing Node.js applications and orchestrating them with Kubernetes. Includes service discovery, load balancing, and autoscaling.',
159
+ votes: 103,
160
+ replyCount: 31,
161
+ viewCount: 1890,
162
+ status: 'hot' as const,
163
+ tags: [
164
+ { label: 'Docker', color: 'bg-sky-100 text-sky-700' },
165
+ { label: 'Kubernetes', color: 'bg-blue-100 text-blue-700' },
166
+ { label: 'Microservices', color: 'bg-violet-100 text-violet-700' },
167
+ ],
168
+ author: { name: 'Marie Dubois', initials: 'MD' },
169
+ createdAt: '2d ago',
170
+ },
171
+ {
172
+ id: '11',
173
+ title: 'Writing accessible React applications',
174
+ excerpt:
175
+ 'Essential ARIA patterns and semantic HTML for building inclusive web apps. Screen reader testing checklist and common accessibility pitfalls.',
176
+ votes: 58,
177
+ replyCount: 14,
178
+ viewCount: 923,
179
+ status: 'open' as const,
180
+ tags: [
181
+ { label: 'Accessibility', color: 'bg-emerald-100 text-emerald-700' },
182
+ { label: 'React', color: 'bg-cyan-100 text-cyan-700' },
183
+ { label: 'A11y', color: 'bg-lime-100 text-lime-700' },
184
+ ],
185
+ author: { name: '김민수', initials: 'KM' },
186
+ createdAt: '3d ago',
187
+ },
188
+ {
189
+ id: '12',
190
+ title: 'TypeScript utility types explained with examples',
191
+ excerpt:
192
+ 'Deep dive into TypeScript utility types like Pick, Omit, Partial, Record, and more. Practical examples for everyday use.',
193
+ votes: 81,
194
+ replyCount: 22,
195
+ viewCount: 1456,
196
+ status: 'hot' as const,
197
+ tags: [
198
+ { label: 'TypeScript', color: 'bg-blue-100 text-blue-700' },
199
+ { label: 'Guide', color: 'bg-emerald-100 text-emerald-700' },
200
+ ],
201
+ author: { name: 'Anna Müller', initials: 'AM' },
202
+ createdAt: '3d ago',
203
+ },
204
+ {
205
+ id: '13',
206
+ title: 'Redis caching strategies for high-traffic APIs',
207
+ excerpt:
208
+ 'Implementing Redis caching layers for REST APIs. Cache invalidation strategies, TTL policies, and handling cache stampedes.',
209
+ votes: 64,
210
+ replyCount: 9,
211
+ viewCount: 1012,
212
+ status: 'solved' as const,
213
+ tags: [
214
+ { label: 'Redis', color: 'bg-red-100 text-red-700' },
215
+ { label: 'Caching', color: 'bg-orange-100 text-orange-700' },
216
+ { label: 'API', color: 'bg-sky-100 text-sky-700' },
217
+ ],
218
+ author: { name: 'Carlos Silva', initials: 'CS' },
219
+ createdAt: '3d ago',
220
+ },
221
+ {
222
+ id: '14',
223
+ title: 'GraphQL Federation for microservices architecture',
224
+ excerpt:
225
+ 'Combining multiple GraphQL services into a unified API with Apollo Federation. Schema stitching, type composition, and distributed tracing.',
226
+ votes: 47,
227
+ replyCount: 0,
228
+ viewCount: 623,
229
+ status: 'unanswered' as const,
230
+ tags: [
231
+ { label: 'GraphQL', color: 'bg-pink-100 text-pink-700' },
232
+ { label: 'Microservices', color: 'bg-violet-100 text-violet-700' },
233
+ ],
234
+ author: { name: '李明', initials: 'LM' },
235
+ createdAt: '4h ago',
236
+ },
237
+ {
238
+ id: '15',
239
+ title: 'Testing React components with Vitest and Testing Library',
240
+ excerpt:
241
+ 'Modern testing setup with Vitest and React Testing Library. Writing maintainable tests, mocking external dependencies, and snapshot testing.',
242
+ votes: 76,
243
+ replyCount: 17,
244
+ viewCount: 1234,
245
+ status: 'discussion' as const,
246
+ tags: [
247
+ { label: 'Testing', color: 'bg-amber-100 text-amber-700' },
248
+ { label: 'React', color: 'bg-cyan-100 text-cyan-700' },
249
+ { label: 'Vitest', color: 'bg-purple-100 text-purple-700' },
250
+ ],
251
+ author: { name: 'Elena Popova', initials: 'EP' },
252
+ createdAt: '5h ago',
253
+ },
254
+ {
255
+ id: '16',
256
+ title: 'RESTful API design best practices',
257
+ excerpt:
258
+ 'Comprehensive guide to designing REST APIs. Resource naming, HTTP methods, status codes, pagination, filtering, and versioning strategies.',
259
+ votes: 92,
260
+ replyCount: 28,
261
+ viewCount: 1678,
262
+ status: 'hot' as const,
263
+ tags: [
264
+ { label: 'API Design', color: 'bg-sky-100 text-sky-700' },
265
+ { label: 'REST', color: 'bg-emerald-100 text-emerald-700' },
266
+ { label: 'Architecture', color: 'bg-orange-100 text-orange-700' },
267
+ ],
268
+ author: { name: '佐藤健', initials: 'SK' },
269
+ createdAt: '6h ago',
270
+ },
271
+ {
272
+ id: '17',
273
+ title: 'CSS Grid vs Flexbox — when to use which?',
274
+ excerpt:
275
+ 'Practical comparison of CSS Grid and Flexbox layouts. Use cases, browser support, and examples of combining both for complex layouts.',
276
+ votes: 39,
277
+ replyCount: 8,
278
+ viewCount: 567,
279
+ status: 'open' as const,
280
+ tags: [
281
+ { label: 'CSS', color: 'bg-indigo-100 text-indigo-700' },
282
+ { label: 'Layout', color: 'bg-purple-100 text-purple-700' },
283
+ ],
284
+ author: { name: 'Olga Ivanova', initials: 'OI' },
285
+ createdAt: '8h ago',
286
+ },
287
+ {
288
+ id: '18',
289
+ title: 'Setting up CI/CD pipeline with GitHub Actions',
290
+ excerpt:
291
+ 'Automating testing, building, and deployment with GitHub Actions. Multi-environment configs, secrets management, and deployment strategies.',
292
+ votes: 68,
293
+ replyCount: 13,
294
+ viewCount: 1102,
295
+ status: 'solved' as const,
296
+ tags: [
297
+ { label: 'CI/CD', color: 'bg-rose-100 text-rose-700' },
298
+ { label: 'GitHub', color: 'bg-slate-100 text-slate-700' },
299
+ { label: 'DevOps', color: 'bg-blue-100 text-blue-700' },
300
+ ],
301
+ author: { name: '黄志强', initials: 'HZ' },
302
+ createdAt: '30m ago',
303
+ },
304
+ {
305
+ id: '19',
306
+ title: 'Node.js event loop explained in depth',
307
+ excerpt:
308
+ 'Understanding the Node.js event loop, call stack, and asynchronous operations. Performance implications and best practices for event-driven apps.',
309
+ votes: 55,
310
+ replyCount: 11,
311
+ viewCount: 845,
312
+ status: 'discussion' as const,
313
+ tags: [
314
+ { label: 'Node.js', color: 'bg-green-100 text-green-700' },
315
+ { label: 'Performance', color: 'bg-amber-100 text-amber-700' },
316
+ ],
317
+ author: { name: 'Giovanni Rossi', initials: 'GR' },
318
+ createdAt: '45m ago',
319
+ },
320
+ {
321
+ id: '20',
322
+ title: 'Handling file uploads in multipart/form-data with Hono',
323
+ excerpt:
324
+ 'Implementing secure file upload endpoints in Hono. Validation, storage with R2, handling large files, and progress tracking.',
325
+ votes: 71,
326
+ replyCount: 16,
327
+ viewCount: 1323,
328
+ status: 'solved' as const,
329
+ tags: [
330
+ { label: 'Hono', color: 'bg-sky-100 text-sky-700' },
331
+ { label: 'File Upload', color: 'bg-indigo-100 text-indigo-700' },
332
+ { label: 'R2', color: 'bg-amber-100 text-amber-700' },
333
+ ],
334
+ author: { name: 'Priya Patel', initials: 'PP' },
335
+ createdAt: '2h ago',
336
+ },
337
+ {
338
+ id: '21',
339
+ title: 'Debouncing and throttling in React applications',
340
+ excerpt:
341
+ 'Implementing debouncing and throttling for search inputs, scroll events, and API calls. Custom hooks and performance considerations.',
342
+ votes: 33,
343
+ replyCount: 5,
344
+ viewCount: 445,
345
+ status: 'open' as const,
346
+ tags: [
347
+ { label: 'React', color: 'bg-cyan-100 text-cyan-700' },
348
+ { label: 'Performance', color: 'bg-amber-100 text-amber-700' },
349
+ { label: 'Hooks', color: 'bg-pink-100 text-pink-700' },
350
+ ],
351
+ author: { name: '山本花子', initials: 'YH' },
352
+ createdAt: '1w ago',
353
+ },
104
354
  ]
105
355
 
106
356
  const MOCK_PROFILE_ACTIVITY = [
@@ -42,7 +42,7 @@ export async function seedContentsIfEmpty(): Promise<void> {
42
42
  JSON.stringify(['最佳实践', '经验']),
43
43
  ]
44
44
 
45
- for (let i = 0; i < 20; i++) {
45
+ for (let i = 0; i < 25; i++) {
46
46
  const category = randomElement(CATEGORIES)
47
47
  const status = randomElement(STATUSES)
48
48
  const createdAt = new Date(randomDate(new Date('2024-01-01'), new Date()))