@objectstack/platform-objects 0.1.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/LICENSE +202 -0
- package/dist/apps/index.d.mts +427 -0
- package/dist/apps/index.d.ts +427 -0
- package/dist/apps/index.js +520 -0
- package/dist/apps/index.js.map +1 -0
- package/dist/apps/index.mjs +510 -0
- package/dist/apps/index.mjs.map +1 -0
- package/dist/audit/index.d.mts +9507 -0
- package/dist/audit/index.d.ts +9507 -0
- package/dist/audit/index.js +492 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/index.mjs +487 -0
- package/dist/audit/index.mjs.map +1 -0
- package/dist/identity/index.d.mts +32482 -0
- package/dist/identity/index.d.ts +32482 -0
- package/dist/identity/index.js +1404 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/index.mjs +1385 -0
- package/dist/identity/index.mjs.map +1 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +4209 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4160 -0
- package/dist/index.mjs.map +1 -0
- package/dist/metadata/index.d.mts +25601 -0
- package/dist/metadata/index.d.ts +25601 -0
- package/dist/metadata/index.js +911 -0
- package/dist/metadata/index.js.map +1 -0
- package/dist/metadata/index.mjs +902 -0
- package/dist/metadata/index.mjs.map +1 -0
- package/dist/security/index.d.mts +3554 -0
- package/dist/security/index.d.ts +3554 -0
- package/dist/security/index.js +178 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/index.mjs +175 -0
- package/dist/security/index.mjs.map +1 -0
- package/dist/state-machine.zod-BFg-VE0M.d-Ek3_yo9P.d.mts +41 -0
- package/dist/state-machine.zod-BFg-VE0M.d-Ek3_yo9P.d.ts +41 -0
- package/dist/tenant/index.d.mts +16454 -0
- package/dist/tenant/index.d.ts +16454 -0
- package/dist/tenant/index.js +741 -0
- package/dist/tenant/index.js.map +1 -0
- package/dist/tenant/index.mjs +733 -0
- package/dist/tenant/index.mjs.map +1 -0
- package/package.json +84 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4209 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var data = require('@objectstack/spec/data');
|
|
4
|
+
var ui = require('@objectstack/spec/ui');
|
|
5
|
+
|
|
6
|
+
// src/identity/sys-user.object.ts
|
|
7
|
+
var SysUser = data.ObjectSchema.create({
|
|
8
|
+
name: "sys_user",
|
|
9
|
+
label: "User",
|
|
10
|
+
pluralLabel: "Users",
|
|
11
|
+
icon: "user",
|
|
12
|
+
isSystem: true,
|
|
13
|
+
description: "User accounts for authentication",
|
|
14
|
+
displayNameField: "name",
|
|
15
|
+
titleFormat: "{name}",
|
|
16
|
+
compactLayout: ["name", "email", "email_verified"],
|
|
17
|
+
fields: {
|
|
18
|
+
// ── Identity (primary business fields) ───────────────────────
|
|
19
|
+
name: data.Field.text({
|
|
20
|
+
label: "Name",
|
|
21
|
+
required: true,
|
|
22
|
+
searchable: true,
|
|
23
|
+
maxLength: 255,
|
|
24
|
+
group: "Identity"
|
|
25
|
+
}),
|
|
26
|
+
email: data.Field.email({
|
|
27
|
+
label: "Email",
|
|
28
|
+
required: true,
|
|
29
|
+
searchable: true,
|
|
30
|
+
group: "Identity"
|
|
31
|
+
}),
|
|
32
|
+
email_verified: data.Field.boolean({
|
|
33
|
+
label: "Email Verified",
|
|
34
|
+
defaultValue: false,
|
|
35
|
+
group: "Identity"
|
|
36
|
+
}),
|
|
37
|
+
two_factor_enabled: data.Field.boolean({
|
|
38
|
+
label: "Two-Factor Enabled",
|
|
39
|
+
defaultValue: false,
|
|
40
|
+
group: "Identity",
|
|
41
|
+
description: "Whether two-factor authentication is enabled for this user. Maintained by the better-auth `twoFactor` plugin."
|
|
42
|
+
}),
|
|
43
|
+
// ── Profile ──────────────────────────────────────────────────
|
|
44
|
+
image: data.Field.url({
|
|
45
|
+
label: "Profile Image",
|
|
46
|
+
required: false,
|
|
47
|
+
group: "Profile"
|
|
48
|
+
}),
|
|
49
|
+
// ── System (auto-managed, hidden from create/edit forms) ─────
|
|
50
|
+
id: data.Field.text({
|
|
51
|
+
label: "User ID",
|
|
52
|
+
required: true,
|
|
53
|
+
readonly: true,
|
|
54
|
+
group: "System"
|
|
55
|
+
}),
|
|
56
|
+
created_at: data.Field.datetime({
|
|
57
|
+
label: "Created At",
|
|
58
|
+
defaultValue: "NOW()",
|
|
59
|
+
readonly: true,
|
|
60
|
+
group: "System"
|
|
61
|
+
}),
|
|
62
|
+
updated_at: data.Field.datetime({
|
|
63
|
+
label: "Updated At",
|
|
64
|
+
defaultValue: "NOW()",
|
|
65
|
+
readonly: true,
|
|
66
|
+
group: "System"
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
indexes: [
|
|
70
|
+
{ fields: ["email"], unique: true },
|
|
71
|
+
{ fields: ["created_at"], unique: false }
|
|
72
|
+
],
|
|
73
|
+
enable: {
|
|
74
|
+
trackHistory: true,
|
|
75
|
+
searchable: true,
|
|
76
|
+
apiEnabled: true,
|
|
77
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
78
|
+
trash: true,
|
|
79
|
+
mru: true
|
|
80
|
+
},
|
|
81
|
+
validations: [
|
|
82
|
+
{
|
|
83
|
+
name: "email_unique",
|
|
84
|
+
type: "unique",
|
|
85
|
+
severity: "error",
|
|
86
|
+
message: "Email must be unique",
|
|
87
|
+
fields: ["email"],
|
|
88
|
+
caseSensitive: false
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
});
|
|
92
|
+
var SysSession = data.ObjectSchema.create({
|
|
93
|
+
name: "sys_session",
|
|
94
|
+
label: "Session",
|
|
95
|
+
pluralLabel: "Sessions",
|
|
96
|
+
icon: "key",
|
|
97
|
+
isSystem: true,
|
|
98
|
+
description: "Active user sessions",
|
|
99
|
+
displayNameField: "user_id",
|
|
100
|
+
titleFormat: "Session \u2014 {user_id}",
|
|
101
|
+
compactLayout: ["user_id", "ip_address", "expires_at"],
|
|
102
|
+
fields: {
|
|
103
|
+
// ── Session owner & expiry ──────────────────────────────────
|
|
104
|
+
user_id: data.Field.lookup("sys_user", {
|
|
105
|
+
label: "User",
|
|
106
|
+
required: true,
|
|
107
|
+
searchable: true,
|
|
108
|
+
group: "Session"
|
|
109
|
+
}),
|
|
110
|
+
expires_at: data.Field.datetime({
|
|
111
|
+
label: "Expires At",
|
|
112
|
+
required: true,
|
|
113
|
+
group: "Session"
|
|
114
|
+
}),
|
|
115
|
+
// ── Active context (multi-org/team) ──────────────────────────
|
|
116
|
+
active_organization_id: data.Field.lookup("sys_organization", {
|
|
117
|
+
label: "Active Organization",
|
|
118
|
+
required: false,
|
|
119
|
+
group: "Context"
|
|
120
|
+
}),
|
|
121
|
+
active_team_id: data.Field.lookup("sys_team", {
|
|
122
|
+
label: "Active Team",
|
|
123
|
+
required: false,
|
|
124
|
+
group: "Context"
|
|
125
|
+
}),
|
|
126
|
+
// ── Client fingerprint ───────────────────────────────────────
|
|
127
|
+
ip_address: data.Field.text({
|
|
128
|
+
label: "IP Address",
|
|
129
|
+
required: false,
|
|
130
|
+
maxLength: 45,
|
|
131
|
+
// Support IPv6
|
|
132
|
+
group: "Client"
|
|
133
|
+
}),
|
|
134
|
+
user_agent: data.Field.textarea({
|
|
135
|
+
label: "User Agent",
|
|
136
|
+
required: false,
|
|
137
|
+
group: "Client"
|
|
138
|
+
}),
|
|
139
|
+
// ── Secret (hidden by default) ──────────────────────────────
|
|
140
|
+
token: data.Field.text({
|
|
141
|
+
label: "Session Token",
|
|
142
|
+
required: true,
|
|
143
|
+
hidden: true,
|
|
144
|
+
readonly: true,
|
|
145
|
+
description: "Opaque session token \u2014 never exposed in UI",
|
|
146
|
+
group: "Secret"
|
|
147
|
+
}),
|
|
148
|
+
// ── System ───────────────────────────────────────────────────
|
|
149
|
+
id: data.Field.text({
|
|
150
|
+
label: "Session ID",
|
|
151
|
+
required: true,
|
|
152
|
+
readonly: true,
|
|
153
|
+
group: "System"
|
|
154
|
+
}),
|
|
155
|
+
created_at: data.Field.datetime({
|
|
156
|
+
label: "Created At",
|
|
157
|
+
defaultValue: "NOW()",
|
|
158
|
+
readonly: true,
|
|
159
|
+
group: "System"
|
|
160
|
+
}),
|
|
161
|
+
updated_at: data.Field.datetime({
|
|
162
|
+
label: "Updated At",
|
|
163
|
+
defaultValue: "NOW()",
|
|
164
|
+
readonly: true,
|
|
165
|
+
group: "System"
|
|
166
|
+
})
|
|
167
|
+
},
|
|
168
|
+
indexes: [
|
|
169
|
+
{ fields: ["token"], unique: true },
|
|
170
|
+
{ fields: ["user_id"], unique: false },
|
|
171
|
+
{ fields: ["expires_at"], unique: false }
|
|
172
|
+
],
|
|
173
|
+
enable: {
|
|
174
|
+
trackHistory: false,
|
|
175
|
+
searchable: false,
|
|
176
|
+
apiEnabled: true,
|
|
177
|
+
apiMethods: ["get", "list", "create", "delete"],
|
|
178
|
+
trash: false,
|
|
179
|
+
mru: false,
|
|
180
|
+
clone: false
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
var SysAccount = data.ObjectSchema.create({
|
|
184
|
+
name: "sys_account",
|
|
185
|
+
label: "Account",
|
|
186
|
+
pluralLabel: "Accounts",
|
|
187
|
+
icon: "link",
|
|
188
|
+
isSystem: true,
|
|
189
|
+
description: "OAuth and authentication provider accounts",
|
|
190
|
+
titleFormat: "{provider_id} - {account_id}",
|
|
191
|
+
compactLayout: ["provider_id", "user_id", "account_id"],
|
|
192
|
+
fields: {
|
|
193
|
+
id: data.Field.text({
|
|
194
|
+
label: "Account ID",
|
|
195
|
+
required: true,
|
|
196
|
+
readonly: true
|
|
197
|
+
}),
|
|
198
|
+
created_at: data.Field.datetime({
|
|
199
|
+
label: "Created At",
|
|
200
|
+
defaultValue: "NOW()",
|
|
201
|
+
readonly: true
|
|
202
|
+
}),
|
|
203
|
+
updated_at: data.Field.datetime({
|
|
204
|
+
label: "Updated At",
|
|
205
|
+
defaultValue: "NOW()",
|
|
206
|
+
readonly: true
|
|
207
|
+
}),
|
|
208
|
+
provider_id: data.Field.text({
|
|
209
|
+
label: "Provider ID",
|
|
210
|
+
required: true,
|
|
211
|
+
description: "OAuth provider identifier (google, github, etc.)"
|
|
212
|
+
}),
|
|
213
|
+
account_id: data.Field.text({
|
|
214
|
+
label: "Provider Account ID",
|
|
215
|
+
required: true,
|
|
216
|
+
description: "User's ID in the provider's system"
|
|
217
|
+
}),
|
|
218
|
+
user_id: data.Field.lookup("sys_user", {
|
|
219
|
+
label: "User",
|
|
220
|
+
required: true,
|
|
221
|
+
description: "Link to user table"
|
|
222
|
+
}),
|
|
223
|
+
access_token: data.Field.textarea({
|
|
224
|
+
label: "Access Token",
|
|
225
|
+
required: false
|
|
226
|
+
}),
|
|
227
|
+
refresh_token: data.Field.textarea({
|
|
228
|
+
label: "Refresh Token",
|
|
229
|
+
required: false
|
|
230
|
+
}),
|
|
231
|
+
id_token: data.Field.textarea({
|
|
232
|
+
label: "ID Token",
|
|
233
|
+
required: false
|
|
234
|
+
}),
|
|
235
|
+
access_token_expires_at: data.Field.datetime({
|
|
236
|
+
label: "Access Token Expires At",
|
|
237
|
+
required: false
|
|
238
|
+
}),
|
|
239
|
+
refresh_token_expires_at: data.Field.datetime({
|
|
240
|
+
label: "Refresh Token Expires At",
|
|
241
|
+
required: false
|
|
242
|
+
}),
|
|
243
|
+
scope: data.Field.text({
|
|
244
|
+
label: "OAuth Scope",
|
|
245
|
+
required: false
|
|
246
|
+
}),
|
|
247
|
+
password: data.Field.text({
|
|
248
|
+
label: "Password Hash",
|
|
249
|
+
required: false,
|
|
250
|
+
description: "Hashed password for email/password provider"
|
|
251
|
+
})
|
|
252
|
+
},
|
|
253
|
+
indexes: [
|
|
254
|
+
{ fields: ["user_id"], unique: false },
|
|
255
|
+
{ fields: ["provider_id", "account_id"], unique: true }
|
|
256
|
+
],
|
|
257
|
+
enable: {
|
|
258
|
+
trackHistory: false,
|
|
259
|
+
searchable: false,
|
|
260
|
+
apiEnabled: true,
|
|
261
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
262
|
+
trash: true,
|
|
263
|
+
mru: false
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
var SysVerification = data.ObjectSchema.create({
|
|
267
|
+
name: "sys_verification",
|
|
268
|
+
label: "Verification",
|
|
269
|
+
pluralLabel: "Verifications",
|
|
270
|
+
icon: "shield-check",
|
|
271
|
+
isSystem: true,
|
|
272
|
+
description: "Email and phone verification tokens",
|
|
273
|
+
titleFormat: "Verification for {identifier}",
|
|
274
|
+
compactLayout: ["identifier", "expires_at", "created_at"],
|
|
275
|
+
fields: {
|
|
276
|
+
id: data.Field.text({
|
|
277
|
+
label: "Verification ID",
|
|
278
|
+
required: true,
|
|
279
|
+
readonly: true
|
|
280
|
+
}),
|
|
281
|
+
created_at: data.Field.datetime({
|
|
282
|
+
label: "Created At",
|
|
283
|
+
defaultValue: "NOW()",
|
|
284
|
+
readonly: true
|
|
285
|
+
}),
|
|
286
|
+
updated_at: data.Field.datetime({
|
|
287
|
+
label: "Updated At",
|
|
288
|
+
defaultValue: "NOW()",
|
|
289
|
+
readonly: true
|
|
290
|
+
}),
|
|
291
|
+
value: data.Field.text({
|
|
292
|
+
label: "Verification Token",
|
|
293
|
+
required: true,
|
|
294
|
+
description: "Token or code for verification"
|
|
295
|
+
}),
|
|
296
|
+
expires_at: data.Field.datetime({
|
|
297
|
+
label: "Expires At",
|
|
298
|
+
required: true
|
|
299
|
+
}),
|
|
300
|
+
identifier: data.Field.text({
|
|
301
|
+
label: "Identifier",
|
|
302
|
+
required: true,
|
|
303
|
+
description: "Email address or phone number"
|
|
304
|
+
})
|
|
305
|
+
},
|
|
306
|
+
indexes: [
|
|
307
|
+
{ fields: ["value"], unique: true },
|
|
308
|
+
{ fields: ["identifier"], unique: false },
|
|
309
|
+
{ fields: ["expires_at"], unique: false }
|
|
310
|
+
],
|
|
311
|
+
enable: {
|
|
312
|
+
trackHistory: false,
|
|
313
|
+
searchable: false,
|
|
314
|
+
apiEnabled: true,
|
|
315
|
+
apiMethods: ["get", "create", "delete"],
|
|
316
|
+
trash: false,
|
|
317
|
+
mru: false
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
var SysOrganization = data.ObjectSchema.create({
|
|
321
|
+
name: "sys_organization",
|
|
322
|
+
label: "Organization",
|
|
323
|
+
pluralLabel: "Organizations",
|
|
324
|
+
icon: "building-2",
|
|
325
|
+
isSystem: true,
|
|
326
|
+
description: "Organizations for multi-tenant grouping",
|
|
327
|
+
displayNameField: "name",
|
|
328
|
+
titleFormat: "{name}",
|
|
329
|
+
compactLayout: ["name", "slug"],
|
|
330
|
+
fields: {
|
|
331
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
332
|
+
name: data.Field.text({
|
|
333
|
+
label: "Name",
|
|
334
|
+
required: true,
|
|
335
|
+
searchable: true,
|
|
336
|
+
maxLength: 255,
|
|
337
|
+
group: "Identity"
|
|
338
|
+
}),
|
|
339
|
+
slug: data.Field.text({
|
|
340
|
+
label: "Slug",
|
|
341
|
+
required: false,
|
|
342
|
+
searchable: true,
|
|
343
|
+
maxLength: 255,
|
|
344
|
+
description: "URL-friendly identifier",
|
|
345
|
+
group: "Identity"
|
|
346
|
+
}),
|
|
347
|
+
// ── Branding ─────────────────────────────────────────────────
|
|
348
|
+
logo: data.Field.url({
|
|
349
|
+
label: "Logo",
|
|
350
|
+
required: false,
|
|
351
|
+
group: "Branding"
|
|
352
|
+
}),
|
|
353
|
+
// ── Configuration ────────────────────────────────────────────
|
|
354
|
+
metadata: data.Field.textarea({
|
|
355
|
+
label: "Metadata",
|
|
356
|
+
required: false,
|
|
357
|
+
description: "JSON-serialized organization metadata",
|
|
358
|
+
group: "Configuration"
|
|
359
|
+
}),
|
|
360
|
+
// ── System ───────────────────────────────────────────────────
|
|
361
|
+
id: data.Field.text({
|
|
362
|
+
label: "Organization ID",
|
|
363
|
+
required: true,
|
|
364
|
+
readonly: true,
|
|
365
|
+
group: "System"
|
|
366
|
+
}),
|
|
367
|
+
created_at: data.Field.datetime({
|
|
368
|
+
label: "Created At",
|
|
369
|
+
defaultValue: "NOW()",
|
|
370
|
+
readonly: true,
|
|
371
|
+
group: "System"
|
|
372
|
+
}),
|
|
373
|
+
updated_at: data.Field.datetime({
|
|
374
|
+
label: "Updated At",
|
|
375
|
+
defaultValue: "NOW()",
|
|
376
|
+
readonly: true,
|
|
377
|
+
group: "System"
|
|
378
|
+
})
|
|
379
|
+
},
|
|
380
|
+
indexes: [
|
|
381
|
+
{ fields: ["slug"], unique: true },
|
|
382
|
+
{ fields: ["name"] }
|
|
383
|
+
],
|
|
384
|
+
enable: {
|
|
385
|
+
trackHistory: true,
|
|
386
|
+
searchable: true,
|
|
387
|
+
apiEnabled: true,
|
|
388
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
389
|
+
trash: true,
|
|
390
|
+
mru: true
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
var SysMember = data.ObjectSchema.create({
|
|
394
|
+
name: "sys_member",
|
|
395
|
+
label: "Member",
|
|
396
|
+
pluralLabel: "Members",
|
|
397
|
+
icon: "user-check",
|
|
398
|
+
isSystem: true,
|
|
399
|
+
description: "Organization membership records",
|
|
400
|
+
titleFormat: "{user_id} in {organization_id}",
|
|
401
|
+
compactLayout: ["user_id", "organization_id", "role"],
|
|
402
|
+
fields: {
|
|
403
|
+
id: data.Field.text({
|
|
404
|
+
label: "Member ID",
|
|
405
|
+
required: true,
|
|
406
|
+
readonly: true
|
|
407
|
+
}),
|
|
408
|
+
created_at: data.Field.datetime({
|
|
409
|
+
label: "Created At",
|
|
410
|
+
defaultValue: "NOW()",
|
|
411
|
+
readonly: true
|
|
412
|
+
}),
|
|
413
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
414
|
+
label: "Organization",
|
|
415
|
+
required: true
|
|
416
|
+
}),
|
|
417
|
+
user_id: data.Field.lookup("sys_user", {
|
|
418
|
+
label: "User",
|
|
419
|
+
required: true
|
|
420
|
+
}),
|
|
421
|
+
role: data.Field.text({
|
|
422
|
+
label: "Role",
|
|
423
|
+
required: false,
|
|
424
|
+
description: "Member role within the organization (e.g. admin, member)",
|
|
425
|
+
maxLength: 100
|
|
426
|
+
})
|
|
427
|
+
},
|
|
428
|
+
indexes: [
|
|
429
|
+
{ fields: ["organization_id", "user_id"], unique: true },
|
|
430
|
+
{ fields: ["user_id"] }
|
|
431
|
+
],
|
|
432
|
+
enable: {
|
|
433
|
+
trackHistory: true,
|
|
434
|
+
searchable: false,
|
|
435
|
+
apiEnabled: true,
|
|
436
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
437
|
+
trash: false,
|
|
438
|
+
mru: false
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
var SysInvitation = data.ObjectSchema.create({
|
|
442
|
+
name: "sys_invitation",
|
|
443
|
+
label: "Invitation",
|
|
444
|
+
pluralLabel: "Invitations",
|
|
445
|
+
icon: "mail",
|
|
446
|
+
isSystem: true,
|
|
447
|
+
description: "Organization invitations for user onboarding",
|
|
448
|
+
titleFormat: "Invitation to {organization_id}",
|
|
449
|
+
compactLayout: ["email", "organization_id", "status"],
|
|
450
|
+
fields: {
|
|
451
|
+
id: data.Field.text({
|
|
452
|
+
label: "Invitation ID",
|
|
453
|
+
required: true,
|
|
454
|
+
readonly: true
|
|
455
|
+
}),
|
|
456
|
+
created_at: data.Field.datetime({
|
|
457
|
+
label: "Created At",
|
|
458
|
+
defaultValue: "NOW()",
|
|
459
|
+
readonly: true
|
|
460
|
+
}),
|
|
461
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
462
|
+
label: "Organization",
|
|
463
|
+
required: true
|
|
464
|
+
}),
|
|
465
|
+
email: data.Field.email({
|
|
466
|
+
label: "Email",
|
|
467
|
+
required: true,
|
|
468
|
+
description: "Email address of the invited user"
|
|
469
|
+
}),
|
|
470
|
+
role: data.Field.text({
|
|
471
|
+
label: "Role",
|
|
472
|
+
required: false,
|
|
473
|
+
maxLength: 100,
|
|
474
|
+
description: "Role to assign upon acceptance"
|
|
475
|
+
}),
|
|
476
|
+
status: data.Field.select(["pending", "accepted", "rejected", "expired", "canceled"], {
|
|
477
|
+
label: "Status",
|
|
478
|
+
required: true,
|
|
479
|
+
defaultValue: "pending"
|
|
480
|
+
}),
|
|
481
|
+
inviter_id: data.Field.lookup("sys_user", {
|
|
482
|
+
label: "Inviter",
|
|
483
|
+
required: true,
|
|
484
|
+
description: "User who sent the invitation"
|
|
485
|
+
}),
|
|
486
|
+
expires_at: data.Field.datetime({
|
|
487
|
+
label: "Expires At",
|
|
488
|
+
required: true
|
|
489
|
+
}),
|
|
490
|
+
team_id: data.Field.lookup("sys_team", {
|
|
491
|
+
label: "Team",
|
|
492
|
+
required: false,
|
|
493
|
+
description: "Optional team to assign upon acceptance"
|
|
494
|
+
})
|
|
495
|
+
},
|
|
496
|
+
indexes: [
|
|
497
|
+
{ fields: ["organization_id"] },
|
|
498
|
+
{ fields: ["email"] },
|
|
499
|
+
{ fields: ["expires_at"] }
|
|
500
|
+
],
|
|
501
|
+
enable: {
|
|
502
|
+
trackHistory: true,
|
|
503
|
+
searchable: false,
|
|
504
|
+
apiEnabled: true,
|
|
505
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
506
|
+
trash: false,
|
|
507
|
+
mru: false
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
var SysTeam = data.ObjectSchema.create({
|
|
511
|
+
name: "sys_team",
|
|
512
|
+
label: "Team",
|
|
513
|
+
pluralLabel: "Teams",
|
|
514
|
+
icon: "users",
|
|
515
|
+
isSystem: true,
|
|
516
|
+
description: "Teams within organizations for fine-grained grouping",
|
|
517
|
+
displayNameField: "name",
|
|
518
|
+
titleFormat: "{name}",
|
|
519
|
+
compactLayout: ["name", "organization_id"],
|
|
520
|
+
fields: {
|
|
521
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
522
|
+
name: data.Field.text({
|
|
523
|
+
label: "Name",
|
|
524
|
+
required: true,
|
|
525
|
+
searchable: true,
|
|
526
|
+
maxLength: 255,
|
|
527
|
+
group: "Identity"
|
|
528
|
+
}),
|
|
529
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
530
|
+
label: "Organization",
|
|
531
|
+
required: true,
|
|
532
|
+
description: "Parent organization for this team",
|
|
533
|
+
group: "Identity"
|
|
534
|
+
}),
|
|
535
|
+
// ── System ───────────────────────────────────────────────────
|
|
536
|
+
id: data.Field.text({
|
|
537
|
+
label: "Team ID",
|
|
538
|
+
required: true,
|
|
539
|
+
readonly: true,
|
|
540
|
+
group: "System"
|
|
541
|
+
}),
|
|
542
|
+
created_at: data.Field.datetime({
|
|
543
|
+
label: "Created At",
|
|
544
|
+
defaultValue: "NOW()",
|
|
545
|
+
readonly: true,
|
|
546
|
+
group: "System"
|
|
547
|
+
}),
|
|
548
|
+
updated_at: data.Field.datetime({
|
|
549
|
+
label: "Updated At",
|
|
550
|
+
defaultValue: "NOW()",
|
|
551
|
+
readonly: true,
|
|
552
|
+
group: "System"
|
|
553
|
+
})
|
|
554
|
+
},
|
|
555
|
+
indexes: [
|
|
556
|
+
{ fields: ["organization_id"] },
|
|
557
|
+
{ fields: ["name", "organization_id"], unique: true }
|
|
558
|
+
],
|
|
559
|
+
enable: {
|
|
560
|
+
trackHistory: true,
|
|
561
|
+
searchable: true,
|
|
562
|
+
apiEnabled: true,
|
|
563
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
564
|
+
trash: true,
|
|
565
|
+
mru: false
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
var SysTeamMember = data.ObjectSchema.create({
|
|
569
|
+
name: "sys_team_member",
|
|
570
|
+
label: "Team Member",
|
|
571
|
+
pluralLabel: "Team Members",
|
|
572
|
+
icon: "user-plus",
|
|
573
|
+
isSystem: true,
|
|
574
|
+
description: "Team membership records linking users to teams",
|
|
575
|
+
titleFormat: "{user_id} in {team_id}",
|
|
576
|
+
compactLayout: ["user_id", "team_id", "created_at"],
|
|
577
|
+
fields: {
|
|
578
|
+
id: data.Field.text({
|
|
579
|
+
label: "Team Member ID",
|
|
580
|
+
required: true,
|
|
581
|
+
readonly: true
|
|
582
|
+
}),
|
|
583
|
+
created_at: data.Field.datetime({
|
|
584
|
+
label: "Created At",
|
|
585
|
+
defaultValue: "NOW()",
|
|
586
|
+
readonly: true
|
|
587
|
+
}),
|
|
588
|
+
team_id: data.Field.lookup("sys_team", {
|
|
589
|
+
label: "Team",
|
|
590
|
+
required: true
|
|
591
|
+
}),
|
|
592
|
+
user_id: data.Field.lookup("sys_user", {
|
|
593
|
+
label: "User",
|
|
594
|
+
required: true
|
|
595
|
+
})
|
|
596
|
+
},
|
|
597
|
+
indexes: [
|
|
598
|
+
{ fields: ["team_id", "user_id"], unique: true },
|
|
599
|
+
{ fields: ["user_id"] }
|
|
600
|
+
],
|
|
601
|
+
enable: {
|
|
602
|
+
trackHistory: true,
|
|
603
|
+
searchable: false,
|
|
604
|
+
apiEnabled: true,
|
|
605
|
+
apiMethods: ["get", "list", "create", "delete"],
|
|
606
|
+
trash: false,
|
|
607
|
+
mru: false
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
var SysApiKey = data.ObjectSchema.create({
|
|
611
|
+
name: "sys_api_key",
|
|
612
|
+
label: "API Key",
|
|
613
|
+
pluralLabel: "API Keys",
|
|
614
|
+
icon: "key-round",
|
|
615
|
+
isSystem: true,
|
|
616
|
+
description: "API keys for programmatic access",
|
|
617
|
+
displayNameField: "name",
|
|
618
|
+
titleFormat: "{name}",
|
|
619
|
+
compactLayout: ["name", "prefix", "user_id", "expires_at", "revoked"],
|
|
620
|
+
fields: {
|
|
621
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
622
|
+
name: data.Field.text({
|
|
623
|
+
label: "Name",
|
|
624
|
+
required: true,
|
|
625
|
+
searchable: true,
|
|
626
|
+
maxLength: 255,
|
|
627
|
+
description: "Human-readable label for the API key",
|
|
628
|
+
group: "Identity"
|
|
629
|
+
}),
|
|
630
|
+
prefix: data.Field.text({
|
|
631
|
+
label: "Prefix",
|
|
632
|
+
required: false,
|
|
633
|
+
maxLength: 16,
|
|
634
|
+
description: 'Visible prefix for identifying the key (e.g., "osk_")',
|
|
635
|
+
group: "Identity"
|
|
636
|
+
}),
|
|
637
|
+
user_id: data.Field.lookup("sys_user", {
|
|
638
|
+
label: "Owner",
|
|
639
|
+
required: true,
|
|
640
|
+
description: "User who owns this API key",
|
|
641
|
+
group: "Identity"
|
|
642
|
+
}),
|
|
643
|
+
// ── Access ───────────────────────────────────────────────────
|
|
644
|
+
scopes: data.Field.textarea({
|
|
645
|
+
label: "Scopes",
|
|
646
|
+
required: false,
|
|
647
|
+
description: "JSON array of permission scopes",
|
|
648
|
+
group: "Access"
|
|
649
|
+
}),
|
|
650
|
+
// ── Lifecycle ────────────────────────────────────────────────
|
|
651
|
+
expires_at: data.Field.datetime({
|
|
652
|
+
label: "Expires At",
|
|
653
|
+
required: false,
|
|
654
|
+
group: "Lifecycle"
|
|
655
|
+
}),
|
|
656
|
+
last_used_at: data.Field.datetime({
|
|
657
|
+
label: "Last Used At",
|
|
658
|
+
required: false,
|
|
659
|
+
readonly: true,
|
|
660
|
+
description: "Automatically updated on each API call",
|
|
661
|
+
group: "Lifecycle"
|
|
662
|
+
}),
|
|
663
|
+
revoked: data.Field.boolean({
|
|
664
|
+
label: "Revoked",
|
|
665
|
+
defaultValue: false,
|
|
666
|
+
group: "Lifecycle"
|
|
667
|
+
}),
|
|
668
|
+
// ── Secret (hidden by default) ──────────────────────────────
|
|
669
|
+
key: data.Field.text({
|
|
670
|
+
label: "Hashed Key",
|
|
671
|
+
required: true,
|
|
672
|
+
hidden: true,
|
|
673
|
+
readonly: true,
|
|
674
|
+
description: "Hashed API key value \u2014 never exposed to clients",
|
|
675
|
+
group: "Secret"
|
|
676
|
+
}),
|
|
677
|
+
// ── System ───────────────────────────────────────────────────
|
|
678
|
+
id: data.Field.text({
|
|
679
|
+
label: "API Key ID",
|
|
680
|
+
required: true,
|
|
681
|
+
readonly: true,
|
|
682
|
+
group: "System"
|
|
683
|
+
}),
|
|
684
|
+
created_at: data.Field.datetime({
|
|
685
|
+
label: "Created At",
|
|
686
|
+
defaultValue: "NOW()",
|
|
687
|
+
readonly: true,
|
|
688
|
+
group: "System"
|
|
689
|
+
}),
|
|
690
|
+
updated_at: data.Field.datetime({
|
|
691
|
+
label: "Updated At",
|
|
692
|
+
defaultValue: "NOW()",
|
|
693
|
+
readonly: true,
|
|
694
|
+
group: "System"
|
|
695
|
+
})
|
|
696
|
+
},
|
|
697
|
+
indexes: [
|
|
698
|
+
{ fields: ["key"], unique: true },
|
|
699
|
+
{ fields: ["user_id"] },
|
|
700
|
+
{ fields: ["prefix"] },
|
|
701
|
+
{ fields: ["revoked"] }
|
|
702
|
+
],
|
|
703
|
+
enable: {
|
|
704
|
+
trackHistory: true,
|
|
705
|
+
searchable: false,
|
|
706
|
+
apiEnabled: true,
|
|
707
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
708
|
+
trash: false,
|
|
709
|
+
mru: false
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
var SysTwoFactor = data.ObjectSchema.create({
|
|
713
|
+
name: "sys_two_factor",
|
|
714
|
+
label: "Two Factor",
|
|
715
|
+
pluralLabel: "Two Factor Credentials",
|
|
716
|
+
icon: "smartphone",
|
|
717
|
+
isSystem: true,
|
|
718
|
+
description: "Two-factor authentication credentials",
|
|
719
|
+
titleFormat: "Two-factor for {user_id}",
|
|
720
|
+
compactLayout: ["user_id", "created_at"],
|
|
721
|
+
fields: {
|
|
722
|
+
id: data.Field.text({
|
|
723
|
+
label: "Two Factor ID",
|
|
724
|
+
required: true,
|
|
725
|
+
readonly: true
|
|
726
|
+
}),
|
|
727
|
+
created_at: data.Field.datetime({
|
|
728
|
+
label: "Created At",
|
|
729
|
+
defaultValue: "NOW()",
|
|
730
|
+
readonly: true
|
|
731
|
+
}),
|
|
732
|
+
updated_at: data.Field.datetime({
|
|
733
|
+
label: "Updated At",
|
|
734
|
+
defaultValue: "NOW()",
|
|
735
|
+
readonly: true
|
|
736
|
+
}),
|
|
737
|
+
user_id: data.Field.lookup("sys_user", {
|
|
738
|
+
label: "User",
|
|
739
|
+
required: true
|
|
740
|
+
}),
|
|
741
|
+
secret: data.Field.text({
|
|
742
|
+
label: "Secret",
|
|
743
|
+
required: true,
|
|
744
|
+
description: "TOTP secret key"
|
|
745
|
+
}),
|
|
746
|
+
backup_codes: data.Field.textarea({
|
|
747
|
+
label: "Backup Codes",
|
|
748
|
+
required: false,
|
|
749
|
+
description: "JSON-serialized backup recovery codes"
|
|
750
|
+
})
|
|
751
|
+
},
|
|
752
|
+
indexes: [
|
|
753
|
+
{ fields: ["user_id"], unique: true }
|
|
754
|
+
],
|
|
755
|
+
enable: {
|
|
756
|
+
trackHistory: false,
|
|
757
|
+
searchable: false,
|
|
758
|
+
apiEnabled: true,
|
|
759
|
+
apiMethods: ["get", "create", "update", "delete"],
|
|
760
|
+
trash: false,
|
|
761
|
+
mru: false
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
var SysDeviceCode = data.ObjectSchema.create({
|
|
765
|
+
name: "sys_device_code",
|
|
766
|
+
label: "Device Code",
|
|
767
|
+
pluralLabel: "Device Codes",
|
|
768
|
+
icon: "key-round",
|
|
769
|
+
isSystem: true,
|
|
770
|
+
description: "OAuth 2.0 Device Authorization Grant (RFC 8628) pending requests",
|
|
771
|
+
titleFormat: "{user_code}",
|
|
772
|
+
compactLayout: ["user_code", "status", "client_id", "expires_at"],
|
|
773
|
+
fields: {
|
|
774
|
+
id: data.Field.text({
|
|
775
|
+
label: "Device Code ID",
|
|
776
|
+
required: true,
|
|
777
|
+
readonly: true
|
|
778
|
+
}),
|
|
779
|
+
created_at: data.Field.datetime({
|
|
780
|
+
label: "Created At",
|
|
781
|
+
defaultValue: "NOW()",
|
|
782
|
+
readonly: true
|
|
783
|
+
}),
|
|
784
|
+
updated_at: data.Field.datetime({
|
|
785
|
+
label: "Updated At",
|
|
786
|
+
defaultValue: "NOW()",
|
|
787
|
+
readonly: true
|
|
788
|
+
}),
|
|
789
|
+
/** High-entropy token returned to the device (CLI). Polled at /device/token. */
|
|
790
|
+
device_code: data.Field.text({
|
|
791
|
+
label: "Device Code",
|
|
792
|
+
required: true,
|
|
793
|
+
description: "High-entropy token returned to the polling device"
|
|
794
|
+
}),
|
|
795
|
+
/** Human-readable short code displayed to the user (e.g. ABCD-EFGH). */
|
|
796
|
+
user_code: data.Field.text({
|
|
797
|
+
label: "User Code",
|
|
798
|
+
required: true,
|
|
799
|
+
description: "Short user-facing code (e.g. ABCD-EFGH)"
|
|
800
|
+
}),
|
|
801
|
+
/** Owning user — populated when the request is approved. */
|
|
802
|
+
user_id: data.Field.lookup("sys_user", {
|
|
803
|
+
label: "User",
|
|
804
|
+
required: false,
|
|
805
|
+
description: "User who approved the device authorization"
|
|
806
|
+
}),
|
|
807
|
+
expires_at: data.Field.datetime({
|
|
808
|
+
label: "Expires At",
|
|
809
|
+
required: true,
|
|
810
|
+
description: "When the device & user codes are no longer valid"
|
|
811
|
+
}),
|
|
812
|
+
/** 'pending' | 'approved' | 'denied' */
|
|
813
|
+
status: data.Field.text({
|
|
814
|
+
label: "Status",
|
|
815
|
+
required: true,
|
|
816
|
+
description: "Current status: 'pending' | 'approved' | 'denied'"
|
|
817
|
+
}),
|
|
818
|
+
last_polled_at: data.Field.datetime({
|
|
819
|
+
label: "Last Polled At",
|
|
820
|
+
required: false,
|
|
821
|
+
description: "Timestamp of the most recent /device/token poll"
|
|
822
|
+
}),
|
|
823
|
+
polling_interval: data.Field.number({
|
|
824
|
+
label: "Polling Interval (ms)",
|
|
825
|
+
required: false,
|
|
826
|
+
description: "Server-recommended minimum polling interval, in ms"
|
|
827
|
+
}),
|
|
828
|
+
client_id: data.Field.text({
|
|
829
|
+
label: "Client ID",
|
|
830
|
+
required: false,
|
|
831
|
+
description: "OAuth client identifier of the requesting device"
|
|
832
|
+
}),
|
|
833
|
+
scope: data.Field.text({
|
|
834
|
+
label: "Scope",
|
|
835
|
+
required: false,
|
|
836
|
+
description: "Space-separated OAuth scopes requested by the device"
|
|
837
|
+
})
|
|
838
|
+
},
|
|
839
|
+
indexes: [
|
|
840
|
+
{ fields: ["device_code"], unique: true },
|
|
841
|
+
{ fields: ["user_code"], unique: true },
|
|
842
|
+
{ fields: ["status"], unique: false }
|
|
843
|
+
],
|
|
844
|
+
enable: {
|
|
845
|
+
trackHistory: false,
|
|
846
|
+
searchable: false,
|
|
847
|
+
apiEnabled: true,
|
|
848
|
+
apiMethods: ["get", "create", "update", "delete"],
|
|
849
|
+
trash: false,
|
|
850
|
+
mru: false
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
var SysUserPreference = data.ObjectSchema.create({
|
|
854
|
+
name: "sys_user_preference",
|
|
855
|
+
label: "User Preference",
|
|
856
|
+
pluralLabel: "User Preferences",
|
|
857
|
+
icon: "settings",
|
|
858
|
+
isSystem: true,
|
|
859
|
+
description: "Per-user key-value preferences (theme, locale, etc.)",
|
|
860
|
+
titleFormat: "{key}",
|
|
861
|
+
compactLayout: ["user_id", "key"],
|
|
862
|
+
fields: {
|
|
863
|
+
id: data.Field.text({
|
|
864
|
+
label: "Preference ID",
|
|
865
|
+
required: true,
|
|
866
|
+
readonly: true
|
|
867
|
+
}),
|
|
868
|
+
created_at: data.Field.datetime({
|
|
869
|
+
label: "Created At",
|
|
870
|
+
defaultValue: "NOW()",
|
|
871
|
+
readonly: true
|
|
872
|
+
}),
|
|
873
|
+
updated_at: data.Field.datetime({
|
|
874
|
+
label: "Updated At",
|
|
875
|
+
defaultValue: "NOW()",
|
|
876
|
+
readonly: true
|
|
877
|
+
}),
|
|
878
|
+
user_id: data.Field.lookup("sys_user", {
|
|
879
|
+
label: "User",
|
|
880
|
+
required: true,
|
|
881
|
+
description: "Owner user of this preference"
|
|
882
|
+
}),
|
|
883
|
+
key: data.Field.text({
|
|
884
|
+
label: "Key",
|
|
885
|
+
required: true,
|
|
886
|
+
maxLength: 255,
|
|
887
|
+
description: "Preference key (e.g., theme, locale, plugin.ai.auto_save)"
|
|
888
|
+
}),
|
|
889
|
+
value: data.Field.json({
|
|
890
|
+
label: "Value",
|
|
891
|
+
description: "Preference value (any JSON-serializable type)"
|
|
892
|
+
})
|
|
893
|
+
},
|
|
894
|
+
indexes: [
|
|
895
|
+
{ fields: ["user_id", "key"], unique: true },
|
|
896
|
+
{ fields: ["user_id"], unique: false }
|
|
897
|
+
],
|
|
898
|
+
enable: {
|
|
899
|
+
trackHistory: false,
|
|
900
|
+
searchable: false,
|
|
901
|
+
apiEnabled: true,
|
|
902
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
903
|
+
trash: false,
|
|
904
|
+
mru: false
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
var SysOauthApplication = data.ObjectSchema.create({
|
|
908
|
+
name: "sys_oauth_application",
|
|
909
|
+
label: "OAuth Application",
|
|
910
|
+
pluralLabel: "OAuth Applications",
|
|
911
|
+
icon: "key-round",
|
|
912
|
+
isSystem: true,
|
|
913
|
+
description: "Registered OAuth/OIDC client applications",
|
|
914
|
+
displayNameField: "name",
|
|
915
|
+
titleFormat: "{name}",
|
|
916
|
+
compactLayout: ["name", "client_id", "type", "disabled"],
|
|
917
|
+
fields: {
|
|
918
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
919
|
+
id: data.Field.text({
|
|
920
|
+
label: "ID",
|
|
921
|
+
required: true,
|
|
922
|
+
readonly: true,
|
|
923
|
+
group: "System"
|
|
924
|
+
}),
|
|
925
|
+
name: data.Field.text({
|
|
926
|
+
label: "Name",
|
|
927
|
+
required: false,
|
|
928
|
+
searchable: true,
|
|
929
|
+
maxLength: 255,
|
|
930
|
+
group: "Identity"
|
|
931
|
+
}),
|
|
932
|
+
icon: data.Field.url({
|
|
933
|
+
label: "Icon",
|
|
934
|
+
required: false,
|
|
935
|
+
description: "Logo URL shown on the consent screen",
|
|
936
|
+
group: "Identity"
|
|
937
|
+
}),
|
|
938
|
+
uri: data.Field.url({
|
|
939
|
+
label: "Home URI",
|
|
940
|
+
required: false,
|
|
941
|
+
description: "Public homepage of the registered client",
|
|
942
|
+
group: "Identity"
|
|
943
|
+
}),
|
|
944
|
+
contacts: data.Field.textarea({
|
|
945
|
+
label: "Contacts",
|
|
946
|
+
required: false,
|
|
947
|
+
description: "JSON-serialized list of contact email addresses",
|
|
948
|
+
group: "Identity"
|
|
949
|
+
}),
|
|
950
|
+
tos: data.Field.url({
|
|
951
|
+
label: "Terms of Service",
|
|
952
|
+
required: false,
|
|
953
|
+
group: "Identity"
|
|
954
|
+
}),
|
|
955
|
+
policy: data.Field.url({
|
|
956
|
+
label: "Privacy Policy",
|
|
957
|
+
required: false,
|
|
958
|
+
group: "Identity"
|
|
959
|
+
}),
|
|
960
|
+
metadata: data.Field.textarea({
|
|
961
|
+
label: "Metadata",
|
|
962
|
+
required: false,
|
|
963
|
+
description: "JSON-serialized application metadata",
|
|
964
|
+
group: "Identity"
|
|
965
|
+
}),
|
|
966
|
+
// ── OAuth Credentials ────────────────────────────────────────
|
|
967
|
+
client_id: data.Field.text({
|
|
968
|
+
label: "Client ID",
|
|
969
|
+
required: true,
|
|
970
|
+
readonly: true,
|
|
971
|
+
maxLength: 255,
|
|
972
|
+
description: "Public OAuth client identifier",
|
|
973
|
+
group: "Credentials"
|
|
974
|
+
}),
|
|
975
|
+
client_secret: data.Field.text({
|
|
976
|
+
label: "Client Secret",
|
|
977
|
+
required: false,
|
|
978
|
+
maxLength: 1024,
|
|
979
|
+
description: "OAuth client secret (hashed/encrypted at rest)",
|
|
980
|
+
group: "Credentials"
|
|
981
|
+
}),
|
|
982
|
+
redirect_uris: data.Field.textarea({
|
|
983
|
+
label: "Redirect URIs",
|
|
984
|
+
required: true,
|
|
985
|
+
description: "JSON-serialized list of allowed redirect URIs",
|
|
986
|
+
group: "Credentials"
|
|
987
|
+
}),
|
|
988
|
+
post_logout_redirect_uris: data.Field.textarea({
|
|
989
|
+
label: "Post-logout Redirect URIs",
|
|
990
|
+
required: false,
|
|
991
|
+
description: "JSON-serialized list of allowed post-logout redirect URIs",
|
|
992
|
+
group: "Credentials"
|
|
993
|
+
}),
|
|
994
|
+
type: data.Field.select(["web", "native", "user-agent-based", "public"], {
|
|
995
|
+
label: "Client Type",
|
|
996
|
+
required: false,
|
|
997
|
+
defaultValue: "web",
|
|
998
|
+
group: "Credentials"
|
|
999
|
+
}),
|
|
1000
|
+
public: data.Field.boolean({
|
|
1001
|
+
label: "Public Client",
|
|
1002
|
+
required: false,
|
|
1003
|
+
description: "Marks the client as a public (non-confidential) OAuth client",
|
|
1004
|
+
group: "Credentials"
|
|
1005
|
+
}),
|
|
1006
|
+
require_pkce: data.Field.boolean({
|
|
1007
|
+
label: "Require PKCE",
|
|
1008
|
+
required: false,
|
|
1009
|
+
group: "Credentials"
|
|
1010
|
+
}),
|
|
1011
|
+
token_endpoint_auth_method: data.Field.text({
|
|
1012
|
+
label: "Token Endpoint Auth Method",
|
|
1013
|
+
required: false,
|
|
1014
|
+
maxLength: 64,
|
|
1015
|
+
description: "e.g. client_secret_basic, client_secret_post, none",
|
|
1016
|
+
group: "Credentials"
|
|
1017
|
+
}),
|
|
1018
|
+
grant_types: data.Field.textarea({
|
|
1019
|
+
label: "Grant Types",
|
|
1020
|
+
required: false,
|
|
1021
|
+
description: "JSON-serialized list of allowed grant types",
|
|
1022
|
+
group: "Credentials"
|
|
1023
|
+
}),
|
|
1024
|
+
response_types: data.Field.textarea({
|
|
1025
|
+
label: "Response Types",
|
|
1026
|
+
required: false,
|
|
1027
|
+
description: "JSON-serialized list of allowed response types",
|
|
1028
|
+
group: "Credentials"
|
|
1029
|
+
}),
|
|
1030
|
+
scopes: data.Field.textarea({
|
|
1031
|
+
label: "Allowed Scopes",
|
|
1032
|
+
required: false,
|
|
1033
|
+
description: "JSON-serialized list of scopes the client may request",
|
|
1034
|
+
group: "Credentials"
|
|
1035
|
+
}),
|
|
1036
|
+
subject_type: data.Field.text({
|
|
1037
|
+
label: "Subject Type",
|
|
1038
|
+
required: false,
|
|
1039
|
+
maxLength: 32,
|
|
1040
|
+
description: "OIDC subject type (e.g. public, pairwise)",
|
|
1041
|
+
group: "Credentials"
|
|
1042
|
+
}),
|
|
1043
|
+
// ── Behaviour flags ──────────────────────────────────────────
|
|
1044
|
+
disabled: data.Field.boolean({
|
|
1045
|
+
label: "Disabled",
|
|
1046
|
+
required: false,
|
|
1047
|
+
defaultValue: false,
|
|
1048
|
+
group: "Behaviour"
|
|
1049
|
+
}),
|
|
1050
|
+
skip_consent: data.Field.boolean({
|
|
1051
|
+
label: "Skip Consent",
|
|
1052
|
+
required: false,
|
|
1053
|
+
description: "Treat as a trusted client and bypass the consent screen",
|
|
1054
|
+
group: "Behaviour"
|
|
1055
|
+
}),
|
|
1056
|
+
enable_end_session: data.Field.boolean({
|
|
1057
|
+
label: "Enable End Session",
|
|
1058
|
+
required: false,
|
|
1059
|
+
description: "Allow the client to call the OIDC end-session endpoint",
|
|
1060
|
+
group: "Behaviour"
|
|
1061
|
+
}),
|
|
1062
|
+
// ── Software statement (RFC 7591 §2.3) ───────────────────────
|
|
1063
|
+
software_id: data.Field.text({
|
|
1064
|
+
label: "Software ID",
|
|
1065
|
+
required: false,
|
|
1066
|
+
maxLength: 255,
|
|
1067
|
+
group: "Software"
|
|
1068
|
+
}),
|
|
1069
|
+
software_version: data.Field.text({
|
|
1070
|
+
label: "Software Version",
|
|
1071
|
+
required: false,
|
|
1072
|
+
maxLength: 64,
|
|
1073
|
+
group: "Software"
|
|
1074
|
+
}),
|
|
1075
|
+
software_statement: data.Field.textarea({
|
|
1076
|
+
label: "Software Statement",
|
|
1077
|
+
required: false,
|
|
1078
|
+
description: "Signed JWT asserting the client metadata (RFC 7591 \xA72.3)",
|
|
1079
|
+
group: "Software"
|
|
1080
|
+
}),
|
|
1081
|
+
// ── Ownership / system ───────────────────────────────────────
|
|
1082
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1083
|
+
label: "Owner User",
|
|
1084
|
+
required: false,
|
|
1085
|
+
description: "User who registered this application",
|
|
1086
|
+
group: "System"
|
|
1087
|
+
}),
|
|
1088
|
+
reference_id: data.Field.text({
|
|
1089
|
+
label: "Reference ID",
|
|
1090
|
+
required: false,
|
|
1091
|
+
maxLength: 255,
|
|
1092
|
+
description: "Caller-supplied correlation identifier",
|
|
1093
|
+
group: "System"
|
|
1094
|
+
}),
|
|
1095
|
+
created_at: data.Field.datetime({
|
|
1096
|
+
label: "Created At",
|
|
1097
|
+
defaultValue: "NOW()",
|
|
1098
|
+
readonly: true,
|
|
1099
|
+
group: "System"
|
|
1100
|
+
}),
|
|
1101
|
+
updated_at: data.Field.datetime({
|
|
1102
|
+
label: "Updated At",
|
|
1103
|
+
defaultValue: "NOW()",
|
|
1104
|
+
readonly: true,
|
|
1105
|
+
group: "System"
|
|
1106
|
+
})
|
|
1107
|
+
},
|
|
1108
|
+
indexes: [
|
|
1109
|
+
{ fields: ["client_id"], unique: true },
|
|
1110
|
+
{ fields: ["user_id"] },
|
|
1111
|
+
{ fields: ["reference_id"] }
|
|
1112
|
+
],
|
|
1113
|
+
enable: {
|
|
1114
|
+
trackHistory: true,
|
|
1115
|
+
searchable: true,
|
|
1116
|
+
apiEnabled: true,
|
|
1117
|
+
apiMethods: ["get", "list", "delete"],
|
|
1118
|
+
trash: false,
|
|
1119
|
+
mru: false
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
var SysOauthAccessToken = data.ObjectSchema.create({
|
|
1123
|
+
name: "sys_oauth_access_token",
|
|
1124
|
+
label: "OAuth Access Token",
|
|
1125
|
+
pluralLabel: "OAuth Access Tokens",
|
|
1126
|
+
icon: "ticket",
|
|
1127
|
+
isSystem: true,
|
|
1128
|
+
description: "Opaque OAuth access tokens issued to client applications",
|
|
1129
|
+
compactLayout: ["client_id", "user_id", "expires_at"],
|
|
1130
|
+
fields: {
|
|
1131
|
+
id: data.Field.text({
|
|
1132
|
+
label: "ID",
|
|
1133
|
+
required: true,
|
|
1134
|
+
readonly: true
|
|
1135
|
+
}),
|
|
1136
|
+
token: data.Field.text({
|
|
1137
|
+
label: "Token",
|
|
1138
|
+
required: true,
|
|
1139
|
+
maxLength: 1024,
|
|
1140
|
+
description: "Opaque access token value"
|
|
1141
|
+
}),
|
|
1142
|
+
client_id: data.Field.text({
|
|
1143
|
+
label: "Client ID",
|
|
1144
|
+
required: true,
|
|
1145
|
+
description: "Foreign key to sys_oauth_application.client_id"
|
|
1146
|
+
}),
|
|
1147
|
+
session_id: data.Field.lookup("sys_session", {
|
|
1148
|
+
label: "Session",
|
|
1149
|
+
required: false,
|
|
1150
|
+
description: "Foreign key to sys_session.id"
|
|
1151
|
+
}),
|
|
1152
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1153
|
+
label: "User",
|
|
1154
|
+
required: false,
|
|
1155
|
+
description: "Foreign key to sys_user.id"
|
|
1156
|
+
}),
|
|
1157
|
+
refresh_id: data.Field.lookup("sys_oauth_refresh_token", {
|
|
1158
|
+
label: "Refresh Token",
|
|
1159
|
+
required: false,
|
|
1160
|
+
description: "Foreign key to sys_oauth_refresh_token.id"
|
|
1161
|
+
}),
|
|
1162
|
+
reference_id: data.Field.text({
|
|
1163
|
+
label: "Reference ID",
|
|
1164
|
+
required: false,
|
|
1165
|
+
maxLength: 255,
|
|
1166
|
+
description: "Caller-supplied correlation identifier"
|
|
1167
|
+
}),
|
|
1168
|
+
scopes: data.Field.textarea({
|
|
1169
|
+
label: "Scopes",
|
|
1170
|
+
required: true,
|
|
1171
|
+
description: "JSON-serialized list of scopes granted to this token"
|
|
1172
|
+
}),
|
|
1173
|
+
expires_at: data.Field.datetime({
|
|
1174
|
+
label: "Expires At",
|
|
1175
|
+
required: true
|
|
1176
|
+
}),
|
|
1177
|
+
created_at: data.Field.datetime({
|
|
1178
|
+
label: "Created At",
|
|
1179
|
+
defaultValue: "NOW()",
|
|
1180
|
+
readonly: true
|
|
1181
|
+
})
|
|
1182
|
+
},
|
|
1183
|
+
indexes: [
|
|
1184
|
+
{ fields: ["token"], unique: true },
|
|
1185
|
+
{ fields: ["client_id"] },
|
|
1186
|
+
{ fields: ["session_id"] },
|
|
1187
|
+
{ fields: ["user_id"] },
|
|
1188
|
+
{ fields: ["refresh_id"] }
|
|
1189
|
+
],
|
|
1190
|
+
enable: {
|
|
1191
|
+
trackHistory: false,
|
|
1192
|
+
searchable: false,
|
|
1193
|
+
apiEnabled: false,
|
|
1194
|
+
apiMethods: [],
|
|
1195
|
+
trash: false,
|
|
1196
|
+
mru: false
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
var SysOauthRefreshToken = data.ObjectSchema.create({
|
|
1200
|
+
name: "sys_oauth_refresh_token",
|
|
1201
|
+
label: "OAuth Refresh Token",
|
|
1202
|
+
pluralLabel: "OAuth Refresh Tokens",
|
|
1203
|
+
icon: "refresh-cw",
|
|
1204
|
+
isSystem: true,
|
|
1205
|
+
description: "Opaque OAuth refresh tokens (linked to a session)",
|
|
1206
|
+
compactLayout: ["client_id", "user_id", "expires_at"],
|
|
1207
|
+
fields: {
|
|
1208
|
+
id: data.Field.text({
|
|
1209
|
+
label: "ID",
|
|
1210
|
+
required: true,
|
|
1211
|
+
readonly: true
|
|
1212
|
+
}),
|
|
1213
|
+
token: data.Field.text({
|
|
1214
|
+
label: "Token",
|
|
1215
|
+
required: true,
|
|
1216
|
+
maxLength: 1024,
|
|
1217
|
+
description: "Opaque refresh token value"
|
|
1218
|
+
}),
|
|
1219
|
+
client_id: data.Field.text({
|
|
1220
|
+
label: "Client ID",
|
|
1221
|
+
required: true,
|
|
1222
|
+
description: "Foreign key to sys_oauth_application.client_id"
|
|
1223
|
+
}),
|
|
1224
|
+
session_id: data.Field.lookup("sys_session", {
|
|
1225
|
+
label: "Session",
|
|
1226
|
+
required: false,
|
|
1227
|
+
description: "Foreign key to sys_session.id"
|
|
1228
|
+
}),
|
|
1229
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1230
|
+
label: "User",
|
|
1231
|
+
required: true,
|
|
1232
|
+
description: "Foreign key to sys_user.id"
|
|
1233
|
+
}),
|
|
1234
|
+
reference_id: data.Field.text({
|
|
1235
|
+
label: "Reference ID",
|
|
1236
|
+
required: false,
|
|
1237
|
+
maxLength: 255,
|
|
1238
|
+
description: "Caller-supplied correlation identifier"
|
|
1239
|
+
}),
|
|
1240
|
+
scopes: data.Field.textarea({
|
|
1241
|
+
label: "Scopes",
|
|
1242
|
+
required: true,
|
|
1243
|
+
description: "JSON-serialized list of scopes granted to this token"
|
|
1244
|
+
}),
|
|
1245
|
+
expires_at: data.Field.datetime({
|
|
1246
|
+
label: "Expires At",
|
|
1247
|
+
required: true
|
|
1248
|
+
}),
|
|
1249
|
+
created_at: data.Field.datetime({
|
|
1250
|
+
label: "Created At",
|
|
1251
|
+
defaultValue: "NOW()",
|
|
1252
|
+
readonly: true
|
|
1253
|
+
}),
|
|
1254
|
+
revoked: data.Field.datetime({
|
|
1255
|
+
label: "Revoked At",
|
|
1256
|
+
required: false,
|
|
1257
|
+
description: "Timestamp at which this refresh token was revoked"
|
|
1258
|
+
}),
|
|
1259
|
+
auth_time: data.Field.datetime({
|
|
1260
|
+
label: "Auth Time",
|
|
1261
|
+
required: false,
|
|
1262
|
+
description: "When the user originally authenticated for this token chain"
|
|
1263
|
+
})
|
|
1264
|
+
},
|
|
1265
|
+
indexes: [
|
|
1266
|
+
{ fields: ["token"], unique: true },
|
|
1267
|
+
{ fields: ["client_id"] },
|
|
1268
|
+
{ fields: ["session_id"] },
|
|
1269
|
+
{ fields: ["user_id"] }
|
|
1270
|
+
],
|
|
1271
|
+
enable: {
|
|
1272
|
+
trackHistory: false,
|
|
1273
|
+
searchable: false,
|
|
1274
|
+
apiEnabled: false,
|
|
1275
|
+
apiMethods: [],
|
|
1276
|
+
trash: false,
|
|
1277
|
+
mru: false
|
|
1278
|
+
}
|
|
1279
|
+
});
|
|
1280
|
+
var SysOauthConsent = data.ObjectSchema.create({
|
|
1281
|
+
name: "sys_oauth_consent",
|
|
1282
|
+
label: "OAuth Consent",
|
|
1283
|
+
pluralLabel: "OAuth Consents",
|
|
1284
|
+
icon: "shield-check",
|
|
1285
|
+
isSystem: true,
|
|
1286
|
+
description: "User consent records for OAuth client applications",
|
|
1287
|
+
compactLayout: ["client_id", "user_id", "scopes"],
|
|
1288
|
+
fields: {
|
|
1289
|
+
id: data.Field.text({
|
|
1290
|
+
label: "ID",
|
|
1291
|
+
required: true,
|
|
1292
|
+
readonly: true
|
|
1293
|
+
}),
|
|
1294
|
+
client_id: data.Field.text({
|
|
1295
|
+
label: "Client ID",
|
|
1296
|
+
required: true,
|
|
1297
|
+
description: "Foreign key to sys_oauth_application.client_id"
|
|
1298
|
+
}),
|
|
1299
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1300
|
+
label: "User",
|
|
1301
|
+
required: false,
|
|
1302
|
+
description: "Foreign key to sys_user.id"
|
|
1303
|
+
}),
|
|
1304
|
+
reference_id: data.Field.text({
|
|
1305
|
+
label: "Reference ID",
|
|
1306
|
+
required: false,
|
|
1307
|
+
maxLength: 255,
|
|
1308
|
+
description: "Caller-supplied correlation identifier"
|
|
1309
|
+
}),
|
|
1310
|
+
scopes: data.Field.textarea({
|
|
1311
|
+
label: "Scopes",
|
|
1312
|
+
required: true,
|
|
1313
|
+
description: "JSON-serialized list of scopes the user consented to"
|
|
1314
|
+
}),
|
|
1315
|
+
created_at: data.Field.datetime({
|
|
1316
|
+
label: "Created At",
|
|
1317
|
+
defaultValue: "NOW()",
|
|
1318
|
+
readonly: true
|
|
1319
|
+
}),
|
|
1320
|
+
updated_at: data.Field.datetime({
|
|
1321
|
+
label: "Updated At",
|
|
1322
|
+
defaultValue: "NOW()",
|
|
1323
|
+
readonly: true
|
|
1324
|
+
})
|
|
1325
|
+
},
|
|
1326
|
+
indexes: [
|
|
1327
|
+
{ fields: ["client_id"] },
|
|
1328
|
+
{ fields: ["user_id"] }
|
|
1329
|
+
],
|
|
1330
|
+
enable: {
|
|
1331
|
+
trackHistory: false,
|
|
1332
|
+
searchable: false,
|
|
1333
|
+
apiEnabled: false,
|
|
1334
|
+
apiMethods: [],
|
|
1335
|
+
trash: false,
|
|
1336
|
+
mru: false
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1339
|
+
var SysJwks = data.ObjectSchema.create({
|
|
1340
|
+
name: "sys_jwks",
|
|
1341
|
+
label: "JWKS Key",
|
|
1342
|
+
pluralLabel: "JWKS Keys",
|
|
1343
|
+
icon: "key",
|
|
1344
|
+
isSystem: true,
|
|
1345
|
+
description: "Asymmetric key pairs used to sign and verify issued JWTs",
|
|
1346
|
+
compactLayout: ["id", "created_at", "expires_at"],
|
|
1347
|
+
fields: {
|
|
1348
|
+
id: data.Field.text({
|
|
1349
|
+
label: "Key ID",
|
|
1350
|
+
required: true,
|
|
1351
|
+
readonly: true,
|
|
1352
|
+
description: "JWK `kid` value"
|
|
1353
|
+
}),
|
|
1354
|
+
public_key: data.Field.textarea({
|
|
1355
|
+
label: "Public Key",
|
|
1356
|
+
required: true,
|
|
1357
|
+
description: "JSON-serialized JWK public key"
|
|
1358
|
+
}),
|
|
1359
|
+
private_key: data.Field.textarea({
|
|
1360
|
+
label: "Private Key",
|
|
1361
|
+
required: true,
|
|
1362
|
+
description: "JSON-serialized JWK private key (encrypted at rest)"
|
|
1363
|
+
}),
|
|
1364
|
+
created_at: data.Field.datetime({
|
|
1365
|
+
label: "Created At",
|
|
1366
|
+
required: true,
|
|
1367
|
+
defaultValue: "NOW()",
|
|
1368
|
+
readonly: true
|
|
1369
|
+
}),
|
|
1370
|
+
expires_at: data.Field.datetime({
|
|
1371
|
+
label: "Expires At",
|
|
1372
|
+
required: false,
|
|
1373
|
+
description: "When the key may no longer be used to verify tokens"
|
|
1374
|
+
})
|
|
1375
|
+
},
|
|
1376
|
+
enable: {
|
|
1377
|
+
trackHistory: false,
|
|
1378
|
+
searchable: false,
|
|
1379
|
+
apiEnabled: false,
|
|
1380
|
+
apiMethods: [],
|
|
1381
|
+
trash: false,
|
|
1382
|
+
mru: false
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1385
|
+
var SysRole = data.ObjectSchema.create({
|
|
1386
|
+
name: "sys_role",
|
|
1387
|
+
label: "Role",
|
|
1388
|
+
pluralLabel: "Roles",
|
|
1389
|
+
icon: "shield",
|
|
1390
|
+
isSystem: true,
|
|
1391
|
+
description: "Role definitions for RBAC access control",
|
|
1392
|
+
displayNameField: "label",
|
|
1393
|
+
titleFormat: "{label}",
|
|
1394
|
+
compactLayout: ["label", "name", "active", "is_default"],
|
|
1395
|
+
fields: {
|
|
1396
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
1397
|
+
label: data.Field.text({
|
|
1398
|
+
label: "Display Name",
|
|
1399
|
+
required: true,
|
|
1400
|
+
searchable: true,
|
|
1401
|
+
maxLength: 255,
|
|
1402
|
+
group: "Identity"
|
|
1403
|
+
}),
|
|
1404
|
+
name: data.Field.text({
|
|
1405
|
+
label: "API Name",
|
|
1406
|
+
required: true,
|
|
1407
|
+
searchable: true,
|
|
1408
|
+
maxLength: 100,
|
|
1409
|
+
description: "Unique machine name for the role (e.g. admin, editor, viewer)",
|
|
1410
|
+
group: "Identity"
|
|
1411
|
+
}),
|
|
1412
|
+
description: data.Field.textarea({
|
|
1413
|
+
label: "Description",
|
|
1414
|
+
required: false,
|
|
1415
|
+
group: "Identity"
|
|
1416
|
+
}),
|
|
1417
|
+
// ── Configuration ────────────────────────────────────────────
|
|
1418
|
+
permissions: data.Field.textarea({
|
|
1419
|
+
label: "Permissions",
|
|
1420
|
+
required: false,
|
|
1421
|
+
description: "JSON-serialized array of permission strings",
|
|
1422
|
+
group: "Configuration"
|
|
1423
|
+
}),
|
|
1424
|
+
// ── Status ───────────────────────────────────────────────────
|
|
1425
|
+
active: data.Field.boolean({
|
|
1426
|
+
label: "Active",
|
|
1427
|
+
defaultValue: true,
|
|
1428
|
+
group: "Status"
|
|
1429
|
+
}),
|
|
1430
|
+
is_default: data.Field.boolean({
|
|
1431
|
+
label: "Default Role",
|
|
1432
|
+
defaultValue: false,
|
|
1433
|
+
description: "Automatically assigned to new users",
|
|
1434
|
+
group: "Status"
|
|
1435
|
+
}),
|
|
1436
|
+
// ── System ───────────────────────────────────────────────────
|
|
1437
|
+
id: data.Field.text({
|
|
1438
|
+
label: "Role ID",
|
|
1439
|
+
required: true,
|
|
1440
|
+
readonly: true,
|
|
1441
|
+
group: "System"
|
|
1442
|
+
}),
|
|
1443
|
+
created_at: data.Field.datetime({
|
|
1444
|
+
label: "Created At",
|
|
1445
|
+
defaultValue: "NOW()",
|
|
1446
|
+
readonly: true,
|
|
1447
|
+
group: "System"
|
|
1448
|
+
}),
|
|
1449
|
+
updated_at: data.Field.datetime({
|
|
1450
|
+
label: "Updated At",
|
|
1451
|
+
defaultValue: "NOW()",
|
|
1452
|
+
readonly: true,
|
|
1453
|
+
group: "System"
|
|
1454
|
+
})
|
|
1455
|
+
},
|
|
1456
|
+
indexes: [
|
|
1457
|
+
{ fields: ["name"], unique: true },
|
|
1458
|
+
{ fields: ["active"] }
|
|
1459
|
+
],
|
|
1460
|
+
enable: {
|
|
1461
|
+
trackHistory: true,
|
|
1462
|
+
searchable: true,
|
|
1463
|
+
apiEnabled: true,
|
|
1464
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
1465
|
+
trash: true,
|
|
1466
|
+
mru: true
|
|
1467
|
+
}
|
|
1468
|
+
});
|
|
1469
|
+
var SysPermissionSet = data.ObjectSchema.create({
|
|
1470
|
+
name: "sys_permission_set",
|
|
1471
|
+
label: "Permission Set",
|
|
1472
|
+
pluralLabel: "Permission Sets",
|
|
1473
|
+
icon: "lock",
|
|
1474
|
+
isSystem: true,
|
|
1475
|
+
description: "Named permission groupings for fine-grained access control",
|
|
1476
|
+
displayNameField: "label",
|
|
1477
|
+
titleFormat: "{label}",
|
|
1478
|
+
compactLayout: ["label", "name", "active"],
|
|
1479
|
+
fields: {
|
|
1480
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
1481
|
+
label: data.Field.text({
|
|
1482
|
+
label: "Display Name",
|
|
1483
|
+
required: true,
|
|
1484
|
+
searchable: true,
|
|
1485
|
+
maxLength: 255,
|
|
1486
|
+
group: "Identity"
|
|
1487
|
+
}),
|
|
1488
|
+
name: data.Field.text({
|
|
1489
|
+
label: "API Name",
|
|
1490
|
+
required: true,
|
|
1491
|
+
searchable: true,
|
|
1492
|
+
maxLength: 100,
|
|
1493
|
+
description: "Unique machine name for the permission set",
|
|
1494
|
+
group: "Identity"
|
|
1495
|
+
}),
|
|
1496
|
+
description: data.Field.textarea({
|
|
1497
|
+
label: "Description",
|
|
1498
|
+
required: false,
|
|
1499
|
+
group: "Identity"
|
|
1500
|
+
}),
|
|
1501
|
+
// ── Permissions ──────────────────────────────────────────────
|
|
1502
|
+
object_permissions: data.Field.textarea({
|
|
1503
|
+
label: "Object Permissions",
|
|
1504
|
+
required: false,
|
|
1505
|
+
description: "JSON-serialized object-level CRUD permissions",
|
|
1506
|
+
group: "Permissions"
|
|
1507
|
+
}),
|
|
1508
|
+
field_permissions: data.Field.textarea({
|
|
1509
|
+
label: "Field Permissions",
|
|
1510
|
+
required: false,
|
|
1511
|
+
description: "JSON-serialized field-level read/write permissions",
|
|
1512
|
+
group: "Permissions"
|
|
1513
|
+
}),
|
|
1514
|
+
// ── Status ───────────────────────────────────────────────────
|
|
1515
|
+
active: data.Field.boolean({
|
|
1516
|
+
label: "Active",
|
|
1517
|
+
defaultValue: true,
|
|
1518
|
+
group: "Status"
|
|
1519
|
+
}),
|
|
1520
|
+
// ── System ───────────────────────────────────────────────────
|
|
1521
|
+
id: data.Field.text({
|
|
1522
|
+
label: "Permission Set ID",
|
|
1523
|
+
required: true,
|
|
1524
|
+
readonly: true,
|
|
1525
|
+
group: "System"
|
|
1526
|
+
}),
|
|
1527
|
+
created_at: data.Field.datetime({
|
|
1528
|
+
label: "Created At",
|
|
1529
|
+
defaultValue: "NOW()",
|
|
1530
|
+
readonly: true,
|
|
1531
|
+
group: "System"
|
|
1532
|
+
}),
|
|
1533
|
+
updated_at: data.Field.datetime({
|
|
1534
|
+
label: "Updated At",
|
|
1535
|
+
defaultValue: "NOW()",
|
|
1536
|
+
readonly: true,
|
|
1537
|
+
group: "System"
|
|
1538
|
+
})
|
|
1539
|
+
},
|
|
1540
|
+
indexes: [
|
|
1541
|
+
{ fields: ["name"], unique: true },
|
|
1542
|
+
{ fields: ["active"] }
|
|
1543
|
+
],
|
|
1544
|
+
enable: {
|
|
1545
|
+
trackHistory: true,
|
|
1546
|
+
searchable: true,
|
|
1547
|
+
apiEnabled: true,
|
|
1548
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
1549
|
+
trash: true,
|
|
1550
|
+
mru: true
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
var SysAuditLog = data.ObjectSchema.create({
|
|
1554
|
+
name: "sys_audit_log",
|
|
1555
|
+
label: "Audit Log",
|
|
1556
|
+
pluralLabel: "Audit Logs",
|
|
1557
|
+
icon: "scroll-text",
|
|
1558
|
+
isSystem: true,
|
|
1559
|
+
description: "Immutable audit trail for platform events",
|
|
1560
|
+
displayNameField: "action",
|
|
1561
|
+
titleFormat: "{action} \xB7 {object_name}",
|
|
1562
|
+
compactLayout: ["created_at", "action", "object_name", "record_id", "user_id"],
|
|
1563
|
+
fields: {
|
|
1564
|
+
// ── Event ────────────────────────────────────────────────────
|
|
1565
|
+
created_at: data.Field.datetime({
|
|
1566
|
+
label: "Timestamp",
|
|
1567
|
+
required: true,
|
|
1568
|
+
defaultValue: "NOW()",
|
|
1569
|
+
readonly: true,
|
|
1570
|
+
group: "Event"
|
|
1571
|
+
}),
|
|
1572
|
+
action: data.Field.select(
|
|
1573
|
+
["create", "update", "delete", "restore", "login", "logout", "permission_change", "config_change", "export", "import"],
|
|
1574
|
+
{
|
|
1575
|
+
label: "Action",
|
|
1576
|
+
required: true,
|
|
1577
|
+
readonly: true,
|
|
1578
|
+
searchable: true,
|
|
1579
|
+
description: "Action type (snake_case)",
|
|
1580
|
+
group: "Event"
|
|
1581
|
+
}
|
|
1582
|
+
),
|
|
1583
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1584
|
+
label: "Actor",
|
|
1585
|
+
required: false,
|
|
1586
|
+
readonly: true,
|
|
1587
|
+
searchable: true,
|
|
1588
|
+
description: "User who performed the action (null for system actions)",
|
|
1589
|
+
group: "Event"
|
|
1590
|
+
}),
|
|
1591
|
+
// ── Target record ────────────────────────────────────────────
|
|
1592
|
+
object_name: data.Field.text({
|
|
1593
|
+
label: "Object",
|
|
1594
|
+
required: false,
|
|
1595
|
+
readonly: true,
|
|
1596
|
+
searchable: true,
|
|
1597
|
+
maxLength: 255,
|
|
1598
|
+
description: "Target object (e.g. sys_user, project_task)",
|
|
1599
|
+
group: "Target"
|
|
1600
|
+
}),
|
|
1601
|
+
record_id: data.Field.text({
|
|
1602
|
+
label: "Record ID",
|
|
1603
|
+
required: false,
|
|
1604
|
+
readonly: true,
|
|
1605
|
+
searchable: true,
|
|
1606
|
+
description: "ID of the affected record",
|
|
1607
|
+
group: "Target"
|
|
1608
|
+
}),
|
|
1609
|
+
// ── Change payload ───────────────────────────────────────────
|
|
1610
|
+
old_value: data.Field.textarea({
|
|
1611
|
+
label: "Old Value",
|
|
1612
|
+
required: false,
|
|
1613
|
+
readonly: true,
|
|
1614
|
+
description: "JSON-serialized previous state",
|
|
1615
|
+
group: "Changes"
|
|
1616
|
+
}),
|
|
1617
|
+
new_value: data.Field.textarea({
|
|
1618
|
+
label: "New Value",
|
|
1619
|
+
required: false,
|
|
1620
|
+
readonly: true,
|
|
1621
|
+
description: "JSON-serialized new state",
|
|
1622
|
+
group: "Changes"
|
|
1623
|
+
}),
|
|
1624
|
+
// ── Client fingerprint ───────────────────────────────────────
|
|
1625
|
+
ip_address: data.Field.text({
|
|
1626
|
+
label: "IP Address",
|
|
1627
|
+
required: false,
|
|
1628
|
+
readonly: true,
|
|
1629
|
+
maxLength: 45,
|
|
1630
|
+
group: "Client"
|
|
1631
|
+
}),
|
|
1632
|
+
user_agent: data.Field.textarea({
|
|
1633
|
+
label: "User Agent",
|
|
1634
|
+
required: false,
|
|
1635
|
+
readonly: true,
|
|
1636
|
+
group: "Client"
|
|
1637
|
+
}),
|
|
1638
|
+
// ── Context ──────────────────────────────────────────────────
|
|
1639
|
+
tenant_id: data.Field.lookup("sys_organization", {
|
|
1640
|
+
label: "Tenant",
|
|
1641
|
+
required: false,
|
|
1642
|
+
readonly: true,
|
|
1643
|
+
description: "Tenant context for multi-tenant isolation",
|
|
1644
|
+
group: "Context"
|
|
1645
|
+
}),
|
|
1646
|
+
metadata: data.Field.textarea({
|
|
1647
|
+
label: "Metadata",
|
|
1648
|
+
required: false,
|
|
1649
|
+
readonly: true,
|
|
1650
|
+
description: "JSON-serialized additional context",
|
|
1651
|
+
group: "Context"
|
|
1652
|
+
}),
|
|
1653
|
+
// ── System ───────────────────────────────────────────────────
|
|
1654
|
+
id: data.Field.text({
|
|
1655
|
+
label: "Audit Log ID",
|
|
1656
|
+
required: true,
|
|
1657
|
+
readonly: true,
|
|
1658
|
+
group: "System"
|
|
1659
|
+
})
|
|
1660
|
+
},
|
|
1661
|
+
indexes: [
|
|
1662
|
+
{ fields: ["created_at"] },
|
|
1663
|
+
{ fields: ["user_id"] },
|
|
1664
|
+
{ fields: ["object_name", "record_id"] },
|
|
1665
|
+
{ fields: ["action"] },
|
|
1666
|
+
{ fields: ["tenant_id"] }
|
|
1667
|
+
],
|
|
1668
|
+
enable: {
|
|
1669
|
+
trackHistory: false,
|
|
1670
|
+
// Audit logs are themselves the audit trail
|
|
1671
|
+
searchable: true,
|
|
1672
|
+
apiEnabled: true,
|
|
1673
|
+
apiMethods: ["get", "list"],
|
|
1674
|
+
// Read-only — creation happens via internal system hooks only
|
|
1675
|
+
trash: false,
|
|
1676
|
+
// Never soft-delete audit logs
|
|
1677
|
+
mru: false,
|
|
1678
|
+
clone: false
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
var SysPresence = data.ObjectSchema.create({
|
|
1682
|
+
name: "sys_presence",
|
|
1683
|
+
label: "Presence",
|
|
1684
|
+
pluralLabel: "Presences",
|
|
1685
|
+
icon: "wifi",
|
|
1686
|
+
isSystem: true,
|
|
1687
|
+
description: "Real-time user presence and activity tracking",
|
|
1688
|
+
titleFormat: "{user_id} ({status})",
|
|
1689
|
+
compactLayout: ["user_id", "status", "last_seen"],
|
|
1690
|
+
fields: {
|
|
1691
|
+
id: data.Field.text({
|
|
1692
|
+
label: "Presence ID",
|
|
1693
|
+
required: true,
|
|
1694
|
+
readonly: true
|
|
1695
|
+
}),
|
|
1696
|
+
created_at: data.Field.datetime({
|
|
1697
|
+
label: "Created At",
|
|
1698
|
+
defaultValue: "NOW()",
|
|
1699
|
+
readonly: true
|
|
1700
|
+
}),
|
|
1701
|
+
updated_at: data.Field.datetime({
|
|
1702
|
+
label: "Updated At",
|
|
1703
|
+
defaultValue: "NOW()",
|
|
1704
|
+
readonly: true
|
|
1705
|
+
}),
|
|
1706
|
+
user_id: data.Field.lookup("sys_user", {
|
|
1707
|
+
label: "User",
|
|
1708
|
+
required: true,
|
|
1709
|
+
searchable: true
|
|
1710
|
+
}),
|
|
1711
|
+
session_id: data.Field.lookup("sys_session", {
|
|
1712
|
+
label: "Session",
|
|
1713
|
+
required: true
|
|
1714
|
+
}),
|
|
1715
|
+
status: data.Field.select({
|
|
1716
|
+
label: "Status",
|
|
1717
|
+
required: true,
|
|
1718
|
+
defaultValue: "online",
|
|
1719
|
+
options: [
|
|
1720
|
+
{ value: "online", label: "Online" },
|
|
1721
|
+
{ value: "away", label: "Away" },
|
|
1722
|
+
{ value: "busy", label: "Busy" },
|
|
1723
|
+
{ value: "offline", label: "Offline" }
|
|
1724
|
+
]
|
|
1725
|
+
}),
|
|
1726
|
+
last_seen: data.Field.datetime({
|
|
1727
|
+
label: "Last Seen",
|
|
1728
|
+
required: true,
|
|
1729
|
+
defaultValue: "NOW()"
|
|
1730
|
+
}),
|
|
1731
|
+
current_location: data.Field.text({
|
|
1732
|
+
label: "Current Location",
|
|
1733
|
+
required: false,
|
|
1734
|
+
maxLength: 500
|
|
1735
|
+
}),
|
|
1736
|
+
device: data.Field.select({
|
|
1737
|
+
label: "Device",
|
|
1738
|
+
required: false,
|
|
1739
|
+
options: [
|
|
1740
|
+
{ value: "desktop", label: "Desktop" },
|
|
1741
|
+
{ value: "mobile", label: "Mobile" },
|
|
1742
|
+
{ value: "tablet", label: "Tablet" },
|
|
1743
|
+
{ value: "other", label: "Other" }
|
|
1744
|
+
]
|
|
1745
|
+
}),
|
|
1746
|
+
custom_status: data.Field.text({
|
|
1747
|
+
label: "Custom Status",
|
|
1748
|
+
required: false,
|
|
1749
|
+
maxLength: 255
|
|
1750
|
+
}),
|
|
1751
|
+
metadata: data.Field.json({
|
|
1752
|
+
label: "Metadata",
|
|
1753
|
+
required: false,
|
|
1754
|
+
description: "Arbitrary JSON metadata associated with the presence state (matches PresenceStateSchema.metadata)."
|
|
1755
|
+
})
|
|
1756
|
+
},
|
|
1757
|
+
indexes: [
|
|
1758
|
+
{ fields: ["user_id"], unique: false },
|
|
1759
|
+
{ fields: ["session_id"], unique: true },
|
|
1760
|
+
{ fields: ["status"], unique: false }
|
|
1761
|
+
],
|
|
1762
|
+
enable: {
|
|
1763
|
+
trackHistory: false,
|
|
1764
|
+
searchable: false,
|
|
1765
|
+
apiEnabled: true,
|
|
1766
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
1767
|
+
trash: false,
|
|
1768
|
+
mru: false
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
var SysActivity = data.ObjectSchema.create({
|
|
1772
|
+
name: "sys_activity",
|
|
1773
|
+
label: "Activity",
|
|
1774
|
+
pluralLabel: "Activities",
|
|
1775
|
+
icon: "activity",
|
|
1776
|
+
isSystem: true,
|
|
1777
|
+
description: "Recent activity stream entries (lightweight, denormalized)",
|
|
1778
|
+
displayNameField: "summary",
|
|
1779
|
+
titleFormat: "{type} \xB7 {summary}",
|
|
1780
|
+
compactLayout: ["timestamp", "type", "actor_name", "summary"],
|
|
1781
|
+
fields: {
|
|
1782
|
+
id: data.Field.text({
|
|
1783
|
+
label: "Activity ID",
|
|
1784
|
+
required: true,
|
|
1785
|
+
readonly: true,
|
|
1786
|
+
group: "System"
|
|
1787
|
+
}),
|
|
1788
|
+
timestamp: data.Field.datetime({
|
|
1789
|
+
label: "Timestamp",
|
|
1790
|
+
required: true,
|
|
1791
|
+
defaultValue: "NOW()",
|
|
1792
|
+
readonly: true,
|
|
1793
|
+
group: "Event"
|
|
1794
|
+
}),
|
|
1795
|
+
type: data.Field.select(
|
|
1796
|
+
[
|
|
1797
|
+
"created",
|
|
1798
|
+
"updated",
|
|
1799
|
+
"deleted",
|
|
1800
|
+
"commented",
|
|
1801
|
+
"mentioned",
|
|
1802
|
+
"shared",
|
|
1803
|
+
"assigned",
|
|
1804
|
+
"completed",
|
|
1805
|
+
"login",
|
|
1806
|
+
"logout",
|
|
1807
|
+
"system"
|
|
1808
|
+
],
|
|
1809
|
+
{
|
|
1810
|
+
label: "Type",
|
|
1811
|
+
required: true,
|
|
1812
|
+
readonly: true,
|
|
1813
|
+
searchable: true,
|
|
1814
|
+
group: "Event"
|
|
1815
|
+
}
|
|
1816
|
+
),
|
|
1817
|
+
summary: data.Field.text({
|
|
1818
|
+
label: "Summary",
|
|
1819
|
+
required: true,
|
|
1820
|
+
readonly: true,
|
|
1821
|
+
maxLength: 500,
|
|
1822
|
+
searchable: true,
|
|
1823
|
+
description: "Human-readable one-line summary",
|
|
1824
|
+
group: "Event"
|
|
1825
|
+
}),
|
|
1826
|
+
// ── Actor ───────────────────────────────────────────────────
|
|
1827
|
+
actor_id: data.Field.lookup("sys_user", {
|
|
1828
|
+
label: "Actor",
|
|
1829
|
+
required: false,
|
|
1830
|
+
readonly: true,
|
|
1831
|
+
searchable: true,
|
|
1832
|
+
group: "Actor"
|
|
1833
|
+
}),
|
|
1834
|
+
actor_name: data.Field.text({
|
|
1835
|
+
label: "Actor Name",
|
|
1836
|
+
required: false,
|
|
1837
|
+
readonly: true,
|
|
1838
|
+
group: "Actor"
|
|
1839
|
+
}),
|
|
1840
|
+
actor_avatar_url: data.Field.url({
|
|
1841
|
+
label: "Actor Avatar",
|
|
1842
|
+
required: false,
|
|
1843
|
+
readonly: true,
|
|
1844
|
+
group: "Actor"
|
|
1845
|
+
}),
|
|
1846
|
+
// ── Target ───────────────────────────────────────────────────
|
|
1847
|
+
object_name: data.Field.text({
|
|
1848
|
+
label: "Object",
|
|
1849
|
+
required: false,
|
|
1850
|
+
readonly: true,
|
|
1851
|
+
searchable: true,
|
|
1852
|
+
maxLength: 255,
|
|
1853
|
+
description: "Target object short name (e.g. account, sys_user)",
|
|
1854
|
+
group: "Target"
|
|
1855
|
+
}),
|
|
1856
|
+
record_id: data.Field.text({
|
|
1857
|
+
label: "Record ID",
|
|
1858
|
+
required: false,
|
|
1859
|
+
readonly: true,
|
|
1860
|
+
searchable: true,
|
|
1861
|
+
group: "Target"
|
|
1862
|
+
}),
|
|
1863
|
+
record_label: data.Field.text({
|
|
1864
|
+
label: "Record Label",
|
|
1865
|
+
required: false,
|
|
1866
|
+
readonly: true,
|
|
1867
|
+
maxLength: 255,
|
|
1868
|
+
description: "Display label of the target record at write time",
|
|
1869
|
+
group: "Target"
|
|
1870
|
+
}),
|
|
1871
|
+
url: data.Field.url({
|
|
1872
|
+
label: "URL",
|
|
1873
|
+
required: false,
|
|
1874
|
+
readonly: true,
|
|
1875
|
+
description: "Optional deep-link to the activity target",
|
|
1876
|
+
group: "Target"
|
|
1877
|
+
}),
|
|
1878
|
+
// ── Context ──────────────────────────────────────────────────
|
|
1879
|
+
project_id: data.Field.lookup("sys_project", {
|
|
1880
|
+
label: "Project",
|
|
1881
|
+
required: false,
|
|
1882
|
+
readonly: true,
|
|
1883
|
+
searchable: true,
|
|
1884
|
+
description: "Project context (multi-project deployments)",
|
|
1885
|
+
group: "Context"
|
|
1886
|
+
}),
|
|
1887
|
+
metadata: data.Field.textarea({
|
|
1888
|
+
label: "Metadata",
|
|
1889
|
+
required: false,
|
|
1890
|
+
readonly: true,
|
|
1891
|
+
description: "JSON-serialized additional context",
|
|
1892
|
+
group: "Context"
|
|
1893
|
+
})
|
|
1894
|
+
},
|
|
1895
|
+
indexes: [
|
|
1896
|
+
{ fields: ["timestamp"] },
|
|
1897
|
+
{ fields: ["actor_id"] },
|
|
1898
|
+
{ fields: ["object_name", "record_id"] },
|
|
1899
|
+
{ fields: ["type"] },
|
|
1900
|
+
{ fields: ["project_id"] }
|
|
1901
|
+
],
|
|
1902
|
+
enable: {
|
|
1903
|
+
trackHistory: false,
|
|
1904
|
+
searchable: true,
|
|
1905
|
+
apiEnabled: true,
|
|
1906
|
+
apiMethods: ["get", "list"],
|
|
1907
|
+
trash: false,
|
|
1908
|
+
mru: false,
|
|
1909
|
+
clone: false
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
var SysComment = data.ObjectSchema.create({
|
|
1913
|
+
name: "sys_comment",
|
|
1914
|
+
label: "Comment",
|
|
1915
|
+
pluralLabel: "Comments",
|
|
1916
|
+
icon: "message-square",
|
|
1917
|
+
isSystem: true,
|
|
1918
|
+
description: "Threaded comments attached to records via thread_id",
|
|
1919
|
+
displayNameField: "body",
|
|
1920
|
+
titleFormat: "{author_name}: {body}",
|
|
1921
|
+
compactLayout: ["created_at", "author_name", "body"],
|
|
1922
|
+
fields: {
|
|
1923
|
+
id: data.Field.text({
|
|
1924
|
+
label: "Comment ID",
|
|
1925
|
+
required: true,
|
|
1926
|
+
readonly: true,
|
|
1927
|
+
group: "System"
|
|
1928
|
+
}),
|
|
1929
|
+
// ── Thread ───────────────────────────────────────────────────
|
|
1930
|
+
thread_id: data.Field.text({
|
|
1931
|
+
label: "Thread",
|
|
1932
|
+
required: true,
|
|
1933
|
+
searchable: true,
|
|
1934
|
+
maxLength: 255,
|
|
1935
|
+
description: "Thread identifier \u2014 conventionally `{object}:{record_id}` (e.g. `sys_user:abc123`)",
|
|
1936
|
+
group: "Thread"
|
|
1937
|
+
}),
|
|
1938
|
+
parent_id: data.Field.lookup("sys_comment", {
|
|
1939
|
+
label: "Parent Comment",
|
|
1940
|
+
required: false,
|
|
1941
|
+
description: "Optional parent comment for nested replies",
|
|
1942
|
+
group: "Thread"
|
|
1943
|
+
}),
|
|
1944
|
+
reply_count: data.Field.number({
|
|
1945
|
+
label: "Reply Count",
|
|
1946
|
+
defaultValue: 0,
|
|
1947
|
+
readonly: true,
|
|
1948
|
+
group: "Thread"
|
|
1949
|
+
}),
|
|
1950
|
+
// ── Author ───────────────────────────────────────────────────
|
|
1951
|
+
author_id: data.Field.lookup("sys_user", {
|
|
1952
|
+
label: "Author",
|
|
1953
|
+
required: true,
|
|
1954
|
+
searchable: true,
|
|
1955
|
+
group: "Author"
|
|
1956
|
+
}),
|
|
1957
|
+
author_name: data.Field.text({
|
|
1958
|
+
label: "Author Name",
|
|
1959
|
+
required: false,
|
|
1960
|
+
group: "Author"
|
|
1961
|
+
}),
|
|
1962
|
+
author_avatar_url: data.Field.url({
|
|
1963
|
+
label: "Author Avatar",
|
|
1964
|
+
required: false,
|
|
1965
|
+
group: "Author"
|
|
1966
|
+
}),
|
|
1967
|
+
// ── Body ─────────────────────────────────────────────────────
|
|
1968
|
+
body: data.Field.textarea({
|
|
1969
|
+
label: "Body",
|
|
1970
|
+
required: true,
|
|
1971
|
+
searchable: true,
|
|
1972
|
+
description: "Comment text (Markdown supported)",
|
|
1973
|
+
group: "Body"
|
|
1974
|
+
}),
|
|
1975
|
+
mentions: data.Field.textarea({
|
|
1976
|
+
label: "Mentions",
|
|
1977
|
+
required: false,
|
|
1978
|
+
description: "JSON array of @mention objects",
|
|
1979
|
+
group: "Body"
|
|
1980
|
+
}),
|
|
1981
|
+
reactions: data.Field.textarea({
|
|
1982
|
+
label: "Reactions",
|
|
1983
|
+
required: false,
|
|
1984
|
+
description: "JSON array of emoji reaction objects",
|
|
1985
|
+
group: "Body"
|
|
1986
|
+
}),
|
|
1987
|
+
// ── Lifecycle ────────────────────────────────────────────────
|
|
1988
|
+
is_edited: data.Field.boolean({
|
|
1989
|
+
label: "Edited",
|
|
1990
|
+
defaultValue: false,
|
|
1991
|
+
group: "Lifecycle"
|
|
1992
|
+
}),
|
|
1993
|
+
edited_at: data.Field.datetime({
|
|
1994
|
+
label: "Edited At",
|
|
1995
|
+
required: false,
|
|
1996
|
+
group: "Lifecycle"
|
|
1997
|
+
}),
|
|
1998
|
+
visibility: data.Field.select(
|
|
1999
|
+
["public", "internal", "private"],
|
|
2000
|
+
{
|
|
2001
|
+
label: "Visibility",
|
|
2002
|
+
defaultValue: "public",
|
|
2003
|
+
group: "Lifecycle"
|
|
2004
|
+
}
|
|
2005
|
+
),
|
|
2006
|
+
created_at: data.Field.datetime({
|
|
2007
|
+
label: "Created At",
|
|
2008
|
+
required: true,
|
|
2009
|
+
defaultValue: "NOW()",
|
|
2010
|
+
readonly: true,
|
|
2011
|
+
group: "System"
|
|
2012
|
+
}),
|
|
2013
|
+
updated_at: data.Field.datetime({
|
|
2014
|
+
label: "Updated At",
|
|
2015
|
+
required: false,
|
|
2016
|
+
group: "System"
|
|
2017
|
+
})
|
|
2018
|
+
},
|
|
2019
|
+
indexes: [
|
|
2020
|
+
{ fields: ["thread_id", "created_at"] },
|
|
2021
|
+
{ fields: ["parent_id"] },
|
|
2022
|
+
{ fields: ["author_id"] }
|
|
2023
|
+
],
|
|
2024
|
+
enable: {
|
|
2025
|
+
trackHistory: true,
|
|
2026
|
+
searchable: true,
|
|
2027
|
+
apiEnabled: true,
|
|
2028
|
+
trash: true,
|
|
2029
|
+
mru: false,
|
|
2030
|
+
clone: false
|
|
2031
|
+
}
|
|
2032
|
+
});
|
|
2033
|
+
var SysProject = data.ObjectSchema.create({
|
|
2034
|
+
name: "sys_project",
|
|
2035
|
+
label: "Project",
|
|
2036
|
+
pluralLabel: "Projects",
|
|
2037
|
+
icon: "layers",
|
|
2038
|
+
isSystem: true,
|
|
2039
|
+
description: "Control-plane registry of tenant projects (prod/test/dev/sandbox).",
|
|
2040
|
+
titleFormat: "{display_name}",
|
|
2041
|
+
compactLayout: ["display_name", "status", "is_default"],
|
|
2042
|
+
fields: {
|
|
2043
|
+
id: data.Field.text({
|
|
2044
|
+
label: "Project ID",
|
|
2045
|
+
required: true,
|
|
2046
|
+
readonly: true,
|
|
2047
|
+
description: "UUID of the project (stable, never reused)."
|
|
2048
|
+
}),
|
|
2049
|
+
created_at: data.Field.datetime({
|
|
2050
|
+
label: "Created At",
|
|
2051
|
+
defaultValue: "NOW()",
|
|
2052
|
+
readonly: true,
|
|
2053
|
+
description: "Creation timestamp."
|
|
2054
|
+
}),
|
|
2055
|
+
updated_at: data.Field.datetime({
|
|
2056
|
+
label: "Updated At",
|
|
2057
|
+
defaultValue: "NOW()",
|
|
2058
|
+
readonly: true,
|
|
2059
|
+
description: "Last update timestamp."
|
|
2060
|
+
}),
|
|
2061
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
2062
|
+
label: "Organization",
|
|
2063
|
+
required: true,
|
|
2064
|
+
description: "Foreign key to sys_organization."
|
|
2065
|
+
}),
|
|
2066
|
+
display_name: data.Field.text({
|
|
2067
|
+
label: "Display Name",
|
|
2068
|
+
required: true,
|
|
2069
|
+
maxLength: 255,
|
|
2070
|
+
description: "Display name shown in Studio and APIs."
|
|
2071
|
+
}),
|
|
2072
|
+
is_default: data.Field.boolean({
|
|
2073
|
+
label: "Is Default",
|
|
2074
|
+
required: true,
|
|
2075
|
+
defaultValue: false,
|
|
2076
|
+
description: "Whether this is the default project for the organization. Exactly one per org."
|
|
2077
|
+
}),
|
|
2078
|
+
is_system: data.Field.boolean({
|
|
2079
|
+
label: "Is System",
|
|
2080
|
+
required: true,
|
|
2081
|
+
defaultValue: false,
|
|
2082
|
+
description: "Whether this is a system project (platform infrastructure, not user data)."
|
|
2083
|
+
}),
|
|
2084
|
+
plan: data.Field.select({
|
|
2085
|
+
label: "Plan",
|
|
2086
|
+
required: true,
|
|
2087
|
+
defaultValue: "free",
|
|
2088
|
+
description: "Plan tier applied to this project for quota and billing.",
|
|
2089
|
+
options: [
|
|
2090
|
+
{ value: "free", label: "Free" },
|
|
2091
|
+
{ value: "starter", label: "Starter" },
|
|
2092
|
+
{ value: "pro", label: "Pro" },
|
|
2093
|
+
{ value: "enterprise", label: "Enterprise" },
|
|
2094
|
+
{ value: "custom", label: "Custom" }
|
|
2095
|
+
]
|
|
2096
|
+
}),
|
|
2097
|
+
status: data.Field.select({
|
|
2098
|
+
label: "Status",
|
|
2099
|
+
required: true,
|
|
2100
|
+
defaultValue: "provisioning",
|
|
2101
|
+
description: "Project lifecycle status.",
|
|
2102
|
+
options: [
|
|
2103
|
+
{ value: "provisioning", label: "Provisioning" },
|
|
2104
|
+
{ value: "active", label: "Active" },
|
|
2105
|
+
{ value: "suspended", label: "Suspended" },
|
|
2106
|
+
{ value: "archived", label: "Archived" },
|
|
2107
|
+
{ value: "failed", label: "Failed" },
|
|
2108
|
+
{ value: "migrating", label: "Migrating" }
|
|
2109
|
+
]
|
|
2110
|
+
}),
|
|
2111
|
+
created_by: data.Field.lookup("sys_user", {
|
|
2112
|
+
label: "Created By",
|
|
2113
|
+
required: true,
|
|
2114
|
+
description: "User that created the project."
|
|
2115
|
+
}),
|
|
2116
|
+
database_url: data.Field.url({
|
|
2117
|
+
label: "Database URL",
|
|
2118
|
+
required: false,
|
|
2119
|
+
description: "Connection URL for the project database (e.g. libsql://proj-uuid.turso.io). Set after provisioning."
|
|
2120
|
+
}),
|
|
2121
|
+
database_driver: data.Field.text({
|
|
2122
|
+
label: "Database Driver",
|
|
2123
|
+
required: false,
|
|
2124
|
+
maxLength: 50,
|
|
2125
|
+
description: "Data-plane driver key (turso, libsql, sqlite, memory, postgres)."
|
|
2126
|
+
}),
|
|
2127
|
+
storage_limit_mb: data.Field.number({
|
|
2128
|
+
label: "Storage Limit (MB)",
|
|
2129
|
+
required: false,
|
|
2130
|
+
defaultValue: 1024,
|
|
2131
|
+
description: "Storage quota in megabytes."
|
|
2132
|
+
}),
|
|
2133
|
+
provisioned_at: data.Field.datetime({
|
|
2134
|
+
label: "Provisioned At",
|
|
2135
|
+
required: false,
|
|
2136
|
+
description: "When the physical database was provisioned."
|
|
2137
|
+
}),
|
|
2138
|
+
metadata: data.Field.textarea({
|
|
2139
|
+
label: "Metadata",
|
|
2140
|
+
required: false,
|
|
2141
|
+
description: "JSON-serialized free-form metadata (feature flags, tags, \u2026)."
|
|
2142
|
+
}),
|
|
2143
|
+
hostname: data.Field.text({
|
|
2144
|
+
label: "Hostname",
|
|
2145
|
+
required: false,
|
|
2146
|
+
maxLength: 255,
|
|
2147
|
+
unique: true,
|
|
2148
|
+
description: "Canonical hostname for this project (e.g. acme-dev.objectstack.app or api.acme.com). UNIQUE. Auto-set on creation; can be overridden for custom domains."
|
|
2149
|
+
})
|
|
2150
|
+
},
|
|
2151
|
+
indexes: [
|
|
2152
|
+
{ fields: ["organization_id"] },
|
|
2153
|
+
{ fields: ["organization_id", "is_default"] },
|
|
2154
|
+
{ fields: ["status"] },
|
|
2155
|
+
{ fields: ["database_driver"] },
|
|
2156
|
+
{ fields: ["hostname"], unique: true }
|
|
2157
|
+
],
|
|
2158
|
+
enable: {
|
|
2159
|
+
trackHistory: true,
|
|
2160
|
+
searchable: true,
|
|
2161
|
+
apiEnabled: true,
|
|
2162
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
2163
|
+
trash: false,
|
|
2164
|
+
mru: true
|
|
2165
|
+
}
|
|
2166
|
+
});
|
|
2167
|
+
var SysProjectMember = data.ObjectSchema.create({
|
|
2168
|
+
name: "sys_project_member",
|
|
2169
|
+
label: "Project Member",
|
|
2170
|
+
pluralLabel: "Project Members",
|
|
2171
|
+
icon: "users",
|
|
2172
|
+
isSystem: true,
|
|
2173
|
+
description: "Per-project user/role assignments.",
|
|
2174
|
+
titleFormat: "{user_id} @ {project_id}",
|
|
2175
|
+
compactLayout: ["user_id", "project_id", "role"],
|
|
2176
|
+
fields: {
|
|
2177
|
+
id: data.Field.text({
|
|
2178
|
+
label: "Membership ID",
|
|
2179
|
+
required: true,
|
|
2180
|
+
readonly: true,
|
|
2181
|
+
description: "UUID of the membership."
|
|
2182
|
+
}),
|
|
2183
|
+
created_at: data.Field.datetime({
|
|
2184
|
+
label: "Created At",
|
|
2185
|
+
defaultValue: "NOW()",
|
|
2186
|
+
readonly: true,
|
|
2187
|
+
description: "Creation timestamp."
|
|
2188
|
+
}),
|
|
2189
|
+
updated_at: data.Field.datetime({
|
|
2190
|
+
label: "Updated At",
|
|
2191
|
+
defaultValue: "NOW()",
|
|
2192
|
+
readonly: true,
|
|
2193
|
+
description: "Last update timestamp."
|
|
2194
|
+
}),
|
|
2195
|
+
project_id: data.Field.lookup("sys_project", {
|
|
2196
|
+
label: "Project",
|
|
2197
|
+
required: true,
|
|
2198
|
+
description: "Foreign key to sys_project."
|
|
2199
|
+
}),
|
|
2200
|
+
user_id: data.Field.lookup("sys_user", {
|
|
2201
|
+
label: "User",
|
|
2202
|
+
required: true,
|
|
2203
|
+
description: "Foreign key to sys_user."
|
|
2204
|
+
}),
|
|
2205
|
+
role: data.Field.select({
|
|
2206
|
+
label: "Role",
|
|
2207
|
+
required: true,
|
|
2208
|
+
description: "Per-project role (owner/admin/maker/reader/guest).",
|
|
2209
|
+
options: [
|
|
2210
|
+
{ value: "owner", label: "Owner" },
|
|
2211
|
+
{ value: "admin", label: "Administrator" },
|
|
2212
|
+
{ value: "maker", label: "Maker / Developer" },
|
|
2213
|
+
{ value: "reader", label: "Reader" },
|
|
2214
|
+
{ value: "guest", label: "Guest" }
|
|
2215
|
+
]
|
|
2216
|
+
}),
|
|
2217
|
+
invited_by: data.Field.lookup("sys_user", {
|
|
2218
|
+
label: "Invited By",
|
|
2219
|
+
required: true,
|
|
2220
|
+
description: "User that granted this membership."
|
|
2221
|
+
})
|
|
2222
|
+
},
|
|
2223
|
+
indexes: [
|
|
2224
|
+
{ fields: ["project_id", "user_id"], unique: true },
|
|
2225
|
+
{ fields: ["project_id"] },
|
|
2226
|
+
{ fields: ["user_id"] },
|
|
2227
|
+
{ fields: ["role"] }
|
|
2228
|
+
],
|
|
2229
|
+
enable: {
|
|
2230
|
+
trackHistory: true,
|
|
2231
|
+
searchable: true,
|
|
2232
|
+
apiEnabled: true,
|
|
2233
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
2234
|
+
trash: true,
|
|
2235
|
+
mru: false
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
2238
|
+
var SysProjectCredential = data.ObjectSchema.create({
|
|
2239
|
+
name: "sys_project_credential",
|
|
2240
|
+
label: "Project Credential",
|
|
2241
|
+
pluralLabel: "Project Credentials",
|
|
2242
|
+
icon: "key",
|
|
2243
|
+
isSystem: true,
|
|
2244
|
+
description: "Rotatable encrypted credentials for project databases.",
|
|
2245
|
+
titleFormat: "{id}",
|
|
2246
|
+
compactLayout: ["project_id", "status", "authorization", "expires_at"],
|
|
2247
|
+
fields: {
|
|
2248
|
+
id: data.Field.text({
|
|
2249
|
+
label: "Credential ID",
|
|
2250
|
+
required: true,
|
|
2251
|
+
readonly: true,
|
|
2252
|
+
description: "UUID of the credential."
|
|
2253
|
+
}),
|
|
2254
|
+
created_at: data.Field.datetime({
|
|
2255
|
+
label: "Created At",
|
|
2256
|
+
defaultValue: "NOW()",
|
|
2257
|
+
readonly: true,
|
|
2258
|
+
description: "Creation timestamp."
|
|
2259
|
+
}),
|
|
2260
|
+
updated_at: data.Field.datetime({
|
|
2261
|
+
label: "Updated At",
|
|
2262
|
+
defaultValue: "NOW()",
|
|
2263
|
+
readonly: true,
|
|
2264
|
+
description: "Last update timestamp."
|
|
2265
|
+
}),
|
|
2266
|
+
project_id: data.Field.lookup("sys_project", {
|
|
2267
|
+
label: "Project",
|
|
2268
|
+
required: true,
|
|
2269
|
+
description: "Foreign key to sys_project."
|
|
2270
|
+
}),
|
|
2271
|
+
secret_ciphertext: data.Field.textarea({
|
|
2272
|
+
label: "Secret Ciphertext",
|
|
2273
|
+
required: true,
|
|
2274
|
+
description: "Encrypted auth token or secret (never store plaintext)."
|
|
2275
|
+
}),
|
|
2276
|
+
encryption_key_id: data.Field.text({
|
|
2277
|
+
label: "Encryption Key ID",
|
|
2278
|
+
required: true,
|
|
2279
|
+
maxLength: 255,
|
|
2280
|
+
description: "KMS/encryption key ID that produced the ciphertext."
|
|
2281
|
+
}),
|
|
2282
|
+
authorization: data.Field.select({
|
|
2283
|
+
label: "Authorization",
|
|
2284
|
+
required: true,
|
|
2285
|
+
defaultValue: "full_access",
|
|
2286
|
+
description: "Authorization scope for this credential.",
|
|
2287
|
+
options: [
|
|
2288
|
+
{ value: "full_access", label: "Full Access" },
|
|
2289
|
+
{ value: "read_only", label: "Read Only" }
|
|
2290
|
+
]
|
|
2291
|
+
}),
|
|
2292
|
+
status: data.Field.select({
|
|
2293
|
+
label: "Status",
|
|
2294
|
+
required: true,
|
|
2295
|
+
defaultValue: "active",
|
|
2296
|
+
description: "Credential lifecycle status.",
|
|
2297
|
+
options: [
|
|
2298
|
+
{ value: "active", label: "Active" },
|
|
2299
|
+
{ value: "rotating", label: "Rotating" },
|
|
2300
|
+
{ value: "revoked", label: "Revoked" }
|
|
2301
|
+
]
|
|
2302
|
+
}),
|
|
2303
|
+
expires_at: data.Field.datetime({
|
|
2304
|
+
label: "Expires At",
|
|
2305
|
+
required: false,
|
|
2306
|
+
description: "Optional expiry \u2014 after this timestamp the credential must be rotated."
|
|
2307
|
+
}),
|
|
2308
|
+
revoked_at: data.Field.datetime({
|
|
2309
|
+
label: "Revoked At",
|
|
2310
|
+
required: false,
|
|
2311
|
+
description: "Timestamp when the credential was revoked (null while active)."
|
|
2312
|
+
})
|
|
2313
|
+
},
|
|
2314
|
+
indexes: [
|
|
2315
|
+
{ fields: ["project_id"] },
|
|
2316
|
+
{ fields: ["project_id", "status"] },
|
|
2317
|
+
{ fields: ["status"] },
|
|
2318
|
+
{ fields: ["expires_at"] }
|
|
2319
|
+
],
|
|
2320
|
+
enable: {
|
|
2321
|
+
trackHistory: true,
|
|
2322
|
+
searchable: false,
|
|
2323
|
+
apiEnabled: true,
|
|
2324
|
+
apiMethods: ["get", "list", "create", "update"],
|
|
2325
|
+
trash: false,
|
|
2326
|
+
mru: false
|
|
2327
|
+
}
|
|
2328
|
+
});
|
|
2329
|
+
var SysApp = data.ObjectSchema.create({
|
|
2330
|
+
name: "sys_app",
|
|
2331
|
+
label: "App",
|
|
2332
|
+
pluralLabel: "Apps",
|
|
2333
|
+
icon: "layout-grid",
|
|
2334
|
+
isSystem: true,
|
|
2335
|
+
description: "Org-scoped catalog of apps across all projects (sys_app).",
|
|
2336
|
+
titleFormat: "{label}",
|
|
2337
|
+
compactLayout: ["label", "project_name", "source", "active"],
|
|
2338
|
+
fields: {
|
|
2339
|
+
id: data.Field.text({
|
|
2340
|
+
label: "App Catalog ID",
|
|
2341
|
+
required: true,
|
|
2342
|
+
readonly: true,
|
|
2343
|
+
description: "UUID of this catalog entry (stable, never reused)."
|
|
2344
|
+
}),
|
|
2345
|
+
created_at: data.Field.datetime({
|
|
2346
|
+
label: "Created At",
|
|
2347
|
+
defaultValue: "NOW()",
|
|
2348
|
+
readonly: true,
|
|
2349
|
+
description: "Creation timestamp (ISO-8601)."
|
|
2350
|
+
}),
|
|
2351
|
+
updated_at: data.Field.datetime({
|
|
2352
|
+
label: "Updated At",
|
|
2353
|
+
defaultValue: "NOW()",
|
|
2354
|
+
readonly: true,
|
|
2355
|
+
description: "Last update timestamp (ISO-8601)."
|
|
2356
|
+
}),
|
|
2357
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
2358
|
+
label: "Organization",
|
|
2359
|
+
required: true,
|
|
2360
|
+
description: "Foreign key to sys_organization. Drives tenant isolation \u2014 ControlPlaneProxyDriver auto-injects this filter on all reads."
|
|
2361
|
+
}),
|
|
2362
|
+
project_id: data.Field.lookup("sys_project", {
|
|
2363
|
+
label: "Project",
|
|
2364
|
+
required: true,
|
|
2365
|
+
description: "Foreign key to sys_project. The project this app lives in."
|
|
2366
|
+
}),
|
|
2367
|
+
project_name: data.Field.text({
|
|
2368
|
+
label: "Project Name",
|
|
2369
|
+
required: false,
|
|
2370
|
+
description: "Denormalized project display name. Cached here so the catalog list avoids a JOIN against sys_project for card rendering."
|
|
2371
|
+
}),
|
|
2372
|
+
name: data.Field.text({
|
|
2373
|
+
label: "App Name",
|
|
2374
|
+
required: true,
|
|
2375
|
+
description: "Short, machine name of the app (snake_case). Unique within a project."
|
|
2376
|
+
}),
|
|
2377
|
+
label: data.Field.text({
|
|
2378
|
+
label: "Display Label",
|
|
2379
|
+
required: false,
|
|
2380
|
+
description: "Human-readable display label shown on the catalog card."
|
|
2381
|
+
}),
|
|
2382
|
+
icon: data.Field.text({
|
|
2383
|
+
label: "Icon",
|
|
2384
|
+
required: false,
|
|
2385
|
+
description: "Icon identifier (e.g. lucide name, emoji, or URL)."
|
|
2386
|
+
}),
|
|
2387
|
+
branding: data.Field.textarea({
|
|
2388
|
+
label: "Branding",
|
|
2389
|
+
required: false,
|
|
2390
|
+
description: "JSON-serialized branding subset (color, logo, \u2026) used for catalog rendering."
|
|
2391
|
+
}),
|
|
2392
|
+
is_default: data.Field.boolean({
|
|
2393
|
+
label: "Is Default",
|
|
2394
|
+
required: false,
|
|
2395
|
+
defaultValue: false,
|
|
2396
|
+
description: "Whether this is the default app for its project."
|
|
2397
|
+
}),
|
|
2398
|
+
active: data.Field.boolean({
|
|
2399
|
+
label: "Active",
|
|
2400
|
+
required: true,
|
|
2401
|
+
defaultValue: true,
|
|
2402
|
+
description: "Whether the app is currently enabled in its project kernel."
|
|
2403
|
+
}),
|
|
2404
|
+
source: data.Field.select({
|
|
2405
|
+
label: "Source",
|
|
2406
|
+
required: true,
|
|
2407
|
+
defaultValue: "package",
|
|
2408
|
+
description: "Where this app originates from.",
|
|
2409
|
+
options: [
|
|
2410
|
+
{ value: "package", label: "Package" },
|
|
2411
|
+
{ value: "user", label: "User" }
|
|
2412
|
+
]
|
|
2413
|
+
}),
|
|
2414
|
+
package_id: data.Field.lookup("sys_package", {
|
|
2415
|
+
label: "Package",
|
|
2416
|
+
required: false,
|
|
2417
|
+
description: "Foreign key to sys_package when source = package. Null for user-created apps."
|
|
2418
|
+
})
|
|
2419
|
+
},
|
|
2420
|
+
indexes: [
|
|
2421
|
+
{ fields: ["project_id", "name"], unique: true },
|
|
2422
|
+
{ fields: ["organization_id"] },
|
|
2423
|
+
{ fields: ["project_id"] }
|
|
2424
|
+
],
|
|
2425
|
+
enable: {
|
|
2426
|
+
trackHistory: false,
|
|
2427
|
+
searchable: true,
|
|
2428
|
+
apiEnabled: true,
|
|
2429
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
2430
|
+
trash: false,
|
|
2431
|
+
mru: false
|
|
2432
|
+
}
|
|
2433
|
+
});
|
|
2434
|
+
var SysPackage = data.ObjectSchema.create({
|
|
2435
|
+
name: "sys_package",
|
|
2436
|
+
label: "Package",
|
|
2437
|
+
pluralLabel: "Packages",
|
|
2438
|
+
icon: "package",
|
|
2439
|
+
isSystem: true,
|
|
2440
|
+
description: "Control-plane registry of installable packages / solutions (sys_package).",
|
|
2441
|
+
titleFormat: "{display_name}",
|
|
2442
|
+
compactLayout: ["display_name", "manifest_id", "visibility", "created_at"],
|
|
2443
|
+
fields: {
|
|
2444
|
+
id: data.Field.text({
|
|
2445
|
+
label: "Package ID",
|
|
2446
|
+
required: true,
|
|
2447
|
+
readonly: true,
|
|
2448
|
+
description: "UUID of the package (stable, never reused)."
|
|
2449
|
+
}),
|
|
2450
|
+
created_at: data.Field.datetime({
|
|
2451
|
+
label: "Created At",
|
|
2452
|
+
defaultValue: "NOW()",
|
|
2453
|
+
readonly: true,
|
|
2454
|
+
description: "Creation timestamp (ISO-8601)."
|
|
2455
|
+
}),
|
|
2456
|
+
updated_at: data.Field.datetime({
|
|
2457
|
+
label: "Updated At",
|
|
2458
|
+
defaultValue: "NOW()",
|
|
2459
|
+
readonly: true,
|
|
2460
|
+
description: "Last update timestamp (ISO-8601)."
|
|
2461
|
+
}),
|
|
2462
|
+
manifest_id: data.Field.text({
|
|
2463
|
+
label: "Manifest ID",
|
|
2464
|
+
required: true,
|
|
2465
|
+
readonly: true,
|
|
2466
|
+
maxLength: 255,
|
|
2467
|
+
description: "Globally unique reverse-domain package identifier (e.g. com.acme.crm). Immutable once set. Used as the stable public key for dependency declarations."
|
|
2468
|
+
}),
|
|
2469
|
+
owner_org_id: data.Field.lookup("sys_organization", {
|
|
2470
|
+
label: "Owner Organization",
|
|
2471
|
+
required: true,
|
|
2472
|
+
description: "Organization that owns and publishes this package."
|
|
2473
|
+
}),
|
|
2474
|
+
display_name: data.Field.text({
|
|
2475
|
+
label: "Display Name",
|
|
2476
|
+
required: true,
|
|
2477
|
+
maxLength: 128,
|
|
2478
|
+
description: "Human-readable name shown in Studio and Marketplace."
|
|
2479
|
+
}),
|
|
2480
|
+
description: data.Field.textarea({
|
|
2481
|
+
label: "Description",
|
|
2482
|
+
required: false,
|
|
2483
|
+
description: "Short package description shown in search results and install dialogs (max 512 chars)."
|
|
2484
|
+
}),
|
|
2485
|
+
readme: data.Field.textarea({
|
|
2486
|
+
label: "Readme",
|
|
2487
|
+
required: false,
|
|
2488
|
+
description: "Long-form package documentation (markdown). Displayed on the Marketplace detail page."
|
|
2489
|
+
}),
|
|
2490
|
+
visibility: data.Field.select({
|
|
2491
|
+
label: "Visibility",
|
|
2492
|
+
required: true,
|
|
2493
|
+
defaultValue: "private",
|
|
2494
|
+
description: "Controls who can discover and install the package. private = owner org only; org = all envs in owner org; marketplace = public registry.",
|
|
2495
|
+
options: [
|
|
2496
|
+
{ value: "private", label: "Private" },
|
|
2497
|
+
{ value: "org", label: "Organization" },
|
|
2498
|
+
{ value: "marketplace", label: "Marketplace" }
|
|
2499
|
+
]
|
|
2500
|
+
}),
|
|
2501
|
+
category: data.Field.text({
|
|
2502
|
+
label: "Category",
|
|
2503
|
+
required: false,
|
|
2504
|
+
maxLength: 100,
|
|
2505
|
+
description: "Primary category for Marketplace filtering (e.g. crm, hr, finance, devtools)."
|
|
2506
|
+
}),
|
|
2507
|
+
tags: data.Field.textarea({
|
|
2508
|
+
label: "Tags",
|
|
2509
|
+
required: false,
|
|
2510
|
+
description: 'JSON-serialized array of search/filter tags (e.g. ["salesforce","sync","crm"]).'
|
|
2511
|
+
}),
|
|
2512
|
+
icon_url: data.Field.url({
|
|
2513
|
+
label: "Icon URL",
|
|
2514
|
+
required: false,
|
|
2515
|
+
description: "URL to the package icon image displayed in Studio and Marketplace."
|
|
2516
|
+
}),
|
|
2517
|
+
homepage_url: data.Field.url({
|
|
2518
|
+
label: "Homepage URL",
|
|
2519
|
+
required: false,
|
|
2520
|
+
description: "URL to the package homepage or external documentation site."
|
|
2521
|
+
}),
|
|
2522
|
+
license: data.Field.text({
|
|
2523
|
+
label: "License",
|
|
2524
|
+
required: false,
|
|
2525
|
+
maxLength: 64,
|
|
2526
|
+
description: "SPDX license identifier (e.g. MIT, Apache-2.0, proprietary)."
|
|
2527
|
+
}),
|
|
2528
|
+
created_by: data.Field.lookup("sys_user", {
|
|
2529
|
+
label: "Created By",
|
|
2530
|
+
required: true,
|
|
2531
|
+
description: "User that registered this package in the Control Plane."
|
|
2532
|
+
})
|
|
2533
|
+
},
|
|
2534
|
+
indexes: [
|
|
2535
|
+
{ fields: ["manifest_id"], unique: true },
|
|
2536
|
+
{ fields: ["owner_org_id"] },
|
|
2537
|
+
{ fields: ["visibility"] },
|
|
2538
|
+
{ fields: ["owner_org_id", "visibility"] }
|
|
2539
|
+
],
|
|
2540
|
+
enable: {
|
|
2541
|
+
trackHistory: false,
|
|
2542
|
+
searchable: true,
|
|
2543
|
+
apiEnabled: true,
|
|
2544
|
+
apiMethods: ["get", "list", "create", "update"],
|
|
2545
|
+
trash: false,
|
|
2546
|
+
mru: false
|
|
2547
|
+
}
|
|
2548
|
+
});
|
|
2549
|
+
var SysPackageVersion = data.ObjectSchema.create({
|
|
2550
|
+
name: "sys_package_version",
|
|
2551
|
+
label: "Package Version",
|
|
2552
|
+
pluralLabel: "Package Versions",
|
|
2553
|
+
icon: "tag",
|
|
2554
|
+
isSystem: true,
|
|
2555
|
+
description: "Immutable release snapshot of a package (sys_package_version).",
|
|
2556
|
+
titleFormat: "{package_id} v{version}",
|
|
2557
|
+
compactLayout: ["package_id", "version", "status", "published_at"],
|
|
2558
|
+
fields: {
|
|
2559
|
+
id: data.Field.text({
|
|
2560
|
+
label: "Version ID",
|
|
2561
|
+
required: true,
|
|
2562
|
+
readonly: true,
|
|
2563
|
+
description: "UUID of this package version row (stable, never reused)."
|
|
2564
|
+
}),
|
|
2565
|
+
created_at: data.Field.datetime({
|
|
2566
|
+
label: "Created At",
|
|
2567
|
+
defaultValue: "NOW()",
|
|
2568
|
+
readonly: true,
|
|
2569
|
+
description: "Creation timestamp (ISO-8601)."
|
|
2570
|
+
}),
|
|
2571
|
+
updated_at: data.Field.datetime({
|
|
2572
|
+
label: "Updated At",
|
|
2573
|
+
defaultValue: "NOW()",
|
|
2574
|
+
readonly: true,
|
|
2575
|
+
description: "Last update timestamp (ISO-8601). Only modified while status is draft."
|
|
2576
|
+
}),
|
|
2577
|
+
package_id: data.Field.lookup("sys_package", {
|
|
2578
|
+
label: "Package",
|
|
2579
|
+
required: true,
|
|
2580
|
+
description: "Foreign key to sys_package (the parent package)."
|
|
2581
|
+
}),
|
|
2582
|
+
version: data.Field.text({
|
|
2583
|
+
label: "Version",
|
|
2584
|
+
required: true,
|
|
2585
|
+
maxLength: 64,
|
|
2586
|
+
description: "Semantic version string (e.g. 1.2.3, 2.0.0-beta.1). Follows semver spec."
|
|
2587
|
+
}),
|
|
2588
|
+
status: data.Field.select({
|
|
2589
|
+
label: "Status",
|
|
2590
|
+
required: true,
|
|
2591
|
+
defaultValue: "draft",
|
|
2592
|
+
description: "Lifecycle status. draft = being authored, may be mutated. published = immutable snapshot, installable in any environment. deprecated = published but superseded; new installs blocked.",
|
|
2593
|
+
options: [
|
|
2594
|
+
{ value: "draft", label: "Draft" },
|
|
2595
|
+
{ value: "published", label: "Published" },
|
|
2596
|
+
{ value: "deprecated", label: "Deprecated" }
|
|
2597
|
+
]
|
|
2598
|
+
}),
|
|
2599
|
+
manifest_json: data.Field.textarea({
|
|
2600
|
+
label: "Manifest JSON",
|
|
2601
|
+
required: false,
|
|
2602
|
+
description: "Full package manifest serialized as JSON. Frozen on publish \u2014 writing to this field after status = published is rejected by the service layer."
|
|
2603
|
+
}),
|
|
2604
|
+
checksum: data.Field.text({
|
|
2605
|
+
label: "Checksum",
|
|
2606
|
+
required: false,
|
|
2607
|
+
maxLength: 64,
|
|
2608
|
+
readonly: true,
|
|
2609
|
+
description: "SHA-256 hex digest of manifest_json. Computed and set on publish. Used for tamper detection."
|
|
2610
|
+
}),
|
|
2611
|
+
release_notes: data.Field.textarea({
|
|
2612
|
+
label: "Release Notes",
|
|
2613
|
+
required: false,
|
|
2614
|
+
description: "Human-readable changelog for this version (markdown). Optional."
|
|
2615
|
+
}),
|
|
2616
|
+
min_platform_version: data.Field.text({
|
|
2617
|
+
label: "Min Platform Version",
|
|
2618
|
+
required: false,
|
|
2619
|
+
maxLength: 32,
|
|
2620
|
+
description: "Minimum ObjectStack platform version required to run this version (semver, e.g. 4.0.0). Denormalized from manifest_json for fast validation."
|
|
2621
|
+
}),
|
|
2622
|
+
is_pre_release: data.Field.boolean({
|
|
2623
|
+
label: "Pre-release",
|
|
2624
|
+
required: true,
|
|
2625
|
+
defaultValue: false,
|
|
2626
|
+
description: 'Whether this is a pre-release version (alpha, beta, rc). Pre-release versions are not installed by default when resolving "latest".'
|
|
2627
|
+
}),
|
|
2628
|
+
published_at: data.Field.datetime({
|
|
2629
|
+
label: "Published At",
|
|
2630
|
+
required: false,
|
|
2631
|
+
description: "Timestamp when this version was published. Null while status is draft."
|
|
2632
|
+
}),
|
|
2633
|
+
published_by: data.Field.lookup("sys_user", {
|
|
2634
|
+
label: "Published By",
|
|
2635
|
+
required: false,
|
|
2636
|
+
description: "User who published this version. Set on the draft \u2192 published transition."
|
|
2637
|
+
}),
|
|
2638
|
+
created_by: data.Field.lookup("sys_user", {
|
|
2639
|
+
label: "Created By",
|
|
2640
|
+
required: true,
|
|
2641
|
+
description: "User that created this version row."
|
|
2642
|
+
})
|
|
2643
|
+
},
|
|
2644
|
+
indexes: [
|
|
2645
|
+
{ fields: ["package_id", "version"], unique: true },
|
|
2646
|
+
{ fields: ["package_id"] },
|
|
2647
|
+
{ fields: ["status"] },
|
|
2648
|
+
{ fields: ["package_id", "status"] }
|
|
2649
|
+
],
|
|
2650
|
+
enable: {
|
|
2651
|
+
trackHistory: false,
|
|
2652
|
+
searchable: false,
|
|
2653
|
+
apiEnabled: true,
|
|
2654
|
+
apiMethods: ["get", "list", "create", "update"],
|
|
2655
|
+
trash: false,
|
|
2656
|
+
mru: false
|
|
2657
|
+
}
|
|
2658
|
+
});
|
|
2659
|
+
var SysPackageInstallation = data.ObjectSchema.create({
|
|
2660
|
+
name: "sys_package_installation",
|
|
2661
|
+
label: "Package Installation",
|
|
2662
|
+
pluralLabel: "Package Installations",
|
|
2663
|
+
icon: "package",
|
|
2664
|
+
isSystem: true,
|
|
2665
|
+
description: "Per-project package installation registry (sys_package_installation).",
|
|
2666
|
+
titleFormat: "{package_id} @ {project_id}",
|
|
2667
|
+
compactLayout: ["package_version_id", "project_id", "status", "installed_at"],
|
|
2668
|
+
fields: {
|
|
2669
|
+
id: data.Field.text({
|
|
2670
|
+
label: "Installation ID",
|
|
2671
|
+
required: true,
|
|
2672
|
+
readonly: true,
|
|
2673
|
+
description: "UUID of this installation record (stable, never reused)."
|
|
2674
|
+
}),
|
|
2675
|
+
created_at: data.Field.datetime({
|
|
2676
|
+
label: "Created At",
|
|
2677
|
+
defaultValue: "NOW()",
|
|
2678
|
+
readonly: true,
|
|
2679
|
+
description: "Creation timestamp (ISO-8601)."
|
|
2680
|
+
}),
|
|
2681
|
+
updated_at: data.Field.datetime({
|
|
2682
|
+
label: "Updated At",
|
|
2683
|
+
defaultValue: "NOW()",
|
|
2684
|
+
readonly: true,
|
|
2685
|
+
description: "Last update timestamp \u2014 changes on upgrade, rollback, enable/disable (ISO-8601)."
|
|
2686
|
+
}),
|
|
2687
|
+
project_id: data.Field.lookup("sys_project", {
|
|
2688
|
+
label: "Project",
|
|
2689
|
+
required: true,
|
|
2690
|
+
description: "Foreign key to sys_project. The project that owns this installation."
|
|
2691
|
+
}),
|
|
2692
|
+
package_version_id: data.Field.lookup("sys_package_version", {
|
|
2693
|
+
label: "Package Version",
|
|
2694
|
+
required: true,
|
|
2695
|
+
description: "Foreign key to sys_package_version. The specific, immutable release snapshot currently installed in this project. Upgrading = swapping this field to a newer version. Rollback = swapping to an older version."
|
|
2696
|
+
}),
|
|
2697
|
+
package_id: data.Field.lookup("sys_package", {
|
|
2698
|
+
label: "Package",
|
|
2699
|
+
required: true,
|
|
2700
|
+
description: "Foreign key to sys_package. Denormalized from the linked package_version row at install time to enforce the UNIQUE (project_id, package_id) constraint without a JOIN."
|
|
2701
|
+
}),
|
|
2702
|
+
status: data.Field.select({
|
|
2703
|
+
label: "Status",
|
|
2704
|
+
required: true,
|
|
2705
|
+
defaultValue: "installed",
|
|
2706
|
+
description: "Current lifecycle status of this installation within the project.",
|
|
2707
|
+
options: [
|
|
2708
|
+
{ value: "installed", label: "Installed" },
|
|
2709
|
+
{ value: "installing", label: "Installing" },
|
|
2710
|
+
{ value: "upgrading", label: "Upgrading" },
|
|
2711
|
+
{ value: "disabled", label: "Disabled" },
|
|
2712
|
+
{ value: "error", label: "Error" }
|
|
2713
|
+
]
|
|
2714
|
+
}),
|
|
2715
|
+
enabled: data.Field.boolean({
|
|
2716
|
+
label: "Enabled",
|
|
2717
|
+
required: true,
|
|
2718
|
+
defaultValue: true,
|
|
2719
|
+
description: "Whether the package metadata is actively loaded into this project. Disabled packages are installed but their schema is not visible to the runtime."
|
|
2720
|
+
}),
|
|
2721
|
+
settings: data.Field.textarea({
|
|
2722
|
+
label: "Settings",
|
|
2723
|
+
required: false,
|
|
2724
|
+
description: "JSON-serialized per-installation configuration overrides. Keys mirror the package manifest configurationSchema.properties."
|
|
2725
|
+
}),
|
|
2726
|
+
installed_at: data.Field.datetime({
|
|
2727
|
+
label: "Installed At",
|
|
2728
|
+
required: true,
|
|
2729
|
+
defaultValue: "NOW()",
|
|
2730
|
+
description: "Timestamp when this installation was first created (ISO-8601)."
|
|
2731
|
+
}),
|
|
2732
|
+
installed_by: data.Field.lookup("sys_user", {
|
|
2733
|
+
label: "Installed By",
|
|
2734
|
+
required: false,
|
|
2735
|
+
description: "User who performed the initial install. Null for system-automated installs."
|
|
2736
|
+
}),
|
|
2737
|
+
error_message: data.Field.textarea({
|
|
2738
|
+
label: "Error Message",
|
|
2739
|
+
required: false,
|
|
2740
|
+
description: "Error details when status is error. Cleared on next successful install/upgrade."
|
|
2741
|
+
})
|
|
2742
|
+
},
|
|
2743
|
+
indexes: [
|
|
2744
|
+
{ fields: ["project_id", "package_id"], unique: true },
|
|
2745
|
+
{ fields: ["project_id"] },
|
|
2746
|
+
{ fields: ["package_id"] },
|
|
2747
|
+
{ fields: ["package_version_id"] },
|
|
2748
|
+
{ fields: ["status"] }
|
|
2749
|
+
],
|
|
2750
|
+
enable: {
|
|
2751
|
+
trackHistory: false,
|
|
2752
|
+
searchable: true,
|
|
2753
|
+
apiEnabled: true,
|
|
2754
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
2755
|
+
trash: false,
|
|
2756
|
+
mru: false
|
|
2757
|
+
}
|
|
2758
|
+
});
|
|
2759
|
+
var SysMetadataObject = data.ObjectSchema.create({
|
|
2760
|
+
name: "sys_metadata",
|
|
2761
|
+
label: "System Metadata",
|
|
2762
|
+
pluralLabel: "System Metadata",
|
|
2763
|
+
icon: "settings",
|
|
2764
|
+
isSystem: true,
|
|
2765
|
+
description: "Stores platform and user-scope metadata records (objects, views, flows, etc.)",
|
|
2766
|
+
fields: {
|
|
2767
|
+
/** Primary Key (UUID) */
|
|
2768
|
+
id: data.Field.text({
|
|
2769
|
+
label: "ID",
|
|
2770
|
+
required: true,
|
|
2771
|
+
readonly: true
|
|
2772
|
+
}),
|
|
2773
|
+
/** Machine name — unique identifier used in code references */
|
|
2774
|
+
name: data.Field.text({
|
|
2775
|
+
label: "Name",
|
|
2776
|
+
required: true,
|
|
2777
|
+
searchable: true,
|
|
2778
|
+
maxLength: 255
|
|
2779
|
+
}),
|
|
2780
|
+
/** Metadata type (e.g. "object", "view", "flow") */
|
|
2781
|
+
type: data.Field.text({
|
|
2782
|
+
label: "Metadata Type",
|
|
2783
|
+
required: true,
|
|
2784
|
+
searchable: true,
|
|
2785
|
+
maxLength: 100
|
|
2786
|
+
}),
|
|
2787
|
+
/** Namespace / module grouping (e.g. "crm", "core") */
|
|
2788
|
+
namespace: data.Field.text({
|
|
2789
|
+
label: "Namespace",
|
|
2790
|
+
required: false,
|
|
2791
|
+
defaultValue: "default",
|
|
2792
|
+
maxLength: 100
|
|
2793
|
+
}),
|
|
2794
|
+
/** Package that owns/delivered this metadata (legacy string identifier, kept for compat) */
|
|
2795
|
+
package_id: data.Field.text({
|
|
2796
|
+
label: "Package ID",
|
|
2797
|
+
required: false,
|
|
2798
|
+
maxLength: 255,
|
|
2799
|
+
description: "Legacy package manifest ID string. Use package_version_id for new records."
|
|
2800
|
+
}),
|
|
2801
|
+
/**
|
|
2802
|
+
* FK → sys_package_version (UUID). Set for metadata that belongs to a specific
|
|
2803
|
+
* package release snapshot. NULL = platform-built-in or environment override.
|
|
2804
|
+
*/
|
|
2805
|
+
package_version_id: data.Field.lookup("sys_package_version", {
|
|
2806
|
+
label: "Package Version",
|
|
2807
|
+
required: false,
|
|
2808
|
+
description: "Foreign key to sys_package_version (UUID). Null = platform-built-in or env-level override."
|
|
2809
|
+
}),
|
|
2810
|
+
/** Who manages this record: package, platform, or user */
|
|
2811
|
+
managed_by: data.Field.select(["package", "platform", "user"], {
|
|
2812
|
+
label: "Managed By",
|
|
2813
|
+
required: false
|
|
2814
|
+
}),
|
|
2815
|
+
/** Scope: system (code), platform (admin DB), user (personal DB) */
|
|
2816
|
+
scope: data.Field.select(["system", "platform", "user"], {
|
|
2817
|
+
label: "Scope",
|
|
2818
|
+
required: true,
|
|
2819
|
+
defaultValue: "platform"
|
|
2820
|
+
}),
|
|
2821
|
+
/** JSON payload — the actual metadata configuration */
|
|
2822
|
+
metadata: data.Field.textarea({
|
|
2823
|
+
label: "Metadata",
|
|
2824
|
+
required: true,
|
|
2825
|
+
description: "JSON-serialized metadata payload"
|
|
2826
|
+
}),
|
|
2827
|
+
/** Parent metadata name for extension/override */
|
|
2828
|
+
extends: data.Field.text({
|
|
2829
|
+
label: "Extends",
|
|
2830
|
+
required: false,
|
|
2831
|
+
maxLength: 255
|
|
2832
|
+
}),
|
|
2833
|
+
/** Merge strategy when extending parent metadata */
|
|
2834
|
+
strategy: data.Field.select(["merge", "replace"], {
|
|
2835
|
+
label: "Strategy",
|
|
2836
|
+
required: false,
|
|
2837
|
+
defaultValue: "merge"
|
|
2838
|
+
}),
|
|
2839
|
+
/** Owner user ID (for user-scope items) */
|
|
2840
|
+
owner: data.Field.text({
|
|
2841
|
+
label: "Owner",
|
|
2842
|
+
required: false,
|
|
2843
|
+
maxLength: 255
|
|
2844
|
+
}),
|
|
2845
|
+
/** Lifecycle state */
|
|
2846
|
+
state: data.Field.select(["draft", "active", "archived", "deprecated"], {
|
|
2847
|
+
label: "State",
|
|
2848
|
+
required: false,
|
|
2849
|
+
defaultValue: "active"
|
|
2850
|
+
}),
|
|
2851
|
+
/** Organization ID for multi-tenant isolation */
|
|
2852
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
2853
|
+
label: "Organization",
|
|
2854
|
+
required: false,
|
|
2855
|
+
description: "Organization for multi-tenant isolation."
|
|
2856
|
+
}),
|
|
2857
|
+
/** Project ID — null = platform-global, set = project-scoped */
|
|
2858
|
+
project_id: data.Field.lookup("sys_project", {
|
|
2859
|
+
label: "Project",
|
|
2860
|
+
required: false,
|
|
2861
|
+
description: "Foreign key to sys_project (UUID). Null = platform-global."
|
|
2862
|
+
}),
|
|
2863
|
+
/** Version number for optimistic concurrency */
|
|
2864
|
+
version: data.Field.number({
|
|
2865
|
+
label: "Version",
|
|
2866
|
+
required: false,
|
|
2867
|
+
defaultValue: 1
|
|
2868
|
+
}),
|
|
2869
|
+
/** Content checksum for change detection */
|
|
2870
|
+
checksum: data.Field.text({
|
|
2871
|
+
label: "Checksum",
|
|
2872
|
+
required: false,
|
|
2873
|
+
maxLength: 64
|
|
2874
|
+
}),
|
|
2875
|
+
/** Origin of this metadata record */
|
|
2876
|
+
source: data.Field.select(["filesystem", "database", "api", "migration"], {
|
|
2877
|
+
label: "Source",
|
|
2878
|
+
required: false
|
|
2879
|
+
}),
|
|
2880
|
+
/** Classification tags (JSON array) */
|
|
2881
|
+
tags: data.Field.textarea({
|
|
2882
|
+
label: "Tags",
|
|
2883
|
+
required: false,
|
|
2884
|
+
description: "JSON-serialized array of classification tags"
|
|
2885
|
+
}),
|
|
2886
|
+
/** Audit fields */
|
|
2887
|
+
created_by: data.Field.lookup("sys_user", {
|
|
2888
|
+
label: "Created By",
|
|
2889
|
+
required: false,
|
|
2890
|
+
readonly: true
|
|
2891
|
+
}),
|
|
2892
|
+
created_at: data.Field.datetime({
|
|
2893
|
+
label: "Created At",
|
|
2894
|
+
required: false,
|
|
2895
|
+
readonly: true
|
|
2896
|
+
}),
|
|
2897
|
+
updated_by: data.Field.lookup("sys_user", {
|
|
2898
|
+
label: "Updated By",
|
|
2899
|
+
required: false
|
|
2900
|
+
}),
|
|
2901
|
+
updated_at: data.Field.datetime({
|
|
2902
|
+
label: "Updated At",
|
|
2903
|
+
required: false
|
|
2904
|
+
})
|
|
2905
|
+
},
|
|
2906
|
+
indexes: [
|
|
2907
|
+
{ fields: ["type", "name", "project_id"], unique: true },
|
|
2908
|
+
{ fields: ["type", "scope"] },
|
|
2909
|
+
{ fields: ["organization_id"] },
|
|
2910
|
+
{ fields: ["project_id"] },
|
|
2911
|
+
{ fields: ["package_version_id"] },
|
|
2912
|
+
{ fields: ["state"] },
|
|
2913
|
+
{ fields: ["namespace"] }
|
|
2914
|
+
],
|
|
2915
|
+
enable: {
|
|
2916
|
+
trackHistory: true,
|
|
2917
|
+
searchable: false,
|
|
2918
|
+
apiEnabled: true,
|
|
2919
|
+
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
2920
|
+
trash: false
|
|
2921
|
+
}
|
|
2922
|
+
});
|
|
2923
|
+
var SysMetadataHistoryObject = data.ObjectSchema.create({
|
|
2924
|
+
name: "sys_metadata_history",
|
|
2925
|
+
label: "Metadata History",
|
|
2926
|
+
pluralLabel: "Metadata History",
|
|
2927
|
+
icon: "history",
|
|
2928
|
+
isSystem: true,
|
|
2929
|
+
description: "Version history and audit trail for metadata changes",
|
|
2930
|
+
fields: {
|
|
2931
|
+
/** Primary Key (UUID) */
|
|
2932
|
+
id: data.Field.text({
|
|
2933
|
+
label: "ID",
|
|
2934
|
+
required: true,
|
|
2935
|
+
readonly: true
|
|
2936
|
+
}),
|
|
2937
|
+
/** Foreign key to sys_metadata.id */
|
|
2938
|
+
metadata_id: data.Field.lookup("sys_metadata", {
|
|
2939
|
+
label: "Metadata",
|
|
2940
|
+
required: true,
|
|
2941
|
+
readonly: true
|
|
2942
|
+
}),
|
|
2943
|
+
/** Machine name (denormalized for easier querying) */
|
|
2944
|
+
name: data.Field.text({
|
|
2945
|
+
label: "Name",
|
|
2946
|
+
required: true,
|
|
2947
|
+
searchable: true,
|
|
2948
|
+
readonly: true,
|
|
2949
|
+
maxLength: 255
|
|
2950
|
+
}),
|
|
2951
|
+
/** Metadata type (denormalized for easier querying) */
|
|
2952
|
+
type: data.Field.text({
|
|
2953
|
+
label: "Metadata Type",
|
|
2954
|
+
required: true,
|
|
2955
|
+
searchable: true,
|
|
2956
|
+
readonly: true,
|
|
2957
|
+
maxLength: 100
|
|
2958
|
+
}),
|
|
2959
|
+
/** Version number at this snapshot */
|
|
2960
|
+
version: data.Field.number({
|
|
2961
|
+
label: "Version",
|
|
2962
|
+
required: true,
|
|
2963
|
+
readonly: true
|
|
2964
|
+
}),
|
|
2965
|
+
/** Type of operation that created this history entry */
|
|
2966
|
+
operation_type: data.Field.select(["create", "update", "publish", "revert", "delete"], {
|
|
2967
|
+
label: "Operation Type",
|
|
2968
|
+
required: true,
|
|
2969
|
+
readonly: true
|
|
2970
|
+
}),
|
|
2971
|
+
/** Historical metadata snapshot (JSON payload) */
|
|
2972
|
+
metadata: data.Field.textarea({
|
|
2973
|
+
label: "Metadata",
|
|
2974
|
+
required: true,
|
|
2975
|
+
readonly: true,
|
|
2976
|
+
description: "JSON-serialized metadata snapshot at this version"
|
|
2977
|
+
}),
|
|
2978
|
+
/** SHA-256 checksum of metadata content */
|
|
2979
|
+
checksum: data.Field.text({
|
|
2980
|
+
label: "Checksum",
|
|
2981
|
+
required: true,
|
|
2982
|
+
readonly: true,
|
|
2983
|
+
maxLength: 64
|
|
2984
|
+
}),
|
|
2985
|
+
/** Checksum of the previous version */
|
|
2986
|
+
previous_checksum: data.Field.text({
|
|
2987
|
+
label: "Previous Checksum",
|
|
2988
|
+
required: false,
|
|
2989
|
+
readonly: true,
|
|
2990
|
+
maxLength: 64
|
|
2991
|
+
}),
|
|
2992
|
+
/** Human-readable description of changes */
|
|
2993
|
+
change_note: data.Field.textarea({
|
|
2994
|
+
label: "Change Note",
|
|
2995
|
+
required: false,
|
|
2996
|
+
readonly: true,
|
|
2997
|
+
description: "Description of what changed in this version"
|
|
2998
|
+
}),
|
|
2999
|
+
/** Organization ID for multi-tenant isolation */
|
|
3000
|
+
organization_id: data.Field.lookup("sys_organization", {
|
|
3001
|
+
label: "Organization",
|
|
3002
|
+
required: false,
|
|
3003
|
+
readonly: true,
|
|
3004
|
+
description: "Organization for multi-tenant isolation."
|
|
3005
|
+
}),
|
|
3006
|
+
/** Environment ID — null = platform-global, set = env-scoped */
|
|
3007
|
+
project_id: data.Field.text({
|
|
3008
|
+
label: "Environment ID",
|
|
3009
|
+
required: false,
|
|
3010
|
+
readonly: true,
|
|
3011
|
+
maxLength: 255,
|
|
3012
|
+
description: "Scopes this history entry to a specific environment."
|
|
3013
|
+
}),
|
|
3014
|
+
/** User who made this change */
|
|
3015
|
+
recorded_by: data.Field.lookup("sys_user", {
|
|
3016
|
+
label: "Recorded By",
|
|
3017
|
+
required: false,
|
|
3018
|
+
readonly: true
|
|
3019
|
+
}),
|
|
3020
|
+
/** When was this version recorded */
|
|
3021
|
+
recorded_at: data.Field.datetime({
|
|
3022
|
+
label: "Recorded At",
|
|
3023
|
+
required: true,
|
|
3024
|
+
readonly: true
|
|
3025
|
+
})
|
|
3026
|
+
},
|
|
3027
|
+
indexes: [
|
|
3028
|
+
{ fields: ["metadata_id", "version"], unique: true },
|
|
3029
|
+
{ fields: ["metadata_id", "recorded_at"] },
|
|
3030
|
+
{ fields: ["type", "name"] },
|
|
3031
|
+
{ fields: ["recorded_at"] },
|
|
3032
|
+
{ fields: ["operation_type"] },
|
|
3033
|
+
{ fields: ["organization_id"] },
|
|
3034
|
+
{ fields: ["project_id"] }
|
|
3035
|
+
],
|
|
3036
|
+
enable: {
|
|
3037
|
+
trackHistory: false,
|
|
3038
|
+
// Don't track history of history records
|
|
3039
|
+
searchable: false,
|
|
3040
|
+
apiEnabled: true,
|
|
3041
|
+
apiMethods: ["get", "list"],
|
|
3042
|
+
// Read-only via API
|
|
3043
|
+
trash: false
|
|
3044
|
+
}
|
|
3045
|
+
});
|
|
3046
|
+
var SysObject = data.ObjectSchema.create({
|
|
3047
|
+
name: "sys_object",
|
|
3048
|
+
label: "Object Definition",
|
|
3049
|
+
pluralLabel: "Object Definitions",
|
|
3050
|
+
description: "Metadata for business objects",
|
|
3051
|
+
icon: "database",
|
|
3052
|
+
isSystem: true,
|
|
3053
|
+
fields: {
|
|
3054
|
+
// Core Identity
|
|
3055
|
+
name: data.Field.text({
|
|
3056
|
+
label: "Object Name",
|
|
3057
|
+
required: true,
|
|
3058
|
+
maxLength: 255,
|
|
3059
|
+
description: "Machine name (snake_case)"
|
|
3060
|
+
}),
|
|
3061
|
+
project_id: data.Field.text({
|
|
3062
|
+
label: "Environment ID",
|
|
3063
|
+
maxLength: 255,
|
|
3064
|
+
description: "Project/environment scope \u2014 null = control-plane global"
|
|
3065
|
+
}),
|
|
3066
|
+
label: data.Field.text({
|
|
3067
|
+
label: "Display Label",
|
|
3068
|
+
required: true,
|
|
3069
|
+
maxLength: 255
|
|
3070
|
+
}),
|
|
3071
|
+
plural_label: data.Field.text({
|
|
3072
|
+
label: "Plural Label",
|
|
3073
|
+
maxLength: 255
|
|
3074
|
+
}),
|
|
3075
|
+
description: data.Field.textarea({
|
|
3076
|
+
label: "Description"
|
|
3077
|
+
}),
|
|
3078
|
+
icon: data.Field.text({
|
|
3079
|
+
label: "Icon",
|
|
3080
|
+
maxLength: 100
|
|
3081
|
+
}),
|
|
3082
|
+
// Classification
|
|
3083
|
+
namespace: data.Field.text({
|
|
3084
|
+
label: "Namespace",
|
|
3085
|
+
maxLength: 100,
|
|
3086
|
+
description: "Logical domain namespace"
|
|
3087
|
+
}),
|
|
3088
|
+
tags: data.Field.text({
|
|
3089
|
+
label: "Tags",
|
|
3090
|
+
description: "Comma-separated categorization tags"
|
|
3091
|
+
}),
|
|
3092
|
+
active: data.Field.boolean({
|
|
3093
|
+
label: "Active",
|
|
3094
|
+
defaultValue: true
|
|
3095
|
+
}),
|
|
3096
|
+
is_system: data.Field.boolean({
|
|
3097
|
+
label: "System Object",
|
|
3098
|
+
defaultValue: false,
|
|
3099
|
+
description: "Protected from deletion"
|
|
3100
|
+
}),
|
|
3101
|
+
abstract: data.Field.boolean({
|
|
3102
|
+
label: "Abstract",
|
|
3103
|
+
defaultValue: false,
|
|
3104
|
+
description: "Cannot be instantiated"
|
|
3105
|
+
}),
|
|
3106
|
+
// Storage
|
|
3107
|
+
datasource: data.Field.text({
|
|
3108
|
+
label: "Datasource",
|
|
3109
|
+
maxLength: 100,
|
|
3110
|
+
defaultValue: "default"
|
|
3111
|
+
}),
|
|
3112
|
+
table_name: data.Field.text({
|
|
3113
|
+
label: "Table Name",
|
|
3114
|
+
maxLength: 255,
|
|
3115
|
+
description: "Physical table/collection name"
|
|
3116
|
+
}),
|
|
3117
|
+
// Complex Data (stored as JSON)
|
|
3118
|
+
fields_json: data.Field.textarea({
|
|
3119
|
+
label: "Fields (JSON)",
|
|
3120
|
+
description: "Field definitions as JSON"
|
|
3121
|
+
}),
|
|
3122
|
+
indexes_json: data.Field.textarea({
|
|
3123
|
+
label: "Indexes (JSON)",
|
|
3124
|
+
description: "Index definitions as JSON"
|
|
3125
|
+
}),
|
|
3126
|
+
validations_json: data.Field.textarea({
|
|
3127
|
+
label: "Validations (JSON)",
|
|
3128
|
+
description: "Validation rules as JSON"
|
|
3129
|
+
}),
|
|
3130
|
+
state_machines_json: data.Field.textarea({
|
|
3131
|
+
label: "State Machines (JSON)",
|
|
3132
|
+
description: "State machine definitions as JSON"
|
|
3133
|
+
}),
|
|
3134
|
+
capabilities_json: data.Field.textarea({
|
|
3135
|
+
label: "Capabilities (JSON)",
|
|
3136
|
+
description: "Enabled system features as JSON"
|
|
3137
|
+
}),
|
|
3138
|
+
// Denormalized Fields
|
|
3139
|
+
field_count: data.Field.number({
|
|
3140
|
+
label: "Field Count",
|
|
3141
|
+
description: "Number of fields defined"
|
|
3142
|
+
}),
|
|
3143
|
+
// Display
|
|
3144
|
+
display_name_field: data.Field.text({
|
|
3145
|
+
label: "Display Name Field",
|
|
3146
|
+
maxLength: 100,
|
|
3147
|
+
description: "Field to use as record display name"
|
|
3148
|
+
}),
|
|
3149
|
+
title_format: data.Field.text({
|
|
3150
|
+
label: "Title Format",
|
|
3151
|
+
maxLength: 255,
|
|
3152
|
+
description: "Title expression template"
|
|
3153
|
+
}),
|
|
3154
|
+
compact_layout: data.Field.text({
|
|
3155
|
+
label: "Compact Layout",
|
|
3156
|
+
description: "Comma-separated field names for cards"
|
|
3157
|
+
}),
|
|
3158
|
+
// Capabilities
|
|
3159
|
+
track_history: data.Field.boolean({
|
|
3160
|
+
label: "Track History",
|
|
3161
|
+
defaultValue: false
|
|
3162
|
+
}),
|
|
3163
|
+
searchable: data.Field.boolean({
|
|
3164
|
+
label: "Searchable",
|
|
3165
|
+
defaultValue: true
|
|
3166
|
+
}),
|
|
3167
|
+
api_enabled: data.Field.boolean({
|
|
3168
|
+
label: "API Enabled",
|
|
3169
|
+
defaultValue: true
|
|
3170
|
+
}),
|
|
3171
|
+
files: data.Field.boolean({
|
|
3172
|
+
label: "Files",
|
|
3173
|
+
defaultValue: false
|
|
3174
|
+
}),
|
|
3175
|
+
feeds: data.Field.boolean({
|
|
3176
|
+
label: "Feeds",
|
|
3177
|
+
defaultValue: false
|
|
3178
|
+
}),
|
|
3179
|
+
activities: data.Field.boolean({
|
|
3180
|
+
label: "Activities",
|
|
3181
|
+
defaultValue: false
|
|
3182
|
+
}),
|
|
3183
|
+
trash: data.Field.boolean({
|
|
3184
|
+
label: "Trash",
|
|
3185
|
+
defaultValue: true
|
|
3186
|
+
}),
|
|
3187
|
+
mru: data.Field.boolean({
|
|
3188
|
+
label: "MRU",
|
|
3189
|
+
defaultValue: true
|
|
3190
|
+
}),
|
|
3191
|
+
clone: data.Field.boolean({
|
|
3192
|
+
label: "Clone",
|
|
3193
|
+
defaultValue: true
|
|
3194
|
+
}),
|
|
3195
|
+
// Package Management
|
|
3196
|
+
package_id: data.Field.lookup("sys_package", {
|
|
3197
|
+
label: "Package"
|
|
3198
|
+
}),
|
|
3199
|
+
managed_by: data.Field.select({
|
|
3200
|
+
label: "Managed By",
|
|
3201
|
+
options: [
|
|
3202
|
+
{ value: "package", label: "Package" },
|
|
3203
|
+
{ value: "platform", label: "Platform" },
|
|
3204
|
+
{ value: "user", label: "User" }
|
|
3205
|
+
]
|
|
3206
|
+
}),
|
|
3207
|
+
// Audit
|
|
3208
|
+
created_by: data.Field.lookup("sys_user", { label: "Created By" }),
|
|
3209
|
+
created_at: data.Field.datetime({ label: "Created At" }),
|
|
3210
|
+
updated_by: data.Field.lookup("sys_user", { label: "Updated By" }),
|
|
3211
|
+
updated_at: data.Field.datetime({ label: "Updated At" })
|
|
3212
|
+
},
|
|
3213
|
+
indexes: [
|
|
3214
|
+
{ fields: ["name", "project_id"], unique: true },
|
|
3215
|
+
{ fields: ["project_id"] },
|
|
3216
|
+
{ fields: ["namespace"] },
|
|
3217
|
+
{ fields: ["package_id"] },
|
|
3218
|
+
{ fields: ["active"] },
|
|
3219
|
+
{ fields: ["is_system"] }
|
|
3220
|
+
],
|
|
3221
|
+
enable: {
|
|
3222
|
+
trackHistory: true,
|
|
3223
|
+
searchable: true,
|
|
3224
|
+
apiEnabled: true,
|
|
3225
|
+
trash: true,
|
|
3226
|
+
mru: true
|
|
3227
|
+
}
|
|
3228
|
+
});
|
|
3229
|
+
var SysView = data.ObjectSchema.create({
|
|
3230
|
+
name: "sys_view",
|
|
3231
|
+
label: "View Definition",
|
|
3232
|
+
pluralLabel: "View Definitions",
|
|
3233
|
+
description: "Metadata for UI views (grid, kanban, calendar, etc.)",
|
|
3234
|
+
icon: "layout-grid",
|
|
3235
|
+
isSystem: true,
|
|
3236
|
+
fields: {
|
|
3237
|
+
// Core Identity
|
|
3238
|
+
name: data.Field.text({
|
|
3239
|
+
label: "View Name",
|
|
3240
|
+
required: true,
|
|
3241
|
+
maxLength: 255
|
|
3242
|
+
}),
|
|
3243
|
+
project_id: data.Field.text({
|
|
3244
|
+
label: "Environment ID",
|
|
3245
|
+
maxLength: 255,
|
|
3246
|
+
description: "Project/environment scope \u2014 null = control-plane global"
|
|
3247
|
+
}),
|
|
3248
|
+
label: data.Field.text({
|
|
3249
|
+
label: "Display Label",
|
|
3250
|
+
required: true,
|
|
3251
|
+
maxLength: 255
|
|
3252
|
+
}),
|
|
3253
|
+
description: data.Field.textarea({
|
|
3254
|
+
label: "Description"
|
|
3255
|
+
}),
|
|
3256
|
+
// Reference to Object
|
|
3257
|
+
object_name: data.Field.text({
|
|
3258
|
+
label: "Object Name",
|
|
3259
|
+
required: true,
|
|
3260
|
+
maxLength: 255,
|
|
3261
|
+
description: "The object this view displays"
|
|
3262
|
+
}),
|
|
3263
|
+
// View Type
|
|
3264
|
+
view_type: data.Field.select({
|
|
3265
|
+
label: "View Type",
|
|
3266
|
+
required: true,
|
|
3267
|
+
options: [
|
|
3268
|
+
{ value: "grid", label: "Grid" },
|
|
3269
|
+
{ value: "kanban", label: "Kanban" },
|
|
3270
|
+
{ value: "calendar", label: "Calendar" },
|
|
3271
|
+
{ value: "gantt", label: "Gantt" },
|
|
3272
|
+
{ value: "form", label: "Form" },
|
|
3273
|
+
{ value: "timeline", label: "Timeline" }
|
|
3274
|
+
]
|
|
3275
|
+
}),
|
|
3276
|
+
// Complex Configuration
|
|
3277
|
+
columns_json: data.Field.textarea({
|
|
3278
|
+
label: "Columns (JSON)",
|
|
3279
|
+
description: "Column definitions as JSON"
|
|
3280
|
+
}),
|
|
3281
|
+
filters_json: data.Field.textarea({
|
|
3282
|
+
label: "Filters (JSON)",
|
|
3283
|
+
description: "Filter definitions as JSON"
|
|
3284
|
+
}),
|
|
3285
|
+
sort_json: data.Field.textarea({
|
|
3286
|
+
label: "Sort (JSON)",
|
|
3287
|
+
description: "Sort configuration as JSON"
|
|
3288
|
+
}),
|
|
3289
|
+
config_json: data.Field.textarea({
|
|
3290
|
+
label: "Configuration (JSON)",
|
|
3291
|
+
description: "View-specific configuration as JSON"
|
|
3292
|
+
}),
|
|
3293
|
+
// Display Options
|
|
3294
|
+
page_size: data.Field.number({
|
|
3295
|
+
label: "Page Size",
|
|
3296
|
+
defaultValue: 25,
|
|
3297
|
+
min: 1,
|
|
3298
|
+
max: 200
|
|
3299
|
+
}),
|
|
3300
|
+
show_search: data.Field.boolean({
|
|
3301
|
+
label: "Show Search",
|
|
3302
|
+
defaultValue: true
|
|
3303
|
+
}),
|
|
3304
|
+
show_filters: data.Field.boolean({
|
|
3305
|
+
label: "Show Filters",
|
|
3306
|
+
defaultValue: true
|
|
3307
|
+
}),
|
|
3308
|
+
// Classification
|
|
3309
|
+
namespace: data.Field.text({
|
|
3310
|
+
label: "Namespace",
|
|
3311
|
+
maxLength: 100
|
|
3312
|
+
}),
|
|
3313
|
+
// Package Management
|
|
3314
|
+
package_id: data.Field.lookup("sys_package", {
|
|
3315
|
+
label: "Package"
|
|
3316
|
+
}),
|
|
3317
|
+
managed_by: data.Field.select({
|
|
3318
|
+
label: "Managed By",
|
|
3319
|
+
options: [
|
|
3320
|
+
{ value: "package", label: "Package" },
|
|
3321
|
+
{ value: "platform", label: "Platform" },
|
|
3322
|
+
{ value: "user", label: "User" }
|
|
3323
|
+
]
|
|
3324
|
+
}),
|
|
3325
|
+
// Audit
|
|
3326
|
+
created_by: data.Field.lookup("sys_user", { label: "Created By" }),
|
|
3327
|
+
created_at: data.Field.datetime({ label: "Created At" }),
|
|
3328
|
+
updated_by: data.Field.lookup("sys_user", { label: "Updated By" }),
|
|
3329
|
+
updated_at: data.Field.datetime({ label: "Updated At" })
|
|
3330
|
+
},
|
|
3331
|
+
indexes: [
|
|
3332
|
+
{ fields: ["name", "project_id"], unique: true },
|
|
3333
|
+
{ fields: ["project_id"] },
|
|
3334
|
+
{ fields: ["object_name"] },
|
|
3335
|
+
{ fields: ["view_type"] },
|
|
3336
|
+
{ fields: ["namespace"] },
|
|
3337
|
+
{ fields: ["package_id"] }
|
|
3338
|
+
],
|
|
3339
|
+
enable: {
|
|
3340
|
+
trackHistory: true,
|
|
3341
|
+
searchable: true,
|
|
3342
|
+
apiEnabled: true,
|
|
3343
|
+
trash: true,
|
|
3344
|
+
mru: true
|
|
3345
|
+
}
|
|
3346
|
+
});
|
|
3347
|
+
var SysAgent = data.ObjectSchema.create({
|
|
3348
|
+
name: "sys_agent",
|
|
3349
|
+
label: "AI Agent",
|
|
3350
|
+
pluralLabel: "AI Agents",
|
|
3351
|
+
description: "AI agent definitions",
|
|
3352
|
+
icon: "bot",
|
|
3353
|
+
isSystem: true,
|
|
3354
|
+
fields: {
|
|
3355
|
+
// Core Identity
|
|
3356
|
+
name: data.Field.text({
|
|
3357
|
+
label: "Agent Name",
|
|
3358
|
+
required: true,
|
|
3359
|
+
maxLength: 255
|
|
3360
|
+
}),
|
|
3361
|
+
project_id: data.Field.text({
|
|
3362
|
+
label: "Environment ID",
|
|
3363
|
+
maxLength: 255,
|
|
3364
|
+
description: "Project/environment scope \u2014 null = control-plane global"
|
|
3365
|
+
}),
|
|
3366
|
+
label: data.Field.text({
|
|
3367
|
+
label: "Display Label",
|
|
3368
|
+
required: true,
|
|
3369
|
+
maxLength: 255
|
|
3370
|
+
}),
|
|
3371
|
+
description: data.Field.textarea({
|
|
3372
|
+
label: "Description"
|
|
3373
|
+
}),
|
|
3374
|
+
// Agent Type
|
|
3375
|
+
agent_type: data.Field.select({
|
|
3376
|
+
label: "Agent Type",
|
|
3377
|
+
options: [
|
|
3378
|
+
{ value: "conversational", label: "Conversational" },
|
|
3379
|
+
{ value: "task", label: "Task-Based" },
|
|
3380
|
+
{ value: "analytical", label: "Analytical" },
|
|
3381
|
+
{ value: "workflow", label: "Workflow" }
|
|
3382
|
+
]
|
|
3383
|
+
}),
|
|
3384
|
+
// Model Configuration
|
|
3385
|
+
model: data.Field.text({
|
|
3386
|
+
label: "Model ID",
|
|
3387
|
+
maxLength: 255,
|
|
3388
|
+
description: "AI model identifier"
|
|
3389
|
+
}),
|
|
3390
|
+
temperature: data.Field.number({
|
|
3391
|
+
label: "Temperature",
|
|
3392
|
+
min: 0,
|
|
3393
|
+
max: 2,
|
|
3394
|
+
defaultValue: 0.7
|
|
3395
|
+
}),
|
|
3396
|
+
max_tokens: data.Field.number({
|
|
3397
|
+
label: "Max Tokens",
|
|
3398
|
+
min: 1,
|
|
3399
|
+
max: 1e5
|
|
3400
|
+
}),
|
|
3401
|
+
top_p: data.Field.number({
|
|
3402
|
+
label: "Top P",
|
|
3403
|
+
min: 0,
|
|
3404
|
+
max: 1
|
|
3405
|
+
}),
|
|
3406
|
+
// System Prompt
|
|
3407
|
+
system_prompt: data.Field.textarea({
|
|
3408
|
+
label: "System Prompt",
|
|
3409
|
+
description: "Instructions for the AI agent"
|
|
3410
|
+
}),
|
|
3411
|
+
// Tools Configuration
|
|
3412
|
+
tools_json: data.Field.textarea({
|
|
3413
|
+
label: "Tools (JSON)",
|
|
3414
|
+
description: "Available tools as JSON array"
|
|
3415
|
+
}),
|
|
3416
|
+
// Skills Configuration
|
|
3417
|
+
skills_json: data.Field.textarea({
|
|
3418
|
+
label: "Skills (JSON)",
|
|
3419
|
+
description: "Available skills as JSON array"
|
|
3420
|
+
}),
|
|
3421
|
+
// Memory Configuration
|
|
3422
|
+
memory_enabled: data.Field.boolean({
|
|
3423
|
+
label: "Memory Enabled",
|
|
3424
|
+
defaultValue: false
|
|
3425
|
+
}),
|
|
3426
|
+
memory_window: data.Field.number({
|
|
3427
|
+
label: "Memory Window",
|
|
3428
|
+
description: "Number of conversation turns to remember",
|
|
3429
|
+
defaultValue: 10
|
|
3430
|
+
}),
|
|
3431
|
+
// Classification
|
|
3432
|
+
namespace: data.Field.text({
|
|
3433
|
+
label: "Namespace",
|
|
3434
|
+
maxLength: 100
|
|
3435
|
+
}),
|
|
3436
|
+
// Package Management
|
|
3437
|
+
package_id: data.Field.lookup("sys_package", {
|
|
3438
|
+
label: "Package"
|
|
3439
|
+
}),
|
|
3440
|
+
managed_by: data.Field.select({
|
|
3441
|
+
label: "Managed By",
|
|
3442
|
+
options: [
|
|
3443
|
+
{ value: "package", label: "Package" },
|
|
3444
|
+
{ value: "platform", label: "Platform" },
|
|
3445
|
+
{ value: "user", label: "User" }
|
|
3446
|
+
]
|
|
3447
|
+
}),
|
|
3448
|
+
// Audit
|
|
3449
|
+
created_by: data.Field.lookup("sys_user", { label: "Created By" }),
|
|
3450
|
+
created_at: data.Field.datetime({ label: "Created At" }),
|
|
3451
|
+
updated_by: data.Field.lookup("sys_user", { label: "Updated By" }),
|
|
3452
|
+
updated_at: data.Field.datetime({ label: "Updated At" })
|
|
3453
|
+
},
|
|
3454
|
+
indexes: [
|
|
3455
|
+
{ fields: ["name", "project_id"], unique: true },
|
|
3456
|
+
{ fields: ["project_id"] },
|
|
3457
|
+
{ fields: ["agent_type"] },
|
|
3458
|
+
{ fields: ["namespace"] },
|
|
3459
|
+
{ fields: ["package_id"] }
|
|
3460
|
+
],
|
|
3461
|
+
enable: {
|
|
3462
|
+
trackHistory: true,
|
|
3463
|
+
searchable: true,
|
|
3464
|
+
apiEnabled: true,
|
|
3465
|
+
trash: true,
|
|
3466
|
+
mru: true
|
|
3467
|
+
}
|
|
3468
|
+
});
|
|
3469
|
+
var SysTool = data.ObjectSchema.create({
|
|
3470
|
+
name: "sys_tool",
|
|
3471
|
+
label: "AI Tool",
|
|
3472
|
+
pluralLabel: "AI Tools",
|
|
3473
|
+
description: "AI tool definitions",
|
|
3474
|
+
icon: "wrench",
|
|
3475
|
+
isSystem: true,
|
|
3476
|
+
fields: {
|
|
3477
|
+
// Core Identity
|
|
3478
|
+
name: data.Field.text({
|
|
3479
|
+
label: "Tool Name",
|
|
3480
|
+
required: true,
|
|
3481
|
+
maxLength: 255
|
|
3482
|
+
}),
|
|
3483
|
+
project_id: data.Field.text({
|
|
3484
|
+
label: "Environment ID",
|
|
3485
|
+
maxLength: 255,
|
|
3486
|
+
description: "Project/environment scope \u2014 null = control-plane global"
|
|
3487
|
+
}),
|
|
3488
|
+
label: data.Field.text({
|
|
3489
|
+
label: "Display Label",
|
|
3490
|
+
required: true,
|
|
3491
|
+
maxLength: 255
|
|
3492
|
+
}),
|
|
3493
|
+
description: data.Field.textarea({
|
|
3494
|
+
label: "Description",
|
|
3495
|
+
required: true
|
|
3496
|
+
}),
|
|
3497
|
+
// Parameters
|
|
3498
|
+
parameters_json: data.Field.textarea({
|
|
3499
|
+
label: "Parameters (JSON)",
|
|
3500
|
+
description: "Tool parameter schema as JSON"
|
|
3501
|
+
}),
|
|
3502
|
+
// Implementation
|
|
3503
|
+
handler_code: data.Field.textarea({
|
|
3504
|
+
label: "Handler Code",
|
|
3505
|
+
description: "Tool implementation code"
|
|
3506
|
+
}),
|
|
3507
|
+
// Classification
|
|
3508
|
+
namespace: data.Field.text({
|
|
3509
|
+
label: "Namespace",
|
|
3510
|
+
maxLength: 100
|
|
3511
|
+
}),
|
|
3512
|
+
// Package Management
|
|
3513
|
+
package_id: data.Field.lookup("sys_package", {
|
|
3514
|
+
label: "Package"
|
|
3515
|
+
}),
|
|
3516
|
+
managed_by: data.Field.select({
|
|
3517
|
+
label: "Managed By",
|
|
3518
|
+
options: [
|
|
3519
|
+
{ value: "package", label: "Package" },
|
|
3520
|
+
{ value: "platform", label: "Platform" },
|
|
3521
|
+
{ value: "user", label: "User" }
|
|
3522
|
+
]
|
|
3523
|
+
}),
|
|
3524
|
+
// Audit
|
|
3525
|
+
created_by: data.Field.lookup("sys_user", { label: "Created By" }),
|
|
3526
|
+
created_at: data.Field.datetime({ label: "Created At" }),
|
|
3527
|
+
updated_by: data.Field.lookup("sys_user", { label: "Updated By" }),
|
|
3528
|
+
updated_at: data.Field.datetime({ label: "Updated At" })
|
|
3529
|
+
},
|
|
3530
|
+
indexes: [
|
|
3531
|
+
{ fields: ["name", "project_id"], unique: true },
|
|
3532
|
+
{ fields: ["project_id"] },
|
|
3533
|
+
{ fields: ["namespace"] },
|
|
3534
|
+
{ fields: ["package_id"] }
|
|
3535
|
+
],
|
|
3536
|
+
enable: {
|
|
3537
|
+
trackHistory: true,
|
|
3538
|
+
searchable: true,
|
|
3539
|
+
apiEnabled: true,
|
|
3540
|
+
trash: true,
|
|
3541
|
+
mru: true
|
|
3542
|
+
}
|
|
3543
|
+
});
|
|
3544
|
+
var SysFlow = data.ObjectSchema.create({
|
|
3545
|
+
name: "sys_flow",
|
|
3546
|
+
label: "Flow",
|
|
3547
|
+
pluralLabel: "Flows",
|
|
3548
|
+
description: "Visual logic flow definitions",
|
|
3549
|
+
icon: "workflow",
|
|
3550
|
+
isSystem: true,
|
|
3551
|
+
fields: {
|
|
3552
|
+
// Core Identity
|
|
3553
|
+
name: data.Field.text({
|
|
3554
|
+
label: "Flow Name",
|
|
3555
|
+
required: true,
|
|
3556
|
+
maxLength: 255
|
|
3557
|
+
}),
|
|
3558
|
+
project_id: data.Field.text({
|
|
3559
|
+
label: "Environment ID",
|
|
3560
|
+
maxLength: 255,
|
|
3561
|
+
description: "Project/environment scope \u2014 null = control-plane global"
|
|
3562
|
+
}),
|
|
3563
|
+
label: data.Field.text({
|
|
3564
|
+
label: "Display Label",
|
|
3565
|
+
required: true,
|
|
3566
|
+
maxLength: 255
|
|
3567
|
+
}),
|
|
3568
|
+
description: data.Field.textarea({
|
|
3569
|
+
label: "Description"
|
|
3570
|
+
}),
|
|
3571
|
+
// Flow Type
|
|
3572
|
+
flow_type: data.Field.select({
|
|
3573
|
+
label: "Flow Type",
|
|
3574
|
+
required: true,
|
|
3575
|
+
options: [
|
|
3576
|
+
{ value: "autolaunched", label: "Autolaunched" },
|
|
3577
|
+
{ value: "screen", label: "Screen Flow" },
|
|
3578
|
+
{ value: "schedule", label: "Scheduled" },
|
|
3579
|
+
{ value: "trigger", label: "Trigger-Based" }
|
|
3580
|
+
]
|
|
3581
|
+
}),
|
|
3582
|
+
// Flow Definition
|
|
3583
|
+
nodes_json: data.Field.textarea({
|
|
3584
|
+
label: "Nodes (JSON)",
|
|
3585
|
+
description: "Flow nodes as JSON"
|
|
3586
|
+
}),
|
|
3587
|
+
edges_json: data.Field.textarea({
|
|
3588
|
+
label: "Edges (JSON)",
|
|
3589
|
+
description: "Flow edges as JSON"
|
|
3590
|
+
}),
|
|
3591
|
+
variables_json: data.Field.textarea({
|
|
3592
|
+
label: "Variables (JSON)",
|
|
3593
|
+
description: "Flow variables as JSON"
|
|
3594
|
+
}),
|
|
3595
|
+
// Trigger Configuration
|
|
3596
|
+
trigger_type: data.Field.select({
|
|
3597
|
+
label: "Trigger Type",
|
|
3598
|
+
options: [
|
|
3599
|
+
{ value: "record_created", label: "Record Created" },
|
|
3600
|
+
{ value: "record_updated", label: "Record Updated" },
|
|
3601
|
+
{ value: "record_deleted", label: "Record Deleted" },
|
|
3602
|
+
{ value: "schedule", label: "Schedule" },
|
|
3603
|
+
{ value: "platform_event", label: "Platform Event" }
|
|
3604
|
+
]
|
|
3605
|
+
}),
|
|
3606
|
+
trigger_object: data.Field.text({
|
|
3607
|
+
label: "Trigger Object",
|
|
3608
|
+
maxLength: 255
|
|
3609
|
+
}),
|
|
3610
|
+
// Status
|
|
3611
|
+
active: data.Field.boolean({
|
|
3612
|
+
label: "Active",
|
|
3613
|
+
defaultValue: false
|
|
3614
|
+
}),
|
|
3615
|
+
// Classification
|
|
3616
|
+
namespace: data.Field.text({
|
|
3617
|
+
label: "Namespace",
|
|
3618
|
+
maxLength: 100
|
|
3619
|
+
}),
|
|
3620
|
+
// Package Management
|
|
3621
|
+
package_id: data.Field.lookup("sys_package", {
|
|
3622
|
+
label: "Package"
|
|
3623
|
+
}),
|
|
3624
|
+
managed_by: data.Field.select({
|
|
3625
|
+
label: "Managed By",
|
|
3626
|
+
options: [
|
|
3627
|
+
{ value: "package", label: "Package" },
|
|
3628
|
+
{ value: "platform", label: "Platform" },
|
|
3629
|
+
{ value: "user", label: "User" }
|
|
3630
|
+
]
|
|
3631
|
+
}),
|
|
3632
|
+
// Audit
|
|
3633
|
+
created_by: data.Field.lookup("sys_user", { label: "Created By" }),
|
|
3634
|
+
created_at: data.Field.datetime({ label: "Created At" }),
|
|
3635
|
+
updated_by: data.Field.lookup("sys_user", { label: "Updated By" }),
|
|
3636
|
+
updated_at: data.Field.datetime({ label: "Updated At" })
|
|
3637
|
+
},
|
|
3638
|
+
indexes: [
|
|
3639
|
+
{ fields: ["name", "project_id"], unique: true },
|
|
3640
|
+
{ fields: ["project_id"] },
|
|
3641
|
+
{ fields: ["flow_type"] },
|
|
3642
|
+
{ fields: ["active"] },
|
|
3643
|
+
{ fields: ["namespace"] },
|
|
3644
|
+
{ fields: ["package_id"] }
|
|
3645
|
+
],
|
|
3646
|
+
enable: {
|
|
3647
|
+
trackHistory: true,
|
|
3648
|
+
searchable: true,
|
|
3649
|
+
apiEnabled: true,
|
|
3650
|
+
trash: true,
|
|
3651
|
+
mru: true
|
|
3652
|
+
}
|
|
3653
|
+
});
|
|
3654
|
+
|
|
3655
|
+
// src/apps/setup.app.ts
|
|
3656
|
+
var SETUP_APP = {
|
|
3657
|
+
name: "setup",
|
|
3658
|
+
label: "Setup",
|
|
3659
|
+
description: "Platform settings and administration",
|
|
3660
|
+
icon: "settings",
|
|
3661
|
+
active: true,
|
|
3662
|
+
isDefault: false,
|
|
3663
|
+
branding: {
|
|
3664
|
+
primaryColor: "#475569"
|
|
3665
|
+
// Slate-600 — neutral admin palette
|
|
3666
|
+
},
|
|
3667
|
+
requiredPermissions: ["setup.access"],
|
|
3668
|
+
navigation: [
|
|
3669
|
+
{
|
|
3670
|
+
id: "group_overview",
|
|
3671
|
+
type: "group",
|
|
3672
|
+
label: "Overview",
|
|
3673
|
+
icon: "layout-dashboard",
|
|
3674
|
+
children: [
|
|
3675
|
+
{ id: "nav_system_overview", type: "dashboard", label: "System Overview", dashboardName: "system_overview", icon: "activity" },
|
|
3676
|
+
{ id: "nav_security_overview", type: "dashboard", label: "Security Overview", dashboardName: "security_overview", icon: "shield" }
|
|
3677
|
+
]
|
|
3678
|
+
},
|
|
3679
|
+
{
|
|
3680
|
+
id: "group_administration",
|
|
3681
|
+
type: "group",
|
|
3682
|
+
label: "Administration",
|
|
3683
|
+
icon: "shield",
|
|
3684
|
+
children: [
|
|
3685
|
+
{ id: "nav_users", type: "object", label: "Users", objectName: "sys_user", icon: "users" },
|
|
3686
|
+
{ id: "nav_organizations", type: "object", label: "Organizations", objectName: "sys_organization", icon: "building-2" },
|
|
3687
|
+
{ id: "nav_teams", type: "object", label: "Teams", objectName: "sys_team", icon: "users-round" },
|
|
3688
|
+
{ id: "nav_api_keys", type: "object", label: "API Keys", objectName: "sys_api_key", icon: "key" },
|
|
3689
|
+
{ id: "nav_roles", type: "object", label: "Roles", objectName: "sys_role", icon: "shield-check" },
|
|
3690
|
+
{ id: "nav_permission_sets", type: "object", label: "Permission Sets", objectName: "sys_permission_set", icon: "lock" },
|
|
3691
|
+
{ id: "nav_oauth_apps", type: "object", label: "OAuth Apps", objectName: "sys_oauth_application", icon: "app-window" },
|
|
3692
|
+
{ id: "nav_jwks", type: "object", label: "Signing Keys", objectName: "sys_jwks", icon: "key-round" }
|
|
3693
|
+
]
|
|
3694
|
+
},
|
|
3695
|
+
{
|
|
3696
|
+
id: "group_platform",
|
|
3697
|
+
type: "group",
|
|
3698
|
+
label: "Platform",
|
|
3699
|
+
icon: "layers",
|
|
3700
|
+
children: [
|
|
3701
|
+
{ id: "nav_objects", type: "object", label: "Objects", objectName: "sys_object", icon: "database" },
|
|
3702
|
+
{ id: "nav_views", type: "object", label: "Views", objectName: "sys_view", icon: "table" },
|
|
3703
|
+
{ id: "nav_flows", type: "object", label: "Flows", objectName: "sys_flow", icon: "workflow" },
|
|
3704
|
+
{ id: "nav_agents", type: "object", label: "AI Agents", objectName: "sys_agent", icon: "bot" },
|
|
3705
|
+
{ id: "nav_tools", type: "object", label: "AI Tools", objectName: "sys_tool", icon: "wrench" },
|
|
3706
|
+
{ id: "nav_apps", type: "object", label: "Apps", objectName: "sys_app", icon: "layout-grid" },
|
|
3707
|
+
{ id: "nav_packages", type: "object", label: "Packages", objectName: "sys_package", icon: "package" },
|
|
3708
|
+
{ id: "nav_package_installations", type: "object", label: "Installations", objectName: "sys_package_installation", icon: "package-check" },
|
|
3709
|
+
{ id: "nav_metadata", type: "object", label: "All Metadata", objectName: "sys_metadata", icon: "file-cog" }
|
|
3710
|
+
]
|
|
3711
|
+
},
|
|
3712
|
+
{
|
|
3713
|
+
id: "group_system",
|
|
3714
|
+
type: "group",
|
|
3715
|
+
label: "System",
|
|
3716
|
+
icon: "settings",
|
|
3717
|
+
children: [
|
|
3718
|
+
{ id: "nav_sessions", type: "object", label: "Sessions", objectName: "sys_session", icon: "monitor" },
|
|
3719
|
+
{ id: "nav_audit_logs", type: "object", label: "Audit Logs", objectName: "sys_audit_log", icon: "scroll-text" },
|
|
3720
|
+
{ id: "nav_activity", type: "object", label: "Activity", objectName: "sys_activity", icon: "activity" },
|
|
3721
|
+
{ id: "nav_comments", type: "object", label: "Comments", objectName: "sys_comment", icon: "message-square" }
|
|
3722
|
+
]
|
|
3723
|
+
}
|
|
3724
|
+
]
|
|
3725
|
+
};
|
|
3726
|
+
|
|
3727
|
+
// src/apps/views/users.view.ts
|
|
3728
|
+
var UsersView = {
|
|
3729
|
+
name: "users",
|
|
3730
|
+
label: "Users",
|
|
3731
|
+
type: "grid",
|
|
3732
|
+
data: {
|
|
3733
|
+
provider: "object",
|
|
3734
|
+
object: "sys_user"
|
|
3735
|
+
},
|
|
3736
|
+
columns: [
|
|
3737
|
+
{ field: "name", label: "Name", sortable: true },
|
|
3738
|
+
{ field: "email", label: "Email", sortable: true },
|
|
3739
|
+
{ field: "phone", label: "Phone" },
|
|
3740
|
+
{ field: "status", label: "Status", sortable: true },
|
|
3741
|
+
{ field: "active", label: "Active", sortable: true },
|
|
3742
|
+
{ field: "created_at", label: "Created", sortable: true }
|
|
3743
|
+
],
|
|
3744
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
3745
|
+
filter: [],
|
|
3746
|
+
searchableFields: ["name", "email"],
|
|
3747
|
+
pagination: {
|
|
3748
|
+
pageSize: 20
|
|
3749
|
+
}
|
|
3750
|
+
};
|
|
3751
|
+
|
|
3752
|
+
// src/apps/views/organizations.view.ts
|
|
3753
|
+
var OrganizationsView = {
|
|
3754
|
+
name: "organizations",
|
|
3755
|
+
label: "Organizations",
|
|
3756
|
+
type: "grid",
|
|
3757
|
+
data: {
|
|
3758
|
+
provider: "object",
|
|
3759
|
+
object: "sys_organization"
|
|
3760
|
+
},
|
|
3761
|
+
columns: [
|
|
3762
|
+
{ field: "name", label: "Name", sortable: true },
|
|
3763
|
+
{ field: "status", label: "Status", sortable: true },
|
|
3764
|
+
{ field: "plan_tier", label: "Plan Tier" },
|
|
3765
|
+
{ field: "member_count", label: "Members" },
|
|
3766
|
+
{ field: "created_at", label: "Created", sortable: true }
|
|
3767
|
+
],
|
|
3768
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
3769
|
+
filter: [],
|
|
3770
|
+
searchableFields: ["name"],
|
|
3771
|
+
pagination: {
|
|
3772
|
+
pageSize: 20
|
|
3773
|
+
}
|
|
3774
|
+
};
|
|
3775
|
+
|
|
3776
|
+
// src/apps/views/roles.view.ts
|
|
3777
|
+
var RolesView = {
|
|
3778
|
+
name: "roles",
|
|
3779
|
+
label: "Roles",
|
|
3780
|
+
type: "grid",
|
|
3781
|
+
data: {
|
|
3782
|
+
provider: "object",
|
|
3783
|
+
object: "sys_role"
|
|
3784
|
+
},
|
|
3785
|
+
columns: [
|
|
3786
|
+
{ field: "name", label: "Name", sortable: true },
|
|
3787
|
+
{ field: "description", label: "Description" },
|
|
3788
|
+
{ field: "is_system", label: "System Role" },
|
|
3789
|
+
{ field: "created_at", label: "Created", sortable: true }
|
|
3790
|
+
],
|
|
3791
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
3792
|
+
filter: [],
|
|
3793
|
+
searchableFields: ["name", "description"],
|
|
3794
|
+
pagination: {
|
|
3795
|
+
pageSize: 20
|
|
3796
|
+
}
|
|
3797
|
+
};
|
|
3798
|
+
|
|
3799
|
+
// src/apps/views/sessions.view.ts
|
|
3800
|
+
var SessionsView = {
|
|
3801
|
+
name: "sessions",
|
|
3802
|
+
label: "Sessions",
|
|
3803
|
+
type: "grid",
|
|
3804
|
+
data: {
|
|
3805
|
+
provider: "object",
|
|
3806
|
+
object: "sys_session"
|
|
3807
|
+
},
|
|
3808
|
+
columns: [
|
|
3809
|
+
{ field: "user_id", label: "User", sortable: true },
|
|
3810
|
+
{ field: "ip_address", label: "IP Address" },
|
|
3811
|
+
{ field: "created_at", label: "Created", sortable: true },
|
|
3812
|
+
{ field: "expires_at", label: "Expires", sortable: true }
|
|
3813
|
+
],
|
|
3814
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
3815
|
+
filter: [],
|
|
3816
|
+
searchableFields: ["user_id"],
|
|
3817
|
+
pagination: {
|
|
3818
|
+
pageSize: 20
|
|
3819
|
+
}
|
|
3820
|
+
};
|
|
3821
|
+
|
|
3822
|
+
// src/apps/views/audit_logs.view.ts
|
|
3823
|
+
var AuditLogsView = {
|
|
3824
|
+
name: "audit_logs",
|
|
3825
|
+
label: "Audit Logs",
|
|
3826
|
+
type: "grid",
|
|
3827
|
+
data: {
|
|
3828
|
+
provider: "object",
|
|
3829
|
+
object: "sys_audit_log"
|
|
3830
|
+
},
|
|
3831
|
+
columns: [
|
|
3832
|
+
{ field: "created_at", label: "Timestamp", sortable: true },
|
|
3833
|
+
{ field: "action", label: "Action", sortable: true },
|
|
3834
|
+
{ field: "user_id", label: "Actor" },
|
|
3835
|
+
{ field: "object_name", label: "Object" },
|
|
3836
|
+
{ field: "record_id", label: "Record ID" }
|
|
3837
|
+
],
|
|
3838
|
+
sort: [{ field: "created_at", order: "desc" }],
|
|
3839
|
+
filter: [],
|
|
3840
|
+
searchableFields: ["action", "object_name", "record_id"],
|
|
3841
|
+
pagination: {
|
|
3842
|
+
pageSize: 20
|
|
3843
|
+
}
|
|
3844
|
+
};
|
|
3845
|
+
|
|
3846
|
+
// src/apps/views/package_installations.view.ts
|
|
3847
|
+
var PackageInstallationsView = {
|
|
3848
|
+
name: "package_installations",
|
|
3849
|
+
label: "Package Installations",
|
|
3850
|
+
type: "grid",
|
|
3851
|
+
data: {
|
|
3852
|
+
provider: "object",
|
|
3853
|
+
object: "sys_package_installation"
|
|
3854
|
+
},
|
|
3855
|
+
columns: [
|
|
3856
|
+
{ field: "package_id", label: "Package", sortable: true },
|
|
3857
|
+
{ field: "project_id", label: "Project", sortable: true },
|
|
3858
|
+
{ field: "package_version_id", label: "Version" },
|
|
3859
|
+
{ field: "status", label: "Status", sortable: true },
|
|
3860
|
+
{ field: "installed_at", label: "Installed", sortable: true }
|
|
3861
|
+
],
|
|
3862
|
+
sort: [{ field: "installed_at", order: "desc" }],
|
|
3863
|
+
filter: [],
|
|
3864
|
+
searchableFields: ["package_id", "project_id"],
|
|
3865
|
+
pagination: {
|
|
3866
|
+
pageSize: 20
|
|
3867
|
+
}
|
|
3868
|
+
};
|
|
3869
|
+
var SystemOverviewDashboard = ui.Dashboard.create({
|
|
3870
|
+
name: "system_overview",
|
|
3871
|
+
label: "System Overview",
|
|
3872
|
+
description: "Platform health, sessions, and audit activity",
|
|
3873
|
+
// 12-column grid matches the widget `w` values below (3, 6, 12). Without
|
|
3874
|
+
// this, the renderer falls back to a 4-column grid and `w: 3` becomes 75%
|
|
3875
|
+
// width per metric — so KPI cards stack vertically instead of forming a
|
|
3876
|
+
// 4-up row.
|
|
3877
|
+
columns: 12,
|
|
3878
|
+
gap: 4,
|
|
3879
|
+
widgets: [
|
|
3880
|
+
// ── Active Sessions Widget ──────────────────────────────────────
|
|
3881
|
+
{
|
|
3882
|
+
id: "widget_active_sessions",
|
|
3883
|
+
title: "Active Sessions",
|
|
3884
|
+
type: "metric",
|
|
3885
|
+
object: "sys_session",
|
|
3886
|
+
layout: {
|
|
3887
|
+
x: 0,
|
|
3888
|
+
y: 0,
|
|
3889
|
+
w: 3,
|
|
3890
|
+
h: 2
|
|
3891
|
+
},
|
|
3892
|
+
aggregate: "count",
|
|
3893
|
+
colorVariant: "blue",
|
|
3894
|
+
description: "Number of currently active user sessions"
|
|
3895
|
+
},
|
|
3896
|
+
// ── Total Users Widget ──────────────────────────────────────────
|
|
3897
|
+
{
|
|
3898
|
+
id: "widget_total_users",
|
|
3899
|
+
title: "Total Users",
|
|
3900
|
+
type: "metric",
|
|
3901
|
+
object: "sys_user",
|
|
3902
|
+
layout: {
|
|
3903
|
+
x: 3,
|
|
3904
|
+
y: 0,
|
|
3905
|
+
w: 3,
|
|
3906
|
+
h: 2
|
|
3907
|
+
},
|
|
3908
|
+
aggregate: "count",
|
|
3909
|
+
colorVariant: "teal",
|
|
3910
|
+
description: "Total registered users in the system"
|
|
3911
|
+
},
|
|
3912
|
+
// ── Organizations Widget ────────────────────────────────────────
|
|
3913
|
+
{
|
|
3914
|
+
id: "widget_organizations",
|
|
3915
|
+
title: "Organizations",
|
|
3916
|
+
type: "metric",
|
|
3917
|
+
object: "sys_organization",
|
|
3918
|
+
layout: {
|
|
3919
|
+
x: 6,
|
|
3920
|
+
y: 0,
|
|
3921
|
+
w: 3,
|
|
3922
|
+
h: 2
|
|
3923
|
+
},
|
|
3924
|
+
aggregate: "count",
|
|
3925
|
+
colorVariant: "orange",
|
|
3926
|
+
description: "Total organizations on the platform"
|
|
3927
|
+
},
|
|
3928
|
+
// ── Packages Installed Widget ───────────────────────────────────
|
|
3929
|
+
{
|
|
3930
|
+
id: "widget_packages_installed",
|
|
3931
|
+
title: "Packages Installed",
|
|
3932
|
+
type: "metric",
|
|
3933
|
+
object: "sys_package_installation",
|
|
3934
|
+
layout: {
|
|
3935
|
+
x: 9,
|
|
3936
|
+
y: 0,
|
|
3937
|
+
w: 3,
|
|
3938
|
+
h: 2
|
|
3939
|
+
},
|
|
3940
|
+
filter: {
|
|
3941
|
+
field: "status",
|
|
3942
|
+
operator: "equals",
|
|
3943
|
+
value: "installed"
|
|
3944
|
+
},
|
|
3945
|
+
aggregate: "count",
|
|
3946
|
+
colorVariant: "success",
|
|
3947
|
+
description: "Active package installations across projects"
|
|
3948
|
+
},
|
|
3949
|
+
// ── Audit Actions by Type (last 7 days) ─────────────────────────
|
|
3950
|
+
{
|
|
3951
|
+
id: "widget_audit_actions",
|
|
3952
|
+
title: "Audit Actions (7d)",
|
|
3953
|
+
description: "Distribution of audit events by action type",
|
|
3954
|
+
type: "pie",
|
|
3955
|
+
object: "sys_audit_log",
|
|
3956
|
+
layout: {
|
|
3957
|
+
x: 0,
|
|
3958
|
+
y: 2,
|
|
3959
|
+
w: 6,
|
|
3960
|
+
h: 4
|
|
3961
|
+
},
|
|
3962
|
+
categoryField: "action",
|
|
3963
|
+
aggregate: "count",
|
|
3964
|
+
filter: {
|
|
3965
|
+
field: "created_at",
|
|
3966
|
+
operator: "gte",
|
|
3967
|
+
value: "NOW() - INTERVAL 7 DAY"
|
|
3968
|
+
}
|
|
3969
|
+
},
|
|
3970
|
+
// ── Session Status Overview ─────────────────────────────────────
|
|
3971
|
+
{
|
|
3972
|
+
id: "widget_active_orgs",
|
|
3973
|
+
title: "Sessions by Organization",
|
|
3974
|
+
description: "Active sessions grouped by organization",
|
|
3975
|
+
type: "bar",
|
|
3976
|
+
object: "sys_session",
|
|
3977
|
+
layout: {
|
|
3978
|
+
x: 6,
|
|
3979
|
+
y: 2,
|
|
3980
|
+
w: 6,
|
|
3981
|
+
h: 4
|
|
3982
|
+
},
|
|
3983
|
+
categoryField: "active_organization_id",
|
|
3984
|
+
aggregate: "count"
|
|
3985
|
+
},
|
|
3986
|
+
// ── Recent Audit Log (Table) ────────────────────────────────────
|
|
3987
|
+
{
|
|
3988
|
+
id: "widget_recent_events",
|
|
3989
|
+
title: "Recent Audit Events",
|
|
3990
|
+
description: "Latest platform events",
|
|
3991
|
+
type: "metric",
|
|
3992
|
+
object: "sys_audit_log",
|
|
3993
|
+
layout: {
|
|
3994
|
+
x: 0,
|
|
3995
|
+
y: 6,
|
|
3996
|
+
w: 12,
|
|
3997
|
+
h: 3
|
|
3998
|
+
},
|
|
3999
|
+
aggregate: "count",
|
|
4000
|
+
colorVariant: "default"
|
|
4001
|
+
}
|
|
4002
|
+
],
|
|
4003
|
+
globalFilters: [
|
|
4004
|
+
{
|
|
4005
|
+
field: "created_at",
|
|
4006
|
+
type: "date",
|
|
4007
|
+
label: "Date Range",
|
|
4008
|
+
scope: "dashboard",
|
|
4009
|
+
defaultValue: "last_7_days"
|
|
4010
|
+
}
|
|
4011
|
+
]
|
|
4012
|
+
});
|
|
4013
|
+
var SecurityOverviewDashboard = ui.Dashboard.create({
|
|
4014
|
+
name: "security_overview",
|
|
4015
|
+
label: "Security Overview",
|
|
4016
|
+
description: "Security events, authentication, and audit trails",
|
|
4017
|
+
// 12-column grid matches the widget `w` values below.
|
|
4018
|
+
columns: 12,
|
|
4019
|
+
gap: 4,
|
|
4020
|
+
widgets: [
|
|
4021
|
+
// ── Failed Login Attempts Widget ────────────────────────────────
|
|
4022
|
+
{
|
|
4023
|
+
id: "widget_failed_logins",
|
|
4024
|
+
title: "Failed Login Attempts",
|
|
4025
|
+
type: "metric",
|
|
4026
|
+
object: "sys_audit_log",
|
|
4027
|
+
layout: {
|
|
4028
|
+
x: 0,
|
|
4029
|
+
y: 0,
|
|
4030
|
+
w: 3,
|
|
4031
|
+
h: 2
|
|
4032
|
+
},
|
|
4033
|
+
filter: {
|
|
4034
|
+
field: "action",
|
|
4035
|
+
operator: "equals",
|
|
4036
|
+
value: "login"
|
|
4037
|
+
},
|
|
4038
|
+
aggregate: "count",
|
|
4039
|
+
colorVariant: "danger",
|
|
4040
|
+
description: "Failed authentication attempts (24h)"
|
|
4041
|
+
},
|
|
4042
|
+
// ── Permission Changes Widget ───────────────────────────────────
|
|
4043
|
+
{
|
|
4044
|
+
id: "widget_permission_changes",
|
|
4045
|
+
title: "Permission Changes",
|
|
4046
|
+
type: "metric",
|
|
4047
|
+
object: "sys_audit_log",
|
|
4048
|
+
layout: {
|
|
4049
|
+
x: 3,
|
|
4050
|
+
y: 0,
|
|
4051
|
+
w: 3,
|
|
4052
|
+
h: 2
|
|
4053
|
+
},
|
|
4054
|
+
filter: {
|
|
4055
|
+
field: "action",
|
|
4056
|
+
operator: "equals",
|
|
4057
|
+
value: "permission_change"
|
|
4058
|
+
},
|
|
4059
|
+
aggregate: "count",
|
|
4060
|
+
colorVariant: "warning",
|
|
4061
|
+
description: "Recent permission and role modifications"
|
|
4062
|
+
},
|
|
4063
|
+
// ── System Config Changes Widget ────────────────────────────────
|
|
4064
|
+
{
|
|
4065
|
+
id: "widget_config_changes",
|
|
4066
|
+
title: "Config Changes",
|
|
4067
|
+
type: "metric",
|
|
4068
|
+
object: "sys_audit_log",
|
|
4069
|
+
layout: {
|
|
4070
|
+
x: 6,
|
|
4071
|
+
y: 0,
|
|
4072
|
+
w: 3,
|
|
4073
|
+
h: 2
|
|
4074
|
+
},
|
|
4075
|
+
filter: {
|
|
4076
|
+
field: "action",
|
|
4077
|
+
operator: "equals",
|
|
4078
|
+
value: "config_change"
|
|
4079
|
+
},
|
|
4080
|
+
aggregate: "count",
|
|
4081
|
+
colorVariant: "blue",
|
|
4082
|
+
description: "System configuration modifications"
|
|
4083
|
+
},
|
|
4084
|
+
// ── Active Sessions Widget ──────────────────────────────────────
|
|
4085
|
+
{
|
|
4086
|
+
id: "widget_active_sessions",
|
|
4087
|
+
title: "Active Sessions",
|
|
4088
|
+
type: "metric",
|
|
4089
|
+
object: "sys_session",
|
|
4090
|
+
layout: {
|
|
4091
|
+
x: 9,
|
|
4092
|
+
y: 0,
|
|
4093
|
+
w: 3,
|
|
4094
|
+
h: 2
|
|
4095
|
+
},
|
|
4096
|
+
aggregate: "count",
|
|
4097
|
+
colorVariant: "success",
|
|
4098
|
+
description: "Currently active user sessions"
|
|
4099
|
+
},
|
|
4100
|
+
// ── Audit Events by Type ────────────────────────────────────────
|
|
4101
|
+
{
|
|
4102
|
+
id: "widget_events_by_type",
|
|
4103
|
+
title: "Audit Events by Type",
|
|
4104
|
+
description: "Distribution of security and audit events",
|
|
4105
|
+
type: "pie",
|
|
4106
|
+
object: "sys_audit_log",
|
|
4107
|
+
layout: {
|
|
4108
|
+
x: 0,
|
|
4109
|
+
y: 2,
|
|
4110
|
+
w: 6,
|
|
4111
|
+
h: 4
|
|
4112
|
+
},
|
|
4113
|
+
categoryField: "action",
|
|
4114
|
+
aggregate: "count"
|
|
4115
|
+
},
|
|
4116
|
+
// ── Audit Events by User ────────────────────────────────────────
|
|
4117
|
+
{
|
|
4118
|
+
id: "widget_events_by_user",
|
|
4119
|
+
title: "Events by User",
|
|
4120
|
+
description: "Activity distribution across users",
|
|
4121
|
+
type: "bar",
|
|
4122
|
+
object: "sys_audit_log",
|
|
4123
|
+
layout: {
|
|
4124
|
+
x: 6,
|
|
4125
|
+
y: 2,
|
|
4126
|
+
w: 6,
|
|
4127
|
+
h: 4
|
|
4128
|
+
},
|
|
4129
|
+
categoryField: "user_id",
|
|
4130
|
+
aggregate: "count"
|
|
4131
|
+
},
|
|
4132
|
+
// ── Recent Security Events (Table) ──────────────────────────────
|
|
4133
|
+
{
|
|
4134
|
+
id: "widget_recent_security_events",
|
|
4135
|
+
title: "Recent Security Events",
|
|
4136
|
+
description: "Latest permission and config changes",
|
|
4137
|
+
type: "metric",
|
|
4138
|
+
object: "sys_audit_log",
|
|
4139
|
+
layout: {
|
|
4140
|
+
x: 0,
|
|
4141
|
+
y: 6,
|
|
4142
|
+
w: 12,
|
|
4143
|
+
h: 3
|
|
4144
|
+
},
|
|
4145
|
+
aggregate: "count",
|
|
4146
|
+
colorVariant: "default"
|
|
4147
|
+
}
|
|
4148
|
+
],
|
|
4149
|
+
globalFilters: [
|
|
4150
|
+
{
|
|
4151
|
+
field: "created_at",
|
|
4152
|
+
type: "date",
|
|
4153
|
+
label: "Date Range",
|
|
4154
|
+
scope: "dashboard",
|
|
4155
|
+
defaultValue: "last_7_days"
|
|
4156
|
+
}
|
|
4157
|
+
]
|
|
4158
|
+
});
|
|
4159
|
+
|
|
4160
|
+
exports.AuditLogsView = AuditLogsView;
|
|
4161
|
+
exports.OrganizationsView = OrganizationsView;
|
|
4162
|
+
exports.PackageInstallationsView = PackageInstallationsView;
|
|
4163
|
+
exports.RolesView = RolesView;
|
|
4164
|
+
exports.SETUP_APP = SETUP_APP;
|
|
4165
|
+
exports.SecurityOverviewDashboard = SecurityOverviewDashboard;
|
|
4166
|
+
exports.SessionsView = SessionsView;
|
|
4167
|
+
exports.SysAccount = SysAccount;
|
|
4168
|
+
exports.SysActivity = SysActivity;
|
|
4169
|
+
exports.SysAgent = SysAgent;
|
|
4170
|
+
exports.SysApiKey = SysApiKey;
|
|
4171
|
+
exports.SysApp = SysApp;
|
|
4172
|
+
exports.SysAuditLog = SysAuditLog;
|
|
4173
|
+
exports.SysComment = SysComment;
|
|
4174
|
+
exports.SysDeviceCode = SysDeviceCode;
|
|
4175
|
+
exports.SysFlow = SysFlow;
|
|
4176
|
+
exports.SysInvitation = SysInvitation;
|
|
4177
|
+
exports.SysJwks = SysJwks;
|
|
4178
|
+
exports.SysMember = SysMember;
|
|
4179
|
+
exports.SysMetadata = SysMetadataObject;
|
|
4180
|
+
exports.SysMetadataHistoryObject = SysMetadataHistoryObject;
|
|
4181
|
+
exports.SysMetadataObject = SysMetadataObject;
|
|
4182
|
+
exports.SysOauthAccessToken = SysOauthAccessToken;
|
|
4183
|
+
exports.SysOauthApplication = SysOauthApplication;
|
|
4184
|
+
exports.SysOauthConsent = SysOauthConsent;
|
|
4185
|
+
exports.SysOauthRefreshToken = SysOauthRefreshToken;
|
|
4186
|
+
exports.SysObject = SysObject;
|
|
4187
|
+
exports.SysOrganization = SysOrganization;
|
|
4188
|
+
exports.SysPackage = SysPackage;
|
|
4189
|
+
exports.SysPackageInstallation = SysPackageInstallation;
|
|
4190
|
+
exports.SysPackageVersion = SysPackageVersion;
|
|
4191
|
+
exports.SysPermissionSet = SysPermissionSet;
|
|
4192
|
+
exports.SysPresence = SysPresence;
|
|
4193
|
+
exports.SysProject = SysProject;
|
|
4194
|
+
exports.SysProjectCredential = SysProjectCredential;
|
|
4195
|
+
exports.SysProjectMember = SysProjectMember;
|
|
4196
|
+
exports.SysRole = SysRole;
|
|
4197
|
+
exports.SysSession = SysSession;
|
|
4198
|
+
exports.SysTeam = SysTeam;
|
|
4199
|
+
exports.SysTeamMember = SysTeamMember;
|
|
4200
|
+
exports.SysTool = SysTool;
|
|
4201
|
+
exports.SysTwoFactor = SysTwoFactor;
|
|
4202
|
+
exports.SysUser = SysUser;
|
|
4203
|
+
exports.SysUserPreference = SysUserPreference;
|
|
4204
|
+
exports.SysVerification = SysVerification;
|
|
4205
|
+
exports.SysView = SysView;
|
|
4206
|
+
exports.SystemOverviewDashboard = SystemOverviewDashboard;
|
|
4207
|
+
exports.UsersView = UsersView;
|
|
4208
|
+
//# sourceMappingURL=index.js.map
|
|
4209
|
+
//# sourceMappingURL=index.js.map
|