data-primals-engine 1.6.2 → 1.6.3

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