@foundrynorth/flux-schema 1.19.3 → 1.19.5

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
@@ -186,6 +186,8 @@ export const fluxUsers = pgTable("flux_users", {
186
186
  primaryRole: fluxPrimaryRoleEnum("primary_role").notNull().default("strategist"),
187
187
  isAdmin: boolean("is_admin").default(false).notNull(),
188
188
  hasSentinelAccess: boolean("has_sentinel_access").notNull().default(false),
189
+ hasVarsityAccess: boolean("has_varsity_access").notNull().default(false),
190
+ hasOpinionAccess: boolean("has_opinion_access").notNull().default(false),
189
191
  hasDashboardAccess: boolean("has_dashboard_access").notNull().default(true),
190
192
  privacyKeywords: jsonb("privacy_keywords").default([]).$type(),
191
193
  /** HubSpot owner ID for reverse lookup (Flux user → HubSpot owner) */
@@ -2438,6 +2440,25 @@ export const fluxSemAlertSeverityEnum = pgEnum("flux_sem_alert_severity", [
2438
2440
  "warning",
2439
2441
  "critical",
2440
2442
  ]);
2443
+ /**
2444
+ * SEM alert source — where the alert originated.
2445
+ *
2446
+ * - `internal_heuristics` — generated by the fn-flux SEM optimization engine
2447
+ * (rank drops, pacing deltas, staleness triggers, etc.). Default for every
2448
+ * row before the source column was added.
2449
+ * - `google_recommendations` — ingested from the Google Ads Recommendations
2450
+ * API (via the fn-v2 `sem-sync-recommendations` task, gated on Google Ads
2451
+ * credentials from Q3). Each alert of this kind carries a
2452
+ * `recommendation_id` that uniquely identifies the Google recommendation
2453
+ * so repeat ingests are idempotent.
2454
+ *
2455
+ * Add a new value (planned source-system addition) via `ALTER TYPE ... ADD
2456
+ * VALUE` in a follow-up migration — cannot run inside a transaction.
2457
+ */
2458
+ export const fluxSemAlertSourceEnum = pgEnum("flux_sem_alert_source", [
2459
+ "internal_heuristics",
2460
+ "google_recommendations",
2461
+ ]);
2441
2462
  /** SEM ticket complexity for workload sizing on the team board. */
2442
2463
  export const fluxSemComplexityEnum = pgEnum("flux_sem_complexity", [
2443
2464
  "light",
@@ -5727,6 +5748,26 @@ export const fluxSemOptimizationAlerts = pgTable("flux_sem_optimization_alerts",
5727
5748
  alertType: fluxSemAlertTypeEnum("alert_type").notNull(),
5728
5749
  /** Alert severity */
5729
5750
  severity: fluxSemAlertSeverityEnum("severity").notNull(),
5751
+ /**
5752
+ * Source of this alert.
5753
+ *
5754
+ * - `internal_heuristics` — produced by the SEM optimization engine
5755
+ * (rank changes, pacing deltas, staleness, competitor moves, etc.).
5756
+ * - `google_recommendations` — ingested from the Google Ads
5757
+ * Recommendations API; paired with `recommendation_id` for idempotency.
5758
+ *
5759
+ * Defaults to `internal_heuristics` so existing rows (all produced by
5760
+ * the heuristic engine) retain accurate provenance after backfill.
5761
+ */
5762
+ source: fluxSemAlertSourceEnum("source").notNull().default("internal_heuristics"),
5763
+ /**
5764
+ * Stable external identifier for this alert's source record, when
5765
+ * applicable. Today only populated by `google_recommendations` alerts
5766
+ * (the Google Ads recommendation resource name / ID). Null for
5767
+ * internal-heuristic alerts. Enables idempotent re-ingest — see the
5768
+ * partial unique index below.
5769
+ */
5770
+ recommendationId: text("recommendation_id"),
5730
5771
  /** Short alert title */
5731
5772
  title: text("title").notNull(),
5732
5773
  /** Detailed description of what was detected */
@@ -5745,6 +5786,15 @@ export const fluxSemOptimizationAlerts = pgTable("flux_sem_optimization_alerts",
5745
5786
  }, (table) => [
5746
5787
  index("flux_sem_alerts_campaign_idx").on(table.semCampaignId),
5747
5788
  index("flux_sem_alerts_unacked_idx").on(table.semCampaignId, table.acknowledged),
5789
+ /**
5790
+ * Idempotency guard for source-system ingest (today: Google Ads
5791
+ * Recommendations API). Scoped with `WHERE recommendation_id IS NOT NULL`
5792
+ * so it doesn't constrain internal-heuristic alerts, which have no
5793
+ * external stable ID.
5794
+ */
5795
+ uniqueIndex("flux_sem_alerts_source_recommendation_uniq")
5796
+ .on(table.semCampaignId, table.source, table.recommendationId)
5797
+ .where(sql `${table.recommendationId} IS NOT NULL`),
5748
5798
  ]);
5749
5799
  /**
5750
5800
  * flux_sem_optimization_log — Proof-of-work optimization entries.