yarn install # install dependencies
yarn dev # start dev server (netlify dev, NOT vite dev)
yarn build # production build (tsc -b && vite build)
npx tsc --noEmit # type-check without emittingsrc/
├── App.tsx # Root component: auth gate + data orchestration
├── types.ts # All shared interfaces (ClassifiedPR, ColumnId, etc.)
├── constants.ts # Repo owner/name, column metadata, intervals
├── index.css # Tailwind v4 @import + @theme tokens + animations
├── components/ # React components (Board, Column, PRCard, FilterBar, etc.)
├── hooks/
│ ├── useAuth.ts # OAuth token management
│ ├── usePullRequests.ts # Main data-fetching hook (fetches PRs, reviews, CI, merge stats)
│ ├── useSearchParams.ts # URL ↔ filter state sync via useSyncExternalStore
│ └── useTimelineEvents.ts # Lazy timeline event loading for PR popover
├── contexts/
│ └── TokenContext.tsx # Auth token React context
└── lib/
├── github.ts # Octokit factory + all GitHub API calls
├── classify.ts # PR → column classification (priority chain: approved > changes_requested > ready/ai-approved > wip)
├── mergeScore.ts # Merge likelihood score: author rate (35%), size (35%), review progress (30%) + org bonus
├── concurrency.ts # mapWithConcurrency — bounded Promise.all
├── mergeCache.ts # localStorage TTL cache for author merge stats
├── scoreColors.ts # Score → CSS color mapping
└── format.ts # Date/number formatters
netlify/functions/
└── auth-callback.ts # OAuth code→token exchange (NOT type-checked by tsc — outside src/)
- GitHub API: All calls go through
lib/github.tsusing Octokit. Bounded concurrency viamapWithConcurrency(default 10 concurrent requests). - Classification:
classify.tsis a pure function. The priority chain inclassifyColumndetermines column assignment — changes here affect the entire board. - Merge score:
mergeScore.tsis a pure function. Uses Bayesian smoothing on author merge rate. - URL-persisted filters:
useSearchParams.tssyncs filter state to URL search params usinguseSyncExternalStore, enabling shareable filtered views. - Caching:
mergeCache.tscaches author merge stats in localStorage with a 30-minute TTL to reduce API calls. - CodeRabbit detection: Identified by login name containing "coderabbitai" (case-insensitive).
- TypeScript strict mode (
strict: true,noUnusedLocals,noUnusedParameters) - Tailwind CSS v4 for all styling (utility classes,
@themeblock for custom tokens) - Default-export for React components, named-export for hooks and lib modules
- No external state management — React context + URL params + localStorage only
- Theme tokens defined in
src/index.css@themeblock (surface colors, text colors, accent, font)
src/types.ts— all shared types (start here when understanding the data model)src/constants.ts— repo config, column definitions, timing constantssrc/index.css— theme tokens and custom animations
netlify/functions/auth-callback.tsis NOT included in tsconfig (onlysrc/is) — it won't be caught bynpx tsc --noEmit- Must use
yarn dev(runsnetlify dev) notyarn vite— the OAuth flow needs the Netlify Functions proxy - Tailwind v4 uses
@import "tailwindcss"syntax, not the v3@tailwinddirectives - CodeRabbit is detected by login name, not by any API flag
yarn buildrequiresVITE_GITHUB_CLIENT_IDenv var to be set (referenced in constants.ts viaimport.meta.env)