Skip to main content

Layer 4: Storybook + Chromatic — Component Visual Regression

Why Storybook Over Figma

Decision based on analysis of 7 Sergey feedback documents (Mar 16 → Apr 7), 63+ review files, and 42 existing components.

FactorStorybookFigma
Matches Sergey's feedback styleStories = page scenarios ("CISO sees overview, gets WOW in 15 seconds")Figma = pixel specs (Sergey gives architecture feedback, not pixel feedback)
Design tool compatibilityIndependent of Stitch — stories are codeWould require moving designs from Stitch to Figma (second tool)
Living catalogStories become the missing component documentationFigma is a separate tool outside the dev workflow
Iteration pattern17 rounds on Overview = story variants documenting each iterationFigma can't show runtime behavior or data states
ChromaticNative integration — every story = visual regression testWould need Applitools ($500+/mo) for Figma comparison
Existing tokensCSS custom properties in index.css work in Storybook automaticallyWould need to export tokens to Figma Variables
CostChromatic free tier (5K snapshots/mo)Applitools enterprise pricing

Evidence from March Sprint

Sergey's feedback operates at two levels:

  • Page architecture (dominant, 90%): "Top section should be cluster-driven hero, not generic stats"
  • Component-level (rare, 10%): "Fingerprint icon wrong", "Jira CTA too quiet"

Page-level stories map directly to how Sergey reviews. Component stories catch the token regressions that slip through page-level review.

Current State

AssetCountStatus
React components42Well-structured, pure-presentational, use CSS tokens
Pages24Data-fetching via TanStack Query hooks
Storybook0Not installed
Component tests0No unit tests for components
DESIGN.md1120-line design system (19 color tokens, typography, rules)
Design Principles6Codified with acceptance tests

Components are already reusable and well-bounded — badges, cards, tables, graphs are domain-organized. Stories will map naturally.

Phased Rollout

Phase A: Page-Level Stories (2-3 days)

Goal: Stories for the 3 pages Sergey reviews most — Overview, Risk Cluster Detail, Remediation Brief.

What to build:

  • OverviewPage.stories.tsx — variants: cluster-driven hero, empty state, single cluster, many clusters
  • RiskClusterDetailPage.stories.tsx — variants: orphaned sensitive, scope drift, with/without remediation
  • RemediationBriefPage.stories.tsx — variants: 404 state (old), full brief (new), action pending

Mock data: Create fixture factories for FindingDoc, RiskCluster, RemediationPlan that return realistic demo-w1 data. Use TanStack Query's QueryClient with pre-populated cache for page stories.

Validation: Compare story screenshots against prod/dev screenshots from the visual-verify run. This proves whether stories reproduce what's actually deployed.

Phase B: Shared Primitives (2-3 days)

Goal: Stories for the 15 most-reused components.

Priority order (by reuse count across pages):

ComponentUsed inStory variants
SeverityBadge8+ pagescritical, high, medium, low, informational
DeltaBadge / DeltaIndicator5+ pagespositive, negative, zero, large delta
EvidenceBadge5+ pagesexecution_confirmed, standing_authority, structural, inferred, correlated
DataTable + filters + pagination6+ pagesempty, loading, populated, filtered, sorted
StatCard4+ pagesnumber, trend, with delta, compact
RiskClusterCard3+ pagescritical cluster, info cluster, with/without remediation
EntityBadge6+ pagesidentity, workload, resource, data domain
TabNav5+ pages2 tabs, 5 tabs, with counts
EmptyState / ErrorMessageall pagesno data, error, 404
PathLabel4+ pagesshort path, long path, with execution count

Phase C: Chromatic CI Integration (1 day)

Goal: Every PR auto-snapshots changed stories.

Setup:

npx storybook@latest init  # one-time setup
npx chromatic --project-token=<token> # connect to Chromatic

CI workflow addition (.github/workflows/chromatic.yml):

  • Trigger: PRs modifying ui/**
  • Run: npx chromatic --exit-zero-on-changes
  • TurboSnap: Only snapshot stories whose dependencies changed (85% faster)
  • Post: PR comment with Chromatic build link + change count

Free tier: 5,000 snapshots/month. With TurboSnap and ~30 stories, this covers ~160 PRs/month.

Phase D: Full Component Catalog (Ongoing)

Goal: Remaining 27+ components get stories over time.

Rule: Any PR that modifies a component must add/update its story. This grows the catalog organically without a big upfront investment.

Graph components (9 files) are the hardest — ELK.js layout + @xyflow/react. Defer these unless graph visualization changes are planned.

How This Integrates with Existing Layers

Layer 1: Agent rules (AGENTS.md)
→ Agent must reference evidence before claiming done

Layer 2: Dual-output diff report (visual-diff-report.ts --agent-report)
→ Page-level pixel comparison, structured PASS/FAIL

Layer 3: Local deploy + CI gate (visual-deploy.ts)
→ Immediate Cloudflare Pages links, PR comments with summaries

Layer 4: Storybook + Chromatic (THIS PLAN)
→ Component-level visual regression, catches what page-level misses
→ Stories document component states (living catalog)
→ Chromatic catches regressions before they propagate to pages

What each layer catches:

Issue typeLayer that catches it
Agent blindly claims "fixed"Layer 1 (rules block it)
Page layout regressionLayer 2 (pixel diff)
Token color drift on a badgeLayer 4 (Chromatic component snapshot)
Intentional redesign needs reviewLayer 3 (/visual-verify verdicts)
Component state missing (empty, error)Layer 4 (story variants)

Validation Plan

Before committing to full Chromatic rollout, validate with Phase A:

  1. Create stories for Overview + Remediation Brief
  2. Capture story screenshots locally (npx storybook build && npx test-storybook)
  3. Compare against production screenshots from the visual-verify run
  4. If stories reproduce the actual deployed UI → Storybook works for our stack
  5. If stories diverge significantly → investigate mock data / token issues before proceeding

Next Action

Status: draft

Decision needed from: CTO

Options:

  1. Start Phase A now — create stories for 3 key pages as proof-of-concept alongside current UI work
  2. Start after current sprint — defer until Overview + Remediation pages are stable
  3. Skip Layer 4 — Layers 1-3 are sufficient for current team size

GitHub Issue: SecurityV0/sv0-platform — to be created when Phase A starts