@opencxh/domain 1.172.1 → 1.172.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/entities/activity/blocks.d.ts +30 -30
  2. package/dist/entities/activity/catalog.d.ts +63 -86
  3. package/dist/entities/activity/descriptor.d.ts +31 -32
  4. package/dist/entities/activity/index.d.ts +2 -2
  5. package/dist/entities/activity/preview.d.ts +7 -7
  6. package/dist/entities/activity/resolve.d.ts +37 -38
  7. package/dist/entities/activity/types.d.ts +34 -34
  8. package/dist/entities/ai-account/types.d.ts +3 -3
  9. package/dist/entities/ai-account/vendors.d.ts +25 -32
  10. package/dist/entities/ai-budget/types.d.ts +5 -5
  11. package/dist/entities/ai-conversation/types.d.ts +12 -12
  12. package/dist/entities/ai-profile/types.d.ts +14 -21
  13. package/dist/entities/ai-settings/types.d.ts +12 -13
  14. package/dist/entities/analytics/index.d.ts +4 -4
  15. package/dist/entities/analytics/source.d.ts +1 -1
  16. package/dist/entities/analytics/usage.d.ts +23 -28
  17. package/dist/entities/artifact/blocks.d.ts +54 -69
  18. package/dist/entities/artifact/markdown.d.ts +2 -3
  19. package/dist/entities/artifact/types.d.ts +46 -54
  20. package/dist/entities/assignment/types.d.ts +74 -88
  21. package/dist/entities/channel/index.d.ts +1 -1
  22. package/dist/entities/channel/signature.d.ts +8 -9
  23. package/dist/entities/communication/index.d.ts +1 -1
  24. package/dist/entities/contact/index.d.ts +1 -1
  25. package/dist/entities/custom-field-def/types.d.ts +14 -14
  26. package/dist/entities/external-identity/types.d.ts +45 -50
  27. package/dist/entities/interaction/index.d.ts +1 -1
  28. package/dist/entities/interaction/types.d.ts +44 -47
  29. package/dist/entities/live-lens/types.d.ts +39 -44
  30. package/dist/entities/mcp/types.d.ts +53 -57
  31. package/dist/entities/memory/alias.d.ts +7 -7
  32. package/dist/entities/memory/browse.d.ts +21 -21
  33. package/dist/entities/memory/ingest.d.ts +24 -28
  34. package/dist/entities/memory/item.d.ts +53 -58
  35. package/dist/entities/memory/kind.d.ts +25 -25
  36. package/dist/entities/memory/query.d.ts +49 -51
  37. package/dist/entities/playbook/actor.d.ts +17 -17
  38. package/dist/entities/playbook/assignment.d.ts +54 -63
  39. package/dist/entities/playbook/index.d.ts +2 -2
  40. package/dist/entities/playbook/labels.d.ts +4 -4
  41. package/dist/entities/playbook/trigger-vars.d.ts +14 -15
  42. package/dist/entities/playbook/types.d.ts +172 -302
  43. package/dist/entities/resource-reminder/types.d.ts +8 -9
  44. package/dist/entities/time-entry/duration.d.ts +11 -11
  45. package/dist/entities/time-entry/types.d.ts +59 -59
  46. package/dist/entities/time-entry/work-type.d.ts +21 -24
  47. package/dist/entities/topic/examples.d.ts +26 -27
  48. package/dist/entities/topic/scope.d.ts +11 -12
  49. package/dist/entities/topic/types.d.ts +26 -28
  50. package/dist/entities/user/types.d.ts +24 -28
  51. package/dist/entities/webhook/types.d.ts +6 -6
  52. package/dist/entities/work/keys.d.ts +25 -26
  53. package/dist/entities/work/ladder.d.ts +48 -52
  54. package/dist/entities/work/types.d.ts +108 -114
  55. package/dist/index.cjs +6 -6
  56. package/dist/index.d.ts +29 -28
  57. package/dist/index.js +1377 -1242
  58. package/dist/platform/account.d.ts +34 -38
  59. package/dist/platform/ai-tools.d.ts +48 -52
  60. package/dist/platform/api.d.ts +9 -10
  61. package/dist/platform/author.d.ts +7 -9
  62. package/dist/platform/capabilities.d.ts +3 -3
  63. package/dist/platform/communication.d.ts +163 -204
  64. package/dist/platform/context.d.ts +8 -8
  65. package/dist/platform/identity.d.ts +16 -19
  66. package/dist/platform/kernel.d.ts +1 -1
  67. package/dist/platform/manifest.d.ts +2 -2
  68. package/dist/platform/media.d.ts +13 -15
  69. package/dist/platform/permission.d.ts +39 -0
  70. package/dist/platform/permission.test.d.ts +1 -0
  71. package/dist/platform/presence.d.ts +30 -30
  72. package/dist/platform/provider.d.ts +14 -15
  73. package/dist/platform/resource-source.d.ts +43 -45
  74. package/dist/platform/resource.d.ts +17 -23
  75. package/dist/platform/scope.d.ts +35 -61
  76. package/dist/platform/services.d.ts +4 -4
  77. package/dist/platform/storage.d.ts +1 -1
  78. package/dist/platform/sync-source.d.ts +196 -216
  79. package/dist/platform/transcript-cadence.d.ts +37 -41
  80. package/dist/platform/ui.d.ts +6 -6
  81. package/dist/text/endpoint.d.ts +11 -27
  82. package/package.json +3 -2
@@ -1,58 +1,56 @@
1
1
  import { OwnerScope } from '../scope/types';
2
2
  /**
3
- * Work management — één entiteit voor alles wat *werk* is.
3
+ * Work management — one entity for everything that is *work*.
4
4
  *
5
- * Taak, subtaak, zaak, project, fase, deal en campagne zijn hier rijen in hetzelfde model.
6
- * Wat ze onderscheidt is configuratie, geen code: het **project** draagt de workflow, de
7
- * veldselectie en de toegang, en `typeKey` is niet meer dan een icoon met een etiket.
5
+ * Task, subtask, case, project, phase, deal and campaign are rows in the same model here. What
6
+ * distinguishes them is configuration, not code: the **project** carries the workflow, the field
7
+ * selection and the access, and `typeKey` is no more than an icon with a label.
8
8
  *
9
- * De regel waarmee dit model is afgebakend, in drie vragen:
9
+ * The rule that bounds this model, in three questions:
10
10
  *
11
- * 1. *Wie bepaalt de statusovergang?* Onze gebruikers → een `WorkItem`. Een extern systeem
12
- * (Shopify, de boekhouding) → gespiegeld door de bron-app, hier hooguit een `WorkLink`.
13
- * 2. *Eigen levensduur, of hangt het ergens aan?* Eigen → een item. Hangt eraan (uren,
14
- * notities, attributen, geheugen) → een annotatie op een `scopeKey`, nooit een rij hier.
15
- * 3. *Ander gedrag, of andere woorden?* Alleen andere woorden → een `WorkProject` met andere
16
- * statussen. Pas bij ander gedrag komt er code bij.
11
+ * 1. *Who decides the status transition?* Our users → a `WorkItem`. An external system (Shopify,
12
+ * the accounting package) → mirrored by the source app, at most a `WorkLink` here.
13
+ * 2. *Own lifetime, or does it hang off something?* Own → an item. Hangs off it (hours, notes,
14
+ * attributes, memory) → an annotation on a `scopeKey`, never a row here.
15
+ * 3. *Different behaviour, or different words?* Only different words → a `WorkProject` with other
16
+ * statuses. Code is added only for different behaviour.
17
17
  *
18
- * Test 3 is waarom "Dossier", "Project" en "Deal" geen drie entiteiten zijn.
18
+ * Test 3 is why "Case", "Project" and "Deal" are not three entities.
19
19
  */
20
20
  /**
21
- * De drie categorieën waarin elke status valt.
21
+ * The three categories every status falls into.
22
22
  *
23
- * Vast, terwijl de statusnaam per project vrij is ("Offerte", "Wacht op cliënt"). Dit is de
24
- * vraag die élke consument stelt — de lijst, de teller, de rapportage — en zou die de
25
- * projectconfiguratie moeten lezen om hem te beantwoorden, dan kon geen enkele query het
26
- * geïndexeerd doen.
23
+ * Fixed, while the status name is free per project ("Offerte", "Wacht op cliënt"). This is the
24
+ * question *every* consumer asks — the list, the counter, the reporting — and if it had to read
25
+ * the project configuration to answer it, no query could do it from an index.
27
26
  */
28
27
  export type WorkStatusCategory = "todo" | "in_progress" | "done";
29
28
  /**
30
- * Eén stap in de workflow van een project.
29
+ * One step in a project's workflow.
31
30
  *
32
- * `key` is **org-uniek en niet project-uniek**, en dat is een bewuste last op het
33
- * beheerscherm in ruil voor iets belangrijks: het item draagt alleen `statusKey`, dus
34
- * "al mijn open werk over alle projecten heen" is één `{ statusKey: anyOf(openKeys) }`.
35
- * Zouden twee projecten allebei een `done` mogen hebben met een andere categorie, dan gaf
36
- * diezelfde query stilzwijgend het verkeerde antwoord. De sleutel wordt daarom net als bij
37
- * de werksoorten uit het label geslugd en bij botsing opgehoogd.
31
+ * `key` is **org-unique and not project-unique**, a deliberate burden on the admin screen in
32
+ * exchange for something important: the item carries only `statusKey`, so "all my open work across
33
+ * every project" is one `{ statusKey: anyOf(openKeys) }`. If two projects could each have a `done`
34
+ * with a different category, that same query would silently give the wrong answer. So the key is
35
+ * slugged from the label and bumped on collision, as with the work types.
38
36
  *
39
- * `label` is vrij te hernoemen; `key` ligt vast zodra er items op staan.
37
+ * `label` is free to rename; `key` is fixed once items sit on it.
40
38
  */
41
39
  export interface WorkStatus {
42
40
  key: string;
43
41
  label: string;
44
42
  category: WorkStatusCategory;
45
43
  order: number;
46
- /** Optionele accentkleur voor de bolletjes in de lijst en het beheerscherm. */
44
+ /** Optional accent colour for the dots in the list and the admin screen. */
47
45
  color?: string;
48
46
  }
49
47
  /**
50
- * Een afloopreden: hóé iets eindigde, los van wáár het staat.
48
+ * A resolution: *how* something ended, apart from where it sits.
51
49
  *
52
- * Bewust een vrij label zonder vaste betekenis en zonder uitkomst-vlag. Een advocatenkantoor
53
- * onderscheidt "geschikt" van "vonnis", een salesteam "gewonnen" van "verloren", en geen van
54
- * beide past in een enum die wij bedenken. De prijs staat in het plan: niets kan uitrekenen
55
- * hoeveel er goed afliep. Komt die vraag, dan is een `positive?: boolean` hier de plek.
50
+ * Deliberately a free label with no fixed meaning and no outcome flag. A law firm distinguishes
51
+ * "settled" from "judgment", a sales team "won" from "lost", and neither fits an enum we invent.
52
+ * The price is in the plan: nothing can compute how much ended well. If that question comes, a
53
+ * `positive?: boolean` belongs here.
56
54
  */
57
55
  export interface WorkResolution {
58
56
  key: string;
@@ -60,58 +58,57 @@ export interface WorkResolution {
60
58
  order: number;
61
59
  }
62
60
  /**
63
- * Een project: de drager van een werkproces.
61
+ * A project: the carrier of a work process.
64
62
  *
65
- * Dit is waar Jira zijn schemes heeft en wij niet. Workflow, veldselectie en toegang hangen
66
- * rechtstreeks aan het project in plaats van aan drie koppelbare configuratieobjecten — dat
67
- * scheelt de drie schermen die je bij Jira langs moet om één status te veranderen.
63
+ * This is where Jira has its schemes and we do not. Workflow, field selection and access hang
64
+ * directly off the project instead of off three linkable configuration objects — which saves the
65
+ * three screens Jira makes you visit to change one status.
68
66
  */
69
67
  export interface WorkProject {
70
68
  id: string;
71
69
  organizationId: string;
72
70
  /**
73
- * Org-uniek, hoofdletters: `"SAL"`. Vormt het voorvoegsel van elke itemsleutel
74
- * (`SAL-142`), en ligt daarom vast zodra er items zijn — hem wijzigen zou elke sleutel
75
- * hernoemen, inclusief de exemplaren die mensen in een mail hebben geplakt.
71
+ * Org-unique, uppercase: `"SAL"`. Forms the prefix of every item key (`SAL-142`), and is
72
+ * therefore fixed once items exist — changing it would rename every key, including the ones
73
+ * people pasted into an email.
76
74
  */
77
75
  key: string;
78
76
  name: string;
79
77
  description?: string;
80
- /** Lucide-icoonnaam. */
78
+ /** Lucide icon name. */
81
79
  icon?: string;
82
80
  color?: string;
83
81
  ownerScope: OwnerScope;
84
- /** Leden bovenop `ownerScope` — wie er nog meer bij mag. */
82
+ /** Members on top of `ownerScope` — who else may reach it. */
85
83
  memberUserIds?: string[];
86
84
  memberTeamIds?: string[];
87
85
  /**
88
- * De workflow, ingebed in plaats van een eigen entiteit.
86
+ * The workflow, embedded instead of its own entity.
89
87
  *
90
- * Drie redenen. Niets bevraagt ooit een losse statusrij: elke itemvraag wordt beantwoord
91
- * door de platte `statusKey` op het item. De leesvorm is altijd "de hele ladder tegelijk",
92
- * want een lijst rendert alle labels, kleuren en volgordes. En het beheerscherm bewerkt de
93
- * ladder als één herordening — deze store kent geen transactie, dus als losse rijen zou
94
- * "sleep status 3 boven status 1" N updates worden die half kunnen landen en twee
95
- * statussen op dezelfde `order` achterlaten. Als array is het één `$set`.
88
+ * Three reasons. Nothing ever queries a single status row: every item question is answered by
89
+ * the flat `statusKey` on the item. The read shape is always "the whole ladder at once", because
90
+ * a list renders all labels, colours and orders. And the admin screen edits the ladder as one
91
+ * reordering — this store has no transaction, so as separate rows "drag status 3 above status 1"
92
+ * would become N updates that can land halfway and leave two statuses on the same `order`. As an
93
+ * array it is one `$set`.
96
94
  *
97
- * Wat het kost: uniciteit van `key` wordt niet door de store bewaakt maar door
98
- * `validateStatuses` in de app.
95
+ * The cost: uniqueness of `key` is not guarded by the store but by `validateStatuses` in the app.
99
96
  */
100
97
  statuses: WorkStatus[];
101
- /** Afloopredenen, vrij per project. Leeg = afronden vraagt geen reden. */
98
+ /** Resolutions, free per project. Empty = closing asks for no reason. */
102
99
  resolutions?: WorkResolution[];
103
- /** Welke itemtypes dit project aanbiedt. Leeg = alle. */
100
+ /** Which item types this project offers. Empty = all of them. */
104
101
  typeKeys?: string[];
105
- /** Sleutels van de `CustomFieldDef`s die op dit project aan staan, in weergavevolgorde. */
102
+ /** Keys of the `CustomFieldDef`s enabled on this project, in display order. */
106
103
  fieldKeys?: string[];
107
- /** Waar een nieuw item begint. Afwezig = de eerste status in `order`. */
104
+ /** Where a new item starts. Absent = the first status in `order`. */
108
105
  defaultStatusKey?: string;
109
106
  /**
110
- * Duurzaam ankerpunt voor de sleutelteller.
107
+ * Durable anchor for the key counter.
111
108
  *
112
- * De teller zelf leeft in `Bridge.kv`, maar kv is een cache: hij kan koud starten of
113
- * geëvicteerd worden. Dit veld en de `(organizationId, projectId, sequenceNumber)`-index
114
- * zijn samen de weg terug, zodat een lege kv geen sleutels hergebruikt.
109
+ * The counter itself lives in `Bridge.kv`, but kv is a cache: it can start cold or be evicted.
110
+ * This field and the `(organizationId, projectId, sequenceNumber)` index are together the way
111
+ * back, so an empty kv does not reuse keys.
115
112
  */
116
113
  lastSequence?: number;
117
114
  archived?: boolean;
@@ -121,93 +118,92 @@ export interface WorkProject {
121
118
  updatedAt?: number;
122
119
  }
123
120
  export type WorkPriority = "low" | "normal" | "high" | "urgent";
124
- /** Waar een item vandaan komt — een mens of iets automatisch. */
121
+ /** Where an item came from — a person or something automatic. */
125
122
  export interface WorkItemSource {
126
123
  initiator: "user" | "system";
127
- /** Vrije reden bij `system` ("missed_call", "stale_interaction"). */
124
+ /** Free-form reason with `system` ("missed_call", "stale_interaction"). */
128
125
  systemReason?: string;
129
126
  }
130
127
  /**
131
- * Een werkitem.
128
+ * A work item.
132
129
  *
133
- * Let op wat hier **niet** staat: geen `interactionId`, geen `contactId`, geen `companyId`.
134
- * Verbanden lopen via {@link WorkLink} plus de platgeslagen {@link WorkItem.keys}, zodat "de
135
- * items op dit gesprek" één geïndexeerde `$in` blijft die combineerbaar is met een
136
- * statusfilter — wat een omweg langs de koppeltabel niet is.
130
+ * Note what is **not** here: no `interactionId`, no `contactId`, no `companyId`. Relations run
131
+ * through {@link WorkLink} plus the flattened {@link WorkItem.keys}, so "the items on this
132
+ * conversation" stays one indexed `$in` that combines with a status filter — which a detour past
133
+ * the link table does not.
137
134
  *
138
- * En geen `value`/`currency`: bedragen zijn aangepaste velden in de generieke
139
- * attribuutstore. Dat maakt sorteren erop een geheugenoperatie; zie het plan.
135
+ * And no `value`/`currency`: amounts are custom fields in the generic attribute store. That makes
136
+ * sorting on them an in-memory operation; see the plan.
140
137
  */
141
138
  export interface WorkItem {
142
139
  id: string;
143
140
  organizationId: string;
144
141
  /**
145
- * Afwezig = een **los item**: geen sleutel, geen projectvelden, en de vaste ladder uit
146
- * {@link LOOSE_STATUSES}. Dat is wat een losse taak is ("terugbellen", een opvolging op
147
- * een gesprek), en het bestaat vanaf dag één zodat werk dat later uit een andere app
148
- * hierheen komt geen modelwijziging vraagt.
142
+ * Absent = a **loose item**: no key, no project fields, and the fixed ladder from
143
+ * {@link LOOSE_STATUSES}. That is what a loose task is ("call back", a follow-up on a
144
+ * conversation), and it exists from day one so work arriving later from another app needs no
145
+ * model change.
149
146
  */
150
147
  projectId?: string;
151
- /** `SAL-142` / `SAL-142-1`. Afwezig bij een los item. Org-uniek waar aanwezig. */
148
+ /** `SAL-142` / `SAL-142-1`. Absent on a loose item. Org-unique where present. */
152
149
  key?: string;
153
150
  sequenceNumber?: number;
154
- /** Volgnummer binnen de ouder — het `-1` in `SAL-142-1`. */
151
+ /** Sequence number within the parent — the `-1` in `SAL-142-1`. */
155
152
  subSequence?: number;
156
- /** Lichte classificatie: icoon en welke velden zinvol zijn. Nooit een workflow. */
153
+ /** Light classification: icon and which fields make sense. Never a workflow. */
157
154
  typeKey: string;
158
155
  ownerScope: OwnerScope;
159
156
  title: string;
160
157
  description?: string;
161
158
  /**
162
- * Een {@link WorkStatus.key} — die van het project, of uit de vaste ladder. Omdat de
163
- * sleutels org-uniek zijn is de categorie er altijd eenduidig bij te zoeken; daarom
164
- * staat die hier níet als tweede kolom.
159
+ * A {@link WorkStatus.key} — the project's, or from the fixed ladder. Because the keys are
160
+ * org-unique the category can always be looked up unambiguously, which is why it is *not* a
161
+ * second column here.
165
162
  */
166
163
  statusKey: string;
167
- /** {@link WorkResolution.key}. Alleen zinvol als de status in categorie `done` valt. */
164
+ /** {@link WorkResolution.key}. Only meaningful when the status falls in category `done`. */
168
165
  resolution?: string;
169
166
  parentId?: string;
170
167
  /**
171
- * De scopeKeys van álle voorouders, platgeslagen op schrijfmoment
172
- * (`["work_item:program-1", "work_item:project-7"]`, van boven naar beneden).
168
+ * The scopeKeys of *all* ancestors, flattened at write time
169
+ * (`["work_item:program-1", "work_item:project-7"]`, top to bottom).
173
170
  *
174
- * Dít maakt onbeperkte diepte betaalbaar: "alles onder dit project" is één geïndexeerde
175
- * `$in` in plaats van een recursieve traversal, en die kan deze store niet. De prijs zit
176
- * aan de schrijfkant — een item verslepen betekent de `ancestorKeys` van zijn hele
177
- * subtree herschrijven, en dat is een job, geen request.
171
+ * This is what makes unlimited depth affordable: "everything under this project" is one indexed
172
+ * `$in` instead of a recursive traversal, which this store cannot do. The price is on the write
173
+ * side — dragging an item means rewriting the `ancestorKeys` of its whole subtree, and that is a
174
+ * job, not a request.
178
175
  */
179
176
  ancestorKeys?: string[];
180
- /** UserIds die dit doen. Leeg = de pool van het team. */
177
+ /** UserIds doing this. Empty = the team's pool. */
181
178
  assignees?: string[];
182
- /** Wie het inbracht, los van wie het doet. */
179
+ /** Who brought it in, apart from who does it. */
183
180
  reporterId?: string;
184
181
  watchers?: string[];
185
182
  priority?: WorkPriority;
186
183
  labels?: string[];
187
184
  /**
188
- * De partijen, plat en zonder rol: `["company:123", "contact:456"]`.
185
+ * The parties, flat and without a role: `["company:123", "contact:456"]`.
189
186
  *
190
- * Afgeleid uit de {@link WorkLink}s op schrijfmoment. Twee vormen naast elkaar omdat ze
191
- * twee vragen beantwoorden: de link weet *in welke hoedanigheid* (cliënt, wederpartij),
192
- * deze kolom beantwoordt "alle items waar dit bedrijf in zit" in één indexhit — wat over
193
- * een koppeltabel een tweede ronde zou kosten.
187
+ * Derived from the {@link WorkLink}s at write time. Two shapes side by side because they answer
188
+ * two questions: the link knows *in which capacity* (client, opposing party), this column
189
+ * answers "every item this company is in" in one index hit — which over a link table would cost
190
+ * a second round.
194
191
  */
195
192
  partyKeys: string[];
196
193
  /**
197
- * Dossiersleutels — de `keys`-conventie uit `platform/scope.ts`. Eigen sleutel,
198
- * projectsleutel, voorouders en partijen. Hiermee vinden uren, geheugen en attributen
199
- * dit item terug.
194
+ * File keys — the `keys` convention from `platform/scope.ts`. Own key, project key, ancestors
195
+ * and parties. This is how hours, memory and attributes find this item back.
200
196
  */
201
197
  keys: string[];
202
- /** Verwijzingen naar externe systemen (`shopify_order:8842`). Nooit een kopie. */
198
+ /** References to external systems (`shopify_order:8842`). Never a copy. */
203
199
  externalIds?: string[];
204
200
  /** Epoch ms. */
205
201
  startDate?: number;
206
202
  dueDate?: number;
207
- /** Gezet zodra de status naar categorie `done` gaat, gewist als hij terugkomt. */
203
+ /** Set as soon as the status moves to category `done`, cleared when it comes back. */
208
204
  closedAt?: number;
209
205
  estimateSeconds?: number;
210
- /** Standaard voor uren die hierop geboekt worden; de urenregel mag afwijken. */
206
+ /** Default for hours booked on this; the time entry may differ. */
211
207
  billable?: boolean;
212
208
  source: WorkItemSource;
213
209
  createdBy: string;
@@ -215,40 +211,38 @@ export interface WorkItem {
215
211
  updatedAt?: number;
216
212
  }
217
213
  /**
218
- * Een getypeerde koppeling tussen een werkitem en wat dan ook.
214
+ * A typed link between a work item and anything at all.
219
215
  *
220
- * **Eén hop, nooit getraverseerd.** Dat is de afspraak die deze tabel naast de
221
- * `keys`-conventie laat bestaan in plaats van ermee te concurreren: context en lidmaatschap
222
- * lopen via `keys` (platgeslagen bij schrijven, één indexhit), en dit is de expliciete,
223
- * laag-volume, één-niveau-diepe relatie tussen twee dingen. Een link-tabel die alsnog de
224
- * contextvraag beantwoordt is het begin van de grafiek die hier bewust niet gebouwd is —
225
- * deze store kan niet recursief traverseren.
216
+ * **One hop, never traversed.** That is the agreement letting this table exist next to the `keys`
217
+ * convention instead of competing with it: context and membership run through `keys` (flattened at
218
+ * write time, one index hit), and this is the explicit, low-volume, one-level-deep relation
219
+ * between two things. A link table that starts answering the context question too is the
220
+ * beginning of the graph deliberately not built here — this store cannot traverse recursively.
226
221
  */
227
222
  export interface WorkLink {
228
223
  id: string;
229
224
  organizationId: string;
230
- /** Altijd `work_item:<id>` op de heenrij. */
225
+ /** Always `work_item:<id>` on the outbound row. */
231
226
  fromKey: string;
232
- /** Elke scopeKey: een ander item, een gesprek, een contact, een artefact. */
227
+ /** Any scopeKey: another item, a conversation, a contact, an artifact. */
233
228
  toKey: string;
234
229
  /**
235
- * De relatie én de partijrol in één vocabulaire: `client` · `opposing` · `context` ·
230
+ * The relation and the party role in one vocabulary: `client` · `opposing` · `context` ·
236
231
  * `blocks` · `blocked_by` · `relates` · `duplicates` · `attachment`.
237
232
  *
238
- * Eén veld en geen aparte rol-kolom, want het zijn dezelfde soort uitspraak: "dit bedrijf
239
- * is de cliënt" en "dit item blokkeert dat item" zijn allebei een benoemde pijl.
233
+ * One field and no separate role column, because they are the same kind of statement: "this
234
+ * company is the client" and "this item blocks that item" are both a named arrow.
240
235
  */
241
236
  type: string;
242
237
  /**
243
- * Gedeeld door de heen- en terugrij.
238
+ * Shared by the outbound and the inbound row.
244
239
  *
245
- * Elke koppeling wordt als **twee** rijen geschreven, zodat een lookup één geïndexeerde
246
- * query op `fromKey` is in plaats van een `$or` over twee kolommen — en zodat "welk werk
247
- * hangt aan `interaction:123`" dezelfde query is als "wat hangt aan dit item". Dit veld
248
- * houdt ontkoppelen daarmee één handeling.
240
+ * Every link is written as **two** rows, so a lookup is one indexed query on `fromKey` instead
241
+ * of an `$or` across two columns — and so "which work hangs off `interaction:123`" is the same
242
+ * query as "what hangs off this item". This field keeps unlinking a single action.
249
243
  */
250
244
  pairId: string;
251
- /** Waar de terugrij zich mee bekendmaakt, zodat de UI "wordt geblokkeerd door" kan tonen. */
245
+ /** How the inbound row identifies itself, so the UI can show "is blocked by". */
252
246
  inverse?: boolean;
253
247
  createdBy: string;
254
248
  createdAt?: number;