Feature Store Registry
blockaiFeast 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.
Installation
$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/feature-store-registry.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/feature-store-registry.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/feature-store-registry.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/feature-store-registry.jsonNamed registry:
npx shadcn-vue@latest add @uipkge/feature-store-registryInstalls to:app/components/blocks/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
class | HTMLAttributes['class'] | — | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
FeatureDefinitioninterface FeatureDefinition {
name: string
dtype: 'Float64' | 'Int32' | 'String'
description: string
aggregationWindow: string
onlineCacheKey: string
freshness: string
status: 'Online & Batch Ready'
sourceSql: string
sampleValue: string
}MetricCardinterface 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, '&').replace(/</g, '<').replace(/>/g, '>') } function highlightPythonLine(line: string): string { if (!line.trim()) return ' ' 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 · < 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">< 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 & 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 & 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">< 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