@objectql/starter-basic 1.6.1
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.
- package/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/demo.app.yml +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/main.menu.yml +30 -0
- package/dist/modules/kitchen-sink/kitchen_sink.data.yml +18 -0
- package/dist/modules/kitchen-sink/kitchen_sink.object.yml +154 -0
- package/dist/modules/projects/pages/create_project_wizard.page.yml +244 -0
- package/dist/modules/projects/pages/project_detail.page.yml +258 -0
- package/dist/modules/projects/project_approval.workflow.yml +51 -0
- package/dist/modules/projects/project_status.report.yml +39 -0
- package/dist/modules/projects/projects.action.d.ts +104 -0
- package/dist/modules/projects/projects.action.js +363 -0
- package/dist/modules/projects/projects.action.js.map +1 -0
- package/dist/modules/projects/projects.data.yml +13 -0
- package/dist/modules/projects/projects.form.yml +41 -0
- package/dist/modules/projects/projects.hook.d.ts +15 -0
- package/dist/modules/projects/projects.hook.js +302 -0
- package/dist/modules/projects/projects.hook.js.map +1 -0
- package/dist/modules/projects/projects.object.yml +148 -0
- package/dist/modules/projects/projects.permission.yml +141 -0
- package/dist/modules/projects/projects.validation.yml +37 -0
- package/dist/modules/projects/projects.view.yml +35 -0
- package/dist/modules/tasks/tasks.data.yml +23 -0
- package/dist/modules/tasks/tasks.object.yml +34 -0
- package/dist/modules/tasks/tasks.permission.yml +167 -0
- package/dist/pages/dashboard.page.yml +206 -0
- package/dist/pages/landing.page.yml +275 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +20 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/kitchen_sink.d.ts +99 -0
- package/dist/types/kitchen_sink.js +3 -0
- package/dist/types/kitchen_sink.js.map +1 -0
- package/dist/types/projects.d.ts +47 -0
- package/dist/types/projects.js +3 -0
- package/dist/types/projects.js.map +1 -0
- package/dist/types/tasks.d.ts +31 -0
- package/dist/types/tasks.js +3 -0
- package/dist/types/tasks.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Project Hooks - Comprehensive Example
|
|
5
|
+
*
|
|
6
|
+
* This file demonstrates all major hook patterns according to the ObjectQL specification:
|
|
7
|
+
* 1. Data validation and defaulting (beforeCreate)
|
|
8
|
+
* 2. Query modification for security (beforeFind)
|
|
9
|
+
* 3. State transition validation (beforeUpdate)
|
|
10
|
+
* 4. Change tracking and notifications (afterUpdate)
|
|
11
|
+
* 5. Dependency checking (beforeDelete)
|
|
12
|
+
* 6. Side effects and cleanup (afterDelete)
|
|
13
|
+
*/
|
|
14
|
+
const hooks = {
|
|
15
|
+
/**
|
|
16
|
+
* beforeCreate - Data Validation & Defaulting
|
|
17
|
+
*
|
|
18
|
+
* Use case:
|
|
19
|
+
* - Set default values
|
|
20
|
+
* - Auto-assign ownership
|
|
21
|
+
* - Validate business rules
|
|
22
|
+
* - Check for duplicates
|
|
23
|
+
*/
|
|
24
|
+
beforeCreate: async ({ data, user, api }) => {
|
|
25
|
+
// 1. Auto-assign owner if not specified
|
|
26
|
+
if (data && !data.owner && (user === null || user === void 0 ? void 0 : user.id)) {
|
|
27
|
+
console.log(`[Hook] Projects: Auto-assigning owner ${user.id}`);
|
|
28
|
+
data.owner = String(user.id);
|
|
29
|
+
}
|
|
30
|
+
// 2. Set default status if not provided
|
|
31
|
+
if (data && !data.status) {
|
|
32
|
+
data.status = 'planned';
|
|
33
|
+
}
|
|
34
|
+
// 3. Validate required fields
|
|
35
|
+
if (data && (!data.name || data.name.trim().length === 0)) {
|
|
36
|
+
throw new Error('Project name is required');
|
|
37
|
+
}
|
|
38
|
+
// 4. Validate name length
|
|
39
|
+
if (data && data.name && data.name.length > 100) {
|
|
40
|
+
throw new Error('Project name must be 100 characters or less');
|
|
41
|
+
}
|
|
42
|
+
// 5. Check for duplicate names (using API)
|
|
43
|
+
if (data && data.name) {
|
|
44
|
+
const existing = await api.count('projects', [['name', '=', data.name]]);
|
|
45
|
+
if (existing > 0) {
|
|
46
|
+
throw new Error(`A project named "${data.name}" already exists`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// 6. Set initial budget if not provided
|
|
50
|
+
if (data && !data.budget) {
|
|
51
|
+
data.budget = 0;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
/**
|
|
55
|
+
* afterCreate - Side Effects
|
|
56
|
+
*
|
|
57
|
+
* Use case:
|
|
58
|
+
* - Send notifications
|
|
59
|
+
* - Create related records
|
|
60
|
+
* - Log audit trail
|
|
61
|
+
* - Trigger workflows
|
|
62
|
+
*/
|
|
63
|
+
afterCreate: async ({ result, user, api, state }) => {
|
|
64
|
+
console.log(`[Hook] Projects: Project created - ${result === null || result === void 0 ? void 0 : result.name} by ${user === null || user === void 0 ? void 0 : user.id}`);
|
|
65
|
+
// Example: Create a default task for new projects
|
|
66
|
+
// Uncomment if tasks object exists
|
|
67
|
+
/*
|
|
68
|
+
if (result) {
|
|
69
|
+
await api.create('tasks', {
|
|
70
|
+
name: 'Setup Project',
|
|
71
|
+
project_id: result._id,
|
|
72
|
+
status: 'pending',
|
|
73
|
+
description: 'Initial project setup task'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
*/
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* beforeFind - Query Filtering for Security
|
|
80
|
+
*
|
|
81
|
+
* Use case:
|
|
82
|
+
* - Enforce multi-tenancy
|
|
83
|
+
* - Apply row-level security
|
|
84
|
+
* - Add default filters
|
|
85
|
+
* - Restrict data access based on user role
|
|
86
|
+
*/
|
|
87
|
+
beforeFind: async ({ query, user, api }) => {
|
|
88
|
+
// Example: If not admin, restrict to own projects
|
|
89
|
+
// Uncomment to enable row-level security
|
|
90
|
+
/*
|
|
91
|
+
if (user && !user.isAdmin) {
|
|
92
|
+
// Add filter to only show projects owned by current user
|
|
93
|
+
if (!query.filters) {
|
|
94
|
+
query.filters = [];
|
|
95
|
+
}
|
|
96
|
+
query.filters.push(['owner', '=', user.id]);
|
|
97
|
+
console.log(`[Hook] Projects: Filtering to user ${user.id}'s projects`);
|
|
98
|
+
}
|
|
99
|
+
*/
|
|
100
|
+
// Example: Add default sort
|
|
101
|
+
if (!query.sort) {
|
|
102
|
+
query.sort = [{ field: 'created_at', direction: 'desc' }];
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* afterFind - Result Transformation
|
|
107
|
+
*
|
|
108
|
+
* Use case:
|
|
109
|
+
* - Add computed fields
|
|
110
|
+
* - Mask sensitive data
|
|
111
|
+
* - Enrich data from external sources
|
|
112
|
+
* - Transform dates/formats
|
|
113
|
+
*/
|
|
114
|
+
afterFind: async ({ result, user }) => {
|
|
115
|
+
// Example: Add computed progress field based on status
|
|
116
|
+
if (Array.isArray(result)) {
|
|
117
|
+
result.forEach((project) => {
|
|
118
|
+
switch (project.status) {
|
|
119
|
+
case 'planned':
|
|
120
|
+
project.progress = 0;
|
|
121
|
+
break;
|
|
122
|
+
case 'in_progress':
|
|
123
|
+
project.progress = 50;
|
|
124
|
+
break;
|
|
125
|
+
case 'completed':
|
|
126
|
+
project.progress = 100;
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
project.progress = 0;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* beforeUpdate - State Transition Validation
|
|
136
|
+
*
|
|
137
|
+
* Use case:
|
|
138
|
+
* - Validate state machine transitions
|
|
139
|
+
* - Check permissions for specific updates
|
|
140
|
+
* - Validate budget changes
|
|
141
|
+
* - Track modifications
|
|
142
|
+
*/
|
|
143
|
+
beforeUpdate: async ({ data, previousData, isModified, user, state }) => {
|
|
144
|
+
// 1. Check budget constraints
|
|
145
|
+
if (isModified('budget')) {
|
|
146
|
+
if (data && data.budget != undefined && data.budget < 0) {
|
|
147
|
+
throw new Error('Budget cannot be negative');
|
|
148
|
+
}
|
|
149
|
+
if (data && data.budget != undefined && previousData && data.budget < (previousData.budget || 0)) {
|
|
150
|
+
console.warn(`[Hook] Projects: Budget reduced from ${previousData.budget} to ${data.budget}`);
|
|
151
|
+
// Optional: Require approval for budget reduction
|
|
152
|
+
/*
|
|
153
|
+
if ((previousData.budget || 0) - data.budget > 10000) {
|
|
154
|
+
throw new Error('Budget reductions over $10,000 require approval');
|
|
155
|
+
}
|
|
156
|
+
*/
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// 2. Validate status transitions
|
|
160
|
+
if (isModified('status') && previousData) {
|
|
161
|
+
const oldStatus = previousData.status;
|
|
162
|
+
const newStatus = data === null || data === void 0 ? void 0 : data.status;
|
|
163
|
+
// Define valid transitions
|
|
164
|
+
const validTransitions = {
|
|
165
|
+
'planned': ['in_progress'],
|
|
166
|
+
'in_progress': ['completed', 'planned'], // Can go back to planning
|
|
167
|
+
'completed': [] // Cannot change from completed
|
|
168
|
+
};
|
|
169
|
+
if (oldStatus && newStatus) {
|
|
170
|
+
const allowed = validTransitions[oldStatus] || [];
|
|
171
|
+
if (!allowed.includes(newStatus)) {
|
|
172
|
+
throw new Error(`Invalid status transition: cannot change from "${oldStatus}" to "${newStatus}"`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 3. Require end_date when marking as completed
|
|
177
|
+
if (isModified('status') && (data === null || data === void 0 ? void 0 : data.status) === 'completed') {
|
|
178
|
+
if (!data.end_date && !(previousData === null || previousData === void 0 ? void 0 : previousData.end_date)) {
|
|
179
|
+
throw new Error('End date is required when completing a project');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 4. Store change summary in state for afterUpdate hook
|
|
183
|
+
if (isModified('status')) {
|
|
184
|
+
state.statusChanged = true;
|
|
185
|
+
state.oldStatus = previousData === null || previousData === void 0 ? void 0 : previousData.status;
|
|
186
|
+
state.newStatus = data === null || data === void 0 ? void 0 : data.status;
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
/**
|
|
190
|
+
* afterUpdate - Change Notifications & Side Effects
|
|
191
|
+
*
|
|
192
|
+
* Use case:
|
|
193
|
+
* - Send notifications based on changes
|
|
194
|
+
* - Update related records
|
|
195
|
+
* - Trigger workflows
|
|
196
|
+
* - Log audit trail
|
|
197
|
+
*/
|
|
198
|
+
afterUpdate: async ({ isModified, data, previousData, result, state, api, user }) => {
|
|
199
|
+
// 1. Notify on status change
|
|
200
|
+
if (state.statusChanged) {
|
|
201
|
+
console.log(`[Hook] Projects: Status changed from "${state.oldStatus}" to "${state.newStatus}" by ${user === null || user === void 0 ? void 0 : user.id}`);
|
|
202
|
+
// Example: Create notification record
|
|
203
|
+
/*
|
|
204
|
+
if (data.status === 'completed' && previousData?.owner) {
|
|
205
|
+
await api.create('notifications', {
|
|
206
|
+
user_id: previousData.owner,
|
|
207
|
+
message: `Project "${result?.name}" has been completed!`,
|
|
208
|
+
type: 'project_completed',
|
|
209
|
+
link: `/projects/${result?._id}`
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
*/
|
|
213
|
+
}
|
|
214
|
+
// 2. Notify on budget changes over threshold
|
|
215
|
+
if (isModified('budget') && previousData) {
|
|
216
|
+
const oldBudget = previousData.budget || 0;
|
|
217
|
+
const newBudget = (data === null || data === void 0 ? void 0 : data.budget) || 0;
|
|
218
|
+
const change = Math.abs(newBudget - oldBudget);
|
|
219
|
+
if (change > 5000) {
|
|
220
|
+
console.log(`[Hook] Projects: Significant budget change detected: ${oldBudget} -> ${newBudget}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// 3. Update related tasks when project is completed
|
|
224
|
+
/*
|
|
225
|
+
if (data.status === 'completed') {
|
|
226
|
+
await api.updateMany('tasks',
|
|
227
|
+
{ filters: [['project_id', '=', result._id]] },
|
|
228
|
+
{ status: 'completed' }
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
*/
|
|
232
|
+
},
|
|
233
|
+
/**
|
|
234
|
+
* beforeDelete - Dependency Checking
|
|
235
|
+
*
|
|
236
|
+
* Use case:
|
|
237
|
+
* - Prevent deletion if dependencies exist
|
|
238
|
+
* - Check permissions
|
|
239
|
+
* - Validate business rules
|
|
240
|
+
*/
|
|
241
|
+
beforeDelete: async ({ id, previousData, api, user }) => {
|
|
242
|
+
// 1. Prevent deletion of completed projects
|
|
243
|
+
if ((previousData === null || previousData === void 0 ? void 0 : previousData.status) === 'completed') {
|
|
244
|
+
throw new Error('Cannot delete completed projects. Please archive instead.');
|
|
245
|
+
}
|
|
246
|
+
// 2. Check for dependent tasks
|
|
247
|
+
/*
|
|
248
|
+
const taskCount = await api.count('tasks', [['project_id', '=', id]]);
|
|
249
|
+
|
|
250
|
+
if (taskCount > 0) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`Cannot delete project: ${taskCount} tasks are still associated with it. ` +
|
|
253
|
+
'Please delete or reassign tasks first.'
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
*/
|
|
257
|
+
// 3. Require admin permission for deletion
|
|
258
|
+
/*
|
|
259
|
+
if (!user?.isAdmin) {
|
|
260
|
+
throw new Error('Only administrators can delete projects');
|
|
261
|
+
}
|
|
262
|
+
*/
|
|
263
|
+
console.log(`[Hook] Projects: Preparing to delete project ${id}`);
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* afterDelete - Cleanup & Side Effects
|
|
267
|
+
*
|
|
268
|
+
* Use case:
|
|
269
|
+
* - Delete related records (cascade)
|
|
270
|
+
* - Clean up external resources
|
|
271
|
+
* - Send notifications
|
|
272
|
+
* - Log audit trail
|
|
273
|
+
*/
|
|
274
|
+
afterDelete: async ({ id, previousData, api, user }) => {
|
|
275
|
+
console.log(`[Hook] Projects: Project deleted - ${previousData === null || previousData === void 0 ? void 0 : previousData.name} by ${user === null || user === void 0 ? void 0 : user.id}`);
|
|
276
|
+
// Example: Clean up related data
|
|
277
|
+
/*
|
|
278
|
+
// Delete associated tasks
|
|
279
|
+
await api.deleteMany('tasks', {
|
|
280
|
+
filters: [['project_id', '=', id]]
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Delete associated files from S3
|
|
284
|
+
if (previousData?.attachments) {
|
|
285
|
+
for (const attachment of previousData.attachments) {
|
|
286
|
+
await deleteFromS3(attachment.key);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Create audit log
|
|
291
|
+
await api.create('audit_logs', {
|
|
292
|
+
action: 'project_deleted',
|
|
293
|
+
entity_id: id,
|
|
294
|
+
entity_name: previousData?.name,
|
|
295
|
+
user_id: user?.id,
|
|
296
|
+
timestamp: new Date()
|
|
297
|
+
});
|
|
298
|
+
*/
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
exports.default = hooks;
|
|
302
|
+
//# sourceMappingURL=projects.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.hook.js","sourceRoot":"","sources":["../../../src/modules/projects/projects.hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
label: Project
|
|
2
|
+
icon: building-line
|
|
3
|
+
fields:
|
|
4
|
+
name:
|
|
5
|
+
type: text
|
|
6
|
+
required: true
|
|
7
|
+
index: true # Field-level index
|
|
8
|
+
|
|
9
|
+
status:
|
|
10
|
+
options:
|
|
11
|
+
- planned
|
|
12
|
+
- in_progress
|
|
13
|
+
- completed
|
|
14
|
+
defaultValue: planned
|
|
15
|
+
index: true
|
|
16
|
+
|
|
17
|
+
priority:
|
|
18
|
+
options:
|
|
19
|
+
- low
|
|
20
|
+
- normal
|
|
21
|
+
- high
|
|
22
|
+
defaultValue: normal
|
|
23
|
+
|
|
24
|
+
description:
|
|
25
|
+
type: textarea
|
|
26
|
+
|
|
27
|
+
owner:
|
|
28
|
+
type: text
|
|
29
|
+
|
|
30
|
+
budget:
|
|
31
|
+
type: currency
|
|
32
|
+
|
|
33
|
+
start_date:
|
|
34
|
+
type: date
|
|
35
|
+
|
|
36
|
+
end_date:
|
|
37
|
+
type: date
|
|
38
|
+
|
|
39
|
+
approved_by:
|
|
40
|
+
type: text
|
|
41
|
+
|
|
42
|
+
approved_at:
|
|
43
|
+
type: datetime
|
|
44
|
+
|
|
45
|
+
approval_comment:
|
|
46
|
+
type: textarea
|
|
47
|
+
|
|
48
|
+
indexes:
|
|
49
|
+
# Composite index for reporting
|
|
50
|
+
status_priority_idx:
|
|
51
|
+
fields: [status, priority]
|
|
52
|
+
|
|
53
|
+
ai:
|
|
54
|
+
search:
|
|
55
|
+
enabled: true
|
|
56
|
+
fields: [name, description]
|
|
57
|
+
model: text-embedding-3-small
|
|
58
|
+
|
|
59
|
+
actions:
|
|
60
|
+
# Record Actions (operate on specific records)
|
|
61
|
+
complete:
|
|
62
|
+
type: record
|
|
63
|
+
label: Complete Project
|
|
64
|
+
icon: checkbox-circle-line
|
|
65
|
+
confirm_text: "Are you sure you want to complete this project?"
|
|
66
|
+
params:
|
|
67
|
+
comment:
|
|
68
|
+
type: textarea
|
|
69
|
+
label: Completion Comment
|
|
70
|
+
completion_date:
|
|
71
|
+
type: date
|
|
72
|
+
label: Completion Date
|
|
73
|
+
|
|
74
|
+
approve:
|
|
75
|
+
type: record
|
|
76
|
+
label: Approve Project
|
|
77
|
+
icon: shield-check-line
|
|
78
|
+
confirm_text: "Are you sure you want to approve this project?"
|
|
79
|
+
params:
|
|
80
|
+
comment:
|
|
81
|
+
type: textarea
|
|
82
|
+
required: true
|
|
83
|
+
label: Approval Comment
|
|
84
|
+
help_text: "Provide a reason for approving this project"
|
|
85
|
+
|
|
86
|
+
clone:
|
|
87
|
+
type: record
|
|
88
|
+
label: Clone Project
|
|
89
|
+
icon: file-copy-line
|
|
90
|
+
description: Create a copy of this project
|
|
91
|
+
params:
|
|
92
|
+
new_name:
|
|
93
|
+
type: text
|
|
94
|
+
required: true
|
|
95
|
+
label: New Project Name
|
|
96
|
+
copy_tasks:
|
|
97
|
+
type: checkbox
|
|
98
|
+
label: Copy Associated Tasks
|
|
99
|
+
defaultValue: false
|
|
100
|
+
|
|
101
|
+
# Global Actions (operate on collections)
|
|
102
|
+
import_projects:
|
|
103
|
+
type: global
|
|
104
|
+
label: Import Projects
|
|
105
|
+
icon: download-line
|
|
106
|
+
internal: false
|
|
107
|
+
description: Import multiple projects from various sources
|
|
108
|
+
params:
|
|
109
|
+
source:
|
|
110
|
+
required: true
|
|
111
|
+
label: Import Source
|
|
112
|
+
options:
|
|
113
|
+
- csv
|
|
114
|
+
- json
|
|
115
|
+
- api
|
|
116
|
+
data:
|
|
117
|
+
type: textarea
|
|
118
|
+
label: JSON Data
|
|
119
|
+
help_text: "Paste JSON array of projects (optional if using file_url)"
|
|
120
|
+
file_url:
|
|
121
|
+
type: text
|
|
122
|
+
label: File URL
|
|
123
|
+
help_text: "URL to fetch data from (optional if using data field)"
|
|
124
|
+
|
|
125
|
+
bulk_update_status:
|
|
126
|
+
type: global
|
|
127
|
+
label: Bulk Update Status
|
|
128
|
+
icon: edit-box-line
|
|
129
|
+
description: Update status for multiple projects at once
|
|
130
|
+
params:
|
|
131
|
+
project_ids:
|
|
132
|
+
type: textarea
|
|
133
|
+
required: true
|
|
134
|
+
label: Project IDs
|
|
135
|
+
help_text: "List of project IDs"
|
|
136
|
+
new_status:
|
|
137
|
+
required: true
|
|
138
|
+
label: New Status
|
|
139
|
+
options:
|
|
140
|
+
- planned
|
|
141
|
+
- in_progress
|
|
142
|
+
- completed
|
|
143
|
+
|
|
144
|
+
generate_report:
|
|
145
|
+
type: global
|
|
146
|
+
label: Generate Project Report
|
|
147
|
+
icon: file-chart-line
|
|
148
|
+
description: Generate statistical report of all projects
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
name: projects_permission
|
|
2
|
+
object: projects
|
|
3
|
+
description: "Comprehensive access control rules for Project object"
|
|
4
|
+
|
|
5
|
+
# Roles (defined in demo.app.yml, referenced here)
|
|
6
|
+
# This list documents which system roles have permissions on this object
|
|
7
|
+
roles:
|
|
8
|
+
- admin
|
|
9
|
+
- manager
|
|
10
|
+
- developer
|
|
11
|
+
- user
|
|
12
|
+
- viewer
|
|
13
|
+
|
|
14
|
+
# Object-level permissions (CRUD)
|
|
15
|
+
object_permissions:
|
|
16
|
+
create: [admin, manager]
|
|
17
|
+
read: [admin, manager, developer, user, viewer]
|
|
18
|
+
update: [admin, manager]
|
|
19
|
+
delete: [admin]
|
|
20
|
+
view_all: [admin] # Admins can see all projects
|
|
21
|
+
modify_all: [admin] # Admins can edit all projects
|
|
22
|
+
|
|
23
|
+
# Field-level security
|
|
24
|
+
field_permissions:
|
|
25
|
+
budget:
|
|
26
|
+
read: [admin, manager]
|
|
27
|
+
update: [admin] # Only admin can change budget
|
|
28
|
+
|
|
29
|
+
approved_by:
|
|
30
|
+
read: [admin, manager, user]
|
|
31
|
+
update: [] # Read-only, set by system/workflow
|
|
32
|
+
|
|
33
|
+
approved_at:
|
|
34
|
+
read: [admin, manager, user]
|
|
35
|
+
update: []
|
|
36
|
+
|
|
37
|
+
approval_comment:
|
|
38
|
+
read: [admin, manager, user]
|
|
39
|
+
update: [admin, manager]
|
|
40
|
+
|
|
41
|
+
# Record-level rules for dynamic access control
|
|
42
|
+
record_rules:
|
|
43
|
+
- name: owner_full_access
|
|
44
|
+
priority: 100
|
|
45
|
+
description: Project owner has full access to their projects
|
|
46
|
+
condition:
|
|
47
|
+
type: simple
|
|
48
|
+
field: owner
|
|
49
|
+
operator: "="
|
|
50
|
+
value: $current_user.id
|
|
51
|
+
permissions:
|
|
52
|
+
read: true
|
|
53
|
+
update: true
|
|
54
|
+
delete: true
|
|
55
|
+
|
|
56
|
+
- name: public_read_access
|
|
57
|
+
priority: 10
|
|
58
|
+
description: Completed projects are publicly readable
|
|
59
|
+
condition:
|
|
60
|
+
type: simple
|
|
61
|
+
field: status
|
|
62
|
+
operator: "="
|
|
63
|
+
value: completed
|
|
64
|
+
permissions:
|
|
65
|
+
read: true
|
|
66
|
+
update: false
|
|
67
|
+
delete: false
|
|
68
|
+
|
|
69
|
+
# Sharing rules
|
|
70
|
+
sharing_rules:
|
|
71
|
+
- name: manual_share
|
|
72
|
+
type: manual
|
|
73
|
+
description: Users can manually share projects with team members
|
|
74
|
+
enabled: true
|
|
75
|
+
permissions:
|
|
76
|
+
read: true
|
|
77
|
+
update: false
|
|
78
|
+
delete: false
|
|
79
|
+
|
|
80
|
+
# Action permissions
|
|
81
|
+
action_permissions:
|
|
82
|
+
approve:
|
|
83
|
+
execute: [admin, manager]
|
|
84
|
+
conditions:
|
|
85
|
+
- field: status
|
|
86
|
+
operator: "="
|
|
87
|
+
value: in_progress
|
|
88
|
+
|
|
89
|
+
complete:
|
|
90
|
+
execute: [admin, manager]
|
|
91
|
+
|
|
92
|
+
clone:
|
|
93
|
+
execute: [admin, manager, developer]
|
|
94
|
+
|
|
95
|
+
import_projects:
|
|
96
|
+
execute: [admin]
|
|
97
|
+
rate_limit:
|
|
98
|
+
requests_per_hour: 10
|
|
99
|
+
|
|
100
|
+
bulk_update_status:
|
|
101
|
+
execute: [admin, manager]
|
|
102
|
+
|
|
103
|
+
# View permissions
|
|
104
|
+
view_permissions:
|
|
105
|
+
all_projects:
|
|
106
|
+
access: [admin, manager, developer, user, viewer]
|
|
107
|
+
field_restrictions:
|
|
108
|
+
budget:
|
|
109
|
+
visible_to: [admin, manager]
|
|
110
|
+
|
|
111
|
+
# Row-level security
|
|
112
|
+
row_level_security:
|
|
113
|
+
enabled: true
|
|
114
|
+
default_rule:
|
|
115
|
+
field: owner
|
|
116
|
+
operator: "="
|
|
117
|
+
value: $current_user.id
|
|
118
|
+
exceptions:
|
|
119
|
+
- role: admin
|
|
120
|
+
bypass: true
|
|
121
|
+
- role: manager
|
|
122
|
+
condition:
|
|
123
|
+
type: simple
|
|
124
|
+
field: status
|
|
125
|
+
operator: "!="
|
|
126
|
+
value: completed
|
|
127
|
+
|
|
128
|
+
# Audit trail
|
|
129
|
+
audit:
|
|
130
|
+
enabled: true
|
|
131
|
+
events:
|
|
132
|
+
- permission_grant
|
|
133
|
+
- permission_revoke
|
|
134
|
+
- access_denied
|
|
135
|
+
- sensitive_field_access
|
|
136
|
+
retention_days: 365
|
|
137
|
+
alerts:
|
|
138
|
+
- event: access_denied
|
|
139
|
+
threshold: 5
|
|
140
|
+
window_minutes: 10
|
|
141
|
+
notify: [admin]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: projects_validation
|
|
2
|
+
object: projects
|
|
3
|
+
description: "Validation rules for Projects"
|
|
4
|
+
|
|
5
|
+
rules:
|
|
6
|
+
- name: valid_date_range
|
|
7
|
+
type: cross_field
|
|
8
|
+
ai_context:
|
|
9
|
+
intent: "Ensure project timeline is valid"
|
|
10
|
+
business_rule: "Projects cannot end before they start"
|
|
11
|
+
rule:
|
|
12
|
+
field: end_date
|
|
13
|
+
operator: ">="
|
|
14
|
+
compare_to: start_date
|
|
15
|
+
message: "End Date must be after Start Date"
|
|
16
|
+
|
|
17
|
+
- name: positive_budget
|
|
18
|
+
type: field
|
|
19
|
+
rule:
|
|
20
|
+
field: budget
|
|
21
|
+
operator: ">="
|
|
22
|
+
value: 0
|
|
23
|
+
message: "Budget cannot be negative"
|
|
24
|
+
|
|
25
|
+
- name: comment_required_if_high_budget
|
|
26
|
+
type: conditional
|
|
27
|
+
description: "Description is required for high budget projects"
|
|
28
|
+
ai_context:
|
|
29
|
+
business_rule: "High value projects (>10k) must have a detailed description"
|
|
30
|
+
condition:
|
|
31
|
+
field: budget
|
|
32
|
+
operator: ">"
|
|
33
|
+
value: 10000
|
|
34
|
+
rule:
|
|
35
|
+
field: description
|
|
36
|
+
operator: "not_empty"
|
|
37
|
+
message: "Description is required for high budget projects (> $10,000)"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: all_projects
|
|
2
|
+
label: "Active Projects"
|
|
3
|
+
type: list
|
|
4
|
+
object: projects
|
|
5
|
+
description: "Standard list view of all active projects"
|
|
6
|
+
|
|
7
|
+
config:
|
|
8
|
+
columns:
|
|
9
|
+
- field: name
|
|
10
|
+
width: 250
|
|
11
|
+
- field: status
|
|
12
|
+
width: 120
|
|
13
|
+
- field: priority
|
|
14
|
+
width: 100
|
|
15
|
+
- field: owner
|
|
16
|
+
width: 150
|
|
17
|
+
- field: budget
|
|
18
|
+
width: 120
|
|
19
|
+
- field: end_date
|
|
20
|
+
width: 120
|
|
21
|
+
|
|
22
|
+
sort:
|
|
23
|
+
- field: created_at
|
|
24
|
+
direction: desc
|
|
25
|
+
|
|
26
|
+
filters:
|
|
27
|
+
- field: status
|
|
28
|
+
operator: "!="
|
|
29
|
+
value: "archived"
|
|
30
|
+
|
|
31
|
+
actions:
|
|
32
|
+
- edit
|
|
33
|
+
- delete
|
|
34
|
+
- clone
|
|
35
|
+
- custom: approve
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
- _id: TASK-001
|
|
2
|
+
name: "Design Homepage Mockups"
|
|
3
|
+
project: "PROJ-001"
|
|
4
|
+
due_date: "2024-12-31"
|
|
5
|
+
completed: false
|
|
6
|
+
|
|
7
|
+
- _id: TASK-002
|
|
8
|
+
name: "Setup CI/CD Pipeline"
|
|
9
|
+
project: "PROJ-001"
|
|
10
|
+
due_date: "2024-11-15"
|
|
11
|
+
completed: true
|
|
12
|
+
|
|
13
|
+
- _id: TASK-003
|
|
14
|
+
name: "Draft App Requirements"
|
|
15
|
+
project: "PROJ-002"
|
|
16
|
+
due_date: "2025-01-20"
|
|
17
|
+
completed: false
|
|
18
|
+
|
|
19
|
+
- _id: TASK-004
|
|
20
|
+
name: "Choose Tech Stack"
|
|
21
|
+
project: "PROJ-002"
|
|
22
|
+
due_date: "2025-01-10"
|
|
23
|
+
completed: true
|