howone 0.1.22 → 0.1.25

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 (26) hide show
  1. package/package.json +1 -1
  2. package/templates/nextjs/lib/sdk.ts +3 -0
  3. package/templates/vite/.howone/skills/howone-sdk/01-architect/01-app-generation.md +183 -69
  4. package/templates/vite/.howone/skills/howone-sdk/01-architect/02-manifest-codegen.md +98 -23
  5. package/templates/vite/.howone/skills/howone-sdk/02-database/01-schema-design.md +463 -69
  6. package/templates/vite/.howone/skills/howone-sdk/02-database/02-schema-operations.md +366 -64
  7. package/templates/vite/.howone/skills/howone-sdk/02-database/03-data-access-patterns.md +204 -67
  8. package/templates/vite/.howone/skills/howone-sdk/02-database/04-query-dsl-and-responses.md +237 -0
  9. package/templates/vite/.howone/skills/howone-sdk/02-database/05-ai-persistence-patterns.md +372 -0
  10. package/templates/vite/.howone/skills/howone-sdk/03-sdk/01-client-setup.md +58 -36
  11. package/templates/vite/.howone/skills/howone-sdk/03-sdk/02-entity-operations.md +67 -0
  12. package/templates/vite/.howone/skills/howone-sdk/03-sdk/03-auth.md +267 -469
  13. package/templates/vite/.howone/skills/howone-sdk/03-sdk/04-react-integration.md +113 -322
  14. package/templates/vite/.howone/skills/howone-sdk/03-sdk/07-ai-action-calls.md +95 -48
  15. package/templates/vite/.howone/skills/howone-sdk/03-sdk/08-extension-boundaries.md +226 -0
  16. package/templates/vite/.howone/skills/howone-sdk/04-ai/01-ai-capability-architecture.md +205 -0
  17. package/templates/vite/.howone/skills/howone-sdk/04-ai/02-workflow-contract-rules.md +426 -0
  18. package/templates/vite/.howone/skills/howone-sdk/04-ai/03-ai-sdk-handoff.md +219 -0
  19. package/templates/vite/.howone/skills/howone-sdk/04-ai/04-service-capability-catalog.md +281 -0
  20. package/templates/vite/.howone/skills/howone-sdk/04-ai/05-workflow-operations.md +256 -0
  21. package/templates/vite/.howone/skills/howone-sdk/04-ai/06-ai-feature-playbooks.md +296 -0
  22. package/templates/vite/.howone/skills/howone-sdk/SKILL.md +83 -15
  23. package/templates/vite/.howone/skills/howone-sdk/agents/openai.yaml +2 -2
  24. package/templates/vite/package.json +1 -1
  25. package/templates/vite/src/lib/sdk.ts +3 -0
  26. package/templates/vite/.howone/skills/howone-sdk/04-ai/.gitkeep +0 -1
@@ -1,76 +1,332 @@
1
1
  # Schema Operations
2
2
 
3
- Use this reference when applying backend entity schema changes through HowOne runtime tools.
3
+ Use this reference when applying backend entity schema changes through HowOne runtime tools or
4
+ `client.schema.*`. It answers: **how do I safely change the schema and keep app code in sync?**
5
+
6
+ For schema design decisions, read `01-schema-design.md` first.
4
7
 
5
8
  ## Source Of Truth
6
9
 
7
10
  ```text
8
- agent proposal != source of truth
9
- validated backend manifest = source of truth
10
- synced .howone/database files = local copy of a backend version
11
- src/lib/sdk.ts = app binding generated from synced manifest
11
+ agent proposal = draft
12
+ backend preview/apply result = validated contract
13
+ synced .howone/database files = local copy of backend version
14
+ src/lib/sdk.ts = generated app binding from synced manifest
15
+ frontend code = consumer of generated bindings
12
16
  ```
13
17
 
14
- Do not hand-write `.howone/database` files. Sync them from a concrete backend schema version.
18
+ Do not hand-write `.howone/database/*`. Sync artifacts from a concrete backend version.
15
19
 
16
20
  ## Preferred Patch Flow
17
21
 
18
- For feature-level schema work:
22
+ Use patch flow for most feature-level changes:
19
23
 
20
- 1. Inspect current schema definitions or schema state.
21
- 2. Design one complete patch containing all related operations.
24
+ 1. Inspect current `schema.getState()` and current entity definitions.
25
+ 2. Design a full patch containing all related operations.
22
26
  3. Preview the patch.
23
- 4. Apply the exact same operations if risk is acceptable.
24
- 5. Sync schema artifacts using the returned `next.versionId`.
25
- 6. Read `.howone/database/manifest.json`.
26
- 7. Update `src/lib/sdk.ts` from the manifest.
27
- 8. Update frontend calls according to access.
28
- 9. Validate.
27
+ 4. Review risk, diff, and current version.
28
+ 5. Apply the exact same patch with `expectedVersionId`.
29
+ 6. Sync schema artifacts from `next.versionId`.
30
+ 7. Read `.howone/database/manifest.json`.
31
+ 8. Regenerate/update `src/lib/sdk.ts` bindings.
32
+ 9. Update frontend calls according to `access`.
33
+ 10. Run typecheck/build/tests.
29
34
 
30
- Do not preview a patch and then apply a different set of single operations.
35
+ Do not preview one patch and apply a different operation set.
31
36
 
32
- ## Operation Types
37
+ ## SDK Schema Client
38
+
39
+ ```ts
40
+ const state = await client.schema.getState()
41
+ const definitions = await client.schema.listDefinitions()
42
+ const todo = await client.schema.getDefinition('Todo')
43
+
44
+ const preview = await client.schema.previewPatch(patch, {
45
+ expectedVersionId: state.currentVersionId,
46
+ reason: 'Add priority field to Todo',
47
+ })
48
+
49
+ if (preview.risk?.level === 'dangerous') {
50
+ // stop and ask for confirmation
51
+ }
52
+
53
+ const applied = await client.schema.applyPatch(patch, {
54
+ expectedVersionId: state.currentVersionId,
55
+ reason: 'Add priority field to Todo',
56
+ })
57
+ ```
33
58
 
34
- Supported schema operations:
59
+ Available schema methods:
35
60
 
36
- | Type | Purpose |
61
+ | Method | Use |
37
62
  |---|---|
38
- | `list_entities` | List current entity definitions. |
39
- | `get_entity` | Read one entity definition before modifying it. |
40
- | `create_entity` | Create a new entity contract. |
41
- | `update_entity` | Update entity metadata such as description, visibility, access, indexes, relations, presentation, lifecycle, performance. |
42
- | `delete_entity` | Soft or hard delete an entity definition. |
43
- | `add_field` | Add a new field. |
44
- | `update_field` | Patch an existing field definition. |
45
- | `delete_field` | Remove a field from schema, optionally from historical data. |
46
- | `set_field_required` | Add a field to top-level `required`. |
47
- | `unset_field_required` | Remove a field from top-level `required`. |
48
-
49
- ## Payload Rules
50
-
51
- - `entityName` is required for every operation except `list_entities`.
52
- - `payload.properties` is required for `create_entity`.
53
- - `payload.required` must only contain fields that exist in `properties`.
54
- - `add_field` should use `{ fieldName, field, required }`.
55
- - `update_field` should use `{ fieldName, patch, required? }`.
56
- - `delete_field` should use `{ fieldName, removeFromData: false }` by default.
57
- - `required` belongs to the entity top level, not inside individual field definitions.
58
-
59
- ## Risk Guardrails
60
-
61
- - Default entity deletion to soft delete.
62
- - Use hard delete only when the user explicitly asks.
63
- - Use `deleteData: true` only when the user explicitly asks to delete all records too.
64
- - Use `removeFromData: true` only after explicit confirmation.
65
- - Adding a required field to an existing entity should include a default when possible.
66
- - Changing a field type is high risk; inspect current schema and confirm intent before applying.
67
- - Schema restore creates a new restore version; it does not roll business data back.
68
-
69
- ## Version Rules
70
-
71
- Schema versions manage entity definitions only. They do not roll back `entitydatashares`.
72
-
73
- After apply, use the returned version context:
63
+ | `listDefinitions()` | Get current entity definitions. |
64
+ | `getDefinition(entityName)` | Inspect one entity. |
65
+ | `upsertDefinitions(definition | definition[])` | Direct definition upsert; prefer patch for agent changes. |
66
+ | `operate(operation)` | Single operation endpoint. |
67
+ | `previewPatch(patch, options)` | Risk/diff preview without applying. |
68
+ | `applyPatch(patch, options)` | Apply versioned patch. |
69
+ | `getState()` | Current schema version pointer. |
70
+ | `listVersions()` | Version history. |
71
+ | `getVersion(versionId)` | Inspect version manifest. |
72
+ | `restore(versionId, reason?)` | Restore definitions by creating a new restore version. |
73
+
74
+ ## Operation Types
75
+
76
+ ```ts
77
+ type EntitySchemaOperationType =
78
+ | 'list_entities'
79
+ | 'get_entity'
80
+ | 'create_entity'
81
+ | 'update_entity'
82
+ | 'delete_entity'
83
+ | 'add_field'
84
+ | 'update_field'
85
+ | 'delete_field'
86
+ | 'set_field_required'
87
+ | 'unset_field_required'
88
+ ```
89
+
90
+ Operation shape:
91
+
92
+ ```ts
93
+ type EntitySchemaOperation = {
94
+ type: EntitySchemaOperationType
95
+ entityName?: string
96
+ payload?: Record<string, unknown>
97
+ }
98
+ ```
99
+
100
+ Patch shape:
101
+
102
+ ```ts
103
+ type EntitySchemaPatch = {
104
+ operations: EntitySchemaOperation[]
105
+ }
106
+ ```
107
+
108
+ ## Operation Payloads
109
+
110
+ ### create_entity
111
+
112
+ Use when the entity does not exist.
113
+
114
+ ```json
115
+ {
116
+ "type": "create_entity",
117
+ "entityName": "Todo",
118
+ "payload": {
119
+ "definition": {
120
+ "name": "Todo",
121
+ "type": "object",
122
+ "visibility": "private",
123
+ "properties": {
124
+ "text": { "type": "string" },
125
+ "completed": { "type": "boolean", "default": false }
126
+ },
127
+ "required": ["text"],
128
+ "access": {
129
+ "authenticated": { "read": "own", "create": "own", "update": "own", "delete": "own" },
130
+ "public": { "read": "none", "create": "none", "update": "none", "delete": "none" }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ Rules:
138
+
139
+ - `payload.definition.properties` is required.
140
+ - `required` must reference existing fields.
141
+ - Include explicit `access`, even if `visibility` seems obvious.
142
+
143
+ ### update_entity
144
+
145
+ Use for metadata and contract sections, not individual field changes.
146
+
147
+ ```json
148
+ {
149
+ "type": "update_entity",
150
+ "entityName": "Article",
151
+ "payload": {
152
+ "patch": {
153
+ "access": {
154
+ "authenticated": { "read": "all", "create": "all", "update": "all", "delete": "all" },
155
+ "public": {
156
+ "read": "list",
157
+ "create": "none",
158
+ "update": "none",
159
+ "delete": "none",
160
+ "allowedFilters": ["status", "slug"],
161
+ "allowedSorts": ["publishedAt"],
162
+ "defaultLimit": 20,
163
+ "maxLimit": 100
164
+ }
165
+ },
166
+ "performance": {
167
+ "defaultLimit": 20,
168
+ "maxLimit": 100,
169
+ "allowedSorts": ["publishedAt", "updatedDate"]
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ Use this for:
177
+
178
+ - `description`
179
+ - `visibility`
180
+ - `access`
181
+ - `indexes`
182
+ - `relations`
183
+ - `presentation`
184
+ - `lifecycle`
185
+ - `performance`
186
+
187
+ ### add_field
188
+
189
+ ```json
190
+ {
191
+ "type": "add_field",
192
+ "entityName": "Todo",
193
+ "payload": {
194
+ "fieldName": "priority",
195
+ "field": {
196
+ "type": "string",
197
+ "enum": ["low", "medium", "high"],
198
+ "default": "medium"
199
+ },
200
+ "required": false
201
+ }
202
+ }
203
+ ```
204
+
205
+ Rules:
206
+
207
+ - If adding a required field to an existing entity, prefer a default.
208
+ - If no default exists and records already exist, treat as risky and ask for migration policy.
209
+ - Add indexes only when new query paths need them.
210
+
211
+ ### update_field
212
+
213
+ ```json
214
+ {
215
+ "type": "update_field",
216
+ "entityName": "Todo",
217
+ "payload": {
218
+ "fieldName": "priority",
219
+ "patch": {
220
+ "enum": ["low", "medium", "high", "urgent"]
221
+ }
222
+ }
223
+ }
224
+ ```
225
+
226
+ Risk levels:
227
+
228
+ - Adding enum values: usually safe.
229
+ - Removing enum values: risky if existing records use them.
230
+ - Changing type: high risk.
231
+ - Making nullable field required: high risk.
232
+ - Removing default: risky for create flows.
233
+
234
+ ### delete_field
235
+
236
+ ```json
237
+ {
238
+ "type": "delete_field",
239
+ "entityName": "Todo",
240
+ "payload": {
241
+ "fieldName": "legacyTag",
242
+ "removeFromData": false
243
+ }
244
+ }
245
+ ```
246
+
247
+ Rules:
248
+
249
+ - Default `removeFromData` to `false`.
250
+ - Only use `removeFromData: true` after explicit confirmation.
251
+ - Removing from schema does not necessarily remove historical data.
252
+
253
+ ### set_field_required / unset_field_required
254
+
255
+ ```json
256
+ {
257
+ "type": "set_field_required",
258
+ "entityName": "Todo",
259
+ "payload": { "fieldName": "text" }
260
+ }
261
+ ```
262
+
263
+ Rules:
264
+
265
+ - Required fields must exist in `properties`.
266
+ - Setting required on an existing field is risky unless a default exists or old records are acceptable.
267
+ - Unsetting required is generally safe but may change frontend validation expectations.
268
+
269
+ ### delete_entity
270
+
271
+ ```json
272
+ {
273
+ "type": "delete_entity",
274
+ "entityName": "Todo",
275
+ "payload": {
276
+ "hard": false,
277
+ "deleteData": false
278
+ }
279
+ }
280
+ ```
281
+
282
+ Rules:
283
+
284
+ - Default to soft delete.
285
+ - Hard delete requires explicit user request.
286
+ - `deleteData: true` requires explicit confirmation because it destroys records.
287
+
288
+ ## Risk Checklist
289
+
290
+ Stop and ask before applying when:
291
+
292
+ - deleting an entity;
293
+ - deleting a field used by UI or workflow output;
294
+ - removing historical data;
295
+ - changing field type;
296
+ - making a field required without default;
297
+ - broadening public access;
298
+ - enabling public write;
299
+ - reducing public guardrails such as removing required scopes or raising max limits;
300
+ - changing owner/public scope semantics.
301
+
302
+ Usually safe:
303
+
304
+ - adding optional field;
305
+ - adding field with default;
306
+ - adding enum value;
307
+ - adding index for existing query path;
308
+ - adding presentation metadata;
309
+ - adding stricter public filter/sort limits.
310
+
311
+ ## Version Semantics
312
+
313
+ Schema versions manage definitions, not business records.
314
+
315
+ Restore behavior:
316
+
317
+ ```text
318
+ restore(versionId)
319
+ -> creates a new current schema version from old manifest
320
+ -> future create/update uses restored definitions
321
+ -> old entitydatashares records are not rolled back
322
+ ```
323
+
324
+ Data records may still carry old fields after schema changes. Do not assume restore deletes or
325
+ rewrites data.
326
+
327
+ ## Manifest Sync Handoff
328
+
329
+ After apply, the result should include a version hint:
74
330
 
75
331
  ```json
76
332
  {
@@ -81,16 +337,62 @@ After apply, use the returned version context:
81
337
  }
82
338
  ```
83
339
 
84
- The synced manifest must be read before updating SDK bindings.
340
+ Agent handoff sequence:
341
+
342
+ 1. Sync artifacts for `versionId`.
343
+ 2. Read `.howone/database/manifest.json`.
344
+ 3. Update `src/lib/sdk.ts` generated entity bindings.
345
+ 4. Update frontend CRUD/query code.
346
+ 5. Validate build.
85
347
 
86
- ## Narrow Edit Flow
348
+ Never update frontend entity types from the draft patch alone when a synced manifest exists.
349
+
350
+ ## Common Agent Mistakes
351
+
352
+ | Mistake | Correct behavior |
353
+ |---|---|
354
+ | Hand-writing `.howone/database/manifest.json` | Sync from backend version. |
355
+ | Applying one operation after previewing a different patch | Apply the exact previewed patch. |
356
+ | Adding required field without default | Treat as risk; ask migration/default policy. |
357
+ | Public read list without `allowedFilters` / `allowedSorts` | Add public guardrails. |
358
+ | Using `visibility: "public"` as permission model | Write explicit `access.public`. |
359
+ | Deleting data because schema changed | Schema changes do not imply data deletion. |
360
+ | Updating `src/lib/sdk.ts` before manifest sync | Wait for synced manifest. |
87
361
 
88
- Single operations are acceptable for small explicit edits, such as "add priority to Todo":
362
+ ## Minimal Safe Patch Template
89
363
 
90
- 1. `get_entity`
91
- 2. Check whether field already exists.
92
- 3. Preview/apply one `add_field` patch or use the schema operation fallback.
93
- 4. Sync artifacts.
94
- 5. Update SDK/UI.
364
+ ```ts
365
+ const state = await client.schema.getState()
95
366
 
96
- For broader features, batch operations into one patch.
367
+ const patch = {
368
+ operations: [
369
+ {
370
+ type: 'add_field',
371
+ entityName: 'Todo',
372
+ payload: {
373
+ fieldName: 'priority',
374
+ field: {
375
+ type: 'string',
376
+ enum: ['low', 'medium', 'high'],
377
+ default: 'medium',
378
+ },
379
+ required: false,
380
+ },
381
+ },
382
+ ],
383
+ }
384
+
385
+ const preview = await client.schema.previewPatch(patch, {
386
+ expectedVersionId: state.currentVersionId,
387
+ reason: 'Add todo priority',
388
+ })
389
+
390
+ if (preview.risk?.level === 'dangerous') {
391
+ throw new Error('User confirmation required before applying schema patch')
392
+ }
393
+
394
+ const applied = await client.schema.applyPatch(patch, {
395
+ expectedVersionId: state.currentVersionId,
396
+ reason: 'Add todo priority',
397
+ })
398
+ ```