Architecture
The application uses a deliberate four-layer split so product logic stays out of the page entrypoint and GitHub-specific behavior stays on the server.
3-Layer Separation Plus View Layer
Page (app/) -> View (views/) -> API Route (app/api/) -> Service (services/)| Layer | Location | Responsibility |
|---|---|---|
| Page | src/app/analyzer/page.js | Server component that only renders the view |
| View | src/views/AnalyzerView/ | Client-side state, form handling, event handlers, and rendering |
| API Route | src/app/api/analyze/route.js | Validates input, sanitizes URLs, calls the service layer, formats response |
| Service | src/services/ | Server-only GitHub API fetches, scoring, caching, orchestration |
Data Flow
User pastes URLs
-> RepoForm validates with Zod
-> AnalyzerView sends POST via Axios
-> API route sanitizes URLs
-> analyzer.service orchestrates
-> github.service fetches data with Octokit
-> scoring.service computes scores
-> cache.service stores results
-> JSON response with repos + summary + rateLimit
-> View renders tables, cards, and export actionsWhy This Split Works
- The page layer stays trivial and cache-safe.
- The view layer owns UX concerns without mixing in Octokit or scoring logic.
- The API route becomes the boundary for validation and sanitization.
- The service layer remains testable and reusable.
Main Service Responsibilities
| Service | Responsibility |
|---|---|
analyzer.service.js | Orchestrates multi-repo analysis and proactive rate-limit checks |
github.service.js | GitHub API integration via Octokit and throttling plugin |
scoring.service.js | Normalization, weighted scoring, and difficulty classification |
cache.service.js | In-memory TTL cache keyed by normalized owner/repo |
Project Structure
src/
├── app/
│ ├── globals.css
│ ├── layout.js
│ ├── page.js
│ ├── analyzer/page.js
│ └── api/analyze/route.js
├── views/
│ └── AnalyzerView/
│ ├── index.js
│ ├── RepoForm.js
│ ├── ResultsTable.js
│ ├── RepoCard.js
│ ├── SummaryCard.js
│ ├── ScoreBadge.js
│ └── LoadingState.js
├── services/
│ ├── cache.service.js
│ ├── github.service.js
│ ├── scoring.service.js
│ └── analyzer.service.js
├── lib/
│ ├── axios.js
│ ├── validators.js
│ ├── constants.js
│ └── utils.js
└── components/
├── ErrorBoundary.js
├── ThemeProvider.js
└── ui/Design Assumption
The architecture assumes the expensive and rate-limited operations stay server-side. The client only sends repository URLs and receives structured results. That keeps secrets out of the browser and avoids duplicating logic between the UI and API path.