@foundrynorth/flux-schema 1.19.11 → 1.20.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/schema.js CHANGED
@@ -168,6 +168,28 @@ export const fluxSecretsAuditActionEnum = pgEnum("flux_secrets_audit_action", [
168
168
  "sync_failed",
169
169
  ]);
170
170
  // =============================================================================
171
+ // MILESTONE NOTIFICATIONS (Real-time per-AM Slack DMs)
172
+ // =============================================================================
173
+ /**
174
+ * Milestone events that can trigger a per-user Slack DM. Owners on a ticket
175
+ * (account manager, account executive, strategist, fulfillment owner) receive
176
+ * these by default; non-owner subscribers must opt in per event type via
177
+ * `flux_users.notificationPreferences.milestones.subscriberOptIn`.
178
+ */
179
+ export const MILESTONE_EVENT_TYPES = [
180
+ "ticket_created",
181
+ "creative_needed",
182
+ "creative_approved",
183
+ "ready_to_traffic",
184
+ "campaign_live",
185
+ "campaign_completed",
186
+ "campaign_paused",
187
+ "campaign_cancelled",
188
+ "change_required",
189
+ "sem_live",
190
+ "sem_failed",
191
+ ];
192
+ // =============================================================================
171
193
  // USERS (Extension table - references Clerk, not Forge users)
172
194
  // =============================================================================
173
195
  /**
@@ -459,6 +481,43 @@ export const fluxActivityItems = pgTable("flux_activity_items", {
459
481
  projectOccurredIdx: index("flux_activity_items_project_occurred_idx").on(table.projectId, table.occurredAt),
460
482
  }));
461
483
  // =============================================================================
484
+ // MILESTONE NOTIFICATIONS (delivery ledger for per-AM Slack DMs)
485
+ // =============================================================================
486
+ /**
487
+ * Idempotency ledger for milestone Slack DMs. The dispatcher inserts one row
488
+ * per (user, source, event) before sending the DM; the unique index causes
489
+ * `ON CONFLICT DO NOTHING` to no-op on retries / re-syncs / webhook replays.
490
+ *
491
+ * Source rows:
492
+ * sourceType = "fulfillment_ticket" → sourceId = flux_fulfillment_tickets.id
493
+ * sourceType = "sem_campaign" → sourceId = flux_sem_campaigns.id
494
+ *
495
+ * `slackTs` captures the Slack message timestamp so future code can thread
496
+ * follow-up updates (e.g. edit the "campaign live" message when it completes).
497
+ */
498
+ export const fluxMilestoneNotifications = pgTable("flux_milestone_notifications", {
499
+ id: varchar("id")
500
+ .primaryKey()
501
+ .default(sql `gen_random_uuid()`),
502
+ userId: varchar("user_id")
503
+ .references(() => fluxUsers.id, { onDelete: "cascade" })
504
+ .notNull(),
505
+ sourceType: varchar("source_type").notNull(),
506
+ sourceId: varchar("source_id").notNull(),
507
+ eventType: varchar("event_type").notNull(),
508
+ projectId: varchar("project_id").references(() => fluxProjects.id, {
509
+ onDelete: "set null",
510
+ }),
511
+ deliveredAt: timestamp("delivered_at").defaultNow().notNull(),
512
+ slackTs: varchar("slack_ts"),
513
+ metadata: jsonb("metadata").default({}).$type(),
514
+ }, (table) => ({
515
+ uniqueDelivery: uniqueIndex("flux_milestone_notifications_unique_idx").on(table.userId, table.sourceType, table.sourceId, table.eventType),
516
+ userIdx: index("flux_milestone_notifications_user_idx").on(table.userId),
517
+ projectIdx: index("flux_milestone_notifications_project_idx").on(table.projectId),
518
+ deliveredIdx: index("flux_milestone_notifications_delivered_idx").on(table.deliveredAt),
519
+ }));
520
+ // =============================================================================
462
521
  // ALERT RULES
463
522
  // =============================================================================
464
523
  export const fluxAlertRules = pgTable("flux_alert_rules", {