Full-stack software engineer building fast, reliable web & mobile products with the MERN stack, React Native and machine learning.
Click the preview to open the live site · API on Render: https://portfolio-backend-ie6f.onrender.com
- Immersive, engineer-themed UI — dark & light themes, a fluid type system and a 12-column layout that uses the full width of laptops and large screens.
- Hero — the name decodes from binary (hover it to see the initials A D as
01000001 01000100), a 3D code-editor card with parallax layers, and a node network that reacts to the cursor. - Live data — GitHub commits/repos and LeetCode stats fetched server-side, cached, and shown with a "synced X min ago" indicator.
- Scroll storytelling — cards unfold into place, headlines flip up and the tech ribbons react to scroll speed — all compositor-only CSS, with a full reduced-motion fallback.
- Useful details — certificate cover-flow with drag + lightbox, in-page interactive map of Dehradun, 12-hour IST clock, one-click email copy, accessible contact form.
- Fast, accessible, SEO-ready — Lighthouse 100 across the board on desktop; Open Graph cards, JSON-LD, sitemap.
![]() Hero · dark |
![]() Hero · light |
![]() About · live GitHub & LeetCode stats |
![]() Selected work · demo videos |
![]() Stack · bento grid |
![]() Certificates · cover-flow |
![]() Contact |
![]() In-page full-screen map |
![]() Mobile · hero & menu |
Lighthouse on the production build, before → after the redesign:
| Metric | Previous design | New design |
|---|---|---|
| Performance (desktop / mobile) | 89 / 66 | 100 / ~90 |
| Accessibility | 76 | 100 |
| Best Practices | 96 | 100 |
| SEO | 92 | 100 |
| JavaScript (gzipped, initial) | 243 kB + jQuery/Bootstrap | 75 kB (+33 kB icons, loaded on demand) |
| Total page weight | 1,918 kB · 50 requests | ~250 kB · 15 requests |
| Largest Contentful Paint (mobile) | 6.4 s | ~2.9 s |
| Frontend | Backend | Tooling & hosting |
|---|---|---|
| React 18 (Create React App) | Node.js + Express | Vercel (frontend) |
| Hand-built CSS design system | PostgreSQL (Neon) via pg |
Render (API) |
| CSS scroll-driven animations | SendGrid (email notifications) | GitHub & LeetCode APIs |
| Canvas 2D (hero network) | In-memory caching & rate limiting | Self-hosted fonts, WebP images |
| react-icons | dotenv, cors | Jest + Testing Library, node:test |
| GitHub Actions (CI on every push & PR) |
Portfolio/
├── client/ # React frontend (Vercel root directory)
│ ├── public/ # index.html (SEO/meta), fonts, icons, og-image, sitemap, robots
│ ├── src/
│ │ ├── sections/ # Hero, About, Work, Journey, Stack, Certificates, Contact
│ │ ├── components/ # Nav, Footer (+ map dialog), CodeCard, Marquee, NeuralField, ScrambleText…
│ │ ├── data/profile.js # ← all site content: profile, projects, journey, certificates
│ │ ├── lib/ # API client (shared fetch cache), scroll-reveal helpers
│ │ ├── context/ # ThemeContext (dark / light, persisted)
│ │ ├── styles/ # global design tokens, scroll "unfold" animations
│ │ └── assets/ # resume PDF, optimised WebP images, certificates
│ ├── vercel.json # security & caching headers
│ └── package.json
│
├── backend/ # Node.js + Express API (Render root directory)
│ ├── controllers/ # contact form, GitHub stats, LeetCode stats
│ ├── middleware/rateLimit.js # per-IP rate limiting (Cloudflare-aware on Render)
│ ├── routes/portfolioRoutes.js
│ ├── lib/contact.js # contact form validation, honeypot, HTML escaping
│ ├── config/db.js # PostgreSQL (Neon) pool, verified TLS
│ ├── app.js # security headers, CORS allow-list, /health, JSON errors
│ ├── server.js # loads .env and starts the server
│ └── test/ # API, contact, rate-limit and stats tests (node:test)
│
├── .github/workflows/ci.yml # tests + production build on every push and pull request
├── docs/ # README screenshots and the previous-design recording
└── README.md
To update projects, experience or certificates, edit
client/src/data/profile.js— no component changes needed.
REACT_APP_BACKEND_URL=https://portfolio-backend-ie6f.onrender.comREACT_APP_* variable is compiled into the public JavaScript bundle. Never put tokens or keys in the frontend — GitHub data is fetched by the backend instead.
PORT=8080
DATABASE_URL=your_neon_postgres_url
SENDGRID_API_KEY=your_sendgrid_api_key
SENDGRID_SENDER_EMAIL=sender@example.com
SENDGRID_RECEIVER_EMAIL=receiver@example.com
# Strongly recommended: a GitHub token with NO scopes (public read only).
# Raises the API limit from 60 to 5,000 requests/hour; without it, shared hosting IPs can hit the limit.
GITHUB_TOKEN=your_github_token
# Optional: comma-separated origins allowed to call the API. When unset, the API allows
# the production site, this project's Vercel preview URLs and localhost (3000 / 5173).
CORS_ORIGIN=https://portfolio-nine-orcin-33.vercel.app,http://localhost:3000.env files. They are covered by .gitignore.
Backend
cd backend
npm install
npm run dev # http://localhost:8080 (npm start for production)Frontend
cd client
npm install
npm start # http://localhost:3000To use the local API during development, create client/.env.development.local with REACT_APP_BACKEND_URL=http://localhost:8080.
npm test # client tests (in client/) or API tests (in backend/)
CI=true npm run build # production build — warnings fail the build, same as VercelThe backend tests use Node's built-in test runner and never touch the database, SendGrid, GitHub or LeetCode (network calls are mocked). GitHub Actions runs both test suites and the production build on every push to main and on every pull request.
Backend → Render
- Root directory:
backend· Build:npm install· Start:npm start· Health check path:/health - Set the backend environment variables above (including
GITHUB_TOKEN;CORS_ORIGINonly if you use other domains).
Frontend → Vercel
- Root directory:
client· Framework preset: Create React App - Environment variable:
REACT_APP_BACKEND_URL= your Render URL client/vercel.jsonadds security headers (anti-clickjacking,nosniff, referrer & permissions policies) and long-term caching for hashed assets.
Base URL: https://portfolio-backend-ie6f.onrender.com/api/v1/portfolio
Served at the root (https://portfolio-backend-ie6f.onrender.com/health), not under the base URL. Returns { "status": "ok", "uptime": 42 } without calling any other service, so it suits uptime monitors and Render's health check.
{ "name": "Ankit Dimri", "email": "dimri.ankitdimri@gmail.com", "msg": "Hello, I want to connect!" }{ "success": true, "message": "Message sent and saved successfully" }Validation: all fields required, valid email (max 150 chars), name max 100 chars, message max 5,000 chars. Rate limited to 5 messages per 15 minutes per IP (429 with Retry-After when exceeded). Visitor input is HTML-escaped in the notification email.
The message is saved and emailed independently: if one of the two fails, the other still delivers it and the visitor gets a success response (so they don't resend and create duplicates). A 500 is returned only when both fail. An optional hidden company field acts as a honeypot: if it is filled in, the request gets a normal-looking success response but nothing is saved or sent.
Public repositories with commit counts, stars, language and last push, plus totalCommits. Fetched server-side and cached for 1 hour. If some counts can't be fetched (e.g. rate limiting), last known values are used; if a total can't be computed reliably, totalCommits is null and partial is true rather than returning an undercount.
totalSolved, solvedByDifficulty (easy / medium / hard), acceptanceRate and global ranking. acceptanceRate matches the LeetCode profile: accepted submissions ÷ all submissions. Cached for 10 minutes.
GitHub and LeetCode calls time out after 10 seconds. If either service is slow or down, the last good result is served; 502 is returned only when there is nothing cached yet.
Errors are always JSON with a message field and never include stack traces.
Contact messages are stored in the contacts table (PostgreSQL / Neon):
CREATE TABLE contacts (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(150),
message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);- No secrets in the frontend bundle or the repository; GitHub access is server-side only.
- JSON-only errors (no stack traces),
X-Powered-Byremoved,nosniff/ frame-deny / referrer headers, CORS allow-list on by default. - Contact form: validation, HTML escaping, honeypot, 20 kB body limit, per-IP rate limiting (using Cloudflare's visitor IP on Render); parameterised SQL.
- Database connections use TLS with certificate verification.
npm audit: 0 vulnerabilities in backend dependencies and in the frontend code shipped to visitors.
Ankit Dimri — Full-Stack Software Engineer · 📍 Dehradun, India


















