@effect.healthcare/messenger 0.4.2 → 0.6.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.
- package/README.md +2 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/messenger.d.ts +30 -13
- package/dist/messenger.js +66 -38
- package/dist/messenger.meta.d.ts +11 -5
- package/dist/messenger.meta.js +8 -2
- package/dist/messenger.validation.d.ts +3 -3
- package/dist/messenger.validation.js +4 -7
- package/package.json +7 -2
- package/.claude/CLAUDE.md +0 -88
- package/.claude/context/composition.md +0 -921
- package/.claude/context/data.md +0 -1036
- package/.claude/context/event.md +0 -686
- package/.claude/context/gesture.md +0 -614
- package/.claude/context/operation.md +0 -596
- package/.claude/context/state.md +0 -864
- package/.claude/context/testing.md +0 -876
- package/.claude/context/validation.md +0 -350
- package/.claude/context/workflow.md +0 -608
- package/.claude/settings.json +0 -7
- package/.mcp.json +0 -12
- package/dist/.gitkeep +0 -1
- package/src/index.ts +0 -16
- package/src/messenger.meta.ts +0 -132
- package/src/messenger.ts +0 -386
- package/src/messenger.validation.ts +0 -25
- package/web-dev-server.config.mjs +0 -8
package/.claude/context/data.md
DELETED
|
@@ -1,1036 +0,0 @@
|
|
|
1
|
-
# Data
|
|
2
|
-
|
|
3
|
-
This document defines an implementation policy for **component data**, then illustrates how specifications are implemented by applying this policy.
|
|
4
|
-
|
|
5
|
-
This document is intentionally **data** only, but part of a set of implementation policies which together define how specifications should be transformed into implementations which are predictable, maintainable, and production-ready at scale.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# How to Read This Policy
|
|
10
|
-
|
|
11
|
-
Rules in this policy fall into three strengths. Read each rule with its strength in mind:
|
|
12
|
-
|
|
13
|
-
- **Principles** are non-negotiable. They derive from framework correctness or TDD discipline and hold for every component. A conflict with a principle is a defect.
|
|
14
|
-
- **Templates** are invariant skeletons with explicit variation points. The skeleton applies to every component; specific steps activate or deactivate based on the component's declared classification (e.g., attribute-backed vs non-attribute, readonly vs writable, payload-bearing vs payload-free). Variation is part of the template, not a deviation from it.
|
|
15
|
-
- **Conventions** are canonical defaults that keep implementations readable across components. A second component may deviate when its shape genuinely warrants it; the deviation should be explained at review time, not forbidden by the policy.
|
|
16
|
-
|
|
17
|
-
When applying this policy to a new component, classify each rule before reconciling conflicts. A conflict with a principle is a defect; a conflict with a template means a variation point needs to be made explicit; a conflict with a convention is a documented deviation.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
# 1) Data Contract Must Be Declared in the Specification
|
|
22
|
-
|
|
23
|
-
Each component specification must declare its data contract under `Data`.
|
|
24
|
-
|
|
25
|
-
`Data` must be an object whose property names are the canonical data names.
|
|
26
|
-
|
|
27
|
-
Each data definition must include:
|
|
28
|
-
|
|
29
|
-
- `type`
|
|
30
|
-
- `description`
|
|
31
|
-
|
|
32
|
-
A data definition may also include:
|
|
33
|
-
|
|
34
|
-
- `properties`
|
|
35
|
-
- `default`
|
|
36
|
-
- `readonly`
|
|
37
|
-
|
|
38
|
-
Interpretation:
|
|
39
|
-
|
|
40
|
-
- `type` defines the public runtime shape category of the data
|
|
41
|
-
- `description` defines the semantic purpose of the data
|
|
42
|
-
- `properties` defines the structured fields of object-shaped data
|
|
43
|
-
- `default` defines the default runtime value when one exists
|
|
44
|
-
- `readonly` defines whether the data is externally writable or internally owned
|
|
45
|
-
- if `properties` is present, the data is structured
|
|
46
|
-
- if `properties` is absent, the data is scalar or otherwise non-structured
|
|
47
|
-
|
|
48
|
-
Example specification:
|
|
49
|
-
|
|
50
|
-
```json
|
|
51
|
-
{
|
|
52
|
-
"Data": {
|
|
53
|
-
"metadata": {
|
|
54
|
-
"type": "object",
|
|
55
|
-
"description": "The metadata of the clinical pathway.",
|
|
56
|
-
"properties": {
|
|
57
|
-
"id": {
|
|
58
|
-
"type": "uuid",
|
|
59
|
-
"description": "The unique identifier of the clinical pathway."
|
|
60
|
-
},
|
|
61
|
-
"name": {
|
|
62
|
-
"type": "string",
|
|
63
|
-
"description": "The name of the clinical pathway.",
|
|
64
|
-
"default": "Clinical Pathway"
|
|
65
|
-
},
|
|
66
|
-
"type": {
|
|
67
|
-
"type": "MapType",
|
|
68
|
-
"description": "The type of the map.",
|
|
69
|
-
"default": "pathway"
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
"default": null,
|
|
73
|
-
"readonly": false
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
This defines the public data contract that the implementation must honor.
|
|
80
|
-
|
|
81
|
-
# Template Variation Points
|
|
82
|
-
|
|
83
|
-
Data items vary by structure, ownership, and runtime nullability:
|
|
84
|
-
|
|
85
|
-
- **Structured vs scalar** — structured data declares `properties` and uses an explicit metadata type (Section 4); scalar data has a flat runtime shape and may not require a structured type definition.
|
|
86
|
-
- **Writable vs read-only** — writable data exposes a public setter and follows the normalize → validate → guard → mutate → synchronize mutation order (Sections 8.2, 9); read-only data exposes only a getter and is mutated internally (Section 8.1).
|
|
87
|
-
- **Supports unloaded state vs always-present** — when the runtime contract permits an unloaded or cleared state, the public getter and setter types reflect that possibility, and validation may bypass the unloaded sentinel (Section 10). Always-present data does not exercise this variation.
|
|
88
|
-
|
|
89
|
-
Data-creation operations (Section 13.1), data-loading operations (Section 13.2), workflow events (Section 15), and the editing-surface pattern (Section 17) activate only when the component's specification declares the corresponding patterns. They are valid template instantiations, not extensions of the policy.
|
|
90
|
-
|
|
91
|
-
# 2) Data Must Represent Canonical Component-Owned Content
|
|
92
|
-
|
|
93
|
-
This framework distinguishes:
|
|
94
|
-
|
|
95
|
-
- `Data`: structured or scalar content owned by the component
|
|
96
|
-
- `State`: finite runtime mode, visibility, status, or other UI/runtime condition
|
|
97
|
-
- `Operations`: callable public actions
|
|
98
|
-
- `Events`: observable semantic outcomes
|
|
99
|
-
- `Gestures`: interaction inputs
|
|
100
|
-
|
|
101
|
-
Policy:
|
|
102
|
-
|
|
103
|
-
- data describes canonical component-owned content
|
|
104
|
-
- state describes runtime condition
|
|
105
|
-
- operations describe callable public actions
|
|
106
|
-
- events describe semantic outcomes
|
|
107
|
-
- gestures describe interaction input
|
|
108
|
-
- data must not be used to declare state
|
|
109
|
-
- data must not be used to declare operations
|
|
110
|
-
- data must not be used to declare events
|
|
111
|
-
- data must not be used to declare gestures
|
|
112
|
-
|
|
113
|
-
Examples of valid data:
|
|
114
|
-
|
|
115
|
-
- `metadata`
|
|
116
|
-
- `record`
|
|
117
|
-
- `document`
|
|
118
|
-
- `selection`
|
|
119
|
-
- `payload`
|
|
120
|
-
|
|
121
|
-
Examples that must not be modeled as data:
|
|
122
|
-
|
|
123
|
-
- `visibility`
|
|
124
|
-
- `status`
|
|
125
|
-
- `mode`
|
|
126
|
-
- `click`
|
|
127
|
-
- `onload`
|
|
128
|
-
- `save`
|
|
129
|
-
|
|
130
|
-
Data is the authoritative component-owned content model, not a substitute for the other constructs.
|
|
131
|
-
|
|
132
|
-
# 3) Public Data Names Must Be Declared in Metadata
|
|
133
|
-
|
|
134
|
-
For every data item declared in the specification, the implementation must define corresponding metadata in `<component>.meta.ts`.
|
|
135
|
-
|
|
136
|
-
This metadata defines the canonical data vocabulary for the component.
|
|
137
|
-
|
|
138
|
-
Policy:
|
|
139
|
-
|
|
140
|
-
- every declared public data item must have a key in `Data`
|
|
141
|
-
- `Data` contains only declared public data names
|
|
142
|
-
- the implementation must use data metadata consistently as the canonical data vocabulary
|
|
143
|
-
|
|
144
|
-
Example pattern:
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
export const Data = {
|
|
148
|
-
METADATA: "metadata",
|
|
149
|
-
} as const;
|
|
150
|
-
|
|
151
|
-
export type Data = (typeof Data)[keyof typeof Data];
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
This gives the implementation a stable, centralized vocabulary that prevents string duplication and keeps naming consistent across metadata, validation, component API, and data-oriented events.
|
|
155
|
-
|
|
156
|
-
# 4) Data Shape Must Be Defined in Metadata
|
|
157
|
-
|
|
158
|
-
For every declared data item, the implementation must define the corresponding runtime type in `<component>.meta.ts`.
|
|
159
|
-
|
|
160
|
-
This type defines the allowed runtime shape of the canonical data object or value.
|
|
161
|
-
|
|
162
|
-
Policy:
|
|
163
|
-
|
|
164
|
-
- every declared data item must have a corresponding runtime type definition in metadata
|
|
165
|
-
- structured data should be expressed through an explicit TypeScript type
|
|
166
|
-
- nested constrained fields may use additional metadata value domains
|
|
167
|
-
- the metadata type is the public runtime data contract used by the implementation
|
|
168
|
-
|
|
169
|
-
Example pattern:
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
export const MapType = {
|
|
173
|
-
PATHWAY: "pathway",
|
|
174
|
-
} as const;
|
|
175
|
-
|
|
176
|
-
export type MapType = (typeof MapType)[keyof typeof MapType];
|
|
177
|
-
|
|
178
|
-
export type Metadata = {
|
|
179
|
-
id: string;
|
|
180
|
-
name: string;
|
|
181
|
-
type: MapType;
|
|
182
|
-
};
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
This makes the data contract explicit in the same way state value domains are made explicit in metadata.
|
|
186
|
-
|
|
187
|
-
# 5) Data Validation Must Be Implemented in `<component>.validation.ts`
|
|
188
|
-
|
|
189
|
-
For every declared data item, the implementation must define validation logic in `<component>.validation.ts`.
|
|
190
|
-
|
|
191
|
-
This validation serves as the runtime enforcement layer for the data contract declared in the specification and expressed in metadata.
|
|
192
|
-
|
|
193
|
-
Policy:
|
|
194
|
-
|
|
195
|
-
- validation logic for data must be implemented in `<component>.validation.ts`
|
|
196
|
-
- validation must enforce the allowed runtime shape and constrained field domains declared in metadata
|
|
197
|
-
- public writable mutation paths must call validation before mutation proceeds
|
|
198
|
-
- if validation fails, mutation must not proceed
|
|
199
|
-
- validation functions should return the validated value in its narrowed runtime type
|
|
200
|
-
|
|
201
|
-
Example:
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
import { MapType } from "./title.meta.js";
|
|
205
|
-
import type { Metadata } from "./title.meta.js";
|
|
206
|
-
|
|
207
|
-
export class Validate {
|
|
208
|
-
public static metadata = (value: Metadata) => {
|
|
209
|
-
if (!value.id) {
|
|
210
|
-
throw new Error("Invalid metadata value: id is required");
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (!Object.values(MapType).includes(value.type as MapType)) {
|
|
214
|
-
throw new Error("Invalid metadata value: type is invalid");
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return value as Metadata;
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
This makes the contract explicit:
|
|
223
|
-
|
|
224
|
-
- `<component>.meta.ts` defines the data shape
|
|
225
|
-
- `<component>.validation.ts` enforces the data shape
|
|
226
|
-
- `<component>.ts` uses validation in the mutation path
|
|
227
|
-
|
|
228
|
-
# 6) Data Must Have a Canonical Internal Source of Truth
|
|
229
|
-
|
|
230
|
-
Each declared data item must have a canonical internal source of truth on the component instance.
|
|
231
|
-
|
|
232
|
-
That source may be nullable when the runtime contract supports an unloaded or cleared state.
|
|
233
|
-
|
|
234
|
-
Policy:
|
|
235
|
-
|
|
236
|
-
- every declared data item must have a canonical internally owned runtime source of truth
|
|
237
|
-
- canonical data should normally be stored in a private backing field
|
|
238
|
-
- if the runtime data contract includes an unloaded or cleared state, that state must be represented explicitly
|
|
239
|
-
- external API access must read from the canonical internal source of truth
|
|
240
|
-
|
|
241
|
-
Example:
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
private _metadata: Metadata | null = null;
|
|
245
|
-
|
|
246
|
-
public get metadata(): Metadata | null {
|
|
247
|
-
return this._metadata;
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
This keeps ownership clear and prevents DOM structure, transient form controls, or ad hoc derived values from becoming accidental sources of truth.
|
|
252
|
-
|
|
253
|
-
# 7) Data Does Not Participate in DOM Attribute Observation by Default
|
|
254
|
-
|
|
255
|
-
Unlike attribute-backed state, data is not DOM attribute-backed by default.
|
|
256
|
-
|
|
257
|
-
Policy:
|
|
258
|
-
|
|
259
|
-
- data must not be declared in `Attributes` unless an explicit policy for attribute-backed data exists
|
|
260
|
-
- data does not participate in `attributeChangedCallback` by default
|
|
261
|
-
- data must not be treated as DOM attribute state merely because it is externally readable or writable
|
|
262
|
-
- data reflection to DOM, serialization, or persistence must be modeled explicitly rather than assumed
|
|
263
|
-
|
|
264
|
-
This keeps structured content separate from the DOM attribute system used for finite state.
|
|
265
|
-
|
|
266
|
-
# 8) Data Must Declare External Access Contract
|
|
267
|
-
|
|
268
|
-
For each non-attribute data item, the implementation must declare its external access contract as one of:
|
|
269
|
-
|
|
270
|
-
- **Read-only external**
|
|
271
|
-
- **Writable external**
|
|
272
|
-
|
|
273
|
-
## 8.1) Read-only External Data
|
|
274
|
-
|
|
275
|
-
For data with `readonly: true`:
|
|
276
|
-
|
|
277
|
-
- expose a public getter
|
|
278
|
-
- do not expose a public setter
|
|
279
|
-
- internal logic may update the canonical value
|
|
280
|
-
|
|
281
|
-
Example:
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
private _metadata: Metadata | null = null;
|
|
285
|
-
|
|
286
|
-
public get metadata(): Metadata | null {
|
|
287
|
-
return this._metadata;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
protected _loadMetadata = (metadata: Metadata) => {
|
|
291
|
-
this._metadata = Validate.metadata(metadata);
|
|
292
|
-
};
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
## 8.2) Writable External Data
|
|
296
|
-
|
|
297
|
-
For data with `readonly: false`:
|
|
298
|
-
|
|
299
|
-
- expose a public getter
|
|
300
|
-
- expose a public setter
|
|
301
|
-
- public writable mutation must converge on that setter
|
|
302
|
-
|
|
303
|
-
Example:
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
private _metadata: Metadata | null = null;
|
|
307
|
-
|
|
308
|
-
public get metadata(): Metadata | null {
|
|
309
|
-
return this._metadata;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
public set metadata(metadata: Metadata | null) {
|
|
313
|
-
this._metadata = metadata ? Validate.metadata(metadata) : null;
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
Readonly therefore does **not** mean the data never changes. It means the data is externally readable but internally owned.
|
|
318
|
-
|
|
319
|
-
# 9) Public Data Mutation Path Must Be Normalize → Validate → Guard → Mutate → Synchronize
|
|
320
|
-
|
|
321
|
-
For writable data, the public mutation path must follow this order:
|
|
322
|
-
|
|
323
|
-
1. **Normalize**
|
|
324
|
-
2. **Validate**
|
|
325
|
-
3. **Guard**
|
|
326
|
-
4. **Mutate**
|
|
327
|
-
5. **Synchronize**
|
|
328
|
-
|
|
329
|
-
Interpretation:
|
|
330
|
-
|
|
331
|
-
- **Normalize** converts incoming values into the runtime shape expected by validation
|
|
332
|
-
- **Validate** enforces the declared data contract
|
|
333
|
-
- **Guard** prevents duplicate accepted outcomes when no effective change is needed
|
|
334
|
-
- **Mutate** updates the canonical internal value
|
|
335
|
-
- **Synchronize** updates dependent projections such as state, composition, or internal helpers
|
|
336
|
-
|
|
337
|
-
A mutation path may omit phases that are not needed for a given data item, but the order of any phases that are used must remain Normalize → Validate → Guard → Mutate → Synchronize.
|
|
338
|
-
|
|
339
|
-
Example:
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
public set metadata(metadata: Metadata | null) {
|
|
343
|
-
// Normalize
|
|
344
|
-
metadata = metadata ?? null;
|
|
345
|
-
|
|
346
|
-
// Validate
|
|
347
|
-
metadata = metadata ? Validate.metadata(metadata) : null;
|
|
348
|
-
|
|
349
|
-
// Guard
|
|
350
|
-
if (this._metadata === metadata) return;
|
|
351
|
-
|
|
352
|
-
// Mutate
|
|
353
|
-
this._metadata = metadata;
|
|
354
|
-
|
|
355
|
-
// Synchronize
|
|
356
|
-
this._updateLabel();
|
|
357
|
-
this._syncContent();
|
|
358
|
-
this._syncMode();
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
For structured object data, the guard strategy may be referential, structural, semantic, or omitted when no safe equality rule is available. The implementation must choose a strategy that is predictable for the declared contract.
|
|
363
|
-
|
|
364
|
-
# 10) Null or Unloaded Runtime Data State Must Be Explicitly Modeled
|
|
365
|
-
|
|
366
|
-
Some components support a meaningful runtime state where data is not yet loaded, has been cleared, or has not yet been created.
|
|
367
|
-
|
|
368
|
-
This is valid, but it must be modeled explicitly.
|
|
369
|
-
|
|
370
|
-
Policy:
|
|
371
|
-
|
|
372
|
-
- when a data item supports an unloaded or cleared runtime state, that state must be explicit in the implementation contract
|
|
373
|
-
- the public getter and setter types must reflect that runtime possibility
|
|
374
|
-
- validation may bypass the unloaded sentinel if that sentinel is part of the runtime access contract rather than part of the structured data shape itself
|
|
375
|
-
- operations and events must treat the unloaded state predictably
|
|
376
|
-
|
|
377
|
-
Example:
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
private _metadata: Metadata | null = null;
|
|
381
|
-
|
|
382
|
-
public set metadata(metadata: Metadata | null) {
|
|
383
|
-
this._metadata = metadata ? Validate.metadata(metadata) : null;
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
This keeps unloaded runtime absence distinct from invalid structured data.
|
|
388
|
-
|
|
389
|
-
# 11) Data Synchronization May Update Dependent State and Composition
|
|
390
|
-
|
|
391
|
-
Data often drives state projections and rendered composition.
|
|
392
|
-
|
|
393
|
-
This is valid, but those dependent constructs must preserve their own authoritative mutation behavior.
|
|
394
|
-
|
|
395
|
-
Policy:
|
|
396
|
-
|
|
397
|
-
- data mutation may synchronize dependent component state
|
|
398
|
-
- data mutation may synchronize composition-facing values such as labels, inputs, or cached display content
|
|
399
|
-
- when data mutation updates writable state, it should do so through that state's authoritative mutation path
|
|
400
|
-
- data synchronization must remain predictable and traceable from the data contract to the dependent runtime behavior
|
|
401
|
-
|
|
402
|
-
Example:
|
|
403
|
-
|
|
404
|
-
```typescript
|
|
405
|
-
private _updateLabel = () =>
|
|
406
|
-
(this.elements.label.textContent = this.metadata?.name ?? "Untitled");
|
|
407
|
-
|
|
408
|
-
private _syncContent = () =>
|
|
409
|
-
(this.content = !this.metadata?.name ? Content.EMPTY : Content.NAME);
|
|
410
|
-
|
|
411
|
-
private _syncMode = () =>
|
|
412
|
-
(this.mode = this.content === Content.EMPTY ? Mode.EDIT : Mode.VIEW);
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
In this pattern:
|
|
416
|
-
|
|
417
|
-
- `metadata` is the canonical data
|
|
418
|
-
- `content` is derived runtime state
|
|
419
|
-
- `mode` may be further coordinated from that derived state
|
|
420
|
-
- label text is a composition projection of the canonical data
|
|
421
|
-
|
|
422
|
-
# 12) Operations Must Remain Thin or Orchestrational Around Data
|
|
423
|
-
|
|
424
|
-
When an operation affects component data, it must not become a second authoritative mutation system.
|
|
425
|
-
|
|
426
|
-
Policy:
|
|
427
|
-
|
|
428
|
-
- operations that affect data must remain thin where possible
|
|
429
|
-
- operations may orchestrate multi-step workflows around data
|
|
430
|
-
- operations must not duplicate validation logic that belongs to the authoritative data mutation path
|
|
431
|
-
- operations must not mutate scattered data fields ad hoc when a canonical data mutation path exists
|
|
432
|
-
- operations may derive a next data value and delegate it through the authoritative data mutation path
|
|
433
|
-
|
|
434
|
-
Examples:
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
public load = (metadata: Metadata) => {
|
|
438
|
-
this.metadata = metadata;
|
|
439
|
-
|
|
440
|
-
const event = { detail: { metadata: this.metadata } };
|
|
441
|
-
this._dispatchEvent(Event.ON_LOAD, event);
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
public update = () => {
|
|
445
|
-
if (!this.metadata) return;
|
|
446
|
-
|
|
447
|
-
this.metadata = {
|
|
448
|
-
...this.metadata,
|
|
449
|
-
name: this.elements.name.value.trim(),
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
const event = { detail: { metadata: this.metadata } };
|
|
453
|
-
this._dispatchEvent(Event.ON_UPDATE, event);
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
public reset = () => {
|
|
457
|
-
this.metadata = null;
|
|
458
|
-
this._syncName();
|
|
459
|
-
this._dispatchEvent(Event.ON_RESET);
|
|
460
|
-
};
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
This preserves a single authoritative mutation path for the canonical data while still allowing workflow-oriented operations.
|
|
464
|
-
|
|
465
|
-
# 13) Data-Creation and Data-Loading Operations Are Valid Public Patterns
|
|
466
|
-
|
|
467
|
-
Some components need to create internal default data or load external data into the component.
|
|
468
|
-
|
|
469
|
-
These are valid public operation patterns.
|
|
470
|
-
|
|
471
|
-
## 13.1) Create
|
|
472
|
-
|
|
473
|
-
A create operation may internally construct a valid data instance and assign it through the authoritative data mutation path.
|
|
474
|
-
|
|
475
|
-
Example:
|
|
476
|
-
|
|
477
|
-
```typescript
|
|
478
|
-
public create = () => {
|
|
479
|
-
this.metadata = {
|
|
480
|
-
id: crypto.randomUUID(),
|
|
481
|
-
name: "",
|
|
482
|
-
type: MapType.PATHWAY,
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
const event = { detail: { metadata: this.metadata } };
|
|
486
|
-
this._dispatchEvent(Event.ON_CREATE, event);
|
|
487
|
-
};
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
## 13.2) Load
|
|
491
|
-
|
|
492
|
-
A load operation may accept external data and assign it through the authoritative data mutation path.
|
|
493
|
-
|
|
494
|
-
Example:
|
|
495
|
-
|
|
496
|
-
```typescript
|
|
497
|
-
public load = (metadata: Metadata) => {
|
|
498
|
-
this.metadata = metadata;
|
|
499
|
-
|
|
500
|
-
const event = { detail: { metadata: this.metadata } };
|
|
501
|
-
this._dispatchEvent(Event.ON_LOAD, event);
|
|
502
|
-
};
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
These patterns are especially common for structured domain data and should be treated as first-class data workflows.
|
|
506
|
-
|
|
507
|
-
# 14) Data Update Should Prefer Whole-Value Reassignment Over Ad Hoc Nested Mutation
|
|
508
|
-
|
|
509
|
-
When public behavior changes canonical data, the implementation should prefer constructing the next accepted data value and assigning it through the authoritative data mutation path.
|
|
510
|
-
|
|
511
|
-
Policy:
|
|
512
|
-
|
|
513
|
-
- public data updates should prefer whole-value reassignment when practical
|
|
514
|
-
- nested ad hoc mutation should be avoided in public workflow paths when it bypasses the authoritative mutation path
|
|
515
|
-
- reconstructing the next data value keeps validation, guard logic, synchronization, and event behavior centralized
|
|
516
|
-
|
|
517
|
-
Example:
|
|
518
|
-
|
|
519
|
-
```typescript
|
|
520
|
-
public update = () => {
|
|
521
|
-
if (!this.metadata) return;
|
|
522
|
-
|
|
523
|
-
this.metadata = {
|
|
524
|
-
...this.metadata,
|
|
525
|
-
name: this.elements.name.value.trim(),
|
|
526
|
-
};
|
|
527
|
-
};
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
This keeps the data setter authoritative rather than letting workflow operations mutate backing fields directly.
|
|
531
|
-
|
|
532
|
-
# 15) Data-Oriented Semantic Events Must Be Emitted by Accepted Data Outcomes or Declared Workflow Outcomes
|
|
533
|
-
|
|
534
|
-
Public data-oriented events must represent accepted semantic outcomes.
|
|
535
|
-
|
|
536
|
-
Some data events describe a direct accepted data outcome, such as load or update. Others describe a declared workflow milestone, such as save, reset, or create.
|
|
537
|
-
|
|
538
|
-
Policy:
|
|
539
|
-
|
|
540
|
-
- public data-oriented events must be dispatched through `_dispatchEvent(...)`
|
|
541
|
-
- data-outcome events must not be emitted before the corresponding accepted outcome has occurred
|
|
542
|
-
- when an event payload includes data, that payload must be emitted through `detail`
|
|
543
|
-
- emitted data payload must match the declared event contract
|
|
544
|
-
- operations must not dispatch data-outcome events before the authoritative data mutation path has accepted the outcome
|
|
545
|
-
|
|
546
|
-
Examples:
|
|
547
|
-
|
|
548
|
-
```typescript
|
|
549
|
-
public load = (metadata: Metadata) => {
|
|
550
|
-
this.metadata = metadata;
|
|
551
|
-
|
|
552
|
-
const event = { detail: { metadata: this.metadata } };
|
|
553
|
-
this._dispatchEvent(Event.ON_LOAD, event);
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
public save = () => {
|
|
557
|
-
if (!this.metadata) return;
|
|
558
|
-
|
|
559
|
-
this.update();
|
|
560
|
-
|
|
561
|
-
const event = { detail: { metadata: this.metadata } };
|
|
562
|
-
this._dispatchEvent(Event.ON_SAVE, event);
|
|
563
|
-
|
|
564
|
-
this.mode = Mode.VIEW;
|
|
565
|
-
};
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
This preserves the same event discipline already used for state-outcome events, while accommodating richer data workflows.
|
|
569
|
-
|
|
570
|
-
# 16) Data Payload Contract Must Match the Specification
|
|
571
|
-
|
|
572
|
-
When a public event emits data payload, the runtime payload must match the declared data contract or declared event payload contract.
|
|
573
|
-
|
|
574
|
-
Policy:
|
|
575
|
-
|
|
576
|
-
- data payload emitted through events must use `detail`
|
|
577
|
-
- the emitted payload must conform to the declared runtime data shape
|
|
578
|
-
- the implementation must not emit undeclared data payload for a declared public event
|
|
579
|
-
- payload should reflect the accepted canonical value, not a stale or pre-validation value
|
|
580
|
-
|
|
581
|
-
Example event contract:
|
|
582
|
-
|
|
583
|
-
```json
|
|
584
|
-
{
|
|
585
|
-
"Events": {
|
|
586
|
-
"onload": {
|
|
587
|
-
"description": "Dispatched when the metadata is loaded.",
|
|
588
|
-
"parameters": [
|
|
589
|
-
{
|
|
590
|
-
"name": "detail",
|
|
591
|
-
"type": "object",
|
|
592
|
-
"properties": {
|
|
593
|
-
"metadata": {
|
|
594
|
-
"type": "Metadata"
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
]
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
Example dispatch:
|
|
605
|
-
|
|
606
|
-
```typescript
|
|
607
|
-
const event = { detail: { metadata: this.metadata } };
|
|
608
|
-
this._dispatchEvent(Event.ON_LOAD, event);
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
# 17) Data May Drive Temporary Editing Surfaces Without Those Surfaces Becoming Canonical
|
|
612
|
-
|
|
613
|
-
Components often project canonical data into editable DOM controls such as inputs, textareas, or other form surfaces.
|
|
614
|
-
|
|
615
|
-
These controls are not themselves canonical data.
|
|
616
|
-
|
|
617
|
-
Policy:
|
|
618
|
-
|
|
619
|
-
- DOM editing controls must not become the canonical source of truth for the component data
|
|
620
|
-
- canonical data may be projected into the editing surface
|
|
621
|
-
- user edits may remain tentative until accepted through an operation or authoritative update path
|
|
622
|
-
- operations such as `edit`, `change`, `save`, and `cancel` may coordinate the relationship between tentative input and canonical data
|
|
623
|
-
|
|
624
|
-
Example:
|
|
625
|
-
|
|
626
|
-
```typescript
|
|
627
|
-
private _syncName = () =>
|
|
628
|
-
(this.elements.name.value = this.metadata?.name ?? "");
|
|
629
|
-
|
|
630
|
-
public edit = () => {
|
|
631
|
-
this._syncName();
|
|
632
|
-
this._focusName();
|
|
633
|
-
this.mode = Mode.EDIT;
|
|
634
|
-
};
|
|
635
|
-
|
|
636
|
-
public save = () => {
|
|
637
|
-
if (!this.metadata) return;
|
|
638
|
-
|
|
639
|
-
this.update();
|
|
640
|
-
|
|
641
|
-
const event = { detail: { metadata: this.metadata } };
|
|
642
|
-
this._dispatchEvent(Event.ON_SAVE, event);
|
|
643
|
-
|
|
644
|
-
this.mode = Mode.VIEW;
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
public cancel = () => {
|
|
648
|
-
this._syncName();
|
|
649
|
-
this.content = !this.metadata?.name ? Content.EMPTY : Content.NAME;
|
|
650
|
-
this._dispatchEvent(Event.ON_CANCEL);
|
|
651
|
-
this.mode = Mode.VIEW;
|
|
652
|
-
};
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
In this pattern:
|
|
656
|
-
|
|
657
|
-
- the input field is an editing surface
|
|
658
|
-
- `metadata` remains canonical
|
|
659
|
-
- save accepts the edited value into canonical data
|
|
660
|
-
- cancel restores the editing surface from canonical data
|
|
661
|
-
|
|
662
|
-
# 18) Initialization Policy Must Be Explicit About Data Lifecycle Entry
|
|
663
|
-
|
|
664
|
-
If a component requires initial data creation or default data loading during initialization, that behavior must be explicit and predictable.
|
|
665
|
-
|
|
666
|
-
Policy:
|
|
667
|
-
|
|
668
|
-
- initialization must not hide data lifecycle behavior
|
|
669
|
-
- if the component creates default data on mount, that should occur through a declared operation or controlled internal helper
|
|
670
|
-
- if callers are expected to load external data after connection, that expectation should be explicit in the implementation contract
|
|
671
|
-
- initialization behavior must remain compatible with the declared data access contract
|
|
672
|
-
|
|
673
|
-
Example:
|
|
674
|
-
|
|
675
|
-
```typescript
|
|
676
|
-
protected _initialize = () => {
|
|
677
|
-
this.setAttribute(Attributes.VISIBILITY, this._visibility);
|
|
678
|
-
this.setAttribute(Attributes.STATUS, this._status);
|
|
679
|
-
this.setAttribute(Attributes.CONTENT, this._content);
|
|
680
|
-
this.setAttribute(Attributes.MODE, this._mode);
|
|
681
|
-
|
|
682
|
-
this.create();
|
|
683
|
-
};
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
This pattern is valid because the initialization path is explicit and the creation behavior still routes through the authoritative data mutation path.
|
|
687
|
-
|
|
688
|
-
# 19) Readonly Policy Must Define Internal Ownership for Data
|
|
689
|
-
|
|
690
|
-
`readonly` defines whether data is externally writable.
|
|
691
|
-
|
|
692
|
-
- `readonly: false`
|
|
693
|
-
The data may participate in the component's public mutation contract.
|
|
694
|
-
|
|
695
|
-
- `readonly: true`
|
|
696
|
-
The data is externally readable but internally owned. External mutation must not be authoritative.
|
|
697
|
-
|
|
698
|
-
This rule applies to all data, regardless of whether the data is scalar or structured.
|
|
699
|
-
|
|
700
|
-
Readonly therefore does **not** mean the value never changes. It means the value is **not writable from the outside**. The component implementation retains ownership of mutation.
|
|
701
|
-
|
|
702
|
-
# 20) Naming Must Be Predictably Transformed Across Layers
|
|
703
|
-
|
|
704
|
-
Public data naming must remain consistent across the specification, metadata, component API, validation, operations, and event payloads.
|
|
705
|
-
|
|
706
|
-
Policy:
|
|
707
|
-
|
|
708
|
-
- the specification defines the canonical public data name
|
|
709
|
-
- metadata must define a corresponding `Data` key whose value is that canonical data name
|
|
710
|
-
- the component class must expose a public getter using that same canonical name
|
|
711
|
-
- if externally writable, the component class must expose a public setter using that same canonical name
|
|
712
|
-
- validation should use a predictably related function name
|
|
713
|
-
- event payload properties should use the same canonical data name when they emit that data
|
|
714
|
-
|
|
715
|
-
Transformation pattern:
|
|
716
|
-
|
|
717
|
-
| Layer | Example |
|
|
718
|
-
|---|---|
|
|
719
|
-
| Specification | `metadata` |
|
|
720
|
-
| Metadata Vocabulary | `Data.METADATA = "metadata"` |
|
|
721
|
-
| Metadata Type | `type Metadata = { ... }` |
|
|
722
|
-
| Validation | `Validate.metadata(...)` |
|
|
723
|
-
| Component API | `get metadata()` / `set metadata(...)` |
|
|
724
|
-
| Event Payload | `detail.metadata` |
|
|
725
|
-
|
|
726
|
-
This predictable transformation keeps the implementation traceable back to the specification and consistent with the framework's metadata-driven design.
|
|
727
|
-
|
|
728
|
-
---
|
|
729
|
-
|
|
730
|
-
# Policy Applied to Specification
|
|
731
|
-
|
|
732
|
-
Specification fragment:
|
|
733
|
-
|
|
734
|
-
```json
|
|
735
|
-
{
|
|
736
|
-
"Data": {
|
|
737
|
-
"metadata": {
|
|
738
|
-
"type": "object",
|
|
739
|
-
"description": "The metadata of the clinical pathway.",
|
|
740
|
-
"properties": {
|
|
741
|
-
"id": {
|
|
742
|
-
"type": "uuid",
|
|
743
|
-
"description": "The unique identifier of the clinical pathway."
|
|
744
|
-
},
|
|
745
|
-
"name": {
|
|
746
|
-
"type": "string",
|
|
747
|
-
"description": "The name of the clinical pathway."
|
|
748
|
-
},
|
|
749
|
-
"type": {
|
|
750
|
-
"type": "MapType",
|
|
751
|
-
"description": "The type of the map."
|
|
752
|
-
}
|
|
753
|
-
},
|
|
754
|
-
"default": null,
|
|
755
|
-
"readonly": false
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
How this specification is implemented:
|
|
762
|
-
|
|
763
|
-
- `metadata`
|
|
764
|
-
- canonical data item
|
|
765
|
-
- structured object-shaped data
|
|
766
|
-
- writable external data
|
|
767
|
-
- represented in metadata vocabulary as `Data.METADATA`
|
|
768
|
-
- represented in metadata type space as `type Metadata = { id, name, type }`
|
|
769
|
-
- validated by `Validate.metadata(...)`
|
|
770
|
-
- stored canonically in `private _metadata`
|
|
771
|
-
- exposed through `get metadata()` and `set metadata(...)`
|
|
772
|
-
- synchronized into dependent state and composition through helper methods
|
|
773
|
-
- acted on through data-oriented operations such as `create`, `load`, `update`, `save`, and `reset`
|
|
774
|
-
- emitted through semantic workflow events such as `oncreate`, `onload`, `onupdate`, `onsave`, and `onreset`
|
|
775
|
-
|
|
776
|
-
Implementation:
|
|
777
|
-
|
|
778
|
-
```typescript
|
|
779
|
-
export const Data = {
|
|
780
|
-
METADATA: "metadata",
|
|
781
|
-
} as const;
|
|
782
|
-
|
|
783
|
-
export type Data = (typeof Data)[keyof typeof Data];
|
|
784
|
-
|
|
785
|
-
export const MapType = {
|
|
786
|
-
PATHWAY: "pathway",
|
|
787
|
-
} as const;
|
|
788
|
-
|
|
789
|
-
export type MapType = (typeof MapType)[keyof typeof MapType];
|
|
790
|
-
|
|
791
|
-
export type Metadata = {
|
|
792
|
-
id: string;
|
|
793
|
-
name: string;
|
|
794
|
-
type: MapType;
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
export class Validate {
|
|
798
|
-
public static metadata = (value: Metadata) => {
|
|
799
|
-
if (!value.id) {
|
|
800
|
-
throw new Error("Invalid metadata value: id is required");
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
if (!Object.values(MapType).includes(value.type as MapType)) {
|
|
804
|
-
throw new Error("Invalid metadata value: type is invalid");
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
return value as Metadata;
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
private _metadata: Metadata | null = null;
|
|
812
|
-
|
|
813
|
-
public get metadata(): Metadata | null {
|
|
814
|
-
return this._metadata;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
public set metadata(metadata: Metadata | null) {
|
|
818
|
-
// Normalize
|
|
819
|
-
metadata = metadata ?? null;
|
|
820
|
-
|
|
821
|
-
// Validate
|
|
822
|
-
metadata = metadata ? Validate.metadata(metadata) : null;
|
|
823
|
-
|
|
824
|
-
// Guard
|
|
825
|
-
if (this._metadata === metadata) return;
|
|
826
|
-
|
|
827
|
-
// Mutate
|
|
828
|
-
this._metadata = metadata;
|
|
829
|
-
|
|
830
|
-
// Synchronize
|
|
831
|
-
this._updateLabel();
|
|
832
|
-
this._syncContent();
|
|
833
|
-
this._syncMode();
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
public create = () => {
|
|
837
|
-
this.metadata = {
|
|
838
|
-
id: crypto.randomUUID(),
|
|
839
|
-
name: "",
|
|
840
|
-
type: MapType.PATHWAY,
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
const event = { detail: { metadata: this.metadata } };
|
|
844
|
-
this._dispatchEvent(Event.ON_CREATE, event);
|
|
845
|
-
};
|
|
846
|
-
|
|
847
|
-
public load = (metadata: Metadata) => {
|
|
848
|
-
this.metadata = metadata;
|
|
849
|
-
|
|
850
|
-
const event = { detail: { metadata: this.metadata } };
|
|
851
|
-
this._dispatchEvent(Event.ON_LOAD, event);
|
|
852
|
-
};
|
|
853
|
-
|
|
854
|
-
public update = () => {
|
|
855
|
-
if (!this.metadata) return;
|
|
856
|
-
|
|
857
|
-
this.metadata = {
|
|
858
|
-
...this.metadata,
|
|
859
|
-
name: this.elements.name.value.trim(),
|
|
860
|
-
};
|
|
861
|
-
|
|
862
|
-
const event = { detail: { metadata: this.metadata } };
|
|
863
|
-
this._dispatchEvent(Event.ON_UPDATE, event);
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
public reset = () => {
|
|
867
|
-
this.metadata = null;
|
|
868
|
-
this._syncName();
|
|
869
|
-
this._dispatchEvent(Event.ON_RESET);
|
|
870
|
-
};
|
|
871
|
-
```
|
|
872
|
-
|
|
873
|
-
How the implementation applies the policy:
|
|
874
|
-
|
|
875
|
-
- the specification declares the data contract under `Data`
|
|
876
|
-
- metadata defines both the canonical data vocabulary and the runtime data shape
|
|
877
|
-
- validation enforces the runtime data contract
|
|
878
|
-
- the component owns the canonical data through a private backing field
|
|
879
|
-
- the public getter and setter define the external data access contract
|
|
880
|
-
- the setter is the authoritative public mutation path
|
|
881
|
-
- data mutation follows the normalize → validate → guard → mutate → synchronize order
|
|
882
|
-
- data mutation synchronizes dependent state and composition
|
|
883
|
-
- operations remain thin or orchestrational around the authoritative data path
|
|
884
|
-
- semantic data workflow events are emitted through the framework dispatch path
|
|
885
|
-
- event payloads expose canonical accepted data through `detail`
|
|
886
|
-
|
|
887
|
-
---
|
|
888
|
-
|
|
889
|
-
# Policy Checklist
|
|
890
|
-
|
|
891
|
-
A compliant component must:
|
|
892
|
-
|
|
893
|
-
1. Declare all public data under `Data` in the specification.
|
|
894
|
-
2. Define each data item using the required specification contract.
|
|
895
|
-
3. Use `type` and `description` for every declared data item.
|
|
896
|
-
4. Use `properties` when the data is structured.
|
|
897
|
-
5. Use `default` when the runtime contract includes a default or unloaded sentinel.
|
|
898
|
-
6. Use `readonly` to declare external ownership rules.
|
|
899
|
-
7. Define all declared public data names in `<component>.meta.ts`.
|
|
900
|
-
8. Use `Data` metadata as the canonical data vocabulary.
|
|
901
|
-
9. Define the runtime data shape in `<component>.meta.ts`.
|
|
902
|
-
10. Implement validation for each declared data item in `<component>.validation.ts`.
|
|
903
|
-
11. Ensure validation enforces the declared runtime shape and constrained field domains.
|
|
904
|
-
12. Give each declared data item a canonical internal source of truth.
|
|
905
|
-
13. Expose an external access contract for each data item as read-only or writable.
|
|
906
|
-
14. Keep public writable data mutation paths authoritative and centralized.
|
|
907
|
-
15. Use the mutation order normalize → validate → guard → mutate → synchronize whenever those phases are needed.
|
|
908
|
-
16. Model unloaded or cleared runtime data explicitly when supported.
|
|
909
|
-
17. Keep data out of `Attributes` and DOM attribute observation by default.
|
|
910
|
-
18. Allow data mutation to synchronize dependent state and composition predictably.
|
|
911
|
-
19. Preserve authoritative ownership of dependent state when data updates it.
|
|
912
|
-
20. Keep data-oriented operations thin or orchestrational around the canonical data mutation path.
|
|
913
|
-
21. Prefer whole-value reassignment over ad hoc nested mutation in public workflow paths.
|
|
914
|
-
22. Dispatch public data-oriented events through `_dispatchEvent(...)`.
|
|
915
|
-
23. Emit data events only after the accepted data outcome or declared workflow outcome has occurred.
|
|
916
|
-
24. Emit data payload through `event.detail`.
|
|
917
|
-
25. Ensure emitted data payload matches the declared contract.
|
|
918
|
-
26. Keep DOM editing surfaces non-canonical unless the specification explicitly says otherwise.
|
|
919
|
-
27. Keep naming predictably aligned across specification, metadata, validation, component API, and event payloads.
|
|
920
|
-
|
|
921
|
-
---
|
|
922
|
-
|
|
923
|
-
# Component Data Specification Schema
|
|
924
|
-
|
|
925
|
-
JSON Schema:
|
|
926
|
-
|
|
927
|
-
```json
|
|
928
|
-
{
|
|
929
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
930
|
-
"$id": "https://scalable.software/schema/component-data.schema.json",
|
|
931
|
-
"title": "Component Data",
|
|
932
|
-
"description": "Schema for the Data object in a component specification.",
|
|
933
|
-
"type": "object",
|
|
934
|
-
"propertyNames": {
|
|
935
|
-
"type": "string",
|
|
936
|
-
"pattern": "^[a-z][a-zA-Z0-9]*$",
|
|
937
|
-
"description": "Canonical data name in lowerCamelCase, for example: metadata, document, payload."
|
|
938
|
-
},
|
|
939
|
-
"additionalProperties": {
|
|
940
|
-
"type": "object",
|
|
941
|
-
"description": "A data definition.",
|
|
942
|
-
"required": ["type", "description"],
|
|
943
|
-
"additionalProperties": false,
|
|
944
|
-
"properties": {
|
|
945
|
-
"type": {
|
|
946
|
-
"type": "string",
|
|
947
|
-
"minLength": 1,
|
|
948
|
-
"description": "Declared runtime shape category for the data, for example: object, array, string, Metadata."
|
|
949
|
-
},
|
|
950
|
-
"description": {
|
|
951
|
-
"type": "string",
|
|
952
|
-
"minLength": 1,
|
|
953
|
-
"description": "Human-readable description of the component-owned data."
|
|
954
|
-
},
|
|
955
|
-
"properties": {
|
|
956
|
-
"type": "object",
|
|
957
|
-
"description": "Structured field definitions for object-shaped data.",
|
|
958
|
-
"minProperties": 1,
|
|
959
|
-
"propertyNames": {
|
|
960
|
-
"type": "string",
|
|
961
|
-
"pattern": "^[a-z][a-zA-Z0-9]*$",
|
|
962
|
-
"description": "Canonical property name in lowerCamelCase, for example: id, name, type."
|
|
963
|
-
},
|
|
964
|
-
"additionalProperties": {
|
|
965
|
-
"type": "object",
|
|
966
|
-
"required": ["type", "description"],
|
|
967
|
-
"additionalProperties": false,
|
|
968
|
-
"properties": {
|
|
969
|
-
"type": {
|
|
970
|
-
"type": "string",
|
|
971
|
-
"minLength": 1,
|
|
972
|
-
"description": "Declared field type, for example: string, uuid, MapType."
|
|
973
|
-
},
|
|
974
|
-
"description": {
|
|
975
|
-
"type": "string",
|
|
976
|
-
"minLength": 1,
|
|
977
|
-
"description": "Human-readable description of the field."
|
|
978
|
-
},
|
|
979
|
-
"default": {
|
|
980
|
-
"description": "Default value for the field when applicable."
|
|
981
|
-
},
|
|
982
|
-
"values": {
|
|
983
|
-
"type": "array",
|
|
984
|
-
"minItems": 1,
|
|
985
|
-
"description": "Allowed values when the field has a constrained domain."
|
|
986
|
-
},
|
|
987
|
-
"readonly": {
|
|
988
|
-
"type": "boolean",
|
|
989
|
-
"description": "Whether the field is externally writable. Field-level readonly is optional and may be interpreted by component-specific policy."
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
},
|
|
994
|
-
"default": {
|
|
995
|
-
"description": "Default runtime value for the declared data item."
|
|
996
|
-
},
|
|
997
|
-
"readonly": {
|
|
998
|
-
"type": "boolean",
|
|
999
|
-
"description": "Whether the data item is externally writable. If true, the data is externally readable but internally owned."
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
```
|
|
1005
|
-
|
|
1006
|
-
Example JSON:
|
|
1007
|
-
|
|
1008
|
-
```json
|
|
1009
|
-
{
|
|
1010
|
-
"Data": {
|
|
1011
|
-
"metadata": {
|
|
1012
|
-
"type": "object",
|
|
1013
|
-
"description": "The metadata of the clinical pathway.",
|
|
1014
|
-
"properties": {
|
|
1015
|
-
"id": {
|
|
1016
|
-
"type": "uuid",
|
|
1017
|
-
"description": "The unique identifier of the clinical pathway."
|
|
1018
|
-
},
|
|
1019
|
-
"name": {
|
|
1020
|
-
"type": "string",
|
|
1021
|
-
"description": "The name of the clinical pathway.",
|
|
1022
|
-
"default": "Clinical Pathway"
|
|
1023
|
-
},
|
|
1024
|
-
"type": {
|
|
1025
|
-
"type": "MapType",
|
|
1026
|
-
"description": "The type of the map.",
|
|
1027
|
-
"default": "pathway",
|
|
1028
|
-
"values": ["pathway"]
|
|
1029
|
-
}
|
|
1030
|
-
},
|
|
1031
|
-
"default": null,
|
|
1032
|
-
"readonly": false
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
```
|