@foundrynorth/compass-schema 1.0.13 → 1.0.15
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/relations.d.ts +22 -0
- package/dist/relations.d.ts.map +1 -1
- package/dist/relations.js +54 -2
- package/dist/relations.js.map +1 -1
- package/dist/schema.d.ts +1704 -237
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +161 -0
- package/dist/schema.js.map +1 -1
- package/package.json +1 -1
- package/src/relations.ts +61 -1
- package/src/schema.ts +203 -0
package/package.json
CHANGED
package/src/relations.ts
CHANGED
|
@@ -15,6 +15,11 @@ import {
|
|
|
15
15
|
semCampaigns,
|
|
16
16
|
mediaOrders,
|
|
17
17
|
mediaOrderLineItems,
|
|
18
|
+
planOptions,
|
|
19
|
+
researchSnapshots,
|
|
20
|
+
researchRuns,
|
|
21
|
+
engagements,
|
|
22
|
+
planConfigurations,
|
|
18
23
|
} from "./schema.js";
|
|
19
24
|
|
|
20
25
|
export const deepEnrichmentUsageRelations = relations(deepEnrichmentUsage, ({one}) => ({
|
|
@@ -24,9 +29,16 @@ export const deepEnrichmentUsageRelations = relations(deepEnrichmentUsage, ({one
|
|
|
24
29
|
}),
|
|
25
30
|
}));
|
|
26
31
|
|
|
27
|
-
export const plansRelations = relations(plans, ({many}) => ({
|
|
32
|
+
export const plansRelations = relations(plans, ({one, many}) => ({
|
|
28
33
|
deepEnrichmentUsages: many(deepEnrichmentUsage),
|
|
29
34
|
planEnrichments: many(planEnrichments),
|
|
35
|
+
planOptions: many(planOptions),
|
|
36
|
+
researchSnapshots: many(researchSnapshots),
|
|
37
|
+
researchRuns: many(researchRuns),
|
|
38
|
+
selectedOption: one(planOptions, {
|
|
39
|
+
fields: [plans.selectedOptionId],
|
|
40
|
+
references: [planOptions.id],
|
|
41
|
+
}),
|
|
30
42
|
}));
|
|
31
43
|
|
|
32
44
|
export const pdfTemplateFieldMappingsRelations = relations(pdfTemplateFieldMappings, ({one}) => ({
|
|
@@ -98,6 +110,54 @@ export const googleAdSearchesRelations = relations(googleAdSearches, ({many}) =>
|
|
|
98
110
|
googleAdCreatives: many(googleAdCreatives),
|
|
99
111
|
}));
|
|
100
112
|
|
|
113
|
+
/** Canonical planning model relations */
|
|
114
|
+
export const researchSnapshotsRelations = relations(researchSnapshots, ({one, many}) => ({
|
|
115
|
+
plan: one(plans, {
|
|
116
|
+
fields: [researchSnapshots.planId],
|
|
117
|
+
references: [plans.id],
|
|
118
|
+
}),
|
|
119
|
+
engagement: one(engagements, {
|
|
120
|
+
fields: [researchSnapshots.engagementId],
|
|
121
|
+
references: [engagements.id],
|
|
122
|
+
}),
|
|
123
|
+
planOptions: many(planOptions),
|
|
124
|
+
researchRuns: many(researchRuns),
|
|
125
|
+
}));
|
|
126
|
+
|
|
127
|
+
export const planOptionsRelations = relations(planOptions, ({one}) => ({
|
|
128
|
+
plan: one(plans, {
|
|
129
|
+
fields: [planOptions.planId],
|
|
130
|
+
references: [plans.id],
|
|
131
|
+
}),
|
|
132
|
+
engagement: one(engagements, {
|
|
133
|
+
fields: [planOptions.engagementId],
|
|
134
|
+
references: [engagements.id],
|
|
135
|
+
}),
|
|
136
|
+
legacyConfiguration: one(planConfigurations, {
|
|
137
|
+
fields: [planOptions.legacyConfigurationId],
|
|
138
|
+
references: [planConfigurations.id],
|
|
139
|
+
}),
|
|
140
|
+
researchSnapshot: one(researchSnapshots, {
|
|
141
|
+
fields: [planOptions.researchSnapshotId],
|
|
142
|
+
references: [researchSnapshots.id],
|
|
143
|
+
}),
|
|
144
|
+
}));
|
|
145
|
+
|
|
146
|
+
export const researchRunsRelations = relations(researchRuns, ({one}) => ({
|
|
147
|
+
plan: one(plans, {
|
|
148
|
+
fields: [researchRuns.planId],
|
|
149
|
+
references: [plans.id],
|
|
150
|
+
}),
|
|
151
|
+
engagement: one(engagements, {
|
|
152
|
+
fields: [researchRuns.engagementId],
|
|
153
|
+
references: [engagements.id],
|
|
154
|
+
}),
|
|
155
|
+
researchSnapshot: one(researchSnapshots, {
|
|
156
|
+
fields: [researchRuns.researchSnapshotId],
|
|
157
|
+
references: [researchSnapshots.id],
|
|
158
|
+
}),
|
|
159
|
+
}));
|
|
160
|
+
|
|
101
161
|
/** SEM campaign relations — links to media order and line item. */
|
|
102
162
|
export const semCampaignsRelations = relations(semCampaigns, ({ one }) => ({
|
|
103
163
|
mediaOrder: one(mediaOrders, {
|
package/src/schema.ts
CHANGED
|
@@ -1025,6 +1025,7 @@ export const plans = pgTable("plans", {
|
|
|
1025
1025
|
// Partner association (null = legacy plans before partner system)
|
|
1026
1026
|
partnerId: varchar("partner_id"),
|
|
1027
1027
|
engagementId: varchar("engagement_id"), // FK → engagements.id (nullable for backward compatibility)
|
|
1028
|
+
selectedOptionId: varchar("selected_option_id"), // FK → plan_options.id (nullable during migration)
|
|
1028
1029
|
contractId: uuid("contract_id"), // FK → contracts.id (nullable — links to annual contract)
|
|
1029
1030
|
|
|
1030
1031
|
// Workflow mode: determines which UI sections and features are available
|
|
@@ -1255,6 +1256,7 @@ export const proposals = pgTable(
|
|
|
1255
1256
|
|
|
1256
1257
|
// Configuration references (which plan_configurations to include)
|
|
1257
1258
|
configurationIds: jsonb("configuration_ids").$type<string[]>(),
|
|
1259
|
+
optionIds: jsonb("option_ids").$type<string[]>(),
|
|
1258
1260
|
|
|
1259
1261
|
// Organization
|
|
1260
1262
|
partnerId: varchar("partner_id"),
|
|
@@ -1363,6 +1365,195 @@ export const insertPlanConfigurationSchema = createInsertSchema(planConfiguratio
|
|
|
1363
1365
|
export type InsertPlanConfiguration = z.infer<typeof insertPlanConfigurationSchema>;
|
|
1364
1366
|
export type PlanConfiguration = typeof planConfigurations.$inferSelect;
|
|
1365
1367
|
|
|
1368
|
+
// Canonical planning model enums
|
|
1369
|
+
export const planOptionSourceEnum = pgEnum("plan_option_source", [
|
|
1370
|
+
"strategist",
|
|
1371
|
+
"ai",
|
|
1372
|
+
"derived_snapshot",
|
|
1373
|
+
]);
|
|
1374
|
+
|
|
1375
|
+
export const planOptionKindEnum = pgEnum("plan_option_kind", [
|
|
1376
|
+
"base",
|
|
1377
|
+
"alternative",
|
|
1378
|
+
]);
|
|
1379
|
+
|
|
1380
|
+
export const planOptionStatusEnum = pgEnum("plan_option_status", [
|
|
1381
|
+
"draft",
|
|
1382
|
+
"recommended",
|
|
1383
|
+
"selected",
|
|
1384
|
+
"ordered",
|
|
1385
|
+
"archived",
|
|
1386
|
+
]);
|
|
1387
|
+
|
|
1388
|
+
export const researchRunStatusEnum = pgEnum("research_run_status", [
|
|
1389
|
+
"queued",
|
|
1390
|
+
"running",
|
|
1391
|
+
"completed",
|
|
1392
|
+
"failed",
|
|
1393
|
+
"cancelled",
|
|
1394
|
+
"reused",
|
|
1395
|
+
]);
|
|
1396
|
+
|
|
1397
|
+
// Canonical research snapshot store
|
|
1398
|
+
export const researchSnapshots = pgTable(
|
|
1399
|
+
"research_snapshots",
|
|
1400
|
+
{
|
|
1401
|
+
id: varchar("id")
|
|
1402
|
+
.primaryKey()
|
|
1403
|
+
.default(sql`gen_random_uuid()`),
|
|
1404
|
+
engagementId: varchar("engagement_id").references(() => engagements.id, {
|
|
1405
|
+
onDelete: "set null",
|
|
1406
|
+
}),
|
|
1407
|
+
planId: varchar("plan_id")
|
|
1408
|
+
.notNull()
|
|
1409
|
+
.references(() => plans.id, { onDelete: "cascade" }),
|
|
1410
|
+
scopeType: text("scope_type").notNull(),
|
|
1411
|
+
scopeKey: text("scope_key").notNull(),
|
|
1412
|
+
sourceMode: text("source_mode").notNull(),
|
|
1413
|
+
snapshotVersion: integer("snapshot_version").notNull().default(1),
|
|
1414
|
+
prospectProfile: jsonb("prospect_profile").$type<Record<string, any>>(),
|
|
1415
|
+
competitiveContext: jsonb("competitive_context").$type<Record<string, any>>(),
|
|
1416
|
+
marketContext: jsonb("market_context").$type<Record<string, any>>(),
|
|
1417
|
+
constraints: jsonb("constraints").$type<Record<string, any>>(),
|
|
1418
|
+
fulfillmentContext: jsonb("fulfillment_context").$type<Record<string, any>>(),
|
|
1419
|
+
brandContext: jsonb("brand_context").$type<Record<string, any>>(),
|
|
1420
|
+
provenance: jsonb("provenance").$type<Record<string, any>>().notNull(),
|
|
1421
|
+
freshUntil: timestamp("fresh_until"),
|
|
1422
|
+
reuseHash: text("reuse_hash"),
|
|
1423
|
+
triggerRunId: varchar("trigger_run_id"),
|
|
1424
|
+
costMeta: jsonb("cost_meta").$type<Record<string, any>>(),
|
|
1425
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
1426
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
1427
|
+
},
|
|
1428
|
+
(table) => [
|
|
1429
|
+
index("research_snapshots_plan_id_idx").on(table.planId),
|
|
1430
|
+
index("research_snapshots_plan_version_idx").on(table.planId, table.snapshotVersion),
|
|
1431
|
+
index("research_snapshots_scope_key_idx").on(table.scopeKey),
|
|
1432
|
+
index("research_snapshots_reuse_hash_idx").on(table.reuseHash),
|
|
1433
|
+
]
|
|
1434
|
+
);
|
|
1435
|
+
|
|
1436
|
+
export const insertResearchSnapshotSchema = createInsertSchema(researchSnapshots).omit({
|
|
1437
|
+
id: true,
|
|
1438
|
+
createdAt: true,
|
|
1439
|
+
updatedAt: true,
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
export type InsertResearchSnapshot = z.infer<typeof insertResearchSnapshotSchema>;
|
|
1443
|
+
export type ResearchSnapshot = typeof researchSnapshots.$inferSelect;
|
|
1444
|
+
|
|
1445
|
+
// Canonical actionable option store
|
|
1446
|
+
export const planOptions = pgTable(
|
|
1447
|
+
"plan_options",
|
|
1448
|
+
{
|
|
1449
|
+
id: varchar("id")
|
|
1450
|
+
.primaryKey()
|
|
1451
|
+
.default(sql`gen_random_uuid()`),
|
|
1452
|
+
planId: varchar("plan_id")
|
|
1453
|
+
.notNull()
|
|
1454
|
+
.references(() => plans.id, { onDelete: "cascade" }),
|
|
1455
|
+
engagementId: varchar("engagement_id").references(() => engagements.id, {
|
|
1456
|
+
onDelete: "set null",
|
|
1457
|
+
}),
|
|
1458
|
+
legacyConfigurationId: varchar("legacy_configuration_id").references(
|
|
1459
|
+
() => planConfigurations.id,
|
|
1460
|
+
{ onDelete: "set null" }
|
|
1461
|
+
),
|
|
1462
|
+
legacyTierKey: text("legacy_tier_key"),
|
|
1463
|
+
name: text("name").notNull(),
|
|
1464
|
+
label: text("label"),
|
|
1465
|
+
source: planOptionSourceEnum("source").notNull(),
|
|
1466
|
+
kind: planOptionKindEnum("kind").notNull(),
|
|
1467
|
+
status: planOptionStatusEnum("status").notNull().default("draft"),
|
|
1468
|
+
derivedFromOptionId: varchar("derived_from_option_id"),
|
|
1469
|
+
researchSnapshotId: varchar("research_snapshot_id").references(
|
|
1470
|
+
() => researchSnapshots.id,
|
|
1471
|
+
{ onDelete: "set null" }
|
|
1472
|
+
),
|
|
1473
|
+
generationRunId: varchar("generation_run_id"),
|
|
1474
|
+
budgetTotal: integer("budget_total"),
|
|
1475
|
+
durationMonths: integer("duration_months"),
|
|
1476
|
+
allocations: jsonb("allocations")
|
|
1477
|
+
.$type<Record<string, any>[]>()
|
|
1478
|
+
.notNull()
|
|
1479
|
+
.default(sql`'[]'::jsonb`),
|
|
1480
|
+
rationale: text("rationale"),
|
|
1481
|
+
assumptions: jsonb("assumptions").$type<Record<string, any>>(),
|
|
1482
|
+
constraints: jsonb("constraints").$type<Record<string, any>>(),
|
|
1483
|
+
fulfillmentNotes: text("fulfillment_notes"),
|
|
1484
|
+
generationContext: jsonb("generation_context").$type<Record<string, any>>(),
|
|
1485
|
+
displayOrder: integer("display_order").notNull().default(0),
|
|
1486
|
+
createdBy: text("created_by"),
|
|
1487
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
1488
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
1489
|
+
},
|
|
1490
|
+
(table) => [
|
|
1491
|
+
index("plan_options_plan_id_idx").on(table.planId),
|
|
1492
|
+
index("plan_options_plan_display_order_idx").on(table.planId, table.displayOrder),
|
|
1493
|
+
index("plan_options_engagement_id_idx").on(table.engagementId),
|
|
1494
|
+
index("plan_options_research_snapshot_id_idx").on(table.researchSnapshotId),
|
|
1495
|
+
uniqueIndex("plan_options_one_recommended_idx")
|
|
1496
|
+
.on(table.planId)
|
|
1497
|
+
.where(sql`${table.status} = 'recommended'::plan_option_status`),
|
|
1498
|
+
uniqueIndex("plan_options_one_selected_idx")
|
|
1499
|
+
.on(table.planId)
|
|
1500
|
+
.where(sql`${table.status} = 'selected'::plan_option_status`),
|
|
1501
|
+
]
|
|
1502
|
+
);
|
|
1503
|
+
|
|
1504
|
+
export const insertPlanOptionSchema = createInsertSchema(planOptions).omit({
|
|
1505
|
+
id: true,
|
|
1506
|
+
createdAt: true,
|
|
1507
|
+
updatedAt: true,
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
export type InsertPlanOption = z.infer<typeof insertPlanOptionSchema>;
|
|
1511
|
+
export type PlanOption = typeof planOptions.$inferSelect;
|
|
1512
|
+
|
|
1513
|
+
// Operational ledger for research runs and snapshot materialization
|
|
1514
|
+
export const researchRuns = pgTable(
|
|
1515
|
+
"research_runs",
|
|
1516
|
+
{
|
|
1517
|
+
id: varchar("id")
|
|
1518
|
+
.primaryKey()
|
|
1519
|
+
.default(sql`gen_random_uuid()`),
|
|
1520
|
+
triggerRunId: varchar("trigger_run_id"),
|
|
1521
|
+
taskId: text("task_id").notNull(),
|
|
1522
|
+
engagementId: varchar("engagement_id").references(() => engagements.id, {
|
|
1523
|
+
onDelete: "set null",
|
|
1524
|
+
}),
|
|
1525
|
+
planId: varchar("plan_id").references(() => plans.id, {
|
|
1526
|
+
onDelete: "set null",
|
|
1527
|
+
}),
|
|
1528
|
+
researchSnapshotId: varchar("research_snapshot_id").references(
|
|
1529
|
+
() => researchSnapshots.id,
|
|
1530
|
+
{ onDelete: "set null" }
|
|
1531
|
+
),
|
|
1532
|
+
status: researchRunStatusEnum("status").notNull().default("queued"),
|
|
1533
|
+
requestedBy: text("requested_by"),
|
|
1534
|
+
runReason: text("run_reason"),
|
|
1535
|
+
inputHash: text("input_hash"),
|
|
1536
|
+
costMeta: jsonb("cost_meta").$type<Record<string, any>>(),
|
|
1537
|
+
startedAt: timestamp("started_at"),
|
|
1538
|
+
completedAt: timestamp("completed_at"),
|
|
1539
|
+
error: text("error"),
|
|
1540
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
1541
|
+
},
|
|
1542
|
+
(table) => [
|
|
1543
|
+
index("research_runs_plan_id_idx").on(table.planId),
|
|
1544
|
+
index("research_runs_trigger_run_id_idx").on(table.triggerRunId),
|
|
1545
|
+
index("research_runs_task_status_idx").on(table.taskId, table.status),
|
|
1546
|
+
]
|
|
1547
|
+
);
|
|
1548
|
+
|
|
1549
|
+
export const insertResearchRunSchema = createInsertSchema(researchRuns).omit({
|
|
1550
|
+
id: true,
|
|
1551
|
+
createdAt: true,
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
export type InsertResearchRun = z.infer<typeof insertResearchRunSchema>;
|
|
1555
|
+
export type ResearchRun = typeof researchRuns.$inferSelect;
|
|
1556
|
+
|
|
1366
1557
|
// Jobs Table for async operations
|
|
1367
1558
|
export const jobs = pgTable("jobs", {
|
|
1368
1559
|
id: varchar("id")
|
|
@@ -4525,6 +4716,7 @@ export const mediaOrders = pgTable(
|
|
|
4525
4716
|
planId: varchar("plan_id"), // FK → plans.id (nullable — can exist without a plan)
|
|
4526
4717
|
engagementId: varchar("engagement_id"), // FK → engagements.id (nullable during transition)
|
|
4527
4718
|
configurationId: varchar("configuration_id"), // FK → plan_configurations.id (named product mix)
|
|
4719
|
+
optionId: varchar("option_id"), // FK → plan_options.id (canonical selected option)
|
|
4528
4720
|
contractId: uuid("contract_id"), // FK → contracts.id (nullable — links to annual contract)
|
|
4529
4721
|
partnerId: varchar("partner_id"),
|
|
4530
4722
|
hubspotDealId: text("hubspot_deal_id"),
|
|
@@ -8003,3 +8195,14 @@ export const compassEventOutbox = pgTable(
|
|
|
8003
8195
|
|
|
8004
8196
|
export type CompassEventOutboxRecord = typeof compassEventOutbox.$inferSelect;
|
|
8005
8197
|
export type InsertCompassEventOutbox = typeof compassEventOutbox.$inferInsert;
|
|
8198
|
+
|
|
8199
|
+
// ─── Creative Deliveries (Prism webhook idempotency) ────────────────────────
|
|
8200
|
+
|
|
8201
|
+
export const creativeDeliveries = pgTable("creative_deliveries", {
|
|
8202
|
+
id: serial("id").primaryKey(),
|
|
8203
|
+
packageId: varchar("package_id", { length: 255 }).notNull().unique(),
|
|
8204
|
+
compassCampaignId: varchar("compass_campaign_id", { length: 255 }).notNull(),
|
|
8205
|
+
status: varchar("status", { length: 50 }).notNull(),
|
|
8206
|
+
assetCount: integer("asset_count").notNull().default(0),
|
|
8207
|
+
receivedAt: timestamp("received_at").defaultNow().notNull(),
|
|
8208
|
+
});
|