@abeedoo/radish-schemas 1.11.0 → 1.12.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.
- package/index.js +1 -1
- package/package.json +1 -1
- package/prompts/radish-types-generation.md +18 -7
- package/schemas/types.schema.json +7 -3
package/index.js
CHANGED
|
@@ -31,7 +31,7 @@ export {
|
|
|
31
31
|
* @property {string} minCliVersion - Minimum radish-cli version compatible with this package
|
|
32
32
|
*/
|
|
33
33
|
export const VERSIONING = {
|
|
34
|
-
packageVersion: '1.
|
|
34
|
+
packageVersion: '1.12.0',
|
|
35
35
|
currentSpecVersion: 1,
|
|
36
36
|
supportedSpecVersions: [1],
|
|
37
37
|
minCliVersion: '0.1.0'
|
package/package.json
CHANGED
|
@@ -127,19 +127,30 @@ The following entities are already provided by the system. DO NOT recreate them
|
|
|
127
127
|
```
|
|
128
128
|
`matchUserField` supports array match — if `user.orgIds` is an array, checks if `record.orgId` is in that array.
|
|
129
129
|
|
|
130
|
-
9. **Tenancy** (optional): If the app is multi-tenant — every record belongs to an organization, workspace, clinic, or similar — mark that one entity
|
|
130
|
+
9. **Tenancy** (optional): If the app is multi-tenant — every record belongs to an organization, workspace, clinic, or similar — mark that one entity with `"tenant": true`, then declare only the exceptions:
|
|
131
131
|
```json
|
|
132
132
|
{
|
|
133
|
-
"Org": { "plural": "orgs", "
|
|
133
|
+
"Org": { "plural": "orgs", "tenant": true, "fields": { ... } },
|
|
134
134
|
"User": { "plural": "users", "fields": { "orgIds": { "type": "objectId[]", "ref": "Org" } } },
|
|
135
|
-
"Invoice": { "plural": "invoices", "fields": { "orgId": { "type": "objectId", "ref": "Org", "required": true } } }
|
|
135
|
+
"Invoice": { "plural": "invoices", "fields": { "orgId": { "type": "objectId", "ref": "Org", "required": true } } },
|
|
136
|
+
"Setting": { "plural": "settings", "tenancy": "optional", "fields": { "orgId": { "type": "objectId", "ref": "Org" } } },
|
|
137
|
+
"AuditLog": { "plural": "auditLogs", "tenancy": "none", "fields": { "orgId": { "type": "objectId", "ref": "Org" } } }
|
|
136
138
|
}
|
|
137
139
|
```
|
|
138
|
-
|
|
139
|
-
- **`"global"`**: for an entity that refs the boundary entity but must NOT be confined by it — a tenant id recorded for provenance rather than ownership, such as an audit row naming the org an action occurred in that admins read across orgs. Rare; only needed when the ref exists.
|
|
140
|
-
- **Omit entirely** for ordinary entities, including reference data with no ref to the boundary entity — those are global by construction, since there is nothing to partition on.
|
|
140
|
+
Two separate keys, because they answer questions about different entities:
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
- **`"tenant": true`** — on the boundary entity itself, and at most one entity per blueprint. `true` is the only valid value; omit the key everywhere else. Nothing is partitioned until some entity declares it. Once declared, every entity with a ref to it is confined automatically — no per-entity declaration needed. `User` must have exactly one field ref-ing it (`objectId[]` if a user can belong to several tenants, `objectId` for exactly one); that field is discovered as the membership field.
|
|
143
|
+
- **`"tenancy"`** — on a *member* entity, to record an exception:
|
|
144
|
+
- **absent** (the default): strictly partitioned if it refs the boundary entity. This is the safe state — a forgotten key confines rather than exposes.
|
|
145
|
+
- **`"optional"`**: partitioned, but rows with NO tenant are visible to everyone — a shared default with per-tenant overrides. Use for settings, templates, categories, feature flags.
|
|
146
|
+
- **`"none"`**: never confined despite ref-ing the boundary — a tenant id kept for provenance rather than ownership, such as an audit row naming the org an action occurred in.
|
|
147
|
+
- **Omit both** on ordinary entities, including reference data with no ref to the boundary — those are global by construction, since there is nothing to partition on.
|
|
148
|
+
|
|
149
|
+
Do not guess at any of this:
|
|
150
|
+
- A tenant and a group look identical in a blueprint (an entity, a membership field, an id on the records they cover), but a tenant **confines** results while a group **widens** them. Set `"tenant": true` only when the description actually describes tenant isolation; if it describes teams, clans, or groups that share access, leave these keys off and model it with `scope` instead.
|
|
151
|
+
- Never infer `"optional"` from the ref field being non-required. A nullable tenant ref means "shared with everyone" in one app and "not backfilled yet, keep hidden" in another — identical shape, opposite intent. Declare `"optional"` only when the description says the rows are genuinely shared.
|
|
152
|
+
|
|
153
|
+
Note that `ownership` is a different axis: it says who owns rows (`"user"` or `"system"`), not what partitions them.
|
|
143
154
|
|
|
144
155
|
10. **Enhanced Enums**: Use key-value pairs for better UX:
|
|
145
156
|
```json
|
|
@@ -55,13 +55,17 @@
|
|
|
55
55
|
},
|
|
56
56
|
"ownership": {
|
|
57
57
|
"type": "string",
|
|
58
|
-
"enum": ["user", "system"
|
|
58
|
+
"enum": ["user", "system"],
|
|
59
59
|
"default": "user"
|
|
60
60
|
},
|
|
61
|
+
"tenant": {
|
|
62
|
+
"const": true,
|
|
63
|
+
"description": "This entity is the tenancy boundary (Org, Workspace, Clinic). Nothing is partitioned until exactly one entity declares this. Every entity with a ref to it is then confined to the caller's tenants. Only true is valid — omit the key on every other entity. Unrelated to ownership, which says who owns rows rather than what partitions them."
|
|
64
|
+
},
|
|
61
65
|
"tenancy": {
|
|
62
66
|
"type": "string",
|
|
63
|
-
"enum": ["
|
|
64
|
-
"description": "
|
|
67
|
+
"enum": ["optional", "none"],
|
|
68
|
+
"description": "How tenancy applies to THIS entity. Absent (the default): strictly partitioned, if it refs the boundary entity. \"optional\": partitioned, but rows with NO tenant are visible to everyone — a shared default with per-tenant overrides. \"none\": never confined, even though it refs the boundary (a tenant id kept for provenance, not ownership)."
|
|
65
69
|
},
|
|
66
70
|
"extends": {
|
|
67
71
|
"type": "string",
|