@sumrco/cli 0.3.0 → 0.3.1
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/ai/modules/kontract/resources/api-generation-standards.rf.md +83 -0
- package/ai/modules/kontract/resources/{configuration.rf.md → authoring/configuration.rf.md} +49 -11
- package/ai/modules/kontract/resources/authoring/design-profile/api-styles.rf.md +241 -0
- package/ai/modules/kontract/resources/authoring/design-profile/async-styles.rf.md +134 -0
- package/ai/modules/kontract/resources/authoring/design-profile/overview.md +64 -0
- package/ai/modules/kontract/resources/authoring/design-profile/schema-layout-styles.rf.md +356 -0
- package/ai/modules/kontract/resources/authoring/overview.md +56 -0
- package/ai/modules/kontract/resources/{schema-reuse.rf.md → authoring/schema-reuse.rf.md} +222 -46
- package/ai/modules/kontract/resources/{scope-and-splitting.rf.md → authoring/scope-and-splitting.rf.md} +113 -57
- package/ai/modules/kontract/resources/authoring/spec-layout.rf.md +492 -0
- package/ai/modules/kontract/resources/authoring/team-members/spec-author.tm.md +77 -0
- package/ai/modules/kontract/resources/{workflows/contract-change.wf.md → authoring/workflows/spec-change.wf.md} +21 -15
- package/ai/modules/kontract/resources/generated-output.rf.md +19 -14
- package/ai/modules/kontract/resources/openapi-sdk-generator-research.rf.md +17 -19
- package/ai/modules/kontract/resources/overview.md +115 -82
- package/ai/modules/kontract/resources/performance.rf.md +7 -7
- package/ai/modules/kontract/sumr.module.yaml +3 -0
- package/ai/modules/mission/sumr.module.yaml +6 -0
- package/ai/modules/playbook/resources/authoring/content-structure.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/cross-referencing.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/descriptions.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/extraction.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/flows.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/folder-structure.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/frontmatter.rf.md +4 -1
- package/ai/modules/playbook/resources/authoring/markdown.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/overview.md +1 -1
- package/ai/modules/playbook/resources/team-members/{playbook-technical-writer.tm.md → technical-writer.tm.md} +3 -2
- package/ai/modules/playbook/sumr.module.yaml +7 -2
- package/index.js +332 -276
- package/package.json +1 -1
- package/ai/modules/kontract/resources/language-sdk-generator-extension.rf.md +0 -62
- package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +0 -61
- package/ai/modules/kontract/resources/spec-layout.rf.md +0 -275
- package/ai/modules/kontract/resources/team-members/contract-author.tm.md +0 -60
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
category: reference
|
|
3
3
|
name: schema-reuse
|
|
4
4
|
title: Schema Reuse and Shared Components
|
|
5
|
-
description: "How to author
|
|
5
|
+
description: "How to author API and async schemas with reusable shared components, $ref, Kontract sets, and safe composition so Kontract output stays consistent and avoids duplicated contract shapes."
|
|
6
6
|
label: Schema Reuse
|
|
7
7
|
when: Adding repeated fields, response envelopes, pagination, errors, schedules, config objects, or reviewing generated diffs with duplicated DTO/model shapes
|
|
8
8
|
order: 12
|
|
@@ -17,10 +17,25 @@ operations or services, define it once and reference it with `$ref`.
|
|
|
17
17
|
This reduces drift in the source specs immediately. It also gives Kontract a
|
|
18
18
|
clear path to emit more shared generated code as the generator evolves.
|
|
19
19
|
|
|
20
|
-
Before extracting or naming a shared component, choose a name from
|
|
20
|
+
Before extracting or naming a shared component, choose a name from product
|
|
21
21
|
language. Shared names should stay specific enough for generated DTO/model/SDK
|
|
22
22
|
symbols.
|
|
23
23
|
|
|
24
|
+
## Local-first promotion model
|
|
25
|
+
|
|
26
|
+
Keep a schema in the smallest owning place until reuse proves it should move:
|
|
27
|
+
|
|
28
|
+
1. **Surface-local** — define one-off request, response, and model shapes in the
|
|
29
|
+
root file's `components.schemas`.
|
|
30
|
+
2. **Capability-local shared** — move the shape into the capability's
|
|
31
|
+
`shared/` folder when two or more surfaces in that capability reuse the same
|
|
32
|
+
concept.
|
|
33
|
+
3. **Repo-level shared** — move the shape into `schema/shared/` only when two or
|
|
34
|
+
more capabilities share the same semantics, lifecycle, and owner.
|
|
35
|
+
|
|
36
|
+
Do not create shared files only because a shape might become reusable later.
|
|
37
|
+
Shared components are a promotion step, not the default folder for every model.
|
|
38
|
+
|
|
24
39
|
## What to share
|
|
25
40
|
|
|
26
41
|
Prefer shared components for concepts that mean the same thing everywhere:
|
|
@@ -84,26 +99,107 @@ content:
|
|
|
84
99
|
$ref: ../shared/common.yml#/components/schemas/ImageMimeType
|
|
85
100
|
```
|
|
86
101
|
|
|
87
|
-
##
|
|
102
|
+
## Protocol scenarios for reuse
|
|
103
|
+
|
|
104
|
+
Pick the protocol scenario before extracting shared components:
|
|
105
|
+
|
|
106
|
+
1. **API-only** — share HTTP schemas, parameters, responses, envelopes,
|
|
107
|
+
pagination, errors, and scalar constraints through API schema components.
|
|
108
|
+
2. **async-only** — share message payload schemas, message enums, scalar
|
|
109
|
+
constraints, and value objects through async schema components or
|
|
110
|
+
capability-local model fragments.
|
|
111
|
+
3. **API + async** — keep protocol layers separate and share only neutral
|
|
112
|
+
components with identical meaning. The safest cross-protocol sharing is
|
|
113
|
+
usually enums, IDs, slugs, scalar value objects, and simple payload shapes.
|
|
114
|
+
|
|
115
|
+
Do not create cross-protocol shared files only because API schema and async schema
|
|
116
|
+
payloads look similar today. Shared components must have the same product
|
|
117
|
+
meaning and owner.
|
|
118
|
+
|
|
119
|
+
## API-only reuse
|
|
120
|
+
|
|
121
|
+
If the repo only has API schema sources, keep one-off schemas in the owning
|
|
122
|
+
API schema surface. Use a capability-local `shared/` folder only after multiple
|
|
123
|
+
surfaces in that capability reuse the same concept. Use `schema/shared/` only
|
|
124
|
+
after multiple capabilities share the same concept.
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
schema/
|
|
128
|
+
bookstore/
|
|
129
|
+
main.api.yml
|
|
130
|
+
catalog.api.yml
|
|
131
|
+
reviews.api.yml
|
|
132
|
+
shared/
|
|
133
|
+
enums.yml # reused by catalog and reviews
|
|
134
|
+
components.yml
|
|
135
|
+
shared/
|
|
136
|
+
errors.yml # reused by multiple capabilities
|
|
137
|
+
pagination.yml
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Use API schema `components` for reusable HTTP shapes:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
# schema/bookstore/shared/enums.yml
|
|
144
|
+
components:
|
|
145
|
+
schemas:
|
|
146
|
+
BookFormat:
|
|
147
|
+
type: string
|
|
148
|
+
enum: [hardcover, paperback, ebook]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## async-only reuse
|
|
88
152
|
|
|
89
|
-
|
|
90
|
-
|
|
153
|
+
If the repo only has async schema sources, keep reusable message payload schemas and
|
|
154
|
+
enums close to the messaging roots or under `schema/shared/` when several
|
|
155
|
+
message families share the same meaning.
|
|
91
156
|
|
|
92
157
|
```text
|
|
93
158
|
schema/
|
|
159
|
+
shared/
|
|
160
|
+
message-enums.yml
|
|
94
161
|
bookstore/
|
|
95
|
-
bookstore.
|
|
96
|
-
|
|
162
|
+
bookstore.async.yml
|
|
163
|
+
messages/
|
|
164
|
+
book-commands.yml
|
|
165
|
+
book-events.yml
|
|
166
|
+
models/
|
|
167
|
+
books.yml
|
|
168
|
+
enums.yml
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```yaml
|
|
172
|
+
# schema/bookstore/models/enums.yml
|
|
173
|
+
BookFormat:
|
|
174
|
+
type: string
|
|
175
|
+
enum: [hardcover, paperback, ebook]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## API + async shared components
|
|
179
|
+
|
|
180
|
+
When one product capability has both HTTP and messaging contracts, keep protocol
|
|
181
|
+
entrypoints separate and share only business schemas.
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
schema/
|
|
185
|
+
bookstore/
|
|
186
|
+
bookstore.api.yml
|
|
187
|
+
bookstore.async.yml
|
|
97
188
|
paths/books.yml
|
|
98
189
|
messages/books.yml
|
|
99
|
-
models/
|
|
190
|
+
models/enums.yml
|
|
100
191
|
models/books.yml
|
|
101
192
|
```
|
|
102
193
|
|
|
103
194
|
Good shared fragment:
|
|
104
195
|
|
|
105
196
|
```yaml
|
|
106
|
-
# schema/bookstore/models/
|
|
197
|
+
# schema/bookstore/models/enums.yml
|
|
198
|
+
BookFormat:
|
|
199
|
+
type: string
|
|
200
|
+
enum: [hardcover, paperback, ebook]
|
|
201
|
+
|
|
202
|
+
# schema/bookstore/models/books.yml
|
|
107
203
|
BookSlug:
|
|
108
204
|
type: string
|
|
109
205
|
minLength: 1
|
|
@@ -114,30 +210,28 @@ PaginationMeta:
|
|
|
114
210
|
$ref: ../../shared/common.yml#/components/schemas/PaginationMeta
|
|
115
211
|
```
|
|
116
212
|
|
|
117
|
-
|
|
213
|
+
API schema can use it through path and response fragments:
|
|
118
214
|
|
|
119
215
|
```yaml
|
|
120
216
|
# schema/bookstore/paths/books.yml
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
schema:
|
|
137
|
-
$ref: ../models/books.yml#/Book
|
|
217
|
+
parameters:
|
|
218
|
+
- name: bookSlug
|
|
219
|
+
in: path
|
|
220
|
+
required: true
|
|
221
|
+
schema:
|
|
222
|
+
$ref: ../models/books.yml#/BookSlug
|
|
223
|
+
get:
|
|
224
|
+
operationId: getBook
|
|
225
|
+
responses:
|
|
226
|
+
"200":
|
|
227
|
+
description: Book detail.
|
|
228
|
+
content:
|
|
229
|
+
application/json:
|
|
230
|
+
schema:
|
|
231
|
+
$ref: ../models/books.yml#/Book
|
|
138
232
|
```
|
|
139
233
|
|
|
140
|
-
|
|
234
|
+
async schema can use the same payload schema from a message fragment:
|
|
141
235
|
|
|
142
236
|
```yaml
|
|
143
237
|
# schema/bookstore/messages/books.yml
|
|
@@ -152,15 +246,94 @@ messages:
|
|
|
152
246
|
|
|
153
247
|
Keep protocol-specific pieces out of `models/`:
|
|
154
248
|
|
|
155
|
-
-
|
|
249
|
+
- API schema paths, parameters, request bodies, responses → `paths/` or
|
|
156
250
|
`components/`.
|
|
157
|
-
-
|
|
158
|
-
- Payload objects, enums, scalars,
|
|
159
|
-
|
|
251
|
+
- async schema channels, operations, messages → `messages/`.
|
|
252
|
+
- Payload objects, enums, scalars, and reusable business shapes → `models/`.
|
|
253
|
+
- Share enums through `models/enums.yml` when API schema and async schema use the same
|
|
254
|
+
vocabulary and values.
|
|
160
255
|
|
|
161
|
-
This keeps
|
|
256
|
+
This keeps API contracts, async messages, and generated models aligned without
|
|
162
257
|
making either protocol depend on the other's metadata.
|
|
163
258
|
|
|
259
|
+
## Kontract sets for reusable map fragments
|
|
260
|
+
|
|
261
|
+
Use `kontract.sets` when repeated YAML maps make the source noisy but the
|
|
262
|
+
reusable concept is not a standalone schema. `$sets` can apply reusable maps in
|
|
263
|
+
responses, parameters, schema properties, headers, request bodies, async
|
|
264
|
+
operations, messages, payload schemas, or any other mapping.
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
# schema/bookings/shared/components.yml
|
|
268
|
+
kontract:
|
|
269
|
+
sets:
|
|
270
|
+
StandardErrors:
|
|
271
|
+
"400":
|
|
272
|
+
$ref: '#/components/responses/BadRequest'
|
|
273
|
+
"401":
|
|
274
|
+
$ref: '#/components/responses/Unauthorized'
|
|
275
|
+
"403":
|
|
276
|
+
$ref: '#/components/responses/Forbidden'
|
|
277
|
+
"404":
|
|
278
|
+
$ref: '#/components/responses/NotFound'
|
|
279
|
+
"500":
|
|
280
|
+
$ref: '#/components/responses/InternalServerError'
|
|
281
|
+
AuditedFields:
|
|
282
|
+
createdAt:
|
|
283
|
+
type: string
|
|
284
|
+
format: date-time
|
|
285
|
+
updatedAt:
|
|
286
|
+
type: string
|
|
287
|
+
format: date-time
|
|
288
|
+
components:
|
|
289
|
+
responses:
|
|
290
|
+
BadRequest:
|
|
291
|
+
description: Bad request.
|
|
292
|
+
Unauthorized:
|
|
293
|
+
description: Unauthorized.
|
|
294
|
+
Forbidden:
|
|
295
|
+
description: Forbidden.
|
|
296
|
+
NotFound:
|
|
297
|
+
description: Not found.
|
|
298
|
+
InternalServerError:
|
|
299
|
+
description: Internal server error.
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
```yaml
|
|
303
|
+
# schema/bookings/public.api.yml
|
|
304
|
+
api: 3.0.3
|
|
305
|
+
paths:
|
|
306
|
+
/bookings:
|
|
307
|
+
post:
|
|
308
|
+
responses:
|
|
309
|
+
$sets:
|
|
310
|
+
- $ref: ./shared/components.yml#/kontract/sets/StandardErrors
|
|
311
|
+
"201":
|
|
312
|
+
description: Booking created.
|
|
313
|
+
content:
|
|
314
|
+
application/json:
|
|
315
|
+
schema:
|
|
316
|
+
$ref: '#/components/schemas/CreateBookingResponse'
|
|
317
|
+
components:
|
|
318
|
+
schemas:
|
|
319
|
+
Booking:
|
|
320
|
+
type: object
|
|
321
|
+
properties:
|
|
322
|
+
$sets:
|
|
323
|
+
- $ref: ./shared/components.yml#/kontract/sets/AuditedFields
|
|
324
|
+
id:
|
|
325
|
+
type: string
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Set rules:
|
|
329
|
+
|
|
330
|
+
- `$sets` merges maps only; it does not concatenate arrays.
|
|
331
|
+
- Local keys override set keys.
|
|
332
|
+
- Multiple sets that define the same key must use identical values.
|
|
333
|
+
- Kontract rebases copied `$ref` values when a set comes from another file.
|
|
334
|
+
- Normalized files passed to validators and generators do not contain
|
|
335
|
+
`kontract` or `$sets`.
|
|
336
|
+
|
|
164
337
|
## Response envelopes
|
|
165
338
|
|
|
166
339
|
If every endpoint repeats the same envelope fields, do not retype them in every
|
|
@@ -187,7 +360,7 @@ components:
|
|
|
187
360
|
```
|
|
188
361
|
|
|
189
362
|
```yaml
|
|
190
|
-
# schema/recipes/catalog.
|
|
363
|
+
# schema/recipes/catalog.api.yml
|
|
191
364
|
components:
|
|
192
365
|
schemas:
|
|
193
366
|
RecipesFindOneResponse:
|
|
@@ -261,7 +434,7 @@ Then service-specific schedules can reference or compose those shared pieces.
|
|
|
261
434
|
|
|
262
435
|
## Review checklist
|
|
263
436
|
|
|
264
|
-
After writing or updating any `*.
|
|
437
|
+
After writing or updating any `*.api.yml` or `*.async.yml` file, review
|
|
265
438
|
the spec before running generation. Actively look for these smells:
|
|
266
439
|
|
|
267
440
|
- the same `success/timestamp/path/message` fields repeated in many response
|
|
@@ -276,7 +449,7 @@ the spec before running generation. Actively look for these smells:
|
|
|
276
449
|
- repeated day-of-week schedule structures;
|
|
277
450
|
- error response schemas or problem-details bodies copied instead of referencing
|
|
278
451
|
shared responses;
|
|
279
|
-
- event envelopes or
|
|
452
|
+
- event envelopes or async schema reply wrappers copied with the same product
|
|
280
453
|
meaning;
|
|
281
454
|
- generated diffs adding many near-identical DTO/model files after a small API
|
|
282
455
|
change.
|
|
@@ -293,24 +466,27 @@ components when:
|
|
|
293
466
|
- a request DTO and response DTO intentionally differ, even if fields overlap;
|
|
294
467
|
- names would become vague (`CommonThing`, `BaseData`, `GenericConfig`);
|
|
295
468
|
- the reusable name would hide a real product term, such as using `Collection`
|
|
296
|
-
when collections are a
|
|
297
|
-
- sharing would force unrelated teams
|
|
469
|
+
when collections are a product concept;
|
|
470
|
+
- sharing would force unrelated teams or product areas to coordinate every
|
|
471
|
+
future change.
|
|
298
472
|
|
|
299
473
|
A good shared component has a clear product meaning and a stable owner.
|
|
300
474
|
|
|
301
475
|
## Safe workflow
|
|
302
476
|
|
|
303
|
-
1.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
3.
|
|
477
|
+
1. Keep new schemas local to the root or surface that owns them.
|
|
478
|
+
2. When reuse appears inside one capability, move the repeated shape into that
|
|
479
|
+
capability's `shared/` folder and replace duplicates with `$ref`.
|
|
480
|
+
3. When reuse appears across capabilities, promote the shape to
|
|
481
|
+
`schema/shared/` and update `$ref` links deliberately.
|
|
482
|
+
4. Use supported `allOf` object composition when a concrete response extends a
|
|
307
483
|
shared base.
|
|
308
|
-
|
|
309
|
-
|
|
484
|
+
5. Run `sumr kontract validate`.
|
|
485
|
+
6. Run a scoped generation first, for example:
|
|
310
486
|
|
|
311
487
|
```bash
|
|
312
488
|
sumr kontract generate --source api --target backend --specific recipes/catalog
|
|
313
489
|
```
|
|
314
490
|
|
|
315
|
-
|
|
316
|
-
unrelated
|
|
491
|
+
7. Review both the spec diff and generated diff. If generated output changed in
|
|
492
|
+
unrelated product areas, stop and investigate before committing.
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
category: reference
|
|
3
3
|
name: scope-and-splitting
|
|
4
4
|
title: Scope, Size, and Splitting
|
|
5
|
-
description: "How to keep Kontract specs and generator code small,
|
|
5
|
+
description: "How to keep Kontract specs and generator code small, product-aligned, and reviewable with explicit line-count budgets and split triggers."
|
|
6
6
|
label: Scope and Splitting
|
|
7
|
-
when: Reviewing large specs or code files, deciding whether to split a
|
|
7
|
+
when: Reviewing large specs or code files, deciding whether to split a product capability/API surface spec, or optimizing oversized Kontract modules
|
|
8
8
|
order: 18
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Scope, Size, and Splitting
|
|
12
12
|
|
|
13
|
-
Kontract is the next iteration of the AutoSync/
|
|
13
|
+
Kontract is the next iteration of the AutoSync/async schema idea: keep the
|
|
14
14
|
documentation-first and DRY discipline, but make the boundaries more explicit.
|
|
15
15
|
Large files are not automatically bad, but they hide duplicated concepts,
|
|
16
|
-
mixed
|
|
16
|
+
mixed product areas, and unstable generated output. Treat size limits as review
|
|
17
17
|
triggers first and hard caps second.
|
|
18
18
|
|
|
19
19
|
## Source-of-truth rule
|
|
@@ -29,7 +29,7 @@ Files under `resources/` become public AI guidance. Never use internal SUMR,
|
|
|
29
29
|
customer, product, infrastructure, event-subject, route, table, or data-model
|
|
30
30
|
examples there. Public examples must be sanitized and generic.
|
|
31
31
|
|
|
32
|
-
Use
|
|
32
|
+
Use example areas such as:
|
|
33
33
|
|
|
34
34
|
- kitchen recipes and ingredients;
|
|
35
35
|
- bookstore inventory;
|
|
@@ -48,7 +48,7 @@ explain the module's current behavior.
|
|
|
48
48
|
| File kind | Healthy target | Review trigger | Split/optimize trigger | Hard stop |
|
|
49
49
|
|---|---:|---:|---:|---:|
|
|
50
50
|
| Kontract TypeScript source | <= 200 lines | > 250 lines | > 400 lines | > 500 lines |
|
|
51
|
-
|
|
|
51
|
+
| API/async service spec | 150-350 lines | > 400 lines | > 700 lines | > 1000 lines |
|
|
52
52
|
| Shared component YAML | 100-300 lines | > 400 lines | > 600 lines | > 900 lines |
|
|
53
53
|
| Generated TypeScript output | no manual target | review if surprising | fix generator/spec, never hand-split | no hand edits |
|
|
54
54
|
|
|
@@ -60,7 +60,7 @@ manual splitting, but they can still reveal generator or spec-design problems.
|
|
|
60
60
|
|
|
61
61
|
Split or optimize before adding more content when a file shows any of these:
|
|
62
62
|
|
|
63
|
-
- multiple product
|
|
63
|
+
- multiple product capabilities or API surfaces in one spec;
|
|
64
64
|
- more than roughly 7-10 operations with different lifecycle owners;
|
|
65
65
|
- request/response schemas for unrelated use cases in one component block;
|
|
66
66
|
- repeated envelope, pagination, error, scalar, schedule, or config shapes;
|
|
@@ -73,92 +73,148 @@ Do not split only by line count. First identify the product or technical
|
|
|
73
73
|
boundary that gives the new file a stable name and owner.
|
|
74
74
|
|
|
75
75
|
Visual section comments can help readers navigate a healthy file, but they are
|
|
76
|
-
not a substitute for splitting an oversized or mixed-
|
|
77
|
-
start acting like a table of contents, split by
|
|
76
|
+
not a substitute for splitting an oversized or mixed-surface spec. If comments
|
|
77
|
+
start acting like a table of contents, split by capability/surface instead.
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## Product capability and API surface spec structure
|
|
80
80
|
|
|
81
81
|
Use directory nesting to communicate product ownership. The path should answer
|
|
82
82
|
"who owns this contract?" and the filename should answer "which surface is this?"
|
|
83
|
+
Read `kontract.guidance.profile.schemaLayoutStyle` before proposing a layout and
|
|
84
|
+
use the canonical trees in the schema layout style reference. Do not describe
|
|
85
|
+
resource-area fragments inside a product-capability folder as a repo-wide
|
|
86
|
+
`by-resource-area` layout.
|
|
87
|
+
|
|
88
|
+
For an API-only repo, keep the example API-only:
|
|
83
89
|
|
|
84
90
|
```text
|
|
85
91
|
schema/
|
|
92
|
+
recipes/
|
|
93
|
+
main.api.yml # api: 3.0.3; grouped under recipes/http
|
|
94
|
+
catalog.api.yml
|
|
95
|
+
ingredients.api.yml
|
|
96
|
+
shared/ # only promoted reusable recipe concepts
|
|
97
|
+
enums.yml
|
|
98
|
+
components.yml
|
|
99
|
+
kitchen/
|
|
100
|
+
stations.api.yml
|
|
86
101
|
shared/
|
|
87
|
-
|
|
88
|
-
pagination.yml
|
|
102
|
+
pagination.yml # only promoted cross-capability components
|
|
89
103
|
errors.yml
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For an async-only repo, keep the example async-only:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
schema/
|
|
110
|
+
shared/
|
|
111
|
+
message-enums.yml
|
|
92
112
|
recipes/
|
|
93
|
-
recipes.
|
|
94
|
-
ingredients.openapi.yml
|
|
95
|
-
publishing.asyncapi.yml
|
|
96
|
-
kitchen/
|
|
97
|
-
stations.openapi.yml
|
|
98
|
-
prep-jobs.asyncapi.yml
|
|
99
|
-
inventory.asyncapi.yml
|
|
100
|
-
bookstore/
|
|
101
|
-
bookstore.openapi.yml # OpenAPI root entrypoint
|
|
102
|
-
bookstore.asyncapi.yml # AsyncAPI root entrypoint
|
|
103
|
-
paths/
|
|
104
|
-
books.yml # HTTP paths by subdomain
|
|
105
|
-
authors.yml
|
|
113
|
+
recipes.async.yml
|
|
106
114
|
messages/
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
recipe-commands.yml
|
|
116
|
+
recipe-events.yml
|
|
109
117
|
models/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
authors.yml
|
|
118
|
+
recipe.yml
|
|
119
|
+
enums.yml
|
|
113
120
|
```
|
|
114
121
|
|
|
115
|
-
When a folder already carries the
|
|
116
|
-
|
|
122
|
+
When a folder already carries the product-capability name, prefer
|
|
123
|
+
`*.api.yml` for focused surfaces that should generate as one package:
|
|
117
124
|
|
|
118
125
|
```text
|
|
119
126
|
schema/
|
|
120
127
|
recipes/
|
|
121
|
-
catalog.
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
catalog.api.yml # api: 3.0.3
|
|
129
|
+
ingredients.api.yml # api: 3.0.3
|
|
130
|
+
shared/
|
|
131
|
+
enums.yml # promoted after both surfaces need it
|
|
132
|
+
components.yml
|
|
124
133
|
```
|
|
125
134
|
|
|
126
135
|
Kontract content-detects the protocol marker and groups those files under the
|
|
127
|
-
first folder (`recipes` in this example). Use explicit `*.
|
|
128
|
-
`*.
|
|
136
|
+
first folder (`recipes` in this example). Use explicit `*.api.yml` or
|
|
137
|
+
`*.async.yml` when each nested file should remain an independently generated
|
|
129
138
|
service path.
|
|
130
139
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
Add async schema examples only when messaging contracts exist:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
schema/
|
|
144
|
+
recipes/
|
|
145
|
+
catalog.api.yml # api: 3.0.3
|
|
146
|
+
publishing.async.yml # async: 3.0.0
|
|
147
|
+
inventory.async.yml # async: 3.0.0
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
When API schema and async schema both exist, keep `paths/` and `messages/` separate.
|
|
151
|
+
Share only schemas, especially enums, scalar value objects, IDs, and
|
|
152
|
+
slugs, through `models/` or `schema/shared/`.
|
|
153
|
+
|
|
154
|
+
If the selected schema layout style is `by-resource-area`, the resource
|
|
155
|
+
areas should be top-level roots under the configured schema input, not nested
|
|
156
|
+
under a product-capability folder. Moving from capability roots to resource-area
|
|
157
|
+
roots changes generated output namespaces/import paths, so call it out as a
|
|
158
|
+
schema and generated-output migration before recommending it.
|
|
159
|
+
|
|
160
|
+
When one product capability should keep a single generated package but the
|
|
161
|
+
contract is too large for one file, keep the explicit root files and split the
|
|
162
|
+
internals into plain `.yml` fragments. This mirrors Redocly-style authoring:
|
|
163
|
+
roots are the public entrypoints, fragments are implementation detail, and
|
|
164
|
+
schemas can be shared by API schema and async schema only when the business shape is
|
|
165
|
+
protocol-neutral.
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
schema/
|
|
169
|
+
bookstore/
|
|
170
|
+
bookstore.api.yml # API schema root entrypoint
|
|
171
|
+
paths/
|
|
172
|
+
books.yml # API schema Path Item fragment
|
|
173
|
+
authors.yml # API schema Path Item fragment
|
|
174
|
+
models/
|
|
175
|
+
shared.yml
|
|
176
|
+
books.yml
|
|
177
|
+
authors.yml
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Only add `bookstore.async.yml` and `messages/` fragments if the repo has
|
|
181
|
+
async schema contracts or the user asks for messaging. Do not use split fragments as
|
|
182
|
+
the default answer for a small API schema file.
|
|
136
183
|
|
|
137
184
|
Guidelines:
|
|
138
185
|
|
|
139
|
-
- Keep one entry-point spec per
|
|
140
|
-
repo.
|
|
186
|
+
- Keep one entry-point spec per independently released API surface, not one
|
|
187
|
+
giant file per repo.
|
|
141
188
|
- Split by product meaning: `recipes`, `ingredients`, `orders`, `jobs`, or
|
|
142
189
|
`inventory`, not by generic words like `common`, `misc`, or `helpers`.
|
|
190
|
+
- Keep API schema route hierarchies aligned with the selected HTTP style. When a
|
|
191
|
+
child route depends on a parent for authorization, tenancy, lifecycle, or
|
|
192
|
+
meaning, nest it under that parent unless the selected style documents a
|
|
193
|
+
different public pattern.
|
|
143
194
|
- Use short section markers only as editor landmarks inside a file that is still
|
|
144
195
|
small enough to review.
|
|
145
|
-
- Use `schema/shared/` only for cross-
|
|
146
|
-
an obvious owner.
|
|
147
|
-
- Prefer
|
|
148
|
-
|
|
149
|
-
- Keep
|
|
196
|
+
- Use `schema/shared/` only for cross-capability concepts with stable semantics
|
|
197
|
+
and an obvious owner.
|
|
198
|
+
- Prefer capability-local shared components when a concept is reused only inside
|
|
199
|
+
one product capability.
|
|
200
|
+
- Keep one-off schemas inside the surface that owns them. Do not move every
|
|
201
|
+
component into `shared/` to anticipate future reuse.
|
|
202
|
+
- Keep `info.title` deliberate because async schema NATS namespaces derive from it;
|
|
150
203
|
filenames and titles should not drift semantically.
|
|
151
204
|
- Keep `$ref` paths repo-relative and validate after moving files.
|
|
152
205
|
|
|
153
206
|
## Refactor order for oversized specs
|
|
154
207
|
|
|
155
|
-
1.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
3.
|
|
208
|
+
1. Keep one-off schemas local to the root or surface that owns them.
|
|
209
|
+
2. Extract repeated capability-only shapes into a capability-local `shared/`
|
|
210
|
+
folder.
|
|
211
|
+
3. Promote repeated cross-capability scalars, pagination, errors, envelopes,
|
|
212
|
+
schedules, and config objects into `schema/shared/` only when the same meaning
|
|
213
|
+
is reused across capabilities.
|
|
214
|
+
4. Split operations by API surface when the file still mixes independently owned
|
|
159
215
|
workflows.
|
|
160
|
-
|
|
161
|
-
|
|
216
|
+
5. Validate the moved refs with `sumr kontract validate`.
|
|
217
|
+
6. Generate with the smallest useful scope and review both the spec diff and
|
|
162
218
|
generated output diff.
|
|
163
219
|
|
|
164
220
|
## Refactor order for oversized code
|