@elevasis/core 0.31.0 → 0.32.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/dist/auth/index.d.ts +55 -2
- package/dist/index.d.ts +15 -3
- package/dist/index.js +69 -4
- package/dist/knowledge/index.d.ts +10 -2
- package/dist/organization-model/index.d.ts +15 -3
- package/dist/organization-model/index.js +69 -4
- package/dist/test-utils/index.d.ts +55 -2
- package/dist/test-utils/index.js +69 -4
- package/package.json +1 -1
- package/src/organization-model/__tests__/domains/passthrough-extensibility.test.ts +199 -0
- package/src/organization-model/domains/branding.ts +58 -16
- package/src/organization-model/domains/identity.ts +122 -94
- package/src/supabase/database.types.ts +45 -0
package/dist/auth/index.d.ts
CHANGED
|
@@ -2153,6 +2153,51 @@ type Database = {
|
|
|
2153
2153
|
}
|
|
2154
2154
|
];
|
|
2155
2155
|
};
|
|
2156
|
+
deployment_organization_models: {
|
|
2157
|
+
Row: {
|
|
2158
|
+
created_at: string;
|
|
2159
|
+
deployment_id: string;
|
|
2160
|
+
model_hash: string | null;
|
|
2161
|
+
organization_id: string;
|
|
2162
|
+
organization_model: Json;
|
|
2163
|
+
schema_version: string;
|
|
2164
|
+
updated_at: string;
|
|
2165
|
+
};
|
|
2166
|
+
Insert: {
|
|
2167
|
+
created_at?: string;
|
|
2168
|
+
deployment_id: string;
|
|
2169
|
+
model_hash?: string | null;
|
|
2170
|
+
organization_id: string;
|
|
2171
|
+
organization_model: Json;
|
|
2172
|
+
schema_version?: string;
|
|
2173
|
+
updated_at?: string;
|
|
2174
|
+
};
|
|
2175
|
+
Update: {
|
|
2176
|
+
created_at?: string;
|
|
2177
|
+
deployment_id?: string;
|
|
2178
|
+
model_hash?: string | null;
|
|
2179
|
+
organization_id?: string;
|
|
2180
|
+
organization_model?: Json;
|
|
2181
|
+
schema_version?: string;
|
|
2182
|
+
updated_at?: string;
|
|
2183
|
+
};
|
|
2184
|
+
Relationships: [
|
|
2185
|
+
{
|
|
2186
|
+
foreignKeyName: "deployment_organization_models_deployment_id_fkey";
|
|
2187
|
+
columns: ["deployment_id"];
|
|
2188
|
+
isOneToOne: true;
|
|
2189
|
+
referencedRelation: "deployments";
|
|
2190
|
+
referencedColumns: ["id"];
|
|
2191
|
+
},
|
|
2192
|
+
{
|
|
2193
|
+
foreignKeyName: "deployment_organization_models_organization_id_fkey";
|
|
2194
|
+
columns: ["organization_id"];
|
|
2195
|
+
isOneToOne: false;
|
|
2196
|
+
referencedRelation: "organizations";
|
|
2197
|
+
referencedColumns: ["id"];
|
|
2198
|
+
}
|
|
2199
|
+
];
|
|
2200
|
+
};
|
|
2156
2201
|
deployments: {
|
|
2157
2202
|
Row: {
|
|
2158
2203
|
created_at: string;
|
|
@@ -4399,7 +4444,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4399
4444
|
light: z.ZodOptional<z.ZodString>;
|
|
4400
4445
|
dark: z.ZodOptional<z.ZodString>;
|
|
4401
4446
|
}, z.core.$strip>>;
|
|
4402
|
-
|
|
4447
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
4448
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
4449
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
4450
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
4451
|
+
}, z.core.$loose>>;
|
|
4403
4452
|
navigation: z.ZodDefault<z.ZodObject<{
|
|
4404
4453
|
sidebar: z.ZodDefault<z.ZodObject<{
|
|
4405
4454
|
primary: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<SidebarNode, unknown, z.core.$ZodTypeInternals<SidebarNode, unknown>>>>;
|
|
@@ -4446,7 +4495,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4446
4495
|
}, z.core.$strip>>;
|
|
4447
4496
|
}, z.core.$strip>>;
|
|
4448
4497
|
clientBrief: z.ZodDefault<z.ZodString>;
|
|
4449
|
-
|
|
4498
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
4499
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
4500
|
+
shortName: z.ZodOptional<z.ZodString>;
|
|
4501
|
+
description: z.ZodOptional<z.ZodString>;
|
|
4502
|
+
}, z.core.$loose>>;
|
|
4450
4503
|
customers: z.ZodDefault<z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
4451
4504
|
id: z.ZodString;
|
|
4452
4505
|
order: z.ZodNumber;
|
package/dist/index.d.ts
CHANGED
|
@@ -321,7 +321,11 @@ declare const OrganizationModelBrandingSchema: z.ZodObject<{
|
|
|
321
321
|
light: z.ZodOptional<z.ZodString>;
|
|
322
322
|
dark: z.ZodOptional<z.ZodString>;
|
|
323
323
|
}, z.core.$strip>>;
|
|
324
|
-
|
|
324
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
325
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
326
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
327
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
328
|
+
}, z.core.$loose>;
|
|
325
329
|
|
|
326
330
|
/** One entry in the lead-gen stage catalog. */
|
|
327
331
|
interface LeadGenStageCatalogEntry {
|
|
@@ -4067,7 +4071,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4067
4071
|
light: z.ZodOptional<z.ZodString>;
|
|
4068
4072
|
dark: z.ZodOptional<z.ZodString>;
|
|
4069
4073
|
}, z.core.$strip>>;
|
|
4070
|
-
|
|
4074
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
4075
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
4076
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
4077
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
4078
|
+
}, z.core.$loose>>;
|
|
4071
4079
|
navigation: z.ZodDefault<z.ZodObject<{
|
|
4072
4080
|
sidebar: z.ZodDefault<z.ZodObject<{
|
|
4073
4081
|
primary: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<SidebarNode, unknown, z.core.$ZodTypeInternals<SidebarNode, unknown>>>>;
|
|
@@ -4114,7 +4122,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4114
4122
|
}, z.core.$strip>>;
|
|
4115
4123
|
}, z.core.$strip>>;
|
|
4116
4124
|
clientBrief: z.ZodDefault<z.ZodString>;
|
|
4117
|
-
|
|
4125
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
4126
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
4127
|
+
shortName: z.ZodOptional<z.ZodString>;
|
|
4128
|
+
description: z.ZodOptional<z.ZodString>;
|
|
4129
|
+
}, z.core.$loose>>;
|
|
4118
4130
|
customers: z.ZodDefault<z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
4119
4131
|
id: z.ZodString;
|
|
4120
4132
|
order: z.ZodNumber;
|
package/dist/index.js
CHANGED
|
@@ -494,15 +494,55 @@ DisplayMetadataSchema.extend({
|
|
|
494
494
|
|
|
495
495
|
// src/organization-model/domains/branding.ts
|
|
496
496
|
var OrganizationModelBrandingSchema = z.object({
|
|
497
|
+
/**
|
|
498
|
+
* @deprecated Prefer `identity.organizationName`; branding retains it for back-compat.
|
|
499
|
+
* Legacy tenants that have not set `identity.organizationName` fall back to this field.
|
|
500
|
+
*/
|
|
497
501
|
organizationName: LabelSchema,
|
|
502
|
+
/**
|
|
503
|
+
* @deprecated Prefer `identity.productName`; branding retains it for back-compat.
|
|
504
|
+
* Legacy tenants that have not set `identity.productName` fall back to this field.
|
|
505
|
+
*/
|
|
498
506
|
productName: LabelSchema,
|
|
507
|
+
/**
|
|
508
|
+
* @deprecated Prefer `identity.shortName`; branding retains it for back-compat.
|
|
509
|
+
* Legacy tenants that have not set `identity.shortName` fall back to this field.
|
|
510
|
+
*/
|
|
499
511
|
shortName: z.string().trim().min(1).max(40),
|
|
512
|
+
/**
|
|
513
|
+
* @deprecated Prefer `identity.description`; branding retains it for back-compat.
|
|
514
|
+
* Legacy tenants that have not set `identity.description` fall back to this field.
|
|
515
|
+
*/
|
|
500
516
|
description: DescriptionSchema.optional(),
|
|
501
517
|
logos: z.object({
|
|
502
518
|
light: z.string().trim().min(1).max(2048).optional(),
|
|
503
519
|
dark: z.string().trim().min(1).max(2048).optional()
|
|
504
|
-
}).default({})
|
|
505
|
-
|
|
520
|
+
}).default({}),
|
|
521
|
+
/**
|
|
522
|
+
* Brand voice — how the organization communicates. Plain-language description
|
|
523
|
+
* of tone, register, and personality (e.g. "Direct and human — no jargon").
|
|
524
|
+
* Max 280 characters.
|
|
525
|
+
*/
|
|
526
|
+
voice: z.string().trim().max(280).optional(),
|
|
527
|
+
/**
|
|
528
|
+
* Brand tagline or positioning statement — the memorable one-liner that
|
|
529
|
+
* captures the brand's promise or differentiator. Max 200 characters.
|
|
530
|
+
*/
|
|
531
|
+
tagline: z.string().trim().max(200).optional(),
|
|
532
|
+
/**
|
|
533
|
+
* Core brand values — an ordered list of principles the organization stands
|
|
534
|
+
* for (e.g. ["Transparency", "Craftsmanship", "Velocity"]). Each entry must
|
|
535
|
+
* be a non-empty trimmed string.
|
|
536
|
+
*/
|
|
537
|
+
values: z.array(z.string().trim().min(1)).optional(),
|
|
538
|
+
/**
|
|
539
|
+
* ID of the active UI theme preset from the UI theme-presets registry.
|
|
540
|
+
* The UI layer resolves this to colors and typography via `usePresetsContext()`.
|
|
541
|
+
* Free-form string — validation and fallback state are handled at the UI layer.
|
|
542
|
+
* Min 1, max 64 characters.
|
|
543
|
+
*/
|
|
544
|
+
themePresetId: z.string().trim().min(1).max(64).optional()
|
|
545
|
+
}).passthrough();
|
|
506
546
|
var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
|
|
507
547
|
organizationName: "Default Organization",
|
|
508
548
|
productName: "Organization OS",
|
|
@@ -633,8 +673,33 @@ var IdentityDomainSchema = z.object({
|
|
|
633
673
|
* background. Populated by /setup; surfaced to agents as organizational context.
|
|
634
674
|
* Optional — many projects have no external client.
|
|
635
675
|
*/
|
|
636
|
-
clientBrief: z.string().trim().default("")
|
|
637
|
-
|
|
676
|
+
clientBrief: z.string().trim().default(""),
|
|
677
|
+
/**
|
|
678
|
+
* Display name of the organization as shown to end users.
|
|
679
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
680
|
+
* `branding.organizationName`. Falls back to `branding.organizationName` for
|
|
681
|
+
* legacy tenants that have not yet migrated.
|
|
682
|
+
*/
|
|
683
|
+
organizationName: LabelSchema.optional(),
|
|
684
|
+
/**
|
|
685
|
+
* Display name of the primary product or platform.
|
|
686
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
687
|
+
* `branding.productName`. Falls back to `branding.productName` for legacy tenants.
|
|
688
|
+
*/
|
|
689
|
+
productName: LabelSchema.optional(),
|
|
690
|
+
/**
|
|
691
|
+
* Short abbreviated name used in space-constrained UI surfaces (max 40 chars).
|
|
692
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
693
|
+
* `branding.shortName`. Falls back to `branding.shortName` for legacy tenants.
|
|
694
|
+
*/
|
|
695
|
+
shortName: z.string().trim().min(1).max(40).optional(),
|
|
696
|
+
/**
|
|
697
|
+
* Plain-language description of the organization for display and discovery.
|
|
698
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
699
|
+
* `branding.description`. Falls back to `branding.description` for legacy tenants.
|
|
700
|
+
*/
|
|
701
|
+
description: DescriptionSchema.optional()
|
|
702
|
+
}).passthrough();
|
|
638
703
|
var DEFAULT_ORGANIZATION_MODEL_IDENTITY = {
|
|
639
704
|
mission: "",
|
|
640
705
|
vision: "",
|
|
@@ -537,7 +537,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
537
537
|
light: z.ZodOptional<z.ZodString>;
|
|
538
538
|
dark: z.ZodOptional<z.ZodString>;
|
|
539
539
|
}, z.core.$strip>>;
|
|
540
|
-
|
|
540
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
541
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
542
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
543
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
544
|
+
}, z.core.$loose>>;
|
|
541
545
|
navigation: z.ZodDefault<z.ZodObject<{
|
|
542
546
|
sidebar: z.ZodDefault<z.ZodObject<{
|
|
543
547
|
primary: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<SidebarNode, unknown, z.core.$ZodTypeInternals<SidebarNode, unknown>>>>;
|
|
@@ -584,7 +588,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
584
588
|
}, z.core.$strip>>;
|
|
585
589
|
}, z.core.$strip>>;
|
|
586
590
|
clientBrief: z.ZodDefault<z.ZodString>;
|
|
587
|
-
|
|
591
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
592
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
593
|
+
shortName: z.ZodOptional<z.ZodString>;
|
|
594
|
+
description: z.ZodOptional<z.ZodString>;
|
|
595
|
+
}, z.core.$loose>>;
|
|
588
596
|
customers: z.ZodDefault<z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
589
597
|
id: z.ZodString;
|
|
590
598
|
order: z.ZodNumber;
|
|
@@ -321,7 +321,11 @@ declare const OrganizationModelBrandingSchema: z.ZodObject<{
|
|
|
321
321
|
light: z.ZodOptional<z.ZodString>;
|
|
322
322
|
dark: z.ZodOptional<z.ZodString>;
|
|
323
323
|
}, z.core.$strip>>;
|
|
324
|
-
|
|
324
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
325
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
326
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
327
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
328
|
+
}, z.core.$loose>;
|
|
325
329
|
|
|
326
330
|
/** One entry in the lead-gen stage catalog. */
|
|
327
331
|
interface LeadGenStageCatalogEntry {
|
|
@@ -4067,7 +4071,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4067
4071
|
light: z.ZodOptional<z.ZodString>;
|
|
4068
4072
|
dark: z.ZodOptional<z.ZodString>;
|
|
4069
4073
|
}, z.core.$strip>>;
|
|
4070
|
-
|
|
4074
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
4075
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
4076
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
4077
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
4078
|
+
}, z.core.$loose>>;
|
|
4071
4079
|
navigation: z.ZodDefault<z.ZodObject<{
|
|
4072
4080
|
sidebar: z.ZodDefault<z.ZodObject<{
|
|
4073
4081
|
primary: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<SidebarNode, unknown, z.core.$ZodTypeInternals<SidebarNode, unknown>>>>;
|
|
@@ -4114,7 +4122,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4114
4122
|
}, z.core.$strip>>;
|
|
4115
4123
|
}, z.core.$strip>>;
|
|
4116
4124
|
clientBrief: z.ZodDefault<z.ZodString>;
|
|
4117
|
-
|
|
4125
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
4126
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
4127
|
+
shortName: z.ZodOptional<z.ZodString>;
|
|
4128
|
+
description: z.ZodOptional<z.ZodString>;
|
|
4129
|
+
}, z.core.$loose>>;
|
|
4118
4130
|
customers: z.ZodDefault<z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
4119
4131
|
id: z.ZodString;
|
|
4120
4132
|
order: z.ZodNumber;
|
|
@@ -494,15 +494,55 @@ DisplayMetadataSchema.extend({
|
|
|
494
494
|
|
|
495
495
|
// src/organization-model/domains/branding.ts
|
|
496
496
|
var OrganizationModelBrandingSchema = z.object({
|
|
497
|
+
/**
|
|
498
|
+
* @deprecated Prefer `identity.organizationName`; branding retains it for back-compat.
|
|
499
|
+
* Legacy tenants that have not set `identity.organizationName` fall back to this field.
|
|
500
|
+
*/
|
|
497
501
|
organizationName: LabelSchema,
|
|
502
|
+
/**
|
|
503
|
+
* @deprecated Prefer `identity.productName`; branding retains it for back-compat.
|
|
504
|
+
* Legacy tenants that have not set `identity.productName` fall back to this field.
|
|
505
|
+
*/
|
|
498
506
|
productName: LabelSchema,
|
|
507
|
+
/**
|
|
508
|
+
* @deprecated Prefer `identity.shortName`; branding retains it for back-compat.
|
|
509
|
+
* Legacy tenants that have not set `identity.shortName` fall back to this field.
|
|
510
|
+
*/
|
|
499
511
|
shortName: z.string().trim().min(1).max(40),
|
|
512
|
+
/**
|
|
513
|
+
* @deprecated Prefer `identity.description`; branding retains it for back-compat.
|
|
514
|
+
* Legacy tenants that have not set `identity.description` fall back to this field.
|
|
515
|
+
*/
|
|
500
516
|
description: DescriptionSchema.optional(),
|
|
501
517
|
logos: z.object({
|
|
502
518
|
light: z.string().trim().min(1).max(2048).optional(),
|
|
503
519
|
dark: z.string().trim().min(1).max(2048).optional()
|
|
504
|
-
}).default({})
|
|
505
|
-
|
|
520
|
+
}).default({}),
|
|
521
|
+
/**
|
|
522
|
+
* Brand voice — how the organization communicates. Plain-language description
|
|
523
|
+
* of tone, register, and personality (e.g. "Direct and human — no jargon").
|
|
524
|
+
* Max 280 characters.
|
|
525
|
+
*/
|
|
526
|
+
voice: z.string().trim().max(280).optional(),
|
|
527
|
+
/**
|
|
528
|
+
* Brand tagline or positioning statement — the memorable one-liner that
|
|
529
|
+
* captures the brand's promise or differentiator. Max 200 characters.
|
|
530
|
+
*/
|
|
531
|
+
tagline: z.string().trim().max(200).optional(),
|
|
532
|
+
/**
|
|
533
|
+
* Core brand values — an ordered list of principles the organization stands
|
|
534
|
+
* for (e.g. ["Transparency", "Craftsmanship", "Velocity"]). Each entry must
|
|
535
|
+
* be a non-empty trimmed string.
|
|
536
|
+
*/
|
|
537
|
+
values: z.array(z.string().trim().min(1)).optional(),
|
|
538
|
+
/**
|
|
539
|
+
* ID of the active UI theme preset from the UI theme-presets registry.
|
|
540
|
+
* The UI layer resolves this to colors and typography via `usePresetsContext()`.
|
|
541
|
+
* Free-form string — validation and fallback state are handled at the UI layer.
|
|
542
|
+
* Min 1, max 64 characters.
|
|
543
|
+
*/
|
|
544
|
+
themePresetId: z.string().trim().min(1).max(64).optional()
|
|
545
|
+
}).passthrough();
|
|
506
546
|
var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
|
|
507
547
|
organizationName: "Default Organization",
|
|
508
548
|
productName: "Organization OS",
|
|
@@ -633,8 +673,33 @@ var IdentityDomainSchema = z.object({
|
|
|
633
673
|
* background. Populated by /setup; surfaced to agents as organizational context.
|
|
634
674
|
* Optional — many projects have no external client.
|
|
635
675
|
*/
|
|
636
|
-
clientBrief: z.string().trim().default("")
|
|
637
|
-
|
|
676
|
+
clientBrief: z.string().trim().default(""),
|
|
677
|
+
/**
|
|
678
|
+
* Display name of the organization as shown to end users.
|
|
679
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
680
|
+
* `branding.organizationName`. Falls back to `branding.organizationName` for
|
|
681
|
+
* legacy tenants that have not yet migrated.
|
|
682
|
+
*/
|
|
683
|
+
organizationName: LabelSchema.optional(),
|
|
684
|
+
/**
|
|
685
|
+
* Display name of the primary product or platform.
|
|
686
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
687
|
+
* `branding.productName`. Falls back to `branding.productName` for legacy tenants.
|
|
688
|
+
*/
|
|
689
|
+
productName: LabelSchema.optional(),
|
|
690
|
+
/**
|
|
691
|
+
* Short abbreviated name used in space-constrained UI surfaces (max 40 chars).
|
|
692
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
693
|
+
* `branding.shortName`. Falls back to `branding.shortName` for legacy tenants.
|
|
694
|
+
*/
|
|
695
|
+
shortName: z.string().trim().min(1).max(40).optional(),
|
|
696
|
+
/**
|
|
697
|
+
* Plain-language description of the organization for display and discovery.
|
|
698
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
699
|
+
* `branding.description`. Falls back to `branding.description` for legacy tenants.
|
|
700
|
+
*/
|
|
701
|
+
description: DescriptionSchema.optional()
|
|
702
|
+
}).passthrough();
|
|
638
703
|
var DEFAULT_ORGANIZATION_MODEL_IDENTITY = {
|
|
639
704
|
mission: "",
|
|
640
705
|
vision: "",
|
|
@@ -1464,6 +1464,51 @@ type Database = {
|
|
|
1464
1464
|
}
|
|
1465
1465
|
];
|
|
1466
1466
|
};
|
|
1467
|
+
deployment_organization_models: {
|
|
1468
|
+
Row: {
|
|
1469
|
+
created_at: string;
|
|
1470
|
+
deployment_id: string;
|
|
1471
|
+
model_hash: string | null;
|
|
1472
|
+
organization_id: string;
|
|
1473
|
+
organization_model: Json;
|
|
1474
|
+
schema_version: string;
|
|
1475
|
+
updated_at: string;
|
|
1476
|
+
};
|
|
1477
|
+
Insert: {
|
|
1478
|
+
created_at?: string;
|
|
1479
|
+
deployment_id: string;
|
|
1480
|
+
model_hash?: string | null;
|
|
1481
|
+
organization_id: string;
|
|
1482
|
+
organization_model: Json;
|
|
1483
|
+
schema_version?: string;
|
|
1484
|
+
updated_at?: string;
|
|
1485
|
+
};
|
|
1486
|
+
Update: {
|
|
1487
|
+
created_at?: string;
|
|
1488
|
+
deployment_id?: string;
|
|
1489
|
+
model_hash?: string | null;
|
|
1490
|
+
organization_id?: string;
|
|
1491
|
+
organization_model?: Json;
|
|
1492
|
+
schema_version?: string;
|
|
1493
|
+
updated_at?: string;
|
|
1494
|
+
};
|
|
1495
|
+
Relationships: [
|
|
1496
|
+
{
|
|
1497
|
+
foreignKeyName: "deployment_organization_models_deployment_id_fkey";
|
|
1498
|
+
columns: ["deployment_id"];
|
|
1499
|
+
isOneToOne: true;
|
|
1500
|
+
referencedRelation: "deployments";
|
|
1501
|
+
referencedColumns: ["id"];
|
|
1502
|
+
},
|
|
1503
|
+
{
|
|
1504
|
+
foreignKeyName: "deployment_organization_models_organization_id_fkey";
|
|
1505
|
+
columns: ["organization_id"];
|
|
1506
|
+
isOneToOne: false;
|
|
1507
|
+
referencedRelation: "organizations";
|
|
1508
|
+
referencedColumns: ["id"];
|
|
1509
|
+
}
|
|
1510
|
+
];
|
|
1511
|
+
};
|
|
1467
1512
|
deployments: {
|
|
1468
1513
|
Row: {
|
|
1469
1514
|
created_at: string;
|
|
@@ -3961,7 +4006,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
3961
4006
|
light: z.ZodOptional<z.ZodString>;
|
|
3962
4007
|
dark: z.ZodOptional<z.ZodString>;
|
|
3963
4008
|
}, z.core.$strip>>;
|
|
3964
|
-
|
|
4009
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
4010
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
4011
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
4012
|
+
themePresetId: z.ZodOptional<z.ZodString>;
|
|
4013
|
+
}, z.core.$loose>>;
|
|
3965
4014
|
navigation: z.ZodDefault<z.ZodObject<{
|
|
3966
4015
|
sidebar: z.ZodDefault<z.ZodObject<{
|
|
3967
4016
|
primary: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<SidebarNode, unknown, z.core.$ZodTypeInternals<SidebarNode, unknown>>>>;
|
|
@@ -4008,7 +4057,11 @@ declare const OrganizationModelSchema: z.ZodObject<{
|
|
|
4008
4057
|
}, z.core.$strip>>;
|
|
4009
4058
|
}, z.core.$strip>>;
|
|
4010
4059
|
clientBrief: z.ZodDefault<z.ZodString>;
|
|
4011
|
-
|
|
4060
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
4061
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
4062
|
+
shortName: z.ZodOptional<z.ZodString>;
|
|
4063
|
+
description: z.ZodOptional<z.ZodString>;
|
|
4064
|
+
}, z.core.$loose>>;
|
|
4012
4065
|
customers: z.ZodDefault<z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
4013
4066
|
id: z.ZodString;
|
|
4014
4067
|
order: z.ZodNumber;
|
package/dist/test-utils/index.js
CHANGED
|
@@ -19895,15 +19895,55 @@ DisplayMetadataSchema.extend({
|
|
|
19895
19895
|
|
|
19896
19896
|
// src/organization-model/domains/branding.ts
|
|
19897
19897
|
var OrganizationModelBrandingSchema = z.object({
|
|
19898
|
+
/**
|
|
19899
|
+
* @deprecated Prefer `identity.organizationName`; branding retains it for back-compat.
|
|
19900
|
+
* Legacy tenants that have not set `identity.organizationName` fall back to this field.
|
|
19901
|
+
*/
|
|
19898
19902
|
organizationName: LabelSchema,
|
|
19903
|
+
/**
|
|
19904
|
+
* @deprecated Prefer `identity.productName`; branding retains it for back-compat.
|
|
19905
|
+
* Legacy tenants that have not set `identity.productName` fall back to this field.
|
|
19906
|
+
*/
|
|
19899
19907
|
productName: LabelSchema,
|
|
19908
|
+
/**
|
|
19909
|
+
* @deprecated Prefer `identity.shortName`; branding retains it for back-compat.
|
|
19910
|
+
* Legacy tenants that have not set `identity.shortName` fall back to this field.
|
|
19911
|
+
*/
|
|
19900
19912
|
shortName: z.string().trim().min(1).max(40),
|
|
19913
|
+
/**
|
|
19914
|
+
* @deprecated Prefer `identity.description`; branding retains it for back-compat.
|
|
19915
|
+
* Legacy tenants that have not set `identity.description` fall back to this field.
|
|
19916
|
+
*/
|
|
19901
19917
|
description: DescriptionSchema.optional(),
|
|
19902
19918
|
logos: z.object({
|
|
19903
19919
|
light: z.string().trim().min(1).max(2048).optional(),
|
|
19904
19920
|
dark: z.string().trim().min(1).max(2048).optional()
|
|
19905
|
-
}).default({})
|
|
19906
|
-
|
|
19921
|
+
}).default({}),
|
|
19922
|
+
/**
|
|
19923
|
+
* Brand voice — how the organization communicates. Plain-language description
|
|
19924
|
+
* of tone, register, and personality (e.g. "Direct and human — no jargon").
|
|
19925
|
+
* Max 280 characters.
|
|
19926
|
+
*/
|
|
19927
|
+
voice: z.string().trim().max(280).optional(),
|
|
19928
|
+
/**
|
|
19929
|
+
* Brand tagline or positioning statement — the memorable one-liner that
|
|
19930
|
+
* captures the brand's promise or differentiator. Max 200 characters.
|
|
19931
|
+
*/
|
|
19932
|
+
tagline: z.string().trim().max(200).optional(),
|
|
19933
|
+
/**
|
|
19934
|
+
* Core brand values — an ordered list of principles the organization stands
|
|
19935
|
+
* for (e.g. ["Transparency", "Craftsmanship", "Velocity"]). Each entry must
|
|
19936
|
+
* be a non-empty trimmed string.
|
|
19937
|
+
*/
|
|
19938
|
+
values: z.array(z.string().trim().min(1)).optional(),
|
|
19939
|
+
/**
|
|
19940
|
+
* ID of the active UI theme preset from the UI theme-presets registry.
|
|
19941
|
+
* The UI layer resolves this to colors and typography via `usePresetsContext()`.
|
|
19942
|
+
* Free-form string — validation and fallback state are handled at the UI layer.
|
|
19943
|
+
* Min 1, max 64 characters.
|
|
19944
|
+
*/
|
|
19945
|
+
themePresetId: z.string().trim().min(1).max(64).optional()
|
|
19946
|
+
}).passthrough();
|
|
19907
19947
|
var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
|
|
19908
19948
|
organizationName: "Default Organization",
|
|
19909
19949
|
productName: "Organization OS",
|
|
@@ -20022,8 +20062,33 @@ var IdentityDomainSchema = z.object({
|
|
|
20022
20062
|
* background. Populated by /setup; surfaced to agents as organizational context.
|
|
20023
20063
|
* Optional — many projects have no external client.
|
|
20024
20064
|
*/
|
|
20025
|
-
clientBrief: z.string().trim().default("")
|
|
20026
|
-
|
|
20065
|
+
clientBrief: z.string().trim().default(""),
|
|
20066
|
+
/**
|
|
20067
|
+
* Display name of the organization as shown to end users.
|
|
20068
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
20069
|
+
* `branding.organizationName`. Falls back to `branding.organizationName` for
|
|
20070
|
+
* legacy tenants that have not yet migrated.
|
|
20071
|
+
*/
|
|
20072
|
+
organizationName: LabelSchema.optional(),
|
|
20073
|
+
/**
|
|
20074
|
+
* Display name of the primary product or platform.
|
|
20075
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
20076
|
+
* `branding.productName`. Falls back to `branding.productName` for legacy tenants.
|
|
20077
|
+
*/
|
|
20078
|
+
productName: LabelSchema.optional(),
|
|
20079
|
+
/**
|
|
20080
|
+
* Short abbreviated name used in space-constrained UI surfaces (max 40 chars).
|
|
20081
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
20082
|
+
* `branding.shortName`. Falls back to `branding.shortName` for legacy tenants.
|
|
20083
|
+
*/
|
|
20084
|
+
shortName: z.string().trim().min(1).max(40).optional(),
|
|
20085
|
+
/**
|
|
20086
|
+
* Plain-language description of the organization for display and discovery.
|
|
20087
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
20088
|
+
* `branding.description`. Falls back to `branding.description` for legacy tenants.
|
|
20089
|
+
*/
|
|
20090
|
+
description: DescriptionSchema.optional()
|
|
20091
|
+
}).passthrough();
|
|
20027
20092
|
var DEFAULT_ORGANIZATION_MODEL_IDENTITY = {
|
|
20028
20093
|
mission: "",
|
|
20029
20094
|
vision: "",
|
package/package.json
CHANGED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { IdentityDomainSchema } from '../../domains/identity'
|
|
3
|
+
import { resolveOrganizationModel } from '../../resolve'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Profile-singleton domains (`branding`, `identity`) use `.passthrough()` so that
|
|
7
|
+
* tenant-authored direct properties survive `resolveOrganizationModel` instead of
|
|
8
|
+
* being silently stripped by Zod's default `.strip()`. These tests lock that
|
|
9
|
+
* behavior in and verify the broadened typed branding fields round-trip.
|
|
10
|
+
*/
|
|
11
|
+
describe('profile-singleton passthrough extensibility', () => {
|
|
12
|
+
it('keeps an unknown direct property on branding through resolve', () => {
|
|
13
|
+
const model = resolveOrganizationModel({
|
|
14
|
+
branding: {
|
|
15
|
+
organizationName: 'Acme',
|
|
16
|
+
productName: 'AcmeOS',
|
|
17
|
+
shortName: 'Acme',
|
|
18
|
+
// Unknown tenant-authored direct property — must survive passthrough.
|
|
19
|
+
brandVibe: 'warm'
|
|
20
|
+
} as never
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
expect((model.branding as Record<string, unknown>).brandVibe).toBe('warm')
|
|
24
|
+
// Known fields still resolve normally.
|
|
25
|
+
expect(model.branding.organizationName).toBe('Acme')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('keeps an unknown direct property on identity through resolve', () => {
|
|
29
|
+
const model = resolveOrganizationModel({
|
|
30
|
+
identity: {
|
|
31
|
+
// Unknown tenant-authored direct property — must survive passthrough.
|
|
32
|
+
founderNote: 'bootstrapped'
|
|
33
|
+
} as never
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
expect((model.identity as Record<string, unknown>).founderNote).toBe('bootstrapped')
|
|
37
|
+
// Known identity fields still resolve from defaults.
|
|
38
|
+
expect(model.identity.timeZone).toBe('UTC')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('parses and round-trips the broadened typed branding fields', () => {
|
|
42
|
+
const model = resolveOrganizationModel({
|
|
43
|
+
branding: {
|
|
44
|
+
organizationName: 'Acme',
|
|
45
|
+
productName: 'AcmeOS',
|
|
46
|
+
shortName: 'Acme',
|
|
47
|
+
voice: 'Direct and human — no jargon',
|
|
48
|
+
tagline: 'Automation that works while you sleep',
|
|
49
|
+
values: ['Transparency', 'Craftsmanship', 'Velocity'],
|
|
50
|
+
themePresetId: 'midnight'
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
expect(model.branding.voice).toBe('Direct and human — no jargon')
|
|
55
|
+
expect(model.branding.tagline).toBe('Automation that works while you sleep')
|
|
56
|
+
expect(model.branding.values).toEqual(['Transparency', 'Craftsmanship', 'Velocity'])
|
|
57
|
+
expect(model.branding.themePresetId).toBe('midnight')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('leaves the broadened branding fields undefined when not authored', () => {
|
|
61
|
+
const model = resolveOrganizationModel()
|
|
62
|
+
|
|
63
|
+
expect(model.branding.voice).toBeUndefined()
|
|
64
|
+
expect(model.branding.tagline).toBeUndefined()
|
|
65
|
+
expect(model.branding.values).toBeUndefined()
|
|
66
|
+
expect(model.branding.themePresetId).toBeUndefined()
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Names → identity: the four display-name fields (organizationName, productName,
|
|
72
|
+
* shortName, description) are now the recommended placement on `identity`. They are
|
|
73
|
+
* optional so that legacy tenants can continue to rely on `branding.*` fallbacks
|
|
74
|
+
* without breaking. These tests lock the contract: fields round-trip, are truly
|
|
75
|
+
* optional (no default), and branding fields still validate unchanged.
|
|
76
|
+
*/
|
|
77
|
+
describe('identity display-name fields — recommended placement (Step 5)', () => {
|
|
78
|
+
it('accepts all four name fields on identity and round-trips them through resolveOrganizationModel', () => {
|
|
79
|
+
const model = resolveOrganizationModel({
|
|
80
|
+
identity: {
|
|
81
|
+
organizationName: 'Acme Corp',
|
|
82
|
+
productName: 'AcmeOS',
|
|
83
|
+
shortName: 'Acme',
|
|
84
|
+
description: 'AI orchestration for modern teams.'
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
expect(model.identity.organizationName).toBe('Acme Corp')
|
|
89
|
+
expect(model.identity.productName).toBe('AcmeOS')
|
|
90
|
+
expect(model.identity.shortName).toBe('Acme')
|
|
91
|
+
expect(model.identity.description).toBe('AI orchestration for modern teams.')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('identity name fields are optional — a model with none set still resolves, and resolved values are undefined', () => {
|
|
95
|
+
const model = resolveOrganizationModel()
|
|
96
|
+
|
|
97
|
+
expect(model.identity.organizationName).toBeUndefined()
|
|
98
|
+
expect(model.identity.productName).toBeUndefined()
|
|
99
|
+
expect(model.identity.shortName).toBeUndefined()
|
|
100
|
+
expect(model.identity.description).toBeUndefined()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('identity name fields parse as undefined through IdentityDomainSchema directly (no defaults injected)', () => {
|
|
104
|
+
const result = IdentityDomainSchema.safeParse({})
|
|
105
|
+
expect(result.success).toBe(true)
|
|
106
|
+
if (result.success) {
|
|
107
|
+
expect(result.data.organizationName).toBeUndefined()
|
|
108
|
+
expect(result.data.productName).toBeUndefined()
|
|
109
|
+
expect(result.data.shortName).toBeUndefined()
|
|
110
|
+
expect(result.data.description).toBeUndefined()
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('identity.shortName rejects values exceeding 40 characters', () => {
|
|
115
|
+
expect(() =>
|
|
116
|
+
resolveOrganizationModel({
|
|
117
|
+
identity: { shortName: 'a'.repeat(41) } as never
|
|
118
|
+
})
|
|
119
|
+
).toThrow()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('identity.organizationName rejects empty string (LabelSchema min 1)', () => {
|
|
123
|
+
expect(() =>
|
|
124
|
+
resolveOrganizationModel({
|
|
125
|
+
identity: { organizationName: '' } as never
|
|
126
|
+
})
|
|
127
|
+
).toThrow()
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('identity.description rejects empty string (DescriptionSchema min 1)', () => {
|
|
131
|
+
expect(() =>
|
|
132
|
+
resolveOrganizationModel({
|
|
133
|
+
identity: { description: '' } as never
|
|
134
|
+
})
|
|
135
|
+
).toThrow()
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('identity name fields trim whitespace', () => {
|
|
139
|
+
const model = resolveOrganizationModel({
|
|
140
|
+
identity: {
|
|
141
|
+
organizationName: ' Acme Corp ',
|
|
142
|
+
shortName: ' Acme '
|
|
143
|
+
} as never
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
expect(model.identity.organizationName).toBe('Acme Corp')
|
|
147
|
+
expect(model.identity.shortName).toBe('Acme')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('branding still validates with its name fields — @deprecated tags change nothing at runtime', () => {
|
|
151
|
+
const model = resolveOrganizationModel({
|
|
152
|
+
branding: {
|
|
153
|
+
organizationName: 'Legacy Org',
|
|
154
|
+
productName: 'LegacyOS',
|
|
155
|
+
shortName: 'LGO',
|
|
156
|
+
description: 'Legacy description for back-compat.'
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
expect(model.branding.organizationName).toBe('Legacy Org')
|
|
161
|
+
expect(model.branding.productName).toBe('LegacyOS')
|
|
162
|
+
expect(model.branding.shortName).toBe('LGO')
|
|
163
|
+
expect(model.branding.description).toBe('Legacy description for back-compat.')
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The broadened branding fields are *typed*, not passthrough — their constraints
|
|
169
|
+
* are part of the published contract. These tests lock those bounds so a future
|
|
170
|
+
* edit can't silently widen/drop them, and confirm `.passthrough()` does NOT
|
|
171
|
+
* bypass validation for known fields (only unknown ones are let through).
|
|
172
|
+
*/
|
|
173
|
+
describe('broadened branding typed-field validation', () => {
|
|
174
|
+
it('rejects a voice longer than 280 characters', () => {
|
|
175
|
+
expect(() => resolveOrganizationModel({ branding: { voice: 'a'.repeat(281) } as never })).toThrow()
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('rejects a tagline longer than 200 characters', () => {
|
|
179
|
+
expect(() => resolveOrganizationModel({ branding: { tagline: 'a'.repeat(201) } as never })).toThrow()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('rejects an empty-string entry in values (each entry must be non-empty)', () => {
|
|
183
|
+
expect(() => resolveOrganizationModel({ branding: { values: ['Valid', ''] } as never })).toThrow()
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('rejects a themePresetId outside the 1–64 character bounds', () => {
|
|
187
|
+
expect(() => resolveOrganizationModel({ branding: { themePresetId: '' } as never })).toThrow()
|
|
188
|
+
expect(() => resolveOrganizationModel({ branding: { themePresetId: 'a'.repeat(65) } as never })).toThrow()
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('trims whitespace on string fields', () => {
|
|
192
|
+
const model = resolveOrganizationModel({
|
|
193
|
+
branding: { voice: ' trimmed voice ', tagline: ' trimmed tagline ' } as never
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
expect(model.branding.voice).toBe('trimmed voice')
|
|
197
|
+
expect(model.branding.tagline).toBe('trimmed tagline')
|
|
198
|
+
})
|
|
199
|
+
})
|
|
@@ -1,19 +1,61 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
import { DescriptionSchema, LabelSchema } from './shared'
|
|
3
|
-
|
|
4
|
-
export const OrganizationModelBrandingSchema = z
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { DescriptionSchema, LabelSchema } from './shared'
|
|
3
|
+
|
|
4
|
+
export const OrganizationModelBrandingSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Prefer `identity.organizationName`; branding retains it for back-compat.
|
|
8
|
+
* Legacy tenants that have not set `identity.organizationName` fall back to this field.
|
|
9
|
+
*/
|
|
10
|
+
organizationName: LabelSchema,
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Prefer `identity.productName`; branding retains it for back-compat.
|
|
13
|
+
* Legacy tenants that have not set `identity.productName` fall back to this field.
|
|
14
|
+
*/
|
|
15
|
+
productName: LabelSchema,
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Prefer `identity.shortName`; branding retains it for back-compat.
|
|
18
|
+
* Legacy tenants that have not set `identity.shortName` fall back to this field.
|
|
19
|
+
*/
|
|
20
|
+
shortName: z.string().trim().min(1).max(40),
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Prefer `identity.description`; branding retains it for back-compat.
|
|
23
|
+
* Legacy tenants that have not set `identity.description` fall back to this field.
|
|
24
|
+
*/
|
|
25
|
+
description: DescriptionSchema.optional(),
|
|
26
|
+
logos: z
|
|
27
|
+
.object({
|
|
28
|
+
light: z.string().trim().min(1).max(2048).optional(),
|
|
29
|
+
dark: z.string().trim().min(1).max(2048).optional()
|
|
30
|
+
})
|
|
31
|
+
.default({}),
|
|
32
|
+
/**
|
|
33
|
+
* Brand voice — how the organization communicates. Plain-language description
|
|
34
|
+
* of tone, register, and personality (e.g. "Direct and human — no jargon").
|
|
35
|
+
* Max 280 characters.
|
|
36
|
+
*/
|
|
37
|
+
voice: z.string().trim().max(280).optional(),
|
|
38
|
+
/**
|
|
39
|
+
* Brand tagline or positioning statement — the memorable one-liner that
|
|
40
|
+
* captures the brand's promise or differentiator. Max 200 characters.
|
|
41
|
+
*/
|
|
42
|
+
tagline: z.string().trim().max(200).optional(),
|
|
43
|
+
/**
|
|
44
|
+
* Core brand values — an ordered list of principles the organization stands
|
|
45
|
+
* for (e.g. ["Transparency", "Craftsmanship", "Velocity"]). Each entry must
|
|
46
|
+
* be a non-empty trimmed string.
|
|
47
|
+
*/
|
|
48
|
+
values: z.array(z.string().trim().min(1)).optional(),
|
|
49
|
+
/**
|
|
50
|
+
* ID of the active UI theme preset from the UI theme-presets registry.
|
|
51
|
+
* The UI layer resolves this to colors and typography via `usePresetsContext()`.
|
|
52
|
+
* Free-form string — validation and fallback state are handled at the UI layer.
|
|
53
|
+
* Min 1, max 64 characters.
|
|
54
|
+
*/
|
|
55
|
+
themePresetId: z.string().trim().min(1).max(64).optional()
|
|
56
|
+
})
|
|
57
|
+
.passthrough()
|
|
58
|
+
|
|
17
59
|
export const DEFAULT_ORGANIZATION_MODEL_BRANDING: z.infer<typeof OrganizationModelBrandingSchema> = {
|
|
18
60
|
organizationName: 'Default Organization',
|
|
19
61
|
productName: 'Organization OS',
|
|
@@ -1,94 +1,122 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.
|
|
17
|
-
.
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { DescriptionSchema, LabelSchema } from './shared'
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Business hours — simplest shape that captures weekday ranges.
|
|
6
|
+
// Each day of the week is optional; when present it holds open/close times
|
|
7
|
+
// in "HH:MM" 24-hour format. An empty object (default) means "not configured".
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
export const BusinessHoursDaySchema = z.object({
|
|
11
|
+
open: z
|
|
12
|
+
.string()
|
|
13
|
+
.trim()
|
|
14
|
+
.regex(/^\d{2}:\d{2}$/, 'Expected HH:MM format'),
|
|
15
|
+
close: z
|
|
16
|
+
.string()
|
|
17
|
+
.trim()
|
|
18
|
+
.regex(/^\d{2}:\d{2}$/, 'Expected HH:MM format')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export const BusinessHoursSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
monday: BusinessHoursDaySchema.optional(),
|
|
24
|
+
tuesday: BusinessHoursDaySchema.optional(),
|
|
25
|
+
wednesday: BusinessHoursDaySchema.optional(),
|
|
26
|
+
thursday: BusinessHoursDaySchema.optional(),
|
|
27
|
+
friday: BusinessHoursDaySchema.optional(),
|
|
28
|
+
saturday: BusinessHoursDaySchema.optional(),
|
|
29
|
+
sunday: BusinessHoursDaySchema.optional()
|
|
30
|
+
})
|
|
31
|
+
.default({})
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Identity domain schema — legal identity, mission/vision, industry anchors,
|
|
35
|
+
// and temporal/geographic context. Distinct from branding (display identity).
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
export const IdentityDomainSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
/** Why the organization exists — one or two plain-language sentences. */
|
|
41
|
+
mission: z.string().trim().max(1000).default(''),
|
|
42
|
+
/** Long-term direction the organization is moving toward. */
|
|
43
|
+
vision: z.string().trim().max(1000).default(''),
|
|
44
|
+
/** Legal registered name of the entity. */
|
|
45
|
+
legalName: z.string().trim().max(200).default(''),
|
|
46
|
+
/**
|
|
47
|
+
* Type of legal entity (e.g. "LLC", "Corporation", "Sole Proprietor",
|
|
48
|
+
* "Non-profit"). Free-form string so it covers any jurisdiction.
|
|
49
|
+
*/
|
|
50
|
+
entityType: z.string().trim().max(100).default(''),
|
|
51
|
+
/**
|
|
52
|
+
* Primary jurisdiction of registration or operation
|
|
53
|
+
* (e.g. "United States – Delaware", "Canada – Ontario").
|
|
54
|
+
*/
|
|
55
|
+
jurisdiction: z.string().trim().max(200).default(''),
|
|
56
|
+
/**
|
|
57
|
+
* Industry category — broad classification (e.g. "Marketing Agency",
|
|
58
|
+
* "Software / SaaS", "Professional Services").
|
|
59
|
+
*/
|
|
60
|
+
industryCategory: z.string().trim().max(200).default(''),
|
|
61
|
+
/**
|
|
62
|
+
* Geographic focus — where the organization primarily operates or serves
|
|
63
|
+
* (e.g. "North America", "Global", "Southeast Asia").
|
|
64
|
+
*/
|
|
65
|
+
geographicFocus: z.string().trim().max(200).default(''),
|
|
66
|
+
/**
|
|
67
|
+
* IANA timezone identifier for the organization's primary operating timezone
|
|
68
|
+
* (e.g. "America/Los_Angeles", "Europe/London", "UTC").
|
|
69
|
+
*/
|
|
70
|
+
timeZone: z.string().trim().max(100).default('UTC'),
|
|
71
|
+
/** Typical operating hours per day of week. Empty object means not configured. */
|
|
72
|
+
businessHours: BusinessHoursSchema,
|
|
73
|
+
/**
|
|
74
|
+
* Long-form markdown capturing client context, problem narrative, and domain
|
|
75
|
+
* background. Populated by /setup; surfaced to agents as organizational context.
|
|
76
|
+
* Optional — many projects have no external client.
|
|
77
|
+
*/
|
|
78
|
+
clientBrief: z.string().trim().default(''),
|
|
79
|
+
/**
|
|
80
|
+
* Display name of the organization as shown to end users.
|
|
81
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
82
|
+
* `branding.organizationName`. Falls back to `branding.organizationName` for
|
|
83
|
+
* legacy tenants that have not yet migrated.
|
|
84
|
+
*/
|
|
85
|
+
organizationName: LabelSchema.optional(),
|
|
86
|
+
/**
|
|
87
|
+
* Display name of the primary product or platform.
|
|
88
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
89
|
+
* `branding.productName`. Falls back to `branding.productName` for legacy tenants.
|
|
90
|
+
*/
|
|
91
|
+
productName: LabelSchema.optional(),
|
|
92
|
+
/**
|
|
93
|
+
* Short abbreviated name used in space-constrained UI surfaces (max 40 chars).
|
|
94
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
95
|
+
* `branding.shortName`. Falls back to `branding.shortName` for legacy tenants.
|
|
96
|
+
*/
|
|
97
|
+
shortName: z.string().trim().min(1).max(40).optional(),
|
|
98
|
+
/**
|
|
99
|
+
* Plain-language description of the organization for display and discovery.
|
|
100
|
+
* Recommended placement for display naming — prefer this over the deprecated
|
|
101
|
+
* `branding.description`. Falls back to `branding.description` for legacy tenants.
|
|
102
|
+
*/
|
|
103
|
+
description: DescriptionSchema.optional()
|
|
104
|
+
})
|
|
105
|
+
.passthrough()
|
|
106
|
+
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Seed — placeholder defaults; external adapters override per organization.
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
export const DEFAULT_ORGANIZATION_MODEL_IDENTITY: z.infer<typeof IdentityDomainSchema> = {
|
|
112
|
+
mission: '',
|
|
113
|
+
vision: '',
|
|
114
|
+
legalName: '',
|
|
115
|
+
entityType: '',
|
|
116
|
+
jurisdiction: '',
|
|
117
|
+
industryCategory: '',
|
|
118
|
+
geographicFocus: '',
|
|
119
|
+
timeZone: 'UTC',
|
|
120
|
+
businessHours: {},
|
|
121
|
+
clientBrief: ''
|
|
122
|
+
}
|
|
@@ -1465,6 +1465,51 @@ export type Database = {
|
|
|
1465
1465
|
},
|
|
1466
1466
|
]
|
|
1467
1467
|
}
|
|
1468
|
+
deployment_organization_models: {
|
|
1469
|
+
Row: {
|
|
1470
|
+
created_at: string
|
|
1471
|
+
deployment_id: string
|
|
1472
|
+
model_hash: string | null
|
|
1473
|
+
organization_id: string
|
|
1474
|
+
organization_model: Json
|
|
1475
|
+
schema_version: string
|
|
1476
|
+
updated_at: string
|
|
1477
|
+
}
|
|
1478
|
+
Insert: {
|
|
1479
|
+
created_at?: string
|
|
1480
|
+
deployment_id: string
|
|
1481
|
+
model_hash?: string | null
|
|
1482
|
+
organization_id: string
|
|
1483
|
+
organization_model: Json
|
|
1484
|
+
schema_version?: string
|
|
1485
|
+
updated_at?: string
|
|
1486
|
+
}
|
|
1487
|
+
Update: {
|
|
1488
|
+
created_at?: string
|
|
1489
|
+
deployment_id?: string
|
|
1490
|
+
model_hash?: string | null
|
|
1491
|
+
organization_id?: string
|
|
1492
|
+
organization_model?: Json
|
|
1493
|
+
schema_version?: string
|
|
1494
|
+
updated_at?: string
|
|
1495
|
+
}
|
|
1496
|
+
Relationships: [
|
|
1497
|
+
{
|
|
1498
|
+
foreignKeyName: "deployment_organization_models_deployment_id_fkey"
|
|
1499
|
+
columns: ["deployment_id"]
|
|
1500
|
+
isOneToOne: true
|
|
1501
|
+
referencedRelation: "deployments"
|
|
1502
|
+
referencedColumns: ["id"]
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
foreignKeyName: "deployment_organization_models_organization_id_fkey"
|
|
1506
|
+
columns: ["organization_id"]
|
|
1507
|
+
isOneToOne: false
|
|
1508
|
+
referencedRelation: "organizations"
|
|
1509
|
+
referencedColumns: ["id"]
|
|
1510
|
+
},
|
|
1511
|
+
]
|
|
1512
|
+
}
|
|
1468
1513
|
deployments: {
|
|
1469
1514
|
Row: {
|
|
1470
1515
|
created_at: string
|