levrops-contracts 1.3.1 → 1.3.2
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/README.md +83 -0
- package/contracts/backend/schema/migration_discipline.schema.yaml +220 -0
- package/contracts/content/heirloom/lead-capture.ts +212 -0
- package/contracts/content/index.ts +8 -0
- package/creative/README.md +21 -0
- package/creative/creative_cluster.schema.json +44 -0
- package/creative/creative_edge_alignment.schema.json +59 -0
- package/creative/creative_signal_profile.schema.json +71 -0
- package/creative/creative_whisper.schema.json +70 -0
- package/creative/models.py +86 -0
- package/creative/requirements.txt +2 -0
- package/package.json +6 -4
- package/sanity/schema/generated/blocks/cta.ts +68 -0
- package/sanity/schema/generated/blocks/editorial_grid.ts +58 -0
- package/sanity/schema/generated/blocks/hero.ts +72 -0
- package/sanity/schema/generated/blocks/product.ts +66 -0
- package/sanity/schema/generated/blocks/story.ts +59 -0
- package/sanity/schema/generated/index.ts +16 -0
- package/sanity/schema/generated/page.ts +74 -0
- package/sanity/schema/levropsStructure/blocks/cta.ts +77 -0
- package/sanity/schema/levropsStructure/blocks/editorialGrid.ts +66 -0
- package/sanity/schema/levropsStructure/blocks/hero.ts +71 -0
- package/sanity/schema/levropsStructure/blocks/product.ts +69 -0
- package/sanity/schema/levropsStructure/blocks/ritual.ts +59 -0
- package/sanity/schema/levropsStructure/blocks/story.ts +57 -0
- package/sanity/schema/levropsStructure/index.ts +21 -0
- package/sanity/schema/levropsStructure/page.ts +118 -0
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Source of truth for LevrOps API and event contracts, JSON schemas, and generated
|
|
|
8
8
|
- `asyncapi/` – AsyncAPI contracts for event/webhook payloads (`events.yaml`)
|
|
9
9
|
- `schemas/` – Shared JSON Schemas for core LevrOps domain objects
|
|
10
10
|
- `contracts/content/` – Content contracts for Sanity schema generation
|
|
11
|
+
- `contracts/designops/` – DesignOps contracts for design system orchestration (design systems, projects, artifacts, agents)
|
|
12
|
+
- `examples/` – Example contract instances for reference
|
|
11
13
|
- `clients/ts/` – TypeScript SDK generated from the OpenAPI specification
|
|
12
14
|
- `sanity/generated/` – Generated Sanity schema from content contracts
|
|
13
15
|
- `COMPAT.json` – Compatibility matrix between API, events, and SDK releases
|
|
@@ -134,6 +136,87 @@ export default {
|
|
|
134
136
|
|
|
135
137
|
See `docs/sanity-integration.md` for detailed integration instructions.
|
|
136
138
|
|
|
139
|
+
## DesignOps Contracts
|
|
140
|
+
|
|
141
|
+
DesignOps contracts enable ConductorOps and other agents to reason about and orchestrate design work (Figma, design systems, UI flows) in the same way they already reason about backend/frontend/ops.
|
|
142
|
+
|
|
143
|
+
**Contract Types:**
|
|
144
|
+
- **DesignSystemContract** - Reusable design systems (colors, typography, spacing, components)
|
|
145
|
+
- **DesignProjectContract** - Design projects (apps, features, flows, landing pages)
|
|
146
|
+
- **DesignArtifactContract** - Maps Figma components/frames to code components/tokens
|
|
147
|
+
- **DesignOpsAgentContract** - Agent configuration for orchestrating design workflows
|
|
148
|
+
|
|
149
|
+
**Schema Files:**
|
|
150
|
+
- `schemas/design_system.json` - DesignSystemContract schema
|
|
151
|
+
- `schemas/design_project.json` - DesignProjectContract schema
|
|
152
|
+
- `schemas/design_artifact.json` - DesignArtifactContract schema
|
|
153
|
+
- `schemas/designops_agent.json` - DesignOpsAgentContract schema
|
|
154
|
+
|
|
155
|
+
**Examples:**
|
|
156
|
+
- `examples/designops/levrops-core-design-system.json` - Example design system
|
|
157
|
+
- `examples/designops/conductorops-dashboard-project.json` - Example design project
|
|
158
|
+
- `examples/designops/design-artifacts-example.json` - Example artifact mappings
|
|
159
|
+
- `examples/designops/designops-agent-example.json` - Example agent configuration
|
|
160
|
+
|
|
161
|
+
See `docs/designops.md` for detailed documentation on DesignOps contracts and integration with ConductorOps.
|
|
162
|
+
|
|
163
|
+
## E-commerce Contracts
|
|
164
|
+
|
|
165
|
+
E-commerce contracts enable reporting and management of preorder deposits across multi-tenant e-commerce integrations.
|
|
166
|
+
|
|
167
|
+
**Contract Types:**
|
|
168
|
+
- **PreorderDepositReport** - Aggregated report of preorder deposits with summary statistics
|
|
169
|
+
- **PreorderDepositOrder** - Individual preorder deposit order with deposit and balance information
|
|
170
|
+
|
|
171
|
+
**Schema Files:**
|
|
172
|
+
- `schemas/preorder_deposit_report.json` - PreorderDepositReport schema
|
|
173
|
+
- `schemas/preorder_deposit_order.json` - PreorderDepositOrder schema
|
|
174
|
+
|
|
175
|
+
**API Endpoints:**
|
|
176
|
+
- `GET /api/v1/tenants/{tenantId}/ecommerce/preorder-deposits` - Get preorder deposit report
|
|
177
|
+
- `GET /api/v1/tenants/{tenantId}/ecommerce/preorder-deposits/{orderId}` - Get order details
|
|
178
|
+
- `POST /api/v1/tenants/{tenantId}/ecommerce/preorder-deposits/{orderId}/charge-balance` - Charge balance
|
|
179
|
+
|
|
180
|
+
**Examples:**
|
|
181
|
+
- `examples/ecommerce/preorder-deposit-report-example.json` - Example preorder deposit report
|
|
182
|
+
|
|
183
|
+
## Editorial Content Engine Contracts
|
|
184
|
+
|
|
185
|
+
The Editorial Content Engine provides standardized content management capabilities for creating, scheduling, and publishing content across multiple channels (social media, blogs, email campaigns) across all LevrOps products.
|
|
186
|
+
|
|
187
|
+
**Contract Types:**
|
|
188
|
+
- **Campaign** - Marketing campaigns that organize multiple content assets
|
|
189
|
+
- **ContentAsset** - Content assets (articles, blog posts, social posts, emails, videos) with rich content support
|
|
190
|
+
- **Channel** - Publishing channels (Instagram, Facebook, Newsletter, Sanity, Shopify Blog, etc.)
|
|
191
|
+
- **ContentTopic** - Topics/categories for organizing content
|
|
192
|
+
|
|
193
|
+
**Schema Files:**
|
|
194
|
+
- `schemas/campaign.json` - Campaign schema
|
|
195
|
+
- `schemas/content_asset.json` - ContentAsset schema (updated with rich content, media attachments, timezone support)
|
|
196
|
+
- `schemas/channel.json` - Channel schema
|
|
197
|
+
- `schemas/content_topic.json` - ContentTopic schema
|
|
198
|
+
|
|
199
|
+
**API Endpoints:**
|
|
200
|
+
All endpoints are under `/api/v1/editorial/`:
|
|
201
|
+
- Campaign management: `/campaigns/`, `/campaigns/{id}/`, `/campaigns/{id}/add-assets/`, `/campaigns/{id}/remove-assets/`
|
|
202
|
+
- Content asset management: `/assets/`, `/assets/{id}/`, `/assets/{id}/publish/`, `/assets/{id}/publish-status/`
|
|
203
|
+
- Channel management: `/channels/`, `/channels/{id}/`
|
|
204
|
+
- Topic management: `/topics/`, `/topics/{id}/`
|
|
205
|
+
|
|
206
|
+
**Key Features:**
|
|
207
|
+
- Rich content support (HTML body + structured JSON for Portable Text, Slate, etc.)
|
|
208
|
+
- Media attachments with metadata
|
|
209
|
+
- Timezone-aware scheduling
|
|
210
|
+
- Multi-channel publishing (Instagram, Facebook, TikTok, Newsletter, Sanity, Shopify Blog)
|
|
211
|
+
- Campaign organization and performance tracking
|
|
212
|
+
- Publishing workflow status tracking
|
|
213
|
+
|
|
214
|
+
**Examples:**
|
|
215
|
+
- `examples/editorial/summer-collection-campaign.json` - Example campaign
|
|
216
|
+
- `examples/editorial/summer-collection-preview-asset.json` - Example content asset
|
|
217
|
+
- `examples/editorial/instagram-channel.json` - Example channel
|
|
218
|
+
- `examples/editorial/fashion-topic.json` - Example topic
|
|
219
|
+
|
|
137
220
|
## Versioning
|
|
138
221
|
|
|
139
222
|
- Use semantic versioning for the repo (`VERSION`) and the TypeScript SDK.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
$schema: "https://json-schema.org/draft/2020-12/schema"
|
|
2
|
+
$id: "https://contracts.levrops.com/schemas/backend/migration_discipline.json"
|
|
3
|
+
title: "Migration Drift Prevention Contract"
|
|
4
|
+
description: |
|
|
5
|
+
Defines rules and constraints for Django migrations in a multi-tenant
|
|
6
|
+
django-tenants environment to prevent migration drift, cross-tenancy FK
|
|
7
|
+
violations, and improper migration ordering.
|
|
8
|
+
|
|
9
|
+
type: object
|
|
10
|
+
required:
|
|
11
|
+
- version
|
|
12
|
+
- rules
|
|
13
|
+
- enforcement
|
|
14
|
+
|
|
15
|
+
properties:
|
|
16
|
+
version:
|
|
17
|
+
type: string
|
|
18
|
+
description: "Contract version (semver)"
|
|
19
|
+
pattern: "^\\d+\\.\\d+\\.\\d+$"
|
|
20
|
+
default: "1.0.0"
|
|
21
|
+
|
|
22
|
+
rules:
|
|
23
|
+
type: object
|
|
24
|
+
description: "Migration discipline rules"
|
|
25
|
+
required:
|
|
26
|
+
- migration_commands
|
|
27
|
+
- cross_tenancy_fk
|
|
28
|
+
- migration_dependencies
|
|
29
|
+
|
|
30
|
+
properties:
|
|
31
|
+
migration_commands:
|
|
32
|
+
type: object
|
|
33
|
+
description: "Rules for allowed migration commands"
|
|
34
|
+
properties:
|
|
35
|
+
forbidden_patterns:
|
|
36
|
+
type: array
|
|
37
|
+
description: |
|
|
38
|
+
Command patterns that are forbidden. These patterns match
|
|
39
|
+
app-level migrate commands that bypass schema/tenant isolation.
|
|
40
|
+
items:
|
|
41
|
+
type: string
|
|
42
|
+
default:
|
|
43
|
+
- "manage.py migrate core"
|
|
44
|
+
- "manage.py migrate org"
|
|
45
|
+
- "manage.py migrate [a-z_]+"
|
|
46
|
+
examples:
|
|
47
|
+
- "manage.py migrate core"
|
|
48
|
+
- "manage.py migrate org"
|
|
49
|
+
- "manage.py migrate api"
|
|
50
|
+
|
|
51
|
+
required_patterns:
|
|
52
|
+
type: array
|
|
53
|
+
description: |
|
|
54
|
+
Command patterns that must be used instead. These ensure
|
|
55
|
+
proper schema/tenant isolation.
|
|
56
|
+
items:
|
|
57
|
+
type: string
|
|
58
|
+
default:
|
|
59
|
+
- "manage.py migrate"
|
|
60
|
+
- "manage.py migrate_schemas --shared"
|
|
61
|
+
- "manage.py migrate_schemas --tenant"
|
|
62
|
+
|
|
63
|
+
explanation:
|
|
64
|
+
type: string
|
|
65
|
+
description: "Human-readable explanation of why app-level migrations are forbidden"
|
|
66
|
+
default: |
|
|
67
|
+
In django-tenants, app-level migrations (e.g., `migrate core`)
|
|
68
|
+
bypass schema isolation and can cause migration drift. Always use:
|
|
69
|
+
- `manage.py migrate` (for public schema)
|
|
70
|
+
- `manage.py migrate_schemas --shared` (for shared apps)
|
|
71
|
+
- `manage.py migrate_schemas --tenant` (for tenant apps)
|
|
72
|
+
|
|
73
|
+
cross_tenancy_fk:
|
|
74
|
+
type: object
|
|
75
|
+
description: "Rules preventing cross-tenancy foreign key violations"
|
|
76
|
+
properties:
|
|
77
|
+
forbidden:
|
|
78
|
+
type: boolean
|
|
79
|
+
description: "Whether cross-tenancy FKs are forbidden"
|
|
80
|
+
default: true
|
|
81
|
+
|
|
82
|
+
definition:
|
|
83
|
+
type: string
|
|
84
|
+
description: "What constitutes a cross-tenancy FK violation"
|
|
85
|
+
default: |
|
|
86
|
+
A model in SHARED_APPS having a ForeignKey, OneToOneField, or
|
|
87
|
+
ManyToManyField to a model in TENANT_APPS (or vice versa).
|
|
88
|
+
|
|
89
|
+
allowed_exceptions:
|
|
90
|
+
type: array
|
|
91
|
+
description: |
|
|
92
|
+
Specific model/field combinations that are allowed despite
|
|
93
|
+
being cross-tenancy. Use sparingly and document why.
|
|
94
|
+
items:
|
|
95
|
+
type: object
|
|
96
|
+
properties:
|
|
97
|
+
app:
|
|
98
|
+
type: string
|
|
99
|
+
model:
|
|
100
|
+
type: string
|
|
101
|
+
field:
|
|
102
|
+
type: string
|
|
103
|
+
reason:
|
|
104
|
+
type: string
|
|
105
|
+
default: []
|
|
106
|
+
|
|
107
|
+
explanation:
|
|
108
|
+
type: string
|
|
109
|
+
description: "Why cross-tenancy FKs are problematic"
|
|
110
|
+
default: |
|
|
111
|
+
Cross-tenancy FKs break schema isolation. Shared apps are
|
|
112
|
+
schema-agnostic and cannot reference tenant-specific models.
|
|
113
|
+
Tenant apps cannot reference shared models via FK (use string
|
|
114
|
+
IDs or separate lookup tables instead).
|
|
115
|
+
|
|
116
|
+
migration_dependencies:
|
|
117
|
+
type: object
|
|
118
|
+
description: "Rules for migration dependency declarations"
|
|
119
|
+
properties:
|
|
120
|
+
require_explicit_dependencies:
|
|
121
|
+
type: boolean
|
|
122
|
+
description: |
|
|
123
|
+
Whether migrations that create cross-app FKs must explicitly
|
|
124
|
+
declare dependencies on the target app's migrations.
|
|
125
|
+
default: true
|
|
126
|
+
|
|
127
|
+
dependency_detection:
|
|
128
|
+
type: object
|
|
129
|
+
description: "How to detect missing dependencies"
|
|
130
|
+
properties:
|
|
131
|
+
scan_patterns:
|
|
132
|
+
type: array
|
|
133
|
+
description: "File patterns to scan for migrations"
|
|
134
|
+
items:
|
|
135
|
+
type: string
|
|
136
|
+
default:
|
|
137
|
+
- "apps/*/migrations/*.py"
|
|
138
|
+
- "*/migrations/*.py"
|
|
139
|
+
|
|
140
|
+
field_types:
|
|
141
|
+
type: array
|
|
142
|
+
description: "Field types that create dependencies"
|
|
143
|
+
items:
|
|
144
|
+
type: string
|
|
145
|
+
default:
|
|
146
|
+
- "ForeignKey"
|
|
147
|
+
- "OneToOneField"
|
|
148
|
+
- "ManyToManyField"
|
|
149
|
+
|
|
150
|
+
explanation:
|
|
151
|
+
type: string
|
|
152
|
+
description: "Why explicit dependencies are required"
|
|
153
|
+
default: |
|
|
154
|
+
When a migration in app A creates a FK to app B, it must
|
|
155
|
+
explicitly depend on app B's latest migration. This ensures
|
|
156
|
+
migrations run in the correct order and prevents dependency
|
|
157
|
+
errors in fresh databases.
|
|
158
|
+
|
|
159
|
+
enforcement:
|
|
160
|
+
type: object
|
|
161
|
+
description: "How these rules are enforced"
|
|
162
|
+
properties:
|
|
163
|
+
pre_commit_checks:
|
|
164
|
+
type: boolean
|
|
165
|
+
description: "Whether checks run pre-commit"
|
|
166
|
+
default: true
|
|
167
|
+
|
|
168
|
+
ci_checks:
|
|
169
|
+
type: boolean
|
|
170
|
+
description: "Whether checks run in CI"
|
|
171
|
+
default: true
|
|
172
|
+
|
|
173
|
+
scripts:
|
|
174
|
+
type: object
|
|
175
|
+
description: "Scripts that enforce these rules"
|
|
176
|
+
properties:
|
|
177
|
+
guard_migrate_commands:
|
|
178
|
+
type: string
|
|
179
|
+
description: "Script that guards against forbidden migrate commands"
|
|
180
|
+
default: "scripts/guard_migrate_commands.py"
|
|
181
|
+
|
|
182
|
+
check_cross_tenancy_fk:
|
|
183
|
+
type: string
|
|
184
|
+
description: "Script that checks for cross-tenancy FK violations"
|
|
185
|
+
default: "scripts/check_cross_tenancy_fk.py"
|
|
186
|
+
|
|
187
|
+
check_migration_dependencies:
|
|
188
|
+
type: string
|
|
189
|
+
description: "Script that checks migration dependency declarations"
|
|
190
|
+
default: "scripts/check_migration_dependencies.py"
|
|
191
|
+
|
|
192
|
+
make_target:
|
|
193
|
+
type: string
|
|
194
|
+
description: "Make target that runs all checks"
|
|
195
|
+
default: "check-schema-discipline"
|
|
196
|
+
|
|
197
|
+
examples:
|
|
198
|
+
- |
|
|
199
|
+
version: "1.0.0"
|
|
200
|
+
rules:
|
|
201
|
+
migration_commands:
|
|
202
|
+
forbidden_patterns:
|
|
203
|
+
- "manage.py migrate core"
|
|
204
|
+
- "manage.py migrate org"
|
|
205
|
+
required_patterns:
|
|
206
|
+
- "manage.py migrate"
|
|
207
|
+
- "manage.py migrate_schemas --shared"
|
|
208
|
+
- "manage.py migrate_schemas --tenant"
|
|
209
|
+
cross_tenancy_fk:
|
|
210
|
+
forbidden: true
|
|
211
|
+
allowed_exceptions: []
|
|
212
|
+
migration_dependencies:
|
|
213
|
+
require_explicit_dependencies: true
|
|
214
|
+
enforcement:
|
|
215
|
+
ci_checks: true
|
|
216
|
+
scripts:
|
|
217
|
+
guard_migrate_commands: "scripts/guard_migrate_commands.py"
|
|
218
|
+
check_cross_tenancy_fk: "scripts/check_cross_tenancy_fk.py"
|
|
219
|
+
check_migration_dependencies: "scripts/check_migration_dependencies.py"
|
|
220
|
+
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead Capture Module Content Contract
|
|
3
|
+
*
|
|
4
|
+
* Reusable lead capture form module for Heirloom Supply.
|
|
5
|
+
* Can be placed inline, in hero, footer, or as a modal.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ContentContract } from "../types";
|
|
9
|
+
|
|
10
|
+
export const leadCaptureModuleContract: ContentContract = {
|
|
11
|
+
id: "lead-capture-module",
|
|
12
|
+
title: "Lead Capture Module",
|
|
13
|
+
type: "document",
|
|
14
|
+
description: "Reusable lead capture form module with configurable variants and messaging",
|
|
15
|
+
scope: {
|
|
16
|
+
tenants: ["hewn"],
|
|
17
|
+
},
|
|
18
|
+
fields: [
|
|
19
|
+
{
|
|
20
|
+
name: "title",
|
|
21
|
+
type: "string",
|
|
22
|
+
title: "Title",
|
|
23
|
+
description: "Internal title for this module (not displayed)",
|
|
24
|
+
required: true,
|
|
25
|
+
options: {
|
|
26
|
+
maxLength: 200,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "slug",
|
|
31
|
+
type: "slug",
|
|
32
|
+
title: "Slug",
|
|
33
|
+
description: "Unique identifier for this module (used for tracking)",
|
|
34
|
+
required: true,
|
|
35
|
+
options: {
|
|
36
|
+
source: "title",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "variant",
|
|
41
|
+
type: "string",
|
|
42
|
+
title: "Variant",
|
|
43
|
+
description: "Visual variant/style of the form",
|
|
44
|
+
required: true,
|
|
45
|
+
options: {
|
|
46
|
+
options: ["inline", "hero", "footer", "modal"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "headline",
|
|
51
|
+
type: "string",
|
|
52
|
+
title: "Headline",
|
|
53
|
+
description: "Main headline text",
|
|
54
|
+
required: true,
|
|
55
|
+
options: {
|
|
56
|
+
maxLength: 100,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "subcopy",
|
|
61
|
+
type: "text",
|
|
62
|
+
title: "Subcopy",
|
|
63
|
+
description: "Supporting text below headline",
|
|
64
|
+
required: false,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "ctaText",
|
|
68
|
+
type: "string",
|
|
69
|
+
title: "CTA Text",
|
|
70
|
+
description: "Button text (e.g., 'Subscribe', 'Get Started')",
|
|
71
|
+
required: true,
|
|
72
|
+
options: {
|
|
73
|
+
maxLength: 50,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "disclaimer",
|
|
78
|
+
type: "text",
|
|
79
|
+
title: "Disclaimer",
|
|
80
|
+
description: "Optional disclaimer text (privacy, terms, etc.)",
|
|
81
|
+
required: false,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "listId",
|
|
85
|
+
type: "string",
|
|
86
|
+
title: "List ID",
|
|
87
|
+
description: "Optional email list ID for segmentation",
|
|
88
|
+
required: false,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "tag",
|
|
92
|
+
type: "string",
|
|
93
|
+
title: "Tag",
|
|
94
|
+
description: "Optional tag for lead categorization",
|
|
95
|
+
required: false,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "successMessage",
|
|
99
|
+
type: "string",
|
|
100
|
+
title: "Success Message",
|
|
101
|
+
description: "Message shown after successful submission",
|
|
102
|
+
required: true,
|
|
103
|
+
options: {
|
|
104
|
+
maxLength: 200,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "designOverrides",
|
|
109
|
+
type: "object",
|
|
110
|
+
title: "Design Overrides",
|
|
111
|
+
description: "Optional design system overrides (colors, spacing, etc.)",
|
|
112
|
+
required: false,
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
preview: {
|
|
116
|
+
select: {
|
|
117
|
+
title: "title",
|
|
118
|
+
variant: "variant",
|
|
119
|
+
slug: "slug.current",
|
|
120
|
+
},
|
|
121
|
+
prepare: (selection) => ({
|
|
122
|
+
title: selection.title,
|
|
123
|
+
subtitle: `${selection.variant} • ${selection.slug || "no slug"}`,
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const marketingSettingsContract: ContentContract = {
|
|
129
|
+
id: "marketing-settings",
|
|
130
|
+
title: "Marketing Settings",
|
|
131
|
+
type: "document",
|
|
132
|
+
description: "Global marketing settings including lead capture placements",
|
|
133
|
+
scope: {
|
|
134
|
+
tenants: ["hewn"],
|
|
135
|
+
},
|
|
136
|
+
fields: [
|
|
137
|
+
{
|
|
138
|
+
name: "globalLeadModule",
|
|
139
|
+
type: "reference",
|
|
140
|
+
title: "Global Lead Module",
|
|
141
|
+
description: "Default lead capture module for global placements",
|
|
142
|
+
required: false,
|
|
143
|
+
options: {
|
|
144
|
+
to: ["lead-capture-module"],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "showHeaderBar",
|
|
149
|
+
type: "boolean",
|
|
150
|
+
title: "Show Header Bar",
|
|
151
|
+
description: "Display lead capture in header bar",
|
|
152
|
+
required: false,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "showExitModal",
|
|
156
|
+
type: "boolean",
|
|
157
|
+
title: "Show Exit Modal",
|
|
158
|
+
description: "Display lead capture modal on exit intent",
|
|
159
|
+
required: false,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "exitModalModule",
|
|
163
|
+
type: "reference",
|
|
164
|
+
title: "Exit Modal Module",
|
|
165
|
+
description: "Lead capture module to show in exit modal",
|
|
166
|
+
required: false,
|
|
167
|
+
options: {
|
|
168
|
+
to: ["lead-capture-module"],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
preview: {
|
|
173
|
+
select: {
|
|
174
|
+
showHeader: "showHeaderBar",
|
|
175
|
+
showExit: "showExitModal",
|
|
176
|
+
},
|
|
177
|
+
prepare: (selection) => ({
|
|
178
|
+
title: "Marketing Settings",
|
|
179
|
+
subtitle: `Header: ${selection.showHeader ? "On" : "Off"} • Exit Modal: ${selection.showExit ? "On" : "Off"}`,
|
|
180
|
+
}),
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const moduleRefBlockContract: ContentContract = {
|
|
185
|
+
id: "module-ref-block",
|
|
186
|
+
title: "Module Reference Block",
|
|
187
|
+
type: "object",
|
|
188
|
+
description: "Block type for referencing a lead capture module in page builder",
|
|
189
|
+
scope: {
|
|
190
|
+
tenants: ["hewn"],
|
|
191
|
+
},
|
|
192
|
+
fields: [
|
|
193
|
+
{
|
|
194
|
+
name: "module",
|
|
195
|
+
type: "reference",
|
|
196
|
+
title: "Module",
|
|
197
|
+
description: "Lead capture module to render",
|
|
198
|
+
required: true,
|
|
199
|
+
options: {
|
|
200
|
+
to: ["lead-capture-module"],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "anchorId",
|
|
205
|
+
type: "string",
|
|
206
|
+
title: "Anchor ID",
|
|
207
|
+
description: "Optional anchor ID for deep linking",
|
|
208
|
+
required: false,
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
import type { ContentContract } from "./types";
|
|
19
19
|
import { blogPostContract, heroSectionContract } from "./example";
|
|
20
20
|
import { productContract } from "./heirloom/product";
|
|
21
|
+
import {
|
|
22
|
+
leadCaptureModuleContract,
|
|
23
|
+
marketingSettingsContract,
|
|
24
|
+
moduleRefBlockContract,
|
|
25
|
+
} from "./heirloom/lead-capture";
|
|
21
26
|
import { artistContract } from "./studioops/artist";
|
|
22
27
|
|
|
23
28
|
/**
|
|
@@ -35,6 +40,9 @@ export const contentContracts: ContentContract[] = [
|
|
|
35
40
|
|
|
36
41
|
// Heirloom Supply contracts
|
|
37
42
|
productContract,
|
|
43
|
+
leadCaptureModuleContract,
|
|
44
|
+
marketingSettingsContract,
|
|
45
|
+
moduleRefBlockContract,
|
|
38
46
|
|
|
39
47
|
// StudioOps contracts
|
|
40
48
|
artistContract,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Creative Whisperer Contracts
|
|
2
|
+
|
|
3
|
+
JSON schemas for Creative Whisperer synthesis—extracting and synthesizing creative signals from artist assets.
|
|
4
|
+
|
|
5
|
+
## Schemas
|
|
6
|
+
|
|
7
|
+
| Schema | Description |
|
|
8
|
+
|--------|-------------|
|
|
9
|
+
| `creative_signal_profile.schema.json` | Extracted profile from a single asset (emotions, themes, energy, intensity, etc.) |
|
|
10
|
+
| `creative_edge_alignment.schema.json` | Alignment metrics between two profiles (semantic, emotional, theme overlap) |
|
|
11
|
+
| `creative_cluster.schema.json` | Cluster of related profiles grouped by affinity |
|
|
12
|
+
| `creative_whisper.schema.json` | Synthesis output (cluster summary, patterns, citations, follow-up questions) |
|
|
13
|
+
|
|
14
|
+
## Enums
|
|
15
|
+
|
|
16
|
+
- **asset_type**: `note` | `audio` | `url` | `lyric` | `image` | `other`
|
|
17
|
+
- **energy**: `low` | `mid` | `high`
|
|
18
|
+
|
|
19
|
+
## References
|
|
20
|
+
|
|
21
|
+
- `$id` base: `https://contracts.levrops.com/creative/`
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.levrops.com/creative/creative_cluster.schema.json",
|
|
4
|
+
"title": "CreativeCluster",
|
|
5
|
+
"description": "A cluster of related creative signal profiles grouped by semantic/emotional affinity for Creative Whisperer synthesis.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["cluster_id", "asset_ids"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"cluster_id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Unique identifier for the cluster",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"maxLength": 255
|
|
14
|
+
},
|
|
15
|
+
"asset_ids": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"description": "IDs of assets in this cluster",
|
|
18
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 255 },
|
|
19
|
+
"minItems": 1,
|
|
20
|
+
"maxItems": 100
|
|
21
|
+
},
|
|
22
|
+
"dominant_emotions": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"description": "Dominant emotions across the cluster",
|
|
25
|
+
"items": { "type": "string", "maxLength": 100 },
|
|
26
|
+
"maxItems": 10,
|
|
27
|
+
"default": []
|
|
28
|
+
},
|
|
29
|
+
"dominant_themes": {
|
|
30
|
+
"type": "array",
|
|
31
|
+
"description": "Dominant themes across the cluster",
|
|
32
|
+
"items": { "type": "string", "maxLength": 100 },
|
|
33
|
+
"maxItems": 10,
|
|
34
|
+
"default": []
|
|
35
|
+
},
|
|
36
|
+
"cohesion_score": {
|
|
37
|
+
"type": "number",
|
|
38
|
+
"description": "How tightly the cluster coheres (0–1)",
|
|
39
|
+
"minimum": 0,
|
|
40
|
+
"maximum": 1
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"additionalProperties": false
|
|
44
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.levrops.com/creative/creative_edge_alignment.schema.json",
|
|
4
|
+
"title": "CreativeEdgeAlignment",
|
|
5
|
+
"description": "Alignment metrics between two creative signal profiles. Used to measure semantic, emotional, and thematic overlap for Creative Whisperer synthesis.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"source_asset_id",
|
|
9
|
+
"target_asset_id",
|
|
10
|
+
"semantic_score",
|
|
11
|
+
"emotional_score",
|
|
12
|
+
"theme_overlap_count",
|
|
13
|
+
"motif_overlap_count",
|
|
14
|
+
"resonance_score"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"source_asset_id": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "ID of the source asset",
|
|
20
|
+
"minLength": 1,
|
|
21
|
+
"maxLength": 255
|
|
22
|
+
},
|
|
23
|
+
"target_asset_id": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "ID of the target asset being aligned",
|
|
26
|
+
"minLength": 1,
|
|
27
|
+
"maxLength": 255
|
|
28
|
+
},
|
|
29
|
+
"semantic_score": {
|
|
30
|
+
"type": "number",
|
|
31
|
+
"description": "Semantic similarity score (0–1)",
|
|
32
|
+
"minimum": 0,
|
|
33
|
+
"maximum": 1
|
|
34
|
+
},
|
|
35
|
+
"emotional_score": {
|
|
36
|
+
"type": "number",
|
|
37
|
+
"description": "Emotional alignment score (0–1)",
|
|
38
|
+
"minimum": 0,
|
|
39
|
+
"maximum": 1
|
|
40
|
+
},
|
|
41
|
+
"theme_overlap_count": {
|
|
42
|
+
"type": "integer",
|
|
43
|
+
"description": "Number of overlapping themes",
|
|
44
|
+
"minimum": 0
|
|
45
|
+
},
|
|
46
|
+
"motif_overlap_count": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"description": "Number of overlapping motifs/imagery",
|
|
49
|
+
"minimum": 0
|
|
50
|
+
},
|
|
51
|
+
"resonance_score": {
|
|
52
|
+
"type": "number",
|
|
53
|
+
"description": "Overall resonance score (0–1)",
|
|
54
|
+
"minimum": 0,
|
|
55
|
+
"maximum": 1
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"additionalProperties": false
|
|
59
|
+
}
|