Anurag.dev is a bleeding-edge, full-stack personal brand platform. It transcends traditional static portfolios by integrating a fully autonomous LangChain LLM Agent that serves as a 24/7 personal assistant for visitors. Built on an Express REST API backend with PostgreSQL + Prisma and a highly animated Next.js frontend, this project demonstrates scalability, resilience, and advanced AI integration.
Anurag.dev relies on a strictly decoupled architecture, meaning the frontend, backend, database, and AI inference engines can all crash, restart, and scale independently without tearing each other down.
flowchart TB
subgraph Frontend [Next.js Client Domain]
subgraph UI [React Layout & Logic]
Port["Portfolio Views"]
AgentW["Agent Widget Floating UI"]
Admin["Admin Dashboard"]
end
subgraph Hooks [State & API Hooks]
SessionHook["useAgentSession.ts"]
Api["Custom API Client"]
end
CircuitBreaker{"Offline Circuit Breaker"}
end
subgraph Backend [Node.js / Express API Domain]
Router["Express Router /api/v1/"]
StandardBusiness["Standard CRUD Services"]
subgraph LangChain_Agent [Enterprise LangChain Engine]
AgentLoop["Manual ReAct Loop"]
Memory["Persistent Session Memory"]
Logger["Structured Agent Logger"]
subgraph Models [Dual-LLM with Sticky Fallback]
HF["Primary: Qwen 2.5 72B"]
Gemini["Fallback: Gemini 2.5 Flash"]
end
subgraph MCP_Tools [Model Context Protocols]
GitHubTool["GitHub Activity + README"]
LeetCodeTool["LeetCode Stats"]
PortfolioTool["Portfolio Project Search"]
ContactTool["Direct DB Lead Insertion"]
end
end
end
subgraph Persistence [Data Layer]
Postgres[("PostgreSQL Database")]
Redis[("Redis Cache")]
end
%% Connections
Port <--> Api
AgentW <--> SessionHook
SessionHook <--> Api
Api <--> CircuitBreaker
CircuitBreaker <--> Router
Router <--> StandardBusiness
Router <--> AgentLoop
StandardBusiness <--> Postgres
StandardBusiness <--> Redis
AgentLoop <--> Memory
AgentLoop --> Logger
AgentLoop --> HF
HF -.-> |Primary fails| Gemini
AgentLoop <--> MCP_Tools
MCP_Tools <--> Postgres
MCP_Tools -.-> |External APIs| GitHubTool
Instead of basic chatbot text-in/text-out completions, the Anurag.dev agent operates using the Model Context Protocol (MCP) and a manual ReAct (Reasoning and Acting) loop with enterprise-grade failover.
SystemPersona prompt alongside screen-awareness context (currentUrl).search_projects("React") and get_leetcode_stats().The system operates on a dual-engine core (src/modules/agent/core/llm.factory.ts):
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā LLM Invocation Flow ā
ā ā
ā Request Loop 1: ā
ā āāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā HuggingFace āāāāāāŗā Success? ā Continue ā ā
ā ā (Primary) ā ā Fail? ā Set STICKY ā ā
ā āāāāāāāāāāāāāāā ā flag, try Gemini ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā
ā Request Loops 2-4: ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā STICKY flag set? ā Skip Primary entirely ā ā
ā ā Go directly to Gemini (no timeout wait) ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Key design decisions:
Promise.race() timeout to prevent SDK-level internal retry hangs (Google's SDK retries internally for ~3 minutes by default).| Tool | Description | External API |
|---|---|---|
get_github_activity | Fetches GitHub profile stats and recent 5 events | api.github.com |
read_github_readme | Reads raw README.md from any public repository | api.github.com |
get_leetcode_stats | Fetches LeetCode solving stats and ranking | alfa-leetcode-api.onrender.com |
search_projects | Searches published portfolio projects by keyword | PostgreSQL (Prisma) |
submit_contact_lead | Inserts a contact lead directly into the database | PostgreSQL (Prisma) |
The Agent can trigger client-side routing via [NAVIGATE:/path] tokens embedded in its response. The frontend's useAgentSession hook intercepts these tokens, executes router.push(), and strips the command from the visible message ā so the user sees a seamless page transition.
The Agent pipeline includes a centralized logging system (agent.logger.ts) that provides full visibility into every layer:
[2026-03-26 01:58:22] [INFO] [Agent:SYSTEM] āāā New Request āāā
{"sessionId":"abc","llmMode":"dual","primary":"HuggingFace","fallback":"Gemini"}
[2026-03-26 01:58:23] [INFO] [Agent:LLM] š§ Invoking HuggingFace (Qwen2.5-72B-Instruct)
[2026-03-26 01:58:27] [INFO] [Agent:LLM] ā
LLM responded {"durationMs":4600,"hasToolCalls":true}
[2026-03-26 01:58:27] [INFO] [Agent:TOOL] ā” Executing: get_github_activity
[2026-03-26 01:58:28] [INFO] [Agent:TOOL] ā
get_github_activity completed {"durationMs":875}
[2026-03-26 01:58:52] [INFO] [Agent:SYSTEM] āāā Request Complete āāā
{"usedProvider":"HuggingFace","totalDurationMs":30200,"llmLoops":2}
Log Categories: SYSTEM, LLM, TOOL, MEMORY, CTRL
Log Levels: INFO, WARN, ERROR, DEBUG (DEBUG only in development)
Anurag.dev implements a zero-crash error handling philosophy. The AI Agent is designed to never return an HTTP 500 to the frontend.
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Tool Execution Error (e.g., GitHub API down) ā
ā ā Caught inside tool ā Returns error string ā
ā ā LLM reads error ā Generates human-friendly msg ā
ā ā User sees: "I can't fetch GitHub right now..." ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā LLM Invocation Error (e.g., API rate limit) ā
ā ā Primary fails ā Sticky flag set ā
ā ā Fallback LLM invoked ā Success ā
ā ā User doesn't notice anything ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Both LLMs Fail (catastrophic) ā
ā ā Controller catches ā Returns HTTP 200 ā
ā ā reply: "I ran into a hiccup..." ā
ā ā Error category logged: RATE_LIMIT / TIMEOUT / ā
ā NETWORK / INTERNAL ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
| Layer | Strategy |
|---|---|
useAgentSession hook | All API errors caught ā displayed as a chat bubble. Error never propagates to React tree. |
ApiClientError handling | Reads .message directly (not Axios-style .response.data). Fallback message for network errors. |
Global error.tsx boundary | Styled terminal-themed error page with stack trace toggle (dev only) and recovery button. Only triggers for non-Agent rendering crashes. |
| Circuit Breaker | After 3 consecutive API failures, portfolio falls back to static JSON. Background health checks resume live API after recovery. |
To guarantee 100% uptime regardless of backend maintenance windows, the frontend wraps API calls in a Circuit Breaker state machine:
client/src/api/fallback/) containing last-known-good data.health route every 60 seconds. Once healthy, the breaker closes and live API requests resume.The visitor never sees a white error screen.
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, Tailwind CSS v4, Framer Motion |
| Backend | Express, TypeScript, Prisma ORM, Zod validation |
| Database | PostgreSQL 14+ |
| Cache | Redis 6+ |
| AI Primary | HuggingFace Inference API (Qwen 2.5 72B-Instruct) via @langchain/openai |
| AI Fallback | Google Gemini 2.5 Flash via @langchain/google-genai |
| Auth | JWT (access + refresh tokens), bcrypt, account lockout |
| Media | Cloudinary (image/file uploads via Multer) |
| Observability | Custom structured logger with timestamped categories |
server/.env)| Variable | Required | Description |
|---|---|---|
NODE_ENV | ā | development or production |
PORT | ā | Backend port (default: 4000) |
DATABASE_URL | ā | PostgreSQL connection string |
REDIS_HOST / REDIS_PORT | ā | Redis instance for route caching |
JWT_SECRET | ā | 64-char symmetric key for access tokens |
JWT_REFRESH_SECRET | ā | Symmetric key for refresh tokens |
CLOUDINARY_CLOUD_NAME | ā | Cloudinary cloud name |
CLOUDINARY_API_KEY | ā | Cloudinary API key |
CLOUDINARY_API_SECRET | ā | Cloudinary API secret |
HF_TOKEN | ā | HuggingFace access token (primary LLM) |
GEMINI_API_KEY | ā | Google Gemini API key (fallback LLM) |
AI_PROVIDER | ā | Force-select provider (legacy, defaults to gemini) |
GITHUB_TOKEN | ā | GitHub PAT for elevated API rate limits |
client/.env.local)| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_API_URL | ā | Backend URL (e.g., http://localhost:4000) |
NEXT_PUBLIC_API_TIMEOUT_MS | ā | API timeout in ms (default 5000; mobile uses a higher floor) |
For production deployments, set NEXT_PUBLIC_API_URL to a publicly reachable HTTPS backend URL (not localhost).
# 1. Backend
cd server
npm install
cp .env.example .env # Fill in all variables
npm run db:generate # Generate Prisma types
npm run db:migrate # Push schema to PostgreSQL
npm run db:seed # Seed initial data + admin account
npm run dev # ā http://localhost:4000
# 2. Frontend
cd ../client
npm install
cp .env.local.example .env.local
npm run dev # ā http://localhost:3000
Default Admin: admin / admin123
personal_portfolio/
āāā server/ # Node.js + Express + Prisma
ā āāā prisma/ # Schema, migrations, seed
ā āāā src/
ā āāā controllers/ # Standard HTTP handlers
ā āāā services/ # Business logic (DB, external APIs)
ā āāā routes/ # Express routing + API docs
ā āāā schemas/ # Zod validation schemas
ā āāā middleware/ # Auth, validation, rate limiting
ā āāā config/ # Environment & app config
ā āāā utils/ # ApiError, ApiResponse helpers
ā āāā modules/
ā āāā agent/ # [STANDALONE] AI Agent Engine
ā āāā agent.service.ts # ReAct loop with sticky fallback
ā āāā agent.controller.ts # Zero-crash error handling
ā āāā agent.admin.* # Admin CRUD for sessions
ā āāā core/
ā ā āāā llm.factory.ts # Dual-LLM singleton init
ā ā āāā agent.logger.ts # Structured observability
ā ā āāā memory.service.ts# Persistent Prisma sessions
ā ā āāā prompts.ts # System persona
ā āāā tools/ # MCP tool implementations
ā ā āāā github.tool.ts # GitHub activity + events
ā ā āāā github.repo.tool.ts # README reader
ā ā āāā leetcode.tool.ts # LeetCode stats
ā ā āāā portfolio.tool.ts# Project search
ā ā āāā contact.tool.ts # Lead insertion
ā āāā rag/ # Context retrieval
ā
āāā client/ # React + Next.js App Router
āāā src/
āāā app/ # Portfolio, Admin, Resume, README
āāā modules/ # Feature modules (profile, projects, blog...)
ā āāā agent/ # AI Widget UI
ā āāā components/ # Chat window, bubbles, loader
ā āāā hooks/ # useAgentSession (error isolation)
ā āāā types/ # Message interfaces
āāā layout/ # App shell (sidebar, scroll, TOC)
āāā api/ # API client + circuit breaker + fallback
āāā lib/ # Skill icons, routes, utils
āāā boot/ # Splash animation
sessionIds ā users cannot read or poison other sessions.sanitize-html before database insertion.express-rate-limit restricts Agent chat to 15 messages/minute per IP.Access full API documentation at GET /api/v1/docs.
Live AI Agent architecture status at GET /api/v1/docs/agent.
Designed and Architected by Anurag Basuri
This project is licensed under the MIT License - see the LICENSE file for details.