data-primals-engine 1.5.0 → 1.5.2

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 (63) hide show
  1. package/README.md +37 -0
  2. package/client/src/AddWidgetTypeModal.jsx +47 -43
  3. package/client/src/App.jsx +2 -6
  4. package/client/src/App.scss +13 -1
  5. package/client/src/AssistantChat.jsx +363 -323
  6. package/client/src/AssistantChat.scss +27 -10
  7. package/client/src/Dashboard.jsx +480 -396
  8. package/client/src/Dashboard.scss +1 -1
  9. package/client/src/DashboardHtmlViewItem.jsx +147 -0
  10. package/client/src/DashboardView.jsx +654 -569
  11. package/client/src/DataEditor.jsx +10 -3
  12. package/client/src/DataLayout.jsx +807 -755
  13. package/client/src/DataLayout.scss +14 -0
  14. package/client/src/DataTable.jsx +39 -75
  15. package/client/src/Dialog.scss +1 -1
  16. package/client/src/Field.jsx +2057 -1825
  17. package/client/src/FlexViewCard.jsx +44 -0
  18. package/client/src/HistoryDialog.jsx +69 -14
  19. package/client/src/HtmlViewBuilderModal.jsx +91 -0
  20. package/client/src/HtmlViewBuilderModal.scss +18 -0
  21. package/client/src/HtmlViewCard.jsx +44 -0
  22. package/client/src/HtmlViewCard.scss +35 -0
  23. package/client/src/KanbanCard.jsx +1 -2
  24. package/client/src/ModelCreator.jsx +5 -4
  25. package/client/src/ModelCreatorField.jsx +51 -4
  26. package/client/src/ModelList.jsx +280 -236
  27. package/client/src/Notification.jsx +136 -136
  28. package/client/src/Notification.scss +0 -18
  29. package/client/src/Pagination.jsx +5 -3
  30. package/client/src/RelationField.jsx +354 -258
  31. package/client/src/RelationSelectorWidget.jsx +173 -0
  32. package/client/src/contexts/ModelContext.jsx +10 -1
  33. package/client/src/contexts/UIContext.jsx +72 -63
  34. package/client/src/filter.js +263 -212
  35. package/client/src/hooks/useValidation.js +75 -0
  36. package/client/src/translations.js +24 -24
  37. package/package.json +7 -6
  38. package/src/constants.js +1 -1
  39. package/src/core.js +8 -1
  40. package/src/defaultModels.js +1596 -1544
  41. package/src/engine.js +85 -43
  42. package/src/events.js +137 -113
  43. package/src/i18n.js +710 -10
  44. package/src/index.js +3 -0
  45. package/src/modules/assistant/assistant.js +253 -134
  46. package/src/modules/assistant/constants.js +2 -1
  47. package/src/modules/bucket.js +2 -1
  48. package/src/modules/data/data.core.js +118 -92
  49. package/src/modules/data/data.history.js +555 -492
  50. package/src/modules/data/data.js +3 -53
  51. package/src/modules/data/data.operations.js +3381 -3231
  52. package/src/modules/data/data.relations.js +686 -686
  53. package/src/modules/data/data.routes.js +1879 -1821
  54. package/src/modules/data/data.validation.js +81 -2
  55. package/src/modules/file.js +247 -238
  56. package/src/modules/user.js +1 -0
  57. package/src/modules/workflow.js +2 -2
  58. package/src/openai.jobs.js +3 -2
  59. package/src/packs.js +5482 -5478
  60. package/src/sso.js +2 -2
  61. package/src/workers/import-export-worker.js +1 -1
  62. package/test/data.history.integration.test.js +264 -192
  63. package/test/data.integration.test.js +149 -3
@@ -1,1544 +1,1596 @@
1
- // Définition des structures de modèles
2
- export const defaultModels = {
3
- permission: {
4
- "name": "permission",
5
- "icon": "FaKey",
6
- "description": "",
7
- "fields": [
8
- {
9
- "name": "name",
10
- "type": "string_t",
11
- color: '#757BCC'
12
- },
13
- {
14
- "name": "description",
15
- "type": "richtext"
16
- }
17
- ]
18
- },
19
- role: {
20
- name: 'role',
21
- "icon": "FaUserTag",
22
- "description": "",
23
- fields: [
24
- { name: 'name', type: 'string_t', required: true, unique: true, color: '#363636' },
25
- { name: 'permissions', type: 'relation', multiple: true, relation: 'permission' }
26
- ]
27
- },
28
- user: {
29
- name: 'user',
30
- "description": "",
31
- "icon": "FaUser",
32
- locked: true,
33
- fields: [
34
- { name: 'username', type: 'string', required: true, unique: true, color: '#3C7D08' },
35
- { name: 'password', type: 'password' },
36
- {
37
- "name": "gender",
38
- "type": "enum",
39
- "items": ["male", "female", "other", "prefer_not_to_say"]
40
- },
41
- { name: 'contact', type: 'relation', relation: 'contact' },
42
- { name: 'roles', type: 'relation', multiple: true, relation: 'role' },
43
- { name: 'lang', type: 'relation', relation: 'lang', color: '#4CACCD' },
44
- {
45
- "name": "profilePicture",
46
- "type": "file",
47
- "mimeTypes": ["image/jpeg", "image/png"]
48
- },
49
- { name: 'tokens', type: 'relation', multiple: true, relation: 'token' }
50
- ]
51
- },
52
- userPermission: {
53
- "icon": "FaUserCheck",
54
- "name": "userPermission",
55
- "description": "Gère les exceptions aux permissions des rôles pour un utilisateur (ajouts ou retraits, permanents ou temporaires).",
56
- "fields": [
57
- {
58
- "name": "user",
59
- "type": "relation",
60
- "relation": "user",
61
- "required": true,
62
- "index": true
63
- },
64
- {
65
- "name": "permission",
66
- "type": "relation",
67
- "relation": "permission",
68
- "required": true,
69
- "index": true
70
- },
71
- {
72
- "name": "isGranted",
73
- "type": "boolean",
74
- "required": true,
75
- "hint": "True pour accorder la permission, False pour la révoquer explicitement."
76
- },
77
- {
78
- "name": "expiresAt",
79
- "type": "datetime",
80
- "required": false,
81
- "index": true,
82
- "hint": "Si défini, l'exception (l'octroi ou la révocation) est temporaire."
83
- }
84
- ]
85
- },
86
- token: {
87
- name: 'token',
88
- "icon": "FaKey",
89
- "description": "",
90
- fields: [
91
- { name: 'name', type: 'string' },
92
- { name: 'value', type: 'password' },
93
- { name: 'lastRefresh', type: 'datetime' }
94
- ]
95
- },
96
- translation: {
97
- name: 'translation',
98
- "icon": "FaLanguage",
99
- locked: true,
100
- "description": "",
101
- fields: [
102
- { name: 'lang', type: 'relation', 'relation': 'lang', required: true, color: '#4CACCD' },
103
- { name: 'key', type: 'string', maxlength: 200, required: true },
104
- { name: 'value', type: 'string' }
105
- ]
106
- },
107
- lang: {
108
- name: 'lang',
109
- "icon": "FaGlobe",
110
- locked: true,
111
- "description": "",
112
- fields: [
113
- { name: 'name', unique: true, type: 'string_t', maxlength: 200, color: '#4CACCD' },
114
- { name: 'code', type: 'string', maxlength: 5 }
115
- ]
116
- },
117
- currency: {
118
- name: 'currency',
119
- "icon": "FaMoneyBill",
120
- "description": "",
121
- locked: true,
122
- fields: [
123
- { name: 'symbol', type: 'string', required: true, color: '#E0E0E0', maxlength: 20, asMain: true },
124
- { name: 'code', type: 'string', required: true, unique: true, maxlength: 3, asMain: true },
125
- { name: 'name', type: 'string_t', required: true, color: '#AE6FA3' },
126
- { name: 'exchangeRate', type: 'number', required: false },
127
- { name: 'default', type: 'boolean', default: false }
128
- ]
129
- },
130
- channel: {
131
- name: 'channel',
132
- "icon": "FaComments",
133
- "description": "",
134
- fields: [
135
- { name: 'name', type: 'string_t', required: true, unique: true }, // Nom du canal (ex: "email", "SMS")
136
- { name: 'description', type: 'string_t' },
137
- { name: 'type', type: 'enum', items: ['web', 'mobile', 'email', 'sms', 'push'], required: true } // Type de canal
138
- ]
139
- },
140
- message: {
141
- name: 'message',
142
- "icon": "FaEnvelope",
143
- "description": "",
144
- locked: true,
145
- fields: [
146
- { name: 'sender', type: 'relation', relation: 'user' }, // Utilisateur émetteur (si applicable, sinon système)
147
- { name: 'recipient', type: 'relation', relation: 'user' }, // Utilisateur destinataire
148
- { name: 'lang', type: 'relation', relation: 'lang' }, // Utilisateur destinataire
149
- { name: 'subject', type: 'string' }, // Sujet de la notification (ex: titre de l'email)
150
- { name: 'content', type: 'richtext', required: true }, // Contenu du message (localisable)
151
- { name: 'channels', type: 'relation', multiple: true, relation: 'channel' }, // Canaux de diffusion (email, SMS, forum, etc.)
152
- { name: 'status', type: 'enum', items: ['pending', 'sent', 'read', 'failed'] },
153
- { name: 'sentAt', type: 'datetime' },
154
- { name: 'readAt', type: 'datetime' },
155
- { name: 'type', type: 'string' }, // Type de notification (ex: "commande.miseAJour", "messageForum")
156
- { name: 'priority', type: 'enum', items: ['low', 'medium', 'high']}
157
- ]
158
- },
159
- alert: {
160
- name: "alert",
161
- "icon": "FaBell",
162
- description: "Définit les règles pour les alertes et les insights automatiques.",
163
- fields: [
164
- { name: "name", type: "string", required: true, asMain: true },
165
- { name: "targetModel", type: "model", required: true },
166
- { name: "description", type: "string_t", multiline: true },
167
- {
168
- name: "triggerCondition",
169
- type: "code",
170
- language: "json",
171
- conditionBuilder: true,
172
- targetModel: '$targetModel',
173
- required: true,
174
- hint: "La condition qui, si elle est remplie, déclenchera l'alerte."
175
- },
176
- {
177
- name: "frequency",
178
- type: "cronSchedule",
179
- required: true,
180
- cronMask: [false, true, true, true, true, true],
181
- hint: "À quelle fréquence vérifier si la condition est remplie."
182
- },
183
- { name: "isActive", type: "boolean", default: true },
184
- {
185
- name: "sendEmail",
186
- type: "boolean",
187
- default: false,
188
- hint: "Cochez pour envoyer également une notification par e-mail."
189
- },
190
- {
191
- name: "lastNotifiedAt",
192
- type: "datetime",
193
- required: false, // Important: ce champ est géré par le système
194
- hint: "Timestamp de la dernière notification envoyée pour cette alerte."
195
- },
196
- {
197
- name: "message",
198
- type: "richtext_t",
199
- required: false,
200
- hint: "Message personnalisé pour l'e-mail. Si vide, un message par défaut sera utilisé. Vous pouvez utiliser les variables {count}, {alert.name}....",
201
- condition: { $eq: ["$sendEmail", true] }
202
- }
203
- ]
204
- },
205
- env: {
206
- name: "env",
207
- "icon": "FaCog",
208
- description: "Définit les variables d'environnement qui seront accessibles dans vos scripts et webhooks.",
209
- fields: [
210
- { name: "name", type: "string", required: true, unique: true, asMain: true },
211
- { name: "value", type: "string", anonymized: true, hiddenable: true }
212
- ]
213
- },
214
- webpage: {
215
- name: 'webpage',
216
- "icon": "FaFileAlt",
217
- locked: true,
218
- "description": "",
219
- fields: [
220
- { name: 'title', type: 'string_t', required: true, color: '#659DE6' },
221
- { name: 'path', type: 'string', required: true, unique: true, color: '#DEDEDE' },
222
- { name: 'html', type: 'richtext' },
223
- { name: 'published', type: 'boolean', default: false },
224
- { name: 'inSitemap', type: 'boolean', default: true },
225
- { name: 'description', type: 'string' },
226
- { name: 'keywords', type: 'relation', relation: 'taxonomy', multiple: true },
227
- { name: 'image', type: 'url' },
228
- { name: 'category', type: 'relation', relation: 'taxonomy' }
229
- ]
230
- },
231
- content: {
232
- name: 'content',
233
- "icon": "FaFileAlt",
234
- "description": "",
235
- fields: [
236
- { name: 'lang', type: 'relation', relation: 'lang' },
237
- { name: 'title', type: 'string_t', required: true },
238
- { name: 'slug', type: 'string' },
239
- { name: 'html', type: 'richtext_t' },
240
- { name: 'image', type: 'file', mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] },
241
- { name: 'published', type: 'boolean' },
242
- { name: 'publishedAt', type: 'datetime' },
243
- { name: 'author', type: 'relation', relation: 'user' },
244
- { name: 'category', type: 'relation', relation: 'taxonomy', "relationFilter": {
245
- "path": [
246
- "type"
247
- ],
248
- "op": "$eq",
249
- "value": "category"
250
- } },
251
- { name: 'keywords', type: 'relation', relation: 'taxonomy', multiple: true, "relationFilter": {
252
- "path": [
253
- "type"
254
- ],
255
- "op": "$eq",
256
- "value": "keyword"
257
- } },
258
- { name: 'order', type: 'number', step: 1, default: 0 },
259
- { name: 'inSitemap', type: 'boolean', default: false }
260
- ]
261
- },
262
- resource: {
263
- name: 'resource',
264
- "icon": "FaBoxOpen",
265
- "description": "",
266
- fields: [
267
- { name: "source", type: "url"},
268
- { name: "file", type: "file"}
269
- ]
270
- },
271
- taxonomy: {
272
- name: 'taxonomy',
273
- "icon": "FaTags",
274
- "description": "",
275
- fields: [
276
- { name: 'name', type: 'string_t', required: true, color: '#71A314' },
277
- { name: 'parent', type: 'relation', relation: 'taxonomy', color: '#233607' }, // Relation vers la taxonomie parente
278
- { name: 'type', type: 'enum', items: ['keyword', 'category'], color: '#BFBFBF' },
279
- { name: 'identifier', type: 'string' },
280
- { name: 'order', type: 'number', step: 1, default: 0 },
281
- { name: 'description', type: 'richtext' }
282
- ]
283
- },
284
- contact: {
285
- locked: true,
286
- name: 'contact',
287
- "icon": "FaAddressBook",
288
- "description": "",
289
- fields: [
290
- { name: 'legalName', type: 'string', asMain: true, color: '#D9D9D9' },
291
- { name: 'firstName', type: 'string', asMain: true},
292
- { name: 'lastName', type: 'string', asMain: true },
293
- { name: 'email', type: 'email', color: '#F4ECE2' },
294
- { name: 'phone', type: 'phone', color: '#B4A693' },
295
- { name: 'location', type: 'relation', relation: 'location' }
296
- ]
297
- },
298
-
299
- location: {
300
- "name": "location",
301
- "icon": "FaMapMarkerAlt",
302
- locked: true,
303
- "description": "",
304
- "fields": [
305
- {
306
- "name": "address_1",
307
- "type": "string",
308
- asMain: true,
309
- color: '#D6D6D6'
310
- },
311
- {
312
- "name": "address_2",
313
- "type": "string"
314
- },
315
- {
316
- "name": "address_3",
317
- "type": "string"
318
- },
319
- {
320
- "name": "address_4",
321
- "type": "string"
322
- },
323
- {
324
- "name": "city",
325
- "type": "string",
326
- asMain: true,
327
- color: '#E63345'
328
- },
329
- {
330
- "name": "postalCode",
331
- "type": "string",
332
- asMain: true,
333
- color: '#8B1D1D'
334
- },
335
- {
336
- "name": "region",
337
- "type": "string"
338
- },
339
- {
340
- "name": "country",
341
- "type": "string",
342
- color: "#4F80BF",
343
- asMain: true
344
- },
345
- {
346
- "name": "latitude",
347
- "type": "number",
348
- "unit": "°"
349
- },
350
- {
351
- "name": "longitude",
352
- "type": "number",
353
- "unit": "°"
354
- }
355
- ]
356
- },
357
-
358
- brand: {
359
- name: 'brand',
360
- "icon": "FaTrademark",
361
- "description": "",
362
- fields: [
363
- { name: 'name', type: 'string', required: true },
364
- { name: 'logo', type: 'file' },
365
- { name: 'company', type: 'relation', relation: 'contact' }
366
- ]
367
- },
368
-
369
- product: {
370
- name: 'product',
371
- "icon": "FaShoppingBag",
372
- "description": "",
373
- fields: [
374
- { name: 'name', type: 'string_t', required: true },
375
- { name: 'image', type: 'array', itemsType: 'file', mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] },
376
- { name: 'description', type: 'richtext_t' },
377
- { name: 'price', type: 'number', required: true },
378
- { name: 'currency', type: 'relation', relation: 'currency', required: true },
379
- { name: 'billingFrequency', type: 'enum', items: ['aucune', 'au mois', 'à l\'année'] },
380
- { name: 'slug', type: 'string', required: true, unique: true },
381
- { name: 'brand', type: 'relation', relation: 'brand' },
382
- { name: 'category', type: 'relation', relation: 'taxonomy' },
383
- { name: 'seoTitle', type: 'string_t' },
384
- { name: 'seoDescription', type: 'string_t' }
385
- ]
386
- },
387
- productVariant: {
388
- name: 'productVariant',
389
- "icon": "FaBox",
390
- "description": "",
391
- fields: [
392
- { name: 'product', type: 'relation', relation: 'product', required: true },
393
- { name: 'size', type: 'string' },
394
- { name: 'color', type: 'color' },
395
- { name: 'sku', type: 'string', unique: true },
396
- { name: 'price', type: 'number', required: true },
397
- { name: 'currency', type: 'relation', relation: 'currency', required: true },
398
- { name: 'stock', type: 'number', default: 0 },
399
- { name: 'description', type: 'richtext' },
400
- { name: 'image', type: 'url' }
401
- ]
402
- },
403
- cart: {
404
- name: 'cart',
405
- "icon": "FaShoppingCart",
406
- "description": "",
407
- fields: [
408
- { name: 'user', type: 'relation', relation: 'user', required: true },
409
- { name: 'items', type: 'relation', relation: 'cartItem', multiple: true },
410
- { name: 'creationDate', type: 'datetime', required: true },
411
- { name: 'lastUpdate', type: 'datetime', required: true },
412
- { name: 'active', type: 'boolean', default: true }
413
- ]
414
- },
415
- cartItem: {
416
- name: 'cartItem',
417
- "icon": "FaShoppingBasket",
418
- "description": "",
419
- fields: [
420
- { name: 'product', type: 'relation', relation: 'product', required: true },
421
- { name: 'quantity', type: 'number', required: true, min: 1, step: 1 },
422
- { name: 'variant', type: 'relation', relation: 'productVariant' } // Optionnel, si vous avez des variantes
423
- ]
424
- },
425
- discount: {
426
- name: "discount",
427
- "icon": "FaTicketAlt",
428
- locked: true,
429
- "description": "",
430
- fields: [
431
- { "name": "code", "type": "string", "required": true, "unique": true },
432
- { "name": "productSelection", "type": "relation", "relation": "product", "required": false, multiple: true },
433
- { "name": "description", "type": "richtext" },
434
- { "name": "percentAmount", "type": "number", "unit": "%", default: null, min: 0 },
435
- { "name": "fixedAmount", "type": "number", default: null, min: 0 },
436
- { "name": "minAmount", "type": "number", "unit": "€", default: null, min: 0 }, // Montant minimum pour la promotion
437
- { "name": "minProductQuantity", "type": "number", min: 0 }, // Montant minimum pour la promotion
438
- { "name": "freeProductQuantity", "type": "number", default: null, min: 0 }, // Quantité de produits offerts
439
- { "name": "startDate", "type": "datetime" },
440
- { "name": "endDate", "type": "datetime" }
441
- ]
442
- },
443
- order: {
444
- name: "order",
445
- "icon": "FaClipboardList",
446
- locked: true,
447
- "description": "",
448
- fields: [
449
- { "name": "orderId", "type": "string", "required": true, "unique": true },
450
- { "name": "orderDate", "type": "datetime" },
451
- { "name": "status", "type": "enum", items: ["pending", "processing", "shipped", "delivered", "cancelled"] },
452
- { "name": "products", "type": "relation", "relation": "cartItem", "required": true, multiple: true },
453
- { "name": "customer", "type": "relation", relation: 'user' }, // Relation vers le modèle 'user'
454
- { "name": "totalAmount", "type": "number", "required": true },
455
- { "name": "paymentIntentId", "type": "string", "hint": "Stripe Payment Intent ID for this order." },
456
- { "name": "currency", "type": "relation", "relation": "currency" },
457
- { "name": "paymentMethod", "type": "string" },
458
- { "name": "shippingAddress", "type": "relation", "relation": "location" },
459
- { "name": "billingAddress", "type": "relation", "relation": "location" },
460
- { "name": "shippedDate", "type": "datetime" },
461
- { "name": "deliveryDate", "type": "datetime" },
462
- { "name": "discount", "type": "relation", relation: 'discount' } // Relation vers le modèle 'promotion'
463
- ]
464
- },
465
- invoice: {
466
- name: 'invoice',
467
- "icon": "FaFileInvoice",
468
- "description": "",
469
- fields: [
470
- { name: 'order', type: 'relation', relation: 'order', required: true },
471
- { name: 'invoiceId', type: 'string', required: true, unique: true },
472
- { name: 'invoiceDate', type: 'datetime', required: true },
473
- { name: 'dueDate', type: 'datetime' },
474
- { name: 'status', type: 'enum', items: ['paid', 'unpaid', 'partially_paid', 'cancelled'] }
475
- ]
476
- },
477
- userSubscription: {
478
- name: 'userSubscription',
479
- "icon": "FaCalendarCheck",
480
- "description": "",
481
- locked: true,
482
- fields: [
483
- { name: 'user', type: 'relation', relation: 'user', required: true },
484
- { name: 'product', type: 'relation', relation: 'product', required: true },
485
- { name: 'startDate', type: 'datetime', required: true },
486
- { name: 'endDate', type: 'datetime' },
487
- { name: 'price', type: 'number', required: true },
488
- { name: 'currency', type: 'relation', relation: 'currency', required: true },
489
- { name: 'paymentMethod', type: 'enum', items: ['bank_card', 'SEPA_mandate', 'cash', 'check', 'other'] },
490
- { name: 'status', type: 'enum', items: ['active', 'inactive', 'cancelled', 'expired', 'pending'] },
491
- { name: 'billingCycleAnchor', type: 'datetime' },
492
- { name: 'nextBillingDate', type: 'datetime' },
493
- { name: 'lastBillingDate', type: 'datetime' },
494
- { name: 'cancelReason', type: 'string' },
495
- { name: 'autoRenew', type: 'boolean', default: false }
496
- ]
497
- },
498
- stock: {
499
- name: 'stock',
500
- "icon": "FaWarehouse",
501
- "description": "",
502
- fields: [
503
- { name: 'product', type: 'relation', relation: 'product', required: true },
504
- { name: 'variant', type: 'relation', relation: 'productVariant' }, // Optionnel
505
- { name: 'warehouse', type: 'relation', relation: 'warehouse', required: true },
506
- { name: 'available', type: 'number', default: 0 },
507
- { name: 'reserved', type: 'number', default: 0 } // Quantité réservée (pour les commandes en cours)
508
- ]
509
- },
510
- stockAlert: {
511
- name: 'stockAlert',
512
- "icon": "FaExclamationTriangle",
513
- "description": "",
514
- fields: [
515
- { name: 'user', type: 'relation', relation: 'user', required: true },
516
- { name: 'stock', type: 'relation', relation: 'stock', required: true },
517
- { name: 'threshold', type: 'number', required: true, min: 0 }
518
- ]
519
- // how to implement unique fields on COMBINATION of multiple columns ?
520
- },
521
- shipment: {
522
- name: 'shipment',
523
- "icon": "FaTruck",
524
- "description": "",
525
- fields: [
526
- { name: 'order', type: 'relation', relation: 'order', required: true },
527
- { name: 'trackingNumber', type: 'string' },
528
- { name: 'carrier', type: 'string' },
529
- { name: 'status', type: 'enum', items: ['pending', 'in_transit', 'delivered', 'issue'] },
530
- { name: 'estimatedDeliveryDate', type: 'datetime' },
531
- { name: 'actualDeliveryDate', type: 'datetime' }
532
- ]
533
- },
534
- warehouse: {
535
- name: 'warehouse',
536
- "description": "",
537
- "icon": "FaWarehouse",
538
- fields: [
539
- { name: 'name', type: 'string_t', required: true },
540
- { name: 'location', type: 'relation', relation: 'location' },
541
- { name: 'capacity', type: 'number' }
542
- ]
543
- },
544
- 'return': {
545
- name: "return",
546
- "description": "",
547
- "icon": "FaUndo",
548
- fields: [
549
- { "name": "order", "type": "relation", "relation": "order", "required": true },
550
- { "name": "user", "type": "relation", relation: "user" },
551
- { "name": "reason", "type": "string", maxlength: 2048, required: true },
552
- { "name": "channel", "type": "relation", relation: 'channel' },
553
- { "name": "status", "type": "enum", items: ["pending", "approved", "refunded", "refused"] },
554
- { name: 'amount', type: 'number', min: 0 },
555
- { name: 'currency', type: 'relation', relation: 'currency' },
556
- { name: 'refundDate', type: 'datetime' }
557
- ]
558
- },
559
- returnItem: {
560
- name: 'returnItem',
561
- "icon": "FaBoxOpen",
562
- "description": "",
563
- fields: [
564
- { name: 'return', type: 'relation', relation: 'return', required: true },
565
- { name: 'product', type: 'relation', relation: 'product', required: true },
566
- { name: 'variant', type: 'relation', relation: 'productVariant' },
567
- { name: 'quantity', type: 'number', required: true, min: 1 },
568
- { name: 'condition', type: 'enum', items: ['new', 'very_good', 'good', 'degraded', 'damaged', 'unusable'] }
569
- ]
570
- },
571
- ticket: {
572
- name: 'ticket',
573
- "icon": "FaTicketAlt",
574
- "description": "",
575
- locked: true,
576
- fields: [
577
- { name: 'user', type: 'relation', relation: 'user', required: true },
578
- { name: 'order', type: 'relation', relation: 'order' },
579
- { name: 'channel', type: 'relation', relation: 'channel' },
580
- { name: 'parent', type: 'relation', relation: 'ticket' },
581
- { name: 'subject', type: 'string', required: true },
582
- { name: 'message', type: 'richtext', required: true },
583
- { name: 'status', type: 'enum', items: ['opened', 'in_progress', 'closed'] },
584
- { name: 'priority', type: 'enum', items: ['low', 'medium', 'high', 'urgent'] },
585
- { name: 'assignedTo', type: 'relation', relation: 'user' },
586
- { name: 'createdAt', type: 'datetime', required: true }
587
- ]
588
- },
589
- review: {
590
- name: "review",
591
- "icon": "FaStar",
592
- "description": "",
593
- fields: [
594
- { "name": "user", "type": "relation", relation: "user" },
595
- { "name": "product", "type": "relation", relation: 'product' },
596
- { "name": "productVariant", "type": "relation", relation: 'productVariant' },
597
- { "name": "comment", "type": "richtext", maxlength: 2048, required: true },
598
- { "name": "score", "type": "number" },
599
- { "name": "publishedAt", "type": "datetime", required: true }
600
- ]
601
- },
602
- device: {
603
- name: "device",
604
- "icon": "FaMobile",
605
- "description": "",
606
- fields: [
607
- { "name": "location", "type": "relation", relation: 'location' },
608
- { "name": "lastLocationUpdate", "type": "datetime" }
609
- ]
610
- },
611
- // Modèle pour l'exercice comptable et l'entreprise
612
- accountingExercise: {
613
- name: 'accountingExercise',
614
- "icon": "FaBook",
615
- description: "Représente un exercice comptable pour une entreprise donnée.",
616
- fields: [
617
- { name: 'name', type: 'string_t', 'required': true, unique: true, hint: "Intitulé de l'exercice comptable" },
618
- { name: 'companyContact', type: 'relation', relation: 'contact', 'required': true, hint: "Désignation de l'entreprise" },
619
- { name: 'companyIdentifier', type: 'string', asMain: true, hint: "SIRET de l'entreprise", unique: true },
620
- { name: 'startDate', type: 'date', required: true, asMain: true, hint: "Date de début de l'exercice" },
621
- { name: 'endDate', type: 'date', required: true, asMain: true, hint: "Date de clôture de l'exercice" }
622
- ]
623
- },
624
-
625
- // Modèle pour définir la structure des lignes comptables (le "plan")
626
- accountingLineItem: {
627
- name: 'accountingLineItem',
628
- "icon": "FaListAlt",
629
- description: "Définit une ligne/catégorie dans un document comptable.",
630
- locked: true, // Probablement géré par l'application, pas par l'utilisateur final
631
- fields: [
632
- { name: 'accountingExercise', type: 'relation', required: true, unique: true, relation: "accountingExercise" },
633
- { name: 'code', type: 'string', required: true, unique: true, hint: "Code unique de la ligne (ex: AA, FB, HA)" },
634
- { name: 'label', type: 'string_t', required: true, hint: "Libellé de la ligne (ex: Frais d'établissement)" },
635
- {
636
- name: 'documentType', type: 'enum', required: true,
637
- items: ['bilan_actif', 'bilan_passif', 'compte_resultat', 'immobilisations', 'amortissements', 'provisions', 'creances_dettes',
638
- 'deficits',
639
- 'plus_moins_values',
640
- 'effectifs_valeur_ajoutee',
641
- 'capital_social',
642
- 'filiales_participations',
643
- 'resultat_fiscal']
644
- },
645
- { name: 'section', type: 'string_t', required: true, hint: "Section principale (ex: ACTIF IMMOBILISÉ)" },
646
- { name: 'subSection', type: 'string_t', hint: "Sous-section (ex: IMMOBILISATIONS INCORPORELLES)" },
647
- { name: 'order', type: 'number', hint: "Ordre d'affichage dans la section/sous-section" },
648
- { name: 'calculationFormula', type: 'string', hint: "Formule de calcul (si applicable)" },
649
- {
650
- name: 'values', type: 'array', itemsType: 'number', required: true,
651
- hint: "Valeurs de la ligne comptable"
652
- },
653
- { name: 'notes', type: 'richtext', hint: "Notes ou renvois (ex: (1), (3))" }
654
- ]
655
- },
656
- accountingEntry: {
657
- "name": "accountingEntry",
658
- "icon": "FaPenAlt",
659
- "description": "",
660
- "fields": [
661
- {
662
- "name": "exercise",
663
- "type": "relation",
664
- "relation": "accountingExercise",
665
- "required": true
666
- },
667
- {
668
- "name": "label",
669
- "type": "string",
670
- "required": true,
671
- "asMain": true,
672
- "maxlength": 255
673
- },
674
- {
675
- "name": "entryDate",
676
- "type": "date",
677
- "required": true
678
- },
679
- {
680
- "name": "amount",
681
- "type": "number",
682
- "default": 0
683
- },
684
- {
685
- "name": "currency",
686
- "type": "relation",
687
- "relation": "currency",
688
- "required": true
689
- },
690
- {
691
- "name": "referenceNumber",
692
- "type": "string",
693
- "maxlength": 100
694
- },
695
- {
696
- "name": "notes",
697
- "type": "richtext"
698
- },
699
- {
700
- "name": "status",
701
- "type": "enum",
702
- "items": ["draft", "validated", "cancelled"],
703
- "default": "brouillon"
704
- },
705
- {
706
- "name": "createdBy",
707
- "type": "relation",
708
- "relation": "user"
709
- },
710
- {
711
- "name": "validatedBy",
712
- "type": "relation",
713
- "relation": "user"
714
- },
715
- {
716
- "name": "validationDate",
717
- "type": "datetime"
718
- },
719
- {
720
- "name": "attachments",
721
- "type": "array",
722
- "itemsType": "file"
723
- }
724
- ]
725
- },
726
- employee: {
727
- "name": "employee",
728
- "icon": "FaUserTie",
729
- "description": "",
730
- "fields": [
731
- {
732
- "name": "employeeId",
733
- "type": "string",
734
- "required": true,
735
- "unique": true
736
- },
737
- {
738
- "name": "personalInfo",
739
- "type": "relation",
740
- "relation": "user",
741
- "required": true
742
- },
743
- {
744
- "name": "jobTitle",
745
- "type": "string",
746
- "required": true
747
- },
748
- {
749
- "name": "department",
750
- "type": "string"
751
- },
752
- {
753
- "name": "manager",
754
- "type": "relation",
755
- "relation": "employee"
756
- },
757
- {
758
- "name": "workLocation",
759
- "type": "relation",
760
- "relation": "location"
761
- },
762
- {
763
- "name": "employmentType",
764
- "type": "enum",
765
- "items": ["full_time", "part_time", "contractor", "intern", "temporary"]
766
- },
767
- {
768
- "name": "emergencyContact",
769
- "type": "relation",
770
- "relation": "contact"
771
- },
772
- {
773
- "name": "homeAddress",
774
- "type": "relation",
775
- "relation": "location"
776
- },
777
- {
778
- "name": "dateOfBirth",
779
- "type": "date"
780
- },
781
- {
782
- "name": "nationality",
783
- "type": "string"
784
- },
785
- {
786
- "name": "nationalId",
787
- "type": "string"
788
- },
789
- {
790
- "name": "socialSecurityNumber",
791
- "type": "string"
792
- },
793
- {
794
- "name": "taxId",
795
- "type": "string"
796
- },
797
- {
798
- "name": "startDate",
799
- "type": "date",
800
- "required": true
801
- },
802
- {
803
- "name": "endDate",
804
- "type": "date"
805
- },
806
- {
807
- "name": "contractType",
808
- "type": "string"
809
- },
810
- {
811
- "name": "salary",
812
- "type": "number"
813
- },
814
- {
815
- "name": "salaryCurrency",
816
- "type": "relation",
817
- "relation": "currency"
818
- },
819
- {
820
- "name": "payFrequency",
821
- "type": "enum",
822
- "items": ["weekly", "bi_weekly", "monthly"]
823
- },
824
- {
825
- "name": "bankAccountNumber",
826
- "type": "string"
827
- },
828
- {
829
- "name": "bankName",
830
- "type": "string"
831
- },
832
- {
833
- "name": "iban",
834
- "type": "string"
835
- },
836
- {
837
- "name": "swiftBic",
838
- "type": "string"
839
- },
840
- {
841
- "name": "workPermitNumber",
842
- "type": "string"
843
- },
844
- {
845
- "name": "workPermitExpiry",
846
- "type": "date"
847
- },
848
- {
849
- "name": "visaType",
850
- "type": "string"
851
- },
852
- {
853
- "name": "visaExpiry",
854
- "type": "date"
855
- },
856
- {
857
- "name": "skills",
858
- "type": "array",
859
- "itemsType": "string"
860
- },
861
- {
862
- "name": "notes",
863
- "type": "richtext"
864
- }
865
- ]
866
- },
867
- workflow: {
868
- name: 'workflow',
869
- "icon": "FaProjectDiagram",
870
- description: "Defines an automated process.",
871
- fields: [
872
- { name: 'name', type: 'string_t', required: true, hint: "Unique name for the workflow (e.g., 'Order Validation', 'Low Stock Notification')." },
873
- { name: 'description', type: 'richtext', hint: "Detailed explanation of the workflow's purpose." },
874
- { name: 'startStep', type: 'relation', relation: 'workflowStep', required: false, hint: "The first step to execute when the workflow starts." }
875
- ]
876
- },
877
- workflowTrigger: {
878
- name: 'workflowTrigger',
879
- "icon": "FaPlay",
880
- description: "Represents an event that can initiate a workflow.",
881
- fields: [
882
- { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
883
- { name: 'name', type: 'string_t', required: true, unique: true, hint: "Descriptive name for the trigger (e.g., 'New Order Created', 'Stock < 5', 'Monday 9 AM Report')." },
884
- {
885
- name: 'type',
886
- type: 'enum',
887
- items: ['manual', 'scheduled'],
888
- required: true
889
- },
890
- {
891
- name: 'onEvent',
892
- type: 'enum',
893
- items: ['DataAdded', 'DataEdited', 'DataDeleted', 'ModelAdded', 'ModelEdited', 'ModelDeleted'],
894
- condition: { $eq: ["$type", "manual"] }
895
- },
896
- { name: 'targetModel', type: 'model', condition: { // Condition pour afficher le champ
897
- $and: [
898
- {$eq: ["$type", "manual"]},
899
- {
900
- $or: [
901
- { $eq: ["$onEvent", "DataAdded"] },
902
- { $eq: ["$onEvent", "DataEdited"] },
903
- { $eq: ["$onEvent", "DataDeleted"] }
904
- ]
905
- }
906
- ]
907
- }},
908
- { name: 'dataFilter', type: 'code', language: 'json', targetModel: '$targetModel', conditionBuilder: true, hint: "Optional conditions checked before executing the step's action.",
909
- condition: { // Condition pour afficher le champ
910
- $and: [
911
- {$eq: ["$type", "manual"]},
912
- {
913
- $or: [
914
- { $eq: ["$onEvent", "DataAdded"] },
915
- { $eq: ["$onEvent", "DataEdited"] },
916
- { $eq: ["$onEvent", "DataDeleted"] }
917
- ]
918
- }
919
- ]
920
- }
921
- },
922
- { name: 'env', type: 'code', language: 'json', hint: "Environment variables (JSON key/value pairs)",default: {} },
923
- { name: 'isActive', type: 'boolean' },
924
- { name: 'cronExpression', type: 'cronSchedule', cronMask:[false, true, true, true, true, true], hint: "Cron expression for scheduling (e.g., '0 9 * * 1' for Monday 9 AM) (used by Scheduled type).",
925
- condition:
926
- {$eq: ["$type", "scheduled"]}}
927
- ]
928
- },
929
- workflowStep: {
930
- name: 'workflowStep',
931
- "icon": "FaStepForward",
932
- description: "A single step within a workflow process.",
933
- fields: [
934
- { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
935
- { name: 'name', type: 'string_t', hint: "Optional descriptive name for the step (e.g., 'Check Inventory', 'Send Confirmation Email')." },
936
- { name: 'conditions', type: 'code', language: 'json', conditionBuilder: true, hint: "Optional conditions checked before executing the step's action." },
937
- { name: 'actions', type: 'relation', relation: 'workflowAction', multiple: true, required: true, hint: "The main actions performed by this step." },
938
- { name: 'onSuccessStep', type: 'relation', relation: 'workflowStep', hint: "Optional: The next step if this step's action succeeds." },
939
- { name: 'onFailureStep', type: 'relation', relation: 'workflowStep', hint: "Optional: The next step if conditions fail or the action fails." },
940
- { name: 'isTerminal', type: 'boolean', default: false, hint: "Indicates if this step marks the end of a workflow path." }
941
- ]
942
- },
943
- workflowAction: {
944
- name: 'workflowAction',
945
- "icon": "FaCogs",
946
- description: "Defines a specific operation to be performed by a workflow step.",
947
- fields: [
948
- { name: 'name', type: 'string_t', required: true, hint: "Name of the action (e.g., 'Update Order Status', 'Send Email', 'Call Payment API')." },
949
- {
950
- name: 'type',
951
- type: 'enum',
952
- required: true,
953
- items: ['UpdateData', 'CreateData', 'DeleteData', 'ExecuteScript', 'HttpRequest', 'SendEmail', 'Wait', 'GenerateAIContent', 'ExecuteServiceFunction'],
954
- hint: "The type of operation to perform."
955
- },
956
- // For UpdateData / CreateData / DeleteData
957
- { name: 'targetModel', condition: {
958
- $or: [
959
- {$eq: ["$type", "CreateData"]},
960
- {$eq: ["$type", "UpdateData"]},
961
- {$eq: ["$type", "DeleteData"]}
962
- ]
963
- }, type: 'model', hint: "Model to target" },
964
-
965
- // For UpdateData / DeleteData
966
- { name: 'targetSelector', targetModel: "$targetModel", conditionBuilder: true, condition: {
967
- $or: [
968
- {$eq: ["$type", "UpdateData"]},
969
- {$eq: ["$type", "DeleteData"]}
970
- ]
971
- }, type: 'code', language: 'json', hint: "Expression to filter to the target document(s)." },
972
-
973
- // For UpdateData
974
- { name: 'fieldsToUpdate', condition: {$eq: ["$type", "UpdateData"]}, type: 'code', language: 'json', default: {}, hint: "Key-value pairs of fields to update (e.g., { status: 'Validé', lastUpdated: '{now}' })" },
975
-
976
- // For CreateData
977
- { name: 'dataToCreate', condition: {$eq: ["$type", "CreateData"]}, type: 'code', language: 'json', default: {}, hint: "Object template for the new document to create" },
978
-
979
- // For HttpRequest
980
- { name: 'url', condition: {$eq: ["$type", "HttpRequest"]}, type: 'string', hint: "The URL to call." },
981
- { name: 'method', condition: {$eq: ["$type", "HttpRequest"]}, type: 'enum', items: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], default: 'POST', hint: "HTTP method." },
982
- { name: 'headers', condition: {$eq: ["$type", "HttpRequest"]}, type: 'code', language: 'json',default: {}, hint: "HTTP headers as key-value pairs." },
983
- { name: 'body', condition: {$eq: ["$type", "HttpRequest"]}, type: 'code', language: 'json',default: {}, hint: "Request body, can include variables." },
984
-
985
- // For SendEmail
986
- {
987
- name: 'emailRecipients',
988
- type: 'array',
989
- itemsType: 'string',
990
- condition: { $eq: ["$type", "SendEmail"] },
991
- hint: "Destinataire(s) de l'e-mail. Peut être une adresse, plusieurs adresses séparées par des virgules, ou une variable comme {triggerData.client.email}."
992
- },
993
- {
994
- name: 'emailSubject',
995
- type: 'string',
996
- condition: { $eq: ["$type", "SendEmail"] },
997
- hint: "Sujet de l'e-mail. Peut contenir des variables."
998
- },
999
- {
1000
- name: 'emailContent',
1001
- type: 'richtext',
1002
- condition: { $eq: ["$type", "SendEmail"] },
1003
- hint: "Contenu de l'e-mail. Peut contenir des variables et du HTML."
1004
- },
1005
-
1006
- // For Wait
1007
- { name: 'duration', condition: {$eq: ["$type", "Wait"]}, type: 'number', hint: "Duration to wait." },
1008
- { name: 'durationUnit', condition:{$eq: ["$type", "Wait"]}, type: 'enum', items: ['milliseconds', 'seconds', 'minutes', 'hours', 'days'], default: 'seconds', hint: "Unit for the duration." },
1009
-
1010
- // For GenerateAIContents
1011
- {
1012
- name: 'aiProvider',
1013
- condition: { $eq: ["$type", "GenerateAIContent"] },
1014
- type: 'enum',
1015
- items: ['OpenAI', 'GoogleGemini'], // Extensible avec d'autres fournisseurs
1016
- hint: "Le fournisseur de LLM à utiliser."
1017
- },
1018
- {
1019
- name: 'aiModel',
1020
- condition: { $eq: ["$type", "GenerateAIContent"] },
1021
- type: 'string',
1022
- default: 'gpt-4o-mini', // Un défaut raisonnable
1023
- hint: "Le modèle spécifique à utiliser (ex: gpt-4o-mini, gemini-1.5-pro-latest)."
1024
- },
1025
- {
1026
- name: 'prompt',
1027
- condition: { $eq: ["$type", "GenerateAIContent"] },
1028
- type: 'richtext', // richtext est bien pour les longs prompts
1029
- hint: "Le modèle de prompt. Utilise des variables comme {triggerData.field} ou {context.variable}."
1030
- },
1031
-
1032
- // For ExecuteScript
1033
- { name: 'script', condition: {$eq: ["$type", "ExecuteScript"]}, type: 'code', language: 'javascript', hint: "The script to execute." },
1034
-
1035
- // For ExecuteServiceFunction
1036
- { name: 'serviceName', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'string', hint: "The name of the registered service to call (e.g., 'stripe')." },
1037
- { name: 'functionName', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'string', hint: "The name of the function to execute within the service." },
1038
- { name: 'args', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'code', language: 'json', default: [], hint: "An array of arguments to pass to the function. Can include variables." }
1039
-
1040
- ]
1041
- },
1042
-
1043
- workflowRun: {
1044
- name: 'workflowRun',
1045
- "icon": "FaRunning",
1046
- description: "Tracks a specific execution instance of a workflow.",
1047
- fields: [
1048
- { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow definition that was executed." },
1049
- { name: 'contextData', type: 'code', language: 'json',default: {}, hint: "Snapshot of the data or event that triggered this run." },
1050
- {
1051
- name: 'status',
1052
- type: 'enum',
1053
- required: true,
1054
- items: ['pending', 'running', 'completed', 'failed', 'waiting', 'cancelled'],
1055
- default: 'pending',
1056
- hint: "The current status of the workflow execution."
1057
- },
1058
- { name: 'stepExecutionsCount', type: 'object' },
1059
- { name: 'currentStep', type: 'relation', relation: 'workflowStep', hint: "The step currently being executed or waited on." },
1060
- { name: 'owner', type: 'relation', relation: 'user', required: false },
1061
- { name: 'startedAt', type: 'datetime', required: true, hint: "Timestamp when the workflow run began." },
1062
- { name: 'completedAt', type: 'datetime', hint: "Timestamp when the workflow run finished (successfully or failed)." },
1063
- { name: 'log', type: 'string', maxlength: 4096, hint: "Error message if the workflow run failed." }
1064
- ]
1065
- },
1066
- dashboard:{
1067
- name: 'dashboard', // Nom technique du modèle
1068
- "icon": "FaTachometerAlt",
1069
- description: "Configuration d'un tableau de bord personnalisé par l'utilisateur.", // Description du modèle
1070
- locked: false, // Indique si le modèle peut être modifié par l'utilisateur (false = modifiable)
1071
- fields: [
1072
- {
1073
- name: 'name', // Nom du tableau de bord
1074
- type: 'string', // Type texte simple
1075
- required: true, // Ce champ est obligatoire
1076
- hint: "Nom affiché et personnalisable du tableau de bord."
1077
- },
1078
- {
1079
- name: 'description', // Description optionnelle
1080
- type: 'string', // Type texte simple (pourrait être 'richtext' si besoin de mise en forme)
1081
- hint: "Description facultative pour donner plus de contexte au tableau de bord."
1082
- },
1083
- {
1084
- name: 'layout', // Configuration de la disposition des éléments
1085
- type: 'code', // Utilisation du type 'code' pour stocker une structure JSON flexible
1086
- language: 'json', // Précise que le contenu est du JSON
1087
- required: true, // La disposition est essentielle
1088
- default: { "type": "columns", "columns": [] }, // Valeur par défaut : une disposition en colonnes vide, stockée comme chaîne JSON
1089
- hint: "Structure JSON décrivant l'organisation des KPIs. Exemple : { \"type\": \"columns\", \"columns\": [ [\"kpi_id_1\"], [\"kpi_id_2\", \"kpi_id_3\"] ] }."
1090
- },
1091
- {
1092
- name: 'refreshInterval',
1093
- type: 'number',
1094
- delay: true, // Sera interprété par le front-end comme un champ de durée
1095
- unit: 's',
1096
- min: 0,
1097
- hint: "Intervalle de rafraîchissement automatique en secondes. Laisser vide ou à 0 pour désactiver."
1098
- },
1099
- {
1100
- name: 'isDefault', // Indicateur pour le tableau de bord par défaut
1101
- type: 'boolean', // Type booléen (vrai/faux)
1102
- default: false, // Par défaut, un nouveau tableau de bord n'est pas celui par défaut
1103
- hint: "Si 'true', ce tableau de bord est affiché par défaut pour l'utilisateur."
1104
- }
1105
- ]
1106
- },
1107
- 'request': {
1108
- name: 'request',
1109
- "icon": "FaExchangeAlt",
1110
- description: "Journal des requêtes reçues par l'API.",
1111
- locked: true, // Géré par le système, non modifiable directement par l'utilisateur via l'UI standard
1112
- fields: [
1113
- {
1114
- name: 'timestamp',
1115
- type: 'datetime',
1116
- required: true,
1117
- hint: "Date et heure exactes de la réception de la requête."
1118
- },
1119
- {
1120
- name: 'method',
1121
- type: 'enum',
1122
- items: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'],
1123
- required: true,
1124
- hint: "Méthode HTTP utilisée (GET, POST, etc.)."
1125
- },
1126
- {
1127
- name: 'url',
1128
- type: 'string',
1129
- required: true,
1130
- multiline: false,
1131
- maxlength: 2048, // Limite raisonnable pour une URL
1132
- hint: "URL complète de la requête, incluant les query parameters."
1133
- },
1134
- {
1135
- name: 'status',
1136
- type: 'number',
1137
- step: 100,
1138
- default: 200,
1139
- required: true,
1140
- hint: "Code de statut HTTP retourné par le serveur (ex: 200, 404, 500)."
1141
- },
1142
- {
1143
- name: 'latencyMs',
1144
- type: 'number',
1145
- required: true,
1146
- color: '#e8c965',
1147
- unit: 'ms',
1148
- hint: "Temps de traitement de la requête par le serveur, en millisecondes."
1149
- },
1150
- {
1151
- name: 'ip',
1152
- type: 'string',
1153
- hint: "Adresse IP du client ayant effectué la requête."
1154
- },
1155
- /*{
1156
- name: 'requestHeaders',
1157
- type: 'code',
1158
- language: 'json',
1159
- required: false,
1160
- hint: "En-têtes HTTP de la requête (stockés sous forme de chaîne JSON). Peut être volumineux."
1161
- },*/
1162
- {
1163
- name: 'requestBody', // Optionnel, peut être sensible/volumineux
1164
- type: 'code',
1165
- language: 'json', // Ou 'text' si ce n'est pas toujours du JSON
1166
- required: false,
1167
- hint: "Corps de la requête (stocké sous forme de chaîne JSON/texte). Attention: peut contenir des données sensibles et être volumineux."
1168
- },
1169
- {
1170
- name: 'responseBody', // Optionnel, peut être volumineux
1171
- type: 'code',
1172
- language: 'json', // Ou 'text'
1173
- required: false,
1174
- "condition": {
1175
- "path": [
1176
- "status"
1177
- ],
1178
- "op": "$gte",
1179
- "value": "400"
1180
- },
1181
- hint: "Corps de la réponse (stocké sous forme de chaîne JSON/texte). Attention: peut être volumineux."
1182
- },
1183
- {
1184
- name: 'error',
1185
- type: 'string',
1186
- maxlength: 4096, // Espace pour les messages d'erreur détaillés
1187
- required: false,
1188
- hint: "Message d'erreur si la requête a échoué côté serveur (ex: statut 500)."
1189
- }
1190
- ]
1191
- },
1192
-
1193
- kpi : {
1194
- name: 'kpi',
1195
- "icon": "FaChartLine",
1196
- description: "Configuration d'un Indicateur Clé de Performance (KPI)",
1197
- fields: [
1198
- { name: 'name', type: 'string_t', required: true, hint: "Nom affiché du KPI (ex: Chiffre d'affaires total)" },
1199
- { name: 'description', type: 'string_t', hint: "Informations complémentaires sur le KPI" },
1200
- { name: 'targetModel', type: 'model', required: true, hint: "Nom du modèle sur lequel calculer le KPI (ex: order)" },
1201
- {
1202
- name: 'aggregationType',
1203
- type: 'enum',
1204
- required: true,
1205
- items: ['count', 'sum', 'avg', 'min', 'max'], // Types d'agrégation courants
1206
- hint: "Type de calcul à effectuer"
1207
- },
1208
- {
1209
- name: 'aggregationField',
1210
- type: 'modelField',
1211
- targetModel: '$targetModel',
1212
- condition: { $ne: ["$aggregationType", "count"] },
1213
- hint: "Nom du champ numérique sur lequel appliquer l'agrégation (ex: totalAmount). Non requis pour 'count'."
1214
- },
1215
- {
1216
- name: 'matchFormula',
1217
- type: 'code', // Utiliser l'éditeur de code pour le JSON
1218
- language: 'json',
1219
- conditionBuilder: true,
1220
- targetModel: '$targetModel',
1221
- default: {}, // Valeur par défaut: aucun filtre
1222
- hint: "Filtre JSON (MongoDB $match) à appliquer avant l'agrégation (ex: { \"status\": \"delivered\" })"
1223
- },
1224
- {
1225
- "name": "showTotal",
1226
- "hint": "Afficher le total",
1227
- "type": "boolean"
1228
- },
1229
- {
1230
- "name": "showPercentTotal",
1231
- "hint": "Afficher le total en %",
1232
- "type": "boolean"
1233
- },
1234
- {
1235
- "name": "totalMatchFormula",
1236
- "hint": "Formule pour le total (calcul %)",
1237
- "type": "code",
1238
- "language": "json",
1239
- "required": false,
1240
- "default": "{}",
1241
- condition: { "$or": [
1242
- {$eq: ["$showTotal", true]},
1243
- {$eq: ["$showPercentTotal", true]}
1244
- ]}
1245
- },
1246
- {
1247
- name: 'unit', // Optionnel: Unité à afficher avec la valeur
1248
- type: 'string',
1249
- hint: "Unité à afficher (ex: €, $, utilisateurs)"
1250
- },
1251
- {
1252
- name: 'icon', // Optionnel: Icône à afficher
1253
- type: 'string', // Ou un type 'icon' si tu en as un
1254
- hint: "Nom de l'icône (ex: FaUsers, FaShoppingCart)"
1255
- },
1256
- // Optionnel: Ajouter des champs pour le style, l'ordre d'affichage, etc.
1257
- { name: 'order', type: 'number', hint: "Ordre d'affichage sur un tableau de bord" },
1258
- { name: 'color', type: 'color', hint: "Couleur associée au KPI" }
1259
- ]
1260
- },
1261
- imageGallery: {
1262
- name: 'imageGallery',
1263
- "icon": "FaImages",
1264
- description: "Représente une galerie d'images avec un titre et une description.",
1265
- locked: false, // Les utilisateurs peuvent créer/gérer leurs galeries
1266
- fields: [
1267
- {
1268
- name: 'name',
1269
- type: 'string_t', // Titre traduisible
1270
- required: true,
1271
- asMain: true, // Champ principal pour l'affichage
1272
- color: '#4CAF50', // Couleur indicative
1273
- hint: "Le nom ou titre de la galerie d'images."
1274
- },
1275
- {
1276
- name: 'images',
1277
- type: 'array',
1278
- itemsType: 'file', // Type des éléments du tableau
1279
- required: false, // Permet de créer une galerie vide initialement
1280
- mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], // Types d'images autorisés
1281
- hint: "Les fichiers images de cette galerie."
1282
- },
1283
- {
1284
- name: 'description',
1285
- type: 'richtext', // Description riche
1286
- hint: "Description de la galerie (optionnel)."
1287
- },
1288
- {
1289
- name: 'tags',
1290
- type: 'relation',
1291
- relation: 'taxonomy', // Relation vers le modèle 'taxonomy'
1292
- multiple: true, // Peut avoir plusieurs tags
1293
- hint: "Tags ou catégories pour organiser les galeries (optionnel)."
1294
- },
1295
- {
1296
- name: 'createdAt',
1297
- type: 'datetime',
1298
- // Ce champ pourrait être rempli automatiquement par le système lors de la création
1299
- hint: "Date de création de la galerie (généralement géré par le système)."
1300
- }
1301
- ]
1302
- },
1303
- budget: {
1304
- name: 'budget',
1305
- "icon": "FaMoneyCheck",
1306
- description: "Un budget permet de lister vos transactions personnelles.",
1307
- fields: [
1308
- {
1309
- name: 'name',
1310
- type: 'string_t',
1311
- asMain: true,
1312
- hint: "Nom ou description de la transaction (ex: Courses, Salaire Janvier)."
1313
- },
1314
- {
1315
- name: 'amount',
1316
- type: 'number',
1317
- step: 1,
1318
- asMain: true,
1319
- required: true,
1320
- hint: "Montant de la transaction. Positif pour un revenu, négatif pour une dépense."
1321
- },
1322
- {
1323
- name: 'currency',
1324
- type: 'relation',
1325
- relation: 'currency',
1326
- asMain: true,
1327
- required: true,
1328
- hint: "Devise de la transaction."
1329
- },
1330
- {
1331
- name: 'transactionDate',
1332
- type: 'datetime',
1333
- required: true,
1334
- asMain: true,
1335
- hint: "Date à laquelle la transaction a eu lieu."
1336
- },
1337
- {
1338
- name: 'description',
1339
- type: 'richtext', // Pour des notes plus détaillées
1340
- hint: "Notes ou détails supplémentaires sur la transaction."
1341
- },
1342
- {
1343
- name: 'paymentMethod',
1344
- type: 'string', // Ou enum si vous avez une liste fixe
1345
- hint: "Méthode de paiement utilisée (ex: Carte de crédit, Espèces, Virement)."
1346
- },
1347
- {
1348
- name: 'category',
1349
- type: 'relation',
1350
- relation: 'taxonomy', // Utiliser le modèle 'taxonomy' pour les catégories
1351
- // Vous pourriez vouloir filtrer les taxonomies de type 'budget_category'
1352
- hint: "Catégorie de la transaction (ex: Alimentation, Logement, Transport)."
1353
- },
1354
- {
1355
- name: 'isRecurring',
1356
- type: 'boolean',
1357
- default: false,
1358
- hint: "Indique si cette transaction est récurrente."
1359
- },
1360
- {
1361
- name: 'recurringFrequency',
1362
- type: 'enum',
1363
- items: ['daily', 'weekly', 'monthly', 'yearly'],
1364
- condition: {$eq: ["$isRecurring", true]}
1365
- },
1366
- {name: 'recurringEndDate', type: 'date', condition: {$eq: ["$isRecurring", true]}},
1367
- {
1368
- name: 'attachments',
1369
- type: 'array',
1370
- itemsType: 'file', // Pour joindre des reçus, factures, etc.
1371
- hint: "Pièces jointes (reçus, factures)."
1372
- }
1373
- ]
1374
- },
1375
- event: {
1376
- "name": "event",
1377
- "icon": "FaCalendar",
1378
- "description": "A model for managing events, conferences, meetups, and gatherings.",
1379
- "fields": [
1380
- {
1381
- "name": "title",
1382
- "type": "string",
1383
- "required": true,
1384
- "asMain": true,
1385
- "hint": "The title of the event"
1386
- },
1387
- {
1388
- "name": "description",
1389
- "type": "richtext_t",
1390
- "hint": "A detailed description of the event, including agenda, speakers, and other relevant information."
1391
- },
1392
- {
1393
- "name": "startDate",
1394
- "type": "datetime",
1395
- "required": true,
1396
- "hint": "The starting date and time of the event"
1397
- },
1398
- {
1399
- "name": "endDate",
1400
- "type": "datetime",
1401
- "required": true,
1402
- "hint": "The ending date and time of the event"
1403
- },
1404
- {
1405
- "name": "location",
1406
- "type": "relation",
1407
- "relation": "location",
1408
- "hint": "The venue or location where the event will be held. This could be a physical address or an online meeting link."
1409
- },
1410
- {
1411
- "name": "categories",
1412
- "type": "relation",
1413
- "relation": "taxonomy",
1414
- "multiple": true,
1415
- "hint": "Categories or tags associated with the event (e.g., \"conference\", \"workshop\", \"music\", \"technology\")."
1416
- },
1417
- {
1418
- "name": "organizer",
1419
- "type": "relation",
1420
- "relation": "contact",
1421
- "hint": "The name of the organization or individual hosting the event."
1422
- },
1423
- {
1424
- "name": "isOnline",
1425
- "type": "boolean",
1426
- "default": false,
1427
- "hint": "Whether the event is online or in-person."
1428
- },
1429
- {
1430
- "name": "eventUrl",
1431
- "type": "url",
1432
- "hint": "A link to the official event webpage or registration page."
1433
- },
1434
- {
1435
- "name": "imageUrl",
1436
- "type": "file",
1437
- "hint": "URL of the event image or banner."
1438
- },
1439
- {
1440
- "name": "status",
1441
- "type": "enum",
1442
- "items": [
1443
- "scheduled",
1444
- "ongoing",
1445
- "completed",
1446
- "cancelled",
1447
- "postponed"
1448
- ],
1449
- "hint": "The current status of the event."
1450
- },
1451
- {
1452
- "name": "capacity",
1453
- "type": "number",
1454
- "hint": "The maximum number of attendees allowed for the event."
1455
- },
1456
- {
1457
- "name": "price",
1458
- "type": "number",
1459
- "hint": "The price of admission, if applicable."
1460
- },
1461
- {
1462
- "name": "currency",
1463
- "type": "relation",
1464
- "relation": "currency",
1465
- "hint": "The currency for the price (e.g., USD, EUR)."
1466
- },
1467
- {
1468
- "name": "registrationDeadline",
1469
- "type": "datetime",
1470
- "hint": "The date by which attendees must register for the event."
1471
- },
1472
- {
1473
- "name": "attendees",
1474
- "type": "relation",
1475
- "relation": "contact",
1476
- "multiple": true,
1477
- "hint": "A relation to the contacts attending the event"
1478
- },
1479
- {
1480
- "name": "sponsors",
1481
- "type": "relation",
1482
- "relation": "contact",
1483
- "multiple": true,
1484
- "hint": "List of sponsors or partners involved in the event."
1485
- }
1486
- ]
1487
- },
1488
- endpoint: {
1489
- name: "endpoint",
1490
- "icon": "FaCode",
1491
- description: "Defines custom API endpoints that execute a server-side script.",
1492
- fields: [
1493
- {
1494
- name: "isActive",
1495
- type: "boolean",
1496
- default: true,
1497
- hint: "If checked, the endpoint is active and can be called."
1498
- },
1499
- {
1500
- name: "name",
1501
- type: "string",
1502
- required: true,
1503
- asMain: true,
1504
- hint: "A human-readable name to identify the endpoint."
1505
- },
1506
- {
1507
- name: "path",
1508
- type: "string",
1509
- required: true,
1510
- hint: "The URL path after /api/actions/ (e.g., 'send-welcome-email'). Do not include '/'.",
1511
- placeholder: "my-custom-action"
1512
- },
1513
- {
1514
- name: "method",
1515
- type: "enum",
1516
- items: ["GET", "POST", "PUT", "PATCH", "DELETE"],
1517
- required: true,
1518
- default: "POST",
1519
- hint: "The HTTP method required to call this endpoint."
1520
- },
1521
- {
1522
- name: "code",
1523
- type: "code",
1524
- language: "javascript",
1525
- required: true,
1526
- hint: "The script to execute. Must return a value or an object that will be the JSON response.",
1527
- default: `// The script can access 'db', 'logger', 'env'.
1528
- // request.body, request.query, request.params, request.headers available
1529
- // The returned value will be the API's JSON response.
1530
-
1531
- logger.info('Custom endpoint executed with body:', request.body);
1532
-
1533
- return { success: true, message: 'Endpoint executed!', received: request.body };
1534
- `
1535
- },
1536
- {
1537
- name: 'isPublic',
1538
- type: 'boolean',
1539
- default: false,
1540
- hint: "Si coché, ce point d'accès sera accessible sans authentification."
1541
- }
1542
- ]
1543
- }
1544
- };
1
+ // Définition des structures de modèles
2
+ export const defaultModels = {
3
+ permission: {
4
+ "name": "permission",
5
+ "icon": "FaKey",
6
+ "description": "",
7
+ "tags": ["system", "security"],
8
+ "fields": [
9
+ {
10
+ "name": "name",
11
+ "type": "string_t",
12
+ color: '#757BCC'
13
+ },
14
+ {
15
+ "name": "description",
16
+ "type": "richtext"
17
+ }
18
+ ]
19
+ },
20
+ role: {
21
+ name: 'role',
22
+ "icon": "FaUserTag",
23
+ "description": "",
24
+ "tags": ["system", "security"],
25
+ fields: [
26
+ { name: 'name', type: 'string_t', required: true, unique: true, color: '#363636' },
27
+ { name: 'permissions', type: 'relation', multiple: true, relation: 'permission' }
28
+ ]
29
+ },
30
+ user: {
31
+ name: 'user',
32
+ "description": "",
33
+ "icon": "FaUser",
34
+ locked: true,
35
+ "tags": ["system", "users"],
36
+ fields: [
37
+ { name: 'username', type: 'string', required: true, unique: true, color: '#3C7D08' },
38
+ { name: 'password', type: 'password' },
39
+ {
40
+ "name": "gender",
41
+ "type": "enum",
42
+ "items": ["male", "female", "other", "prefer_not_to_say"]
43
+ },
44
+ { name: 'contact', type: 'relation', relation: 'contact' },
45
+ { name: 'roles', type: 'relation', multiple: true, relation: 'role' },
46
+ { name: 'lang', type: 'relation', relation: 'lang', color: '#4CACCD' },
47
+ {
48
+ "name": "profilePicture",
49
+ "type": "file",
50
+ "mimeTypes": ["image/jpeg", "image/png"]
51
+ },
52
+ { name: 'tokens', type: 'relation', multiple: true, relation: 'token' }
53
+ ]
54
+ },
55
+ userPermission: {
56
+ "icon": "FaUserCheck",
57
+ "name": "userPermission",
58
+ "description": "Gère les exceptions aux permissions des rôles pour un utilisateur (ajouts ou retraits, permanents ou temporaires).",
59
+ "tags": ["system", "security"],
60
+ "fields": [
61
+ {
62
+ "name": "user",
63
+ "type": "relation",
64
+ "relation": "user",
65
+ "required": true,
66
+ "index": true
67
+ },
68
+ {
69
+ "name": "permission",
70
+ "type": "relation",
71
+ "relation": "permission",
72
+ "required": true,
73
+ "index": true
74
+ },
75
+ {
76
+ "name": "isGranted",
77
+ "type": "boolean",
78
+ "required": true,
79
+ "hint": "True pour accorder la permission, False pour la révoquer explicitement."
80
+ },
81
+ {
82
+ "name": "expiresAt",
83
+ "type": "datetime",
84
+ "required": false,
85
+ "index": true,
86
+ "hint": "Si défini, l'exception (l'octroi ou la révocation) est temporaire."
87
+ }
88
+ ]
89
+ },
90
+ token: {
91
+ name: 'token',
92
+ "icon": "FaKey",
93
+ "description": "",
94
+ "tags": ["system", "security"],
95
+ fields: [
96
+ { name: 'name', type: 'string' },
97
+ { name: 'value', type: 'password' },
98
+ { name: 'lastRefresh', type: 'datetime' }
99
+ ]
100
+ },
101
+ translation: {
102
+ name: 'translation',
103
+ "icon": "FaLanguage",
104
+ locked: true,
105
+ "description": "",
106
+ "tags": ["system", "i18n"],
107
+ fields: [
108
+ { name: 'lang', type: 'relation', 'relation': 'lang', required: true, color: '#4CACCD' },
109
+ { name: 'key', type: 'string', maxlength: 200, required: true },
110
+ { name: 'value', type: 'string' }
111
+ ]
112
+ },
113
+ lang: {
114
+ name: 'lang',
115
+ "icon": "FaGlobe",
116
+ locked: true,
117
+ "description": "",
118
+ "tags": ["system", "i18n"],
119
+ fields: [
120
+ { name: 'name', unique: true, type: 'string_t', maxlength: 200, color: '#4CACCD' },
121
+ { name: 'code', type: 'string', maxlength: 5 }
122
+ ]
123
+ },
124
+ currency: {
125
+ name: 'currency',
126
+ "icon": "FaMoneyBill",
127
+ "description": "",
128
+ locked: true,
129
+ "tags": ["system", "finance"],
130
+ fields: [
131
+ { name: 'symbol', type: 'string', required: true, color: '#E0E0E0', maxlength: 20, asMain: true },
132
+ { name: 'code', type: 'string', required: true, unique: true, maxlength: 3, asMain: true },
133
+ { name: 'name', type: 'string_t', required: true, color: '#AE6FA3' },
134
+ { name: 'exchangeRate', type: 'number', required: false },
135
+ { name: 'default', type: 'boolean', default: false }
136
+ ]
137
+ },
138
+ channel: {
139
+ name: 'channel',
140
+ "icon": "FaComments",
141
+ "description": "",
142
+ "tags": ["system", "messaging"],
143
+ fields: [
144
+ { name: 'name', type: 'string_t', required: true, unique: true }, // Nom du canal (ex: "email", "SMS")
145
+ { name: 'description', type: 'string_t' },
146
+ { name: 'type', type: 'enum', items: ['web', 'mobile', 'email', 'sms', 'push'], required: true } // Type de canal
147
+ ]
148
+ },
149
+ message: {
150
+ name: 'message',
151
+ "icon": "FaEnvelope",
152
+ "description": "",
153
+ locked: true,
154
+ "tags": ["system", "messaging"],
155
+ fields: [
156
+ { name: 'sender', type: 'relation', relation: 'user' }, // Utilisateur émetteur (si applicable, sinon système)
157
+ { name: 'recipient', type: 'relation', relation: 'user' }, // Utilisateur destinataire
158
+ { name: 'lang', type: 'relation', relation: 'lang' }, // Utilisateur destinataire
159
+ { name: 'subject', type: 'string' }, // Sujet de la notification (ex: titre de l'email)
160
+ { name: 'content', type: 'richtext', required: true }, // Contenu du message (localisable)
161
+ { name: 'channels', type: 'relation', multiple: true, relation: 'channel' }, // Canaux de diffusion (email, SMS, forum, etc.)
162
+ { name: 'status', type: 'enum', items: ['pending', 'sent', 'read', 'failed'] },
163
+ { name: 'sentAt', type: 'datetime' },
164
+ { name: 'readAt', type: 'datetime' },
165
+ { name: 'type', type: 'string' }, // Type de notification (ex: "commande.miseAJour", "messageForum")
166
+ { name: 'priority', type: 'enum', items: ['low', 'medium', 'high']}
167
+ ]
168
+ },
169
+ alert: {
170
+ name: "alert",
171
+ "icon": "FaBell",
172
+ description: "Définit les règles pour les alertes et les insights automatiques.",
173
+ "tags": ["system", "automation", "monitoring"],
174
+ fields: [
175
+ { name: "name", type: "string", required: true, asMain: true },
176
+ { name: "targetModel", type: "model", required: true },
177
+ { name: "description", type: "string_t", multiline: true },
178
+ {
179
+ name: "triggerCondition",
180
+ type: "code",
181
+ language: "json",
182
+ conditionBuilder: true,
183
+ targetModel: '$targetModel',
184
+ required: true,
185
+ hint: "La condition qui, si elle est remplie, déclenchera l'alerte."
186
+ },
187
+ {
188
+ name: "frequency",
189
+ type: "cronSchedule",
190
+ required: true,
191
+ cronMask: [false, true, true, true, true, true],
192
+ hint: "À quelle fréquence vérifier si la condition est remplie."
193
+ },
194
+ { name: "isActive", type: "boolean", default: true },
195
+ {
196
+ name: "sendEmail",
197
+ type: "boolean",
198
+ default: false,
199
+ hint: "Cochez pour envoyer également une notification par e-mail."
200
+ },
201
+ {
202
+ name: "lastNotifiedAt",
203
+ type: "datetime",
204
+ required: false, // Important: ce champ est géré par le système
205
+ hint: "Timestamp de la dernière notification envoyée pour cette alerte."
206
+ },
207
+ {
208
+ name: "message",
209
+ type: "richtext_t",
210
+ required: false,
211
+ hint: "Message personnalisé pour l'e-mail. Si vide, un message par défaut sera utilisé. Vous pouvez utiliser les variables {count}, {alert.name}....",
212
+ condition: { $eq: ["$sendEmail", true] }
213
+ }
214
+ ]
215
+ },
216
+ env: {
217
+ name: "env",
218
+ "icon": "FaCog",
219
+ description: "Définit les variables d'environnement qui seront accessibles dans vos scripts et webhooks.",
220
+ "tags": ["system", "configuration"],
221
+ fields: [
222
+ { name: "name", type: "string", required: true, unique: true, asMain: true },
223
+ { name: "value", type: "string", anonymized: true, hiddenable: true }
224
+ ]
225
+ },
226
+ webpage: {
227
+ name: 'webpage',
228
+ "icon": "FaFileAlt",
229
+ locked: true,
230
+ "description": "",
231
+ "tags": ["cms", "website"],
232
+ fields: [
233
+ { name: 'title', type: 'string_t', required: true, color: '#659DE6' },
234
+ { name: 'path', type: 'string', required: true, unique: true, color: '#DEDEDE' },
235
+ { name: 'html', type: 'richtext' },
236
+ { name: 'published', type: 'boolean', default: false },
237
+ { name: 'inSitemap', type: 'boolean', default: true },
238
+ { name: 'description', type: 'string' },
239
+ { name: 'keywords', type: 'relation', relation: 'taxonomy', multiple: true },
240
+ { name: 'image', type: 'url' },
241
+ { name: 'category', type: 'relation', relation: 'taxonomy' }
242
+ ]
243
+ },
244
+ content: {
245
+ name: 'content',
246
+ "icon": "FaFileAlt",
247
+ "description": "",
248
+ "tags": ["cms", "website"],
249
+ fields: [
250
+ { name: 'lang', type: 'relation', relation: 'lang' },
251
+ { name: 'title', type: 'string_t', required: true },
252
+ { name: 'slug', type: 'string' },
253
+ { name: 'html', type: 'richtext_t' },
254
+ { name: 'image', type: 'file', mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] },
255
+ { name: 'published', type: 'boolean' },
256
+ { name: 'publishedAt', type: 'datetime' },
257
+ { name: 'author', type: 'relation', relation: 'user' },
258
+ { name: 'category', type: 'relation', relation: 'taxonomy', "relationFilter": {
259
+ "path": [
260
+ "type"
261
+ ],
262
+ "op": "$eq",
263
+ "value": "category"
264
+ } },
265
+ { name: 'keywords', type: 'relation', relation: 'taxonomy', multiple: true, "relationFilter": {
266
+ "path": [
267
+ "type"
268
+ ],
269
+ "op": "$eq",
270
+ "value": "keyword"
271
+ } },
272
+ { name: 'order', type: 'number', step: 1, default: 0 },
273
+ { name: 'inSitemap', type: 'boolean', default: false }
274
+ ]
275
+ },
276
+ resource: {
277
+ name: 'resource',
278
+ "icon": "FaBoxOpen",
279
+ "description": "",
280
+ "tags": ["cms", "assets"],
281
+ fields: [
282
+ { name: "source", type: "url"},
283
+ { name: "file", type: "file"}
284
+ ]
285
+ },
286
+ taxonomy: {
287
+ name: 'taxonomy',
288
+ "icon": "FaTags",
289
+ "description": "",
290
+ "tags": ["cms", "organization"],
291
+ fields: [
292
+ { name: 'name', type: 'string_t', required: true, color: '#71A314' },
293
+ { name: 'parent', type: 'relation', relation: 'taxonomy', color: '#233607' }, // Relation vers la taxonomie parente
294
+ { name: 'type', type: 'enum', items: ['keyword', 'category'], color: '#BFBFBF' },
295
+ { name: 'identifier', type: 'string' },
296
+ { name: 'order', type: 'number', step: 1, default: 0 },
297
+ { name: 'description', type: 'richtext' }
298
+ ]
299
+ },
300
+ contact: {
301
+ locked: true,
302
+ name: 'contact',
303
+ "icon": "FaAddressBook",
304
+ "description": "",
305
+ "tags": ["crm", "contacts"],
306
+ fields: [
307
+ { name: 'legalName', type: 'string', asMain: true, color: '#D9D9D9' },
308
+ { name: 'firstName', type: 'string', asMain: true},
309
+ { name: 'lastName', type: 'string', asMain: true },
310
+ { name: 'email', type: 'email', color: '#F4ECE2' },
311
+ { name: 'phone', type: 'phone', color: '#B4A693' },
312
+ { name: 'location', type: 'relation', relation: 'location' }
313
+ ]
314
+ },
315
+
316
+ location: {
317
+ "name": "location",
318
+ "icon": "FaMapMarkerAlt",
319
+ locked: true,
320
+ "description": "",
321
+ "tags": ["crm", "geolocation"],
322
+ "fields": [
323
+ {
324
+ "name": "address_1",
325
+ "type": "string",
326
+ asMain: true,
327
+ color: '#D6D6D6'
328
+ },
329
+ {
330
+ "name": "address_2",
331
+ "type": "string"
332
+ },
333
+ {
334
+ "name": "address_3",
335
+ "type": "string"
336
+ },
337
+ {
338
+ "name": "address_4",
339
+ "type": "string"
340
+ },
341
+ {
342
+ "name": "city",
343
+ "type": "string",
344
+ asMain: true,
345
+ color: '#E63345'
346
+ },
347
+ {
348
+ "name": "postalCode",
349
+ "type": "string",
350
+ asMain: true,
351
+ color: '#8B1D1D'
352
+ },
353
+ {
354
+ "name": "region",
355
+ "type": "string"
356
+ },
357
+ {
358
+ "name": "country",
359
+ "type": "string",
360
+ color: "#4F80BF",
361
+ asMain: true
362
+ },
363
+ {
364
+ "name": "latitude",
365
+ "type": "number",
366
+ "unit": "°"
367
+ },
368
+ {
369
+ "name": "longitude",
370
+ "type": "number",
371
+ "unit": "°"
372
+ }
373
+ ]
374
+ },
375
+
376
+ brand: {
377
+ name: 'brand',
378
+ "icon": "FaTrademark",
379
+ "description": "",
380
+ "tags": ["ecommerce", "products"],
381
+ fields: [
382
+ { name: 'name', type: 'string', required: true },
383
+ { name: 'logo', type: 'file' },
384
+ { name: 'company', type: 'relation', relation: 'contact' }
385
+ ]
386
+ },
387
+
388
+ product: {
389
+ name: 'product',
390
+ "icon": "FaShoppingBag",
391
+ "description": "",
392
+ "tags": ["ecommerce", "products"],
393
+ fields: [
394
+ { name: 'name', type: 'string_t', required: true },
395
+ { name: 'image', type: 'array', itemsType: 'file', mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] },
396
+ { name: 'description', type: 'richtext_t' },
397
+ { name: 'price', type: 'number', required: true },
398
+ { name: 'currency', type: 'relation', relation: 'currency', required: true },
399
+ { name: 'billingFrequency', type: 'enum', items: ['aucune', 'au mois', 'à l\'année'] },
400
+ { name: 'slug', type: 'string', required: true, unique: true },
401
+ { name: 'brand', type: 'relation', relation: 'brand' },
402
+ { name: 'category', type: 'relation', relation: 'taxonomy' },
403
+ { name: 'seoTitle', type: 'string_t' },
404
+ { name: 'seoDescription', type: 'string_t' }
405
+ ]
406
+ },
407
+ productVariant: {
408
+ name: 'productVariant',
409
+ "icon": "FaBox",
410
+ "description": "",
411
+ "tags": ["ecommerce", "products"],
412
+ fields: [
413
+ { name: 'product', type: 'relation', relation: 'product', required: true },
414
+ { name: 'size', type: 'string' },
415
+ { name: 'color', type: 'color' },
416
+ { name: 'sku', type: 'string', unique: true },
417
+ { name: 'price', type: 'number', required: true },
418
+ { name: 'currency', type: 'relation', relation: 'currency', required: true },
419
+ { name: 'stock', type: 'number', default: 0 },
420
+ { name: 'description', type: 'richtext' },
421
+ { name: 'image', type: 'url' }
422
+ ]
423
+ },
424
+ cart: {
425
+ name: 'cart',
426
+ "icon": "FaShoppingCart",
427
+ "description": "",
428
+ "tags": ["ecommerce", "sales"],
429
+ fields: [
430
+ { name: 'user', type: 'relation', relation: 'user', required: true },
431
+ { name: 'items', type: 'relation', relation: 'cartItem', multiple: true },
432
+ { name: 'creationDate', type: 'datetime', required: true },
433
+ { name: 'lastUpdate', type: 'datetime', required: true },
434
+ { name: 'active', type: 'boolean', default: true }
435
+ ]
436
+ },
437
+ cartItem: {
438
+ name: 'cartItem',
439
+ "icon": "FaShoppingBasket",
440
+ "description": "",
441
+ "tags": ["ecommerce", "sales"],
442
+ fields: [
443
+ { name: 'product', type: 'relation', relation: 'product', required: true },
444
+ { name: 'quantity', type: 'number', required: true, min: 1, step: 1 },
445
+ { name: 'variant', type: 'relation', relation: 'productVariant' } // Optionnel, si vous avez des variantes
446
+ ]
447
+ },
448
+ discount: {
449
+ name: "discount",
450
+ "icon": "FaTicketAlt",
451
+ locked: true,
452
+ "description": "",
453
+ "tags": ["ecommerce", "sales"],
454
+ fields: [
455
+ { "name": "code", "type": "string", "required": true, "unique": true },
456
+ { "name": "productSelection", "type": "relation", "relation": "product", "required": false, multiple: true },
457
+ { "name": "description", "type": "richtext" },
458
+ { "name": "percentAmount", "type": "number", "unit": "%", default: null, min: 0 },
459
+ { "name": "fixedAmount", "type": "number", default: null, min: 0 },
460
+ { "name": "minAmount", "type": "number", "unit": "€", default: null, min: 0 }, // Montant minimum pour la promotion
461
+ { "name": "minProductQuantity", "type": "number", min: 0 }, // Montant minimum pour la promotion
462
+ { "name": "freeProductQuantity", "type": "number", default: null, min: 0 }, // Quantité de produits offerts
463
+ { "name": "startDate", "type": "datetime" },
464
+ { "name": "endDate", "type": "datetime" }
465
+ ]
466
+ },
467
+ order: {
468
+ name: "order",
469
+ "icon": "FaClipboardList",
470
+ locked: true,
471
+ "description": "",
472
+ "tags": ["ecommerce", "sales"],
473
+ fields: [
474
+ { "name": "orderId", "type": "string", "required": true, "unique": true },
475
+ { "name": "orderDate", "type": "datetime" },
476
+ { "name": "status", "type": "enum", items: ["pending", "processing", "shipped", "delivered", "cancelled"] },
477
+ { "name": "products", "type": "relation", "relation": "cartItem", "required": true, multiple: true },
478
+ { "name": "customer", "type": "relation", relation: 'user' }, // Relation vers le modèle 'user'
479
+ { "name": "totalAmount", "type": "number", "required": true },
480
+ { "name": "paymentIntentId", "type": "string", "hint": "Stripe Payment Intent ID for this order." },
481
+ { "name": "currency", "type": "relation", "relation": "currency" },
482
+ { "name": "paymentMethod", "type": "string" },
483
+ { "name": "shippingAddress", "type": "relation", "relation": "location" },
484
+ { "name": "billingAddress", "type": "relation", "relation": "location" },
485
+ { "name": "shippedDate", "type": "datetime" },
486
+ { "name": "deliveryDate", "type": "datetime" },
487
+ { "name": "discount", "type": "relation", relation: 'discount' } // Relation vers le modèle 'promotion'
488
+ ]
489
+ },
490
+ invoice: {
491
+ name: 'invoice',
492
+ "icon": "FaFileInvoice",
493
+ "description": "",
494
+ "tags": ["ecommerce", "finance"],
495
+ fields: [
496
+ { name: 'order', type: 'relation', relation: 'order', required: true },
497
+ { name: 'invoiceId', type: 'string', required: true, unique: true },
498
+ { name: 'invoiceDate', type: 'datetime', required: true },
499
+ { name: 'dueDate', type: 'datetime' },
500
+ { name: 'status', type: 'enum', items: ['paid', 'unpaid', 'partially_paid', 'cancelled'] }
501
+ ]
502
+ },
503
+ userSubscription: {
504
+ name: 'userSubscription',
505
+ "icon": "FaCalendarCheck",
506
+ "description": "",
507
+ locked: true,
508
+ "tags": ["ecommerce", "billing"],
509
+ fields: [
510
+ { name: 'user', type: 'relation', relation: 'user', required: true },
511
+ { name: 'product', type: 'relation', relation: 'product', required: true },
512
+ { name: 'startDate', type: 'datetime', required: true },
513
+ { name: 'endDate', type: 'datetime' },
514
+ { name: 'price', type: 'number', required: true },
515
+ { name: 'currency', type: 'relation', relation: 'currency', required: true },
516
+ { name: 'paymentMethod', type: 'enum', items: ['bank_card', 'SEPA_mandate', 'cash', 'check', 'other'] },
517
+ { name: 'status', type: 'enum', items: ['active', 'inactive', 'cancelled', 'expired', 'pending'] },
518
+ { name: 'billingCycleAnchor', type: 'datetime' },
519
+ { name: 'nextBillingDate', type: 'datetime' },
520
+ { name: 'lastBillingDate', type: 'datetime' },
521
+ { name: 'cancelReason', type: 'string' },
522
+ { name: 'autoRenew', type: 'boolean', default: false }
523
+ ]
524
+ },
525
+ stock: {
526
+ name: 'stock',
527
+ "icon": "FaWarehouse",
528
+ "description": "",
529
+ "tags": ["ecommerce", "inventory"],
530
+ fields: [
531
+ { name: 'product', type: 'relation', relation: 'product', required: true },
532
+ { name: 'variant', type: 'relation', relation: 'productVariant' }, // Optionnel
533
+ { name: 'warehouse', type: 'relation', relation: 'warehouse', required: true },
534
+ { name: 'available', type: 'number', default: 0 },
535
+ { name: 'reserved', type: 'number', default: 0 } // Quantité réservée (pour les commandes en cours)
536
+ ]
537
+ },
538
+ stockAlert: {
539
+ name: 'stockAlert',
540
+ "icon": "FaExclamationTriangle",
541
+ "description": "",
542
+ "tags": ["ecommerce", "inventory", "monitoring"],
543
+ fields: [
544
+ { name: 'user', type: 'relation', relation: 'user', required: true },
545
+ { name: 'stock', type: 'relation', relation: 'stock', required: true },
546
+ { name: 'threshold', type: 'number', required: true, min: 0 }
547
+ ]
548
+ // how to implement unique fields on COMBINATION of multiple columns ?
549
+ },
550
+ shipment: {
551
+ name: 'shipment',
552
+ "icon": "FaTruck",
553
+ "description": "",
554
+ "tags": ["ecommerce", "logistics"],
555
+ fields: [
556
+ { name: 'order', type: 'relation', relation: 'order', required: true },
557
+ { name: 'trackingNumber', type: 'string' },
558
+ { name: 'carrier', type: 'string' },
559
+ { name: 'status', type: 'enum', items: ['pending', 'in_transit', 'delivered', 'issue'] },
560
+ { name: 'estimatedDeliveryDate', type: 'datetime' },
561
+ { name: 'actualDeliveryDate', type: 'datetime' }
562
+ ]
563
+ },
564
+ warehouse: {
565
+ name: 'warehouse',
566
+ "description": "",
567
+ "icon": "FaWarehouse",
568
+ "tags": ["ecommerce", "inventory"],
569
+ fields: [
570
+ { name: 'name', type: 'string_t', required: true },
571
+ { name: 'location', type: 'relation', relation: 'location' },
572
+ { name: 'capacity', type: 'number' }
573
+ ]
574
+ },
575
+ 'return': {
576
+ name: "return",
577
+ "description": "",
578
+ "icon": "FaUndo",
579
+ "tags": ["ecommerce", "sales"],
580
+ fields: [
581
+ { "name": "order", "type": "relation", "relation": "order", "required": true },
582
+ { "name": "user", "type": "relation", relation: "user" },
583
+ { "name": "reason", "type": "string", maxlength: 2048, required: true },
584
+ { "name": "channel", "type": "relation", relation: 'channel' },
585
+ { "name": "status", "type": "enum", items: ["pending", "approved", "refunded", "refused"] },
586
+ { name: 'amount', type: 'number', min: 0 },
587
+ { name: 'currency', type: 'relation', relation: 'currency' },
588
+ { name: 'refundDate', type: 'datetime' }
589
+ ]
590
+ },
591
+ returnItem: {
592
+ name: 'returnItem',
593
+ "icon": "FaBoxOpen",
594
+ "description": "",
595
+ "tags": ["ecommerce", "sales"],
596
+ fields: [
597
+ { name: 'return', type: 'relation', relation: 'return', required: true },
598
+ { name: 'product', type: 'relation', relation: 'product', required: true },
599
+ { name: 'variant', type: 'relation', relation: 'productVariant' },
600
+ { name: 'quantity', type: 'number', required: true, min: 1 },
601
+ { name: 'condition', type: 'enum', items: ['new', 'very_good', 'good', 'degraded', 'damaged', 'unusable'] }
602
+ ]
603
+ },
604
+ ticket: {
605
+ name: 'ticket',
606
+ "icon": "FaTicketAlt",
607
+ "description": "",
608
+ locked: true,
609
+ "tags": ["support", "communication"],
610
+ fields: [
611
+ { name: 'user', type: 'relation', relation: 'user', required: true },
612
+ { name: 'order', type: 'relation', relation: 'order' },
613
+ { name: 'channel', type: 'relation', relation: 'channel' },
614
+ { name: 'parent', type: 'relation', relation: 'ticket' },
615
+ { name: 'subject', type: 'string', required: true },
616
+ { name: 'message', type: 'richtext', required: true },
617
+ { name: 'status', type: 'enum', items: ['opened', 'in_progress', 'closed'] },
618
+ { name: 'priority', type: 'enum', items: ['low', 'medium', 'high', 'urgent'] },
619
+ { name: 'assignedTo', type: 'relation', relation: 'user' },
620
+ { name: 'createdAt', type: 'datetime', required: true }
621
+ ]
622
+ },
623
+ review: {
624
+ name: "review",
625
+ "icon": "FaStar",
626
+ "description": "",
627
+ "tags": ["ecommerce", "feedback"],
628
+ fields: [
629
+ { "name": "user", "type": "relation", relation: "user" },
630
+ { "name": "product", "type": "relation", relation: 'product' },
631
+ { "name": "productVariant", "type": "relation", relation: 'productVariant' },
632
+ { "name": "comment", "type": "richtext", maxlength: 2048, required: true },
633
+ { "name": "score", "type": "number" },
634
+ { "name": "publishedAt", "type": "datetime", required: true }
635
+ ]
636
+ },
637
+ device: {
638
+ name: "device",
639
+ "icon": "FaMobile",
640
+ "description": "",
641
+ "tags": ["system", "iot"],
642
+ fields: [
643
+ { "name": "location", "type": "relation", relation: 'location' },
644
+ { "name": "lastLocationUpdate", "type": "datetime" }
645
+ ]
646
+ },
647
+ // Modèle pour l'exercice comptable et l'entreprise
648
+ accountingExercise: {
649
+ name: 'accountingExercise',
650
+ "icon": "FaBook",
651
+ description: "Représente un exercice comptable pour une entreprise donnée.",
652
+ "tags": ["finance", "accounting"],
653
+ fields: [
654
+ { name: 'name', type: 'string_t', 'required': true, unique: true, hint: "Intitulé de l'exercice comptable" },
655
+ { name: 'companyContact', type: 'relation', relation: 'contact', 'required': true, hint: "Désignation de l'entreprise" },
656
+ { name: 'companyIdentifier', type: 'string', asMain: true, hint: "SIRET de l'entreprise", unique: true },
657
+ { name: 'startDate', type: 'date', required: true, asMain: true, hint: "Date de début de l'exercice" },
658
+ { name: 'endDate', type: 'date', required: true, asMain: true, hint: "Date de clôture de l'exercice" }
659
+ ]
660
+ },
661
+
662
+ // Modèle pour définir la structure des lignes comptables (le "plan")
663
+ accountingLineItem: {
664
+ name: 'accountingLineItem',
665
+ "icon": "FaListAlt",
666
+ description: "Définit une ligne/catégorie dans un document comptable.",
667
+ locked: true, // Probablement géré par l'application, pas par l'utilisateur final
668
+ "tags": ["finance", "accounting"],
669
+ fields: [
670
+ { name: 'accountingExercise', type: 'relation', required: true, unique: true, relation: "accountingExercise" },
671
+ { name: 'code', type: 'string', required: true, unique: true, hint: "Code unique de la ligne (ex: AA, FB, HA)" },
672
+ { name: 'label', type: 'string_t', required: true, hint: "Libellé de la ligne (ex: Frais d'établissement)" },
673
+ {
674
+ name: 'documentType', type: 'enum', required: true,
675
+ items: ['bilan_actif', 'bilan_passif', 'compte_resultat', 'immobilisations', 'amortissements', 'provisions', 'creances_dettes',
676
+ 'deficits',
677
+ 'plus_moins_values',
678
+ 'effectifs_valeur_ajoutee',
679
+ 'capital_social',
680
+ 'filiales_participations',
681
+ 'resultat_fiscal']
682
+ },
683
+ { name: 'section', type: 'string_t', required: true, hint: "Section principale (ex: ACTIF IMMOBILISÉ)" },
684
+ { name: 'subSection', type: 'string_t', hint: "Sous-section (ex: IMMOBILISATIONS INCORPORELLES)" },
685
+ { name: 'order', type: 'number', hint: "Ordre d'affichage dans la section/sous-section" },
686
+ { name: 'calculationFormula', type: 'string', hint: "Formule de calcul (si applicable)" },
687
+ {
688
+ name: 'values', type: 'array', itemsType: 'number', required: true,
689
+ hint: "Valeurs de la ligne comptable"
690
+ },
691
+ { name: 'notes', type: 'richtext', hint: "Notes ou renvois (ex: (1), (3))" }
692
+ ]
693
+ },
694
+ accountingEntry: {
695
+ "name": "accountingEntry",
696
+ "icon": "FaPenAlt",
697
+ "description": "",
698
+ "tags": ["finance", "accounting"],
699
+ "fields": [
700
+ {
701
+ "name": "exercise",
702
+ "type": "relation",
703
+ "relation": "accountingExercise",
704
+ "required": true
705
+ },
706
+ {
707
+ "name": "label",
708
+ "type": "string",
709
+ "required": true,
710
+ "asMain": true,
711
+ "maxlength": 255
712
+ },
713
+ {
714
+ "name": "entryDate",
715
+ "type": "date",
716
+ "required": true
717
+ },
718
+ {
719
+ "name": "amount",
720
+ "type": "number",
721
+ "default": 0
722
+ },
723
+ {
724
+ "name": "currency",
725
+ "type": "relation",
726
+ "relation": "currency",
727
+ "required": true
728
+ },
729
+ {
730
+ "name": "referenceNumber",
731
+ "type": "string",
732
+ "maxlength": 100
733
+ },
734
+ {
735
+ "name": "notes",
736
+ "type": "richtext"
737
+ },
738
+ {
739
+ "name": "status",
740
+ "type": "enum",
741
+ "items": ["draft", "validated", "cancelled"],
742
+ "default": "brouillon"
743
+ },
744
+ {
745
+ "name": "createdBy",
746
+ "type": "relation",
747
+ "relation": "user"
748
+ },
749
+ {
750
+ "name": "validatedBy",
751
+ "type": "relation",
752
+ "relation": "user"
753
+ },
754
+ {
755
+ "name": "validationDate",
756
+ "type": "datetime"
757
+ },
758
+ {
759
+ "name": "attachments",
760
+ "type": "array",
761
+ "itemsType": "file"
762
+ }
763
+ ]
764
+ },
765
+ employee: {
766
+ "name": "employee",
767
+ "icon": "FaUserTie",
768
+ "description": "",
769
+ "tags": ["hr", "users"],
770
+ "fields": [
771
+ {
772
+ "name": "employeeId",
773
+ "type": "string",
774
+ "required": true,
775
+ "unique": true
776
+ },
777
+ {
778
+ "name": "personalInfo",
779
+ "type": "relation",
780
+ "relation": "user",
781
+ "required": true
782
+ },
783
+ {
784
+ "name": "jobTitle",
785
+ "type": "string",
786
+ "required": true
787
+ },
788
+ {
789
+ "name": "department",
790
+ "type": "string"
791
+ },
792
+ {
793
+ "name": "manager",
794
+ "type": "relation",
795
+ "relation": "employee"
796
+ },
797
+ {
798
+ "name": "workLocation",
799
+ "type": "relation",
800
+ "relation": "location"
801
+ },
802
+ {
803
+ "name": "employmentType",
804
+ "type": "enum",
805
+ "items": ["full_time", "part_time", "contractor", "intern", "temporary"]
806
+ },
807
+ {
808
+ "name": "emergencyContact",
809
+ "type": "relation",
810
+ "relation": "contact"
811
+ },
812
+ {
813
+ "name": "homeAddress",
814
+ "type": "relation",
815
+ "relation": "location"
816
+ },
817
+ {
818
+ "name": "dateOfBirth",
819
+ "type": "date"
820
+ },
821
+ {
822
+ "name": "nationality",
823
+ "type": "string"
824
+ },
825
+ {
826
+ "name": "nationalId",
827
+ "type": "string"
828
+ },
829
+ {
830
+ "name": "socialSecurityNumber",
831
+ "type": "string"
832
+ },
833
+ {
834
+ "name": "taxId",
835
+ "type": "string"
836
+ },
837
+ {
838
+ "name": "startDate",
839
+ "type": "date",
840
+ "required": true
841
+ },
842
+ {
843
+ "name": "endDate",
844
+ "type": "date"
845
+ },
846
+ {
847
+ "name": "contractType",
848
+ "type": "string"
849
+ },
850
+ {
851
+ "name": "salary",
852
+ "type": "number"
853
+ },
854
+ {
855
+ "name": "salaryCurrency",
856
+ "type": "relation",
857
+ "relation": "currency"
858
+ },
859
+ {
860
+ "name": "payFrequency",
861
+ "type": "enum",
862
+ "items": ["weekly", "bi_weekly", "monthly"]
863
+ },
864
+ {
865
+ "name": "bankAccountNumber",
866
+ "type": "string"
867
+ },
868
+ {
869
+ "name": "bankName",
870
+ "type": "string"
871
+ },
872
+ {
873
+ "name": "iban",
874
+ "type": "string"
875
+ },
876
+ {
877
+ "name": "swiftBic",
878
+ "type": "string"
879
+ },
880
+ {
881
+ "name": "workPermitNumber",
882
+ "type": "string"
883
+ },
884
+ {
885
+ "name": "workPermitExpiry",
886
+ "type": "date"
887
+ },
888
+ {
889
+ "name": "visaType",
890
+ "type": "string"
891
+ },
892
+ {
893
+ "name": "visaExpiry",
894
+ "type": "date"
895
+ },
896
+ {
897
+ "name": "skills",
898
+ "type": "array",
899
+ "itemsType": "string"
900
+ },
901
+ {
902
+ "name": "notes",
903
+ "type": "richtext"
904
+ }
905
+ ]
906
+ },
907
+ workflow: {
908
+ name: 'workflow',
909
+ "icon": "FaProjectDiagram",
910
+ description: "Defines an automated process.",
911
+ "tags": ["system", "automation"],
912
+ fields: [
913
+ { name: 'name', type: 'string_t', required: true, hint: "Unique name for the workflow (e.g., 'Order Validation', 'Low Stock Notification')." },
914
+ { name: 'description', type: 'richtext', hint: "Detailed explanation of the workflow's purpose." },
915
+ { name: 'startStep', type: 'relation', relation: 'workflowStep', required: false, hint: "The first step to execute when the workflow starts." }
916
+ ]
917
+ },
918
+ workflowTrigger: {
919
+ name: 'workflowTrigger',
920
+ "icon": "FaPlay",
921
+ description: "Represents an event that can initiate a workflow.",
922
+ "tags": ["system", "automation"],
923
+ fields: [
924
+ { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
925
+ { name: 'name', type: 'string_t', required: true, unique: true, hint: "Descriptive name for the trigger (e.g., 'New Order Created', 'Stock < 5', 'Monday 9 AM Report')." },
926
+ {
927
+ name: 'type',
928
+ type: 'enum',
929
+ items: ['manual', 'scheduled'],
930
+ required: true
931
+ },
932
+ {
933
+ name: 'onEvent',
934
+ type: 'enum',
935
+ items: ['DataAdded', 'DataEdited', 'DataDeleted', 'ModelAdded', 'ModelEdited', 'ModelDeleted'],
936
+ condition: { $eq: ["$type", "manual"] }
937
+ },
938
+ { name: 'targetModel', type: 'model', condition: { // Condition pour afficher le champ
939
+ $and: [
940
+ {$eq: ["$type", "manual"]},
941
+ {
942
+ $or: [
943
+ { $eq: ["$onEvent", "DataAdded"] },
944
+ { $eq: ["$onEvent", "DataEdited"] },
945
+ { $eq: ["$onEvent", "DataDeleted"] }
946
+ ]
947
+ }
948
+ ]
949
+ }},
950
+ { name: 'dataFilter', type: 'code', language: 'json', targetModel: '$targetModel', conditionBuilder: true, hint: "Optional conditions checked before executing the step's action.",
951
+ condition: { // Condition pour afficher le champ
952
+ $and: [
953
+ {$eq: ["$type", "manual"]},
954
+ {
955
+ $or: [
956
+ { $eq: ["$onEvent", "DataAdded"] },
957
+ { $eq: ["$onEvent", "DataEdited"] },
958
+ { $eq: ["$onEvent", "DataDeleted"] }
959
+ ]
960
+ }
961
+ ]
962
+ }
963
+ },
964
+ { name: 'env', type: 'code', language: 'json', hint: "Environment variables (JSON key/value pairs)",default: {} },
965
+ { name: 'isActive', type: 'boolean' },
966
+ { name: 'cronExpression', type: 'cronSchedule', cronMask:[false, true, true, true, true, true], hint: "Cron expression for scheduling (e.g., '0 9 * * 1' for Monday 9 AM) (used by Scheduled type).",
967
+ condition:
968
+ {$eq: ["$type", "scheduled"]}}
969
+ ]
970
+ },
971
+ workflowStep: {
972
+ name: 'workflowStep',
973
+ "icon": "FaStepForward",
974
+ description: "A single step within a workflow process.",
975
+ "tags": ["system", "automation"],
976
+ fields: [
977
+ { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
978
+ { name: 'name', type: 'string_t', hint: "Optional descriptive name for the step (e.g., 'Check Inventory', 'Send Confirmation Email')." },
979
+ { name: 'conditions', type: 'code', language: 'json', conditionBuilder: true, hint: "Optional conditions checked before executing the step's action." },
980
+ { name: 'actions', type: 'relation', relation: 'workflowAction', multiple: true, required: true, hint: "The main actions performed by this step." },
981
+ { name: 'onSuccessStep', type: 'relation', relation: 'workflowStep', hint: "Optional: The next step if this step's action succeeds." },
982
+ { name: 'onFailureStep', type: 'relation', relation: 'workflowStep', hint: "Optional: The next step if conditions fail or the action fails." },
983
+ { name: 'isTerminal', type: 'boolean', default: false, hint: "Indicates if this step marks the end of a workflow path." }
984
+ ]
985
+ },
986
+ workflowAction: {
987
+ name: 'workflowAction',
988
+ "icon": "FaCogs",
989
+ description: "Defines a specific operation to be performed by a workflow step.",
990
+ "tags": ["system", "automation"],
991
+ fields: [
992
+ { name: 'name', type: 'string_t', required: true, hint: "Name of the action (e.g., 'Update Order Status', 'Send Email', 'Call Payment API')." },
993
+ {
994
+ name: 'type',
995
+ type: 'enum',
996
+ required: true,
997
+ items: ['UpdateData', 'CreateData', 'DeleteData', 'ExecuteScript', 'HttpRequest', 'SendEmail', 'Wait', 'GenerateAIContent', 'ExecuteServiceFunction'],
998
+ hint: "The type of operation to perform."
999
+ },
1000
+ // For UpdateData / CreateData / DeleteData
1001
+ { name: 'targetModel', condition: {
1002
+ $or: [
1003
+ {$eq: ["$type", "CreateData"]},
1004
+ {$eq: ["$type", "UpdateData"]},
1005
+ {$eq: ["$type", "DeleteData"]}
1006
+ ]
1007
+ }, type: 'model', hint: "Model to target" },
1008
+
1009
+ // For UpdateData / DeleteData
1010
+ { name: 'targetSelector', targetModel: "$targetModel", conditionBuilder: true, condition: {
1011
+ $or: [
1012
+ {$eq: ["$type", "UpdateData"]},
1013
+ {$eq: ["$type", "DeleteData"]}
1014
+ ]
1015
+ }, type: 'code', language: 'json', hint: "Expression to filter to the target document(s)." },
1016
+
1017
+ // For UpdateData
1018
+ { name: 'fieldsToUpdate', condition: {$eq: ["$type", "UpdateData"]}, type: 'code', language: 'json', default: {}, hint: "Key-value pairs of fields to update (e.g., { status: 'Validé', lastUpdated: '{now}' })" },
1019
+
1020
+ // For CreateData
1021
+ { name: 'dataToCreate', condition: {$eq: ["$type", "CreateData"]}, type: 'code', language: 'json', default: {}, hint: "Object template for the new document to create" },
1022
+
1023
+ // For HttpRequest
1024
+ { name: 'url', condition: {$eq: ["$type", "HttpRequest"]}, type: 'string', hint: "The URL to call." },
1025
+ { name: 'method', condition: {$eq: ["$type", "HttpRequest"]}, type: 'enum', items: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], default: 'POST', hint: "HTTP method." },
1026
+ { name: 'headers', condition: {$eq: ["$type", "HttpRequest"]}, type: 'code', language: 'json',default: {}, hint: "HTTP headers as key-value pairs." },
1027
+ { name: 'body', condition: {$eq: ["$type", "HttpRequest"]}, type: 'code', language: 'json',default: {}, hint: "Request body, can include variables." },
1028
+
1029
+ // For SendEmail
1030
+ {
1031
+ name: 'emailRecipients',
1032
+ type: 'array',
1033
+ itemsType: 'string',
1034
+ condition: { $eq: ["$type", "SendEmail"] },
1035
+ hint: "Destinataire(s) de l'e-mail. Peut être une adresse, plusieurs adresses séparées par des virgules, ou une variable comme {triggerData.client.email}."
1036
+ },
1037
+ {
1038
+ name: 'emailSubject',
1039
+ type: 'string',
1040
+ condition: { $eq: ["$type", "SendEmail"] },
1041
+ hint: "Sujet de l'e-mail. Peut contenir des variables."
1042
+ },
1043
+ {
1044
+ name: 'emailContent',
1045
+ type: 'richtext',
1046
+ condition: { $eq: ["$type", "SendEmail"] },
1047
+ hint: "Contenu de l'e-mail. Peut contenir des variables et du HTML."
1048
+ },
1049
+
1050
+ // For Wait
1051
+ { name: 'duration', condition: {$eq: ["$type", "Wait"]}, type: 'number', hint: "Duration to wait." },
1052
+ { name: 'durationUnit', condition:{$eq: ["$type", "Wait"]}, type: 'enum', items: ['milliseconds', 'seconds', 'minutes', 'hours', 'days'], default: 'seconds', hint: "Unit for the duration." },
1053
+
1054
+ // For GenerateAIContents
1055
+ {
1056
+ name: 'aiProvider',
1057
+ condition: { $eq: ["$type", "GenerateAIContent"] },
1058
+ type: 'enum',
1059
+ items: ['OpenAI', 'GoogleGemini'], // Extensible avec d'autres fournisseurs
1060
+ hint: "Le fournisseur de LLM à utiliser."
1061
+ },
1062
+ {
1063
+ name: 'aiModel',
1064
+ condition: { $eq: ["$type", "GenerateAIContent"] },
1065
+ type: 'string',
1066
+ default: 'gpt-4o-mini', // Un défaut raisonnable
1067
+ hint: "Le modèle spécifique à utiliser (ex: gpt-4o-mini, gemini-1.5-pro-latest)."
1068
+ },
1069
+ {
1070
+ name: 'prompt',
1071
+ condition: { $eq: ["$type", "GenerateAIContent"] },
1072
+ type: 'richtext', // richtext est bien pour les longs prompts
1073
+ hint: "Le modèle de prompt. Utilise des variables comme {triggerData.field} ou {context.variable}."
1074
+ },
1075
+
1076
+ // For ExecuteScript
1077
+ { name: 'script', condition: {$eq: ["$type", "ExecuteScript"]}, type: 'code', language: 'javascript', hint: "The script to execute." },
1078
+
1079
+ // For ExecuteServiceFunction
1080
+ { name: 'serviceName', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'string', hint: "The name of the registered service to call (e.g., 'stripe')." },
1081
+ { name: 'functionName', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'string', hint: "The name of the function to execute within the service." },
1082
+ { name: 'args', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'code', language: 'json', default: [], hint: "An array of arguments to pass to the function. Can include variables." }
1083
+
1084
+ ]
1085
+ },
1086
+
1087
+ workflowRun: {
1088
+ name: 'workflowRun',
1089
+ "icon": "FaRunning",
1090
+ description: "Tracks a specific execution instance of a workflow.",
1091
+ "tags": ["system", "automation", "logs"],
1092
+ fields: [
1093
+ { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow definition that was executed." },
1094
+ { name: 'contextData', type: 'code', language: 'json',default: {}, hint: "Snapshot of the data or event that triggered this run." },
1095
+ {
1096
+ name: 'status',
1097
+ type: 'enum',
1098
+ required: true,
1099
+ items: ['pending', 'running', 'completed', 'failed', 'waiting', 'cancelled'],
1100
+ default: 'pending',
1101
+ hint: "The current status of the workflow execution."
1102
+ },
1103
+ { name: 'stepExecutionsCount', type: 'object' },
1104
+ { name: 'currentStep', type: 'relation', relation: 'workflowStep', hint: "The step currently being executed or waited on." },
1105
+ { name: 'owner', type: 'relation', relation: 'user', required: false },
1106
+ { name: 'startedAt', type: 'datetime', required: true, hint: "Timestamp when the workflow run began." },
1107
+ { name: 'completedAt', type: 'datetime', hint: "Timestamp when the workflow run finished (successfully or failed)." },
1108
+ { name: 'log', type: 'string', maxlength: 4096, hint: "Error message if the workflow run failed." }
1109
+ ]
1110
+ },
1111
+ dashboard:{
1112
+ name: 'dashboard', // Nom technique du modèle
1113
+ "icon": "FaTachometerAlt",
1114
+ description: "Configuration d'un tableau de bord personnalisé par l'utilisateur.", // Description du modèle
1115
+ locked: false, // Indique si le modèle peut être modifié par l'utilisateur (false = modifiable)
1116
+ "tags": ["reporting", "analytics"],
1117
+ fields: [
1118
+ {
1119
+ name: 'name', // Nom du tableau de bord
1120
+ type: 'string', // Type texte simple
1121
+ required: true, // Ce champ est obligatoire
1122
+ hint: "Nom affiché et personnalisable du tableau de bord."
1123
+ },
1124
+ {
1125
+ name: 'description', // Description optionnelle
1126
+ type: 'string', // Type texte simple (pourrait être 'richtext' si besoin de mise en forme)
1127
+ hint: "Description facultative pour donner plus de contexte au tableau de bord."
1128
+ },
1129
+ {
1130
+ name: 'layout', // Configuration de la disposition des éléments
1131
+ type: 'code', // Utilisation du type 'code' pour stocker une structure JSON flexible
1132
+ language: 'json', // Précise que le contenu est du JSON
1133
+ required: true, // La disposition est essentielle
1134
+ default: { "type": "columns", "columns": [] }, // Valeur par défaut : une disposition en colonnes vide, stockée comme chaîne JSON
1135
+ hint: "Structure JSON décrivant l'organisation des KPIs. Exemple : { \"type\": \"columns\", \"columns\": [ [\"kpi_id_1\"], [\"kpi_id_2\", \"kpi_id_3\"] ] }."
1136
+ },
1137
+ {
1138
+ name: 'refreshInterval',
1139
+ type: 'number',
1140
+ delay: true, // Sera interprété par le front-end comme un champ de durée
1141
+ unit: 's',
1142
+ min: 0,
1143
+ hint: "Intervalle de rafraîchissement automatique en secondes. Laisser vide ou à 0 pour désactiver."
1144
+ },
1145
+ {
1146
+ name: 'isDefault', // Indicateur pour le tableau de bord par défaut
1147
+ type: 'boolean', // Type booléen (vrai/faux)
1148
+ default: false, // Par défaut, un nouveau tableau de bord n'est pas celui par défaut
1149
+ hint: "Si 'true', ce tableau de bord est affiché par défaut pour l'utilisateur."
1150
+ }
1151
+ ]
1152
+ },
1153
+ 'request': {
1154
+ name: 'request',
1155
+ "icon": "FaExchangeAlt",
1156
+ description: "Journal des requêtes reçues par l'API.",
1157
+ locked: true, // Géré par le système, non modifiable directement par l'utilisateur via l'UI standard
1158
+ "tags": ["system", "logs", "monitoring"],
1159
+ fields: [
1160
+ {
1161
+ name: 'timestamp',
1162
+ type: 'datetime',
1163
+ required: true,
1164
+ hint: "Date et heure exactes de la réception de la requête."
1165
+ },
1166
+ {
1167
+ name: 'method',
1168
+ type: 'enum',
1169
+ items: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'],
1170
+ required: true,
1171
+ hint: "Méthode HTTP utilisée (GET, POST, etc.)."
1172
+ },
1173
+ {
1174
+ name: 'url',
1175
+ type: 'string',
1176
+ required: true,
1177
+ multiline: false,
1178
+ maxlength: 2048, // Limite raisonnable pour une URL
1179
+ hint: "URL complète de la requête, incluant les query parameters."
1180
+ },
1181
+ {
1182
+ name: 'status',
1183
+ type: 'number',
1184
+ step: 100,
1185
+ default: 200,
1186
+ required: true,
1187
+ hint: "Code de statut HTTP retourné par le serveur (ex: 200, 404, 500)."
1188
+ },
1189
+ {
1190
+ name: 'latencyMs',
1191
+ type: 'number',
1192
+ required: true,
1193
+ color: '#e8c965',
1194
+ unit: 'ms',
1195
+ hint: "Temps de traitement de la requête par le serveur, en millisecondes."
1196
+ },
1197
+ {
1198
+ name: 'ip',
1199
+ type: 'string',
1200
+ hint: "Adresse IP du client ayant effectué la requête."
1201
+ },
1202
+ /*{
1203
+ name: 'requestHeaders',
1204
+ type: 'code',
1205
+ language: 'json',
1206
+ required: false,
1207
+ hint: "En-têtes HTTP de la requête (stockés sous forme de chaîne JSON). Peut être volumineux."
1208
+ },*/
1209
+ {
1210
+ name: 'requestBody', // Optionnel, peut être sensible/volumineux
1211
+ type: 'code',
1212
+ language: 'json', // Ou 'text' si ce n'est pas toujours du JSON
1213
+ required: false,
1214
+ hint: "Corps de la requête (stocké sous forme de chaîne JSON/texte). Attention: peut contenir des données sensibles et être volumineux."
1215
+ },
1216
+ {
1217
+ name: 'responseBody', // Optionnel, peut être volumineux
1218
+ type: 'code',
1219
+ language: 'json', // Ou 'text'
1220
+ required: false,
1221
+ "condition": {
1222
+ "path": [
1223
+ "status"
1224
+ ],
1225
+ "op": "$gte",
1226
+ "value": "400"
1227
+ },
1228
+ hint: "Corps de la réponse (stocké sous forme de chaîne JSON/texte). Attention: peut être volumineux."
1229
+ },
1230
+ {
1231
+ name: 'error',
1232
+ type: 'string',
1233
+ maxlength: 4096, // Espace pour les messages d'erreur détaillés
1234
+ required: false,
1235
+ hint: "Message d'erreur si la requête a échoué côté serveur (ex: statut 500)."
1236
+ }
1237
+ ]
1238
+ },
1239
+
1240
+ kpi : {
1241
+ name: 'kpi',
1242
+ "icon": "FaChartLine",
1243
+ description: "Configuration d'un Indicateur Clé de Performance (KPI)",
1244
+ "tags": ["reporting", "analytics"],
1245
+ fields: [
1246
+ { name: 'name', type: 'string_t', required: true, hint: "Nom affiché du KPI (ex: Chiffre d'affaires total)" },
1247
+ { name: 'description', type: 'string_t', hint: "Informations complémentaires sur le KPI" },
1248
+ { name: 'targetModel', type: 'model', required: true, hint: "Nom du modèle sur lequel calculer le KPI (ex: order)" },
1249
+ {
1250
+ name: 'aggregationType',
1251
+ type: 'enum',
1252
+ required: true,
1253
+ items: ['count', 'sum', 'avg', 'min', 'max'], // Types d'agrégation courants
1254
+ hint: "Type de calcul à effectuer"
1255
+ },
1256
+ {
1257
+ name: 'aggregationField',
1258
+ type: 'modelField',
1259
+ targetModel: '$targetModel',
1260
+ condition: { $ne: ["$aggregationType", "count"] },
1261
+ hint: "Nom du champ numérique sur lequel appliquer l'agrégation (ex: totalAmount). Non requis pour 'count'."
1262
+ },
1263
+ {
1264
+ name: 'matchFormula',
1265
+ type: 'code', // Utiliser l'éditeur de code pour le JSON
1266
+ language: 'json',
1267
+ conditionBuilder: true,
1268
+ targetModel: '$targetModel',
1269
+ default: {}, // Valeur par défaut: aucun filtre
1270
+ hint: "Filtre JSON (MongoDB $match) à appliquer avant l'agrégation (ex: { \"status\": \"delivered\" })"
1271
+ },
1272
+ {
1273
+ "name": "showTotal",
1274
+ "hint": "Afficher le total",
1275
+ "type": "boolean"
1276
+ },
1277
+ {
1278
+ "name": "showPercentTotal",
1279
+ "hint": "Afficher le total en %",
1280
+ "type": "boolean"
1281
+ },
1282
+ {
1283
+ "name": "totalMatchFormula",
1284
+ "hint": "Formule pour le total (calcul %)",
1285
+ "type": "code",
1286
+ "language": "json",
1287
+ "required": false,
1288
+ "default": "{}",
1289
+ condition: { "$or": [
1290
+ {$eq: ["$showTotal", true]},
1291
+ {$eq: ["$showPercentTotal", true]}
1292
+ ]}
1293
+ },
1294
+ {
1295
+ name: 'unit', // Optionnel: Unité à afficher avec la valeur
1296
+ type: 'string',
1297
+ hint: "Unité à afficher (ex: €, $, utilisateurs)"
1298
+ },
1299
+ {
1300
+ name: 'icon', // Optionnel: Icône à afficher
1301
+ type: 'string', // Ou un type 'icon' si tu en as un
1302
+ hint: "Nom de l'icône (ex: FaUsers, FaShoppingCart)"
1303
+ },
1304
+ // Optionnel: Ajouter des champs pour le style, l'ordre d'affichage, etc.
1305
+ { name: 'order', type: 'number', hint: "Ordre d'affichage sur un tableau de bord" },
1306
+ { name: 'color', type: 'color', hint: "Couleur associée au KPI" }
1307
+ ]
1308
+ },
1309
+ imageGallery: {
1310
+ name: 'imageGallery',
1311
+ "icon": "FaImages",
1312
+ description: "Représente une galerie d'images avec un titre et une description.",
1313
+ locked: false, // Les utilisateurs peuvent créer/gérer leurs galeries
1314
+ "tags": ["cms", "assets"],
1315
+ fields: [
1316
+ {
1317
+ name: 'name',
1318
+ type: 'string_t', // Titre traduisible
1319
+ required: true,
1320
+ asMain: true, // Champ principal pour l'affichage
1321
+ color: '#4CAF50', // Couleur indicative
1322
+ hint: "Le nom ou titre de la galerie d'images."
1323
+ },
1324
+ {
1325
+ name: 'images',
1326
+ type: 'array',
1327
+ itemsType: 'file', // Type des éléments du tableau
1328
+ required: false, // Permet de créer une galerie vide initialement
1329
+ mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], // Types d'images autorisés
1330
+ hint: "Les fichiers images de cette galerie."
1331
+ },
1332
+ {
1333
+ name: 'description',
1334
+ type: 'richtext', // Description riche
1335
+ hint: "Description de la galerie (optionnel)."
1336
+ },
1337
+ {
1338
+ name: 'tags',
1339
+ type: 'relation',
1340
+ relation: 'taxonomy', // Relation vers le modèle 'taxonomy'
1341
+ multiple: true, // Peut avoir plusieurs tags
1342
+ hint: "Tags ou catégories pour organiser les galeries (optionnel)."
1343
+ },
1344
+ {
1345
+ name: 'createdAt',
1346
+ type: 'datetime',
1347
+ // Ce champ pourrait être rempli automatiquement par le système lors de la création
1348
+ hint: "Date de création de la galerie (généralement géré par le système)."
1349
+ }
1350
+ ]
1351
+ },
1352
+ budget: {
1353
+ name: 'budget',
1354
+ "icon": "FaMoneyCheck",
1355
+ description: "Un budget permet de lister vos transactions personnelles.",
1356
+ "tags": ["personal", "finance"],
1357
+ fields: [
1358
+ {
1359
+ name: 'name',
1360
+ type: 'string_t',
1361
+ asMain: true,
1362
+ hint: "Nom ou description de la transaction (ex: Courses, Salaire Janvier)."
1363
+ },
1364
+ {
1365
+ name: 'amount',
1366
+ type: 'number',
1367
+ step: 1,
1368
+ asMain: true,
1369
+ required: true,
1370
+ hint: "Montant de la transaction. Positif pour un revenu, négatif pour une dépense."
1371
+ },
1372
+ {
1373
+ name: 'currency',
1374
+ type: 'relation',
1375
+ relation: 'currency',
1376
+ asMain: true,
1377
+ required: true,
1378
+ hint: "Devise de la transaction."
1379
+ },
1380
+ {
1381
+ name: 'transactionDate',
1382
+ type: 'datetime',
1383
+ required: true,
1384
+ asMain: true,
1385
+ hint: "Date à laquelle la transaction a eu lieu."
1386
+ },
1387
+ {
1388
+ name: 'description',
1389
+ type: 'richtext', // Pour des notes plus détaillées
1390
+ hint: "Notes ou détails supplémentaires sur la transaction."
1391
+ },
1392
+ {
1393
+ name: 'paymentMethod',
1394
+ type: 'string', // Ou enum si vous avez une liste fixe
1395
+ hint: "Méthode de paiement utilisée (ex: Carte de crédit, Espèces, Virement)."
1396
+ },
1397
+ {
1398
+ name: 'category',
1399
+ type: 'relation',
1400
+ relation: 'taxonomy', // Utiliser le modèle 'taxonomy' pour les catégories
1401
+ // Vous pourriez vouloir filtrer les taxonomies de type 'budget_category'
1402
+ hint: "Catégorie de la transaction (ex: Alimentation, Logement, Transport)."
1403
+ },
1404
+ {
1405
+ name: 'isRecurring',
1406
+ type: 'boolean',
1407
+ default: false,
1408
+ hint: "Indique si cette transaction est récurrente."
1409
+ },
1410
+ {
1411
+ name: 'recurringFrequency',
1412
+ type: 'enum',
1413
+ items: ['daily', 'weekly', 'monthly', 'yearly'],
1414
+ condition: {$eq: ["$isRecurring", true]}
1415
+ },
1416
+ {name: 'recurringEndDate', type: 'date', condition: {$eq: ["$isRecurring", true]}},
1417
+ {
1418
+ name: 'attachments',
1419
+ type: 'array',
1420
+ itemsType: 'file', // Pour joindre des reçus, factures, etc.
1421
+ hint: "Pièces jointes (reçus, factures)."
1422
+ }
1423
+ ]
1424
+ },
1425
+ event: {
1426
+ "name": "event",
1427
+ "icon": "FaCalendar",
1428
+ "description": "A model for managing events, conferences, meetups, and gatherings.",
1429
+ "tags": ["cms", "events"],
1430
+ "fields": [
1431
+ {
1432
+ "name": "title",
1433
+ "type": "string",
1434
+ "required": true,
1435
+ "asMain": true,
1436
+ "hint": "The title of the event"
1437
+ },
1438
+ {
1439
+ "name": "description",
1440
+ "type": "richtext_t",
1441
+ "hint": "A detailed description of the event, including agenda, speakers, and other relevant information."
1442
+ },
1443
+ {
1444
+ "name": "startDate",
1445
+ "type": "datetime",
1446
+ "required": true,
1447
+ "hint": "The starting date and time of the event"
1448
+ },
1449
+ {
1450
+ "name": "endDate",
1451
+ "type": "datetime",
1452
+ "required": true,
1453
+ "hint": "The ending date and time of the event"
1454
+ },
1455
+ {
1456
+ "name": "location",
1457
+ "type": "relation",
1458
+ "relation": "location",
1459
+ "hint": "The venue or location where the event will be held. This could be a physical address or an online meeting link."
1460
+ },
1461
+ {
1462
+ "name": "categories",
1463
+ "type": "relation",
1464
+ "relation": "taxonomy",
1465
+ "multiple": true,
1466
+ "hint": "Categories or tags associated with the event (e.g., \"conference\", \"workshop\", \"music\", \"technology\")."
1467
+ },
1468
+ {
1469
+ "name": "organizer",
1470
+ "type": "relation",
1471
+ "relation": "contact",
1472
+ "hint": "The name of the organization or individual hosting the event."
1473
+ },
1474
+ {
1475
+ "name": "isOnline",
1476
+ "type": "boolean",
1477
+ "default": false,
1478
+ "hint": "Whether the event is online or in-person."
1479
+ },
1480
+ {
1481
+ "name": "eventUrl",
1482
+ "type": "url",
1483
+ "hint": "A link to the official event webpage or registration page."
1484
+ },
1485
+ {
1486
+ "name": "imageUrl",
1487
+ "type": "file",
1488
+ "hint": "URL of the event image or banner."
1489
+ },
1490
+ {
1491
+ "name": "status",
1492
+ "type": "enum",
1493
+ "items": [
1494
+ "scheduled",
1495
+ "ongoing",
1496
+ "completed",
1497
+ "cancelled",
1498
+ "postponed"
1499
+ ],
1500
+ "hint": "The current status of the event."
1501
+ },
1502
+ {
1503
+ "name": "capacity",
1504
+ "type": "number",
1505
+ "hint": "The maximum number of attendees allowed for the event."
1506
+ },
1507
+ {
1508
+ "name": "price",
1509
+ "type": "number",
1510
+ "hint": "The price of admission, if applicable."
1511
+ },
1512
+ {
1513
+ "name": "currency",
1514
+ "type": "relation",
1515
+ "relation": "currency",
1516
+ "hint": "The currency for the price (e.g., USD, EUR)."
1517
+ },
1518
+ {
1519
+ "name": "registrationDeadline",
1520
+ "type": "datetime",
1521
+ "hint": "The date by which attendees must register for the event."
1522
+ },
1523
+ {
1524
+ "name": "attendees",
1525
+ "type": "relation",
1526
+ "relation": "contact",
1527
+ "multiple": true,
1528
+ "hint": "A relation to the contacts attending the event"
1529
+ },
1530
+ {
1531
+ "name": "sponsors",
1532
+ "type": "relation",
1533
+ "relation": "contact",
1534
+ "multiple": true,
1535
+ "hint": "List of sponsors or partners involved in the event."
1536
+ }
1537
+ ]
1538
+ },
1539
+ endpoint: {
1540
+ name: "endpoint",
1541
+ "icon": "FaCode",
1542
+ description: "Defines custom API endpoints that execute a server-side script.",
1543
+ "tags": ["system", "api", "automation"],
1544
+ fields: [
1545
+ {
1546
+ name: "isActive",
1547
+ type: "boolean",
1548
+ default: true,
1549
+ hint: "If checked, the endpoint is active and can be called."
1550
+ },
1551
+ {
1552
+ name: "name",
1553
+ type: "string",
1554
+ required: true,
1555
+ asMain: true,
1556
+ hint: "A human-readable name to identify the endpoint."
1557
+ },
1558
+ {
1559
+ name: "path",
1560
+ type: "string",
1561
+ required: true,
1562
+ hint: "The URL path after /api/actions/ (e.g., 'send-welcome-email'). Do not include '/'.",
1563
+ placeholder: "my-custom-action"
1564
+ },
1565
+ {
1566
+ name: "method",
1567
+ type: "enum",
1568
+ items: ["GET", "POST", "PUT", "PATCH", "DELETE"],
1569
+ required: true,
1570
+ default: "POST",
1571
+ hint: "The HTTP method required to call this endpoint."
1572
+ },
1573
+ {
1574
+ name: "code",
1575
+ type: "code",
1576
+ language: "javascript",
1577
+ required: true,
1578
+ hint: "The script to execute. Must return a value or an object that will be the JSON response.",
1579
+ default: `// The script can access 'db', 'logger', 'env'.
1580
+ // request.body, request.query, request.params, request.headers available
1581
+ // The returned value will be the API's JSON response.
1582
+
1583
+ logger.info('Custom endpoint executed with body:', request.body);
1584
+
1585
+ return { success: true, message: 'Endpoint executed!', received: request.body };
1586
+ `
1587
+ },
1588
+ {
1589
+ name: 'isPublic',
1590
+ type: 'boolean',
1591
+ default: false,
1592
+ hint: "Si coché, ce point d'accès sera accessible sans authentification."
1593
+ }
1594
+ ]
1595
+ }
1596
+ };