@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.
- package/ai/modules/kontract/resources/api-generation-standards.rf.md +83 -0
- package/ai/modules/kontract/resources/authoring/configuration.rf.md +220 -0
- 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/authoring/schema-reuse.rf.md +492 -0
- package/ai/modules/kontract/resources/authoring/scope-and-splitting.rf.md +244 -0
- 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} +24 -16
- package/ai/modules/kontract/resources/generated-output.rf.md +185 -17
- package/ai/modules/kontract/resources/openapi-sdk-generator-research.rf.md +57 -0
- package/ai/modules/kontract/resources/overview.md +130 -44
- package/ai/modules/kontract/resources/performance.rf.md +7 -7
- package/ai/modules/kontract/sumr.module.yaml +5 -2
- 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 +486 -284
- package/package.json +1 -1
- package/ai/modules/kontract/resources/configuration.rf.md +0 -123
- package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +0 -61
- package/ai/modules/kontract/resources/schema-reuse.rf.md +0 -233
- package/ai/modules/kontract/resources/scope-and-splitting.rf.md +0 -147
- package/ai/modules/kontract/resources/spec-layout.rf.md +0 -69
- package/ai/modules/kontract/resources/team-members/contract-author.tm.md +0 -52
package/package.json
CHANGED
|
@@ -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.
|