React SPA (UI)
Built with Vite + TanStack Query + Tailwind CSS + shadcn/ui components. Deployed on Cloudflare, served by the Worker for non-API routes. TanStack Router is installed as a dependency but not yet wired up — App.tsx uses useState for page navigation. The UI uses CSS variable theming with system/light/dark mode support and Lucide icons.
Design Priority
The UI is an investigative tool, not a monitoring dashboard. The primary interaction is: notice something unexpected (cost delta) -> drill down to find the cause -> take action. Every click should move the user closer to answering "why?"
Routes
Implemented
App.tsx (useState-based routing, 5 pages)
routes/index.tsx -> Dashboard (KPI cards by role + top 5 customers table)
routes/delta/index.tsx -> Cost delta decomposition (ranked movers + resource drill-down)
routes/costs/index.tsx -> Cost overview (full customer cost table)
routes/resources/index.tsx -> Filterable resource table
routes/hierarchy/index.tsx -> Hierarchy explorer (expandable tree + cost trend chart)
Planned
When TanStack Router is wired up, the route tree will expand to include:
routes/
__root.tsx -> Layout: sidebar nav, breadcrumbs
costs/
$nodeId.tsx -> Drill into a hierarchy node
forecast.tsx -> Budget burn-down chart with projected end-of-month
resources/
$arn.tsx -> Resource detail: properties, cost history, event timeline
topology/
index.tsx -> D3 force-directed graph of resource relationships
actions/
index.tsx -> Suggestions list sorted by estimated saving
savings.tsx -> Savings dashboard
log.tsx -> Action audit log
policies/
index.tsx -> Budget rule list + rule builder form
violations.tsx -> Violations feed with severity badges
anomalies/
index.tsx -> Anomaly timeline with drill-down to delta view
changelog/
index.tsx -> Daily diff: created, terminated, cost changed
system/
index.tsx -> Collector health, account coverage, ClickHouse stats
Components
Implemented
| Component | Purpose |
|---|---|
| Layout.tsx | Responsive sidebar with Lucide icons, mobile hamburger menu, header with page title, system/light/dark theme toggle |
| CostTrendChart.tsx | Recharts AreaChart with semantic CSS variable colors |
| ResourceTable.tsx | Resource inventory table using shadcn Table + Badge |
| ui/card.tsx | Card, CardHeader, CardTitle, CardDescription, CardContent |
| ui/button.tsx | Button with variant (default/destructive/outline/ghost) and size (sm/md/lg) |
| ui/badge.tsx | Badge with variant (default/success/warning/destructive/info) |
| ui/table.tsx | Table, TableHeader, TableBody, TableHead, TableRow, TableCell |
| ui/select.tsx | Styled select wrapper |
| ui/skeleton.tsx | Animated loading placeholder |
| ui/resource-type-badge.tsx | Color-coded badge for resource types (ec2:instance, ebs:volume, etc.) |
Planned
| Component | Purpose |
|---|---|
| ResourceTimeline.tsx | Chronological event list for a resource (API + hook ready). |
| CostTreemap.tsx | Hierarchical cost breakdown. Click to drill. |
| SavingsChart.tsx | Cumulative savings over time. |
| TopologyGraph.tsx | Force-directed graph of resource relationships. |
| SuggestionCard.tsx | Action suggestion with evidence and estimated saving. |
| PreviewDialog.tsx | Dry-run modal with Confirm/Cancel. |
| ActionLogTable.tsx | Audit log with expandable before/after state. |
TanStack Query Hooks
Implemented (src/api/)
// src/api/client.ts — base query function
export async function apiQuery<T>(path: string, params?: Record<string, string>): Promise<T>
// src/api/useCosts.ts
export function useCostByCustomer(days: number) // -> /api/v1/cost/by-customer
export function useCostByAccountRole(days: number) // -> /api/v1/cost/by-account-role
// src/api/useResources.ts
export function useResources(filters) // -> /api/v1/resources
// src/api/useDelta.ts
export function useCostDelta(params) // -> /api/v1/cost/delta
export function useCostDeltaResources(params) // -> /api/v1/cost/delta/resources
export function useResourceEvents(params) // -> /api/v1/cost/delta/events
// src/api/useHierarchy.ts
export function useHierarchyTree(hierarchy) // -> /api/v1/hierarchy/tree
export function useCostTrend(nodeId, days) // -> /api/v1/cost/trend/:nodeId
Planned
useResourceDetail(arn) // -> /api/v1/resources/:arn
useActionSuggestions() // -> /api/v1/actions/suggestions
Libraries
@tanstack/react-query— Server state, caching, refetching@tanstack/react-table— Resource table with sorting/filtering/pagination@tanstack/react-router— Installed, not yet wired uprecharts— Charts (AreaChart for trends)tailwindcss— Styling (CSS variable theming with light/dark mode)lucide-react— Icons (LayoutDashboard, DollarSign, Server, TrendingUpDown, Network, etc.)clsx+tailwind-merge—cn()utility for conditional class mergingvitest+@testing-library/react— Unit testing@playwright/test— E2e testing (26 tests, 14 screenshots across dark/light themes)