@sumrco/cli 0.2.1 → 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.
Files changed (37) hide show
  1. package/ai/modules/kontract/resources/api-generation-standards.rf.md +83 -0
  2. package/ai/modules/kontract/resources/authoring/configuration.rf.md +220 -0
  3. package/ai/modules/kontract/resources/authoring/design-profile/api-styles.rf.md +241 -0
  4. package/ai/modules/kontract/resources/authoring/design-profile/async-styles.rf.md +134 -0
  5. package/ai/modules/kontract/resources/authoring/design-profile/overview.md +64 -0
  6. package/ai/modules/kontract/resources/authoring/design-profile/schema-layout-styles.rf.md +356 -0
  7. package/ai/modules/kontract/resources/authoring/overview.md +56 -0
  8. package/ai/modules/kontract/resources/authoring/schema-reuse.rf.md +492 -0
  9. package/ai/modules/kontract/resources/authoring/scope-and-splitting.rf.md +244 -0
  10. package/ai/modules/kontract/resources/authoring/spec-layout.rf.md +492 -0
  11. package/ai/modules/kontract/resources/authoring/team-members/spec-author.tm.md +77 -0
  12. package/ai/modules/kontract/resources/{workflows/contract-change.wf.md → authoring/workflows/spec-change.wf.md} +24 -16
  13. package/ai/modules/kontract/resources/generated-output.rf.md +185 -17
  14. package/ai/modules/kontract/resources/openapi-sdk-generator-research.rf.md +57 -0
  15. package/ai/modules/kontract/resources/overview.md +130 -44
  16. package/ai/modules/kontract/resources/performance.rf.md +7 -7
  17. package/ai/modules/kontract/sumr.module.yaml +5 -2
  18. package/ai/modules/mission/sumr.module.yaml +6 -0
  19. package/ai/modules/playbook/resources/authoring/content-structure.rf.md +1 -1
  20. package/ai/modules/playbook/resources/authoring/cross-referencing.rf.md +1 -1
  21. package/ai/modules/playbook/resources/authoring/descriptions.rf.md +1 -1
  22. package/ai/modules/playbook/resources/authoring/extraction.rf.md +1 -1
  23. package/ai/modules/playbook/resources/authoring/flows.rf.md +1 -1
  24. package/ai/modules/playbook/resources/authoring/folder-structure.rf.md +1 -1
  25. package/ai/modules/playbook/resources/authoring/frontmatter.rf.md +4 -1
  26. package/ai/modules/playbook/resources/authoring/markdown.rf.md +1 -1
  27. package/ai/modules/playbook/resources/authoring/overview.md +1 -1
  28. package/ai/modules/playbook/resources/team-members/{playbook-technical-writer.tm.md → technical-writer.tm.md} +3 -2
  29. package/ai/modules/playbook/sumr.module.yaml +7 -2
  30. package/index.js +486 -284
  31. package/package.json +1 -1
  32. package/ai/modules/kontract/resources/configuration.rf.md +0 -123
  33. package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +0 -61
  34. package/ai/modules/kontract/resources/schema-reuse.rf.md +0 -233
  35. package/ai/modules/kontract/resources/scope-and-splitting.rf.md +0 -147
  36. package/ai/modules/kontract/resources/spec-layout.rf.md +0 -69
  37. package/ai/modules/kontract/resources/team-members/contract-author.tm.md +0 -52
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sumrco/cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "SUMR public CLI",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1,123 +0,0 @@
1
- ---
2
- category: reference
3
- name: configuration
4
- title: Kontract Configuration
5
- description: "How `sumr.yaml` configures Kontract sources, targets, generator types, and NestJS output options."
6
- label: Configuration
7
- when: Adding a Kontract target, debugging missing generated files, or comparing generated output across repos
8
- order: 15
9
- ---
10
-
11
- # Kontract Configuration
12
-
13
- Kontract reads repo-local configuration from `sumr.yaml`. A source points at a
14
- schema directory; each target chooses an output directory and generator.
15
-
16
- ```yaml
17
- kontract:
18
- sources:
19
- - name: api
20
- input: schema
21
- targets:
22
- - name: backend
23
- output: backend/src/shared/models
24
- generator:
25
- type: typescript-nestjs
26
- zod: true
27
- dtos: true
28
- - name: frontend
29
- output: frontend/src/shared/api
30
- generator:
31
- type: typescript-fetch
32
- modelPropertyNaming: original
33
- paramNaming: original
34
- stringEnums: true
35
- ```
36
-
37
- ## Sources
38
-
39
- | Field | Meaning |
40
- |---|---|
41
- | `name` | Stable source name used by `--source`. |
42
- | `input` | Directory scanned recursively for `*.openapi.yml`, `*.openapi.yaml`, `*.asyncapi.yml`, and `*.asyncapi.yaml`. |
43
- | `targets` | One or more generated outputs. |
44
-
45
- Use `--source <name>` to scope validation or generation to one source.
46
-
47
- ## Targets
48
-
49
- | Field | Meaning |
50
- |---|---|
51
- | `name` | Stable target name used by `--target`. |
52
- | `output` | Root directory for generated output. Treat this folder as generated/read-only. |
53
- | `generator.type` | Generator family. |
54
-
55
- Use `--target <name>` to scope generation to one target.
56
-
57
- ## Generator types
58
-
59
- | Type | Purpose |
60
- |---|---|
61
- | `typescript-nestjs` | Backend HTTP contracts for NestJS services. |
62
- | `asyncapi-nats` | NATS subjects, message schemas, server interfaces, and clients. |
63
- | `typescript-fetch` | TypeScript fetch SDK. |
64
- | `typescript-axios` | TypeScript axios SDK. |
65
- | `typescript-angular` | Angular SDK. |
66
- | `typescript-models` | Framework-neutral model-only output. |
67
-
68
- ## `typescript-nestjs` options
69
-
70
- | Option | Output |
71
- |---|---|
72
- | `zod: true` | Emits `http/zod/*.contract.ts` with Zod schemas and `createZodDto()` classes. |
73
- | `dtos: true` | Emits `http/dto/*.dto.ts` plus `http/swagger.ts` operation metadata. |
74
-
75
- `dtos` is the canonical spelling. `dto: true` is accepted as a compatibility
76
- alias and is normalized internally to `dtos: true`.
77
-
78
- Framework-neutral interfaces under `http/models/` and enums under `http/enums/`
79
- are emitted for OpenAPI object schemas regardless of the Zod/DTO flavor.
80
-
81
- ## Common debugging cases
82
-
83
- ### `http/dto/` or `http/swagger.ts` is missing
84
-
85
- Check both:
86
-
87
- 1. The target config has `generator.type: typescript-nestjs` and `dtos: true`.
88
- `dto: true` is also accepted, but prefer `dtos` in new config.
89
- 2. The installed `SUMR Kontract module` version includes DTO/swagger support.
90
-
91
- If two configs generate identical output and both miss `dto/` + `swagger.ts`,
92
- the likely issue is the generator version being executed, not the consumer
93
- repo's config.
94
-
95
- ### `http/zod/` is missing
96
-
97
- Check that the NestJS target has `zod: true` or that Zod generation has not been
98
- explicitly disabled.
99
-
100
- ### Generated files are stale
101
-
102
- Run a scoped clean generation:
103
-
104
- ```bash
105
- sumr kontract generate --source api --target backend --clean
106
- ```
107
-
108
- Prefer scoping `--clean` in large repos so only the intended generated output
109
- and selected Kontract cache are removed before regeneration.
110
-
111
- ### Warm generation is still slow
112
-
113
- Kontract stores incremental manifests under `.sumr-cache/kontract`. An unchanged
114
- warm run should skip unchanged services before parse/emit and should not run a
115
- formatter subprocess.
116
-
117
- If warm runs regenerate everything, check for:
118
-
119
- 1. generated files being manually edited or deleted;
120
- 2. changing generator config in `sumr.yaml`;
121
- 3. a changed installed `SUMR Kontract module` version;
122
- 4. ambiguous or remote `$ref` usage that forces the safe path;
123
- 5. `--clean`, which intentionally clears selected output and cache state.
@@ -1,61 +0,0 @@
1
- ---
2
- category: reference
3
- name: openapi-generator-lessons
4
- title: OpenAPI Generator Bug Lessons
5
- description: "Hardening lessons Kontract applies from public OpenAPI Generator NestJS/TypeScript bug reports. Use when reviewing generated output risks, query parameters, inline schemas, and strict TypeScript compatibility."
6
- label: OpenAPI Generator Lessons
7
- when: Reviewing Kontract specs or generator changes for known OpenAPI/NestJS codegen failure modes
8
- order: 45
9
- ---
10
-
11
- # OpenAPI Generator Bug Lessons
12
-
13
- Kontract learns from public OpenAPI/NestJS generator bugs without inheriting their
14
- architecture. These lessons are guardrails for spec authors, reviewers, and AI agents
15
- working on generated contracts.
16
-
17
- ## Core lessons
18
-
19
- - **Preserve query parameter semantics.** Optional query params stay optional, array query
20
- params serialize as repeated keys, and enum query params use generated enum symbols instead
21
- of raw literal imports.
22
- - **Do not let wire names become unsafe local variables.** Parameter names such as `from`,
23
- `class`, and `default` must remain valid wire keys while generated local identifiers are
24
- safe TypeScript names.
25
- - **Prefer component `$ref` schemas over anonymous inline operation models.** Kontract rejects
26
- inline request/response schemas because anonymous model naming commonly causes duplicate
27
- `InlineObject` outputs and unstable imports.
28
- - **Generate maps deliberately.** `additionalProperties` map schemas must preserve named
29
- properties and typed catch-all/index-signature values consistently across Zod, DTOs, models,
30
- and SDK output. Unsupported `oneOf`, `anyOf`, `not`, and discriminators should produce clear
31
- errors instead of partially generated code with missing symbols such as `AnyType` or
32
- `InnerEnum`.
33
- - **Keep NestJS ownership boundaries clean.** Kontract emits contracts, DTOs, models, swagger
34
- metadata, and SDK clients. Application modules, controllers, providers, and DI wiring stay in
35
- the consuming NestJS app.
36
- - **Compile generated code under strict TypeScript assumptions.** Generated output should avoid
37
- dangling imports, deprecated Nest HTTP client imports, stale `basePath` globals, `Map` headers
38
- where records are expected, and framework symbols that were never emitted.
39
- - **Stay Bun-native.** Kontract does not depend on Java, Docker images, downloaded generator
40
- binaries, or template folders at generation time.
41
-
42
- ## Spec authoring rules
43
-
44
- - Put reusable request/response bodies, parameters, enums, and object fragments under
45
- `components` and reference them with `$ref`.
46
- - Encode validation constraints in the OpenAPI schema (`minLength`, `maxLength`, `minimum`,
47
- `maximum`, `pattern`, `format`) so DTO/Zod output can enforce them.
48
- - Use `additionalProperties` when the payload is intentionally map-shaped. Prefer typed map values
49
- over `additionalProperties: true`; Kontract preserves named fields and emits a safe unknown
50
- catch-all when the spec intentionally allows arbitrary values.
51
- - For repeated query values, use `type: array` with scalar `items`; generated SDKs must not
52
- collapse values into comma-separated strings.
53
-
54
- ## Reviewer checklist
55
-
56
- - Generated files include the auto-generated header and are not hand-edited.
57
- - Query DTOs and SDK request types preserve optionality from the spec.
58
- - No generated file contains `any`, `AnyType`, `InlineObject`, `InnerEnum`, `queryParameters`,
59
- deprecated `HttpService`, stale `basePath`, or unsafe `apiKeys` access.
60
- - Operation schemas reference named components instead of inline request/response objects.
61
- - Unsupported schema features fail before any consumer repo is left with partial broken output.
@@ -1,233 +0,0 @@
1
- ---
2
- category: reference
3
- name: schema-reuse
4
- title: Schema Reuse and Shared Components
5
- description: "How to author OpenAPI/AsyncAPI specs with reusable shared components, $ref, and safe composition so Kontract output stays consistent and avoids copy-pasted contract drift."
6
- label: Schema Reuse
7
- when: Adding repeated fields, response envelopes, pagination, errors, schedules, config objects, or reviewing generated diffs with duplicated DTO/model shapes
8
- order: 12
9
- ---
10
-
11
- # Schema Reuse and Shared Components
12
-
13
- Kontract works best when the spec is designed like a product API, not like a
14
- collection of copied YAML snippets. If the same concept appears in multiple
15
- operations or services, define it once and reference it with `$ref`.
16
-
17
- This reduces drift in the source specs immediately. It also gives Kontract a
18
- clear path to emit more shared generated code as the generator evolves.
19
-
20
- ## What to share
21
-
22
- Prefer shared components for concepts that mean the same thing everywhere:
23
-
24
- - scalar primitives: UUIDs, ISO dates, slugs, URLs, MIME types, time strings;
25
- - path/query parameters: `id`, `recipeId`, pagination, date ranges;
26
- - standard error responses and error body schemas;
27
- - pagination metadata;
28
- - common response envelope fields such as `success`, `timestamp`, `path`, and
29
- optional `message`;
30
- - weekly schedules and reusable time-slot shapes;
31
- - repeated configuration objects, such as measurement units, recipe step labels,
32
- display colors, notification settings, or payment settings when they truly
33
- share semantics.
34
-
35
- Example shared scalar and parameter file:
36
-
37
- ```yaml
38
- # schema/shared/common.yml
39
- components:
40
- schemas:
41
- UuidString:
42
- type: string
43
- format: uuid
44
- ImageMimeType:
45
- type: string
46
- pattern: '^image\/(jpeg|png|webp|gif)$'
47
- PaginationMeta:
48
- type: object
49
- required: [page, pageSize, pageCount, total]
50
- properties:
51
- page:
52
- type: integer
53
- minimum: 1
54
- pageSize:
55
- type: integer
56
- minimum: 1
57
- pageCount:
58
- type: integer
59
- minimum: 0
60
- total:
61
- type: integer
62
- minimum: 0
63
- parameters:
64
- id:
65
- name: id
66
- in: path
67
- required: true
68
- schema:
69
- $ref: '#/components/schemas/UuidString'
70
- ```
71
-
72
- Use those components from service specs:
73
-
74
- ```yaml
75
- parameters:
76
- - $ref: ../shared/common.yml#/components/parameters/id
77
- content:
78
- application/json:
79
- schema:
80
- $ref: ../shared/common.yml#/components/schemas/ImageMimeType
81
- ```
82
-
83
- ## Response envelopes
84
-
85
- If every endpoint repeats the same envelope fields, do not retype them in every
86
- schema. Put the shared part in a component and compose concrete responses with
87
- `allOf`.
88
-
89
- ```yaml
90
- # schema/shared/common.yml
91
- components:
92
- schemas:
93
- SuccessResponseBase:
94
- type: object
95
- required: [success, timestamp, path]
96
- properties:
97
- success:
98
- type: boolean
99
- timestamp:
100
- type: string
101
- format: date-time
102
- path:
103
- type: string
104
- message:
105
- type: string
106
- ```
107
-
108
- ```yaml
109
- # schema/recipes/catalog.openapi.yml
110
- components:
111
- schemas:
112
- RecipesFindOneResponse:
113
- allOf:
114
- - $ref: ../shared/common.yml#/components/schemas/SuccessResponseBase
115
- - type: object
116
- required: [data]
117
- properties:
118
- data:
119
- $ref: '#/components/schemas/RecipeResponse'
120
- ```
121
-
122
- Use the same pattern for paginated responses:
123
-
124
- ```yaml
125
- components:
126
- schemas:
127
- RecipesFindAllResponse:
128
- allOf:
129
- - $ref: ../shared/common.yml#/components/schemas/SuccessResponseBase
130
- - type: object
131
- required: [data]
132
- properties:
133
- data:
134
- type: array
135
- items:
136
- $ref: '#/components/schemas/RecipeResponse'
137
- meta:
138
- $ref: ../shared/common.yml#/components/schemas/PaginationMeta
139
- ```
140
-
141
- Kontract supports object `allOf` composition by flattening supported object refs
142
- and inline object parts. Today this mainly reduces YAML duplication and contract
143
- semantic drift. It may still emit concrete generated DTO/model properties per
144
- response until the generator grows preserved composition or shared-output
145
- emission.
146
-
147
- ## Schedules and repeated nested objects
148
-
149
- If several features define the same day-of-week schedule or time-slot object,
150
- share the object definitions instead of duplicating each day shape.
151
-
152
- ```yaml
153
- # schema/shared/scheduling.yml
154
- components:
155
- schemas:
156
- WeeklyTimeSlot:
157
- type: object
158
- required: [from, to]
159
- properties:
160
- from:
161
- type: string
162
- pattern: '^(0[6-9]|1\d|2[0-3]):[0-5]\d$'
163
- to:
164
- type: string
165
- pattern: '^(0[6-9]|1\d|2[0-3]):[0-5]\d$'
166
- WeeklySchedule:
167
- type: object
168
- properties:
169
- sunday:
170
- type: array
171
- items:
172
- $ref: '#/components/schemas/WeeklyTimeSlot'
173
- monday:
174
- type: array
175
- items:
176
- $ref: '#/components/schemas/WeeklyTimeSlot'
177
- ```
178
-
179
- Then service-specific schedules can reference or compose those shared pieces.
180
-
181
- ## Review checklist
182
-
183
- After writing or updating any `*.openapi.yml` or `*.asyncapi.yml` file, review
184
- the spec before running generation. Actively look for these smells:
185
-
186
- - the same `success/timestamp/path/message` fields repeated in many response
187
- schemas;
188
- - identical pagination `meta` objects or `PaginationMeta` definitions copied
189
- across services instead of referencing a shared component;
190
- - many `id` parameters declared inline instead of referencing a shared
191
- parameter;
192
- - inline UUID, date, date-time, URL, slug, or enum-like scalar constraints that
193
- already exist in a shared component;
194
- - identical regex patterns copied into multiple schemas;
195
- - repeated day-of-week schedule structures;
196
- - error response schemas or problem-details bodies copied instead of referencing
197
- shared responses;
198
- - event envelopes or AsyncAPI reply wrappers copied with the same product
199
- meaning;
200
- - generated diffs adding many near-identical DTO/model files after a small API
201
- change.
202
-
203
- When you see a smell, propose a shared component before generating.
204
-
205
- ## When not to share
206
-
207
- Do not share only because two shapes currently look alike. Keep separate
208
- components when:
209
-
210
- - endpoints have different validation rules or lifecycle/backwards-compatibility
211
- needs;
212
- - a request DTO and response DTO intentionally differ, even if fields overlap;
213
- - names would become vague (`CommonThing`, `BaseData`, `GenericConfig`);
214
- - sharing would force unrelated teams/domains to coordinate every future change.
215
-
216
- A good shared component has a clear product meaning and a stable owner.
217
-
218
- ## Safe workflow
219
-
220
- 1. Move the repeated shape into `schema/shared/*.yml` or a domain-level shared
221
- component.
222
- 2. Replace duplicated schemas/parameters/responses with `$ref`.
223
- 3. Use supported `allOf` object composition when a concrete response extends a
224
- shared base.
225
- 4. Run `sumr kontract validate`.
226
- 5. Run a scoped generation first, for example:
227
-
228
- ```bash
229
- sumr kontract generate --source api --target backend --specific recipes/catalog
230
- ```
231
-
232
- 6. Review both the spec diff and generated diff. If generated output changed in
233
- unrelated domains, stop and investigate before committing.
@@ -1,147 +0,0 @@
1
- ---
2
- category: reference
3
- name: scope-and-splitting
4
- title: Scope, Size, and Splitting
5
- description: "How to keep Kontract specs and generator code small, domain-aligned, and reviewable with explicit line-count budgets and split triggers."
6
- label: Scope and Splitting
7
- when: Reviewing large specs or code files, deciding whether to split a domain/subdomain spec, or optimizing oversized Kontract modules
8
- order: 18
9
- ---
10
-
11
- # Scope, Size, and Splitting
12
-
13
- Kontract is the next iteration of the AutoSync/AsyncAPI idea: keep the
14
- documentation-first and DRY discipline, but make the boundaries more explicit.
15
- Large files are not automatically bad, but they hide duplicated concepts,
16
- mixed domains, and unstable generated output. Treat size limits as review
17
- triggers first and hard caps second.
18
-
19
- ## Source-of-truth rule
20
-
21
- Put durable guidance in Playbook resources and module docs; generated editor
22
- rules should point back to those resources. Do not copy long rules into Cursor,
23
- Claude, Codex, or generated contracts. The source contract spec and the source
24
- Playbook resource are the maintained truth.
25
-
26
- ## Public example hygiene
27
-
28
- Files under `resources/` become public AI guidance. Never use internal SUMR,
29
- customer, product, infrastructure, event-subject, route, table, or data-model
30
- examples there. Public examples must be sanitized and generic.
31
-
32
- Use neutral domains such as:
33
-
34
- - kitchen recipes and ingredients;
35
- - bookstore inventory;
36
- - parcel shipping;
37
- - job hierarchies and departments;
38
- - todos or calendar events.
39
-
40
- Prefer `example.*`, `recipes`, `orders`, `ingredients`, `jobs`, or similarly
41
- generic names. Do not use real service names, internal nouns, customer nouns,
42
- NATS subject prefixes, API paths, or entity relationships as examples. Internal
43
- examples are acceptable in private `docs/` only when they are necessary to
44
- explain the module's current behavior.
45
-
46
- ## File size budgets
47
-
48
- | File kind | Healthy target | Review trigger | Split/optimize trigger | Hard stop |
49
- |---|---:|---:|---:|---:|
50
- | Kontract TypeScript source | <= 200 lines | > 250 lines | > 400 lines | > 500 lines |
51
- | OpenAPI/AsyncAPI service spec | 150-350 lines | > 400 lines | > 700 lines | > 1000 lines |
52
- | Shared component YAML | 100-300 lines | > 400 lines | > 600 lines | > 900 lines |
53
- | Generated TypeScript output | no manual target | review if surprising | fix generator/spec, never hand-split | no hand edits |
54
-
55
- Exceptions require a documented reason in the PR or handoff. Generated files,
56
- large fixtures, and intentionally dense compatibility snapshots are exempt from
57
- manual splitting, but they can still reveal generator or spec-design problems.
58
-
59
- ## Split triggers
60
-
61
- Split or optimize before adding more content when a file shows any of these:
62
-
63
- - multiple product domains or subdomains in one spec;
64
- - more than roughly 7-10 operations with different lifecycle owners;
65
- - request/response schemas for unrelated use cases in one component block;
66
- - repeated envelope, pagination, error, scalar, schedule, or config shapes;
67
- - repeated operation patterns that should become shared parameters/responses;
68
- - a TypeScript file with orchestration, parsing, emitting, IO, and formatting
69
- responsibilities mixed together;
70
- - a generated diff where a small spec change creates many near-identical files.
71
-
72
- Do not split only by line count. First identify the product or technical
73
- boundary that gives the new file a stable name and owner.
74
-
75
- ## Domain and subdomain spec structure
76
-
77
- Use directory nesting to communicate product ownership. The path should answer
78
- "who owns this contract?" and the filename should answer "which surface is this?"
79
-
80
- ```text
81
- schema/
82
- shared/
83
- scalars.yml
84
- pagination.yml
85
- errors.yml
86
- events.yml
87
- scheduling.yml
88
- recipes/
89
- recipes.openapi.yml
90
- ingredients.openapi.yml
91
- publishing.asyncapi.yml
92
- kitchen/
93
- stations.openapi.yml
94
- prep-jobs.asyncapi.yml
95
- inventory.asyncapi.yml
96
- ```
97
-
98
- Guidelines:
99
-
100
- - Keep one entry-point spec per bounded API surface, not one giant file per
101
- repo.
102
- - Split by product meaning: `recipes`, `ingredients`, `orders`, `jobs`, or
103
- `inventory`, not by generic words like `common`, `misc`, or `helpers`.
104
- - Use `schema/shared/` only for cross-domain concepts with stable semantics and
105
- an obvious owner.
106
- - Prefer domain-local shared components when a concept is reused only inside one
107
- domain.
108
- - Keep `info.title` deliberate because AsyncAPI NATS namespaces derive from it;
109
- filenames and titles should not drift semantically.
110
- - Keep `$ref` paths repo-relative and validate after moving files.
111
-
112
- ## Refactor order for oversized specs
113
-
114
- 1. Extract repeated cross-domain scalars, pagination, errors, envelopes, events,
115
- schedules, and config objects into `schema/shared/`.
116
- 2. Extract repeated domain-only shapes into a domain-local shared YAML file.
117
- 3. Split operations by subdomain when the file still mixes independently owned
118
- workflows.
119
- 4. Validate the moved refs with `sumr kontract validate`.
120
- 5. Generate with the smallest useful scope and review both the spec diff and
121
- generated output diff.
122
-
123
- ## Refactor order for oversized code
124
-
125
- 1. Name the current responsibilities in the file.
126
- 2. Extract pure helpers first, then emitters/readers, then orchestration.
127
- 3. Move interfaces and types into `src/types/` or `*.types.ts`; logic files
128
- should import types instead of declaring them inline.
129
- 4. Move reusable constants to `src/lib/constants.ts` or the existing constants
130
- module.
131
- 5. Add or adjust focused tests around the extracted seam before broad rewrites.
132
-
133
- Prefer small safe extractions over a big rewrite. The goal is a clearer module
134
- boundary, not a larger abstraction layer.
135
-
136
- ## Review checklist
137
-
138
- Before accepting a large spec or source file:
139
-
140
- - [ ] The file is under the healthy target, or the reason for exceeding it is
141
- documented.
142
- - [ ] The file has one clear product/technical owner.
143
- - [ ] Shared concepts are referenced with `$ref` rather than copied.
144
- - [ ] No generic bucket names (`common`, `misc`, `utils`) hide unrelated
145
- responsibilities.
146
- - [ ] Generated output changes match the intended API surface only.
147
- - [ ] Any split keeps spec and regenerated output committed together.
@@ -1,69 +0,0 @@
1
- ---
2
- category: reference
3
- name: spec-layout
4
- title: Spec File Layout
5
- description: "Required folder and file conventions for Kontract OpenAPI/AsyncAPI source specs."
6
- label: Spec Layout
7
- when: Creating or moving API spec files, adding a shared base spec, or debugging why a spec is not picked up
8
- order: 10
9
- ---
10
-
11
- # Spec File Layout
12
-
13
- Kontract discovers specs by filename convention under the configured schema
14
- directory (default `schema/`).
15
-
16
- ```text
17
- schema/
18
- recipes.openapi.yml ← one OpenAPI doc per service/domain
19
- recipes.asyncapi.yml ← one AsyncAPI doc per service/domain
20
- base.yml ← shared components, referenced via $ref
21
- ```
22
-
23
- ## Rules
24
-
25
- - OpenAPI specs end in `*.openapi.yml` / `*.openapi.yaml`.
26
- - AsyncAPI specs end in `*.asyncapi.yml` / `*.asyncapi.yaml`.
27
- - Discovery is recursive; `base.yml` is skipped as an entry point.
28
- - Service output paths mirror nested spec paths under the configured source
29
- input directory.
30
- - Use nested domain/subdomain paths when one root file would mix independently
31
- owned API surfaces; see the scope and splitting reference for line-count
32
- thresholds and naming rules.
33
- - Share common schemas through `$ref` into `base.yml`. Do **not** duplicate
34
- schemas across specs and do **not** merge by hand-mutating parsed JSON.
35
- - Prefer a `schema/shared/` folder for cross-domain components such as common
36
- parameters, error responses, pagination, scalar constraints, response envelope
37
- fragments, schedules, and reusable config objects.
38
- - The NATS namespace comes from the AsyncAPI `info.title`, not the filename —
39
- set `info.title` deliberately.
40
- - Multi-file specs are bundled automatically (OpenAPI via Redocly core in-process
41
- with CLI fallback, AsyncAPI via `@asyncapi/cli bundle`); keep `$ref` paths
42
- repo-relative.
43
-
44
- ## OpenAPI authoring rules
45
-
46
- - Put reusable HTTP payloads in `components.schemas`.
47
- - Operation request/response schemas should reference components with `$ref`.
48
- Inline operation schemas are rejected so generated DTO/model names stay stable.
49
- - Prefer explicit object schemas over anonymous nested shapes when a payload is
50
- shared by multiple operations.
51
- - If multiple responses repeat the same envelope fields, extract the envelope
52
- fragment and compose concrete responses with supported object `allOf`.
53
- - If multiple schemas repeat the same regex or scalar validation, extract a
54
- named scalar component and reference it.
55
- - Use stable `operationId` values. They become Swagger metadata constants such
56
- as `SWG_LIST_RECIPES`.
57
- - Unsupported composition features (`oneOf`, `anyOf`, `not`, `discriminator`)
58
- must either be modeled differently or implemented in Kontract before use.
59
-
60
- ## AsyncAPI operation classification
61
-
62
- | AsyncAPI shape | Generated client kind |
63
- |---------------------|-----------------------|
64
- | `receive` + `reply` | Query |
65
- | `receive` | Command |
66
- | `send` | Event |
67
-
68
- Run `sumr kontract validate` after any layout change to confirm specs still
69
- resolve before generating.