@izara_project/izara-core-generate-service-code 1.0.83 → 1.0.84

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 (59) hide show
  1. package/package.json +4 -4
  2. package/src/compile/flowValidator.js +13 -2
  3. package/src/compile/loadSchemas.js +116 -7
  4. package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
  5. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +29 -1
  6. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +16 -3
  7. package/src/emit/crud/crudActionPlan.js +38 -5
  8. package/src/emit/crud/emitCrudApplicationArtifacts.js +19 -4
  9. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +27 -6
  10. package/src/emit/crud/generateCrudApplicationArtifacts.js +3 -2
  11. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +3 -2
  12. package/src/emit/crud/loadLocalSchemaArrays.js +3 -3
  13. package/src/emit/crud/templates/CreateComplete_Main.ejs +1 -1
  14. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +50 -19
  15. package/src/emit/crud/templates/CreateLogicalLib.ejs +73 -8
  16. package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
  17. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +33 -8
  18. package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
  19. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +2 -2
  20. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -0
  21. package/src/emit/crud/templates/FlowMain_Wbs.ejs +1 -1
  22. package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
  23. package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
  24. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +52 -3
  25. package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
  26. package/src/emit/custom/customFlows.js +47 -0
  27. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
  28. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
  29. package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
  30. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
  31. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  32. package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
  33. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
  34. package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
  35. package/src/emit/rbac/templates/CancelUsage_Main.ejs +103 -0
  36. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +71 -0
  37. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +49 -6
  38. package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
  39. package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
  40. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +147 -0
  41. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +59 -23
  42. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +1 -1
  43. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
  44. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +4 -4
  45. package/src/emit/resource/emitResourceArtifacts.js +342 -108
  46. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +53 -2
  47. package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -5
  48. package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
  49. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +7 -0
  50. package/src/emit/systemText/emitSystemTextSchemas.js +1 -1
  51. package/src/generate.js +41 -10
  52. package/test/attributeTreeSchemas.test.js +219 -0
  53. package/test/createTargetRoleHandler.test.js +59 -4
  54. package/test/crudApplicationArtifacts.test.js +20 -3
  55. package/test/customFlowApplicationArtifacts.test.js +5 -5
  56. package/test/dynamicCrudFlowSchemas.test.js +91 -4
  57. package/test/dynamicRbacFlowSchemas.test.js +15 -2
  58. package/test/publicApi.test.js +6 -6
  59. package/test/resourceArtifacts.test.js +68 -27
@@ -70,6 +70,10 @@ const externalServices = {
70
70
  dynamoTableNames.add('RolePermissions');
71
71
  dynamoTableNames.add('RoleUsers');
72
72
  dynamoTableNames.add('UserRoles');
73
+ dynamoTableNames.add('RbacPermissionCaches');
74
+ dynamoTableNames.add('RoleLimit');
75
+ dynamoTableNames.add('RunningTotalUsage');
76
+ dynamoTableNames.add('RunningTotalReservedUsage');
73
77
  }
74
78
  if (typeof s3Flows !== 'undefined' && (s3Flows || []).length > 0) {
75
79
  dynamoTableNames.add('ReservedDataMain');
@@ -176,16 +180,25 @@ const tableConfigs = {
176
180
  if (crud && typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0) {
177
181
  const allRbacTags = Array.from(new Set(['Rbac', ...rbacValidatorServiceTags]));
178
182
  const hasGraph = typeof objectGraphServiceTags !== 'undefined' && objectGraphServiceTags && objectGraphServiceTags.length > 0;
183
+ const createEndpoint = hasGraph ? 'CreateRbacCallbackHdrSqs' : 'CreateCompleteHdrSqs';
179
184
  const updateEndpoint = hasGraph ? 'UpdateRbacCallbackHdrSqs' : 'UpdateCompleteHdrSqs';
180
185
  const deleteEndpoint = hasGraph ? 'DeleteRbacCallbackHdrSqs' : 'DeleteCompleteHdrSqs';
181
186
  allRbacTags.forEach(function(tag) {
182
- if (!hasGraph) {
183
- rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
184
- }
187
+ rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: createEndpoint });
185
188
  rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: updateEndpoint });
186
189
  rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: deleteEndpoint });
187
190
  });
188
191
  }
192
+
193
+ if (typeof customRbacFlowTags !== 'undefined' && customRbacFlowTags && customRbacFlowTags.length > 0) {
194
+ const allRbacTags = Array.from(new Set(['Rbac', ...(typeof rbacValidatorServiceTags !== 'undefined' ? rbacValidatorServiceTags : [])]));
195
+ customRbacFlowTags.forEach(function(flowTag) {
196
+ const tagUpper = flowTag[0].toUpperCase() + flowTag.slice(1);
197
+ allRbacTags.forEach(function(tag) {
198
+ rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: `${tagUpper}RbacCallbackHdrSqs` });
199
+ });
200
+ });
201
+ }
189
202
  -%>
190
203
  const snsTopicSubscriptions = [
191
204
  <% if (relSubs.length > 0) { -%>
@@ -5,36 +5,41 @@ export function createCrudActionPlans(objects = []) {
5
5
  const hasRbac = objects.some(
6
6
  (object) => isCrudObject(object) && hasRbacObject(object, objects)
7
7
  );
8
+ const isBillable = objects.some(
9
+ (object) => isCrudObject(object) && isBillableObject(object, objects)
10
+ );
8
11
 
9
12
  return Object.fromEntries(
10
13
  CRUD_ACTIONS.map((action) => [
11
14
  action,
12
- createCrudActionPlan(action, { hasGraph, hasRbac })
15
+ createCrudActionPlan(action, { hasGraph, hasRbac, isBillable })
13
16
  ])
14
17
  );
15
18
  }
16
19
 
17
20
  export function createCrudActionPlan(
18
21
  action,
19
- { hasGraph = false, hasRbac = false } = {}
22
+ { hasGraph = false, hasRbac = false, isBillable = true } = {}
20
23
  ) {
21
- const actionHasRbac = action !== 'Create' && action !== 'Get' && hasRbac;
24
+ const actionHasRbac = action !== 'Get' && hasRbac;
22
25
  const outputTopic = action !== 'Get';
26
+ const hasQuotaReservation = action === 'Create' && hasRbac && isBillable;
23
27
 
24
28
  return {
25
29
  action,
26
30
  outputTopic,
27
31
  hasGraph: outputTopic && hasGraph,
28
32
  hasRbac: actionHasRbac,
33
+ hasQuotaReservation,
29
34
  hasComplete: outputTopic && (actionHasRbac || hasGraph),
30
35
  hasRbacCallback: outputTopic && actionHasRbac && hasGraph
31
36
  };
32
37
  }
33
38
 
34
- const VALID_CRUD_GENERATED_BY = new Set([
39
+ export const VALID_CRUD_GENERATED_BY = new Set([
35
40
  'user',
36
41
  'systemWithUser',
37
- 'systemWithNoUser'
42
+ 'systemNoUser'
38
43
  ]);
39
44
 
40
45
  export function isCrudObject(object) {
@@ -83,3 +88,31 @@ function normalizeBelongTo(object) {
83
88
  if (!object?.belongTo) return [];
84
89
  return Array.isArray(object.belongTo) ? object.belongTo : [object.belongTo];
85
90
  }
91
+
92
+ export function isBillableObject(object, objects = []) {
93
+ if (!isCrudObject(object)) return false;
94
+
95
+ const targets = normalizeBelongTo(object);
96
+ if (targets.length > 0) {
97
+ for (const target of targets) {
98
+ if (typeof target?.billable === 'boolean') {
99
+ return target.billable;
100
+ }
101
+ }
102
+ }
103
+
104
+ if (Array.isArray(object?.addOnDataStructure)) {
105
+ const rbacAddOn = object.addOnDataStructure.find(
106
+ (addOn) => addOn?.type === 'rbac'
107
+ );
108
+ if (typeof rbacAddOn?.billable === 'boolean') {
109
+ return rbacAddOn.billable;
110
+ }
111
+ }
112
+
113
+ if (typeof object?.billable === 'boolean') {
114
+ return object.billable;
115
+ }
116
+
117
+ return true;
118
+ }
@@ -11,7 +11,8 @@ import {
11
11
  import {
12
12
  CRUD_ACTIONS,
13
13
  createCrudActionPlans,
14
- isCrudObject
14
+ isCrudObject,
15
+ VALID_CRUD_GENERATED_BY
15
16
  } from './crudActionPlan.js';
16
17
 
17
18
  const ACTIONS = CRUD_ACTIONS;
@@ -22,12 +23,26 @@ const SHARED_TEMPLATE_URL = new URL('../shared/templates/', import.meta.url);
22
23
  export async function emitCrudApplicationArtifacts({
23
24
  objects,
24
25
  flows = [],
25
- serviceTag
26
+ serviceTag,
27
+ logger
26
28
  }) {
27
29
  if (!Array.isArray(objects) || !Array.isArray(flows)) {
28
30
  throw new TypeError('objects and flows must be arrays');
29
31
  }
30
- if (!objects.some(isCrudObject)) return [];
32
+ if (!objects.some(isCrudObject)) {
33
+ if (objects.length > 0) {
34
+ const summary = objects.map((obj) => ({
35
+ objectType: obj?.objectType ?? '(undefined)',
36
+ generatedBy: obj?.generatedBy ?? '(missing)'
37
+ }));
38
+ logger?.warn?.(
39
+ `[WARN] [CRUD Application] Skipped FlowObjects application artifacts generation: No valid CRUD ObjectSchema found. ` +
40
+ `Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
41
+ `Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
42
+ );
43
+ }
44
+ return [];
45
+ }
31
46
 
32
47
  const handlers = await Promise.all(
33
48
  ACTIONS.map((action) => emitAction(action, objects, serviceTag))
@@ -87,7 +102,7 @@ async function emitAction(action, objects, serviceTag) {
87
102
  flow: null,
88
103
  flowStepName: '',
89
104
  startConfig: null,
90
- objects: action === 'Create' ? [] : objects,
105
+ objects: objects,
91
106
  isCrudObject,
92
107
  hasRbacAddOn: (object) => hasRbacAddOn(object, objects),
93
108
  plan
@@ -3,7 +3,8 @@ import {
3
3
  CRUD_ACTIONS,
4
4
  createCrudActionPlans,
5
5
  hasGraphStorageResource,
6
- isCrudObject
6
+ isCrudObject,
7
+ VALID_CRUD_GENERATED_BY
7
8
  } from './crudActionPlan.js';
8
9
 
9
10
  const MESSAGE_ATTRIBUTES = ['userId', 'correlationId'];
@@ -13,24 +14,44 @@ export const dynamicCrudFlowSchemaPaths = CRUD_ACTIONS.map(
13
14
  `app/src/schemas/FlowSchemas/generateCode/FlowObjects/${action}.js`
14
15
  );
15
16
 
16
- export function emitDynamicCrudFlowSchemas({ objects, flows = [], serviceTag }) {
17
+ export function emitDynamicCrudFlowSchemas({
18
+ objects,
19
+ flows = [],
20
+ serviceTag,
21
+ logger
22
+ }) {
17
23
  if (!Array.isArray(objects) || !Array.isArray(flows)) {
18
24
  throw new TypeError('objects and flows must be arrays');
19
25
  }
20
- if (!objects.some(isCrudObject)) return [];
26
+ if (!objects.some(isCrudObject)) {
27
+ if (objects.length > 0) {
28
+ const summary = objects.map((obj) => ({
29
+ objectType: obj?.objectType ?? '(undefined)',
30
+ generatedBy: obj?.generatedBy ?? '(missing)'
31
+ }));
32
+ logger?.warn?.(
33
+ `[WARN] [CRUD FlowSchemas] Skipped FlowObjects FlowSchemas generation: No valid CRUD ObjectSchema found. ` +
34
+ `Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
35
+ `Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
36
+ );
37
+ }
38
+ return [];
39
+ }
21
40
 
22
41
  const plans = createCrudActionPlans(objects);
42
+ const primaryObject = objects.find(isCrudObject);
43
+ const initiateBy = primaryObject?.generatedBy || 'user';
23
44
 
24
45
  return CRUD_ACTIONS.map((action, index) => ({
25
46
  path: dynamicCrudFlowSchemaPaths[index],
26
47
  content: renderDynamicCrudFlowSchema(
27
48
  action,
28
- _createDynamicFlow(action, plans[action], serviceTag)
49
+ _createDynamicFlow(action, plans[action], serviceTag, initiateBy)
29
50
  )
30
51
  }));
31
52
  }
32
53
 
33
- function _createDynamicFlow(action, plan, serviceTag = '') {
54
+ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user') {
34
55
  const flowSteps = [
35
56
  {
36
57
  stepName: 'Start',
@@ -103,7 +124,7 @@ function _createDynamicFlow(action, plan, serviceTag = '') {
103
124
 
104
125
  return {
105
126
  flowTag: action,
106
- initiateBy: 'systemWithNoUser',
127
+ initiateBy,
107
128
  handleObj: 'one',
108
129
  statusType: 'none',
109
130
  event: plan.outputTopic ? ['ownTopic'] : ['lambdaSyncInv', 'lambdaSyncApi'],
@@ -9,10 +9,11 @@ import {
9
9
 
10
10
  export async function generateCrudApplicationArtifacts(rootPath, options = {}) {
11
11
  const project = compileProject({ ...options, rootPath });
12
- const schemas = await loadLocalSchemaArrays(project);
12
+ const schemas = await loadLocalSchemaArrays(project, options);
13
13
  const artifacts = await emitCrudApplicationArtifacts({
14
14
  ...schemas,
15
- serviceTag: project.serviceTag
15
+ serviceTag: project.serviceTag,
16
+ logger: options.logger
16
17
  });
17
18
  const files = await commitArtifacts(
18
19
  buildGenerationPlan(project, artifacts, {
@@ -9,12 +9,13 @@ import { loadLocalSchemaArrays } from './loadLocalSchemaArrays.js';
9
9
 
10
10
  export async function generateDynamicCrudFlowSchemas(rootPath, options = {}) {
11
11
  const project = compileProject({ ...options, rootPath });
12
- const schemaInputs = await loadLocalSchemaArrays(project);
12
+ const schemaInputs = await loadLocalSchemaArrays(project, options);
13
13
  const plan = buildGenerationPlan(
14
14
  project,
15
15
  emitDynamicCrudFlowSchemas({
16
16
  ...schemaInputs,
17
- serviceTag: project.serviceTag
17
+ serviceTag: project.serviceTag,
18
+ logger: options.logger
18
19
  }),
19
20
  {
20
21
  managedPaths: dynamicCrudFlowSchemaPaths,
@@ -1,8 +1,8 @@
1
1
  import { loadLocalSchemaDirectory } from '../../compile/loadSchemas.js';
2
2
 
3
- export async function loadLocalSchemaArrays(project) {
3
+ export async function loadLocalSchemaArrays(project, options = {}) {
4
4
  return {
5
- objects: await loadLocalSchemaDirectory(project, 'ObjectSchemas'),
6
- flows: await loadLocalSchemaDirectory(project, 'FlowSchemas')
5
+ objects: await loadLocalSchemaDirectory(project, 'ObjectSchemas', options),
6
+ flows: await loadLocalSchemaDirectory(project, 'FlowSchemas', options)
7
7
  };
8
8
  }
@@ -52,7 +52,7 @@ export default async function CreateComplete(
52
52
  //(</additionalParams>)
53
53
  ) {
54
54
  try {
55
- _izContext.logger.debug('[CreateComplete] started', {
55
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateComplete] started`, {
56
56
  requestParams
57
57
  });
58
58
  const {
@@ -65,7 +65,7 @@ export default async function <%- flowTag %>(
65
65
  //(</additionalParams>)
66
66
  ) {
67
67
  try {
68
- _izContext.logger.debug('[<%- flowTag %>] createMain:', {
68
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createMain:`, {
69
69
  requestParams,
70
70
  callingFlowConfig
71
71
  });
@@ -78,19 +78,42 @@ export default async function <%- flowTag %>(
78
78
  _izContext,
79
79
  objType
80
80
  );
81
- _izContext.logger.debug('objectSchema', objectSchema);
81
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
82
82
 
83
- // ── Resolve userId / targetId ─────────────────────────────────────────────
84
- let userId, targetId;
83
+ // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
84
+ let submittedByUserId, targetIdentifiers;
85
85
  if (
86
86
  objectSchema.generatedBy === 'user' ||
87
87
  objectSchema.generatedBy === 'systemWithUser'
88
88
  ) {
89
- userId = _izContext.correlationIds.get(coreConsts.BASE_USER_ID);
90
- targetId = _izContext.correlationIds.get(coreConsts.TARGET_ID);
91
- if (!userId) errorsFound.push('Not have userId');
92
- if (objectSchema.hasOwnProperty('belongTo') && !targetId)
93
- errorsFound.push('not have targetId');
89
+ submittedByUserId =
90
+ requestParams.submittedByUserId ||
91
+ _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
92
+
93
+ targetIdentifiers = requestParams.targetIdentifiers;
94
+
95
+ if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
96
+ targetIdentifiers = { submittedByUserId };
97
+ }
98
+
99
+ if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
100
+ if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
101
+ errorsFound.push('not have targetIdentifiers');
102
+
103
+ requestParams.submittedByUserId = submittedByUserId;
104
+ if (targetIdentifiers) {
105
+ if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
106
+ targetIdentifiers.submittedByUserId = submittedByUserId;
107
+ }
108
+ requestParams.targetIdentifiers = targetIdentifiers;
109
+ }
110
+
111
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
112
+ submittedByUserId: requestParams.submittedByUserId,
113
+ targetIdentifiers: requestParams.targetIdentifiers,
114
+ belongTo: objectSchema.belongTo,
115
+ generatedBy: objectSchema.generatedBy
116
+ });
94
117
  } else if (objectSchema.generatedBy === 'searchResultGenerated') {
95
118
  throw new NoRetryError(
96
119
  'error searchResultGenerated should not happen here'
@@ -106,14 +129,14 @@ export default async function <%- flowTag %>(
106
129
  _izContext,
107
130
  objectSchema
108
131
  );
109
- _izContext.logger.debug('objectSchemas', objectSchemas);
132
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchemas:`, objectSchemas);
110
133
 
111
134
  // ── Build createDataDetails ───────────────────────────────────────────────
112
135
  const createDataDetails = await createDataDetailsLib(
113
136
  _izContext,
114
137
  objectSchemas
115
138
  );
116
- _izContext.logger.debug('createDataDetails:', createDataDetails);
139
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createDataDetails:`, createDataDetails);
117
140
 
118
141
  if (requestParams.relationships?.length > 0) {
119
142
  //(<beforeValidateRelationships>)
@@ -127,7 +150,7 @@ export default async function <%- flowTag %>(
127
150
  requestParams.relationships
128
151
  ))
129
152
  );
130
- _izContext.logger.debug('errorsFound', errorsFound);
153
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound:`, errorsFound);
131
154
 
132
155
  // ── Resolve fromRequiredOnCreate fields ──────────────────────────────────
133
156
  if (objectSchemas.fieldNames) {
@@ -136,8 +159,12 @@ export default async function <%- flowTag %>(
136
159
  if (val.fromRequiredOnCreate && requestParams.fieldNames[fieldName] === undefined) {
137
160
  const fromConfig = val.fromRequiredOnCreate;
138
161
  const sourceField = fromConfig.fieldName || fieldName;
139
- if (fromConfig.belongToObjType === true && targetId) {
140
- requestParams.fieldNames[fieldName] = targetId;
162
+ if (fromConfig.belongToObjType === true && targetIdentifiers) {
163
+ const targetValue =
164
+ targetIdentifiers[sourceField] !== undefined
165
+ ? targetIdentifiers[sourceField]
166
+ : Object.values(targetIdentifiers)[0];
167
+ requestParams.fieldNames[fieldName] = targetValue;
141
168
  } else if (fromConfig.relType && requestParams.relationships?.length > 0) {
142
169
  const matchedRel = requestParams.relationships.find(
143
170
  (rel) =>
@@ -152,6 +179,9 @@ export default async function <%- flowTag %>(
152
179
  }
153
180
  }
154
181
 
182
+ const listOfRequiredOnCreate = [];
183
+ const listOfOptionalOnCreate = [];
184
+
155
185
  for (const [key, val] of Object.entries(objectSchemas.fieldNames)) {
156
186
  if (
157
187
  val.randomOnCreate === true ||
@@ -200,9 +230,9 @@ export default async function <%- flowTag %>(
200
230
  }
201
231
  }
202
232
 
203
- _izContext.logger.debug('requestParams:', requestParams);
233
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams:`, requestParams);
204
234
  errorsFound.push(...errors);
205
- _izContext.logger.debug('errorsFound::', errorsFound);
235
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound after identifiers:`, errorsFound);
206
236
 
207
237
  if (errorsFound.length > 0)
208
238
  return await <%- flowTag %>LogicalLib(
@@ -239,7 +269,7 @@ export default async function <%- flowTag %>(
239
269
  });
240
270
  }
241
271
  if (errorsFound.length > 0) {
242
- _izContext.logger.debug('HaveError::', errorsFound);
272
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] HaveError:`, errorsFound);
243
273
  break;
244
274
  }
245
275
  }
@@ -288,12 +318,12 @@ export default async function <%- flowTag %>(
288
318
  serviceTag: <%- rbacServiceTags.length === 1 ? rbacServiceTags[0] : `{ ${Object.entries(rbacServiceTagMap).map(([k, v]) => `'${k}': ${v}`).join(', ')} }[requestParams.objectType] || process.env.iz_serviceTag` %>
289
319
  },
290
320
  requestParams: requestParams,
291
- nextFlowStepName: '<%- flowTag %>RbacCallback'
321
+ nextFlowStepName: '<%- plan?.hasRbacCallback ? `${flowTag}RbacCallback` : `${flowTag}Complete` %>'
292
322
  }
293
323
  );
294
324
 
295
325
  _izContext.logger.debug(
296
- '[lib:auth:checkRbacPermission] resultPermissionCheck:',
326
+ `[${process.env.iz_serviceTag}:<%- flowTag %>] checkRbacPermission result:`,
297
327
  resultPermissionCheck
298
328
  );
299
329
 
@@ -459,6 +489,7 @@ export default async function <%- flowTag %>(
459
489
  errorsFound
460
490
  );
461
491
  } catch (err) {
492
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, err);
462
493
  throw err;
463
494
  }
464
495
  }
@@ -77,10 +77,11 @@ export async function <%- flowTag %>LogicalLib(
77
77
  phaseResults = {}
78
78
  ) {
79
79
  try {
80
- _izContext.logger.debug('[<%- flowTag %>LogicalLib] started', {
80
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
81
81
  requestParams,
82
82
  callingFlowConfig,
83
- phaseResults
83
+ phaseResults,
84
+ targetIdentifiers: requestParams.targetIdentifiers
84
85
  });
85
86
 
86
87
  //(<beforeCreateMainLogical>)
@@ -93,14 +94,14 @@ export async function <%- flowTag %>LogicalLib(
93
94
  _izContext,
94
95
  objType
95
96
  );
96
- _izContext.logger.debug('objectSchema', objectSchema);
97
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
97
98
 
98
99
  const objectSchemas =
99
100
  uploadUseCase.generateObjectSchemaForCombineFieldNames(
100
101
  _izContext,
101
102
  objectSchema
102
103
  );
103
- _izContext.logger.debug('objectSchemas', objectSchemas);
104
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchemas:`, objectSchemas);
104
105
 
105
106
  // ── Parent object ─────────────────────────────────────────────────────────
106
107
  let parentObject;
@@ -121,7 +122,7 @@ export async function <%- flowTag %>LogicalLib(
121
122
  _izContext,
122
123
  objectSchemas
123
124
  );
124
- _izContext.logger.debug('createDataDetails:', createDataDetails);
125
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] createDataDetails:`, createDataDetails);
125
126
 
126
127
  // ── Build objInstanceFull identifiers ─────────────────────────────────────
127
128
  const objInstanceFull = { identifiers: {}, fields: {} };
@@ -177,7 +178,7 @@ export async function <%- flowTag %>LogicalLib(
177
178
 
178
179
  // ── DynamoDB ──────────────────────────────────────────────────────────
179
180
  if (createDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB) {
180
- _izContext.logger.debug('::::::DynamoDB::::::', {
181
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] DynamoDB:`, {
181
182
  storageTag,
182
183
  objInstanceFull
183
184
  });
@@ -256,6 +257,66 @@ export async function <%- flowTag %>LogicalLib(
256
257
  );
257
258
 
258
259
  objInstanceFullForDynamoDb.fields = {};
260
+
261
+ // ── Auto-provision owner TargetRole for Root Object with RBAC ─────
262
+ const hasRbacAddOn = Array.isArray(objectSchema?.addOnDataStructure) &&
263
+ objectSchema.addOnDataStructure.some((addOn) => addOn?.type === 'rbac');
264
+ const isRootRbacObject =
265
+ hasRbacAddOn &&
266
+ !objectSchema?.belongTo &&
267
+ objectSchema?.objectType !== 'user' &&
268
+ objectSchema?.generatedBy !== 'systemNoUser';
269
+
270
+ if (isRootRbacObject) {
271
+ try {
272
+ const submittedByUserId = requestParams.submittedByUserId || _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
273
+ if (submittedByUserId) {
274
+ const targetIdentKeys = Object.entries(identifiersForCreateData)
275
+ .map(([k, v]) => `${k}#${v}`)
276
+ .join('_');
277
+ const targetIdentifiersConcat = targetIdentKeys || (identifiersForCreateData[Object.keys(identifiersForCreateData)[0]] ? `${Object.keys(identifiersForCreateData)[0]}#${identifiersForCreateData[Object.keys(identifiersForCreateData)[0]]}` : '');
278
+
279
+ if (targetIdentifiersConcat) {
280
+ const roleIdKey = `${targetIdentifiersConcat}_owner`;
281
+ _izContext.logger.debug('[CreateLogicalLib] Auto-provisioning owner TargetRole:', {
282
+ identifiersConcat: targetIdentifiersConcat,
283
+ roleIdKey,
284
+ submittedByUserId,
285
+ roleName: 'owner'
286
+ });
287
+
288
+ await dynamodbSharedLib.putItem(
289
+ _izContext,
290
+ dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
291
+ {
292
+ identifiersConcat: targetIdentifiersConcat,
293
+ roleIdKey,
294
+ submittedByUserId,
295
+ roleName: 'owner',
296
+ assignedAt: new Date().toISOString()
297
+ }
298
+ ).catch(() => {});
299
+
300
+ await dynamodbSharedLib.transactWriteItems(_izContext, [
301
+ {
302
+ Put: {
303
+ TableName: dynamodbSharedLib.tableName(_izContext, 'RoleUsers'),
304
+ Item: { roleIdKey, submittedByUserId }
305
+ }
306
+ },
307
+ {
308
+ Put: {
309
+ TableName: dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
310
+ Item: { submittedByUserId, roleIdKey }
311
+ }
312
+ }
313
+ ]).catch(() => {});
314
+ }
315
+ }
316
+ } catch (roleError) {
317
+ _izContext.logger.warn('[CreateLogicalLib] Failed to auto-provision owner TargetRole:', { roleError });
318
+ }
319
+ }
259
320
  }
260
321
 
261
322
  //(<afterCreateRecordDynamo>)
@@ -267,7 +328,7 @@ export async function <%- flowTag %>LogicalLib(
267
328
  ) {
268
329
  //(<beforeCreateNode>)
269
330
  //(</beforeCreateNode>)
270
- _izContext.logger.debug('::::::Graph::::::', {
331
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] Graph:`, {
271
332
  storageTag,
272
333
  objInstanceFull
273
334
  });
@@ -435,6 +496,7 @@ export async function <%- flowTag %>LogicalLib(
435
496
  objType,
436
497
  objInstanceFull: objInstanceFullForGraph,
437
498
  relationships: requestParams.relationships || [],
499
+ targetIdentifiers: requestParams.targetIdentifiers,
438
500
  status: 'complete',
439
501
  errorsFound
440
502
  };
@@ -444,7 +506,7 @@ export async function <%- flowTag %>LogicalLib(
444
506
 
445
507
  // ── Handle errors ─────────────────────────────────────────────────────────
446
508
  if (errorsFound.length > 0) {
447
- _izContext.logger.debug('Case have errorsFound:::', errorsFound);
509
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] errorsFound:`, errorsFound);
448
510
 
449
511
  await asyncFlowSharedLib.clearAllAwaitingSteps(
450
512
  _izContext,
@@ -479,6 +541,7 @@ export async function <%- flowTag %>LogicalLib(
479
541
  objType,
480
542
  objInstanceFull,
481
543
  relationships: requestParams.relationships || [],
544
+ targetIdentifiers: requestParams.targetIdentifiers,
482
545
  status: 'error',
483
546
  errorsFound
484
547
  };
@@ -529,10 +592,12 @@ export async function <%- flowTag %>LogicalLib(
529
592
  fields: objInstanceFullForDynamoDb.fields
530
593
  },
531
594
  relationships: requestParams.relationships || [],
595
+ targetIdentifiers: requestParams.targetIdentifiers,
532
596
  status: 'complete',
533
597
  errorsFound
534
598
  };
535
599
  } catch (err) {
600
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
536
601
  throw err;
537
602
  }
538
603
  }
@@ -52,7 +52,7 @@ export default async function DeleteComplete(
52
52
  //(</additionalParams>)
53
53
  ) {
54
54
  try {
55
- _izContext.logger.debug('[DeleteComplete] started', {
55
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:DeleteComplete] started`, {
56
56
  requestParams
57
57
  });
58
58
  const {