|
| 1 | +--- |
| 2 | +title: Next.js + Tailwind/shadcn Migration |
| 3 | +status: active |
| 4 | +created: 2026-02-18 |
| 5 | +estimate: 6h |
| 6 | +tier: standard |
| 7 | +--- |
| 8 | + |
| 9 | +# Next.js + Tailwind/shadcn Migration |
| 10 | + |
| 11 | +## Context |
| 12 | + |
| 13 | +Migrate codebase-visualizer from Express+vanilla HTML to Next.js App Router with Tailwind CSS and shadcn/ui. Full rewrite of the 3D rendering layer (3d-force-graph CDN → react-force-graph-3d npm), Express API routes → Next.js Route Handlers, MCP tools → Next.js API integration. Pipeline code (parser/graph/analyzer) stays untouched. |
| 14 | + |
| 15 | +## Codebase Impact (MANDATORY) |
| 16 | + |
| 17 | +| Area | Impact | Detail | |
| 18 | +|------|--------|--------| |
| 19 | +| `package.json` | MODIFY | Add next, react, react-dom, tailwindcss, shadcn deps; remove express, open; add react-force-graph-3d | |
| 20 | +| `tsconfig.json` | MODIFY | Merge with Next.js defaults (jsx: preserve, next plugin) | |
| 21 | +| `eslint.config.js` | MODIFY | Add next/core-web-vitals, react-hooks rules | |
| 22 | +| `app/` | CREATE | Next.js App Router: layout, page, API routes | |
| 23 | +| `app/api/graph/route.ts` | CREATE | Replace Express GET /api/graph | |
| 24 | +| `app/api/file/[...path]/route.ts` | CREATE | Replace Express GET /api/file/* | |
| 25 | +| `app/api/modules/route.ts` | CREATE | Replace Express GET /api/modules | |
| 26 | +| `app/api/hotspots/route.ts` | CREATE | Replace Express GET /api/hotspots | |
| 27 | +| `app/api/forces/route.ts` | CREATE | Replace Express GET /api/forces | |
| 28 | +| `app/api/meta/route.ts` | CREATE | Replace Express GET /api/meta | |
| 29 | +| `app/api/ping/route.ts` | CREATE | Replace Express GET /api/ping | |
| 30 | +| `app/api/mcp/route.ts` | CREATE | MCP tool invocation via HTTP | |
| 31 | +| `components/` | CREATE | ~12 React components decomposed from index.html | |
| 32 | +| `components/graph-canvas.tsx` | CREATE | react-force-graph-3d wrapper with imperative API | |
| 33 | +| `components/view-tabs.tsx` | CREATE | 8 view tabs | |
| 34 | +| `components/project-bar.tsx` | CREATE | Title + stats panel | |
| 35 | +| `components/detail-panel.tsx` | CREATE | Right-side file detail drawer | |
| 36 | +| `components/settings-panel.tsx` | CREATE | Config sliders (shadcn Slider, Checkbox) | |
| 37 | +| `components/search-input.tsx` | CREATE | Graph search with camera fly | |
| 38 | +| `components/legend.tsx` | CREATE | Per-view color legend | |
| 39 | +| `components/debug-log.tsx` | CREATE | Collapsible debug overlay | |
| 40 | +| `hooks/use-graph-data.ts` | CREATE | SWR/fetch hook for graph + forces + meta | |
| 41 | +| `hooks/use-graph-config.ts` | CREATE | Graph config state (replaces cfg object) | |
| 42 | +| `hooks/use-module-clouds.ts` | CREATE | THREE.js module cloud management | |
| 43 | +| `lib/graph-store.ts` | CREATE | Server-side CodebaseGraph singleton for Route Handlers | |
| 44 | +| `lib/views.ts` | CREATE | 8 view derivation functions (pure: nodes+config → colors/sizes) | |
| 45 | +| `tailwind.config.ts` | CREATE | Tailwind config | |
| 46 | +| `components.json` | CREATE | shadcn config | |
| 47 | +| `app/globals.css` | CREATE | Tailwind base + custom vars | |
| 48 | +| `src/server/index.ts` | DELETE | Express server replaced by Next.js | |
| 49 | +| `src/server/api.ts` | DELETE | Routes moved to app/api/ | |
| 50 | +| `src/server/api.test.ts` | MODIFY | Rewrite for Next.js Route Handler testing | |
| 51 | +| `src/cli.ts` | MODIFY | Web mode: launch Next.js dev/start instead of Express | |
| 52 | +| `public/index.html` | DELETE | Replaced by React components | |
| 53 | +| `src/parser/index.ts` | UNAFFECTED | Pipeline code stays | |
| 54 | +| `src/graph/index.ts` | UNAFFECTED | Pipeline code stays | |
| 55 | +| `src/analyzer/index.ts` | UNAFFECTED | Pipeline code stays | |
| 56 | +| `src/mcp/index.ts` | AFFECTED | Keep stdio mode; add HTTP adapter for Next.js API | |
| 57 | +| `vitest.config.ts` | MODIFY | Add jsdom environment for React component tests | |
| 58 | + |
| 59 | +**Files:** ~20 create | ~6 modify | ~3 delete | ~4 unaffected |
| 60 | +**Reuse:** All pipeline code (parser, graph, analyzer) reused as-is. View logic from index.html translates to pure functions in `lib/views.ts`. API route logic from `api.ts` directly portable. |
| 61 | +**Breaking changes:** CLI `--server` mode behavior changes (launches Next.js instead of Express). Package no longer works as pure Express server. |
| 62 | +**New dependencies:** next, react, react-dom, @types/react, @types/react-dom, tailwindcss, @tailwindcss/postcss, react-force-graph-3d (React wrapper for 3d-force-graph), three (peer dep), swr (data fetching). shadcn components installed via CLI. |
| 63 | + |
| 64 | +## User Journey (MANDATORY) |
| 65 | + |
| 66 | +### Primary Journey |
| 67 | + |
| 68 | +ACTOR: Developer analyzing a TypeScript codebase |
| 69 | +GOAL: Visualize codebase structure in an interactive 3D graph with modern UI |
| 70 | +PRECONDITION: TypeScript project exists, codebase-visualizer installed |
| 71 | + |
| 72 | +1. User runs `codebase-visualizer ./src` |
| 73 | + -> System parses codebase, builds graph, starts Next.js server |
| 74 | + -> User sees "Server ready at http://localhost:3333" + browser opens |
| 75 | + |
| 76 | +2. User sees modern UI: project bar (title + stats), 8 view tabs, 3D graph canvas |
| 77 | + -> System renders Galaxy view by default with Tailwind-styled panels |
| 78 | + -> User sees shadcn-styled settings panel with config sliders |
| 79 | + |
| 80 | +3. User clicks view tabs (Galaxy, DepFlow, Hotspot, Focus, Module, Forces, Churn, Coverage) |
| 81 | + -> System re-renders graph with view-specific colors/sizes/layout |
| 82 | + -> User sees view legend update, graph transitions |
| 83 | + |
| 84 | +4. User clicks a node in the graph |
| 85 | + -> System shows detail panel (shadcn Sheet) with all metrics |
| 86 | + -> User sees file path, all metrics, imports, dependents, focus button |
| 87 | + |
| 88 | +5. User searches for a file |
| 89 | + -> System flies camera to matching node |
| 90 | + -> User sees the node highlighted |
| 91 | + |
| 92 | +6. User adjusts settings (opacity, size, repulsion, etc.) |
| 93 | + -> System live-updates graph rendering |
| 94 | + -> User sees immediate visual feedback |
| 95 | + |
| 96 | +7. User runs `codebase-visualizer ./src --mcp` |
| 97 | + -> System starts MCP stdio server (unchanged behavior) |
| 98 | + -> LLM tools work as before |
| 99 | + |
| 100 | +POSTCONDITION: Full 3D visualization with modern UI, all 8 views working, MCP mode operational |
| 101 | + |
| 102 | +### Error Journeys |
| 103 | + |
| 104 | +E1. Next.js server port conflict |
| 105 | + Trigger: Port 3333 already in use |
| 106 | + 1. System detects port conflict |
| 107 | + -> System tries ports 3334-3337 |
| 108 | + -> User sees "Server ready at http://localhost:{available_port}" |
| 109 | + Recovery: Server starts on next available port |
| 110 | + |
| 111 | +E2. No TypeScript files found |
| 112 | + Trigger: Target directory has no .ts files |
| 113 | + 1. System completes parsing with 0 files |
| 114 | + -> System shows empty graph with message "No TypeScript files found" |
| 115 | + Recovery: User can re-run with correct path |
| 116 | + |
| 117 | +E3. Graph data fetch failure |
| 118 | + Trigger: API route returns error |
| 119 | + 1. Client fetch fails |
| 120 | + -> System retries with exponential backoff (3 retries) |
| 121 | + -> User sees loading state during retries |
| 122 | + 2. After 3 failures |
| 123 | + -> User sees error message with retry button |
| 124 | + Recovery: User clicks retry or refreshes page |
| 125 | + |
| 126 | +### Edge Cases |
| 127 | + |
| 128 | +EC1. Very large codebase (1000+ files): Graph renders but may be slow; settings panel allows reducing visual complexity |
| 129 | +EC2. Circular dependencies: Highlighted in DepFlow view, graph still renders |
| 130 | +EC3. No git history: Churn metrics show 0, churn view still renders with uniform sizing |
| 131 | + |
| 132 | +## Acceptance Criteria (MANDATORY) |
| 133 | + |
| 134 | +### Must Have (BLOCKING) |
| 135 | + |
| 136 | +- [ ] AC-1: GIVEN a TS project WHEN user runs `codebase-visualizer ./src` THEN Next.js server starts and browser opens with 3D graph |
| 137 | +- [ ] AC-2: GIVEN the app is loaded WHEN user clicks each of the 8 view tabs THEN graph re-renders with correct view-specific styling (colors, sizes, layout) |
| 138 | +- [ ] AC-3: GIVEN a graph is rendered WHEN user clicks a node THEN shadcn-styled detail panel shows with all file metrics |
| 139 | +- [ ] AC-4: GIVEN the settings panel WHEN user adjusts any slider/checkbox THEN graph updates in real-time |
| 140 | +- [ ] AC-5: GIVEN the search input WHEN user types a filename THEN camera flies to matching node |
| 141 | +- [ ] AC-6: GIVEN the app WHEN loaded THEN project bar shows title + all 9 stats (files, functions, deps, circular, coverage, dead exports, avg complexity, tension, bridges) |
| 142 | +- [ ] AC-7: GIVEN each view WHEN rendered THEN correct color legend displays |
| 143 | +- [ ] AC-8: GIVEN the app WHEN running THEN all API routes return same data as current Express routes |
| 144 | +- [ ] AC-9: GIVEN `--mcp` flag WHEN user runs CLI THEN MCP stdio server starts with all 7 tools working |
| 145 | +- [ ] AC-10: GIVEN the app WHEN running THEN MCP tools are accessible via HTTP API route |
| 146 | + |
| 147 | +### Error Criteria (BLOCKING) |
| 148 | + |
| 149 | +- [ ] AC-E1: GIVEN port conflict WHEN server starts THEN auto-finds next available port (3333-3337) |
| 150 | +- [ ] AC-E2: GIVEN API fetch failure WHEN client loads THEN shows retry with exponential backoff |
| 151 | +- [ ] AC-E3: GIVEN empty codebase WHEN parsed THEN shows empty graph with informative message |
| 152 | + |
| 153 | +### Should Have |
| 154 | + |
| 155 | +- [ ] AC-11: GIVEN the UI WHEN viewed THEN all panels use Tailwind CSS classes (no inline styles) |
| 156 | +- [ ] AC-12: GIVEN the UI WHEN viewed THEN interactive elements use shadcn components (Button, Slider, Sheet, Input) |
| 157 | +- [ ] AC-13: GIVEN dev mode WHEN files change THEN Next.js hot-reloads (tsx watch replaced by next dev) |
| 158 | + |
| 159 | +## Scope |
| 160 | + |
| 161 | +- [x] 1. Initialize Next.js + Tailwind + shadcn in project -> AC-11, AC-12 |
| 162 | +- [x] 2. Create graph singleton + API Route Handlers (7 routes) -> AC-8 |
| 163 | +- [x] 3. Create MCP HTTP API route -> AC-10 |
| 164 | +- [x] 4. Create GraphCanvas component (react-force-graph-3d wrapper) -> AC-1, AC-2 |
| 165 | +- [x] 5. Create 8 view derivation functions (pure: data+config -> visual props) -> AC-2 |
| 166 | +- [x] 6. Create ViewTabs + Legend components -> AC-2, AC-7 |
| 167 | +- [x] 7. Create ProjectBar component (title + 9 stats) -> AC-6 |
| 168 | +- [x] 8. Create DetailPanel component (shadcn Sheet) -> AC-3 |
| 169 | +- [x] 9. Create SettingsPanel component (shadcn sliders/checkbox) -> AC-4 |
| 170 | +- [x] 10. Create SearchInput component with camera fly -> AC-5 |
| 171 | +- [x] 11. Create module clouds hook (THREE.js imperative) -> AC-2 |
| 172 | +- [x] 12. Create data fetching hooks (SWR) -> AC-E2 |
| 173 | +- [x] 13. Wire main page layout (app/page.tsx) -> AC-1, AC-6 |
| 174 | +- [x] 14. Update CLI to launch Next.js server -> AC-1, AC-E1 |
| 175 | +- [x] 15. Update MCP to keep stdio mode working -> AC-9 |
| 176 | +- [x] 16. Migrate API tests to Next.js Route Handler tests -> AC-8 |
| 177 | +- [ ] 17. Add React component tests -> AC-2, AC-3, AC-4 |
| 178 | +- [x] 18. Delete Express server code + public/index.html -> AC-1 |
| 179 | + |
| 180 | +### Out of Scope |
| 181 | + |
| 182 | +- SSR/SSG for the 3D graph (WebGL is client-only by nature) |
| 183 | +- Authentication/multi-user (stays single-user local tool) |
| 184 | +- Database/persistence (stays in-memory graph) |
| 185 | +- React Native/mobile |
| 186 | +- Deployment to Vercel/cloud (stays local CLI tool) |
| 187 | +- Dark/light theme toggle (keep current dark theme) |
| 188 | + |
| 189 | +## Quality Checklist |
| 190 | + |
| 191 | +### Blocking |
| 192 | + |
| 193 | +- [ ] All Must Have ACs passing |
| 194 | +- [ ] All Error Criteria ACs passing |
| 195 | +- [ ] All 8 views render correctly with proper colors/sizes |
| 196 | +- [ ] No regressions in pipeline tests (parser, graph, analyzer) |
| 197 | +- [ ] API routes return identical data to current Express routes |
| 198 | +- [ ] MCP stdio mode works unchanged |
| 199 | +- [ ] No hardcoded secrets or credentials |
| 200 | +- [ ] No innerHTML usage (React handles this; verify no dangerouslySetInnerHTML) |
| 201 | +- [ ] Build succeeds (`next build`) |
| 202 | +- [ ] TypeScript strict mode passes |
| 203 | +- [ ] ESLint passes |
| 204 | + |
| 205 | +### Advisory |
| 206 | + |
| 207 | +- [ ] All Should Have ACs passing |
| 208 | +- [ ] shadcn components used for all interactive elements |
| 209 | +- [ ] Consistent Tailwind class patterns (no mixed styling approaches) |
| 210 | +- [ ] Bundle size reasonable (< 500KB initial JS) |
| 211 | +- [ ] 3D graph performance comparable to vanilla version |
| 212 | + |
| 213 | +## Risks |
| 214 | + |
| 215 | +| Risk | Impact | Likelihood | Mitigation | |
| 216 | +|------|--------|------------|------------| |
| 217 | +| react-force-graph-3d missing features vs vanilla 3d-force-graph | HIGH | MED | Test imperative API access early (scope item 4); fallback to vanilla wrapper if React wrapper insufficient | |
| 218 | +| Graph singleton state in Next.js Route Handlers | MED | LOW | Module-level singleton works for single-process `next start`; tested in scope item 2 | |
| 219 | +| THREE.js module clouds conflict with React lifecycle | MED | MED | Isolate in custom hook with cleanup; use refs not state for THREE.js objects | |
| 220 | +| Performance regression from React overhead on 3D canvas | MED | LOW | React only wraps the canvas; 3d-force-graph manages its own render loop | |
| 221 | +| Large migration scope exceeds estimate | HIGH | MED | Scope items ordered by dependency; ship incrementally (API first, then components) | |
| 222 | + |
| 223 | +**Kill criteria:** If react-force-graph-3d cannot expose imperative API (scene(), d3Force(), graphData()) → abort React wrapper approach, use vanilla 3d-force-graph in a React ref instead. |
| 224 | + |
| 225 | +## State Machine |
| 226 | + |
| 227 | +**Status**: N/A — Stateless feature |
| 228 | + |
| 229 | +**Rationale**: The migration changes implementation but not state behavior. The app remains: load data -> render graph -> respond to user interactions. No new stateful flows introduced. View switching, settings, and detail panel are React state transitions managed by React's built-in state system. |
| 230 | + |
| 231 | +## Analysis |
| 232 | + |
| 233 | +### Assumptions Challenged |
| 234 | + |
| 235 | +| Assumption | Evidence For | Evidence Against | Verdict | |
| 236 | +|------------|-------------|-----------------|---------| |
| 237 | +| react-force-graph-3d exposes same imperative API as vanilla | It's the official React wrapper from the same author; docs show ref-based API access | Some advanced features (scene(), custom THREE.js objects) may need workarounds | RISKY | |
| 238 | +| Module-level singleton works for graph data in Next.js | Works in single-process `next start`; common pattern for in-memory caches | Next.js dev mode may restart modules; serverless deployments would break (but we're local-only) | VALID | |
| 239 | +| shadcn components work well with 3D canvas overlay | shadcn uses Radix primitives with z-index management | 3D canvas may capture pointer events, interfering with UI overlays | RISKY | |
| 240 | +| SWR is the right data-fetching choice | Built-in caching, revalidation, error retry; widely used with Next.js | Data is static after initial load (parsed once) — SWR's revalidation is overkill; simple fetch + useState may suffice | VALID | |
| 241 | +| CLI can launch Next.js dev server programmatically | `next dev` is a CLI command; can spawn as child process | Programmatic API for Next.js server is not well-documented; may need child_process.spawn | RISKY | |
| 242 | + |
| 243 | +### Blind Spots |
| 244 | + |
| 245 | +1. **[Integration]** How react-force-graph-3d handles the module clouds (custom THREE.js objects added to scene) |
| 246 | + Why it matters: Module clouds are a key visual feature. If the React wrapper isolates the THREE.js scene, adding custom meshes/sprites may break. |
| 247 | + |
| 248 | +2. **[DX]** Dev mode experience: `tsx watch` is instant; `next dev` has cold start + HMR overhead |
| 249 | + Why it matters: Current dev experience is fast; Next.js dev mode may feel slower for a tool that's primarily a CLI utility. |
| 250 | + |
| 251 | +3. **[Ops]** Package size increase: Next.js + React + Tailwind adds significant node_modules bloat to what's currently a lean CLI tool |
| 252 | + Why it matters: This is an npm package installed globally; users may not want 200MB+ of Next.js deps for a visualization tool. |
| 253 | + |
| 254 | +### Failure Hypotheses |
| 255 | + |
| 256 | +| IF | THEN | BECAUSE | Severity | Mitigation | |
| 257 | +|----|------|---------|----------|------------| |
| 258 | +| react-force-graph-3d doesn't expose .scene() | Module clouds feature breaks | React wrapper may abstract away THREE.js scene access | HIGH | Test in scope item 4; fallback: use vanilla 3d-force-graph with useRef | |
| 259 | +| Next.js dev server is slow to start (>5s) | Poor DX for CLI tool users who expect instant startup | Next.js compilation overhead | MED | Use `next start` (pre-built) for production; accept dev mode overhead | |
| 260 | +| Pointer events conflict between shadcn overlays and WebGL canvas | UI panels unclickable when overlapping canvas | WebGL canvas may capture all pointer events | MED | Use pointer-events-none on canvas container; explicit pointer-events-auto on panels | |
| 261 | + |
| 262 | +### The Real Question |
| 263 | + |
| 264 | +Confirmed — spec solves the right problem. The current vanilla HTML approach works but doesn't scale for UI complexity (settings, multiple panels, component reuse). Next.js + React provides proper component architecture. The risk is scope: this is a full rewrite of the client layer with server restructuring. |
| 265 | + |
| 266 | +**Recommendation:** Proceed, but validate react-force-graph-3d imperative API access first (scope item 4 is the highest-risk item). |
| 267 | + |
| 268 | +### Open Items |
| 269 | + |
| 270 | +- [risk] react-force-graph-3d scene access for module clouds -> explore (spike before full implementation) |
| 271 | +- [question] Should CLI `codebase-visualizer ./src` run `next dev` or `next start` (pre-built)? -> question |
| 272 | +- [improvement] Consider keeping Express as fallback for environments where Next.js is too heavy -> no action (out of scope) |
| 273 | + |
| 274 | +## Notes |
| 275 | + |
| 276 | +## Progress |
| 277 | + |
| 278 | +| # | Scope Item | Status | Iteration | |
| 279 | +|---|-----------|--------|-----------| |
| 280 | +| 1 | Init Next.js + Tailwind + shadcn | pending | - | |
| 281 | +| 2 | Graph singleton + API routes | pending | - | |
| 282 | +| 3 | MCP HTTP API route | pending | - | |
| 283 | +| 4 | GraphCanvas component | pending | - | |
| 284 | +| 5 | View derivation functions | pending | - | |
| 285 | +| 6 | ViewTabs + Legend | pending | - | |
| 286 | +| 7 | ProjectBar | pending | - | |
| 287 | +| 8 | DetailPanel | pending | - | |
| 288 | +| 9 | SettingsPanel | pending | - | |
| 289 | +| 10 | SearchInput | pending | - | |
| 290 | +| 11 | Module clouds hook | pending | - | |
| 291 | +| 12 | Data fetching hooks | pending | - | |
| 292 | +| 13 | Main page layout | pending | - | |
| 293 | +| 14 | Update CLI for Next.js | pending | - | |
| 294 | +| 15 | MCP stdio mode | pending | - | |
| 295 | +| 16 | Migrate API tests | pending | - | |
| 296 | +| 17 | React component tests | pending | - | |
| 297 | +| 18 | Delete Express + HTML | pending | - | |
| 298 | + |
| 299 | +## Timeline |
| 300 | + |
| 301 | +| Action | Timestamp | Duration | Notes | |
| 302 | +|--------|-----------|----------|-------| |
| 303 | +| plan | 2026-02-18T00:00:00Z | - | Created | |
0 commit comments