@living-architecture/riviere-schema 0.2.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/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@living-architecture/riviere-schema",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ "./package.json": "./package.json",
13
+ ".": {
14
+ "@living-architecture/source": "./src/index.ts",
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./schema.json": "./riviere.schema.json"
20
+ },
21
+ "dependencies": {
22
+ "ajv": "^8.17.1",
23
+ "ajv-formats": "^3.0.1",
24
+ "tslib": "^2.3.0"
25
+ }
26
+ }
package/project.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "riviere-schema"
3
+ }
@@ -0,0 +1,581 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://riviere.arch/schema/riviere.schema.json",
4
+ "title": "Rivière Architecture Graph",
5
+ "description": "Flow-based architecture graph format for operational visualization",
6
+ "type": "object",
7
+ "required": ["version", "metadata", "components", "links"],
8
+ "properties": {
9
+ "version": {
10
+ "type": "string",
11
+ "description": "Schema version",
12
+ "pattern": "^[0-9]+\\.[0-9]+$"
13
+ },
14
+ "metadata": {
15
+ "type": "object",
16
+ "description": "Graph-level metadata",
17
+ "required": ["domains"],
18
+ "properties": {
19
+ "name": {
20
+ "type": "string",
21
+ "description": "Human-readable name for this architecture graph"
22
+ },
23
+ "description": {
24
+ "type": "string",
25
+ "description": "Description of what this graph represents"
26
+ },
27
+ "generated": {
28
+ "type": "string",
29
+ "format": "date-time",
30
+ "description": "Timestamp when this graph was generated"
31
+ },
32
+ "sources": {
33
+ "type": "array",
34
+ "description": "Source repositories this graph was extracted from",
35
+ "items": {
36
+ "type": "object",
37
+ "required": ["repository"],
38
+ "properties": {
39
+ "repository": {
40
+ "type": "string",
41
+ "description": "Repository name or identifier"
42
+ },
43
+ "commit": {
44
+ "type": "string",
45
+ "description": "Git commit SHA"
46
+ },
47
+ "extractedAt": {
48
+ "type": "string",
49
+ "format": "date-time",
50
+ "description": "When this repository was extracted"
51
+ }
52
+ }
53
+ }
54
+ },
55
+ "domains": {
56
+ "type": "object",
57
+ "description": "Domain-level metadata keyed by domain name",
58
+ "minProperties": 1,
59
+ "additionalProperties": {
60
+ "$ref": "#/definitions/domainMetadata"
61
+ }
62
+ },
63
+ "customTypes": {
64
+ "type": "object",
65
+ "description": "User-defined custom component types with their required and optional properties",
66
+ "additionalProperties": {
67
+ "$ref": "#/definitions/customTypeDefinition"
68
+ }
69
+ }
70
+ }
71
+ },
72
+ "components": {
73
+ "type": "array",
74
+ "description": "Architectural components in the system",
75
+ "items": {
76
+ "$ref": "#/definitions/component"
77
+ }
78
+ },
79
+ "links": {
80
+ "type": "array",
81
+ "description": "Operational flows between components",
82
+ "items": {
83
+ "$ref": "#/definitions/link"
84
+ }
85
+ },
86
+ "externalLinks": {
87
+ "type": "array",
88
+ "description": "Links to external systems outside the graph",
89
+ "items": {
90
+ "$ref": "#/definitions/externalLink"
91
+ }
92
+ }
93
+ },
94
+ "definitions": {
95
+ "component": {
96
+ "oneOf": [
97
+ { "$ref": "#/definitions/uiComponent" },
98
+ { "$ref": "#/definitions/apiRestComponent" },
99
+ { "$ref": "#/definitions/apiGraphqlComponent" },
100
+ { "$ref": "#/definitions/apiOtherComponent" },
101
+ { "$ref": "#/definitions/useCaseComponent" },
102
+ { "$ref": "#/definitions/domainOpComponent" },
103
+ { "$ref": "#/definitions/eventComponent" },
104
+ { "$ref": "#/definitions/eventHandlerComponent" },
105
+ { "$ref": "#/definitions/customComponent" }
106
+ ]
107
+ },
108
+ "baseComponentProperties": {
109
+ "type": "object",
110
+ "properties": {
111
+ "id": {
112
+ "type": "string",
113
+ "description": "Globally unique identifier following format: {domain}:{module}:{type}:{name}[:{lineNumber}].",
114
+ "minLength": 1
115
+ },
116
+ "name": {
117
+ "type": "string",
118
+ "description": "Human-readable name",
119
+ "minLength": 1
120
+ },
121
+ "domain": {
122
+ "type": "string",
123
+ "description": "Domain boundary this node belongs to",
124
+ "minLength": 1
125
+ },
126
+ "module": {
127
+ "type": "string",
128
+ "description": "Functional module within the domain",
129
+ "minLength": 1
130
+ },
131
+ "description": {
132
+ "type": "string",
133
+ "description": "Optional description of what this node does"
134
+ },
135
+ "sourceLocation": {
136
+ "$ref": "#/definitions/sourceLocation"
137
+ },
138
+ "metadata": {
139
+ "type": "object",
140
+ "description": "Extensible metadata for custom properties",
141
+ "additionalProperties": true
142
+ }
143
+ }
144
+ },
145
+ "uiComponent": {
146
+ "type": "object",
147
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "route"],
148
+ "properties": {
149
+ "id": { "type": "string", "minLength": 1 },
150
+ "type": { "const": "UI" },
151
+ "name": { "type": "string", "minLength": 1 },
152
+ "domain": { "type": "string", "minLength": 1 },
153
+ "module": { "type": "string", "minLength": 1 },
154
+ "description": { "type": "string" },
155
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
156
+ "metadata": { "type": "object", "additionalProperties": true },
157
+ "route": { "type": "string", "description": "URL route where UI component is rendered", "minLength": 1 }
158
+ },
159
+ "additionalProperties": false
160
+ },
161
+ "apiRestComponent": {
162
+ "type": "object",
163
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "apiType", "httpMethod", "path"],
164
+ "properties": {
165
+ "id": { "type": "string", "minLength": 1 },
166
+ "type": { "const": "API" },
167
+ "name": { "type": "string", "minLength": 1 },
168
+ "domain": { "type": "string", "minLength": 1 },
169
+ "module": { "type": "string", "minLength": 1 },
170
+ "description": { "type": "string" },
171
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
172
+ "metadata": { "type": "object", "additionalProperties": true },
173
+ "apiType": { "const": "REST" },
174
+ "httpMethod": { "type": "string", "enum": ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"] },
175
+ "path": { "type": "string", "description": "API path" }
176
+ },
177
+ "additionalProperties": false
178
+ },
179
+ "apiGraphqlComponent": {
180
+ "type": "object",
181
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "apiType", "operationName"],
182
+ "properties": {
183
+ "id": { "type": "string", "minLength": 1 },
184
+ "type": { "const": "API" },
185
+ "name": { "type": "string", "minLength": 1 },
186
+ "domain": { "type": "string", "minLength": 1 },
187
+ "module": { "type": "string", "minLength": 1 },
188
+ "description": { "type": "string" },
189
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
190
+ "metadata": { "type": "object", "additionalProperties": true },
191
+ "apiType": { "const": "GraphQL" },
192
+ "operationName": { "type": "string", "description": "GraphQL operation name" }
193
+ },
194
+ "additionalProperties": false
195
+ },
196
+ "apiOtherComponent": {
197
+ "type": "object",
198
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "apiType"],
199
+ "properties": {
200
+ "id": { "type": "string", "minLength": 1 },
201
+ "type": { "const": "API" },
202
+ "name": { "type": "string", "minLength": 1 },
203
+ "domain": { "type": "string", "minLength": 1 },
204
+ "module": { "type": "string", "minLength": 1 },
205
+ "description": { "type": "string" },
206
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
207
+ "metadata": { "type": "object", "additionalProperties": true },
208
+ "apiType": { "const": "other" }
209
+ },
210
+ "additionalProperties": false
211
+ },
212
+ "useCaseComponent": {
213
+ "type": "object",
214
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation"],
215
+ "properties": {
216
+ "id": { "type": "string", "minLength": 1 },
217
+ "type": { "const": "UseCase" },
218
+ "name": { "type": "string", "minLength": 1 },
219
+ "domain": { "type": "string", "minLength": 1 },
220
+ "module": { "type": "string", "minLength": 1 },
221
+ "description": { "type": "string" },
222
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
223
+ "metadata": { "type": "object", "additionalProperties": true }
224
+ },
225
+ "additionalProperties": false
226
+ },
227
+ "domainOpComponent": {
228
+ "type": "object",
229
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "operationName"],
230
+ "properties": {
231
+ "id": { "type": "string", "minLength": 1 },
232
+ "type": { "const": "DomainOp" },
233
+ "name": { "type": "string", "minLength": 1 },
234
+ "domain": { "type": "string", "minLength": 1 },
235
+ "module": { "type": "string", "minLength": 1 },
236
+ "description": { "type": "string" },
237
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
238
+ "metadata": { "type": "object", "additionalProperties": true },
239
+ "operationName": { "type": "string", "description": "Operation name" },
240
+ "entity": { "type": "string", "description": "Entity name" },
241
+ "signature": { "$ref": "#/definitions/operationSignature" },
242
+ "behavior": { "$ref": "#/definitions/operationBehavior" },
243
+ "stateChanges": { "type": "array", "items": { "$ref": "#/definitions/stateTransition" } },
244
+ "businessRules": { "type": "array", "items": { "type": "string", "minLength": 1 } }
245
+ },
246
+ "additionalProperties": false
247
+ },
248
+ "eventComponent": {
249
+ "type": "object",
250
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "eventName"],
251
+ "properties": {
252
+ "id": { "type": "string", "minLength": 1 },
253
+ "type": { "const": "Event" },
254
+ "name": { "type": "string", "minLength": 1 },
255
+ "domain": { "type": "string", "minLength": 1 },
256
+ "module": { "type": "string", "minLength": 1 },
257
+ "description": { "type": "string" },
258
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
259
+ "metadata": { "type": "object", "additionalProperties": true },
260
+ "eventName": { "type": "string", "description": "Event name" },
261
+ "eventSchema": { "type": "string", "description": "Event schema definition" }
262
+ },
263
+ "additionalProperties": false
264
+ },
265
+ "eventHandlerComponent": {
266
+ "type": "object",
267
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "subscribedEvents"],
268
+ "properties": {
269
+ "id": { "type": "string", "minLength": 1 },
270
+ "type": { "const": "EventHandler" },
271
+ "name": { "type": "string", "minLength": 1 },
272
+ "domain": { "type": "string", "minLength": 1 },
273
+ "module": { "type": "string", "minLength": 1 },
274
+ "description": { "type": "string" },
275
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
276
+ "metadata": { "type": "object", "additionalProperties": true },
277
+ "subscribedEvents": { "type": "array", "items": { "type": "string" }, "description": "Events this handler subscribes to" }
278
+ },
279
+ "additionalProperties": false
280
+ },
281
+ "customComponent": {
282
+ "type": "object",
283
+ "required": ["id", "type", "name", "domain", "module", "sourceLocation", "customTypeName"],
284
+ "properties": {
285
+ "id": { "type": "string", "minLength": 1 },
286
+ "type": { "const": "Custom" },
287
+ "name": { "type": "string", "minLength": 1 },
288
+ "domain": { "type": "string", "minLength": 1 },
289
+ "module": { "type": "string", "minLength": 1 },
290
+ "description": { "type": "string" },
291
+ "sourceLocation": { "$ref": "#/definitions/sourceLocation" },
292
+ "metadata": { "type": "object", "additionalProperties": true },
293
+ "customTypeName": { "type": "string", "description": "Name of the custom type (must match a key in metadata.customTypes)", "minLength": 1 }
294
+ },
295
+ "additionalProperties": false
296
+ },
297
+ "link": {
298
+ "type": "object",
299
+ "required": ["source", "target"],
300
+ "properties": {
301
+ "id": {
302
+ "type": "string",
303
+ "description": "Optional unique identifier for this link"
304
+ },
305
+ "source": {
306
+ "type": "string",
307
+ "description": "Source component ID",
308
+ "minLength": 1
309
+ },
310
+ "target": {
311
+ "type": "string",
312
+ "description": "Target component ID",
313
+ "minLength": 1
314
+ },
315
+ "type": {
316
+ "type": "string",
317
+ "enum": ["sync", "async"],
318
+ "description": "Link type: sync (request/response) or async (fire-and-forget, events)"
319
+ },
320
+ "payload": {
321
+ "type": "object",
322
+ "description": "Data transferred through this flow",
323
+ "properties": {
324
+ "type": {
325
+ "type": "string",
326
+ "description": "Payload type name"
327
+ },
328
+ "schema": {
329
+ "type": "object",
330
+ "description": "Schema definition as JSON object"
331
+ }
332
+ }
333
+ },
334
+ "sourceLocation": {
335
+ "$ref": "#/definitions/sourceLocation"
336
+ },
337
+ "metadata": {
338
+ "type": "object",
339
+ "description": "Extensible metadata for custom properties",
340
+ "additionalProperties": true
341
+ }
342
+ },
343
+ "additionalProperties": false
344
+ },
345
+ "externalLink": {
346
+ "type": "object",
347
+ "description": "Link from an internal component to an external system",
348
+ "required": ["source", "target"],
349
+ "properties": {
350
+ "id": {
351
+ "type": "string",
352
+ "description": "Optional unique identifier for this link"
353
+ },
354
+ "source": {
355
+ "type": "string",
356
+ "description": "Source component ID (must exist in graph)",
357
+ "minLength": 1
358
+ },
359
+ "target": {
360
+ "$ref": "#/definitions/externalTarget",
361
+ "description": "External system being called"
362
+ },
363
+ "type": {
364
+ "type": "string",
365
+ "enum": ["sync", "async"],
366
+ "description": "Link type: sync (request/response) or async (fire-and-forget)"
367
+ },
368
+ "description": {
369
+ "type": "string",
370
+ "description": "Human-readable description of this integration"
371
+ },
372
+ "sourceLocation": {
373
+ "$ref": "#/definitions/sourceLocation"
374
+ },
375
+ "metadata": {
376
+ "type": "object",
377
+ "description": "Extensible metadata for custom properties",
378
+ "additionalProperties": true
379
+ }
380
+ },
381
+ "additionalProperties": false
382
+ },
383
+ "externalTarget": {
384
+ "type": "object",
385
+ "description": "Reference to an external system outside the graph",
386
+ "required": ["name"],
387
+ "properties": {
388
+ "name": {
389
+ "type": "string",
390
+ "description": "Name of the external system",
391
+ "minLength": 1
392
+ },
393
+ "domain": {
394
+ "type": "string",
395
+ "description": "Domain name if known"
396
+ },
397
+ "repository": {
398
+ "type": "string",
399
+ "description": "Repository name if known"
400
+ },
401
+ "url": {
402
+ "type": "string",
403
+ "format": "uri",
404
+ "description": "URL to the external system"
405
+ }
406
+ },
407
+ "additionalProperties": false
408
+ },
409
+ "sourceLocation": {
410
+ "type": "object",
411
+ "required": ["repository", "filePath"],
412
+ "properties": {
413
+ "repository": {
414
+ "type": "string",
415
+ "description": "Repository name or identifier"
416
+ },
417
+ "filePath": {
418
+ "type": "string",
419
+ "description": "Relative file path within repository",
420
+ "minLength": 1
421
+ },
422
+ "lineNumber": {
423
+ "type": "integer",
424
+ "description": "Starting line number",
425
+ "minimum": 1
426
+ },
427
+ "endLineNumber": {
428
+ "type": "integer",
429
+ "description": "Ending line number",
430
+ "minimum": 1
431
+ },
432
+ "methodName": {
433
+ "type": "string",
434
+ "description": "Method or function name"
435
+ },
436
+ "url": {
437
+ "type": "string",
438
+ "format": "uri",
439
+ "description": "Direct URL to view this location in source control"
440
+ }
441
+ },
442
+ "additionalProperties": false
443
+ },
444
+ "domainMetadata": {
445
+ "type": "object",
446
+ "description": "Domain-level metadata for UI display",
447
+ "required": ["description", "systemType"],
448
+ "properties": {
449
+ "description": {
450
+ "type": "string",
451
+ "description": "Human-readable description of domain purpose"
452
+ },
453
+ "systemType": {
454
+ "type": "string",
455
+ "enum": ["domain", "bff", "ui", "other"],
456
+ "description": "Classification of domain's role in system"
457
+ }
458
+ },
459
+ "additionalProperties": true
460
+ },
461
+ "customTypeDefinition": {
462
+ "type": "object",
463
+ "description": "Definition of a custom component type with required and optional properties",
464
+ "properties": {
465
+ "description": {
466
+ "type": "string",
467
+ "description": "Human-readable description of this custom type"
468
+ },
469
+ "requiredProperties": {
470
+ "type": "object",
471
+ "description": "Properties required for components of this custom type (beyond base component properties)",
472
+ "additionalProperties": {
473
+ "$ref": "#/definitions/customPropertyDefinition"
474
+ }
475
+ },
476
+ "optionalProperties": {
477
+ "type": "object",
478
+ "description": "Optional properties for components of this custom type",
479
+ "additionalProperties": {
480
+ "$ref": "#/definitions/customPropertyDefinition"
481
+ }
482
+ }
483
+ },
484
+ "additionalProperties": false
485
+ },
486
+ "customPropertyDefinition": {
487
+ "type": "object",
488
+ "description": "Definition of a property in a custom type",
489
+ "required": ["type"],
490
+ "properties": {
491
+ "type": {
492
+ "type": "string",
493
+ "description": "JSON Schema type (string, number, boolean, array, object)",
494
+ "enum": ["string", "number", "boolean", "array", "object"]
495
+ },
496
+ "description": {
497
+ "type": "string",
498
+ "description": "Human-readable description of this property"
499
+ }
500
+ },
501
+ "additionalProperties": false
502
+ },
503
+ "operationSignature": {
504
+ "type": "object",
505
+ "description": "Method signature including parameters and return type",
506
+ "properties": {
507
+ "parameters": {
508
+ "type": "array",
509
+ "items": {
510
+ "type": "object",
511
+ "required": ["name", "type"],
512
+ "properties": {
513
+ "name": {
514
+ "type": "string",
515
+ "minLength": 1
516
+ },
517
+ "type": {
518
+ "type": "string",
519
+ "minLength": 1
520
+ },
521
+ "description": {
522
+ "type": "string"
523
+ }
524
+ },
525
+ "additionalProperties": false
526
+ }
527
+ },
528
+ "returnType": {
529
+ "type": "string",
530
+ "minLength": 1
531
+ }
532
+ },
533
+ "additionalProperties": false
534
+ },
535
+ "operationBehavior": {
536
+ "type": "object",
537
+ "description": "Behavioral characteristics of the operation",
538
+ "properties": {
539
+ "reads": {
540
+ "type": "array",
541
+ "description": "Entity fields or state read by this operation",
542
+ "items": { "type": "string" }
543
+ },
544
+ "validates": {
545
+ "type": "array",
546
+ "description": "Invariants or preconditions validated",
547
+ "items": { "type": "string" }
548
+ },
549
+ "modifies": {
550
+ "type": "array",
551
+ "description": "Entity fields or state modified by this operation",
552
+ "items": { "type": "string" }
553
+ },
554
+ "emits": {
555
+ "type": "array",
556
+ "description": "Events emitted by this operation",
557
+ "items": { "type": "string" }
558
+ }
559
+ },
560
+ "additionalProperties": false
561
+ },
562
+ "stateTransition": {
563
+ "type": "object",
564
+ "description": "A single state transition caused by an operation",
565
+ "required": ["from", "to"],
566
+ "properties": {
567
+ "from": {
568
+ "type": "string",
569
+ "description": "Source state (use '*' for any state)",
570
+ "minLength": 1
571
+ },
572
+ "to": {
573
+ "type": "string",
574
+ "description": "Target state",
575
+ "minLength": 1
576
+ }
577
+ },
578
+ "additionalProperties": false
579
+ }
580
+ }
581
+ }
@@ -0,0 +1,65 @@
1
+ import { ComponentId } from './component-id'
2
+
3
+ describe('ComponentId', () => {
4
+ describe('create', () => {
5
+ it('creates ID from parts with correct format', () => {
6
+ const id = ComponentId.create({
7
+ domain: 'orders',
8
+ module: 'checkout',
9
+ type: 'domainop',
10
+ name: 'Place Order',
11
+ })
12
+
13
+ expect(id.toString()).toBe('orders:checkout:domainop:place-order')
14
+ })
15
+
16
+ it('lowercases and hyphenates name', () => {
17
+ const id = ComponentId.create({
18
+ domain: 'orders',
19
+ module: 'checkout',
20
+ type: 'usecase',
21
+ name: 'Handle Customer Request',
22
+ })
23
+
24
+ expect(id.toString()).toBe('orders:checkout:usecase:handle-customer-request')
25
+ })
26
+
27
+ it('exposes name segment', () => {
28
+ const id = ComponentId.create({
29
+ domain: 'orders',
30
+ module: 'checkout',
31
+ type: 'domainop',
32
+ name: 'Place Order',
33
+ })
34
+
35
+ expect(id.name()).toBe('place-order')
36
+ })
37
+ })
38
+
39
+ describe('parse', () => {
40
+ it('parses valid ID string', () => {
41
+ const id = ComponentId.parse('orders:checkout:domainop:place-order')
42
+
43
+ expect(id.name()).toBe('place-order')
44
+ expect(id.toString()).toBe('orders:checkout:domainop:place-order')
45
+ })
46
+
47
+ it('throws on invalid format with too few segments', () => {
48
+ expect(() => ComponentId.parse('orders:checkout')).toThrow(
49
+ "Invalid component ID format: 'orders:checkout'. Expected 'domain:module:type:name'"
50
+ )
51
+ })
52
+
53
+ it('throws on invalid format with too many segments', () => {
54
+ expect(() => ComponentId.parse('orders:checkout:domainop:place:order')).toThrow(
55
+ "Invalid component ID format: 'orders:checkout:domainop:place:order'. Expected 'domain:module:type:name'"
56
+ )
57
+ })
58
+
59
+ it('throws on empty string', () => {
60
+ expect(() => ComponentId.parse('')).toThrow(
61
+ "Invalid component ID format: ''. Expected 'domain:module:type:name'"
62
+ )
63
+ })
64
+ })
65
+ })