Data Mesh Domain Catalog
blockdevopsZhamak Dehghani Data Mesh architecture domain catalog, Data Products directory, polyglot output ports (Snowflake, Kafka, GraphQL, S3), and federated computational governance SLA scorecards.
Installation
$pnpm dlx uipkge-ng@latest add data-mesh-domain-catalog$npx uipkge-ng@latest add data-mesh-domain-catalog$yarn dlx uipkge-ng@latest add data-mesh-domain-catalog$bunx uipkge-ng@latest add data-mesh-domain-catalogManifest:
https://uipkge.dev/r/angular/data-mesh-domain-catalog.jsonInstalls to:src/app/components/blocks/data-mesh-domain-catalog/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
IconSpecinterface IconSpec {
icon: LucideIconData
class: string
}DataMeshCopyEventinterface DataMeshCopyEvent {
text: string
identifier: string
}DomainMetainterface DomainMeta {
id: string
name: string
lead: string
role: string
productsCount: number
slaScore: number
activeConsumers: number
storageVolume: string
throughput: string
tier: string
description: string
iconName: 'CreditCard' | 'Users' | 'Truck' | 'Activity'
}OutputPortSchemaColumninterface OutputPortSchemaColumn {
name: string
type: string
nullable: boolean
isKey?: boolean
desc: string
constraints?: string
}OutputPortDetailsinterface OutputPortDetails {
id: DataMeshPortId
name: string
typeLabel: string
badgeVariant?: 'default' | 'secondary' | 'outline'
protocol: string
uri: string
accessRole: string
schemaRegistry?: string
format?: string
syncCadence?: string
throughput?: string
rateLimit?: string
columns?: OutputPortSchemaColumn[]
sampleQuery?: string
samplePayload?: string
mockResults?: Array<Record<string, string | number | boolean>>
}DataProductIteminterface DataProductItem {
id: string
name: string
displayName: string
domainId: string
domainName: string
version: string
tier: string
classification: 'PII-Confidential' | 'Financial-Audit' | 'Internal-Ops' | 'Platform-Internal'
description: string
contractHash: string
owner: {
name: string
role: string
handle: string
team: string
initials: string
avatar?: string
}
slaScore: number
freshnessLatency: string
uptime: string
assertionsPassed: number
assertionsTotal: number
activeConsumersCount: number
topConsumers: string[]
ports: OutputPortDetails[]
governancePolicies: string[]
}npm dependencies
Files installed (7)
src/app/components/blocks/data-mesh-domain-catalog/data-mesh-domain-catalog.component.ts25.9 kB
import { Component, DestroyRef, Input, OnInit, computed, inject, signal, ChangeDetectionStrategy } from '@angular/core' import { Activity, Copy, CreditCard, Database, Eye, FileCode2, HardDrive, KeyRound, Layers, LucideAngularModule, MoreHorizontal, Network, Plus, Search, ShieldCheck, Table2, Terminal, Truck, Users, Zap, type LucideIconData, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiAvatarComponent, UiAvatarFallbackComponent } from '@/ui/avatar/avatar.component' import { UiBadgeComponent, type BadgeVariant } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiDropdownMenuComponent, UiDropdownMenuContentComponent, UiDropdownMenuItemComponent, UiDropdownMenuLabelComponent, UiDropdownMenuSeparatorComponent, UiDropdownMenuTriggerComponent, } from '@/ui/dropdown-menu/dropdown-menu.component' import { UiProgressComponent } from '@/ui/progress/progress.component' import { UiTableBodyComponent, UiTableCellComponent, UiTableComponent, UiTableHeadComponent, UiTableHeaderComponent, UiTableRowComponent, } from '@/ui/table/table.component' import { UiDataMeshProductDetailComponent } from './data-mesh-product-detail.component' import { UiDataMeshQueryRunnerComponent } from './data-mesh-query-runner.component' import { UiDataMeshModalsComponent } from './data-mesh-modals.component' import { DOMAINS, DATA_PRODUCTS } from './data-mesh-data' import type { DomainMeta, OutputPortSchemaColumn, OutputPortDetails, DataProductItem, DataMeshPortId, } from './data-mesh-types' export type { DomainMeta, OutputPortSchemaColumn, OutputPortDetails, DataProductItem, DataMeshPortId } interface IconSpec { icon: LucideIconData class: string } const DOMAIN_ICONS: Record<DomainMeta['iconName'], IconSpec> = { CreditCard: { icon: CreditCard, class: 'text-chart-1 size-4' }, Users: { icon: Users, class: 'text-info size-4' }, Truck: { icon: Truck, class: 'text-warning size-4' }, Activity: { icon: Activity, class: 'text-success size-4' }, } const PORT_BADGE_ICONS: Record<DataMeshPortId, IconSpec> = { snowflake: { icon: Table2, class: 'text-info size-3' }, kafka: { icon: Zap, class: 'text-warning size-3' }, graphql: { icon: Network, class: 'size-3 text-pink-400' }, s3: { icon: HardDrive, class: 'text-success size-3' }, } /** * Data Mesh domain catalog: domain node cards, the data products table, the selected * product's output-port inspector, an inline query runner and the access / register modals. */ @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-data-mesh-domain-catalog, [ui-data-mesh-domain-catalog]', standalone: true, host: { class: 'contents' }, imports: [ LucideAngularModule, UiAvatarComponent, UiAvatarFallbackComponent, UiBadgeComponent, UiButtonComponent, UiDropdownMenuComponent, UiDropdownMenuContentComponent, UiDropdownMenuItemComponent, UiDropdownMenuLabelComponent, UiDropdownMenuSeparatorComponent, UiDropdownMenuTriggerComponent, UiProgressComponent, UiTableComponent, UiTableHeaderComponent, UiTableBodyComponent, UiTableRowComponent, UiTableHeadComponent, UiTableCellComponent, UiDataMeshProductDetailComponent, UiDataMeshQueryRunnerComponent, UiDataMeshModalsComponent, ], template: ` <div data-slot="data-mesh-domain-catalog" [class]="rootClass"> <!-- Modals: Request Access & Register Product (fixed overlays; first so the last visible section keeps no bottom margin) --> <ui-data-mesh-modals [accessModalOpen]="isAccessModalOpen()" (accessModalOpenChange)="isAccessModalOpen.set($event)" [registerModalOpen]="isRegisterModalOpen()" (registerModalOpenChange)="isRegisterModalOpen.set($event)" [product]="selectedProduct()" [domains]="domains" /> <!-- Header Section --> <header class="border-border bg-card/70 rounded-xl border p-4 sm:p-5"> <div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between"> <div class="space-y-2"> <!-- Top Row: Org Breadcrumb & Governance Status --> <div class="flex flex-wrap items-center gap-2 text-xs"> <div class="bg-primary/10 text-primary flex size-6 items-center justify-center rounded-md"> <lucide-icon [img]="Network" class="size-3.5" /> </div> <span class="text-foreground font-semibold">UIPKGE Global Data Mesh</span> <span class="text-muted-foreground font-mono">4 Core Domains</span> <div class="border-success/30 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 font-medium" > <span class="relative flex size-2"> <span class="bg-success absolute inline-flex size-full rounded-full opacity-75"></span> <span class="bg-success relative inline-flex size-2 rounded-full"></span> </span> <lucide-icon [img]="ShieldCheck" class="text-success size-3.5" /> <span>Federated Computational Governance Active</span> </div> </div> <!-- Main Title --> <h1 class="text-foreground text-xl font-bold tracking-tight sm:text-2xl"> Data Mesh Domain Catalog & Data Products Directory </h1> <p class="text-muted-foreground max-w-3xl text-xs leading-relaxed sm:text-sm"> Zhamak Dehghani architectural architecture for decentralized domain data ownership, discoverable polyglot output ports, and automated computational governance SLA scorecards. </p> </div> <!-- Header Action Button --> <div class="flex shrink-0 items-center gap-2 pt-1 lg:pt-0"> <button ui-button variant="default" size="sm" class="h-9 gap-1.5 text-xs font-medium" (click)="isRegisterModalOpen.set(true)" > <lucide-icon [img]="Plus" class="size-3.5" /> <span>Register New Data Product</span> </button> </div> </div> </header> <!-- 4 Domain Summary Cards --> <section class="space-y-3"> <div class="flex items-center justify-between gap-x-2 px-1"> <div class="flex items-center gap-2"> <lucide-icon [img]="Layers" class="text-primary size-4" /> <h2 class="text-foreground text-xs font-semibold tracking-wider uppercase"> Decentralized Domain Nodes (4) </h2> </div> <span class="text-muted-foreground text-xs">Click a domain card to filter Data Products</span> </div> <div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4"> @for (domain of domains; track domain.id) { <div [class]="domainCardClass(domain.id)" (click)="selectDomain(domain.id)"> <!-- Domain Card Header --> <div class="flex items-start justify-between gap-2"> <div class="flex items-center gap-2.5"> <div class="bg-muted border-border/80 flex size-8 shrink-0 items-center justify-center rounded-lg border" > <lucide-icon [img]="domainIcon(domain).icon" [class]="domainIcon(domain).class" /> </div> <div> <h3 class="text-foreground leading-tight font-semibold">{{ domain.name }}</h3> <span class="text-muted-foreground text-xs">{{ domain.productsCount }} Data Products</span> </div> </div> <span ui-badge [variant]="selectedDomainFilter() === domain.id ? 'default' : 'secondary'" class="shrink-0 font-mono text-xs" > {{ selectedDomainFilter() === domain.id ? 'Filtered' : domain.slaScore + '% SLA' }} </span> </div> <!-- Domain Description --> <p class="text-muted-foreground line-clamp-2 leading-relaxed">{{ domain.description }}</p> <!-- Domain Meta & Operational Metrics --> <div class="border-border/60 grid grid-cols-2 gap-2 border-t pt-2.5 text-xs"> <div> <span class="text-muted-foreground block">Storage Vol</span> <span class="text-foreground font-mono font-medium">{{ domain.storageVolume }}</span> </div> <div> <span class="text-muted-foreground block">Throughput</span> <span class="text-foreground font-mono font-medium">{{ domain.throughput }}</span> </div> </div> <!-- Domain Lead Info --> <div class="bg-muted/50 flex items-center justify-between gap-x-2 rounded-lg px-2.5 py-1.5"> <div class="flex items-center gap-1.5 overflow-hidden"> <ui-avatar class="size-4.5 shrink-0"> <ui-avatar-fallback class="text-xs">{{ initialsOf(domain.lead) }}</ui-avatar-fallback> </ui-avatar> <span class="text-foreground truncate font-medium">{{ domain.lead }}</span> </div> <span class="text-muted-foreground shrink-0 font-mono text-xs"> {{ domain.activeConsumers }} clients </span> </div> </div> } </div> </section> <!-- Data Products Table Section --> <section class="border-border bg-card space-y-4 rounded-xl border p-4 shadow-xs sm:p-5"> <!-- Toolbar: Title, Search, Port Type Selector --> <div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"> <div class="space-y-0.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Database" class="text-primary size-4" /> <h2 class="text-foreground text-sm font-semibold">Data Products Catalog</h2> <span ui-badge variant="outline" class="font-mono text-xs"> {{ filteredDataProducts().length }} / {{ dataProducts.length }} </span> </div> <p class="text-muted-foreground text-xs"> Autonomous product quantum nodes adhering to computational policies and explicit input/output schemas. </p> </div> <div class="flex flex-wrap items-center gap-2"> <!-- Port Filter Selector --> <div class="flex items-center gap-1.5"> <span class="text-muted-foreground text-xs font-medium">Output:</span> <select (change)="selectedPortTypeFilter.set(valueOf($event))" class="border-border bg-background text-foreground focus-visible:ring-ring h-8 rounded-md border px-2.5 text-xs outline-none focus-visible:ring-1" > @for (opt of portFilterOptions; track opt.value) { <option [value]="opt.value" [selected]="selectedPortTypeFilter() === opt.value"> {{ opt.label }} </option> } </select> </div> <!-- Search Input --> <div class="relative w-full sm:w-56"> <lucide-icon [img]="Search" class="text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2" /> <input [value]="searchQuery()" (input)="searchQuery.set(valueOf($event))" placeholder="Search product, owner, domain..." class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8 w-full rounded-md border pr-3 pl-8 text-xs outline-none focus-visible:ring-1" /> </div> </div> </div> <!-- Main Data Products Table --> <div class="border-border overflow-x-auto rounded-lg border"> <div ui-table> <thead ui-table-header> <tr ui-table-row class="bg-muted/40"> <th ui-table-head class="text-xs">Data Product & Contract</th> <th ui-table-head class="text-xs">Domain Node</th> <th ui-table-head class="text-xs">Freshness SLA</th> <th ui-table-head class="text-xs">Active Output Ports</th> <th ui-table-head class="text-xs">Consumers & Traffic</th> <th ui-table-head class="text-right text-xs">Actions</th> </tr> </thead> <tbody ui-table-body> @for (product of filteredDataProducts(); track product.id) { <tr ui-table-row [class]="rowClass(product.id)" (click)="selectProduct(product)"> <!-- Name & Contract --> <td ui-table-cell class="py-3"> <div class="space-y-1"> <div class="flex items-center gap-2"> <span class="text-foreground font-semibold">{{ product.displayName }}</span> <span ui-badge variant="outline" class="font-mono text-xs">v{{ product.version }}</span> </div> <div class="flex items-center gap-1.5 text-xs"> <code class="text-muted-foreground font-mono">{{ product.name }}</code> <span class="text-muted-foreground/40">·</span> <span ui-badge [variant]="classificationVariant(product)" class="text-xs"> {{ product.classification }} </span> </div> </div> </td> <!-- Domain Node & Owner --> <td ui-table-cell class="py-3"> <div class="space-y-1"> <span class="text-foreground text-xs font-medium">{{ product.domainName }}</span> <div class="flex items-center gap-1.5"> <ui-avatar class="size-4 shrink-0"> <ui-avatar-fallback class="text-xs">{{ product.owner.initials }}</ui-avatar-fallback> </ui-avatar> <span class="text-muted-foreground text-xs">{{ product.owner.name }}</span> </div> </div> </td> <!-- SLA & Quality Telemetry --> <td ui-table-cell class="py-3"> <div class="w-36 space-y-1.5"> <div class="flex items-center justify-between text-xs"> <span class="text-muted-foreground font-mono">SLA Score</span> <span class="text-success font-mono font-semibold">{{ product.slaScore }}%</span> </div> <ui-progress [value]="product.slaScore" class="h-1.5" /> <div class="text-muted-foreground flex items-center justify-between font-mono text-xs"> <span>Latency: {{ product.freshnessLatency }}</span> <span>{{ product.assertionsPassed }}/{{ product.assertionsTotal }} Checks</span> </div> </div> </td> <!-- Active Output Ports Badges --> <td ui-table-cell class="py-3"> <div class="flex flex-wrap gap-1.5"> @for (port of product.ports; track port.id) { <span ui-badge [variant]=" port.id === activePortId() && selectedProductId() === product.id ? 'default' : 'secondary' " class="h-6 gap-1 font-mono text-xs" > <lucide-icon [img]="portBadgeIcon(port.id).icon" [class]="portBadgeIcon(port.id).class" /> <span>{{ port.id.toUpperCase() }}</span> </span> } </div> </td> <!-- Consumers & Volume --> <td ui-table-cell class="py-3"> <div class="space-y-0.5 text-xs"> <div class="flex items-center gap-1 text-xs"> <lucide-icon [img]="Users" class="text-muted-foreground size-3" /> <span class="text-foreground font-semibold">{{ product.activeConsumersCount }}</span> <span class="text-muted-foreground">registered apps</span> </div> <p class="text-muted-foreground truncate font-mono text-xs"> {{ product.topConsumers.slice(0, 2).join(', ') }} </p> </div> </td> <!-- Row Action Dropdown --> <td ui-table-cell class="py-3 text-right" (click)="$event.stopPropagation()"> <ui-dropdown-menu> <button ui-button ui-dropdown-menu-trigger variant="ghost" size="sm" class="size-8 p-0"> <lucide-icon [img]="MoreHorizontal" class="size-4" /> </button> <ui-dropdown-menu-content align="end" class="w-48 text-xs"> <ui-dropdown-menu-label class="text-xs">Product Actions</ui-dropdown-menu-label> <ui-dropdown-menu-item class="cursor-pointer gap-2" (select)="selectProduct(product)"> <lucide-icon [img]="Eye" class="size-3.5" /> <span>View Specifications</span> </ui-dropdown-menu-item> <ui-dropdown-menu-item class="cursor-pointer gap-2" (select)="handleOpenQueryRunner(product)"> <lucide-icon [img]="Terminal" class="text-primary size-3.5" /> <span>Interactive Query Runner</span> </ui-dropdown-menu-item> <ui-dropdown-menu-item class="cursor-pointer gap-2" (select)="handleOpenAccessModal(product)"> <lucide-icon [img]="KeyRound" class="text-warning size-3.5" /> <span>Request Consumer Access</span> </ui-dropdown-menu-item> <ui-dropdown-menu-separator /> <ui-dropdown-menu-item class="cursor-pointer gap-2" (select)="copyToClipboard(product.ports[0]?.uri || '', product.id)" > <lucide-icon [img]="Copy" class="size-3.5" /> <span>Copy Primary Port URI</span> </ui-dropdown-menu-item> <ui-dropdown-menu-item class="cursor-pointer gap-2" (select)="copyToClipboard(product.contractHash, product.contractHash)" > <lucide-icon [img]="FileCode2" class="text-chart-2 size-3.5" /> <span>Copy Contract Hash</span> </ui-dropdown-menu-item> </ui-dropdown-menu-content> </ui-dropdown-menu> </td> </tr> } </tbody> </div> </div> </section> <!-- Data Product Output Port Architecture & Governance Card (Selected Product) --> <section ui-data-mesh-product-detail [product]="selectedProduct()" [port]="activePort()" [activePortId]="activePortId()" [copiedKey]="copiedUri()" (portChange)="activePortId.set($event)" (copyText)="copyToClipboard($event.text, $event.identifier)" (requestAccess)="handleOpenAccessModal($event)" (runQuery)="handleOpenQueryRunner($event)" ></section> <!-- Interactive Drawer / Modal: Query Output Port --> @if (isQueryDrawerOpen()) { <div ui-data-mesh-query-runner [product]="selectedProduct()" [port]="activePort()" [isSimulatingQuery]="isSimulatingQuery()" (closed)="isQueryDrawerOpen.set(false)" (runQuery)="runSimulatedQuery()" ></div> } </div> `, }) export class UiDataMeshDomainCatalogComponent implements OnInit { @Input('class') className?: string @Input() initialSelectedProductId = 'dp_customer_360_profile' @Input() initialDomainFilter = 'all' readonly domains: DomainMeta[] = DOMAINS readonly dataProducts: DataProductItem[] = DATA_PRODUCTS readonly portFilterOptions = [ { value: 'all', label: 'All Ports' }, { value: 'snowflake', label: 'Snowflake View' }, { value: 'kafka', label: 'Kafka Stream' }, { value: 'graphql', label: 'GraphQL Mesh' }, { value: 's3', label: 'S3 Delta Lake' }, ] readonly selectedDomainFilter = signal('all') readonly selectedPortTypeFilter = signal('all') readonly searchQuery = signal('') readonly selectedProductId = signal('dp_customer_360_profile') readonly activePortId = signal<DataMeshPortId>('snowflake') readonly copiedUri = signal<string | null>(null) // Modals & drawer state readonly isAccessModalOpen = signal(false) readonly isRegisterModalOpen = signal(false) readonly isQueryDrawerOpen = signal(false) readonly isSimulatingQuery = signal(false) readonly selectedProduct = computed<DataProductItem>( () => this.dataProducts.find((p) => p.id === this.selectedProductId()) || this.dataProducts[0]!, ) readonly activePort = computed<OutputPortDetails>(() => { const ports = this.selectedProduct().ports return ports.find((p) => p.id === this.activePortId()) || ports[0]! }) readonly filteredDataProducts = computed(() => { const domain = this.selectedDomainFilter() const portType = this.selectedPortTypeFilter() const query = this.searchQuery() return this.dataProducts.filter((product) => { if (domain !== 'all' && product.domainId !== domain) return false if (portType !== 'all' && !product.ports.some((p) => p.id === portType)) return false if (query.trim()) { const q = query.toLowerCase() const matches = [product.name, product.displayName, product.domainName, product.owner.name, product.description] .map((s) => s.toLowerCase()) .some((s) => s.includes(q)) if (!matches) return false } return true }) }) private readonly timers = new Set<ReturnType<typeof setTimeout>>() constructor() { inject(DestroyRef).onDestroy(() => this.timers.forEach((t) => clearTimeout(t))) } ngOnInit(): void { this.selectedDomainFilter.set(this.initialDomainFilter) this.selectedProductId.set(this.initialSelectedProductId) } get rootClass(): string { return cn( 'bg-background text-foreground border-border w-full space-y-6 rounded-xl border p-4 shadow-xs sm:p-6', this.className, ) } domainCardClass(domainId: string): string { return cn( 'group relative cursor-pointer space-y-3 rounded-xl border p-4 text-xs shadow-xs transition-colors', this.selectedDomainFilter() === domainId ? 'border-primary bg-primary/5 ring-primary/30 ring-1' : 'border-border bg-card hover:border-border/80 hover:bg-muted/30', ) } rowClass(productId: string): string { return cn( 'hover:bg-muted/50 cursor-pointer transition-colors', this.selectedProductId() === productId && 'bg-primary/5 font-medium', ) } domainIcon(domain: DomainMeta): IconSpec { return DOMAIN_ICONS[domain.iconName] } portBadgeIcon(id: DataMeshPortId): IconSpec { return PORT_BADGE_ICONS[id] } classificationVariant(product: DataProductItem): BadgeVariant { if (product.classification === 'PII-Confidential') return 'destructive' if (product.classification === 'Financial-Audit') return 'default' return 'secondary' } initialsOf(name: string): string { return name .split(' ') .map((n) => n[0]) .join('') } valueOf(event: Event): string { return (event.target as HTMLInputElement | HTMLSelectElement).value } selectDomain(domainId: string): void { this.selectedDomainFilter.set(this.selectedDomainFilter() === domainId ? 'all' : domainId) } selectProduct(product: DataProductItem): void { this.selectedProductId.set(product.id) const first = product.ports[0] if (first) this.activePortId.set(first.id) } copyToClipboard(text: string, identifier: string): void { if (typeof navigator !== 'undefined' && navigator.clipboard) { navigator.clipboard.writeText(text).catch(() => {}) this.copiedUri.set(identifier) this.later(() => this.copiedUri.set(null), 2000) } } runSimulatedQuery(): void { this.isSimulatingQuery.set(true) this.later(() => this.isSimulatingQuery.set(false), 1000) } handleOpenAccessModal(product: DataProductItem): void { this.selectProduct(product) this.isAccessModalOpen.set(true) } handleOpenQueryRunner(product: DataProductItem): void { this.selectProduct(product) this.isQueryDrawerOpen.set(true) } private later(fn: () => void, ms: number): void { const t = setTimeout(() => { this.timers.delete(t) fn() }, ms) this.timers.add(t) } protected readonly Copy = Copy protected readonly Database = Database protected readonly Eye = Eye protected readonly FileCode2 = FileCode2 protected readonly KeyRound = KeyRound protected readonly Layers = Layers protected readonly MoreHorizontal = MoreHorizontal protected readonly Network = Network protected readonly Plus = Plus protected readonly Search = Search protected readonly ShieldCheck = ShieldCheck protected readonly Terminal = Terminal protected readonly Users = Users }src/app/components/blocks/data-mesh-domain-catalog/data-mesh-product-detail.component.ts18 kB
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from '@angular/core' import { Boxes, Check, Copy, Database, FileCode2, HardDrive, KeyRound, LucideAngularModule, Network, Package, Radio, Server, ShieldCheck, Terminal, Users, Zap, type LucideIconData, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiTableBodyComponent, UiTableCellComponent, UiTableComponent, UiTableHeadComponent, UiTableHeaderComponent, UiTableRowComponent, } from '@/ui/table/table.component' import type { DataProductItem, OutputPortDetails, DataMeshPortId } from './data-mesh-types' export type { DataMeshPortId } export interface DataMeshCopyEvent { text: string identifier: string } interface IconSpec { icon: LucideIconData class: string } const PORT_TAB_ICONS: Record<DataMeshPortId, IconSpec> = { snowflake: { icon: Database, class: 'text-info size-3.5' }, kafka: { icon: Zap, class: 'text-warning size-3.5' }, graphql: { icon: Network, class: 'text-chart-1 size-3.5' }, s3: { icon: HardDrive, class: 'text-success size-3.5' }, } /** Selected data product inspector: pillars, output port tabs, schema, sample code and governance scorecard. */ @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-data-mesh-product-detail, [ui-data-mesh-product-detail]', standalone: true, host: { class: 'border-border bg-card/60 block space-y-6 rounded-xl border p-4 sm:p-6' }, imports: [ LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiTableComponent, UiTableHeaderComponent, UiTableBodyComponent, UiTableRowComponent, UiTableHeadComponent, UiTableCellComponent, ], template: ` <!-- Section Header with Selected Product Meta --> <div class="border-border/80 flex flex-col gap-3 border-b pb-4 lg:flex-row lg:items-start lg:justify-between"> <div class="space-y-1.5"> <div class="flex flex-wrap items-center gap-2"> <div class="bg-primary/10 text-primary flex size-6 items-center justify-center rounded-md"> <lucide-icon [img]="Boxes" class="size-3.5" /> </div> <span class="text-muted-foreground font-mono text-xs">Inspecting Quantum Architecture:</span> <h2 class="text-foreground font-mono text-base font-bold break-all sm:text-lg">{{ product.name }}</h2> <span ui-badge variant="secondary" class="font-mono text-xs">{{ product.version }}</span> <span ui-badge variant="outline" class="font-mono text-xs">{{ product.domainName }}</span> </div> <p class="text-muted-foreground text-xs sm:text-sm">{{ product.description }}</p> </div> <div class="flex flex-wrap items-center gap-2"> <!-- Contract Hash copy pill --> <div class="border-border bg-background inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs"> <span class="text-muted-foreground font-mono">Contract:</span> <span class="text-foreground font-mono">{{ product.contractHash.slice(0, 16) }}...</span> <button ui-button variant="ghost" size="sm" class="h-5 px-1 text-xs" (click)="emitCopy(product.contractHash, 'hash')" > @if (copiedKey === 'hash') { <lucide-icon [img]="Check" class="text-success size-3" /> } @else { <lucide-icon [img]="Copy" class="size-3" /> } </button> </div> <button ui-button variant="outline" size="sm" class="h-8.5 gap-1.5 text-xs" (click)="requestAccess.emit(product)" > <lucide-icon [img]="KeyRound" class="text-warning size-3.5" /> <span>Request Port Access</span> </button> <button ui-button variant="default" size="sm" class="h-8.5 gap-1.5 text-xs" (click)="runQuery.emit(product)"> <lucide-icon [img]="Terminal" class="size-3.5" /> <span>Run Port Query</span> </button> </div> </div> <!-- 4 Core Pillars of Data Mesh Architecture Banner --> <div class="grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-4"> <div class="border-border bg-background/80 space-y-1 rounded-lg border p-3 text-xs"> <div class="text-primary flex items-center gap-1.5 font-semibold"> <lucide-icon [img]="Users" class="size-3.5" /> <span>1. Domain Ownership</span> </div> <p class="text-muted-foreground text-xs leading-relaxed"> Autonomous squad accountability: <span class="text-foreground font-medium">{{ product.owner.name }}</span> ({{ product.owner.team }}). </p> </div> <div class="border-border bg-background/80 space-y-1 rounded-lg border p-3 text-xs"> <div class="text-success flex items-center gap-1.5 font-semibold"> <lucide-icon [img]="Package" class="size-3.5" /> <span>2. Data as a Product</span> </div> <p class="text-muted-foreground text-xs leading-relaxed"> Standardized contract with <span class="text-foreground font-mono font-medium">{{ product.slaScore }}% SLA</span> and automated test assertions. </p> </div> <div class="border-border bg-background/80 space-y-1 rounded-lg border p-3 text-xs"> <div class="text-info flex items-center gap-1.5 font-semibold"> <lucide-icon [img]="Server" class="size-3.5" /> <span>3. Self-Serve Platform</span> </div> <p class="text-muted-foreground text-xs leading-relaxed"> Polyglot multi-modal output endpoints: SQL, Event Stream, API & Parquet Lake. </p> </div> <div class="border-border bg-background/80 space-y-1 rounded-lg border p-3 text-xs"> <div class="text-warning flex items-center gap-1.5 font-semibold"> <lucide-icon [img]="ShieldCheck" class="size-3.5" /> <span>4. Computational Gov</span> </div> <p class="text-muted-foreground text-xs leading-relaxed"> Policy-as-code OPA masking, SOC2 audit trail & automated RBAC grants. </p> </div> </div> <!-- Output Ports Multi-Modal Tabs --> <div class="space-y-4"> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="flex items-center gap-2"> <lucide-icon [img]="Radio" class="text-primary size-4" /> <h3 class="text-foreground text-xs font-semibold tracking-wider uppercase"> Output Ports & Endpoints ({{ product.ports.length }}) </h3> </div> <!-- Port selector tabs --> <div class="border-border bg-muted/60 inline-flex items-center gap-1 rounded-lg border p-1"> @for (p of product.ports; track p.id) { <button type="button" [class]="portTabClass(p.id)" (click)="portChange.emit(p.id)"> <lucide-icon [img]="portTabIcon(p.id).icon" [class]="portTabIcon(p.id).class" /> <span>{{ p.name }}</span> </button> } </div> </div> <!-- Active Port Deep Inspector Container --> <div class="border-border bg-background space-y-4 rounded-xl border p-4 sm:p-5"> <!-- Port Meta Bar --> <div class="border-border/80 flex flex-col gap-3 border-b pb-3 lg:flex-row lg:items-center lg:justify-between"> <div class="space-y-1"> <div class="flex flex-wrap items-center gap-2"> <span class="text-foreground font-mono text-sm font-bold">{{ port.name }}</span> <span ui-badge variant="secondary" class="font-mono text-xs">{{ port.protocol }}</span> <span ui-badge variant="outline" class="font-mono text-xs">{{ port.accessRole }}</span> </div> <div class="flex items-center gap-2"> <span class="text-muted-foreground text-xs">Port Endpoint URI:</span> <code class="bg-muted text-foreground border-border/60 rounded border px-2 py-0.5 font-mono text-xs">{{ port.uri }}</code> <button ui-button variant="ghost" size="sm" class="h-6 px-1.5 text-xs" (click)="emitCopy(port.uri, port.uri)" > @if (copiedKey === port.uri) { <lucide-icon [img]="Check" class="text-success size-3" /> } @else { <lucide-icon [img]="Copy" class="size-3" /> } <span class="ml-1 font-mono text-xs">{{ copiedKey === port.uri ? 'Copied' : 'Copy' }}</span> </button> </div> </div> <div class="flex items-center gap-2"> @if (port.throughput) { <span class="border-border bg-muted/40 text-muted-foreground rounded-md border px-2.5 py-1 font-mono text-xs" > Throughput: <strong class="text-foreground">{{ port.throughput }}</strong> </span> } @if (port.rateLimit) { <span class="border-border bg-muted/40 text-muted-foreground rounded-md border px-2.5 py-1 font-mono text-xs" > Limit: <strong class="text-foreground">{{ port.rateLimit }}</strong> </span> } </div> </div> <!-- Port Schema Dictionary (If Columns Defined) --> @if (port.columns && port.columns.length > 0) { <div class="space-y-2"> <div class="flex items-center justify-between gap-x-2"> <span class="text-foreground text-xs font-semibold">Schema Column Definitions & Constraints</span> <span class="text-muted-foreground font-mono text-xs">{{ port.columns.length }} columns registered</span> </div> <div class="border-border bg-card overflow-hidden rounded-lg border"> <div ui-table> <thead ui-table-header> <tr ui-table-row class="bg-muted/40 hover:bg-muted/40"> <th ui-table-head class="text-xs font-semibold">Column Name</th> <th ui-table-head class="text-xs font-semibold">Data Type</th> <th ui-table-head class="text-xs font-semibold">Nullability</th> <th ui-table-head class="text-xs font-semibold">Constraint</th> <th ui-table-head class="text-xs font-semibold">Description</th> </tr> </thead> <tbody ui-table-body> @for (col of port.columns; track col.name) { <tr ui-table-row class="font-mono text-xs"> <td ui-table-cell class="text-foreground font-bold"> <div class="flex items-center gap-1.5"> @if (col.isKey) { <lucide-icon [img]="KeyRound" class="text-warning size-3.5" /> } <span>{{ col.name }}</span> </div> </td> <td ui-table-cell> <span ui-badge variant="secondary" class="font-mono text-xs font-normal">{{ col.type }}</span> </td> <td ui-table-cell> <span [class]="col.nullable ? 'text-muted-foreground' : 'text-foreground font-semibold'"> {{ col.nullable ? 'NULLABLE' : 'NOT NULL' }} </span> </td> <td ui-table-cell> @if (col.constraints) { <span ui-badge variant="outline" class="font-mono text-xs">{{ col.constraints }}</span> } @else { <span class="text-muted-foreground">—</span> } </td> <td ui-table-cell class="text-muted-foreground font-sans">{{ col.desc }}</td> </tr> } </tbody> </div> </div> </div> } <!-- Port Code / Sample Payload Explorer --> @if (port.sampleQuery || port.samplePayload) { <div class="space-y-2"> <div class="flex items-center justify-between gap-x-2"> <div class="flex items-center gap-2"> <lucide-icon [img]="FileCode2" class="text-primary size-3.5" /> <span class="text-foreground text-xs font-semibold"> {{ port.sampleQuery ? 'Sample Query / Contract Call' : 'Event Message Payload Schema' }} </span> </div> <button ui-button variant="ghost" size="sm" class="h-7 gap-1 font-mono text-xs" (click)="emitCopy(port.sampleQuery || port.samplePayload || '', 'code')" > @if (copiedKey === 'code') { <lucide-icon [img]="Check" class="text-success size-3" /> } @else { <lucide-icon [img]="Copy" class="size-3" /> } <span>{{ copiedKey === 'code' ? 'Copied' : 'Copy Code' }}</span> </button> </div> <div class="overflow-x-auto rounded-lg bg-neutral-950 p-4 font-mono text-xs leading-relaxed text-neutral-100 dark:bg-neutral-950" > <pre class="whitespace-pre"><code>{{ port.sampleQuery || port.samplePayload }}</code></pre> </div> </div> } </div> </div> <!-- Federated Computational Governance SLA Scorecard & Compliance Matrix --> <div class="space-y-3 pt-2"> <div class="flex items-center gap-2"> <lucide-icon [img]="ShieldCheck" class="text-success size-4" /> <h3 class="text-foreground text-xs font-semibold tracking-wider uppercase"> Federated Governance SLA Scorecard & Policy Rules </h3> </div> <div class="grid grid-cols-1 gap-4 lg:grid-cols-3"> <!-- Scorecard Metrics --> <div class="border-border bg-background space-y-3 rounded-lg border p-4 text-xs"> <span class="text-foreground border-border/60 block border-b pb-1.5 font-semibold"> Service Level Objectives (SLOs) </span> <div class="space-y-2"> <div class="flex items-center justify-between gap-x-2"> <span class="text-muted-foreground">SLA Availability:</span> <span class="text-success font-mono font-bold">{{ product.uptime }}</span> </div> <div class="flex items-center justify-between gap-x-2"> <span class="text-muted-foreground">Freshness Latency:</span> <span class="text-foreground font-mono font-medium">{{ product.freshnessLatency }}</span> </div> <div class="flex items-center justify-between gap-x-2"> <span class="text-muted-foreground">Quality Check Assertions:</span> <span class="text-foreground text-success font-mono font-medium"> {{ product.assertionsPassed }}/{{ product.assertionsTotal }} Passing </span> </div> <div class="flex items-center justify-between gap-x-2"> <span class="text-muted-foreground">Data Classification:</span> <span ui-badge variant="secondary" class="font-mono text-xs">{{ product.classification }}</span> </div> </div> </div> <!-- Policy-as-Code Engine --> <div class="border-border bg-background space-y-2.5 rounded-lg border p-4 text-xs lg:col-span-2"> <span class="text-foreground border-border/60 block border-b pb-1.5 font-semibold"> Active Computational Governance Policies (Policy-as-Code) </span> <div class="space-y-2"> @for (policy of product.governancePolicies; track $index) { <div class="border-border/70 bg-muted/30 flex items-start gap-2.5 rounded-md border p-2.5"> <div class="bg-success/10 text-success mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full" > <lucide-icon [img]="Check" class="size-2.5" /> </div> <p class="text-muted-foreground text-xs leading-relaxed">{{ policy }}</p> </div> } </div> </div> </div> </div> `, }) export class UiDataMeshProductDetailComponent { @Input({ required: true }) product!: DataProductItem @Input({ required: true }) port!: OutputPortDetails @Input() activePortId: DataMeshPortId = 'snowflake' @Input() copiedKey: string | null = null @Output() portChange = new EventEmitter<DataMeshPortId>() @Output() copyText = new EventEmitter<DataMeshCopyEvent>() @Output() requestAccess = new EventEmitter<DataProductItem>() @Output() runQuery = new EventEmitter<DataProductItem>() emitCopy(text: string, identifier: string): void { this.copyText.emit({ text, identifier }) } portTabIcon(id: DataMeshPortId): IconSpec { return PORT_TAB_ICONS[id] } portTabClass(id: DataMeshPortId): string { return cn( 'inline-flex items-center gap-1.5 rounded-md px-3 py-1 text-xs font-medium transition-colors', this.activePortId === id ? 'bg-background text-foreground font-semibold shadow-xs' : 'text-muted-foreground hover:text-foreground', ) } protected readonly Boxes = Boxes protected readonly Check = Check protected readonly Copy = Copy protected readonly FileCode2 = FileCode2 protected readonly KeyRound = KeyRound protected readonly Package = Package protected readonly Radio = Radio protected readonly Server = Server protected readonly ShieldCheck = ShieldCheck protected readonly Terminal = Terminal protected readonly Users = Users }src/app/components/blocks/data-mesh-domain-catalog/data-mesh-query-runner.component.ts4.5 kB
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from '@angular/core' import { LucideAngularModule, RefreshCw, Terminal, X } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiTableBodyComponent, UiTableCellComponent, UiTableComponent, UiTableHeadComponent, UiTableHeaderComponent, UiTableRowComponent, } from '@/ui/table/table.component' import type { DataProductItem, OutputPortDetails } from './data-mesh-types' type MockRow = Record<string, string | number | boolean> /** Inline query runner for the selected output port. The parent renders it only while open. */ @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-data-mesh-query-runner, [ui-data-mesh-query-runner]', standalone: true, host: { class: 'border-border bg-muted/30 block overflow-hidden rounded-xl border transition-colors' }, imports: [ LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiTableComponent, UiTableHeaderComponent, UiTableBodyComponent, UiTableRowComponent, UiTableHeadComponent, UiTableCellComponent, ], template: ` <div class="border-border bg-card flex items-center justify-between gap-x-2 border-b px-4 py-2.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Terminal" class="text-primary size-4" /> <span class="text-foreground font-mono text-xs font-semibold"> Interactive Query Runner · {{ product.name }} ({{ port.name }}) </span> <span ui-badge variant="outline" class="font-mono text-xs">{{ port.protocol }}</span> </div> <div class="flex items-center gap-2"> <button ui-button variant="default" size="sm" class="h-7 gap-1 text-xs" [disabled]="isSimulatingQuery" (click)="runQuery.emit()" > <lucide-icon [img]="RefreshCw" [class]="spinnerClass" /> <span>{{ isSimulatingQuery ? 'Executing Query...' : 'Execute Run' }}</span> </button> <button ui-button variant="ghost" size="sm" class="size-7 p-0" (click)="closed.emit()"> <lucide-icon [img]="X" class="size-4" /> </button> </div> </div> <div class="space-y-3 p-4"> <div class="overflow-x-auto rounded-lg bg-neutral-950 p-3 font-mono text-xs text-neutral-100 dark:bg-neutral-950"> <pre class="leading-relaxed whitespace-pre"><code>{{ port.sampleQuery || port.samplePayload }}</code></pre> </div> @if (port.mockResults; as rows) { <div class="border-border bg-card overflow-hidden rounded-lg border"> <div class="border-border bg-muted/50 text-foreground flex items-center justify-between gap-x-2 border-b px-3 py-1.5 text-xs font-semibold" > <span>Query Results Preview (3 Records returned in 42ms)</span> <span ui-badge variant="secondary" class="font-mono text-xs">Snowflake XS Warehouse</span> </div> <div ui-table> <thead ui-table-header> <tr ui-table-row class="bg-muted/30 hover:bg-muted/30"> @for (key of columnsOf(rows); track key) { <th ui-table-head class="font-mono text-xs">{{ key }}</th> } </tr> </thead> <tbody ui-table-body> @for (row of rows; track $index) { <tr ui-table-row class="font-mono text-xs"> @for (cell of cellsOf(row); track cell.key) { <td ui-table-cell>{{ cell.value }}</td> } </tr> } </tbody> </div> </div> } </div> `, }) export class UiDataMeshQueryRunnerComponent { @Input({ required: true }) product!: DataProductItem @Input({ required: true }) port!: OutputPortDetails @Input() isSimulatingQuery = false @Output() closed = new EventEmitter<void>() @Output() runQuery = new EventEmitter<void>() get spinnerClass(): string { return cn('size-3', this.isSimulatingQuery && 'animate-spin') } columnsOf(rows: MockRow[]): string[] { return Object.keys(rows[0] || {}) } cellsOf(row: MockRow): { key: string; value: string }[] { return Object.entries(row).map(([key, value]) => ({ key, value: String(value) })) } protected readonly RefreshCw = RefreshCw protected readonly Terminal = Terminal protected readonly X = X }src/app/components/blocks/data-mesh-domain-catalog/data-mesh-modals.component.ts15.4 kB
import { Component, DestroyRef, EventEmitter, Input, Output, inject, signal, ChangeDetectionStrategy, } from '@angular/core' import { CheckCircle2, KeyRound, LucideAngularModule, Plus, X } from 'lucide-angular' import { UiButtonComponent } from '@/ui/button/button.component' import type { DataProductItem, DomainMeta } from './data-mesh-types' export type DataMeshClassification = DataProductItem['classification'] /** Request-access and register-product overlays (fixed, above the catalog). */ @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-data-mesh-modals, [ui-data-mesh-modals]', standalone: true, host: { class: 'contents' }, imports: [LucideAngularModule, UiButtonComponent], template: ` <!-- Modal: Request Access to Output Port --> @if (accessModalOpen) { <div class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-xs" (click)="accessModalOpenChange.emit(false)" > <div class="border-border bg-card text-card-foreground w-full max-w-lg space-y-4 rounded-xl border p-5 shadow-lg" (click)="$event.stopPropagation()" > <div class="border-border/80 flex items-start justify-between border-b pb-3"> <div class="space-y-1"> <div class="flex items-center gap-2"> <lucide-icon [img]="KeyRound" class="text-warning size-4" /> <h3 class="text-foreground text-sm font-semibold">Request Output Port Access</h3> </div> <p class="text-muted-foreground text-xs"> Automated computational governance approval workflow for <code class="text-foreground font-mono font-semibold">{{ product.name }}</code >. </p> </div> <button ui-button variant="ghost" size="sm" class="size-7 p-0" (click)="accessModalOpenChange.emit(false)"> <lucide-icon [img]="X" class="size-4" /> </button> </div> @if (isAccessApproved()) { <div class="border-success/30 bg-success/10 space-y-2 rounded-lg border p-4 text-center"> <div class="bg-success/20 text-success inline-flex size-8 items-center justify-center rounded-full"> <lucide-icon [img]="CheckCircle2" class="size-5" /> </div> <h4 class="text-success text-xs font-semibold">Access Grant Provisioned</h4> <p class="text-muted-foreground text-xs"> Federated governance policy-as-code approved request. Token and RBAC role bound to consumer application. </p> </div> } @else { <form class="space-y-3 text-xs" (submit)="submitAccessRequest($event)"> <div class="space-y-1"> <label class="text-foreground block font-medium">Consumer Service / Application Name</label> <input [value]="accessAppName()" (input)="accessAppName.set(valueOf($event))" required placeholder="e.g. revops-lead-scoring-service" class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 text-xs outline-none focus-visible:ring-1" /> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Consumer Squad / Team</label> <input [value]="accessSquad()" (input)="accessSquad.set(valueOf($event))" required placeholder="e.g. #growth-eng-squad" class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 text-xs outline-none focus-visible:ring-1" /> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Target Output Port</label> <select (change)="accessPort.set(valueOf($event))" class="border-border bg-background text-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 text-xs outline-none focus-visible:ring-1" > @for (port of product.ports; track port.id) { <option [value]="port.id" [selected]="accessPort() === port.id"> {{ port.name }} ({{ port.typeLabel }}) </option> } </select> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Business Justification & Data Usage Scope</label> <textarea [value]="accessReason()" (input)="accessReason.set(valueOf($event))" required rows="2" placeholder="Explain how this data product will be consumed and compliance adherence..." class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring w-full rounded-md border p-2 text-xs outline-none focus-visible:ring-1" ></textarea> </div> <div class="border-border/80 flex items-center justify-end gap-2 border-t pt-3"> <button ui-button type="button" variant="outline" size="sm" class="h-8 text-xs" (click)="accessModalOpenChange.emit(false)" > Cancel </button> <button ui-button type="submit" variant="default" size="sm" class="h-8 text-xs font-medium"> Submit Access Request </button> </div> </form> } </div> </div> } <!-- Modal: Register New Data Product --> @if (registerModalOpen) { <div class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-xs" (click)="registerModalOpenChange.emit(false)" > <div class="border-border bg-card text-card-foreground w-full max-w-lg space-y-4 rounded-xl border p-5 shadow-lg" (click)="$event.stopPropagation()" > <div class="border-border/80 flex items-start justify-between border-b pb-3"> <div class="space-y-1"> <div class="flex items-center gap-2"> <lucide-icon [img]="Plus" class="text-primary size-4" /> <h3 class="text-foreground text-sm font-semibold">Register New Data Product</h3> </div> <p class="text-muted-foreground text-xs"> Publish a new data product quantum to the federated Data Mesh catalog with contract SLA specs. </p> </div> <button ui-button variant="ghost" size="sm" class="size-7 p-0" (click)="registerModalOpenChange.emit(false)" > <lucide-icon [img]="X" class="size-4" /> </button> </div> @if (isRegisterSuccess()) { <div class="border-success/30 bg-success/10 space-y-2 rounded-lg border p-4 text-center"> <div class="bg-success/20 text-success inline-flex size-8 items-center justify-center rounded-full"> <lucide-icon [img]="CheckCircle2" class="size-5" /> </div> <h4 class="text-success text-xs font-semibold">Data Product Registered Successfully</h4> <p class="text-muted-foreground text-xs"> Published to catalog registry with contract hash, automated CI/CD validation tests, and SLA telemetry. </p> </div> } @else { <form class="space-y-3 text-xs" (submit)="submitRegisterProduct($event)"> <div class="grid grid-cols-1 gap-3 sm:grid-cols-2"> <div class="space-y-1"> <label class="text-foreground block font-medium">Product Name / ID</label> <input [value]="newProductName()" (input)="newProductName.set(valueOf($event))" required placeholder="dp_merchant_settlement_ledger" class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 font-mono text-xs outline-none focus-visible:ring-1" /> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Domain Node</label> <select (change)="newProductDomain.set(valueOf($event))" class="border-border bg-background text-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 text-xs outline-none focus-visible:ring-1" > @for (d of domains; track d.id) { <option [value]="d.id" [selected]="newProductDomain() === d.id">{{ d.name }}</option> } </select> </div> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Data Product Description</label> <textarea [value]="newProductDesc()" (input)="newProductDesc.set(valueOf($event))" required rows="2" placeholder="Describe the product quantum purpose, source transformations, and consumer target..." class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring w-full rounded-md border p-2 text-xs outline-none focus-visible:ring-1" ></textarea> </div> <div class="grid grid-cols-1 gap-3 sm:grid-cols-2"> <div class="space-y-1"> <label class="text-foreground block font-medium">Product Owner Name</label> <input [value]="newProductOwner()" (input)="newProductOwner.set(valueOf($event))" required placeholder="Marcus Vance" class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 text-xs outline-none focus-visible:ring-1" /> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Squad Slack Handle / Team</label> <input [value]="newProductTeam()" (input)="newProductTeam.set(valueOf($event))" required placeholder="#payments-core" class="border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 font-mono text-xs outline-none focus-visible:ring-1" /> </div> </div> <div class="space-y-1"> <label class="text-foreground block font-medium">Data Classification Tier</label> <select (change)="setClassification(valueOf($event))" class="border-border bg-background text-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 text-xs outline-none focus-visible:ring-1" > @for (opt of classificationOptions; track opt.value) { <option [value]="opt.value" [selected]="newProductClassification() === opt.value"> {{ opt.label }} </option> } </select> </div> <div class="border-border/80 flex items-center justify-end gap-2 border-t pt-3"> <button ui-button type="button" variant="outline" size="sm" class="h-8 text-xs" (click)="registerModalOpenChange.emit(false)" > Cancel </button> <button ui-button type="submit" variant="default" size="sm" class="h-8 text-xs font-medium"> Publish to Mesh Registry </button> </div> </form> } </div> </div> } `, }) export class UiDataMeshModalsComponent { @Input() accessModalOpen = false @Output() accessModalOpenChange = new EventEmitter<boolean>() @Input() registerModalOpen = false @Output() registerModalOpenChange = new EventEmitter<boolean>() @Input({ required: true }) product!: DataProductItem @Input() domains: DomainMeta[] = [] readonly classificationOptions: { value: DataMeshClassification; label: string }[] = [ { value: 'PII-Confidential', label: 'PII-Confidential (GDPR Masked)' }, { value: 'Financial-Audit', label: 'Financial-Audit (SOX Certified)' }, { value: 'Internal-Ops', label: 'Internal-Ops (Standard RBAC)' }, { value: 'Platform-Internal', label: 'Platform-Internal (System Only)' }, ] readonly isAccessApproved = signal(false) readonly isRegisterSuccess = signal(false) readonly accessAppName = signal('') readonly accessSquad = signal('') readonly accessPort = signal('snowflake') readonly accessReason = signal('') readonly newProductName = signal('') readonly newProductDomain = signal('checkout-payments') readonly newProductDesc = signal('') readonly newProductOwner = signal('') readonly newProductTeam = signal('') readonly newProductClassification = signal<DataMeshClassification>('PII-Confidential') private readonly timers = new Set<ReturnType<typeof setTimeout>>() constructor() { inject(DestroyRef).onDestroy(() => this.timers.forEach((t) => clearTimeout(t))) } valueOf(event: Event): string { return (event.target as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).value } setClassification(value: string): void { const match = this.classificationOptions.find((o) => o.value === value) if (match) this.newProductClassification.set(match.value) } submitAccessRequest(event: Event): void { event.preventDefault() this.isAccessApproved.set(true) this.later(() => { this.accessModalOpenChange.emit(false) this.isAccessApproved.set(false) this.accessAppName.set('') this.accessSquad.set('') this.accessReason.set('') }, 1800) } submitRegisterProduct(event: Event): void { event.preventDefault() this.isRegisterSuccess.set(true) this.later(() => { this.registerModalOpenChange.emit(false) this.isRegisterSuccess.set(false) this.newProductName.set('') this.newProductDesc.set('') this.newProductOwner.set('') this.newProductTeam.set('') }, 1600) } private later(fn: () => void, ms: number): void { const t = setTimeout(() => { this.timers.delete(t) fn() }, ms) this.timers.add(t) } protected readonly CheckCircle2 = CheckCircle2 protected readonly KeyRound = KeyRound protected readonly Plus = Plus protected readonly X = X }src/app/components/blocks/data-mesh-domain-catalog/data-mesh-types.ts1.6 kB
export interface DomainMeta { id: string name: string lead: string role: string productsCount: number slaScore: number activeConsumers: number storageVolume: string throughput: string tier: string description: string iconName: 'CreditCard' | 'Users' | 'Truck' | 'Activity' } export interface OutputPortSchemaColumn { name: string type: string nullable: boolean isKey?: boolean desc: string constraints?: string } export type DataMeshPortId = 'snowflake' | 'kafka' | 'graphql' | 's3' export interface OutputPortDetails { id: DataMeshPortId name: string typeLabel: string badgeVariant?: 'default' | 'secondary' | 'outline' protocol: string uri: string accessRole: string schemaRegistry?: string format?: string syncCadence?: string throughput?: string rateLimit?: string columns?: OutputPortSchemaColumn[] sampleQuery?: string samplePayload?: string mockResults?: Array<Record<string, string | number | boolean>> } export interface DataProductItem { id: string name: string displayName: string domainId: string domainName: string version: string tier: string classification: 'PII-Confidential' | 'Financial-Audit' | 'Internal-Ops' | 'Platform-Internal' description: string contractHash: string owner: { name: string role: string handle: string team: string initials: string avatar?: string } slaScore: number freshnessLatency: string uptime: string assertionsPassed: number assertionsTotal: number activeConsumersCount: number topConsumers: string[] ports: OutputPortDetails[] governancePolicies: string[] }src/app/components/blocks/data-mesh-domain-catalog/data-mesh-data.ts24.7 kB
import type { DomainMeta, DataProductItem } from './data-mesh-types' export const DOMAINS: DomainMeta[] = [ { id: 'checkout-payments', name: 'Checkout & Payments', lead: 'Marcus Vance', role: 'Principal Data Architect', productsCount: 6, slaScore: 99.8, activeConsumers: 33, storageVolume: '4.8 TB', throughput: '45k ops/sec', tier: 'Tier 1 Core Gold', description: 'Real-time order authorization, payment settlements, GAAP recurring revenue ledgers, and fraud velocity pipelines.', iconName: 'CreditCard', }, { id: 'customer-intelligence', name: 'Customer Intelligence', lead: 'Elena Rostova', role: 'Staff Data PM', productsCount: 4, slaScore: 99.6, activeConsumers: 24, storageVolume: '12.2 TB', throughput: '12k ops/sec', tier: 'Tier 1 Core Gold', description: 'Unified real-time customer 360 identity resolution graph, behavioral propensity scores, cohort attribution, and churn risk models.', iconName: 'Users', }, { id: 'logistics-supply-chain', name: 'Logistics & Supply Chain', lead: 'David Chen', role: 'Lead Data Engineer', productsCount: 5, slaScore: 99.5, activeConsumers: 25, storageVolume: '8.4 TB', throughput: '18k ops/sec', tier: 'Tier 2 Certified', description: 'Global container telematics, port dwell predictions, multi-warehouse stock allocations, and carrier SLA breach risk monitors.', iconName: 'Truck', }, { id: 'platform-observability', name: 'Platform & Observability', lead: 'Sarah Jenkins', role: 'VP Data Infrastructure', productsCount: 3, slaScore: 99.99, activeConsumers: 41, storageVolume: '19.5 TB', throughput: '85k ops/sec', tier: 'Tier 1 Operational', description: 'Federated query execution traces, cross-domain consumer lineage logs, SLA breach alarms, and FinOps egress telemetry.', iconName: 'Activity', }, ] export const DATA_PRODUCTS: DataProductItem[] = [ { id: 'dp_customer_360_profile', name: 'dp_customer_360_profile', displayName: 'Customer 360 Unified Identity Graph', domainId: 'customer-intelligence', domainName: 'Customer Intelligence', version: 'v3.2.0', tier: 'Tier 1 Core Gold', classification: 'PII-Confidential', description: 'Unified real-time customer identity graph, behavioral propensity scores, multi-touch attribution, and consent preferences.', contractHash: 'sha256:8f4c9a12b3e70d4f9012a67e', owner: { name: 'Elena Rostova', role: 'Staff Data PM', handle: '@elena.rostova', team: '#cust-intel-squad', initials: 'ER', }, slaScore: 99.9, freshnessLatency: '< 2m', uptime: '99.98%', assertionsPassed: 18, assertionsTotal: 18, activeConsumersCount: 14, topConsumers: ['RevOps Dashboard', 'Churn Predictor', 'Zendesk Sync', 'Marketing Cloud', 'Billing Automation'], ports: [ { id: 'snowflake', name: 'Snowflake Analytical Mart', typeLabel: 'Snowflake Table', protocol: 'Snowflake SQL over Arrow Flight', uri: 'snowflake://prod_dw.analytics_customer.dim_customer_360', accessRole: 'ROLE: ANALYTICS_READER', columns: [ { name: 'customer_id', type: 'varchar(64)', nullable: false, isKey: true, desc: 'Globally unique customer GUID', constraints: 'PRIMARY KEY', }, { name: 'email_hash', type: 'varchar(64)', nullable: false, desc: 'SHA-256 hashed customer email for pseudonymization', constraints: 'OPA MASKED', }, { name: 'lifetime_value_usd', type: 'decimal(18,2)', nullable: false, desc: 'Cumulative GAAP realized revenue recognized', constraints: 'CHECK (>= 0)', }, { name: 'churn_risk_score', type: 'decimal(5,4)', nullable: true, desc: 'ML predicted churn risk probability (0.0000 - 1.0000)', constraints: '0.0 TO 1.0', }, { name: 'primary_tier', type: 'varchar(32)', nullable: false, desc: 'Enterprise / Pro / Team membership classification', }, { name: 'last_active_at', type: 'timestamp_tz', nullable: false, desc: 'ISO-8601 UTC timestamp of last observed touchpoint', }, ], sampleQuery: `SELECT customer_id, primary_tier, lifetime_value_usd, churn_risk_score\nFROM prod_dw.analytics_customer.dim_customer_360\nWHERE churn_risk_score > 0.65\nORDER BY lifetime_value_usd DESC\nLIMIT 5;`, mockResults: [ { customer_id: 'cust_9821a', primary_tier: 'Enterprise', lifetime_value_usd: '$84,200.00', churn_risk_score: '0.7820', }, { customer_id: 'cust_4412b', primary_tier: 'Enterprise', lifetime_value_usd: '$62,450.00', churn_risk_score: '0.6910', }, { customer_id: 'cust_1109c', primary_tier: 'Pro Team', lifetime_value_usd: '$28,900.00', churn_risk_score: '0.7140', }, ], }, { id: 'graphql', name: 'GraphQL Customer Query Endpoint', typeLabel: 'GraphQL API', protocol: 'GraphQL over HTTPS / HTTP/2', uri: 'https://api.uipkge.internal/graphql/v1/customer-360', accessRole: 'Bearer MeshToken (scope: read:customer_360)', rateLimit: '5,000 req/min · P99 < 45ms', sampleQuery: `query GetCustomerProfile($id: ID!) {\n customer(id: $id) {\n id\n primaryTier\n lifetimeValueUsd\n churnRiskScore\n consentPreferences {\n analyticsAllowed\n marketingAllowed\n }\n }\n}`, }, { id: 's3', name: 'S3 Parquet Lake Export', typeLabel: 'Parquet S3', protocol: 'S3 Object Store / AWS Lake Formation', uri: 's3://uipkge-data-mesh-lake/customer-intelligence/profiles/v3/', accessRole: 'AWS IAM ARN: arn:aws:iam::data-lake-reader', format: 'Snappy Apache Parquet · Partitioned by date(last_active_at)', syncCadence: 'Hourly Micro-batch Sync', }, ], governancePolicies: [ 'OPA Masking: Email and phone attributes hashed on egress', 'GDPR Article 17: Automated erasure pipeline triggered on deletion events', 'Differential Privacy: ε=0.5 noise applied to aggregated analytical views', ], }, { id: 'dp_realtime_order_stream', name: 'dp_realtime_order_stream', displayName: 'Realtime Checkout Order Stream', domainId: 'checkout-payments', domainName: 'Checkout & Payments', version: 'v2.4.1', tier: 'Tier 1 Mission Critical', classification: 'Financial-Audit', description: 'Sub-second immutable stream of global checkout events, payment authorizations, 3D Secure validations, and refunds.', contractHash: 'sha256:4a7e9102c89f33b1e2a05d8c', owner: { name: 'Marcus Vance', role: 'Principal Architect', handle: '@marcus.vance', team: '#payments-core', initials: 'MV', }, slaScore: 99.95, freshnessLatency: '< 150ms', uptime: '99.99%', assertionsPassed: 24, assertionsTotal: 24, activeConsumersCount: 22, topConsumers: ['Fraud Engine', 'Inventory Lock', 'Stripe Settlement', 'Fulfillment Dispatch', 'NetSuite ERP'], ports: [ { id: 'kafka', name: 'Kafka High-Throughput Event Topic', typeLabel: 'Kafka Stream', protocol: 'Kafka Protocol v3.6 / Avro Schema Registry', uri: 'kafka://events.kafka.internal:9092/payments.checkout.orders.v2', accessRole: 'mTLS Certificate (CN=service.payments.consumer)', schemaRegistry: 'Avro v2.4 (Subject: payments-checkout-orders-value)', throughput: '45,000 msg/sec (16 partitions · RF: 3)', samplePayload: `{\n "event_id": "evt_9941a80c-b4",\n "order_id": "ord_88201",\n "customer_id": "cust_9821a",\n "amount_cents": 184500,\n "currency": "USD",\n "payment_method": "stripe_card_v2",\n "status": "AUTHORIZED",\n "timestamp_utc": "2026-08-21T14:28:10.194Z"\n}`, }, { id: 'snowflake', name: 'Raw Streaming Ingestion Table', typeLabel: 'Snowflake Table', protocol: 'Snowpipe Streaming / Arrow Flight', uri: 'snowflake://prod_dw.raw_payments.fct_orders_stream', accessRole: 'ROLE: PAYMENTS_READER', columns: [ { name: 'event_id', type: 'varchar(64)', nullable: false, isKey: true, desc: 'Immutable idempotency event GUID', constraints: 'PRIMARY KEY', }, { name: 'order_id', type: 'varchar(32)', nullable: false, desc: 'Reference checkout order ID' }, { name: 'amount_usd', type: 'decimal(18,2)', nullable: false, desc: 'Settled transactional amount in USD' }, { name: 'payment_status', type: 'varchar(24)', nullable: false, desc: 'AUTHORIZED / CAPTURED / FAILED / REFUNDED', }, { name: 'event_timestamp', type: 'timestamp_tz', nullable: false, desc: 'Sub-second event creation timestamp', }, ], sampleQuery: `SELECT event_id, order_id, amount_usd, payment_status, event_timestamp\nFROM prod_dw.raw_payments.fct_orders_stream\nWHERE event_timestamp >= DATEADD(minute, -15, CURRENT_TIMESTAMP())\nORDER BY event_timestamp DESC\nLIMIT 5;`, mockResults: [ { event_id: 'evt_9941a', order_id: 'ord_88201', amount_usd: '$1,845.00', payment_status: 'AUTHORIZED', event_timestamp: '14:28:10 UTC', }, { event_id: 'evt_9940b', order_id: 'ord_88200', amount_usd: '$420.50', payment_status: 'CAPTURED', event_timestamp: '14:28:08 UTC', }, ], }, { id: 'graphql', name: 'Realtime Orders Webhook/API', typeLabel: 'GraphQL API', protocol: 'GraphQL Subscriptions over WebSockets', uri: 'https://api.uipkge.internal/graphql/v1/orders-stream', accessRole: 'Bearer MeshToken (scope: read:orders)', rateLimit: '10,000 req/min · P99 < 30ms', sampleQuery: `subscription OnNewOrderAuthorized {\n orderAuthorized {\n orderId\n amountUsd\n status\n timestamp\n }\n}`, }, ], governancePolicies: [ 'PCI-DSS Tier 1: Zero plain-text card data in payload schema', 'Idempotent Delivery: Exactly-once consumer semantics guaranteed via Kafka transactional producer', 'Audit Immutability: Append-only write ledger with cryptographic hash chaining', ], }, { id: 'dp_carrier_delivery_performance', name: 'dp_carrier_delivery_performance', displayName: 'Carrier Dwell & Delivery Telematics', domainId: 'logistics-supply-chain', domainName: 'Logistics & Supply Chain', version: 'v1.8.0', tier: 'Tier 2 Certified', classification: 'Internal-Ops', description: 'Real-time carrier transit telematics, port dwell times, ETA machine learning forecasts, and SLA breach risk scoring.', contractHash: 'sha256:19bc2a40e87d12f4581109aa', owner: { name: 'David Chen', role: 'Lead Data Engineer', handle: '@david.chen', team: '#logistics-mesh', initials: 'DC', }, slaScore: 99.4, freshnessLatency: '< 5m', uptime: '99.92%', assertionsPassed: 12, assertionsTotal: 12, activeConsumersCount: 9, topConsumers: ['Control Tower UI', 'Carrier Scorecard', 'Customs Broker Portal', 'Exception Dispatcher'], ports: [ { id: 'snowflake', name: 'Logistics Telematics Mart', typeLabel: 'Snowflake Table', protocol: 'Snowflake SQL / DBT Mart', uri: 'snowflake://prod_dw.logistics_marts.fct_carrier_telematics', accessRole: 'ROLE: LOGISTICS_ANALYST', columns: [ { name: 'shipment_id', type: 'varchar(48)', nullable: false, isKey: true, desc: 'Global multimodal consignment identifier', constraints: 'PRIMARY KEY', }, { name: 'carrier_scac', type: 'varchar(8)', nullable: false, desc: 'Standard Carrier Alpha Code (MAEU, MSCU, COSU)', }, { name: 'port_dwell_hours', type: 'decimal(6,2)', nullable: false, desc: 'Current container dwell interval at marine terminal', }, { name: 'eta_prediction_confidence', type: 'decimal(5,4)', nullable: false, desc: 'ML ensemble model forecast confidence score', }, { name: 'sla_breach_flag', type: 'boolean', nullable: false, desc: 'Flagged true if predicted delivery > guaranteed SLA', }, ], sampleQuery: `SELECT shipment_id, carrier_scac, port_dwell_hours, sla_breach_flag\nFROM prod_dw.logistics_marts.fct_carrier_telematics\nWHERE sla_breach_flag = TRUE\nORDER BY port_dwell_hours DESC\nLIMIT 5;`, mockResults: [ { shipment_id: 'SHP-90812', carrier_scac: 'MAEU', port_dwell_hours: '74.2 hrs', sla_breach_flag: true }, { shipment_id: 'SHP-90804', carrier_scac: 'MSCU', port_dwell_hours: '61.5 hrs', sla_breach_flag: true }, ], }, { id: 's3', name: 'Telematics Parquet Batch Stream', typeLabel: 'Parquet S3', protocol: 'S3 Data Lake / Hive Metastore', uri: 's3://uipkge-data-mesh-lake/supply-chain/telematics/v1/', accessRole: 'AWS IAM: arn:aws:iam::supply-chain-lake-reader', format: 'Snappy Parquet partitioned by carrier_scac / year / month', syncCadence: 'Every 5 minutes', }, ], governancePolicies: [ 'Geospatial Resolution Cap: GPS telematics coordinates rounded to 3 decimal places outside geofences', 'SLA Alert Threshold: Automatic PagerDuty alert on > 5% carrier breach rate', ], }, { id: 'dp_subscription_mrr_ledger', name: 'dp_subscription_mrr_ledger', displayName: 'Subscription MRR & Revenue Recognition', domainId: 'checkout-payments', domainName: 'Checkout & Payments', version: 'v4.0.2', tier: 'Tier 1 Core Gold', classification: 'Financial-Audit', description: 'GAAP/IFRS compliant monthly recurring revenue recognition ledger, expansion/contraction deltas, and cohort retention.', contractHash: 'sha256:d82e1194fa8892bc0147ae55', owner: { name: 'Marcus Vance', role: 'Principal Architect', handle: '@marcus.vance', team: '#payments-core', initials: 'MV', }, slaScore: 100.0, freshnessLatency: '< 1h', uptime: '99.99%', assertionsPassed: 32, assertionsTotal: 32, activeConsumersCount: 11, topConsumers: ['Executive Board Deck', 'NetSuite Sync', 'FP&A Forecasting', 'Investor Reporting'], ports: [ { id: 'snowflake', name: 'Gold Certified Financial Mart', typeLabel: 'Snowflake Table', protocol: 'Snowflake SQL / Incremental Gold Mart', uri: 'snowflake://prod_dw.finance_gold.fct_subscription_mrr_ledger', accessRole: 'ROLE: FINANCE_EXECUTIVE', columns: [ { name: 'fiscal_month', type: 'varchar(7)', nullable: false, isKey: true, desc: 'YYYY-MM accounting partition key', constraints: 'PRIMARY KEY', }, { name: 'starting_mrr', type: 'decimal(18,2)', nullable: false, desc: 'Beginning of period monthly recurring revenue', }, { name: 'expansion_mrr', type: 'decimal(18,2)', nullable: false, desc: 'Net upgrade and seat expansion recognized', }, { name: 'churn_mrr', type: 'decimal(18,2)', nullable: false, desc: 'Lost subscriptions recognized in period', }, { name: 'ending_mrr', type: 'decimal(18,2)', nullable: false, desc: 'Period closing MRR for GAAP balance sheet', }, ], sampleQuery: `SELECT fiscal_month, starting_mrr, expansion_mrr, churn_mrr, ending_mrr\nFROM prod_dw.finance_gold.fct_subscription_mrr_ledger\nORDER BY fiscal_month DESC\nLIMIT 3;`, mockResults: [ { fiscal_month: '2026-03', starting_mrr: '$1,220,000.00', expansion_mrr: '$64,500.00', churn_mrr: '-$12,450.00', ending_mrr: '$1,272,050.00', }, { fiscal_month: '2026-02', starting_mrr: '$1,175,000.00', expansion_mrr: '$58,100.00', churn_mrr: '-$13,100.00', ending_mrr: '$1,220,000.00', }, ], }, { id: 's3', name: 'Finance Cold-Storage Delta Lake', typeLabel: 'Parquet S3', protocol: 'Delta Lake 3.0 ACID table with 7-year retention', uri: 's3://uipkge-data-mesh-lake/finance/mrr-ledger/v4/', accessRole: 'AWS IAM: arn:aws:iam::finance-audit-reader', format: 'Delta Lake ACID Snappy Parquet', syncCadence: 'Daily Fiscal Close', }, ], governancePolicies: [ 'SOX Compliance: Dual-sign-off required before schema mutation', 'Cryptographic Seal: Daily ledger snapshot sealed with SHA-256 digest', ], }, { id: 'dp_global_inventory_snapshot', name: 'dp_global_inventory_snapshot', displayName: 'Global Multi-Warehouse Inventory', domainId: 'logistics-supply-chain', domainName: 'Logistics & Supply Chain', version: 'v2.1.0', tier: 'Tier 1 Core Gold', classification: 'Internal-Ops', description: 'Multi-warehouse SKU inventory levels, safety stock thresholds, in-transit allocations, and backorder risk indices.', contractHash: 'sha256:55f01e89bc21340aa482910d', owner: { name: 'David Chen', role: 'Lead Data Engineer', handle: '@david.chen', team: '#logistics-mesh', initials: 'DC', }, slaScore: 99.7, freshnessLatency: '< 1m', uptime: '99.95%', assertionsPassed: 16, assertionsTotal: 16, activeConsumersCount: 16, topConsumers: ['Storefront Stock Badge', 'Warehouse WMS', 'Restock Bot', 'ERP Allocator'], ports: [ { id: 'snowflake', name: 'Warehouse Stock Levels Table', typeLabel: 'Snowflake Table', protocol: 'Snowflake SQL / Materialized View', uri: 'snowflake://prod_dw.inventory.dim_warehouse_stock_levels', accessRole: 'ROLE: INVENTORY_OPERATOR', columns: [ { name: 'sku_id', type: 'varchar(32)', nullable: false, isKey: true, desc: 'Universal Stock Keeping Unit token', constraints: 'PRIMARY KEY', }, { name: 'warehouse_code', type: 'varchar(12)', nullable: false, isKey: true, desc: 'Facility code (e.g. WH-ORD1, WH-FRA2)', constraints: 'PRIMARY KEY', }, { name: 'quantity_available', type: 'integer', nullable: false, desc: 'Unallocated physical stock ready to pick', }, { name: 'quantity_reserved', type: 'integer', nullable: false, desc: 'Allocated to in-flight pending checkout baskets', }, { name: 'reorder_threshold', type: 'integer', nullable: false, desc: 'Automated PO replenishment trigger watermark', }, ], sampleQuery: `SELECT sku_id, warehouse_code, quantity_available, quantity_reserved\nFROM prod_dw.inventory.dim_warehouse_stock_levels\nWHERE quantity_available <= reorder_threshold\nLIMIT 5;`, mockResults: [ { sku_id: 'SKU-8819-A', warehouse_code: 'WH-ORD1', quantity_available: 12, quantity_reserved: 8 }, { sku_id: 'SKU-4402-Z', warehouse_code: 'WH-FRA2', quantity_available: 4, quantity_reserved: 4 }, ], }, { id: 'kafka', name: 'Inventory Delta Stream Topic', typeLabel: 'Kafka Stream', protocol: 'Kafka Event Topic / Avro v2.1', uri: 'kafka://events.kafka.internal:9092/supplychain.inventory.deltas.v2', accessRole: 'mTLS Certificate (CN=service.inventory.allocator)', throughput: '18,000 msg/sec', samplePayload: `{\n "sku_id": "SKU-8819-A",\n "warehouse_code": "WH-ORD1",\n "delta_units": -1,\n "reason": "CHECKOUT_PICKED",\n "timestamp_utc": "2026-08-21T14:29:40.012Z"\n}`, }, ], governancePolicies: [ 'Real-time Stock Consistency: Sub-second reconciliation against Physical WMS barcode scans', 'Zero Phantom Inventory: Automated cycle count variance audit', ], }, { id: 'dp_mesh_observability_telemetry', name: 'dp_mesh_observability_telemetry', displayName: 'Mesh Observability & Query Lineage', domainId: 'platform-observability', domainName: 'Platform & Observability', version: 'v1.5.0', tier: 'Tier 1 Operational', classification: 'Platform-Internal', description: 'Federated query execution traces, cross-domain consumer lineage logs, SLA breach alarms, and FinOps egress telemetry.', contractHash: 'sha256:2210aae88401bdfe771032cf', owner: { name: 'Sarah Jenkins', role: 'VP Data Infrastructure', handle: '@sarah.jenkins', team: '#platform-infra', initials: 'SJ', }, slaScore: 99.99, freshnessLatency: '< 500ms', uptime: '99.99%', assertionsPassed: 14, assertionsTotal: 14, activeConsumersCount: 28, topConsumers: ['Mesh Control Plane', 'Datadog Gateway', 'FinOps Cost Allocator', 'Governance Engine'], ports: [ { id: 'snowflake', name: 'Mesh Query Audit Table', typeLabel: 'Snowflake Table', protocol: 'Snowflake SQL / Observability DW', uri: 'snowflake://prod_dw.observability.fct_mesh_query_logs', accessRole: 'ROLE: MESH_ADMIN', columns: [ { name: 'query_execution_id', type: 'varchar(64)', nullable: false, isKey: true, desc: 'Federated query execution trace ID', constraints: 'PRIMARY KEY', }, { name: 'caller_principal', type: 'varchar(64)', nullable: false, desc: 'Service account or user querying the port', }, { name: 'target_data_product', type: 'varchar(64)', nullable: false, desc: 'Queried Data Product identifier', }, { name: 'duration_ms', type: 'integer', nullable: false, desc: 'Execution duration in milliseconds' }, { name: 'bytes_scanned_mb', type: 'decimal(12,2)', nullable: false, desc: 'Egress bandwidth volume for FinOps attribution', }, ], sampleQuery: `SELECT caller_principal, target_data_product, duration_ms, bytes_scanned_mb\nFROM prod_dw.observability.fct_mesh_query_logs\nORDER BY duration_ms DESC\nLIMIT 5;`, mockResults: [ { caller_principal: 'svc_revops_dashboard', target_data_product: 'dp_customer_360_profile', duration_ms: 38, bytes_scanned_mb: '14.2 MB', }, { caller_principal: 'svc_fraud_detector', target_data_product: 'dp_realtime_order_stream', duration_ms: 12, bytes_scanned_mb: '4.8 MB', }, ], }, { id: 'kafka', name: 'OpenTelemetry OTLP Trace Stream', typeLabel: 'Kafka Stream', protocol: 'Kafka Event Topic / Protobuf v3', uri: 'kafka://events.kafka.internal:9092/platform.mesh.audit.v1', accessRole: 'mTLS Certificate (CN=service.mesh.observer)', throughput: '85,000 msg/sec', samplePayload: `{\n "trace_id": "tr_99014ab",\n "caller": "svc_fraud_detector",\n "product": "dp_realtime_order_stream",\n "port": "kafka",\n "latency_ms": 12,\n "status": 200\n}`, }, ], governancePolicies: [ 'FinOps Cost Attribution: Every query query-plan tagged with consumer squad ID', 'Zero Trust Egress: Real-time anomaly alerts on unauthorized consumer bursts', ], }, ]src/app/components/blocks/data-mesh-domain-catalog/index.ts0.6 kB
export { UiDataMeshDomainCatalogComponent, type DomainMeta, type OutputPortSchemaColumn, type OutputPortDetails, type DataProductItem, type DataMeshPortId, } from './data-mesh-domain-catalog.component' export { UiDataMeshProductDetailComponent, type DataMeshCopyEvent } from './data-mesh-product-detail.component' export { UiDataMeshQueryRunnerComponent } from './data-mesh-query-runner.component' export { UiDataMeshModalsComponent, type DataMeshClassification } from './data-mesh-modals.component' export { DOMAINS, DATA_PRODUCTS } from './data-mesh-data'
Raw manifest:https://uipkge.dev/r/angular/data-mesh-domain-catalog.json