@oneie/sdk 0.13.9 → 0.14.1

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 (62) hide show
  1. package/LICENSE +81 -13
  2. package/README.md +3 -3
  3. package/dist/brain.d.ts +2 -0
  4. package/dist/brain.d.ts.map +1 -1
  5. package/dist/brain.js +8 -0
  6. package/dist/brain.js.map +1 -1
  7. package/dist/client.d.ts +46 -3
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +67 -5
  10. package/dist/client.js.map +1 -1
  11. package/dist/compile.d.ts.map +1 -1
  12. package/dist/compile.js +6 -3
  13. package/dist/compile.js.map +1 -1
  14. package/dist/errors.d.ts +8 -0
  15. package/dist/errors.d.ts.map +1 -1
  16. package/dist/errors.js +16 -0
  17. package/dist/errors.js.map +1 -1
  18. package/dist/generated/fn-map.d.ts +15 -0
  19. package/dist/generated/fn-map.d.ts.map +1 -0
  20. package/dist/generated/fn-map.js +1170 -0
  21. package/dist/generated/fn-map.js.map +1 -0
  22. package/dist/generated/schemas/index.d.ts +241 -0
  23. package/dist/generated/schemas/index.d.ts.map +1 -0
  24. package/dist/generated/schemas/index.js +129 -0
  25. package/dist/generated/schemas/index.js.map +1 -0
  26. package/dist/generated/schemas.d.ts +804 -0
  27. package/dist/generated/schemas.d.ts.map +1 -0
  28. package/dist/generated/schemas.js +643 -0
  29. package/dist/generated/schemas.js.map +1 -0
  30. package/dist/generated/skins/engineering.d.ts +37 -0
  31. package/dist/generated/skins/engineering.d.ts.map +1 -0
  32. package/dist/generated/skins/engineering.js +33 -0
  33. package/dist/generated/skins/engineering.js.map +1 -0
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +5 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/plugin-build.d.ts +18 -0
  39. package/dist/plugin-build.d.ts.map +1 -0
  40. package/dist/plugin-build.js +15 -0
  41. package/dist/plugin-build.js.map +1 -0
  42. package/dist/receivers.d.ts +373 -10
  43. package/dist/receivers.d.ts.map +1 -1
  44. package/dist/receivers.js +372 -5
  45. package/dist/receivers.js.map +1 -1
  46. package/dist/schemas.d.ts +2 -2
  47. package/dist/skills.d.ts +7 -5
  48. package/dist/skills.d.ts.map +1 -1
  49. package/dist/skills.js.map +1 -1
  50. package/dist/templates.d.ts +1 -0
  51. package/dist/templates.d.ts.map +1 -1
  52. package/dist/templates.js +950 -72
  53. package/dist/templates.js.map +1 -1
  54. package/dist/trail.d.ts +25 -0
  55. package/dist/trail.d.ts.map +1 -0
  56. package/dist/trail.js +25 -0
  57. package/dist/trail.js.map +1 -0
  58. package/dist/types.d.ts +49 -0
  59. package/dist/types.d.ts.map +1 -1
  60. package/dist/types.js +9 -0
  61. package/dist/types.js.map +1 -1
  62. package/package.json +10 -3
package/dist/templates.js CHANGED
@@ -1,125 +1,962 @@
1
+ // ─── Industry & department resource-type templates ───────────────────────────
2
+ //
3
+ // Each template is a ready-made ontology a workspace can seed into its manifest
4
+ // (world:declare-types { template }). Every type maps to one of the 6 ONE
5
+ // dimensions (groups · actors · things · paths · events · learning) and the
6
+ // `/u/{slug}/types` canvas renders them — dimension sets the node tone, and a
7
+ // `relation` field whose option names a sibling key draws an edge between nodes.
8
+ //
9
+ // The library is layered:
10
+ // • one / world — the substrate itself and an operating workspace
11
+ // • crm — the shared contact graph every department reads
12
+ // • sales · marketing · service · education · staff — the departments
13
+ // • ecommerce — a store
14
+ // • roofers · movers — field-service verticals
15
+ //
16
+ // Authoring rules that keep the graph clean:
17
+ // • columns = the 2–4 fields shown on the card and the table list
18
+ // • fields = the full edit form
19
+ // • filters = the select/tag fields worth faceting on
20
+ // • relation field options MUST name a key in the SAME template, or no edge
21
+ // is drawn (extractRelationEdges drops dangling targets).
22
+ // • `ecommerce` is intentionally relation-free — a unit test pins that.
23
+ const THING_ACTIONS = ["world:create-thing", "world:update-thing", "world:remove-thing"];
24
+ const ACTOR_ACTIONS = ["world:create-actor", "world:update-actor"];
25
+ const GROUP_ACTIONS = ["world:create-group", "world:update-group"];
1
26
  export const TEMPLATES = {
2
- ecommerce: [
27
+ // ── one — the substrate itself: the 6 dimensions as a living graph ──────────
28
+ one: [
3
29
  {
4
- key: "products", label: "Products", dimension: "things", type: "product", icon: "Package",
30
+ key: "groups", label: "Groups", dimension: "groups", type: "group", icon: "Boxes",
5
31
  columns: [
6
32
  { field: "name", label: "Name", kind: "text", required: true },
7
- { field: "price", label: "Price", kind: "currency" },
33
+ { field: "group_type", label: "Type", kind: "select", options: ["world", "team", "org", "community", "dao", "workspace", "personal"] },
34
+ { field: "plan", label: "Plan", kind: "select", options: ["starter", "growth", "enterprise"] },
35
+ ],
36
+ fields: [
37
+ { field: "name", label: "Name", kind: "text", required: true },
38
+ { field: "group_type", label: "Group type", kind: "select", options: ["world", "team", "org", "community", "dao", "workspace", "personal"] },
39
+ { field: "brand", label: "Brand", kind: "text" },
40
+ { field: "plan", label: "Plan", kind: "select", options: ["starter", "growth", "enterprise"] },
41
+ { field: "visibility", label: "Visibility", kind: "select", options: ["private", "group", "public"] },
42
+ ],
43
+ filters: [{ field: "group_type", label: "Type", kind: "select", options: ["world", "team", "org", "community", "dao", "workspace", "personal"] }],
44
+ actions: GROUP_ACTIONS,
45
+ },
46
+ {
47
+ key: "actors", label: "Actors", dimension: "actors", type: "actor", icon: "Users",
48
+ columns: [
49
+ { field: "name", label: "Name", kind: "text", required: true },
50
+ { field: "actor_type", label: "Kind", kind: "select", options: ["human", "agent", "world", "animal"] },
51
+ { field: "model", label: "Model", kind: "text" },
52
+ ],
53
+ fields: [
54
+ { field: "name", label: "Name", kind: "text", required: true },
55
+ { field: "actor_type", label: "Actor type", kind: "select", options: ["human", "agent", "world", "animal"] },
56
+ { field: "model", label: "LLM model", kind: "text" },
57
+ { field: "prompt", label: "System prompt", kind: "markdown" },
58
+ { field: "wallet", label: "Wallet", kind: "text" },
8
59
  { field: "tags", label: "Tags", kind: "tags" },
60
+ { field: "group", label: "Member of", kind: "relation", options: ["groups"] },
61
+ ],
62
+ filters: [{ field: "actor_type", label: "Kind", kind: "select", options: ["human", "agent", "world", "animal"] }],
63
+ actions: ACTOR_ACTIONS,
64
+ },
65
+ {
66
+ key: "things", label: "Things", dimension: "things", type: "thing", icon: "Box",
67
+ columns: [
68
+ { field: "name", label: "Name", kind: "text", required: true },
69
+ { field: "thing_type", label: "Type", kind: "select", options: ["skill", "task", "token", "service", "plan"] },
70
+ { field: "price", label: "Price", kind: "currency" },
9
71
  ],
10
72
  fields: [
11
73
  { field: "name", label: "Name", kind: "text", required: true },
74
+ { field: "thing_type", label: "Thing type", kind: "select", options: ["skill", "task", "token", "service", "plan"] },
12
75
  { field: "price", label: "Price", kind: "currency" },
13
- { field: "description", label: "Description", kind: "markdown" },
14
- { field: "image", label: "Image", kind: "image" },
76
+ { field: "status", label: "Status", kind: "text" },
15
77
  { field: "tags", label: "Tags", kind: "tags" },
78
+ { field: "provider", label: "Provided by", kind: "relation", options: ["actors"] },
16
79
  ],
17
- filters: [{ field: "tags", label: "Tags", kind: "tags" }],
18
- actions: ["world:create-thing", "world:update-thing", "world:remove-thing"],
80
+ filters: [{ field: "thing_type", label: "Type", kind: "select", options: ["skill", "task", "token", "service", "plan"] }],
81
+ actions: THING_ACTIONS,
19
82
  },
20
83
  {
21
- key: "orders", label: "Orders", dimension: "things", type: "order", icon: "ShoppingCart",
84
+ key: "paths", label: "Paths", dimension: "paths", type: "path", icon: "Spline",
22
85
  columns: [
23
- { field: "name", label: "Order #", kind: "text", required: true },
24
- { field: "price", label: "Total", kind: "currency" },
25
- { field: "tags", label: "Status", kind: "select", options: ["pending", "paid", "shipped", "cancelled"] },
86
+ { field: "name", label: "Path", kind: "text", required: true },
87
+ { field: "strength", label: "Strength", kind: "number" },
88
+ { field: "resistance", label: "Resistance", kind: "number" },
26
89
  ],
27
90
  fields: [
28
- { field: "name", label: "Order #", kind: "text", required: true },
29
- { field: "price", label: "Total", kind: "currency" },
30
- { field: "tags", label: "Status", kind: "select", options: ["pending", "paid", "shipped", "cancelled"] },
91
+ { field: "name", label: "Path", kind: "text", required: true },
92
+ { field: "strength", label: "Strength (mark)", kind: "number" },
93
+ { field: "resistance", label: "Resistance (warn)", kind: "number" },
94
+ { field: "traversals", label: "Traversals", kind: "number" },
95
+ { field: "scope", label: "Scope", kind: "select", options: ["private", "group", "public"] },
96
+ { field: "from", label: "Source", kind: "relation", options: ["actors"] },
97
+ { field: "to", label: "Target", kind: "relation", options: ["actors"] },
31
98
  ],
32
- filters: [{ field: "tags", label: "Status", kind: "select", options: ["pending", "paid", "shipped", "cancelled"] }],
33
- actions: ["world:update-thing"],
99
+ filters: [{ field: "scope", label: "Scope", kind: "select", options: ["private", "group", "public"] }],
100
+ actions: [],
34
101
  },
35
102
  {
36
- key: "customers", label: "Customers", dimension: "actors", type: "customer", icon: "Users",
103
+ key: "events", label: "Events", dimension: "events", type: "signal", icon: "Zap",
104
+ columns: [
105
+ { field: "name", label: "Signal", kind: "text", required: true },
106
+ { field: "amount", label: "Amount", kind: "currency" },
107
+ { field: "ts", label: "When", kind: "date" },
108
+ ],
109
+ fields: [
110
+ { field: "name", label: "Receiver", kind: "text", required: true },
111
+ { field: "payload", label: "Payload", kind: "markdown" },
112
+ { field: "amount", label: "Amount", kind: "currency" },
113
+ { field: "success", label: "Success", kind: "select", options: ["yes", "no"] },
114
+ { field: "latency", label: "Latency (ms)", kind: "number" },
115
+ { field: "ts", label: "Timestamp", kind: "date" },
116
+ { field: "sender", label: "Sender", kind: "relation", options: ["actors"] },
117
+ { field: "receiver", label: "Receiver", kind: "relation", options: ["actors"] },
118
+ ],
119
+ filters: [{ field: "success", label: "Success", kind: "select", options: ["yes", "no"] }],
120
+ actions: [],
121
+ },
122
+ {
123
+ key: "learning", label: "Learning", dimension: "learning", type: "hypothesis", icon: "Lightbulb",
124
+ columns: [
125
+ { field: "name", label: "Statement", kind: "text", required: true },
126
+ { field: "status", label: "Status", kind: "select", options: ["pending", "confirmed", "rejected"] },
127
+ { field: "confidence", label: "Confidence", kind: "number" },
128
+ ],
129
+ fields: [
130
+ { field: "name", label: "Statement", kind: "text", required: true },
131
+ { field: "status", label: "Status", kind: "select", options: ["pending", "confirmed", "rejected"] },
132
+ { field: "confidence", label: "Confidence", kind: "number" },
133
+ { field: "p_value", label: "p-value", kind: "number" },
134
+ { field: "observations", label: "Observations", kind: "number" },
135
+ { field: "source", label: "Source receiver", kind: "text" },
136
+ { field: "about", label: "Belongs to", kind: "relation", options: ["groups"] },
137
+ ],
138
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["pending", "confirmed", "rejected"] }],
139
+ actions: ["world:create-hypothesis"],
140
+ },
141
+ ],
142
+ // ── world — an operating workspace: who acts, what they make, what they aim at ─
143
+ world: [
144
+ {
145
+ key: "members", label: "Members", dimension: "actors", type: "member", icon: "Users",
37
146
  columns: [
38
147
  { field: "name", label: "Name", kind: "text", required: true },
39
- { field: "tags", label: "Tags", kind: "tags" },
148
+ { field: "role", label: "Role", kind: "select", options: ["owner", "admin", "member", "viewer", "agent", "auditor"] },
149
+ { field: "actor_type", label: "Kind", kind: "select", options: ["human", "agent"] },
40
150
  ],
41
151
  fields: [
42
152
  { field: "name", label: "Name", kind: "text", required: true },
153
+ { field: "role", label: "Role", kind: "select", options: ["owner", "admin", "member", "viewer", "agent", "auditor"] },
154
+ { field: "actor_type", label: "Kind", kind: "select", options: ["human", "agent"] },
43
155
  { field: "tags", label: "Tags", kind: "tags" },
44
156
  ],
45
- filters: [],
46
- actions: ["world:create-actor", "world:update-actor"],
157
+ filters: [{ field: "role", label: "Role", kind: "select", options: ["owner", "admin", "member", "viewer", "agent", "auditor"] }],
158
+ actions: ACTOR_ACTIONS,
159
+ },
160
+ {
161
+ key: "skills", label: "Skills", dimension: "things", type: "skill", icon: "Sparkles",
162
+ columns: [
163
+ { field: "name", label: "Skill", kind: "text", required: true },
164
+ { field: "price", label: "Price", kind: "currency" },
165
+ { field: "tags", label: "Tags", kind: "tags" },
166
+ ],
167
+ fields: [
168
+ { field: "name", label: "Skill", kind: "text", required: true },
169
+ { field: "description", label: "Description", kind: "markdown" },
170
+ { field: "price", label: "Price", kind: "currency" },
171
+ { field: "tags", label: "Tags", kind: "tags" },
172
+ { field: "provider", label: "Provider", kind: "relation", options: ["members"] },
173
+ ],
174
+ filters: [{ field: "tags", label: "Tags", kind: "tags" }],
175
+ actions: THING_ACTIONS,
176
+ },
177
+ {
178
+ key: "tasks", label: "Tasks", dimension: "things", type: "task", icon: "ListTodo",
179
+ columns: [
180
+ { field: "name", label: "Task", kind: "text", required: true },
181
+ { field: "status", label: "Status", kind: "select", options: ["open", "blocked", "picked", "done", "verified", "failed"] },
182
+ { field: "wave", label: "Wave", kind: "select", options: ["W1", "W2", "W3", "W4"] },
183
+ ],
184
+ fields: [
185
+ { field: "name", label: "Task", kind: "text", required: true },
186
+ { field: "status", label: "Status", kind: "select", options: ["open", "blocked", "picked", "done", "verified", "failed"] },
187
+ { field: "wave", label: "Wave", kind: "select", options: ["W1", "W2", "W3", "W4"] },
188
+ { field: "effort", label: "Effort", kind: "number" },
189
+ { field: "value", label: "Value", kind: "number" },
190
+ { field: "assignee", label: "Assignee", kind: "relation", options: ["members"] },
191
+ ],
192
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["open", "blocked", "picked", "done", "verified", "failed"] }],
193
+ actions: THING_ACTIONS,
194
+ },
195
+ {
196
+ key: "objectives", label: "Objectives", dimension: "things", type: "objective", icon: "Target",
197
+ columns: [
198
+ { field: "name", label: "Objective", kind: "text", required: true },
199
+ { field: "status", label: "Status", kind: "select", options: ["pending", "active", "complete"] },
200
+ { field: "progress", label: "Progress", kind: "number" },
201
+ ],
202
+ fields: [
203
+ { field: "name", label: "Objective", kind: "text", required: true },
204
+ { field: "status", label: "Status", kind: "select", options: ["pending", "active", "complete"] },
205
+ { field: "priority", label: "Priority", kind: "number" },
206
+ { field: "progress", label: "Progress", kind: "number" },
207
+ { field: "frontier", label: "Spawned from", kind: "relation", options: ["frontiers"] },
208
+ ],
209
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["pending", "active", "complete"] }],
210
+ actions: THING_ACTIONS,
211
+ },
212
+ {
213
+ key: "frontiers", label: "Frontiers", dimension: "learning", type: "frontier", icon: "Compass",
214
+ columns: [
215
+ { field: "name", label: "Frontier", kind: "text", required: true },
216
+ { field: "status", label: "Status", kind: "select", options: ["unexplored", "exploring", "exhausted"] },
217
+ { field: "expected_value", label: "Expected value", kind: "number" },
218
+ ],
219
+ fields: [
220
+ { field: "name", label: "Frontier", kind: "text", required: true },
221
+ { field: "frontier_type", label: "Type", kind: "text" },
222
+ { field: "status", label: "Status", kind: "select", options: ["unexplored", "exploring", "exhausted"] },
223
+ { field: "expected_value", label: "Expected value", kind: "number" },
224
+ ],
225
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["unexplored", "exploring", "exhausted"] }],
226
+ actions: [],
227
+ },
228
+ {
229
+ key: "contributions", label: "Contributions", dimension: "events", type: "contribution", icon: "Activity",
230
+ columns: [
231
+ { field: "name", label: "Contribution", kind: "text", required: true },
232
+ { field: "contribution_type", label: "Type", kind: "select", options: ["signal", "payment", "discovery"] },
233
+ { field: "impact", label: "Impact", kind: "number" },
234
+ ],
235
+ fields: [
236
+ { field: "name", label: "Contribution", kind: "text", required: true },
237
+ { field: "contribution_type", label: "Type", kind: "select", options: ["signal", "payment", "discovery"] },
238
+ { field: "impact", label: "Impact score", kind: "number" },
239
+ { field: "contributor", label: "Contributor", kind: "relation", options: ["members"] },
240
+ ],
241
+ filters: [{ field: "contribution_type", label: "Type", kind: "select", options: ["signal", "payment", "discovery"] }],
242
+ actions: [],
47
243
  },
48
244
  ],
245
+ // ── crm — contacts, the companies they belong to, deals, and the work ───────
49
246
  crm: [
50
247
  {
51
248
  key: "contacts", label: "Contacts", dimension: "actors", type: "contact", icon: "UserRound",
52
249
  columns: [
53
250
  { field: "name", label: "Name", kind: "text", required: true },
54
- { field: "tags", label: "Tags", kind: "tags" },
251
+ { field: "lifecycle", label: "Stage", kind: "select", options: ["lead", "mql", "sql", "customer", "churned"] },
252
+ { field: "company", label: "Company", kind: "relation", options: ["companies"] },
55
253
  ],
56
254
  fields: [
57
255
  { field: "name", label: "Name", kind: "text", required: true },
256
+ { field: "email", label: "Email", kind: "text" },
257
+ { field: "phone", label: "Phone", kind: "text" },
258
+ { field: "title", label: "Job title", kind: "text" },
259
+ { field: "lifecycle", label: "Lifecycle", kind: "select", options: ["lead", "mql", "sql", "customer", "churned"] },
58
260
  { field: "tags", label: "Tags", kind: "tags" },
261
+ { field: "company", label: "Company", kind: "relation", options: ["companies"] },
59
262
  ],
60
- filters: [],
61
- actions: ["world:create-actor", "world:update-actor"],
263
+ filters: [{ field: "lifecycle", label: "Stage", kind: "select", options: ["lead", "mql", "sql", "customer", "churned"] }],
264
+ actions: ACTOR_ACTIONS,
265
+ },
266
+ {
267
+ key: "companies", label: "Companies", dimension: "groups", type: "company", icon: "Building2",
268
+ columns: [
269
+ { field: "name", label: "Company", kind: "text", required: true },
270
+ { field: "industry", label: "Industry", kind: "text" },
271
+ { field: "size", label: "Size", kind: "select", options: ["1-10", "11-50", "51-200", "201-1000", "1000+"] },
272
+ ],
273
+ fields: [
274
+ { field: "name", label: "Company", kind: "text", required: true },
275
+ { field: "domain", label: "Domain", kind: "text" },
276
+ { field: "industry", label: "Industry", kind: "text" },
277
+ { field: "size", label: "Headcount", kind: "select", options: ["1-10", "11-50", "51-200", "201-1000", "1000+"] },
278
+ { field: "tags", label: "Tags", kind: "tags" },
279
+ ],
280
+ filters: [{ field: "size", label: "Size", kind: "select", options: ["1-10", "11-50", "51-200", "201-1000", "1000+"] }],
281
+ actions: GROUP_ACTIONS,
62
282
  },
63
283
  {
64
284
  key: "deals", label: "Deals", dimension: "things", type: "deal", icon: "Handshake",
65
285
  columns: [
66
286
  { field: "name", label: "Deal", kind: "text", required: true },
67
- { field: "price", label: "Value", kind: "currency" },
68
- { field: "tags", label: "Stage", kind: "select", options: ["prospect", "qualified", "proposal", "closed-won", "closed-lost"] },
287
+ { field: "value", label: "Value", kind: "currency" },
288
+ { field: "stage", label: "Stage", kind: "select", options: ["prospect", "qualified", "proposal", "negotiation", "closed-won", "closed-lost"] },
69
289
  ],
70
290
  fields: [
71
291
  { field: "name", label: "Deal", kind: "text", required: true },
72
- { field: "price", label: "Value", kind: "currency" },
73
- { field: "tags", label: "Stage", kind: "select", options: ["prospect", "qualified", "proposal", "closed-won", "closed-lost"] },
292
+ { field: "value", label: "Value", kind: "currency" },
293
+ { field: "stage", label: "Stage", kind: "select", options: ["prospect", "qualified", "proposal", "negotiation", "closed-won", "closed-lost"] },
294
+ { field: "close_date", label: "Close date", kind: "date" },
295
+ { field: "probability", label: "Probability %", kind: "number" },
296
+ { field: "contact", label: "Primary contact", kind: "relation", options: ["contacts"] },
297
+ { field: "company", label: "Company", kind: "relation", options: ["companies"] },
74
298
  ],
75
- filters: [{ field: "tags", label: "Stage", kind: "select", options: ["prospect", "qualified", "proposal", "closed-won", "closed-lost"] }],
76
- actions: ["world:create-thing", "world:update-thing"],
299
+ filters: [{ field: "stage", label: "Stage", kind: "select", options: ["prospect", "qualified", "proposal", "negotiation", "closed-won", "closed-lost"] }],
300
+ actions: THING_ACTIONS,
77
301
  },
78
302
  {
79
- key: "companies", label: "Companies", dimension: "groups", type: "company", icon: "Building2",
303
+ key: "activities", label: "Activities", dimension: "events", type: "activity", icon: "CalendarClock",
80
304
  columns: [
81
- { field: "name", label: "Company", kind: "text", required: true },
82
- { field: "tags", label: "Tags", kind: "tags" },
305
+ { field: "name", label: "Activity", kind: "text", required: true },
306
+ { field: "kind", label: "Kind", kind: "select", options: ["call", "email", "meeting", "note", "task"] },
307
+ { field: "date", label: "Date", kind: "date" },
308
+ ],
309
+ fields: [
310
+ { field: "name", label: "Activity", kind: "text", required: true },
311
+ { field: "kind", label: "Kind", kind: "select", options: ["call", "email", "meeting", "note", "task"] },
312
+ { field: "date", label: "Date", kind: "date" },
313
+ { field: "notes", label: "Notes", kind: "markdown" },
314
+ { field: "contact", label: "Contact", kind: "relation", options: ["contacts"] },
315
+ { field: "deal", label: "Deal", kind: "relation", options: ["deals"] },
316
+ ],
317
+ filters: [{ field: "kind", label: "Kind", kind: "select", options: ["call", "email", "meeting", "note", "task"] }],
318
+ actions: [],
319
+ },
320
+ {
321
+ key: "tasks", label: "Tasks", dimension: "things", type: "task", icon: "CheckSquare",
322
+ columns: [
323
+ { field: "name", label: "Task", kind: "text", required: true },
324
+ { field: "status", label: "Status", kind: "select", options: ["open", "done"] },
325
+ { field: "due", label: "Due", kind: "date" },
83
326
  ],
84
327
  fields: [
328
+ { field: "name", label: "Task", kind: "text", required: true },
329
+ { field: "status", label: "Status", kind: "select", options: ["open", "done"] },
330
+ { field: "priority", label: "Priority", kind: "select", options: ["high", "medium", "low"] },
331
+ { field: "due", label: "Due date", kind: "date" },
332
+ { field: "deal", label: "Deal", kind: "relation", options: ["deals"] },
333
+ ],
334
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["open", "done"] }],
335
+ actions: THING_ACTIONS,
336
+ },
337
+ ],
338
+ // ── sales — pipeline: lead → opportunity → quote → order, worked by reps ─────
339
+ sales: [
340
+ {
341
+ key: "leads", label: "Leads", dimension: "actors", type: "lead", icon: "Flame",
342
+ columns: [
85
343
  { field: "name", label: "Name", kind: "text", required: true },
344
+ { field: "status", label: "Status", kind: "select", options: ["new", "contacted", "qualified", "unqualified"] },
345
+ { field: "source", label: "Source", kind: "select", options: ["inbound", "outbound", "referral", "event", "ads"] },
346
+ ],
347
+ fields: [
348
+ { field: "name", label: "Name", kind: "text", required: true },
349
+ { field: "email", label: "Email", kind: "text" },
350
+ { field: "phone", label: "Phone", kind: "text" },
351
+ { field: "status", label: "Status", kind: "select", options: ["new", "contacted", "qualified", "unqualified"] },
352
+ { field: "source", label: "Source", kind: "select", options: ["inbound", "outbound", "referral", "event", "ads"] },
353
+ { field: "owner", label: "Owner", kind: "relation", options: ["reps"] },
354
+ ],
355
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["new", "contacted", "qualified", "unqualified"] }],
356
+ actions: ACTOR_ACTIONS,
357
+ },
358
+ {
359
+ key: "opportunities", label: "Opportunities", dimension: "things", type: "opportunity", icon: "TrendingUp",
360
+ columns: [
361
+ { field: "name", label: "Opportunity", kind: "text", required: true },
362
+ { field: "value", label: "Value", kind: "currency" },
363
+ { field: "stage", label: "Stage", kind: "select", options: ["prospecting", "qualification", "proposal", "negotiation", "closed-won", "closed-lost"] },
364
+ ],
365
+ fields: [
366
+ { field: "name", label: "Opportunity", kind: "text", required: true },
367
+ { field: "value", label: "Value", kind: "currency" },
368
+ { field: "stage", label: "Stage", kind: "select", options: ["prospecting", "qualification", "proposal", "negotiation", "closed-won", "closed-lost"] },
369
+ { field: "close_date", label: "Expected close", kind: "date" },
370
+ { field: "probability", label: "Probability %", kind: "number" },
371
+ { field: "lead", label: "Lead", kind: "relation", options: ["leads"] },
372
+ { field: "rep", label: "Owner", kind: "relation", options: ["reps"] },
373
+ ],
374
+ filters: [{ field: "stage", label: "Stage", kind: "select", options: ["prospecting", "qualification", "proposal", "negotiation", "closed-won", "closed-lost"] }],
375
+ actions: THING_ACTIONS,
376
+ },
377
+ {
378
+ key: "quotes", label: "Quotes", dimension: "things", type: "quote", icon: "FileText",
379
+ columns: [
380
+ { field: "name", label: "Quote", kind: "text", required: true },
381
+ { field: "amount", label: "Amount", kind: "currency" },
382
+ { field: "status", label: "Status", kind: "select", options: ["draft", "sent", "accepted", "expired"] },
383
+ ],
384
+ fields: [
385
+ { field: "name", label: "Quote", kind: "text", required: true },
386
+ { field: "amount", label: "Amount", kind: "currency" },
387
+ { field: "status", label: "Status", kind: "select", options: ["draft", "sent", "accepted", "expired"] },
388
+ { field: "valid_until", label: "Valid until", kind: "date" },
389
+ { field: "opportunity", label: "Opportunity", kind: "relation", options: ["opportunities"] },
390
+ ],
391
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["draft", "sent", "accepted", "expired"] }],
392
+ actions: THING_ACTIONS,
393
+ },
394
+ {
395
+ key: "orders", label: "Orders", dimension: "things", type: "order", icon: "ShoppingBag",
396
+ columns: [
397
+ { field: "name", label: "Order #", kind: "text", required: true },
398
+ { field: "total", label: "Total", kind: "currency" },
399
+ { field: "status", label: "Status", kind: "select", options: ["pending", "paid", "fulfilled", "refunded"] },
400
+ ],
401
+ fields: [
402
+ { field: "name", label: "Order #", kind: "text", required: true },
403
+ { field: "total", label: "Total", kind: "currency" },
404
+ { field: "status", label: "Status", kind: "select", options: ["pending", "paid", "fulfilled", "refunded"] },
405
+ { field: "ordered_at", label: "Ordered", kind: "date" },
406
+ { field: "quote", label: "Quote", kind: "relation", options: ["quotes"] },
407
+ ],
408
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["pending", "paid", "fulfilled", "refunded"] }],
409
+ actions: THING_ACTIONS,
410
+ },
411
+ {
412
+ key: "reps", label: "Reps", dimension: "actors", type: "rep", icon: "UserRound",
413
+ columns: [
414
+ { field: "name", label: "Name", kind: "text", required: true },
415
+ { field: "region", label: "Region", kind: "text" },
416
+ { field: "quota", label: "Quota", kind: "currency" },
417
+ ],
418
+ fields: [
419
+ { field: "name", label: "Name", kind: "text", required: true },
420
+ { field: "region", label: "Region", kind: "text" },
421
+ { field: "quota", label: "Quota", kind: "currency" },
86
422
  { field: "tags", label: "Tags", kind: "tags" },
87
423
  ],
88
424
  filters: [],
89
- actions: [],
425
+ actions: ACTOR_ACTIONS,
90
426
  },
91
427
  ],
92
- lms: [
428
+ // ── marketing — campaigns → audiences → content → leads, with experiments ───
429
+ marketing: [
430
+ {
431
+ key: "campaigns", label: "Campaigns", dimension: "groups", type: "campaign", icon: "Megaphone",
432
+ columns: [
433
+ { field: "name", label: "Campaign", kind: "text", required: true },
434
+ { field: "status", label: "Status", kind: "select", options: ["draft", "scheduled", "running", "paused", "shipped", "killed"] },
435
+ { field: "budget", label: "Budget", kind: "currency" },
436
+ ],
437
+ fields: [
438
+ { field: "name", label: "Campaign", kind: "text", required: true },
439
+ { field: "status", label: "Status", kind: "select", options: ["draft", "scheduled", "running", "paused", "shipped", "killed"] },
440
+ { field: "budget", label: "Budget", kind: "currency" },
441
+ { field: "spend", label: "Spend", kind: "currency" },
442
+ { field: "north_star", label: "North-star KPI", kind: "text" },
443
+ { field: "start", label: "Start", kind: "date" },
444
+ { field: "end", label: "End", kind: "date" },
445
+ { field: "audience", label: "Audience", kind: "relation", options: ["audiences"] },
446
+ { field: "channel", label: "Channel", kind: "relation", options: ["channels"] },
447
+ ],
448
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["draft", "scheduled", "running", "paused", "shipped", "killed"] }],
449
+ actions: GROUP_ACTIONS,
450
+ },
451
+ {
452
+ key: "audiences", label: "Audiences", dimension: "groups", type: "audience", icon: "Target",
453
+ columns: [
454
+ { field: "name", label: "Audience", kind: "text", required: true },
455
+ { field: "stage", label: "Stage", kind: "select", options: ["awareness", "consideration", "decision", "retention", "advocacy"] },
456
+ { field: "size", label: "Size", kind: "number" },
457
+ ],
458
+ fields: [
459
+ { field: "name", label: "Audience", kind: "text", required: true },
460
+ { field: "stage", label: "Lifecycle stage", kind: "select", options: ["awareness", "consideration", "decision", "retention", "advocacy"] },
461
+ { field: "size", label: "Estimated size", kind: "number" },
462
+ { field: "geo", label: "Geo", kind: "text" },
463
+ { field: "tags", label: "Tags", kind: "tags" },
464
+ ],
465
+ filters: [{ field: "stage", label: "Stage", kind: "select", options: ["awareness", "consideration", "decision", "retention", "advocacy"] }],
466
+ actions: GROUP_ACTIONS,
467
+ },
93
468
  {
94
- key: "courses", label: "Courses", dimension: "things", type: "course", icon: "BookOpen",
469
+ key: "offers", label: "Offers", dimension: "things", type: "offer", icon: "Gift",
470
+ columns: [
471
+ { field: "name", label: "Offer", kind: "text", required: true },
472
+ { field: "price", label: "Price", kind: "currency" },
473
+ { field: "guarantee", label: "Guarantee", kind: "select", options: ["money-back", "better-than", "service", "conditional", "reverse"] },
474
+ ],
475
+ fields: [
476
+ { field: "name", label: "Offer", kind: "text", required: true },
477
+ { field: "dream_outcome", label: "Dream outcome", kind: "text" },
478
+ { field: "price", label: "Price", kind: "currency" },
479
+ { field: "guarantee", label: "Guarantee", kind: "select", options: ["money-back", "better-than", "service", "conditional", "reverse"] },
480
+ { field: "value_score", label: "Value score", kind: "number" },
481
+ { field: "tags", label: "Tags", kind: "tags" },
482
+ ],
483
+ filters: [{ field: "guarantee", label: "Guarantee", kind: "select", options: ["money-back", "better-than", "service", "conditional", "reverse"] }],
484
+ actions: THING_ACTIONS,
485
+ },
486
+ {
487
+ key: "content", label: "Content", dimension: "things", type: "content", icon: "FileText",
95
488
  columns: [
96
489
  { field: "name", label: "Title", kind: "text", required: true },
490
+ { field: "state", label: "State", kind: "select", options: ["draft", "review", "approved", "scheduled", "published", "live", "archived"] },
491
+ { field: "variant", label: "Variant", kind: "select", options: ["a", "b", "c"] },
492
+ ],
493
+ fields: [
494
+ { field: "name", label: "Title", kind: "text", required: true },
495
+ { field: "headline", label: "Headline", kind: "text" },
496
+ { field: "cta", label: "Call to action", kind: "text" },
497
+ { field: "image", label: "Creative", kind: "image" },
498
+ { field: "state", label: "Workflow state", kind: "select", options: ["draft", "review", "approved", "scheduled", "published", "live", "archived"] },
499
+ { field: "variant", label: "Variant", kind: "select", options: ["a", "b", "c"] },
500
+ { field: "publish_at", label: "Publish at", kind: "date" },
501
+ { field: "campaign", label: "Campaign", kind: "relation", options: ["campaigns"] },
502
+ { field: "offer", label: "Offer", kind: "relation", options: ["offers"] },
503
+ ],
504
+ filters: [{ field: "state", label: "State", kind: "select", options: ["draft", "review", "approved", "scheduled", "published", "live", "archived"] }],
505
+ actions: THING_ACTIONS,
506
+ },
507
+ {
508
+ key: "leads", label: "Leads", dimension: "actors", type: "lead", icon: "UserPlus",
509
+ columns: [
510
+ { field: "name", label: "Name", kind: "text", required: true },
511
+ { field: "lifecycle", label: "Lifecycle", kind: "select", options: ["anonymous", "lead", "mql", "sql", "customer", "advocate", "churned"] },
512
+ { field: "ltv", label: "LTV", kind: "currency" },
513
+ ],
514
+ fields: [
515
+ { field: "name", label: "Name", kind: "text", required: true },
516
+ { field: "lifecycle", label: "Lifecycle", kind: "select", options: ["anonymous", "lead", "mql", "sql", "customer", "advocate", "churned"] },
517
+ { field: "ltv", label: "Lifetime value", kind: "currency" },
518
+ { field: "cac", label: "Acquisition cost", kind: "currency" },
519
+ { field: "fit_score", label: "Fit score", kind: "number" },
520
+ { field: "consent", label: "Consent", kind: "tags" },
521
+ { field: "audience", label: "Audience", kind: "relation", options: ["audiences"] },
522
+ ],
523
+ filters: [{ field: "lifecycle", label: "Lifecycle", kind: "select", options: ["anonymous", "lead", "mql", "sql", "customer", "advocate", "churned"] }],
524
+ actions: ACTOR_ACTIONS,
525
+ },
526
+ {
527
+ key: "channels", label: "Channels", dimension: "groups", type: "channel", icon: "Radio",
528
+ columns: [
529
+ { field: "name", label: "Channel", kind: "text", required: true },
530
+ { field: "kind", label: "Kind", kind: "select", options: ["email", "meta", "google-ads", "tiktok", "seo", "sms"] },
531
+ { field: "roas", label: "ROAS", kind: "number" },
532
+ ],
533
+ fields: [
534
+ { field: "name", label: "Channel", kind: "text", required: true },
535
+ { field: "kind", label: "Kind", kind: "select", options: ["email", "meta", "google-ads", "tiktok", "seo", "sms"] },
536
+ { field: "spend", label: "Spend", kind: "currency" },
537
+ { field: "roas", label: "ROAS", kind: "number" },
538
+ ],
539
+ filters: [{ field: "kind", label: "Kind", kind: "select", options: ["email", "meta", "google-ads", "tiktok", "seo", "sms"] }],
540
+ actions: GROUP_ACTIONS,
541
+ },
542
+ {
543
+ key: "creative-asset", label: "Creative assets", dimension: "things", type: "thing", icon: "Image",
544
+ columns: [
545
+ { field: "format_key", label: "Format", kind: "select", options: ["image:static", "image:carousel", "video", "text", "google:performance-max", "google:responsive-display"] },
546
+ { field: "platform", label: "Platform", kind: "select", options: ["meta", "google", "tiktok", "linkedin"] },
547
+ { field: "variant", label: "Variant", kind: "text" },
548
+ { field: "kind", label: "Kind", kind: "select", options: ["image", "video", "text"] },
549
+ ],
550
+ fields: [
551
+ { field: "format_key", label: "Format", kind: "select", options: ["image:static", "image:carousel", "video", "text", "google:performance-max", "google:responsive-display"] },
552
+ { field: "platform", label: "Platform", kind: "select", options: ["meta", "google", "tiktok", "linkedin"] },
553
+ { field: "placement", label: "Placement", kind: "text" },
554
+ { field: "variant", label: "Variant", kind: "text" },
555
+ { field: "kind", label: "Kind", kind: "select", options: ["image", "video", "text"] },
556
+ { field: "headline", label: "Headline", kind: "text", maxChars: 40 },
557
+ { field: "primaryText", label: "Primary text", kind: "text", maxChars: 125, multiLine: true },
558
+ { field: "cta", label: "Call to action", kind: "text", maxChars: 25 },
559
+ { field: "url", label: "Asset URL", kind: "text" },
560
+ { field: "campaign", label: "Campaign", kind: "relation", options: ["campaigns"] },
561
+ ],
562
+ filters: [
563
+ { field: "platform", label: "Platform", kind: "select", options: ["meta", "google", "tiktok", "linkedin"] },
564
+ { field: "kind", label: "Kind", kind: "select", options: ["image", "video", "text"] },
565
+ ],
566
+ actions: THING_ACTIONS,
567
+ render: { card: "VariantCard", detail: "CreativeReviewPanel" },
568
+ },
569
+ {
570
+ key: "experiments", label: "Experiments", dimension: "learning", type: "experiment", icon: "FlaskConical",
571
+ columns: [
572
+ { field: "name", label: "Hypothesis", kind: "text", required: true },
573
+ { field: "status", label: "Status", kind: "select", options: ["backlog", "running", "shipped", "killed", "inconclusive"] },
574
+ { field: "metric", label: "Metric", kind: "select", options: ["ctr", "cvr", "aov", "ltv", "cac", "roas", "open-rate"] },
575
+ ],
576
+ fields: [
577
+ { field: "name", label: "Hypothesis", kind: "text", required: true },
578
+ { field: "metric", label: "Target metric", kind: "select", options: ["ctr", "cvr", "aov", "ltv", "cac", "roas", "open-rate"] },
579
+ { field: "status", label: "Status", kind: "select", options: ["backlog", "running", "shipped", "killed", "inconclusive"] },
580
+ { field: "ice_score", label: "ICE score", kind: "number" },
581
+ { field: "observed_lift", label: "Observed lift", kind: "number" },
582
+ { field: "p_value", label: "p-value", kind: "number" },
583
+ { field: "campaign", label: "Campaign", kind: "relation", options: ["campaigns"] },
584
+ ],
585
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["backlog", "running", "shipped", "killed", "inconclusive"] }],
586
+ actions: ["world:create-hypothesis"],
587
+ },
588
+ ],
589
+ // ── service — support desk: tickets worked by agents for customers ──────────
590
+ service: [
591
+ {
592
+ key: "tickets", label: "Tickets", dimension: "things", type: "ticket", icon: "Ticket",
593
+ columns: [
594
+ { field: "name", label: "Subject", kind: "text", required: true },
595
+ { field: "priority", label: "Priority", kind: "select", options: ["urgent", "high", "normal", "low"] },
596
+ { field: "status", label: "Status", kind: "select", options: ["open", "pending", "on-hold", "solved", "closed"] },
597
+ ],
598
+ fields: [
599
+ { field: "name", label: "Subject", kind: "text", required: true },
600
+ { field: "description", label: "Description", kind: "markdown" },
601
+ { field: "priority", label: "Priority", kind: "select", options: ["urgent", "high", "normal", "low"] },
602
+ { field: "status", label: "Status", kind: "select", options: ["open", "pending", "on-hold", "solved", "closed"] },
603
+ { field: "channel", label: "Channel", kind: "select", options: ["email", "chat", "phone", "web", "social"] },
604
+ { field: "customer", label: "Customer", kind: "relation", options: ["customers"] },
605
+ { field: "agent", label: "Assigned agent", kind: "relation", options: ["agents"] },
606
+ ],
607
+ filters: [
608
+ { field: "priority", label: "Priority", kind: "select", options: ["urgent", "high", "normal", "low"] },
609
+ { field: "status", label: "Status", kind: "select", options: ["open", "pending", "on-hold", "solved", "closed"] },
610
+ ],
611
+ actions: THING_ACTIONS,
612
+ },
613
+ {
614
+ key: "customers", label: "Customers", dimension: "actors", type: "customer", icon: "UserRound",
615
+ columns: [
616
+ { field: "name", label: "Name", kind: "text", required: true },
617
+ { field: "tier", label: "Tier", kind: "select", options: ["free", "pro", "enterprise"] },
618
+ { field: "email", label: "Email", kind: "text" },
619
+ ],
620
+ fields: [
621
+ { field: "name", label: "Name", kind: "text", required: true },
622
+ { field: "email", label: "Email", kind: "text" },
623
+ { field: "tier", label: "Plan tier", kind: "select", options: ["free", "pro", "enterprise"] },
97
624
  { field: "tags", label: "Tags", kind: "tags" },
98
625
  ],
626
+ filters: [{ field: "tier", label: "Tier", kind: "select", options: ["free", "pro", "enterprise"] }],
627
+ actions: ACTOR_ACTIONS,
628
+ },
629
+ {
630
+ key: "agents", label: "Agents", dimension: "actors", type: "support-agent", icon: "Headset",
631
+ columns: [
632
+ { field: "name", label: "Name", kind: "text", required: true },
633
+ { field: "team", label: "Team", kind: "text" },
634
+ { field: "status", label: "Status", kind: "select", options: ["online", "away", "offline"] },
635
+ ],
636
+ fields: [
637
+ { field: "name", label: "Name", kind: "text", required: true },
638
+ { field: "team", label: "Team", kind: "text" },
639
+ { field: "status", label: "Status", kind: "select", options: ["online", "away", "offline"] },
640
+ { field: "tags", label: "Skills", kind: "tags" },
641
+ ],
642
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["online", "away", "offline"] }],
643
+ actions: ACTOR_ACTIONS,
644
+ },
645
+ {
646
+ key: "messages", label: "Messages", dimension: "events", type: "message", icon: "MessageSquare",
647
+ columns: [
648
+ { field: "name", label: "Message", kind: "text", required: true },
649
+ { field: "direction", label: "Direction", kind: "select", options: ["inbound", "outbound"] },
650
+ { field: "date", label: "Date", kind: "date" },
651
+ ],
652
+ fields: [
653
+ { field: "name", label: "Message", kind: "text", required: true },
654
+ { field: "body", label: "Body", kind: "markdown" },
655
+ { field: "direction", label: "Direction", kind: "select", options: ["inbound", "outbound"] },
656
+ { field: "date", label: "Date", kind: "date" },
657
+ { field: "ticket", label: "Ticket", kind: "relation", options: ["tickets"] },
658
+ ],
659
+ filters: [{ field: "direction", label: "Direction", kind: "select", options: ["inbound", "outbound"] }],
660
+ actions: [],
661
+ },
662
+ {
663
+ key: "articles", label: "Help articles", dimension: "things", type: "article", icon: "BookOpen",
664
+ columns: [
665
+ { field: "name", label: "Title", kind: "text", required: true },
666
+ { field: "category", label: "Category", kind: "text" },
667
+ { field: "status", label: "Status", kind: "select", options: ["draft", "published", "archived"] },
668
+ ],
669
+ fields: [
670
+ { field: "name", label: "Title", kind: "text", required: true },
671
+ { field: "category", label: "Category", kind: "text" },
672
+ { field: "body", label: "Body", kind: "markdown" },
673
+ { field: "status", label: "Status", kind: "select", options: ["draft", "published", "archived"] },
674
+ { field: "tags", label: "Tags", kind: "tags" },
675
+ ],
676
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["draft", "published", "archived"] }],
677
+ actions: THING_ACTIONS,
678
+ },
679
+ ],
680
+ // ── education — courses, learners, lessons, mastery, attempts, certificates ──
681
+ education: [
682
+ {
683
+ key: "courses", label: "Courses", dimension: "groups", type: "course", icon: "BookOpen",
684
+ columns: [
685
+ { field: "name", label: "Title", kind: "text", required: true },
686
+ { field: "level", label: "Level", kind: "select", options: ["beginner", "intermediate", "advanced"] },
687
+ { field: "status", label: "Status", kind: "select", options: ["draft", "published", "archived"] },
688
+ ],
99
689
  fields: [
100
690
  { field: "name", label: "Title", kind: "text", required: true },
101
691
  { field: "description", label: "Description", kind: "markdown" },
102
692
  { field: "image", label: "Cover", kind: "image" },
693
+ { field: "level", label: "Level", kind: "select", options: ["beginner", "intermediate", "advanced"] },
694
+ { field: "status", label: "Status", kind: "select", options: ["draft", "published", "archived"] },
103
695
  { field: "tags", label: "Tags", kind: "tags" },
104
696
  ],
105
- filters: [{ field: "tags", label: "Tags", kind: "tags" }],
106
- actions: ["world:create-thing", "world:update-thing"],
697
+ filters: [{ field: "level", label: "Level", kind: "select", options: ["beginner", "intermediate", "advanced"] }],
698
+ actions: GROUP_ACTIONS,
699
+ },
700
+ {
701
+ key: "learners", label: "Learners", dimension: "actors", type: "learner", icon: "GraduationCap",
702
+ columns: [
703
+ { field: "name", label: "Name", kind: "text", required: true },
704
+ { field: "status", label: "Status", kind: "select", options: ["active", "paused", "completed"] },
705
+ { field: "email", label: "Email", kind: "text" },
706
+ ],
707
+ fields: [
708
+ { field: "name", label: "Name", kind: "text", required: true },
709
+ { field: "email", label: "Email", kind: "text" },
710
+ { field: "status", label: "Status", kind: "select", options: ["active", "paused", "completed"] },
711
+ { field: "tags", label: "Tags", kind: "tags" },
712
+ ],
713
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["active", "paused", "completed"] }],
714
+ actions: ACTOR_ACTIONS,
715
+ },
716
+ {
717
+ key: "lessons", label: "Lessons", dimension: "things", type: "lesson", icon: "PlayCircle",
718
+ columns: [
719
+ { field: "name", label: "Lesson", kind: "text", required: true },
720
+ { field: "kind", label: "Kind", kind: "select", options: ["reading", "video", "quiz", "interactive", "problem"] },
721
+ { field: "order", label: "Order", kind: "number" },
722
+ ],
723
+ fields: [
724
+ { field: "name", label: "Lesson", kind: "text", required: true },
725
+ { field: "kind", label: "Kind", kind: "select", options: ["reading", "video", "quiz", "interactive", "problem"] },
726
+ { field: "order", label: "Order", kind: "number" },
727
+ { field: "duration", label: "Duration (min)", kind: "number" },
728
+ { field: "course", label: "Course", kind: "relation", options: ["courses"] },
729
+ { field: "skill", label: "Teaches skill", kind: "relation", options: ["skills"] },
730
+ ],
731
+ filters: [{ field: "kind", label: "Kind", kind: "select", options: ["reading", "video", "quiz", "interactive", "problem"] }],
732
+ actions: THING_ACTIONS,
733
+ },
734
+ {
735
+ key: "skills", label: "Skills", dimension: "things", type: "skill", icon: "Award",
736
+ columns: [
737
+ { field: "name", label: "Skill", kind: "text", required: true },
738
+ { field: "domain", label: "Domain", kind: "tags" },
739
+ ],
740
+ fields: [
741
+ { field: "name", label: "Skill", kind: "text", required: true },
742
+ { field: "description", label: "Description", kind: "markdown" },
743
+ { field: "domain", label: "Domain", kind: "tags" },
744
+ ],
745
+ filters: [{ field: "domain", label: "Domain", kind: "tags" }],
746
+ actions: THING_ACTIONS,
107
747
  },
108
748
  {
109
749
  key: "enrollments", label: "Enrollments", dimension: "paths", type: "enrollment", icon: "UserCheck",
110
750
  columns: [
111
751
  { field: "name", label: "Enrollment", kind: "text", required: true },
112
- { field: "tags", label: "Status", kind: "select", options: ["active", "completed", "paused"] },
752
+ { field: "status", label: "Status", kind: "select", options: ["active", "completed", "paused", "dropped"] },
753
+ { field: "progress", label: "Progress", kind: "number" },
113
754
  ],
114
755
  fields: [
115
756
  { field: "name", label: "Enrollment", kind: "text", required: true },
116
- { field: "tags", label: "Status", kind: "select", options: ["active", "completed", "paused"] },
757
+ { field: "status", label: "Status", kind: "select", options: ["active", "completed", "paused", "dropped"] },
758
+ { field: "progress", label: "Progress %", kind: "number" },
759
+ { field: "enrolled_at", label: "Enrolled", kind: "date" },
760
+ { field: "learner", label: "Learner", kind: "relation", options: ["learners"] },
761
+ { field: "course", label: "Course", kind: "relation", options: ["courses"] },
762
+ ],
763
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["active", "completed", "paused", "dropped"] }],
764
+ actions: [],
765
+ },
766
+ {
767
+ key: "attempts", label: "Attempts", dimension: "events", type: "attempt", icon: "ClipboardCheck",
768
+ columns: [
769
+ { field: "name", label: "Attempt", kind: "text", required: true },
770
+ { field: "verb", label: "Verb", kind: "select", options: ["started", "submitted", "completed", "scored"] },
771
+ { field: "score", label: "Score", kind: "number" },
772
+ ],
773
+ fields: [
774
+ { field: "name", label: "Attempt", kind: "text", required: true },
775
+ { field: "verb", label: "Verb", kind: "select", options: ["started", "submitted", "completed", "scored"] },
776
+ { field: "correct", label: "Correct", kind: "select", options: ["yes", "no"] },
777
+ { field: "score", label: "Score", kind: "number" },
778
+ { field: "elapsed_ms", label: "Elapsed (ms)", kind: "number" },
779
+ { field: "learner", label: "Learner", kind: "relation", options: ["learners"] },
780
+ { field: "lesson", label: "Lesson", kind: "relation", options: ["lessons"] },
781
+ ],
782
+ filters: [{ field: "verb", label: "Verb", kind: "select", options: ["started", "submitted", "completed", "scored"] }],
783
+ actions: [],
784
+ },
785
+ {
786
+ key: "certificates", label: "Certificates", dimension: "things", type: "certificate", icon: "Medal",
787
+ columns: [
788
+ { field: "name", label: "Certificate", kind: "text", required: true },
789
+ { field: "issued_at", label: "Issued", kind: "date" },
790
+ ],
791
+ fields: [
792
+ { field: "name", label: "Certificate", kind: "text", required: true },
793
+ { field: "issued_at", label: "Issued", kind: "date" },
794
+ { field: "tags", label: "Tags", kind: "tags" },
795
+ { field: "learner", label: "Learner", kind: "relation", options: ["learners"] },
796
+ { field: "course", label: "Course", kind: "relation", options: ["courses"] },
797
+ ],
798
+ filters: [],
799
+ actions: THING_ACTIONS,
800
+ },
801
+ ],
802
+ // ── staff — people ops: employees in departments, roles, shifts, time-off ───
803
+ staff: [
804
+ {
805
+ key: "employees", label: "Employees", dimension: "actors", type: "employee", icon: "Users",
806
+ columns: [
807
+ { field: "name", label: "Name", kind: "text", required: true },
808
+ { field: "title", label: "Title", kind: "text" },
809
+ { field: "status", label: "Status", kind: "select", options: ["active", "on-leave", "offboarded"] },
810
+ ],
811
+ fields: [
812
+ { field: "name", label: "Name", kind: "text", required: true },
813
+ { field: "email", label: "Email", kind: "text" },
814
+ { field: "title", label: "Title", kind: "text" },
815
+ { field: "status", label: "Status", kind: "select", options: ["active", "on-leave", "offboarded"] },
816
+ { field: "start_date", label: "Start date", kind: "date" },
817
+ { field: "department", label: "Department", kind: "relation", options: ["departments"] },
818
+ { field: "role", label: "Role", kind: "relation", options: ["roles"] },
819
+ { field: "manager", label: "Manager", kind: "relation", options: ["employees"] },
820
+ ],
821
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["active", "on-leave", "offboarded"] }],
822
+ actions: ACTOR_ACTIONS,
823
+ },
824
+ {
825
+ key: "departments", label: "Departments", dimension: "groups", type: "department", icon: "Building2",
826
+ columns: [
827
+ { field: "name", label: "Department", kind: "text", required: true },
828
+ { field: "function", label: "Function", kind: "select", options: ["sales", "marketing", "service", "education", "engineering", "ops", "finance"] },
829
+ ],
830
+ fields: [
831
+ { field: "name", label: "Department", kind: "text", required: true },
832
+ { field: "function", label: "Function", kind: "select", options: ["sales", "marketing", "service", "education", "engineering", "ops", "finance"] },
833
+ { field: "head", label: "Department head", kind: "relation", options: ["employees"] },
834
+ ],
835
+ filters: [{ field: "function", label: "Function", kind: "select", options: ["sales", "marketing", "service", "education", "engineering", "ops", "finance"] }],
836
+ actions: GROUP_ACTIONS,
837
+ },
838
+ {
839
+ key: "roles", label: "Roles", dimension: "things", type: "role", icon: "BadgeCheck",
840
+ columns: [
841
+ { field: "name", label: "Role", kind: "text", required: true },
842
+ { field: "level", label: "Level", kind: "select", options: ["junior", "mid", "senior", "lead", "head"] },
843
+ ],
844
+ fields: [
845
+ { field: "name", label: "Role", kind: "text", required: true },
846
+ { field: "level", label: "Level", kind: "select", options: ["junior", "mid", "senior", "lead", "head"] },
847
+ { field: "description", label: "Description", kind: "markdown" },
848
+ ],
849
+ filters: [{ field: "level", label: "Level", kind: "select", options: ["junior", "mid", "senior", "lead", "head"] }],
850
+ actions: THING_ACTIONS,
851
+ },
852
+ {
853
+ key: "shifts", label: "Shifts", dimension: "events", type: "shift", icon: "CalendarClock",
854
+ columns: [
855
+ { field: "name", label: "Shift", kind: "text", required: true },
856
+ { field: "date", label: "Date", kind: "date" },
857
+ { field: "hours", label: "Hours", kind: "number" },
858
+ ],
859
+ fields: [
860
+ { field: "name", label: "Shift", kind: "text", required: true },
861
+ { field: "date", label: "Date", kind: "date" },
862
+ { field: "start", label: "Start time", kind: "text" },
863
+ { field: "end", label: "End time", kind: "text" },
864
+ { field: "hours", label: "Hours", kind: "number" },
865
+ { field: "employee", label: "Employee", kind: "relation", options: ["employees"] },
117
866
  ],
118
867
  filters: [],
119
868
  actions: [],
120
869
  },
870
+ {
871
+ key: "timeoff", label: "Time off", dimension: "events", type: "time-off", icon: "Plane",
872
+ columns: [
873
+ { field: "name", label: "Request", kind: "text", required: true },
874
+ { field: "kind", label: "Kind", kind: "select", options: ["vacation", "sick", "personal", "unpaid"] },
875
+ { field: "status", label: "Status", kind: "select", options: ["pending", "approved", "rejected"] },
876
+ ],
877
+ fields: [
878
+ { field: "name", label: "Request", kind: "text", required: true },
879
+ { field: "kind", label: "Kind", kind: "select", options: ["vacation", "sick", "personal", "unpaid"] },
880
+ { field: "start", label: "From", kind: "date" },
881
+ { field: "end", label: "To", kind: "date" },
882
+ { field: "status", label: "Status", kind: "select", options: ["pending", "approved", "rejected"] },
883
+ { field: "employee", label: "Employee", kind: "relation", options: ["employees"] },
884
+ ],
885
+ filters: [{ field: "status", label: "Status", kind: "select", options: ["pending", "approved", "rejected"] }],
886
+ actions: [],
887
+ },
888
+ {
889
+ key: "reviews", label: "Reviews", dimension: "things", type: "review", icon: "Star",
890
+ columns: [
891
+ { field: "name", label: "Review", kind: "text", required: true },
892
+ { field: "period", label: "Period", kind: "text" },
893
+ { field: "rating", label: "Rating", kind: "number" },
894
+ ],
895
+ fields: [
896
+ { field: "name", label: "Review", kind: "text", required: true },
897
+ { field: "period", label: "Period", kind: "text" },
898
+ { field: "rating", label: "Rating (1-5)", kind: "number" },
899
+ { field: "notes", label: "Notes", kind: "markdown" },
900
+ { field: "employee", label: "Employee", kind: "relation", options: ["employees"] },
901
+ ],
902
+ filters: [],
903
+ actions: THING_ACTIONS,
904
+ },
121
905
  ],
122
- roofing: [
906
+ // ── ecommerce — RELATION-FREE by contract (schema-canvas.test.ts) ───────────
907
+ ecommerce: [
908
+ {
909
+ key: "products", label: "Products", dimension: "things", type: "product", icon: "Package",
910
+ bind: "commerce",
911
+ columns: [
912
+ { field: "name", label: "Name", kind: "text", required: true },
913
+ { field: "price", label: "Price", kind: "currency" },
914
+ { field: "tags", label: "Tags", kind: "tags" },
915
+ ],
916
+ fields: [
917
+ { field: "name", label: "Name", kind: "text", required: true },
918
+ { field: "price", label: "Price", kind: "currency" },
919
+ { field: "description", label: "Description", kind: "markdown" },
920
+ { field: "image", label: "Image", kind: "image" },
921
+ { field: "tags", label: "Tags", kind: "tags" },
922
+ ],
923
+ filters: [{ field: "tags", label: "Tags", kind: "tags" }],
924
+ // bind:"commerce" routes create/update/archive to the real Stripe-backed products:* receivers.
925
+ actions: ["products:create", "products:update", "products:archive"],
926
+ },
927
+ {
928
+ key: "orders", label: "Orders", dimension: "things", type: "order", icon: "ShoppingCart",
929
+ bind: "commerce",
930
+ columns: [
931
+ { field: "name", label: "Order #", kind: "text", required: true },
932
+ { field: "price", label: "Total", kind: "currency" },
933
+ { field: "tags", label: "Status", kind: "select", options: ["pending", "paid", "shipped", "cancelled"] },
934
+ ],
935
+ fields: [
936
+ { field: "name", label: "Order #", kind: "text", required: true },
937
+ { field: "price", label: "Total", kind: "currency" },
938
+ { field: "tags", label: "Status", kind: "select", options: ["pending", "paid", "shipped", "cancelled"] },
939
+ ],
940
+ filters: [{ field: "tags", label: "Status", kind: "select", options: ["pending", "paid", "shipped", "cancelled"] }],
941
+ // Orders are read-only in the generic admin — they're minted by the storefront webhook, never hand-created.
942
+ actions: [],
943
+ },
944
+ {
945
+ key: "customers", label: "Customers", dimension: "actors", type: "customer", icon: "Users",
946
+ columns: [
947
+ { field: "name", label: "Name", kind: "text", required: true },
948
+ { field: "tags", label: "Tags", kind: "tags" },
949
+ ],
950
+ fields: [
951
+ { field: "name", label: "Name", kind: "text", required: true },
952
+ { field: "tags", label: "Tags", kind: "tags" },
953
+ ],
954
+ filters: [],
955
+ actions: ["world:create-actor", "world:update-actor"],
956
+ },
957
+ ],
958
+ // ── roofers — lead → inspection → estimate → job, with crews ─────────────────
959
+ roofers: [
123
960
  {
124
961
  key: "leads", label: "Leads", dimension: "things", type: "lead", icon: "PhoneCall",
125
962
  columns: [
@@ -154,6 +991,7 @@ export const TEMPLATES = {
154
991
  { field: "name", label: "Inspection", kind: "text", required: true },
155
992
  { field: "date", label: "Date", kind: "date" },
156
993
  { field: "notes", label: "Site notes", kind: "markdown" },
994
+ { field: "lead", label: "Lead", kind: "relation", options: ["leads"] },
157
995
  { field: "tags", label: "Status", kind: "select", options: ["scheduled", "complete", "cancelled"] },
158
996
  ],
159
997
  filters: [{ field: "tags", label: "Status", kind: "select", options: ["scheduled", "complete", "cancelled"] }],
@@ -171,6 +1009,7 @@ export const TEMPLATES = {
171
1009
  { field: "price", label: "Total", kind: "currency" },
172
1010
  { field: "material", label: "Material", kind: "text" },
173
1011
  { field: "warranty", label: "Warranty", kind: "text" },
1012
+ { field: "lead", label: "Lead", kind: "relation", options: ["leads"] },
174
1013
  { field: "tags", label: "Status", kind: "select", options: ["pending", "accepted", "rejected", "insurance-pending"] },
175
1014
  ],
176
1015
  filters: [{ field: "tags", label: "Status", kind: "select", options: ["pending", "accepted", "rejected", "insurance-pending"] }],
@@ -190,6 +1029,7 @@ export const TEMPLATES = {
190
1029
  { field: "start_date", label: "Start date", kind: "date" },
191
1030
  { field: "material", label: "Material", kind: "text" },
192
1031
  { field: "squares", label: "Squares", kind: "number" },
1032
+ { field: "estimate", label: "Estimate", kind: "relation", options: ["estimates"] },
193
1033
  { field: "crew", label: "Assigned crew", kind: "relation", options: ["crews"] },
194
1034
  { field: "tags", label: "Status", kind: "select", options: ["scheduled", "active", "completed", "invoiced"] },
195
1035
  ],
@@ -210,7 +1050,8 @@ export const TEMPLATES = {
210
1050
  actions: ["world:create-actor", "world:update-actor"],
211
1051
  },
212
1052
  ],
213
- moving: [
1053
+ // ── movers — quote → survey → move, with customers ──────────────────────────
1054
+ movers: [
214
1055
  {
215
1056
  key: "quotes", label: "Quotes", dimension: "things", type: "quote", icon: "FileSearch",
216
1057
  columns: [
@@ -226,6 +1067,7 @@ export const TEMPLATES = {
226
1067
  { field: "destination", label: "Destination address", kind: "text" },
227
1068
  { field: "move_date", label: "Move date", kind: "date" },
228
1069
  { field: "home_size", label: "Home size", kind: "select", options: ["studio", "1bed", "2bed", "3bed", "4bed+"] },
1070
+ { field: "customer", label: "Customer", kind: "relation", options: ["customers"] },
229
1071
  { field: "tags", label: "Status", kind: "select", options: ["open", "survey-booked", "deposit-paid", "lost"] },
230
1072
  ],
231
1073
  filters: [
@@ -246,6 +1088,7 @@ export const TEMPLATES = {
246
1088
  { field: "date", label: "Date", kind: "date" },
247
1089
  { field: "duration", label: "Duration (min)", kind: "number" },
248
1090
  { field: "notes", label: "Notes", kind: "markdown" },
1091
+ { field: "quote", label: "Quote", kind: "relation", options: ["quotes"] },
249
1092
  { field: "tags", label: "Status", kind: "select", options: ["scheduled", "complete", "cancelled"] },
250
1093
  ],
251
1094
  filters: [{ field: "tags", label: "Status", kind: "select", options: ["scheduled", "complete", "cancelled"] }],
@@ -285,36 +1128,71 @@ export const TEMPLATES = {
285
1128
  actions: ["world:create-actor", "world:update-actor"],
286
1129
  },
287
1130
  ],
288
- service: [
289
- {
290
- key: "jobs", label: "Jobs", dimension: "things", type: "job", icon: "Wrench",
291
- columns: [
292
- { field: "name", label: "Job", kind: "text", required: true },
293
- { field: "price", label: "Value", kind: "currency" },
294
- { field: "tags", label: "Status", kind: "select", options: ["open", "in-progress", "done", "invoiced"] },
295
- ],
296
- fields: [
297
- { field: "name", label: "Job", kind: "text", required: true },
298
- { field: "price", label: "Value", kind: "currency" },
299
- { field: "description", label: "Notes", kind: "markdown" },
300
- { field: "tags", label: "Status", kind: "select", options: ["open", "in-progress", "done", "invoiced"] },
301
- ],
302
- filters: [{ field: "tags", label: "Status", kind: "select", options: ["open", "in-progress", "done", "invoiced"] }],
303
- actions: ["world:create-thing", "world:update-thing"],
304
- },
305
- {
306
- key: "clients", label: "Clients", dimension: "actors", type: "client", icon: "User",
307
- columns: [
308
- { field: "name", label: "Name", kind: "text", required: true },
309
- { field: "tags", label: "Tags", kind: "tags" },
310
- ],
311
- fields: [
312
- { field: "name", label: "Name", kind: "text", required: true },
313
- { field: "tags", label: "Tags", kind: "tags" },
314
- ],
315
- filters: [],
316
- actions: ["world:create-actor", "world:update-actor"],
317
- },
318
- ],
319
1131
  };
1132
+ // ─── Manifest → TypeQL ───────────────────────────────────────────────────────
1133
+ // Compile a resource-type manifest into a TypeDB 3.0 schema string so it can be
1134
+ // rendered in the TQL schema viewer. The mapping is idiomatic TypeDB:
1135
+ // • nouns (groups · actors · things · learning) → `entity`
1136
+ // • flows (paths · events) with relation fields → `relation` (fields = roles)
1137
+ // • every non-relation field → `attribute`
1138
+ // • relation fields on an entity → a generated binary relation
1139
+ // The output is for visualisation/teaching, not for `define` against a live DB.
1140
+ const VTYPE = {
1141
+ text: "string", markdown: "string", select: "string", image: "string",
1142
+ tags: "string[]", number: "double", currency: "double", date: "datetime",
1143
+ relation: "string",
1144
+ };
1145
+ const ident = (s) => s.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "x";
1146
+ export function manifestToTql(types, title = "Workspace types") {
1147
+ const keys = new Set(types.map(t => t.key));
1148
+ const linksTo = (kind, opt) => kind === "relation" && !!opt?.[0] && keys.has(opt[0]);
1149
+ const attrs = new Map(); // field -> value type (first wins)
1150
+ const playsBy = new Map(); // entity key -> ["rel:role", …]
1151
+ const relations = [];
1152
+ const entities = [];
1153
+ const addPlays = (k, p) => { const a = playsBy.get(k) ?? []; a.push(p); playsBy.set(k, a); };
1154
+ for (const t of types)
1155
+ for (const f of t.fields)
1156
+ if (f.kind !== "relation" && !attrs.has(f.field))
1157
+ attrs.set(f.field, VTYPE[f.kind]);
1158
+ for (const t of types) {
1159
+ const tk = ident(t.key);
1160
+ const scalars = t.fields.filter(f => f.kind !== "relation").map(f => ident(f.field));
1161
+ const rels = t.fields.filter(f => linksTo(f.kind, f.options));
1162
+ const isFlow = (t.dimension === "paths" || t.dimension === "events") && rels.length > 0;
1163
+ if (isFlow) {
1164
+ relations.push({ name: tk, relates: rels.map(f => ident(f.field)), owns: scalars });
1165
+ for (const f of rels)
1166
+ addPlays(ident(f.options[0]), `${tk}:${ident(f.field)}`);
1167
+ }
1168
+ else {
1169
+ entities.push({ key: tk, label: t.label, dim: t.dimension, owns: scalars });
1170
+ for (const f of rels) {
1171
+ const rn = `${tk}_${ident(f.field)}`;
1172
+ relations.push({ name: rn, relates: ["src", "dst"], owns: [] });
1173
+ addPlays(tk, `${rn}:src`);
1174
+ addPlays(ident(f.options[0]), `${rn}:dst`);
1175
+ }
1176
+ }
1177
+ }
1178
+ const out = [`# ${title} — generated TypeDB 3.0 schema`, "", "define", ""];
1179
+ out.push("# ── Attributes ──────────────────────────");
1180
+ for (const [name, vt] of [...attrs.keys()].sort().map(k => [k, attrs.get(k)]))
1181
+ out.push(`attribute ${ident(name)}, value ${vt};`);
1182
+ out.push("");
1183
+ out.push("# ── Entities ────────────────────────────");
1184
+ for (const e of entities) {
1185
+ const body = [...e.owns.map((o, i) => `owns ${o}${i === 0 ? " @key" : ""}`), ...(playsBy.get(e.key) ?? []).map(p => `plays ${p}`)];
1186
+ out.push(`# ${e.label} · ${e.dim}`);
1187
+ out.push(body.length ? `entity ${e.key},\n ${body.join(",\n ")};` : `entity ${e.key};`);
1188
+ }
1189
+ if (relations.length) {
1190
+ out.push("", "# ── Relations ───────────────────────────");
1191
+ for (const r of relations) {
1192
+ const body = [...r.relates.map(x => `relates ${x}`), ...r.owns.map(o => `owns ${o}`)];
1193
+ out.push(`relation ${r.name},\n ${body.join(",\n ")};`);
1194
+ }
1195
+ }
1196
+ return out.join("\n") + "\n";
1197
+ }
320
1198
  //# sourceMappingURL=templates.js.map