micro-contracts 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,366 @@
1
+ # Screen Spec — Frontend Screen Contracts in OpenAPI
2
+
3
+ The Screen Spec feature repurposes standard OpenAPI constructs (`paths`, `schemas`, `links`, `security`) to declaratively define **frontend screen contracts** — bridging the API layer and UI components. A single YAML file drives frontend types, test scaffolding, and quality analysis.
4
+
5
+ ```
6
+ Screen Spec (OpenAPI YAML)
7
+ ├── micro-contracts generate ──┬── ViewModel Types (type-safe)
8
+ │ ├── Navigation Map (typed routing)
9
+ │ └── Event Hooks (typed analytics)
10
+ ├── E2E scaffold ─── Playwright test stubs + coverage
11
+ └── Data lineage ─── ViewModel → API → DB traceability
12
+ ```
13
+
14
+ > **Important**: This is NOT "auto-generated UI from schema" but rather **screen-level contract definition**, which aligns with micro-contracts' "Contract-first vertical slices" philosophy.
15
+
16
+ ---
17
+
18
+ ## The HTTP-Screen Analogy
19
+
20
+ Standard OpenAPI semantics map directly to screen specification concepts:
21
+
22
+ | OpenAPI Construct | API Usage | Screen Spec Usage |
23
+ | ---------------------- | ---------------------- | ------------------------------------------------------- |
24
+ | `paths: /home` | Endpoint | React/Vue route |
25
+ | `GET /home` | Fetch resource | **Render screen** — what the user sees |
26
+ | `POST /home` | Create/modify resource | **User action** — what the user can do |
27
+ | `parameters` | Filter/identify | **Screen init params** — route/query params |
28
+ | `responses.200.schema` | Response shape | **ViewModel** — typed interface for the screen |
29
+ | `requestBody` | Submitted data shape | **Action payload** — typed user action interface |
30
+ | `links` | HATEOAS related resources | **Forward navigation** — statically known screen targets |
31
+ | `security` | Auth requirement | **Auth guard** — does the screen require login? |
32
+
33
+ All standard OpenAPI tooling works out of the box: linters, documentation generators, and diff tools.
34
+
35
+ ---
36
+
37
+ ## Required Extensions (`x-*`)
38
+
39
+ Only concerns with **no OpenAPI-native representation** need extensions:
40
+
41
+ | Extension | Required | Purpose | Justification |
42
+ | ------------------- | -------- | ----------------------------------------- | --------------------------------------------------------------- |
43
+ | `x-screen-const` | Yes* | Stable constant name (e.g., `HOME`) | No OpenAPI equivalent for generated symbol names |
44
+ | `x-screen-id` | Yes | Traceability ID (e.g., `SCR-001`) | Links to requirements and E2E annotations |
45
+ | `x-screen-name` | Yes* | Generated symbol name (e.g., `HomePage`) | Drives `use{Name}Events()`, `wrap{Name}ViewModel()` |
46
+ | `x-back-navigation` | No | History-based back navigation support | `links` only cover forward navigation with known targets |
47
+ | `x-events` | No | Analytics event declarations | No OpenAPI concept for client-side event tracking |
48
+ | `x-view-model` | No | Explicit ViewModel schema name | Alternative to auto-inference from `$ref` |
49
+ | `x-view-props` | No | ViewProps interface name | For framework-specific wrapper generation |
50
+
51
+ \* When `x-screen-id` is present, `x-screen-const` and `x-screen-name` are required (enforced by lint).
52
+
53
+ ---
54
+
55
+ ## Quick Start
56
+
57
+ ### 1. Initialize a Screen Module
58
+
59
+ ```bash
60
+ npx micro-contracts init myScreens --screens
61
+ ```
62
+
63
+ This command generates:
64
+ - `spec/myScreens/openapi/myScreens.yaml` — Starter screen spec (2-screen scaffold)
65
+ - `spec/default/templates/screen-navigation.hbs` — Navigation map template
66
+ - `spec/default/templates/screen-events.hbs` — Event hooks template
67
+ - `micro-contracts.config.yaml` — Module config with `screen: true`
68
+
69
+ ### 2. Edit the Screen Spec
70
+
71
+ Edit `spec/myScreens/openapi/myScreens.yaml` to add your screen definitions.
72
+
73
+ ### 3. Generate Code
74
+
75
+ ```bash
76
+ npx micro-contracts generate
77
+ ```
78
+
79
+ Generated artifacts:
80
+ - `packages/contract/myScreens/schemas/types.ts` — ViewModel TypeScript types
81
+ - `frontend/src/screens/navigation.generated.ts` — Navigation map
82
+ - `frontend/src/screens/events.generated.ts` — Analytics event hooks
83
+
84
+ ---
85
+
86
+ ## Configuration
87
+
88
+ ### `micro-contracts.config.yaml`
89
+
90
+ Screen modules are enabled with the `screen: true` flag:
91
+
92
+ ```yaml
93
+ modules:
94
+ myScreens:
95
+ openapi: spec/myScreens/openapi/myScreens.yaml
96
+ screen: true
97
+ outputs:
98
+ frontend-api:
99
+ enabled: false # Not needed for screen modules
100
+ screen-navigation:
101
+ output: frontend/src/screens/navigation.generated.ts
102
+ template: screen-navigation.hbs
103
+ screen-events:
104
+ output: frontend/src/screens/events.generated.ts
105
+ template: screen-events.hbs
106
+ ```
107
+
108
+ Effects of `screen: true`:
109
+ - Suppresses `x-micro-contracts-service` / `x-micro-contracts-method` lint warnings
110
+ - Populates `TemplateContext.screens` with pre-parsed `ScreenContext[]`
111
+ - Enables screen-specific lint rules (`x-screen-id` requires `x-screen-const`/`x-screen-name`)
112
+
113
+ ---
114
+
115
+ ## Screen Spec YAML Structure
116
+
117
+ ```yaml
118
+ openapi: '3.1.0'
119
+ info:
120
+ title: App Screen Specification
121
+ version: '1.0.0'
122
+ description: Screen contracts — not a server API
123
+ servers:
124
+ - url: /
125
+ description: Screen routes (client-side)
126
+
127
+ paths:
128
+ /home:
129
+ get:
130
+ operationId: renderHomePage
131
+ security: [{session: []}]
132
+ x-screen-const: HOME
133
+ x-screen-id: SCR-001
134
+ x-screen-name: HomePage
135
+ x-back-navigation: false
136
+ x-events:
137
+ - name: home_view
138
+ type: screen_view
139
+ method: trackView
140
+ - name: sign_out
141
+ type: user_action
142
+ method: trackSignOut
143
+ summary: Render home page
144
+ responses:
145
+ '200':
146
+ description: Home page ViewModel
147
+ content:
148
+ application/json:
149
+ schema:
150
+ $ref: '#/components/schemas/HomePageViewModel'
151
+ links:
152
+ goToSettings:
153
+ operationId: renderSettingsPage
154
+ goToChat:
155
+ operationId: renderChatPage
156
+ ```
157
+
158
+ ### Field Reference
159
+
160
+ **`operationId`** — Unique identifier referenced by generated code. The naming convention `render` + screen name + `Page` is recommended.
161
+
162
+ **`security`** — Auth guard. `[{session: []}]` means authentication is required; `[]` means no authentication needed.
163
+
164
+ **`x-screen-const`** — SCREAMING_SNAKE_CASE name used for constant access like `SCREENS.HOME`.
165
+
166
+ **`x-screen-id`** — Unique ID for requirements and test traceability. The format `SCR-{domain}-{number}` is recommended.
167
+
168
+ **`x-screen-name`** — PascalCase name for generated symbols like `useHomePageEvents()`.
169
+
170
+ **`x-back-navigation`** — When `true`, declares that the screen supports browser back or UI back button navigation. Unlike forward navigation covered by `links`, the back destination is determined at runtime.
171
+
172
+ **`x-events`** — Array of analytics event declarations. Each event has `name` (event name), `type` (category), and `method` (generated method name), with an optional `params` map of parameter names to types.
173
+
174
+ **`responses.200.links`** — Forward navigation targets. References target screens by `operationId`.
175
+
176
+ **`POST` operations** — A `POST` on the same path defines user actions (form submissions, button taps, etc.). Specify the action payload schema in `requestBody`.
177
+
178
+ ---
179
+
180
+ ## TemplateContext.screens
181
+
182
+ When `screen: true` is enabled, `TemplateContext` includes a pre-parsed `screens: ScreenContext[]`. This eliminates the need to iterate over deeply nested `spec.paths` in templates.
183
+
184
+ ```typescript
185
+ interface ScreenContext {
186
+ route: string; // '/home'
187
+ screenConst: string; // 'HOME'
188
+ screenId: string; // 'SCR-001'
189
+ screenName: string; // 'HomePage'
190
+ operationId: string; // 'renderHomePage'
191
+ supportsBack: boolean; // false
192
+ viewModelSchema: string; // 'HomePageViewModel'
193
+ links: ScreenLink[]; // [{name, targetRoute, targetOperationId}]
194
+ events: ScreenEventDefinition[]; // [{name, type, method, params?}]
195
+ requiresAuth: boolean; // true
196
+ }
197
+ ```
198
+
199
+ ### Template Usage Comparison
200
+
201
+ **Using `screens[]` (recommended):**
202
+
203
+ ```handlebars
204
+ {{#each screens}}
205
+ {{screenConst}}: { id: '{{screenId}}', route: '{{route}}' },
206
+ {{/each}}
207
+ ```
208
+
209
+ **Iterating `spec.paths` directly (not recommended):**
210
+
211
+ ```handlebars
212
+ {{#each spec.paths}}
213
+ {{#each this}}
214
+ {{#unless (eq @key "parameters")}}
215
+ {{#unless (eq @key "servers")}}
216
+ {{#unless (eq @key "summary")}}
217
+ {{#unless (eq @key "description")}}
218
+ {{#if this.x-screen-id}}
219
+ {{this.x-screen-const}}: { id: '{{this.x-screen-id}}', route: '{{@../key}}' },
220
+ {{/if}}
221
+ {{/unless}}
222
+ {{/unless}}
223
+ {{/unless}}
224
+ {{/unless}}
225
+ {{/each}}
226
+ {{/each}}
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Default Templates
232
+
233
+ ### screen-navigation.hbs
234
+
235
+ Generates a navigation map. Outputs a `SCREENS` constant and `*_PAGE_LINKS` for each screen.
236
+
237
+ Example output:
238
+
239
+ ```typescript
240
+ const _OP_ROUTES = {
241
+ renderHomePage: '/home',
242
+ renderSettingsPage: '/settings',
243
+ renderChatPage: '/chat',
244
+ } as const;
245
+
246
+ export const SCREENS = {
247
+ HOME: { id: 'SCR-001' as const, route: _OP_ROUTES.renderHomePage, supportsBack: false } as const,
248
+ SETTINGS: { id: 'SCR-002' as const, route: _OP_ROUTES.renderSettingsPage, supportsBack: true } as const,
249
+ } as const;
250
+
251
+ export const HOME_PAGE_LINKS = {
252
+ goToSettings: _OP_ROUTES.renderSettingsPage,
253
+ goToChat: _OP_ROUTES.renderChatPage,
254
+ } as const;
255
+ ```
256
+
257
+ ### screen-events.hbs
258
+
259
+ Generates analytics event hooks. Outputs a `use{ScreenName}Events()` function for each screen that has `x-events`.
260
+
261
+ Example output:
262
+
263
+ ```typescript
264
+ export function useHomePageEvents() {
265
+ return {
266
+ trackView: () =>
267
+ trackEvent('home_view', 'screen_view', {}),
268
+ trackSignOut: () =>
269
+ trackEvent('sign_out', 'user_action', {}),
270
+ };
271
+ }
272
+ ```
273
+
274
+ Events with parameters are also supported with type safety:
275
+
276
+ ```typescript
277
+ export function useChatPageEvents() {
278
+ return {
279
+ trackMessageSend: (message_length: number) =>
280
+ trackEvent('chat_message_send', 'user_action', { message_length }),
281
+ };
282
+ }
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Lint Rules
288
+
289
+ `micro-contracts lint` performs the following screen-specific checks:
290
+
291
+ | Code | Level | Description |
292
+ | ----------------------------- | ------- | -------------------------------------------------------- |
293
+ | `SCREEN_MISSING_CONST` | Error | `x-screen-id` present but `x-screen-const` missing |
294
+ | `SCREEN_MISSING_NAME` | Error | `x-screen-id` present but `x-screen-name` missing |
295
+ | `SCREEN_MISSING_OPERATION_ID` | Error | Screen operation missing `operationId` |
296
+ | `SCREEN_INVALID_EVENTS` | Error | `x-events` is not an array |
297
+ | `SCREEN_INVALID_EVENT` | Error | `x-events` item missing `name`, `type`, or `method` |
298
+
299
+ In `screen: true` modules, `MISSING_X_SERVICE` / `MISSING_X_METHOD` warnings are suppressed (screen specs do not need service/method declarations).
300
+
301
+ ---
302
+
303
+ ## Custom Templates
304
+
305
+ You can extend the default templates or create new ones for additional generated artifacts. All `ScreenContext` fields are available in templates.
306
+
307
+ ### ViewProps Template Example
308
+
309
+ `spec/default/templates/screen-view-props.hbs`:
310
+
311
+ ```handlebars
312
+ {{#each screens}}
313
+ export interface {{screenName}}ViewProps {
314
+ // ViewModel: {{viewModelSchema}}
315
+ // Screen ID: {{screenId}}
316
+ }
317
+ {{/each}}
318
+ ```
319
+
320
+ Add to config:
321
+
322
+ ```yaml
323
+ outputs:
324
+ screen-view-props:
325
+ output: frontend/src/screens/view-props.generated.ts
326
+ template: screen-view-props.hbs
327
+ ```
328
+
329
+ ### Available Template Context
330
+
331
+ | Field | Type | Description |
332
+ | ----------------- | --------- | -------------------------------------------------- |
333
+ | `screens` | array | `ScreenContext[]` — array of screen definitions |
334
+ | `spec` | object | Raw OpenAPI spec (for direct access when needed) |
335
+ | `title` | string | OpenAPI title |
336
+ | `version` | string | OpenAPI version |
337
+ | `moduleName` | string | Module name |
338
+ | `contractPackage` | string | Contract package import path |
339
+ | `schemaNames` | string[] | All schema names |
340
+
341
+ ---
342
+
343
+ ## Tiered Integration
344
+
345
+ ### Tier 1 — Core (built into micro-contracts)
346
+
347
+ - Type definitions: `x-screen-*` fields on `OperationObject`
348
+ - Screen context extraction: `TemplateContext.screens`
349
+ - Lint rules: Screen spec consistency checks
350
+ - `init --screens`: Starter file generation
351
+ - Default templates: `screen-navigation.hbs`, `screen-events.hbs`
352
+
353
+ ### Tier 2 — Optional Packages / Official Recipes (future)
354
+
355
+ | Package | Purpose |
356
+ | ------------------------------ | ------------------------------------------------------------------------ |
357
+ | `@micro-contracts/e2e-scaffold`| Parse screen spec to generate Playwright test stubs with coverage |
358
+ | ViewProp / data-testid pattern | Derive stable test IDs from ViewModel fields + `x-screen-const` |
359
+
360
+ ### Tier 3 — Documentation Only (future)
361
+
362
+ | Pattern | Description |
363
+ | ------------------------- | -------------------------------------------------------------------- |
364
+ | Design tool integration | Link screen IDs to design tool frames via `x-pen-node` or similar |
365
+ | Requirements traceability | Link screens to user stories via `x-satisfies` |
366
+ | Data lineage declarations | Declare upstream API/DB origins on ViewModel schemas via `x-lineage-source` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-contracts",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "description": "Contract-first OpenAPI toolchain that keeps TypeScript UI and microservices aligned via code generation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",