{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "database-migration-schema-diff",
  "title": "Database Migration Schema Diff",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/database-migration-schema-diff/DatabaseMigrationSchemaDiff.vue",
      "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  AlertCircle,\n  ArrowRight,\n  Check,\n  CheckCircle2,\n  Clock,\n  Code2,\n  Copy,\n  Database,\n  FileCode2,\n  GitBranch,\n  GitCommit,\n  HardDrive,\n  Layers,\n  Loader2,\n  Play,\n  RotateCcw,\n  Server,\n  ShieldCheck,\n  Terminal,\n  Timer,\n  Undo2,\n  Zap,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Separator } from '@/components/ui/separator'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'\n\ninterface DiffLine {\n  num: number\n  type: 'addition' | 'modification' | 'deletion' | 'neutral'\n  prefix: string\n  text: string\n}\n\ninterface HistoricalMigration {\n  id: string\n  filename: string\n  version: string\n  description: string\n  appliedAt: string\n  author: string\n  executionTime: string\n  tablesAffected: string\n  status: 'applied' | 'pending' | 'rolled_back'\n  checksum: string\n}\n\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n}>()\n\nconst activeTab = ref('up')\nconst isApplying = ref(false)\nconst isApplied = ref(false)\nconst copiedUpSql = ref(false)\nconst copiedDownSql = ref(false)\nconst copiedCli = ref(false)\n\nconst upSqlRaw = `-- Up Migration\n-- Migration: 20260821142850_add_org_billing_seats_and_quotas.sql\n-- Target: public.organizations\n\nALTER TABLE public.organizations \n  ADD COLUMN billing_seats_allocated INTEGER NOT NULL DEFAULT 5,\n  ADD COLUMN max_seat_limit INTEGER NOT NULL DEFAULT 20,\n  ADD COLUMN last_seat_audit_at TIMESTAMPTZ DEFAULT NOW();\n\nCREATE INDEX idx_orgs_seat_audit ON public.organizations(last_seat_audit_at);`\n\nconst downSqlRaw = `-- Down Migration (Rollback)\n-- Reverts: 20260821142850_add_org_billing_seats_and_quotas.sql\n-- Target: public.organizations\n\nDROP INDEX IF EXISTS idx_orgs_seat_audit;\n\nALTER TABLE public.organizations \n  DROP COLUMN IF EXISTS billing_seats_allocated,\n  DROP COLUMN IF EXISTS max_seat_limit,\n  DROP COLUMN IF EXISTS last_seat_audit_at;`\n\nconst upDiffLines: DiffLine[] = [\n  { num: 1, type: 'neutral', prefix: ' ', text: '-- Up Migration' },\n  { num: 2, type: 'neutral', prefix: ' ', text: '-- Migration: 20260821142850_add_org_billing_seats_and_quotas.sql' },\n  { num: 3, type: 'neutral', prefix: ' ', text: '-- Target: public.organizations' },\n  { num: 4, type: 'neutral', prefix: ' ', text: '' },\n  { num: 5, type: 'modification', prefix: '~', text: 'ALTER TABLE public.organizations ' },\n  { num: 6, type: 'addition', prefix: '+', text: '  ADD COLUMN billing_seats_allocated INTEGER NOT NULL DEFAULT 5,' },\n  { num: 7, type: 'addition', prefix: '+', text: '  ADD COLUMN max_seat_limit INTEGER NOT NULL DEFAULT 20,' },\n  { num: 8, type: 'addition', prefix: '+', text: '  ADD COLUMN last_seat_audit_at TIMESTAMPTZ DEFAULT NOW();' },\n  { num: 9, type: 'neutral', prefix: ' ', text: '' },\n  {\n    num: 10,\n    type: 'addition',\n    prefix: '+',\n    text: 'CREATE INDEX idx_orgs_seat_audit ON public.organizations(last_seat_audit_at);',\n  },\n]\n\nconst downDiffLines: DiffLine[] = [\n  { num: 1, type: 'neutral', prefix: ' ', text: '-- Down Migration (Rollback)' },\n  { num: 2, type: 'neutral', prefix: ' ', text: '-- Reverts: 20260821142850_add_org_billing_seats_and_quotas.sql' },\n  { num: 3, type: 'neutral', prefix: ' ', text: '-- Target: public.organizations' },\n  { num: 4, type: 'neutral', prefix: ' ', text: '' },\n  { num: 5, type: 'deletion', prefix: '-', text: 'DROP INDEX IF EXISTS idx_orgs_seat_audit;' },\n  { num: 6, type: 'neutral', prefix: ' ', text: '' },\n  { num: 7, type: 'modification', prefix: '~', text: 'ALTER TABLE public.organizations ' },\n  { num: 8, type: 'deletion', prefix: '-', text: '  DROP COLUMN IF EXISTS billing_seats_allocated,' },\n  { num: 9, type: 'deletion', prefix: '-', text: '  DROP COLUMN IF EXISTS max_seat_limit,' },\n  { num: 10, type: 'deletion', prefix: '-', text: '  DROP COLUMN IF EXISTS last_seat_audit_at;' },\n]\n\nconst historicalMigrations: HistoricalMigration[] = [\n  {\n    id: 'mig_48',\n    filename: '20260814091522_add_audit_logs_partitioning.sql',\n    version: 'v2026.08.14.02',\n    description: 'Partition audit_logs table by month range and attach default tablespace',\n    appliedAt: 'Aug 14, 2026 · 09:15 UTC',\n    author: 'alex.chen@corp',\n    executionTime: '1.8s',\n    tablesAffected: 'audit_logs, audit_logs_2026_08',\n    status: 'applied',\n    checksum: 'sha256:4e8b39c0',\n  },\n  {\n    id: 'mig_47',\n    filename: '20260810143011_create_api_rate_limits_table.sql',\n    version: 'v2026.08.10.01',\n    description: 'Create rate_limits table & redis fallback synchronization schema',\n    appliedAt: 'Aug 10, 2026 · 14:30 UTC',\n    author: 'sarah.m@corp',\n    executionTime: '0.9s',\n    tablesAffected: 'api_rate_limits',\n    status: 'applied',\n    checksum: 'sha256:d12c88f1',\n  },\n  {\n    id: 'mig_46',\n    filename: '20260802110540_add_saml_sso_workspaces.sql',\n    version: 'v2026.08.02.03',\n    description: 'Add SAML SSO domain verification and enterprise IdP metadata records',\n    appliedAt: 'Aug 02, 2026 · 11:05 UTC',\n    author: 'devops-bot',\n    executionTime: '2.1s',\n    tablesAffected: 'workspaces, idp_configs',\n    status: 'applied',\n    checksum: 'sha256:88a3b114',\n  },\n  {\n    id: 'mig_45',\n    filename: '20260725184219_optimize_query_cache_indexes.sql',\n    version: 'v2026.07.25.01',\n    description: 'Add CONCURRENT B-Tree composite index on team_id + created_at timestamp',\n    appliedAt: 'Jul 25, 2026 · 18:42 UTC',\n    author: 'alex.chen@corp',\n    executionTime: '4.2s',\n    tablesAffected: 'query_logs, cache_entries',\n    status: 'applied',\n    checksum: 'sha256:fa2300b9',\n  },\n  {\n    id: 'mig_44',\n    filename: '20260718082005_init_multi_tenant_memberships.sql',\n    version: 'v2026.07.18.01',\n    description: 'Initialize organization_memberships, team_roles, and permission cascades',\n    appliedAt: 'Jul 18, 2026 · 08:20 UTC',\n    author: 'elena.r@corp',\n    executionTime: '1.2s',\n    tablesAffected: 'org_members, permissions',\n    status: 'applied',\n    checksum: 'sha256:56df9201',\n  },\n]\n\nfunction handleApplyMigration() {\n  if (isApplying.value || isApplied.value) return\n  isApplying.value = true\n  setTimeout(() => {\n    isApplying.value = false\n    isApplied.value = true\n  }, 900)\n}\n\nfunction handlePreviewRollback() {\n  activeTab.value = 'rollback'\n}\n\nfunction handleResetState() {\n  isApplied.value = false\n  isApplying.value = false\n}\n\nfunction copyActiveSql() {\n  copyToClipboard(\n    activeTab.value === 'rollback' ? downSqlRaw : upSqlRaw,\n    activeTab.value === 'rollback' ? 'down' : 'up',\n  )\n}\n\nfunction copyToClipboard(text: string, type: 'up' | 'down' | 'cli') {\n  navigator.clipboard.writeText(text)\n  if (type === 'up') {\n    copiedUpSql.value = true\n    setTimeout(() => {\n      copiedUpSql.value = false\n    }, 2000)\n  } else if (type === 'down') {\n    copiedDownSql.value = true\n    setTimeout(() => {\n      copiedDownSql.value = false\n    }, 2000)\n  } else if (type === 'cli') {\n    copiedCli.value = true\n    setTimeout(() => {\n      copiedCli.value = false\n    }, 2000)\n  }\n}\n</script>\n\n<template>\n  <div data-slot=\"database-migration-schema-diff\" :class=\"cn('w-full space-y-6', props.class)\">\n    <!-- Header: Target Database & Version Runner Status -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-4\">\n        <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n          <div class=\"space-y-1.5\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <div class=\"text-foreground flex items-center gap-2 text-base font-semibold sm:text-lg\">\n                <Database class=\"text-primary size-5 shrink-0\" />\n                <span>PostgreSQL 16.2 · production_primary_cluster</span>\n              </div>\n              <div\n                class=\"bg-success/10 text-success flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium\"\n              >\n                <span class=\"bg-success size-1.5 animate-pulse rounded-full\" />\n                <span>Connected</span>\n              </div>\n            </div>\n\n            <div class=\"text-muted-foreground flex flex-wrap items-center gap-2 text-xs sm:text-sm\">\n              <span class=\"text-foreground font-mono font-medium\">v2026.08.21.01_add_org_billing_seats</span>\n              <Separator orientation=\"vertical\" class=\"h-3.5\" />\n              <span>db.us-east-1.aws.neon.tech:5432</span>\n              <Separator orientation=\"vertical\" class=\"h-3.5\" />\n              <span>public schema</span>\n            </div>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <Badge wrap v-if=\"!isApplied\" variant=\"warning\" class=\"gap-1.5 px-2.5 py-1 text-xs\">\n              <Clock class=\"size-3.5\" />\n              <span>1 Pending Migration Ready to Apply</span>\n            </Badge>\n            <Badge wrap v-else variant=\"success\" class=\"gap-1.5 px-2.5 py-1 text-xs\">\n              <CheckCircle2 class=\"size-3.5\" />\n              <span>All Migrations Applied · In Sync</span>\n            </Badge>\n\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 text-xs font-medium shadow-xs active:scale-[0.98]\"\n              @click=\"handlePreviewRollback\"\n            >\n              <Undo2 class=\"text-muted-foreground size-3.5\" />\n              <span>Preview Rollback Script</span>\n            </Button>\n\n            <Button\n              v-if=\"!isApplied\"\n              variant=\"default\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 text-xs font-medium shadow-xs active:scale-[0.98]\"\n              :disabled=\"isApplying\"\n              @click=\"handleApplyMigration\"\n            >\n              <Loader2 v-if=\"isApplying\" class=\"size-3.5 animate-spin\" />\n              <Play v-else class=\"size-3.5 fill-current\" />\n              <span>{{ isApplying ? 'Applying Migration...' : 'Apply Migration (prisma migrate deploy)' }}</span>\n            </Button>\n\n            <Button\n              v-else\n              variant=\"secondary\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 text-xs font-medium active:scale-[0.98]\"\n              @click=\"handleResetState\"\n            >\n              <RotateCcw class=\"size-3.5\" />\n              <span>Reset State</span>\n            </Button>\n          </div>\n        </div>\n      </CardHeader>\n    </Card>\n\n    <!-- 4 Migration Telemetry Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <!-- Total Applied Migrations -->\n      <Card class=\"border-border bg-card shadow-xs\">\n        <CardContent class=\"p-4 sm:p-5\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Total Applied Migrations</span>\n            <div class=\"bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md\">\n              <Layers class=\"size-4\" />\n            </div>\n          </div>\n          <div class=\"mt-3\">\n            <div class=\"text-foreground text-2xl font-bold tracking-tight\">\n              {{ isApplied ? '49' : '48' }}\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">48 Migrations Applied · Baseline to v2026.08.14</p>\n          </div>\n          <div class=\"text-success mt-3 flex items-center gap-1.5 text-xs font-medium\">\n            <Check class=\"size-3.5\" />\n            <span>100% successful execution history</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- Pending Migrations -->\n      <Card :class=\"cn('border-border bg-card shadow-xs transition-colors', !isApplied && 'border-warning/40')\">\n        <CardContent class=\"p-4 sm:p-5\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Pending Migrations</span>\n            <div\n              :class=\"\n                cn(\n                  'flex size-8 items-center justify-center rounded-md',\n                  !isApplied ? 'bg-warning/10 text-warning' : 'bg-success/10 text-success',\n                )\n              \"\n            >\n              <Clock v-if=\"!isApplied\" class=\"size-4\" />\n              <CheckCircle2 v-else class=\"size-4\" />\n            </div>\n          </div>\n          <div class=\"mt-3\">\n            <div class=\"text-foreground text-2xl font-bold tracking-tight\">\n              {{ isApplied ? '0' : '1' }}\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">\n              {{ isApplied ? '0 Pending · Schema up to date' : '1 Pending Deployment' }}\n            </p>\n          </div>\n          <div\n            :class=\"\n              cn('mt-3 flex items-center gap-1.5 text-xs font-medium', !isApplied ? 'text-warning' : 'text-success')\n            \"\n          >\n            <ShieldCheck v-if=\"!isApplied\" class=\"size-3.5\" />\n            <Check v-else class=\"size-3.5\" />\n            <span>{{ !isApplied ? 'Safe DDL · Non-blocking ALTER' : 'Schema verified against shadow DB' }}</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- Last Migration Execution -->\n      <Card class=\"border-border bg-card shadow-xs\">\n        <CardContent class=\"p-4 sm:p-5\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Last Migration Execution</span>\n            <div class=\"bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md\">\n              <Zap class=\"size-4\" />\n            </div>\n          </div>\n          <div class=\"mt-3\">\n            <div class=\"text-foreground text-2xl font-bold tracking-tight\">\n              {{ isApplied ? '0.12s' : '3.4s' }}\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">3.4s execution time · 0 lock timeouts</p>\n          </div>\n          <div class=\"text-muted-foreground mt-3 flex items-center gap-1.5 text-xs\">\n            <Timer class=\"size-3.5\" />\n            <span>Zero query contention or lock waits</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- Target Schema Integrity -->\n      <Card class=\"border-border bg-card shadow-xs\">\n        <CardContent class=\"p-4 sm:p-5\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Target Schema Integrity</span>\n            <div class=\"bg-success/10 text-success flex size-8 items-center justify-center rounded-md\">\n              <ShieldCheck class=\"size-4\" />\n            </div>\n          </div>\n          <div class=\"mt-3\">\n            <div class=\"text-foreground text-2xl font-bold tracking-tight\">100%</div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">100% Validated · Zero Drift</p>\n          </div>\n          <div class=\"text-success mt-3 flex items-center gap-1.5 text-xs font-medium\">\n            <CheckCircle2 class=\"size-3.5\" />\n            <span>Prisma schema & DB in sync</span>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- Active Migration Inspector & DDL Diff Card -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"border-border border-b pb-4\">\n        <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n          <div class=\"space-y-1\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <FileCode2 class=\"text-primary size-4 shrink-0\" />\n              <CardTitle class=\"text-foreground font-mono text-sm font-semibold sm:text-base\">\n                20260821142850_add_org_billing_seats_and_quotas.sql\n              </CardTitle>\n              <Badge wrap v-if=\"!isApplied\" variant=\"warning\" class=\"text-xs\"> Pending DDL Execution </Badge>\n              <Badge wrap v-else variant=\"success\" class=\"text-xs\"> Applied in Production </Badge>\n            </div>\n            <CardDescription class=\"text-muted-foreground text-xs\">\n              Target Table: <span class=\"text-foreground font-mono font-medium\">public.organizations</span> · Author:\n              <span class=\"text-foreground\">alex.chen@corp</span> · Estimated duration:\n              <span class=\"text-foreground font-mono font-medium\">~120ms</span>\n            </CardDescription>\n          </div>\n\n          <div class=\"flex items-center gap-2\">\n            <Button variant=\"outline\" size=\"sm\" class=\"h-8 gap-1.5 text-xs font-medium\" @click=\"copyActiveSql\">\n              <Check v-if=\"activeTab === 'rollback' ? copiedDownSql : copiedUpSql\" class=\"text-success size-3.5\" />\n              <Copy v-else class=\"size-3.5\" />\n              <span>{{ (activeTab === 'rollback' ? copiedDownSql : copiedUpSql) ? 'Copied SQL' : 'Copy SQL' }}</span>\n            </Button>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-4 sm:p-6\">\n        <Tabs v-model=\"activeTab\" class=\"w-full space-y-4\">\n          <TabsList class=\"grid w-full grid-cols-2 sm:inline-flex sm:w-auto sm:grid-cols-none\">\n            <TabsTrigger value=\"up\" class=\"gap-1.5 text-xs\">\n              <Code2 class=\"size-3.5\" />\n              <span>DDL Diff (Up)</span>\n            </TabsTrigger>\n            <TabsTrigger value=\"rollback\" class=\"gap-1.5 text-xs\">\n              <Undo2 class=\"size-3.5\" />\n              <span>Rollback Script (Down)</span>\n            </TabsTrigger>\n            <TabsTrigger value=\"impact\" class=\"gap-1.5 text-xs\">\n              <HardDrive class=\"size-3.5\" />\n              <span>Schema Impact</span>\n            </TabsTrigger>\n            <TabsTrigger value=\"cli\" class=\"gap-1.5 text-xs\">\n              <Terminal class=\"size-3.5\" />\n              <span>Prisma / CLI Runner</span>\n            </TabsTrigger>\n          </TabsList>\n\n          <!-- Tab 1: DDL Diff (Up) -->\n          <TabsContent value=\"up\" class=\"space-y-3 focus-visible:outline-none\">\n            <div\n              class=\"border-border bg-muted/50 flex items-center justify-between rounded-t-md border-x border-t px-3 py-2 text-xs\"\n            >\n              <div class=\"text-muted-foreground flex items-center gap-2\">\n                <span class=\"text-foreground font-medium\">Forward Migration (Up)</span>\n                <span>·</span>\n                <span class=\"text-success font-medium\">+3 columns added</span>\n                <span>·</span>\n                <span class=\"text-info font-medium\">+1 index created</span>\n              </div>\n              <span class=\"text-muted-foreground font-mono\">SQL (PostgreSQL DDL)</span>\n            </div>\n\n            <div\n              class=\"border-border bg-muted/20 overflow-x-auto rounded-b-md border font-mono text-xs leading-relaxed\"\n            >\n              <div class=\"max-w-[540px] min-w-full py-2\">\n                <div\n                  v-for=\"line in upDiffLines\"\n                  :key=\"line.num\"\n                  :class=\"\n                    cn(\n                      'flex items-center px-3 py-0.5 transition-colors',\n                      line.type === 'addition' && 'border-success bg-success/10 text-success border-l-2 font-medium',\n                      line.type === 'modification' && 'border-info bg-info/10 text-info border-l-2 font-medium',\n                      line.type === 'neutral' && 'text-muted-foreground border-l-2 border-transparent',\n                    )\n                  \"\n                >\n                  <span class=\"text-muted-foreground/50 w-7 shrink-0 pr-3 text-right select-none\">{{ line.num }}</span>\n                  <span\n                    :class=\"\n                      cn(\n                        'w-4 shrink-0 text-center font-bold select-none',\n                        line.type === 'addition' && 'text-success',\n                        line.type === 'modification' && 'text-info',\n                        line.type === 'neutral' && 'text-transparent',\n                      )\n                    \"\n                    >{{ line.prefix }}</span\n                  >\n                  <span class=\"pl-1 whitespace-pre\">{{ line.text }}</span>\n                </div>\n              </div>\n            </div>\n          </TabsContent>\n\n          <!-- Tab 2: Rollback Script (Down) -->\n          <TabsContent value=\"rollback\" class=\"space-y-3 focus-visible:outline-none\">\n            <div\n              class=\"border-border bg-muted/50 flex items-center justify-between rounded-t-md border-x border-t px-3 py-2 text-xs\"\n            >\n              <div class=\"text-muted-foreground flex items-center gap-2\">\n                <span class=\"text-foreground font-medium\">Revert Script (Down)</span>\n                <span>·</span>\n                <span class=\"text-destructive font-medium\">-3 columns dropped</span>\n                <span>·</span>\n                <span class=\"text-destructive font-medium\">-1 index dropped</span>\n              </div>\n              <span class=\"text-muted-foreground font-mono\">SQL (PostgreSQL DDL)</span>\n            </div>\n\n            <div\n              class=\"border-border bg-muted/20 overflow-x-auto rounded-b-md border font-mono text-xs leading-relaxed\"\n            >\n              <div class=\"max-w-[540px] min-w-full py-2\">\n                <div\n                  v-for=\"line in downDiffLines\"\n                  :key=\"line.num\"\n                  :class=\"\n                    cn(\n                      'flex items-center px-3 py-0.5 transition-colors',\n                      line.type === 'deletion' &&\n                        'border-destructive bg-destructive/10 text-destructive border-l-2 font-medium',\n                      line.type === 'modification' && 'border-info bg-info/10 text-info border-l-2 font-medium',\n                      line.type === 'neutral' && 'text-muted-foreground border-l-2 border-transparent',\n                    )\n                  \"\n                >\n                  <span class=\"text-muted-foreground/50 w-7 shrink-0 pr-3 text-right select-none\">{{ line.num }}</span>\n                  <span\n                    :class=\"\n                      cn(\n                        'w-4 shrink-0 text-center font-bold select-none',\n                        line.type === 'deletion' && 'text-destructive',\n                        line.type === 'modification' && 'text-info',\n                        line.type === 'neutral' && 'text-transparent',\n                      )\n                    \"\n                    >{{ line.prefix }}</span\n                  >\n                  <span class=\"pl-1 whitespace-pre\">{{ line.text }}</span>\n                </div>\n              </div>\n            </div>\n          </TabsContent>\n\n          <!-- Tab 3: Schema Impact & Locks -->\n          <TabsContent value=\"impact\" class=\"space-y-4 focus-visible:outline-none\">\n            <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <div class=\"border-border bg-muted/30 space-y-3 rounded-lg border p-4\">\n                <div class=\"text-foreground flex items-center gap-2 text-sm font-medium\">\n                  <Database class=\"text-primary size-4 shrink-0\" />\n                  <span>Target Table & Column Additions</span>\n                </div>\n                <div class=\"space-y-2 text-xs\">\n                  <div class=\"border-border/60 bg-card flex items-center justify-between rounded-md border p-2\">\n                    <span class=\"text-foreground font-mono font-medium\">billing_seats_allocated</span>\n                    <Badge wrap variant=\"secondary\" class=\"font-mono text-xs\">INTEGER NOT NULL DEFAULT 5</Badge>\n                  </div>\n                  <div class=\"border-border/60 bg-card flex items-center justify-between rounded-md border p-2\">\n                    <span class=\"text-foreground font-mono font-medium\">max_seat_limit</span>\n                    <Badge wrap variant=\"secondary\" class=\"font-mono text-xs\">INTEGER NOT NULL DEFAULT 20</Badge>\n                  </div>\n                  <div class=\"border-border/60 bg-card flex items-center justify-between rounded-md border p-2\">\n                    <span class=\"text-foreground font-mono font-medium\">last_seat_audit_at</span>\n                    <Badge wrap variant=\"secondary\" class=\"font-mono text-xs\">TIMESTAMPTZ DEFAULT NOW()</Badge>\n                  </div>\n                </div>\n              </div>\n\n              <div class=\"border-border bg-muted/30 space-y-3 rounded-lg border p-4\">\n                <div class=\"text-foreground flex items-center gap-2 text-sm font-medium\">\n                  <ShieldCheck class=\"text-success size-4 shrink-0\" />\n                  <span>Lock Safety & Concurrency Evaluation</span>\n                </div>\n                <div class=\"text-muted-foreground space-y-2 text-xs\">\n                  <div class=\"border-border/60 bg-card flex items-center justify-between rounded-md border p-2\">\n                    <span>Lock Level Required</span>\n                    <span class=\"text-foreground font-mono font-medium\">ACCESS EXCLUSIVE (Catalog only)</span>\n                  </div>\n                  <div class=\"border-border/60 bg-card flex items-center justify-between rounded-md border p-2\">\n                    <span>Table Rewrite Required</span>\n                    <Badge wrap variant=\"success\" class=\"text-xs\">No (PG11+ Constant Default)</Badge>\n                  </div>\n                  <div class=\"border-border/60 bg-card flex items-center justify-between rounded-md border p-2\">\n                    <span>Estimated Lock Duration</span>\n                    <span class=\"text-success font-mono font-medium\">&lt; 2ms</span>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </TabsContent>\n\n          <!-- Tab 4: CLI Runner -->\n          <TabsContent value=\"cli\" class=\"space-y-3 focus-visible:outline-none\">\n            <div class=\"border-border bg-card space-y-3 rounded-lg border p-4\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"text-foreground flex items-center gap-2 text-xs font-medium\">\n                  <Terminal class=\"text-primary size-4 shrink-0\" />\n                  <span>Execute via Prisma CLI</span>\n                </div>\n                <Button\n                  variant=\"outline\"\n                  size=\"xs\"\n                  class=\"h-7 gap-1 text-xs\"\n                  @click=\"copyToClipboard('npx prisma migrate deploy --schema=./prisma/schema.prisma', 'cli')\"\n                >\n                  <Check v-if=\"copiedCli\" class=\"text-success size-3\" />\n                  <Copy v-else class=\"size-3\" />\n                  <span>{{ copiedCli ? 'Copied' : 'Copy' }}</span>\n                </Button>\n              </div>\n              <div class=\"bg-muted/60 text-foreground rounded-md p-3 font-mono text-xs select-all\">\n                npx prisma migrate deploy --schema=./prisma/schema.prisma\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                Applies all pending migrations to the configured datasource cluster without prompting for interactive\n                confirmation.\n              </p>\n            </div>\n          </TabsContent>\n        </Tabs>\n      </CardContent>\n    </Card>\n\n    <!-- Historical Migrations Table Card -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex items-center justify-between\">\n          <div>\n            <CardTitle class=\"text-foreground text-base font-semibold\"> Recent Applied Migrations </CardTitle>\n            <CardDescription class=\"text-muted-foreground text-xs\">\n              Historical DDL execution logs, author signatures, and validation checksums\n            </CardDescription>\n          </div>\n          <Badge wrap variant=\"outline\" class=\"font-mono text-xs\"> 5 Most Recent </Badge>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"overflow-x-auto\">\n          <Table>\n            <TableHeader>\n              <TableRow class=\"hover:bg-transparent\">\n                <TableHead class=\"text-xs font-medium\">Migration & Version</TableHead>\n                <TableHead class=\"text-xs font-medium\">Target Scope</TableHead>\n                <TableHead class=\"text-xs font-medium\">Executed At</TableHead>\n                <TableHead class=\"text-xs font-medium\">Author</TableHead>\n                <TableHead class=\"text-xs font-medium\">Duration</TableHead>\n                <TableHead class=\"text-right text-xs font-medium\">Status</TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              <TableRow\n                v-for=\"migration in historicalMigrations\"\n                :key=\"migration.id\"\n                class=\"hover:bg-muted/50 text-xs transition-colors\"\n              >\n                <TableCell class=\"py-3\">\n                  <div class=\"space-y-0.5\">\n                    <div class=\"text-foreground font-mono font-medium\">\n                      {{ migration.filename }}\n                    </div>\n                    <div class=\"text-muted-foreground flex items-center gap-1.5\">\n                      <span class=\"text-primary font-mono font-medium\">{{ migration.version }}</span>\n                      <span>·</span>\n                      <span>{{ migration.description }}</span>\n                    </div>\n                  </div>\n                </TableCell>\n                <TableCell class=\"text-muted-foreground font-mono whitespace-nowrap\">\n                  {{ migration.tablesAffected }}\n                </TableCell>\n                <TableCell class=\"text-muted-foreground whitespace-nowrap\">\n                  {{ migration.appliedAt }}\n                </TableCell>\n                <TableCell class=\"text-muted-foreground whitespace-nowrap\">\n                  {{ migration.author }}\n                </TableCell>\n                <TableCell class=\"text-foreground font-mono font-medium whitespace-nowrap\">\n                  {{ migration.executionTime }}\n                </TableCell>\n                <TableCell class=\"text-right whitespace-nowrap\">\n                  <Badge wrap variant=\"success\" class=\"gap-1 px-2 py-0.5 text-xs font-medium\">\n                    <CheckCircle2 class=\"size-3\" />\n                    <span>Applied</span>\n                  </Badge>\n                </TableCell>\n              </TableRow>\n            </TableBody>\n          </Table>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/DatabaseMigrationSchemaDiff.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/separator.json",
    "https://uipkge.dev/r/vue/table.json",
    "https://uipkge.dev/r/vue/tabs.json"
  ],
  "description": "Prisma, Flyway, and Liquibase database migration runner with pending DDL visual diffs, rollback scripts, schema integrity telemetry, and execution history.",
  "categories": [
    "devops",
    "app"
  ]
}