UIPackage
Menu

Framework

Change language

Boilerplate repo

Feature Store Registry

blockai

Feast and Tecton style machine learning feature store registry with entity definitions, low-latency Redis online cache status, Snowflake batch source lineage, feature schema inspection table, throughput metrics, and Python Feast feature view code generator.

Also available for React ->

Installation

$npx shadcn-vue@latest add https://uipkge.dev/r/vue/feature-store-registry.json
Named registry:npx shadcn-vue@latest add @uipkge/feature-store-registryInstalls to:app/components/blocks/

Variants

Loading interactive previews…

Props

NameType / ValuesDefaultRequired
classHTMLAttributes['class']optional

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

FeatureDefinition
interface FeatureDefinition {
  name: string
  dtype: 'Float64' | 'Int32' | 'String'
  description: string
  aggregationWindow: string
  onlineCacheKey: string
  freshness: string
  status: 'Online & Batch Ready'
  sourceSql: string
  sampleValue: string
}
MetricCard
interface MetricCard {
  title: string
  value: string
  subtitle: string
  badge: string
  icon: any
}

Files installed (1)

  • app/components/blocks/FeatureStoreRegistry.vue32.6 kB
    <script setup lang="ts">
    import { computed, ref } from 'vue'
    import type { HTMLAttributes } from 'vue'
    import {
      Activity,
      Check,
      CheckCircle2,
      Clock,
      Code2,
      Copy,
      Cpu,
      Database,
      Download,
      Fingerprint,
      Key,
      Layers,
      Loader2,
      Search,
      ShieldCheck,
      Table2,
      Workflow,
      Zap,
    } from 'lucide-vue-next'
    import { cn } from '@/lib/utils'
    import { Badge } from '@/components/ui/badge'
    import { Button } from '@/components/ui/button'
    import { Card, CardContent } from '@/components/ui/card'
    import { Input } from '@/components/ui/input'
    import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
    import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
    
    interface FeatureDefinition {
      name: string
      dtype: 'Float64' | 'Int32' | 'String'
      description: string
      aggregationWindow: string
      onlineCacheKey: string
      freshness: string
      status: 'Online & Batch Ready'
      sourceSql: string
      sampleValue: string
    }
    
    interface MetricCard {
      title: string
      value: string
      subtitle: string
      badge: string
      icon: any
    }
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    
    const activeTab = ref<'features' | 'python-feast' | 'lineage'>('features')
    const searchQuery = ref('')
    const selectedType = ref<'all' | 'Float64' | 'Int32' | 'String'>('all')
    const isMaterializing = ref(false)
    const materializeSuccess = ref(false)
    const isGeneratingDataset = ref(false)
    const datasetSuccess = ref(false)
    const copiedFeast = ref(false)
    const copiedKey = ref<string | null>(null)
    const selectedEntityId = ref('usr_9a4f201d-7e2b-4d68')
    
    const metrics: MetricCard[] = [
      {
        title: 'Total Features Registered',
        value: '18 Active Features',
        subtitle: '5 in this view · 4 views active',
        badge: '18 in Registry',
        icon: Layers,
      },
      {
        title: 'Online Cache Hit Rate',
        value: '99.8%',
        subtitle: '1.4ms p95 latency · Redis Cluster',
        badge: '< 2ms SLA',
        icon: Zap,
      },
      {
        title: 'Daily Ingestion Throughput',
        value: '14.8M Updates / Day',
        subtitle: '171.2 req/s avg · Stream + Batch',
        badge: 'Real-time CDC',
        icon: Activity,
      },
      {
        title: 'Max Point-in-Time TTL',
        value: '30 Days',
        subtitle: 'Lookback window · Anti-leakage safe',
        badge: 'AS-OF Safe',
        icon: Clock,
      },
    ]
    
    const features: FeatureDefinition[] = [
      {
        name: 'avg_transaction_value_30d',
        dtype: 'Float64',
        description: '30-day sliding average transaction amount in base USD currency',
        aggregationWindow: '30-day sliding mean',
        onlineCacheKey: 'user:ft:avg_tx_val_30d',
        freshness: 'Synced 4m ago',
        status: 'Online & Batch Ready',
        sourceSql: 'AVG(amount_usd) OVER (PARTITION BY user_id ROWS BETWEEN 30 PRECEDING AND CURRENT ROW)',
        sampleValue: '$342.80',
      },
      {
        name: 'failed_logins_24h',
        dtype: 'Int32',
        description: 'Failed authentication attempts in rolling 24-hour security window',
        aggregationWindow: '24-hour count',
        onlineCacheKey: 'user:ft:fail_login_24h',
        freshness: 'Synced 2m ago',
        status: 'Online & Batch Ready',
        sourceSql: 'SUM(CASE WHEN auth_success = FALSE THEN 1 ELSE 0 END)',
        sampleValue: '0',
      },
      {
        name: 'lifetime_chargeback_count',
        dtype: 'Int32',
        description: 'Total historical dispute and payment chargeback occurrences',
        aggregationWindow: 'Cumulative lifetime',
        onlineCacheKey: 'user:ft:cb_cnt_lt',
        freshness: 'Synced 12m ago',
        status: 'Online & Batch Ready',
        sourceSql: 'COUNT(chargeback_id) OVER (PARTITION BY user_id)',
        sampleValue: '0',
      },
      {
        name: 'preferred_payment_method',
        dtype: 'String',
        description: 'Most frequently utilized payment method category across checkout sessions',
        aggregationWindow: 'Mode category',
        onlineCacheKey: 'user:ft:pref_pay_method',
        freshness: 'Synced 18m ago',
        status: 'Online & Batch Ready',
        sourceSql: 'MODE(payment_method_code) OVER (PARTITION BY user_id)',
        sampleValue: '"apple_pay"',
      },
      {
        name: 'risk_score_ml_v3',
        dtype: 'Float64',
        description: 'Real-time XGBoost inference fraud risk score probability [0.0 - 1.0]',
        aggregationWindow: 'Real-time inference',
        onlineCacheKey: 'user:ft:risk_score_v3',
        freshness: 'Synced 1m ago',
        status: 'Online & Batch Ready',
        sourceSql: 'MODEL_PREDICT_FRAUD_V3(features)',
        sampleValue: '0.042',
      },
    ]
    
    const pythonFeastSource = `from datetime import timedelta
    from feast import (
        BatchSource,
        Entity,
        FeatureView,
        Field,
        SnowflakeSource,
        ValueType,
    )
    from feast.types import Float64, Int32, String
    
    # 1. Define Primary Entity
    user_entity = Entity(
        name="user_id",
        value_type=ValueType.STRING,
        join_keys=["user_id"],
        description="Global UUID representing verified consumer and business accounts",
    )
    
    # 2. Snowflake Gold DW Batch Offline Source
    transactions_batch_source = SnowflakeSource(
        database="ANALYTICS_PROD",
        schema="GOLD_MARTS",
        table="fct_user_transactions_daily",
        timestamp_field="event_timestamp",
        created_timestamp_column="created_at",
    )
    
    # 3. Dual-Store Feature View Definition (Redis Online + Snowflake Batch)
    user_30d_transaction_aggregates = FeatureView(
        name="user_30d_transaction_aggregates",
        entities=[user_entity],
        ttl=timedelta(days=30),
        schema=[
            Field(
                name="avg_transaction_value_30d",
                dtype=Float64,
                description="30-day sliding average transaction amount in base USD currency",
            ),
            Field(
                name="failed_logins_24h",
                dtype=Int32,
                description="Failed authentication attempts in rolling 24-hour security window",
            ),
            Field(
                name="lifetime_chargeback_count",
                dtype=Int32,
                description="Total historical dispute and payment chargeback occurrences",
            ),
            Field(
                name="preferred_payment_method",
                dtype=String,
                description="Most frequently utilized payment method category across checkout sessions",
            ),
            Field(
                name="risk_score_ml_v3",
                dtype=Float64,
                description="Real-time XGBoost inference fraud risk score probability [0.0 - 1.0]",
            ),
        ],
        online=True,
        source=transactions_batch_source,
        tags={
            "team": "fraud-ml",
            "tier": "tier-1-prod",
            "online_store": "redis_cluster",
            "batch_store": "snowflake_gold",
            "sla": "sub-2ms",
        },
    )`
    
    const pythonLines = computed(() => pythonFeastSource.split('\n'))
    
    const filteredFeatures = computed(() => {
      const query = searchQuery.value.trim().toLowerCase()
      return features.filter((f) => {
        const matchesSearch =
          !query ||
          f.name.toLowerCase().includes(query) ||
          f.description.toLowerCase().includes(query) ||
          f.onlineCacheKey.toLowerCase().includes(query) ||
          f.dtype.toLowerCase().includes(query)
        const matchesType = selectedType.value === 'all' || f.dtype === selectedType.value
        return matchesSearch && matchesType
      })
    })
    
    function escapeHtml(str: string): string {
      return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    }
    
    function highlightPythonLine(line: string): string {
      if (!line.trim()) return '&nbsp;'
      const escaped = escapeHtml(line)
    
      // Comments
      if (/^\s*#/.test(escaped)) {
        return `<span class="text-neutral-500 italic">${escaped}</span>`
      }
    
      // Each emitted <span> is parked behind a letter-only placeholder so a later
      // pass cannot match inside markup an earlier pass produced.
      const parked: string[] = []
      const park = (html: string) => {
        const key = String(parked.length)
          .split('')
          .map((d) => String.fromCharCode(97 + Number(d)))
          .join('')
        parked.push(html)
        return `\u0000${key}\u0000`
      }
    
      let res = escaped
    
      // Strings
      res = res.replace(/(["'])(?:(?=(\\?))\2.)*?\1/g, (match) =>
        park(`<span class="text-success font-normal">${match}</span>`),
      )
    
      // Keywords
      res = res.replace(
        /\b(from|import|def|class|return|as|True|False|None|with|for|in|and|or|not|is|if|else|elif)\b/g,
        (m) => park(`<span class="text-chart-1 font-semibold">${m}</span>`),
      )
    
      // Types / Feast Classes
      res = res.replace(
        /\b(Entity|FeatureView|Field|SnowflakeSource|BatchSource|ValueType|Float64|Int32|String|timedelta)\b/g,
        (m) => park(`<span class="text-warning font-medium">${m}</span>`),
      )
    
      // Arguments
      res = res.replace(
        /\b(name|value_type|join_keys|description|database|schema|table|timestamp_field|created_timestamp_column|entities|ttl|dtype|online|source|tags|days)\b(?=\s*=)/g,
        (m) => park(`<span class="text-info">${m}</span>`),
      )
    
      // Numbers
      res = res.replace(/\b(\d+)\b/g, (m) => park(`<span class="text-warning font-medium">${m}</span>`))
    
      // Restore every parked span
      return res.replace(/\u0000([a-j]+)\u0000/g, (_, key: string) => {
        const idx = Number(
          key
            .split('')
            .map((c: string) => String(c.charCodeAt(0) - 97))
            .join(''),
        )
        return parked[idx] ?? ''
      })
    }
    
    function copyToClipboard(text: string, type: 'code' | 'key', keyName?: string) {
      if (typeof navigator !== 'undefined' && navigator.clipboard) {
        navigator.clipboard.writeText(text)
        if (type === 'code') {
          copiedFeast.value = true
          setTimeout(() => {
            copiedFeast.value = false
          }, 2000)
        } else if (type === 'key' && keyName) {
          copiedKey.value = keyName
          setTimeout(() => {
            copiedKey.value = null
          }, 2000)
        }
      }
    }
    
    function handleMaterialize() {
      if (isMaterializing.value) return
      isMaterializing.value = true
      materializeSuccess.value = false
    
      setTimeout(() => {
        isMaterializing.value = false
        materializeSuccess.value = true
        setTimeout(() => {
          materializeSuccess.value = false
        }, 3000)
      }, 1200)
    }
    
    function handleGenerateDataset() {
      if (isGeneratingDataset.value) return
      isGeneratingDataset.value = true
      datasetSuccess.value = false
    
      setTimeout(() => {
        isGeneratingDataset.value = false
        datasetSuccess.value = true
        setTimeout(() => {
          datasetSuccess.value = false
        }, 3000)
      }, 1000)
    }
    </script>
    
    <template>
      <div
        data-slot="feature-store-registry"
        :class="
          cn(
            'bg-background text-foreground border-border flex w-full flex-col overflow-hidden rounded-xl border shadow-xs',
            props.class,
          )
        "
      >
        <!-- TOP FEATURE VIEW HEADER -->
        <header class="border-border bg-card/70 border-b px-4 py-4 sm:px-6">
          <div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
            <!-- Left: Title, Entity, Stores -->
            <div class="flex flex-wrap items-center gap-3">
              <div class="bg-primary/10 text-primary flex size-10 items-center justify-center rounded-lg shadow-xs">
                <Cpu class="size-5" />
              </div>
    
              <div class="flex flex-col gap-1">
                <div class="flex flex-wrap items-center gap-2">
                  <span class="text-muted-foreground font-mono text-xs">feature_view /</span>
                  <h1 class="text-foreground font-mono text-base font-bold tracking-tight break-all sm:text-lg">
                    user_30d_transaction_aggregates
                  </h1>
                  <Badge wrap variant="outline" class="font-mono text-xs font-normal">v2.4.0</Badge>
                </div>
    
                <!-- Metadata Badges Strip -->
                <div class="flex flex-wrap items-center gap-2 pt-0.5">
                  <!-- Entity Pill -->
                  <div
                    class="border-border bg-muted/40 text-foreground inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 font-mono text-xs"
                  >
                    <Key class="text-primary size-3" />
                    <span class="text-muted-foreground">Entity:</span>
                    <span class="font-semibold">user_id</span>
                    <span class="text-muted-foreground">[UUID]</span>
                  </div>
    
                  <!-- Online Store Pill -->
                  <div
                    class="border-success/30 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 font-mono text-xs font-medium"
                  >
                    <span class="bg-success size-1.5 animate-pulse rounded-full" />
                    <span>Redis Cluster · &lt; 2ms latency</span>
                  </div>
    
                  <!-- Batch Store Pill -->
                  <div
                    class="border-info/30 bg-info/10 text-info inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 font-mono text-xs font-medium"
                  >
                    <Database class="text-info size-3" />
                    <span>Snowflake Gold DW</span>
                  </div>
                </div>
              </div>
            </div>
    
            <!-- Right: Action Buttons -->
            <div class="flex flex-wrap items-center gap-2">
              <!-- Generate Training Dataset Button -->
              <Button
                aria-label="Download attachment"
                variant="outline"
                size="sm"
                class="h-9 gap-1.5 text-xs font-medium shadow-none"
                :disabled="isGeneratingDataset"
                @click="handleGenerateDataset"
              >
                <Loader2 v-if="isGeneratingDataset" class="size-3.5 animate-spin" />
                <Check v-else-if="datasetSuccess" class="text-success size-3.5" />
                <Download v-else class="size-3.5" />
                <span>{{
                  isGeneratingDataset
                    ? 'Building Parquet...'
                    : datasetSuccess
                      ? 'Dataset Exported (14.2 MB)'
                      : 'Generate Training Dataset'
                }}</span>
              </Button>
    
              <!-- Materialize Online Features Button -->
              <Button
                variant="default"
                size="sm"
                class="bg-primary text-primary-foreground hover:bg-primary/90 h-9 gap-1.5 text-xs font-semibold shadow-xs"
                :disabled="isMaterializing"
                @click="handleMaterialize"
              >
                <Loader2 v-if="isMaterializing" class="size-3.5 animate-spin" />
                <Check v-else-if="materializeSuccess" class="text-success size-3.5" />
                <Zap v-else class="size-3.5 fill-current" />
                <span>{{
                  isMaterializing
                    ? 'Syncing to Redis...'
                    : materializeSuccess
                      ? 'Materialized 18.4k Keys!'
                      : 'Materialize Online Features'
                }}</span>
              </Button>
            </div>
          </div>
        </header>
    
        <!-- 4 FEATURE STORE METRIC CARDS -->
        <div class="border-border bg-muted/15 border-b p-4 sm:p-6">
          <div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
            <Card
              v-for="metric in metrics"
              :key="metric.title"
              class="border-border bg-card hover:bg-muted/30 shadow-none transition-colors"
            >
              <CardContent class="flex flex-col justify-between gap-3 p-4">
                <div class="flex items-center justify-between">
                  <span class="text-muted-foreground text-xs font-medium">{{ metric.title }}</span>
                  <div class="bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md">
                    <component :is="metric.icon" class="size-3.5" />
                  </div>
                </div>
    
                <div>
                  <div class="text-foreground font-mono text-xl font-bold tracking-tight">
                    {{ metric.value }}
                  </div>
                  <div class="flex items-center justify-between pt-1 text-xs">
                    <span class="text-muted-foreground truncate">{{ metric.subtitle }}</span>
                    <Badge wrap variant="secondary" class="ml-1 shrink-0 font-mono text-xs font-normal">
                      {{ metric.badge }}
                    </Badge>
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>
        </div>
    
        <!-- MAIN TABS STUDIO -->
        <div class="flex flex-1 flex-col">
          <Tabs v-model="activeTab" default-value="features" class="flex flex-1 flex-col">
            <!-- Tabs Bar -->
            <div
              class="border-border bg-card flex flex-wrap items-center justify-between gap-3 border-b px-4 py-2.5 sm:px-6"
            >
              <TabsList class="grid h-9 grid-cols-3">
                <TabsTrigger value="features" class="gap-1.5 text-xs">
                  <Table2 class="text-primary size-3.5" />
                  <span>Feature Definitions</span>
                  <Badge wrap variant="secondary" class="ml-1 h-4 px-1 font-mono text-xs">{{ features.length }}</Badge>
                </TabsTrigger>
                <TabsTrigger value="python-feast" class="gap-1.5 text-xs">
                  <Code2 class="text-warning size-3.5" />
                  <span>Feast Definition</span>
                </TabsTrigger>
                <TabsTrigger value="lineage" class="gap-1.5 text-xs">
                  <Workflow class="text-info size-3.5" />
                  <span>Lineage & Architecture</span>
                </TabsTrigger>
              </TabsList>
    
              <div class="flex items-center gap-2">
                <Badge wrap variant="outline" class="text-success gap-1 font-mono text-xs">
                  <ShieldCheck class="size-3" />
                  <span>Redis Online Serving: ACTIVE</span>
                </Badge>
              </div>
            </div>
    
            <!-- TAB 1: FEATURE DEFINITIONS TABLE -->
            <TabsContent value="features" class="m-0 flex flex-1 flex-col space-y-5 p-4 sm:p-6">
              <!-- Filter / Search Controls -->
              <div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                <div class="flex flex-wrap items-center gap-2">
                  <div class="relative w-full sm:w-72">
                    <Search class="text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2" />
                    <Input
                      v-model="searchQuery"
                      placeholder="Filter by feature name, type, or cache key..."
                      class="h-8 pl-8 font-mono text-xs"
                    />
                  </div>
    
                  <!-- Type filter pills -->
                  <div class="flex items-center gap-1">
                    <button
                      v-for="t in ['all', 'Float64', 'Int32', 'String'] as const"
                      :key="t"
                      type="button"
                      :class="
                        cn(
                          'cursor-pointer rounded-md px-2 py-1 font-mono text-xs transition-colors',
                          selectedType === t
                            ? 'bg-primary text-primary-foreground font-medium shadow-xs'
                            : 'bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground',
                        )
                      "
                      @click="selectedType = t"
                    >
                      {{ t === 'all' ? 'All Types' : t }}
                    </button>
                  </div>
                </div>
    
                <div class="text-muted-foreground flex items-center gap-2 font-mono text-xs">
                  <span>Showing {{ filteredFeatures.length }} of {{ features.length }} features</span>
                </div>
              </div>
    
              <!-- Feature Definitions Table -->
              <Card class="border-border overflow-hidden border shadow-none">
                <div class="overflow-x-auto">
                  <Table>
                    <TableHeader>
                      <TableRow class="bg-muted/40 hover:bg-muted/40">
                        <TableHead class="text-xs font-semibold">Feature Name & Type</TableHead>
                        <TableHead class="text-xs font-semibold">Description & Aggregation Window</TableHead>
                        <TableHead class="text-xs font-semibold">Online Cache Key (Redis)</TableHead>
                        <TableHead class="text-xs font-semibold">Freshness</TableHead>
                        <TableHead class="text-xs font-semibold">Status</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      <TableRow v-for="feature in filteredFeatures" :key="feature.name" class="text-xs">
                        <!-- Feature Name & Type -->
                        <TableCell class="font-mono">
                          <div class="space-y-1">
                            <div class="text-foreground font-semibold tracking-tight">
                              {{ feature.name }}
                            </div>
                            <Badge
                              wrap
                              variant="secondary"
                              :class="
                                cn(
                                  'font-mono text-xs font-normal',
                                  feature.dtype === 'Float64' && 'border-warning/20 bg-warning/10 text-warning border',
                                  feature.dtype === 'Int32' && 'border-info/20 bg-info/10 text-info border',
                                  feature.dtype === 'String' && 'border-chart-1/20 bg-chart-1/10 text-chart-1 border',
                                )
                              "
                            >
                              {{ feature.dtype }}
                            </Badge>
                          </div>
                        </TableCell>
    
                        <!-- Description & Aggregation Window -->
                        <TableCell class="max-w-[280px]">
                          <div class="space-y-1">
                            <p class="text-muted-foreground text-xs leading-relaxed">
                              {{ feature.description }}
                            </p>
                            <Badge wrap variant="outline" class="gap-1 font-mono text-xs font-normal">
                              <Clock class="text-muted-foreground size-2.5" />
                              {{ feature.aggregationWindow }}
                            </Badge>
                          </div>
                        </TableCell>
    
                        <!-- Online Cache Key -->
                        <TableCell>
                          <button
                            type="button"
                            class="border-border/80 bg-muted/60 hover:bg-muted hover:border-primary/40 text-foreground group inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 font-mono text-xs transition-colors"
                            title="Click to copy Redis key"
                            @click="copyToClipboard(feature.onlineCacheKey, 'key', feature.name)"
                          >
                            <span class="text-primary font-semibold">GET</span>
                            <span>{{ feature.onlineCacheKey }}</span>
                            <Check v-if="copiedKey === feature.name" class="text-success size-3 transition-transform" />
                            <Copy v-else class="text-muted-foreground size-3 opacity-60 group-hover:opacity-100" />
                          </button>
                        </TableCell>
    
                        <!-- Freshness / Last Synced -->
                        <TableCell class="text-muted-foreground font-mono whitespace-nowrap">
                          <div class="flex items-center gap-1.5">
                            <Clock class="text-success size-3" />
                            <span>{{ feature.freshness }}</span>
                          </div>
                        </TableCell>
    
                        <!-- Feature Status -->
                        <TableCell class="whitespace-nowrap">
                          <Badge
                            wrap
                            variant="outline"
                            class="border-success/30 bg-success/10 text-success gap-1.5 font-mono text-xs font-medium"
                          >
                            <span class="bg-success size-1.5 rounded-full" />
                            {{ feature.status }}
                          </Badge>
                        </TableCell>
                      </TableRow>
                    </TableBody>
                  </Table>
                </div>
              </Card>
    
              <!-- Interactive Entity Live Feature Vector Inspector -->
              <Card class="border-border bg-card/60 space-y-4 border p-4 shadow-none sm:p-5">
                <div
                  class="border-border/80 flex flex-col gap-2 border-b pb-3 sm:flex-row sm:items-center sm:justify-between"
                >
                  <div class="flex flex-wrap items-center gap-2">
                    <Fingerprint class="text-primary size-4 shrink-0" />
                    <span class="text-foreground text-xs font-semibold">Live Online Feature Vector Lookup Simulator</span>
                    <Badge wrap variant="secondary" class="font-mono text-xs">feast.get_online_features()</Badge>
                  </div>
                  <div class="flex items-center gap-2">
                    <span class="text-muted-foreground font-mono text-xs">Target Entity:</span>
                    <span class="text-foreground font-mono text-xs font-semibold">{{ selectedEntityId }}</span>
                  </div>
                </div>
    
                <div class="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-5">
                  <div
                    v-for="feature in features"
                    :key="feature.name"
                    class="border-border/70 bg-muted/25 flex flex-col justify-between rounded-lg border p-3"
                  >
                    <div class="space-y-1">
                      <span class="text-muted-foreground block truncate font-mono text-xs font-medium">
                        {{ feature.name }}
                      </span>
                      <span class="text-muted-foreground text-xs">{{ feature.aggregationWindow }}</span>
                    </div>
                    <div
                      class="border-border/40 mt-3 flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 border-t pt-2"
                    >
                      <span class="text-foreground font-mono text-sm font-bold">{{ feature.sampleValue }}</span>
                      <span class="text-success font-mono text-xs">&lt; 1.2ms</span>
                    </div>
                  </div>
                </div>
              </Card>
            </TabsContent>
    
            <!-- TAB 2: PYTHON FEAST DEFINITION CODE BOX -->
            <TabsContent value="python-feast" class="m-0 flex flex-1 flex-col space-y-4 p-4 sm:p-6">
              <div class="border-border bg-muted/40 overflow-hidden rounded-xl border">
                <!-- Code Box Toolbar Header -->
                <div class="border-border bg-card flex items-center justify-between border-b px-4 py-2.5">
                  <div class="flex items-center gap-2">
                    <div class="bg-warning/10 text-warning flex size-6 items-center justify-center rounded">
                      <Code2 class="size-3.5" />
                    </div>
                    <span class="text-foreground font-mono text-xs font-semibold">
                      feature_definitions/user_aggregates.py
                    </span>
                    <Badge wrap variant="secondary" class="font-mono text-xs">Python 3.11 · Feast 0.42+</Badge>
                  </div>
    
                  <Button
                    variant="outline"
                    size="sm"
                    class="h-7 gap-1.5 text-xs font-medium"
                    @click="copyToClipboard(pythonFeastSource, 'code')"
                  >
                    <Check v-if="copiedFeast" class="text-success size-3" />
                    <Copy v-else class="size-3" />
                    <span>{{ copiedFeast ? 'Copied Feast Code!' : 'Copy Python Code' }}</span>
                  </Button>
                </div>
    
                <!-- Code Gutter and Syntax Highlighter -->
                <div
                  class="relative flex overflow-x-auto bg-neutral-950 font-mono text-xs leading-relaxed text-neutral-100 dark:bg-neutral-950"
                >
                  <!-- Line Numbers Gutter -->
                  <div
                    class="w-11 shrink-0 overflow-hidden border-r border-neutral-800 bg-neutral-900/60 py-3 pr-2 text-right text-neutral-500 select-none"
                  >
                    <div v-for="(_, idx) in pythonLines" :key="idx">{{ idx + 1 }}</div>
                  </div>
    
                  <!-- Python Code Content -->
                  <div class="flex-1 overflow-x-auto p-3 whitespace-pre select-text">
                    <div
                      v-for="(line, idx) in pythonLines"
                      :key="idx"
                      class="h-5 font-mono leading-5"
                      v-html="highlightPythonLine(line)"
                    />
                  </div>
                </div>
    
                <!-- Code Footer Meta -->
                <div
                  class="border-border/60 bg-muted/20 text-muted-foreground flex items-center justify-between border-t px-4 py-1.5 font-mono text-xs"
                >
                  <div class="flex items-center gap-3">
                    <span>{{ pythonLines.length }} lines</span>
                    <span>·</span>
                    <span>UTF-8</span>
                    <span>·</span>
                    <span>Feast Entity &amp; FeatureView DSL</span>
                  </div>
                  <div class="text-success flex items-center gap-1.5">
                    <CheckCircle2 class="size-3.5" />
                    <span>Valid Feast Schema Contract</span>
                  </div>
                </div>
              </div>
            </TabsContent>
    
            <!-- TAB 3: STORAGE & LINEAGE ARCHITECTURE -->
            <TabsContent value="lineage" class="m-0 flex flex-1 flex-col space-y-4 p-4 sm:p-6">
              <div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
                <!-- Offline Batch Lineage Card -->
                <Card class="border-border bg-card space-y-3 border p-5 shadow-none">
                  <div class="border-border flex items-center justify-between border-b pb-2.5">
                    <div class="flex items-center gap-2">
                      <Database class="text-info size-4" />
                      <span class="text-foreground text-xs font-semibold">Offline Batch Store Architecture</span>
                    </div>
                    <Badge wrap variant="secondary" class="font-mono text-xs">Snowflake Gold</Badge>
                  </div>
    
                  <p class="text-muted-foreground text-xs leading-relaxed">
                    Immutable historical logs for time-travel queries, training set generation, and AS-OF joins without
                    point-in-time data leakage.
                  </p>
    
                  <div class="border-border/60 bg-muted/20 space-y-2 rounded-lg border p-3 font-mono text-xs">
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Database &amp; Schema:</span>
                      <span class="text-foreground font-semibold">ANALYTICS_PROD.GOLD_MARTS</span>
                    </div>
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Source Table:</span>
                      <span class="text-foreground font-semibold">fct_user_transactions_daily</span>
                    </div>
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Timestamp Partition:</span>
                      <span class="text-foreground">event_timestamp (UTC)</span>
                    </div>
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Historical Depth:</span>
                      <span class="text-foreground">3 Years (Lookback TTL 30 Days)</span>
                    </div>
                  </div>
                </Card>
    
                <!-- Online Low-Latency Cache Card -->
                <Card class="border-border bg-card space-y-3 border p-5 shadow-none">
                  <div class="border-border flex items-center justify-between border-b pb-2.5">
                    <div class="flex items-center gap-2">
                      <Zap class="text-success size-4" />
                      <span class="text-foreground text-xs font-semibold">Online Key-Value Cache Architecture</span>
                    </div>
                    <Badge wrap variant="outline" class="border-success/30 text-success font-mono text-xs">
                      Redis 7.2 Cluster
                    </Badge>
                  </div>
    
                  <p class="text-muted-foreground text-xs leading-relaxed">
                    Ultra-low latency memory tier providing sub-2 millisecond retrieval for online model inference
                    microservices and fraud scoring.
                  </p>
    
                  <div class="border-border/60 bg-muted/20 space-y-2 rounded-lg border p-3 font-mono text-xs">
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Cluster Topology:</span>
                      <span class="text-foreground font-semibold">3 Master Shards + 3 Replicas</span>
                    </div>
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Key Prefix Pattern:</span>
                      <span class="text-foreground font-semibold">user:ft:{feature_name}</span>
                    </div>
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Read SLA (p95):</span>
                      <span class="text-success font-semibold">&lt; 1.4ms Latency</span>
                    </div>
                    <div class="flex justify-between">
                      <span class="text-muted-foreground">Materialization Schedule:</span>
                      <span class="text-foreground">Every 15 mins via Feast Job</span>
                    </div>
                  </div>
                </Card>
              </div>
            </TabsContent>
          </Tabs>
        </div>
      </div>
    </template>
    

Raw manifest:https://uipkge.dev/r/vue/feature-store-registry.json