@jskit-ai/agent-docs 0.1.94 → 0.1.96
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/guide/agent/generators/crud-generators.md +18 -0
- package/package.json +1 -1
- package/patterns/crud-scaffolding.md +43 -1
- package/reference/autogen/packages/crud-server-generator.md +1 -0
- package/reference/autogen/packages/database-runtime-mysql.md +4 -0
- package/reference/autogen/packages/workspaces-web.md +2 -0
- package/reference/autogen/tooling/jskit-cli.md +3 -2
- package/templates/app/AGENTS.md +3 -0
|
@@ -230,6 +230,24 @@ w/[workspaceSlug]/admin/...
|
|
|
230
230
|
|
|
231
231
|
then `workspace` is usually the normal default. If you are generating a CRUD for a global operator or account area, `public` or `user` may make more sense.
|
|
232
232
|
|
|
233
|
+
## Schema contract for generated CRUD
|
|
234
|
+
|
|
235
|
+
Generated CRUD tables use one single-column integer primary key, normally
|
|
236
|
+
`id`. Each foreign key must also be single-column and must reference the target
|
|
237
|
+
table's single-column primary key. Composite indexes remain useful for business
|
|
238
|
+
uniqueness such as `(workspace_id, slug)`, but they are never relationship
|
|
239
|
+
targets.
|
|
240
|
+
|
|
241
|
+
Tenant isolation comes from a direct `workspace_id` and/or `user_id` ownership
|
|
242
|
+
column, the exactly matching generated ownership filter, scoped service
|
|
243
|
+
lookups, and cross-tenant tests. Do not encode ownership into a composite
|
|
244
|
+
foreign key such as `(workspace_id, parent_id) -> (workspace_id, id)`.
|
|
245
|
+
|
|
246
|
+
The generator rejects unsupported key shapes. If an approved application truly
|
|
247
|
+
needs a different persistence model, record the durable decision in
|
|
248
|
+
`.jskit/APP_BLUEPRINT.md` and use the explicit table-ownership exception path
|
|
249
|
+
instead of modifying generated CRUD files.
|
|
250
|
+
|
|
233
251
|
## Example 1: `contacts`
|
|
234
252
|
|
|
235
253
|
This is the baseline pattern. If you understand this example, the rest of the chapter becomes much easier.
|
package/package.json
CHANGED
|
@@ -14,9 +14,38 @@ Check first:
|
|
|
14
14
|
- `jskit show crud-server-generator --details`
|
|
15
15
|
- whether the request is server-only CRUD or server-plus-UI CRUD
|
|
16
16
|
|
|
17
|
+
## Non-negotiable database contract
|
|
18
|
+
|
|
19
|
+
Before database, schema, CRUD, repository, or persistence work, read this
|
|
20
|
+
pattern completely. Use the database selected for this app's development
|
|
21
|
+
runtime; never alter a production, legacy, historical, or other valuable
|
|
22
|
+
database to develop or verify schema changes. Prove the complete migration
|
|
23
|
+
chain against a fresh disposable database before reporting completion.
|
|
24
|
+
|
|
25
|
+
For normal app-owned CRUD tables:
|
|
26
|
+
|
|
27
|
+
- use exactly one non-null integer primary-key column, normally
|
|
28
|
+
`id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY`
|
|
29
|
+
- make every foreign key single-column and point it directly to the referenced
|
|
30
|
+
table's single-column primary key
|
|
31
|
+
- use multi-column unique indexes only for business uniqueness, never as
|
|
32
|
+
relationship targets
|
|
33
|
+
- use only direct `workspace_id` and/or `user_id` columns for generated JSKIT
|
|
34
|
+
ownership, and select the ownership filter that matches those columns exactly
|
|
35
|
+
- express tenant-safe relationships as direct ownership plus a normal
|
|
36
|
+
`parent_id -> parent.id` relationship; resolve related IDs through the
|
|
37
|
+
workspace-scoped service and test both allowed and cross-workspace cases
|
|
38
|
+
|
|
39
|
+
Do not use composite primary keys or composite foreign keys to encode tenant
|
|
40
|
+
ownership, target a business key from a foreign key, or duplicate parent
|
|
41
|
+
identity when the related row ID already identifies it. Stop before generation
|
|
42
|
+
if the proposed table violates these constraints.
|
|
43
|
+
|
|
17
44
|
Rules:
|
|
18
45
|
|
|
19
|
-
- For a CRUD-backed entity,
|
|
46
|
+
- For a CRUD-backed entity, create the validated table in the managed
|
|
47
|
+
development database first. Then make
|
|
48
|
+
`jskit generate crud-server-generator scaffold ...` the first JSKIT scaffold.
|
|
20
49
|
- Unless the table is already owned by a JSKIT baseline package or is an explicit narrow exception recorded in `.jskit/table-ownership.json`, every persisted app-owned table must go through that server CRUD step first.
|
|
21
50
|
- That server scaffold is the crucial first step even if no CRUD UI will be created yet.
|
|
22
51
|
- If the table should already be CRUD-owned but should not expose public CRUD HTTP routes yet, scaffold it with `jskit generate crud-server-generator scaffold ... --internal` instead of dropping to direct knex or a hand-built pseudo-repository.
|
|
@@ -64,6 +93,19 @@ When a weird-custom persistence lane is proposed:
|
|
|
64
93
|
- Record the exact approval and the approved exception in `.jskit/WORKBOARD.md` before coding.
|
|
65
94
|
- If that exception changes the durable architecture rather than only the current chunk, record it in `.jskit/APP_BLUEPRINT.md` too.
|
|
66
95
|
- Without that explicit approval record, do not take the weird-custom persistence path.
|
|
96
|
+
- Record durable, approved schema exceptions in `.jskit/APP_BLUEPRINT.md` as
|
|
97
|
+
well as the table-ownership exception; an exception must not silently weaken
|
|
98
|
+
the normal generated CRUD contract.
|
|
99
|
+
|
|
100
|
+
Before reporting completion:
|
|
101
|
+
|
|
102
|
+
- verify there are no composite primary or foreign keys in the generated CRUD
|
|
103
|
+
tables
|
|
104
|
+
- verify every generated CRUD foreign key targets a single-column primary key
|
|
105
|
+
- apply the generated migrations from zero to a fresh disposable database
|
|
106
|
+
- compare the recreated schema with the intended development schema
|
|
107
|
+
- run positive and negative cross-workspace relationship tests where ownership
|
|
108
|
+
applies, then run JSKIT Doctor and the project's normal verifier
|
|
67
109
|
|
|
68
110
|
Avoid:
|
|
69
111
|
|
|
@@ -68,6 +68,7 @@ Local functions
|
|
|
68
68
|
- `renderJsonRestSearchSchemaLines(columns = [])`
|
|
69
69
|
- `renderJsonRestDefaultSortLine(columns = [])`
|
|
70
70
|
- `renderResourceDefaultSortLiteral(columns = [])`
|
|
71
|
+
- `renderCurrentTimestampExpression(expression, column)`
|
|
71
72
|
- `renderMigrationDefaultClause(column)`
|
|
72
73
|
- `renderMigrationSpecificStringType(column, { tableCollation = "" } = {})`
|
|
73
74
|
- `renderTemporalColumnBuilder(column, methodName)`
|
|
@@ -44,15 +44,19 @@ Local functions
|
|
|
44
44
|
- `toBoolean(value)`
|
|
45
45
|
- `toNullableNumber(value)`
|
|
46
46
|
- `normalizeColumnDefault(value)`
|
|
47
|
+
- `normalizeCurrentTimestampExpression(value)`
|
|
48
|
+
- `normalizeOnUpdateExpression(value)`
|
|
47
49
|
- `parseEnumValues(columnType = "")`
|
|
48
50
|
- `resolveTypeKind(column)`
|
|
49
51
|
- `normalizeColumn(row = {})`
|
|
50
52
|
- `normalizePrimaryKeyColumns(rows = [])`
|
|
53
|
+
- `normalizePrimaryKeyColumnsByTable(rows = [])`
|
|
51
54
|
- `normalizeIndexes(rows = [])`
|
|
52
55
|
- `normalizeForeignKeys(rows = [])`
|
|
53
56
|
- `normalizeCheckConstraints(rows = [])`
|
|
54
57
|
- `requireIdColumn(columns, idColumn)`
|
|
55
58
|
- `requirePrimaryKeyContainsId(primaryKeyColumns, idColumn)`
|
|
59
|
+
- `requireSupportedForeignKeys(foreignKeys, primaryKeyColumnsByTable)`
|
|
56
60
|
|
|
57
61
|
### root
|
|
58
62
|
|
|
@@ -465,7 +465,7 @@ Exports
|
|
|
465
465
|
- `isSensitiveManagedTextRecord({ packageEntry = {}, record = {} } = {})`
|
|
466
466
|
- `isSensitivePackageOption(packageEntry = {}, optionName = "")`
|
|
467
467
|
- `isSensitiveTextMutation({ packageEntry = {}, mutation = {}, resolvedKey = "" } = {})`
|
|
468
|
-
- `resolveSensitiveOptionEnvFallbacks({ packageEntry = {}, appRoot = "", optionInput = {}, readFileBufferIfExists } = {})`
|
|
468
|
+
- `resolveSensitiveOptionEnvFallbacks({ packageEntry = {}, appRoot = "", optionInput = {}, readFileBufferIfExists, environment = process.env } = {})`
|
|
469
469
|
- `sanitizeInstalledPackageRecordForLock(record = {}, packageEntry = {})`
|
|
470
470
|
- `sanitizeLockSecretsForWrite(lock = {}, packageRegistry = null)`
|
|
471
471
|
- `sanitizeManagedTextForLock(packageEntry = {}, managedText = {})`
|
|
@@ -550,8 +550,9 @@ Local functions
|
|
|
550
550
|
- `cookieHeader(setCookie = [])`
|
|
551
551
|
- `responsePayload(response = {})`
|
|
552
552
|
- `upstreamError(payload = {}, response = {}, extra = {})`
|
|
553
|
+
- `request(fetchImpl, href, options)`
|
|
553
554
|
- `postJson(fetchImpl, href, body, headers = {})`
|
|
554
|
-
- `readSession(fetchImpl, targetOrigin
|
|
555
|
+
- `readSession(fetchImpl, targetOrigin)`
|
|
555
556
|
- `logout(fetchImpl, targetOrigin, session)`
|
|
556
557
|
- `login(fetchImpl, targetOrigin, identity, secret, session)`
|
|
557
558
|
|
package/templates/app/AGENTS.md
CHANGED
|
@@ -7,4 +7,7 @@ Recommended references:
|
|
|
7
7
|
- `node_modules/@jskit-ai/agent-docs/guide/agent/index.md`
|
|
8
8
|
- `node_modules/@jskit-ai/agent-docs/patterns/INDEX.md`
|
|
9
9
|
|
|
10
|
+
Before database, schema, CRUD, repository, or persistence work, read and follow
|
|
11
|
+
`node_modules/@jskit-ai/agent-docs/patterns/crud-scaffolding.md`.
|
|
12
|
+
|
|
10
13
|
Keep changes scoped to the user request and verify runtime behavior with tests or explicit checks.
|