From f972b97de8594680e1c8fb6fbd0a40f652e03b38 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 10:09:23 +0200 Subject: [PATCH 01/13] feat(settings): move auto-triage to the AI tab with provider cards and a save bar The AI tab now has two sections: a model provider choice (Maple managed or your OpenRouter key, with the key form and add-on upsell inside the card) and auto-triage (instant switch, investigations per day with today's usage, model-pass ceiling under advanced limits). Limit edits go through the save bar and show validation errors instead of silently reverting. --- .../settings/ai-provider-section.tsx | 405 +++++++++++------- .../settings/ai-triage-limits.test.ts | 43 ++ .../components/settings/ai-triage-limits.ts | 42 ++ .../settings/ai-triage-settings-section.tsx | 347 ++++++++------- .../settings/automation-section.tsx | 12 +- .../src/components/settings/settings-nav.tsx | 2 +- apps/web/src/routes/investigations/index.tsx | 2 +- apps/web/src/routes/settings.tsx | 14 +- 8 files changed, 531 insertions(+), 336 deletions(-) create mode 100644 apps/web/src/components/settings/ai-triage-limits.test.ts create mode 100644 apps/web/src/components/settings/ai-triage-limits.ts diff --git a/apps/web/src/components/settings/ai-provider-section.tsx b/apps/web/src/components/settings/ai-provider-section.tsx index 8c4b87e26c..5454a7ec5f 100644 --- a/apps/web/src/components/settings/ai-provider-section.tsx +++ b/apps/web/src/components/settings/ai-provider-section.tsx @@ -1,17 +1,17 @@ -import { useState } from "react" +import { type ReactNode, useState } from "react" import { OPENROUTER_BYOK_ADDON_ID } from "@maple/domain/billing" -import { OpenRouterKeyUpdateRequest } from "@maple/domain/http" +import { type OpenRouterKeyDocument, OpenRouterKeyUpdateRequest } from "@maple/domain/http" import { Badge } from "@maple/ui/components/ui/badge" import { Button } from "@maple/ui/components/ui/button" import { ConfirmDialog } from "@maple/ui/components/ui/confirm-dialog" import { Field, FieldDescription, FieldLabel } from "@maple/ui/components/ui/field" import { Input } from "@maple/ui/components/ui/input" -import { Panel } from "@maple/ui/components/ui/panel" -import { SettingRow } from "@maple/ui/components/ui/setting-row" +import { Radio, RadioGroup } from "@maple/ui/components/ui/radio-group" import { Skeleton } from "@maple/ui/components/ui/skeleton" import { toastManager } from "@maple/ui/components/ui/toast" +import { cn } from "@maple/ui/lib/utils" import { ErrorState } from "@/components/common/error-state" -import { SectionHeading } from "@/components/common/section-heading" +import { SettingsSection } from "@/components/settings/settings-section" import { useBillingActions } from "@/hooks/use-billing-actions" import { useAsyncAction } from "@/hooks/use-mutation-action" import { buildCheckoutSuccessUrl } from "@/lib/billing/checkout-return" @@ -23,28 +23,205 @@ const KEY_REACTIVITY_KEYS = ["openRouterKey"] const ADD_ON_PRICE = "$15/month" +type Provider = "managed" | "openrouter" + /** - * The org's own OpenRouter key. Without the add-on it is the upsell; with it, the key form. + * Which models run the org's AI: Maple managed, or the org's own OpenRouter key (an add-on). * Admin-only: the nav hides the tab from everyone else, and the API refuses their writes. */ -export function AiProviderSection() { +export function ModelProviderSection() { const keyQueryAtom = retainedInternalQuery("openRouterKey", "get", { reactivityKeys: KEY_REACTIVITY_KEYS, }) const keyResult = useAtomValue(keyQueryAtom) const refreshKey = useAtomRefresh(keyQueryAtom) - const setMutation = useAtomSet(MapleInternalAtomClient.mutation("openRouterKey", "set"), { - mode: "promiseExit", - }) + return ( + + {Result.builder(keyResult) + .onInitial(() => ) + .onError((error) => ( + refreshKey()} + /> + )) + .onSuccess((current) => ) + .render()} + + ) +} + +function ProviderChoice({ + current, + onAddOnAttached, +}: { + current: OpenRouterKeyDocument + onAddOnAttached: () => void +}) { const removeMutation = useAtomSet(MapleInternalAtomClient.mutation("openRouterKey", "remove"), { mode: "promiseExit", }) - const { attach } = useBillingActions() + const inUse = current.entitled && current.configured + // A pick only opens a card; the provider itself changes when a key is saved or removed. + const [picked, setPicked] = useState(null) + const selected: Provider = picked ?? (inUse ? "openrouter" : "managed") + const [confirmRemove, setConfirmRemove] = useState(false) + + const [removeKey, isRemoving] = useAsyncAction(async () => { + const exit = await removeMutation({ reactivityKeys: KEY_REACTIVITY_KEYS }) + if (toastExit(exit, { success: "Switched to Maple managed", error: "Failed to remove the key" })) { + setPicked(null) + } + }) + + return ( + <> + { + if (value === "managed" && inUse) setConfirmRemove(true) + else setPicked(value === "openrouter" ? "openrouter" : "managed") + }} + className="grid items-start gap-3 sm:grid-cols-2" + > + + In use : null} + description="OpenRouter bills the tokens. Maple stops charging for AI usage." + > + setConfirmRemove(true)} + onAddOnAttached={onAddOnAttached} + /> + + + + removeKey()} + /> + + ) +} + +function ProviderCard({ + value, + selected, + title, + badge, + description, + children, +}: { + value: Provider + selected: boolean + title: string + badge?: ReactNode + description: string + /** Shown only while this card is selected. */ + children?: ReactNode +}) { + return ( +
+ + {selected && children !== undefined ?
{children}
: null} +
+ ) +} + +/** Inside the OpenRouter card: the add-on upsell, the saved key, or the key form. */ +function OpenRouterKeyPanel({ + current, + busy, + onRemove, + onAddOnAttached, +}: { + current: OpenRouterKeyDocument + busy: boolean + onRemove: () => void + onAddOnAttached: () => void +}) { + const [replacing, setReplacing] = useState(false) + + if (!current.entitled) return + if (current.configured && !replacing) { + return ( +
+ sk-or-...{current.keyHint} +
+ + +
+
+ ) + } + + return ( + setReplacing(false) : undefined} + onSaved={() => setReplacing(false)} + /> + ) +} + +function OpenRouterKeyForm({ + replacing, + onCancel, + onSaved, +}: { + replacing: boolean + onCancel?: () => void + onSaved: () => void +}) { + const setMutation = useAtomSet(MapleInternalAtomClient.mutation("openRouterKey", "set"), { + mode: "promiseExit", + }) const [draft, setDraft] = useState("") - const [confirmRemove, setConfirmRemove] = useState(false) - const [confirmAddOn, setConfirmAddOn] = useState(false) const [saveKey, isSaving] = useAsyncAction(async (apiKey: string) => { const exit = await setMutation({ @@ -53,13 +230,54 @@ export function AiProviderSection() { }) if (toastExit(exit, { success: "OpenRouter key saved", error: "Failed to save the key" })) { setDraft("") + onSaved() } }) - const [removeKey, isRemoving] = useAsyncAction(async () => { - const exit = await removeMutation({ reactivityKeys: KEY_REACTIVITY_KEYS }) - return toastExit(exit, { success: "OpenRouter key removed", error: "Failed to remove the key" }) - }) + return ( +
{ + event.preventDefault() + const apiKey = draft.trim() + if (apiKey !== "") saveKey(apiKey) + }} + > + + + {replacing ? "New OpenRouter API key" : "OpenRouter API key"} + + setDraft(event.target.value)} + /> + + Create one at openrouter.ai/settings/keys. Maple checks it with OpenRouter, then stores it + encrypted. + + +
+ + {onCancel ? ( + + ) : null} +
+
+ ) +} + +function AddOnUpsell({ current, onAttached }: { current: OpenRouterKeyDocument; onAttached: () => void }) { + const [confirmAddOn, setConfirmAddOn] = useState(false) + const { attach } = useBillingActions() const [addOn, isAttaching] = useAsyncAction(() => attach({ @@ -72,138 +290,37 @@ export function AiProviderSection() { return } toastManager.add({ title: "Add-on added", type: "success" }) - refreshKey() + onAttached() }, (error: unknown) => showErrorToast(error, { title: "Failed to add the add-on" }), ), ) - const busy = isSaving || isRemoving - return ( - - {Result.builder(keyResult) - .onInitial(() => ) - .onError((error) => ( - refreshKey()} - /> - )) - .onSuccess((current) => ( - <> -
- In use - ) : null - } - className="items-center gap-2" - /> -

- Run Maple's AI on your own OpenRouter account: chat, incident investigations - and pull request reviews. OpenRouter bills you for the tokens, and Maple stops - charging for AI usage. Models stay the same. -

-
- - {current.configured ? ( - - sk-or-...{current.keyHint} - - - } - /> - ) : null} - - {current.entitled ? ( -
{ - event.preventDefault() - const apiKey = draft.trim() - if (apiKey !== "") saveKey(apiKey) - }} - > - - - {current.configured ? "Replace key" : "OpenRouter API key"} - - setDraft(event.target.value)} - /> - - Create one at openrouter.ai/settings/keys. Maple checks it with - OpenRouter, then stores it encrypted. - - - -
- ) : ( - setConfirmAddOn(true)}> - Add to plan - - } - /> - )} - - {/* With a card on file the attach charges at once and no checkout page follows. */} - addOn()} - /> - - removeKey()} - /> - - )) - .render()} -
+
+ {current.configured ? ( +

+ Your saved key (sk-or-...{current.keyHint}) is not in use because the add-on has lapsed. +

+ ) : null} +

+ Needs the OpenRouter add-on, {ADD_ON_PRICE}, billed with your plan. Cancel any time from + billing. +

+ + {/* With a card on file the attach charges at once and no checkout page follows. */} + addOn()} + /> +
) } diff --git a/apps/web/src/components/settings/ai-triage-limits.test.ts b/apps/web/src/components/settings/ai-triage-limits.test.ts new file mode 100644 index 0000000000..d9ffad114a --- /dev/null +++ b/apps/web/src/components/settings/ai-triage-limits.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from "vitest" + +import { limitsUpdate, parseDailyLimit, RUNS_PER_DAY_LIMITS } from "./ai-triage-limits" + +describe("parseDailyLimit", () => { + it("accepts whole numbers inside the bounds, ignoring surrounding space", () => { + expect(parseDailyLimit(" 300 ", RUNS_PER_DAY_LIMITS)).toEqual({ ok: true, value: 300 }) + expect(parseDailyLimit("1", RUNS_PER_DAY_LIMITS)).toEqual({ ok: true, value: 1 }) + expect(parseDailyLimit("500", RUNS_PER_DAY_LIMITS)).toEqual({ ok: true, value: 500 }) + }) + + it("rejects empty, fractional, negative and out of range input with the range", () => { + for (const input of ["", "1.5", "-3", "0", "501", "1e3", "abc"]) { + const parsed = parseDailyLimit(input, RUNS_PER_DAY_LIMITS) + expect(parsed.ok).toBe(false) + if (!parsed.ok) expect(parsed.message).toContain("1 to 500") + } + }) +}) + +describe("limitsUpdate", () => { + const saved = { maxRunsPerDay: 100, maxPassesPerDay: 1000 } + + it("sends only the ceilings that changed", () => { + expect(limitsUpdate({ maxRunsPerDay: "300", maxPassesPerDay: "1000" }, saved)).toEqual({ + ok: true, + maxRunsPerDay: 300, + maxPassesPerDay: null, + }) + }) + + it("treats a retyped equal value as unchanged", () => { + expect(limitsUpdate({ maxRunsPerDay: "0100", maxPassesPerDay: " 1000" }, saved)).toEqual({ + ok: true, + maxRunsPerDay: null, + maxPassesPerDay: null, + }) + }) + + it("refuses the save when either field is invalid", () => { + expect(limitsUpdate({ maxRunsPerDay: "300", maxPassesPerDay: "5000" }, saved).ok).toBe(false) + }) +}) diff --git a/apps/web/src/components/settings/ai-triage-limits.ts b/apps/web/src/components/settings/ai-triage-limits.ts new file mode 100644 index 0000000000..8d1c8ede08 --- /dev/null +++ b/apps/web/src/components/settings/ai-triage-limits.ts @@ -0,0 +1,42 @@ +/** The bounds the API enforces on each auto-triage ceiling (`AiTriageSettingsUpdateRequest`). */ +export const RUNS_PER_DAY_LIMITS = { min: 1, max: 500 } as const +export const PASSES_PER_DAY_LIMITS = { min: 1, max: 2000 } as const + +export type ParsedLimit = + | { readonly ok: true; readonly value: number } + | { readonly ok: false; readonly message: string } + +/** Reads a typed ceiling: a whole number within the API's bounds, or the reason it is not. */ +export function parseDailyLimit(text: string, bounds: { min: number; max: number }): ParsedLimit { + const trimmed = text.trim() + const range = `Enter a whole number from ${bounds.min} to ${bounds.max}.` + if (!/^\d+$/.test(trimmed)) return { ok: false, message: range } + const value = Number(trimmed) + if (value < bounds.min || value > bounds.max) return { ok: false, message: range } + return { ok: true, value } +} + +export interface AiTriageLimitsDraft { + readonly maxRunsPerDay: string + readonly maxPassesPerDay: string +} + +/** + * The update a draft amounts to: only the ceilings that changed, or the first validation error. + * `null` fields mean unchanged, so a save never rewrites a ceiling the user did not touch. + */ +export function limitsUpdate( + draft: AiTriageLimitsDraft, + saved: { readonly maxRunsPerDay: number; readonly maxPassesPerDay: number }, +): + | { readonly ok: true; readonly maxRunsPerDay: number | null; readonly maxPassesPerDay: number | null } + | { readonly ok: false } { + const runs = parseDailyLimit(draft.maxRunsPerDay, RUNS_PER_DAY_LIMITS) + const passes = parseDailyLimit(draft.maxPassesPerDay, PASSES_PER_DAY_LIMITS) + if (!runs.ok || !passes.ok) return { ok: false } + return { + ok: true, + maxRunsPerDay: runs.value === saved.maxRunsPerDay ? null : runs.value, + maxPassesPerDay: passes.value === saved.maxPassesPerDay ? null : passes.value, + } +} diff --git a/apps/web/src/components/settings/ai-triage-settings-section.tsx b/apps/web/src/components/settings/ai-triage-settings-section.tsx index a166bada34..ef545ee3fe 100644 --- a/apps/web/src/components/settings/ai-triage-settings-section.tsx +++ b/apps/web/src/components/settings/ai-triage-settings-section.tsx @@ -1,212 +1,209 @@ import { Result, useAtomRefresh, useAtomSet, useAtomValue } from "@/lib/effect-atom" -import { useState } from "react" import { formatNumber } from "@maple/ui/lib/format" -import { Badge } from "@maple/ui/components/ui/badge" -import { Field, FieldDescription, FieldLabel } from "@maple/ui/components/ui/field" -import { Panel } from "@maple/ui/components/ui/panel" -import { RefreshButton } from "@maple/ui/components/ui/refresh-button" +import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "@maple/ui/components/ui/collapsible" +import { Field, FieldDescription, FieldError, FieldLabel } from "@maple/ui/components/ui/field" import { Input } from "@maple/ui/components/ui/input" -import { Skeleton } from "@maple/ui/components/ui/skeleton" +import { Meter } from "@maple/ui/components/ui/meter" +import { Panel } from "@maple/ui/components/ui/panel" import { SettingRow } from "@maple/ui/components/ui/setting-row" +import { Skeleton } from "@maple/ui/components/ui/skeleton" import { Switch } from "@maple/ui/components/ui/switch" -import { MapleInternalAtomClient, retainedInternalQuery } from "@/lib/services/common/internal-atom-client" -import { AiTriageSettingsUpdateRequest } from "@maple/domain/http" +import { type AiTriageSettingsDocument, AiTriageSettingsUpdateRequest } from "@maple/domain/http" +import { ChevronRightIcon } from "@/components/icons" import { ErrorState } from "@/components/common/error-state" -import { SectionHeading } from "@/components/common/section-heading" +import { SettingsSaveBar } from "@/components/settings/settings-save-bar" +import { SettingsSection } from "@/components/settings/settings-section" +import { useSettingsDraft } from "@/components/settings/settings-draft" +import { + type AiTriageLimitsDraft, + limitsUpdate, + PASSES_PER_DAY_LIMITS, + parseDailyLimit, + RUNS_PER_DAY_LIMITS, +} from "@/components/settings/ai-triage-limits" +import { MapleInternalAtomClient, retainedInternalQuery } from "@/lib/services/common/internal-atom-client" import { useAsyncAction } from "@/hooks/use-mutation-action" import { toastExit } from "@/lib/error-toast" -interface AiTriageSettingsSectionProps { - isAdmin: boolean - hasEntitlement: boolean -} - const SETTINGS_REACTIVITY_KEYS = ["aiTriageSettings"] -/** - * A number field that commits on blur and only when the value actually changed. - * - * Shared by both ceilings rather than written twice: the draft state, the parse, - * the range guard and the no-op check are the same six lines, and the second copy - * is where the two fields drift apart. - */ -function DailyLimitField({ - id, - label, - value, - min, - max, - disabled, - help, - spent, - onCommit, -}: { - id: string - label: string - value: number - min: number - max: number - disabled: boolean - help: React.ReactNode - /** Consumed so far today. A ceiling on its own does not say whether it is about to bite. */ - spent: number - onCommit: (next: number) => void -}) { - const [draft, setDraft] = useState(null) - return ( - - {label} - setDraft(event.target.value)} - onBlur={() => { - if (draft === null) return - const parsed = Number.parseInt(draft, 10) - setDraft(null) - if (Number.isFinite(parsed) && parsed >= min && parsed <= max && parsed !== value) { - onCommit(parsed) - } - }} - /> - - - {formatNumber(spent)} of {formatNumber(value)} used today - {" "} - · {help} - - - ) -} +const DESCRIPTION = + "When an error or anomaly incident opens, an agent investigates it with read-only tools and attaches a triage summary. Runs on the model provider above." -export function AiTriageSettingsSection({ isAdmin, hasEntitlement }: AiTriageSettingsSectionProps) { +/** Auto-triage on the AI tab: the switch saves at once, the two ceilings go through the save bar. */ +export function AutoTriageSection() { const settingsQueryAtom = retainedInternalQuery("aiTriage", "getSettings", { reactivityKeys: SETTINGS_REACTIVITY_KEYS, }) const settingsResult = useAtomValue(settingsQueryAtom) const refreshSettings = useAtomRefresh(settingsQueryAtom) - const updateMutation = useAtomSet(MapleInternalAtomClient.mutation("aiTriage", "updateSettings"), { - mode: "promiseExit", - }) - - const [save, isSaving] = useAsyncAction( - async (request: AiTriageSettingsUpdateRequest, successMessage: string) => { - const result = await updateMutation({ - payload: request, - reactivityKeys: SETTINGS_REACTIVITY_KEYS, - }) - toastExit(result, { success: successMessage, error: "Failed to update AI triage settings" }) - }, - ) - - if (!isAdmin || !hasEntitlement) { - return null - } - - const settings = Result.builder(settingsResult) - .onSuccess((value) => value) - .orElse(() => null) - return ( - -
- Enabled : null} - className="items-center gap-2" - /> -

- When a new error or anomaly incident opens, an AI agent automatically investigates it with - read-only tools and attaches a triage summary. Runs use Maple's managed AI, no setup - required. -

-
+ {Result.builder(settingsResult) - .onInitial(() => ) + .onInitial(() => ) .onError((error) => ( refreshSettings()} /> )) - .onSuccess((current) => ( - <> - - save( - new AiTriageSettingsUpdateRequest({ enabled: checked }), - checked ? "AI auto-triage enabled" : "AI auto-triage disabled", - ) - } - /> - } - /> + .onSuccess((current) => ) + .render()} + + ) +} - - save( - new AiTriageSettingsUpdateRequest({ maxRunsPerDay: parsed }), - "Daily run cap updated", - ) - } - /> +function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { + const updateMutation = useAtomSet(MapleInternalAtomClient.mutation("aiTriage", "updateSettings"), { + mode: "promiseExit", + }) + const saved: AiTriageLimitsDraft = { + maxRunsPerDay: String(current.maxRunsPerDay), + maxPassesPerDay: String(current.maxPassesPerDay), + } + const { draft, isDirty, updateDraft, discard } = useSettingsDraft(saved) + + const send = async (request: AiTriageSettingsUpdateRequest, success: string) => + toastExit(await updateMutation({ payload: request, reactivityKeys: SETTINGS_REACTIVITY_KEYS }), { + success, + error: "Failed to update auto-triage settings", + }) + + const [toggle, isToggling] = useAsyncAction((enabled: boolean) => + send( + new AiTriageSettingsUpdateRequest({ enabled }), + enabled ? "Auto-triage turned on" : "Auto-triage turned off", + ), + ) + + const update = limitsUpdate(draft, current) + const [saveLimits, isSavingLimits] = useAsyncAction(async () => { + if (!update.ok) return + const request = new AiTriageSettingsUpdateRequest({ + ...(update.maxRunsPerDay === null ? undefined : { maxRunsPerDay: update.maxRunsPerDay }), + ...(update.maxPassesPerDay === null ? undefined : { maxPassesPerDay: update.maxPassesPerDay }), + }) + if (await send(request, "Auto-triage limits saved")) discard() + }) + + const runsError = parseDailyLimit(draft.maxRunsPerDay, RUNS_PER_DAY_LIMITS) + const passesError = parseDailyLimit(draft.maxPassesPerDay, PASSES_PER_DAY_LIMITS) - + + toggle(checked)} + /> + } + /> + updateDraft((d) => ({ ...d, maxRunsPerDay }))} + /> + + + + Advanced limits + + Model passes per day, reserve for high and critical incidents + + + + - save( - new AiTriageSettingsUpdateRequest({ maxPassesPerDay: parsed }), - "Daily model-pass cap updated", - ) - } + disabled={isSavingLimits} + onChange={(maxPassesPerDay) => updateDraft((d) => ({ ...d, maxPassesPerDay }))} /> + + + + saveLimits()} + saveDisabled={!update.ok} + /> + + ) +} -

- Both ceilings apply to automatic triage only. Investigations you start or retry - yourself are never blocked by them. -

- -
- refreshSettings()} - /> -
+/** A daily ceiling with today's consumption under it, so it is clear whether it is about to bite. */ +function LimitRow({ + id, + label, + help, + value, + error, + limit, + spent, + disabled, + onChange, +}: { + id: string + label: string + help: string + value: string + error: string | null + limit: number + spent: number + disabled: boolean + onChange: (next: string) => void +}) { + return ( + +
+ {label} + {help} +
+
+ onChange(event.target.value)} + /> + {error === null ? ( + <> + + + {formatNumber(spent)} used today + - )) - .render()} - + ) : ( + {error} + )} +
+
) } diff --git a/apps/web/src/components/settings/automation-section.tsx b/apps/web/src/components/settings/automation-section.tsx index a116999ed5..e15d2f3909 100644 --- a/apps/web/src/components/settings/automation-section.tsx +++ b/apps/web/src/components/settings/automation-section.tsx @@ -17,7 +17,6 @@ import { SeverityBadge } from "@/components/errors/severity-badge" import { ErrorState } from "@/components/common/error-state" import { SkeletonList } from "@maple/ui/components/ui/skeleton" import { SeveritySelect } from "@/components/errors/severity-select" -import { AiTriageSettingsSection } from "./ai-triage-settings-section" import { EscalationPolicySection } from "./escalation-policy-section" import { SettingsSection, SettingsSections } from "@/components/settings/settings-section" import { MapleInternalAtomClient, retainedInternalQuery } from "@/lib/services/common/internal-atom-client" @@ -28,13 +27,7 @@ import { toastExit } from "@/lib/error-toast" const CONFIDENCES: ReadonlyArray = ["high", "medium", "low"] -export function AutomationSection({ - isAdmin, - hasEntitlement, -}: { - isAdmin: boolean - hasEntitlement: boolean -}) { +export function AutomationSection({ isAdmin }: { isAdmin: boolean }) { // The evaluate endpoint only reads the stored policy, so unsaved edits are invisible to it. // `revision` bumps on every edit, so a decision computed before it is never shown after a save. const [policy, setPolicy] = useState({ dirty: false, revision: 0 }) @@ -42,9 +35,6 @@ export function AutomationSection({ setPolicy((current) => ({ dirty, revision: dirty ? current.revision + 1 : current.revision })) return ( - - - } + render={} > Raise the limit diff --git a/apps/web/src/routes/settings.tsx b/apps/web/src/routes/settings.tsx index a51f3b08af..e8bd481eb4 100644 --- a/apps/web/src/routes/settings.tsx +++ b/apps/web/src/routes/settings.tsx @@ -11,7 +11,9 @@ import { IngestionSection } from "@/components/settings/ingestion-section" import { ApiKeysSection } from "@/components/settings/api-keys-section" import { AuditLogSection } from "@/components/settings/audit-log-section" import { McpSection } from "@/components/settings/mcp-section" -import { AiProviderSection } from "@/components/settings/ai-provider-section" +import { ModelProviderSection } from "@/components/settings/ai-provider-section" +import { AutoTriageSection } from "@/components/settings/ai-triage-settings-section" +import { SettingsSections } from "@/components/settings/settings-section" import { AutomationSection } from "@/components/settings/automation-section" import { OrgClickHouseSettingsSection } from "@/components/settings/org-clickhouse-settings-section" import { OrganizationSection } from "@/components/settings/organization-section" @@ -108,10 +110,14 @@ function SettingsPage() { {activeTab === "ingestion" && } {activeTab === "keys" && } {activeTab === "mcp" && } - {activeTab === "ai" && } - {activeTab === "automation" && ( - + {activeTab === "ai" && ( + + + {/* The tab is admin-only; auto-triage also needs its flag. */} + {canAccessAi && } + )} + {activeTab === "automation" && } {activeTab === "billing" && } {activeTab === "data-platform" && ( Date: Sat, 17 Oct 2026 10:11:49 +0200 Subject: [PATCH 02/13] feat(digest): send digests on the subscriber's day, hour and time zone Adds a send_hour column (default 09:00) and computes whether a digest is due on the subscriber's local clock with Effect DateTime instead of the UTC weekday. Both the ops and web analytics digests use it; lastSentAt keeps sends idempotent with a six day minimum gap, so moving the hour or zone after a send does not resend. The upsert API validates the weekday, hour and IANA zone. --- apps/api/src/routes/internal/digest.http.ts | 1 + .../src/services/digest/DigestService.test.ts | 22 +- .../src/services/digest/DigestService.ts | 12 +- .../digest/WebAnalyticsDigestService.ts | 11 +- .../services/digest/digest-schedule.test.ts | 73 + .../src/services/digest/digest-schedule.ts | 36 + .../migration.sql | 2 + .../snapshot.json | 13101 ++++++++++++++++ packages/db/src/tables/digest.ts | 2 + packages/domain/src/http/digest.test.ts | 25 + packages/domain/src/http/digest.ts | 29 +- 11 files changed, 13294 insertions(+), 20 deletions(-) create mode 100644 packages/backend/src/services/digest/digest-schedule.test.ts create mode 100644 packages/backend/src/services/digest/digest-schedule.ts create mode 100644 packages/db/drizzle/20261017080931_digest_send_hour/migration.sql create mode 100644 packages/db/drizzle/20261017080931_digest_send_hour/snapshot.json create mode 100644 packages/domain/src/http/digest.test.ts diff --git a/apps/api/src/routes/internal/digest.http.ts b/apps/api/src/routes/internal/digest.http.ts index ba7e4b2c20..c78cf302c5 100644 --- a/apps/api/src/routes/internal/digest.http.ts +++ b/apps/api/src/routes/internal/digest.http.ts @@ -23,6 +23,7 @@ export const HttpDigestLive = HttpApiBuilder.group(MapleInternalApi, "digest", ( email: payload.email, enabled: payload.enabled, dayOfWeek: payload.dayOfWeek, + sendHour: payload.sendHour, timezone: payload.timezone, namespaces: payload.namespaces, environments: payload.environments, diff --git a/packages/backend/src/services/digest/DigestService.test.ts b/packages/backend/src/services/digest/DigestService.test.ts index 62ea9c1cb6..08d6c82c31 100644 --- a/packages/backend/src/services/digest/DigestService.test.ts +++ b/packages/backend/src/services/digest/DigestService.test.ts @@ -36,11 +36,11 @@ const testConfig = () => }), ) -// Monday 2026-07-06 08:00 UTC — getUTCDay() === 1, matching the default -// subscription dayOfWeek. All seeded timestamps derive from this epoch so +// Monday 2026-07-06 09:00 UTC, when the default schedule (Monday, 09:00, UTC) is due. +// All seeded timestamps derive from this epoch so // rows and the service (which reads Clock.currentTimeMillis) share one // time base. -const TICK_MS = Date.UTC(2026, 6, 6, 8, 0, 0) +const TICK_MS = Date.UTC(2026, 6, 6, 9, 0, 0) interface StubOverviewRow { serviceName: string @@ -236,6 +236,22 @@ describe("DigestService.runDigestTick", () => { }).pipe(Effect.provide(layer)) }) + it.effect("sends only to subscribers whose own day, hour and zone have come round", () => { + const { sends, layer } = makeHarness() + return Effect.gen(function* () { + // 09:00 UTC Monday is 11:00 in Berlin, 02:00 in Los Angeles and 18:00 Monday in Tokyo. + yield* TestClock.setTime(TICK_MS) + yield* seedSub({ email: "berlin@example.com", timezone: "Europe/Berlin", sendHour: 10 }) + yield* seedSub({ email: "la@example.com", timezone: "America/Los_Angeles", sendHour: 9 }) + yield* seedSub({ email: "tokyo@example.com", timezone: "Asia/Tokyo", dayOfWeek: 2, sendHour: 0 }) + + const digest = yield* DigestService + yield* digest.runDigestTick() + + assert.deepStrictEqual(sends, ["berlin@example.com"]) + }).pipe(Effect.provide(layer)) + }) + it.effect("does not re-send to a sub already attempted today when another sub is claimed", () => { const { sends, layer } = makeHarness() return Effect.gen(function* () { diff --git a/packages/backend/src/services/digest/DigestService.ts b/packages/backend/src/services/digest/DigestService.ts index a4261b6a40..6464c72246 100644 --- a/packages/backend/src/services/digest/DigestService.ts +++ b/packages/backend/src/services/digest/DigestService.ts @@ -53,6 +53,7 @@ import { import { formatWarehouseDateTime } from "@maple/query-engine" import * as CH from "@maple/query-engine/ch" +import { isDigestDue } from "./digest-schedule" import { resolveOrgName } from "./resolve-org-name" import { unsubscribeLinks, verifyUnsubscribeToken } from "./unsubscribe-token" import { summarizeCause } from "@maple/backend/platform/describe-cause" @@ -320,6 +321,7 @@ export class DigestService extends Context.Service()("@maple/api/ email: string enabled?: boolean dayOfWeek?: number + sendHour?: number timezone?: string namespaces?: ReadonlyArray environments?: ReadonlyArray @@ -343,6 +345,7 @@ export class DigestService extends Context.Service()("@maple/api/ enabled: input.enabled !== false, optedOutAt: input.enabled === false ? now : null, dayOfWeek: input.dayOfWeek ?? 1, + ...(input.sendHour != null ? { sendHour: input.sendHour } : undefined), timezone: input.timezone ?? "UTC", namespacesJson: JSON.stringify(input.namespaces ?? []), environmentsJson: JSON.stringify(input.environments ?? []), @@ -361,6 +364,7 @@ export class DigestService extends Context.Service()("@maple/api/ // can tell an opt-out from a member it disabled itself. optedOutAt: input.enabled === false ? now : null, ...(input.dayOfWeek != null ? { dayOfWeek: input.dayOfWeek } : undefined), + ...(input.sendHour != null ? { sendHour: input.sendHour } : undefined), ...(input.timezone != null ? { timezone: input.timezone } : undefined), ...(input.namespaces != null ? { namespacesJson: JSON.stringify(input.namespaces) } @@ -1035,9 +1039,7 @@ export class DigestService extends Context.Service()("@maple/api/ ) const now = yield* Clock.currentTimeMillis - const sevenDaysAgo = now - 7 * 24 * 60 * 60 * 1000 const todayStartMs = now - (now % 86_400_000) - const currentDayOfWeek = new Date(now).getUTCDay() const subs = yield* dbExecute((db) => db.run( @@ -1047,10 +1049,7 @@ export class DigestService extends Context.Service()("@maple/api/ ), ) - const dueSubs = subs.filter( - (s) => - s.dayOfWeek === currentDayOfWeek && (s.lastSentAt == null || s.lastSentAt < sevenDaysAgo), - ) + const dueSubs = subs.filter((s) => isDigestDue(s, s.lastSentAt, now)) if (dueSubs.length === 0) { return { sentCount: 0, errorCount: 0, skipped: false } @@ -1265,6 +1264,7 @@ function rowToResponse(row: DigestSubscriptionRow): DigestSubscriptionResponse { email: row.email, enabled: row.enabled, dayOfWeek: row.dayOfWeek, + sendHour: row.sendHour, timezone: row.timezone, namespaces: parseScopeColumn(row.namespacesJson), environments: parseScopeColumn(row.environmentsJson), diff --git a/packages/backend/src/services/digest/WebAnalyticsDigestService.ts b/packages/backend/src/services/digest/WebAnalyticsDigestService.ts index 44283ffdd2..22052a87d8 100644 --- a/packages/backend/src/services/digest/WebAnalyticsDigestService.ts +++ b/packages/backend/src/services/digest/WebAnalyticsDigestService.ts @@ -43,6 +43,7 @@ import { isOrgWarehouseQuarantined, quarantineOnConfigClassCause, } from "@maple/backend/services/warehouse/warehouse-org-quarantine" +import { isDigestDue } from "./digest-schedule" import { resolveOrgName } from "./resolve-org-name" import { unsubscribeLinks } from "./unsubscribe-token" @@ -448,16 +449,14 @@ export class WebAnalyticsDigestService extends Context.Service db.run( @@ -467,11 +466,7 @@ export class WebAnalyticsDigestService extends Context.Service - s.dayOfWeek === currentDayOfWeek && - (s.webAnalyticsLastSentAt == null || s.webAnalyticsLastSentAt < sevenDaysAgo), - ) + const due = subs.filter((s) => isDigestDue(s, s.webAnalyticsLastSentAt, now)) if (due.length === 0) return { sentCount: 0, errorCount: 0, skipped: false } const byOrg = Arr.groupBy(due, (s) => s.orgId) diff --git a/packages/backend/src/services/digest/digest-schedule.test.ts b/packages/backend/src/services/digest/digest-schedule.test.ts new file mode 100644 index 0000000000..c9d5dcacad --- /dev/null +++ b/packages/backend/src/services/digest/digest-schedule.test.ts @@ -0,0 +1,73 @@ +import { describe, expect, it } from "vitest" + +import { isDigestDue } from "./digest-schedule" + +const at = (iso: string) => Date.parse(iso) +const MONDAY = 1 +const SUNDAY = 0 +const WEEK_MS = 7 * 24 * 60 * 60 * 1000 + +describe("isDigestDue", () => { + it("waits for the send hour on the local clock, not the UTC one", () => { + const berlin = { dayOfWeek: MONDAY, sendHour: 9, timezone: "Europe/Berlin" } + // Summer time: 09:00 in Berlin is 07:00 UTC. + expect(isDigestDue(berlin, null, at("2026-07-06T06:45:00Z"))).toBe(false) + expect(isDigestDue(berlin, null, at("2026-07-06T07:00:00Z"))).toBe(true) + }) + + it("uses the local weekday when it differs from the UTC one", () => { + const tokyo = { dayOfWeek: MONDAY, sendHour: 9, timezone: "Asia/Tokyo" } + // Monday 09:00 in Tokyo is Monday 00:00 UTC; Sunday 23:59 UTC is Monday 08:59 there. + expect(isDigestDue(tokyo, null, at("2026-07-05T23:59:00Z"))).toBe(false) + expect(isDigestDue(tokyo, null, at("2026-07-06T00:00:00Z"))).toBe(true) + // Monday 15:00 UTC is already Tuesday in Tokyo. + expect(isDigestDue(tokyo, null, at("2026-07-06T15:00:00Z"))).toBe(false) + + const losAngeles = { dayOfWeek: MONDAY, sendHour: 9, timezone: "America/Los_Angeles" } + // Monday 08:00 UTC is still 01:00 Monday in Los Angeles. + expect(isDigestDue(losAngeles, null, at("2026-07-06T08:00:00Z"))).toBe(false) + expect(isDigestDue(losAngeles, null, at("2026-07-06T16:00:00Z"))).toBe(true) + }) + + it("stays due for the rest of the local day so a missed tick still sends", () => { + const utc = { dayOfWeek: MONDAY, sendHour: 9, timezone: "UTC" } + expect(isDigestDue(utc, null, at("2026-07-06T23:45:00Z"))).toBe(true) + expect(isDigestDue(utc, null, at("2026-07-07T00:00:00Z"))).toBe(false) + }) + + it("sends once per week however many ticks fall in the window", () => { + const utc = { dayOfWeek: MONDAY, sendHour: 9, timezone: "UTC" } + const sentAt = at("2026-07-06T09:00:00Z") + expect(isDigestDue(utc, sentAt, at("2026-07-06T09:15:00Z"))).toBe(false) + expect(isDigestDue(utc, sentAt, sentAt + WEEK_MS)).toBe(true) + }) + + it("does not send twice when the hour or zone moves right after a send", () => { + const sentAt = at("2026-07-06T07:00:00Z") + const later = { dayOfWeek: MONDAY, sendHour: 15, timezone: "Europe/Berlin" } + expect(isDigestDue(later, sentAt, at("2026-07-06T13:00:00Z"))).toBe(false) + }) + + it("follows the local clock across the spring DST change", () => { + const berlin = { dayOfWeek: MONDAY, sendHour: 9, timezone: "Europe/Berlin" } + // Sent Monday 23 March at 09:00 CET (08:00 UTC); clocks go forward on Sunday 29 March. + const sentAt = at("2026-03-23T08:00:00Z") + expect(isDigestDue(berlin, sentAt, at("2026-03-30T06:45:00Z"))).toBe(false) + // 09:00 CEST is 07:00 UTC, less than seven days after the last send. + expect(isDigestDue(berlin, sentAt, at("2026-03-30T07:00:00Z"))).toBe(true) + }) + + it("does not resend in the repeated hour when clocks fall back", () => { + const newYork = { dayOfWeek: SUNDAY, sendHour: 1, timezone: "America/New_York" } + // 01:00 happens twice on Sunday 1 November 2026: 05:00 UTC (EDT) and 06:00 UTC (EST). + const sentAt = at("2026-11-01T05:00:00Z") + expect(isDigestDue(newYork, null, sentAt)).toBe(true) + expect(isDigestDue(newYork, sentAt, at("2026-11-01T06:00:00Z"))).toBe(false) + }) + + it("falls back to UTC for a zone the runtime does not know", () => { + const unknown = { dayOfWeek: MONDAY, sendHour: 9, timezone: "Mars/Olympus_Mons" } + expect(isDigestDue(unknown, null, at("2026-07-06T08:59:00Z"))).toBe(false) + expect(isDigestDue(unknown, null, at("2026-07-06T09:00:00Z"))).toBe(true) + }) +}) diff --git a/packages/backend/src/services/digest/digest-schedule.ts b/packages/backend/src/services/digest/digest-schedule.ts new file mode 100644 index 0000000000..3788e58640 --- /dev/null +++ b/packages/backend/src/services/digest/digest-schedule.ts @@ -0,0 +1,36 @@ +import { DateTime, Option } from "effect" + +const DAY_MS = 24 * 60 * 60 * 1000 + +/** + * The shortest gap between two sends of one digest. Shorter than a week so a send that ran + * late last week never blocks this week's, longer than a day so moving the hour or zone right + * after a send cannot fire the same week's digest twice. + */ +const MIN_RESEND_GAP_MS = 6 * DAY_MS + +export interface DigestSchedule { + /** 0 = Sunday ... 6 = Saturday, in `timezone`. */ + readonly dayOfWeek: number + /** Local hour (0-23) from which the digest is due for the rest of that local day. */ + readonly sendHour: number + /** IANA zone; an unknown one falls back to UTC rather than never sending. */ + readonly timezone: string +} + +const resolveZone = (timezone: string): DateTime.TimeZone => + Option.getOrElse(DateTime.zoneMakeNamed(timezone), () => DateTime.zoneMakeOffset(0)) + +/** + * Whether a weekly digest should go out at `nowMs`: it is the subscriber's chosen weekday in + * their zone, the local clock has reached their send hour, and nothing went out in the last + * six days. The digest tick runs every 15 minutes, so this window is hit on the first tick at + * or after the send hour, and `lastSentAt` keeps every later tick that day idempotent. + */ +export function isDigestDue(schedule: DigestSchedule, lastSentAt: number | null, nowMs: number): boolean { + const local = DateTime.toParts( + DateTime.makeZonedUnsafe(nowMs, { timeZone: resolveZone(schedule.timezone) }), + ) + if (local.weekDay !== schedule.dayOfWeek || local.hour < schedule.sendHour) return false + return lastSentAt === null || lastSentAt <= nowMs - MIN_RESEND_GAP_MS +} diff --git a/packages/db/drizzle/20261017080931_digest_send_hour/migration.sql b/packages/db/drizzle/20261017080931_digest_send_hour/migration.sql new file mode 100644 index 0000000000..caa357452e --- /dev/null +++ b/packages/db/drizzle/20261017080931_digest_send_hour/migration.sql @@ -0,0 +1,2 @@ +-- metadata +ALTER TABLE "digest_subscriptions" ADD COLUMN IF NOT EXISTS "send_hour" integer NOT NULL DEFAULT 9; diff --git a/packages/db/drizzle/20261017080931_digest_send_hour/snapshot.json b/packages/db/drizzle/20261017080931_digest_send_hour/snapshot.json new file mode 100644 index 0000000000..8d40369926 --- /dev/null +++ b/packages/db/drizzle/20261017080931_digest_send_hour/snapshot.json @@ -0,0 +1,13101 @@ +{ + "version": "1", + "dialect": "postgres", + "id": "a240a246596b6192403f5133d7dbd6f57e559f11ea408e7c6998b0049ab9c03e", + "prevIds": [ + "48d3838043af2317670b4d331517fd04bd0799b1c95720a38eda958dac3f91dd" + ], + "entities": [ + { + "kind": "table", + "name": "actors", + "primaryKey": { + "name": "actors_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "agent_feedback", + "primaryKey": { + "name": "agent_feedback_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "ai_triage_settings", + "primaryKey": { + "name": "ai_triage_settings_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "alert_delivery_events", + "primaryKey": { + "name": "alert_delivery_events_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "alert_destinations", + "primaryKey": { + "name": "alert_destinations_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "alert_incidents", + "primaryKey": { + "name": "alert_incidents_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "alert_rule_claims", + "primaryKey": { + "name": "alert_rule_claims_pkey", + "columns": [ + "rule_id" + ] + } + }, + { + "kind": "table", + "name": "alert_rule_states", + "primaryKey": { + "name": "alert_rule_states_org_id_rule_id_group_key_pk", + "columns": [ + "org_id", + "rule_id", + "group_key" + ] + } + }, + { + "kind": "table", + "name": "alert_rules", + "primaryKey": { + "name": "alert_rules_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "anomaly_detector_settings", + "primaryKey": { + "name": "anomaly_detector_settings_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "anomaly_detector_states", + "primaryKey": { + "name": "anomaly_detector_states_org_id_detector_key_pk", + "columns": [ + "org_id", + "detector_key" + ] + } + }, + { + "kind": "table", + "name": "anomaly_incidents", + "primaryKey": { + "name": "anomaly_incidents_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "api_keys", + "primaryKey": { + "name": "api_keys_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "cancellation_reviews", + "primaryKey": { + "name": "cancellation_reviews_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "chat_identities", + "primaryKey": { + "name": "chat_identities_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "chat_workspaces", + "primaryKey": { + "name": "chat_workspaces_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "cli_device_authorizations", + "primaryKey": { + "name": "cli_device_authorizations_pkey", + "columns": [ + "device_code_hash" + ] + } + }, + { + "kind": "table", + "name": "cloudflare_analytics_state", + "primaryKey": { + "name": "cloudflare_analytics_state_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "cloudflare_hyperdrive_configs", + "primaryKey": { + "name": "cloudflare_hyperdrive_configs_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "cloudflare_logpush_connectors", + "primaryKey": { + "name": "cloudflare_logpush_connectors_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "dashboard_shares", + "primaryKey": { + "name": "dashboard_shares_org_id_id_pk", + "columns": [ + "org_id", + "id" + ] + } + }, + { + "kind": "table", + "name": "dashboard_versions", + "primaryKey": { + "name": "dashboard_versions_org_id_id_pk", + "columns": [ + "org_id", + "id" + ] + } + }, + { + "kind": "table", + "name": "dashboards", + "primaryKey": { + "name": "dashboards_org_id_id_pk", + "columns": [ + "org_id", + "id" + ] + } + }, + { + "kind": "table", + "name": "digest_subscriptions", + "primaryKey": { + "name": "digest_subscriptions_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_fingerprint_candidates", + "primaryKey": { + "name": "error_fingerprint_candidates_org_id_fingerprint_hash_pk", + "columns": [ + "org_id", + "fingerprint_hash" + ] + } + }, + { + "kind": "table", + "name": "error_incidents", + "primaryKey": { + "name": "error_incidents_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_issue_events", + "primaryKey": { + "name": "error_issue_events_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_issue_pull_requests", + "primaryKey": { + "name": "error_issue_pull_requests_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_issue_states", + "primaryKey": { + "name": "error_issue_states_org_id_issue_id_pk", + "columns": [ + "org_id", + "issue_id" + ] + } + }, + { + "kind": "table", + "name": "error_issue_verifications", + "primaryKey": { + "name": "error_issue_verifications_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_issues", + "primaryKey": { + "name": "error_issues_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_notification_deliveries", + "primaryKey": { + "name": "error_notification_deliveries_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "error_notification_policies", + "primaryKey": { + "name": "error_notification_policies_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "error_tick_states", + "primaryKey": { + "name": "error_tick_states_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "gcp_connectors", + "primaryKey": { + "name": "gcp_connectors_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "gcp_resources", + "primaryKey": { + "name": "gcp_resources_pkey", + "columns": [ + "connector_id", + "name" + ] + } + }, + { + "kind": "table", + "name": "investigations", + "primaryKey": { + "name": "investigations_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "issue_escalation_policies", + "primaryKey": { + "name": "issue_escalation_policies_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "issue_escalations", + "primaryKey": { + "name": "issue_escalations_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "live_activities", + "primaryKey": { + "name": "live_activities_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "mcp_oauth_authorizations", + "primaryKey": { + "name": "mcp_oauth_authorizations_pkey", + "columns": [ + "request_id_hash" + ] + } + }, + { + "kind": "table", + "name": "mcp_oauth_clients", + "primaryKey": { + "name": "mcp_oauth_clients_pkey", + "columns": [ + "client_id" + ] + } + }, + { + "kind": "table", + "name": "mcp_oauth_refresh_tokens", + "primaryKey": { + "name": "mcp_oauth_refresh_tokens_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "mobile_devices", + "primaryKey": { + "name": "mobile_devices_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "oauth_auth_states", + "primaryKey": { + "name": "oauth_auth_states_pkey", + "columns": [ + "state" + ] + } + }, + { + "kind": "table", + "name": "oauth_connections", + "primaryKey": { + "name": "oauth_connections_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "org_clickhouse_schema_apply_runs", + "primaryKey": { + "name": "org_clickhouse_schema_apply_runs_org_id_pk", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "org_clickhouse_settings", + "primaryKey": { + "name": "org_clickhouse_settings_org_id_pk", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "org_ingest_attribute_mappings", + "primaryKey": { + "name": "org_ingest_attribute_mappings_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "org_ingest_keys", + "primaryKey": { + "name": "org_ingest_keys_org_id_pk", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "org_ingest_sampling_policies", + "primaryKey": { + "name": "org_ingest_sampling_policies_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "org_onboarding_state", + "primaryKey": { + "name": "org_onboarding_state_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "org_openrouter_keys", + "primaryKey": { + "name": "org_openrouter_keys_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "org_recommendation_issues", + "primaryKey": { + "name": "org_recommendation_issues_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "org_support_channels", + "primaryKey": { + "name": "org_support_channels_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "planetscale_connections", + "primaryKey": { + "name": "planetscale_connections_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "planetscale_databases", + "primaryKey": { + "name": "planetscale_databases_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "planetscale_events", + "primaryKey": { + "name": "planetscale_events_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "planetscale_issue_receipts", + "primaryKey": { + "name": "planetscale_issue_receipts_org_id_event_id_pk", + "columns": [ + "org_id", + "event_id" + ] + } + }, + { + "kind": "table", + "name": "planetscale_poll_state", + "primaryKey": { + "name": "planetscale_poll_state_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "pr_review_edits", + "primaryKey": { + "name": "pr_review_edits_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "pr_review_finding_embeddings", + "primaryKey": { + "name": "pr_review_finding_embeddings_pkey", + "columns": [ + "finding_id" + ] + } + }, + { + "kind": "table", + "name": "pr_review_findings", + "primaryKey": { + "name": "pr_review_findings_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "pr_review_merge_steps", + "primaryKey": { + "name": "pr_review_merge_steps_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "pr_review_replies", + "primaryKey": { + "name": "pr_review_replies_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "pr_review_settings", + "primaryKey": { + "name": "pr_review_settings_pkey", + "columns": [ + "org_id" + ] + } + }, + { + "kind": "table", + "name": "pr_reviews", + "primaryKey": { + "name": "pr_reviews_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "railway_connections", + "primaryKey": { + "name": "railway_connections_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "railway_environments", + "primaryKey": { + "name": "railway_environments_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "scrape_target_checks", + "primaryKey": { + "name": "scrape_target_checks_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "scrape_targets", + "primaryKey": { + "name": "scrape_targets_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "vcs_commits", + "primaryKey": { + "name": "vcs_commits_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "vcs_installations", + "primaryKey": { + "name": "vcs_installations_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "vcs_repositories", + "primaryKey": { + "name": "vcs_repositories_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "table", + "name": "vcs_repository_branches", + "primaryKey": { + "name": "vcs_repository_branches_pkey", + "columns": [ + "id" + ] + } + }, + { + "kind": "column", + "table": "actors", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "type", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "user_id", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "agent_name", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "model", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "capabilities_json", + "position": 6, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "created_by", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "created_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "actors", + "name": "last_active_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "user_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "kind", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "impact", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "summary", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "reason", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "details", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "related_to", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "agent_type", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "agent_name", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "agent_model", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "agent_version", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "source", + "position": 13, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "agent_feedback", + "name": "created_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "ai_triage_settings", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "ai_triage_settings", + "name": "enabled", + "position": 1, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "ai_triage_settings", + "name": "max_runs_per_day", + "position": 2, + "type": "integer", + "notNull": true, + "default": "20", + "identity": null + }, + { + "kind": "column", + "table": "ai_triage_settings", + "name": "max_passes_per_day", + "position": 3, + "type": "integer", + "notNull": true, + "default": "90", + "identity": null + }, + { + "kind": "column", + "table": "ai_triage_settings", + "name": "updated_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "ai_triage_settings", + "name": "updated_by", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "incident_id", + "position": 2, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "rule_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "destination_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "delivery_key", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "event_type", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "attempt_number", + "position": 7, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "status", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "scheduled_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "claimed_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "claim_expires_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "claimed_by", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "attempted_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "provider_message", + "position": 14, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "provider_reference", + "position": 15, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "response_code", + "position": 16, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "error_message", + "position": 17, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "payload_json", + "position": 18, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "created_at", + "position": 19, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_delivery_events", + "name": "updated_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "type", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "enabled", + "position": 4, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "config_json", + "position": 5, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "secret_ciphertext", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "secret_iv", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "secret_tag", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "last_tested_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "last_test_error", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "consecutive_failures", + "position": 11, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "last_failure_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "disabled_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "disabled_reason", + "position": 14, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "created_by", + "position": 17, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_destinations", + "name": "updated_by", + "position": 18, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "rule_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "incident_key", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "rule_name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "group_key", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "signal_type", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "severity", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "status", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "comparator", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "threshold", + "position": 10, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "threshold_upper", + "position": 11, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "first_triggered_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "last_triggered_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "resolved_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "last_observed_value", + "position": 15, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "last_sample_count", + "position": 16, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "last_evaluated_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "dedupe_key", + "position": 18, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "last_delivered_event_type", + "position": 19, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "last_notified_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "hold_reason", + "position": 21, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "held_since", + "position": 22, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "error_issue_id", + "position": 23, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "created_at", + "position": 24, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_incidents", + "name": "updated_at", + "position": 25, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_claims", + "name": "rule_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_claims", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_claims", + "name": "last_scheduled_at", + "position": 2, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "rule_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "group_key", + "position": 2, + "type": "text", + "notNull": true, + "default": "'__total__'", + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "consecutive_breaches", + "position": 3, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "consecutive_healthy", + "position": 4, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "last_status", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "last_value", + "position": 6, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "last_sample_count", + "position": 7, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "last_evaluated_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "last_error", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rule_states", + "name": "updated_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "notes", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "notification_template_json", + "position": 4, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "enabled", + "position": 5, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "severity", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "service_names_json", + "position": 7, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "exclude_service_names_json", + "position": 8, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "environments_json", + "position": 9, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "tags_json", + "position": 10, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "signal_type", + "position": 11, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "comparator", + "position": 12, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "threshold", + "position": 13, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "threshold_upper", + "position": 14, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "window_minutes", + "position": 15, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "minimum_sample_count", + "position": 16, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "consecutive_breaches_required", + "position": 17, + "type": "integer", + "notNull": true, + "default": "2", + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "consecutive_healthy_required", + "position": 18, + "type": "integer", + "notNull": true, + "default": "2", + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "renotify_interval_minutes", + "position": 19, + "type": "integer", + "notNull": true, + "default": "30", + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "apdex_threshold_ms", + "position": 20, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "query_builder_draft_json", + "position": 21, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "raw_query_sql", + "position": 22, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "group_by", + "position": 23, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "destination_ids_json", + "position": 24, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "query_spec_json", + "position": 25, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "reducer", + "position": 26, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "sample_count_strategy", + "position": 27, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "no_data_behavior", + "position": 28, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "last_scheduled_at", + "position": 29, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "created_at", + "position": 30, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "updated_at", + "position": 31, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "created_by", + "position": 32, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "alert_rules", + "name": "updated_by", + "position": 33, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "enabled", + "position": 1, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "sensitivity", + "position": 2, + "type": "text", + "notNull": true, + "default": "'normal'", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "muted_signals_json", + "position": 3, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "last_tick_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "created_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "updated_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_settings", + "name": "updated_by", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "detector_key", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "signal_type", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "service_name", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "deployment_env", + "position": 4, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "fingerprint_hash", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "consecutive_breaches", + "position": 6, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "consecutive_healthy", + "position": 7, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "last_status", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "last_value", + "position": 9, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "baseline_median", + "position": 10, + "type": "double precision", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "last_sample_count", + "position": 11, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "last_evaluated_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "open_incident_id", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "last_resolved_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "last_incident_id", + "position": 15, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_detector_states", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "detector_key", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "signal_type", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "service_name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "deployment_env", + "position": 5, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "fingerprint_hash", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "error_issue_id", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "status", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "severity", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "opened_value", + "position": 10, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "baseline_median", + "position": 11, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "baseline_sigma", + "position": 12, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "threshold_value", + "position": 13, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "last_observed_value", + "position": 14, + "type": "double precision", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "last_sample_count", + "position": 15, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "first_triggered_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "last_triggered_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "resolved_at", + "position": 18, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "resolve_reason", + "position": 19, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "triage_status", + "position": 20, + "type": "text", + "notNull": true, + "default": "'none'", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "dedupe_key", + "position": 21, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "fingerprints_json", + "position": 22, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "reopen_count", + "position": 23, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "last_reopened_at", + "position": 24, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "created_at", + "position": 25, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "anomaly_incidents", + "name": "updated_at", + "position": 26, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "description", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "key_hash", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "key_prefix", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "revoked", + "position": 6, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "revoked_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "last_used_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "expires_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "metadata_json", + "position": 10, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "scopes", + "position": 11, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "kind", + "position": 12, + "type": "text", + "notNull": true, + "default": "'standard'", + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "created_by", + "position": 14, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "api_keys", + "name": "created_by_email", + "position": 15, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "plan_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "subscription_started_at", + "position": 3, + "type": "bigint", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "canceled_at", + "position": 4, + "type": "bigint", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "snapshot_json", + "position": 5, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "rule_reason", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "posted_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "created_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cancellation_reviews", + "name": "updated_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "connector", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "external_user_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "user_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "display_name", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_identities", + "name": "created_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "connector", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "external_workspace_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "settings", + "position": 5, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "credentials_ciphertext", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "credentials_iv", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "credentials_tag", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "chat_workspaces", + "name": "created_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "device_code_hash", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "user_code_hash", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "device_name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "approved_org_id", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "approved_user_id", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "approved_roles", + "position": 5, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "approved_user_email", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "api_key_id", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "token_ciphertext", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "token_iv", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "token_tag", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "approved_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "denied_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cli_device_authorizations", + "name": "expires_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "account_id", + "position": 2, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "dataset", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "zone_id", + "position": 4, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "zone_name", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "enabled", + "position": 6, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "watermark_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "backfill_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "settings_json", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "settings_fetched_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "quantiles_available", + "position": 11, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "discovered_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "live_scripts_json", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "grant_call_cap", + "position": 14, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "last_success_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "last_error", + "position": 16, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "last_error_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "lease_until", + "position": 18, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "created_at", + "position": 19, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_analytics_state", + "name": "updated_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "account_id", + "position": 2, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "config_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "origin_host", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "origin_port", + "position": 6, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "origin_scheme", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "origin_database", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "origin_user", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "deleted_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "created_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_hyperdrive_configs", + "name": "updated_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "zone_name", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "service_name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "dataset", + "position": 5, + "type": "text", + "notNull": true, + "default": "'http_requests'", + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "secret_ciphertext", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "secret_iv", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "secret_tag", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "secret_hash", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "enabled", + "position": 10, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "last_received_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "last_error", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "secret_rotated_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "created_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "updated_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "created_by", + "position": 16, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "cloudflare_logpush_connectors", + "name": "updated_by", + "position": 17, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "dashboard_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "widget_id", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "mode", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "token_hash", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "token_ciphertext", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "token_iv", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "token_tag", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "token_suffix", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "created_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "created_by", + "position": 11, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "updated_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "updated_by", + "position": 13, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_shares", + "name": "revoked_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "dashboard_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "version_number", + "position": 3, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "snapshot_json", + "position": 4, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "change_kind", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "change_summary", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "source_version_id", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "created_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboard_versions", + "name": "created_by", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "payload_json", + "position": 3, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "created_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "updated_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "created_by", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "updated_by", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "dashboards", + "name": "version", + "position": 8, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "user_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "email", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "enabled", + "position": 4, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "opted_out_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "day_of_week", + "position": 6, + "type": "integer", + "notNull": true, + "default": "1", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "timezone", + "position": 7, + "type": "text", + "notNull": true, + "default": "'UTC'", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "send_hour", + "position": 8, + "type": "integer", + "notNull": true, + "default": "9", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "namespaces_json", + "position": 9, + "type": "text", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "environments_json", + "position": 10, + "type": "text", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "last_sent_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "last_attempted_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "web_analytics_enabled", + "position": 13, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "web_analytics_opted_out_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "web_analytics_last_sent_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "web_analytics_last_attempted_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "created_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "digest_subscriptions", + "name": "updated_at", + "position": 18, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "fingerprint_hash", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "service_name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "exception_type", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "exception_message", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "error_label", + "position": 5, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "top_frame", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "service_versions_json", + "position": 7, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "occurrence_count", + "position": 8, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "first_seen_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "last_seen_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_fingerprint_candidates", + "name": "updated_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "issue_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "status", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "reason", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "first_triggered_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "last_triggered_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "resolved_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "occurrence_count", + "position": 8, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "created_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_incidents", + "name": "updated_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "issue_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "actor_id", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "type", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "from_state", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "to_state", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "payload_json", + "position": 7, + "type": "jsonb", + "notNull": true, + "default": "'{}'", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_events", + "name": "created_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "issue_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "provider", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "external_repo_id", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "repo_full_name", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "number", + "position": 6, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "url", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "title", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "author_login", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "state", + "position": 10, + "type": "text", + "notNull": true, + "default": "'open'", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "merged_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "merge_commit_sha", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "link_source", + "position": 13, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "linked_by_actor_id", + "position": 14, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_pull_requests", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_states", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_states", + "name": "issue_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_states", + "name": "last_observed_occurrence_at", + "position": 2, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_states", + "name": "last_evaluated_at", + "position": 3, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_states", + "name": "open_incident_id", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_states", + "name": "updated_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "issue_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "pull_request_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "status", + "position": 4, + "type": "text", + "notNull": true, + "default": "'waiting'", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "merged_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "verify_after", + "position": 6, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "baseline_versions_json", + "position": 7, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "baseline_occurrence_count", + "position": 8, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "baseline_rate_per_hour", + "position": 9, + "type": "double precision", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "investigation_id", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "verdict", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "verdict_note", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "post_merge_occurrence_count", + "position": 13, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "attempt", + "position": 14, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issue_verifications", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "kind", + "position": 2, + "type": "text", + "notNull": true, + "default": "'error'", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "source_ref_json", + "position": 3, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "fingerprint_hash", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "fingerprint_version", + "position": 5, + "type": "integer", + "notNull": true, + "default": "1", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "service_name", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "exception_type", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "exception_message", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "error_label", + "position": 9, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "top_frame", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "workflow_state", + "position": 11, + "type": "text", + "notNull": true, + "default": "'triage'", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "priority", + "position": 12, + "type": "integer", + "notNull": true, + "default": "3", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "severity", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "severity_source", + "position": 14, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "assigned_actor_id", + "position": 15, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "lease_holder_actor_id", + "position": 16, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "lease_expires_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "claimed_at", + "position": 18, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "notes", + "position": 19, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "first_seen_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "last_seen_at", + "position": 21, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "occurrence_count", + "position": 22, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "resolved_at", + "position": 23, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "resolved_by_actor_id", + "position": 24, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "last_resolved_at", + "position": 25, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "last_regressed_at", + "position": 26, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "regression_count", + "position": 27, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "seen_versions_json", + "position": 28, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "resolved_versions_json", + "position": 29, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "snooze_until", + "position": 30, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "archived_at", + "position": 31, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "created_at", + "position": 32, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_issues", + "name": "updated_at", + "position": 33, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "destination_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "delivery_key", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "payload_json", + "position": 4, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "status", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "attempt_count", + "position": 6, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "scheduled_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "claimed_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "claim_expires_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "claimed_by", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "attempted_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "error_message", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_deliveries", + "name": "updated_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "enabled", + "position": 1, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "destination_ids_json", + "position": 2, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "notify_on_first_seen", + "position": 3, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "notify_on_regression", + "position": 4, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "notify_on_resolve", + "position": 5, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "notify_on_transition_in_review", + "position": 6, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "notify_on_transition_done", + "position": 7, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "notify_on_claim", + "position": 8, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "min_occurrence_count", + "position": 9, + "type": "integer", + "notNull": true, + "default": "1", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "severity", + "position": 10, + "type": "text", + "notNull": true, + "default": "'warning'", + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "updated_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_notification_policies", + "name": "updated_by", + "position": 12, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_tick_states", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_tick_states", + "name": "processed_through", + "position": 1, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_tick_states", + "name": "bootstrap_completed", + "position": 2, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "error_tick_states", + "name": "claim_token", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_tick_states", + "name": "claim_expires_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "error_tick_states", + "name": "updated_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "scope_type", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "scope_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "project_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "logs_enabled", + "position": 5, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "metrics_enabled", + "position": 6, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "secret_ciphertext", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "secret_iv", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "secret_tag", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "secret_hash", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "last_received_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "last_error", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "applied_logs_enabled", + "position": 13, + "type": "boolean", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "applied_metrics_enabled", + "position": 14, + "type": "boolean", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "setup_reported_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "metrics_watermark_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "last_metrics_received_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "last_metrics_error", + "position": 18, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "metrics_lease_until", + "position": 19, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "resources_synced_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "last_resources_error", + "position": 21, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "created_by", + "position": 22, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "created_at", + "position": 23, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_connectors", + "name": "updated_at", + "position": 24, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "connector_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "asset_type", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "project_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "location", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "display_name", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "state", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "labels", + "position": 8, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "details", + "position": 9, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "resource_created_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "resource_updated_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "gcp_resources", + "name": "last_seen_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "status", + "position": 2, + "type": "text", + "notNull": true, + "default": "'investigating'", + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "seeded_by", + "position": 3, + "type": "text", + "notNull": true, + "default": "'user'", + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "subject_json", + "position": 4, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "snapshot_json", + "position": 5, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "incident_kind", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "incident_id", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "issue_id", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "report_json", + "position": 9, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "progress_json", + "position": 10, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "severity", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "confidence", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "model", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "input_tokens", + "position": 14, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "output_tokens", + "position": 15, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "error", + "position": 16, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "started_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "autonomous_turns", + "position": 18, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "created_by", + "position": 19, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "created_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "diagnosed_at", + "position": 21, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "investigations", + "name": "updated_at", + "position": 22, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalation_policies", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalation_policies", + "name": "enabled", + "position": 1, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "issue_escalation_policies", + "name": "rules_json", + "position": 2, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "issue_escalation_policies", + "name": "updated_at", + "position": 3, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalation_policies", + "name": "updated_by", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "issue_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "severity", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "source", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "reason", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "run_id", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "investigation_id", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "payload_json", + "position": 8, + "type": "jsonb", + "notNull": true, + "default": "'{}'", + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "delivery_results_json", + "position": 9, + "type": "jsonb", + "notNull": true, + "default": "'[]'", + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "status", + "position": 10, + "type": "text", + "notNull": true, + "default": "'queued'", + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "attempts", + "position": 11, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "dedupe_key", + "position": 12, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "error", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "created_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "issue_escalations", + "name": "processed_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "device_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "incident_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "activity_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "push_token", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "ended_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "ended_reason", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "created_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "live_activities", + "name": "updated_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "request_id_hash", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "client_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "client_name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "redirect_uri", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "state", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "resource", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "scopes", + "position": 6, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "code_challenge", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "authorization_code_hash", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "approved_org_id", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "approved_user_id", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "approved_roles", + "position": 11, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "approved_user_email", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "approved_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "denied_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "used_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "created_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_authorizations", + "name": "expires_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_clients", + "name": "client_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_clients", + "name": "client_name", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_clients", + "name": "redirect_uris", + "position": 2, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_clients", + "name": "client_uri", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_clients", + "name": "created_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "token_hash", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "family_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "client_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "resource", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "scopes", + "position": 5, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "org_id", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "user_id", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "roles", + "position": 8, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "user_email", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "access_key_id", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "replaced_by_id", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "revoked_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "expires_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mcp_oauth_refresh_tokens", + "name": "family_expires_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "user_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "platform", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "token", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "environment", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "bundle_id", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "app_version", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "live_activity_start_token", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "device_name", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "preferences", + "position": 10, + "type": "jsonb", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "disabled_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "disabled_reason", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "last_pushed_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "last_seen_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "mobile_devices", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "state", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "provider", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "initiated_by_user_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "redirect_uri", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "return_to", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "code_verifier", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "created_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_auth_states", + "name": "expires_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "provider", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "external_user_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "external_user_email", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "external_account_name", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "granted_accounts_json", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "connected_by_user_id", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "scope", + "position": 8, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "access_token_ciphertext", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "access_token_iv", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "access_token_tag", + "position": 11, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "refresh_token_ciphertext", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "refresh_token_iv", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "refresh_token_tag", + "position": 14, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "expires_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "revoked_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "created_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "oauth_connections", + "name": "updated_at", + "position": 18, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "workflow_instance_id", + "position": 1, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "status", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "phase", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "current_migration", + "position": 4, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "steps_total", + "position": 5, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "steps_done", + "position": 6, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "applied_versions", + "position": 7, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "skipped", + "position": 8, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "error_message", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "started_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "finished_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "created_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_schema_apply_runs", + "name": "updated_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "ch_url", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "ch_user", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "ch_password_ciphertext", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "ch_password_iv", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "ch_password_tag", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "ch_database", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "sync_status", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "last_sync_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "last_sync_error", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "schema_version", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "created_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "updated_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "created_by", + "position": 13, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_clickhouse_settings", + "name": "updated_by", + "position": 14, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "source_context", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "source_key", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "target_key", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "operation", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "enabled", + "position": 7, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "created_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": "now()", + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_attribute_mappings", + "name": "updated_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": "now()", + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "public_key", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "public_key_hash", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "private_key_ciphertext", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "private_key_iv", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "private_key_tag", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "private_key_hash", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "public_rotated_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "private_rotated_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "created_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "updated_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "created_by", + "position": 11, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_keys", + "name": "updated_by", + "position": 12, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_sampling_policies", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_sampling_policies", + "name": "trace_sample_ratio", + "position": 1, + "type": "double precision", + "notNull": true, + "default": "1", + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_sampling_policies", + "name": "always_keep_error_spans", + "position": 2, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_sampling_policies", + "name": "always_keep_slow_spans_ms", + "position": 3, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_sampling_policies", + "name": "created_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": true, + "default": "now()", + "identity": null + }, + { + "kind": "column", + "table": "org_ingest_sampling_policies", + "name": "updated_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": "now()", + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "user_id", + "position": 1, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "email", + "position": 2, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "role", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "demo_data_requested", + "position": 4, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "onboarding_completed_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "checklist_dismissed_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "first_data_received_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "welcome_email_sent_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "connect_nudge_email_sent_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "stalled_email_sent_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "activation_email_sent_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "reward_claimed_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "reward_reserved_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "created_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_onboarding_state", + "name": "updated_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "key_ciphertext", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "key_iv", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "key_tag", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "key_hint", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "created_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "updated_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_openrouter_keys", + "name": "updated_by", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "number", + "position": 2, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "recommendation_key", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "kind", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "source_key", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "canonical_key", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "status", + "position": 7, + "type": "text", + "notNull": true, + "default": "'open'", + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "usage_count", + "position": 8, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "opened_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": true, + "default": "now()", + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "updated_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": "now()", + "identity": null + }, + { + "kind": "column", + "table": "org_recommendation_issues", + "name": "resolved_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "slack_channel_id", + "position": 1, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "slack_channel_name", + "position": 2, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "reservation_id", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "reserved_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "created_by_user_id", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "created_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "org_support_channels", + "name": "updated_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "ps_organization", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "connected_by_user_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "scrape_target_id", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "webhook_secret_ciphertext", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "webhook_secret_iv", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "webhook_secret_tag", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "detected_permissions_json", + "position": 8, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "last_inventory_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "last_inventory_error", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "created_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_connections", + "name": "updated_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "database_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "name", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "kind", + "position": 4, + "type": "text", + "notNull": true, + "default": "'mysql'", + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "state", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "region", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "plan", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "branches_json", + "position": 8, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "deleted_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "created_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_databases", + "name": "updated_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "database_id", + "position": 2, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "database_name", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "branch_name", + "position": 4, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "category", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "event_type", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "state", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "external_id", + "position": 8, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "title", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "source", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "actor_login", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "url", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "payload_json", + "position": 13, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "occurred_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_events", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_issue_receipts", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_issue_receipts", + "name": "event_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_issue_receipts", + "name": "processed_at", + "position": 2, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "dataset", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "database_id", + "position": 3, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "enabled", + "position": 4, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "watermark_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "last_success_at", + "position": 6, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "last_error", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "last_error_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "lease_until", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "created_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "planetscale_poll_state", + "name": "updated_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "reply_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "seq", + "position": 3, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "path", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "old_text", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "new_text", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_edits", + "name": "created_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_finding_embeddings", + "name": "finding_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_finding_embeddings", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_finding_embeddings", + "name": "repository_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_finding_embeddings", + "name": "model", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_finding_embeddings", + "name": "embedding", + "position": 4, + "type": "real[]", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_finding_embeddings", + "name": "created_at", + "position": 5, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "repository_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "number", + "position": 3, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "review_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "handle", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "path", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "line", + "position": 7, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "category", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "severity", + "position": 9, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "title", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "status", + "position": 11, + "type": "text", + "notNull": true, + "default": "'open'", + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "comment_id", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "resolved_sha", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "reactions_up", + "position": 14, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "reactions_down", + "position": 15, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "created_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_findings", + "name": "updated_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "repository_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "number", + "position": 3, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "key", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "kind", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "title", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "source", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "path", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "status", + "position": 9, + "type": "text", + "notNull": true, + "default": "'open'", + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "done_by", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "done_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "reminded_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "first_review_id", + "position": 13, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "last_review_id", + "position": 14, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_merge_steps", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "repository_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "number", + "position": 3, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "comment_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "surface", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "thread_root_id", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "author_login", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "command", + "position": 8, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "head_sha", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "status", + "position": 10, + "type": "text", + "notNull": true, + "default": "'queued'", + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "session_id", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "reply_url", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "commit_sha", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "error", + "position": 14, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "created_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_replies", + "name": "updated_at", + "position": 16, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_settings", + "name": "org_id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_settings", + "name": "model", + "position": 1, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_settings", + "name": "defaults", + "position": 2, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_settings", + "name": "updated_at", + "position": 3, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_review_settings", + "name": "updated_by", + "position": 4, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "repository_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "number", + "position": 3, + "type": "integer", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "head_sha", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "base_sha", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "url", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "title", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "author_login", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "status", + "position": 9, + "type": "text", + "notNull": true, + "default": "'queued'", + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "skip_reason", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "session_id", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "comment_attempt", + "position": 12, + "type": "integer", + "notNull": true, + "default": "0", + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "report_json", + "position": 13, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "score", + "position": 14, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "check_run_url", + "position": 15, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "comment_url", + "position": 16, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "review_url", + "position": 17, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "publish_error", + "position": 18, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "error", + "position": 19, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "model", + "position": 20, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "input_tokens", + "position": 21, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "output_tokens", + "position": 22, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "started_at", + "position": 23, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "finished_at", + "position": 24, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "merged_at", + "position": 25, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "telemetry_json", + "position": 26, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "merge_commit_sha", + "position": 27, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "post_merge_status", + "position": 28, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "post_merge_after", + "position": 29, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "post_merge_json", + "position": 30, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "created_at", + "position": 31, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "pr_reviews", + "name": "updated_at", + "position": 32, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "token_ciphertext", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "token_iv", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "token_tag", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "workspace_names", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "connected_by_user_id", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "auth_failed_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "discovered_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "lease_until", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "last_success_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "last_error", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "last_error_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_connections", + "name": "updated_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "connection_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "project_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "project_name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "environment_id", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "environment_name", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "services_json", + "position": 7, + "type": "text", + "notNull": true, + "default": "'{}'", + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "enabled", + "position": 8, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "watermark_at", + "position": 9, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "last_success_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "last_error", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "last_error_at", + "position": 12, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "railway_environments", + "name": "updated_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "id", + "position": 0, + "type": "integer", + "notNull": true, + "default": null, + "identity": "by default" + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "target_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "org_id", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "sub_target_key", + "position": 3, + "type": "text", + "notNull": true, + "default": "''", + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "checked_at", + "position": 4, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "error", + "position": 5, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "duration_ms", + "position": 6, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "samples_scraped", + "position": 7, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_target_checks", + "name": "samples_post_relabel", + "position": 8, + "type": "integer", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "name", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "service_name", + "position": 3, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "url", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "target_type", + "position": 5, + "type": "text", + "notNull": true, + "default": "'prometheus'", + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "discovery_config_json", + "position": 6, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "scrape_interval_seconds", + "position": 7, + "type": "integer", + "notNull": true, + "default": "15", + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "labels_json", + "position": 8, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "auth_type", + "position": 9, + "type": "text", + "notNull": true, + "default": "'none'", + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "managed_by", + "position": 10, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "auth_credentials_ciphertext", + "position": 11, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "auth_credentials_iv", + "position": 12, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "auth_credentials_tag", + "position": 13, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "enabled", + "position": 14, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "last_scrape_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "last_scrape_error", + "position": 16, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "created_at", + "position": 17, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "scrape_targets", + "name": "updated_at", + "position": 18, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "provider", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "repository_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "sha", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "message", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "author_name", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "author_email", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "author_login", + "position": 8, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "author_avatar_url", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "authored_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "committed_at", + "position": 11, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "html_url", + "position": 12, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_commits", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "provider", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "external_installation_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "account_login", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "account_type", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "external_account_id", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "account_avatar_url", + "position": 7, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "repository_selection", + "position": 8, + "type": "text", + "notNull": true, + "default": "'all'", + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "status", + "position": 9, + "type": "text", + "notNull": true, + "default": "'active'", + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "suspended_at", + "position": 10, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "ci_traces_enabled", + "position": 11, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "installed_by_user_id", + "position": 12, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "created_at", + "position": 13, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_installations", + "name": "updated_at", + "position": 14, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "provider", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "installation_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "external_repo_id", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "owner", + "position": 5, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "name", + "position": 6, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "full_name", + "position": 7, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "default_branch", + "position": 8, + "type": "text", + "notNull": true, + "default": "'main'", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "tracked_branch", + "position": 9, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "html_url", + "position": 10, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "is_private", + "position": 11, + "type": "boolean", + "notNull": true, + "default": "true", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "is_archived", + "position": 12, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "status", + "position": 13, + "type": "text", + "notNull": true, + "default": "'active'", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "sync_status", + "position": 14, + "type": "text", + "notNull": true, + "default": "'pending'", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "last_synced_at", + "position": 15, + "type": "timestamp with time zone", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "last_sync_error", + "position": 16, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "pr_review_enabled", + "position": 17, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "pr_review_config", + "position": 18, + "type": "jsonb", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "created_at", + "position": 19, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repositories", + "name": "updated_at", + "position": 20, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "id", + "position": 0, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "org_id", + "position": 1, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "provider", + "position": 2, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "repository_id", + "position": 3, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "name", + "position": 4, + "type": "text", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "is_default", + "position": 5, + "type": "boolean", + "notNull": true, + "default": "false", + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "head_sha", + "position": 6, + "type": "text", + "notNull": false, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "created_at", + "position": 7, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "column", + "table": "vcs_repository_branches", + "name": "updated_at", + "position": 8, + "type": "timestamp with time zone", + "notNull": true, + "default": null, + "identity": null + }, + { + "kind": "index", + "table": "actors", + "name": "actors_org_agent_name_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"agent_name\"" + ], + "where": null + }, + { + "kind": "index", + "table": "actors", + "name": "actors_org_type_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"type\"" + ], + "where": null + }, + { + "kind": "index", + "table": "actors", + "name": "actors_org_user_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"user_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "agent_feedback", + "name": "agent_feedback_kind_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"kind\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "agent_feedback", + "name": "agent_feedback_org_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_delivery_events", + "name": "alert_delivery_events_claim_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"status\"", + "\"claim_expires_at\"", + "\"scheduled_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_delivery_events", + "name": "alert_delivery_events_delivery_attempt_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"delivery_key\"", + "\"attempt_number\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_delivery_events", + "name": "alert_delivery_events_due_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"status\"", + "\"scheduled_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_delivery_events", + "name": "alert_delivery_events_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_delivery_events", + "name": "alert_delivery_events_org_incident_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"incident_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_destinations", + "name": "alert_destinations_org_enabled_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"enabled\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_destinations", + "name": "alert_destinations_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_destinations", + "name": "alert_destinations_org_name_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"name\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_incidents", + "name": "alert_incidents_incident_key_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"incident_key\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_incidents", + "name": "alert_incidents_open_group_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"rule_id\"", + "\"group_key\"" + ], + "where": "\"status\" = 'open'" + }, + { + "kind": "index", + "table": "alert_incidents", + "name": "alert_incidents_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_incidents", + "name": "alert_incidents_org_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"error_issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_incidents", + "name": "alert_incidents_org_rule_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"rule_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_incidents", + "name": "alert_incidents_org_status_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"status\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_rule_claims", + "name": "alert_rule_claims_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_rule_states", + "name": "alert_rule_states_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_rules", + "name": "alert_rules_org_enabled_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"enabled\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_rules", + "name": "alert_rules_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "alert_rules", + "name": "alert_rules_org_name_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"name\"" + ], + "where": null + }, + { + "kind": "index", + "table": "anomaly_detector_states", + "name": "anomaly_detector_states_evaluated_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"last_evaluated_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "anomaly_detector_states", + "name": "anomaly_detector_states_open_incident_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"open_incident_id\"" + ], + "where": "\"open_incident_id\" is not null" + }, + { + "kind": "index", + "table": "anomaly_incidents", + "name": "anomaly_incidents_open_detector_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"detector_key\"" + ], + "where": "\"status\" = 'open'" + }, + { + "kind": "index", + "table": "anomaly_incidents", + "name": "anomaly_incidents_org_detector_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"detector_key\"" + ], + "where": null + }, + { + "kind": "index", + "table": "anomaly_incidents", + "name": "anomaly_incidents_org_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"error_issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "anomaly_incidents", + "name": "anomaly_incidents_org_status_triggered_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"status\"", + "\"last_triggered_at\"", + "\"id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "anomaly_incidents", + "name": "anomaly_incidents_org_triggered_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"last_triggered_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "api_keys", + "name": "api_keys_key_hash_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"key_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "api_keys", + "name": "api_keys_org_id_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cancellation_reviews", + "name": "cancellation_reviews_subscription_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"plan_id\"", + "\"subscription_started_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "chat_identities", + "name": "chat_identities_org_connector_external_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"connector\"", + "\"external_user_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "chat_identities", + "name": "chat_identities_org_connector_user_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"connector\"", + "\"user_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "chat_identities", + "name": "chat_identities_org_user_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"user_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "chat_workspaces", + "name": "chat_workspaces_connector_external_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"connector\"", + "\"external_workspace_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "chat_workspaces", + "name": "chat_workspaces_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cli_device_authorizations", + "name": "cli_device_authorizations_expires_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cli_device_authorizations", + "name": "cli_device_authorizations_user_code_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"user_code_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_analytics_state", + "name": "cf_analytics_state_org_account_dataset_zone_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"account_id\"", + "\"dataset\"", + "\"zone_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_analytics_state", + "name": "cf_analytics_state_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_hyperdrive_configs", + "name": "cloudflare_hyperdrive_configs_org_config_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"config_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_hyperdrive_configs", + "name": "cloudflare_hyperdrive_configs_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_logpush_connectors", + "name": "cloudflare_logpush_connectors_org_enabled_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"enabled\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_logpush_connectors", + "name": "cloudflare_logpush_connectors_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "cloudflare_logpush_connectors", + "name": "cloudflare_logpush_connectors_secret_hash_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"secret_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboard_shares", + "name": "dashboard_shares_id_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboard_shares", + "name": "dashboard_shares_live_unq", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"dashboard_id\"", + "coalesce(widget_id, '')" + ], + "where": "revoked_at is null" + }, + { + "kind": "index", + "table": "dashboard_shares", + "name": "dashboard_shares_org_dashboard_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"dashboard_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboard_shares", + "name": "dashboard_shares_token_hash_unq", + "unique": true, + "method": "btree", + "columns": [ + "\"token_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboard_versions", + "name": "dashboard_versions_org_dashboard_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"dashboard_id\"", + "\"version_number\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboard_versions", + "name": "dashboard_versions_org_dashboard_version_unq", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"dashboard_id\"", + "\"version_number\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboards", + "name": "dashboards_org_name_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"name\"" + ], + "where": null + }, + { + "kind": "index", + "table": "dashboards", + "name": "dashboards_org_updated_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"updated_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "digest_subscriptions", + "name": "digest_subscriptions_org_enabled_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"enabled\"" + ], + "where": null + }, + { + "kind": "index", + "table": "digest_subscriptions", + "name": "digest_subscriptions_org_user_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"user_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_fingerprint_candidates", + "name": "error_fingerprint_candidates_last_seen_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"last_seen_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_incidents", + "name": "error_incidents_org_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_incidents", + "name": "error_incidents_org_status_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"status\"", + "\"last_triggered_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_events", + "name": "error_issue_events_actor_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"actor_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_events", + "name": "error_issue_events_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_events", + "name": "error_issue_events_type_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"type\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_pull_requests", + "name": "error_issue_pull_requests_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_pull_requests", + "name": "error_issue_pull_requests_issue_pr_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"", + "\"provider\"", + "\"repo_full_name\"", + "\"number\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_pull_requests", + "name": "error_issue_pull_requests_repo_number_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"provider\"", + "\"repo_full_name\"", + "\"number\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_verifications", + "name": "error_issue_verifications_due_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"status\"", + "\"verify_after\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_verifications", + "name": "error_issue_verifications_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issue_verifications", + "name": "error_issue_verifications_open_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"" + ], + "where": "\"status\" in ('waiting', 'running')" + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_lease_expiry_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"lease_expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_archived_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"archived_at\"" + ], + "where": "\"archived_at\" is not null" + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_assignee_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"assigned_actor_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_fp_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"fingerprint_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_fp_version_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"fingerprint_version\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_live_seen_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"last_seen_at\"", + "\"id\"" + ], + "where": "\"archived_at\" is null" + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_severity_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"severity\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_issues", + "name": "error_issues_org_workflow_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"workflow_state\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_notification_deliveries", + "name": "error_notification_deliveries_due_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"status\"", + "\"scheduled_at\"", + "\"claim_expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_notification_deliveries", + "name": "error_notification_deliveries_key_destination_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"delivery_key\"", + "\"destination_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_notification_deliveries", + "name": "error_notification_deliveries_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "error_tick_states", + "name": "error_tick_states_claim_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"claim_expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "gcp_connectors", + "name": "gcp_connectors_org_scope_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"scope_type\"", + "\"scope_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "gcp_connectors", + "name": "gcp_connectors_secret_hash_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"secret_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "investigations", + "name": "investigations_incident_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"incident_kind\"", + "\"incident_id\"" + ], + "where": "\"incident_id\" is not null" + }, + { + "kind": "index", + "table": "investigations", + "name": "investigations_org_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "investigations", + "name": "investigations_org_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "investigations", + "name": "investigations_org_status_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"status\"" + ], + "where": null + }, + { + "kind": "index", + "table": "issue_escalations", + "name": "issue_escalations_dedupe_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"dedupe_key\"" + ], + "where": null + }, + { + "kind": "index", + "table": "issue_escalations", + "name": "issue_escalations_due_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"status\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "issue_escalations", + "name": "issue_escalations_org_issue_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"issue_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "live_activities", + "name": "live_activities_device_incident_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"device_id\"", + "\"incident_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "live_activities", + "name": "live_activities_incident_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"incident_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mcp_oauth_authorizations", + "name": "mcp_oauth_authorizations_code_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"authorization_code_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mcp_oauth_authorizations", + "name": "mcp_oauth_authorizations_expires_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mcp_oauth_refresh_tokens", + "name": "mcp_oauth_refresh_tokens_expires_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mcp_oauth_refresh_tokens", + "name": "mcp_oauth_refresh_tokens_family_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"family_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mcp_oauth_refresh_tokens", + "name": "mcp_oauth_refresh_tokens_hash_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"token_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mobile_devices", + "name": "mobile_devices_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mobile_devices", + "name": "mobile_devices_org_platform_token_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"platform\"", + "\"token\"" + ], + "where": null + }, + { + "kind": "index", + "table": "mobile_devices", + "name": "mobile_devices_user_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"user_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "oauth_auth_states", + "name": "oauth_auth_states_expires_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"expires_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "oauth_connections", + "name": "oauth_connections_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "oauth_connections", + "name": "oauth_connections_org_provider_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"provider\"" + ], + "where": null + }, + { + "kind": "index", + "table": "org_ingest_attribute_mappings", + "name": "org_ingest_attribute_mappings_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "org_ingest_keys", + "name": "org_ingest_keys_private_key_hash_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"private_key_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "org_ingest_keys", + "name": "org_ingest_keys_public_key_hash_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"public_key_hash\"" + ], + "where": null + }, + { + "kind": "index", + "table": "org_ingest_keys", + "name": "org_ingest_keys_public_key_unique", + "unique": true, + "method": "btree", + "columns": [ + "\"public_key\"" + ], + "where": null + }, + { + "kind": "index", + "table": "org_recommendation_issues", + "name": "org_recommendation_issues_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "org_recommendation_issues", + "name": "org_recommendation_issues_org_key_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"recommendation_key\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_connections", + "name": "planetscale_connections_org_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_databases", + "name": "planetscale_databases_org_db_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"database_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_databases", + "name": "planetscale_databases_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_events", + "name": "planetscale_events_dedupe_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"database_name\"", + "\"event_type\"", + "\"external_id\"", + "\"occurred_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_events", + "name": "planetscale_events_org_db_time_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"database_name\"", + "\"occurred_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_events", + "name": "planetscale_events_org_time_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"occurred_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_issue_receipts", + "name": "planetscale_issue_receipts_processed_at_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"processed_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_poll_state", + "name": "planetscale_poll_state_org_dataset_db_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"dataset\"", + "\"database_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "planetscale_poll_state", + "name": "planetscale_poll_state_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_edits", + "name": "pr_review_edits_reply_seq_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"reply_id\"", + "\"seq\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_finding_embeddings", + "name": "pr_review_finding_embeddings_org_model_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"model\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_findings", + "name": "pr_review_findings_org_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_findings", + "name": "pr_review_findings_pr_handle_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"number\"", + "\"handle\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_merge_steps", + "name": "pr_review_merge_steps_org_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_merge_steps", + "name": "pr_review_merge_steps_pr_key_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"number\"", + "\"key\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_replies", + "name": "pr_review_replies_org_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_review_replies", + "name": "pr_review_replies_repo_comment_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"comment_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_reviews", + "name": "pr_reviews_org_created_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"created_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_reviews", + "name": "pr_reviews_post_merge_due_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"post_merge_after\"" + ], + "where": "\"post_merge_status\" = 'waiting'" + }, + { + "kind": "index", + "table": "pr_reviews", + "name": "pr_reviews_repo_number_head_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"number\"", + "\"head_sha\"" + ], + "where": null + }, + { + "kind": "index", + "table": "pr_reviews", + "name": "pr_reviews_repo_number_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"number\"" + ], + "where": null + }, + { + "kind": "index", + "table": "railway_connections", + "name": "railway_connections_org_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "railway_environments", + "name": "railway_environments_connection_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"connection_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "railway_environments", + "name": "railway_environments_org_env_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"environment_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "scrape_target_checks", + "name": "scrape_target_checks_target_checked_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"target_id\"", + "\"checked_at\"" + ], + "where": null + }, + { + "kind": "index", + "table": "scrape_targets", + "name": "scrape_targets_org_enabled_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"enabled\"" + ], + "where": null + }, + { + "kind": "index", + "table": "scrape_targets", + "name": "scrape_targets_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_commits", + "name": "vcs_commits_org_sha_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"sha\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_commits", + "name": "vcs_commits_repo_sha_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"sha\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_installations", + "name": "vcs_installations_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_installations", + "name": "vcs_installations_provider_external_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"provider\"", + "\"external_installation_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_repositories", + "name": "vcs_repositories_installation_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"installation_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_repositories", + "name": "vcs_repositories_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_repositories", + "name": "vcs_repositories_org_repo_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"org_id\"", + "\"provider\"", + "\"external_repo_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_repository_branches", + "name": "vcs_repository_branches_org_idx", + "unique": false, + "method": "btree", + "columns": [ + "\"org_id\"" + ], + "where": null + }, + { + "kind": "index", + "table": "vcs_repository_branches", + "name": "vcs_repository_branches_repo_name_idx", + "unique": true, + "method": "btree", + "columns": [ + "\"repository_id\"", + "\"name\"" + ], + "where": null + }, + { + "kind": "foreign_key", + "table": "dashboard_shares", + "name": "dashboard_shares_dashboard_fk", + "columns": [ + "org_id", + "dashboard_id" + ], + "foreignTable": "dashboards", + "foreignColumns": [ + "org_id", + "id" + ], + "onDelete": "CASCADE", + "onUpdate": "NO ACTION" + }, + { + "kind": "foreign_key", + "table": "gcp_resources", + "name": "gcp_resources_connector_id_gcp_connectors_id_fk", + "columns": [ + "connector_id" + ], + "foreignTable": "gcp_connectors", + "foreignColumns": [ + "id" + ], + "onDelete": "CASCADE", + "onUpdate": "NO ACTION" + }, + { + "kind": "foreign_key", + "table": "scrape_target_checks", + "name": "scrape_target_checks_target_id_scrape_targets_id_fk", + "columns": [ + "target_id" + ], + "foreignTable": "scrape_targets", + "foreignColumns": [ + "id" + ], + "onDelete": "CASCADE", + "onUpdate": "NO ACTION" + } + ] +} diff --git a/packages/db/src/tables/digest.ts b/packages/db/src/tables/digest.ts index 597857af81..e18665684b 100644 --- a/packages/db/src/tables/digest.ts +++ b/packages/db/src/tables/digest.ts @@ -16,6 +16,8 @@ export const DigestSubscriptions = PG.table("digest_subscriptions", { optedOutAt: PG.column(PG.nullable(PG.timestamptzMillis), { name: "opted_out_at" }), dayOfWeek: PG.column(PG.int4, { name: "day_of_week", default: 1 }), timezone: PG.column(PG.text, { default: "UTC" }), + /** Local hour (0-23) in `timezone` on `day_of_week` from which the digests are due. */ + sendHour: PG.column(PG.int4, { name: "send_hour", default: 9 }), /** * JSON-encoded string arrays scoping the digest to a slice of the org. * Empty array = every namespace / environment, which is the default and diff --git a/packages/domain/src/http/digest.test.ts b/packages/domain/src/http/digest.test.ts new file mode 100644 index 0000000000..ba0acd1322 --- /dev/null +++ b/packages/domain/src/http/digest.test.ts @@ -0,0 +1,25 @@ +import { Schema } from "effect" +import { describe, expect, it } from "vitest" + +import { UpsertDigestSubscriptionRequest } from "./digest" + +const decode = Schema.decodeUnknownExit(UpsertDigestSubscriptionRequest) + +describe("UpsertDigestSubscriptionRequest schedule fields", () => { + it("accepts an IANA zone, a weekday and an hour in range", () => { + const exit = decode({ email: "a@example.com", dayOfWeek: 0, sendHour: 23, timezone: "Europe/Berlin" }) + expect(exit._tag).toBe("Success") + }) + + it("rejects zones the runtime cannot resolve and out of range days and hours", () => { + for (const patch of [ + { timezone: "Mars/Olympus_Mons" }, + { dayOfWeek: 7 }, + { dayOfWeek: 1.5 }, + { sendHour: 24 }, + { sendHour: -1 }, + ]) { + expect(decode({ email: "a@example.com", ...patch })._tag).toBe("Failure") + } + }) +}) diff --git a/packages/domain/src/http/digest.ts b/packages/domain/src/http/digest.ts index b05074914b..c294cad21c 100644 --- a/packages/domain/src/http/digest.ts +++ b/packages/domain/src/http/digest.ts @@ -1,5 +1,5 @@ import { HttpApiEndpoint, HttpApiGroup } from "effect/http-api" -import { Schema } from "effect" +import { DateTime, Option, Schema } from "effect" import { SessionAuthorization } from "./current-tenant" export const DigestSubscriptionId = Schema.String.check(Schema.isUUID()).pipe( @@ -17,7 +17,10 @@ export class DigestSubscriptionResponse extends Schema.Class Option.isSome(DateTime.zoneMakeNamed(zone)) || "unknown time zone", { + identifier: "DigestTimeZone", + }), +) + export class UpsertDigestSubscriptionRequest extends Schema.Class( "UpsertDigestSubscriptionRequest", )({ email: Schema.String, enabled: Schema.optionalKey(Schema.Boolean), - dayOfWeek: Schema.optionalKey(Schema.Number), - timezone: Schema.optionalKey(Schema.String), + dayOfWeek: Schema.optionalKey(DigestDayOfWeek), + sendHour: Schema.optionalKey(DigestSendHour), + timezone: Schema.optionalKey(DigestTimeZone), namespaces: Schema.optionalKey(ScopeValues), environments: Schema.optionalKey(ScopeValues), webAnalyticsEnabled: Schema.optionalKey(Schema.Boolean), From f5e06003b66ca9a11d93a4001f58aec11caaa134 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 10:14:09 +0200 Subject: [PATCH 03/13] feat(account): rebuild email preferences with a schedule and save bar Moves the digest preferences under components/account. The page names the recipient and organization, the two digest switches save instantly, and the schedule (day, hour, time zone) and the namespace and environment scope save through the settings save bar. --- .../account/digest-preferences.test.ts | 37 ++ .../components/account/digest-preferences.ts | 52 +++ .../digest-subscription-load.test.ts | 0 .../digest-subscription-load.ts | 0 .../account/email-preferences-section.tsx | 407 ++++++++++++++++++ .../settings/notifications-section.tsx | 313 -------------- apps/web/src/routes/account.tsx | 4 +- 7 files changed, 498 insertions(+), 315 deletions(-) create mode 100644 apps/web/src/components/account/digest-preferences.test.ts create mode 100644 apps/web/src/components/account/digest-preferences.ts rename apps/web/src/components/{settings => account}/digest-subscription-load.test.ts (100%) rename apps/web/src/components/{settings => account}/digest-subscription-load.ts (100%) create mode 100644 apps/web/src/components/account/email-preferences-section.tsx delete mode 100644 apps/web/src/components/settings/notifications-section.tsx diff --git a/apps/web/src/components/account/digest-preferences.test.ts b/apps/web/src/components/account/digest-preferences.test.ts new file mode 100644 index 0000000000..f1e86892df --- /dev/null +++ b/apps/web/src/components/account/digest-preferences.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from "vitest" + +import { digestTimeZoneOptions, sameDigestDraft } from "./digest-preferences" + +const base = { + dayOfWeek: 1, + sendHour: 9, + timezone: "Europe/Berlin", + namespaces: ["payments", "checkout"], + environments: ["production"], +} + +describe("sameDigestDraft", () => { + it("ignores the order scope values were picked in", () => { + expect(sameDigestDraft(base, { ...base, namespaces: ["checkout", "payments"] })).toBe(true) + }) + + it("sees a change to the day, hour, zone or scope", () => { + expect(sameDigestDraft(base, { ...base, dayOfWeek: 0 })).toBe(false) + expect(sameDigestDraft(base, { ...base, sendHour: 10 })).toBe(false) + expect(sameDigestDraft(base, { ...base, timezone: "UTC" })).toBe(false) + expect(sameDigestDraft(base, { ...base, environments: [] })).toBe(false) + }) +}) + +describe("digestTimeZoneOptions", () => { + it("keeps the saved and browser zones selectable and puts UTC first", () => { + const zones = digestTimeZoneOptions(["Europe/Berlin", "Asia/Tokyo"], "Etc/GMT+5", "America/Denver") + expect(zones[0]).toBe("UTC") + expect(zones).toEqual(["UTC", "America/Denver", "Asia/Tokyo", "Etc/GMT+5", "Europe/Berlin"]) + }) + + it("lists each zone once", () => { + const zones = digestTimeZoneOptions(["UTC", "Europe/Berlin"], "Europe/Berlin", "Europe/Berlin") + expect(zones).toEqual(["UTC", "Europe/Berlin"]) + }) +}) diff --git a/apps/web/src/components/account/digest-preferences.ts b/apps/web/src/components/account/digest-preferences.ts new file mode 100644 index 0000000000..239bc9ddb4 --- /dev/null +++ b/apps/web/src/components/account/digest-preferences.ts @@ -0,0 +1,52 @@ +import { isSameDraft } from "@/components/settings/settings-draft" + +/** Monday first, as people read a week; values are `Date#getDay` numbers (0 = Sunday). */ +export const DIGEST_DAYS = [ + { value: 1, label: "Monday" }, + { value: 2, label: "Tuesday" }, + { value: 3, label: "Wednesday" }, + { value: 4, label: "Thursday" }, + { value: 5, label: "Friday" }, + { value: 6, label: "Saturday" }, + { value: 0, label: "Sunday" }, +] as const + +export const DIGEST_HOURS = Array.from({ length: 24 }, (_, hour) => ({ + value: hour, + label: `${String(hour).padStart(2, "0")}:00`, +})) + +/** What the server applies to a subscriber who never saved a schedule. */ +export const DEFAULT_DIGEST_SCHEDULE = { dayOfWeek: 1, sendHour: 9, timezone: "UTC" } as const + +export interface DigestPreferencesDraft { + readonly dayOfWeek: number + readonly sendHour: number + readonly timezone: string + readonly namespaces: ReadonlyArray + readonly environments: ReadonlyArray +} + +const sorted = (values: ReadonlyArray) => [...values].sort() + +/** Scopes are sets: picking the same namespaces in another order is not an edit. */ +export function sameDigestDraft(a: DigestPreferencesDraft, b: DigestPreferencesDraft): boolean { + return isSameDraft( + { ...a, namespaces: sorted(a.namespaces), environments: sorted(a.environments) }, + { ...b, namespaces: sorted(b.namespaces), environments: sorted(b.environments) }, + ) +} + +/** + * Zones for the picker: every zone the browser knows, plus UTC, the saved zone and the + * browser's own zone, so the current value is always selectable even when the list lacks it. + */ +export function digestTimeZoneOptions( + supported: ReadonlyArray, + saved: string, + browserZone: string | undefined, +): ReadonlyArray { + const zones = new Set([...supported, "UTC", saved]) + if (browserZone) zones.add(browserZone) + return [...zones].sort((a, b) => (a === "UTC" ? -1 : b === "UTC" ? 1 : a.localeCompare(b))) +} diff --git a/apps/web/src/components/settings/digest-subscription-load.test.ts b/apps/web/src/components/account/digest-subscription-load.test.ts similarity index 100% rename from apps/web/src/components/settings/digest-subscription-load.test.ts rename to apps/web/src/components/account/digest-subscription-load.test.ts diff --git a/apps/web/src/components/settings/digest-subscription-load.ts b/apps/web/src/components/account/digest-subscription-load.ts similarity index 100% rename from apps/web/src/components/settings/digest-subscription-load.ts rename to apps/web/src/components/account/digest-subscription-load.ts diff --git a/apps/web/src/components/account/email-preferences-section.tsx b/apps/web/src/components/account/email-preferences-section.tsx new file mode 100644 index 0000000000..ab802a16e6 --- /dev/null +++ b/apps/web/src/components/account/email-preferences-section.tsx @@ -0,0 +1,407 @@ +import { useMemo } from "react" +import { Exit } from "effect" +import { useOrganization, useUser } from "@clerk/clerk-react" +import { type DigestSubscriptionResponse, UpsertDigestSubscriptionRequest } from "@maple/domain/http" +import { formatWarehouseDateTime } from "@maple/query-engine" + +import { Button } from "@maple/ui/components/ui/button" +import { Field, FieldDescription, FieldLabel } from "@maple/ui/components/ui/field" +import { NativeSelect, NativeSelectOption } from "@maple/ui/components/ui/native-select" +import { Panel } from "@maple/ui/components/ui/panel" +import { SettingRow } from "@maple/ui/components/ui/setting-row" +import { Switch } from "@maple/ui/components/ui/switch" +import { MultiSelectCombobox } from "@maple/ui/components/multi-select-combobox" +import { ChartBarTrendUpIcon, EnvelopeIcon } from "@/components/icons" +import { AccountSectionSkeleton } from "@/components/account/account-section-skeleton" +import { readDigestSubscription } from "@/components/account/digest-subscription-load" +import { + DEFAULT_DIGEST_SCHEDULE, + DIGEST_DAYS, + DIGEST_HOURS, + type DigestPreferencesDraft, + digestTimeZoneOptions, + sameDigestDraft, +} from "@/components/account/digest-preferences" +import { ErrorState } from "@/components/common/error-state" +import { SettingsSaveBar } from "@/components/settings/settings-save-bar" +import { SettingsSection, SettingsSections } from "@/components/settings/settings-section" +import { useSettingsDraft } from "@/components/settings/settings-draft" +import { useAsyncAction } from "@/hooks/use-mutation-action" +import { Result, useAtomRefresh, useAtomSet, useAtomValue } from "@/lib/effect-atom" +import { toastExit } from "@/lib/error-toast" +import { getServicesFacetsResultAtom } from "@/lib/services/atoms/warehouse-query-atoms" +import { MapleInternalAtomClient, retainedInternalQuery } from "@/lib/services/common/internal-atom-client" +import { snapRangeForCache } from "@/lib/time-utils" + +const TITLE = "Email preferences" + +/** The weekly digests this user gets for the active organization. */ +export function EmailPreferencesSection() { + const { user } = useUser() + const { organization } = useOrganization() + const email = user?.primaryEmailAddress?.emailAddress + + const subscriptionQueryAtom = retainedInternalQuery("digest", "getSubscription", {}) + const subscriptionResult = useAtomValue(subscriptionQueryAtom) + const refreshSubscription = useAtomRefresh(subscriptionQueryAtom) + const load = readDigestSubscription(subscriptionResult) + + if (load.status === "loading" || !user) return + + const recipient = email ? ( + <> + Sent to {email} + {organization ? ` for ${organization.name}` : null} + + ) : ( + "Add a primary email address to receive digests." + ) + + return ( + + + {/* Switches built on defaults would upsert over preferences we could not read. */} + {load.status === "failed" ? ( + + ) : ( + + )} +

+ Unsubscribe links in each email turn the matching digest off. +

+
+
+ ) +} + +/** The saved schedule and scope, or what the server applies to someone who never saved one. */ +const savedDraft = (saved: DigestSubscriptionResponse | null): DigestPreferencesDraft => + saved === null + ? { ...DEFAULT_DIGEST_SCHEDULE, namespaces: [], environments: [] } + : { + dayOfWeek: saved.dayOfWeek, + sendHour: saved.sendHour, + timezone: saved.timezone, + namespaces: saved.namespaces, + environments: saved.environments, + } + +function DigestPreferences({ + saved, + email, + onSaved, +}: { + saved: DigestSubscriptionResponse | null + email: string | undefined + onSaved: () => void +}) { + const upsertMutation = useAtomSet(MapleInternalAtomClient.mutation("digest", "upsertSubscription"), { + mode: "promiseExit", + }) + const enabled = saved?.enabled ?? true + const webAnalyticsEnabled = saved?.webAnalyticsEnabled ?? true + const { draft, isDirty, updateDraft, discard } = useSettingsDraft(savedDraft(saved), sameDigestDraft) + + // `enabled` always rides along: the upsert treats a missing value as "on". + const upsert = async ( + fields: Omit, + next: { enabled: boolean }, + messages: { success: string; error: string }, + ) => { + if (!email) return false + const exit = await upsertMutation({ + payload: new UpsertDigestSubscriptionRequest({ email, enabled: next.enabled, ...fields }), + }) + const ok = toastExit(exit, messages) + if (ok) onSaved() + return ok + } + + const [toggleOps, isTogglingOps] = useAsyncAction((checked: boolean) => + upsert( + {}, + { enabled: checked }, + { + success: checked ? "Weekly ops digest turned on" : "Weekly ops digest turned off", + error: "Failed to update the weekly ops digest", + }, + ), + ) + const [toggleWeb, isTogglingWeb] = useAsyncAction((checked: boolean) => + upsert( + { webAnalyticsEnabled: checked }, + { enabled }, + { + success: checked ? "Web analytics digest turned on" : "Web analytics digest turned off", + error: "Failed to update the web analytics digest", + }, + ), + ) + const [save, isSaving] = useAsyncAction(async () => { + const ok = await upsert( + { + dayOfWeek: draft.dayOfWeek, + sendHour: draft.sendHour, + timezone: draft.timezone, + namespaces: draft.namespaces, + environments: draft.environments, + }, + { enabled }, + { success: "Email preferences saved", error: "Failed to save email preferences" }, + ) + if (ok) discard() + }) + + const busy = isTogglingOps || isTogglingWeb || isSaving + const schedule = ( + updateDraft((current) => ({ ...current, ...patch }))} + /> + ) + + return ( + <> + + } + label="Weekly ops digest" + description="Errors, latency, alerts and ingest volume for the past week." + control={ + toggleOps(checked)} + /> + } + > + {enabled ? ( + + {schedule} + updateDraft((current) => ({ ...current, ...patch }))} + /> + + + ) : null} + + } + label="Web analytics digest" + description="Weekly overview of visitors, top pages and AI traffic. Only sent once the browser SDK is reporting visits." + control={ + <> + + toggleWeb(checked)} + /> + + } + > + {/* Both digests share one schedule; it lives here only while the ops digest is off. */} + {!enabled && webAnalyticsEnabled ? ( + + {schedule} + + ) : null} + + + save()} /> + + ) +} + +type DraftPatch = Partial + +/** "Every at ", on the subscriber's own clock. */ +function ScheduleField({ + draft, + disabled, + onChange, +}: { + draft: DigestPreferencesDraft + disabled: boolean + onChange: (patch: DraftPatch) => void +}) { + const zones = useMemo( + () => + digestTimeZoneOptions( + Intl.supportedValuesOf("timeZone"), + draft.timezone, + Intl.DateTimeFormat().resolvedOptions().timeZone, + ), + [draft.timezone], + ) + return ( + + Schedule +
+ Every + onChange({ dayOfWeek: Number(event.target.value) })} + > + {DIGEST_DAYS.map((day) => ( + + {day.label} + + ))} + + at + onChange({ sendHour: Number(event.target.value) })} + > + {DIGEST_HOURS.map((hour) => ( + + {hour.label} + + ))} + + onChange({ timezone: event.target.value })} + > + {zones.map((zone) => ( + + {zone} + + ))} + +
+ Sent in your time zone. Both digests follow this schedule. +
+ ) +} + +function ScopeFields({ + draft, + disabled, + onChange, +}: { + draft: DigestPreferencesDraft + disabled: boolean + onChange: (patch: DraftPatch) => void +}) { + // The same snapped 24h probe the overview, service map and namespace switcher run, so this + // shares their cache entry rather than adding a request. + const facetsRange = useMemo(() => { + const end = Date.now() + return snapRangeForCache({ + startTime: formatWarehouseDateTime(end - 24 * 60 * 60 * 1000), + endTime: formatWarehouseDateTime(end), + }) + }, []) + const facetsResult = useAtomValue(getServicesFacetsResultAtom({ data: facetsRange })) + const facets = Result.isSuccess(facetsResult) + ? facetsResult.value.data + : { environments: [], namespaces: [] } + + // The facets carry an empty-string entry for "not reported", which a digest cannot pin to. + const namespaceOptions = useMemo( + () => facets.namespaces.filter((item) => item.name !== "").map((item) => ({ value: item.name })), + [facets.namespaces], + ) + const environmentOptions = useMemo( + () => facets.environments.filter((item) => item.name !== "").map((item) => ({ value: item.name })), + [facets.environments], + ) + + return ( + <> + + Namespaces + onChange({ namespaces })} + placeholder={draft.namespaces.length === 0 ? "All namespaces" : "Add namespace..."} + /> + Leave empty to cover every namespace. + + + Environments + onChange({ environments })} + placeholder={draft.environments.length === 0 ? "All environments" : "Add environment..."} + /> + Leave empty to cover every environment. + + + ) +} + +/** + * The email HTML carries org data (page paths, referrers, names), so it never runs on the app's + * origin: it renders in a sandboxed iframe with no scripts and an opaque origin. Popups stay + * allowed so the email's links still open. + */ +function openPreview(html: string) { + const win = window.open("", "_blank") + if (!win) return + win.opener = null + const doc = win.document + doc.title = "Email preview" + doc.body.style.margin = "0" + const frame = doc.createElement("iframe") + frame.setAttribute("sandbox", "allow-popups allow-popups-to-escape-sandbox") + frame.srcdoc = html + frame.style.cssText = "border:0;width:100vw;height:100vh;display:block" + doc.body.append(frame) +} + +function PreviewButton({ kind, disabled }: { kind: "ops" | "web"; disabled: boolean }) { + const previewOps = useAtomSet(MapleInternalAtomClient.mutation("digest", "preview"), { + mode: "promiseExit", + }) + const previewWeb = useAtomSet(MapleInternalAtomClient.mutation("digest", "previewWebAnalytics"), { + mode: "promiseExit", + }) + const [preview, isPreviewing] = useAsyncAction(async () => { + const exit = await (kind === "ops" ? previewOps({}) : previewWeb({})) + if (toastExit(exit, { error: "Failed to generate the preview" }) && Exit.isSuccess(exit)) + openPreview(exit.value.html) + }) + return ( + + ) +} diff --git a/apps/web/src/components/settings/notifications-section.tsx b/apps/web/src/components/settings/notifications-section.tsx deleted file mode 100644 index 384a14e01f..0000000000 --- a/apps/web/src/components/settings/notifications-section.tsx +++ /dev/null @@ -1,313 +0,0 @@ -import { useMemo, useState } from "react" -import { Exit } from "effect" -import { Field, FieldLabel, FieldDescription } from "@maple/ui/components/ui/field" -import { Result, useAtomRefresh, useAtomSet, useAtomValue } from "@/lib/effect-atom" -import { MapleInternalAtomClient, retainedInternalQuery } from "@/lib/services/common/internal-atom-client" -import { UpsertDigestSubscriptionRequest } from "@maple/domain/http" -import { useUser } from "@clerk/clerk-react" -import { formatWarehouseDateTime } from "@maple/query-engine" - -import { Button } from "@maple/ui/components/ui/button" -import { SettingRow } from "@maple/ui/components/ui/setting-row" -import { Switch } from "@maple/ui/components/ui/switch" -import { Panel } from "@maple/ui/components/ui/panel" -import { MultiSelectCombobox } from "@maple/ui/components/multi-select-combobox" -import { ChartBarTrendUpIcon, EnvelopeIcon } from "@/components/icons" -import { getServicesFacetsResultAtom } from "@/lib/services/atoms/warehouse-query-atoms" -import { snapRangeForCache } from "@/lib/time-utils" -import { useAsyncAction } from "@/hooks/use-mutation-action" -import { toastExit } from "@/lib/error-toast" -import { AccountSectionSkeleton } from "@/components/account/account-section-skeleton" -import { SettingsSection, SettingsSections } from "@/components/settings/settings-section" -import { ErrorState } from "@/components/common/error-state" -import { readDigestSubscription } from "@/components/settings/digest-subscription-load" - -/** Two arrays are the same scope regardless of the order they were picked in. */ -const sameScope = (a: readonly string[], b: readonly string[]) => - a.length === b.length && [...a].sort().every((value, index) => value === [...b].sort()[index]) - -interface DigestSave { - enabled: boolean - environments: string[] - namespaces: string[] - webAnalyticsEnabled?: boolean -} - -export function NotificationsSection() { - const { user } = useUser() - const email = user?.primaryEmailAddress?.emailAddress - - const subscriptionQueryAtom = retainedInternalQuery("digest", "getSubscription", {}) - const subscriptionResult = useAtomValue(subscriptionQueryAtom) - const refreshSubscription = useAtomRefresh(subscriptionQueryAtom) - - const upsertMutation = useAtomSet(MapleInternalAtomClient.mutation("digest", "upsertSubscription"), { - mode: "promiseExit", - }) - - // The saved subscription is the source of truth; local state holds only the - // edits made since it loaded. Derived rather than copied in an effect, so a - // refresh after a save is reflected instead of being locked out by an - // "initialized" flag. - const load = readDigestSubscription(subscriptionResult) - const saved = load.status === "ready" ? load.saved : null - - const [enabledEdit, setEnabledEdit] = useState(null) - const [webAnalyticsEdit, setWebAnalyticsEdit] = useState(null) - const [scopeEdit, setScopeEdit] = useState<{ environments: string[]; namespaces: string[] } | null>(null) - - const enabled = enabledEdit ?? saved?.enabled ?? true - const webAnalyticsEnabled = webAnalyticsEdit ?? saved?.webAnalyticsEnabled ?? true - const savedScope = { - environments: saved ? [...saved.environments] : [], - namespaces: saved ? [...saved.namespaces] : [], - } - const environments = scopeEdit?.environments ?? savedScope.environments - const namespaces = scopeEdit?.namespaces ?? savedScope.namespaces - - const setEnvironments = (values: string[]) => setScopeEdit({ environments: values, namespaces }) - const setNamespaces = (values: string[]) => setScopeEdit({ environments, namespaces: values }) - - const previewMutation = useAtomSet(MapleInternalAtomClient.mutation("digest", "preview"), { - mode: "promiseExit", - }) - const previewWebAnalyticsMutation = useAtomSet( - MapleInternalAtomClient.mutation("digest", "previewWebAnalytics"), - { mode: "promiseExit" }, - ) - - // The same snapped 24h probe the overview, service map and namespace switcher - // run, so this shares their cache entry rather than adding a request. - const facetsRange = useMemo(() => { - const end = Date.now() - return snapRangeForCache({ - startTime: formatWarehouseDateTime(end - 24 * 60 * 60 * 1000), - endTime: formatWarehouseDateTime(end), - }) - }, []) - const facetsResult = useAtomValue(getServicesFacetsResultAtom({ data: facetsRange })) - const facets = Result.isSuccess(facetsResult) - ? facetsResult.value.data - : { environments: [], namespaces: [] } - - // The facets carry an empty-string entry for "not reported", which is not - // something a subscriber can meaningfully pin a digest to. - const environmentOptions = useMemo( - () => facets.environments.filter((item) => item.name !== "").map((item) => ({ value: item.name })), - [facets.environments], - ) - const namespaceOptions = useMemo( - () => facets.namespaces.filter((item) => item.name !== "").map((item) => ({ value: item.name })), - [facets.namespaces], - ) - - const scopeDirty = - !sameScope(environments, savedScope.environments) || !sameScope(namespaces, savedScope.namespaces) - - const [save, isSaving] = useAsyncAction( - async (next: DigestSave, messages: { success: string; error: string }) => { - if (!email) return false - const result = await upsertMutation({ - payload: new UpsertDigestSubscriptionRequest({ - email, - enabled: next.enabled, - environments: next.environments, - namespaces: next.namespaces, - // The saved value when this save is not about it, so the ops digest's - // controls never flip the web analytics email. - webAnalyticsEnabled: next.webAnalyticsEnabled ?? webAnalyticsEnabled, - }), - }) - if (!toastExit(result, messages)) return false - // Drop the local edits; the refreshed subscription now carries them. - setEnabledEdit(null) - setWebAnalyticsEdit(null) - setScopeEdit(null) - refreshSubscription() - return true - }, - ) - - async function handleToggle(checked: boolean) { - setEnabledEdit(checked) - const ok = await save( - { enabled: checked, environments, namespaces }, - { - success: checked ? "Weekly digest enabled" : "Weekly digest disabled", - error: "Failed to update notification preferences", - }, - ) - if (!ok) setEnabledEdit(!checked) - } - - async function handleWebAnalyticsToggle(checked: boolean) { - setWebAnalyticsEdit(checked) - // `enabled` rides along: the upsert treats a missing value as "on". - const ok = await save( - { enabled, environments, namespaces, webAnalyticsEnabled: checked }, - { - success: checked ? "Web analytics email enabled" : "Web analytics email disabled", - error: "Failed to update notification preferences", - }, - ) - if (!ok) setWebAnalyticsEdit(!checked) - } - - function handleSaveScope() { - return save( - { enabled, environments, namespaces }, - { success: "Digest scope updated", error: "Failed to update digest scope" }, - ) - } - - /** - * The email HTML carries org data (page paths, referrers, names), so it never - * runs on the app's origin: it renders in a sandboxed iframe with no scripts - * and an opaque origin. Popups stay allowed so the email's links still open. - */ - function openPreview(html: string) { - const win = window.open("", "_blank") - if (!win) return - win.opener = null - const doc = win.document - doc.title = "Email preview" - doc.body.style.margin = "0" - const frame = doc.createElement("iframe") - frame.setAttribute("sandbox", "allow-popups allow-popups-to-escape-sandbox") - frame.srcdoc = html - frame.style.cssText = "border:0;width:100vw;height:100vh;display:block" - doc.body.append(frame) - } - - const [handlePreview, isPreviewing] = useAsyncAction(async () => { - const result = await previewMutation({}) - if (toastExit(result, { error: "Failed to generate digest preview" }) && Exit.isSuccess(result)) - openPreview(result.value.html) - }) - - const [handlePreviewWebAnalytics, isPreviewingWebAnalytics] = useAsyncAction(async () => { - const result = await previewWebAnalyticsMutation({}) - if ( - toastExit(result, { error: "Failed to generate web analytics preview" }) && - Exit.isSuccess(result) - ) - openPreview(result.value.html) - }) - - if (load.status === "loading" || !user) return - // Switches built on defaults would upsert over preferences we could not read. - if (load.status === "failed") { - return ( - - - - - - ) - } - - return ( - - -
- } - label="Email" - description="Weekly digest via email" - control={ - - } - > - {enabled && ( - - - Namespaces - - - - Environments - - - Leave both empty to receive a digest covering the whole organization. - - -
- - {scopeDirty && ( - - )} -
-
- )} -
- } - label="Web analytics" - description="Weekly overview of visitors, top pages and AI traffic. Only sent once the browser SDK is reporting visits." - control={ - <> - - - - } - /> -
-
-
- ) -} diff --git a/apps/web/src/routes/account.tsx b/apps/web/src/routes/account.tsx index b359fcdc64..8ef7481f62 100644 --- a/apps/web/src/routes/account.tsx +++ b/apps/web/src/routes/account.tsx @@ -17,7 +17,7 @@ import { TwoFactorSection } from "@/components/account/two-factor-section" import { PasskeysSection } from "@/components/account/passkeys-section" import { ConnectedAccountsSection } from "@/components/account/connected-accounts-section" import { ActiveSessionsSection } from "@/components/account/active-sessions-section" -import { NotificationsSection } from "@/components/settings/notifications-section" +import { EmailPreferencesSection } from "@/components/account/email-preferences-section" const AccountSearch = Schema.Struct({ tab: Schema.optional(Schema.Literals(accountTabValues)), @@ -56,7 +56,7 @@ function AccountPage() { {activeTab === "passkeys" && } {activeTab === "connections" && } {activeTab === "sessions" && } - {activeTab === "email-preferences" && } + {activeTab === "email-preferences" && } ) } From 49abaca4f84486dd86eb96ad2b00586f34e969b4 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 11:03:24 +0200 Subject: [PATCH 04/13] fix(settings): guard digest claims on the send window, not UTC midnight --- .../src/services/digest/DigestService.test.ts | 36 +++++++++++++++++++ .../src/services/digest/DigestService.ts | 19 ++++++---- .../digest/WebAnalyticsDigestService.ts | 16 ++++++--- .../services/digest/digest-schedule.test.ts | 11 +++++- .../src/services/digest/digest-schedule.ts | 28 ++++++++++++--- 5 files changed, 92 insertions(+), 18 deletions(-) diff --git a/packages/backend/src/services/digest/DigestService.test.ts b/packages/backend/src/services/digest/DigestService.test.ts index 08d6c82c31..d931c09cee 100644 --- a/packages/backend/src/services/digest/DigestService.test.ts +++ b/packages/backend/src/services/digest/DigestService.test.ts @@ -329,6 +329,42 @@ describe("DigestService.runDigestTick", () => { assert.strictEqual(second.errorCount, 0) }).pipe(Effect.provide(layer)) }) + + it.effect("one local send window gets one attempt even when it crosses UTC midnight", () => { + const { sends, layer } = makeHarness() + return Effect.gen(function* () { + // Monday 15:00 in Los Angeles is 22:00 UTC; the local Monday runs on past UTC midnight. + const firstTickMs = Date.UTC(2026, 6, 6, 22, 0, 0) + yield* TestClock.setTime(firstTickMs) + const id = yield* seedSub({ + email: "la@example.com", + timezone: "America/Los_Angeles", + sendHour: 15, + }) + + const digest = yield* DigestService + yield* digest.runDigestTick() + assert.deepStrictEqual(sends, ["la@example.com"]) + + // The email went out but the lastSentAt write was lost. + const database = yield* Database + yield* database.execute((db) => + db.run( + PG.update(DigestSubscriptions) + .set({ lastSentAt: null }) + .where(($) => [$.id.eq(id)]), + ), + ) + + // Tuesday 00:15 UTC is still Monday 17:15 in Los Angeles. + yield* TestClock.setTime(Date.UTC(2026, 6, 7, 0, 15, 0)) + const second = yield* digest.runDigestTick() + + assert.deepStrictEqual(sends, ["la@example.com"]) + assert.strictEqual(second.sentCount, 0) + assert.strictEqual((yield* getSub(id)).lastAttemptedAt, firstTickMs) + }).pipe(Effect.provide(layer)) + }) }) describe("DigestService.unsubscribeByToken", () => { diff --git a/packages/backend/src/services/digest/DigestService.ts b/packages/backend/src/services/digest/DigestService.ts index 6464c72246..9d4bac94b7 100644 --- a/packages/backend/src/services/digest/DigestService.ts +++ b/packages/backend/src/services/digest/DigestService.ts @@ -53,7 +53,7 @@ import { import { formatWarehouseDateTime } from "@maple/query-engine" import * as CH from "@maple/query-engine/ch" -import { isDigestDue } from "./digest-schedule" +import { digestResendCutoffMs, isDigestDue, lastDigestActivity } from "./digest-schedule" import { resolveOrgName } from "./resolve-org-name" import { unsubscribeLinks, verifyUnsubscribeToken } from "./unsubscribe-token" import { summarizeCause } from "@maple/backend/platform/describe-cause" @@ -1039,7 +1039,7 @@ export class DigestService extends Context.Service()("@maple/api/ ) const now = yield* Clock.currentTimeMillis - const todayStartMs = now - (now % 86_400_000) + const resendCutoffMs = digestResendCutoffMs(now) const subs = yield* dbExecute((db) => db.run( @@ -1049,7 +1049,9 @@ export class DigestService extends Context.Service()("@maple/api/ ), ) - const dueSubs = subs.filter((s) => isDigestDue(s, s.lastSentAt, now)) + const dueSubs = subs.filter((s) => + isDigestDue(s, lastDigestActivity(s.lastSentAt, s.lastAttemptedAt), now), + ) if (dueSubs.length === 0) { return { sentCount: 0, errorCount: 0, skipped: false } @@ -1083,7 +1085,7 @@ export class DigestService extends Context.Service()("@maple/api/ // Orgs whose warehouse rejected queries with an auth/config-class // error are parked (see warehouse-org-quarantine.ts). Checked before - // the claim so a parked org isn't marked attempted for the day. + // the claim so a parked org isn't marked attempted for the window. if (yield* isOrgWarehouseQuarantined(edgeCache, rawOrgId)) { yield* Effect.logInfo("Skipping digest for org with quarantined warehouse").pipe( Effect.annotateLogs({ orgId: rawOrgId }), @@ -1097,14 +1099,17 @@ export class DigestService extends Context.Service()("@maple/api/ .set({ lastAttemptedAt: now }) .where(($) => [ PG.inList($.id, orgSubIds), - PG.or($.lastAttemptedAt.isNull(), $.lastAttemptedAt.lt(todayStartMs)), + PG.or( + $.lastAttemptedAt.isNull(), + $.lastAttemptedAt.lte(resendCutoffMs), + ), ]) .returning("id"), ), ) if (claim.length === 0) { - yield* Effect.logInfo("Skipping digest org already attempted today").pipe( + yield* Effect.logInfo("Skipping digest org already attempted this window").pipe( Effect.annotateLogs({ orgId: rawOrgId, subscriptionCount: orgSubs.length, @@ -1118,7 +1123,7 @@ export class DigestService extends Context.Service()("@maple/api/ if (claimedSubs.length < orgSubs.length) { yield* Effect.logInfo( - "Skipping digest subscriptions already attempted today", + "Skipping digest subscriptions already attempted this window", ).pipe( Effect.annotateLogs({ orgId: rawOrgId, diff --git a/packages/backend/src/services/digest/WebAnalyticsDigestService.ts b/packages/backend/src/services/digest/WebAnalyticsDigestService.ts index 22052a87d8..766e94c94f 100644 --- a/packages/backend/src/services/digest/WebAnalyticsDigestService.ts +++ b/packages/backend/src/services/digest/WebAnalyticsDigestService.ts @@ -43,7 +43,7 @@ import { isOrgWarehouseQuarantined, quarantineOnConfigClassCause, } from "@maple/backend/services/warehouse/warehouse-org-quarantine" -import { isDigestDue } from "./digest-schedule" +import { digestResendCutoffMs, isDigestDue, lastDigestActivity } from "./digest-schedule" import { resolveOrgName } from "./resolve-org-name" import { unsubscribeLinks } from "./unsubscribe-token" @@ -450,13 +450,13 @@ export class WebAnalyticsDigestService extends Context.Service db.run( @@ -466,7 +466,13 @@ export class WebAnalyticsDigestService extends Context.Service isDigestDue(s, s.webAnalyticsLastSentAt, now)) + const due = subs.filter((s) => + isDigestDue( + s, + lastDigestActivity(s.webAnalyticsLastSentAt, s.webAnalyticsLastAttemptedAt), + now, + ), + ) if (due.length === 0) return { sentCount: 0, errorCount: 0, skipped: false } const byOrg = Arr.groupBy(due, (s) => s.orgId) @@ -489,7 +495,7 @@ export class WebAnalyticsDigestService extends Context.Service Date.parse(iso) const MONDAY = 1 @@ -70,4 +70,13 @@ describe("isDigestDue", () => { expect(isDigestDue(unknown, null, at("2026-07-06T08:59:00Z"))).toBe(false) expect(isDigestDue(unknown, null, at("2026-07-06T09:00:00Z"))).toBe(true) }) + + it("counts an attempt whose send was never recorded, across UTC midnight", () => { + const losAngeles = { dayOfWeek: MONDAY, sendHour: 15, timezone: "America/Los_Angeles" } + const attemptedAt = at("2026-07-06T22:00:00Z") + const afterUtcMidnight = at("2026-07-07T00:15:00Z") + expect(isDigestDue(losAngeles, null, afterUtcMidnight)).toBe(true) + expect(isDigestDue(losAngeles, lastDigestActivity(null, attemptedAt), afterUtcMidnight)).toBe(false) + expect(lastDigestActivity(attemptedAt - 1000, attemptedAt)).toBe(attemptedAt) + }) }) diff --git a/packages/backend/src/services/digest/digest-schedule.ts b/packages/backend/src/services/digest/digest-schedule.ts index 3788e58640..90a3702e08 100644 --- a/packages/backend/src/services/digest/digest-schedule.ts +++ b/packages/backend/src/services/digest/digest-schedule.ts @@ -21,16 +21,34 @@ export interface DigestSchedule { const resolveZone = (timezone: string): DateTime.TimeZone => Option.getOrElse(DateTime.zoneMakeNamed(timezone), () => DateTime.zoneMakeOffset(0)) +/** + * Latest instant a previous send or claimed attempt may sit at for a new one to be allowed. + * The tick filter and the claim both guard on it, so one local-day window gets one attempt + * even when it straddles UTC midnight. + */ +export const digestResendCutoffMs = (nowMs: number): number => nowMs - MIN_RESEND_GAP_MS + +/** The later of the last send and the last claimed attempt, the activity the gap is measured from. */ +export const lastDigestActivity = ( + lastSentAt: number | null, + lastAttemptedAt: number | null, +): number | null => + lastSentAt === null + ? lastAttemptedAt + : lastAttemptedAt === null + ? lastSentAt + : Math.max(lastSentAt, lastAttemptedAt) + /** * Whether a weekly digest should go out at `nowMs`: it is the subscriber's chosen weekday in - * their zone, the local clock has reached their send hour, and nothing went out in the last - * six days. The digest tick runs every 15 minutes, so this window is hit on the first tick at - * or after the send hour, and `lastSentAt` keeps every later tick that day idempotent. + * their zone, the local clock has reached their send hour, and nothing was sent or attempted in + * the last six days. The digest tick runs every 15 minutes, so this window is hit on the first + * tick at or after the send hour, and `lastActivityAt` keeps every later tick that day idempotent. */ -export function isDigestDue(schedule: DigestSchedule, lastSentAt: number | null, nowMs: number): boolean { +export function isDigestDue(schedule: DigestSchedule, lastActivityAt: number | null, nowMs: number): boolean { const local = DateTime.toParts( DateTime.makeZonedUnsafe(nowMs, { timeZone: resolveZone(schedule.timezone) }), ) if (local.weekDay !== schedule.dayOfWeek || local.hour < schedule.sendHour) return false - return lastSentAt === null || lastSentAt <= nowMs - MIN_RESEND_GAP_MS + return lastActivityAt === null || lastActivityAt <= digestResendCutoffMs(nowMs) } From 8a90cb77bb8dbec5e96dc74afd2c3e1acf5ed05b Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 11:04:11 +0200 Subject: [PATCH 05/13] fix(settings): prefill the digest zone from the browser and note when changes apply --- .../account/digest-preferences.test.ts | 19 ++++++++++++- .../components/account/digest-preferences.ts | 16 ++++++++++- .../account/email-preferences-section.tsx | 28 +++++++++++-------- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/apps/web/src/components/account/digest-preferences.test.ts b/apps/web/src/components/account/digest-preferences.test.ts index f1e86892df..5c5045f58c 100644 --- a/apps/web/src/components/account/digest-preferences.test.ts +++ b/apps/web/src/components/account/digest-preferences.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest" -import { digestTimeZoneOptions, sameDigestDraft } from "./digest-preferences" +import { digestTimeZoneOptions, newDigestDraft, sameDigestDraft } from "./digest-preferences" const base = { dayOfWeek: 1, @@ -35,3 +35,20 @@ describe("digestTimeZoneOptions", () => { expect(zones).toEqual(["UTC", "Europe/Berlin"]) }) }) + +describe("newDigestDraft", () => { + it("schedules a first-time subscriber in the browser's zone", () => { + expect(newDigestDraft("America/Los_Angeles")).toEqual({ + dayOfWeek: 1, + sendHour: 9, + timezone: "America/Los_Angeles", + namespaces: [], + environments: [], + }) + }) + + it("falls back to UTC when the browser reports no zone", () => { + expect(newDigestDraft(undefined).timezone).toBe("UTC") + expect(newDigestDraft("").timezone).toBe("UTC") + }) +}) diff --git a/apps/web/src/components/account/digest-preferences.ts b/apps/web/src/components/account/digest-preferences.ts index 239bc9ddb4..3e3584daae 100644 --- a/apps/web/src/components/account/digest-preferences.ts +++ b/apps/web/src/components/account/digest-preferences.ts @@ -17,7 +17,7 @@ export const DIGEST_HOURS = Array.from({ length: 24 }, (_, hour) => ({ })) /** What the server applies to a subscriber who never saved a schedule. */ -export const DEFAULT_DIGEST_SCHEDULE = { dayOfWeek: 1, sendHour: 9, timezone: "UTC" } as const +const DEFAULT_DIGEST_SCHEDULE = { dayOfWeek: 1, sendHour: 9, timezone: "UTC" } as const export interface DigestPreferencesDraft { readonly dayOfWeek: number @@ -27,6 +27,20 @@ export interface DigestPreferencesDraft { readonly environments: ReadonlyArray } +/** + * The draft for someone with no subscription yet: the server's day and hour, but in the + * browser's own zone, so the schedule reads in local time before the first save. + */ +export function newDigestDraft(browserZone: string | undefined): DigestPreferencesDraft { + return { + ...DEFAULT_DIGEST_SCHEDULE, + timezone: + browserZone !== undefined && browserZone !== "" ? browserZone : DEFAULT_DIGEST_SCHEDULE.timezone, + namespaces: [], + environments: [], + } +} + const sorted = (values: ReadonlyArray) => [...values].sort() /** Scopes are sets: picking the same namespaces in another order is not an edit. */ diff --git a/apps/web/src/components/account/email-preferences-section.tsx b/apps/web/src/components/account/email-preferences-section.tsx index ab802a16e6..cbacf958a0 100644 --- a/apps/web/src/components/account/email-preferences-section.tsx +++ b/apps/web/src/components/account/email-preferences-section.tsx @@ -15,11 +15,11 @@ import { ChartBarTrendUpIcon, EnvelopeIcon } from "@/components/icons" import { AccountSectionSkeleton } from "@/components/account/account-section-skeleton" import { readDigestSubscription } from "@/components/account/digest-subscription-load" import { - DEFAULT_DIGEST_SCHEDULE, DIGEST_DAYS, DIGEST_HOURS, type DigestPreferencesDraft, digestTimeZoneOptions, + newDigestDraft, sameDigestDraft, } from "@/components/account/digest-preferences" import { ErrorState } from "@/components/common/error-state" @@ -79,10 +79,12 @@ export function EmailPreferencesSection() { ) } -/** The saved schedule and scope, or what the server applies to someone who never saved one. */ +const browserTimeZone = (): string | undefined => Intl.DateTimeFormat().resolvedOptions().timeZone + +/** The saved schedule and scope, or the defaults in the browser's zone for someone who never saved. */ const savedDraft = (saved: DigestSubscriptionResponse | null): DigestPreferencesDraft => saved === null - ? { ...DEFAULT_DIGEST_SCHEDULE, namespaces: [], environments: [] } + ? newDigestDraft(browserTimeZone()) : { dayOfWeek: saved.dayOfWeek, sendHour: saved.sendHour, @@ -105,7 +107,10 @@ function DigestPreferences({ }) const enabled = saved?.enabled ?? true const webAnalyticsEnabled = saved?.webAnalyticsEnabled ?? true - const { draft, isDirty, updateDraft, discard } = useSettingsDraft(savedDraft(saved), sameDigestDraft) + const baseline = savedDraft(saved) + const { draft, isDirty, updateDraft, discard } = useSettingsDraft(baseline, sameDigestDraft) + // The first write records the prefilled zone, so a toggle alone does not leave the row on UTC. + const firstWrite = saved === null ? { timezone: baseline.timezone } : {} // `enabled` always rides along: the upsert treats a missing value as "on". const upsert = async ( @@ -124,7 +129,7 @@ function DigestPreferences({ const [toggleOps, isTogglingOps] = useAsyncAction((checked: boolean) => upsert( - {}, + firstWrite, { enabled: checked }, { success: checked ? "Weekly ops digest turned on" : "Weekly ops digest turned off", @@ -134,7 +139,7 @@ function DigestPreferences({ ) const [toggleWeb, isTogglingWeb] = useAsyncAction((checked: boolean) => upsert( - { webAnalyticsEnabled: checked }, + { ...firstWrite, webAnalyticsEnabled: checked }, { enabled }, { success: checked ? "Web analytics digest turned on" : "Web analytics digest turned off", @@ -236,12 +241,7 @@ function ScheduleField({ onChange: (patch: DraftPatch) => void }) { const zones = useMemo( - () => - digestTimeZoneOptions( - Intl.supportedValuesOf("timeZone"), - draft.timezone, - Intl.DateTimeFormat().resolvedOptions().timeZone, - ), + () => digestTimeZoneOptions(Intl.supportedValuesOf("timeZone"), draft.timezone, browserTimeZone()), [draft.timezone], ) return ( @@ -292,6 +292,10 @@ function ScheduleField({ Sent in your time zone. Both digests follow this schedule. +

+ Changes apply from the next send, so moving the day right after a digest went out skips to + next week. +

) } From 0acb5a106f4395b22a4da93c267e7eb94104bc7e Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 11:06:39 +0200 Subject: [PATCH 06/13] fix(settings): keep saved AI limits and email schedule on screen until the refetch lands --- apps/web/src/components/account/email-preferences-section.tsx | 4 ++-- .../src/components/settings/ai-triage-settings-section.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/account/email-preferences-section.tsx b/apps/web/src/components/account/email-preferences-section.tsx index cbacf958a0..82aba9a032 100644 --- a/apps/web/src/components/account/email-preferences-section.tsx +++ b/apps/web/src/components/account/email-preferences-section.tsx @@ -108,7 +108,7 @@ function DigestPreferences({ const enabled = saved?.enabled ?? true const webAnalyticsEnabled = saved?.webAnalyticsEnabled ?? true const baseline = savedDraft(saved) - const { draft, isDirty, updateDraft, discard } = useSettingsDraft(baseline, sameDigestDraft) + const { draft, isDirty, updateDraft, discard, commit } = useSettingsDraft(baseline, sameDigestDraft) // The first write records the prefilled zone, so a toggle alone does not leave the row on UTC. const firstWrite = saved === null ? { timezone: baseline.timezone } : {} @@ -159,7 +159,7 @@ function DigestPreferences({ { enabled }, { success: "Email preferences saved", error: "Failed to save email preferences" }, ) - if (ok) discard() + if (ok) commit() }) const busy = isTogglingOps || isTogglingWeb || isSaving diff --git a/apps/web/src/components/settings/ai-triage-settings-section.tsx b/apps/web/src/components/settings/ai-triage-settings-section.tsx index ef545ee3fe..e1d4fe332d 100644 --- a/apps/web/src/components/settings/ai-triage-settings-section.tsx +++ b/apps/web/src/components/settings/ai-triage-settings-section.tsx @@ -65,7 +65,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { maxRunsPerDay: String(current.maxRunsPerDay), maxPassesPerDay: String(current.maxPassesPerDay), } - const { draft, isDirty, updateDraft, discard } = useSettingsDraft(saved) + const { draft, isDirty, updateDraft, discard, commit } = useSettingsDraft(saved) const send = async (request: AiTriageSettingsUpdateRequest, success: string) => toastExit(await updateMutation({ payload: request, reactivityKeys: SETTINGS_REACTIVITY_KEYS }), { @@ -87,7 +87,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { ...(update.maxRunsPerDay === null ? undefined : { maxRunsPerDay: update.maxRunsPerDay }), ...(update.maxPassesPerDay === null ? undefined : { maxPassesPerDay: update.maxPassesPerDay }), }) - if (await send(request, "Auto-triage limits saved")) discard() + if (await send(request, "Auto-triage limits saved")) commit() }) const runsError = parseDailyLimit(draft.maxRunsPerDay, RUNS_PER_DAY_LIMITS) From eb6fa94d2f1866ebff080cea3554db0df646a719 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 11:07:55 +0200 Subject: [PATCH 07/13] style(settings): format the investigations limit link --- apps/web/src/routes/investigations/index.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/apps/web/src/routes/investigations/index.tsx b/apps/web/src/routes/investigations/index.tsx index 2ef0dfda75..8919fdeec3 100644 --- a/apps/web/src/routes/investigations/index.tsx +++ b/apps/web/src/routes/investigations/index.tsx @@ -411,11 +411,7 @@ function BudgetExhaustedNotice({ {canEditSettings ? ( - @@ -464,10 +460,7 @@ function TriageStrip({ investigations }: { investigations: ReadonlyArray 0 ? `to review (${stats.critical} critical)` : "to review"} tone={stats.review.length > 0 ? "warn" : undefined} /> - + ) } From 7f5cd8efb8d40bcc47db462ce85bc2d29f227243 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 11:19:47 +0200 Subject: [PATCH 08/13] fix(settings): release the AI limits draft when the save normalized it --- .../src/components/settings/ai-triage-settings-section.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/settings/ai-triage-settings-section.tsx b/apps/web/src/components/settings/ai-triage-settings-section.tsx index e1d4fe332d..e45d809fb4 100644 --- a/apps/web/src/components/settings/ai-triage-settings-section.tsx +++ b/apps/web/src/components/settings/ai-triage-settings-section.tsx @@ -87,7 +87,11 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { ...(update.maxRunsPerDay === null ? undefined : { maxRunsPerDay: update.maxRunsPerDay }), ...(update.maxPassesPerDay === null ? undefined : { maxPassesPerDay: update.maxPassesPerDay }), }) - if (await send(request, "Auto-triage limits saved")) commit() + const sent: AiTriageLimitsDraft = { + maxRunsPerDay: String(update.maxRunsPerDay ?? current.maxRunsPerDay), + maxPassesPerDay: String(update.maxPassesPerDay ?? current.maxPassesPerDay), + } + if (await send(request, "Auto-triage limits saved")) commit(sent) }) const runsError = parseDailyLimit(draft.maxRunsPerDay, RUNS_PER_DAY_LIMITS) From d9e25011c49d9261bbbebd4c1dcf7858b76d4877 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 12:56:14 +0200 Subject: [PATCH 09/13] fix(settings): commit AI limits and the email schedule with the draft the save submitted --- apps/web/src/components/account/email-preferences-section.tsx | 3 ++- .../web/src/components/settings/ai-triage-settings-section.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/account/email-preferences-section.tsx b/apps/web/src/components/account/email-preferences-section.tsx index 82aba9a032..b325467d34 100644 --- a/apps/web/src/components/account/email-preferences-section.tsx +++ b/apps/web/src/components/account/email-preferences-section.tsx @@ -148,6 +148,7 @@ function DigestPreferences({ ), ) const [save, isSaving] = useAsyncAction(async () => { + const submitted = draft const ok = await upsert( { dayOfWeek: draft.dayOfWeek, @@ -159,7 +160,7 @@ function DigestPreferences({ { enabled }, { success: "Email preferences saved", error: "Failed to save email preferences" }, ) - if (ok) commit() + if (ok) commit({ submitted }) }) const busy = isTogglingOps || isTogglingWeb || isSaving diff --git a/apps/web/src/components/settings/ai-triage-settings-section.tsx b/apps/web/src/components/settings/ai-triage-settings-section.tsx index e45d809fb4..479b136f13 100644 --- a/apps/web/src/components/settings/ai-triage-settings-section.tsx +++ b/apps/web/src/components/settings/ai-triage-settings-section.tsx @@ -83,6 +83,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { const update = limitsUpdate(draft, current) const [saveLimits, isSavingLimits] = useAsyncAction(async () => { if (!update.ok) return + const submitted = draft const request = new AiTriageSettingsUpdateRequest({ ...(update.maxRunsPerDay === null ? undefined : { maxRunsPerDay: update.maxRunsPerDay }), ...(update.maxPassesPerDay === null ? undefined : { maxPassesPerDay: update.maxPassesPerDay }), @@ -91,7 +92,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { maxRunsPerDay: String(update.maxRunsPerDay ?? current.maxRunsPerDay), maxPassesPerDay: String(update.maxPassesPerDay ?? current.maxPassesPerDay), } - if (await send(request, "Auto-triage limits saved")) commit(sent) + if (await send(request, "Auto-triage limits saved")) commit({ submitted, sent }) }) const runsError = parseDailyLimit(draft.maxRunsPerDay, RUNS_PER_DAY_LIMITS) From 55229ea556280eb1bd4984db97bb77367bbc2fa0 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 13:13:12 +0200 Subject: [PATCH 10/13] fix(settings): track AI limits and email schedule saves as in flight until they settle --- .../src/components/account/email-preferences-section.tsx | 8 ++++++-- .../components/settings/ai-triage-settings-section.tsx | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/account/email-preferences-section.tsx b/apps/web/src/components/account/email-preferences-section.tsx index b325467d34..b1174e308d 100644 --- a/apps/web/src/components/account/email-preferences-section.tsx +++ b/apps/web/src/components/account/email-preferences-section.tsx @@ -108,7 +108,10 @@ function DigestPreferences({ const enabled = saved?.enabled ?? true const webAnalyticsEnabled = saved?.webAnalyticsEnabled ?? true const baseline = savedDraft(saved) - const { draft, isDirty, updateDraft, discard, commit } = useSettingsDraft(baseline, sameDigestDraft) + const { draft, isDirty, updateDraft, discard, commit, submit, abort } = useSettingsDraft( + baseline, + sameDigestDraft, + ) // The first write records the prefilled zone, so a toggle alone does not leave the row on UTC. const firstWrite = saved === null ? { timezone: baseline.timezone } : {} @@ -148,7 +151,7 @@ function DigestPreferences({ ), ) const [save, isSaving] = useAsyncAction(async () => { - const submitted = draft + const submitted = submit() const ok = await upsert( { dayOfWeek: draft.dayOfWeek, @@ -161,6 +164,7 @@ function DigestPreferences({ { success: "Email preferences saved", error: "Failed to save email preferences" }, ) if (ok) commit({ submitted }) + else abort() }) const busy = isTogglingOps || isTogglingWeb || isSaving diff --git a/apps/web/src/components/settings/ai-triage-settings-section.tsx b/apps/web/src/components/settings/ai-triage-settings-section.tsx index 479b136f13..693e372406 100644 --- a/apps/web/src/components/settings/ai-triage-settings-section.tsx +++ b/apps/web/src/components/settings/ai-triage-settings-section.tsx @@ -65,7 +65,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { maxRunsPerDay: String(current.maxRunsPerDay), maxPassesPerDay: String(current.maxPassesPerDay), } - const { draft, isDirty, updateDraft, discard, commit } = useSettingsDraft(saved) + const { draft, isDirty, updateDraft, discard, commit, submit, abort } = useSettingsDraft(saved) const send = async (request: AiTriageSettingsUpdateRequest, success: string) => toastExit(await updateMutation({ payload: request, reactivityKeys: SETTINGS_REACTIVITY_KEYS }), { @@ -83,7 +83,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { const update = limitsUpdate(draft, current) const [saveLimits, isSavingLimits] = useAsyncAction(async () => { if (!update.ok) return - const submitted = draft + const submitted = submit() const request = new AiTriageSettingsUpdateRequest({ ...(update.maxRunsPerDay === null ? undefined : { maxRunsPerDay: update.maxRunsPerDay }), ...(update.maxPassesPerDay === null ? undefined : { maxPassesPerDay: update.maxPassesPerDay }), @@ -93,6 +93,7 @@ function AutoTriageForm({ current }: { current: AiTriageSettingsDocument }) { maxPassesPerDay: String(update.maxPassesPerDay ?? current.maxPassesPerDay), } if (await send(request, "Auto-triage limits saved")) commit({ submitted, sent }) + else abort() }) const runsError = parseDailyLimit(draft.maxRunsPerDay, RUNS_PER_DAY_LIMITS) From 2d240893a3dd2ed77e4cb01711824d097618d8ab Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 13:28:54 +0200 Subject: [PATCH 11/13] fix(settings): let admins remove a saved OpenRouter key after the add-on lapses --- .../settings/ai-provider-section.tsx | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/settings/ai-provider-section.tsx b/apps/web/src/components/settings/ai-provider-section.tsx index 5454a7ec5f..7cb3e71df0 100644 --- a/apps/web/src/components/settings/ai-provider-section.tsx +++ b/apps/web/src/components/settings/ai-provider-section.tsx @@ -176,7 +176,8 @@ function OpenRouterKeyPanel({ }) { const [replacing, setReplacing] = useState(false) - if (!current.entitled) return + if (!current.entitled) + return if (current.configured && !replacing) { return ( @@ -275,7 +276,17 @@ function OpenRouterKeyForm({ ) } -function AddOnUpsell({ current, onAttached }: { current: OpenRouterKeyDocument; onAttached: () => void }) { +function AddOnUpsell({ + current, + onAttached, + onRemove, + busy, +}: { + current: OpenRouterKeyDocument + onAttached: () => void + onRemove: () => void + busy: boolean +}) { const [confirmAddOn, setConfirmAddOn] = useState(false) const { attach } = useBillingActions() @@ -299,9 +310,21 @@ function AddOnUpsell({ current, onAttached }: { current: OpenRouterKeyDocument; return (
{current.configured ? ( -

- Your saved key (sk-or-...{current.keyHint}) is not in use because the add-on has lapsed. -

+
+

+ Your saved key (sk-or-...{current.keyHint}) is not in use because the add-on has + lapsed. +

+ +
) : null}

Needs the OpenRouter add-on, {ADD_ON_PRICE}, billed with your plan. Cancel any time from From 6ce2206d6bdbd31fc9993bfe9972871ffeae5b6d Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 15:49:09 +0200 Subject: [PATCH 12/13] feat(settings): show auto-triage as coming soon outside the rollout, link escalation routing Orgs without the auto-triage flag saw only the provider cards. They now see the auto-triage rows disabled, and every admin gets a card that opens escalation routing in Automation. --- .../settings/ai-escalation-card.tsx | 28 +++++++++++ .../settings/ai-triage-settings-section.tsx | 47 ++++++++++++++++++- apps/web/src/routes/settings.tsx | 6 ++- 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 apps/web/src/components/settings/ai-escalation-card.tsx diff --git a/apps/web/src/components/settings/ai-escalation-card.tsx b/apps/web/src/components/settings/ai-escalation-card.tsx new file mode 100644 index 0000000000..4485c724b6 --- /dev/null +++ b/apps/web/src/components/settings/ai-escalation-card.tsx @@ -0,0 +1,28 @@ +import { Link } from "@tanstack/react-router" +import { Button } from "@maple/ui/components/ui/button" +import { BellIcon } from "@/components/icons" + +/** Points from the AI tab to where triaged issues are routed, so the two halves read as one flow. */ +export function AiEscalationCard() { + return ( +

+
+ +
+ Escalation routing + + Route triaged issues by severity and confidence to your alert destinations. + +
+
+ +
+ ) +} diff --git a/apps/web/src/components/settings/ai-triage-settings-section.tsx b/apps/web/src/components/settings/ai-triage-settings-section.tsx index 693e372406..2f88bf2a5e 100644 --- a/apps/web/src/components/settings/ai-triage-settings-section.tsx +++ b/apps/web/src/components/settings/ai-triage-settings-section.tsx @@ -1,6 +1,7 @@ import { Result, useAtomRefresh, useAtomSet, useAtomValue } from "@/lib/effect-atom" import { formatNumber } from "@maple/ui/lib/format" +import { Badge } from "@maple/ui/components/ui/badge" import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "@maple/ui/components/ui/collapsible" import { Field, FieldDescription, FieldError, FieldLabel } from "@maple/ui/components/ui/field" import { Input } from "@maple/ui/components/ui/input" @@ -31,8 +32,50 @@ const SETTINGS_REACTIVITY_KEYS = ["aiTriageSettings"] const DESCRIPTION = "When an error or anomaly incident opens, an agent investigates it with read-only tools and attaches a triage summary. Runs on the model provider above." -/** Auto-triage on the AI tab: the switch saves at once, the two ceilings go through the save bar. */ -export function AutoTriageSection() { +/** + * Auto-triage on the AI tab: the switch saves at once, the two ceilings go through the save bar. + * Orgs outside the rollout see the same rows disabled, marked as coming soon. + */ +export function AutoTriageSection({ available }: { available: boolean }) { + if (!available) return + return +} + +function AutoTriageTeaser() { + return ( + Coming soon} + framed={false} + > + + } + /> + + } + /> + + + ) +} + +function AutoTriageSettings() { const settingsQueryAtom = retainedInternalQuery("aiTriage", "getSettings", { reactivityKeys: SETTINGS_REACTIVITY_KEYS, }) diff --git a/apps/web/src/routes/settings.tsx b/apps/web/src/routes/settings.tsx index 664f0f11a5..1b65accd23 100644 --- a/apps/web/src/routes/settings.tsx +++ b/apps/web/src/routes/settings.tsx @@ -13,6 +13,7 @@ import { AuditLogSection } from "@/components/settings/audit-log-section" import { McpSection } from "@/components/settings/mcp-section" import { ModelProviderSection } from "@/components/settings/ai-provider-section" import { AutoTriageSection } from "@/components/settings/ai-triage-settings-section" +import { AiEscalationCard } from "@/components/settings/ai-escalation-card" import { SettingsSections } from "@/components/settings/settings-section" import { AutomationSection } from "@/components/settings/automation-section" import { OrgClickHouseSettingsSection } from "@/components/settings/org-clickhouse-settings-section" @@ -116,8 +117,9 @@ function SettingsPage() { {activeTab === "ai" && ( - {/* The tab is admin-only; auto-triage also needs its flag. */} - {canAccessAi && } + {/* The tab is admin-only; orgs outside the auto-triage rollout see a preview. */} + + )} {activeTab === "automation" && } From 97f68a4470da349bb03b8350f56cb08f7771a38a Mon Sep 17 00:00:00 2001 From: Makisuo Date: Sat, 17 Oct 2026 15:57:50 +0200 Subject: [PATCH 13/13] fix(settings): give both model provider cards the same height --- apps/web/src/components/settings/ai-provider-section.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/settings/ai-provider-section.tsx b/apps/web/src/components/settings/ai-provider-section.tsx index 7cb3e71df0..5fea2e9c9f 100644 --- a/apps/web/src/components/settings/ai-provider-section.tsx +++ b/apps/web/src/components/settings/ai-provider-section.tsx @@ -89,7 +89,7 @@ function ProviderChoice({ if (value === "managed" && inUse) setConfirmRemove(true) else setPicked(value === "openrouter" ? "openrouter" : "managed") }} - className="grid items-start gap-3 sm:grid-cols-2" + className="grid gap-3 sm:grid-cols-2" >