@live-change/frontend-template 0.9.199 → 0.9.201

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 (44) hide show
  1. package/.claude/rules/live-change-backend-actions-views-triggers.md +62 -0
  2. package/.claude/rules/live-change-backend-event-sourcing.md +186 -0
  3. package/.claude/rules/live-change-backend-models-and-relations.md +72 -0
  4. package/.claude/rules/live-change-frontend-vue-primevue.md +26 -0
  5. package/.claude/settings.json +32 -0
  6. package/.claude/skills/create-skills-and-rules/SKILL.md +248 -0
  7. package/.claude/skills/live-change-backend-change-triggers/SKILL.md +186 -0
  8. package/.claude/skills/live-change-design-actions-views-triggers/SKILL.md +462 -0
  9. package/.claude/skills/live-change-design-models-relations/SKILL.md +230 -0
  10. package/.claude/skills/live-change-design-service/SKILL.md +133 -0
  11. package/.claude/skills/live-change-frontend-accessible-objects/SKILL.md +384 -0
  12. package/.claude/skills/live-change-frontend-accessible-objects.md +383 -0
  13. package/.claude/skills/live-change-frontend-action-buttons/SKILL.md +129 -0
  14. package/.claude/skills/live-change-frontend-action-form/SKILL.md +149 -0
  15. package/.claude/skills/live-change-frontend-analytics/SKILL.md +147 -0
  16. package/.claude/skills/live-change-frontend-command-forms/SKILL.md +216 -0
  17. package/.claude/skills/live-change-frontend-data-views/SKILL.md +183 -0
  18. package/.claude/skills/live-change-frontend-editor-form/SKILL.md +240 -0
  19. package/.claude/skills/live-change-frontend-locale-time/SKILL.md +172 -0
  20. package/.claude/skills/live-change-frontend-page-list-detail/SKILL.md +201 -0
  21. package/.claude/skills/live-change-frontend-range-list/SKILL.md +129 -0
  22. package/.claude/skills/live-change-frontend-ssr-setup/SKILL.md +119 -0
  23. package/.cursor/rules/live-change-backend-actions-views-triggers.mdc +88 -0
  24. package/.cursor/rules/live-change-backend-event-sourcing.mdc +185 -0
  25. package/.cursor/rules/live-change-backend-models-and-relations.mdc +62 -0
  26. package/.cursor/skills/create-skills-and-rules.md +248 -0
  27. package/.cursor/skills/live-change-backend-change-triggers.md +186 -0
  28. package/.cursor/skills/live-change-design-actions-views-triggers.md +178 -79
  29. package/.cursor/skills/live-change-design-models-relations.md +112 -50
  30. package/.cursor/skills/live-change-design-service.md +1 -0
  31. package/.cursor/skills/live-change-frontend-accessible-objects.md +384 -0
  32. package/.cursor/skills/live-change-frontend-action-buttons.md +1 -0
  33. package/.cursor/skills/live-change-frontend-action-form.md +9 -3
  34. package/.cursor/skills/live-change-frontend-analytics.md +1 -0
  35. package/.cursor/skills/live-change-frontend-command-forms.md +1 -0
  36. package/.cursor/skills/live-change-frontend-data-views.md +1 -0
  37. package/.cursor/skills/live-change-frontend-editor-form.md +135 -72
  38. package/.cursor/skills/live-change-frontend-locale-time.md +1 -0
  39. package/.cursor/skills/live-change-frontend-page-list-detail.md +1 -0
  40. package/.cursor/skills/live-change-frontend-range-list.md +1 -0
  41. package/.cursor/skills/live-change-frontend-ssr-setup.md +1 -0
  42. package/front/src/router.js +2 -1
  43. package/opencode.json +10 -0
  44. package/package.json +52 -50
@@ -0,0 +1,230 @@
1
+ ---
2
+ name: live-change-design-models-relations
3
+ description: Design models with userItem, itemOf, propertyOf relations and access control
4
+ ---
5
+
6
+ # Skill: live-change-design-models-relations (Claude Code)
7
+
8
+ Use this skill when you design or refactor **models and relations** in a LiveChange service.
9
+
10
+ ## When to use
11
+
12
+ - You are adding a new model to a service.
13
+ - You want to switch from manual CRUD/views to proper relations.
14
+ - You need consistent access control and index usage.
15
+
16
+ ## Step 1 – Decide the relation type
17
+
18
+ For each new model, decide how it relates to the rest of the domain:
19
+
20
+ - **`userItem`** – the object belongs to the signed-in user (e.g. user’s device).
21
+ - **`itemOf`** – a list of children belonging to a parent model (e.g. device connections).
22
+ - **`propertyOf`** – a single state object with the same id as the parent (e.g. cursor state).
23
+ - **no relation** – for global data or other special cases.
24
+
25
+ Choose one main relation; other associations can be plain fields + indexes.
26
+
27
+ ## Step 2 – Define `properties` clearly
28
+
29
+ 1. Use a **multi-line** style for properties, with clear `type`, `default`, `validation`, etc.
30
+ 2. Avoid unreadable one-liners combining everything.
31
+ 3. **Do NOT re-declare fields that are auto-added by relations.** Each relation automatically adds identifier fields and indexes:
32
+
33
+ | Relation | Auto-added field(s) | Auto-added index(es) |
34
+ |---|---|---|
35
+ | `itemOf: { what: Device }` | `device` | `byDevice` |
36
+ | `propertyOf: { what: Device }` | `device` | `byDevice` |
37
+ | `userItem` | `user` | `byUser` |
38
+ | `sessionOrUserProperty` | `sessionOrUserType`, `sessionOrUser` | `bySessionOrUser` |
39
+ | `propertyOfAny: { to: ['owner'] }` | `ownerType`, `owner` | `byOwner` |
40
+
41
+ Naming convention: parent model name with first letter lowercased (`Device` → `device`, `CostInvoice` → `costInvoice`). Polymorphic relations add a `Type` + value pair (e.g. `ownerType` + `owner`).
42
+
43
+ Example:
44
+
45
+ ```js
46
+ // ✅ Only define YOUR fields — 'device' is auto-added by itemOf
47
+ properties: {
48
+ name: {
49
+ type: String,
50
+ validation: ['nonEmpty']
51
+ },
52
+ status: {
53
+ type: String,
54
+ default: 'offline'
55
+ },
56
+ capabilities: {
57
+ type: Array,
58
+ of: {
59
+ type: String
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Step 3 – Configure the relation
66
+
67
+ ### `userItem`
68
+
69
+ 1. Add a `userItem` block inside the model definition.
70
+ 2. Set roles for read/write and list which fields can be written.
71
+
72
+ ```js
73
+ userItem: {
74
+ readAccessControl: { roles: ['owner', 'admin'] },
75
+ writeAccessControl: { roles: ['owner', 'admin'] },
76
+ writeableProperties: ['name']
77
+ }
78
+ ```
79
+
80
+ ### `itemOf`
81
+
82
+ 1. Decide the parent model.
83
+ 2. If the parent is in another service, declare it via `foreignModel` (see next step).
84
+
85
+ ```js
86
+ itemOf: {
87
+ what: Device,
88
+ readAccessControl: { roles: ['owner', 'admin'] },
89
+ writeAccessControl: { roles: ['owner', 'admin'] }
90
+ }
91
+ ```
92
+
93
+ ### `propertyOf`
94
+
95
+ 1. Use when the child should share the same id as the parent.
96
+ 2. This simplifies lookups and avoids extra indexes.
97
+
98
+ ```js
99
+ propertyOf: {
100
+ what: Device,
101
+ readAccessControl: { roles: ['owner', 'admin'] },
102
+ writeAccessControl: { roles: ['owner', 'admin'] }
103
+ }
104
+ ```
105
+
106
+ ### `propertyOf` with multiple parents (1:1 link to each)
107
+
108
+ Use this when a model should act as a dedicated 1:1 link between multiple entities (e.g. invoice ↔ contractor role links),
109
+ so the relations/CRUD generator can treat it as a relation rather than a plain `someId` property.
110
+
111
+ Notes:
112
+
113
+ - Usually you’ll have 1–2 parents, but the `propertyOf` list may contain **any number** of parent models (including 3+).
114
+ - If the entity is a relation, avoid adding manual `...Id` fields in `properties` just to represent the link — CRUD generators won’t treat it as a relation.
115
+
116
+ Example:
117
+
118
+ ```js
119
+ const CostInvoice = definition.foreignModel('invoice', 'CostInvoice')
120
+ const Contractor = definition.foreignModel('company', 'Contractor')
121
+
122
+ definition.model({
123
+ name: 'Supplier',
124
+ properties: {
125
+ // optional extra fields
126
+ },
127
+ propertyOf: [
128
+ { what: CostInvoice },
129
+ { what: Contractor }
130
+ ]
131
+ })
132
+ ```
133
+
134
+ ## Step 4 – Use `foreignModel` for cross-service relations
135
+
136
+ 1. At the top of the domain file, declare:
137
+
138
+ ```js
139
+ const Device = definition.foreignModel('deviceManager', 'Device')
140
+ ```
141
+
142
+ 2. Then use `Device` in `itemOf` or `propertyOf`:
143
+
144
+ ```js
145
+ itemOf: {
146
+ what: Device,
147
+ readAccessControl: { roles: ['owner', 'admin'] }
148
+ }
149
+ ```
150
+
151
+ ## Step 5 – Add indexes
152
+
153
+ 1. Identify frequent queries:
154
+ - by a single field (e.g. `sessionKey`),
155
+ - by combinations (e.g. `(device, status)`).
156
+ 2. Declare indexes in the model:
157
+
158
+ ```js
159
+ indexes: {
160
+ bySessionKey: {
161
+ property: ['sessionKey']
162
+ },
163
+ byDeviceAndStatus: {
164
+ property: ['device', 'status']
165
+ }
166
+ }
167
+ ```
168
+
169
+ 3. Use these indexes in views/actions, via `indexObjectGet` / `indexRangeGet`.
170
+
171
+ ## Step 6 – Set access control on relations
172
+
173
+ 1. For `userItem`, `itemOf`, and `propertyOf`, always define:
174
+ - `readAccessControl`,
175
+ - `writeAccessControl`.
176
+ 2. Don’t rely on unspecified defaults; access rules should be explicit in the model.
177
+
178
+ ## Step 7 – Grant access on `entity` model creation
179
+
180
+ Models with `entity` and `writeAccessControl` / `readAccessControl` check roles on every CRUD operation, but do **not** auto-grant roles to the creator. Without granting roles, the creator cannot even read their own object.
181
+
182
+ Add a change trigger that grants `'owner'` on creation:
183
+
184
+ ```js
185
+ definition.trigger({
186
+ name: 'changeMyService_MyModel',
187
+ properties: {
188
+ object: { type: MyModel, validation: ['nonEmpty'] },
189
+ data: { type: Object },
190
+ oldData: { type: Object }
191
+ },
192
+ async execute({ object, data, oldData }, { client, triggerService }) {
193
+ if (!data || oldData) return // only on create
194
+ if (!client?.user) return
195
+
196
+ await triggerService({ service: 'accessControl', type: 'accessControl_setAccess' }, {
197
+ objectType: 'myService_MyModel', // format: serviceName_ModelName
198
+ object,
199
+ roles: ['owner'],
200
+ sessionOrUserType: 'user_User',
201
+ sessionOrUser: client.user,
202
+ lastUpdate: new Date()
203
+ })
204
+ }
205
+ })
206
+ ```
207
+
208
+ For objects that should also be publicly readable, add `accessControl_setPublicAccess`:
209
+
210
+ ```js
211
+ await triggerService({ service: 'accessControl', type: 'accessControl_setPublicAccess' }, {
212
+ objectType: 'myService_MyModel',
213
+ object,
214
+ userRoles: ['reader'], // roles for all logged-in users
215
+ sessionRoles: ['reader'], // roles for all sessions (including anonymous)
216
+ lastUpdate: new Date()
217
+ })
218
+ ```
219
+
220
+ **Note:** `userItem` and `itemOf`/`propertyOf` relations automatically handle access through the parent — you typically don't need manual `triggerService` calls for those. This step applies primarily to `entity` models.
221
+
222
+ ## Step 8 – Check auto-generated views/actions
223
+
224
+ 1. After adding relations, review the auto-generated views/actions:
225
+ - “my X” views and CRUD for `userItem`,
226
+ - parent-scoped lists for `itemOf`/`propertyOf`.
227
+ 2. Only add custom views/actions when:
228
+ - you need special filters,
229
+ - or custom logic not covered by the generated ones.
230
+
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: live-change-design-service
3
+ description: Create or restructure a LiveChange backend service with proper directory layout
4
+ ---
5
+
6
+ # Skill: live-change-design-service (Claude Code)
7
+
8
+ Use this skill when you need to **create or restructure a LiveChange service** in this project or any other live-change-stack project.
9
+
10
+ ## When to use
11
+
12
+ - You are adding a **new domain service** (payments, devices, notifications, etc.).
13
+ - You are splitting logic out of an existing service.
14
+ - You want to make sure the service structure follows the project conventions.
15
+
16
+ ## Step 1 – Choose the service name
17
+
18
+ 1. Pick a short, domain-oriented name, e.g. `deviceManager`, `payments`, `notifications`.
19
+ 2. This name will be used:
20
+ - as `name` in `app.createServiceDefinition({ name })`,
21
+ - as the `name` entry in `app.config.js` (`services: [{ name: '...' }]`),
22
+ - in `services.list.js` as the property key.
23
+
24
+ ## Step 2 – Create the service directory
25
+
26
+ 1. Create `server/services/<serviceName>/`.
27
+ 2. Inside, create at least:
28
+ - `definition.js`
29
+ - `index.js`
30
+ 3. Optionally also:
31
+ - `config.js` – for resolving `definition.config`,
32
+ - domain files like `models.js`, `authenticator.js`, `actions.js`, or more fine-grained files.
33
+
34
+ ## Step 3 – Implement `definition.js`
35
+
36
+ 1. Import `app` from `@live-change/framework`.
37
+ 2. If the service uses relations or access control:
38
+ - import `relationsPlugin` from `@live-change/relations-plugin`,
39
+ - import `accessControlService` from `@live-change/access-control-service`.
40
+ 3. Call `app.createServiceDefinition({ name: '...', use: [...] })`.
41
+ 4. **Do not register models, actions or views** in this file – only the definition.
42
+
43
+ Example:
44
+
45
+ ```js
46
+ import { app } from '@live-change/framework'
47
+ import relationsPlugin from '@live-change/relations-plugin'
48
+ import accessControlService from '@live-change/access-control-service'
49
+
50
+ const definition = app.createServiceDefinition({
51
+ name: 'myService',
52
+ use: [relationsPlugin, accessControlService]
53
+ })
54
+
55
+ export default definition
56
+ ```
57
+
58
+ ## Step 4 – Implement `index.js`
59
+
60
+ 1. Import `definition` from `./definition.js`.
61
+ 2. Import all domain files (models, views, actions, triggers, authenticators) as side-effect imports.
62
+ 3. Export `definition` as the default export.
63
+ 4. Do **not** put heavy logic into `index.js`.
64
+
65
+ Example:
66
+
67
+ ```js
68
+ import definition from './definition.js'
69
+
70
+ import './models.js'
71
+ import './authenticator.js'
72
+ import './actions.js'
73
+
74
+ export default definition
75
+ ```
76
+
77
+ ## Step 5 – (Optional) Implement `config.js`
78
+
79
+ 1. Import `definition`.
80
+ 2. Read `definition.config` and apply default values.
81
+ 3. Export a plain object.
82
+
83
+ Example:
84
+
85
+ ```js
86
+ import definition from './definition.js'
87
+
88
+ const {
89
+ someOption = 'default'
90
+ } = definition.config
91
+
92
+ export default { someOption }
93
+ ```
94
+
95
+ ## Step 6 – Register the service in `services.list.js`
96
+
97
+ 1. Import from the service directory `index.js`:
98
+
99
+ ```js
100
+ import myService from './services/myService/index.js'
101
+ ```
102
+
103
+ 2. Add the service to the exported object:
104
+
105
+ ```js
106
+ export default {
107
+ // ...
108
+ myService
109
+ }
110
+ ```
111
+
112
+ ## Step 7 – Register the service in `app.config.js`
113
+
114
+ 1. Ensure there is an entry in `services`:
115
+
116
+ ```js
117
+ services: [
118
+ // ...
119
+ { name: 'myService' }
120
+ ]
121
+ ```
122
+
123
+ 2. Keep a sensible order:
124
+ - core/common services and plugins (user, session, accessControl, etc.) first,
125
+ - domain-specific application services later.
126
+
127
+ ## Step 8 – Handle dependencies on other services
128
+
129
+ 1. If the service needs to reference models from other services:
130
+ - use `definition.foreignModel('otherService', 'ModelName')` in domain files,
131
+ - do **not** import their model files directly.
132
+ 2. Make sure the other services are listed **before** this one in `app.config.js`.
133
+