vortex / README.md
anujjoshi3105's picture
fix: readme
7dec74c
---
title: Vortex
emoji: πŸŒ€
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 3000
pinned: false
---
# Vortex
A high-speed, vertical-slice aggregator for competitive programming metrics. Vortex unifies data from LeetCode, Codeforces, CodeChef, AtCoder, and GeeksforGeeks into a single, modular API layer. Built for modern web applications and AI agents via the **Model Context Protocol (MCP)**.
---
## Architecture
Vortex follows a **strict vertical slice architecture**. Each competitive programming platform is an isolated, self-contained plugin that flows through a consistent request pipeline.
### Vortex Flow Diagram
```mermaid
graph TD
A[HTTP Request] --> B[Fastify Router]
B --> C{Route Match}
C -->|/api/v1/leetcode| D1[LeetCode Handler]
C -->|/api/v1/codeforces| D2[Codeforces Handler]
C -->|/api/v1/codechef| D3[CodeChef Handler]
C -->|/api/v1/atcoder| D4[AtCoder Handler]
C -->|/api/v1/gfg| D5[GFG Handler]
C -->|/api/v1/ratings| D6[Aggregator Handler]
D1 --> E1[LeetCode Service]
D2 --> E2[Codeforces Service]
D3 --> E3[CodeChef Service]
D4 --> E4[AtCoder Service]
D5 --> E5[GFG Service]
D6 --> E6[Aggregator Service]
E1 --> F1[LeetCode Provider]
E2 --> F2[Codeforces Provider]
E3 --> F3[CodeChef Provider]
E4 --> F4[AtCoder Provider]
E5 --> F5[GFG Provider]
E6 --> F6[Multi-Platform Provider]
F1 --> G1[LeetCode GraphQL API]
F2 --> G2[Codeforces REST API]
F3 --> G3[CodeChef REST API]
F4 --> G4[AtCoder REST API]
F5 --> G5[GFG Scraper]
G1 --> H[Response]
G2 --> H
G3 --> H
G4 --> H
G5 --> H
H --> I[JSON Response]
style D1 fill:#e3f2fd
style D2 fill:#e3f2fd
style D3 fill:#e3f2fd
style D4 fill:#e3f2fd
style D5 fill:#e3f2fd
style D6 fill:#fff3e0
style E6 fill:#fff3e0
style F6 fill:#fff3e0
```
### Vertical Slice Philosophy
Each platform module (`src/modules/{platform}/`) is a **complete vertical slice**:
| Layer | Responsibility | Dependencies |
|-------|---------------|--------------|
| **routes.ts** | Fastify plugin registration, OpenAPI schemas, endpoint definitions | None (Entry Point) |
| **handlers.ts** | HTTP request/response handling, parameter extraction, validation | Service layer |
| **service.ts** | Business logic, data transformation, error handling | Provider layer |
| **provider.ts** | External API integration, HTTP client configuration | External APIs only |
| **types.ts** | TypeScript interfaces for domain models | None |
| **schemas.ts** | JSON Schema for request/response validation | None |
**Key Constraint:** Each layer can only depend on layers below it. No cross-module dependencies are allowed except through the aggregator service.
---
## Project Structure
```
src/
β”œβ”€β”€ app.ts # Fastify app configuration & plugin registration
β”œβ”€β”€ server.ts # HTTP server bootstrap
β”œβ”€β”€ config/
β”‚ └── env.ts # Environment variable validation
β”œβ”€β”€ shared/
β”‚ β”œβ”€β”€ middlewares/
β”‚ β”‚ └── validate.ts # Global validation middleware
β”‚ └── utils/
β”‚ β”œβ”€β”€ http-client.ts # Axios instance with timeout & retry
β”‚ └── timeout.ts # Request timeout utilities
β”œβ”€β”€ types/
β”‚ β”œβ”€β”€ api.ts # Common API response types
β”‚ └── fastify.ts # Fastify type augmentation
└── modules/
β”œβ”€β”€ leetcode/ # LeetCode vertical slice
β”œβ”€β”€ codeforces/ # Codeforces vertical slice
β”œβ”€β”€ codechef/ # CodeChef vertical slice
β”œβ”€β”€ atcoder/ # AtCoder vertical slice
β”œβ”€β”€ gfg/ # GeeksforGeeks vertical slice
β”œβ”€β”€ ratings/ # Cross-platform aggregator
└── mcp/ # Model Context Protocol server
```
---
## Installation
### Prerequisites
- **Node.js** 18+ (LTS recommended)
- **pnpm** 8+ (install via `npm i -g pnpm`)
### Setup
```bash
# Clone repository
git clone https://github.com/Anujjoshi3105/vortex.git
cd vortex
# Install dependencies
pnpm install
# Configure environment
cp .env.example .env
# Edit .env with your configuration
```
#### `.env.example`
```env
# Server Configuration
PORT=3000
HOST=0.0.0.0
NODE_ENV=development
# Security (optional)
AUTH_SECRET=your_auth_secret_here
```
### Development
```bash
# Start dev server with hot-reload
pnpm dev
```
Server starts at `http://localhost:3000`
API documentation: `http://localhost:3000/docs`
### Production Build
```bash
# Compile TypeScript
pnpm build
# Start production server
pnpm start
```
### MCP Inspector (AI Tool Testing)
```bash
# Launch MCP Inspector UI
pnpm inspect
```
Opens at `http://localhost:6274` for interactive MCP tool testing.
---
## API Reference
### Platform-Specific Endpoints
| Platform | Endpoint | Description |
|----------|----------|-------------|
| **LeetCode** | `GET /api/v1/leetcode/rating?username={user}` | User contest rating & ranking |
| | `GET /api/v1/leetcode/contest-ranking?username={user}` | Contest participation history |
| | `GET /api/v1/leetcode/daily-problem` | Today's daily challenge |
| | `GET /api/v1/leetcode/contests` | Upcoming contests |
| **Codeforces** | `GET /api/v1/codeforces/rating?username={user}` | Current rating & rank |
| | `GET /api/v1/codeforces/contest-history?username={user}` | Rating change graph |
| | `GET /api/v1/codeforces/status?username={user}&from=1&count=10` | Recent submissions |
| | `GET /api/v1/codeforces/solved-problems?username={user}` | Unique solved problems |
| **CodeChef** | `GET /api/v1/codechef/rating?username={user}` | Current rating & stars |
| **AtCoder** | `GET /api/v1/atcoder/rating?username={user}` | Current rating & color |
| **GeeksforGeeks** | `GET /api/v1/gfg/rating?username={user}` | Overall score & rank |
### Aggregator Endpoint
```http
GET /api/v1/ratings?username={user}
```
Returns unified ratings from **all platforms** in a single response:
```json
{
"username": "tourist",
"platforms": {
"leetcode": { "rating": 3200, "rank": "Knight", ... },
"codeforces": { "rating": 3821, "rank": "Legendary Grandmaster", ... },
"codechef": { "rating": 2800, "stars": "7β˜…", ... },
"atcoder": { "rating": 3817, "color": "red", ... },
"gfg": { "score": 9500, "rank": 1, ... }
}
}
```
### Health Check
```http
GET /health
```
Returns `{ "status": "ok" }` for uptime monitoring.
---
## Model Context Protocol (MCP)
Vortex exposes its functionality as **MCP tools** for AI agents (e.g., Claude Desktop, LangChain agents).
### Connecting to Claude Desktop
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"vortex-cp": {
"command": "node",
"args": [
"path/to/vortex/dist/server.js"
],
"env": {
"PORT": "3000"
}
}
}
}
```
Restart Claude Desktop.
### MCP Endpoints (HTTP/SSE)
- **SSE Transport**: `GET /mcp/sse`
- **Message Handler**: `POST /mcp/messages?sessionId={id}`
Use the MCP Inspector (`pnpm inspect`) to test tools interactively before integrating with agents.
---
## Contributors Guide
### Adding a New Platform
To maintain **vertical slice integrity**, follow this checklist when adding a new platform (e.g., HackerRank):
#### 1. Create Module Directory
```bash
mkdir -p src/modules/hackerrank
cd src/modules/hackerrank
touch index.ts routes.ts handlers.ts service.ts provider.ts types.ts schemas.ts
```
#### 2. Define Types (`types.ts`)
```typescript
export interface HackerRankRating {
username: string;
rating: number;
rank: string;
solvedCount: number;
}
```
#### 3. Implement Provider (`provider.ts`)
**Responsibility:** External API integration only. No business logic.
```typescript
import axios from 'axios';
import { HackerRankRating } from './types';
export async function fetchUserRating(username: string): Promise<HackerRankRating> {
const { data } = await axios.get(`https://api.hackerrank.com/users/${username}`);
return {
username: data.username,
rating: data.rating,
rank: data.rank,
solvedCount: data.challenges_solved
};
}
```
#### 4. Implement Service (`service.ts`)
**Responsibility:** Business logic, data transformation, error handling.
```typescript
import * as provider from './provider';
import { HackerRankRating } from './types';
export async function getUserRating(username: string): Promise<HackerRankRating> {
if (!username || username.length < 3) {
throw new Error('Invalid username');
}
const data = await provider.fetchUserRating(username);
// Apply business rules (e.g., normalize rank)
return {
...data,
rank: data.rank.toUpperCase()
};
}
```
#### 5. Implement Handlers (`handlers.ts`)
**Responsibility:** HTTP request/response handling, parameter extraction.
```typescript
import { FastifyRequest, FastifyReply } from 'fastify';
import * as service from './service';
interface RatingQuery {
username: string;
}
export async function getUserRatingHandler(
request: FastifyRequest<{ Querystring: RatingQuery }>,
reply: FastifyReply
) {
const { username } = request.query;
try {
const data = await service.getUserRating(username);
reply.send({ success: true, data });
} catch (error) {
reply.status(500).send({ success: false, error: error.message });
}
}
```
#### 6. Define Schemas (`schemas.ts`)
**Responsibility:** OpenAPI/JSON Schema for validation and documentation.
```typescript
export const ratingQuerySchema = {
type: 'object',
required: ['username'],
properties: {
username: { type: 'string', minLength: 3 }
}
};
export const ratingResponseSchema = {
type: 'object',
properties: {
success: { type: 'boolean' },
data: {
type: 'object',
properties: {
username: { type: 'string' },
rating: { type: 'number' },
rank: { type: 'string' },
solvedCount: { type: 'number' }
}
}
}
};
```
#### 7. Create Routes Plugin (`routes.ts`)
**Responsibility:** Fastify plugin registration, OpenAPI tags.
```typescript
import { FastifyPluginAsync } from 'fastify';
import * as handlers from './handlers';
import * as schemas from './schemas';
export const hackerrankPlugin: FastifyPluginAsync = async (fastify) => {
fastify.get('/rating', {
schema: {
tags: ['HackerRank'],
description: 'Get HackerRank user rating',
querystring: schemas.ratingQuerySchema,
response: { 200: schemas.ratingResponseSchema }
}
}, handlers.getUserRatingHandler);
};
export default hackerrankPlugin;
```
#### 8. Barrel Export (`index.ts`)
```typescript
export { hackerrankPlugin } from './routes';
export * from './types';
```
#### 9. Register in App (`src/app.ts`)
```typescript
import { hackerrankPlugin } from './modules/hackerrank';
// Inside buildApp()
await fastify.register(hackerrankPlugin, { prefix: '/api/v1/hackerrank' });
```
#### 10. Update OpenAPI Tags (`src/app.ts`)
```typescript
tags: [
// ... existing tags
{ name: 'HackerRank', description: 'HackerRank platform integration' }
]
```
**Result:** Your new platform is now a self-contained vertical slice with zero coupling to other modules.
---
## System Auditor Review: Future Resilience Checklist
The following improvements are recommended for production-grade deployments at scale.
### Resiliency
| Feature | Status | Priority | Effort |
|---------|--------|----------|--------|
| **Circuit Breaker** | ❌ Not Implemented | High | Medium |
| └─ Prevent cascading failures when external APIs are down | | | |
| └─ Recommended: [opossum](https://www.npmjs.com/package/opossum) | | | |
| **Retry Logic** | ⚠️ Partial (Axios defaults) | Medium | Low |
| └─ Exponential backoff for transient failures | | | |
| └─ Recommended: [axios-retry](https://www.npmjs.com/package/axios-retry) | | | |
| **Fallback Responses** | ❌ Not Implemented | Medium | Low |
| └─ Return cached/stale data when APIs are unreachable | | | |
### Performance
| Feature | Status | Priority | Effort |
|---------|--------|----------|--------|
| **Redis Caching** | ❌ Not Implemented | High | Medium |
| └─ Cache platform APIs (TTL: 5-15 minutes) | | | |
| └─ Recommended: [@fastify/redis](https://github.com/fastify/fastify-redis) | | | |
| **Response Compression** | ❌ Not Implemented | Medium | Low |
| └─ Compress JSON responses > 1KB | | | |
| └─ Recommended: [@fastify/compress](https://github.com/fastify/fastify-compress) | | | |
| **Request Timeouts** | βœ… Implemented | - | - |
| └─ Per-provider timeout configuration exists | | | |
### Security
| Feature | Status | Priority | Effort |
|---------|--------|----------|--------|
| **Rate Limiting** | ❌ Not Implemented | High | Low |
| └─ Prevent abuse (e.g., 100 req/min per IP) | | | |
| └─ Recommended: [@fastify/rate-limit](https://github.com/fastify/fastify-rate-limit) | | | |
| **API Key Middleware** | ⚠️ Partial (AUTH_SECRET unused) | Medium | Low |
| └─ Optional authentication for public deployments | | | |
| **Input Sanitization** | βœ… Implemented | - | - |
| └─ JSON Schema validation active on all endpoints | | | |
| **CORS Restrictions** | ⚠️ Too Permissive | Medium | Low |
| └─ Currently allows `origin: '*'` - restrict in production | | | |
### Observability
| Feature | Status | Priority | Effort |
|---------|--------|----------|--------|
| **Structured Logging** | ⚠️ Basic (Fastify Logger) | High | Medium |
| └─ Migrate to [Pino](https://github.com/pinojs/pino) with JSON output | | | |
| └─ Add request IDs, trace context | | | |
| **OpenTelemetry** | ❌ Not Implemented | Medium | High |
| └─ Distributed tracing for multi-provider requests | | | |
| └─ Recommended: [@opentelemetry/auto-instrumentations-node](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) | | | |
| **Metrics Endpoint** | ❌ Not Implemented | Medium | Medium |
| └─ Expose Prometheus metrics (`/metrics`) | | | |
| └─ Track: request latency, error rates, cache hit rates | | | |
### Implementation Roadmap
**Phase 1: Resiliency** (Sprint 1-2)
1. Add circuit breaker pattern to all providers
2. Implement Redis caching layer
3. Add rate limiting middleware
**Phase 2: Security** (Sprint 3)
1. Restrict CORS to whitelisted origins
2. Implement API key authentication (optional)
3. Add request/response sanitization audit
**Phase 3: Observability** (Sprint 4-5)
1. Migrate to Pino structured logging
2. Add OpenTelemetry instrumentation
3. Create Prometheus metrics endpoint
4. Build Grafana dashboards
---
## Testing
### Manual Testing
```bash
# Test single platform
curl "http://localhost:3000/api/v1/leetcode/rating?username=tourist"
# Test aggregator
curl "http://localhost:3000/api/v1/ratings?username=tourist"
```
### MCP Tool Testing
```bash
# Launch MCP Inspector
pnpm inspect
# Test in MCP Inspector UI at http://localhost:6274
# Select tool: get_leetcode_user_rating
# Input: { "username": "tourist" }
```
---
## Technology Stack
| Category | Package | Purpose |
|----------|---------|---------|
| **Runtime** | Node.js 18+ | JavaScript runtime |
| **Framework** | Fastify 5.x | High-performance HTTP server |
| **Language** | TypeScript 5.x | Type-safe development |
| **HTTP Client** | Axios 1.x | External API requests |
| **Validation** | Zod 4.x | Runtime type validation |
| **Scraping** | Cheerio 1.x | HTML parsing (GFG) |
| **Documentation** | @fastify/swagger | OpenAPI generation |
| **AI Protocol** | @modelcontextprotocol/sdk | MCP server implementation |
| **Package Manager** | pnpm 8+ | Fast, disk-efficient installs |
---
## Contributing
### Guidelines
1. **Maintain Vertical Slices**: New features must follow the handler β†’ service β†’ provider pattern.
2. **Type Everything**: All functions must have explicit TypeScript types.
3. **Schema Validation**: Add JSON Schema for all new endpoints.
4. **No Cross-Module Imports**: Modules cannot import from other platform modules (use the aggregator pattern).
5. **Update OpenAPI**: Add tags and descriptions for all new routes.
### Pull Request Checklist
- [ ] New vertical slice follows project structure
- [ ] TypeScript types defined in `types.ts`
- [ ] JSON Schema validation in `schemas.ts`
- [ ] OpenAPI documentation updated
- [ ] No cross-module dependencies
- [ ] Tested via Swagger UI and MCP Inspector
---
## License
**ISC** - See [LICENSE](LICENSE) for details.
---
## Project Status
**Current Version:** 1.0.0
**Deployment:** Development (not production-ready - see Auditor Review)
**Maintained By:** [@Anujjoshi3105](https://github.com/Anujjoshi3105)
For issues or feature requests, open a GitHub issue at [Anujjoshi3105/vortex](https://github.com/Anujjoshi3105/vortex).