From 9e6e97e68d9512037fbfd258f225f5b4d50d28c0 Mon Sep 17 00:00:00 2001 From: Shreyas Sane Date: Tue, 3 Mar 2026 13:20:21 -0500 Subject: [PATCH 1/6] feat(templates): revamp all pre-made templates to show-stopper level Completely rewrote and expanded template system from 3 basic templates to 6 professional, information-dense templates with proper component library types, colored trust boundaries, and pre-populated STRIDE threats. Templates: E-Commerce Platform, Cloud Microservices, Mobile Banking, SaaS Platform, IoT Smart Building, Healthcare Data Platform. Each template now includes 12-13 elements (proper shapes: hexagons, database barrels, rectangles), 12-13 data flows with protocols and auth indicators, 3 colored trust boundaries, and 5 STRIDE threats with mitigations. Updated empty state UI to 2x3 grid with per-template Lucide icons and accent colors. Added Playwright screenshot script for visual validation. Added screenshots/ to .gitignore. Co-Authored-By: Claude Opus 4.6 --- .gitignore | 1 + docs/plans/todo.md | 48 + e2e/screenshot-templates.spec.ts | 69 + src/components/canvas/canvas.tsx | 39 +- src/lib/templates.ts | 2201 +++++++++++++++++++++++++++--- 5 files changed, 2129 insertions(+), 229 deletions(-) create mode 100644 e2e/screenshot-templates.spec.ts diff --git a/.gitignore b/.gitignore index f0bd4fe..8b39166 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ dist-ssr playwright-report/ test-results/ blob-report/ +screenshots/ # Editor directories and files .vscode/* diff --git a/docs/plans/todo.md b/docs/plans/todo.md index 5431c1f..0383195 100644 --- a/docs/plans/todo.md +++ b/docs/plans/todo.md @@ -4,6 +4,54 @@ Shared execution plan for humans and LLM agents. Update this file before, during --- +## 2026-03-03 — Revamp Pre-Made Templates (Show-Stopper Level) + +### Context +Current templates are basic — generic types (no proper shapes/icons), no colors, no threats, linear/wonky layouts, only 3 templates. Need to make them professional, complex, and visually impressive. + +### Plan +- [x] Rewrite 3 existing templates with proper component library types + - [x] Use `web_browser`, `api_gateway`, `sql_database`, `cdn`, `load_balancer`, etc. for proper shapes (hexagon, database barrel, rect) + - [x] Add 12-13 elements per template (up from 5-8) + - [x] Add colored trust boundaries (different colors per zone type) + - [x] Add 5 pre-populated STRIDE threats with mitigations per template + - [x] Add rich descriptions, technologies, stores on all elements + - [x] Design professional spatial layouts (layered, hub-and-spoke) +- [x] Add 3 new templates (total 6 for 2x3 grid) + - [x] SaaS Platform + - [x] IoT Smart Building + - [x] Healthcare Data Platform +- [x] Update EmptyCanvas grid layout for 6 templates (2x3 grid, per-template icons + accent colors) +- [x] Visual validation with Playwright + - [x] Screenshot each template after loading + - [x] Fix onboarding suppression (correct localStorage keys + format) + - [x] Iterate on positions — spread columns wider for flow label clarity + - [x] Verify colors, shapes, boundary sizing — all rendering correctly +- [x] Validate: biome clean, tsc clean, vitest 408/408 pass + +### Files Modified +| File | Change | +|------|--------| +| `src/lib/templates.ts` | Complete rewrite — 6 templates (was 3), 12-13 elements each, colored boundaries, 5 STRIDE threats per template, proper component library types | +| `src/components/canvas/canvas.tsx` | 2x3 template grid (was max-w-lg), per-template Lucide icons + accent colors | +| `e2e/screenshot-templates.spec.ts` | New — Playwright visual validation script for all templates | +| `docs/plans/todo.md` | This plan | + +### Files Deleted +| File | Why | +|------|-----| +| `scripts/screenshot-templates.ts` | Superseded by `e2e/screenshot-templates.spec.ts` | + +### Notes +- Template 1: E-Commerce Platform (revamp of Web Application) +- Template 2: Cloud Microservices (revamp of Microservices) +- Template 3: Mobile Banking (revamp of Mobile App) +- Template 4: SaaS Platform (new) +- Template 5: IoT Smart Building (new) +- Template 6: Healthcare Data Platform (new) + +--- + ## 2026-03-03 — Remove Keyboard Shortcuts Dialog + Fix Broken E2E Tests ### Context diff --git a/e2e/screenshot-templates.spec.ts b/e2e/screenshot-templates.spec.ts new file mode 100644 index 0000000..52864c6 --- /dev/null +++ b/e2e/screenshot-templates.spec.ts @@ -0,0 +1,69 @@ +/** + * Playwright script to screenshot all templates for visual validation. + * Usage: npx playwright test e2e/screenshot-templates.spec.ts + */ +import { test } from "@playwright/test"; + +const TEMPLATES = [ + "ecommerce-platform", + "cloud-microservices", + "mobile-banking", + "saas-platform", + "iot-smart-building", + "healthcare-system", +]; + +/** Suppress all onboarding dialogs by pre-setting localStorage */ +async function suppressOnboarding(page: import("@playwright/test").Page) { + await page.addInitScript(() => { + // Mark What's New as seen — must match CURRENT_VERSION exactly ("1.0.0") + localStorage.setItem("threatforge-last-seen-version", "1.0.0"); + // Mark all onboarding guides as completed (flat format, not Zustand persist) + localStorage.setItem( + "threatforge-onboarding", + JSON.stringify({ + completedGuideIds: [ + "welcome", + "dfd-basics", + "stride-analysis", + "ai-assistant", + ], + dismissedGuideIds: [], + }), + ); + }); +} + +test("screenshot empty state", async ({ page }) => { + await suppressOnboarding(page); + await page.goto("/app"); + await page.waitForSelector('[data-testid="empty-canvas"]', { timeout: 10000 }); + await page.waitForTimeout(500); + await page.screenshot({ + path: "screenshots/empty-state.png", + fullPage: false, + }); +}); + +for (const templateId of TEMPLATES) { + test(`screenshot template: ${templateId}`, async ({ page }) => { + await suppressOnboarding(page); + await page.goto("/app"); + await page.waitForSelector('[data-testid="empty-canvas"]', { timeout: 10000 }); + + // Click the template card + await page.click(`[data-testid="template-${templateId}"]`); + + // Wait for canvas to render with nodes + await page.waitForSelector('[data-testid="canvas-area"]', { timeout: 10000 }); + await page.waitForSelector(".react-flow__node", { timeout: 10000 }); + + // Give ReactFlow a moment to settle layout + await page.waitForTimeout(1000); + + await page.screenshot({ + path: `screenshots/template-${templateId}.png`, + fullPage: false, + }); + }); +} diff --git a/src/components/canvas/canvas.tsx b/src/components/canvas/canvas.tsx index 6da21b7..17ffad4 100644 --- a/src/components/canvas/canvas.tsx +++ b/src/components/canvas/canvas.tsx @@ -1,4 +1,15 @@ -import { FileText, FolderOpen, Github } from "lucide-react"; +import { + Building2, + Cloud, + CreditCard, + FolderOpen, + Github, + HeartPulse, + type LucideIcon, + Radio, + ShoppingCart, + Smartphone, +} from "lucide-react"; import { lazy, Suspense, useCallback, useEffect, useRef, useState } from "react"; import { useFileOperations } from "@/hooks/use-file-operations"; import { buildLayoutFromModel } from "@/lib/model-layout-utils"; @@ -85,7 +96,7 @@ function EmptyCanvas() { {/* Templates */} -
+

Start from a template

@@ -120,6 +131,25 @@ function EmptyCanvas() { ); } +const TEMPLATE_ICONS: Record = { + "ecommerce-platform": ShoppingCart, + "cloud-microservices": Cloud, + "mobile-banking": Smartphone, + "saas-platform": CreditCard, + "iot-smart-building": Building2, + "healthcare-system": HeartPulse, +}; + +/** Accent colors per template (matching boundary color families) */ +const TEMPLATE_ACCENT: Record = { + "ecommerce-platform": "text-orange-400", + "cloud-microservices": "text-blue-400", + "mobile-banking": "text-red-400", + "saas-platform": "text-purple-400", + "iot-smart-building": "text-emerald-400", + "healthcare-system": "text-rose-400", +}; + function TemplateCard({ template, onSelect, @@ -127,6 +157,9 @@ function TemplateCard({ template: TemplateInfo; onSelect: (id: string) => void; }) { + const Icon = TEMPLATE_ICONS[template.id] ?? Radio; + const accentClass = TEMPLATE_ACCENT[template.id] ?? "text-muted-foreground"; + return ( diff --git a/src/lib/templates.ts b/src/lib/templates.ts index 73c6c5d..b4335c6 100644 --- a/src/lib/templates.ts +++ b/src/lib/templates.ts @@ -9,19 +9,34 @@ export interface TemplateInfo { export const TEMPLATES: TemplateInfo[] = [ { - id: "web-application", - name: "Web Application", - description: "Frontend, API backend, database, and auth provider", + id: "ecommerce-platform", + name: "E-Commerce Platform", + description: "CDN, WAF, load balancer, app servers, payment processing, and caching", }, { - id: "microservices", - name: "Microservices", - description: "API gateway, services, message queue, cache, and databases", + id: "cloud-microservices", + name: "Cloud Microservices", + description: "API gateway, service mesh, event-driven services, and managed databases", }, { - id: "mobile-app", - name: "Mobile App", - description: "Mobile client, API, push notifications, and analytics", + id: "mobile-banking", + name: "Mobile Banking", + description: "High-security mobile app with fraud detection, PCI compliance, and HSM", + }, + { + id: "saas-platform", + name: "SaaS Platform", + description: "Multi-tenant SaaS with auth, background jobs, CI/CD, and monitoring", + }, + { + id: "iot-smart-building", + name: "IoT Smart Building", + description: "Edge devices, MQTT broker, stream processing, and building analytics", + }, + { + id: "healthcare-system", + name: "Healthcare System", + description: "HIPAA-compliant EHR with FHIR API, patient portal, and audit logging", }, ]; @@ -65,99 +80,269 @@ export function loadTemplate(id: string): ThreatModel | null { type TemplateBuilder = (today: string) => ThreatModel; +/* ───────────────────────────────────────────────────────────────────────────── + * Boundary color palette (hex) + * ────────────────────────────────────────────────────────────────────────── */ +const BOUNDARY_COLORS = { + edge: { fill: "#F97316", stroke: "#F97316", fillOpacity: 0.04, strokeOpacity: 0.45 }, + internal: { fill: "#3B82F6", stroke: "#3B82F6", fillOpacity: 0.04, strokeOpacity: 0.45 }, + data: { fill: "#8B5CF6", stroke: "#8B5CF6", fillOpacity: 0.04, strokeOpacity: 0.45 }, + security: { fill: "#EF4444", stroke: "#EF4444", fillOpacity: 0.05, strokeOpacity: 0.5 }, + external: { fill: "#6B7280", stroke: "#6B7280", fillOpacity: 0.03, strokeOpacity: 0.35 }, + iot: { fill: "#10B981", stroke: "#10B981", fillOpacity: 0.04, strokeOpacity: 0.45 }, +}; + +/* ═════════════════════════════════════════════════════════════════════════════ + * TEMPLATE 1: E-Commerce Platform + * ═════════════════════════════════════════════════════════════════════════ */ const TEMPLATE_BUILDERS: Record = { - "web-application": (today) => ({ + "ecommerce-platform": (today) => ({ version: "1.0", metadata: { - title: "Web Application", + title: "E-Commerce Platform", author: "", created: today, modified: today, description: - "A standard web application with frontend, API backend,\ndatabase, and external authentication provider.", + "Full-stack e-commerce platform with CDN edge delivery, WAF protection,\nload-balanced application servers, payment processing, and caching layer.", }, elements: [ { - id: "browser", - type: "external_entity", - name: "Browser Client", + id: "customer-browser", + type: "web_browser", + name: "Customer Browser", trust_zone: "external", - description: "End-user web browser", - technologies: [], - position: { x: 80, y: 240 }, + description: "End-user web browser accessing the storefront", + technologies: ["spa", "react"], + position: { x: 60, y: 200 }, + }, + { + id: "mobile-shopper", + type: "mobile_app", + name: "Mobile App", + trust_zone: "external", + description: "iOS/Android shopping application", + technologies: ["react-native"], + position: { x: 60, y: 380 }, + }, + { + id: "edge-cdn", + type: "cdn", + name: "CDN / Edge Cache", + trust_zone: "dmz", + description: "Global content delivery for static assets and cached pages", + technologies: ["cloudflare"], + position: { x: 310, y: 120 }, + }, + { + id: "waf", + type: "waf", + name: "WAF", + trust_zone: "dmz", + description: "Web application firewall filtering malicious requests", + technologies: ["cloudflare-waf", "owasp-crs"], + position: { x: 310, y: 290 }, }, { - id: "web-server", - type: "process", - name: "Web Server", + id: "load-balancer", + type: "load_balancer", + name: "Load Balancer", trust_zone: "dmz", - description: "Serves frontend assets and proxies API requests", - technologies: ["nginx", "reverse-proxy"], - position: { x: 350, y: 240 }, + description: "Layer 7 load balancer distributing traffic across app servers", + technologies: ["aws-alb", "tls-termination"], + position: { x: 310, y: 460 }, + }, + { + id: "web-app", + type: "web_server", + name: "Web Application", + trust_zone: "internal", + description: "Server-side rendered storefront and checkout flow", + technologies: ["next.js", "node"], + position: { x: 650, y: 120 }, }, { id: "api-server", - type: "process", + type: "api_gateway", name: "API Server", trust_zone: "internal", - description: "Handles business logic and data access", - technologies: ["node", "express"], - position: { x: 620, y: 240 }, + description: "REST API handling product catalog, cart, and order operations", + technologies: ["express", "node", "openapi"], + position: { x: 650, y: 290 }, + }, + { + id: "order-worker", + type: "background_worker", + name: "Order Worker", + trust_zone: "internal", + description: "Async order processing, inventory updates, and email dispatch", + technologies: ["bull", "node"], + position: { x: 650, y: 460 }, }, { - id: "database", - type: "data_store", - name: "Database", + id: "product-db", + type: "sql_database", + name: "Product Database", trust_zone: "internal", - description: "Primary relational database", - stores: ["user_data", "application_data"], + description: "Primary relational store for products, orders, and users", + stores: ["products", "orders", "customers", "inventory"], encryption: "AES-256-at-rest", - technologies: [], - position: { x: 890, y: 240 }, + technologies: ["postgresql"], + position: { x: 970, y: 120 }, + }, + { + id: "session-cache", + type: "cache", + name: "Session Cache", + trust_zone: "internal", + description: "In-memory session store and API response cache", + stores: ["sessions", "cart_data", "rate_limits"], + technologies: ["redis"], + position: { x: 970, y: 290 }, + }, + { + id: "search-engine", + type: "search_index", + name: "Search Index", + trust_zone: "internal", + description: "Full-text product search and faceted filtering", + stores: ["product_index", "autocomplete"], + technologies: ["elasticsearch"], + position: { x: 970, y: 460 }, + }, + { + id: "payment-gateway", + type: "api_endpoint", + name: "Payment Gateway", + trust_zone: "external", + description: "PCI-compliant payment processor for card transactions", + technologies: ["stripe"], + position: { x: 650, y: 640 }, }, { - id: "auth-provider", - type: "external_entity", - name: "Auth Provider", + id: "auth-idp", + type: "identity_provider", + name: "Identity Provider", trust_zone: "external", - description: "Third-party OAuth2/OIDC identity provider", - technologies: [], - position: { x: 620, y: 480 }, + description: "OAuth 2.0 / OIDC provider for customer SSO", + technologies: ["auth0", "oidc"], + position: { x: 310, y: 640 }, }, ], data_flows: [ { - id: "flow-browser-web", + id: "flow-browser-cdn", + name: "", + from: "customer-browser", + to: "edge-cdn", + protocol: "HTTPS/TLS-1.3", + data: ["static_assets", "cached_pages"], + authenticated: false, + }, + { + id: "flow-browser-waf", name: "", - from: "browser", - to: "web-server", + from: "customer-browser", + to: "waf", protocol: "HTTPS/TLS-1.3", data: ["http_requests", "cookies"], authenticated: false, }, { - id: "flow-web-api", + id: "flow-mobile-waf", + name: "", + from: "mobile-shopper", + to: "waf", + protocol: "HTTPS/TLS-1.3", + data: ["api_requests", "jwt_tokens"], + authenticated: true, + }, + { + id: "flow-waf-lb", + name: "", + from: "waf", + to: "load-balancer", + protocol: "HTTPS/TLS-1.3", + data: ["filtered_requests"], + authenticated: false, + }, + { + id: "flow-cdn-webapp", + name: "", + from: "edge-cdn", + to: "web-app", + protocol: "HTTPS/TLS-1.3", + data: ["cache_misses", "dynamic_requests"], + authenticated: false, + }, + { + id: "flow-lb-api", + name: "", + from: "load-balancer", + to: "api-server", + protocol: "HTTP/2", + data: ["api_requests", "auth_headers"], + authenticated: true, + }, + { + id: "flow-webapp-api", name: "", - from: "web-server", + from: "web-app", to: "api-server", - protocol: "HTTP", - data: ["api_requests", "auth_tokens"], + protocol: "HTTP/2", + data: ["ssr_requests", "api_calls"], authenticated: true, }, { id: "flow-api-db", name: "", from: "api-server", - to: "database", + to: "product-db", protocol: "PostgreSQL/TLS", - data: ["queries", "user_data"], + data: ["queries", "product_data", "order_data"], + authenticated: true, + }, + { + id: "flow-api-cache", + name: "", + from: "api-server", + to: "session-cache", + protocol: "Redis/TLS", + data: ["session_data", "cached_responses"], + authenticated: false, + }, + { + id: "flow-api-search", + name: "", + from: "api-server", + to: "search-engine", + protocol: "HTTPS/TLS-1.2", + data: ["search_queries", "filter_criteria"], authenticated: true, }, + { + id: "flow-api-payment", + name: "", + from: "api-server", + to: "payment-gateway", + protocol: "HTTPS/TLS-1.3", + data: ["tokenized_card_data", "charge_requests"], + authenticated: true, + }, + { + id: "flow-api-worker", + name: "", + from: "api-server", + to: "order-worker", + protocol: "Redis/TLS", + data: ["order_events", "job_payloads"], + authenticated: false, + }, { id: "flow-api-auth", name: "", from: "api-server", - to: "auth-provider", + to: "auth-idp", protocol: "HTTPS/TLS-1.3", data: ["oauth_tokens", "user_claims"], authenticated: true, @@ -165,21 +350,112 @@ const TEMPLATE_BUILDERS: Record = { ], trust_boundaries: [ { - id: "boundary-dmz", - name: "DMZ", - contains: ["web-server"], - position: { x: 300, y: 180 }, - size: { width: 200, height: 160 }, + id: "boundary-edge", + name: "Edge / DMZ", + contains: ["edge-cdn", "waf", "load-balancer"], + position: { x: 265, y: 75 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.edge.fill, + stroke_color: BOUNDARY_COLORS.edge.stroke, + fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.edge.strokeOpacity, + }, + { + id: "boundary-app", + name: "Application Tier", + contains: ["web-app", "api-server", "order-worker"], + position: { x: 605, y: 75 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.internal.fill, + stroke_color: BOUNDARY_COLORS.internal.stroke, + fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.internal.strokeOpacity, + }, + { + id: "boundary-data", + name: "Data Tier", + contains: ["product-db", "session-cache", "search-engine"], + position: { x: 925, y: 75 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.data.fill, + stroke_color: BOUNDARY_COLORS.data.stroke, + fill_opacity: BOUNDARY_COLORS.data.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.data.strokeOpacity, + }, + ], + threats: [ + { + id: "threat-xss", + title: "Cross-site scripting via user-generated content", + category: "Tampering", + element: "web-app", + severity: "high", + description: + "Product reviews and user profiles may contain malicious scripts\nthat execute in other customers' browsers.", + mitigation: { + status: "mitigated", + description: + "CSP headers enforced; output encoding via React's default XSS protection; DOMPurify for rich text", + }, + }, + { + id: "threat-sqli", + title: "SQL injection on product search queries", + category: "Tampering", + element: "api-server", + flow: "flow-api-db", + severity: "critical", + description: + "Malicious SQL could be injected through search parameters\nor filter criteria if input validation is insufficient.", + mitigation: { + status: "mitigated", + description: "Parameterized queries via Prisma ORM; input validation with zod schemas", + }, + }, + { + id: "threat-session-hijack", + title: "Session token theft via cache exposure", + category: "Spoofing", + element: "session-cache", + severity: "high", + description: + "Redis cache stores session tokens; if accessed by an attacker,\nthey could impersonate authenticated users.", + mitigation: { + status: "in_progress", + description: + "Redis AUTH enabled; network-level isolation via VPC; session tokens rotated on privilege escalation", + }, + }, + { + id: "threat-payment-exposure", + title: "Payment card data intercepted in transit", + category: "Information Disclosure", + element: "api-server", + flow: "flow-api-payment", + severity: "critical", + description: + "Card data transmitted to payment gateway could be intercepted\nif TLS is misconfigured or downgraded.", + mitigation: { + status: "mitigated", + description: + "TLS 1.3 enforced; Stripe.js tokenizes cards client-side; PCI DSS Level 1 compliance via Stripe", + }, }, { - id: "boundary-internal", - name: "Internal Network", - contains: ["api-server", "database"], - position: { x: 570, y: 180 }, - size: { width: 400, height: 160 }, + id: "threat-ddos", + title: "Volumetric DDoS attack on storefront", + category: "Denial of Service", + element: "waf", + severity: "medium", + description: + "High-volume traffic floods could overwhelm the WAF and load balancer,\nmaking the storefront unavailable during peak sales.", + mitigation: { + status: "mitigated", + description: + "Cloudflare DDoS protection; rate limiting at WAF and API layers; auto-scaling app servers", + }, }, ], - threats: [], diagrams: [ { id: "main-dfd", @@ -189,191 +465,368 @@ const TEMPLATE_BUILDERS: Record = { ], }), - microservices: (today) => ({ + /* ═════════════════════════════════════════════════════════════════════════ + * TEMPLATE 2: Cloud Microservices + * ═════════════════════════════════════════════════════════════════════ */ + "cloud-microservices": (today) => ({ version: "1.0", metadata: { - title: "Microservices Architecture", + title: "Cloud Microservices", author: "", created: today, modified: today, description: - "A microservices architecture with API gateway, multiple services,\nmessage queue, cache layer, and databases.", + "Cloud-native microservices architecture with API gateway, service mesh,\nevent-driven communication, and managed data stores.", }, elements: [ { - id: "mobile-app", - type: "external_entity", - name: "Mobile App", + id: "web-client", + type: "web_browser", + name: "Web Client", trust_zone: "external", - description: "iOS/Android mobile client", - technologies: [], - position: { x: 80, y: 300 }, + description: "Single-page application served via CDN", + technologies: ["react", "vite"], + position: { x: 60, y: 160 }, }, { - id: "api-gateway", - type: "process", + id: "mobile-client", + type: "mobile_app", + name: "Mobile Client", + trust_zone: "external", + description: "Native iOS/Android application", + technologies: ["swift", "kotlin"], + position: { x: 60, y: 380 }, + }, + { + id: "api-gw", + type: "api_gateway", name: "API Gateway", trust_zone: "dmz", - description: "Routes requests, handles rate limiting and auth", - technologies: ["kong", "rate-limiting"], - position: { x: 350, y: 300 }, + description: "Central entry point handling auth, rate limiting, and request routing", + technologies: ["kong", "jwt-validation", "rate-limiting"], + position: { x: 310, y: 270 }, + }, + { + id: "svc-mesh", + type: "service_mesh", + name: "Service Mesh", + trust_zone: "internal", + description: "Sidecar proxy layer for mTLS, observability, and traffic shaping", + technologies: ["istio", "envoy"], + position: { x: 600, y: 100 }, }, { - id: "user-service", - type: "process", + id: "user-svc", + type: "microservice", name: "User Service", trust_zone: "internal", - description: "Manages user accounts and profiles", - technologies: [], - position: { x: 620, y: 160 }, + description: "Manages user registration, profiles, and authentication", + technologies: ["go", "grpc"], + position: { x: 600, y: 270 }, + }, + { + id: "product-svc", + type: "microservice", + name: "Product Service", + trust_zone: "internal", + description: "Handles product catalog, pricing, and inventory", + technologies: ["go", "grpc"], + position: { x: 600, y: 440 }, }, { - id: "order-service", - type: "process", + id: "order-svc", + type: "microservice", name: "Order Service", trust_zone: "internal", - description: "Handles order processing and fulfillment", - technologies: [], - position: { x: 620, y: 440 }, + description: "Order lifecycle management and fulfillment coordination", + technologies: ["go", "grpc"], + position: { x: 850, y: 270 }, + }, + { + id: "notification-svc", + type: "microservice", + name: "Notification Service", + trust_zone: "internal", + description: "Email, SMS, and push notification dispatch", + technologies: ["node", "typescript"], + position: { x: 850, y: 440 }, + }, + { + id: "event-bus", + type: "event_bus", + name: "Event Bus", + trust_zone: "internal", + description: "Asynchronous event streaming between services", + technologies: ["kafka", "schema-registry"], + position: { x: 850, y: 100 }, }, { id: "user-db", - type: "data_store", + type: "sql_database", name: "User Database", trust_zone: "internal", - description: "", - stores: ["user_profiles", "credentials"], + description: "Relational store for user accounts and credentials", + stores: ["users", "roles", "credentials"], encryption: "AES-256-at-rest", - technologies: [], - position: { x: 920, y: 160 }, + technologies: ["postgresql"], + position: { x: 1110, y: 100 }, }, { - id: "order-db", - type: "data_store", - name: "Order Database", + id: "product-db", + type: "nosql_database", + name: "Product Catalog", trust_zone: "internal", - description: "", - stores: ["orders", "transactions"], - technologies: [], - position: { x: 920, y: 440 }, + description: "Document store for flexible product schemas", + stores: ["products", "categories", "pricing"], + technologies: ["mongodb"], + position: { x: 1110, y: 270 }, }, { - id: "message-queue", - type: "data_store", - name: "Message Queue", + id: "order-db", + type: "sql_database", + name: "Order Database", trust_zone: "internal", - description: "Async communication between services", - technologies: ["rabbitmq"], - position: { x: 620, y: 300 }, + description: "Transactional store for orders and payments", + stores: ["orders", "payments", "shipping"], + encryption: "AES-256-at-rest", + technologies: ["postgresql"], + position: { x: 1110, y: 440 }, }, { - id: "cache", - type: "data_store", - name: "Redis Cache", + id: "secrets-vault", + type: "secret_manager", + name: "Secrets Vault", trust_zone: "internal", - description: "Session and response caching", - technologies: ["redis"], - position: { x: 350, y: 160 }, + description: "Centralized secret storage for service credentials and API keys", + stores: ["api_keys", "db_credentials", "tls_certs"], + technologies: ["hashicorp-vault"], + position: { x: 310, y: 470 }, }, ], data_flows: [ + { + id: "flow-web-gw", + name: "", + from: "web-client", + to: "api-gw", + protocol: "HTTPS/TLS-1.3", + data: ["api_requests", "jwt_tokens"], + authenticated: true, + }, { id: "flow-mobile-gw", name: "", - from: "mobile-app", - to: "api-gateway", + from: "mobile-client", + to: "api-gw", protocol: "HTTPS/TLS-1.3", data: ["api_requests", "jwt_tokens"], authenticated: true, }, { - id: "flow-gw-users", + id: "flow-gw-user", name: "", - from: "api-gateway", - to: "user-service", - protocol: "gRPC/TLS", - data: ["user_requests"], + from: "api-gw", + to: "user-svc", + protocol: "gRPC/mTLS", + data: ["user_requests", "auth_context"], authenticated: true, }, { - id: "flow-gw-orders", + id: "flow-gw-product", name: "", - from: "api-gateway", - to: "order-service", - protocol: "gRPC/TLS", - data: ["order_requests"], + from: "api-gw", + to: "product-svc", + protocol: "gRPC/mTLS", + data: ["catalog_queries", "search_requests"], + authenticated: true, + }, + { + id: "flow-gw-order", + name: "", + from: "api-gw", + to: "order-svc", + protocol: "gRPC/mTLS", + data: ["order_requests", "cart_data"], authenticated: true, }, { - id: "flow-users-db", + id: "flow-user-db", name: "", - from: "user-service", + from: "user-svc", to: "user-db", protocol: "PostgreSQL/TLS", - data: ["user_data"], - authenticated: false, + data: ["user_data", "credential_hashes"], + authenticated: true, + }, + { + id: "flow-product-db", + name: "", + from: "product-svc", + to: "product-db", + protocol: "MongoDB/TLS", + data: ["product_documents", "category_data"], + authenticated: true, }, { - id: "flow-orders-db", + id: "flow-order-db", name: "", - from: "order-service", + from: "order-svc", to: "order-db", protocol: "PostgreSQL/TLS", - data: ["order_data"], - authenticated: false, + data: ["order_records", "payment_data"], + authenticated: true, }, { - id: "flow-users-mq", + id: "flow-user-events", name: "", - from: "user-service", - to: "message-queue", - protocol: "AMQP/TLS", - data: ["user_events"], + from: "user-svc", + to: "event-bus", + protocol: "Kafka/TLS", + data: ["user_created", "profile_updated"], authenticated: false, }, { - id: "flow-mq-orders", + id: "flow-order-events", name: "", - from: "message-queue", - to: "order-service", - protocol: "AMQP/TLS", - data: ["user_events"], + from: "order-svc", + to: "event-bus", + protocol: "Kafka/TLS", + data: ["order_placed", "order_fulfilled"], authenticated: false, }, { - id: "flow-gw-cache", + id: "flow-events-notify", name: "", - from: "api-gateway", - to: "cache", - protocol: "Redis/TLS", - data: ["session_data", "cached_responses"], + from: "event-bus", + to: "notification-svc", + protocol: "Kafka/TLS", + data: ["notification_events"], authenticated: false, }, + { + id: "flow-gw-secrets", + name: "", + from: "api-gw", + to: "secrets-vault", + protocol: "HTTPS/mTLS", + data: ["secret_requests", "token_rotation"], + authenticated: true, + }, ], trust_boundaries: [ { - id: "boundary-dmz", - name: "DMZ", - contains: ["api-gateway"], - position: { x: 300, y: 240 }, - size: { width: 200, height: 160 }, + id: "boundary-edge", + name: "Edge / DMZ", + contains: ["api-gw"], + position: { x: 265, y: 225 }, + size: { width: 230, height: 120 }, + fill_color: BOUNDARY_COLORS.edge.fill, + stroke_color: BOUNDARY_COLORS.edge.stroke, + fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.edge.strokeOpacity, }, { id: "boundary-services", - name: "Internal Services", + name: "Service Tier (Kubernetes)", contains: [ - "user-service", - "order-service", - "message-queue", - "cache", - "user-db", - "order-db", + "svc-mesh", + "user-svc", + "product-svc", + "order-svc", + "notification-svc", + "event-bus", ], - position: { x: 290, y: 90 }, - size: { width: 720, height: 450 }, + position: { x: 555, y: 55 }, + size: { width: 450, height: 480 }, + fill_color: BOUNDARY_COLORS.internal.fill, + stroke_color: BOUNDARY_COLORS.internal.stroke, + fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.internal.strokeOpacity, + }, + { + id: "boundary-data", + name: "Data Tier", + contains: ["user-db", "product-db", "order-db"], + position: { x: 1065, y: 55 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.data.fill, + stroke_color: BOUNDARY_COLORS.data.stroke, + fill_opacity: BOUNDARY_COLORS.data.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.data.strokeOpacity, + }, + ], + threats: [ + { + id: "threat-jwt-forge", + title: "JWT token forgery bypassing API gateway auth", + category: "Spoofing", + element: "api-gw", + severity: "critical", + description: + "An attacker could forge JWT tokens if signing keys are\nweak or leaked, bypassing all downstream authorization.", + mitigation: { + status: "mitigated", + description: + "RS256 asymmetric signing; keys rotated via Vault; token expiry set to 15 minutes", + }, + }, + { + id: "threat-event-tampering", + title: "Event payload tampering in Kafka topics", + category: "Tampering", + element: "event-bus", + severity: "high", + description: + "A compromised service could publish tampered events to Kafka topics,\ncorrupting downstream data in notification and order services.", + mitigation: { + status: "in_progress", + description: + "Schema Registry enforces Avro schemas; mTLS between services; event signing under evaluation", + }, + }, + { + id: "threat-credential-leak", + title: "Database credential leak from Secrets Vault", + category: "Information Disclosure", + element: "secrets-vault", + severity: "critical", + description: + "If Vault is compromised, all database credentials and API keys\nare exposed, enabling full data access.", + mitigation: { + status: "mitigated", + description: + "Vault sealed with Shamir's Secret Sharing; audit logging enabled; dynamic credentials with 1h TTL", + }, + }, + { + id: "threat-noisy-neighbor", + title: "Noisy neighbor DoS via API gateway", + category: "Denial of Service", + element: "api-gw", + severity: "medium", + description: + "A single misbehaving client could exhaust rate limits and\ndegrade service for all other users.", + mitigation: { + status: "mitigated", + description: + "Per-client rate limiting via Kong; circuit breakers in service mesh; horizontal pod autoscaling", + }, + }, + { + id: "threat-lateral-movement", + title: "Lateral movement between microservices", + category: "Elevation of Privilege", + element: "user-svc", + severity: "high", + description: + "If one service is compromised, an attacker could move laterally\nto other services in the Kubernetes cluster.", + mitigation: { + status: "mitigated", + description: + "Istio mTLS enforced; Kubernetes NetworkPolicies isolate namespaces; RBAC with least-privilege service accounts", + }, }, ], - threats: [], diagrams: [ { id: "main-dfd", @@ -383,131 +836,1427 @@ const TEMPLATE_BUILDERS: Record = { ], }), - "mobile-app": (today) => ({ + /* ═════════════════════════════════════════════════════════════════════════ + * TEMPLATE 3: Mobile Banking + * ═════════════════════════════════════════════════════════════════════ */ + "mobile-banking": (today) => ({ version: "1.0", metadata: { - title: "Mobile Application", + title: "Mobile Banking Application", author: "", created: today, modified: today, description: - "A mobile application with API backend, push notifications,\nlocal storage, and third-party analytics.", + "High-security mobile banking application with PCI-compliant payment processing,\nfraud detection, biometric authentication, and comprehensive audit logging.", }, elements: [ { - id: "mobile-client", - type: "external_entity", - name: "Mobile Client", + id: "banking-app", + type: "mobile_app", + name: "Banking App", trust_zone: "external", - description: "iOS/Android app installed on user device", - technologies: [], - position: { x: 80, y: 280 }, + description: "Native mobile banking app with biometric auth and certificate pinning", + technologies: ["swift", "kotlin", "cert-pinning"], + position: { x: 60, y: 280 }, + }, + { + id: "api-gateway", + type: "api_gateway", + name: "API Gateway", + trust_zone: "dmz", + description: "TLS-terminating gateway with OAuth2 validation and request throttling", + technologies: ["kong", "oauth2", "rate-limiting"], + position: { x: 310, y: 280 }, }, { - id: "api-backend", - type: "process", - name: "API Backend", + id: "auth-service", + type: "auth_provider", + name: "Auth Service", trust_zone: "internal", - description: "REST API serving mobile client requests", - technologies: ["python", "fastapi"], - position: { x: 400, y: 280 }, + description: "MFA authentication with biometric, OTP, and password support", + technologies: ["node", "passport", "webauthn"], + position: { x: 600, y: 110 }, }, { - id: "app-db", - type: "data_store", - name: "Application Database", + id: "account-service", + type: "microservice", + name: "Account Service", trust_zone: "internal", - description: "", - stores: ["user_data", "app_state"], + description: "Core banking operations: balances, transfers, and statements", + technologies: ["java", "spring-boot"], + position: { x: 600, y: 280 }, + }, + { + id: "fraud-engine", + type: "microservice", + name: "Fraud Detection", + trust_zone: "internal", + description: "Real-time transaction scoring and anomaly detection", + technologies: ["python", "scikit-learn", "kafka-streams"], + position: { x: 600, y: 450 }, + }, + { + id: "core-db", + type: "sql_database", + name: "Core Banking DB", + trust_zone: "internal", + description: "ACID-compliant transactional database for account balances and ledger", + stores: ["accounts", "transactions", "ledger"], + encryption: "TDE-AES-256", + technologies: ["oracle-db"], + position: { x: 880, y: 280 }, + }, + { + id: "token-store", + type: "cache", + name: "Token Store", + trust_zone: "internal", + description: "Short-lived auth token storage with automatic expiration", + stores: ["access_tokens", "refresh_tokens", "mfa_challenges"], + technologies: ["redis", "cluster-mode"], + position: { x: 880, y: 110 }, + }, + { + id: "audit-log", + type: "data_lake", + name: "Audit Log", + trust_zone: "internal", + description: "Immutable audit trail for all transactions and security events", + stores: ["transaction_logs", "auth_events", "access_logs"], encryption: "AES-256-at-rest", - technologies: [], - position: { x: 720, y: 180 }, + technologies: ["elasticsearch", "s3-archive"], + position: { x: 880, y: 450 }, }, { - id: "file-storage", - type: "data_store", - name: "File Storage", + id: "hsm", + type: "key_management", + name: "HSM", trust_zone: "internal", - description: "User-uploaded media and documents", - technologies: ["s3"], - position: { x: 720, y: 380 }, + description: "Hardware security module for cryptographic key management and signing", + stores: ["master_keys", "signing_keys"], + technologies: ["thales-luna", "pkcs11"], + position: { x: 1110, y: 190 }, + }, + { + id: "card-network", + type: "api_endpoint", + name: "Card Network", + trust_zone: "external", + description: "Visa/Mastercard payment network for card transactions", + technologies: ["iso-8583"], + position: { x: 310, y: 490 }, }, { id: "push-service", - type: "external_entity", - name: "Push Notification Service", + type: "webhook", + name: "Push Notifications", trust_zone: "external", - description: "APNs / FCM push notification delivery", - technologies: [], - position: { x: 400, y: 480 }, + description: "APNs and FCM for transaction alerts and security notifications", + technologies: ["apns", "fcm"], + position: { x: 60, y: 490 }, }, { - id: "analytics", - type: "external_entity", - name: "Analytics Platform", + id: "kyc-provider", + type: "identity_provider", + name: "KYC Provider", trust_zone: "external", - description: "Third-party usage analytics and crash reporting", - technologies: [], - position: { x: 80, y: 480 }, + description: "Know Your Customer identity verification for account opening", + technologies: ["onfido", "document-verification"], + position: { x: 310, y: 110 }, }, ], data_flows: [ { - id: "flow-mobile-api", + id: "flow-app-gw", name: "", - from: "mobile-client", - to: "api-backend", + from: "banking-app", + to: "api-gateway", protocol: "HTTPS/TLS-1.3", - data: ["api_requests", "auth_tokens", "user_input"], + data: ["api_requests", "biometric_tokens", "device_fingerprint"], authenticated: true, }, { - id: "flow-api-db", + id: "flow-gw-auth", name: "", - from: "api-backend", - to: "app-db", - protocol: "PostgreSQL/TLS", - data: ["user_data", "app_state"], + from: "api-gateway", + to: "auth-service", + protocol: "gRPC/mTLS", + data: ["auth_requests", "mfa_challenges"], + authenticated: true, + }, + { + id: "flow-gw-account", + name: "", + from: "api-gateway", + to: "account-service", + protocol: "gRPC/mTLS", + data: ["banking_requests", "transfer_orders"], + authenticated: true, + }, + { + id: "flow-account-fraud", + name: "", + from: "account-service", + to: "fraud-engine", + protocol: "Kafka/TLS", + data: ["transaction_events", "risk_context"], + authenticated: false, + }, + { + id: "flow-auth-tokens", + name: "", + from: "auth-service", + to: "token-store", + protocol: "Redis/TLS", + data: ["access_tokens", "session_data"], + authenticated: false, + }, + { + id: "flow-account-db", + name: "", + from: "account-service", + to: "core-db", + protocol: "Oracle/TLS", + data: ["account_queries", "ledger_entries"], authenticated: true, }, { - id: "flow-api-storage", + id: "flow-account-audit", name: "", - from: "api-backend", - to: "file-storage", + from: "account-service", + to: "audit-log", protocol: "HTTPS/TLS-1.3", - data: ["media_files", "presigned_urls"], + data: ["transaction_logs", "compliance_events"], + authenticated: true, + }, + { + id: "flow-fraud-audit", + name: "", + from: "fraud-engine", + to: "audit-log", + protocol: "HTTPS/TLS-1.3", + data: ["fraud_alerts", "risk_scores"], + authenticated: true, + }, + { + id: "flow-account-card", + name: "", + from: "account-service", + to: "card-network", + protocol: "ISO-8583/TLS", + data: ["authorization_requests", "settlement_data"], + authenticated: true, + }, + { + id: "flow-auth-hsm", + name: "", + from: "auth-service", + to: "hsm", + protocol: "PKCS#11", + data: ["signing_requests", "key_derivation"], authenticated: true, }, { - id: "flow-api-push", + id: "flow-account-push", name: "", - from: "api-backend", + from: "account-service", to: "push-service", protocol: "HTTPS/TLS-1.3", - data: ["push_tokens", "notification_payloads"], + data: ["transaction_alerts", "security_notifications"], authenticated: true, }, { - id: "flow-mobile-analytics", + id: "flow-gw-kyc", name: "", - from: "mobile-client", - to: "analytics", + from: "api-gateway", + to: "kyc-provider", protocol: "HTTPS/TLS-1.3", - data: ["usage_events", "crash_reports", "device_info"], - authenticated: false, + data: ["identity_documents", "verification_requests"], + authenticated: true, }, ], trust_boundaries: [ { - id: "boundary-backend", - name: "Backend Infrastructure", - contains: ["api-backend", "app-db", "file-storage"], - position: { x: 340, y: 120 }, - size: { width: 470, height: 330 }, + id: "boundary-dmz", + name: "DMZ", + contains: ["api-gateway"], + position: { x: 265, y: 235 }, + size: { width: 230, height: 120 }, + fill_color: BOUNDARY_COLORS.edge.fill, + stroke_color: BOUNDARY_COLORS.edge.stroke, + fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.edge.strokeOpacity, + }, + { + id: "boundary-app", + name: "Application Services", + contains: ["auth-service", "account-service", "fraud-engine"], + position: { x: 555, y: 65 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.internal.fill, + stroke_color: BOUNDARY_COLORS.internal.stroke, + fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.internal.strokeOpacity, + }, + { + id: "boundary-data", + name: "Secure Data Zone", + contains: ["core-db", "token-store", "audit-log", "hsm"], + position: { x: 835, y: 65 }, + size: { width: 360, height: 480 }, + fill_color: BOUNDARY_COLORS.security.fill, + stroke_color: BOUNDARY_COLORS.security.stroke, + fill_opacity: BOUNDARY_COLORS.security.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.security.strokeOpacity, + }, + ], + threats: [ + { + id: "threat-credential-stuffing", + title: "Credential stuffing attack on login endpoint", + category: "Spoofing", + element: "auth-service", + severity: "critical", + description: + "Attackers use leaked credential databases to attempt mass logins,\ncompromising accounts with reused passwords.", + mitigation: { + status: "mitigated", + description: + "Biometric MFA required; device fingerprinting; progressive delays; breached password detection via HaveIBeenPwned API", + }, + }, + { + id: "threat-transaction-replay", + title: "Transaction replay attack on fund transfers", + category: "Tampering", + element: "account-service", + flow: "flow-gw-account", + severity: "critical", + description: + "An attacker could replay captured transfer requests to execute\nunauthorized duplicate transactions.", + mitigation: { + status: "mitigated", + description: + "Idempotency keys on all transactions; request signing with timestamp; nonce validation at API gateway", + }, + }, + { + id: "threat-audit-gaps", + title: "Incomplete audit trail for compliance violations", + category: "Repudiation", + element: "audit-log", + severity: "high", + description: + "If audit logs are incomplete or mutable, users could deny transactions\nand regulatory compliance (SOX, PCI DSS) would be violated.", + mitigation: { + status: "mitigated", + description: + "Append-only log with cryptographic chaining; S3 Object Lock for archival; real-time streaming to SIEM", + }, + }, + { + id: "threat-card-data-exposure", + title: "Card data exposure in transit to card network", + category: "Information Disclosure", + flow: "flow-account-card", + severity: "critical", + description: + "PAN and CVV data in ISO-8583 messages could be intercepted\nif the dedicated connection to the card network is compromised.", + mitigation: { + status: "mitigated", + description: + "Point-to-point encryption; HSM-derived session keys; PCI DSS Level 1 certified infrastructure", + }, + }, + { + id: "threat-fraud-bypass", + title: "Fraud detection evasion via slow-rate transfers", + category: "Elevation of Privilege", + element: "fraud-engine", + severity: "high", + description: + "Attackers could structure small, slow transfers below fraud detection\nthresholds to exfiltrate funds undetected.", + mitigation: { + status: "in_progress", + description: + "Cumulative velocity checks over 24h/7d windows; ML model trained on structuring patterns; manual review for new payees", + }, + }, + ], + diagrams: [ + { + id: "main-dfd", + name: "Level 0 DFD", + viewport: { x: 0, y: 0, zoom: 1 }, + }, + ], + }), + + /* ═════════════════════════════════════════════════════════════════════════ + * TEMPLATE 4: SaaS Platform + * ═════════════════════════════════════════════════════════════════════ */ + "saas-platform": (today) => ({ + version: "1.0", + metadata: { + title: "SaaS Platform", + author: "", + created: today, + modified: today, + description: + "Multi-tenant SaaS platform with SSO authentication, background job processing,\nCI/CD pipeline, monitoring, and tenant-isolated data storage.", + }, + elements: [ + { + id: "tenant-browser", + type: "web_browser", + name: "Tenant User", + trust_zone: "external", + description: "Tenant users accessing the SaaS application via browser", + technologies: ["spa", "react"], + position: { x: 60, y: 140 }, + }, + { + id: "admin-browser", + type: "desktop_app", + name: "Admin Console", + trust_zone: "external", + description: "Platform administrators managing tenants and configurations", + technologies: ["electron", "react"], + position: { x: 60, y: 380 }, + }, + { + id: "api-client", + type: "api_client", + name: "API Client", + trust_zone: "external", + description: "Third-party integrations using the public REST API", + technologies: ["rest", "webhooks"], + position: { x: 60, y: 560 }, + }, + { + id: "lb", + type: "load_balancer", + name: "Load Balancer", + trust_zone: "dmz", + description: "Global load balancer with SSL termination and geo-routing", + technologies: ["aws-alb", "waf"], + position: { x: 310, y: 260 }, + }, + { + id: "app-server", + type: "web_server", + name: "Application Server", + trust_zone: "internal", + description: "Multi-tenant application server with tenant context isolation", + technologies: ["node", "nest.js", "typescript"], + position: { x: 620, y: 110 }, + }, + { + id: "api-server", + type: "api_gateway", + name: "API Server", + trust_zone: "internal", + description: "Public REST API with versioning, pagination, and rate limiting", + technologies: ["node", "nest.js", "openapi"], + position: { x: 620, y: 260 }, + }, + { + id: "job-worker", + type: "background_worker", + name: "Job Worker", + trust_zone: "internal", + description: "Async job processing: reports, data exports, bulk operations", + technologies: ["bull", "node"], + position: { x: 620, y: 410 }, + }, + { + id: "sso-provider", + type: "identity_provider", + name: "SSO Provider", + trust_zone: "external", + description: "SAML/OIDC enterprise SSO for tenant authentication", + technologies: ["okta", "saml", "oidc"], + position: { x: 310, y: 90 }, + }, + { + id: "tenant-db", + type: "sql_database", + name: "Tenant Database", + trust_zone: "internal", + description: "Tenant-isolated relational database with row-level security", + stores: ["tenant_data", "user_accounts", "configurations"], + encryption: "AES-256-at-rest", + technologies: ["postgresql", "row-level-security"], + position: { x: 940, y: 110 }, + }, + { + id: "job-queue", + type: "message_queue", + name: "Job Queue", + trust_zone: "internal", + description: "Reliable job queue for background processing", + technologies: ["redis", "bull"], + position: { x: 940, y: 260 }, + }, + { + id: "file-store", + type: "object_storage", + name: "File Storage", + trust_zone: "internal", + description: "Tenant-scoped file uploads with pre-signed URL access", + stores: ["uploads", "exports", "attachments"], + encryption: "SSE-S3", + technologies: ["s3"], + position: { x: 940, y: 410 }, + }, + { + id: "monitoring", + type: "siem", + name: "Monitoring / SIEM", + trust_zone: "internal", + description: "Centralized logging, metrics, alerting, and security monitoring", + technologies: ["datadog", "sentry"], + position: { x: 620, y: 560 }, + }, + { + id: "ci-cd", + type: "ci_cd_pipeline", + name: "CI/CD Pipeline", + trust_zone: "internal", + description: "Automated build, test, and deploy pipeline", + technologies: ["github-actions", "docker", "terraform"], + position: { x: 310, y: 440 }, + }, + ], + data_flows: [ + { + id: "flow-tenant-lb", + name: "", + from: "tenant-browser", + to: "lb", + protocol: "HTTPS/TLS-1.3", + data: ["http_requests", "sso_tokens"], + authenticated: true, + }, + { + id: "flow-admin-lb", + name: "", + from: "admin-browser", + to: "lb", + protocol: "HTTPS/TLS-1.3", + data: ["admin_requests", "mfa_tokens"], + authenticated: true, + }, + { + id: "flow-apiclient-lb", + name: "", + from: "api-client", + to: "lb", + protocol: "HTTPS/TLS-1.3", + data: ["api_requests", "api_keys"], + authenticated: true, + }, + { + id: "flow-lb-app", + name: "", + from: "lb", + to: "app-server", + protocol: "HTTP/2", + data: ["web_requests"], + authenticated: true, + }, + { + id: "flow-lb-api", + name: "", + from: "lb", + to: "api-server", + protocol: "HTTP/2", + data: ["api_requests"], + authenticated: true, + }, + { + id: "flow-sso-app", + name: "", + from: "app-server", + to: "sso-provider", + protocol: "SAML/HTTPS", + data: ["saml_assertions", "oidc_tokens"], + authenticated: true, + }, + { + id: "flow-app-db", + name: "", + from: "app-server", + to: "tenant-db", + protocol: "PostgreSQL/TLS", + data: ["tenant_queries", "user_data"], + authenticated: true, + }, + { + id: "flow-api-db", + name: "", + from: "api-server", + to: "tenant-db", + protocol: "PostgreSQL/TLS", + data: ["api_queries"], + authenticated: true, + }, + { + id: "flow-api-queue", + name: "", + from: "api-server", + to: "job-queue", + protocol: "Redis/TLS", + data: ["job_payloads", "export_requests"], + authenticated: false, + }, + { + id: "flow-worker-queue", + name: "", + from: "job-worker", + to: "job-queue", + protocol: "Redis/TLS", + data: ["job_results", "status_updates"], + authenticated: false, + }, + { + id: "flow-worker-files", + name: "", + from: "job-worker", + to: "file-store", + protocol: "HTTPS/TLS-1.3", + data: ["export_files", "reports"], + authenticated: true, + }, + { + id: "flow-app-monitor", + name: "", + from: "app-server", + to: "monitoring", + protocol: "HTTPS/TLS-1.3", + data: ["metrics", "traces", "error_events"], + authenticated: true, + }, + ], + trust_boundaries: [ + { + id: "boundary-dmz", + name: "DMZ", + contains: ["lb"], + position: { x: 265, y: 215 }, + size: { width: 230, height: 120 }, + fill_color: BOUNDARY_COLORS.edge.fill, + stroke_color: BOUNDARY_COLORS.edge.stroke, + fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.edge.strokeOpacity, + }, + { + id: "boundary-app", + name: "Application Tier (VPC)", + contains: ["app-server", "api-server", "job-worker", "monitoring"], + position: { x: 575, y: 65 }, + size: { width: 230, height: 550 }, + fill_color: BOUNDARY_COLORS.internal.fill, + stroke_color: BOUNDARY_COLORS.internal.stroke, + fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.internal.strokeOpacity, + }, + { + id: "boundary-data", + name: "Data Tier", + contains: ["tenant-db", "job-queue", "file-store"], + position: { x: 895, y: 65 }, + size: { width: 230, height: 440 }, + fill_color: BOUNDARY_COLORS.data.fill, + stroke_color: BOUNDARY_COLORS.data.stroke, + fill_opacity: BOUNDARY_COLORS.data.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.data.strokeOpacity, + }, + ], + threats: [ + { + id: "threat-tenant-isolation", + title: "Cross-tenant data leakage via SQL queries", + category: "Information Disclosure", + element: "tenant-db", + severity: "critical", + description: + "A bug in tenant context resolution could allow one tenant's queries\nto access another tenant's data rows.", + mitigation: { + status: "mitigated", + description: + "PostgreSQL row-level security policies; tenant_id enforced at ORM middleware; integration tests validate isolation", + }, + }, + { + id: "threat-api-key-abuse", + title: "Stolen API key used for unauthorized data access", + category: "Spoofing", + element: "api-server", + severity: "high", + description: + "Compromised API keys could allow attackers to read or modify\ntenant data through the public API.", + mitigation: { + status: "mitigated", + description: + "API keys scoped to specific permissions; IP allowlisting optional; key rotation enforced every 90 days", + }, + }, + { + id: "threat-export-injection", + title: "CSV injection in exported reports", + category: "Tampering", + element: "job-worker", + severity: "medium", + description: + "User-generated data containing formula injections (=CMD) could\nexecute commands when exported CSV is opened in spreadsheet software.", + mitigation: { + status: "mitigated", + description: + "CSV values prefixed with single quote for formula-like strings; Content-Disposition forces download", + }, + }, + { + id: "threat-ssrf", + title: "SSRF via webhook URL configuration", + category: "Elevation of Privilege", + element: "api-server", + severity: "high", + description: + "Tenant-configurable webhook URLs could be pointed at internal services,\nallowing access to metadata endpoints or internal APIs.", + mitigation: { + status: "in_progress", + description: + "URL validation against private IP ranges; webhook calls from isolated subnet; DNS resolution checked before request", + }, + }, + { + id: "threat-log-injection", + title: "Log injection via crafted request headers", + category: "Repudiation", + element: "monitoring", + severity: "medium", + description: + "Attackers could inject fake log entries through crafted HTTP headers,\npolluting SIEM data and masking real attacks.", + mitigation: { + status: "mitigated", + description: + "Structured JSON logging; header values sanitized before logging; log integrity verification via checksums", + }, + }, + ], + diagrams: [ + { + id: "main-dfd", + name: "Level 0 DFD", + viewport: { x: 0, y: 0, zoom: 1 }, + }, + ], + }), + + /* ═════════════════════════════════════════════════════════════════════════ + * TEMPLATE 5: IoT Smart Building + * ═════════════════════════════════════════════════════════════════════ */ + "iot-smart-building": (today) => ({ + version: "1.0", + metadata: { + title: "IoT Smart Building", + author: "", + created: today, + modified: today, + description: + "Smart building IoT system with edge devices, MQTT broker, stream processing,\nbuilding analytics dashboard, and physical access control.", + }, + elements: [ + { + id: "hvac-sensor", + type: "iot_device", + name: "HVAC Sensors", + trust_zone: "external", + description: "Temperature, humidity, and air quality sensors throughout the building", + technologies: ["zigbee", "mqtt"], + position: { x: 60, y: 120 }, + }, + { + id: "access-panel", + type: "iot_device", + name: "Access Panels", + trust_zone: "external", + description: "Badge readers and biometric scanners at entry points", + technologies: ["nfc", "ble"], + position: { x: 60, y: 300 }, + }, + { + id: "camera-system", + type: "iot_device", + name: "Security Cameras", + trust_zone: "external", + description: "IP cameras for surveillance and occupancy detection", + technologies: ["rtsp", "onvif"], + position: { x: 60, y: 480 }, + }, + { + id: "edge-gateway", + type: "proxy", + name: "Edge Gateway", + trust_zone: "dmz", + description: "Local edge computing node aggregating device data and running local rules", + technologies: ["arm", "linux", "docker"], + position: { x: 310, y: 300 }, + }, + { + id: "mqtt-broker", + type: "message_queue", + name: "MQTT Broker", + trust_zone: "internal", + description: "Message broker for device telemetry and command distribution", + technologies: ["mosquitto", "mqtt-v5"], + position: { x: 590, y: 120 }, + }, + { + id: "stream-processor", + type: "stream_processor", + name: "Stream Processor", + trust_zone: "internal", + description: "Real-time event processing for anomaly detection and alerting", + technologies: ["kafka-streams", "flink"], + position: { x: 590, y: 300 }, + }, + { + id: "device-manager", + type: "microservice", + name: "Device Manager", + trust_zone: "internal", + description: "Device provisioning, firmware updates, and fleet management", + technologies: ["go", "grpc"], + position: { x: 590, y: 480 }, + }, + { + id: "timeseries-db", + type: "nosql_database", + name: "Time Series DB", + trust_zone: "internal", + description: "High-write telemetry storage optimized for time-range queries", + stores: ["sensor_data", "energy_metrics", "occupancy"], + technologies: ["influxdb"], + position: { x: 870, y: 120 }, + }, + { + id: "access-db", + type: "sql_database", + name: "Access Control DB", + trust_zone: "internal", + description: "Employee badges, access policies, and entry/exit logs", + stores: ["badges", "access_policies", "entry_logs"], + encryption: "AES-256-at-rest", + technologies: ["postgresql"], + position: { x: 870, y: 300 }, + }, + { + id: "video-storage", + type: "object_storage", + name: "Video Storage", + trust_zone: "internal", + description: "Encrypted video recording archive with retention policies", + stores: ["video_recordings", "motion_events"], + encryption: "AES-256-at-rest", + technologies: ["minio", "s3-compatible"], + position: { x: 870, y: 480 }, + }, + { + id: "dashboard", + type: "web_server", + name: "Building Dashboard", + trust_zone: "internal", + description: "Real-time building analytics, energy monitoring, and alert management", + technologies: ["grafana", "react"], + position: { x: 1100, y: 210 }, + }, + { + id: "facility-mgr", + type: "web_browser", + name: "Facility Manager", + trust_zone: "external", + description: "Building operations staff accessing the management dashboard", + technologies: ["browser"], + position: { x: 1100, y: 410 }, + }, + ], + data_flows: [ + { + id: "flow-hvac-edge", + name: "", + from: "hvac-sensor", + to: "edge-gateway", + protocol: "MQTT/TLS", + data: ["temperature", "humidity", "air_quality"], + authenticated: false, + }, + { + id: "flow-access-edge", + name: "", + from: "access-panel", + to: "edge-gateway", + protocol: "HTTPS/TLS-1.2", + data: ["badge_scans", "biometric_hashes"], + authenticated: true, + }, + { + id: "flow-camera-edge", + name: "", + from: "camera-system", + to: "edge-gateway", + protocol: "RTSP/TLS", + data: ["video_streams", "motion_events"], + authenticated: true, + }, + { + id: "flow-edge-mqtt", + name: "", + from: "edge-gateway", + to: "mqtt-broker", + protocol: "MQTT/TLS", + data: ["aggregated_telemetry", "device_events"], + authenticated: true, + }, + { + id: "flow-mqtt-stream", + name: "", + from: "mqtt-broker", + to: "stream-processor", + protocol: "Kafka/TLS", + data: ["telemetry_events", "alert_triggers"], + authenticated: false, + }, + { + id: "flow-mqtt-ts", + name: "", + from: "mqtt-broker", + to: "timeseries-db", + protocol: "InfluxDB/TLS", + data: ["raw_telemetry", "metrics"], + authenticated: true, + }, + { + id: "flow-stream-accessdb", + name: "", + from: "stream-processor", + to: "access-db", + protocol: "PostgreSQL/TLS", + data: ["access_events", "anomaly_flags"], + authenticated: true, + }, + { + id: "flow-edge-video", + name: "", + from: "edge-gateway", + to: "video-storage", + protocol: "HTTPS/TLS-1.3", + data: ["video_segments", "thumbnails"], + authenticated: true, + }, + { + id: "flow-devmgr-edge", + name: "", + from: "device-manager", + to: "edge-gateway", + protocol: "HTTPS/mTLS", + data: ["firmware_updates", "config_patches"], + authenticated: true, + }, + { + id: "flow-dash-ts", + name: "", + from: "dashboard", + to: "timeseries-db", + protocol: "InfluxDB/TLS", + data: ["metric_queries", "aggregations"], + authenticated: true, + }, + { + id: "flow-dash-accessdb", + name: "", + from: "dashboard", + to: "access-db", + protocol: "PostgreSQL/TLS", + data: ["access_reports", "policy_queries"], + authenticated: true, + }, + { + id: "flow-fmgr-dash", + name: "", + from: "facility-mgr", + to: "dashboard", + protocol: "HTTPS/TLS-1.3", + data: ["dashboard_views", "alert_management"], + authenticated: true, + }, + ], + trust_boundaries: [ + { + id: "boundary-edge", + name: "Edge Network", + contains: ["edge-gateway"], + position: { x: 265, y: 255 }, + size: { width: 230, height: 120 }, + fill_color: BOUNDARY_COLORS.iot.fill, + stroke_color: BOUNDARY_COLORS.iot.stroke, + fill_opacity: BOUNDARY_COLORS.iot.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.iot.strokeOpacity, + }, + { + id: "boundary-processing", + name: "Cloud Processing Tier", + contains: ["mqtt-broker", "stream-processor", "device-manager"], + position: { x: 545, y: 75 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.internal.fill, + stroke_color: BOUNDARY_COLORS.internal.stroke, + fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.internal.strokeOpacity, + }, + { + id: "boundary-data", + name: "Data Tier", + contains: ["timeseries-db", "access-db", "video-storage"], + position: { x: 825, y: 75 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.data.fill, + stroke_color: BOUNDARY_COLORS.data.stroke, + fill_opacity: BOUNDARY_COLORS.data.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.data.strokeOpacity, + }, + ], + threats: [ + { + id: "threat-device-spoof", + title: "Rogue device spoofing HVAC sensor data", + category: "Spoofing", + element: "hvac-sensor", + severity: "high", + description: + "An attacker could introduce a rogue device on the Zigbee network\nthat sends false temperature data, disrupting HVAC operation.", + mitigation: { + status: "in_progress", + description: + "Device certificate provisioning; edge gateway validates device identity; anomaly detection on sensor value ranges", + }, + }, + { + id: "threat-firmware-tamper", + title: "Malicious firmware pushed to edge devices", + category: "Tampering", + element: "device-manager", + flow: "flow-devmgr-edge", + severity: "critical", + description: + "If the device manager or update channel is compromised, malicious firmware\ncould be pushed to all edge gateways simultaneously.", + mitigation: { + status: "mitigated", + description: + "Firmware signed with Ed25519; edge gateway verifies signatures before applying; staged rollouts with automatic rollback", + }, + }, + { + id: "threat-video-privacy", + title: "Unauthorized access to surveillance recordings", + category: "Information Disclosure", + element: "video-storage", + severity: "high", + description: + "Video recordings contain PII (faces, badge numbers); unauthorized access\ncould violate privacy regulations and employee rights.", + mitigation: { + status: "mitigated", + description: + "Encryption at rest; access logged and audited; retention policy auto-deletes after 30 days; face blurring on non-security views", + }, + }, + { + id: "threat-mqtt-flood", + title: "MQTT message flood overwhelming broker", + category: "Denial of Service", + element: "mqtt-broker", + severity: "medium", + description: + "A compromised device or external attacker could flood the MQTT broker\nwith messages, causing telemetry loss and delayed alerts.", + mitigation: { + status: "mitigated", + description: + "Per-client message rate limits; MQTT v5 topic quotas; broker clustering for horizontal scaling", + }, + }, + { + id: "threat-access-bypass", + title: "Physical access control bypass via badge cloning", + category: "Elevation of Privilege", + element: "access-panel", + severity: "critical", + description: + "NFC badge data could be cloned using commodity hardware,\nallowing unauthorized physical access to restricted areas.", + mitigation: { + status: "in_progress", + description: + "Migrating to DESFire EV3 cards with diversified keys; multi-factor (badge + PIN) for high-security zones; anti-passback rules", + }, + }, + ], + diagrams: [ + { + id: "main-dfd", + name: "Level 0 DFD", + viewport: { x: 0, y: 0, zoom: 1 }, + }, + ], + }), + + /* ═════════════════════════════════════════════════════════════════════════ + * TEMPLATE 6: Healthcare System + * ═════════════════════════════════════════════════════════════════════ */ + "healthcare-system": (today) => ({ + version: "1.0", + metadata: { + title: "Healthcare Data Platform", + author: "", + created: today, + modified: today, + description: + "HIPAA-compliant healthcare platform with EHR integration, FHIR API,\npatient portal, clinical analytics, and comprehensive audit logging.", + }, + elements: [ + { + id: "patient-portal", + type: "web_browser", + name: "Patient Portal", + trust_zone: "external", + description: "Patient-facing web portal for records, appointments, and messaging", + technologies: ["react", "wcag-aa"], + position: { x: 60, y: 140 }, + }, + { + id: "clinician-app", + type: "desktop_app", + name: "Clinician App", + trust_zone: "external", + description: "Desktop EHR application used by healthcare providers", + technologies: ["electron", "fhir-smart"], + position: { x: 60, y: 380 }, + }, + { + id: "fhir-gateway", + type: "api_gateway", + name: "FHIR API Gateway", + trust_zone: "dmz", + description: "HL7 FHIR R4 compliant API gateway with SMART on FHIR authorization", + technologies: ["hapi-fhir", "smart-on-fhir", "oauth2"], + position: { x: 310, y: 260 }, + }, + { + id: "patient-svc", + type: "microservice", + name: "Patient Service", + trust_zone: "internal", + description: "Patient demographics, insurance, and care team management", + technologies: ["java", "spring-boot", "fhir-r4"], + position: { x: 600, y: 110 }, + }, + { + id: "clinical-svc", + type: "microservice", + name: "Clinical Service", + trust_zone: "internal", + description: "Clinical records, diagnoses, medications, and lab results", + technologies: ["java", "spring-boot", "fhir-r4"], + position: { x: 600, y: 280 }, + }, + { + id: "scheduling-svc", + type: "microservice", + name: "Scheduling Service", + trust_zone: "internal", + description: "Appointment scheduling, provider availability, and reminders", + technologies: ["node", "typescript"], + position: { x: 600, y: 450 }, + }, + { + id: "ehr-db", + type: "sql_database", + name: "EHR Database", + trust_zone: "internal", + description: "Primary electronic health record store with PHI encryption", + stores: ["patient_records", "clinical_notes", "medications", "lab_results"], + encryption: "TDE-AES-256", + technologies: ["postgresql", "pgcrypto"], + position: { x: 900, y: 110 }, + }, + { + id: "document-store", + type: "object_storage", + name: "Document Store", + trust_zone: "internal", + description: "Medical images, scanned documents, and clinical attachments", + stores: ["dicom_images", "scanned_docs", "consent_forms"], + encryption: "AES-256-at-rest", + technologies: ["s3", "dicom"], + position: { x: 900, y: 280 }, + }, + { + id: "audit-log", + type: "data_lake", + name: "HIPAA Audit Log", + trust_zone: "internal", + description: "Immutable audit trail for all PHI access per HIPAA requirements", + stores: ["access_logs", "phi_queries", "consent_events"], + encryption: "AES-256-at-rest", + technologies: ["elasticsearch", "s3-glacier"], + position: { x: 900, y: 450 }, + }, + { + id: "ehr-system", + type: "api_endpoint", + name: "External EHR", + trust_zone: "external", + description: "Third-party EHR system for health information exchange", + technologies: ["hl7-v2", "fhir-r4", "direct-messaging"], + position: { x: 310, y: 80 }, + }, + { + id: "pharmacy", + type: "api_endpoint", + name: "Pharmacy Network", + trust_zone: "external", + description: "E-prescribing network for electronic prescription transmission", + technologies: ["ncpdp-script", "surescripts"], + position: { x: 310, y: 450 }, + }, + { + id: "analytics-engine", + type: "stream_processor", + name: "Clinical Analytics", + trust_zone: "internal", + description: "De-identified analytics for population health and quality measures", + technologies: ["spark", "hipaa-safe-harbor"], + position: { x: 1130, y: 280 }, + }, + ], + data_flows: [ + { + id: "flow-patient-fhir", + name: "", + from: "patient-portal", + to: "fhir-gateway", + protocol: "HTTPS/TLS-1.3", + data: ["patient_requests", "oauth_tokens"], + authenticated: true, + }, + { + id: "flow-clinician-fhir", + name: "", + from: "clinician-app", + to: "fhir-gateway", + protocol: "HTTPS/TLS-1.3", + data: ["clinical_queries", "smart_tokens"], + authenticated: true, + }, + { + id: "flow-fhir-patient", + name: "", + from: "fhir-gateway", + to: "patient-svc", + protocol: "gRPC/mTLS", + data: ["patient_resources", "demographics"], + authenticated: true, + }, + { + id: "flow-fhir-clinical", + name: "", + from: "fhir-gateway", + to: "clinical-svc", + protocol: "gRPC/mTLS", + data: ["clinical_resources", "observations"], + authenticated: true, + }, + { + id: "flow-fhir-scheduling", + name: "", + from: "fhir-gateway", + to: "scheduling-svc", + protocol: "gRPC/mTLS", + data: ["appointment_requests", "availability_queries"], + authenticated: true, + }, + { + id: "flow-patient-db", + name: "", + from: "patient-svc", + to: "ehr-db", + protocol: "PostgreSQL/TLS", + data: ["patient_data", "insurance_records"], + authenticated: true, + }, + { + id: "flow-clinical-db", + name: "", + from: "clinical-svc", + to: "ehr-db", + protocol: "PostgreSQL/TLS", + data: ["clinical_notes", "lab_results", "medications"], + authenticated: true, + }, + { + id: "flow-clinical-docs", + name: "", + from: "clinical-svc", + to: "document-store", + protocol: "HTTPS/TLS-1.3", + data: ["medical_images", "scanned_documents"], + authenticated: true, + }, + { + id: "flow-all-audit", + name: "", + from: "fhir-gateway", + to: "audit-log", + protocol: "HTTPS/TLS-1.3", + data: ["phi_access_events", "consent_changes"], + authenticated: true, + }, + { + id: "flow-ehr-exchange", + name: "", + from: "fhir-gateway", + to: "ehr-system", + protocol: "FHIR/HTTPS", + data: ["care_summaries", "referrals"], + authenticated: true, + }, + { + id: "flow-clinical-pharmacy", + name: "", + from: "clinical-svc", + to: "pharmacy", + protocol: "NCPDP/TLS", + data: ["e_prescriptions", "medication_history"], + authenticated: true, + }, + { + id: "flow-db-analytics", + name: "", + from: "ehr-db", + to: "analytics-engine", + protocol: "JDBC/TLS", + data: ["de_identified_records", "quality_measures"], + authenticated: true, + }, + ], + trust_boundaries: [ + { + id: "boundary-dmz", + name: "HIPAA DMZ", + contains: ["fhir-gateway"], + position: { x: 265, y: 215 }, + size: { width: 230, height: 120 }, + fill_color: BOUNDARY_COLORS.edge.fill, + stroke_color: BOUNDARY_COLORS.edge.stroke, + fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.edge.strokeOpacity, + }, + { + id: "boundary-app", + name: "Application Services", + contains: ["patient-svc", "clinical-svc", "scheduling-svc"], + position: { x: 555, y: 65 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.internal.fill, + stroke_color: BOUNDARY_COLORS.internal.stroke, + fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.internal.strokeOpacity, + }, + { + id: "boundary-phi", + name: "PHI Data Zone", + contains: ["ehr-db", "document-store", "audit-log"], + position: { x: 855, y: 65 }, + size: { width: 230, height: 480 }, + fill_color: BOUNDARY_COLORS.security.fill, + stroke_color: BOUNDARY_COLORS.security.stroke, + fill_opacity: BOUNDARY_COLORS.security.fillOpacity, + stroke_opacity: BOUNDARY_COLORS.security.strokeOpacity, + }, + ], + threats: [ + { + id: "threat-phi-breach", + title: "Unauthorized PHI access by unauthorized user", + category: "Information Disclosure", + element: "ehr-db", + severity: "critical", + description: + "Protected Health Information could be accessed by unauthorized staff\nor through a compromised clinician account, violating HIPAA Privacy Rule.", + mitigation: { + status: "mitigated", + description: + "Role-based access control; break-the-glass emergency access with mandatory justification; all PHI access logged and audited", + }, + }, + { + id: "threat-patient-impersonation", + title: "Patient account takeover via identity spoofing", + category: "Spoofing", + element: "fhir-gateway", + flow: "flow-patient-fhir", + severity: "critical", + description: + "An attacker could impersonate a patient to access medical records,\nmodify appointments, or intercept prescriptions.", + mitigation: { + status: "mitigated", + description: + "Multi-factor authentication required; identity proofing for account creation; session tokens with 30-minute expiry", + }, + }, + { + id: "threat-record-tampering", + title: "Clinical record tampering to alter diagnoses", + category: "Tampering", + element: "clinical-svc", + flow: "flow-clinical-db", + severity: "critical", + description: + "Malicious modification of clinical records could alter diagnoses,\nmedication dosages, or lab results with life-threatening consequences.", + mitigation: { + status: "mitigated", + description: + "Database versioning with complete change history; cryptographic checksums on records; dual approval for critical changes", + }, + }, + { + id: "threat-audit-denial", + title: "Clinician denies accessing patient records", + category: "Repudiation", + element: "audit-log", + severity: "high", + description: + "Without proper audit logging, a clinician could deny accessing\nrecords they shouldn't have viewed, making HIPAA investigations impossible.", + mitigation: { + status: "mitigated", + description: + "Immutable append-only audit log; SMART token binds access to user identity; tamper-evident log chain", + }, + }, + { + id: "threat-prescription-intercept", + title: "E-prescription interception in transit", + category: "Information Disclosure", + flow: "flow-clinical-pharmacy", + severity: "high", + description: + "Electronic prescriptions contain sensitive patient data and controlled\nsubstance information that could be intercepted or modified in transit.", + mitigation: { + status: "mitigated", + description: + "NCPDP SCRIPT over TLS 1.3; digital signatures on prescriptions; Surescripts network with end-to-end encryption", + }, }, ], - threats: [], diagrams: [ { id: "main-dfd", From 4fad6d830a6f1a55e2d463bf01552e8263c9d43d Mon Sep 17 00:00:00 2001 From: Shreyas Sane Date: Tue, 3 Mar 2026 13:48:57 -0500 Subject: [PATCH 2/6] fix(templates): improve layout spacing, labels, and connectors - Widen column gaps to ~400px across all 6 templates - Trim all flow data arrays to 1 item for shorter edge labels - Add explicit handle overrides on congested nodes (API Server, FHIR Gateway, API Gateway) to fan out connectors - Fix mismatched element positions for IoT and Healthcare templates - Adjust boundary sizes to match new node positions Co-Authored-By: Claude Opus 4.6 --- src/lib/templates.ts | 394 +++++++++++++++++++++++-------------------- 1 file changed, 214 insertions(+), 180 deletions(-) diff --git a/src/lib/templates.ts b/src/lib/templates.ts index b4335c6..6f27ee0 100644 --- a/src/lib/templates.ts +++ b/src/lib/templates.ts @@ -64,7 +64,7 @@ export function loadTemplate(id: string): ThreatModel | null { const updated = { ...flow, flow_number: i + 1 }; const srcPos = posMap.get(flow.from); const tgtPos = posMap.get(flow.to); - if (srcPos && tgtPos) { + if (srcPos && tgtPos && !flow.source_handle && !flow.target_handle) { const pair = getSmartHandlePair( { x: srcPos.x, y: srcPos.y, width: NODE_W, height: NODE_H }, { x: tgtPos.x, y: tgtPos.y, width: NODE_W, height: NODE_H }, @@ -114,7 +114,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "End-user web browser accessing the storefront", technologies: ["spa", "react"], - position: { x: 60, y: 200 }, + position: { x: 80, y: 180 }, }, { id: "mobile-shopper", @@ -123,7 +123,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "iOS/Android shopping application", technologies: ["react-native"], - position: { x: 60, y: 380 }, + position: { x: 80, y: 560 }, }, { id: "edge-cdn", @@ -132,7 +132,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "Global content delivery for static assets and cached pages", technologies: ["cloudflare"], - position: { x: 310, y: 120 }, + position: { x: 440, y: 120 }, }, { id: "waf", @@ -141,7 +141,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "Web application firewall filtering malicious requests", technologies: ["cloudflare-waf", "owasp-crs"], - position: { x: 310, y: 290 }, + position: { x: 440, y: 380 }, }, { id: "load-balancer", @@ -150,7 +150,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "Layer 7 load balancer distributing traffic across app servers", technologies: ["aws-alb", "tls-termination"], - position: { x: 310, y: 460 }, + position: { x: 440, y: 660 }, }, { id: "web-app", @@ -159,7 +159,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Server-side rendered storefront and checkout flow", technologies: ["next.js", "node"], - position: { x: 650, y: 120 }, + position: { x: 840, y: 180 }, }, { id: "api-server", @@ -168,7 +168,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "REST API handling product catalog, cart, and order operations", technologies: ["express", "node", "openapi"], - position: { x: 650, y: 290 }, + position: { x: 840, y: 450 }, }, { id: "order-worker", @@ -177,7 +177,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Async order processing, inventory updates, and email dispatch", technologies: ["bull", "node"], - position: { x: 650, y: 460 }, + position: { x: 840, y: 710 }, }, { id: "product-db", @@ -188,7 +188,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["products", "orders", "customers", "inventory"], encryption: "AES-256-at-rest", technologies: ["postgresql"], - position: { x: 970, y: 120 }, + position: { x: 1240, y: 180 }, }, { id: "session-cache", @@ -198,7 +198,7 @@ const TEMPLATE_BUILDERS: Record = { description: "In-memory session store and API response cache", stores: ["sessions", "cart_data", "rate_limits"], technologies: ["redis"], - position: { x: 970, y: 290 }, + position: { x: 1240, y: 450 }, }, { id: "search-engine", @@ -208,7 +208,7 @@ const TEMPLATE_BUILDERS: Record = { description: "Full-text product search and faceted filtering", stores: ["product_index", "autocomplete"], technologies: ["elasticsearch"], - position: { x: 970, y: 460 }, + position: { x: 1240, y: 710 }, }, { id: "payment-gateway", @@ -217,7 +217,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "PCI-compliant payment processor for card transactions", technologies: ["stripe"], - position: { x: 650, y: 640 }, + position: { x: 840, y: 960 }, }, { id: "auth-idp", @@ -226,7 +226,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "OAuth 2.0 / OIDC provider for customer SSO", technologies: ["auth0", "oidc"], - position: { x: 310, y: 640 }, + position: { x: 440, y: 960 }, }, ], data_flows: [ @@ -236,7 +236,7 @@ const TEMPLATE_BUILDERS: Record = { from: "customer-browser", to: "edge-cdn", protocol: "HTTPS/TLS-1.3", - data: ["static_assets", "cached_pages"], + data: ["static_assets"], authenticated: false, }, { @@ -245,7 +245,7 @@ const TEMPLATE_BUILDERS: Record = { from: "customer-browser", to: "waf", protocol: "HTTPS/TLS-1.3", - data: ["http_requests", "cookies"], + data: ["http_requests"], authenticated: false, }, { @@ -254,7 +254,7 @@ const TEMPLATE_BUILDERS: Record = { from: "mobile-shopper", to: "waf", protocol: "HTTPS/TLS-1.3", - data: ["api_requests", "jwt_tokens"], + data: ["api_requests"], authenticated: true, }, { @@ -272,7 +272,7 @@ const TEMPLATE_BUILDERS: Record = { from: "edge-cdn", to: "web-app", protocol: "HTTPS/TLS-1.3", - data: ["cache_misses", "dynamic_requests"], + data: ["cache_misses"], authenticated: false, }, { @@ -281,7 +281,7 @@ const TEMPLATE_BUILDERS: Record = { from: "load-balancer", to: "api-server", protocol: "HTTP/2", - data: ["api_requests", "auth_headers"], + data: ["api_requests"], authenticated: true, }, { @@ -290,7 +290,7 @@ const TEMPLATE_BUILDERS: Record = { from: "web-app", to: "api-server", protocol: "HTTP/2", - data: ["ssr_requests", "api_calls"], + data: ["ssr_requests"], authenticated: true, }, { @@ -299,8 +299,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "product-db", protocol: "PostgreSQL/TLS", - data: ["queries", "product_data", "order_data"], + data: ["queries"], authenticated: true, + source_handle: "top-right-source", + target_handle: "bottom-left-target", }, { id: "flow-api-cache", @@ -308,8 +310,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "session-cache", protocol: "Redis/TLS", - data: ["session_data", "cached_responses"], + data: ["session_data"], authenticated: false, + source_handle: "right-source", + target_handle: "left-target", }, { id: "flow-api-search", @@ -317,8 +321,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "search-engine", protocol: "HTTPS/TLS-1.2", - data: ["search_queries", "filter_criteria"], + data: ["search_queries"], authenticated: true, + source_handle: "bottom-right-source", + target_handle: "top-left-target", }, { id: "flow-api-payment", @@ -326,8 +332,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "payment-gateway", protocol: "HTTPS/TLS-1.3", - data: ["tokenized_card_data", "charge_requests"], + data: ["tokenized_card_data"], authenticated: true, + source_handle: "bottom-source", + target_handle: "top-target", }, { id: "flow-api-worker", @@ -335,8 +343,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "order-worker", protocol: "Redis/TLS", - data: ["order_events", "job_payloads"], + data: ["order_events"], authenticated: false, + source_handle: "bottom-left-source", + target_handle: "top-left-target", }, { id: "flow-api-auth", @@ -344,7 +354,7 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "auth-idp", protocol: "HTTPS/TLS-1.3", - data: ["oauth_tokens", "user_claims"], + data: ["oauth_tokens"], authenticated: true, }, ], @@ -353,8 +363,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-edge", name: "Edge / DMZ", contains: ["edge-cdn", "waf", "load-balancer"], - position: { x: 265, y: 75 }, - size: { width: 230, height: 480 }, + position: { x: 400, y: 70 }, + size: { width: 220, height: 690 }, fill_color: BOUNDARY_COLORS.edge.fill, stroke_color: BOUNDARY_COLORS.edge.stroke, fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, @@ -364,8 +374,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-app", name: "Application Tier", contains: ["web-app", "api-server", "order-worker"], - position: { x: 605, y: 75 }, - size: { width: 230, height: 480 }, + position: { x: 800, y: 130 }, + size: { width: 220, height: 680 }, fill_color: BOUNDARY_COLORS.internal.fill, stroke_color: BOUNDARY_COLORS.internal.stroke, fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, @@ -375,8 +385,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-data", name: "Data Tier", contains: ["product-db", "session-cache", "search-engine"], - position: { x: 925, y: 75 }, - size: { width: 230, height: 480 }, + position: { x: 1200, y: 130 }, + size: { width: 220, height: 680 }, fill_color: BOUNDARY_COLORS.data.fill, stroke_color: BOUNDARY_COLORS.data.stroke, fill_opacity: BOUNDARY_COLORS.data.fillOpacity, @@ -486,7 +496,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Single-page application served via CDN", technologies: ["react", "vite"], - position: { x: 60, y: 160 }, + position: { x: 80, y: 220 }, }, { id: "mobile-client", @@ -495,7 +505,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Native iOS/Android application", technologies: ["swift", "kotlin"], - position: { x: 60, y: 380 }, + position: { x: 80, y: 500 }, }, { id: "api-gw", @@ -504,7 +514,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "Central entry point handling auth, rate limiting, and request routing", technologies: ["kong", "jwt-validation", "rate-limiting"], - position: { x: 310, y: 270 }, + position: { x: 400, y: 360 }, }, { id: "svc-mesh", @@ -513,7 +523,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Sidecar proxy layer for mTLS, observability, and traffic shaping", technologies: ["istio", "envoy"], - position: { x: 600, y: 100 }, + position: { x: 700, y: 140 }, }, { id: "user-svc", @@ -522,7 +532,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Manages user registration, profiles, and authentication", technologies: ["go", "grpc"], - position: { x: 600, y: 270 }, + position: { x: 700, y: 380 }, }, { id: "product-svc", @@ -531,7 +541,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Handles product catalog, pricing, and inventory", technologies: ["go", "grpc"], - position: { x: 600, y: 440 }, + position: { x: 700, y: 620 }, }, { id: "order-svc", @@ -540,7 +550,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Order lifecycle management and fulfillment coordination", technologies: ["go", "grpc"], - position: { x: 850, y: 270 }, + position: { x: 960, y: 380 }, }, { id: "notification-svc", @@ -549,7 +559,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Email, SMS, and push notification dispatch", technologies: ["node", "typescript"], - position: { x: 850, y: 440 }, + position: { x: 960, y: 620 }, }, { id: "event-bus", @@ -558,7 +568,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Asynchronous event streaming between services", technologies: ["kafka", "schema-registry"], - position: { x: 850, y: 100 }, + position: { x: 960, y: 140 }, }, { id: "user-db", @@ -569,7 +579,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["users", "roles", "credentials"], encryption: "AES-256-at-rest", technologies: ["postgresql"], - position: { x: 1110, y: 100 }, + position: { x: 1260, y: 140 }, }, { id: "product-db", @@ -579,7 +589,7 @@ const TEMPLATE_BUILDERS: Record = { description: "Document store for flexible product schemas", stores: ["products", "categories", "pricing"], technologies: ["mongodb"], - position: { x: 1110, y: 270 }, + position: { x: 1260, y: 380 }, }, { id: "order-db", @@ -590,7 +600,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["orders", "payments", "shipping"], encryption: "AES-256-at-rest", technologies: ["postgresql"], - position: { x: 1110, y: 440 }, + position: { x: 1260, y: 620 }, }, { id: "secrets-vault", @@ -600,7 +610,7 @@ const TEMPLATE_BUILDERS: Record = { description: "Centralized secret storage for service credentials and API keys", stores: ["api_keys", "db_credentials", "tls_certs"], technologies: ["hashicorp-vault"], - position: { x: 310, y: 470 }, + position: { x: 400, y: 600 }, }, ], data_flows: [ @@ -610,7 +620,7 @@ const TEMPLATE_BUILDERS: Record = { from: "web-client", to: "api-gw", protocol: "HTTPS/TLS-1.3", - data: ["api_requests", "jwt_tokens"], + data: ["api_requests"], authenticated: true, }, { @@ -619,7 +629,7 @@ const TEMPLATE_BUILDERS: Record = { from: "mobile-client", to: "api-gw", protocol: "HTTPS/TLS-1.3", - data: ["api_requests", "jwt_tokens"], + data: ["api_requests"], authenticated: true, }, { @@ -628,7 +638,7 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gw", to: "user-svc", protocol: "gRPC/mTLS", - data: ["user_requests", "auth_context"], + data: ["user_requests"], authenticated: true, }, { @@ -637,8 +647,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gw", to: "product-svc", protocol: "gRPC/mTLS", - data: ["catalog_queries", "search_requests"], + data: ["catalog_queries"], authenticated: true, + source_handle: "bottom-right-source", + target_handle: "left-target", }, { id: "flow-gw-order", @@ -646,8 +658,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gw", to: "order-svc", protocol: "gRPC/mTLS", - data: ["order_requests", "cart_data"], + data: ["order_requests"], authenticated: true, + source_handle: "top-right-source", + target_handle: "left-target", }, { id: "flow-user-db", @@ -655,7 +669,7 @@ const TEMPLATE_BUILDERS: Record = { from: "user-svc", to: "user-db", protocol: "PostgreSQL/TLS", - data: ["user_data", "credential_hashes"], + data: ["user_data"], authenticated: true, }, { @@ -664,7 +678,7 @@ const TEMPLATE_BUILDERS: Record = { from: "product-svc", to: "product-db", protocol: "MongoDB/TLS", - data: ["product_documents", "category_data"], + data: ["product_documents"], authenticated: true, }, { @@ -673,7 +687,7 @@ const TEMPLATE_BUILDERS: Record = { from: "order-svc", to: "order-db", protocol: "PostgreSQL/TLS", - data: ["order_records", "payment_data"], + data: ["order_records"], authenticated: true, }, { @@ -682,7 +696,7 @@ const TEMPLATE_BUILDERS: Record = { from: "user-svc", to: "event-bus", protocol: "Kafka/TLS", - data: ["user_created", "profile_updated"], + data: ["user_created"], authenticated: false, }, { @@ -691,7 +705,7 @@ const TEMPLATE_BUILDERS: Record = { from: "order-svc", to: "event-bus", protocol: "Kafka/TLS", - data: ["order_placed", "order_fulfilled"], + data: ["order_placed"], authenticated: false, }, { @@ -709,7 +723,7 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gw", to: "secrets-vault", protocol: "HTTPS/mTLS", - data: ["secret_requests", "token_rotation"], + data: ["secret_requests"], authenticated: true, }, ], @@ -718,8 +732,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-edge", name: "Edge / DMZ", contains: ["api-gw"], - position: { x: 265, y: 225 }, - size: { width: 230, height: 120 }, + position: { x: 360, y: 310 }, + size: { width: 220, height: 130 }, fill_color: BOUNDARY_COLORS.edge.fill, stroke_color: BOUNDARY_COLORS.edge.stroke, fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, @@ -736,8 +750,8 @@ const TEMPLATE_BUILDERS: Record = { "notification-svc", "event-bus", ], - position: { x: 555, y: 55 }, - size: { width: 450, height: 480 }, + position: { x: 660, y: 90 }, + size: { width: 500, height: 650 }, fill_color: BOUNDARY_COLORS.internal.fill, stroke_color: BOUNDARY_COLORS.internal.stroke, fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, @@ -747,8 +761,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-data", name: "Data Tier", contains: ["user-db", "product-db", "order-db"], - position: { x: 1065, y: 55 }, - size: { width: 230, height: 480 }, + position: { x: 1220, y: 90 }, + size: { width: 220, height: 650 }, fill_color: BOUNDARY_COLORS.data.fill, stroke_color: BOUNDARY_COLORS.data.stroke, fill_opacity: BOUNDARY_COLORS.data.fillOpacity, @@ -857,7 +871,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Native mobile banking app with biometric auth and certificate pinning", technologies: ["swift", "kotlin", "cert-pinning"], - position: { x: 60, y: 280 }, + position: { x: 80, y: 400 }, }, { id: "api-gateway", @@ -866,7 +880,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "TLS-terminating gateway with OAuth2 validation and request throttling", technologies: ["kong", "oauth2", "rate-limiting"], - position: { x: 310, y: 280 }, + position: { x: 420, y: 390 }, }, { id: "auth-service", @@ -875,7 +889,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "MFA authentication with biometric, OTP, and password support", technologies: ["node", "passport", "webauthn"], - position: { x: 600, y: 110 }, + position: { x: 760, y: 160 }, }, { id: "account-service", @@ -884,7 +898,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Core banking operations: balances, transfers, and statements", technologies: ["java", "spring-boot"], - position: { x: 600, y: 280 }, + position: { x: 760, y: 420 }, }, { id: "fraud-engine", @@ -893,7 +907,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Real-time transaction scoring and anomaly detection", technologies: ["python", "scikit-learn", "kafka-streams"], - position: { x: 600, y: 450 }, + position: { x: 760, y: 680 }, }, { id: "core-db", @@ -904,7 +918,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["accounts", "transactions", "ledger"], encryption: "TDE-AES-256", technologies: ["oracle-db"], - position: { x: 880, y: 280 }, + position: { x: 1120, y: 530 }, }, { id: "token-store", @@ -914,7 +928,7 @@ const TEMPLATE_BUILDERS: Record = { description: "Short-lived auth token storage with automatic expiration", stores: ["access_tokens", "refresh_tokens", "mfa_challenges"], technologies: ["redis", "cluster-mode"], - position: { x: 880, y: 110 }, + position: { x: 1120, y: 130 }, }, { id: "audit-log", @@ -925,7 +939,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["transaction_logs", "auth_events", "access_logs"], encryption: "AES-256-at-rest", technologies: ["elasticsearch", "s3-archive"], - position: { x: 880, y: 450 }, + position: { x: 1120, y: 730 }, }, { id: "hsm", @@ -935,7 +949,7 @@ const TEMPLATE_BUILDERS: Record = { description: "Hardware security module for cryptographic key management and signing", stores: ["master_keys", "signing_keys"], technologies: ["thales-luna", "pkcs11"], - position: { x: 1110, y: 190 }, + position: { x: 1120, y: 330 }, }, { id: "card-network", @@ -944,7 +958,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Visa/Mastercard payment network for card transactions", technologies: ["iso-8583"], - position: { x: 310, y: 490 }, + position: { x: 420, y: 680 }, }, { id: "push-service", @@ -953,7 +967,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "APNs and FCM for transaction alerts and security notifications", technologies: ["apns", "fcm"], - position: { x: 60, y: 490 }, + position: { x: 80, y: 680 }, }, { id: "kyc-provider", @@ -962,7 +976,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Know Your Customer identity verification for account opening", technologies: ["onfido", "document-verification"], - position: { x: 310, y: 110 }, + position: { x: 420, y: 120 }, }, ], data_flows: [ @@ -972,7 +986,7 @@ const TEMPLATE_BUILDERS: Record = { from: "banking-app", to: "api-gateway", protocol: "HTTPS/TLS-1.3", - data: ["api_requests", "biometric_tokens", "device_fingerprint"], + data: ["api_requests"], authenticated: true, }, { @@ -981,8 +995,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gateway", to: "auth-service", protocol: "gRPC/mTLS", - data: ["auth_requests", "mfa_challenges"], + data: ["auth_requests"], authenticated: true, + source_handle: "top-right-source", + target_handle: "left-target", }, { id: "flow-gw-account", @@ -990,8 +1006,10 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gateway", to: "account-service", protocol: "gRPC/mTLS", - data: ["banking_requests", "transfer_orders"], + data: ["banking_requests"], authenticated: true, + source_handle: "right-source", + target_handle: "left-target", }, { id: "flow-account-fraud", @@ -999,7 +1017,7 @@ const TEMPLATE_BUILDERS: Record = { from: "account-service", to: "fraud-engine", protocol: "Kafka/TLS", - data: ["transaction_events", "risk_context"], + data: ["transaction_events"], authenticated: false, }, { @@ -1008,7 +1026,7 @@ const TEMPLATE_BUILDERS: Record = { from: "auth-service", to: "token-store", protocol: "Redis/TLS", - data: ["access_tokens", "session_data"], + data: ["access_tokens"], authenticated: false, }, { @@ -1017,8 +1035,10 @@ const TEMPLATE_BUILDERS: Record = { from: "account-service", to: "core-db", protocol: "Oracle/TLS", - data: ["account_queries", "ledger_entries"], + data: ["account_queries"], authenticated: true, + source_handle: "right-source", + target_handle: "left-target", }, { id: "flow-account-audit", @@ -1026,8 +1046,10 @@ const TEMPLATE_BUILDERS: Record = { from: "account-service", to: "audit-log", protocol: "HTTPS/TLS-1.3", - data: ["transaction_logs", "compliance_events"], + data: ["transaction_logs"], authenticated: true, + source_handle: "bottom-right-source", + target_handle: "top-left-target", }, { id: "flow-fraud-audit", @@ -1035,7 +1057,7 @@ const TEMPLATE_BUILDERS: Record = { from: "fraud-engine", to: "audit-log", protocol: "HTTPS/TLS-1.3", - data: ["fraud_alerts", "risk_scores"], + data: ["fraud_alerts"], authenticated: true, }, { @@ -1044,7 +1066,7 @@ const TEMPLATE_BUILDERS: Record = { from: "account-service", to: "card-network", protocol: "ISO-8583/TLS", - data: ["authorization_requests", "settlement_data"], + data: ["authorization_requests"], authenticated: true, }, { @@ -1053,7 +1075,7 @@ const TEMPLATE_BUILDERS: Record = { from: "auth-service", to: "hsm", protocol: "PKCS#11", - data: ["signing_requests", "key_derivation"], + data: ["signing_requests"], authenticated: true, }, { @@ -1062,7 +1084,7 @@ const TEMPLATE_BUILDERS: Record = { from: "account-service", to: "push-service", protocol: "HTTPS/TLS-1.3", - data: ["transaction_alerts", "security_notifications"], + data: ["transaction_alerts"], authenticated: true, }, { @@ -1071,7 +1093,7 @@ const TEMPLATE_BUILDERS: Record = { from: "api-gateway", to: "kyc-provider", protocol: "HTTPS/TLS-1.3", - data: ["identity_documents", "verification_requests"], + data: ["identity_documents"], authenticated: true, }, ], @@ -1080,8 +1102,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-dmz", name: "DMZ", contains: ["api-gateway"], - position: { x: 265, y: 235 }, - size: { width: 230, height: 120 }, + position: { x: 380, y: 340 }, + size: { width: 220, height: 130 }, fill_color: BOUNDARY_COLORS.edge.fill, stroke_color: BOUNDARY_COLORS.edge.stroke, fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, @@ -1091,8 +1113,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-app", name: "Application Services", contains: ["auth-service", "account-service", "fraud-engine"], - position: { x: 555, y: 65 }, - size: { width: 230, height: 480 }, + position: { x: 720, y: 110 }, + size: { width: 220, height: 670 }, fill_color: BOUNDARY_COLORS.internal.fill, stroke_color: BOUNDARY_COLORS.internal.stroke, fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, @@ -1102,8 +1124,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-data", name: "Secure Data Zone", contains: ["core-db", "token-store", "audit-log", "hsm"], - position: { x: 835, y: 65 }, - size: { width: 360, height: 480 }, + position: { x: 1080, y: 80 }, + size: { width: 220, height: 750 }, fill_color: BOUNDARY_COLORS.security.fill, stroke_color: BOUNDARY_COLORS.security.stroke, fill_opacity: BOUNDARY_COLORS.security.fillOpacity, @@ -1213,7 +1235,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Tenant users accessing the SaaS application via browser", technologies: ["spa", "react"], - position: { x: 60, y: 140 }, + position: { x: 80, y: 180 }, }, { id: "admin-browser", @@ -1222,7 +1244,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Platform administrators managing tenants and configurations", technologies: ["electron", "react"], - position: { x: 60, y: 380 }, + position: { x: 80, y: 470 }, }, { id: "api-client", @@ -1231,7 +1253,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Third-party integrations using the public REST API", technologies: ["rest", "webhooks"], - position: { x: 60, y: 560 }, + position: { x: 80, y: 720 }, }, { id: "lb", @@ -1240,7 +1262,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "Global load balancer with SSL termination and geo-routing", technologies: ["aws-alb", "waf"], - position: { x: 310, y: 260 }, + position: { x: 420, y: 350 }, }, { id: "app-server", @@ -1249,7 +1271,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Multi-tenant application server with tenant context isolation", technologies: ["node", "nest.js", "typescript"], - position: { x: 620, y: 110 }, + position: { x: 780, y: 160 }, }, { id: "api-server", @@ -1258,7 +1280,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Public REST API with versioning, pagination, and rate limiting", technologies: ["node", "nest.js", "openapi"], - position: { x: 620, y: 260 }, + position: { x: 780, y: 400 }, }, { id: "job-worker", @@ -1267,7 +1289,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Async job processing: reports, data exports, bulk operations", technologies: ["bull", "node"], - position: { x: 620, y: 410 }, + position: { x: 780, y: 620 }, }, { id: "sso-provider", @@ -1276,7 +1298,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "SAML/OIDC enterprise SSO for tenant authentication", technologies: ["okta", "saml", "oidc"], - position: { x: 310, y: 90 }, + position: { x: 420, y: 100 }, }, { id: "tenant-db", @@ -1287,7 +1309,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["tenant_data", "user_accounts", "configurations"], encryption: "AES-256-at-rest", technologies: ["postgresql", "row-level-security"], - position: { x: 940, y: 110 }, + position: { x: 1140, y: 160 }, }, { id: "job-queue", @@ -1296,7 +1318,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Reliable job queue for background processing", technologies: ["redis", "bull"], - position: { x: 940, y: 260 }, + position: { x: 1140, y: 400 }, }, { id: "file-store", @@ -1307,7 +1329,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["uploads", "exports", "attachments"], encryption: "SSE-S3", technologies: ["s3"], - position: { x: 940, y: 410 }, + position: { x: 1140, y: 620 }, }, { id: "monitoring", @@ -1316,7 +1338,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Centralized logging, metrics, alerting, and security monitoring", technologies: ["datadog", "sentry"], - position: { x: 620, y: 560 }, + position: { x: 780, y: 840 }, }, { id: "ci-cd", @@ -1325,7 +1347,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Automated build, test, and deploy pipeline", technologies: ["github-actions", "docker", "terraform"], - position: { x: 310, y: 440 }, + position: { x: 420, y: 590 }, }, ], data_flows: [ @@ -1335,7 +1357,7 @@ const TEMPLATE_BUILDERS: Record = { from: "tenant-browser", to: "lb", protocol: "HTTPS/TLS-1.3", - data: ["http_requests", "sso_tokens"], + data: ["http_requests"], authenticated: true, }, { @@ -1344,7 +1366,7 @@ const TEMPLATE_BUILDERS: Record = { from: "admin-browser", to: "lb", protocol: "HTTPS/TLS-1.3", - data: ["admin_requests", "mfa_tokens"], + data: ["admin_requests"], authenticated: true, }, { @@ -1353,7 +1375,7 @@ const TEMPLATE_BUILDERS: Record = { from: "api-client", to: "lb", protocol: "HTTPS/TLS-1.3", - data: ["api_requests", "api_keys"], + data: ["api_requests"], authenticated: true, }, { @@ -1364,6 +1386,8 @@ const TEMPLATE_BUILDERS: Record = { protocol: "HTTP/2", data: ["web_requests"], authenticated: true, + source_handle: "top-right-source", + target_handle: "left-target", }, { id: "flow-lb-api", @@ -1373,6 +1397,8 @@ const TEMPLATE_BUILDERS: Record = { protocol: "HTTP/2", data: ["api_requests"], authenticated: true, + source_handle: "right-source", + target_handle: "left-target", }, { id: "flow-sso-app", @@ -1380,7 +1406,7 @@ const TEMPLATE_BUILDERS: Record = { from: "app-server", to: "sso-provider", protocol: "SAML/HTTPS", - data: ["saml_assertions", "oidc_tokens"], + data: ["saml_assertions"], authenticated: true, }, { @@ -1389,7 +1415,7 @@ const TEMPLATE_BUILDERS: Record = { from: "app-server", to: "tenant-db", protocol: "PostgreSQL/TLS", - data: ["tenant_queries", "user_data"], + data: ["tenant_queries"], authenticated: true, }, { @@ -1407,7 +1433,7 @@ const TEMPLATE_BUILDERS: Record = { from: "api-server", to: "job-queue", protocol: "Redis/TLS", - data: ["job_payloads", "export_requests"], + data: ["job_payloads"], authenticated: false, }, { @@ -1416,7 +1442,7 @@ const TEMPLATE_BUILDERS: Record = { from: "job-worker", to: "job-queue", protocol: "Redis/TLS", - data: ["job_results", "status_updates"], + data: ["job_results"], authenticated: false, }, { @@ -1425,7 +1451,7 @@ const TEMPLATE_BUILDERS: Record = { from: "job-worker", to: "file-store", protocol: "HTTPS/TLS-1.3", - data: ["export_files", "reports"], + data: ["export_files"], authenticated: true, }, { @@ -1434,7 +1460,7 @@ const TEMPLATE_BUILDERS: Record = { from: "app-server", to: "monitoring", protocol: "HTTPS/TLS-1.3", - data: ["metrics", "traces", "error_events"], + data: ["metrics"], authenticated: true, }, ], @@ -1443,8 +1469,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-dmz", name: "DMZ", contains: ["lb"], - position: { x: 265, y: 215 }, - size: { width: 230, height: 120 }, + position: { x: 380, y: 300 }, + size: { width: 220, height: 130 }, fill_color: BOUNDARY_COLORS.edge.fill, stroke_color: BOUNDARY_COLORS.edge.stroke, fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, @@ -1454,8 +1480,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-app", name: "Application Tier (VPC)", contains: ["app-server", "api-server", "job-worker", "monitoring"], - position: { x: 575, y: 65 }, - size: { width: 230, height: 550 }, + position: { x: 740, y: 110 }, + size: { width: 220, height: 830 }, fill_color: BOUNDARY_COLORS.internal.fill, stroke_color: BOUNDARY_COLORS.internal.stroke, fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, @@ -1465,8 +1491,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-data", name: "Data Tier", contains: ["tenant-db", "job-queue", "file-store"], - position: { x: 895, y: 65 }, - size: { width: 230, height: 440 }, + position: { x: 1100, y: 110 }, + size: { width: 220, height: 610 }, fill_color: BOUNDARY_COLORS.data.fill, stroke_color: BOUNDARY_COLORS.data.stroke, fill_opacity: BOUNDARY_COLORS.data.fillOpacity, @@ -1575,7 +1601,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Temperature, humidity, and air quality sensors throughout the building", technologies: ["zigbee", "mqtt"], - position: { x: 60, y: 120 }, + position: { x: 80, y: 150 }, }, { id: "access-panel", @@ -1584,7 +1610,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Badge readers and biometric scanners at entry points", technologies: ["nfc", "ble"], - position: { x: 60, y: 300 }, + position: { x: 80, y: 380 }, }, { id: "camera-system", @@ -1593,7 +1619,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "IP cameras for surveillance and occupancy detection", technologies: ["rtsp", "onvif"], - position: { x: 60, y: 480 }, + position: { x: 80, y: 610 }, }, { id: "edge-gateway", @@ -1602,7 +1628,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "Local edge computing node aggregating device data and running local rules", technologies: ["arm", "linux", "docker"], - position: { x: 310, y: 300 }, + position: { x: 400, y: 380 }, }, { id: "mqtt-broker", @@ -1611,7 +1637,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Message broker for device telemetry and command distribution", technologies: ["mosquitto", "mqtt-v5"], - position: { x: 590, y: 120 }, + position: { x: 720, y: 170 }, }, { id: "stream-processor", @@ -1620,7 +1646,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Real-time event processing for anomaly detection and alerting", technologies: ["kafka-streams", "flink"], - position: { x: 590, y: 300 }, + position: { x: 720, y: 420 }, }, { id: "device-manager", @@ -1629,7 +1655,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Device provisioning, firmware updates, and fleet management", technologies: ["go", "grpc"], - position: { x: 590, y: 480 }, + position: { x: 720, y: 670 }, }, { id: "timeseries-db", @@ -1639,7 +1665,7 @@ const TEMPLATE_BUILDERS: Record = { description: "High-write telemetry storage optimized for time-range queries", stores: ["sensor_data", "energy_metrics", "occupancy"], technologies: ["influxdb"], - position: { x: 870, y: 120 }, + position: { x: 1040, y: 170 }, }, { id: "access-db", @@ -1650,7 +1676,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["badges", "access_policies", "entry_logs"], encryption: "AES-256-at-rest", technologies: ["postgresql"], - position: { x: 870, y: 300 }, + position: { x: 1040, y: 420 }, }, { id: "video-storage", @@ -1661,7 +1687,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["video_recordings", "motion_events"], encryption: "AES-256-at-rest", technologies: ["minio", "s3-compatible"], - position: { x: 870, y: 480 }, + position: { x: 1040, y: 670 }, }, { id: "dashboard", @@ -1670,7 +1696,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Real-time building analytics, energy monitoring, and alert management", technologies: ["grafana", "react"], - position: { x: 1100, y: 210 }, + position: { x: 1300, y: 260 }, }, { id: "facility-mgr", @@ -1679,7 +1705,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Building operations staff accessing the management dashboard", technologies: ["browser"], - position: { x: 1100, y: 410 }, + position: { x: 1300, y: 510 }, }, ], data_flows: [ @@ -1689,7 +1715,7 @@ const TEMPLATE_BUILDERS: Record = { from: "hvac-sensor", to: "edge-gateway", protocol: "MQTT/TLS", - data: ["temperature", "humidity", "air_quality"], + data: ["temperature"], authenticated: false, }, { @@ -1698,7 +1724,7 @@ const TEMPLATE_BUILDERS: Record = { from: "access-panel", to: "edge-gateway", protocol: "HTTPS/TLS-1.2", - data: ["badge_scans", "biometric_hashes"], + data: ["badge_scans"], authenticated: true, }, { @@ -1707,7 +1733,7 @@ const TEMPLATE_BUILDERS: Record = { from: "camera-system", to: "edge-gateway", protocol: "RTSP/TLS", - data: ["video_streams", "motion_events"], + data: ["video_streams"], authenticated: true, }, { @@ -1716,7 +1742,7 @@ const TEMPLATE_BUILDERS: Record = { from: "edge-gateway", to: "mqtt-broker", protocol: "MQTT/TLS", - data: ["aggregated_telemetry", "device_events"], + data: ["aggregated_telemetry"], authenticated: true, }, { @@ -1725,7 +1751,7 @@ const TEMPLATE_BUILDERS: Record = { from: "mqtt-broker", to: "stream-processor", protocol: "Kafka/TLS", - data: ["telemetry_events", "alert_triggers"], + data: ["telemetry_events"], authenticated: false, }, { @@ -1734,7 +1760,7 @@ const TEMPLATE_BUILDERS: Record = { from: "mqtt-broker", to: "timeseries-db", protocol: "InfluxDB/TLS", - data: ["raw_telemetry", "metrics"], + data: ["raw_telemetry"], authenticated: true, }, { @@ -1743,7 +1769,7 @@ const TEMPLATE_BUILDERS: Record = { from: "stream-processor", to: "access-db", protocol: "PostgreSQL/TLS", - data: ["access_events", "anomaly_flags"], + data: ["access_events"], authenticated: true, }, { @@ -1752,7 +1778,7 @@ const TEMPLATE_BUILDERS: Record = { from: "edge-gateway", to: "video-storage", protocol: "HTTPS/TLS-1.3", - data: ["video_segments", "thumbnails"], + data: ["video_segments"], authenticated: true, }, { @@ -1761,7 +1787,7 @@ const TEMPLATE_BUILDERS: Record = { from: "device-manager", to: "edge-gateway", protocol: "HTTPS/mTLS", - data: ["firmware_updates", "config_patches"], + data: ["firmware_updates"], authenticated: true, }, { @@ -1770,7 +1796,7 @@ const TEMPLATE_BUILDERS: Record = { from: "dashboard", to: "timeseries-db", protocol: "InfluxDB/TLS", - data: ["metric_queries", "aggregations"], + data: ["metric_queries"], authenticated: true, }, { @@ -1779,7 +1805,7 @@ const TEMPLATE_BUILDERS: Record = { from: "dashboard", to: "access-db", protocol: "PostgreSQL/TLS", - data: ["access_reports", "policy_queries"], + data: ["access_reports"], authenticated: true, }, { @@ -1788,7 +1814,7 @@ const TEMPLATE_BUILDERS: Record = { from: "facility-mgr", to: "dashboard", protocol: "HTTPS/TLS-1.3", - data: ["dashboard_views", "alert_management"], + data: ["dashboard_views"], authenticated: true, }, ], @@ -1797,8 +1823,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-edge", name: "Edge Network", contains: ["edge-gateway"], - position: { x: 265, y: 255 }, - size: { width: 230, height: 120 }, + position: { x: 360, y: 330 }, + size: { width: 220, height: 130 }, fill_color: BOUNDARY_COLORS.iot.fill, stroke_color: BOUNDARY_COLORS.iot.stroke, fill_opacity: BOUNDARY_COLORS.iot.fillOpacity, @@ -1808,8 +1834,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-processing", name: "Cloud Processing Tier", contains: ["mqtt-broker", "stream-processor", "device-manager"], - position: { x: 545, y: 75 }, - size: { width: 230, height: 480 }, + position: { x: 680, y: 120 }, + size: { width: 220, height: 650 }, fill_color: BOUNDARY_COLORS.internal.fill, stroke_color: BOUNDARY_COLORS.internal.stroke, fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, @@ -1819,8 +1845,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-data", name: "Data Tier", contains: ["timeseries-db", "access-db", "video-storage"], - position: { x: 825, y: 75 }, - size: { width: 230, height: 480 }, + position: { x: 1000, y: 120 }, + size: { width: 220, height: 650 }, fill_color: BOUNDARY_COLORS.data.fill, stroke_color: BOUNDARY_COLORS.data.stroke, fill_opacity: BOUNDARY_COLORS.data.fillOpacity, @@ -1930,7 +1956,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Patient-facing web portal for records, appointments, and messaging", technologies: ["react", "wcag-aa"], - position: { x: 60, y: 140 }, + position: { x: 80, y: 220 }, }, { id: "clinician-app", @@ -1939,7 +1965,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Desktop EHR application used by healthcare providers", technologies: ["electron", "fhir-smart"], - position: { x: 60, y: 380 }, + position: { x: 80, y: 540 }, }, { id: "fhir-gateway", @@ -1948,7 +1974,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "dmz", description: "HL7 FHIR R4 compliant API gateway with SMART on FHIR authorization", technologies: ["hapi-fhir", "smart-on-fhir", "oauth2"], - position: { x: 310, y: 260 }, + position: { x: 420, y: 380 }, }, { id: "patient-svc", @@ -1957,7 +1983,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Patient demographics, insurance, and care team management", technologies: ["java", "spring-boot", "fhir-r4"], - position: { x: 600, y: 110 }, + position: { x: 760, y: 180 }, }, { id: "clinical-svc", @@ -1966,7 +1992,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Clinical records, diagnoses, medications, and lab results", technologies: ["java", "spring-boot", "fhir-r4"], - position: { x: 600, y: 280 }, + position: { x: 760, y: 430 }, }, { id: "scheduling-svc", @@ -1975,7 +2001,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "Appointment scheduling, provider availability, and reminders", technologies: ["node", "typescript"], - position: { x: 600, y: 450 }, + position: { x: 760, y: 680 }, }, { id: "ehr-db", @@ -1986,7 +2012,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["patient_records", "clinical_notes", "medications", "lab_results"], encryption: "TDE-AES-256", technologies: ["postgresql", "pgcrypto"], - position: { x: 900, y: 110 }, + position: { x: 1100, y: 180 }, }, { id: "document-store", @@ -1997,7 +2023,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["dicom_images", "scanned_docs", "consent_forms"], encryption: "AES-256-at-rest", technologies: ["s3", "dicom"], - position: { x: 900, y: 280 }, + position: { x: 1100, y: 430 }, }, { id: "audit-log", @@ -2008,7 +2034,7 @@ const TEMPLATE_BUILDERS: Record = { stores: ["access_logs", "phi_queries", "consent_events"], encryption: "AES-256-at-rest", technologies: ["elasticsearch", "s3-glacier"], - position: { x: 900, y: 450 }, + position: { x: 1100, y: 680 }, }, { id: "ehr-system", @@ -2017,7 +2043,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "Third-party EHR system for health information exchange", technologies: ["hl7-v2", "fhir-r4", "direct-messaging"], - position: { x: 310, y: 80 }, + position: { x: 420, y: 100 }, }, { id: "pharmacy", @@ -2026,7 +2052,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "external", description: "E-prescribing network for electronic prescription transmission", technologies: ["ncpdp-script", "surescripts"], - position: { x: 310, y: 450 }, + position: { x: 420, y: 640 }, }, { id: "analytics-engine", @@ -2035,7 +2061,7 @@ const TEMPLATE_BUILDERS: Record = { trust_zone: "internal", description: "De-identified analytics for population health and quality measures", technologies: ["spark", "hipaa-safe-harbor"], - position: { x: 1130, y: 280 }, + position: { x: 1300, y: 300 }, }, ], data_flows: [ @@ -2045,7 +2071,7 @@ const TEMPLATE_BUILDERS: Record = { from: "patient-portal", to: "fhir-gateway", protocol: "HTTPS/TLS-1.3", - data: ["patient_requests", "oauth_tokens"], + data: ["patient_requests"], authenticated: true, }, { @@ -2054,7 +2080,7 @@ const TEMPLATE_BUILDERS: Record = { from: "clinician-app", to: "fhir-gateway", protocol: "HTTPS/TLS-1.3", - data: ["clinical_queries", "smart_tokens"], + data: ["clinical_queries"], authenticated: true, }, { @@ -2063,8 +2089,10 @@ const TEMPLATE_BUILDERS: Record = { from: "fhir-gateway", to: "patient-svc", protocol: "gRPC/mTLS", - data: ["patient_resources", "demographics"], + data: ["patient_resources"], authenticated: true, + source_handle: "top-right-source", + target_handle: "left-target", }, { id: "flow-fhir-clinical", @@ -2072,8 +2100,10 @@ const TEMPLATE_BUILDERS: Record = { from: "fhir-gateway", to: "clinical-svc", protocol: "gRPC/mTLS", - data: ["clinical_resources", "observations"], + data: ["clinical_resources"], authenticated: true, + source_handle: "right-source", + target_handle: "left-target", }, { id: "flow-fhir-scheduling", @@ -2081,8 +2111,10 @@ const TEMPLATE_BUILDERS: Record = { from: "fhir-gateway", to: "scheduling-svc", protocol: "gRPC/mTLS", - data: ["appointment_requests", "availability_queries"], + data: ["appointment_requests"], authenticated: true, + source_handle: "bottom-right-source", + target_handle: "left-target", }, { id: "flow-patient-db", @@ -2090,7 +2122,7 @@ const TEMPLATE_BUILDERS: Record = { from: "patient-svc", to: "ehr-db", protocol: "PostgreSQL/TLS", - data: ["patient_data", "insurance_records"], + data: ["patient_data"], authenticated: true, }, { @@ -2099,7 +2131,7 @@ const TEMPLATE_BUILDERS: Record = { from: "clinical-svc", to: "ehr-db", protocol: "PostgreSQL/TLS", - data: ["clinical_notes", "lab_results", "medications"], + data: ["clinical_notes"], authenticated: true, }, { @@ -2108,7 +2140,7 @@ const TEMPLATE_BUILDERS: Record = { from: "clinical-svc", to: "document-store", protocol: "HTTPS/TLS-1.3", - data: ["medical_images", "scanned_documents"], + data: ["medical_images"], authenticated: true, }, { @@ -2117,8 +2149,10 @@ const TEMPLATE_BUILDERS: Record = { from: "fhir-gateway", to: "audit-log", protocol: "HTTPS/TLS-1.3", - data: ["phi_access_events", "consent_changes"], + data: ["phi_access_events"], authenticated: true, + source_handle: "bottom-source", + target_handle: "left-target", }, { id: "flow-ehr-exchange", @@ -2126,7 +2160,7 @@ const TEMPLATE_BUILDERS: Record = { from: "fhir-gateway", to: "ehr-system", protocol: "FHIR/HTTPS", - data: ["care_summaries", "referrals"], + data: ["care_summaries"], authenticated: true, }, { @@ -2135,7 +2169,7 @@ const TEMPLATE_BUILDERS: Record = { from: "clinical-svc", to: "pharmacy", protocol: "NCPDP/TLS", - data: ["e_prescriptions", "medication_history"], + data: ["e_prescriptions"], authenticated: true, }, { @@ -2144,7 +2178,7 @@ const TEMPLATE_BUILDERS: Record = { from: "ehr-db", to: "analytics-engine", protocol: "JDBC/TLS", - data: ["de_identified_records", "quality_measures"], + data: ["de_identified_records"], authenticated: true, }, ], @@ -2153,8 +2187,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-dmz", name: "HIPAA DMZ", contains: ["fhir-gateway"], - position: { x: 265, y: 215 }, - size: { width: 230, height: 120 }, + position: { x: 380, y: 330 }, + size: { width: 220, height: 130 }, fill_color: BOUNDARY_COLORS.edge.fill, stroke_color: BOUNDARY_COLORS.edge.stroke, fill_opacity: BOUNDARY_COLORS.edge.fillOpacity, @@ -2164,8 +2198,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-app", name: "Application Services", contains: ["patient-svc", "clinical-svc", "scheduling-svc"], - position: { x: 555, y: 65 }, - size: { width: 230, height: 480 }, + position: { x: 720, y: 130 }, + size: { width: 220, height: 650 }, fill_color: BOUNDARY_COLORS.internal.fill, stroke_color: BOUNDARY_COLORS.internal.stroke, fill_opacity: BOUNDARY_COLORS.internal.fillOpacity, @@ -2175,8 +2209,8 @@ const TEMPLATE_BUILDERS: Record = { id: "boundary-phi", name: "PHI Data Zone", contains: ["ehr-db", "document-store", "audit-log"], - position: { x: 855, y: 65 }, - size: { width: 230, height: 480 }, + position: { x: 1060, y: 130 }, + size: { width: 220, height: 650 }, fill_color: BOUNDARY_COLORS.security.fill, stroke_color: BOUNDARY_COLORS.security.stroke, fill_opacity: BOUNDARY_COLORS.security.fillOpacity, From 871cbe152652574dad4e6cdeb523913d2b3cebca Mon Sep 17 00:00:00 2001 From: Shreyas Sane Date: Tue, 3 Mar 2026 13:59:27 -0500 Subject: [PATCH 3/6] fix(canvas): render edge labels above connectors with vertical layout - Add z-index to edge label renderer so labels appear above connector lines instead of behind them - Change label layout from horizontal to vertical (flex-col), stacking flow number, protocol, and data on separate lines for better readability Co-Authored-By: Claude Opus 4.6 --- .../canvas/edges/data-flow-edge.tsx | 39 ++++++++----------- src/styles.css | 5 +++ 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/components/canvas/edges/data-flow-edge.tsx b/src/components/canvas/edges/data-flow-edge.tsx index cd2210a..bb22519 100644 --- a/src/components/canvas/edges/data-flow-edge.tsx +++ b/src/components/canvas/edges/data-flow-edge.tsx @@ -291,7 +291,7 @@ export function DataFlowEdge({ ref={labelRef} type="button" className={cn( - "pointer-events-auto nodrag nopan absolute flex items-center gap-1 rounded border px-1.5 py-0.5 text-left transition-colors", + "pointer-events-auto nodrag nopan absolute z-10 flex flex-col items-start gap-0.5 rounded border px-1.5 py-1 text-left transition-colors", selected ? "border-tf-signal bg-tf-signal/10 text-foreground cursor-grab active:cursor-grabbing" : "border-border bg-card text-muted-foreground hover:border-muted-foreground cursor-pointer", @@ -300,30 +300,23 @@ export function DataFlowEdge({ transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`, }} > - {edgeData?.flowNumber != null && ( - - {edgeData.flowNumber} - - )} - {isAuthenticated && } - {hasTextLabel && ( -
- {edgeData?.name && ( -
{edgeData.name}
- )} - {(edgeData?.protocol || (edgeData?.data && edgeData.data.length > 0)) && ( -
- {edgeData?.protocol && {edgeData.protocol}} - {edgeData?.protocol && edgeData?.data && edgeData.data.length > 0 && ( - · - )} - {edgeData?.data && edgeData.data.length > 0 && ( - {edgeData.data.join(", ")} - )} -
+ {(edgeData?.flowNumber != null || isAuthenticated) && ( +
+ {edgeData?.flowNumber != null && ( + + {edgeData.flowNumber} + )} + {isAuthenticated && }
)} + {edgeData?.name && ( +
{edgeData.name}
+ )} + {edgeData?.protocol &&
{edgeData.protocol}
} + {edgeData?.data && edgeData.data.length > 0 && ( +
{edgeData.data.join(", ")}
+ )} )} {isEditing && ( @@ -340,7 +333,7 @@ export function DataFlowEdge({ {!hasLabel && !isEditing && (isHovered || selected) && ( + ))} +
+
+ + )} + + {/* Fill/Stroke colors — not for text annotations */} + {!isTextAnnotation && ( + <> + { + syncElementNodeData({ elementFillColor: color || undefined }); + updateElement(element.id, { fill_color: color || undefined }); + }} + onOpacityChange={(opacity) => { + syncElementNodeData({ elementFillOpacity: opacity }); + updateElement(element.id, { fill_opacity: opacity }); + }} + /> + + { + syncElementNodeData({ elementStrokeColor: color || undefined }); + updateElement(element.id, { stroke_color: color || undefined }); + }} + onOpacityChange={(opacity) => { + syncElementNodeData({ elementStrokeOpacity: opacity }); + updateElement(element.id, { stroke_opacity: opacity }); + }} + /> + + )} - {relatedThreats.length > 0 && ( + {/* Related threats — not for text annotations */} + {!isTextAnnotation && relatedThreats.length > 0 && (

Related Threats ({relatedThreats.length}) diff --git a/src/lib/ai-prompt.ts b/src/lib/ai-prompt.ts index 19b8631..9254e25 100644 --- a/src/lib/ai-prompt.ts +++ b/src/lib/ai-prompt.ts @@ -61,7 +61,7 @@ export function buildSystemPrompt(model: ThreatModel): string { "Supported actions: add_element, update_element, delete_element, add_data_flow, update_data_flow, delete_data_flow, " + "add_trust_boundary, update_trust_boundary, delete_trust_boundary, add_threat, update_threat, delete_threat.\n" + "For updates, only include fields that need to change. For deletes, only the id is needed.\n" + - 'Element types: "process", "data_store", "external_entity". ' + + 'Element types: "process", "data_store", "external_entity", "text" (annotation, no STRIDE threats). ' + "STRIDE categories: Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege. " + "Severities: critical, high, medium, low, info.\n" + "The user will review and approve actions before they are applied.\n\n", diff --git a/src/lib/component-library.test.ts b/src/lib/component-library.test.ts index 3ba42e0..f0c7878 100644 --- a/src/lib/component-library.test.ts +++ b/src/lib/component-library.test.ts @@ -157,11 +157,36 @@ describe("component-library", () => { }); it("every component has a valid shape and stride category", () => { - const validShapes = ["rounded", "database", "rect", "hexagon"]; - const validStride = ["service", "store", "actor"]; + const validShapes = ["rounded", "database", "rect", "hexagon", "text"]; + const validStride = ["service", "store", "actor", "none"]; for (const comp of COMPONENT_LIBRARY) { expect(validShapes, `Invalid shape for ${comp.id}`).toContain(comp.shape); expect(validStride, `Invalid strideCategory for ${comp.id}`).toContain(comp.strideCategory); } }); + + it("has a text component with shape 'text' and strideCategory 'none'", () => { + const text = getComponentByType("text"); + expect(text).toBeDefined(); + expect(text?.shape).toBe("text"); + expect(text?.strideCategory).toBe("none"); + expect(text?.category).toBe("Annotations"); + }); + + it("includes Annotations in COMPONENT_CATEGORIES", () => { + expect(COMPONENT_CATEGORIES).toContain("Annotations"); + }); + + it("getShapeForType returns 'text' for text type", () => { + expect(getShapeForType("text")).toBe("text"); + }); + + it("getStrideCategoryForType returns 'none' for text type", () => { + expect(getStrideCategoryForType("text")).toBe("none"); + }); + + it("searchComponents finds text by annotation tag", () => { + const results = searchComponents("annotation"); + expect(results.some((c) => c.id === "text")).toBe(true); + }); }); diff --git a/src/lib/component-library.ts b/src/lib/component-library.ts index c632e55..5aa76df 100644 --- a/src/lib/component-library.ts +++ b/src/lib/component-library.ts @@ -38,6 +38,7 @@ import { Ship, Smartphone, Terminal, + Type, UserCheck, Waves, Waypoints, @@ -46,10 +47,10 @@ import { } from "lucide-react"; /** Shape categories determine how a component renders on the canvas. */ -export type ShapeCategory = "rounded" | "database" | "rect" | "hexagon"; +export type ShapeCategory = "rounded" | "database" | "rect" | "hexagon" | "text"; /** STRIDE categories determine which STRIDE threats apply to a component. */ -export type StrideCategory = "service" | "store" | "actor"; +export type StrideCategory = "service" | "store" | "actor" | "none"; export interface SubtypeDefinition { /** Subtype value stored in YAML, e.g. "rds" */ @@ -123,6 +124,7 @@ const ICON_MAP: Record = { "package-check": PackageCheck, "code-2": Code2, terminal: Terminal, + type: Type, }; export const COMPONENT_LIBRARY: ComponentDefinition[] = [ @@ -137,6 +139,17 @@ export const COMPONENT_LIBRARY: ComponentDefinition[] = [ tags: ["generic", "component", "node"], }, + // Annotations + { + id: "text", + label: "Text", + shape: "text", + strideCategory: "none", + icon: "type", + category: "Annotations", + tags: ["text", "label", "annotation", "note"], + }, + // Services { id: "web_server", diff --git a/src/lib/stride-engine.test.ts b/src/lib/stride-engine.test.ts index 87ad86c..0729b57 100644 --- a/src/lib/stride-engine.test.ts +++ b/src/lib/stride-engine.test.ts @@ -159,4 +159,34 @@ describe("analyzeStride", () => { const processThreats = threats.filter((t) => t.element === "web-app"); expect(processThreats).toHaveLength(6); }); + + it("generates zero threats for text annotation elements", () => { + const model = sampleModel(); + model.elements.push({ + id: "text-1", + type: "text", + name: "API Gateway Cluster", + trust_zone: "", + description: "", + technologies: [], + }); + const threats = analyzeStride(model); + const textThreats = threats.filter((t) => t.element === "text-1"); + expect(textThreats).toHaveLength(0); + }); + + it("does not affect other element threat counts when text element is present", () => { + const model = sampleModel(); + model.elements.push({ + id: "text-1", + type: "text", + name: "Some annotation", + trust_zone: "", + description: "", + technologies: [], + }); + const threats = analyzeStride(model); + // Same counts as before: 6 (service) + 3 (store) + 2 (actor) + 3 (flow) = 14 + expect(threats).toHaveLength(14); + }); }); diff --git a/src/lib/stride-engine.ts b/src/lib/stride-engine.ts index 747e939..eabf8c2 100644 --- a/src/lib/stride-engine.ts +++ b/src/lib/stride-engine.ts @@ -213,6 +213,7 @@ export function analyzeStride(model: ThreatModel): Threat[] { // Element-based rules for (const element of model.elements) { const elementCategory = getStrideCategoryForType(element.type); + if (elementCategory === "none") continue; for (const rule of rules) { if (rule.targetsFlows) continue; if (!rule.applicableCategories.includes(elementCategory)) continue; diff --git a/src/stores/canvas-store.ts b/src/stores/canvas-store.ts index e522af7..f01c6a6 100644 --- a/src/stores/canvas-store.ts +++ b/src/stores/canvas-store.ts @@ -37,6 +37,10 @@ export type DfdNodeData = { elementFillOpacity?: number; /** Element stroke opacity (0-1) */ elementStrokeOpacity?: number; + /** Font size in pixels (for text annotations) */ + fontSize?: number; + /** Font weight: "normal" | "bold" (for text annotations) */ + fontWeight?: string; /** For trust boundary group nodes */ isBoundary?: boolean; boundaryName?: string; @@ -210,9 +214,10 @@ export function generateBoundaryId(): string { } export function elementToNode(element: Element, position: { x: number; y: number }): DfdNode { + const isText = element.type === "text"; return { id: element.id, - type: "dfdElement", + type: isText ? "textAnnotation" : "dfdElement", position, data: { label: element.name, @@ -226,6 +231,8 @@ export function elementToNode(element: Element, position: { x: number; y: number elementStrokeColor: element.stroke_color, elementFillOpacity: element.fill_opacity, elementStrokeOpacity: element.stroke_opacity, + fontSize: element.font_size, + fontWeight: element.font_weight, }, }; } diff --git a/src/types/threat-model.ts b/src/types/threat-model.ts index 4347ad8..5cfdf1e 100644 --- a/src/types/threat-model.ts +++ b/src/types/threat-model.ts @@ -75,6 +75,8 @@ export interface Element { stroke_color?: string; fill_opacity?: number; stroke_opacity?: number; + font_size?: number; + font_weight?: string; } export interface DataFlow {