Skip to content

Commit c2c9daf

Browse files
committed
Add MI Submitted event schema and update async API spec
1 parent fef239e commit c2c9daf

File tree

7 files changed

+382
-3
lines changed

7 files changed

+382
-3
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"description": "MI",
3+
"type": "object",
4+
"properties": {
5+
"id": {
6+
"type": "string"
7+
},
8+
"lineItem": {
9+
"type": "string"
10+
},
11+
"timestamp": {
12+
"type": "string"
13+
},
14+
"quantity": {
15+
"type": "number"
16+
},
17+
"specificationId": {
18+
"type": "string"
19+
},
20+
"groupId": {
21+
"type": "string"
22+
},
23+
"stockRemaining": {
24+
"type": "number"
25+
},
26+
"supplierId": {
27+
"type": "string"
28+
},
29+
"createdAt": {
30+
"type": "string"
31+
},
32+
"updatedAt": {
33+
"type": "string"
34+
}
35+
},
36+
"required": [
37+
"id",
38+
"lineItem",
39+
"timestamp",
40+
"quantity",
41+
"supplierId",
42+
"createdAt",
43+
"updatedAt"
44+
]
45+
}
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
{
2+
"title": "mi.SUBMITTED Event",
3+
"description": "Event schema for reporting that MI data has been submitted",
4+
"type": "object",
5+
"properties": {
6+
"specversion": {
7+
"title": "CloudEvents spec version",
8+
"description": "CloudEvents specification version (fixed to 1.0).",
9+
"examples": [
10+
"1.0"
11+
],
12+
"type": "string",
13+
"enum": [
14+
"1.0"
15+
]
16+
},
17+
"id": {
18+
"title": "Event ID",
19+
"description": "Unique identifier for this event instance (UUID).",
20+
"examples": [
21+
"6f1c2a53-3d54-4a0a-9a0b-0e9ae2d4c111"
22+
],
23+
"type": "string",
24+
"minLength": 1,
25+
"format": "uuid",
26+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
27+
},
28+
"type": {
29+
"title": "mi.SUBMITTED event type",
30+
"description": "Event type using reverse-DNS style",
31+
"examples": [
32+
"uk.nhs.notify.supplier-api.mi.SUBMITTED.v1"
33+
],
34+
"type": "string",
35+
"enum": [
36+
"uk.nhs.notify.supplier-api.mi.SUBMITTED.v1"
37+
]
38+
},
39+
"dataschema": {
40+
"title": "Data Schema URI",
41+
"description": "URI of a schema that describes the event data\n\nData schema version must match the major version indicated by the type",
42+
"examples": [
43+
"https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json"
44+
],
45+
"type": "string",
46+
"pattern": "^https:\\/\\/notify\\.nhs\\.uk\\/cloudevents\\/schemas\\/supplier-api\\/mi\\.(?<status>SUBMITTED)\\.1\\.\\d+\\.\\d+\\.schema.json$"
47+
},
48+
"source": {
49+
"title": "Event Source",
50+
"description": "Logical event producer path within the supplier-api domain",
51+
"type": "string",
52+
"pattern": "^\\/data-plane\\/supplier-api(?:\\/.*)?$"
53+
},
54+
"subject": {
55+
"title": "Event Subject",
56+
"description": "Resource path (no leading slash) within the source made of segments separated by '/'.",
57+
"examples": [
58+
"mi/f47ac10b-58cc-4372-a567-0e02b2c3d479"
59+
],
60+
"type": "string",
61+
"pattern": "^mi\\/[a-z0-9-]+$"
62+
},
63+
"data": {
64+
"description": "MI",
65+
"type": "object",
66+
"properties": {
67+
"id": {
68+
"type": "string"
69+
},
70+
"lineItem": {
71+
"type": "string"
72+
},
73+
"timestamp": {
74+
"type": "string"
75+
},
76+
"quantity": {
77+
"type": "number"
78+
},
79+
"specificationId": {
80+
"type": "string"
81+
},
82+
"groupId": {
83+
"type": "string"
84+
},
85+
"stockRemaining": {
86+
"type": "number"
87+
},
88+
"supplierId": {
89+
"type": "string"
90+
},
91+
"createdAt": {
92+
"type": "string"
93+
},
94+
"updatedAt": {
95+
"type": "string"
96+
}
97+
},
98+
"required": [
99+
"id",
100+
"lineItem",
101+
"timestamp",
102+
"quantity",
103+
"supplierId",
104+
"createdAt",
105+
"updatedAt"
106+
]
107+
},
108+
"time": {
109+
"title": "Event Time",
110+
"description": "Timestamp when the event occurred (RFC 3339).",
111+
"examples": [
112+
"2025-10-01T10:15:30.000Z"
113+
],
114+
"type": "string",
115+
"format": "date-time",
116+
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
117+
},
118+
"datacontenttype": {
119+
"title": "Data Content Type",
120+
"description": "Media type for the data field (fixed to application/json).",
121+
"examples": [
122+
"application/json"
123+
],
124+
"type": "string",
125+
"enum": [
126+
"application/json"
127+
]
128+
},
129+
"traceparent": {
130+
"title": "Traceparent",
131+
"description": "W3C Trace Context traceparent header value.",
132+
"examples": [
133+
"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
134+
],
135+
"type": "string",
136+
"minLength": 1,
137+
"pattern": "^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$"
138+
},
139+
"tracestate": {
140+
"title": "Tracestate",
141+
"description": "Optional W3C Trace Context tracestate header value.",
142+
"examples": [
143+
"rojo=00f067aa0ba902b7,congo=t61rcWkgMzE"
144+
],
145+
"type": "string"
146+
},
147+
"partitionkey": {
148+
"title": "Partition Key",
149+
"description": "Partition / ordering key (lowercase alphanumerics and hyphen, 1-64 chars).",
150+
"examples": [
151+
"customer-920fca11"
152+
],
153+
"type": "string",
154+
"minLength": 1,
155+
"maxLength": 64,
156+
"pattern": "^[a-z0-9-]+$"
157+
},
158+
"recordedtime": {
159+
"title": "Recorded Time",
160+
"description": "Timestamp when the event was recorded/persisted (should be >= time).",
161+
"examples": [
162+
"2025-10-01T10:15:30.250Z"
163+
],
164+
"type": "string",
165+
"format": "date-time",
166+
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
167+
},
168+
"sampledrate": {
169+
"title": "Sampled Rate",
170+
"description": "Sampling factor: number of similar occurrences this event represents.",
171+
"examples": [
172+
5
173+
],
174+
"type": "integer",
175+
"minimum": 1,
176+
"maximum": 9007199254740991
177+
},
178+
"sequence": {
179+
"title": "Sequence",
180+
"description": "Zero-padded 20 digit numeric sequence (lexicographically sortable).",
181+
"examples": [
182+
"00000000000000000042"
183+
],
184+
"type": "string",
185+
"pattern": "^\\d{20}$"
186+
},
187+
"severitytext": {
188+
"title": "Severity Text",
189+
"description": "Log severity level name.",
190+
"examples": [
191+
"DEBUG"
192+
],
193+
"type": "string",
194+
"enum": [
195+
"TRACE",
196+
"DEBUG",
197+
"INFO",
198+
"WARN",
199+
"ERROR",
200+
"FATAL"
201+
]
202+
},
203+
"severitynumber": {
204+
"title": "Severity Number",
205+
"description": "Numeric severity (TRACE=0, DEBUG=1, INFO=2, WARN=3, ERROR=4, FATAL=5).",
206+
"examples": [
207+
1
208+
],
209+
"type": "integer",
210+
"minimum": 0,
211+
"maximum": 5
212+
},
213+
"dataclassification": {
214+
"title": "Data Classification",
215+
"description": "Data sensitivity classification.",
216+
"examples": [
217+
"restricted"
218+
],
219+
"type": "string",
220+
"enum": [
221+
"public",
222+
"internal",
223+
"confidential",
224+
"restricted"
225+
]
226+
},
227+
"dataregulation": {
228+
"title": "Data Regulation",
229+
"description": "Regulatory regime tag applied to this data.",
230+
"examples": [
231+
"ISO-27001"
232+
],
233+
"type": "string",
234+
"enum": [
235+
"GDPR",
236+
"HIPAA",
237+
"PCI-DSS",
238+
"ISO-27001",
239+
"NIST-800-53",
240+
"CCPA"
241+
]
242+
},
243+
"datacategory": {
244+
"title": "Data Category",
245+
"description": "Data category classification (e.g. standard, special-category).",
246+
"examples": [
247+
"sensitive"
248+
],
249+
"type": "string",
250+
"enum": [
251+
"non-sensitive",
252+
"standard",
253+
"sensitive",
254+
"special-category"
255+
]
256+
}
257+
},
258+
"required": [
259+
"specversion",
260+
"id",
261+
"type",
262+
"dataschema",
263+
"source",
264+
"subject",
265+
"data",
266+
"time",
267+
"traceparent",
268+
"recordedtime",
269+
"severitynumber"
270+
]
271+
}

internal/events/schemas/supplier-api.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ channels:
3535
$ref: '#/components/messages/letter-returned'
3636
letter-any:
3737
$ref: '#/components/messages/letter-any'
38+
mi-submitted:
39+
$ref: '#/components/messages/mi-submitted'
3840

3941
components:
4042
messages:
@@ -179,6 +181,17 @@ components:
179181
payload:
180182
$ref: './events/letter.any.schema.json'
181183

184+
mi-submitted:
185+
name: mi-submitted
186+
title: MI Submitted
187+
summary: |
188+
This indicates that MI data has been submitted to the NHS Notify Supplier API.
189+
contentType: application/json
190+
payload:
191+
$ref: './events/mi.SUBMITTED.schema.json'
192+
182193
schemas:
183194
letter:
184195
$ref: './domain/letter.schema.json'
196+
mi:
197+
$ref: './domain/mi.schema.json'

internal/events/src/cli/generate-json.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import {
55
$LetterEvent,
66
letterEventMap,
77
} from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src/events/letter-events";
8+
import { $MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src/events/mi-events";
9+
import { $MI } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src/domain/mi";
810

911
for (const [key, schema] of Object.entries({
1012
letter: $Letter,
13+
mi: $MI,
1114
})) {
1215
const json = z.toJSONSchema(schema, {
1316
io: "input",
@@ -39,6 +42,16 @@ const json = z.toJSONSchema($LetterEvent, {
3942
reused: "ref",
4043
});
4144
fs.mkdirSync("schemas/events", { recursive: true });
42-
const file = `schemas/events/letter.any.schema.json`;
43-
fs.writeFileSync(file, JSON.stringify(json, null, 2));
44-
console.info(`Wrote JSON schema for letter.any to ${file}`);
45+
const letterJson = `schemas/events/letter.any.schema.json`;
46+
fs.writeFileSync(letterJson, JSON.stringify(json, null, 2));
47+
console.info(`Wrote JSON schema for letter.any to ${letterJson}`);
48+
49+
// MI Submitted Event
50+
const miJson = z.toJSONSchema($MISubmittedEvent, {
51+
io: "input",
52+
target: "openapi-3.0",
53+
reused: "ref",
54+
});
55+
const miFile = `schemas/events/mi.SUBMITTED.schema.json`;
56+
fs.writeFileSync(miFile, JSON.stringify(miJson, null, 2));
57+
console.info(`Wrote JSON schema for letter.any to ${miFile}`);

0 commit comments

Comments
 (0)