Component Architecture

Top-Level Structure

src/
  main.jsx              # App entry, React Query provider
  App.jsx               # Router setup, protected route wrapper
  api/
    client.js           # Axios instance, token interceptor, refresh logic
    auth.js
    repos.js
    metrics.js
  hooks/
    useAuth.js          # Auth state, login/logout
    useRepos.js         # React Query wrappers
    useMetrics.js
  components/
    ui/                 # Primitives: Button, Card, Badge, Spinner
    charts/
      CommitHeatmap.jsx     # D3 calendar heatmap (hand-rolled)
      CycleTimeChart.jsx    # Recharts LineChart
      TurnaroundBar.jsx     # Recharts BarChart
    layout/
      AppShell.jsx          # Sidebar + topbar layout
      Sidebar.jsx
      Topbar.jsx
  pages/
    Login.jsx               # OAuth entry point
    Dashboard.jsx           # Summary metrics, all repos
    RepoDetail.jsx          # Single repo deep-dive
    RepoSettings.jsx        # Add/remove repos
    Compare.jsx             # Period comparison view
  utils/
    dates.js                # Date range helpers
    formatters.js           # Hours → "2d 4h" etc

Component Responsibilities

AppShell — layout wrapper, renders sidebar nav and outlet. Handles responsive collapse.

Dashboard — fetches /api/metrics/summary, renders top-level KPI cards (total commits, avg cycle time, avg review turnaround), renders CommitHeatmap for last 52 weeks.

RepoDetail — fetches /api/metrics/cycle-time and /api/metrics/commits filtered by repoId. Renders CycleTimeChart (line over time) and TurnaroundBar (per-reviewer breakdown).

Compare — two DateRangePicker inputs, fetches /api/metrics/compare, renders side-by-side stat cards with delta indicators (↑ / ↓).

CommitHeatmap — hand-rolled D3 SVG calendar grid. This is your portfolio centerpiece — do not use a library for this. 52 columns × 7 rows, color-scaled by commit count.

api/client.js — Axios instance with a request interceptor that attaches the JWT from memory (not localStorage), and a response interceptor that catches 401s and hits /api/auth/refresh before retrying.