{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "security-data-flow",
  "title": "Security — Data Flow",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/security-data-flow/security-data-flow.component.ts",
      "content": "// Diagram of what crosses the trust boundary and what never does: three labelled\n// zones joined by arrows, with a legend separating metadata from customer rows.\n// Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core'\nimport { ArrowRight, Building2, Cloud, Lock, LucideAngularModule } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\ninterface DataZone {\n  icon: typeof Building2\n  label: string\n  detail: string\n  holds: string[]\n}\n\n// The point of the diagram is the second list: naming what never crosses is\n// more reassuring than any number of things that do.\nconst zones: DataZone[] = [\n  {\n    icon: Building2,\n    label: 'Your warehouse',\n    detail: 'Snowflake, BigQuery, Redshift, Postgres',\n    holds: ['Customer rows', 'PII and PHI', 'Raw event history'],\n  },\n  {\n    icon: Cloud,\n    label: 'Northwind',\n    detail: 'Your chosen region',\n    holds: ['Metric definitions', 'Query plans and timings', 'Access decisions'],\n  },\n  {\n    icon: Lock,\n    label: 'Your viewers',\n    detail: 'Scoped per identity',\n    holds: ['Aggregated results only', 'Nothing cached in the browser'],\n  },\n]\n\nconst crosses = ['Column names and types', 'Aggregate results, scoped', 'Query metadata and timings']\nconst neverCrosses = ['Customer rows', 'Primary keys', 'Free-text fields', 'Anything you have not modelled']\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-security-data-flow, [ui-security-data-flow]',\n  standalone: true,\n  // React renders the root <section> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <section data-slot=\"security-data-flow\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n        <div class=\"max-w-2xl\">\n          <span ui-badge variant=\"secondary\">Data flow</span>\n          <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">What crosses the boundary</h2>\n          <p class=\"text-muted-foreground mt-3 text-lg\">\n            And, more usefully, what never does. Both lists are below the diagram.\n          </p>\n        </div>\n\n        <div ui-card class=\"mt-10\">\n          <div ui-card-content class=\"p-6 lg:p-8\">\n            <div class=\"grid items-stretch gap-4 lg:grid-cols-[1fr_auto_1fr_auto_1fr]\">\n              @for (zone of zones; track zone.label; let index = $index) {\n                <div class=\"border-border bg-muted/30 rounded-lg border p-5\">\n                  <span\n                    class=\"border-border bg-background text-muted-foreground flex size-9 items-center justify-center rounded-lg border\"\n                    aria-hidden=\"true\"\n                  >\n                    <lucide-icon [img]=\"zone.icon\" class=\"size-4\" />\n                  </span>\n                  <p class=\"mt-4 text-sm font-semibold\">{{ zone.label }}</p>\n                  <p class=\"text-muted-foreground mt-0.5 text-xs\">{{ zone.detail }}</p>\n                  <ul class=\"mt-3 space-y-1\">\n                    @for (item of zone.holds; track item) {\n                      <li class=\"text-muted-foreground font-mono text-xs\">\n                        {{ item }}\n                      </li>\n                    }\n                  </ul>\n                </div>\n\n                @if (index < zones.length - 1) {\n                  <div class=\"text-muted-foreground/50 flex items-center justify-center lg:px-2\" aria-hidden=\"true\">\n                    <lucide-icon [img]=\"ArrowRight\" class=\"size-4 rotate-90 lg:rotate-0\" />\n                  </div>\n                }\n              }\n            </div>\n\n            <ui-separator class=\"my-8\" />\n\n            <div class=\"grid gap-8 sm:grid-cols-2\">\n              <div>\n                <p class=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">Crosses the boundary</p>\n                <ul class=\"mt-3 space-y-2\">\n                  @for (item of crosses; track item) {\n                    <li class=\"flex items-center gap-2.5 text-sm\">\n                      <span class=\"bg-primary size-1.5 shrink-0 rounded-full\" aria-hidden=\"true\"></span>\n                      <span>{{ item }}</span>\n                    </li>\n                  }\n                </ul>\n              </div>\n\n              <div>\n                <p class=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">Never crosses</p>\n                <ul class=\"mt-3 space-y-2\">\n                  @for (item of neverCrosses; track item) {\n                    <li class=\"flex items-center gap-2.5 text-sm\">\n                      <span class=\"bg-muted-foreground/40 size-1.5 shrink-0 rounded-full\" aria-hidden=\"true\"></span>\n                      <span class=\"text-muted-foreground\">{{ item }}</span>\n                    </li>\n                  }\n                </ul>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <button ui-button variant=\"outline\" class=\"mt-6\">Read the architecture note</button>\n      </div>\n    </section>\n  `,\n})\nexport class UiSecurityDataFlowComponent {\n  protected readonly ArrowRight = ArrowRight\n  protected readonly zones = zones\n  protected readonly crosses = crosses\n  protected readonly neverCrosses = neverCrosses\n\n  @Input('class') className?: string\n\n  get rootClass(): string {\n    return cn('bg-background', this.className)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/security-data-flow/security-data-flow.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/security-data-flow/index.ts",
      "content": "export { UiSecurityDataFlowComponent } from './security-data-flow.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/security-data-flow/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Diagram of what crosses the boundary and what does not: three labelled zones joined by drawn arrows, with a legend separating metadata from customer rows.",
  "categories": [
    "marketing"
  ]
}