@solidxai/core 0.1.13-beta.7 → 0.1.13-beta.9

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 (259) hide show
  1. package/.claude/settings.local.json +16 -0
  2. package/CHANGELOG.md +1651 -0
  3. package/CLAUDE.md +26 -0
  4. package/dist/constants/draft-publish-fields.d.ts +2 -0
  5. package/dist/constants/draft-publish-fields.d.ts.map +1 -0
  6. package/dist/constants/draft-publish-fields.js +5 -0
  7. package/dist/constants/draft-publish-fields.js.map +1 -0
  8. package/dist/constants/media-file-types.d.ts +9 -0
  9. package/dist/constants/media-file-types.d.ts.map +1 -1
  10. package/dist/constants/media-file-types.js +27 -1
  11. package/dist/constants/media-file-types.js.map +1 -1
  12. package/dist/controllers/action-metadata.controller.d.ts +1 -1
  13. package/dist/controllers/action-metadata.controller.js +1 -1
  14. package/dist/controllers/agent-event.controller.d.ts +1 -1
  15. package/dist/controllers/agent-event.controller.js +1 -1
  16. package/dist/controllers/agent-session.controller.d.ts +1 -1
  17. package/dist/controllers/agent-session.controller.js +1 -1
  18. package/dist/controllers/dashboard-user-layout.controller.d.ts +1 -1
  19. package/dist/controllers/dashboard-user-layout.controller.js +1 -1
  20. package/dist/controllers/email-template.controller.d.ts +1 -1
  21. package/dist/controllers/email-template.controller.js +1 -1
  22. package/dist/controllers/export-template.controller.d.ts +1 -1
  23. package/dist/controllers/export-template.controller.d.ts.map +1 -1
  24. package/dist/controllers/export-template.controller.js +6 -4
  25. package/dist/controllers/export-template.controller.js.map +1 -1
  26. package/dist/controllers/export-transaction.controller.d.ts +1 -1
  27. package/dist/controllers/export-transaction.controller.js +1 -1
  28. package/dist/controllers/import-transaction-error-log.controller.d.ts +1 -1
  29. package/dist/controllers/import-transaction-error-log.controller.js +1 -1
  30. package/dist/controllers/import-transaction.controller.d.ts +1 -1
  31. package/dist/controllers/import-transaction.controller.d.ts.map +1 -1
  32. package/dist/controllers/import-transaction.controller.js +7 -7
  33. package/dist/controllers/import-transaction.controller.js.map +1 -1
  34. package/dist/controllers/list-of-values.controller.d.ts +1 -1
  35. package/dist/controllers/list-of-values.controller.js +1 -1
  36. package/dist/controllers/locale.controller.d.ts +1 -1
  37. package/dist/controllers/locale.controller.js +1 -1
  38. package/dist/controllers/mcp-audit-log.controller.d.ts +1 -1
  39. package/dist/controllers/mcp-audit-log.controller.js +1 -1
  40. package/dist/controllers/media.controller.d.ts +1 -1
  41. package/dist/controllers/media.controller.d.ts.map +1 -1
  42. package/dist/controllers/media.controller.js +12 -7
  43. package/dist/controllers/media.controller.js.map +1 -1
  44. package/dist/controllers/menu-item-metadata.controller.d.ts +1 -1
  45. package/dist/controllers/menu-item-metadata.controller.js +1 -1
  46. package/dist/controllers/model-sequence.controller.d.ts +1 -1
  47. package/dist/controllers/model-sequence.controller.js +1 -1
  48. package/dist/controllers/module-package.controller.d.ts.map +1 -1
  49. package/dist/controllers/module-package.controller.js +2 -3
  50. package/dist/controllers/module-package.controller.js.map +1 -1
  51. package/dist/controllers/mq-message-queue.controller.d.ts +1 -1
  52. package/dist/controllers/mq-message-queue.controller.js +1 -1
  53. package/dist/controllers/mq-message.controller.d.ts +1 -1
  54. package/dist/controllers/mq-message.controller.js +1 -1
  55. package/dist/controllers/permission-metadata.controller.d.ts +1 -1
  56. package/dist/controllers/permission-metadata.controller.js +1 -1
  57. package/dist/controllers/role-metadata.controller.d.ts +1 -1
  58. package/dist/controllers/role-metadata.controller.js +1 -1
  59. package/dist/controllers/saved-filters.controller.d.ts +1 -1
  60. package/dist/controllers/saved-filters.controller.js +1 -1
  61. package/dist/controllers/scheduled-job.controller.d.ts +1 -1
  62. package/dist/controllers/scheduled-job.controller.js +1 -1
  63. package/dist/controllers/security-rule.controller.d.ts +1 -1
  64. package/dist/controllers/security-rule.controller.js +1 -1
  65. package/dist/controllers/sms-template.controller.d.ts +1 -1
  66. package/dist/controllers/sms-template.controller.js +1 -1
  67. package/dist/controllers/user-activity-history.controller.d.ts +1 -1
  68. package/dist/controllers/user-activity-history.controller.js +1 -1
  69. package/dist/controllers/user-view-metadata.controller.d.ts +1 -1
  70. package/dist/controllers/user-view-metadata.controller.js +1 -1
  71. package/dist/controllers/user.controller.d.ts +2 -2
  72. package/dist/controllers/user.controller.js +2 -2
  73. package/dist/controllers/view-metadata.controller.d.ts +2 -2
  74. package/dist/controllers/view-metadata.controller.js +1 -1
  75. package/dist/controllers/workflow-definition.controller.d.ts +1 -1
  76. package/dist/controllers/workflow-definition.controller.js +1 -1
  77. package/dist/controllers/workflow-execution-artifact.controller.d.ts +1 -1
  78. package/dist/controllers/workflow-execution-artifact.controller.js +1 -1
  79. package/dist/controllers/workflow-execution-log.controller.d.ts +1 -1
  80. package/dist/controllers/workflow-execution-log.controller.js +1 -1
  81. package/dist/controllers/workflow-execution.controller.d.ts +1 -1
  82. package/dist/controllers/workflow-execution.controller.js +1 -1
  83. package/dist/controllers/workflow-secret.controller.d.ts +1 -1
  84. package/dist/controllers/workflow-secret.controller.js +1 -1
  85. package/dist/controllers/workflow-step-execution.controller.d.ts +1 -1
  86. package/dist/controllers/workflow-step-execution.controller.js +1 -1
  87. package/dist/controllers/workflow-trigger-execution.controller.d.ts +1 -1
  88. package/dist/controllers/workflow-trigger-execution.controller.js +1 -1
  89. package/dist/dtos/basic-filters.dto.d.ts +0 -1
  90. package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
  91. package/dist/dtos/basic-filters.dto.js +1 -6
  92. package/dist/dtos/basic-filters.dto.js.map +1 -1
  93. package/dist/entities/common.entity.d.ts +4 -0
  94. package/dist/entities/common.entity.d.ts.map +1 -1
  95. package/dist/entities/common.entity.js +25 -1
  96. package/dist/entities/common.entity.js.map +1 -1
  97. package/dist/entities/user.entity.js +2 -2
  98. package/dist/entities/user.entity.js.map +1 -1
  99. package/dist/factories/mail.factory.d.ts.map +1 -1
  100. package/dist/factories/mail.factory.js +4 -0
  101. package/dist/factories/mail.factory.js.map +1 -1
  102. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +1 -0
  103. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
  104. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +18 -11
  105. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
  106. package/dist/helpers/file-download.helper.d.ts +9 -0
  107. package/dist/helpers/file-download.helper.d.ts.map +1 -0
  108. package/dist/helpers/file-download.helper.js +14 -0
  109. package/dist/helpers/file-download.helper.js.map +1 -0
  110. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  111. package/dist/helpers/model-metadata-helper.service.js +30 -1
  112. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  113. package/dist/helpers/solid-registry.js +1 -1
  114. package/dist/helpers/solid-registry.js.map +1 -1
  115. package/dist/index.d.ts +2 -0
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +2 -0
  118. package/dist/index.js.map +1 -1
  119. package/dist/seeders/module-test-data.service.d.ts +3 -1
  120. package/dist/seeders/module-test-data.service.d.ts.map +1 -1
  121. package/dist/seeders/module-test-data.service.js +8 -2
  122. package/dist/seeders/module-test-data.service.js.map +1 -1
  123. package/dist/seeders/seed-data/solid-core-metadata.json +2 -0
  124. package/dist/services/authentication.service.d.ts +4 -1
  125. package/dist/services/authentication.service.d.ts.map +1 -1
  126. package/dist/services/authentication.service.js +52 -4
  127. package/dist/services/authentication.service.js.map +1 -1
  128. package/dist/services/chatter-message.service.d.ts +1 -0
  129. package/dist/services/chatter-message.service.d.ts.map +1 -1
  130. package/dist/services/chatter-message.service.js +8 -0
  131. package/dist/services/chatter-message.service.js.map +1 -1
  132. package/dist/services/crud-helper.service.d.ts +5 -2
  133. package/dist/services/crud-helper.service.d.ts.map +1 -1
  134. package/dist/services/crud-helper.service.js +30 -32
  135. package/dist/services/crud-helper.service.js.map +1 -1
  136. package/dist/services/crud.service.d.ts +11 -1
  137. package/dist/services/crud.service.d.ts.map +1 -1
  138. package/dist/services/crud.service.js +79 -66
  139. package/dist/services/crud.service.js.map +1 -1
  140. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  141. package/dist/services/datasource-introspection.service.js.map +1 -1
  142. package/dist/services/draft-publish-helper.service.d.ts +52 -0
  143. package/dist/services/draft-publish-helper.service.d.ts.map +1 -0
  144. package/dist/services/draft-publish-helper.service.js +368 -0
  145. package/dist/services/draft-publish-helper.service.js.map +1 -0
  146. package/dist/services/internationalisation-helper.service.d.ts +19 -0
  147. package/dist/services/internationalisation-helper.service.d.ts.map +1 -0
  148. package/dist/services/internationalisation-helper.service.js +107 -0
  149. package/dist/services/internationalisation-helper.service.js.map +1 -0
  150. package/dist/services/locale.service.d.ts +1 -1
  151. package/dist/services/media.service.d.ts +2 -1
  152. package/dist/services/media.service.d.ts.map +1 -1
  153. package/dist/services/media.service.js +28 -2
  154. package/dist/services/media.service.js.map +1 -1
  155. package/dist/services/metadata-validation.service.d.ts +7 -0
  156. package/dist/services/metadata-validation.service.d.ts.map +1 -0
  157. package/dist/services/metadata-validation.service.js +42 -0
  158. package/dist/services/metadata-validation.service.js.map +1 -0
  159. package/dist/services/model-metadata.service.d.ts.map +1 -1
  160. package/dist/services/model-metadata.service.js +2 -1
  161. package/dist/services/model-metadata.service.js.map +1 -1
  162. package/dist/services/object.utils.d.ts +2 -0
  163. package/dist/services/object.utils.d.ts.map +1 -0
  164. package/dist/services/object.utils.js +11 -0
  165. package/dist/services/object.utils.js.map +1 -0
  166. package/dist/services/settings/default-settings-provider.service.d.ts +10 -10
  167. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  168. package/dist/services/settings/default-settings-provider.service.js +9 -5
  169. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  170. package/dist/services/user.service.d.ts +2 -2
  171. package/dist/services/user.service.d.ts.map +1 -1
  172. package/dist/services/user.service.js +9 -3
  173. package/dist/services/user.service.js.map +1 -1
  174. package/dist/services/view-metadata.service.d.ts +1 -2
  175. package/dist/services/view-metadata.service.d.ts.map +1 -1
  176. package/dist/services/view-metadata.service.js +3 -55
  177. package/dist/services/view-metadata.service.js.map +1 -1
  178. package/dist/services/workflow-definition.service.d.ts +1 -1
  179. package/dist/solid-core.module.d.ts.map +1 -1
  180. package/dist/solid-core.module.js +10 -1
  181. package/dist/solid-core.module.js.map +1 -1
  182. package/package.json +1 -1
  183. package/src/constants/draft-publish-fields.ts +5 -0
  184. package/src/constants/media-file-types.ts +50 -0
  185. package/src/controllers/export-template.controller.ts +5 -3
  186. package/src/controllers/import-transaction.controller.ts +6 -6
  187. package/src/controllers/media.controller.ts +17 -6
  188. package/src/controllers/module-package.controller.ts +2 -3
  189. package/src/dtos/basic-filters.dto.ts +0 -4
  190. package/src/entities/common.entity.ts +24 -0
  191. package/src/entities/user.entity.ts +2 -2
  192. package/src/factories/mail.factory.ts +7 -1
  193. package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +26 -12
  194. package/src/helpers/file-download.helper.ts +31 -0
  195. package/src/helpers/model-metadata-helper.service.ts +32 -1
  196. package/src/helpers/solid-registry.ts +1 -1
  197. package/src/index.ts +2 -0
  198. package/src/seeders/module-test-data.service.ts +6 -0
  199. package/src/seeders/seed-data/solid-core-metadata.json +2 -0
  200. package/src/services/1.js +6 -0
  201. package/src/services/authentication.service.ts +76 -5
  202. package/src/services/chatter-message.service.ts +16 -0
  203. package/src/services/crud-helper.service.ts +16 -34
  204. package/src/services/crud.service.ts +98 -103
  205. package/src/services/datasource-introspection.service.ts +5 -0
  206. package/src/services/draft-publish-helper.service.ts +529 -0
  207. package/src/services/internationalisation-helper.service.ts +148 -0
  208. package/src/services/media.service.ts +48 -3
  209. package/src/services/metadata-validation.service.ts +39 -0
  210. package/src/services/model-metadata.service.ts +4 -1
  211. package/src/services/object.utils.ts +10 -0
  212. package/src/services/settings/default-settings-provider.service.ts +15 -5
  213. package/src/services/user.service.ts +18 -3
  214. package/src/services/view-metadata.service.ts +5 -145
  215. package/src/solid-core.module.ts +16 -3
  216. package/src/testing/README.md +9 -0
  217. package/dist-tests/api/authenticate.spec.js +0 -119
  218. package/dist-tests/api/authenticate.spec.js.map +0 -1
  219. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
  220. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
  221. package/dist-tests/api/ping.spec.js +0 -21
  222. package/dist-tests/api/ping.spec.js.map +0 -1
  223. package/dist-tests/helpers/auth.js +0 -41
  224. package/dist-tests/helpers/auth.js.map +0 -1
  225. package/dist-tests/helpers/env.js +0 -11
  226. package/dist-tests/helpers/env.js.map +0 -1
  227. package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +0 -136
  228. package/docs/agent-builder/team-ready-note-agent-builder.md +0 -305
  229. package/docs/agent-hub-grooming.md +0 -301
  230. package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
  231. package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
  232. package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
  233. package/docs/datasource-introspection-ddl-analysis.md +0 -326
  234. package/docs/datasource-introspection-implementation-plan.md +0 -306
  235. package/docs/grouping-enhancements.md +0 -89
  236. package/docs/java-spring/README.md +0 -3
  237. package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
  238. package/docs/module-package-import-handoff.md +0 -691
  239. package/docs/seed-changes.md +0 -65
  240. package/docs/test-data-workflow.md +0 -200
  241. package/docs/type-declaration-import-issue.md +0 -24
  242. package/docs/workflow/business-automation-example-notes.md +0 -309
  243. package/docs/workflow/control-flow-node-addition-sop.md +0 -324
  244. package/docs/workflow/data-engineering-pipeline-example-notes.md +0 -330
  245. package/docs/workflow/foreach-example-notes.md +0 -187
  246. package/docs/workflow/hello-world-example-notes.md +0 -271
  247. package/docs/workflow/kestra-concepts-plugins-blueprints.md +0 -315
  248. package/docs/workflow/loop-until-example-notes.md +0 -198
  249. package/docs/workflow/microservices-and-apis-example-notes.md +0 -264
  250. package/docs/workflow/samples.md +0 -25
  251. package/docs/workflow/what-is-kestra.md +0 -79
  252. package/docs/workflow/workflow-core-module-handoff-summary.md +0 -191
  253. package/docs/workflow/workflow-module-brd.md +0 -185
  254. package/docs/workflow/workflow-module-domain-model.md +0 -252
  255. package/docs/workflow/workflow-module-metadata-dsl.md +0 -302
  256. package/docs/workflow/workflow-module-technical-spec.md +0 -293
  257. package/docs/workflow/workflow-node-type-contracts.md +0 -635
  258. package/docs/workflow/workflow-node-ui-metadata-contract.md +0 -1262
  259. package/docs/workflow/workflow-solidx-model-field-spec.md +0 -284
@@ -37,6 +37,8 @@ import { ShortTextFieldCrudManager } from "../helpers/field-crud-managers/ShortT
37
37
  import { UUIDFieldCrudManager } from "../helpers/field-crud-managers/UUIDFieldCrudManager";
38
38
  import { ModelMetadataHelperService } from "src/helpers/model-metadata-helper.service";
39
39
  import { FieldCrudManager, MediaWithFullUrl } from "../interfaces";
40
+ import { DraftPublishHelperService } from "./draft-publish-helper.service";
41
+ import { InternationalisationHelperService } from "./internationalisation-helper.service";
40
42
  import { CrudHelperService, FilterCombinator, UserIdFields } from "./crud-helper.service";
41
43
  import { HashingService } from "./hashing.service";
42
44
  import { SolidRegistry } from "src/helpers/solid-registry";
@@ -50,6 +52,8 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
50
52
 
51
53
  private _modelMetadataService: ModelMetadataService;
52
54
  private _crudHelperService: CrudHelperService;
55
+ private _draftPublishHelperService: DraftPublishHelperService;
56
+ private _internationalisationHelperService: InternationalisationHelperService;
53
57
  private _discoveryService: DiscoveryService;
54
58
  private _settingService: SettingService;
55
59
 
@@ -70,6 +74,14 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
70
74
  return this._crudHelperService ??= this.moduleRef.get(CrudHelperService, { strict: false });
71
75
  }
72
76
 
77
+ protected get draftPublishHelperService(): DraftPublishHelperService {
78
+ return this._draftPublishHelperService ??= this.moduleRef.get(DraftPublishHelperService, { strict: false });
79
+ }
80
+
81
+ protected get internationalisationHelperService(): InternationalisationHelperService {
82
+ return this._internationalisationHelperService ??= this.moduleRef.get(InternationalisationHelperService, { strict: false });
83
+ }
84
+
73
85
  protected get discoveryService(): DiscoveryService {
74
86
  return this._discoveryService ??= this.moduleRef.get(DiscoveryService, { strict: false });
75
87
  }
@@ -78,6 +90,19 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
78
90
  return this._settingService ??= this.moduleRef.get(SettingService, { strict: false });
79
91
  }
80
92
 
93
+ private getDraftPublishCrudContext() {
94
+ return {
95
+ repo: this.repo,
96
+ modelName: this.modelName,
97
+ moduleName: this.moduleName,
98
+ validateAndTransformDto: this.validateAndTransformDto.bind(this),
99
+ saveMedia: this.saveMedia.bind(this),
100
+ getDatasourceDefaultEntityManager: this.getDatasourceDefaultEntityManager.bind(this),
101
+ getColumnDatabaseName: this.getColumnDatabaseName.bind(this),
102
+ escapeDatabaseName: this.escapeDatabaseName.bind(this),
103
+ };
104
+ }
105
+
81
106
  private async tryCreateAsExtensionUser(createDto: any): Promise<T | null> {
82
107
  if (this.repo.metadata?.parentEntityMetadata?.target !== User) return null;
83
108
  const registry = this.moduleRef.get(SolidRegistry, { strict: false });
@@ -123,8 +148,11 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
123
148
  try {
124
149
  // 5. Save the entity
125
150
  // For media, we need to use a storage provider and save the media, then save the associated uri against the entity or media table
151
+ this.draftPublishHelperService.applyCreateDefaults(model, createDto);
152
+ this.internationalisationHelperService.applyCreateDefaults(model, createDto, this.moduleRef.get(SolidRegistry, { strict: false }));
126
153
  const entity = this.repo.create(createDto);
127
- const savedEntity = await this.repo.save(entity) as unknown as T;
154
+ let savedEntity = await this.repo.save(entity) as unknown as T;
155
+ savedEntity = await this.draftPublishHelperService.ensureInitialEntityVersionId(model, this.repo, savedEntity);
128
156
 
129
157
  // 6. Save the media
130
158
  if (hasMediaFields) {
@@ -211,9 +239,10 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
211
239
  throw new Error(`Entity [${this.moduleName}.${this.modelName}] with id ${id} not found`);
212
240
  }
213
241
 
214
- if (model.draftPublishWorkflow === true && entity.publishedAt) {
215
- throw new BadRequestException(`Cannot update a published record for model ${this.modelName}. Unpublish it first.`
216
- );
242
+ this.draftPublishHelperService.assertUpdateAllowed(model, entity, this.modelName);
243
+
244
+ if (this.draftPublishHelperService.shouldCopyPublishedVersionForUpdate(model, entity)) {
245
+ return this.draftPublishHelperService.copyPublishedVersionAndUpdate(this.getDraftPublishCrudContext(), id, updateDto, files, isPartialUpdate, model);
217
246
  }
218
247
 
219
248
  // Capture pre-update many-to-many relation state for audit tracking
@@ -245,6 +274,18 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
245
274
  return savedEntity;
246
275
  }
247
276
 
277
+ private getColumnDatabaseName(propertyName: string): string {
278
+ const column = this.repo.metadata.findColumnWithPropertyName(propertyName);
279
+ if (!column) {
280
+ throw new Error(`Column ${propertyName} not found in entity ${this.repo.metadata.name}`);
281
+ }
282
+ return column.databaseName;
283
+ }
284
+
285
+ private escapeDatabaseName(databaseName: string): string {
286
+ return this.repo.manager.connection.driver.escape(databaseName);
287
+ }
288
+
248
289
  /**
249
290
  * Captures the current state of audit-enabled many-to-many relations
250
291
  * before the entity is updated. The snapshot is attached to the entity
@@ -307,32 +348,37 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
307
348
  throw new Error(`Entity [${this.moduleName}.${this.modelName}] with id ${id} not found`);
308
349
  }
309
350
 
310
- if (model.draftPublishWorkflow === true && entity.publishedAt) {
311
- throw new BadRequestException(`Cannot update a published record for model ${this.modelName}, Unpublish it first.`);
351
+ const entitiesToDelete: T[] = [entity];
352
+ if (this.draftPublishHelperService.isDraftPublishEnabled(model)) {
353
+ this.draftPublishHelperService.assertDraftPublishDeleteAllowed(this.modelName, entitiesToDelete);
312
354
  }
313
355
 
314
- // If the model has internationalisation enabled, delete children with defaultEntityLocaleId === this entity's id
315
- if (model.internationalisation) {
316
- // Find all child entities where defaultEntityLocaleId === this entity's id
317
- const childEntities = await this.repo.find({
318
- where: { defaultEntityLocaleId: id } as any
319
- });
356
+ await this.internationalisationHelperService.deleteChildLocaleEntities(this.repo, model, [id]);
320
357
 
321
- if (childEntities.length > 0) {
322
- if (model.enableSoftDelete === true) {
323
- await this.repo.softRemove(childEntities);
324
- } else {
325
- await this.repo.remove(childEntities);
326
- }
327
- }
328
- }
358
+ return this.deleteEntitiesAndPromote(model, entitiesToDelete);
359
+ }
360
+
361
+ private async deleteEntitiesAndPromote(model: ModelMetadata, entitiesToDelete: T[]): Promise<T[]> {
362
+ const isDraftPublishEnabled = this.draftPublishHelperService.isDraftPublishEnabled(model);
363
+ const deletedLatestChainIds = isDraftPublishEnabled
364
+ ? this.draftPublishHelperService.getLatestDraftPublishChainIds(entitiesToDelete)
365
+ : [];
329
366
 
367
+ let deleteResult: T[];
330
368
  if (model.enableSoftDelete === true) {
331
- await this.repo.softRemove(entity);
332
- return this.repo.save(entity);
369
+ this.draftPublishHelperService.markDeletedDraftPublishVersionsAsNotLatest(model, entitiesToDelete);
370
+ await this.repo.softRemove(entitiesToDelete);
371
+ deleteResult = await this.repo.save(entitiesToDelete);
333
372
  } else {
334
- return this.repo.remove(entity);
373
+ deleteResult = await this.repo.remove(entitiesToDelete);
335
374
  }
375
+
376
+ if (isDraftPublishEnabled) {
377
+ const deletedEntityIds = this.draftPublishHelperService.getEntityIds(entitiesToDelete);
378
+ await this.draftPublishHelperService.promoteLatestDraftPublishVersionAfterDelete(this.repo, deletedLatestChainIds, deletedEntityIds);
379
+ }
380
+
381
+ return deleteResult;
336
382
  }
337
383
 
338
384
  private async fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean = false, isUpdate: boolean = false, entityId?: number) {
@@ -529,9 +575,7 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
529
575
  var qb: SelectQueryBuilder<T> = await this.repo.createSecurityRuleAwareQueryBuilder(alias)
530
576
 
531
577
  if (basicFilterDto.groupBy?.length) {
532
- const groupFilterQb = (internationalisation && draftPublishWorkflow)
533
- ? this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef, FilterCombinator.AND, false, false)
534
- : this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, undefined, undefined, undefined, FilterCombinator.AND, false, false);
578
+ const groupFilterQb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef, FilterCombinator.AND, false, false);
535
579
 
536
580
  return this.crudHelperService.executeGroupPipeline(
537
581
  groupFilterQb, basicFilterDto, alias,
@@ -543,9 +587,7 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
543
587
  );
544
588
  }
545
589
  else {
546
- qb = (internationalisation && draftPublishWorkflow)
547
- ? this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef)
548
- : this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
590
+ qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef);
549
591
  const { meta, records } = await this.handleNonGroupFind(qb, populateUserIdFields, populateMedia, offset, limit, alias);
550
592
  return {
551
593
  meta,
@@ -795,6 +837,7 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
795
837
  module: true,
796
838
  });
797
839
 
840
+ const solidRegistry = this.moduleRef.get(SolidRegistry, { strict: false });
798
841
  const entitiesForSave: T[] = [];
799
842
  for (const createDto of createDtos) {
800
843
  // Validate and transform each createDto sequentially
@@ -807,6 +850,7 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
807
850
  }
808
851
  transformedDto = await fieldManager.transformForCreate(createDto);
809
852
  }
853
+ this.internationalisationHelperService.applyCreateDefaults(model, transformedDto, solidRegistry);
810
854
  const entity = this.repo.create(transformedDto);
811
855
  entitiesForSave.push(entity as unknown as T);
812
856
  }
@@ -844,7 +888,7 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
844
888
 
845
889
 
846
890
 
847
- const removedEntities = [];
891
+ const removedEntities: T[] = [];
848
892
  for (let i = 0; i < ids.length; i++) {
849
893
  const id = ids[i]
850
894
  const entity = await this.repo.findOne({
@@ -853,36 +897,21 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
853
897
  } as unknown as FindOptionsWhere<T>,
854
898
  });
855
899
 
900
+ if (!entity) {
901
+ throw new Error(`Entity [${this.moduleName}.${this.modelName}] with id ${id} not found`);
902
+ }
903
+
856
904
  removedEntities.push(entity);
857
905
  }
858
906
 
859
907
 
860
- // entity-level flag
861
- const isDraftPublishEnabled = model?.draftPublishWorkflow === true;
862
-
863
- let publishedEntitiesExists: T[] = [];
864
-
865
- if (isDraftPublishEnabled) {
866
- publishedEntitiesExists = removedEntities.filter(
867
- (x) => !!x?.publishedAt
868
- );
908
+ if (this.draftPublishHelperService.isDraftPublishEnabled(model)) {
909
+ this.draftPublishHelperService.assertDraftPublishDeleteAllowed(this.modelName, removedEntities);
869
910
  }
870
911
 
871
- if (publishedEntitiesExists.length > 0) {
872
- const publishedEntitiesExistsID = publishedEntitiesExists.map(x => x.id);
912
+ await this.internationalisationHelperService.deleteChildLocaleEntities(this.repo, model, ids);
873
913
 
874
- throw new BadRequestException(
875
- `Cannot delete published record(s) for model ${this.modelName} with Ids ${publishedEntitiesExistsID.join(', ')}. Unpublish them first.`
876
- );
877
- }
878
-
879
- if (model.enableSoftDelete === true) {
880
- await this.repo.softRemove(removedEntities);
881
- return this.repo.save(removedEntities);
882
- } else {
883
- return this.repo.remove(removedEntities);
884
- }
885
- // return removedEntities
914
+ return this.deleteEntitiesAndPromote(model, removedEntities);
886
915
  }
887
916
 
888
917
  async recover(id: number, solidRequestContext: any = {}) {
@@ -912,6 +941,10 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
912
941
  } as unknown as QueryDeepPartialEntity<T>
913
942
  );
914
943
 
944
+ if (this.draftPublishHelperService.isDraftPublishEnabled(loadedmodel)) {
945
+ await this.draftPublishHelperService.promoteRecoveredDraftPublishVersion(this.repo, softDeletedRows);
946
+ }
947
+
915
948
  return { message: SUCCESS_MESSAGES.RECORD_RECOVERED, data: softDeletedRows };
916
949
  } catch (error: any) {
917
950
  if (error instanceof QueryFailedError && (error as any).code === '23505') {
@@ -958,6 +991,14 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
958
991
  { deletedAt: null, deletedTracker: "not-deleted" } as unknown as QueryDeepPartialEntity<T>
959
992
  );
960
993
 
994
+ if (this.draftPublishHelperService.isDraftPublishEnabled(loadedmodel)) {
995
+ // Sequential: two ids in the same batch could belong to the same version
996
+ // chain, and each promotion clears isLatest across the whole chain first.
997
+ for (const entity of softDeletedRows) {
998
+ await this.draftPublishHelperService.promoteRecoveredDraftPublishVersion(this.repo, entity);
999
+ }
1000
+ }
1001
+
961
1002
  return { message: SUCCESS_MESSAGES.SELECTED_RECORDS_RECOVERED, recoveredIds: ids };
962
1003
  } catch (error: any) {
963
1004
  if (error instanceof QueryFailedError && (error as any).code === "23505") {
@@ -1012,18 +1053,11 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
1012
1053
  return model.userKeyField?.name || '';
1013
1054
  }
1014
1055
 
1015
- /* Publish a record - sets publishedAt timestamp */
1056
+ /* Publish a record - marks the selected version as the active published version. */
1016
1057
  async publishRecord(id: number, solidRequestContext: any = {}): Promise<T> {
1017
1058
 
1018
1059
  const model = await this.loadModel();
1019
1060
 
1020
- // Check if publish workflow is enabled for this model
1021
- if (!model.draftPublishWorkflow) {
1022
- throw new BadRequestException(
1023
- `Publish workflow is not enabled for ${this.modelName}`
1024
- );
1025
- }
1026
-
1027
1061
  // Check user permissions
1028
1062
  if (solidRequestContext.activeUser) {
1029
1063
  const hasPermission = this.crudHelperService.hasPublishPermissionOnModel(
@@ -1035,37 +1069,14 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
1035
1069
  }
1036
1070
  }
1037
1071
 
1038
- // Find the entity
1039
- const entity = await this.repo.findOne({ where: { id } as any });
1040
- if (!entity) {
1041
- throw new NotFoundException(`${this.modelName} with id ${id} not found`);
1042
- }
1043
-
1044
- // Check if already published
1045
- if (entity.publishedAt) {
1046
- throw new BadRequestException(
1047
- `${this.modelName} with id ${id} is already published`
1048
- );
1049
- }
1050
-
1051
- // Update publish status
1052
- const updatedEntity = await this.repo.save({ ...entity, publishedAt: new Date() });
1053
-
1054
- return updatedEntity
1072
+ return this.draftPublishHelperService.publishRecord(this.repo, model, this.modelName, id, solidRequestContext.activeUser);
1055
1073
  }
1056
1074
 
1057
- /* Unpublish a record - clears publishedAt timestamp */
1075
+ /* Unpublish a record - marks the selected version as not currently published. */
1058
1076
  async unpublishRecord(id: number, solidRequestContext: any = {}): Promise<T> {
1059
1077
 
1060
1078
  const model = await this.loadModel();
1061
1079
 
1062
- // Check if publish workflow is enabled for this model
1063
- if (!model.draftPublishWorkflow) {
1064
- throw new BadRequestException(
1065
- `Publish workflow is not enabled for ${this.modelName}`
1066
- );
1067
- }
1068
-
1069
1080
  // Check user permissions
1070
1081
  if (solidRequestContext.activeUser) {
1071
1082
  const hasPermission = this.crudHelperService.hasUnpublishPermissionOnModel(
@@ -1077,23 +1088,7 @@ private async prepareManyToManyAuditSnapshot(entity: T,id: number,modelSingularN
1077
1088
  }
1078
1089
  }
1079
1090
 
1080
- // Find the entity
1081
- const entity = await this.repo.findOne({ where: { id } as any });
1082
- if (!entity) {
1083
- throw new NotFoundException(`${this.modelName} with id ${id} not found`);
1084
- }
1085
-
1086
- // Check if already unpublished
1087
- if (!entity.publishedAt) {
1088
- throw new BadRequestException(
1089
- `${this.modelName} with id ${id} is already unpublished`
1090
- );
1091
- }
1092
-
1093
- // Update unpublish status
1094
- const updatedEntity = await this.repo.save({ ...entity, publishedAt: null });
1095
-
1096
- return updatedEntity
1091
+ return this.draftPublishHelperService.unpublishRecord(this.repo, model, this.modelName, id, solidRequestContext.activeUser);
1097
1092
  }
1098
1093
 
1099
1094
  private getDatasourceDefaultEntityManager() {
@@ -1680,6 +1680,11 @@ export class DatasourceIntrospectionService {
1680
1680
 
1681
1681
  private getLegacySuperclassFieldName(columnName: string, legacyTableType: LegacyTableType) {
1682
1682
  const normalized = columnName.toLowerCase();
1683
+ // LegacyCommonEntityWithExistingId doesn't declare the draft/publish versioning
1684
+ // columns (see DRAFT_PUBLISH_VERSIONING_FIELD_NAMES), so their ss_-prefixed column
1685
+ // names must not appear here — otherwise a table that still physically has one of
1686
+ // those columns would have it silently treated as superclass-handled and dropped
1687
+ // from introspection instead of being surfaced as a real column.
1683
1688
  const legacyFieldMap: Record<string, string> = {
1684
1689
  ss_created_at: "createdAt",
1685
1690
  ss_updated_at: "updatedAt",