From 752534f21cf0652c60c74a4147c9a793fd1a587b Mon Sep 17 00:00:00 2001 From: Ciocanel Razvan Date: Tue, 7 Apr 2026 15:31:34 +0300 Subject: [PATCH] feat: dynamic health status + canonical reference ranges + DB migrations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds dynamic status computation, production-safe migrations, and comprehensive reference range data. Dynamic status system: - useDynamicStatus hook computes optimal/borderline/elevated from reference ranges instead of hardcoded thresholds - Panel config maps metrics to clinical categories with display metadata - Enhanced health-utils with percentage-based range evaluation Database migrations (production-safe): - 0009: Schema additions (observations metadata, user demographics) - 0010: Seed missing metric definitions + optimal ranges via migration (not seeds, to avoid duplicates on redeploy). Includes NULL-safe unique index on optimal_ranges. Backfills calculated observations (HOMA-IR) from same-date glucose+insulin pairs. - 0011: Consolidate duplicate metric codes to canonical forms (hemoglobin_a1c → hba1c, etc.) Other improvements: - Extended observations router with correct/confirm/delete mutations - Observation correction tracking (original values preserved) - Optimal ranges seed data for 40+ biomarkers - Labs detail page uses dynamic status --- .../(main)/labs/[metricCode]/page.tsx | 153 +- apps/web/app/(dashboard)/(main)/labs/page.tsx | 8 +- apps/web/hooks/use-dynamic-status.ts | 88 + apps/web/lib/health-utils.ts | 110 +- apps/web/lib/panel-config.ts | 110 + apps/web/server/trpc/routers/observations.ts | 209 +- .../drizzle/0009_purple_dragon_man.sql | 25 + .../drizzle/0010_seed_missing_metric_data.sql | 288 ++ .../drizzle/0011_consolidate_metric_codes.sql | 77 + .../database/drizzle/meta/0009_snapshot.json | 3534 +++++++++++++++++ .../database/drizzle/meta/0010_snapshot.json | 3534 +++++++++++++++++ .../database/drizzle/meta/0011_snapshot.json | 3534 +++++++++++++++++ packages/database/drizzle/meta/_journal.json | 23 +- packages/database/src/schema/observations.ts | 36 + .../database/src/seed/data/optimal-ranges.ts | 164 + packages/database/src/seed/run.ts | 131 +- 16 files changed, 11898 insertions(+), 126 deletions(-) create mode 100644 apps/web/hooks/use-dynamic-status.ts create mode 100644 apps/web/lib/panel-config.ts create mode 100644 packages/database/drizzle/0009_purple_dragon_man.sql create mode 100644 packages/database/drizzle/0010_seed_missing_metric_data.sql create mode 100644 packages/database/drizzle/0011_consolidate_metric_codes.sql create mode 100644 packages/database/drizzle/meta/0009_snapshot.json create mode 100644 packages/database/drizzle/meta/0010_snapshot.json create mode 100644 packages/database/drizzle/meta/0011_snapshot.json diff --git a/apps/web/app/(dashboard)/(main)/labs/[metricCode]/page.tsx b/apps/web/app/(dashboard)/(main)/labs/[metricCode]/page.tsx index c56b0db..faf9e19 100644 --- a/apps/web/app/(dashboard)/(main)/labs/[metricCode]/page.tsx +++ b/apps/web/app/(dashboard)/(main)/labs/[metricCode]/page.tsx @@ -9,13 +9,13 @@ import { } from "@/components/health/status-badge"; import { TrendChart } from "@/components/health/trend-chart"; import { - deriveStatus, deriveOptimalStatus, formatRange, } from "@/lib/health-utils"; +import { useDynamicStatus } from "@/hooks/use-dynamic-status"; import { cn, formatDate, formatObsValue, isDurationMetric } from "@/lib/utils"; import { DataTable, type DataTableColumn } from "@/components/data-table"; -import { Pill, TrendingUp, TrendingDown, Minus } from "lucide-react"; +import { Pill, TrendingUp, TrendingDown, Minus, Pencil, Trash2, Check, X } from "lucide-react"; const TIME_RANGES = [ { key: "3m", label: "3M", months: 3 }, @@ -77,6 +77,7 @@ export default function LabDetailPage({ params: Promise<{ metricCode: string }>; }) { const { metricCode } = use(params); + const { getStatus, getRanges } = useDynamicStatus(); const { data, isLoading } = trpc.observations.list.useQuery({ metricCode, @@ -88,10 +89,26 @@ export default function LabDetailPage({ metricCode, }); const { data: medsData } = trpc.medications.list.useQuery({}); - const displayPrecision = - metricsData?.find((m) => m.id === metricCode)?.displayPrecision ?? null; + const utils = trpc.useUtils(); + const correctMutation = trpc.observations.correct.useMutation({ + onSuccess: () => utils.observations.list.invalidate({ metricCode }), + }); + const deleteMutation = trpc.observations.delete.useMutation({ + onSuccess: () => utils.observations.list.invalidate({ metricCode }), + }); + const [editingId, setEditingId] = useState(null); + const [editValue, setEditValue] = useState(""); + const [editNote, setEditNote] = useState(""); + const metricDef = metricsData?.find((m) => m.id === metricCode); + const displayPrecision = metricDef?.displayPrecision ?? null; const showOptimal = prefsData?.showOptimalRanges ?? true; const optimalRange = optimalRangesData?.[metricCode] ?? null; + // Get canonical ranges from the dynamic status hook + const canonRanges = getRanges(metricCode); + // Display the active range used for status (optimal first, then reference) + const activeRangeLow = canonRanges?.optimalLow ?? canonRanges?.referenceLow; + const activeRangeHigh = canonRanges?.optimalHigh ?? canonRanges?.referenceHigh; + const canonicalRange = formatRange(activeRangeLow, activeRangeHigh, metricDef?.unit); const items = data?.items ?? []; @@ -145,13 +162,14 @@ export default function LabDetailPage({ header: "Value", width: "0.8fr", cell: (obs) => { - const obsStatus = deriveStatus(obs); + const obsStatus = getStatus(obs); + const isAbn = obsStatus !== "normal"; return (
( -
- {formatRange( - obs.referenceRangeLow, - obs.referenceRangeHigh, - obs.unit, - )} +
+
+ {formatRange( + obs.referenceRangeLow, + obs.referenceRangeHigh, + obs.unit, + )} +
), }, @@ -193,8 +213,8 @@ export default function LabDetailPage({ header: "Status", width: "0.8fr", cell: (obs) => { - const obsStatus = deriveStatus(obs); - return obs.isAbnormal ? ( + const obsStatus = getStatus(obs); + return obsStatus !== "normal" ? ( ( -
- {obs.status === "corrected" - ? "Corrected" - : obs.status === "confirmed" - ? "Confirmed" - : "Extracted"} +
+ +
), }, ], - [metricCode, displayPrecision], + [metricCode, displayPrecision, deleteMutation], ); const latest = sorted[0]; const previous = sorted[1]; const metricName = formatMetricName(metricCode); - const status: HealthStatus = latest ? deriveStatus(latest) : "neutral"; + const status: HealthStatus = latest ? getStatus(latest) : "neutral"; const [timeRange, setTimeRange] = useState("all"); @@ -298,7 +331,8 @@ export default function LabDetailPage({ ); } - const refRange = formatRange( + // Use canonical range for the summary card (consistent standard) + const refRange = canonicalRange !== "—" ? canonicalRange : formatRange( latest?.referenceRangeLow, latest?.referenceRangeHigh, latest?.unit, @@ -372,7 +406,11 @@ export default function LabDetailPage({ } /> - + {showOptimal && optimalRange && ( obs.id, getRowTint: (obs) => - obs.isAbnormal + getStatus(obs) !== "normal" ? "bg-health-warning-bg/40" : undefined, }} /> + + {/* Inline edit overlay */} + {editingId && ( +
+
+ + + + +
+
+ )}
); } @@ -493,6 +584,7 @@ function MetricContext({ metricName, }: { observations: Array<{ + metricCode: string; valueNumeric?: number | null; isAbnormal?: boolean | null; observedAt: string | Date; @@ -507,6 +599,7 @@ function MetricContext({ }>; metricName: string; }) { + const { isAbnormal: isObsAbnormal } = useDynamicStatus(); if (observations.length < 2) return null; const oldest = new Date(observations[observations.length - 1]!.observedAt).getTime(); @@ -533,7 +626,7 @@ function MetricContext({ const secondAvg = secondHalf.reduce((s, v) => s + v, 0) / secondHalf.length; const changePct = firstAvg !== 0 ? ((secondAvg - firstAvg) / Math.abs(firstAvg)) * 100 : 0; - const latestAbnormal = observations[0]?.isAbnormal; + const latestAbnormal = observations[0] ? isObsAbnormal(observations[0]) : null; const trendDirection = Math.abs(changePct) < 3 ? 'stable' : changePct > 0 ? 'rising' : 'falling'; if (overlapping.length === 0 && trendDirection === 'stable') return null; diff --git a/apps/web/app/(dashboard)/(main)/labs/page.tsx b/apps/web/app/(dashboard)/(main)/labs/page.tsx index 62a6fda..0a55d34 100644 --- a/apps/web/app/(dashboard)/(main)/labs/page.tsx +++ b/apps/web/app/(dashboard)/(main)/labs/page.tsx @@ -5,7 +5,8 @@ import { TitleActionHeader } from '@/components/title-action-header'; import { MetricCard } from '@/components/health/metric-card'; import { MetricSummaryCard } from '@/components/health/metric-summary-card'; import { AnimatedEmptyState } from '@/components/animated-empty-state'; -import { deriveStatus, formatRange } from '@/lib/health-utils'; +import { formatRange } from '@/lib/health-utils'; +import { useDynamicStatus } from '@/hooks/use-dynamic-status'; import { formatDate, formatObsValue, isDurationMetric } from '@/lib/utils'; import { TestTubes, Droplets, Activity, Microscope, FlaskConical, Dna, Download } from 'lucide-react'; import { Button } from '@/components/button'; @@ -18,6 +19,7 @@ function formatMetricName(code: string) { } export default function LabsPage() { + const { getStatus, isAbnormal: isObsAbnormal } = useDynamicStatus(); const { data, isLoading } = trpc.observations.list.useQuery({ limit: 200 }); const { data: metricsData } = trpc.metrics.list.useQuery(); const precisionMap = new Map( @@ -75,7 +77,7 @@ export default function LabsPage() { ); const latest = sorted[0]!; const previous = sorted[1]; - const status = deriveStatus(latest); + const status = getStatus(latest); const sparkData = sorted.slice(0, 6).reverse().map((o) => o.valueNumeric ?? 0); const deltaVal = @@ -131,7 +133,7 @@ export default function LabsPage() { o.unit, o.referenceRangeLow, o.referenceRangeHigh, - o.isAbnormal ? 'Yes' : 'No', + isObsAbnormal(o) ? 'Yes' : 'No', new Date(o.observedAt).toISOString().split('T')[0], o.category, ]), diff --git a/apps/web/hooks/use-dynamic-status.ts b/apps/web/hooks/use-dynamic-status.ts new file mode 100644 index 0000000..fa7a060 --- /dev/null +++ b/apps/web/hooks/use-dynamic-status.ts @@ -0,0 +1,88 @@ +import { useMemo } from 'react'; +import { trpc } from '@/lib/trpc/client'; +import { + deriveStatus, + isValueAbnormal, + type CanonicalRanges, +} from '@/lib/health-utils'; +import type { HealthStatus } from '@/components/health/status-badge'; + +/** + * Hook that provides dynamic health status calculations using current optimal + * and reference ranges. Replaces static `obs.isAbnormal` and bare `deriveStatus(obs)` + * calls so that changes to ranges update the UI instantly. + */ +export function useDynamicStatus() { + const { data: metricsData, isLoading: metricsLoading } = + trpc.metrics.list.useQuery(); + const { data: optimalRangesData, isLoading: optimalLoading } = + trpc.optimalRanges.forUser.useQuery(); + + const isLoading = metricsLoading || optimalLoading; + + const rangesMap = useMemo(() => { + const map = new Map(); + const metricDefs = metricsData ?? []; + + // Seed from metric definitions (reference ranges) + for (const def of metricDefs) { + map.set(def.id, { + optimalLow: optimalRangesData?.[def.id]?.rangeLow ?? null, + optimalHigh: optimalRangesData?.[def.id]?.rangeHigh ?? null, + referenceLow: def.referenceRangeLow ?? null, + referenceHigh: def.referenceRangeHigh ?? null, + }); + } + + // Include optimal ranges for metrics not in definitions + if (optimalRangesData) { + for (const code of Object.keys(optimalRangesData)) { + if (!map.has(code)) { + map.set(code, { + optimalLow: optimalRangesData[code]?.rangeLow ?? null, + optimalHigh: optimalRangesData[code]?.rangeHigh ?? null, + referenceLow: null, + referenceHigh: null, + }); + } + } + } + + return map; + }, [metricsData, optimalRangesData]); + + /** Derive the display HealthStatus for an observation. */ + function getStatus(obs: { + metricCode: string; + valueNumeric?: number | null; + isAbnormal?: boolean | null; + referenceRangeLow?: number | null; + referenceRangeHigh?: number | null; + }): HealthStatus { + const ranges = rangesMap.get(obs.metricCode); + return deriveStatus(obs, ranges); + } + + /** Check whether an observation value is abnormal (true/false/null). */ + function isAbnormal(obs: { + metricCode: string; + valueNumeric?: number | null; + isAbnormal?: boolean | null; + referenceRangeLow?: number | null; + referenceRangeHigh?: number | null; + }): boolean | null { + const ranges = rangesMap.get(obs.metricCode); + if (ranges) { + return isValueAbnormal(obs.valueNumeric, ranges); + } + // Fall back to stored value when no ranges available + return obs.isAbnormal ?? null; + } + + /** Get the canonical ranges for a specific metric code. */ + function getRanges(metricCode: string): CanonicalRanges | undefined { + return rangesMap.get(metricCode); + } + + return { getStatus, isAbnormal, getRanges, isLoading }; +} diff --git a/apps/web/lib/health-utils.ts b/apps/web/lib/health-utils.ts index f6d2f08..dc3d742 100644 --- a/apps/web/lib/health-utils.ts +++ b/apps/web/lib/health-utils.ts @@ -1,20 +1,71 @@ import type { HealthStatus } from "@/components/health/status-badge"; -export function deriveStatus(obs: { - isAbnormal?: boolean | null; - referenceRangeLow?: number | null; - referenceRangeHigh?: number | null; - valueNumeric?: number | null; -}): HealthStatus { - if (obs.isAbnormal === true) { - if ( - obs.valueNumeric != null && - obs.referenceRangeLow != null && - obs.referenceRangeHigh != null - ) { - const distFromLow = obs.referenceRangeLow - obs.valueNumeric; - const distFromHigh = obs.valueNumeric - obs.referenceRangeHigh; - const rangeSpan = obs.referenceRangeHigh - obs.referenceRangeLow; +/** + * Canonical ranges for dynamic abnormality calculation. + * Priority: optimal range > reference range from metric definition. + */ +export interface CanonicalRanges { + optimalLow?: number | null; + optimalHigh?: number | null; + referenceLow?: number | null; + referenceHigh?: number | null; +} + +/** + * Dynamically compute whether an observation is abnormal using current ranges. + * Uses optimal range first; falls back to metric definition reference range. + * This is computed at display time so changes to ranges update instantly. + */ +export function isValueAbnormal( + value: number | null | undefined, + ranges: CanonicalRanges, +): boolean | null { + if (value == null) return null; + + // Priority 1: optimal range + const low = ranges.optimalLow ?? ranges.referenceLow; + const high = ranges.optimalHigh ?? ranges.referenceHigh; + + if (low == null && high == null) return null; + if (low != null && value < low) return true; + if (high != null && value > high) return true; + return false; +} + +/** + * Derive display status from an observation. + * When canonicalRanges are provided, computes dynamically (ignoring stored isAbnormal). + * Falls back to stored isAbnormal when no canonical ranges available. + */ +export function deriveStatus( + obs: { + isAbnormal?: boolean | null; + referenceRangeLow?: number | null; + referenceRangeHigh?: number | null; + valueNumeric?: number | null; + }, + canonicalRanges?: CanonicalRanges, +): HealthStatus { + // Dynamic calculation when ranges are provided + const abnormal = canonicalRanges + ? isValueAbnormal(obs.valueNumeric, canonicalRanges) + : obs.isAbnormal; + + if (abnormal === true) { + // Determine severity using the active range + const low = + canonicalRanges?.optimalLow ?? + canonicalRanges?.referenceLow ?? + obs.referenceRangeLow; + const high = + canonicalRanges?.optimalHigh ?? + canonicalRanges?.referenceHigh ?? + obs.referenceRangeHigh; + + if (obs.valueNumeric != null && low != null && high != null) { + const distFromLow = low - obs.valueNumeric; + const distFromHigh = obs.valueNumeric - high; + const rangeSpan = high - low; if ( rangeSpan > 0 && (distFromLow > rangeSpan * 0.5 || distFromHigh > rangeSpan * 0.5) @@ -48,6 +99,35 @@ export function formatRelativeTime(date: Date | string): string { }); } +/** + * Determine if a trend delta represents improvement based on optimal range bounds. + * - Only high bound (LDL < 70): lower is better → decrease = improving + * - Only low bound (HDL > 50): higher is better → increase = improving + * - Both bounds (glucose 72–85): moving toward center = improving + * - No range: can't determine → null + */ +export function isTrendImproving( + delta: number, + ranges: CanonicalRanges | undefined, + currentValue: number, +): boolean | null { + if (!ranges || delta === 0) return null; + + const low = ranges.optimalLow ?? ranges.referenceLow ?? null; + const high = ranges.optimalHigh ?? ranges.referenceHigh ?? null; + const hasLow = low != null; + const hasHigh = high != null; + + if (hasHigh && !hasLow) return delta < 0; + if (hasLow && !hasHigh) return delta > 0; + if (hasLow && hasHigh && low != null && high != null) { + const center = (low + high) / 2; + const prevValue = currentValue / (1 + delta / 100); + return Math.abs(currentValue - center) < Math.abs(prevValue - center); + } + return null; +} + export type OptimalStatus = "optimal" | "suboptimal" | "unknown"; export function deriveOptimalStatus(obs: { diff --git a/apps/web/lib/panel-config.ts b/apps/web/lib/panel-config.ts new file mode 100644 index 0000000..646fab8 --- /dev/null +++ b/apps/web/lib/panel-config.ts @@ -0,0 +1,110 @@ +export interface MetricDef { + code: string; + aliases?: string[]; + reason: string; +} + +export interface PanelDef { + id: string; + label: string; + metrics: MetricDef[]; +} + +export const PANELS: PanelDef[] = [ + { + id: "metabolic", + label: "Metabolic", + metrics: [ + { + code: "glucose", + reason: "Fasting blood sugar — key marker for diabetes risk", + }, + { + code: "hba1c", + reason: + "3-month blood sugar average — gold standard for metabolic health", + }, + { + code: "insulin", + reason: "Fasting insulin — early warning for insulin resistance", + }, + { + code: "homa_ir", + reason: "Insulin resistance index — calculated from glucose + insulin", + }, + ], + }, + { + id: "lipid", + label: "Lipid Panel", + metrics: [ + { + code: "ldl_cholesterol", + reason: "LDL cholesterol — primary target for cardiovascular risk", + }, + { + code: "total_cholesterol", + reason: "Total cholesterol — overview of lipid levels", + }, + { + code: "hdl_cholesterol", + reason: "HDL (good) cholesterol — higher is protective", + }, + { + code: "triglycerides", + reason: + "Triglycerides — marker for metabolic and cardiovascular health", + }, + { + code: "apolipoprotein_b", + reason: "ApoB — most accurate predictor of cardiovascular risk", + }, + ], + }, + { + id: "inflammation", + label: "Inflammation", + metrics: [ + { + code: "crp", + reason: "C-reactive protein — systemic inflammation marker", + }, + { + code: "homocysteine", + reason: + "Homocysteine — linked to cardiovascular and neurodegenerative risk", + }, + ], + }, + { + id: "thyroid", + label: "Thyroid", + metrics: [ + { code: "tsh", reason: "TSH — primary thyroid function screening" }, + { code: "free_t3", reason: "Free T3 — active thyroid hormone" }, + { code: "free_t4", reason: "Free T4 — thyroid hormone production" }, + { + code: "tpo_antibodies", + reason: "TPO antibodies — autoimmune thyroid marker", + }, + ], + }, + { + id: "vitamins", + label: "Vitamins & Minerals", + metrics: [ + { + code: "vitamin_d", + reason: "Vitamin D — immune function, bone health, mood", + }, + { code: "vitamin_b12", reason: "B12 — energy, neurological function" }, + { code: "ferritin", reason: "Ferritin — iron stores, fatigue marker" }, + { code: "iron", reason: "Serum iron — oxygen transport, energy" }, + { + code: "magnesium", + reason: "Magnesium — involved in 300+ enzymatic reactions", + }, + { code: "zinc", reason: "Zinc — immune function, wound healing" }, + ], + }, +]; diff --git a/apps/web/server/trpc/routers/observations.ts b/apps/web/server/trpc/routers/observations.ts index 06c293e..0a6015e 100644 --- a/apps/web/server/trpc/routers/observations.ts +++ b/apps/web/server/trpc/routers/observations.ts @@ -1,20 +1,28 @@ -import { z } from 'zod'; -import { TRPCError } from '@trpc/server'; -import { eq, and, ne } from 'drizzle-orm'; -import { createRouter, protectedProcedure } from '../init'; -import { listObservations, getObservationTrend, getObservationWithProvenance, observations, importJobs } from '@openvitals/database'; +import { z } from "zod"; +import { TRPCError } from "@trpc/server"; +import { eq, and, ne } from "drizzle-orm"; +import { createRouter, protectedProcedure } from "../init"; +import { + listObservations, + getObservationTrend, + getObservationWithProvenance, + observations, + importJobs, +} from "@openvitals/database"; export const observationsRouter = createRouter({ list: protectedProcedure - .input(z.object({ - category: z.string().optional(), - metricCode: z.string().optional(), - dateFrom: z.date().optional(), - dateTo: z.date().optional(), - status: z.string().optional(), - limit: z.number().min(1).max(200).default(50), - cursor: z.string().optional(), - })) + .input( + z.object({ + category: z.string().optional(), + metricCode: z.string().optional(), + dateFrom: z.date().optional(), + dateTo: z.date().optional(), + status: z.string().optional(), + limit: z.number().min(1).max(1000).default(50), + cursor: z.string().optional(), + }), + ) .query(async ({ ctx, input }) => { const offset = input.cursor ? parseInt(input.cursor, 10) : 0; const items = await listObservations(ctx.db, { @@ -38,12 +46,16 @@ export const observationsRouter = createRouter({ }), trend: protectedProcedure - .input(z.object({ - metricCode: z.string(), - dateFrom: z.date(), - dateTo: z.date(), - granularity: z.enum(['raw', 'daily', 'weekly', 'monthly']).default('raw'), - })) + .input( + z.object({ + metricCode: z.string(), + dateFrom: z.date(), + dateTo: z.date(), + granularity: z + .enum(["raw", "daily", "weekly", "monthly"]) + .default("raw"), + }), + ) .query(async ({ ctx, input }) => { const rows = await getObservationTrend(ctx.db, { userId: ctx.userId, @@ -72,14 +84,16 @@ export const observationsRouter = createRouter({ }), correct: protectedProcedure - .input(z.object({ - id: z.string().uuid(), - valueNumeric: z.number().optional(), - valueText: z.string().optional(), - metricCode: z.string().optional(), - unit: z.string().optional(), - correctionNote: z.string().optional(), - })) + .input( + z.object({ + id: z.string().uuid(), + valueNumeric: z.number().optional(), + valueText: z.string().optional(), + metricCode: z.string().optional(), + unit: z.string().optional(), + correctionNote: z.string().optional(), + }), + ) .mutation(async ({ ctx, input }) => { const { id, ...corrections } = input; @@ -87,28 +101,42 @@ export const observationsRouter = createRouter({ const [current] = await ctx.db .select() .from(observations) - .where(and(eq(observations.id, id), eq(observations.userId, ctx.userId))) + .where( + and(eq(observations.id, id), eq(observations.userId, ctx.userId)), + ) .limit(1); if (!current) { - throw new TRPCError({ code: 'NOT_FOUND', message: 'Observation not found' }); + throw new TRPCError({ + code: "NOT_FOUND", + message: "Observation not found", + }); } await ctx.db .update(observations) .set({ - ...(corrections.valueNumeric !== undefined && { valueNumeric: corrections.valueNumeric }), - ...(corrections.valueText !== undefined && { valueText: corrections.valueText }), - ...(corrections.metricCode !== undefined && { metricCode: corrections.metricCode }), + ...(corrections.valueNumeric !== undefined && { + valueNumeric: corrections.valueNumeric, + }), + ...(corrections.valueText !== undefined && { + valueText: corrections.valueText, + }), + ...(corrections.metricCode !== undefined && { + metricCode: corrections.metricCode, + }), ...(corrections.unit !== undefined && { unit: corrections.unit }), - originalValueNumeric: current.originalValueNumeric ?? current.valueNumeric, + originalValueNumeric: + current.originalValueNumeric ?? current.valueNumeric, originalValueText: current.originalValueText ?? current.valueText, originalUnit: current.originalUnit ?? current.unit, correctionNote: corrections.correctionNote, - status: 'corrected', + status: "corrected", updatedAt: new Date(), }) - .where(and(eq(observations.id, id), eq(observations.userId, ctx.userId))); + .where( + and(eq(observations.id, id), eq(observations.userId, ctx.userId)), + ); return { success: true }; }), @@ -118,12 +146,20 @@ export const observationsRouter = createRouter({ .mutation(async ({ ctx, input }) => { const result = await ctx.db .update(observations) - .set({ status: 'confirmed', updatedAt: new Date() }) - .where(and(eq(observations.id, input.id), eq(observations.userId, ctx.userId))) + .set({ status: "confirmed", updatedAt: new Date() }) + .where( + and( + eq(observations.id, input.id), + eq(observations.userId, ctx.userId), + ), + ) .returning({ importJobId: observations.importJobId }); if (!result.length) { - throw new TRPCError({ code: 'NOT_FOUND', message: 'Observation not found' }); + throw new TRPCError({ + code: "NOT_FOUND", + message: "Observation not found", + }); } // If all observations for this import job are now confirmed/corrected, mark job completed @@ -136,7 +172,7 @@ export const observationsRouter = createRouter({ and( eq(observations.importJobId, jobId), eq(observations.userId, ctx.userId), - eq(observations.status, 'extracted'), + eq(observations.status, "extracted"), ), ) .limit(1); @@ -144,11 +180,100 @@ export const observationsRouter = createRouter({ if (pending.length === 0) { await ctx.db .update(importJobs) - .set({ status: 'completed', needsReview: false, completedAt: new Date(), updatedAt: new Date() }) - .where(and(eq(importJobs.id, jobId), eq(importJobs.userId, ctx.userId))); + .set({ + status: "completed", + needsReview: false, + completedAt: new Date(), + updatedAt: new Date(), + }) + .where( + and(eq(importJobs.id, jobId), eq(importJobs.userId, ctx.userId)), + ); } } return { success: true }; }), + + delete: protectedProcedure + .input(z.object({ id: z.string().uuid() })) + .mutation(async ({ ctx, input }) => { + const result = await ctx.db + .delete(observations) + .where( + and( + eq(observations.id, input.id), + eq(observations.userId, ctx.userId), + ), + ) + .returning({ + id: observations.id, + importJobId: observations.importJobId, + }); + + if (!result.length) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Observation not found", + }); + } + + // Update extraction count on import job + const jobId = result[0]!.importJobId; + if (jobId) { + const remaining = await ctx.db + .select({ id: observations.id }) + .from(observations) + .where( + and( + eq(observations.importJobId, jobId), + eq(observations.userId, ctx.userId), + ), + ); + + await ctx.db + .update(importJobs) + .set({ extractionCount: remaining.length, updatedAt: new Date() }) + .where( + and(eq(importJobs.id, jobId), eq(importJobs.userId, ctx.userId)), + ); + } + + return { success: true }; + }), + + confirmAll: protectedProcedure + .input(z.object({ importJobId: z.string().uuid() })) + .mutation(async ({ ctx, input }) => { + // Batch confirm all extracted observations for this import job + const result = await ctx.db + .update(observations) + .set({ status: "confirmed", updatedAt: new Date() }) + .where( + and( + eq(observations.importJobId, input.importJobId), + eq(observations.userId, ctx.userId), + eq(observations.status, "extracted"), + ), + ) + .returning({ id: observations.id }); + + // Mark job completed + await ctx.db + .update(importJobs) + .set({ + status: "completed", + needsReview: false, + completedAt: new Date(), + updatedAt: new Date(), + }) + .where( + and( + eq(importJobs.id, input.importJobId), + eq(importJobs.userId, ctx.userId), + ), + ); + + return { confirmed: result.length }; + }), }); diff --git a/packages/database/drizzle/0009_purple_dragon_man.sql b/packages/database/drizzle/0009_purple_dragon_man.sql new file mode 100644 index 0000000..3ad3d6d --- /dev/null +++ b/packages/database/drizzle/0009_purple_dragon_man.sql @@ -0,0 +1,25 @@ +CREATE TABLE "flagged_extractions" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "import_job_id" uuid NOT NULL, + "user_id" text NOT NULL, + "analyte" text NOT NULL, + "value_numeric" real, + "value_text" text, + "unit" varchar(50), + "reference_range_low" real, + "reference_range_high" real, + "reference_range_text" text, + "is_abnormal" boolean, + "observed_at" date, + "flag_reason" text NOT NULL, + "flag_details" text, + "resolved" boolean DEFAULT false NOT NULL, + "resolved_metric_code" varchar(50), + "created_at" timestamp DEFAULT now() +); +--> statement-breakpoint +ALTER TABLE "users" ALTER COLUMN "ai_model" SET DEFAULT 'claude-sonnet-4';--> statement-breakpoint +ALTER TABLE "flagged_extractions" ADD CONSTRAINT "flagged_extractions_import_job_id_import_jobs_id_fk" FOREIGN KEY ("import_job_id") REFERENCES "public"."import_jobs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "flagged_extractions" ADD CONSTRAINT "flagged_extractions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "flagged_extractions" ADD CONSTRAINT "flagged_extractions_resolved_metric_code_metric_definitions_id_fk" FOREIGN KEY ("resolved_metric_code") REFERENCES "public"."metric_definitions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "idx_flagged_import_job" ON "flagged_extractions" USING btree ("import_job_id"); \ No newline at end of file diff --git a/packages/database/drizzle/0010_seed_missing_metric_data.sql b/packages/database/drizzle/0010_seed_missing_metric_data.sql new file mode 100644 index 0000000..b0a3e42 --- /dev/null +++ b/packages/database/drizzle/0010_seed_missing_metric_data.sql @@ -0,0 +1,288 @@ +-- Migration: Insert missing metric_definitions and optimal_ranges +-- These were previously only in seed data, which doesn't run on deploy. +-- All inserts are idempotent (ON CONFLICT DO NOTHING). + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 1. Deduplicate existing optimal_ranges (NULL-safe) +-- The unique constraint doesn't catch NULL age_min/age_max/sex duplicates. +-- Keep only the row with the lowest id for each logical group. +-- ══════════════════════════════════════════════════════════════════════════════ + +DELETE FROM optimal_ranges +WHERE id NOT IN ( + SELECT MIN(id) + FROM optimal_ranges + GROUP BY metric_code, COALESCE(sex, '__null__'), COALESCE(age_min, -1), COALESCE(age_max, -1) +); + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 2. Drop old unique constraint and replace with NULL-safe unique index +-- ══════════════════════════════════════════════════════════════════════════════ + +ALTER TABLE optimal_ranges DROP CONSTRAINT IF EXISTS optimal_ranges_metric_sex_age_uniq; +--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS optimal_ranges_metric_sex_age_uniq + ON optimal_ranges (metric_code, COALESCE(sex, '__null__'), COALESCE(age_min, -1), COALESCE(age_max, -1)); + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 3. Insert missing metric_definitions (alias codes for observation matching) +-- ══════════════════════════════════════════════════════════════════════════════ + +INSERT INTO metric_definitions (id, name, category, unit, loinc_code, snomed_code, aliases, reference_range_low, reference_range_high, reference_range_text, description, display_precision, sort_order) +VALUES + ('homa_ir', 'HOMA-IR', 'metabolic', '', NULL, NULL, '["HOMA IR","HOMA-IR index","homeostatic model assessment"]', NULL, 2.5, '<2.5 (optimal <1.0)', 'Insulin resistance index calculated from fasting glucose and insulin', 2, 112), + ('hba1c', 'Hemoglobin A1c', 'metabolic', '%', '4548-4', NULL, '["HbA1c","A1c","glycated hemoglobin","glycosylated hemoglobin"]', 4.0, 5.6, '4.0-5.6%', 'Hemoglobin A1c (alias for hemoglobin_a1c)', 1, 110), + ('c_reactive_protein', 'C-Reactive Protein', 'inflammation', 'mg/L', '1988-5', NULL, '["CRP","c reactive protein"]', 0, 3.0, '<3.0 mg/L', 'C-Reactive Protein (alias for crp)', 1, 46), + ('apolipoprotein_b', 'Apolipoprotein B', 'lipid', 'mg/dL', '1884-6', NULL, '["ApoB","Apo B","apolipoprotein B-100"]', 40, 120, '40-120 mg/dL', 'Apolipoprotein B (alias for apob)', 0, 35), + ('total_cholesterol', 'Cholesterol, Total', 'lipid', 'mg/dL', '2093-3', NULL, '["total cholesterol","cholesterol total"]', 0, 200, '<200 mg/dL', 'Total Cholesterol (alias for cholesterol_total)', 0, 30), + ('25_hydroxyvitamin_d', '25-Hydroxyvitamin D', 'vitamin', 'ng/mL', '1989-3', NULL, '["25-OH vitamin D","25-hydroxyvitamin D"]', 30, 100, '30-100 ng/mL', '25-Hydroxyvitamin D (alias for vitamin_d)', 1, 60), + ('vitamin_d_25_hydroxyvitamin_d', '25-Hydroxyvitamin D', 'vitamin', 'ng/mL', '1989-3', NULL, '["vitamin D 25-hydroxy"]', 30, 100, '30-100 ng/mL', '25-Hydroxyvitamin D (alias for vitamin_d)', 1, 60), + -- Calculated/derived metric definitions + ('cholesterol_hdl_ratio', 'Cholesterol/HDL Ratio', 'lipid', '', NULL, NULL, '["total cholesterol to HDL ratio","TC/HDL"]', NULL, 5.0, '<5.0 (optimal <3.5)', 'Ratio of total cholesterol to HDL cholesterol', 1, 36), + ('triglyceride_hdl_ratio', 'Triglyceride/HDL Ratio', 'lipid', '', NULL, NULL, '["TG/HDL ratio","triglyceride HDL ratio"]', NULL, 2.0, '<2.0 (optimal <1.0)', 'Ratio of triglycerides to HDL cholesterol — insulin resistance marker', 1, 37), + ('non_hdl_cholesterol', 'Non-HDL Cholesterol', 'lipid', 'mg/dL', NULL, NULL, '["non HDL","non-HDL"]', NULL, 130, '<130 mg/dL', 'Total cholesterol minus HDL cholesterol', 0, 38) +ON CONFLICT (id) DO NOTHING; + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 4. Insert missing optimal_ranges +-- ══════════════════════════════════════════════════════════════════════════════ + +-- Metabolic +INSERT INTO optimal_ranges (metric_code, sex, age_min, age_max, range_low, range_high, range_text, source, source_url) +VALUES + ('glucose', NULL, 18, NULL, 72, 85, '72–85 mg/dL', 'Attia/Outlive', NULL), + ('hemoglobin_a1c', NULL, 18, NULL, 4.0, 5.2, '4.0–5.2%', 'Attia/Function Health', NULL), + ('insulin', NULL, 18, NULL, 2.0, 5.0, '2.0–5.0 µIU/mL', 'Attia/Outlive', NULL), + ('homa_ir', NULL, 18, NULL, 0, 1.0, '<1.0', 'Attia/Outlive', NULL), + ('hba1c', NULL, 18, NULL, 4.0, 5.2, '4.0–5.2%', 'Attia/Function Health', NULL), + + -- Inflammation + ('hs_crp', NULL, 18, NULL, 0, 1.0, '<1.0 mg/L', 'AHA/Attia', NULL), + ('crp', NULL, 18, NULL, 0, 1.0, '<1.0 mg/L', 'AHA/Attia', NULL), + ('c_reactive_protein', NULL, 18, NULL, 0, 1.0, '<1.0 mg/L', 'AHA/Attia', NULL), + ('homocysteine', NULL, 18, NULL, 5, 10, '5–10 µmol/L', 'Attia/Function Health', NULL), + + -- Lipids + ('ldl_cholesterol', NULL, 18, NULL, 0, 70, '<70 mg/dL', 'AHA/Attia', NULL), + ('hdl_cholesterol', 'male', 18, NULL, 50, 90, '50–90 mg/dL', 'Function Health', NULL), + ('hdl_cholesterol', 'female', 18, NULL, 60, 90, '60–90 mg/dL', 'Function Health', NULL), + ('triglycerides', NULL, 18, NULL, 0, 100, '<100 mg/dL', 'Attia/Outlive', NULL), + ('cholesterol_total', NULL, 18, NULL, 0, 180, '<180 mg/dL', 'AHA', NULL), + ('apolipoprotein_b', NULL, 18, NULL, 0, 80, '<80 mg/dL', 'Attia/AHA', NULL), + ('total_cholesterol', NULL, 18, NULL, 0, 180, '<180 mg/dL', 'AHA', NULL), + + -- Vitamins & Minerals + ('vitamin_d', NULL, 18, NULL, 40, 60, '40–60 ng/mL', 'Huberman/Function Health', NULL), + ('25_hydroxyvitamin_d', NULL, 18, NULL, 40, 60, '40–60 ng/mL', 'Huberman/Function Health', NULL), + ('vitamin_d_25_hydroxyvitamin_d', NULL, 18, NULL, 40, 60, '40–60 ng/mL', 'Huberman/Function Health', NULL), + ('vitamin_b12', NULL, 18, NULL, 500, 900, '500–900 pg/mL', 'Function Health', NULL), + ('folate', NULL, 18, NULL, 10, 17, '10–17 ng/mL', 'Function Health', NULL), + ('iron', 'male', 18, NULL, 60, 170, '60–170 µg/dL', 'Function Health', NULL), + ('iron', 'female', 18, NULL, 50, 150, '50–150 µg/dL', 'Function Health', NULL), + ('magnesium', NULL, 18, NULL, 2.0, 2.5, '2.0–2.5 mg/dL', 'Function Health', NULL), + ('zinc', NULL, 18, NULL, 0.7, 1.2, '0.7–1.2 mg/L', 'Function Health', NULL), + ('ferritin', 'male', 18, NULL, 40, 150, '40–150 ng/mL', 'Attia', NULL), + ('ferritin', 'female', 18, NULL, 40, 100, '40–100 ng/mL', 'Attia', NULL), + + -- Thyroid + ('tsh', NULL, 18, NULL, 0.5, 2.5, '0.5–2.5 mIU/L', 'Functional medicine consensus', NULL), + ('free_t4', NULL, 18, NULL, 1.0, 1.5, '1.0–1.5 ng/dL', 'Functional medicine', NULL), + ('free_t3', NULL, 18, NULL, 3.0, 4.0, '3.0–4.0 pg/mL', 'Functional medicine', NULL), + ('tpo_antibodies', NULL, 18, NULL, 0, 9, '<9 IU/mL', 'Functional medicine', NULL), + + -- Hematology + ('hemoglobin', 'male', 18, NULL, 14.0, 16.5, '14.0–16.5 g/dL', 'Function Health', NULL), + ('hemoglobin', 'female', 18, NULL, 12.5, 15.0, '12.5–15.0 g/dL', 'Function Health', NULL), + + -- Hormones + ('testosterone_total', 'male', 18, NULL, 500, 900, '500–900 ng/dL', 'Attia/Huberman', NULL), + ('testosterone_total', 'female', 18, NULL, 30, 60, '30–60 ng/dL', 'Function Health', NULL), + ('dhea_s', 'male', 18, 39, 350, 500, '350–500 µg/dL', 'Functional medicine', NULL), + ('dhea_s', 'male', 40, NULL, 200, 400, '200–400 µg/dL', 'Functional medicine', NULL), + ('dhea_s', 'female', 18, 39, 150, 300, '150–300 µg/dL', 'Functional medicine', NULL), + ('dhea_s', 'female', 40, NULL, 80, 200, '80–200 µg/dL', 'Functional medicine', NULL), + + -- Liver + ('alt', NULL, 18, NULL, 7, 25, '7–25 U/L', 'Attia/Function Health', NULL), + ('ast', NULL, 18, NULL, 10, 25, '10–25 U/L', 'Attia/Function Health', NULL), + ('ggt', NULL, 18, NULL, 9, 25, '9–25 U/L', 'Attia', NULL), + ('albumin', NULL, 18, NULL, 4.2, 5.0, '4.2–5.0 g/dL', 'Function Health', NULL), + + -- Kidney + ('creatinine', 'male', 18, NULL, 0.8, 1.1, '0.8–1.1 mg/dL', 'Function Health', NULL), + ('creatinine', 'female', 18, NULL, 0.6, 0.9, '0.6–0.9 mg/dL', 'Function Health', NULL), + ('egfr', NULL, 18, NULL, 90, NULL, '>90 mL/min', 'Longevity consensus', NULL), + + -- Vitals + ('heart_rate', NULL, 18, NULL, 50, 65, '50–65 bpm', 'Attia/Huberman', NULL), + ('bp_systolic', NULL, 18, NULL, 100, 115, '100–115 mmHg', 'Attia', NULL), + ('bp_diastolic', NULL, 18, NULL, 65, 75, '65–75 mmHg', 'Attia', NULL), + + -- Other + ('uric_acid', 'male', 18, NULL, 3.5, 5.5, '3.5–5.5 mg/dL', 'Attia', NULL), + ('uric_acid', 'female', 18, NULL, 2.5, 4.5, '2.5–4.5 mg/dL', 'Attia', NULL), + ('bmi', NULL, 18, NULL, 18.5, 23.0, '18.5–23.0', 'Attia', NULL), + + -- Calculated/derived metrics + ('cholesterol_hdl_ratio', NULL, 18, NULL, 0, 3.5, '<3.5', 'AHA/Attia', NULL), + ('triglyceride_hdl_ratio', NULL, 18, NULL, 0, 1.0, '<1.0', 'Attia/Outlive', NULL), + ('non_hdl_cholesterol', NULL, 18, NULL, 0, 130, '<130 mg/dL', 'AHA', NULL) +ON CONFLICT DO NOTHING; + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 5. Backfill calculated/derived biomarkers from existing observations +-- Pairs inputs by SAME observation date (same lab draw). +-- For each date where a user has ALL required inputs, compute the derived metric. +-- Only inserts if no calculated observation already exists for that user+metric+date. +-- ══════════════════════════════════════════════════════════════════════════════ + +-- HOMA-IR = (glucose × insulin) / 405 +-- Computed for each date where both glucose AND insulin were tested. +INSERT INTO observations ( + user_id, metric_code, category, value_numeric, value_text, unit, + status, confidence_score, observed_at, metadata_json +) +SELECT + g.user_id, + 'homa_ir', + 'metabolic', + ROUND(CAST((g.value_numeric * i.value_numeric) / 405.0 AS numeric), 2)::real, + ROUND(CAST((g.value_numeric * i.value_numeric) / 405.0 AS numeric), 2)::text, + '', + 'confirmed', + 1.0, + g.observed_at, + jsonb_build_object( + 'source', 'calculated', + 'formula', 'homa_ir', + 'formulaText', '(glucose × insulin) / 405', + 'inputs', jsonb_build_object('glucose', g.value_numeric, 'insulin', i.value_numeric) + ) +FROM observations g +JOIN observations i + ON g.user_id = i.user_id + AND g.observed_at = i.observed_at + AND i.metric_code = 'insulin' + AND i.value_numeric IS NOT NULL + AND i.value_numeric > 0 +WHERE g.metric_code = 'glucose' + AND g.value_numeric IS NOT NULL + AND g.value_numeric > 0 + AND NOT EXISTS ( + SELECT 1 FROM observations ex + WHERE ex.user_id = g.user_id + AND ex.metric_code = 'homa_ir' + AND ex.observed_at = g.observed_at + ); + +-- Triglyceride/HDL Ratio = triglycerides / HDL cholesterol +-- Computed for each date where both were tested. +INSERT INTO observations ( + user_id, metric_code, category, value_numeric, value_text, unit, + status, confidence_score, observed_at, metadata_json +) +SELECT + t.user_id, + 'triglyceride_hdl_ratio', + 'lipid', + ROUND(CAST(t.value_numeric / h.value_numeric AS numeric), 1)::real, + ROUND(CAST(t.value_numeric / h.value_numeric AS numeric), 1)::text, + '', + 'confirmed', + 1.0, + t.observed_at, + jsonb_build_object( + 'source', 'calculated', + 'formula', 'triglyceride_hdl_ratio', + 'formulaText', 'triglycerides / HDL cholesterol', + 'inputs', jsonb_build_object('triglycerides', t.value_numeric, 'hdl_cholesterol', h.value_numeric) + ) +FROM observations t +JOIN observations h + ON t.user_id = h.user_id + AND t.observed_at = h.observed_at + AND h.metric_code = 'hdl_cholesterol' + AND h.value_numeric IS NOT NULL + AND h.value_numeric > 0 +WHERE t.metric_code = 'triglycerides' + AND t.value_numeric IS NOT NULL + AND NOT EXISTS ( + SELECT 1 FROM observations ex + WHERE ex.user_id = t.user_id + AND ex.metric_code = 'triglyceride_hdl_ratio' + AND ex.observed_at = t.observed_at + ); + +-- Cholesterol/HDL Ratio = total_cholesterol / HDL cholesterol +INSERT INTO observations ( + user_id, metric_code, category, value_numeric, value_text, unit, + status, confidence_score, observed_at, metadata_json +) +SELECT + c.user_id, + 'cholesterol_hdl_ratio', + 'lipid', + ROUND(CAST(c.value_numeric / h.value_numeric AS numeric), 1)::real, + ROUND(CAST(c.value_numeric / h.value_numeric AS numeric), 1)::text, + '', + 'confirmed', + 1.0, + c.observed_at, + jsonb_build_object( + 'source', 'calculated', + 'formula', 'cholesterol_hdl_ratio', + 'formulaText', 'total cholesterol / HDL cholesterol', + 'inputs', jsonb_build_object('cholesterol_total', c.value_numeric, 'hdl_cholesterol', h.value_numeric) + ) +FROM observations c +JOIN observations h + ON c.user_id = h.user_id + AND c.observed_at = h.observed_at + AND h.metric_code = 'hdl_cholesterol' + AND h.value_numeric IS NOT NULL + AND h.value_numeric > 0 +WHERE c.metric_code IN ('cholesterol_total', 'total_cholesterol') + AND c.value_numeric IS NOT NULL + AND NOT EXISTS ( + SELECT 1 FROM observations ex + WHERE ex.user_id = c.user_id + AND ex.metric_code = 'cholesterol_hdl_ratio' + AND ex.observed_at = c.observed_at + ); + +-- Non-HDL Cholesterol = total_cholesterol - HDL cholesterol +INSERT INTO observations ( + user_id, metric_code, category, value_numeric, value_text, unit, + status, confidence_score, observed_at, metadata_json +) +SELECT + c.user_id, + 'non_hdl_cholesterol', + 'lipid', + ROUND(CAST(c.value_numeric - h.value_numeric AS numeric), 0)::real, + ROUND(CAST(c.value_numeric - h.value_numeric AS numeric), 0)::text, + 'mg/dL', + 'confirmed', + 1.0, + c.observed_at, + jsonb_build_object( + 'source', 'calculated', + 'formula', 'non_hdl_cholesterol', + 'formulaText', 'total cholesterol − HDL cholesterol', + 'inputs', jsonb_build_object('cholesterol_total', c.value_numeric, 'hdl_cholesterol', h.value_numeric) + ) +FROM observations c +JOIN observations h + ON c.user_id = h.user_id + AND c.observed_at = h.observed_at + AND h.metric_code = 'hdl_cholesterol' + AND h.value_numeric IS NOT NULL + AND h.value_numeric > 0 +WHERE c.metric_code IN ('cholesterol_total', 'total_cholesterol') + AND c.value_numeric IS NOT NULL + AND NOT EXISTS ( + SELECT 1 FROM observations ex + WHERE ex.user_id = c.user_id + AND ex.metric_code = 'non_hdl_cholesterol' + AND ex.observed_at = c.observed_at + ); diff --git a/packages/database/drizzle/0011_consolidate_metric_codes.sql b/packages/database/drizzle/0011_consolidate_metric_codes.sql new file mode 100644 index 0000000..3b7984f --- /dev/null +++ b/packages/database/drizzle/0011_consolidate_metric_codes.sql @@ -0,0 +1,77 @@ +-- Migration: Consolidate duplicate metric codes to canonical forms +-- Problem: The normalizer sometimes creates observations with different codes +-- for the same biomarker (e.g., 'hemoglobin_a1c' vs 'hba1c'). This causes +-- the labs detail page to show empty when navigating from panel cards. +-- +-- Canonical codes chosen for readability and consistency with panel-config: +-- hemoglobin_a1c → hba1c +-- cholesterol_total → total_cholesterol +-- apob → apolipoprotein_b +-- hs_crp, c_reactive_protein → crp +-- 25_hydroxyvitamin_d, vitamin_d_25_hydroxyvitamin_d → vitamin_d +-- +-- All UPDATEs are safe — they only rename the metric_code, no data loss. + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 1. Consolidate observation metric codes +-- ══════════════════════════════════════════════════════════════════════════════ + +UPDATE observations SET metric_code = 'hba1c' + WHERE metric_code = 'hemoglobin_a1c'; +--> statement-breakpoint +UPDATE observations SET metric_code = 'total_cholesterol' + WHERE metric_code = 'cholesterol_total'; +--> statement-breakpoint +UPDATE observations SET metric_code = 'apolipoprotein_b' + WHERE metric_code = 'apob'; +--> statement-breakpoint +UPDATE observations SET metric_code = 'crp' + WHERE metric_code IN ('hs_crp', 'c_reactive_protein'); +--> statement-breakpoint +UPDATE observations SET metric_code = 'vitamin_d' + WHERE metric_code IN ('25_hydroxyvitamin_d', 'vitamin_d_25_hydroxyvitamin_d'); + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 2. Consolidate calculated observations (from migration 0010) +-- ══════════════════════════════════════════════════════════════════════════════ + +-- The cholesterol_hdl_ratio uses total_cholesterol as input — re-point any +-- that were computed from cholesterol_total observations. +-- (No metric_code rename needed for calculated metrics — they already use +-- canonical codes like 'cholesterol_hdl_ratio', 'triglyceride_hdl_ratio', etc.) + +-- ══════════════════════════════════════════════════════════════════════════════ +-- 3. Update optimal_ranges to ensure canonical codes have entries +-- The old aliases still have optimal_range rows (from migration 0010). +-- Copy ranges to canonical codes if they don't already exist. +-- ══════════════════════════════════════════════════════════════════════════════ + +-- hba1c should have an optimal range (may already exist from migration 0010) +INSERT INTO optimal_ranges (metric_code, sex, age_min, age_max, range_low, range_high, range_text, source, source_url) +SELECT 'hba1c', sex, age_min, age_max, range_low, range_high, range_text, source, source_url +FROM optimal_ranges WHERE metric_code = 'hemoglobin_a1c' +ON CONFLICT DO NOTHING; + +-- vitamin_d should have an optimal range +INSERT INTO optimal_ranges (metric_code, sex, age_min, age_max, range_low, range_high, range_text, source, source_url) +SELECT 'vitamin_d', sex, age_min, age_max, range_low, range_high, range_text, source, source_url +FROM optimal_ranges WHERE metric_code = '25_hydroxyvitamin_d' +ON CONFLICT DO NOTHING; + +-- apolipoprotein_b should have an optimal range +INSERT INTO optimal_ranges (metric_code, sex, age_min, age_max, range_low, range_high, range_text, source, source_url) +SELECT 'apolipoprotein_b', sex, age_min, age_max, range_low, range_high, range_text, source, source_url +FROM optimal_ranges WHERE metric_code = 'apob' +ON CONFLICT DO NOTHING; + +-- total_cholesterol should have an optimal range (from cholesterol_total) +INSERT INTO optimal_ranges (metric_code, sex, age_min, age_max, range_low, range_high, range_text, source, source_url) +SELECT 'total_cholesterol', sex, age_min, age_max, range_low, range_high, range_text, source, source_url +FROM optimal_ranges WHERE metric_code = 'cholesterol_total' +ON CONFLICT DO NOTHING; + +-- crp should have an optimal range (from hs_crp) +INSERT INTO optimal_ranges (metric_code, sex, age_min, age_max, range_low, range_high, range_text, source, source_url) +SELECT 'crp', sex, age_min, age_max, range_low, range_high, range_text, source, source_url +FROM optimal_ranges WHERE metric_code = 'hs_crp' +ON CONFLICT DO NOTHING; diff --git a/packages/database/drizzle/meta/0009_snapshot.json b/packages/database/drizzle/meta/0009_snapshot.json new file mode 100644 index 0000000..c99e6f6 --- /dev/null +++ b/packages/database/drizzle/meta/0009_snapshot.json @@ -0,0 +1,3534 @@ +{ + "id": "14b23a3d-57a0-4381-8232-3f1adff69fbb", + "prevId": "3478346f-4511-4d9f-8b38-caab54d01a97", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_user_id_users_id_fk": { + "name": "accounts_user_id_users_id_fk", + "tableFrom": "accounts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sessions_token_unique": { + "name": "sessions_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "timezone": { + "name": "timezone", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'UTC'" + }, + "preferred_units": { + "name": "preferred_units", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'metric'" + }, + "ai_model": { + "name": "ai_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "default": "'claude-sonnet-4'" + }, + "date_of_birth": { + "name": "date_of_birth", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "biological_sex": { + "name": "biological_sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "blood_type": { + "name": "blood_type", + "type": "varchar(5)", + "primaryKey": false, + "notNull": false + }, + "show_optimal_ranges": { + "name": "show_optimal_ranges", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "onboarding_step": { + "name": "onboarding_step", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verifications": { + "name": "verifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_sources": { + "name": "data_sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "data_sources_user_id_users_id_fk": { + "name": "data_sources_user_id_users_id_fk", + "tableFrom": "data_sources", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_jobs": { + "name": "import_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "classified_type": { + "name": "classified_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "classification_confidence": { + "name": "classification_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "parser_id": { + "name": "parser_id", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "parser_version": { + "name": "parser_version", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "extraction_count": { + "name": "extraction_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "needs_review": { + "name": "needs_review", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_detail_json": { + "name": "error_detail_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "classify_completed_at": { + "name": "classify_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "parse_completed_at": { + "name": "parse_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "normalize_completed_at": { + "name": "normalize_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "import_jobs_user_id_users_id_fk": { + "name": "import_jobs_user_id_users_id_fk", + "tableFrom": "import_jobs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "import_jobs_source_artifact_id_source_artifacts_id_fk": { + "name": "import_jobs_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "import_jobs", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.source_artifacts": { + "name": "source_artifacts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "blob_path": { + "name": "blob_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "raw_text_extracted": { + "name": "raw_text_extracted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "classified_type": { + "name": "classified_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "classification_confidence": { + "name": "classification_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "source_artifacts_user_id_users_id_fk": { + "name": "source_artifacts_user_id_users_id_fk", + "tableFrom": "source_artifacts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "source_artifacts_data_source_id_data_sources_id_fk": { + "name": "source_artifacts_data_source_id_data_sources_id_fk", + "tableFrom": "source_artifacts", + "tableTo": "data_sources", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "source_artifacts_user_content_hash_uniq": { + "name": "source_artifacts_user_content_hash_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "content_hash" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.flagged_extractions": { + "name": "flagged_extractions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "analyte": { + "name": "analyte", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value_numeric": { + "name": "value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "value_text": { + "name": "value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_abnormal": { + "name": "is_abnormal", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "observed_at": { + "name": "observed_at", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "flag_reason": { + "name": "flag_reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flag_details": { + "name": "flag_details", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resolved": { + "name": "resolved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "resolved_metric_code": { + "name": "resolved_metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_flagged_import_job": { + "name": "idx_flagged_import_job", + "columns": [ + { + "expression": "import_job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "flagged_extractions_import_job_id_import_jobs_id_fk": { + "name": "flagged_extractions_import_job_id_import_jobs_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "flagged_extractions_user_id_users_id_fk": { + "name": "flagged_extractions_user_id_users_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "flagged_extractions_resolved_metric_code_metric_definitions_id_fk": { + "name": "flagged_extractions_resolved_metric_code_metric_definitions_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "metric_definitions", + "columnsFrom": [ + "resolved_metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.observations": { + "name": "observations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "value_numeric": { + "name": "value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "value_text": { + "name": "value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_abnormal": { + "name": "is_abnormal", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'extracted'" + }, + "confidence_score": { + "name": "confidence_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "observed_at": { + "name": "observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "reported_at": { + "name": "reported_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "original_value_numeric": { + "name": "original_value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_value_text": { + "name": "original_value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_unit": { + "name": "original_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "correction_note": { + "name": "correction_note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "observations_user_category_idx": { + "name": "observations_user_category_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "observations_user_metric_observed_idx": { + "name": "observations_user_metric_observed_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "observations_user_observed_idx": { + "name": "observations_user_observed_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "observations_user_id_users_id_fk": { + "name": "observations_user_id_users_id_fk", + "tableFrom": "observations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "observations_data_source_id_data_sources_id_fk": { + "name": "observations_data_source_id_data_sources_id_fk", + "tableFrom": "observations", + "tableTo": "data_sources", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "observations_source_artifact_id_source_artifacts_id_fk": { + "name": "observations_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "observations", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "observations_import_job_id_import_jobs_id_fk": { + "name": "observations_import_job_id_import_jobs_id_fk", + "tableFrom": "observations", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.medication_logs": { + "name": "medication_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "medication_id": { + "name": "medication_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "log_date": { + "name": "log_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "taken": { + "name": "taken", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "time_of_day": { + "name": "time_of_day", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medication_logs_medication_id_medications_id_fk": { + "name": "medication_logs_medication_id_medications_id_fk", + "tableFrom": "medication_logs", + "tableTo": "medications", + "columnsFrom": [ + "medication_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "medication_logs_user_id_users_id_fk": { + "name": "medication_logs_user_id_users_id_fk", + "tableFrom": "medication_logs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.medications": { + "name": "medications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "generic_name": { + "name": "generic_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'prescription'" + }, + "dosage": { + "name": "dosage", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "frequency": { + "name": "frequency", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "route": { + "name": "route", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "prescriber": { + "name": "prescriber", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "indication": { + "name": "indication", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'manual'" + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medications_user_id_users_id_fk": { + "name": "medications_user_id_users_id_fk", + "tableFrom": "medications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "medications_source_artifact_id_source_artifacts_id_fk": { + "name": "medications_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "medications", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "medications_import_job_id_import_jobs_id_fk": { + "name": "medications_import_job_id_import_jobs_id_fk", + "tableFrom": "medications", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.conditions": { + "name": "conditions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "code_system": { + "name": "code_system", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "severity": { + "name": "severity", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'active'" + }, + "onset_date": { + "name": "onset_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "resolution_date": { + "name": "resolution_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "diagnosed_by": { + "name": "diagnosed_by", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "conditions_user_id_users_id_fk": { + "name": "conditions_user_id_users_id_fk", + "tableFrom": "conditions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "conditions_source_artifact_id_source_artifacts_id_fk": { + "name": "conditions_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "conditions", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "conditions_import_job_id_import_jobs_id_fk": { + "name": "conditions_import_job_id_import_jobs_id_fk", + "tableFrom": "conditions", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.encounters": { + "name": "encounters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "facility": { + "name": "facility", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "encounter_date": { + "name": "encounter_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "chief_complaint": { + "name": "chief_complaint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "encounters_user_id_users_id_fk": { + "name": "encounters_user_id_users_id_fk", + "tableFrom": "encounters", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "encounters_source_artifact_id_source_artifacts_id_fk": { + "name": "encounters_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "encounters", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "encounters_import_job_id_import_jobs_id_fk": { + "name": "encounters_import_job_id_import_jobs_id_fk", + "tableFrom": "encounters", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.access_grants": { + "name": "access_grants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "share_policy_id": { + "name": "share_policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "recipient_email": { + "name": "recipient_email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "has_password": { + "name": "has_password", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "access_grants_share_policy_id_share_policies_id_fk": { + "name": "access_grants_share_policy_id_share_policies_id_fk", + "tableFrom": "access_grants", + "tableTo": "share_policies", + "columnsFrom": [ + "share_policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "access_grants_recipient_user_id_users_id_fk": { + "name": "access_grants_recipient_user_id_users_id_fk", + "tableFrom": "access_grants", + "tableTo": "users", + "columnsFrom": [ + "recipient_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "access_grants_token_unique": { + "name": "access_grants_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.share_policies": { + "name": "share_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "access_level": { + "name": "access_level", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'view'" + }, + "date_from": { + "name": "date_from", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date_to": { + "name": "date_to", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "share_policies_user_id_users_id_fk": { + "name": "share_policies_user_id_users_id_fk", + "tableFrom": "share_policies", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.share_templates": { + "name": "share_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "default_access_level": { + "name": "default_access_level", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'view'" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_events": { + "name": "audit_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "event_type": { + "name": "event_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "detail": { + "name": "detail", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "varchar(45)", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "audit_events_user_event_type_idx": { + "name": "audit_events_user_event_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_events_user_created_idx": { + "name": "audit_events_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_events_user_id_users_id_fk": { + "name": "audit_events_user_id_users_id_fk", + "tableFrom": "audit_events", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.metric_definitions": { + "name": "metric_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "loinc_code": { + "name": "loinc_code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "snomed_code": { + "name": "snomed_code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "aliases": { + "name": "aliases", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_precision": { + "name": "display_precision", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.optimal_ranges": { + "name": "optimal_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "sex": { + "name": "sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "age_min": { + "name": "age_min", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "age_max": { + "name": "age_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_text": { + "name": "range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "optimal_ranges_metric_code_idx": { + "name": "optimal_ranges_metric_code_idx", + "columns": [ + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "optimal_ranges_metric_code_metric_definitions_id_fk": { + "name": "optimal_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "optimal_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "optimal_ranges_metric_sex_age_uniq": { + "name": "optimal_ranges_metric_sex_age_uniq", + "nullsNotDistinct": false, + "columns": [ + "metric_code", + "sex", + "age_min", + "age_max" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reference_ranges": { + "name": "reference_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "sex": { + "name": "sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "age_min": { + "name": "age_min", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "age_max": { + "name": "age_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_text": { + "name": "range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "reference_ranges_metric_code_idx": { + "name": "reference_ranges_metric_code_idx", + "columns": [ + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "reference_ranges_metric_code_metric_definitions_id_fk": { + "name": "reference_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "reference_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "reference_ranges_metric_sex_age_uniq": { + "name": "reference_ranges_metric_sex_age_uniq", + "nullsNotDistinct": false, + "columns": [ + "metric_code", + "sex", + "age_min", + "age_max" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.unit_conversions": { + "name": "unit_conversions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "from_unit": { + "name": "from_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "to_unit": { + "name": "to_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "multiplier": { + "name": "multiplier", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "offset": { + "name": "offset", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "unit_conversions_metric_code_metric_definitions_id_fk": { + "name": "unit_conversions_metric_code_metric_definitions_id_fk", + "tableFrom": "unit_conversions", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unit_conversions_from_to_metric_uniq": { + "name": "unit_conversions_from_to_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "from_unit", + "to_unit", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_optimal_ranges": { + "name": "user_optimal_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_optimal_ranges_user_id_users_id_fk": { + "name": "user_optimal_ranges_user_id_users_id_fk", + "tableFrom": "user_optimal_ranges", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_optimal_ranges_metric_code_metric_definitions_id_fk": { + "name": "user_optimal_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "user_optimal_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_optimal_ranges_user_metric_uniq": { + "name": "user_optimal_ranges_user_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.insights": { + "name": "insights", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generated_by": { + "name": "generated_by", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "source_observation_ids": { + "name": "source_observation_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source_categories": { + "name": "source_categories", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "context_token_count": { + "name": "context_token_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_dismissed": { + "name": "is_dismissed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "insights_user_id_users_id_fk": { + "name": "insights_user_id_users_id_fk", + "tableFrom": "insights", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugin_installations": { + "name": "plugin_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "plugin_id": { + "name": "plugin_id", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "config_json": { + "name": "config_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "plugin_installations_user_id_users_id_fk": { + "name": "plugin_installations_user_id_users_id_fk", + "tableFrom": "plugin_installations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "plugin_installations_plugin_id_plugins_id_fk": { + "name": "plugin_installations_plugin_id_plugins_id_fk", + "tableFrom": "plugin_installations", + "tableTo": "plugins", + "columnsFrom": [ + "plugin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugins": { + "name": "plugins", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(100)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author": { + "name": "author", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "manifest_json": { + "name": "manifest_json", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "capabilities": { + "name": "capabilities", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "is_verified": { + "name": "is_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_connections": { + "name": "integration_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider_user_id": { + "name": "provider_user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "access_token_enc": { + "name": "access_token_enc", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token_enc": { + "name": "refresh_token_enc", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_cursor": { + "name": "last_sync_cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "integration_connections_user_id_users_id_fk": { + "name": "integration_connections_user_id_users_id_fk", + "tableFrom": "integration_connections", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "integration_connections_user_provider_uniq": { + "name": "integration_connections_user_provider_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "provider" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.feedback": { + "name": "feedback", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "page": { + "name": "page", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "feedback_user_created_idx": { + "name": "feedback_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "feedback_user_id_users_id_fk": { + "name": "feedback_user_id_users_id_fk", + "tableFrom": "feedback", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lab_providers": { + "name": "lab_providers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location_finder_url": { + "name": "location_finder_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "supports_walk_in": { + "name": "supports_walk_in", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "supports_insurance": { + "name": "supports_insurance", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "supports_direct_access": { + "name": "supports_direct_access", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "price_range": { + "name": "price_range", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "service_type": { + "name": "service_type", + "type": "varchar(30)", + "primaryKey": false, + "notNull": false + }, + "place_search_query": { + "name": "place_search_query", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.panel_template_metrics": { + "name": "panel_template_metrics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "panel_id": { + "name": "panel_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "is_core": { + "name": "is_core", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "panel_template_metrics_panel_id_panel_templates_id_fk": { + "name": "panel_template_metrics_panel_id_panel_templates_id_fk", + "tableFrom": "panel_template_metrics", + "tableTo": "panel_templates", + "columnsFrom": [ + "panel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "panel_template_metrics_metric_code_metric_definitions_id_fk": { + "name": "panel_template_metrics_metric_code_metric_definitions_id_fk", + "tableFrom": "panel_template_metrics", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "panel_template_metrics_panel_metric_uniq": { + "name": "panel_template_metrics_panel_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "panel_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.panel_templates": { + "name": "panel_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "estimated_cost_low": { + "name": "estimated_cost_low", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "estimated_cost_high": { + "name": "estimated_cost_high", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_sex": { + "name": "target_sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "panel_templates_category_idx": { + "name": "panel_templates_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_retest_settings": { + "name": "user_retest_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "retest_interval_days": { + "name": "retest_interval_days", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "is_paused": { + "name": "is_paused", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_retest_settings_user_id_users_id_fk": { + "name": "user_retest_settings_user_id_users_id_fk", + "tableFrom": "user_retest_settings", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_retest_settings_metric_code_metric_definitions_id_fk": { + "name": "user_retest_settings_metric_code_metric_definitions_id_fk", + "tableFrom": "user_retest_settings", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_retest_settings_user_metric_uniq": { + "name": "user_retest_settings_user_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/database/drizzle/meta/0010_snapshot.json b/packages/database/drizzle/meta/0010_snapshot.json new file mode 100644 index 0000000..c99e6f6 --- /dev/null +++ b/packages/database/drizzle/meta/0010_snapshot.json @@ -0,0 +1,3534 @@ +{ + "id": "14b23a3d-57a0-4381-8232-3f1adff69fbb", + "prevId": "3478346f-4511-4d9f-8b38-caab54d01a97", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_user_id_users_id_fk": { + "name": "accounts_user_id_users_id_fk", + "tableFrom": "accounts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sessions_token_unique": { + "name": "sessions_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "timezone": { + "name": "timezone", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'UTC'" + }, + "preferred_units": { + "name": "preferred_units", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'metric'" + }, + "ai_model": { + "name": "ai_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "default": "'claude-sonnet-4'" + }, + "date_of_birth": { + "name": "date_of_birth", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "biological_sex": { + "name": "biological_sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "blood_type": { + "name": "blood_type", + "type": "varchar(5)", + "primaryKey": false, + "notNull": false + }, + "show_optimal_ranges": { + "name": "show_optimal_ranges", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "onboarding_step": { + "name": "onboarding_step", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verifications": { + "name": "verifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_sources": { + "name": "data_sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "data_sources_user_id_users_id_fk": { + "name": "data_sources_user_id_users_id_fk", + "tableFrom": "data_sources", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_jobs": { + "name": "import_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "classified_type": { + "name": "classified_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "classification_confidence": { + "name": "classification_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "parser_id": { + "name": "parser_id", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "parser_version": { + "name": "parser_version", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "extraction_count": { + "name": "extraction_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "needs_review": { + "name": "needs_review", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_detail_json": { + "name": "error_detail_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "classify_completed_at": { + "name": "classify_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "parse_completed_at": { + "name": "parse_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "normalize_completed_at": { + "name": "normalize_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "import_jobs_user_id_users_id_fk": { + "name": "import_jobs_user_id_users_id_fk", + "tableFrom": "import_jobs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "import_jobs_source_artifact_id_source_artifacts_id_fk": { + "name": "import_jobs_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "import_jobs", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.source_artifacts": { + "name": "source_artifacts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "blob_path": { + "name": "blob_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "raw_text_extracted": { + "name": "raw_text_extracted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "classified_type": { + "name": "classified_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "classification_confidence": { + "name": "classification_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "source_artifacts_user_id_users_id_fk": { + "name": "source_artifacts_user_id_users_id_fk", + "tableFrom": "source_artifacts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "source_artifacts_data_source_id_data_sources_id_fk": { + "name": "source_artifacts_data_source_id_data_sources_id_fk", + "tableFrom": "source_artifacts", + "tableTo": "data_sources", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "source_artifacts_user_content_hash_uniq": { + "name": "source_artifacts_user_content_hash_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "content_hash" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.flagged_extractions": { + "name": "flagged_extractions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "analyte": { + "name": "analyte", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value_numeric": { + "name": "value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "value_text": { + "name": "value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_abnormal": { + "name": "is_abnormal", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "observed_at": { + "name": "observed_at", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "flag_reason": { + "name": "flag_reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flag_details": { + "name": "flag_details", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resolved": { + "name": "resolved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "resolved_metric_code": { + "name": "resolved_metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_flagged_import_job": { + "name": "idx_flagged_import_job", + "columns": [ + { + "expression": "import_job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "flagged_extractions_import_job_id_import_jobs_id_fk": { + "name": "flagged_extractions_import_job_id_import_jobs_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "flagged_extractions_user_id_users_id_fk": { + "name": "flagged_extractions_user_id_users_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "flagged_extractions_resolved_metric_code_metric_definitions_id_fk": { + "name": "flagged_extractions_resolved_metric_code_metric_definitions_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "metric_definitions", + "columnsFrom": [ + "resolved_metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.observations": { + "name": "observations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "value_numeric": { + "name": "value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "value_text": { + "name": "value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_abnormal": { + "name": "is_abnormal", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'extracted'" + }, + "confidence_score": { + "name": "confidence_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "observed_at": { + "name": "observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "reported_at": { + "name": "reported_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "original_value_numeric": { + "name": "original_value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_value_text": { + "name": "original_value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_unit": { + "name": "original_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "correction_note": { + "name": "correction_note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "observations_user_category_idx": { + "name": "observations_user_category_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "observations_user_metric_observed_idx": { + "name": "observations_user_metric_observed_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "observations_user_observed_idx": { + "name": "observations_user_observed_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "observations_user_id_users_id_fk": { + "name": "observations_user_id_users_id_fk", + "tableFrom": "observations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "observations_data_source_id_data_sources_id_fk": { + "name": "observations_data_source_id_data_sources_id_fk", + "tableFrom": "observations", + "tableTo": "data_sources", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "observations_source_artifact_id_source_artifacts_id_fk": { + "name": "observations_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "observations", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "observations_import_job_id_import_jobs_id_fk": { + "name": "observations_import_job_id_import_jobs_id_fk", + "tableFrom": "observations", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.medication_logs": { + "name": "medication_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "medication_id": { + "name": "medication_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "log_date": { + "name": "log_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "taken": { + "name": "taken", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "time_of_day": { + "name": "time_of_day", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medication_logs_medication_id_medications_id_fk": { + "name": "medication_logs_medication_id_medications_id_fk", + "tableFrom": "medication_logs", + "tableTo": "medications", + "columnsFrom": [ + "medication_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "medication_logs_user_id_users_id_fk": { + "name": "medication_logs_user_id_users_id_fk", + "tableFrom": "medication_logs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.medications": { + "name": "medications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "generic_name": { + "name": "generic_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'prescription'" + }, + "dosage": { + "name": "dosage", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "frequency": { + "name": "frequency", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "route": { + "name": "route", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "prescriber": { + "name": "prescriber", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "indication": { + "name": "indication", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'manual'" + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medications_user_id_users_id_fk": { + "name": "medications_user_id_users_id_fk", + "tableFrom": "medications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "medications_source_artifact_id_source_artifacts_id_fk": { + "name": "medications_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "medications", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "medications_import_job_id_import_jobs_id_fk": { + "name": "medications_import_job_id_import_jobs_id_fk", + "tableFrom": "medications", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.conditions": { + "name": "conditions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "code_system": { + "name": "code_system", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "severity": { + "name": "severity", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'active'" + }, + "onset_date": { + "name": "onset_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "resolution_date": { + "name": "resolution_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "diagnosed_by": { + "name": "diagnosed_by", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "conditions_user_id_users_id_fk": { + "name": "conditions_user_id_users_id_fk", + "tableFrom": "conditions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "conditions_source_artifact_id_source_artifacts_id_fk": { + "name": "conditions_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "conditions", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "conditions_import_job_id_import_jobs_id_fk": { + "name": "conditions_import_job_id_import_jobs_id_fk", + "tableFrom": "conditions", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.encounters": { + "name": "encounters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "facility": { + "name": "facility", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "encounter_date": { + "name": "encounter_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "chief_complaint": { + "name": "chief_complaint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "encounters_user_id_users_id_fk": { + "name": "encounters_user_id_users_id_fk", + "tableFrom": "encounters", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "encounters_source_artifact_id_source_artifacts_id_fk": { + "name": "encounters_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "encounters", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "encounters_import_job_id_import_jobs_id_fk": { + "name": "encounters_import_job_id_import_jobs_id_fk", + "tableFrom": "encounters", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.access_grants": { + "name": "access_grants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "share_policy_id": { + "name": "share_policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "recipient_email": { + "name": "recipient_email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "has_password": { + "name": "has_password", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "access_grants_share_policy_id_share_policies_id_fk": { + "name": "access_grants_share_policy_id_share_policies_id_fk", + "tableFrom": "access_grants", + "tableTo": "share_policies", + "columnsFrom": [ + "share_policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "access_grants_recipient_user_id_users_id_fk": { + "name": "access_grants_recipient_user_id_users_id_fk", + "tableFrom": "access_grants", + "tableTo": "users", + "columnsFrom": [ + "recipient_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "access_grants_token_unique": { + "name": "access_grants_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.share_policies": { + "name": "share_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "access_level": { + "name": "access_level", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'view'" + }, + "date_from": { + "name": "date_from", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date_to": { + "name": "date_to", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "share_policies_user_id_users_id_fk": { + "name": "share_policies_user_id_users_id_fk", + "tableFrom": "share_policies", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.share_templates": { + "name": "share_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "default_access_level": { + "name": "default_access_level", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'view'" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_events": { + "name": "audit_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "event_type": { + "name": "event_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "detail": { + "name": "detail", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "varchar(45)", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "audit_events_user_event_type_idx": { + "name": "audit_events_user_event_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_events_user_created_idx": { + "name": "audit_events_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_events_user_id_users_id_fk": { + "name": "audit_events_user_id_users_id_fk", + "tableFrom": "audit_events", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.metric_definitions": { + "name": "metric_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "loinc_code": { + "name": "loinc_code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "snomed_code": { + "name": "snomed_code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "aliases": { + "name": "aliases", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_precision": { + "name": "display_precision", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.optimal_ranges": { + "name": "optimal_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "sex": { + "name": "sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "age_min": { + "name": "age_min", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "age_max": { + "name": "age_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_text": { + "name": "range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "optimal_ranges_metric_code_idx": { + "name": "optimal_ranges_metric_code_idx", + "columns": [ + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "optimal_ranges_metric_code_metric_definitions_id_fk": { + "name": "optimal_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "optimal_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "optimal_ranges_metric_sex_age_uniq": { + "name": "optimal_ranges_metric_sex_age_uniq", + "nullsNotDistinct": false, + "columns": [ + "metric_code", + "sex", + "age_min", + "age_max" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reference_ranges": { + "name": "reference_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "sex": { + "name": "sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "age_min": { + "name": "age_min", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "age_max": { + "name": "age_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_text": { + "name": "range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "reference_ranges_metric_code_idx": { + "name": "reference_ranges_metric_code_idx", + "columns": [ + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "reference_ranges_metric_code_metric_definitions_id_fk": { + "name": "reference_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "reference_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "reference_ranges_metric_sex_age_uniq": { + "name": "reference_ranges_metric_sex_age_uniq", + "nullsNotDistinct": false, + "columns": [ + "metric_code", + "sex", + "age_min", + "age_max" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.unit_conversions": { + "name": "unit_conversions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "from_unit": { + "name": "from_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "to_unit": { + "name": "to_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "multiplier": { + "name": "multiplier", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "offset": { + "name": "offset", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "unit_conversions_metric_code_metric_definitions_id_fk": { + "name": "unit_conversions_metric_code_metric_definitions_id_fk", + "tableFrom": "unit_conversions", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unit_conversions_from_to_metric_uniq": { + "name": "unit_conversions_from_to_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "from_unit", + "to_unit", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_optimal_ranges": { + "name": "user_optimal_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_optimal_ranges_user_id_users_id_fk": { + "name": "user_optimal_ranges_user_id_users_id_fk", + "tableFrom": "user_optimal_ranges", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_optimal_ranges_metric_code_metric_definitions_id_fk": { + "name": "user_optimal_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "user_optimal_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_optimal_ranges_user_metric_uniq": { + "name": "user_optimal_ranges_user_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.insights": { + "name": "insights", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generated_by": { + "name": "generated_by", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "source_observation_ids": { + "name": "source_observation_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source_categories": { + "name": "source_categories", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "context_token_count": { + "name": "context_token_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_dismissed": { + "name": "is_dismissed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "insights_user_id_users_id_fk": { + "name": "insights_user_id_users_id_fk", + "tableFrom": "insights", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugin_installations": { + "name": "plugin_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "plugin_id": { + "name": "plugin_id", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "config_json": { + "name": "config_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "plugin_installations_user_id_users_id_fk": { + "name": "plugin_installations_user_id_users_id_fk", + "tableFrom": "plugin_installations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "plugin_installations_plugin_id_plugins_id_fk": { + "name": "plugin_installations_plugin_id_plugins_id_fk", + "tableFrom": "plugin_installations", + "tableTo": "plugins", + "columnsFrom": [ + "plugin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugins": { + "name": "plugins", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(100)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author": { + "name": "author", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "manifest_json": { + "name": "manifest_json", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "capabilities": { + "name": "capabilities", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "is_verified": { + "name": "is_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_connections": { + "name": "integration_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider_user_id": { + "name": "provider_user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "access_token_enc": { + "name": "access_token_enc", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token_enc": { + "name": "refresh_token_enc", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_cursor": { + "name": "last_sync_cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "integration_connections_user_id_users_id_fk": { + "name": "integration_connections_user_id_users_id_fk", + "tableFrom": "integration_connections", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "integration_connections_user_provider_uniq": { + "name": "integration_connections_user_provider_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "provider" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.feedback": { + "name": "feedback", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "page": { + "name": "page", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "feedback_user_created_idx": { + "name": "feedback_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "feedback_user_id_users_id_fk": { + "name": "feedback_user_id_users_id_fk", + "tableFrom": "feedback", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lab_providers": { + "name": "lab_providers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location_finder_url": { + "name": "location_finder_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "supports_walk_in": { + "name": "supports_walk_in", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "supports_insurance": { + "name": "supports_insurance", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "supports_direct_access": { + "name": "supports_direct_access", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "price_range": { + "name": "price_range", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "service_type": { + "name": "service_type", + "type": "varchar(30)", + "primaryKey": false, + "notNull": false + }, + "place_search_query": { + "name": "place_search_query", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.panel_template_metrics": { + "name": "panel_template_metrics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "panel_id": { + "name": "panel_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "is_core": { + "name": "is_core", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "panel_template_metrics_panel_id_panel_templates_id_fk": { + "name": "panel_template_metrics_panel_id_panel_templates_id_fk", + "tableFrom": "panel_template_metrics", + "tableTo": "panel_templates", + "columnsFrom": [ + "panel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "panel_template_metrics_metric_code_metric_definitions_id_fk": { + "name": "panel_template_metrics_metric_code_metric_definitions_id_fk", + "tableFrom": "panel_template_metrics", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "panel_template_metrics_panel_metric_uniq": { + "name": "panel_template_metrics_panel_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "panel_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.panel_templates": { + "name": "panel_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "estimated_cost_low": { + "name": "estimated_cost_low", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "estimated_cost_high": { + "name": "estimated_cost_high", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_sex": { + "name": "target_sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "panel_templates_category_idx": { + "name": "panel_templates_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_retest_settings": { + "name": "user_retest_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "retest_interval_days": { + "name": "retest_interval_days", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "is_paused": { + "name": "is_paused", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_retest_settings_user_id_users_id_fk": { + "name": "user_retest_settings_user_id_users_id_fk", + "tableFrom": "user_retest_settings", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_retest_settings_metric_code_metric_definitions_id_fk": { + "name": "user_retest_settings_metric_code_metric_definitions_id_fk", + "tableFrom": "user_retest_settings", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_retest_settings_user_metric_uniq": { + "name": "user_retest_settings_user_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/database/drizzle/meta/0011_snapshot.json b/packages/database/drizzle/meta/0011_snapshot.json new file mode 100644 index 0000000..c99e6f6 --- /dev/null +++ b/packages/database/drizzle/meta/0011_snapshot.json @@ -0,0 +1,3534 @@ +{ + "id": "14b23a3d-57a0-4381-8232-3f1adff69fbb", + "prevId": "3478346f-4511-4d9f-8b38-caab54d01a97", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_user_id_users_id_fk": { + "name": "accounts_user_id_users_id_fk", + "tableFrom": "accounts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sessions_token_unique": { + "name": "sessions_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "timezone": { + "name": "timezone", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'UTC'" + }, + "preferred_units": { + "name": "preferred_units", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'metric'" + }, + "ai_model": { + "name": "ai_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "default": "'claude-sonnet-4'" + }, + "date_of_birth": { + "name": "date_of_birth", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "biological_sex": { + "name": "biological_sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "blood_type": { + "name": "blood_type", + "type": "varchar(5)", + "primaryKey": false, + "notNull": false + }, + "show_optimal_ranges": { + "name": "show_optimal_ranges", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "onboarding_step": { + "name": "onboarding_step", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verifications": { + "name": "verifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_sources": { + "name": "data_sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "data_sources_user_id_users_id_fk": { + "name": "data_sources_user_id_users_id_fk", + "tableFrom": "data_sources", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_jobs": { + "name": "import_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "classified_type": { + "name": "classified_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "classification_confidence": { + "name": "classification_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "parser_id": { + "name": "parser_id", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "parser_version": { + "name": "parser_version", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "extraction_count": { + "name": "extraction_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "needs_review": { + "name": "needs_review", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_detail_json": { + "name": "error_detail_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "classify_completed_at": { + "name": "classify_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "parse_completed_at": { + "name": "parse_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "normalize_completed_at": { + "name": "normalize_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "import_jobs_user_id_users_id_fk": { + "name": "import_jobs_user_id_users_id_fk", + "tableFrom": "import_jobs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "import_jobs_source_artifact_id_source_artifacts_id_fk": { + "name": "import_jobs_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "import_jobs", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.source_artifacts": { + "name": "source_artifacts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "blob_path": { + "name": "blob_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "raw_text_extracted": { + "name": "raw_text_extracted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "classified_type": { + "name": "classified_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "classification_confidence": { + "name": "classification_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "source_artifacts_user_id_users_id_fk": { + "name": "source_artifacts_user_id_users_id_fk", + "tableFrom": "source_artifacts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "source_artifacts_data_source_id_data_sources_id_fk": { + "name": "source_artifacts_data_source_id_data_sources_id_fk", + "tableFrom": "source_artifacts", + "tableTo": "data_sources", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "source_artifacts_user_content_hash_uniq": { + "name": "source_artifacts_user_content_hash_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "content_hash" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.flagged_extractions": { + "name": "flagged_extractions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "analyte": { + "name": "analyte", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value_numeric": { + "name": "value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "value_text": { + "name": "value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_abnormal": { + "name": "is_abnormal", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "observed_at": { + "name": "observed_at", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "flag_reason": { + "name": "flag_reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flag_details": { + "name": "flag_details", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resolved": { + "name": "resolved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "resolved_metric_code": { + "name": "resolved_metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_flagged_import_job": { + "name": "idx_flagged_import_job", + "columns": [ + { + "expression": "import_job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "flagged_extractions_import_job_id_import_jobs_id_fk": { + "name": "flagged_extractions_import_job_id_import_jobs_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "flagged_extractions_user_id_users_id_fk": { + "name": "flagged_extractions_user_id_users_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "flagged_extractions_resolved_metric_code_metric_definitions_id_fk": { + "name": "flagged_extractions_resolved_metric_code_metric_definitions_id_fk", + "tableFrom": "flagged_extractions", + "tableTo": "metric_definitions", + "columnsFrom": [ + "resolved_metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.observations": { + "name": "observations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "value_numeric": { + "name": "value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "value_text": { + "name": "value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_abnormal": { + "name": "is_abnormal", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'extracted'" + }, + "confidence_score": { + "name": "confidence_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "observed_at": { + "name": "observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "reported_at": { + "name": "reported_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "original_value_numeric": { + "name": "original_value_numeric", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_value_text": { + "name": "original_value_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_unit": { + "name": "original_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "correction_note": { + "name": "correction_note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "observations_user_category_idx": { + "name": "observations_user_category_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "observations_user_metric_observed_idx": { + "name": "observations_user_metric_observed_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "observations_user_observed_idx": { + "name": "observations_user_observed_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "observations_user_id_users_id_fk": { + "name": "observations_user_id_users_id_fk", + "tableFrom": "observations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "observations_data_source_id_data_sources_id_fk": { + "name": "observations_data_source_id_data_sources_id_fk", + "tableFrom": "observations", + "tableTo": "data_sources", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "observations_source_artifact_id_source_artifacts_id_fk": { + "name": "observations_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "observations", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "observations_import_job_id_import_jobs_id_fk": { + "name": "observations_import_job_id_import_jobs_id_fk", + "tableFrom": "observations", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.medication_logs": { + "name": "medication_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "medication_id": { + "name": "medication_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "log_date": { + "name": "log_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "taken": { + "name": "taken", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "time_of_day": { + "name": "time_of_day", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medication_logs_medication_id_medications_id_fk": { + "name": "medication_logs_medication_id_medications_id_fk", + "tableFrom": "medication_logs", + "tableTo": "medications", + "columnsFrom": [ + "medication_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "medication_logs_user_id_users_id_fk": { + "name": "medication_logs_user_id_users_id_fk", + "tableFrom": "medication_logs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.medications": { + "name": "medications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "generic_name": { + "name": "generic_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'prescription'" + }, + "dosage": { + "name": "dosage", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "frequency": { + "name": "frequency", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "route": { + "name": "route", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "prescriber": { + "name": "prescriber", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "indication": { + "name": "indication", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'manual'" + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medications_user_id_users_id_fk": { + "name": "medications_user_id_users_id_fk", + "tableFrom": "medications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "medications_source_artifact_id_source_artifacts_id_fk": { + "name": "medications_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "medications", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "medications_import_job_id_import_jobs_id_fk": { + "name": "medications_import_job_id_import_jobs_id_fk", + "tableFrom": "medications", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.conditions": { + "name": "conditions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "code_system": { + "name": "code_system", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "severity": { + "name": "severity", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'active'" + }, + "onset_date": { + "name": "onset_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "resolution_date": { + "name": "resolution_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "diagnosed_by": { + "name": "diagnosed_by", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "conditions_user_id_users_id_fk": { + "name": "conditions_user_id_users_id_fk", + "tableFrom": "conditions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "conditions_source_artifact_id_source_artifacts_id_fk": { + "name": "conditions_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "conditions", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "conditions_import_job_id_import_jobs_id_fk": { + "name": "conditions_import_job_id_import_jobs_id_fk", + "tableFrom": "conditions", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.encounters": { + "name": "encounters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "facility": { + "name": "facility", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "encounter_date": { + "name": "encounter_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "chief_complaint": { + "name": "chief_complaint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_artifact_id": { + "name": "source_artifact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "import_job_id": { + "name": "import_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "encounters_user_id_users_id_fk": { + "name": "encounters_user_id_users_id_fk", + "tableFrom": "encounters", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "encounters_source_artifact_id_source_artifacts_id_fk": { + "name": "encounters_source_artifact_id_source_artifacts_id_fk", + "tableFrom": "encounters", + "tableTo": "source_artifacts", + "columnsFrom": [ + "source_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "encounters_import_job_id_import_jobs_id_fk": { + "name": "encounters_import_job_id_import_jobs_id_fk", + "tableFrom": "encounters", + "tableTo": "import_jobs", + "columnsFrom": [ + "import_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.access_grants": { + "name": "access_grants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "share_policy_id": { + "name": "share_policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "recipient_email": { + "name": "recipient_email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "has_password": { + "name": "has_password", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "access_grants_share_policy_id_share_policies_id_fk": { + "name": "access_grants_share_policy_id_share_policies_id_fk", + "tableFrom": "access_grants", + "tableTo": "share_policies", + "columnsFrom": [ + "share_policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "access_grants_recipient_user_id_users_id_fk": { + "name": "access_grants_recipient_user_id_users_id_fk", + "tableFrom": "access_grants", + "tableTo": "users", + "columnsFrom": [ + "recipient_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "access_grants_token_unique": { + "name": "access_grants_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.share_policies": { + "name": "share_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "access_level": { + "name": "access_level", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'view'" + }, + "date_from": { + "name": "date_from", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date_to": { + "name": "date_to", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "share_policies_user_id_users_id_fk": { + "name": "share_policies_user_id_users_id_fk", + "tableFrom": "share_policies", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.share_templates": { + "name": "share_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "default_access_level": { + "name": "default_access_level", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'view'" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_events": { + "name": "audit_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "event_type": { + "name": "event_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "detail": { + "name": "detail", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "varchar(45)", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "audit_events_user_event_type_idx": { + "name": "audit_events_user_event_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_events_user_created_idx": { + "name": "audit_events_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_events_user_id_users_id_fk": { + "name": "audit_events_user_id_users_id_fk", + "tableFrom": "audit_events", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.metric_definitions": { + "name": "metric_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "loinc_code": { + "name": "loinc_code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "snomed_code": { + "name": "snomed_code", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "aliases": { + "name": "aliases", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "reference_range_low": { + "name": "reference_range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_high": { + "name": "reference_range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "reference_range_text": { + "name": "reference_range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_precision": { + "name": "display_precision", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.optimal_ranges": { + "name": "optimal_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "sex": { + "name": "sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "age_min": { + "name": "age_min", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "age_max": { + "name": "age_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_text": { + "name": "range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "optimal_ranges_metric_code_idx": { + "name": "optimal_ranges_metric_code_idx", + "columns": [ + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "optimal_ranges_metric_code_metric_definitions_id_fk": { + "name": "optimal_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "optimal_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "optimal_ranges_metric_sex_age_uniq": { + "name": "optimal_ranges_metric_sex_age_uniq", + "nullsNotDistinct": false, + "columns": [ + "metric_code", + "sex", + "age_min", + "age_max" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reference_ranges": { + "name": "reference_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "sex": { + "name": "sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "age_min": { + "name": "age_min", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "age_max": { + "name": "age_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_text": { + "name": "range_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "reference_ranges_metric_code_idx": { + "name": "reference_ranges_metric_code_idx", + "columns": [ + { + "expression": "metric_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "reference_ranges_metric_code_metric_definitions_id_fk": { + "name": "reference_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "reference_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "reference_ranges_metric_sex_age_uniq": { + "name": "reference_ranges_metric_sex_age_uniq", + "nullsNotDistinct": false, + "columns": [ + "metric_code", + "sex", + "age_min", + "age_max" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.unit_conversions": { + "name": "unit_conversions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "from_unit": { + "name": "from_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "to_unit": { + "name": "to_unit", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "multiplier": { + "name": "multiplier", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "offset": { + "name": "offset", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "unit_conversions_metric_code_metric_definitions_id_fk": { + "name": "unit_conversions_metric_code_metric_definitions_id_fk", + "tableFrom": "unit_conversions", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unit_conversions_from_to_metric_uniq": { + "name": "unit_conversions_from_to_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "from_unit", + "to_unit", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_optimal_ranges": { + "name": "user_optimal_ranges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "range_low": { + "name": "range_low", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "range_high": { + "name": "range_high", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_optimal_ranges_user_id_users_id_fk": { + "name": "user_optimal_ranges_user_id_users_id_fk", + "tableFrom": "user_optimal_ranges", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_optimal_ranges_metric_code_metric_definitions_id_fk": { + "name": "user_optimal_ranges_metric_code_metric_definitions_id_fk", + "tableFrom": "user_optimal_ranges", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_optimal_ranges_user_metric_uniq": { + "name": "user_optimal_ranges_user_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.insights": { + "name": "insights", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generated_by": { + "name": "generated_by", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "source_observation_ids": { + "name": "source_observation_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source_categories": { + "name": "source_categories", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "context_token_count": { + "name": "context_token_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_dismissed": { + "name": "is_dismissed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "insights_user_id_users_id_fk": { + "name": "insights_user_id_users_id_fk", + "tableFrom": "insights", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugin_installations": { + "name": "plugin_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "plugin_id": { + "name": "plugin_id", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "config_json": { + "name": "config_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "plugin_installations_user_id_users_id_fk": { + "name": "plugin_installations_user_id_users_id_fk", + "tableFrom": "plugin_installations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "plugin_installations_plugin_id_plugins_id_fk": { + "name": "plugin_installations_plugin_id_plugins_id_fk", + "tableFrom": "plugin_installations", + "tableTo": "plugins", + "columnsFrom": [ + "plugin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugins": { + "name": "plugins", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(100)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author": { + "name": "author", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "manifest_json": { + "name": "manifest_json", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "capabilities": { + "name": "capabilities", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "is_verified": { + "name": "is_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_connections": { + "name": "integration_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "provider_user_id": { + "name": "provider_user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "access_token_enc": { + "name": "access_token_enc", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token_enc": { + "name": "refresh_token_enc", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_cursor": { + "name": "last_sync_cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "metadata_json": { + "name": "metadata_json", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "integration_connections_user_id_users_id_fk": { + "name": "integration_connections_user_id_users_id_fk", + "tableFrom": "integration_connections", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "integration_connections_user_provider_uniq": { + "name": "integration_connections_user_provider_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "provider" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.feedback": { + "name": "feedback", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "page": { + "name": "page", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "feedback_user_created_idx": { + "name": "feedback_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "feedback_user_id_users_id_fk": { + "name": "feedback_user_id_users_id_fk", + "tableFrom": "feedback", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lab_providers": { + "name": "lab_providers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location_finder_url": { + "name": "location_finder_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "supports_walk_in": { + "name": "supports_walk_in", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "supports_insurance": { + "name": "supports_insurance", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "supports_direct_access": { + "name": "supports_direct_access", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "price_range": { + "name": "price_range", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "service_type": { + "name": "service_type", + "type": "varchar(30)", + "primaryKey": false, + "notNull": false + }, + "place_search_query": { + "name": "place_search_query", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.panel_template_metrics": { + "name": "panel_template_metrics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "panel_id": { + "name": "panel_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "is_core": { + "name": "is_core", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "panel_template_metrics_panel_id_panel_templates_id_fk": { + "name": "panel_template_metrics_panel_id_panel_templates_id_fk", + "tableFrom": "panel_template_metrics", + "tableTo": "panel_templates", + "columnsFrom": [ + "panel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "panel_template_metrics_metric_code_metric_definitions_id_fk": { + "name": "panel_template_metrics_metric_code_metric_definitions_id_fk", + "tableFrom": "panel_template_metrics", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "panel_template_metrics_panel_metric_uniq": { + "name": "panel_template_metrics_panel_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "panel_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.panel_templates": { + "name": "panel_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(50)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "estimated_cost_low": { + "name": "estimated_cost_low", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "estimated_cost_high": { + "name": "estimated_cost_high", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_sex": { + "name": "target_sex", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "panel_templates_category_idx": { + "name": "panel_templates_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_retest_settings": { + "name": "user_retest_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric_code": { + "name": "metric_code", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "retest_interval_days": { + "name": "retest_interval_days", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "is_paused": { + "name": "is_paused", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_retest_settings_user_id_users_id_fk": { + "name": "user_retest_settings_user_id_users_id_fk", + "tableFrom": "user_retest_settings", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_retest_settings_metric_code_metric_definitions_id_fk": { + "name": "user_retest_settings_metric_code_metric_definitions_id_fk", + "tableFrom": "user_retest_settings", + "tableTo": "metric_definitions", + "columnsFrom": [ + "metric_code" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_retest_settings_user_metric_uniq": { + "name": "user_retest_settings_user_metric_uniq", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "metric_code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/database/drizzle/meta/_journal.json b/packages/database/drizzle/meta/_journal.json index 8caa2fb..378fecb 100644 --- a/packages/database/drizzle/meta/_journal.json +++ b/packages/database/drizzle/meta/_journal.json @@ -64,6 +64,27 @@ "when": 1774031593654, "tag": "0008_public_wolverine", "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1775132667401, + "tag": "0009_purple_dragon_man", + "breakpoints": true + }, + { + "idx": 10, + "version": "7", + "when": 1775350800000, + "tag": "0010_seed_missing_metric_data", + "breakpoints": true + }, + { + "idx": 11, + "version": "7", + "when": 1775351400000, + "tag": "0011_consolidate_metric_codes", + "breakpoints": true } ] -} \ No newline at end of file +} diff --git a/packages/database/src/schema/observations.ts b/packages/database/src/schema/observations.ts index 923bdd4..1aea2da 100644 --- a/packages/database/src/schema/observations.ts +++ b/packages/database/src/schema/observations.ts @@ -5,6 +5,7 @@ import { text, boolean, timestamp, + date, real, jsonb, index, @@ -12,6 +13,7 @@ import { import { relations } from 'drizzle-orm'; import { users } from './users'; import { dataSources, sourceArtifacts, importJobs } from './sources'; +import { metricDefinitions } from './metrics'; // ── Observations ─────────────────────────────────────────────────────────────── @@ -79,3 +81,37 @@ export const observationsRelations = relations(observations, ({ one }) => ({ references: [importJobs.id], }), })); + +// ── Flagged Extractions ─────────────────────────────────────────────────────── + +export const flaggedExtractions = pgTable( + 'flagged_extractions', + { + id: uuid('id').primaryKey().defaultRandom(), + importJobId: uuid('import_job_id') + .notNull() + .references(() => importJobs.id, { onDelete: 'cascade' }), + userId: text('user_id') + .notNull() + .references(() => users.id, { onDelete: 'cascade' }), + analyte: text('analyte').notNull(), + valueNumeric: real('value_numeric'), + valueText: text('value_text'), + unit: varchar('unit', { length: 50 }), + referenceRangeLow: real('reference_range_low'), + referenceRangeHigh: real('reference_range_high'), + referenceRangeText: text('reference_range_text'), + isAbnormal: boolean('is_abnormal'), + observedAt: date('observed_at'), + flagReason: text('flag_reason').notNull(), + flagDetails: text('flag_details'), + resolved: boolean('resolved').notNull().default(false), + resolvedMetricCode: varchar('resolved_metric_code', { length: 50 }).references( + () => metricDefinitions.id, + ), + createdAt: timestamp('created_at').defaultNow(), + }, + (table) => ({ + importJobIdx: index('idx_flagged_import_job').on(table.importJobId), + }), +); diff --git a/packages/database/src/seed/data/optimal-ranges.ts b/packages/database/src/seed/data/optimal-ranges.ts index 19b5a06..56471b0 100644 --- a/packages/database/src/seed/data/optimal-ranges.ts +++ b/packages/database/src/seed/data/optimal-ranges.ts @@ -46,6 +46,31 @@ export const optimalRangeSeeds: OptimalRangeSeed[] = [ sourceUrl: null, }, + { + metricCode: "homa_ir", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0, + rangeHigh: 1.0, + rangeText: "<1.0", + source: "Attia/Outlive", + sourceUrl: null, + }, + + // HbA1c alias — observations use "hba1c", seed canonical is "hemoglobin_a1c" + { + metricCode: "hba1c", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 4.0, + rangeHigh: 5.2, + rangeText: "4.0–5.2%", + source: "Attia/Function Health", + sourceUrl: null, + }, + // ── Inflammation ──────────────────────────────────────────────────────────── { metricCode: "hs_crp", @@ -59,6 +84,41 @@ export const optimalRangeSeeds: OptimalRangeSeed[] = [ sourceUrl: null, }, + // CRP alias — observations use "crp" or "c_reactive_protein" + { + metricCode: "crp", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0, + rangeHigh: 1.0, + rangeText: "<1.0 mg/L", + source: "AHA/Attia", + sourceUrl: null, + }, + { + metricCode: "c_reactive_protein", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0, + rangeHigh: 1.0, + rangeText: "<1.0 mg/L", + source: "AHA/Attia", + sourceUrl: null, + }, + { + metricCode: "homocysteine", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 5, + rangeHigh: 10, + rangeText: "5–10 µmol/L", + source: "Attia/Function Health", + sourceUrl: null, + }, + // ── Lipids ────────────────────────────────────────────────────────────────── { metricCode: "ldl_cholesterol", @@ -116,6 +176,30 @@ export const optimalRangeSeeds: OptimalRangeSeed[] = [ sourceUrl: null, }, + { + metricCode: "apolipoprotein_b", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0, + rangeHigh: 80, + rangeText: "<80 mg/dL", + source: "Attia/AHA", + sourceUrl: null, + }, + // total_cholesterol alias — observations use this code + { + metricCode: "total_cholesterol", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0, + rangeHigh: 180, + rangeText: "<180 mg/dL", + source: "AHA", + sourceUrl: null, + }, + // ── Vitamins & Minerals ───────────────────────────────────────────────────── { metricCode: "vitamin_d", @@ -151,6 +235,74 @@ export const optimalRangeSeeds: OptimalRangeSeed[] = [ sourceUrl: null, }, + // vitamin_d aliases — observations may use different codes + { + metricCode: "25_hydroxyvitamin_d", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 40, + rangeHigh: 60, + rangeText: "40–60 ng/mL", + source: "Huberman/Function Health", + sourceUrl: null, + }, + { + metricCode: "vitamin_d_25_hydroxyvitamin_d", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 40, + rangeHigh: 60, + rangeText: "40–60 ng/mL", + source: "Huberman/Function Health", + sourceUrl: null, + }, + { + metricCode: "iron", + sex: "male", + ageMin: 18, + ageMax: null, + rangeLow: 60, + rangeHigh: 170, + rangeText: "60–170 µg/dL", + source: "Function Health", + sourceUrl: null, + }, + { + metricCode: "iron", + sex: "female", + ageMin: 18, + ageMax: null, + rangeLow: 50, + rangeHigh: 150, + rangeText: "50–150 µg/dL", + source: "Function Health", + sourceUrl: null, + }, + { + metricCode: "magnesium", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 2.0, + rangeHigh: 2.5, + rangeText: "2.0–2.5 mg/dL", + source: "Function Health", + sourceUrl: null, + }, + { + metricCode: "zinc", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0.7, + rangeHigh: 1.2, + rangeText: "0.7–1.2 mg/L", + source: "Function Health", + sourceUrl: null, + }, + // ── Iron ──────────────────────────────────────────────────────────────────── { metricCode: "ferritin", @@ -234,6 +386,18 @@ export const optimalRangeSeeds: OptimalRangeSeed[] = [ sourceUrl: null, }, + { + metricCode: "tpo_antibodies", + sex: null, + ageMin: 18, + ageMax: null, + rangeLow: 0, + rangeHigh: 9, + rangeText: "<9 IU/mL", + source: "Functional medicine", + sourceUrl: null, + }, + // ── Hormones ──────────────────────────────────────────────────────────────── { metricCode: "testosterone_total", diff --git a/packages/database/src/seed/run.ts b/packages/database/src/seed/run.ts index efb23a7..01880d6 100644 --- a/packages/database/src/seed/run.ts +++ b/packages/database/src/seed/run.ts @@ -19,6 +19,12 @@ import { panelTemplateSeeds, panelTemplateMetricSeeds, } from "./data/panel-templates"; +import { + additionalMetricSeeds, + aliasUpdates, + displayPrecisionOverrides, +} from "./data/romanian-lab-supplements"; +import { eq, sql } from "drizzle-orm"; async function main() { const db = getDb(); @@ -45,41 +51,71 @@ async function main() { await db .insert(unitConversions) .values([ - { - fromUnit: "mg/dL", - toUnit: "mmol/L", - metricCode: "glucose", - multiplier: 0.0555, - offset: 0, - }, - { - fromUnit: "mg/dL", - toUnit: "mmol/L", - metricCode: "cholesterol_total", - multiplier: 0.0259, - offset: 0, - }, - { - fromUnit: "lb", - toUnit: "kg", - metricCode: null, - multiplier: 0.4536, - offset: 0, - }, - { - fromUnit: "in", - toUnit: "cm", - metricCode: null, - multiplier: 2.54, - offset: 0, - }, - { - fromUnit: "F", - toUnit: "C", - metricCode: null, - multiplier: 0.5556, - offset: -17.7778, - }, + // Imperial/metric basics + { fromUnit: "lb", toUnit: "kg", metricCode: null, multiplier: 0.4536, offset: 0 }, + { fromUnit: "in", toUnit: "cm", metricCode: null, multiplier: 2.54, offset: 0 }, + { fromUnit: "F", toUnit: "C", metricCode: null, multiplier: 0.5556, offset: -17.7778 }, + // Chemistry conversions + { fromUnit: "mg/dL", toUnit: "mmol/L", metricCode: "glucose", multiplier: 0.0555, offset: 0 }, + { fromUnit: "mg/dL", toUnit: "mmol/L", metricCode: "cholesterol_total", multiplier: 0.0259, offset: 0 }, + { fromUnit: "mg/dL", toUnit: "mg/L", metricCode: "crp", multiplier: 10, offset: 0 }, + { fromUnit: "mg/dL", toUnit: "mg/L", metricCode: "hs_crp", multiplier: 10, offset: 0 }, + { fromUnit: "mg/L", toUnit: "mcg/dL", metricCode: "zinc", multiplier: 100, offset: 0 }, + { fromUnit: "ng/mL", toUnit: "ng/dL", metricCode: "total_t3", multiplier: 100, offset: 0 }, + // Hematology: /mm³ to K/uL or M/uL + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "wbc", multiplier: 0.001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "platelets", multiplier: 0.001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "M/uL", metricCode: "rbc", multiplier: 0.000001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "neutrophils_abs", multiplier: 0.001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "lymphocytes_abs", multiplier: 0.001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "monocytes_abs", multiplier: 0.001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "eosinophils_abs", multiplier: 0.001, offset: 0 }, + { fromUnit: "/mm³", toUnit: "K/uL", metricCode: "basophils_abs", multiplier: 0.001, offset: 0 }, + // Medisim/Synlab format: 10^3/ul = K/uL, 10^6/uL = M/uL + { fromUnit: "10^3/ul", toUnit: "K/uL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "10^3/uL", toUnit: "K/uL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "10^6/ul", toUnit: "M/uL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "10^6/uL", toUnit: "M/uL", metricCode: null, multiplier: 1, offset: 0 }, + // Insulin unit variants + { fromUnit: "mU/L", toUnit: "uIU/mL", metricCode: "insulin", multiplier: 1, offset: 0 }, + { fromUnit: "\u03BCU/mL", toUnit: "uIU/mL", metricCode: "insulin", multiplier: 1, offset: 0 }, + { fromUnit: "\u00B5U/mL", toUnit: "uIU/mL", metricCode: "insulin", multiplier: 1, offset: 0 }, + // TSH unit variants + { fromUnit: "uUI/mL", toUnit: "mIU/L", metricCode: "tsh", multiplier: 1, offset: 0 }, + // Unicode micro sign (μ/µ) → ASCII equivalents + { fromUnit: "\u03BCg/dL", toUnit: "mcg/dL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "\u00B5g/dL", toUnit: "mcg/dL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "\u03BCUI/mL", toUnit: "mIU/L", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "\u00B5UI/mL", toUnit: "mIU/L", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "\u03BCmol/L", toUnit: "umol/L", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "\u00B5mol/L", toUnit: "umol/L", metricCode: null, multiplier: 1, offset: 0 }, + // Case-insensitive unit aliases + { fromUnit: "UI/mL", toUnit: "IU/mL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "mg/dl", toUnit: "mg/dL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "ug/dl", toUnit: "mcg/dL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "ug/dL", toUnit: "mcg/dL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "ng/ml", toUnit: "ng/mL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "pg/ml", toUnit: "pg/mL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "g/dl", toUnit: "g/dL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "fl", toUnit: "fL", metricCode: null, multiplier: 1, offset: 0 }, + // Vitamin D: µg/L = ng/mL + { fromUnit: "\u00B5g/L", toUnit: "ng/mL", metricCode: "vitamin_d", multiplier: 1, offset: 0 }, + { fromUnit: "\u03BCg/L", toUnit: "ng/mL", metricCode: "vitamin_d", multiplier: 1, offset: 0 }, + // Albumin: g/L → g/dL + { fromUnit: "g/L", toUnit: "g/dL", metricCode: "albumin", multiplier: 0.1, offset: 0 }, + // MCV/MPV: µm3 = fL + { fromUnit: "\u00B5m3", toUnit: "fL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "\u03BCm3", toUnit: "fL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "um3", toUnit: "fL", metricCode: null, multiplier: 1, offset: 0 }, + // ApoA1: g/L → mg/dL + { fromUnit: "g/L", toUnit: "mg/dL", metricCode: "apoa1", multiplier: 100, offset: 0 }, + // LH: mUI/mL = mIU/mL + { fromUnit: "mUI/mL", toUnit: "mIU/mL", metricCode: null, multiplier: 1, offset: 0 }, + // x10^3/µL = K/uL, x10^6/µL = M/uL (Medisim format with superscript) + { fromUnit: "x10^3/\u00B5L", toUnit: "K/uL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "x10^3/uL", toUnit: "K/uL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "x10^6/\u00B5L", toUnit: "M/uL", metricCode: null, multiplier: 1, offset: 0 }, + { fromUnit: "x10^6/uL", toUnit: "M/uL", metricCode: null, multiplier: 1, offset: 0 }, ]) .onConflictDoNothing(); @@ -155,6 +191,31 @@ async function main() { .values(panelTemplateMetricSeeds) .onConflictDoNothing(); + // ── Romanian/EU lab supplements ──────────────────────────────────────── + console.log("Seeding additional metric definitions (Romanian/EU labs)..."); + await db + .insert(metricDefinitions) + .values(additionalMetricSeeds) + .onConflictDoNothing(); + + console.log("Applying alias updates..."); + for (const [metricId, newAliases] of Object.entries(aliasUpdates)) { + await db + .update(metricDefinitions) + .set({ + aliases: sql`${metricDefinitions.aliases}::jsonb || ${JSON.stringify(newAliases)}::jsonb`, + }) + .where(eq(metricDefinitions.id, metricId)); + } + + console.log("Applying display precision overrides..."); + for (const [metricId, precision] of Object.entries(displayPrecisionOverrides)) { + await db + .update(metricDefinitions) + .set({ displayPrecision: precision }) + .where(eq(metricDefinitions.id, metricId)); + } + console.log("Seed completed successfully."); }