Architecture

Design studio system & UI conventions

The DataFlow AI Platform presents a deep, feature-rich ETL product — pipeline design, monitoring, governance, migration and administration — through one consistent visual system. This page documents the design language: the semantic token model, the dark amber/zinc theme, the persona-adaptive shell, the shared component library, and the accessibility and responsive conventions every screen follows.


Design principles

The interface is built for telecom data engineers, analysts, administrators and stewards working long sessions inside dense operational screens. Four principles shape every component decision.

PrincipleWhat it means in practice
Semantic, not literalComponents reference token classes (bg-surface-1, text-heading) rather than raw colours, so a theme swap never touches component code.
Dark-firstThe default theme is dark; light is a fully supported alternative. Both resolve from the same token set.
Persona-adaptiveThe shell — chiefly the sidebar — shows only the features relevant to the active persona.
Code-split and resilientEvery page is lazy-loaded and wrapped in an error boundary; a failure in one screen never breaks the shell.

Token model

Styling uses Tailwind CSS 4, wired through @tailwindcss/vite. The platform does not scatter hex values across components. Instead it defines a layer of semantic design tokens — named roles such as "surface" or "heading" — and components consume only those.

Surface tokens

Surfaces are layered. Higher-numbered surfaces sit visually closer to the user and are used for raised elements such as cards, panels and modals.

Token classRole
bg-surface-0Page background — the deepest layer
bg-surface-1Cards, panels, the sidebar
bg-surface-2Raised elements — popovers, modals, dropdowns

Text tokens

Text tokens express hierarchy, not colour. A heading is text-heading regardless of theme.

Token classRole
text-headingPage and section titles
text-bodyPrimary reading text
text-secondarySupporting text, labels
text-mutedDe-emphasised text, hints, placeholders

Border and accent

Token classRole
border-primaryDefault separators and component outlines
amber-500The brand accent — primary actions, active navigation, focus highlights
 SURFACE LAYERING (dark theme)

  ┌─ bg-surface-0  (page) ────────────────────────────────┐
  │                                                       │
  │   ┌─ bg-surface-1  (card / panel) ─────────────────┐   │
  │   │  text-heading   Pipeline summary               │   │
  │   │  text-body      14 runs in the last 24 hours   │   │
  │   │  text-muted     last updated 2 minutes ago     │   │
  │   │                              ┌──────────────┐  │   │
  │   │                              │ bg-surface-2 │  │   │
  │   │                              │  (popover)   │  │   │
  │   │                              └──────────────┘  │   │
  │   │   [ amber-500 primary action ]                 │   │
  │   └─────────────────────────────────────────────────┘   │
  └───────────────────────────────────────────────────────┘

Why semantic tokens

Because components reference token classes rather than literal colours, switching between dark and light — or adjusting the palette later — is a token-layer change. No component file is edited.


Colour palette reference

Behind the semantic tokens sits a concrete palette. The platform is a dark-first product and the canonical accent is gold/amber #ffd200. The tables below give the literal values each token resolves to.

Dark theme — backgrounds

RoleHexTailwindUsage
Base#09090bzinc-950Primary page background — the deepest layer
Surface#0c0c0fcustomAlternating section background, cards
Elevated#18181bzinc-900Sidebar, panels, modals
Overlayrgba(255,255,255,0.03)white/3Subtle card overlays
Overlay hoverrgba(255,255,255,0.05)white/5Card hover state
Overlay activergba(255,255,255,0.06)white/6Active / selected state

Dark theme — text

RoleHexTailwindUsage
Primary#ffffffwhiteHeadings, emphasis
Secondary#f1f5f9slate-100Body text
Muted#d1d5dcgray-300Secondary labels
Subtle#6a7282gray-500Placeholders, hints
Disabled#4a5565gray-600Disabled state

Dark theme — borders

RoleHexTailwindUsage
Defaultrgba(255,255,255,0.08)white/8Card borders, dividers
Subtlergba(255,255,255,0.06)white/6Subtle separators
Strongrgba(255,255,255,0.15)white/15Secondary button border

Accent — primary (gold/amber)

RoleHexUsage
Accent primary#ffd200Primary brand colour, CTA
Accent primary hover#e6bd00Hover state
Accent primary text#101828Text on an accent background

Accent — semantic palette

The amber accent is reserved for action and brand. Status and category meaning is carried by a fixed semantic palette.

ColourHexTailwindUsage
Emerald#10b981emerald-500Success, online, healthy
Blue#3b82f6blue-500Info, links, secondary actions
Cyan#06b6d4cyan-500Data, metrics
Violet#8b5cf6violet-500AI features, special
Purple#c084fcpurple-400Creative, design
Amber#f59e0bamber-500Warnings
Red#ef4444red-500Errors, destructive, critical
Orange#f97316orange-500Attention, alerts
Pink#ec4899pink-500Highlights

The dark amber/zinc theme

The signature look is a dark amber/zinc theme: deep neutral zinc surfaces carrying a warm amber accent. Zinc gives long-session screens a low-glare, low-fatigue base; amber (amber-500) marks the few things the user should act on — primary buttons, the active navigation item, focus rings and key status highlights.

The theme is the default. It is the canonical expression of the design language; the light theme is the same token set re-mapped for bright environments.

ThemeBase surfacesAccentDefault
DarkZinc neutrals, deep to raisedAmber (amber-500)Yes
LightLight neutrals, same layeringAmber (amber-500)No

Light and dark theming

Theme state is owned by the themeStore Zustand store, persisted to localStorage under the key dataflow-theme. Its value is 'dark' | 'light', defaulting to 'dark'.

The mechanism is a single class toggle. When the theme changes, the store sets or clears the dark class on document.documentElement (<html>). Tailwind CSS 4 resolves every semantic token against that class, so one class flip re-themes the whole application.

  themeStore.theme  ──────────────►  <html class="dark">
       │                                    │
   persisted to                      Tailwind 4 resolves
   localStorage                      every semantic token
   'dataflow-theme'                   against the class
       │                                    │
   restored on load                  components re-render
                                     with no code change

App.tsx reads theme from useThemeStore on mount and synchronises the <html> class immediately, so the correct theme is applied before the first paint and there is no flash of the wrong theme.

Theme mapping

The same semantic role resolves to a different concrete value per theme. The accent and CTA stay constant — only neutrals re-map.

ElementDark modeLight mode
Page background#09090b (zinc-950)#f8fafc (slate-50)
Surface#0c0c0f#ffffff
Sidebar#18181b (zinc-900)#ffffff
Text primary#ffffff#101828
Text secondary#d1d5dc (gray-300)#4a5565 (gray-600)
Text muted#6a7282 (gray-500)#6a7282 (gray-500)
Borderwhite/8gray-200 (#e5e7eb)
Accent#ffd200#ffd200
CTA buttonGold gradientGold gradient
CTA text#101828#101828

The persona-adaptive shell

The application runs inside one persistent shell — components/shell/AppShell.tsx — and that shell adapts to the active persona. There are four personas: engineer, analyst, admin and steward.

How personas are resolved

In production the persona is derived from Keycloak roles via the ROLE_PERSONA_MAP in auth/keycloak.ts. In dev mode it comes from the personaStore (activePersona, default engineer, persisted under dataflow-persona).

How the shell adapts

The sidebar navigation model lives in data/navigation.ts as navigationItems. Each item declares id, label, an icon (a lucide icon name), a path, a personas[] visibility list and optional children[]. The sidebar filters items by activePersona, and additionally honours a MIGRATION_CENTER_ENABLED feature flag from config/env.ts.

  ENGINEER persona              ANALYST persona              ADMIN persona
  ┌──────────────┐             ┌──────────────┐             ┌──────────────┐
  │ ▸ Home       │             │ ▸ Home       │             │ ▸ Home       │
  │ ▸ Design     │             │ ▸ Data       │             │ ▸ Monitor    │
  │   Studio     │             │   Browser    │             │ ▸ Governance │
  │ ▸ Monitor    │             │ ▸ Monitor    │             │ ▸ Migration  │
  │ ▸ My         │             │ ▸ Marketplace│             │ ▸ Admin (6)  │
  │   Pipelines  │             │ ▸ Templates  │             │   ─ Users    │
  │ ▸ Connections│             │              │             │   ─ Security │
  └──────────────┘             └──────────────┘             └──────────────┘
   navigationItems filtered by activePersona  +  MIGRATION_CENTER_ENABLED flag

Beyond filtering, ProtectedRoute enforces persona access per route: it computes an effectivePersona and calls canAccess(persona, pathname) from data/permissions. If a persona reaches a path it should not see, <AccessDenied /> is rendered instead of the page. The shared PermissionGate UI primitive lets individual controls — buttons, menu actions — be shown or hidden by permission within an otherwise visible page.


Component library conventions

Components are organised by feature area under components/, with one shared, theme-agnostic UI kit under components/ui/.

The UI kit

The ui/ folder holds roughly forty presentation primitives. They are the only place colour and spacing decisions are made; feature components compose these.

CategoryPrimitives
Data displayDataTable, DataGrid, Timeline, Accordion, TreeView, CodeBlock, Badge, Avatar
FormsInput, Select, Checkbox, Radio, Switch, Textarea, FileInput
NavigationTabs, Pagination, Breadcrumbs
FeedbackSkeleton, EmptyState, AlertBanner, ProgressBar, Toast / ToastProvider, Popover, Tooltip
ChartsLineChart, BarChart, GaugeChart
LayoutStack, Show, ResponsiveGrid, Divider, List
AccessSkipNav, PermissionGate

Feature folders — design-studio/, monitor/, governance/, admin/, migration/, ai-copilot/, data-browser/, pipelines/, connections/ — build screen-specific components on top of the kit.

Tables

High-volume tables — pipeline runs, catalog rows, audit logs — are built on @tanstack/react-table 8 and virtualised with @tanstack/react-virtual 3, so a table of thousands of rows renders only the visible window.

Graph and code surfaces

Two specialised surfaces appear across the product:

  • Flow graphs use @xyflow/react 12 (React Flow) — the Design Studio pipeline canvas and the governance lineage graph.
  • Code editing uses @monaco-editor/react 4 for YAML pipeline definitions and SQL.

Typography

The platform uses a single sans-serif family for UI text and a monospace family for code, SQL and YAML.

/* UI text */
font-family: Inter, system-ui, -apple-system, sans-serif;
/* Code, SQL, pipeline YAML */
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

Type scale

LevelSizeWeightLine heightLetter spacingUsage
Display72px7001.1-1.8pxHero headings
H148px7001.0-0.5pxPage headings
H236px7001.1normalSection headings
H324px6001.3normalCard headings
H420px6001.4normalSub-section headings
Body Large18px4001.6normalLead paragraphs
Body16px4001.5normalDefault body text
Body Small14px4001.5normalDescriptions
Caption12px5001.4normalLabels, metadata
Micro11px5001.30.5pxBadges, tags
Tiny10px6001.20.5pxOverline labels

Font weights

WeightValueUsage
Regular400Body text
Medium500Labels, captions
Semibold600Buttons, sub-headings
Bold700Headings
Extrabold800Display metrics

Spacing scale

Spacing follows Tailwind's 4px base unit. Components draw from a fixed set of steps rather than arbitrary values.

TokenValueUsage
space-14pxTight gaps
space-28pxDefault gap
space-312pxCard padding (compact)
space-416pxSection gap
space-624pxSection padding, standard card padding
space-832pxLarge section spacing
space-1248pxPage sections
space-1664pxMajor sections

Border radius

TokenValueUsage
rounded-sm6pxTags, small badges
rounded8pxButtons, inputs, small cards
rounded-md12pxCards, panels
rounded-lg16pxLarge cards, modals
rounded-full9999pxPills, avatars, badges

Shadows

TokenValueUsage
shadow-sm0 1px 2px rgba(0,0,0,0.05)Subtle lift
shadow-md0 4px 6px -1px rgba(0,0,0,0.1)Cards
shadow-lg0 10px 15px -3px rgba(0,0,0,0.1)Elevated cards, buttons
shadow-xl0 20px 25px -5px rgba(0,0,0,0.1)Modals, dropdowns
shadow-2xl0 25px 50px -12px rgba(0,0,0,0.25)Hero elements
shadow-glow0 0 20px rgba(255,210,0,0.15)Gold accent glow

Buttons and interaction states

Buttons come in three weights — a gold primary CTA, a ghost secondary, and a red destructive — at a standard and a large size.

/* Primary CTA — standard */
background: linear-gradient(to right, #ffd200, #d4a00a);
color: #101828;
font-weight: 600;
font-size: 14px;
padding: 8px 16px;
border-radius: 8px;

/* Primary CTA — large */
font-size: 16px;
padding: 16px 32px;
border-radius: 12px;

/* Secondary (ghost) */
background: transparent;
color: #d1d5dc;
border: 0.8px solid rgba(255,255,255,0.15);

/* Destructive */
background: #ef4444;
color: #ffffff;

Interaction states

Every interactive primitive resolves the same four states, so a button, a row and a nav item all respond consistently.

StateEffect
HoverLighten 10%, scale 1.02
ActiveDarken 5%, scale 0.98
DisabledOpacity 0.5, cursor not-allowed
Focus2px ring, amber-500/50 — the amber accent doubles as the focus highlight

Gradients

/* Gold text gradient — headlines */
background: linear-gradient(to right, #ffd200, #e6b800, #cc9e00);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

/* Gold button gradient */
background: linear-gradient(to right, #ffd200 0%, #d4a00a 50%, #b8860b 100%);

/* Subtle gold glow — background accent */
background: radial-gradient(rgba(255,210,0,0.08) 0%, transparent 60%);

Component patterns

The UI kit primitives are built from the tokens above. The recurring patterns below define how a card, a nav item, a badge, an input, a table and a tab bar look in the dark theme.

PatternSpecification
Cardbg white/3, border 1px white/8, radius 12px, padding 24px; hover → bg white/5, border white/12
Sidebar nav itemDefault text-gray-400; hover text-white on bg white/5; active text-amber-400 on bg amber-500/10 with border-l-2 border-amber-500
Badge / tagbg {color}-500/10, text {color}-400, border 1px {color}-500/20, radius 6px, padding 2px 8px, 11px medium
Input fieldbg white/5, border 1px white/10, radius 8px, white text, gray-500 placeholder; focus → border amber-500/50, 2px amber-500/20 ring
TableHeader bg white/3, header text gray-400 uppercase 11px tracking-wider; row border white/5, row hover white/3; cell text gray-300 (data) / white (primary)
Tab barDefault text-gray-400 with border-b-2 border-transparent; hover text-gray-200 / border-gray-600; active text-amber-400 / border-amber-500

Iconography

  • Library — Lucide React. The brand logo icon is the Lucide Workflow glyph.
  • Stroke width — 1.5px by default.
  • Sizes — Small 16px (h-4 w-4, inline with text); Default 20px (h-5 w-5, navigation and buttons); Large 24px (h-6 w-6, feature icons).
  • Colour — icons inherit the surrounding text colour, so they re-theme with the rest of the UI.

Animation and transitions

Motion is restrained and consistent. Each interaction class has a fixed duration and easing.

PropertyDurationEasing
Colour transitions150msease
Background200msease-in-out
Transform (hover)200msease-out
Modal open300msease-out
Sidebar toggle300msease-in-out
Spinner1000mslinear (infinite)

Responsive breakpoints

The layout resolves against Tailwind's five standard breakpoints.

BreakpointWidthUsage
sm640pxMobile landscape
md768pxTablet
lg1024pxDesktop
xl1280pxWide desktop
2xl1536pxUltra-wide

Layout primitives

Pages are assembled from a small set of layout primitives so that spacing, page headers and split views look identical everywhere.

PrimitiveFolderRole
PageContainerlayout/Standard page wrapper with consistent padding and max width
PageHeaderlayout/Title, description and action area at the top of a page
SplitPanelayout/Resizable two-pane layouts (e.g. list plus detail)

The shell itself contributes the persistent frame: Sidebar, TopBar, the <main id="main-content"> outlet, and the AI Copilot trigger and sidebar. Main content is offset by an effectiveMargin that tracks the current sidebar width (collapsed 60px, expanded 240px).


Accessibility

Accessibility is built into the shell and the UI kit rather than bolted on per page.

  • Skip navigation. The shell renders a skip link to #main-content; the SkipNav primitive standardises it. <main> carries the id="main-content" target.
  • Keyboard command surface. Global search opens with Ctrl/Cmd+K via a shell keydown handler; the command palette is built on cmdk. The useKeyboardShortcut hook standardises other shortcuts.
  • Focus visibility. The amber accent doubles as the focus highlight, so keyboard focus is always clearly visible against zinc surfaces.
  • Permission-aware rendering. PermissionGate and ProtectedRoute ensure users are not shown — and cannot tab into — controls or routes they cannot use.
  • Loading and empty states. Skeleton and EmptyState give every async surface a defined, screen-reader-friendly state instead of a blank region.

Resilient by default

Every page is wrapped in an ErrorBoundary (inside SuspenseWrap) and panels use PanelErrorFallback. A user always sees a recoverable error surface, never a blank screen, when something fails.


Responsive behaviour

The layout adapts across three breakpoint classes, computed by useIsMobile, useIsTablet and useSidebarState from hooks/useResponsive (with supporting useMediaQuery and useBreakpoint hooks).

BreakpointNavigationNotes
DesktopFull sidebar, collapsible 60px ⇄ 240pxMain content offset by effectiveMargin
TabletCollapsed sidebar with hover-expandCompact chrome, same routes
MobileMobileMenu overlay + MobileBottomNavSidebar hidden; bottom nav for primary destinations
  DESKTOP                    TABLET                     MOBILE
  ┌────┬────────────┐        ┌──┬──────────────┐        ┌──────────────┐
  │side│  content   │        │░░│   content    │        │   TopBar     │
  │bar │            │        │ho│              │        ├──────────────┤
  │240 │            │        │ve│              │        │              │
  │px  │            │        │r │              │        │   content    │
  │    │            │        │60│              │        │              │
  │    │            │        │px│              │        ├──────────────┤
  └────┴────────────┘        └──┴──────────────┘        │ ▣ ▣ ▣ ▣  nav │
                                                        └──────────────┘

The ResponsiveGrid, Stack and Show layout primitives let feature components reflow without bespoke media-query CSS, keeping responsive behaviour consistent with the design system rather than improvised per page.


Summary

The DataFlow AI design system rests on one idea applied consistently: components describe roles, not pixels. Semantic Tailwind 4 tokens carry surface, text, border and accent meaning; the dark amber/zinc theme is the default expression of those tokens and light is the same set re-mapped; a single dark class toggle re-themes everything; the shell adapts to the active persona; a forty-piece UI kit and a handful of layout primitives keep every screen coherent; and accessibility plus responsive behaviour are wired into the shell so every page inherits them for free.

Previous
Frontend application