@elevasis/core 0.2.0 → 0.3.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.
Files changed (44) hide show
  1. package/dist/index.d.ts +60 -103
  2. package/dist/index.js +162 -109
  3. package/dist/organization-model/index.d.ts +60 -103
  4. package/dist/organization-model/index.js +162 -109
  5. package/package.json +1 -1
  6. package/src/README.md +24 -17
  7. package/src/__tests__/template-foundations-compatibility.test.ts +28 -36
  8. package/src/auth/multi-tenancy/types.ts +4 -11
  9. package/src/auth/multi-tenancy/users/api-schemas.ts +1 -1
  10. package/src/business/base-entities.test.ts +481 -0
  11. package/src/business/base-entities.ts +241 -0
  12. package/src/business/delivery/types.ts +1 -1
  13. package/src/business/index.ts +3 -0
  14. package/src/execution/index.ts +3 -6
  15. package/src/index.ts +1 -1
  16. package/src/organization-model/README.md +25 -26
  17. package/src/organization-model/__tests__/graph.test.ts +103 -71
  18. package/src/organization-model/__tests__/resolve.test.ts +20 -29
  19. package/src/organization-model/contracts.ts +3 -0
  20. package/src/organization-model/defaults.ts +40 -6
  21. package/src/organization-model/domains/features.ts +19 -54
  22. package/src/organization-model/domains/navigation.ts +25 -16
  23. package/src/organization-model/domains/shared.ts +1 -10
  24. package/src/organization-model/foundation.ts +96 -0
  25. package/src/organization-model/graph/build.ts +34 -67
  26. package/src/organization-model/graph/schema.ts +2 -4
  27. package/src/organization-model/graph/types.ts +3 -15
  28. package/src/organization-model/index.ts +2 -0
  29. package/src/organization-model/organization-model.mdx +34 -36
  30. package/src/organization-model/published.ts +12 -3
  31. package/src/organization-model/schema.ts +38 -34
  32. package/src/organization-model/types.ts +5 -10
  33. package/src/platform/constants/versions.ts +1 -1
  34. package/src/platform/sse/events.ts +1 -34
  35. package/src/projects/api-schemas.ts +2 -1
  36. package/src/reference/_generated/contracts.md +10 -31
  37. package/src/reference/glossary.md +14 -18
  38. package/src/supabase/database.types.ts +0 -107
  39. package/src/test-utils/rls/RLSTestContext.ts +1 -31
  40. package/src/execution/calibration/__tests__/schemas.test.ts +0 -320
  41. package/src/execution/calibration/index.ts +0 -3
  42. package/src/execution/calibration/schemas.ts +0 -121
  43. package/src/execution/calibration/sse-events.ts +0 -125
  44. package/src/execution/calibration/types.ts +0 -190
@@ -0,0 +1,241 @@
1
+ import { z } from 'zod'
2
+
3
+ /**
4
+ * Base Entity Contracts
5
+ *
6
+ * Typed base interfaces for CRM, Lead-Gen (Acquisition), and Projects domains.
7
+ * Each uses a `<TMeta>` generic parameter so client projects can narrow the
8
+ * metadata type in their own `foundations/types/` directory.
9
+ *
10
+ * These are PARALLEL abstractions — they do NOT replace or modify the existing
11
+ * row types (ProjectRow, AcqDealRow, etc.). Use these as the SDK-facing contract
12
+ * layer; use the row types internally for direct Supabase access.
13
+ *
14
+ * Usage in a client project:
15
+ * import { BaseProject } from '@elevasis/core' (or '@repo/core' internally)
16
+ * type Project = BaseProject<{ budget: number; riskScore: 'low' | 'medium' | 'high' }>
17
+ *
18
+ * Extending a Zod schema in a client project:
19
+ * import { BaseProjectSchema } from '@elevasis/core'
20
+ * const ProjectMetaSchema = z.object({ budget: z.number(), riskScore: z.enum(['low','medium','high']) })
21
+ * const ProjectSchema = BaseProjectSchema.extend({ metadata: ProjectMetaSchema })
22
+ */
23
+
24
+ // =============================================================================
25
+ // Projects / Delivery
26
+ // =============================================================================
27
+
28
+ /**
29
+ * Common fields shared across all project implementations.
30
+ * `TMeta` narrows the `metadata` JSONB column (prj_projects.metadata).
31
+ */
32
+ export interface BaseProject<TMeta = Record<string, unknown>> {
33
+ id: string
34
+ organizationId: string
35
+ name: string
36
+ kind: string
37
+ status: string
38
+ description: string | null
39
+ metadata: TMeta
40
+ createdAt: string
41
+ updatedAt: string
42
+ }
43
+
44
+ /**
45
+ * Common fields shared across all milestone implementations.
46
+ * `TMeta` narrows the `metadata` JSONB column (prj_milestones.metadata).
47
+ */
48
+ export interface BaseMilestone<TMeta = Record<string, unknown>> {
49
+ id: string
50
+ organizationId: string
51
+ projectId: string
52
+ name: string
53
+ status: string
54
+ description: string | null
55
+ metadata: TMeta
56
+ createdAt: string
57
+ updatedAt: string
58
+ }
59
+
60
+ /**
61
+ * Common fields shared across all task implementations.
62
+ * `TMeta` narrows the `metadata` JSONB column (prj_tasks.metadata).
63
+ */
64
+ export interface BaseTask<TMeta = Record<string, unknown>> {
65
+ id: string
66
+ organizationId: string
67
+ projectId: string
68
+ name: string
69
+ status: string
70
+ type: string
71
+ description: string | null
72
+ metadata: TMeta
73
+ createdAt: string
74
+ updatedAt: string
75
+ }
76
+
77
+ // =============================================================================
78
+ // CRM / Acquisition
79
+ // =============================================================================
80
+
81
+ /**
82
+ * Common fields shared across all deal implementations.
83
+ * `TMeta` is an extension point for client-specific deal metadata.
84
+ * Note: The underlying acq_deals table does not have a `metadata` column;
85
+ * this field serves as a typed extension slot for SDK consumers.
86
+ */
87
+ export interface BaseDeal<TMeta = Record<string, unknown>> {
88
+ id: string
89
+ organizationId: string
90
+ contactEmail: string
91
+ stage: string | null
92
+ metadata: TMeta
93
+ createdAt: string
94
+ updatedAt: string
95
+ }
96
+
97
+ /**
98
+ * Common fields shared across all company implementations.
99
+ * `TMeta` is an extension point for client-specific company metadata.
100
+ */
101
+ export interface BaseCompany<TMeta = Record<string, unknown>> {
102
+ id: string
103
+ organizationId: string
104
+ name: string
105
+ domain: string | null
106
+ status: string
107
+ metadata: TMeta
108
+ createdAt: string
109
+ updatedAt: string
110
+ }
111
+
112
+ /**
113
+ * Common fields shared across all contact implementations.
114
+ * `TMeta` is an extension point for client-specific contact metadata.
115
+ */
116
+ export interface BaseContact<TMeta = Record<string, unknown>> {
117
+ id: string
118
+ organizationId: string
119
+ email: string
120
+ firstName: string | null
121
+ lastName: string | null
122
+ status: string
123
+ metadata: TMeta
124
+ createdAt: string
125
+ updatedAt: string
126
+ }
127
+
128
+ // =============================================================================
129
+ // Base Zod Schemas
130
+ // =============================================================================
131
+
132
+ /**
133
+ * Base Zod schema for a project record.
134
+ * Extend with `BaseProjectSchema.extend({ metadata: ProjectMetaSchema })`.
135
+ */
136
+ export const BaseProjectSchema = z.object({
137
+ id: z.string(),
138
+ organizationId: z.string(),
139
+ name: z.string(),
140
+ kind: z.string(),
141
+ status: z.string(),
142
+ description: z.string().nullable(),
143
+ metadata: z.record(z.string(), z.unknown()).default({}),
144
+ createdAt: z.string(),
145
+ updatedAt: z.string()
146
+ })
147
+
148
+ /**
149
+ * Base Zod schema for a milestone record.
150
+ * Extend with `BaseMilestoneSchema.extend({ metadata: MilestoneMetaSchema })`.
151
+ */
152
+ export const BaseMilestoneSchema = z.object({
153
+ id: z.string(),
154
+ organizationId: z.string(),
155
+ projectId: z.string(),
156
+ name: z.string(),
157
+ status: z.string(),
158
+ description: z.string().nullable(),
159
+ metadata: z.record(z.string(), z.unknown()).default({}),
160
+ createdAt: z.string(),
161
+ updatedAt: z.string()
162
+ })
163
+
164
+ /**
165
+ * Base Zod schema for a task record.
166
+ * Extend with `BaseTaskSchema.extend({ metadata: TaskMetaSchema })`.
167
+ */
168
+ export const BaseTaskSchema = z.object({
169
+ id: z.string(),
170
+ organizationId: z.string(),
171
+ projectId: z.string(),
172
+ name: z.string(),
173
+ status: z.string(),
174
+ type: z.string(),
175
+ description: z.string().nullable(),
176
+ metadata: z.record(z.string(), z.unknown()).default({}),
177
+ createdAt: z.string(),
178
+ updatedAt: z.string()
179
+ })
180
+
181
+ /**
182
+ * Base Zod schema for a deal record.
183
+ * Extend with `BaseDealSchema.extend({ metadata: DealMetaSchema })`.
184
+ */
185
+ export const BaseDealSchema = z.object({
186
+ id: z.string(),
187
+ organizationId: z.string(),
188
+ contactEmail: z.string(),
189
+ stage: z.string().nullable(),
190
+ metadata: z.record(z.string(), z.unknown()).default({}),
191
+ createdAt: z.string(),
192
+ updatedAt: z.string()
193
+ })
194
+
195
+ /**
196
+ * Base Zod schema for a company record.
197
+ * Extend with `BaseCompanySchema.extend({ metadata: CompanyMetaSchema })`.
198
+ */
199
+ export const BaseCompanySchema = z.object({
200
+ id: z.string(),
201
+ organizationId: z.string(),
202
+ name: z.string(),
203
+ domain: z.string().nullable(),
204
+ status: z.string(),
205
+ metadata: z.record(z.string(), z.unknown()).default({}),
206
+ createdAt: z.string(),
207
+ updatedAt: z.string()
208
+ })
209
+
210
+ /**
211
+ * Base Zod schema for a contact record.
212
+ * Extend with `BaseContactSchema.extend({ metadata: ContactMetaSchema })`.
213
+ */
214
+ export const BaseContactSchema = z.object({
215
+ id: z.string(),
216
+ organizationId: z.string(),
217
+ email: z.string(),
218
+ firstName: z.string().nullable(),
219
+ lastName: z.string().nullable(),
220
+ status: z.string(),
221
+ metadata: z.record(z.string(), z.unknown()).default({}),
222
+ createdAt: z.string(),
223
+ updatedAt: z.string()
224
+ })
225
+
226
+ // =============================================================================
227
+ // Inferred types (convenience — matches the interface shapes above)
228
+ // =============================================================================
229
+
230
+ /** Default (unnarrowed) inferred type from BaseProjectSchema */
231
+ export type BaseProjectInput = z.infer<typeof BaseProjectSchema>
232
+ /** Default (unnarrowed) inferred type from BaseMilestoneSchema */
233
+ export type BaseMilestoneInput = z.infer<typeof BaseMilestoneSchema>
234
+ /** Default (unnarrowed) inferred type from BaseTaskSchema */
235
+ export type BaseTaskInput = z.infer<typeof BaseTaskSchema>
236
+ /** Default (unnarrowed) inferred type from BaseDealSchema */
237
+ export type BaseDealInput = z.infer<typeof BaseDealSchema>
238
+ /** Default (unnarrowed) inferred type from BaseCompanySchema */
239
+ export type BaseCompanyInput = z.infer<typeof BaseCompanySchema>
240
+ /** Default (unnarrowed) inferred type from BaseContactSchema */
241
+ export type BaseContactInput = z.infer<typeof BaseContactSchema>
@@ -19,7 +19,7 @@ export type NoteInsert = Database['public']['Tables']['prj_notes']['Insert']
19
19
  // Status enums
20
20
  export type ProjectStatus = 'active' | 'on_track' | 'at_risk' | 'blocked' | 'completed' | 'paused'
21
21
 
22
- export type ProjectKind = 'client_engagement' | 'internal'
22
+ export type ProjectKind = 'client_engagement' | 'internal' | 'research' | 'other'
23
23
 
24
24
  export type MilestoneStatus = 'upcoming' | 'in_progress' | 'completed' | 'overdue' | 'blocked'
25
25
 
@@ -10,3 +10,6 @@ export * from './acquisition/index'
10
10
 
11
11
  // SEO types (seo_pages, seo_metrics, chart types)
12
12
  export * from './seo/index'
13
+
14
+ // Base entity contracts (generic TMeta types for SDK consumers)
15
+ export * from './base-entities'
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Execution group barrel - browser-safe exports
3
3
  *
4
- * Execution engine, core types, scheduler, calibration
4
+ * Execution engine, core types, scheduler
5
5
  */
6
6
 
7
7
  // Execution Engine
@@ -13,8 +13,5 @@ export * from './core/index'
13
13
  // Scheduler types
14
14
  export * from './scheduler/index'
15
15
 
16
- // Calibration types and schemas
17
- export * from './calibration/index'
18
-
19
- // Integration types (browser-safe param/result interfaces for adapters)
20
- export * from './engine/tools/integration/types'
16
+ // Integration types (browser-safe param/result interfaces for adapters)
17
+ export * from './engine/tools/integration/types'
package/src/index.ts CHANGED
@@ -21,7 +21,7 @@ export * from './platform'
21
21
  // Auth: multi-tenancy types
22
22
  export * from './auth'
23
23
 
24
- // Execution: engine, core types, scheduler, calibration
24
+ // Execution: engine, core types, scheduler
25
25
  export * from './execution'
26
26
 
27
27
  // Commands: command queue types
@@ -12,6 +12,9 @@ The public entry point exposes:
12
12
  - `DEFAULT_ORGANIZATION_MODEL`
13
13
  - `defineOrganizationModel`
14
14
  - `resolveOrganizationModel`
15
+ - `PROJECTS_FEATURE_ID`
16
+ - `PROJECTS_INDEX_SURFACE_ID`
17
+ - `DELIVERY_PROJECTS_VIEW_CAPABILITY_ID`
15
18
  - `OrganizationModel` and the supporting domain types
16
19
 
17
20
  Import it from the published subpath:
@@ -19,7 +22,10 @@ Import it from the published subpath:
19
22
  ```ts
20
23
  import {
21
24
  DEFAULT_ORGANIZATION_MODEL,
25
+ DELIVERY_PROJECTS_VIEW_CAPABILITY_ID,
22
26
  defineOrganizationModel,
27
+ PROJECTS_FEATURE_ID,
28
+ PROJECTS_INDEX_SURFACE_ID,
23
29
  resolveOrganizationModel,
24
30
  type OrganizationModel
25
31
  } from '@elevasis/core/organization-model'
@@ -31,43 +37,36 @@ The model is versioned and currently validates against `version: 1`.
31
37
 
32
38
  Top-level fields:
33
39
 
34
- - `domains` - semantic domain entries that bind entity IDs, surface IDs, resource IDs, and capability IDs.
40
+ - `version` - schema version for the resolved contract.
35
41
  - `branding` - organization branding defaults and overrides.
36
- - `features` - grouped shell-level feature flags and labels.
42
+ - `features` - unified feature entries that combine enablement, labels, and semantic references.
37
43
  - `navigation` - navigation model for the product shell.
38
44
  - `crm` - CRM-specific contract data.
39
45
  - `leadGen` - lead generation contract data.
40
46
  - `delivery` - delivery and project contract data.
41
47
  - `resourceMappings` - cross-surface resource mappings.
42
48
 
43
- ## Default Domain Set
49
+ ## Default Feature Set
44
50
 
45
- The default model includes four semantic domains:
51
+ The default model includes seven feature IDs:
46
52
 
47
53
  - `crm` - deal pipeline and relationship management.
48
54
  - `lead-gen` - lists, companies, and contacts.
49
- - `delivery` - projects, milestones, and tasks.
55
+ - `projects` - projects, milestones, and tasks.
50
56
  - `operations` - organization graph and command-view surfaces.
57
+ - `monitoring` - monitoring surfaces.
58
+ - `settings` - organization settings.
59
+ - `seo` - SEO surfaces (disabled by default).
51
60
 
52
- ## Feature Keys
61
+ ## Project Bridge Constants
53
62
 
54
- The current canonical feature keys are grouped shell features:
63
+ The organization-model surface now exports a narrow set of canonical IDs for the shared Projects bridge:
55
64
 
56
- - `acquisition`
57
- - `delivery`
58
- - `operations`
59
- - `monitoring`
60
- - `settings`
61
- - `calibration`
62
- - `seo`
65
+ - `PROJECTS_FEATURE_ID` -> `projects`
66
+ - `PROJECTS_INDEX_SURFACE_ID` -> `projects.index`
67
+ - `DELIVERY_PROJECTS_VIEW_CAPABILITY_ID` -> `delivery.projects.view`
63
68
 
64
- Each feature can carry an enabled flag and an optional label override.
65
-
66
- This is intentionally different from the domain and surface vocabulary:
67
-
68
- - domains and surface IDs still use IDs such as `crm`, `lead-gen`, and `projects.index`
69
- - navigation surfaces point those routes at grouped `featureKey` values such as `acquisition` and `delivery`
70
- - downstream apps may still carry compatibility aliases for legacy route-level keys, but the published organization-model contract does not
69
+ Use these when wiring shared UI manifests, template adapters, or other consumers that need to agree on the same Projects contract without repeating raw literals.
71
70
 
72
71
  ## Resolution Semantics
73
72
 
@@ -82,13 +81,13 @@ This is intentionally different from the domain and surface vocabulary:
82
81
 
83
82
  - `navigation.defaultSurfaceId` must point at a declared navigation surface.
84
83
  - Every navigation group `surfaceId` must resolve to a declared surface.
85
- - Domain, surface, and resource-mapping IDs must resolve to declared counterparts; dangling references fail validation.
86
- - Domain-to-surface and domain/surface-to-resource links are validated in both directions so one-sided declarations fail during resolution.
87
- - Feature-bearing surfaces validate `featureKey` against the canonical grouped feature set.
84
+ - Feature, surface, and resource-mapping IDs must resolve to declared counterparts; dangling references fail validation.
85
+ - Feature-to-surface and feature/surface-to-resource links are validated in both directions so one-sided declarations fail during resolution.
86
+ - Feature-bearing surfaces validate `featureId` against the canonical feature set.
88
87
 
89
88
  ## Practical Guidance
90
89
 
91
90
  - Use `resolveOrganizationModel()` when you need a runtime-safe model for rendering or policy checks.
92
91
  - Use `defineOrganizationModel()` when authoring a static partial model in source.
93
- - Treat `features.enabled` and `features.labels` as the shell-level contract; do not use `crm`, `lead-gen`, or `projects` as canonical feature keys in new organization-model authoring.
94
- - Keep domain IDs, surface IDs, and capability IDs stable because downstream UI and policy code depend on them.
92
+ - Treat feature IDs such as `crm`, `lead-gen`, and `projects` as the canonical shell-level contract in new organization-model authoring.
93
+ - Keep feature IDs, surface IDs, and capability IDs stable because downstream UI and policy code depend on them.