@open-mercato/core 0.4.2-canary-15e78de280 → 0.4.2-canary-f075c3eb92

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 (87) hide show
  1. package/dist/modules/api_keys/setup.js +11 -0
  2. package/dist/modules/api_keys/setup.js.map +7 -0
  3. package/dist/modules/attachments/components/AttachmentLibrary.js +1 -1
  4. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  5. package/dist/modules/attachments/lib/assignmentDetails.js +31 -17
  6. package/dist/modules/attachments/lib/assignmentDetails.js.map +2 -2
  7. package/dist/modules/attachments/lib/partitions.js +3 -3
  8. package/dist/modules/attachments/lib/partitions.js.map +2 -2
  9. package/dist/modules/attachments/setup.js +11 -0
  10. package/dist/modules/attachments/setup.js.map +7 -0
  11. package/dist/modules/audit_logs/setup.js +12 -0
  12. package/dist/modules/audit_logs/setup.js.map +7 -0
  13. package/dist/modules/auth/lib/setup-app.js +29 -159
  14. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  15. package/dist/modules/auth/setup.js +11 -0
  16. package/dist/modules/auth/setup.js.map +7 -0
  17. package/dist/modules/business_rules/setup.js +11 -0
  18. package/dist/modules/business_rules/setup.js.map +7 -0
  19. package/dist/modules/catalog/setup.js +22 -0
  20. package/dist/modules/catalog/setup.js.map +7 -0
  21. package/dist/modules/configs/lib/upgrade-actions.js +65 -15
  22. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  23. package/dist/modules/configs/setup.js +16 -0
  24. package/dist/modules/configs/setup.js.map +7 -0
  25. package/dist/modules/currencies/setup.js +16 -0
  26. package/dist/modules/currencies/setup.js.map +7 -0
  27. package/dist/modules/customers/setup.js +36 -0
  28. package/dist/modules/customers/setup.js.map +7 -0
  29. package/dist/modules/dashboards/setup.js +12 -0
  30. package/dist/modules/dashboards/setup.js.map +7 -0
  31. package/dist/modules/dictionaries/setup.js +12 -0
  32. package/dist/modules/dictionaries/setup.js.map +7 -0
  33. package/dist/modules/directory/setup.js +12 -0
  34. package/dist/modules/directory/setup.js.map +7 -0
  35. package/dist/modules/entities/setup.js +11 -0
  36. package/dist/modules/entities/setup.js.map +7 -0
  37. package/dist/modules/feature_toggles/setup.js +11 -0
  38. package/dist/modules/feature_toggles/setup.js.map +7 -0
  39. package/dist/modules/perspectives/setup.js +12 -0
  40. package/dist/modules/perspectives/setup.js.map +7 -0
  41. package/dist/modules/planner/setup.js +21 -0
  42. package/dist/modules/planner/setup.js.map +7 -0
  43. package/dist/modules/query_index/setup.js +11 -0
  44. package/dist/modules/query_index/setup.js.map +7 -0
  45. package/dist/modules/resources/setup.js +21 -0
  46. package/dist/modules/resources/setup.js.map +7 -0
  47. package/dist/modules/sales/setup.js +99 -0
  48. package/dist/modules/sales/setup.js.map +7 -0
  49. package/dist/modules/staff/setup.js +27 -0
  50. package/dist/modules/staff/setup.js.map +7 -0
  51. package/dist/modules/workflows/lib/seeds.js +3 -15
  52. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  53. package/dist/modules/workflows/migrations/Migration20251207131955.js +76 -72
  54. package/dist/modules/workflows/migrations/Migration20251207131955.js.map +2 -2
  55. package/dist/modules/workflows/setup.js +16 -0
  56. package/dist/modules/workflows/setup.js.map +7 -0
  57. package/package.json +2 -2
  58. package/src/__tests__/module-decoupling.test.ts +356 -0
  59. package/src/modules/api_keys/setup.ts +9 -0
  60. package/src/modules/attachments/components/AttachmentLibrary.tsx +2 -2
  61. package/src/modules/attachments/lib/assignmentDetails.ts +32 -16
  62. package/src/modules/attachments/lib/partitions.ts +3 -3
  63. package/src/modules/attachments/setup.ts +9 -0
  64. package/src/modules/audit_logs/setup.ts +10 -0
  65. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +30 -0
  66. package/src/modules/auth/lib/setup-app.ts +40 -177
  67. package/src/modules/auth/setup.ts +9 -0
  68. package/src/modules/business_rules/setup.ts +9 -0
  69. package/src/modules/catalog/setup.ts +22 -0
  70. package/src/modules/configs/lib/upgrade-actions.ts +78 -17
  71. package/src/modules/configs/setup.ts +14 -0
  72. package/src/modules/currencies/setup.ts +15 -0
  73. package/src/modules/customers/setup.ts +36 -0
  74. package/src/modules/dashboards/setup.ts +10 -0
  75. package/src/modules/dictionaries/setup.ts +10 -0
  76. package/src/modules/directory/setup.ts +10 -0
  77. package/src/modules/entities/setup.ts +9 -0
  78. package/src/modules/feature_toggles/setup.ts +9 -0
  79. package/src/modules/perspectives/setup.ts +10 -0
  80. package/src/modules/planner/setup.ts +21 -0
  81. package/src/modules/query_index/setup.ts +9 -0
  82. package/src/modules/resources/setup.ts +21 -0
  83. package/src/modules/sales/setup.ts +108 -0
  84. package/src/modules/staff/setup.ts +27 -0
  85. package/src/modules/workflows/lib/seeds.ts +4 -16
  86. package/src/modules/workflows/migrations/Migration20251207131955.ts +77 -143
  87. package/src/modules/workflows/setup.ts +15 -0
@@ -4,12 +4,8 @@ import { Role, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/d
4
4
  import { Tenant, Organization } from '@open-mercato/core/modules/directory/data/entities'
5
5
  import { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'
6
6
  import { normalizeTenantId } from './tenantAccess'
7
- import { SalesSettings, SalesDocumentSequence } from '@open-mercato/core/modules/sales/data/entities'
8
- import {
9
- DEFAULT_ORDER_NUMBER_FORMAT,
10
- DEFAULT_QUOTE_NUMBER_FORMAT,
11
- } from '@open-mercato/core/modules/sales/lib/documentNumberTokens'
12
7
  import { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'
8
+ import type { Module } from '@open-mercato/shared/modules/registry'
13
9
  import { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'
14
10
  import { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'
15
11
  import { DEFAULT_ENCRYPTION_MAPS } from '@open-mercato/core/modules/entities/lib/encryptionDefaults'
@@ -95,6 +91,8 @@ export type SetupInitialTenantOptions = {
95
91
  failIfUserExists?: boolean
96
92
  primaryUserRoles?: string[]
97
93
  includeSuperadminRole?: boolean
94
+ /** Optional list of enabled modules. When provided, module setup hooks are called. */
95
+ modules?: Module[]
98
96
  }
99
97
 
100
98
  export type SetupInitialTenantResult = {
@@ -321,9 +319,16 @@ export async function setupInitialTenant(
321
319
  await rebuildHierarchyForTenant(em, tenantId)
322
320
  }
323
321
 
324
- await ensureDefaultRoleAcls(em, tenantId, { includeSuperadminRole })
322
+ const resolvedModules = options.modules ?? tryGetModules()
323
+ await ensureDefaultRoleAcls(em, tenantId, resolvedModules, { includeSuperadminRole })
325
324
  await deactivateDemoSuperAdminIfSelfOnboardingEnabled(em)
326
- await ensureSalesNumberingDefaults(em, { tenantId, organizationId })
325
+
326
+ // Call module onTenantCreated hooks
327
+ for (const mod of resolvedModules) {
328
+ if (mod.setup?.onTenantCreated) {
329
+ await mod.setup.onTenantCreated({ em, tenantId, organizationId })
330
+ }
331
+ }
327
332
 
328
333
  return {
329
334
  tenantId,
@@ -349,6 +354,7 @@ async function resolvePasswordHash(input: PrimaryUserInput): Promise<string | nu
349
354
  async function ensureDefaultRoleAcls(
350
355
  em: EntityManager,
351
356
  tenantId: string,
357
+ modules: Module[],
352
358
  options: { includeSuperadminRole?: boolean } = {},
353
359
  ) {
354
360
  const includeSuperadminRole = options.includeSuperadminRole ?? true
@@ -357,84 +363,27 @@ async function ensureDefaultRoleAcls(
357
363
  const adminRole = await findRoleByName(em, 'admin', roleTenantId)
358
364
  const employeeRole = await findRoleByName(em, 'employee', roleTenantId)
359
365
 
366
+ // Merge features from all enabled modules' setup configs
367
+ const superadminFeatures: string[] = []
368
+ const adminFeatures: string[] = []
369
+ const employeeFeatures: string[] = []
370
+
371
+ for (const mod of modules) {
372
+ const roleFeatures = mod.setup?.defaultRoleFeatures
373
+ if (!roleFeatures) continue
374
+ if (roleFeatures.superadmin) superadminFeatures.push(...roleFeatures.superadmin)
375
+ if (roleFeatures.admin) adminFeatures.push(...roleFeatures.admin)
376
+ if (roleFeatures.employee) employeeFeatures.push(...roleFeatures.employee)
377
+ }
378
+
360
379
  if (includeSuperadminRole && superadminRole) {
361
- await ensureRoleAclFor(em, superadminRole, tenantId, ['directory.tenants.*'], { isSuperAdmin: true })
380
+ await ensureRoleAclFor(em, superadminRole, tenantId, superadminFeatures, { isSuperAdmin: true })
362
381
  }
363
382
  if (adminRole) {
364
- const adminFeatures = [
365
- 'auth.*',
366
- 'entities.*',
367
- 'attachments.*',
368
- 'attachments.view',
369
- 'attachments.manage',
370
- 'query_index.*',
371
- 'search.*',
372
- 'vector.*',
373
- 'feature_toggles.*',
374
- 'configs.system_status.view',
375
- 'configs.cache.view',
376
- 'configs.cache.manage',
377
- 'configs.manage',
378
- 'catalog.*',
379
- 'catalog.variants.manage',
380
- 'catalog.pricing.manage',
381
- 'sales.*',
382
- 'audit_logs.*',
383
- 'directory.organizations.view',
384
- 'directory.organizations.manage',
385
- 'customers.*',
386
- 'customers.people.view',
387
- 'customers.people.manage',
388
- 'customers.companies.view',
389
- 'customers.companies.manage',
390
- 'customers.deals.view',
391
- 'customers.deals.manage',
392
- 'dictionaries.view',
393
- 'dictionaries.manage',
394
- 'example.*',
395
- 'dashboards.*',
396
- 'dashboards.admin.assign-widgets',
397
- 'analytics.view',
398
- 'api_keys.*',
399
- 'perspectives.use',
400
- 'perspectives.role_defaults',
401
- 'business_rules.*',
402
- 'workflows.*',
403
- 'currencies.*',
404
- 'staff.*',
405
- 'staff.leave_requests.manage',
406
- 'resources.*',
407
- 'planner.*',
408
- ]
409
- await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures, { remove: ['directory.organizations.*', 'directory.tenants.*'] })
383
+ await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures)
410
384
  }
411
385
  if (employeeRole) {
412
- await ensureRoleAclFor(em, employeeRole, tenantId, [
413
- 'customers.*',
414
- 'customers.people.view',
415
- 'customers.people.manage',
416
- 'customers.companies.view',
417
- 'customers.companies.manage',
418
- 'vector.*',
419
- 'catalog.*',
420
- 'catalog.variants.manage',
421
- 'catalog.pricing.manage',
422
- 'sales.*',
423
- 'dictionaries.view',
424
- 'example.*',
425
- 'example.widgets.*',
426
- 'dashboards.view',
427
- 'dashboards.configure',
428
- 'analytics.view',
429
- 'audit_logs.undo_self',
430
- 'perspectives.use',
431
- 'staff.leave_requests.send',
432
- 'staff.my_availability.view',
433
- 'staff.my_availability.manage',
434
- 'staff.my_leave_requests.view',
435
- 'staff.my_leave_requests.send',
436
- 'planner.view',
437
- ])
386
+ await ensureRoleAclFor(em, employeeRole, tenantId, employeeFeatures)
438
387
  }
439
388
  }
440
389
 
@@ -443,7 +392,7 @@ async function ensureRoleAclFor(
443
392
  role: Role,
444
393
  tenantId: string,
445
394
  features: string[],
446
- options: { isSuperAdmin?: boolean; remove?: string[] } = {},
395
+ options: { isSuperAdmin?: boolean } = {},
447
396
  ) {
448
397
  const existing = await em.findOne(RoleAcl, { role, tenantId })
449
398
  if (!existing) {
@@ -459,24 +408,10 @@ async function ensureRoleAclFor(
459
408
  }
460
409
  const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []
461
410
  const merged = Array.from(new Set([...currentFeatures, ...features]))
462
- const removeSet = new Set(options.remove ?? [])
463
- const sanitized =
464
- removeSet.size
465
- ? merged.filter((value) => {
466
- if (removeSet.has(value)) return false
467
- for (const entry of removeSet) {
468
- if (entry.endsWith('.*')) {
469
- const prefix = entry.slice(0, -1) // keep trailing dot
470
- if (value === entry || value.startsWith(prefix)) return false
471
- }
472
- }
473
- return true
474
- })
475
- : merged
476
411
  const changed =
477
- sanitized.length !== currentFeatures.length ||
478
- sanitized.some((value, index) => value !== currentFeatures[index])
479
- if (changed) existing.featuresJson = sanitized
412
+ merged.length !== currentFeatures.length ||
413
+ merged.some((value, index) => value !== currentFeatures[index])
414
+ if (changed) existing.featuresJson = merged
480
415
  if (options.isSuperAdmin && !existing.isSuperAdmin) {
481
416
  existing.isSuperAdmin = true
482
417
  }
@@ -507,84 +442,12 @@ async function deactivateDemoSuperAdminIfSelfOnboardingEnabled(em: EntityManager
507
442
  }
508
443
  }
509
444
 
510
- async function ensureSalesNumberingDefaults(
511
- em: EntityManager,
512
- scope: { tenantId: string; organizationId: string },
513
- ) {
514
- const repo = (em as any).getRepository?.(SalesSettings)
515
- const findSettings = async () =>
516
- repo?.findOne({
517
- tenantId: scope.tenantId,
518
- organizationId: scope.organizationId,
519
- }) ??
520
- (em as any).findOne?.(SalesSettings, {
521
- tenantId: scope.tenantId,
522
- organizationId: scope.organizationId,
523
- })
524
-
525
- const exists = await findSettings()
526
- if (!exists) {
527
- const settings =
528
- repo?.create?.({
529
- tenantId: scope.tenantId,
530
- organizationId: scope.organizationId,
531
- orderNumberFormat: DEFAULT_ORDER_NUMBER_FORMAT,
532
- quoteNumberFormat: DEFAULT_QUOTE_NUMBER_FORMAT,
533
- createdAt: new Date(),
534
- updatedAt: new Date(),
535
- }) ??
536
- (em as any).create?.(SalesSettings, {
537
- tenantId: scope.tenantId,
538
- organizationId: scope.organizationId,
539
- orderNumberFormat: DEFAULT_ORDER_NUMBER_FORMAT,
540
- quoteNumberFormat: DEFAULT_QUOTE_NUMBER_FORMAT,
541
- createdAt: new Date(),
542
- updatedAt: new Date(),
543
- })
544
- if (settings && (em as any).persist) {
545
- em.persist(settings)
546
- }
547
- }
548
-
549
- const sequenceRepo = (em as any).getRepository?.(SalesDocumentSequence)
550
- const kinds: Array<'order' | 'quote'> = ['order', 'quote']
551
- for (const kind of kinds) {
552
- const seq =
553
- sequenceRepo?.findOne({
554
- tenantId: scope.tenantId,
555
- organizationId: scope.organizationId,
556
- documentKind: kind,
557
- }) ??
558
- (em as any).findOne?.(SalesDocumentSequence, {
559
- tenantId: scope.tenantId,
560
- organizationId: scope.organizationId,
561
- documentKind: kind,
562
- })
563
- if (!seq) {
564
- const entry =
565
- sequenceRepo?.create?.({
566
- tenantId: scope.tenantId,
567
- organizationId: scope.organizationId,
568
- documentKind: kind,
569
- currentValue: 0,
570
- createdAt: new Date(),
571
- updatedAt: new Date(),
572
- }) ??
573
- (em as any).create?.(SalesDocumentSequence, {
574
- tenantId: scope.tenantId,
575
- organizationId: scope.organizationId,
576
- documentKind: kind,
577
- currentValue: 0,
578
- createdAt: new Date(),
579
- updatedAt: new Date(),
580
- })
581
- if (entry && (em as any).persist) {
582
- em.persist(entry)
583
- }
584
- }
585
- }
586
-
587
- if ((em as any).flush) {
588
- await em.flush()
445
+ /** Try to get modules from runtime registry; returns empty array if not yet registered. */
446
+ function tryGetModules(): Module[] {
447
+ try {
448
+ const { getModules } = require('@open-mercato/shared/lib/modules/registry')
449
+ return getModules()
450
+ } catch {
451
+ return []
589
452
  }
590
453
  }
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['auth.*'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['business_rules.*'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -0,0 +1,22 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+ import { seedCatalogUnits, seedCatalogPriceKinds, seedCatalogExamplesForScope } from './lib/seeds'
3
+
4
+ export const setup: ModuleSetupConfig = {
5
+ seedDefaults: async (ctx) => {
6
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
7
+ await seedCatalogUnits(ctx.em, scope)
8
+ await seedCatalogPriceKinds(ctx.em, scope)
9
+ },
10
+
11
+ seedExamples: async (ctx) => {
12
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
13
+ await seedCatalogExamplesForScope(ctx.em, ctx.container, scope)
14
+ },
15
+
16
+ defaultRoleFeatures: {
17
+ admin: ['catalog.*', 'catalog.variants.manage', 'catalog.pricing.manage'],
18
+ employee: ['catalog.*', 'catalog.variants.manage', 'catalog.pricing.manage'],
19
+ },
20
+ }
21
+
22
+ export default setup
@@ -4,13 +4,8 @@ import type { AwilixContainer } from 'awilix'
4
4
  import { Role, RoleAcl } from '@open-mercato/core/modules/auth/data/entities'
5
5
  import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
6
6
  import { reindexModules } from '@open-mercato/core/modules/configs/lib/reindex-helpers'
7
- import { installExampleCatalogData, type CatalogSeedScope } from '@open-mercato/core/modules/catalog/lib/seeds'
8
- import { seedSalesExamples } from '@open-mercato/core/modules/sales/seed/examples'
9
- import { seedExampleCurrencies } from '@open-mercato/core/modules/currencies/lib/seeds'
10
- import { seedExampleWorkflows } from '@open-mercato/core/modules/workflows/lib/seeds'
11
- import { seedPlannerAvailabilityRuleSetDefaults, seedPlannerUnavailabilityReasons } from '@open-mercato/core/modules/planner/lib/seeds'
12
- import { seedResourcesAddressTypes, seedResourcesCapacityUnits, seedResourcesResourceExamples } from '@open-mercato/core/modules/resources/lib/seeds'
13
- import { seedStaffTeamExamples } from '@open-mercato/core/modules/staff/lib/seeds'
7
+ // Optional module imports are loaded dynamically inside each upgrade action
8
+ // so the app does not crash when a module is disabled.
14
9
  import { collectCrudCacheStats, purgeCrudCacheSegment } from '@open-mercato/shared/lib/crud/cache-stats'
15
10
  import { isCrudCacheEnabled, resolveCrudCache } from '@open-mercato/shared/lib/crud/cache'
16
11
  import * as semver from 'semver'
@@ -91,7 +86,9 @@ async function ensureVectorSearchEncryptionMap(
91
86
  return true
92
87
  }
93
88
 
94
- export type UpgradeActionContext = CatalogSeedScope & {
89
+ export type UpgradeActionContext = {
90
+ tenantId: string
91
+ organizationId: string
95
92
  container: AwilixContainer
96
93
  em: EntityManager
97
94
  }
@@ -155,6 +152,14 @@ export const upgradeActions: UpgradeActionDefinition[] = [
155
152
  successKey: 'upgrades.v034.success',
156
153
  loadingKey: 'upgrades.v034.loading',
157
154
  async run({ container, em, tenantId, organizationId }) {
155
+ let installExampleCatalogData: typeof import('@open-mercato/core/modules/catalog/lib/seeds')['installExampleCatalogData'] | undefined
156
+ try {
157
+ const catalogSeeds = await import('@open-mercato/core/modules/catalog/lib/seeds')
158
+ installExampleCatalogData = catalogSeeds.installExampleCatalogData
159
+ } catch {
160
+ console.warn('[upgrade-actions] catalog module not available, skipping catalog example data')
161
+ return
162
+ }
158
163
  await installExampleCatalogData(container, { tenantId, organizationId }, em)
159
164
  const vectorService = resolveVectorService(container)
160
165
  await reindexModules(em, ['catalog'], { tenantId, organizationId, vectorService })
@@ -214,8 +219,16 @@ export const upgradeActions: UpgradeActionDefinition[] = [
214
219
  successKey: 'upgrades.v036.success',
215
220
  loadingKey: 'upgrades.v036.loading',
216
221
  async run({ container, em, tenantId, organizationId }) {
222
+ let seedSalesExamples: typeof import('@open-mercato/core/modules/sales/seed/examples')['seedSalesExamples'] | undefined
223
+ try {
224
+ const salesSeeds = await import('@open-mercato/core/modules/sales/seed/examples')
225
+ seedSalesExamples = salesSeeds.seedSalesExamples
226
+ } catch {
227
+ console.warn('[upgrade-actions] sales module not available, skipping sales example data')
228
+ return
229
+ }
217
230
  await em.transactional(async (tem) => {
218
- await seedSalesExamples(tem, container, { tenantId, organizationId })
231
+ await seedSalesExamples!(tem, container, { tenantId, organizationId })
219
232
  })
220
233
  const vectorService = resolveVectorService(container)
221
234
  await reindexModules(em, ['sales', 'catalog'], { tenantId, organizationId, vectorService })
@@ -262,9 +275,26 @@ export const upgradeActions: UpgradeActionDefinition[] = [
262
275
  async run({ container, em, tenantId, organizationId }) {
263
276
  const normalizedTenantId = tenantId.trim()
264
277
  const scope = { tenantId, organizationId }
278
+
279
+ let seedExampleCurrencies: typeof import('@open-mercato/core/modules/currencies/lib/seeds')['seedExampleCurrencies'] | undefined
280
+ try {
281
+ const currenciesSeeds = await import('@open-mercato/core/modules/currencies/lib/seeds')
282
+ seedExampleCurrencies = currenciesSeeds.seedExampleCurrencies
283
+ } catch {
284
+ console.warn('[upgrade-actions] currencies module not available, skipping currency seeding')
285
+ }
286
+
287
+ let seedExampleWorkflows: typeof import('@open-mercato/core/modules/workflows/lib/seeds')['seedExampleWorkflows'] | undefined
288
+ try {
289
+ const workflowsSeeds = await import('@open-mercato/core/modules/workflows/lib/seeds')
290
+ seedExampleWorkflows = workflowsSeeds.seedExampleWorkflows
291
+ } catch {
292
+ console.warn('[upgrade-actions] workflows module not available, skipping workflow seeding')
293
+ }
294
+
265
295
  await em.transactional(async (tem) => {
266
- await seedExampleCurrencies(tem, scope)
267
- await seedExampleWorkflows(tem, scope)
296
+ if (seedExampleCurrencies) await seedExampleCurrencies(tem, scope)
297
+ if (seedExampleWorkflows) await seedExampleWorkflows(tem, scope)
268
298
 
269
299
  const adminRole = await tem.findOne(Role, { name: 'admin', tenantId: normalizedTenantId, deletedAt: null })
270
300
  if (!adminRole) return
@@ -315,13 +345,44 @@ export const upgradeActions: UpgradeActionDefinition[] = [
315
345
  async run({ container, em, tenantId, organizationId }) {
316
346
  const normalizedTenantId = tenantId.trim()
317
347
  const scope = { tenantId, organizationId }
348
+
349
+ let seedPlannerAvailabilityRuleSetDefaults: typeof import('@open-mercato/core/modules/planner/lib/seeds')['seedPlannerAvailabilityRuleSetDefaults'] | undefined
350
+ let seedPlannerUnavailabilityReasons: typeof import('@open-mercato/core/modules/planner/lib/seeds')['seedPlannerUnavailabilityReasons'] | undefined
351
+ try {
352
+ const plannerSeeds = await import('@open-mercato/core/modules/planner/lib/seeds')
353
+ seedPlannerAvailabilityRuleSetDefaults = plannerSeeds.seedPlannerAvailabilityRuleSetDefaults
354
+ seedPlannerUnavailabilityReasons = plannerSeeds.seedPlannerUnavailabilityReasons
355
+ } catch {
356
+ console.warn('[upgrade-actions] planner module not available, skipping planner seeding')
357
+ }
358
+
359
+ let seedStaffTeamExamples: typeof import('@open-mercato/core/modules/staff/lib/seeds')['seedStaffTeamExamples'] | undefined
360
+ try {
361
+ const staffSeeds = await import('@open-mercato/core/modules/staff/lib/seeds')
362
+ seedStaffTeamExamples = staffSeeds.seedStaffTeamExamples
363
+ } catch {
364
+ console.warn('[upgrade-actions] staff module not available, skipping staff seeding')
365
+ }
366
+
367
+ let seedResourcesAddressTypes: typeof import('@open-mercato/core/modules/resources/lib/seeds')['seedResourcesAddressTypes'] | undefined
368
+ let seedResourcesCapacityUnits: typeof import('@open-mercato/core/modules/resources/lib/seeds')['seedResourcesCapacityUnits'] | undefined
369
+ let seedResourcesResourceExamples: typeof import('@open-mercato/core/modules/resources/lib/seeds')['seedResourcesResourceExamples'] | undefined
370
+ try {
371
+ const resourcesSeeds = await import('@open-mercato/core/modules/resources/lib/seeds')
372
+ seedResourcesAddressTypes = resourcesSeeds.seedResourcesAddressTypes
373
+ seedResourcesCapacityUnits = resourcesSeeds.seedResourcesCapacityUnits
374
+ seedResourcesResourceExamples = resourcesSeeds.seedResourcesResourceExamples
375
+ } catch {
376
+ console.warn('[upgrade-actions] resources module not available, skipping resources seeding')
377
+ }
378
+
318
379
  await em.transactional(async (tem) => {
319
- await seedPlannerAvailabilityRuleSetDefaults(tem, scope)
320
- await seedPlannerUnavailabilityReasons(tem, scope)
321
- await seedStaffTeamExamples(tem, scope)
322
- await seedResourcesCapacityUnits(tem, scope)
323
- await seedResourcesAddressTypes(tem, scope)
324
- await seedResourcesResourceExamples(tem, scope)
380
+ if (seedPlannerAvailabilityRuleSetDefaults) await seedPlannerAvailabilityRuleSetDefaults(tem, scope)
381
+ if (seedPlannerUnavailabilityReasons) await seedPlannerUnavailabilityReasons(tem, scope)
382
+ if (seedStaffTeamExamples) await seedStaffTeamExamples(tem, scope)
383
+ if (seedResourcesCapacityUnits) await seedResourcesCapacityUnits(tem, scope)
384
+ if (seedResourcesAddressTypes) await seedResourcesAddressTypes(tem, scope)
385
+ if (seedResourcesResourceExamples) await seedResourcesResourceExamples(tem, scope)
325
386
 
326
387
  const adminRole = await tem.findOne(Role, { name: 'admin', tenantId: normalizedTenantId, deletedAt: null })
327
388
  if (!adminRole) return
@@ -0,0 +1,14 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: [
6
+ 'configs.system_status.view',
7
+ 'configs.cache.view',
8
+ 'configs.cache.manage',
9
+ 'configs.manage',
10
+ ],
11
+ },
12
+ }
13
+
14
+ export default setup
@@ -0,0 +1,15 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+ import { seedExampleCurrencies } from './lib/seeds'
3
+
4
+ export const setup: ModuleSetupConfig = {
5
+ seedDefaults: async (ctx) => {
6
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
7
+ await seedExampleCurrencies(ctx.em, scope)
8
+ },
9
+
10
+ defaultRoleFeatures: {
11
+ admin: ['currencies.*'],
12
+ },
13
+ }
14
+
15
+ export default setup
@@ -0,0 +1,36 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+ import { seedCustomerDictionaries, seedCurrencyDictionary, seedCustomerExamples } from './cli'
3
+
4
+ export const setup: ModuleSetupConfig = {
5
+ seedDefaults: async (ctx) => {
6
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
7
+ await seedCustomerDictionaries(ctx.em, scope)
8
+ await seedCurrencyDictionary(ctx.em, scope)
9
+ },
10
+
11
+ seedExamples: async (ctx) => {
12
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
13
+ await seedCustomerExamples(ctx.em, ctx.container, scope)
14
+ },
15
+
16
+ defaultRoleFeatures: {
17
+ admin: [
18
+ 'customers.*',
19
+ 'customers.people.view',
20
+ 'customers.people.manage',
21
+ 'customers.companies.view',
22
+ 'customers.companies.manage',
23
+ 'customers.deals.view',
24
+ 'customers.deals.manage',
25
+ ],
26
+ employee: [
27
+ 'customers.*',
28
+ 'customers.people.view',
29
+ 'customers.people.manage',
30
+ 'customers.companies.view',
31
+ 'customers.companies.manage',
32
+ ],
33
+ },
34
+ }
35
+
36
+ export default setup
@@ -0,0 +1,10 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['dashboards.*', 'dashboards.admin.assign-widgets', 'analytics.view'],
6
+ employee: ['dashboards.view', 'dashboards.configure', 'analytics.view'],
7
+ },
8
+ }
9
+
10
+ export default setup
@@ -0,0 +1,10 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['dictionaries.view', 'dictionaries.manage'],
6
+ employee: ['dictionaries.view'],
7
+ },
8
+ }
9
+
10
+ export default setup
@@ -0,0 +1,10 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ superadmin: ['directory.tenants.*'],
6
+ admin: ['directory.organizations.view', 'directory.organizations.manage'],
7
+ },
8
+ }
9
+
10
+ export default setup
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['entities.*'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['feature_toggles.*'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -0,0 +1,10 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['perspectives.use', 'perspectives.role_defaults'],
6
+ employee: ['perspectives.use'],
7
+ },
8
+ }
9
+
10
+ export default setup
@@ -0,0 +1,21 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+ import { seedPlannerUnavailabilityReasons, seedPlannerAvailabilityRuleSetDefaults } from './lib/seeds'
3
+
4
+ export const setup: ModuleSetupConfig = {
5
+ seedDefaults: async (ctx) => {
6
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
7
+ await seedPlannerUnavailabilityReasons(ctx.em, scope)
8
+ },
9
+
10
+ seedExamples: async (ctx) => {
11
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
12
+ await seedPlannerAvailabilityRuleSetDefaults(ctx.em, scope)
13
+ },
14
+
15
+ defaultRoleFeatures: {
16
+ admin: ['planner.*'],
17
+ employee: ['planner.view'],
18
+ },
19
+ }
20
+
21
+ export default setup
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['query_index.*'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -0,0 +1,21 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+ import { seedResourcesAddressTypes, seedResourcesCapacityUnits, seedResourcesResourceExamples } from './lib/seeds'
3
+
4
+ export const setup: ModuleSetupConfig = {
5
+ seedDefaults: async (ctx) => {
6
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
7
+ await seedResourcesAddressTypes(ctx.em, scope)
8
+ },
9
+
10
+ seedExamples: async (ctx) => {
11
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
12
+ await seedResourcesCapacityUnits(ctx.em, scope)
13
+ await seedResourcesResourceExamples(ctx.em, scope)
14
+ },
15
+
16
+ defaultRoleFeatures: {
17
+ admin: ['resources.*'],
18
+ },
19
+ }
20
+
21
+ export default setup