@almadar/std 16.216.0 → 16.218.0

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,2404 @@
1
+ {
2
+ "description": "std-notification-preferences — per-person notification preference store plus a consultable gate. Owns NotificationPreference rows (one per person + event key: channel override in_app/email/push/slack, mode instant/digest, quiet-hours window 'HH:MM-HH:MM' such as 22:00-07:00). The PreferencesManage trait is standard CRUD over the store (list / create / update / delete, persisted, success/failure cascade arms): a data-grid browse plus ModalRecordModal create/edit forms whose SAVE carries the full row payload (std-list daisy-chain idiom). The PreferenceGate trait is the consult half other notify traits call: emit CHECK_PREFERENCE { personId, eventKey } and the gate fetches the matching row (a row whose eventKey is blank applies to every event) and answers PREFERENCE_RESOLVED { personId, eventKey, channel, mode, suppressed } — suppressed is true only when the row's quietHours window covers the current hour; mode 'digest' rides on the verdict for the caller to defer. Default policy: no matching row — or a failed lookup — resolves fail-open to { channel: in_app, mode: instant, suppressed: false }; the absence of a preference never silences a notification.",
3
+ "ledger": {
4
+ "entries": {
5
+ "ent_01M2HEX5N29SFAW1SYFN346B12": {
6
+ "bakedName": "NotificationPreference",
7
+ "curName": "NotificationPreference",
8
+ "id": "ent_01M2HEX5N29SFAW1SYFN346B12",
9
+ "kind": "entity",
10
+ "owner": "workspace",
11
+ "renames": []
12
+ },
13
+ "ent_01M2HEX5N2Y7H9B3PH0ZSSH9QR": {
14
+ "bakedName": "GateView",
15
+ "curName": "GateView",
16
+ "id": "ent_01M2HEX5N2Y7H9B3PH0ZSSH9QR",
17
+ "kind": "entity",
18
+ "owner": "workspace",
19
+ "renames": []
20
+ },
21
+ "evt_01M2HEX5N246QSGGDXMFT09QJ6": {
22
+ "bakedName": "PREFERENCE_CHECK_FAILED",
23
+ "curName": "PREFERENCE_CHECK_FAILED",
24
+ "id": "evt_01M2HEX5N246QSGGDXMFT09QJ6",
25
+ "kind": "event",
26
+ "owner": "workspace",
27
+ "parent": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6",
28
+ "renames": []
29
+ },
30
+ "evt_01M2HEX5N285MJJBPVPTC5CC31": {
31
+ "bakedName": "PreferenceSaveFailed",
32
+ "curName": "PreferenceSaveFailed",
33
+ "id": "evt_01M2HEX5N285MJJBPVPTC5CC31",
34
+ "kind": "event",
35
+ "owner": "workspace",
36
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
37
+ "renames": []
38
+ },
39
+ "evt_01M2HEX5N2BXMHCTQZSM2CZ8EF": {
40
+ "bakedName": "PreferenceDeleted",
41
+ "curName": "PreferenceDeleted",
42
+ "id": "evt_01M2HEX5N2BXMHCTQZSM2CZ8EF",
43
+ "kind": "event",
44
+ "owner": "workspace",
45
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
46
+ "renames": []
47
+ },
48
+ "evt_01M2HEX5N2C20G8DKMNNETXXV8": {
49
+ "bakedName": "CHECK_PREFERENCE",
50
+ "curName": "CHECK_PREFERENCE",
51
+ "id": "evt_01M2HEX5N2C20G8DKMNNETXXV8",
52
+ "kind": "event",
53
+ "owner": "workspace",
54
+ "parent": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6",
55
+ "renames": []
56
+ },
57
+ "evt_01M2HEX5N2CK3GB34396QDTF77": {
58
+ "bakedName": "PreferencesLoadFailed",
59
+ "curName": "PreferencesLoadFailed",
60
+ "id": "evt_01M2HEX5N2CK3GB34396QDTF77",
61
+ "kind": "event",
62
+ "owner": "workspace",
63
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
64
+ "renames": []
65
+ },
66
+ "evt_01M2HEX5N2J0G7WR4H4MF89J1K": {
67
+ "bakedName": "PREFERENCE_ROWS_LOADED",
68
+ "curName": "PREFERENCE_ROWS_LOADED",
69
+ "id": "evt_01M2HEX5N2J0G7WR4H4MF89J1K",
70
+ "kind": "event",
71
+ "owner": "workspace",
72
+ "parent": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6",
73
+ "renames": []
74
+ },
75
+ "evt_01M2HEX5N2NRGS7RER3F5EVBEY": {
76
+ "bakedName": "PREFERENCE_RESOLVED",
77
+ "curName": "PREFERENCE_RESOLVED",
78
+ "id": "evt_01M2HEX5N2NRGS7RER3F5EVBEY",
79
+ "kind": "event",
80
+ "owner": "workspace",
81
+ "parent": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6",
82
+ "renames": []
83
+ },
84
+ "evt_01M2HEX5N2PYWA1JGBVPEV3YYY": {
85
+ "bakedName": "DELETE",
86
+ "curName": "DELETE",
87
+ "id": "evt_01M2HEX5N2PYWA1JGBVPEV3YYY",
88
+ "kind": "event",
89
+ "owner": "workspace",
90
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
91
+ "renames": []
92
+ },
93
+ "evt_01M2HEX5N2TVADH0YB19NFRW15": {
94
+ "bakedName": "PreferencesLoaded",
95
+ "curName": "PreferencesLoaded",
96
+ "id": "evt_01M2HEX5N2TVADH0YB19NFRW15",
97
+ "kind": "event",
98
+ "owner": "workspace",
99
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
100
+ "renames": []
101
+ },
102
+ "evt_01M2HEX5N2WPK2RGK1VGFNP6MP": {
103
+ "bakedName": "INIT",
104
+ "curName": "INIT",
105
+ "id": "evt_01M2HEX5N2WPK2RGK1VGFNP6MP",
106
+ "kind": "event",
107
+ "owner": "workspace",
108
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
109
+ "renames": []
110
+ },
111
+ "evt_01M2HEX5N2Y4V8B010WJDPPY13": {
112
+ "bakedName": "EDIT",
113
+ "curName": "EDIT",
114
+ "id": "evt_01M2HEX5N2Y4V8B010WJDPPY13",
115
+ "kind": "event",
116
+ "owner": "workspace",
117
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
118
+ "renames": []
119
+ },
120
+ "evt_01M2HEX5N2ZPEFS633G0S54KA1": {
121
+ "bakedName": "PreferenceSaved",
122
+ "curName": "PreferenceSaved",
123
+ "id": "evt_01M2HEX5N2ZPEFS633G0S54KA1",
124
+ "kind": "event",
125
+ "owner": "workspace",
126
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
127
+ "renames": []
128
+ },
129
+ "evt_01M2J1EARY3G1EG29PWVNZZYMM": {
130
+ "bakedName": "RETRY",
131
+ "curName": "RETRY",
132
+ "id": "evt_01M2J1EARY3G1EG29PWVNZZYMM",
133
+ "kind": "event",
134
+ "owner": "workspace",
135
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
136
+ "renames": []
137
+ },
138
+ "evt_01M2J1EARYBKD6GTS10VF710DN": {
139
+ "bakedName": "DO_UPDATE",
140
+ "curName": "DO_UPDATE",
141
+ "id": "evt_01M2J1EARYBKD6GTS10VF710DN",
142
+ "kind": "event",
143
+ "owner": "workspace",
144
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
145
+ "renames": []
146
+ },
147
+ "evt_01M2J1EARYVZMZ0NNS1CZND3GK": {
148
+ "bakedName": "CREATE",
149
+ "curName": "CREATE",
150
+ "id": "evt_01M2J1EARYVZMZ0NNS1CZND3GK",
151
+ "kind": "event",
152
+ "owner": "workspace",
153
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
154
+ "renames": []
155
+ },
156
+ "evt_01M2J1EARYX2SMTRQ0MQ8WFJHS": {
157
+ "bakedName": "DO_CREATE",
158
+ "curName": "DO_CREATE",
159
+ "id": "evt_01M2J1EARYX2SMTRQ0MQ8WFJHS",
160
+ "kind": "event",
161
+ "owner": "workspace",
162
+ "parent": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
163
+ "renames": []
164
+ },
165
+ "orb_01M2HEX5N2DRQ9NPHZKE4R9DBJ": {
166
+ "bakedName": "NotificationPreferencesOrbital",
167
+ "curName": "NotificationPreferencesOrbital",
168
+ "id": "orb_01M2HEX5N2DRQ9NPHZKE4R9DBJ",
169
+ "kind": "orbital",
170
+ "owner": "workspace",
171
+ "renames": []
172
+ },
173
+ "pag_01M2HEX5N34514K7WAZHT6K9WP": {
174
+ "bakedName": "NotificationPreferencesPage",
175
+ "curName": "NotificationPreferencesPage",
176
+ "id": "pag_01M2HEX5N34514K7WAZHT6K9WP",
177
+ "kind": "page",
178
+ "owner": "workspace",
179
+ "renames": []
180
+ },
181
+ "trt_01M2HEX5N2M0FS7QBQECCJBK9X": {
182
+ "bakedName": "PreferencesManage",
183
+ "curName": "PreferencesManage",
184
+ "id": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
185
+ "kind": "trait",
186
+ "owner": "workspace",
187
+ "renames": []
188
+ },
189
+ "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6": {
190
+ "bakedName": "PreferenceGate",
191
+ "curName": "PreferenceGate",
192
+ "id": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6",
193
+ "kind": "trait",
194
+ "owner": "workspace",
195
+ "renames": []
196
+ },
197
+ "trt_01M2J1EARYFYA9YZM5WFH8DZZK": {
198
+ "bakedName": "PreferenceCreate",
199
+ "curName": "PreferenceCreate",
200
+ "id": "trt_01M2J1EARYFYA9YZM5WFH8DZZK",
201
+ "kind": "trait",
202
+ "owner": "workspace",
203
+ "renames": []
204
+ },
205
+ "trt_01M2J1EARYVZKT8FP35Z1B5C4Q": {
206
+ "bakedName": "PreferenceEdit",
207
+ "curName": "PreferenceEdit",
208
+ "id": "trt_01M2J1EARYVZKT8FP35Z1B5C4Q",
209
+ "kind": "trait",
210
+ "owner": "workspace",
211
+ "renames": []
212
+ }
213
+ },
214
+ "schemaVersion": 1
215
+ },
216
+ "name": "std-notification-preferences",
217
+ "orbitals": [
218
+ {
219
+ "auxiliaryEntities": [
220
+ {
221
+ "fields": [
222
+ {
223
+ "name": "id",
224
+ "required": true,
225
+ "type": "string"
226
+ },
227
+ {
228
+ "default": "",
229
+ "description": "Scratch: personId of the consult currently in flight.",
230
+ "name": "personId",
231
+ "synonyms": "current person",
232
+ "type": "string"
233
+ },
234
+ {
235
+ "default": "",
236
+ "description": "Scratch: effective event key of the consult currently in flight (payload eventKey, or the configured eventKey when the payload is blank).",
237
+ "name": "eventKey",
238
+ "synonyms": "current event key",
239
+ "type": "string"
240
+ },
241
+ {
242
+ "default": "",
243
+ "description": "Scratch: resolved channel for the current consult.",
244
+ "name": "channel",
245
+ "synonyms": "resolved channel",
246
+ "type": "string"
247
+ },
248
+ {
249
+ "default": "",
250
+ "description": "Scratch: resolved delivery mode for the current consult.",
251
+ "name": "mode",
252
+ "synonyms": "resolved mode",
253
+ "type": "string"
254
+ },
255
+ {
256
+ "default": "",
257
+ "description": "Scratch: quiet-hours window of the matched row for the current consult; blank = none.",
258
+ "name": "quietHours",
259
+ "synonyms": "resolved quiet hours",
260
+ "type": "string"
261
+ }
262
+ ],
263
+ "id": "ent_01M2HEX5N2Y7H9B3PH0ZSSH9QR",
264
+ "name": "GateView",
265
+ "persistence": "runtime"
266
+ }
267
+ ],
268
+ "entity": {
269
+ "collection": "notification_preferences",
270
+ "fields": [
271
+ {
272
+ "name": "id",
273
+ "required": true,
274
+ "type": "string"
275
+ },
276
+ {
277
+ "description": "The person this preference row belongs to.",
278
+ "name": "personId",
279
+ "required": true,
280
+ "synonyms": "user, recipient, owner, account",
281
+ "type": "string"
282
+ },
283
+ {
284
+ "description": "Event key this preference applies to (matches a notify listener's eventKey); blank = all events.",
285
+ "name": "eventKey",
286
+ "required": true,
287
+ "synonyms": "event, trigger, topic, subscription",
288
+ "type": "string"
289
+ },
290
+ {
291
+ "default": "in_app",
292
+ "description": "Delivery channel override for this person.",
293
+ "name": "channel",
294
+ "synonyms": "preferred channel, delivery method",
295
+ "type": "string",
296
+ "values": [
297
+ "in_app",
298
+ "email",
299
+ "push",
300
+ "slack"
301
+ ]
302
+ },
303
+ {
304
+ "default": "instant",
305
+ "description": "Delivery mode: instant (default) or digest (deferred to a batch cycle).",
306
+ "name": "mode",
307
+ "synonyms": "delivery mode, frequency, cadence, defer",
308
+ "type": "string",
309
+ "values": [
310
+ "instant",
311
+ "digest"
312
+ ]
313
+ },
314
+ {
315
+ "default": "",
316
+ "description": "Quiet-hours window as \"HH:MM-HH:MM\" (e.g. 22:00-07:00); blank or equal start/end = disabled.",
317
+ "name": "quietHours",
318
+ "synonyms": "do not disturb, quiet window, night mode",
319
+ "type": "string"
320
+ },
321
+ {
322
+ "default": 0.0,
323
+ "description": "Timestamp indicating when this preference row was created.",
324
+ "name": "createdAt",
325
+ "synonyms": "creation time, created",
326
+ "type": "number"
327
+ },
328
+ {
329
+ "default": 0.0,
330
+ "description": "Timestamp indicating when this preference row was last updated.",
331
+ "name": "updatedAt",
332
+ "synonyms": "modified, last updated",
333
+ "type": "number"
334
+ }
335
+ ],
336
+ "id": "ent_01M2HEX5N29SFAW1SYFN346B12",
337
+ "name": "NotificationPreference",
338
+ "persistence": "persistent"
339
+ },
340
+ "id": "orb_01M2HEX5N2DRQ9NPHZKE4R9DBJ",
341
+ "name": "NotificationPreferencesOrbital",
342
+ "pages": [
343
+ {
344
+ "id": "pag_01M2HEX5N34514K7WAZHT6K9WP",
345
+ "name": "NotificationPreferencesPage",
346
+ "path": "/notification-preferences",
347
+ "traits": [
348
+ {
349
+ "ref": "PreferencesManage",
350
+ "refId": "trt_01M2HEX5N2M0FS7QBQECCJBK9X"
351
+ },
352
+ {
353
+ "ref": "PreferenceCreate",
354
+ "refId": "trt_01M2J1EARYFYA9YZM5WFH8DZZK"
355
+ },
356
+ {
357
+ "ref": "PreferenceEdit",
358
+ "refId": "trt_01M2J1EARYVZKT8FP35Z1B5C4Q"
359
+ },
360
+ {
361
+ "ref": "PreferenceGate",
362
+ "refId": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6"
363
+ }
364
+ ]
365
+ }
366
+ ],
367
+ "traits": [
368
+ {
369
+ "category": "interaction",
370
+ "config": {
371
+ "tableLook": {
372
+ "default": "dense",
373
+ "description": "Layer 2 visual treatment for the preference data table rendered by this atom.",
374
+ "label": "Table look",
375
+ "tier": "presentation",
376
+ "type": "string",
377
+ "values": [
378
+ "dense",
379
+ "spacious",
380
+ "striped",
381
+ "borderless",
382
+ "card-rows"
383
+ ]
384
+ },
385
+ "title": {
386
+ "default": "Notification preferences",
387
+ "description": "Heading shown above the preference list",
388
+ "label": "Section title",
389
+ "tier": "presentation",
390
+ "type": "string"
391
+ }
392
+ },
393
+ "effectRow": [
394
+ {
395
+ "kind": "fetch",
396
+ "resource": "NotificationPreference"
397
+ },
398
+ {
399
+ "kind": "persist",
400
+ "resource": "NotificationPreference"
401
+ },
402
+ {
403
+ "kind": "render-ui",
404
+ "resource": "main"
405
+ },
406
+ {
407
+ "kind": "render-ui",
408
+ "resource": "toast"
409
+ }
410
+ ],
411
+ "emits": [
412
+ {
413
+ "description": "Opens the blank preference modal.",
414
+ "event": "CREATE",
415
+ "eventId": "evt_01M2J1EARYVZMZ0NNS1CZND3GK",
416
+ "synonyms": "add, new, insert",
417
+ "tier": "domain"
418
+ },
419
+ {
420
+ "description": "Opens a preference row in the edit modal.",
421
+ "event": "EDIT",
422
+ "eventId": "evt_01M2HEX5N2Y4V8B010WJDPPY13",
423
+ "payloadSchema": [
424
+ {
425
+ "name": "id",
426
+ "required": true,
427
+ "type": "string"
428
+ },
429
+ {
430
+ "entity": "NotificationPreference",
431
+ "name": "row",
432
+ "properties": [
433
+ {
434
+ "name": "id",
435
+ "required": true,
436
+ "type": "string"
437
+ },
438
+ {
439
+ "name": "personId",
440
+ "required": true,
441
+ "type": "string"
442
+ },
443
+ {
444
+ "name": "eventKey",
445
+ "required": true,
446
+ "type": "string"
447
+ },
448
+ {
449
+ "name": "channel",
450
+ "type": "string"
451
+ },
452
+ {
453
+ "name": "mode",
454
+ "type": "string"
455
+ },
456
+ {
457
+ "name": "quietHours",
458
+ "type": "string"
459
+ },
460
+ {
461
+ "name": "createdAt",
462
+ "type": "number"
463
+ },
464
+ {
465
+ "name": "updatedAt",
466
+ "type": "number"
467
+ }
468
+ ],
469
+ "type": "object"
470
+ }
471
+ ],
472
+ "synonyms": "modify, update, change",
473
+ "tier": "domain"
474
+ },
475
+ {
476
+ "description": "Removes a preference row.",
477
+ "event": "DELETE",
478
+ "eventId": "evt_01M2HEX5N2PYWA1JGBVPEV3YYY",
479
+ "payloadSchema": [
480
+ {
481
+ "name": "id",
482
+ "required": true,
483
+ "type": "string"
484
+ },
485
+ {
486
+ "entity": "NotificationPreference",
487
+ "name": "row",
488
+ "properties": [
489
+ {
490
+ "name": "id",
491
+ "required": true,
492
+ "type": "string"
493
+ },
494
+ {
495
+ "name": "personId",
496
+ "required": true,
497
+ "type": "string"
498
+ },
499
+ {
500
+ "name": "eventKey",
501
+ "required": true,
502
+ "type": "string"
503
+ },
504
+ {
505
+ "name": "channel",
506
+ "type": "string"
507
+ },
508
+ {
509
+ "name": "mode",
510
+ "type": "string"
511
+ },
512
+ {
513
+ "name": "quietHours",
514
+ "type": "string"
515
+ },
516
+ {
517
+ "name": "createdAt",
518
+ "type": "number"
519
+ },
520
+ {
521
+ "name": "updatedAt",
522
+ "type": "number"
523
+ }
524
+ ],
525
+ "type": "object"
526
+ }
527
+ ],
528
+ "synonyms": "remove, discard, clear",
529
+ "tier": "domain"
530
+ },
531
+ {
532
+ "description": "The preference collection finished loading.",
533
+ "event": "PreferencesLoaded",
534
+ "eventId": "evt_01M2HEX5N2TVADH0YB19NFRW15",
535
+ "payloadSchema": [
536
+ {
537
+ "entity": "NotificationPreference",
538
+ "name": "data",
539
+ "properties": [
540
+ {
541
+ "name": "id",
542
+ "required": true,
543
+ "type": "string"
544
+ },
545
+ {
546
+ "name": "personId",
547
+ "required": true,
548
+ "type": "string"
549
+ },
550
+ {
551
+ "name": "eventKey",
552
+ "required": true,
553
+ "type": "string"
554
+ },
555
+ {
556
+ "name": "channel",
557
+ "type": "string"
558
+ },
559
+ {
560
+ "name": "mode",
561
+ "type": "string"
562
+ },
563
+ {
564
+ "name": "quietHours",
565
+ "type": "string"
566
+ },
567
+ {
568
+ "name": "createdAt",
569
+ "type": "number"
570
+ },
571
+ {
572
+ "name": "updatedAt",
573
+ "type": "number"
574
+ }
575
+ ],
576
+ "type": "[object]"
577
+ }
578
+ ],
579
+ "synonyms": "loaded, fetched, retrieved",
580
+ "tier": "domain"
581
+ },
582
+ {
583
+ "description": "The preference collection failed to load.",
584
+ "event": "PreferencesLoadFailed",
585
+ "eventId": "evt_01M2HEX5N2CK3GB34396QDTF77",
586
+ "payloadSchema": [
587
+ {
588
+ "name": "error",
589
+ "type": "string"
590
+ },
591
+ {
592
+ "name": "code",
593
+ "type": "string"
594
+ }
595
+ ],
596
+ "synonyms": "error, failure, load error",
597
+ "tier": "internal"
598
+ },
599
+ {
600
+ "description": "A preference row persisted (create or update).",
601
+ "event": "PreferenceSaved",
602
+ "eventId": "evt_01M2HEX5N2ZPEFS633G0S54KA1",
603
+ "payloadSchema": [
604
+ {
605
+ "name": "id",
606
+ "required": true,
607
+ "type": "string"
608
+ }
609
+ ],
610
+ "synonyms": "created, updated, persisted",
611
+ "tier": "domain"
612
+ },
613
+ {
614
+ "description": "A preference persist failed.",
615
+ "event": "PreferenceSaveFailed",
616
+ "eventId": "evt_01M2HEX5N285MJJBPVPTC5CC31",
617
+ "payloadSchema": [
618
+ {
619
+ "name": "error",
620
+ "type": "string"
621
+ },
622
+ {
623
+ "name": "code",
624
+ "type": "string"
625
+ }
626
+ ],
627
+ "synonyms": "failed, error, unsuccessful",
628
+ "tier": "internal"
629
+ },
630
+ {
631
+ "description": "A preference row was deleted.",
632
+ "event": "PreferenceDeleted",
633
+ "eventId": "evt_01M2HEX5N2BXMHCTQZSM2CZ8EF",
634
+ "payloadSchema": [
635
+ {
636
+ "name": "id",
637
+ "required": true,
638
+ "type": "string"
639
+ }
640
+ ],
641
+ "synonyms": "removed, purged, discarded",
642
+ "tier": "domain"
643
+ }
644
+ ],
645
+ "entityRefIds": {
646
+ "NotificationPreference": "ent_01M2HEX5N29SFAW1SYFN346B12"
647
+ },
648
+ "id": "trt_01M2HEX5N2M0FS7QBQECCJBK9X",
649
+ "linkedEntity": "NotificationPreference",
650
+ "linkedEntityId": "ent_01M2HEX5N29SFAW1SYFN346B12",
651
+ "listens": [
652
+ {
653
+ "event": "PREFERENCE_CREATED",
654
+ "source": {
655
+ "kind": "trait",
656
+ "trait": "PreferenceCreate",
657
+ "traitId": "trt_01M2J1EARYFYA9YZM5WFH8DZZK"
658
+ },
659
+ "triggers": "DO_CREATE",
660
+ "triggersId": "evt_01M2J1EARYX2SMTRQ0MQ8WFJHS"
661
+ },
662
+ {
663
+ "event": "PREFERENCE_UPDATED",
664
+ "source": {
665
+ "kind": "trait",
666
+ "trait": "PreferenceEdit",
667
+ "traitId": "trt_01M2J1EARYVZKT8FP35Z1B5C4Q"
668
+ },
669
+ "triggers": "DO_UPDATE",
670
+ "triggersId": "evt_01M2J1EARYBKD6GTS10VF710DN"
671
+ }
672
+ ],
673
+ "name": "PreferencesManage",
674
+ "scope": "collection",
675
+ "stateMachine": {
676
+ "events": [
677
+ {
678
+ "id": "evt_01M2HEX5N2WPK2RGK1VGFNP6MP",
679
+ "key": "INIT",
680
+ "name": "Initialize"
681
+ },
682
+ {
683
+ "description": "The preference collection finished loading.",
684
+ "id": "evt_01M2HEX5N2TVADH0YB19NFRW15",
685
+ "key": "PreferencesLoaded",
686
+ "name": "Preferences loaded",
687
+ "payloadSchema": [
688
+ {
689
+ "entity": "NotificationPreference",
690
+ "name": "data",
691
+ "properties": [
692
+ {
693
+ "name": "id",
694
+ "required": true,
695
+ "type": "string"
696
+ },
697
+ {
698
+ "name": "personId",
699
+ "required": true,
700
+ "type": "string"
701
+ },
702
+ {
703
+ "name": "eventKey",
704
+ "required": true,
705
+ "type": "string"
706
+ },
707
+ {
708
+ "name": "channel",
709
+ "type": "string"
710
+ },
711
+ {
712
+ "name": "mode",
713
+ "type": "string"
714
+ },
715
+ {
716
+ "name": "quietHours",
717
+ "type": "string"
718
+ },
719
+ {
720
+ "name": "createdAt",
721
+ "type": "number"
722
+ },
723
+ {
724
+ "name": "updatedAt",
725
+ "type": "number"
726
+ }
727
+ ],
728
+ "type": "[object]"
729
+ }
730
+ ],
731
+ "synonyms": "loaded, fetched, retrieved",
732
+ "tier": "domain"
733
+ },
734
+ {
735
+ "description": "The preference collection failed to load.",
736
+ "id": "evt_01M2HEX5N2CK3GB34396QDTF77",
737
+ "key": "PreferencesLoadFailed",
738
+ "name": "Preferences load failed",
739
+ "payloadSchema": [
740
+ {
741
+ "name": "error",
742
+ "type": "string"
743
+ },
744
+ {
745
+ "name": "code",
746
+ "type": "string"
747
+ }
748
+ ],
749
+ "synonyms": "error, failure, load error",
750
+ "tier": "internal"
751
+ },
752
+ {
753
+ "description": "Removes a preference row.",
754
+ "id": "evt_01M2HEX5N2PYWA1JGBVPEV3YYY",
755
+ "key": "DELETE",
756
+ "name": "Delete",
757
+ "payloadSchema": [
758
+ {
759
+ "name": "id",
760
+ "required": true,
761
+ "type": "string"
762
+ },
763
+ {
764
+ "entity": "NotificationPreference",
765
+ "name": "row",
766
+ "properties": [
767
+ {
768
+ "name": "id",
769
+ "required": true,
770
+ "type": "string"
771
+ },
772
+ {
773
+ "name": "personId",
774
+ "required": true,
775
+ "type": "string"
776
+ },
777
+ {
778
+ "name": "eventKey",
779
+ "required": true,
780
+ "type": "string"
781
+ },
782
+ {
783
+ "name": "channel",
784
+ "type": "string"
785
+ },
786
+ {
787
+ "name": "mode",
788
+ "type": "string"
789
+ },
790
+ {
791
+ "name": "quietHours",
792
+ "type": "string"
793
+ },
794
+ {
795
+ "name": "createdAt",
796
+ "type": "number"
797
+ },
798
+ {
799
+ "name": "updatedAt",
800
+ "type": "number"
801
+ }
802
+ ],
803
+ "type": "object"
804
+ }
805
+ ],
806
+ "synonyms": "remove, discard, clear",
807
+ "tier": "domain"
808
+ },
809
+ {
810
+ "description": "Create persist requested; the modal's SAVE payload carries the full form row.",
811
+ "id": "evt_01M2J1EARYX2SMTRQ0MQ8WFJHS",
812
+ "key": "DO_CREATE",
813
+ "name": "Do Create",
814
+ "payloadSchema": [
815
+ {
816
+ "entity": "NotificationPreference",
817
+ "name": "data",
818
+ "properties": [
819
+ {
820
+ "name": "id",
821
+ "required": true,
822
+ "type": "string"
823
+ },
824
+ {
825
+ "name": "personId",
826
+ "required": true,
827
+ "type": "string"
828
+ },
829
+ {
830
+ "name": "eventKey",
831
+ "required": true,
832
+ "type": "string"
833
+ },
834
+ {
835
+ "name": "channel",
836
+ "type": "string"
837
+ },
838
+ {
839
+ "name": "mode",
840
+ "type": "string"
841
+ },
842
+ {
843
+ "name": "quietHours",
844
+ "type": "string"
845
+ },
846
+ {
847
+ "name": "createdAt",
848
+ "type": "number"
849
+ },
850
+ {
851
+ "name": "updatedAt",
852
+ "type": "number"
853
+ }
854
+ ],
855
+ "required": true,
856
+ "type": "object"
857
+ }
858
+ ],
859
+ "synonyms": "add, new, insert",
860
+ "tier": "internal"
861
+ },
862
+ {
863
+ "description": "Update persist requested; the modal's SAVE payload carries the full form row.",
864
+ "id": "evt_01M2J1EARYBKD6GTS10VF710DN",
865
+ "key": "DO_UPDATE",
866
+ "name": "Do Update",
867
+ "payloadSchema": [
868
+ {
869
+ "entity": "NotificationPreference",
870
+ "name": "data",
871
+ "properties": [
872
+ {
873
+ "name": "id",
874
+ "required": true,
875
+ "type": "string"
876
+ },
877
+ {
878
+ "name": "personId",
879
+ "required": true,
880
+ "type": "string"
881
+ },
882
+ {
883
+ "name": "eventKey",
884
+ "required": true,
885
+ "type": "string"
886
+ },
887
+ {
888
+ "name": "channel",
889
+ "type": "string"
890
+ },
891
+ {
892
+ "name": "mode",
893
+ "type": "string"
894
+ },
895
+ {
896
+ "name": "quietHours",
897
+ "type": "string"
898
+ },
899
+ {
900
+ "name": "createdAt",
901
+ "type": "number"
902
+ },
903
+ {
904
+ "name": "updatedAt",
905
+ "type": "number"
906
+ }
907
+ ],
908
+ "required": true,
909
+ "type": "object"
910
+ }
911
+ ],
912
+ "synonyms": "modified, changed, refreshed",
913
+ "tier": "internal"
914
+ },
915
+ {
916
+ "description": "A preference row persisted (create or update).",
917
+ "id": "evt_01M2HEX5N2ZPEFS633G0S54KA1",
918
+ "key": "PreferenceSaved",
919
+ "name": "Preference saved",
920
+ "payloadSchema": [
921
+ {
922
+ "name": "id",
923
+ "required": true,
924
+ "type": "string"
925
+ }
926
+ ],
927
+ "synonyms": "created, updated, persisted",
928
+ "tier": "domain"
929
+ },
930
+ {
931
+ "description": "A preference row was deleted.",
932
+ "id": "evt_01M2HEX5N2BXMHCTQZSM2CZ8EF",
933
+ "key": "PreferenceDeleted",
934
+ "name": "Preference deleted",
935
+ "payloadSchema": [
936
+ {
937
+ "name": "id",
938
+ "required": true,
939
+ "type": "string"
940
+ }
941
+ ],
942
+ "synonyms": "removed, purged, discarded",
943
+ "tier": "domain"
944
+ },
945
+ {
946
+ "description": "A preference persist failed.",
947
+ "id": "evt_01M2HEX5N285MJJBPVPTC5CC31",
948
+ "key": "PreferenceSaveFailed",
949
+ "name": "Preference save failed",
950
+ "payloadSchema": [
951
+ {
952
+ "name": "error",
953
+ "type": "string"
954
+ },
955
+ {
956
+ "name": "code",
957
+ "type": "string"
958
+ }
959
+ ],
960
+ "synonyms": "failed, error, unsuccessful",
961
+ "tier": "internal"
962
+ },
963
+ {
964
+ "description": "Retries loading the preference collection after a failure.",
965
+ "id": "evt_01M2J1EARY3G1EG29PWVNZZYMM",
966
+ "key": "RETRY",
967
+ "name": "Retry",
968
+ "synonyms": "try again, reload",
969
+ "tier": "presentation"
970
+ },
971
+ {
972
+ "description": "Opens the blank preference modal.",
973
+ "id": "evt_01M2J1EARYVZMZ0NNS1CZND3GK",
974
+ "key": "CREATE",
975
+ "name": "Create",
976
+ "synonyms": "add, new, insert",
977
+ "tier": "domain"
978
+ },
979
+ {
980
+ "description": "Opens a preference row in the edit modal.",
981
+ "id": "evt_01M2HEX5N2Y4V8B010WJDPPY13",
982
+ "key": "EDIT",
983
+ "name": "Edit",
984
+ "payloadSchema": [
985
+ {
986
+ "name": "id",
987
+ "required": true,
988
+ "type": "string"
989
+ },
990
+ {
991
+ "entity": "NotificationPreference",
992
+ "name": "row",
993
+ "properties": [
994
+ {
995
+ "name": "id",
996
+ "required": true,
997
+ "type": "string"
998
+ },
999
+ {
1000
+ "name": "personId",
1001
+ "required": true,
1002
+ "type": "string"
1003
+ },
1004
+ {
1005
+ "name": "eventKey",
1006
+ "required": true,
1007
+ "type": "string"
1008
+ },
1009
+ {
1010
+ "name": "channel",
1011
+ "type": "string"
1012
+ },
1013
+ {
1014
+ "name": "mode",
1015
+ "type": "string"
1016
+ },
1017
+ {
1018
+ "name": "quietHours",
1019
+ "type": "string"
1020
+ },
1021
+ {
1022
+ "name": "createdAt",
1023
+ "type": "number"
1024
+ },
1025
+ {
1026
+ "name": "updatedAt",
1027
+ "type": "number"
1028
+ }
1029
+ ],
1030
+ "type": "object"
1031
+ }
1032
+ ],
1033
+ "synonyms": "modify, update, change",
1034
+ "tier": "domain"
1035
+ }
1036
+ ],
1037
+ "states": [
1038
+ {
1039
+ "isInitial": true,
1040
+ "name": "loading"
1041
+ },
1042
+ {
1043
+ "name": "browsing"
1044
+ },
1045
+ {
1046
+ "name": "error"
1047
+ }
1048
+ ],
1049
+ "transitions": [
1050
+ {
1051
+ "effects": [
1052
+ [
1053
+ "fetch",
1054
+ "NotificationPreference",
1055
+ {
1056
+ "emit": {
1057
+ "failure": "PreferencesLoadFailed",
1058
+ "success": "PreferencesLoaded"
1059
+ }
1060
+ }
1061
+ ],
1062
+ [
1063
+ "render-ui",
1064
+ "main",
1065
+ {
1066
+ "align": "center",
1067
+ "children": [
1068
+ {
1069
+ "type": "spinner"
1070
+ },
1071
+ {
1072
+ "color": "muted",
1073
+ "content": "Loading notification preferences…",
1074
+ "type": "typography",
1075
+ "variant": "caption"
1076
+ }
1077
+ ],
1078
+ "className": "py-12",
1079
+ "direction": "vertical",
1080
+ "gap": "md",
1081
+ "type": "stack"
1082
+ }
1083
+ ]
1084
+ ],
1085
+ "event": "INIT",
1086
+ "eventId": "evt_01M2HEX5N2WPK2RGK1VGFNP6MP",
1087
+ "from": "loading",
1088
+ "to": "loading"
1089
+ },
1090
+ {
1091
+ "effects": [
1092
+ [
1093
+ "render-ui",
1094
+ "main",
1095
+ {
1096
+ "children": [
1097
+ {
1098
+ "children": [
1099
+ {
1100
+ "children": [
1101
+ {
1102
+ "name": "bell",
1103
+ "size": "lg",
1104
+ "type": "icon"
1105
+ },
1106
+ {
1107
+ "content": "@config.title",
1108
+ "type": "typography",
1109
+ "variant": "h3"
1110
+ }
1111
+ ],
1112
+ "direction": "horizontal",
1113
+ "gap": "sm",
1114
+ "type": "stack"
1115
+ },
1116
+ {
1117
+ "action": "CREATE",
1118
+ "icon": "plus",
1119
+ "label": "New preference",
1120
+ "type": "button",
1121
+ "variant": "primary"
1122
+ }
1123
+ ],
1124
+ "direction": "horizontal",
1125
+ "gap": "sm",
1126
+ "justify": "between",
1127
+ "type": "stack"
1128
+ },
1129
+ {
1130
+ "type": "divider"
1131
+ },
1132
+ {
1133
+ "cols": 1.0,
1134
+ "entity": "@payload.data",
1135
+ "fields": [
1136
+ {
1137
+ "label": "Person",
1138
+ "name": "personId",
1139
+ "variant": "h4"
1140
+ },
1141
+ {
1142
+ "label": "Event",
1143
+ "name": "eventKey",
1144
+ "variant": "caption"
1145
+ },
1146
+ {
1147
+ "label": "Channel",
1148
+ "name": "channel",
1149
+ "variant": "badge"
1150
+ },
1151
+ {
1152
+ "label": "Mode",
1153
+ "name": "mode",
1154
+ "variant": "badge"
1155
+ },
1156
+ {
1157
+ "label": "Quiet hours",
1158
+ "name": "quietHours",
1159
+ "variant": "caption"
1160
+ }
1161
+ ],
1162
+ "gap": "sm",
1163
+ "itemActions": [
1164
+ {
1165
+ "event": "EDIT",
1166
+ "icon": "pencil",
1167
+ "label": "Edit",
1168
+ "variant": "secondary"
1169
+ },
1170
+ {
1171
+ "event": "DELETE",
1172
+ "icon": "trash-2",
1173
+ "label": "Delete",
1174
+ "variant": "danger"
1175
+ }
1176
+ ],
1177
+ "look": "@config.tableLook",
1178
+ "type": "data-grid"
1179
+ }
1180
+ ],
1181
+ "direction": "vertical",
1182
+ "gap": "md",
1183
+ "type": "stack"
1184
+ }
1185
+ ]
1186
+ ],
1187
+ "event": "PreferencesLoaded",
1188
+ "eventId": "evt_01M2HEX5N2TVADH0YB19NFRW15",
1189
+ "from": "loading",
1190
+ "to": "browsing"
1191
+ },
1192
+ {
1193
+ "effects": [
1194
+ [
1195
+ "render-ui",
1196
+ "main",
1197
+ {
1198
+ "align": "center",
1199
+ "children": [
1200
+ {
1201
+ "message": "@payload.error",
1202
+ "type": "alert",
1203
+ "variant": "error"
1204
+ },
1205
+ {
1206
+ "action": "RETRY",
1207
+ "icon": "rotate-ccw",
1208
+ "label": "Retry",
1209
+ "type": "button",
1210
+ "variant": "primary"
1211
+ }
1212
+ ],
1213
+ "className": "py-12",
1214
+ "direction": "vertical",
1215
+ "gap": "md",
1216
+ "type": "stack"
1217
+ }
1218
+ ]
1219
+ ],
1220
+ "event": "PreferencesLoadFailed",
1221
+ "eventId": "evt_01M2HEX5N2CK3GB34396QDTF77",
1222
+ "from": "loading",
1223
+ "to": "error"
1224
+ },
1225
+ {
1226
+ "effects": [
1227
+ [
1228
+ "fetch",
1229
+ "NotificationPreference",
1230
+ {
1231
+ "emit": {
1232
+ "failure": "PreferencesLoadFailed",
1233
+ "success": "PreferencesLoaded"
1234
+ }
1235
+ }
1236
+ ],
1237
+ [
1238
+ "render-ui",
1239
+ "main",
1240
+ {
1241
+ "size": "sm",
1242
+ "type": "spinner"
1243
+ }
1244
+ ]
1245
+ ],
1246
+ "event": "INIT",
1247
+ "eventId": "evt_01M2HEX5N2WPK2RGK1VGFNP6MP",
1248
+ "from": "browsing",
1249
+ "to": "loading"
1250
+ },
1251
+ {
1252
+ "effects": [
1253
+ [
1254
+ "persist",
1255
+ "delete",
1256
+ "NotificationPreference",
1257
+ "@payload.id",
1258
+ {
1259
+ "emit": {
1260
+ "failure": "PreferenceSaveFailed",
1261
+ "success": "PreferenceDeleted"
1262
+ }
1263
+ }
1264
+ ]
1265
+ ],
1266
+ "event": "DELETE",
1267
+ "eventId": "evt_01M2HEX5N2PYWA1JGBVPEV3YYY",
1268
+ "from": "browsing",
1269
+ "to": "browsing"
1270
+ },
1271
+ {
1272
+ "effects": [
1273
+ [
1274
+ "persist",
1275
+ "create",
1276
+ "NotificationPreference",
1277
+ "@payload.data",
1278
+ {
1279
+ "emit": {
1280
+ "failure": "PreferenceSaveFailed",
1281
+ "success": "PreferenceSaved"
1282
+ }
1283
+ }
1284
+ ]
1285
+ ],
1286
+ "event": "DO_CREATE",
1287
+ "eventId": "evt_01M2J1EARYX2SMTRQ0MQ8WFJHS",
1288
+ "from": "browsing",
1289
+ "to": "browsing"
1290
+ },
1291
+ {
1292
+ "effects": [
1293
+ [
1294
+ "persist",
1295
+ "update",
1296
+ "NotificationPreference",
1297
+ "@payload.data",
1298
+ {
1299
+ "emit": {
1300
+ "failure": "PreferenceSaveFailed",
1301
+ "success": "PreferenceSaved"
1302
+ }
1303
+ }
1304
+ ]
1305
+ ],
1306
+ "event": "DO_UPDATE",
1307
+ "eventId": "evt_01M2J1EARYBKD6GTS10VF710DN",
1308
+ "from": "browsing",
1309
+ "to": "browsing"
1310
+ },
1311
+ {
1312
+ "effects": [
1313
+ [
1314
+ "render-ui",
1315
+ "toast",
1316
+ {
1317
+ "dismissible": true,
1318
+ "message": "Notification preference saved",
1319
+ "type": "alert",
1320
+ "variant": "success"
1321
+ }
1322
+ ],
1323
+ [
1324
+ "fetch",
1325
+ "NotificationPreference",
1326
+ {
1327
+ "emit": {
1328
+ "failure": "PreferencesLoadFailed",
1329
+ "success": "PreferencesLoaded"
1330
+ }
1331
+ }
1332
+ ]
1333
+ ],
1334
+ "event": "PreferenceSaved",
1335
+ "eventId": "evt_01M2HEX5N2ZPEFS633G0S54KA1",
1336
+ "from": "browsing",
1337
+ "to": "loading"
1338
+ },
1339
+ {
1340
+ "effects": [
1341
+ [
1342
+ "render-ui",
1343
+ "toast",
1344
+ {
1345
+ "dismissible": true,
1346
+ "message": "Notification preference removed",
1347
+ "type": "alert",
1348
+ "variant": "info"
1349
+ }
1350
+ ],
1351
+ [
1352
+ "fetch",
1353
+ "NotificationPreference",
1354
+ {
1355
+ "emit": {
1356
+ "failure": "PreferencesLoadFailed",
1357
+ "success": "PreferencesLoaded"
1358
+ }
1359
+ }
1360
+ ]
1361
+ ],
1362
+ "event": "PreferenceDeleted",
1363
+ "eventId": "evt_01M2HEX5N2BXMHCTQZSM2CZ8EF",
1364
+ "from": "browsing",
1365
+ "to": "loading"
1366
+ },
1367
+ {
1368
+ "effects": [
1369
+ [
1370
+ "render-ui",
1371
+ "toast",
1372
+ {
1373
+ "dismissible": true,
1374
+ "message": "Could not save the notification preference",
1375
+ "type": "alert",
1376
+ "variant": "warning"
1377
+ }
1378
+ ]
1379
+ ],
1380
+ "event": "PreferenceSaveFailed",
1381
+ "eventId": "evt_01M2HEX5N285MJJBPVPTC5CC31",
1382
+ "from": "browsing",
1383
+ "to": "browsing"
1384
+ },
1385
+ {
1386
+ "effects": [
1387
+ [
1388
+ "render-ui",
1389
+ "main",
1390
+ {
1391
+ "align": "center",
1392
+ "children": [
1393
+ {
1394
+ "message": "@payload.error",
1395
+ "type": "alert",
1396
+ "variant": "error"
1397
+ },
1398
+ {
1399
+ "action": "RETRY",
1400
+ "icon": "rotate-ccw",
1401
+ "label": "Retry",
1402
+ "type": "button",
1403
+ "variant": "primary"
1404
+ }
1405
+ ],
1406
+ "className": "py-12",
1407
+ "direction": "vertical",
1408
+ "gap": "md",
1409
+ "type": "stack"
1410
+ }
1411
+ ]
1412
+ ],
1413
+ "event": "PreferencesLoadFailed",
1414
+ "eventId": "evt_01M2HEX5N2CK3GB34396QDTF77",
1415
+ "from": "browsing",
1416
+ "to": "error"
1417
+ },
1418
+ {
1419
+ "effects": [
1420
+ [
1421
+ "fetch",
1422
+ "NotificationPreference",
1423
+ {
1424
+ "emit": {
1425
+ "failure": "PreferencesLoadFailed",
1426
+ "success": "PreferencesLoaded"
1427
+ }
1428
+ }
1429
+ ],
1430
+ [
1431
+ "render-ui",
1432
+ "main",
1433
+ {
1434
+ "size": "sm",
1435
+ "type": "spinner"
1436
+ }
1437
+ ]
1438
+ ],
1439
+ "event": "INIT",
1440
+ "eventId": "evt_01M2HEX5N2WPK2RGK1VGFNP6MP",
1441
+ "from": "error",
1442
+ "to": "loading"
1443
+ },
1444
+ {
1445
+ "effects": [
1446
+ [
1447
+ "fetch",
1448
+ "NotificationPreference",
1449
+ {
1450
+ "emit": {
1451
+ "failure": "PreferencesLoadFailed",
1452
+ "success": "PreferencesLoaded"
1453
+ }
1454
+ }
1455
+ ],
1456
+ [
1457
+ "render-ui",
1458
+ "main",
1459
+ {
1460
+ "size": "sm",
1461
+ "type": "spinner"
1462
+ }
1463
+ ]
1464
+ ],
1465
+ "event": "RETRY",
1466
+ "eventId": "evt_01M2J1EARY3G1EG29PWVNZZYMM",
1467
+ "from": "error",
1468
+ "to": "loading"
1469
+ }
1470
+ ]
1471
+ }
1472
+ },
1473
+ {
1474
+ "config": {
1475
+ "fields": {
1476
+ "default": [
1477
+ "personId",
1478
+ "eventKey",
1479
+ "channel",
1480
+ "mode",
1481
+ "quietHours"
1482
+ ],
1483
+ "type": "unknown"
1484
+ },
1485
+ "icon": {
1486
+ "default": "plus-circle",
1487
+ "type": "unknown"
1488
+ },
1489
+ "mode": {
1490
+ "default": "create",
1491
+ "type": "unknown"
1492
+ },
1493
+ "title": {
1494
+ "default": "New notification preference",
1495
+ "type": "unknown"
1496
+ }
1497
+ },
1498
+ "events": {
1499
+ "OPEN": "CREATE",
1500
+ "SAVE": "PREFERENCE_CREATED"
1501
+ },
1502
+ "id": "trt_01M2J1EARYFYA9YZM5WFH8DZZK",
1503
+ "linkedEntity": "NotificationPreference",
1504
+ "linkedEntityId": "ent_01M2HEX5N29SFAW1SYFN346B12",
1505
+ "listens": [
1506
+ {
1507
+ "event": "CREATE",
1508
+ "source": {
1509
+ "kind": "trait",
1510
+ "trait": "PreferencesManage"
1511
+ },
1512
+ "triggers": "CREATE"
1513
+ }
1514
+ ],
1515
+ "name": "PreferenceCreate",
1516
+ "ref": "Modal.traits.ModalRecordModal"
1517
+ },
1518
+ {
1519
+ "config": {
1520
+ "fields": {
1521
+ "default": [
1522
+ "personId",
1523
+ "eventKey",
1524
+ "channel",
1525
+ "mode",
1526
+ "quietHours"
1527
+ ],
1528
+ "type": "unknown"
1529
+ },
1530
+ "icon": {
1531
+ "default": "pencil",
1532
+ "type": "unknown"
1533
+ },
1534
+ "mode": {
1535
+ "default": "edit",
1536
+ "type": "unknown"
1537
+ },
1538
+ "title": {
1539
+ "default": "Edit notification preference",
1540
+ "type": "unknown"
1541
+ }
1542
+ },
1543
+ "events": {
1544
+ "OPEN": "EDIT",
1545
+ "SAVE": "PREFERENCE_UPDATED"
1546
+ },
1547
+ "id": "trt_01M2J1EARYVZKT8FP35Z1B5C4Q",
1548
+ "linkedEntity": "NotificationPreference",
1549
+ "linkedEntityId": "ent_01M2HEX5N29SFAW1SYFN346B12",
1550
+ "listens": [
1551
+ {
1552
+ "event": "EDIT",
1553
+ "source": {
1554
+ "kind": "trait",
1555
+ "trait": "PreferencesManage"
1556
+ },
1557
+ "triggers": "EDIT"
1558
+ }
1559
+ ],
1560
+ "name": "PreferenceEdit",
1561
+ "ref": "Modal.traits.ModalRecordModal"
1562
+ },
1563
+ {
1564
+ "category": "lifecycle",
1565
+ "config": {
1566
+ "eventKey": {
1567
+ "default": "",
1568
+ "description": "Stable key naming the event this gate checks preferences for (e.g. 'BudgetThreshold' — the std-finance-tracker NotifyOnEventListener convention). A blank CHECK_PREFERENCE payload eventKey falls back to this value. Preference rows whose eventKey is blank apply to every event.",
1569
+ "label": "Event key",
1570
+ "synonyms": "preference key, event name, subscription key, notification topic",
1571
+ "tier": "policy",
1572
+ "type": "string"
1573
+ }
1574
+ },
1575
+ "effectRow": [
1576
+ {
1577
+ "kind": "emit",
1578
+ "resource": "PREFERENCE_RESOLVED"
1579
+ },
1580
+ {
1581
+ "kind": "fetch",
1582
+ "resource": "NotificationPreference"
1583
+ },
1584
+ {
1585
+ "kind": "render-ui",
1586
+ "resource": "toast"
1587
+ },
1588
+ {
1589
+ "kind": "set",
1590
+ "resource": "@entity.channel"
1591
+ },
1592
+ {
1593
+ "kind": "set",
1594
+ "resource": "@entity.eventKey"
1595
+ },
1596
+ {
1597
+ "kind": "set",
1598
+ "resource": "@entity.mode"
1599
+ },
1600
+ {
1601
+ "kind": "set",
1602
+ "resource": "@entity.personId"
1603
+ },
1604
+ {
1605
+ "kind": "set",
1606
+ "resource": "@entity.quietHours"
1607
+ }
1608
+ ],
1609
+ "emits": [
1610
+ {
1611
+ "description": "The gate's verdict for a CHECK_PREFERENCE consult: resolved channel and mode, and whether quiet hours suppress delivery right now. Fail-open: no row or failed lookup = { channel: in_app, mode: instant, suppressed: false }.",
1612
+ "event": "PREFERENCE_RESOLVED",
1613
+ "eventId": "evt_01M2HEX5N2NRGS7RER3F5EVBEY",
1614
+ "payloadSchema": [
1615
+ {
1616
+ "name": "personId",
1617
+ "type": "string"
1618
+ },
1619
+ {
1620
+ "name": "eventKey",
1621
+ "type": "string"
1622
+ },
1623
+ {
1624
+ "name": "channel",
1625
+ "type": "string"
1626
+ },
1627
+ {
1628
+ "name": "mode",
1629
+ "type": "string"
1630
+ },
1631
+ {
1632
+ "name": "suppressed",
1633
+ "type": "boolean"
1634
+ }
1635
+ ],
1636
+ "scope": "external",
1637
+ "synonyms": "verdict, preference answer, gate result, resolved preference",
1638
+ "tier": "domain"
1639
+ },
1640
+ {
1641
+ "description": "NotificationPreference rows loaded; the arm filters to the (personId, eventKey) match and resolves the verdict",
1642
+ "event": "PREFERENCE_ROWS_LOADED",
1643
+ "eventId": "evt_01M2HEX5N2J0G7WR4H4MF89J1K",
1644
+ "payloadSchema": [
1645
+ {
1646
+ "entity": "NotificationPreference",
1647
+ "name": "data",
1648
+ "properties": [
1649
+ {
1650
+ "name": "id",
1651
+ "required": true,
1652
+ "type": "string"
1653
+ },
1654
+ {
1655
+ "name": "personId",
1656
+ "required": true,
1657
+ "type": "string"
1658
+ },
1659
+ {
1660
+ "name": "eventKey",
1661
+ "required": true,
1662
+ "type": "string"
1663
+ },
1664
+ {
1665
+ "name": "channel",
1666
+ "type": "string"
1667
+ },
1668
+ {
1669
+ "name": "mode",
1670
+ "type": "string"
1671
+ },
1672
+ {
1673
+ "name": "quietHours",
1674
+ "type": "string"
1675
+ },
1676
+ {
1677
+ "name": "createdAt",
1678
+ "type": "number"
1679
+ },
1680
+ {
1681
+ "name": "updatedAt",
1682
+ "type": "number"
1683
+ }
1684
+ ],
1685
+ "type": "[object]"
1686
+ }
1687
+ ],
1688
+ "tier": "internal"
1689
+ },
1690
+ {
1691
+ "description": "The preference fetch failed — the arm emits the fail-open verdict",
1692
+ "event": "PREFERENCE_CHECK_FAILED",
1693
+ "eventId": "evt_01M2HEX5N246QSGGDXMFT09QJ6",
1694
+ "payloadSchema": [
1695
+ {
1696
+ "name": "error",
1697
+ "required": true,
1698
+ "type": "string"
1699
+ }
1700
+ ],
1701
+ "tier": "internal"
1702
+ }
1703
+ ],
1704
+ "entityRefIds": {
1705
+ "GateView": "ent_01M2HEX5N2Y7H9B3PH0ZSSH9QR",
1706
+ "NotificationPreference": "ent_01M2HEX5N29SFAW1SYFN346B12"
1707
+ },
1708
+ "id": "trt_01M2HEX5N2Q3KM3X5DEBAS6RV6",
1709
+ "linkedEntity": "GateView",
1710
+ "linkedEntityId": "ent_01M2HEX5N2Y7H9B3PH0ZSSH9QR",
1711
+ "name": "PreferenceGate",
1712
+ "scope": "instance",
1713
+ "stateMachine": {
1714
+ "events": [
1715
+ {
1716
+ "description": "Consult the gate for a person's effective notification preference.",
1717
+ "id": "evt_01M2HEX5N2C20G8DKMNNETXXV8",
1718
+ "key": "CHECK_PREFERENCE",
1719
+ "name": "Check Preference",
1720
+ "payloadSchema": [
1721
+ {
1722
+ "name": "personId",
1723
+ "type": "string"
1724
+ },
1725
+ {
1726
+ "name": "eventKey",
1727
+ "type": "string"
1728
+ }
1729
+ ],
1730
+ "synonyms": "check preference, resolve preference, should notify, gate notification",
1731
+ "tier": "domain"
1732
+ },
1733
+ {
1734
+ "description": "NotificationPreference rows loaded; the arm filters to the (personId, eventKey) match and resolves the verdict",
1735
+ "id": "evt_01M2HEX5N2J0G7WR4H4MF89J1K",
1736
+ "key": "PREFERENCE_ROWS_LOADED",
1737
+ "name": "Preference Rows Loaded",
1738
+ "payloadSchema": [
1739
+ {
1740
+ "entity": "NotificationPreference",
1741
+ "name": "data",
1742
+ "properties": [
1743
+ {
1744
+ "name": "id",
1745
+ "required": true,
1746
+ "type": "string"
1747
+ },
1748
+ {
1749
+ "name": "personId",
1750
+ "required": true,
1751
+ "type": "string"
1752
+ },
1753
+ {
1754
+ "name": "eventKey",
1755
+ "required": true,
1756
+ "type": "string"
1757
+ },
1758
+ {
1759
+ "name": "channel",
1760
+ "type": "string"
1761
+ },
1762
+ {
1763
+ "name": "mode",
1764
+ "type": "string"
1765
+ },
1766
+ {
1767
+ "name": "quietHours",
1768
+ "type": "string"
1769
+ },
1770
+ {
1771
+ "name": "createdAt",
1772
+ "type": "number"
1773
+ },
1774
+ {
1775
+ "name": "updatedAt",
1776
+ "type": "number"
1777
+ }
1778
+ ],
1779
+ "type": "[object]"
1780
+ }
1781
+ ],
1782
+ "tier": "internal"
1783
+ },
1784
+ {
1785
+ "description": "The preference fetch failed — the arm emits the fail-open verdict",
1786
+ "id": "evt_01M2HEX5N246QSGGDXMFT09QJ6",
1787
+ "key": "PREFERENCE_CHECK_FAILED",
1788
+ "name": "Preference Check Failed",
1789
+ "payloadSchema": [
1790
+ {
1791
+ "name": "error",
1792
+ "required": true,
1793
+ "type": "string"
1794
+ }
1795
+ ],
1796
+ "tier": "internal"
1797
+ },
1798
+ {
1799
+ "description": "The gate's verdict for a CHECK_PREFERENCE consult: resolved channel and mode, and whether quiet hours suppress delivery right now. Fail-open: no row or failed lookup = { channel: in_app, mode: instant, suppressed: false }.",
1800
+ "id": "evt_01M2HEX5N2NRGS7RER3F5EVBEY",
1801
+ "key": "PREFERENCE_RESOLVED",
1802
+ "name": "Preference Resolved",
1803
+ "payloadSchema": [
1804
+ {
1805
+ "name": "personId",
1806
+ "type": "string"
1807
+ },
1808
+ {
1809
+ "name": "eventKey",
1810
+ "type": "string"
1811
+ },
1812
+ {
1813
+ "name": "channel",
1814
+ "type": "string"
1815
+ },
1816
+ {
1817
+ "name": "mode",
1818
+ "type": "string"
1819
+ },
1820
+ {
1821
+ "name": "suppressed",
1822
+ "type": "boolean"
1823
+ }
1824
+ ],
1825
+ "synonyms": "verdict, preference answer, gate result, resolved preference",
1826
+ "tier": "domain"
1827
+ }
1828
+ ],
1829
+ "states": [
1830
+ {
1831
+ "isInitial": true,
1832
+ "name": "idle"
1833
+ }
1834
+ ],
1835
+ "transitions": [
1836
+ {
1837
+ "effects": [
1838
+ [
1839
+ "set",
1840
+ "@entity.personId",
1841
+ "@payload.personId"
1842
+ ],
1843
+ [
1844
+ "set",
1845
+ "@entity.eventKey",
1846
+ [
1847
+ "if",
1848
+ [
1849
+ "=",
1850
+ "@payload.eventKey",
1851
+ ""
1852
+ ],
1853
+ "@config.eventKey",
1854
+ "@payload.eventKey"
1855
+ ]
1856
+ ],
1857
+ [
1858
+ "fetch",
1859
+ "NotificationPreference",
1860
+ {
1861
+ "emit": {
1862
+ "failure": "PREFERENCE_CHECK_FAILED",
1863
+ "success": "PREFERENCE_ROWS_LOADED"
1864
+ }
1865
+ }
1866
+ ]
1867
+ ],
1868
+ "event": "CHECK_PREFERENCE",
1869
+ "eventId": "evt_01M2HEX5N2C20G8DKMNNETXXV8",
1870
+ "from": "idle",
1871
+ "to": "idle"
1872
+ },
1873
+ {
1874
+ "effects": [
1875
+ [
1876
+ "set",
1877
+ "@entity.channel",
1878
+ [
1879
+ "if",
1880
+ [
1881
+ "=",
1882
+ [
1883
+ "array/len",
1884
+ [
1885
+ "array/filter",
1886
+ "@payload.data",
1887
+ [
1888
+ "fn",
1889
+ "p",
1890
+ [
1891
+ "and",
1892
+ [
1893
+ "=",
1894
+ [
1895
+ "object/get",
1896
+ "@p",
1897
+ "personId"
1898
+ ],
1899
+ "@entity.personId"
1900
+ ],
1901
+ [
1902
+ "or",
1903
+ [
1904
+ "=",
1905
+ [
1906
+ "object/get",
1907
+ "@p",
1908
+ "eventKey"
1909
+ ],
1910
+ ""
1911
+ ],
1912
+ [
1913
+ "=",
1914
+ [
1915
+ "object/get",
1916
+ "@p",
1917
+ "eventKey"
1918
+ ],
1919
+ "@entity.eventKey"
1920
+ ]
1921
+ ]
1922
+ ]
1923
+ ]
1924
+ ]
1925
+ ],
1926
+ 0.0
1927
+ ],
1928
+ "in_app",
1929
+ [
1930
+ "object/get",
1931
+ [
1932
+ "array/first",
1933
+ [
1934
+ "array/filter",
1935
+ "@payload.data",
1936
+ [
1937
+ "fn",
1938
+ "p",
1939
+ [
1940
+ "and",
1941
+ [
1942
+ "=",
1943
+ [
1944
+ "object/get",
1945
+ "@p",
1946
+ "personId"
1947
+ ],
1948
+ "@entity.personId"
1949
+ ],
1950
+ [
1951
+ "or",
1952
+ [
1953
+ "=",
1954
+ [
1955
+ "object/get",
1956
+ "@p",
1957
+ "eventKey"
1958
+ ],
1959
+ ""
1960
+ ],
1961
+ [
1962
+ "=",
1963
+ [
1964
+ "object/get",
1965
+ "@p",
1966
+ "eventKey"
1967
+ ],
1968
+ "@entity.eventKey"
1969
+ ]
1970
+ ]
1971
+ ]
1972
+ ]
1973
+ ]
1974
+ ],
1975
+ "channel"
1976
+ ]
1977
+ ]
1978
+ ],
1979
+ [
1980
+ "set",
1981
+ "@entity.mode",
1982
+ [
1983
+ "if",
1984
+ [
1985
+ "=",
1986
+ [
1987
+ "array/len",
1988
+ [
1989
+ "array/filter",
1990
+ "@payload.data",
1991
+ [
1992
+ "fn",
1993
+ "p",
1994
+ [
1995
+ "and",
1996
+ [
1997
+ "=",
1998
+ [
1999
+ "object/get",
2000
+ "@p",
2001
+ "personId"
2002
+ ],
2003
+ "@entity.personId"
2004
+ ],
2005
+ [
2006
+ "or",
2007
+ [
2008
+ "=",
2009
+ [
2010
+ "object/get",
2011
+ "@p",
2012
+ "eventKey"
2013
+ ],
2014
+ ""
2015
+ ],
2016
+ [
2017
+ "=",
2018
+ [
2019
+ "object/get",
2020
+ "@p",
2021
+ "eventKey"
2022
+ ],
2023
+ "@entity.eventKey"
2024
+ ]
2025
+ ]
2026
+ ]
2027
+ ]
2028
+ ]
2029
+ ],
2030
+ 0.0
2031
+ ],
2032
+ "instant",
2033
+ [
2034
+ "object/get",
2035
+ [
2036
+ "array/first",
2037
+ [
2038
+ "array/filter",
2039
+ "@payload.data",
2040
+ [
2041
+ "fn",
2042
+ "p",
2043
+ [
2044
+ "and",
2045
+ [
2046
+ "=",
2047
+ [
2048
+ "object/get",
2049
+ "@p",
2050
+ "personId"
2051
+ ],
2052
+ "@entity.personId"
2053
+ ],
2054
+ [
2055
+ "or",
2056
+ [
2057
+ "=",
2058
+ [
2059
+ "object/get",
2060
+ "@p",
2061
+ "eventKey"
2062
+ ],
2063
+ ""
2064
+ ],
2065
+ [
2066
+ "=",
2067
+ [
2068
+ "object/get",
2069
+ "@p",
2070
+ "eventKey"
2071
+ ],
2072
+ "@entity.eventKey"
2073
+ ]
2074
+ ]
2075
+ ]
2076
+ ]
2077
+ ]
2078
+ ],
2079
+ "mode"
2080
+ ]
2081
+ ]
2082
+ ],
2083
+ [
2084
+ "set",
2085
+ "@entity.quietHours",
2086
+ [
2087
+ "if",
2088
+ [
2089
+ "=",
2090
+ [
2091
+ "array/len",
2092
+ [
2093
+ "array/filter",
2094
+ "@payload.data",
2095
+ [
2096
+ "fn",
2097
+ "p",
2098
+ [
2099
+ "and",
2100
+ [
2101
+ "=",
2102
+ [
2103
+ "object/get",
2104
+ "@p",
2105
+ "personId"
2106
+ ],
2107
+ "@entity.personId"
2108
+ ],
2109
+ [
2110
+ "or",
2111
+ [
2112
+ "=",
2113
+ [
2114
+ "object/get",
2115
+ "@p",
2116
+ "eventKey"
2117
+ ],
2118
+ ""
2119
+ ],
2120
+ [
2121
+ "=",
2122
+ [
2123
+ "object/get",
2124
+ "@p",
2125
+ "eventKey"
2126
+ ],
2127
+ "@entity.eventKey"
2128
+ ]
2129
+ ]
2130
+ ]
2131
+ ]
2132
+ ]
2133
+ ],
2134
+ 0.0
2135
+ ],
2136
+ "",
2137
+ [
2138
+ "object/get",
2139
+ [
2140
+ "array/first",
2141
+ [
2142
+ "array/filter",
2143
+ "@payload.data",
2144
+ [
2145
+ "fn",
2146
+ "p",
2147
+ [
2148
+ "and",
2149
+ [
2150
+ "=",
2151
+ [
2152
+ "object/get",
2153
+ "@p",
2154
+ "personId"
2155
+ ],
2156
+ "@entity.personId"
2157
+ ],
2158
+ [
2159
+ "or",
2160
+ [
2161
+ "=",
2162
+ [
2163
+ "object/get",
2164
+ "@p",
2165
+ "eventKey"
2166
+ ],
2167
+ ""
2168
+ ],
2169
+ [
2170
+ "=",
2171
+ [
2172
+ "object/get",
2173
+ "@p",
2174
+ "eventKey"
2175
+ ],
2176
+ "@entity.eventKey"
2177
+ ]
2178
+ ]
2179
+ ]
2180
+ ]
2181
+ ]
2182
+ ],
2183
+ "quietHours"
2184
+ ]
2185
+ ]
2186
+ ],
2187
+ [
2188
+ "emit",
2189
+ "PREFERENCE_RESOLVED",
2190
+ {
2191
+ "channel": "@entity.channel",
2192
+ "eventKey": "@entity.eventKey",
2193
+ "mode": "@entity.mode",
2194
+ "personId": "@entity.personId",
2195
+ "suppressed": [
2196
+ "and",
2197
+ [
2198
+ "str/includes",
2199
+ "@entity.quietHours",
2200
+ "-"
2201
+ ],
2202
+ [
2203
+ "!=",
2204
+ [
2205
+ "str/slice",
2206
+ [
2207
+ "array/first",
2208
+ [
2209
+ "str/split",
2210
+ "@entity.quietHours",
2211
+ "-"
2212
+ ]
2213
+ ],
2214
+ 0.0,
2215
+ 2.0
2216
+ ],
2217
+ [
2218
+ "str/slice",
2219
+ [
2220
+ "array/nth",
2221
+ [
2222
+ "str/split",
2223
+ "@entity.quietHours",
2224
+ "-"
2225
+ ],
2226
+ 1.0
2227
+ ],
2228
+ 0.0,
2229
+ 2.0
2230
+ ]
2231
+ ],
2232
+ [
2233
+ "if",
2234
+ [
2235
+ "<",
2236
+ [
2237
+ "str/slice",
2238
+ [
2239
+ "array/first",
2240
+ [
2241
+ "str/split",
2242
+ "@entity.quietHours",
2243
+ "-"
2244
+ ]
2245
+ ],
2246
+ 0.0,
2247
+ 2.0
2248
+ ],
2249
+ [
2250
+ "str/slice",
2251
+ [
2252
+ "array/nth",
2253
+ [
2254
+ "str/split",
2255
+ "@entity.quietHours",
2256
+ "-"
2257
+ ],
2258
+ 1.0
2259
+ ],
2260
+ 0.0,
2261
+ 2.0
2262
+ ]
2263
+ ],
2264
+ [
2265
+ "and",
2266
+ [
2267
+ ">=",
2268
+ [
2269
+ "time/hour",
2270
+ "@now"
2271
+ ],
2272
+ [
2273
+ "str/slice",
2274
+ [
2275
+ "array/first",
2276
+ [
2277
+ "str/split",
2278
+ "@entity.quietHours",
2279
+ "-"
2280
+ ]
2281
+ ],
2282
+ 0.0,
2283
+ 2.0
2284
+ ]
2285
+ ],
2286
+ [
2287
+ "<",
2288
+ [
2289
+ "time/hour",
2290
+ "@now"
2291
+ ],
2292
+ [
2293
+ "str/slice",
2294
+ [
2295
+ "array/nth",
2296
+ [
2297
+ "str/split",
2298
+ "@entity.quietHours",
2299
+ "-"
2300
+ ],
2301
+ 1.0
2302
+ ],
2303
+ 0.0,
2304
+ 2.0
2305
+ ]
2306
+ ]
2307
+ ],
2308
+ [
2309
+ "or",
2310
+ [
2311
+ ">=",
2312
+ [
2313
+ "time/hour",
2314
+ "@now"
2315
+ ],
2316
+ [
2317
+ "str/slice",
2318
+ [
2319
+ "array/first",
2320
+ [
2321
+ "str/split",
2322
+ "@entity.quietHours",
2323
+ "-"
2324
+ ]
2325
+ ],
2326
+ 0.0,
2327
+ 2.0
2328
+ ]
2329
+ ],
2330
+ [
2331
+ "<",
2332
+ [
2333
+ "time/hour",
2334
+ "@now"
2335
+ ],
2336
+ [
2337
+ "str/slice",
2338
+ [
2339
+ "array/nth",
2340
+ [
2341
+ "str/split",
2342
+ "@entity.quietHours",
2343
+ "-"
2344
+ ],
2345
+ 1.0
2346
+ ],
2347
+ 0.0,
2348
+ 2.0
2349
+ ]
2350
+ ]
2351
+ ]
2352
+ ]
2353
+ ]
2354
+ }
2355
+ ]
2356
+ ],
2357
+ "event": "PREFERENCE_ROWS_LOADED",
2358
+ "eventId": "evt_01M2HEX5N2J0G7WR4H4MF89J1K",
2359
+ "from": "idle",
2360
+ "to": "idle"
2361
+ },
2362
+ {
2363
+ "effects": [
2364
+ [
2365
+ "emit",
2366
+ "PREFERENCE_RESOLVED",
2367
+ {
2368
+ "channel": "in_app",
2369
+ "eventKey": "@entity.eventKey",
2370
+ "mode": "instant",
2371
+ "personId": "@entity.personId",
2372
+ "suppressed": false
2373
+ }
2374
+ ],
2375
+ [
2376
+ "render-ui",
2377
+ "toast",
2378
+ {
2379
+ "message": "@payload.error",
2380
+ "type": "alert",
2381
+ "variant": "error"
2382
+ }
2383
+ ]
2384
+ ],
2385
+ "event": "PREFERENCE_CHECK_FAILED",
2386
+ "eventId": "evt_01M2HEX5N246QSGGDXMFT09QJ6",
2387
+ "from": "idle",
2388
+ "to": "idle"
2389
+ }
2390
+ ]
2391
+ }
2392
+ }
2393
+ ],
2394
+ "uses": [
2395
+ {
2396
+ "as": "Modal",
2397
+ "from": "std/behaviors/std-modal"
2398
+ }
2399
+ ]
2400
+ }
2401
+ ],
2402
+ "schemaVersion": 1,
2403
+ "version": "1.0.0"
2404
+ }