create-seiro 0.1.8 → 0.1.9
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/package.json +1 -1
- package/template/.claude/skills/cqrs-document/SKILL.md +15 -0
- package/template/.claude/skills/cqrs-document/references/seiro.md +7 -6
- package/template/.claude/skills/model-build/SKILL.md +145 -0
- package/template/.claude/skills/model-generate/SKILL.md +237 -0
- package/template/CLAUDE.md +34 -1
- package/template/package.json +1 -1
package/package.json
CHANGED
|
@@ -130,6 +130,21 @@ export type Site = {
|
|
|
130
130
|
- No UML diagrams
|
|
131
131
|
- No abstract entity modelling before documents are clear
|
|
132
132
|
|
|
133
|
+
## Alternative: seiro model
|
|
134
|
+
|
|
135
|
+
For larger systems where you want to visualise the complete domain (entities, documents, commands, events, sequences), use `seiro model`:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bunx seiro model add entity Product
|
|
139
|
+
bunx seiro model add document Catalogue
|
|
140
|
+
bunx seiro model serve # view diagrams
|
|
141
|
+
bunx seiro model export # get JSON for code generation
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Then use the `model-generate` skill to create the application from the export.
|
|
145
|
+
|
|
146
|
+
Use this skill (cqrs-document) for conversational design. Use seiro model when you need the full picture and consistency checking across a larger domain.
|
|
147
|
+
|
|
133
148
|
## Iteration Pattern
|
|
134
149
|
|
|
135
150
|
When requirements change:
|
|
@@ -87,6 +87,7 @@ await server.start({ "/": homepage });
|
|
|
87
87
|
```typescript
|
|
88
88
|
import type { Sql } from "postgres";
|
|
89
89
|
import type { Server } from "seiro";
|
|
90
|
+
import { notifyLogger } from "seiro/server";
|
|
90
91
|
import type { Entity, EntityCommands, EntityQueries, EntityEvents } from "./types";
|
|
91
92
|
|
|
92
93
|
export async function register<
|
|
@@ -103,10 +104,10 @@ export async function register<
|
|
|
103
104
|
try {
|
|
104
105
|
server.emit("entity_created", JSON.parse(payload) as Entity);
|
|
105
106
|
} catch (e) {
|
|
106
|
-
|
|
107
|
+
notifyLogger.error("Failed to parse entity_created payload:", payload, e);
|
|
107
108
|
}
|
|
108
109
|
},
|
|
109
|
-
() =>
|
|
110
|
+
() => notifyLogger.info("Listening on entity_created"),
|
|
110
111
|
);
|
|
111
112
|
|
|
112
113
|
await listener.listen(
|
|
@@ -115,10 +116,10 @@ export async function register<
|
|
|
115
116
|
try {
|
|
116
117
|
server.emit("entity_updated", JSON.parse(payload) as Entity);
|
|
117
118
|
} catch (e) {
|
|
118
|
-
|
|
119
|
+
notifyLogger.error("Failed to parse entity_updated payload:", payload, e);
|
|
119
120
|
}
|
|
120
121
|
},
|
|
121
|
-
() =>
|
|
122
|
+
() => notifyLogger.info("Listening on entity_updated"),
|
|
122
123
|
);
|
|
123
124
|
|
|
124
125
|
// Different payload type for delete - just the id
|
|
@@ -128,10 +129,10 @@ export async function register<
|
|
|
128
129
|
try {
|
|
129
130
|
server.emit("entity_deleted", JSON.parse(payload) as { id: number });
|
|
130
131
|
} catch (e) {
|
|
131
|
-
|
|
132
|
+
notifyLogger.error("Failed to parse entity_deleted payload:", payload, e);
|
|
132
133
|
}
|
|
133
134
|
},
|
|
134
|
-
() =>
|
|
135
|
+
() => notifyLogger.info("Listening on entity_deleted"),
|
|
135
136
|
);
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: model-build
|
|
3
|
+
description: Build a CQRS domain model through conversation using seiro model CLI. Use when designing larger systems where you want diagrams, consistency checking, and a formal model before generating code. Captures entities, documents, commands, events, and their relationships in model.db.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build Domain Model Through Conversation
|
|
7
|
+
|
|
8
|
+
Guide the user through building a complete CQRS domain model using the seiro model CLI. The model can be visualised with `bunx seiro model serve` and used to generate code with the `model-generate` skill.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### 1. Start with Documents
|
|
13
|
+
|
|
14
|
+
Ask: "What documents (views) does the user see?"
|
|
15
|
+
|
|
16
|
+
For each document, capture:
|
|
17
|
+
- Name and description
|
|
18
|
+
- What entities it contains
|
|
19
|
+
- Queries that build it
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bunx seiro model add document Catalogue "All products with parts and faces"
|
|
23
|
+
bunx seiro model add doc-entity Catalogue Product
|
|
24
|
+
bunx seiro model add doc-entity Catalogue Part
|
|
25
|
+
bunx seiro model add doc-entity Catalogue Face
|
|
26
|
+
bunx seiro model add query Catalogue products "SELECT id, name, spec, tag_ids FROM products"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Define Entities
|
|
30
|
+
|
|
31
|
+
For each entity in the documents:
|
|
32
|
+
- Name and description
|
|
33
|
+
- Attributes with types
|
|
34
|
+
- Relationships to other entities
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bunx seiro model add entity Product "A product in the catalogue"
|
|
38
|
+
bunx seiro model add attribute Product name string
|
|
39
|
+
bunx seiro model add attribute Product spec json
|
|
40
|
+
bunx seiro model add relationship Product tagIds Tag --many --reference
|
|
41
|
+
bunx seiro model add relationship Product parts Part --many
|
|
42
|
+
bunx seiro model add relationship Product faces Face --many
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Types: `string`, `integer`, `boolean`, `json`, `integer[]`
|
|
46
|
+
Options: `--nullable`, `--many`, `--reference`
|
|
47
|
+
|
|
48
|
+
### 3. Define Commands for Each Document
|
|
49
|
+
|
|
50
|
+
For each entity in a document, determine what commands change its state. At minimum: save and delete.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Command with input type
|
|
54
|
+
bunx seiro model add entity ProductSaveCmd
|
|
55
|
+
bunx seiro model add attribute ProductSaveCmd id integer --nullable
|
|
56
|
+
bunx seiro model add attribute ProductSaveCmd name string
|
|
57
|
+
bunx seiro model add attribute ProductSaveCmd spec json
|
|
58
|
+
bunx seiro model add attribute ProductSaveCmd tagIds integer[]
|
|
59
|
+
|
|
60
|
+
bunx seiro model add command product.save --entity ProductSaveCmd
|
|
61
|
+
bunx seiro model add command-doc product.save Catalogue
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 4. Define Events for Each Command
|
|
65
|
+
|
|
66
|
+
Each command emits an event with payload describing the change:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Event with payload type
|
|
70
|
+
bunx seiro model add entity ProductSavedEvt
|
|
71
|
+
bunx seiro model add attribute ProductSavedEvt id integer
|
|
72
|
+
bunx seiro model add attribute ProductSavedEvt name string
|
|
73
|
+
bunx seiro model add attribute ProductSavedEvt spec json
|
|
74
|
+
bunx seiro model add attribute ProductSavedEvt tagIds integer[]
|
|
75
|
+
|
|
76
|
+
bunx seiro model add event product_saved product.save --entity ProductSavedEvt
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 5. Ensure Complete Coverage
|
|
80
|
+
|
|
81
|
+
For each entity in each document, verify:
|
|
82
|
+
|
|
83
|
+
| Entity | save command | delete command | save event | delete event |
|
|
84
|
+
|--------|--------------|----------------|------------|--------------|
|
|
85
|
+
| Product | product.save | product.delete | product_saved | product_deleted |
|
|
86
|
+
| Part | part.save | part.delete | part_saved | part_deleted |
|
|
87
|
+
| Face | face.save | face.delete | face_saved | face_deleted |
|
|
88
|
+
| Tag | tag.save | tag.delete | tag_saved | tag_deleted |
|
|
89
|
+
|
|
90
|
+
This is the minimum surface. Additional commands (e.g., `product.tag`) can be added for specific operations.
|
|
91
|
+
|
|
92
|
+
### 6. Visualise and Verify
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
bunx seiro model up # start PlantUML server
|
|
96
|
+
bunx seiro model serve # open browser to view diagrams
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Review:
|
|
100
|
+
- Entity diagram - are relationships correct?
|
|
101
|
+
- Document diagrams - do they contain the right entities?
|
|
102
|
+
- Command coverage - does each document have all needed commands?
|
|
103
|
+
|
|
104
|
+
### 7. Export for Code Generation
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
bunx seiro model export > model.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Then use the `model-generate` skill to create the application code.
|
|
111
|
+
|
|
112
|
+
## CLI Reference
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Entities
|
|
116
|
+
bunx seiro model add entity <name> [description]
|
|
117
|
+
bunx seiro model add attribute <entity> <name> <type> [--nullable]
|
|
118
|
+
bunx seiro model add relationship <from> <field> <to> [--many] [--reference]
|
|
119
|
+
|
|
120
|
+
# Documents
|
|
121
|
+
bunx seiro model add document <name> [description]
|
|
122
|
+
bunx seiro model add doc-entity <document> <entity>
|
|
123
|
+
bunx seiro model add query <document> <name> <sql>
|
|
124
|
+
|
|
125
|
+
# Commands & Events
|
|
126
|
+
bunx seiro model add command <name> [--entity <type>]
|
|
127
|
+
bunx seiro model add command-doc <command> <document>
|
|
128
|
+
bunx seiro model add event <name> <command> [--entity <type>]
|
|
129
|
+
|
|
130
|
+
# View
|
|
131
|
+
bunx seiro model list entities|documents|commands|events
|
|
132
|
+
bunx seiro model serve
|
|
133
|
+
bunx seiro model export
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Conversation Pattern
|
|
137
|
+
|
|
138
|
+
1. "What does the user see?" → identify documents
|
|
139
|
+
2. "What's in each document?" → identify entities and their attributes
|
|
140
|
+
3. "How are they related?" → define relationships
|
|
141
|
+
4. "What can change each document?" → define commands per entity
|
|
142
|
+
5. "What does each change notify?" → define events
|
|
143
|
+
6. "Is the surface complete?" → verify coverage matrix
|
|
144
|
+
7. "Let's visualise" → run serve, review diagrams
|
|
145
|
+
8. "Ready to generate" → export and use model-generate skill
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: model-generate
|
|
3
|
+
description: Generate a seiro application from seiro model export. Use when you have a model.db and want to generate schema.sql, TypeScript types, and command handlers. Run `bunx seiro model export` to get the JSON input.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Generate Seiro Application from Model
|
|
7
|
+
|
|
8
|
+
Takes the JSON export from seiro model and generates a complete seiro application.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Get the model export
|
|
14
|
+
bunx seiro model export > model.json
|
|
15
|
+
|
|
16
|
+
# Or pipe directly
|
|
17
|
+
bunx seiro model export | # use in generation
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Input Format
|
|
21
|
+
|
|
22
|
+
The export JSON contains:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"entities": [
|
|
27
|
+
{
|
|
28
|
+
"name": "Product",
|
|
29
|
+
"attributes": [
|
|
30
|
+
{ "name": "id", "type": "integer" },
|
|
31
|
+
{ "name": "name", "type": "string" }
|
|
32
|
+
],
|
|
33
|
+
"relationships": [
|
|
34
|
+
{ "field": "tagIds", "to": "Tag", "many": true, "reference": true }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"documents": [
|
|
39
|
+
{
|
|
40
|
+
"name": "Catalogue",
|
|
41
|
+
"entities": ["Product", "Part", "Face"],
|
|
42
|
+
"queries": [
|
|
43
|
+
{ "name": "products", "sql": "SELECT ..." }
|
|
44
|
+
],
|
|
45
|
+
"commands": [
|
|
46
|
+
{
|
|
47
|
+
"name": "product.save",
|
|
48
|
+
"input": { "name": "ProductSaveCmd", "attributes": [...] },
|
|
49
|
+
"events": [
|
|
50
|
+
{ "name": "product_saved", "payload": { "name": "ProductSavedEvt", "attributes": [...] } }
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Output Files
|
|
60
|
+
|
|
61
|
+
### 1. SQL Schema (`src/db/schema.sql`)
|
|
62
|
+
|
|
63
|
+
Generate tables from entities:
|
|
64
|
+
|
|
65
|
+
```sql
|
|
66
|
+
CREATE TABLE IF NOT EXISTS products (
|
|
67
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
68
|
+
name TEXT NOT NULL,
|
|
69
|
+
spec TEXT NOT NULL,
|
|
70
|
+
tag_ids TEXT NOT NULL DEFAULT '[]'
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
CREATE TABLE IF NOT EXISTS parts (
|
|
74
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
75
|
+
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
|
76
|
+
child_product_id INTEGER NOT NULL REFERENCES products(id),
|
|
77
|
+
quantity INTEGER NOT NULL
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Type mapping:
|
|
82
|
+
- `string` → `TEXT`
|
|
83
|
+
- `integer` → `INTEGER`
|
|
84
|
+
- `json` → `TEXT` (stored as JSON string)
|
|
85
|
+
- `integer[]` → `TEXT` (stored as JSON array)
|
|
86
|
+
- `boolean` → `INTEGER` (0/1)
|
|
87
|
+
|
|
88
|
+
Relationships:
|
|
89
|
+
- `reference: false` (composition) → foreign key with `ON DELETE CASCADE`
|
|
90
|
+
- `reference: true` (association) → stored as `_ids` JSON array
|
|
91
|
+
|
|
92
|
+
### 2. TypeScript Types (`src/types.ts`)
|
|
93
|
+
|
|
94
|
+
Generate from entities and command/event types:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Domain entities
|
|
98
|
+
export type Product = {
|
|
99
|
+
id: number
|
|
100
|
+
name: string
|
|
101
|
+
spec: Record<string, unknown>
|
|
102
|
+
tagIds: number[]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Command types
|
|
106
|
+
export type ProductSaveCmd = {
|
|
107
|
+
id?: number
|
|
108
|
+
name: string
|
|
109
|
+
spec: Record<string, unknown>
|
|
110
|
+
tagIds: number[]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Event types
|
|
114
|
+
export type ProductSavedEvt = {
|
|
115
|
+
id: number
|
|
116
|
+
name: string
|
|
117
|
+
spec: Record<string, unknown>
|
|
118
|
+
tagIds: number[]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Document types
|
|
122
|
+
export type CatalogueDocument = {
|
|
123
|
+
products: Product[]
|
|
124
|
+
parts: Part[]
|
|
125
|
+
faces: Face[]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Type mapping:
|
|
130
|
+
- `string` → `string`
|
|
131
|
+
- `integer` → `number`
|
|
132
|
+
- `json` → `Record<string, unknown>`
|
|
133
|
+
- `integer[]` → `number[]`
|
|
134
|
+
- `boolean` → `boolean`
|
|
135
|
+
- `nullable: true` → `| null`
|
|
136
|
+
|
|
137
|
+
### 3. Command Handlers (`src/commands.ts`)
|
|
138
|
+
|
|
139
|
+
Generate handler stubs for each command:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import type { CommandContext } from "seiro"
|
|
143
|
+
import type { Events, ProductSaveCmd } from "./types"
|
|
144
|
+
import { db } from "./db"
|
|
145
|
+
|
|
146
|
+
export async function productSave(
|
|
147
|
+
data: ProductSaveCmd,
|
|
148
|
+
ctx: CommandContext<Events>
|
|
149
|
+
): Promise<{ id: number }> {
|
|
150
|
+
const { id, name, spec, tagIds } = data
|
|
151
|
+
|
|
152
|
+
if (id) {
|
|
153
|
+
// Update
|
|
154
|
+
db.run(
|
|
155
|
+
`UPDATE products SET name = ?, spec = ?, tag_ids = ? WHERE id = ?`,
|
|
156
|
+
[name, JSON.stringify(spec), JSON.stringify(tagIds), id]
|
|
157
|
+
)
|
|
158
|
+
} else {
|
|
159
|
+
// Insert
|
|
160
|
+
const result = db.run(
|
|
161
|
+
`INSERT INTO products (name, spec, tag_ids) VALUES (?, ?, ?)`,
|
|
162
|
+
[name, JSON.stringify(spec), JSON.stringify(tagIds)]
|
|
163
|
+
)
|
|
164
|
+
id = result.lastInsertRowid
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
ctx.send("product_saved", { id, name, spec, tagIds })
|
|
168
|
+
return { id }
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 4. Query Handlers (`src/queries.ts`)
|
|
173
|
+
|
|
174
|
+
Generate from document queries:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { db } from "./db"
|
|
178
|
+
import type { Product, Part, Face } from "./types"
|
|
179
|
+
|
|
180
|
+
export async function* catalogueProducts(): AsyncIterable<Product> {
|
|
181
|
+
const rows = db.query(`SELECT id, name, spec, tag_ids FROM products`).all()
|
|
182
|
+
for (const row of rows) {
|
|
183
|
+
yield {
|
|
184
|
+
id: row.id,
|
|
185
|
+
name: row.name,
|
|
186
|
+
spec: JSON.parse(row.spec),
|
|
187
|
+
tagIds: JSON.parse(row.tag_ids)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 5. Server Setup (`src/server.ts`)
|
|
194
|
+
|
|
195
|
+
Wire up commands and queries:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { createServer } from "seiro"
|
|
199
|
+
import type { Commands, Queries, Events } from "./types"
|
|
200
|
+
import { productSave, productDelete, ... } from "./commands"
|
|
201
|
+
import { catalogueProducts, ... } from "./queries"
|
|
202
|
+
|
|
203
|
+
const server = createServer<Commands, Queries, Events>()
|
|
204
|
+
|
|
205
|
+
// Register commands
|
|
206
|
+
server.command("product.save", productSave)
|
|
207
|
+
server.command("product.delete", productDelete)
|
|
208
|
+
// ...
|
|
209
|
+
|
|
210
|
+
// Register queries
|
|
211
|
+
server.query("catalogue.products", catalogueProducts)
|
|
212
|
+
// ...
|
|
213
|
+
|
|
214
|
+
export { server }
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Conventions
|
|
218
|
+
|
|
219
|
+
Follow the same patterns as the `cqrs-document` skill:
|
|
220
|
+
|
|
221
|
+
- Commands are `entity.action` (e.g., `product.save`, `product.delete`)
|
|
222
|
+
- Events are `entity_actioned` (e.g., `product_saved`, `product_deleted`)
|
|
223
|
+
- Save commands handle both create (no id) and update (with id)
|
|
224
|
+
- Delete commands return void, emit event with just `{ id }`
|
|
225
|
+
- Queries yield rows for streaming
|
|
226
|
+
- JSON fields stored as TEXT, parsed on read
|
|
227
|
+
|
|
228
|
+
## Workflow
|
|
229
|
+
|
|
230
|
+
1. Run `bunx @seiro/model export` to get JSON
|
|
231
|
+
2. Generate schema.sql from entities
|
|
232
|
+
3. Generate types.ts from entities + command/event types
|
|
233
|
+
4. Generate command handler stubs
|
|
234
|
+
5. Generate query handlers from document queries
|
|
235
|
+
6. Wire up in server.ts
|
|
236
|
+
|
|
237
|
+
The generated code is a starting point - handlers will need business logic added.
|
package/template/CLAUDE.md
CHANGED
|
@@ -13,7 +13,40 @@ bun test # run tests
|
|
|
13
13
|
|
|
14
14
|
## Adding Features
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Two approaches for designing CQRS systems:
|
|
17
|
+
|
|
18
|
+
### Quick Path: Conversational Design
|
|
19
|
+
|
|
20
|
+
Use the `cqrs-document` skill for direct conversation-to-code design. Good for smaller systems or rapid prototyping.
|
|
21
|
+
|
|
22
|
+
1. Discuss what the user sees (documents)
|
|
23
|
+
2. Derive entities and commands through conversation
|
|
24
|
+
3. Output SQL and TypeScript directly
|
|
25
|
+
|
|
26
|
+
### Model Path: Formal Domain Model
|
|
27
|
+
|
|
28
|
+
Use `seiro model` for larger systems where you want diagrams, consistency checking, and a complete view of the domain.
|
|
29
|
+
|
|
30
|
+
1. Use the `model-build` skill to build model.db through conversation
|
|
31
|
+
```bash
|
|
32
|
+
bunx seiro model add entity Product
|
|
33
|
+
bunx seiro model add document Catalogue
|
|
34
|
+
bunx seiro model add command product.save
|
|
35
|
+
# ... builds complete model via CLI
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. Visualise and verify
|
|
39
|
+
```bash
|
|
40
|
+
bunx seiro model up # start PlantUML
|
|
41
|
+
bunx seiro model serve # view diagrams
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Use the `model-generate` skill to create application code from the export
|
|
45
|
+
```bash
|
|
46
|
+
bunx seiro model export # outputs JSON for code generation
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Choose the quick path when you know what you're building. Choose the model path when you need to see the full picture first.
|
|
17
50
|
|
|
18
51
|
## Type Patterns
|
|
19
52
|
|