Initializing
Back to Projects
Year2024
DomainFullstack
AccessOpen Source
Complexity8.7 / 10
Live LinkArchitecture DocsScreenshots
TypeScriptNext.js 14React 18Express.jsPostgreSQLPrisma ORMFramer MotionCSS ModulesDockerTraefikpnpm WorkspacesJWTZodVitest
FullstackProduction

Portfolio Nexus — The Homopedia Nexus

A production-grade full-stack portfolio monorepo. Three apps (Next.js 14, Vite + React, Express.js), pnpm workspaces, Docker + Traefik VPS deployment, and a public Suggestion Box with JWT-secured admin panel.

Apps in Monorepo0
Shared Packages0
API Domain Modules0
Deployment TargetsVercel + VPS
Lighthouse Score0+

Table of Contents


The Challenge

Most developer portfolios are static HTML pages or Notion exports — they show what you built but not *how* you build. The goal was to make the portfolio itself a living demonstration of engineering capability: a fully deployed, production-grade system with real security, real observability, and a real public API.

Requirements:

  • Public portfolio website with premium aesthetics — not a Tailwind template clone
  • Private admin panel for moderating public-submitted suggestions
  • Secure REST API with JWT auth, CSRF protection, and rate limiting
  • Full CI/CD pipeline with quality gates on every PR
  • Single codebase, multiple deployable apps, shared type contracts

Architecture & Solution

Portfolio Nexus is a pnpm monorepo with three fully independent applications sharing TypeScript contracts through workspace packages.

Parsing system architecture diagram...

Monorepo Structure

code
portfolio-nexus/
├── apps/
│   ├── website/          # Next.js 14 App RouterPublic portfolio
│   ├── admin/            # Vite + React SPAPrivate suggestion moderation
│   └── api/              # Express.js Modular Monolith

├── packages/
│   ├── types/            # Shared TypeScript contracts (single source of truth)
│   ├── content/          # Markdown case studies, blog posts, project metadata
│   └── config/           # Spider-web scores, project status configs

├── infra/                # Dockerfiles + docker-compose.prod.yml (Traefik)
├── .github/workflows/    # CI quality gate
└── *.sh                  # setup, start, stop, dev, deploy scripts

Boundary enforcement: apps/* cannot import from other apps/*. All shared contracts flow through packages/* only. Enforced by ESLint boundaries plugin in CI.


Tech Stack

LayerTechnologyRole
Public WebsiteNext.js 14 App RouterSSG + ISR, Server/Client Components
Admin PanelVite 5 + React 18Private SPA, no SSR needed
APIExpress.js 4 + TypeScriptModular monolith REST API
DatabasePostgreSQL 16 + PrismaSchema, migrations, type-safe queries
AuthJWT in httpOnly cookie8-hour sessions, SameSite=Strict
State (Admin)ZustandLightweight client state
StylingCSS Modules + CSS Custom PropertiesNo Tailwind, no inline styles
AnimationsFramer MotionScroll entrances, hero aurora
LoggerPinoJSON-structured, redacts auth headers
ValidationZodSchema-first, types inferred from schemas
TestingVitest + SupertestUnit + E2E API contract tests
Package Managerpnpm workspacesSingle lockfile, workspace protocol
ContainerizationDocker multi-stagedeps → builder → runner (minimal image)
Reverse ProxyTraefik + Let's EncryptAutomatic HTTPS, zero-downtime routing
CDNVercelEdge SSG serving for public website

Key Engineering Decisions

1. SSG + ISR over Full SSR

The portfolio content (case studies, blog posts) is static by nature. Next.js App Router Server Components read markdown files from packages/content/ at build time using fs.readFileSync — zero runtime API cost, maximum Lighthouse scores, instant page loads globally from Vercel CDN.

Only dynamic content (GitHub contribution heatmap) uses ISR with a 1-hour revalidation window.

2. No TailwindCSS — CSS Modules + Design Tokens

The decision to use CSS Modules with CSS custom properties (not Tailwind) means:

  • The portfolio looks like no other portfolio (custom, not a template)
  • Zero utility class sprawl in JSX
  • Design tokens are a single source of truth in tokens.css
  • prefers-reduced-motion and dark mode handled cleanly at the CSS layer

3. API Modular Monolith

The API follows the same modular monolith pattern as Aatmanova — each domain lives in a vertical slice that passes the deletion test. Clean architecture layers are enforced:

code
Router (Express-only)Controller (parse/respond)Service (orchestrate)
Policy (pure rules, no I/O)Repository (data only)Prisma

No circular dependencies enforced by madge in CI.

4. CSRF Double-Submit Pattern

Admin routes use two independent CSRF defenses simultaneously:

  • SameSite=Strict cookie — browser won't send cookie on cross-origin requests
  • X-Admin-Origin: portfolio-admin custom header — cannot be set by cross-origin forms, only JavaScript (which must already be on the same origin)

Together these make CSRF attacks impossible without compromising the admin origin itself.

5. Manual DI Container

No magic, no decorators, no IoC framework. The entire dependency graph is visible in one file:

typescript
// container.ts — readable dependency wiring
const suggestionsRepo   = new SuggestionsRepository(prisma);
const suggestionsPolicy = new SuggestionsPolicy();
const suggestionsService = new SuggestionsService(
  suggestionsRepo, suggestionsPolicy, emailService, logger
);
export const container = {
  suggestionsController: new SuggestionsController(suggestionsService),
};

API Security Model

ControlImplementation
AuthJWT in httpOnly, secure, SameSite=Strict cookie (8h TTL)
CSRFDouble-submit: SameSite=Strict + X-Admin-Origin header
Rate Limiting3 suggestions/hour/IP (in-memory Map, v1)
Input ValidationZod on every endpoint — body, query params, route params
Security HeadersHelmet.js (11 headers including CSP, HSTS, X-Frame-Options)
CORSExplicit origin allowlist — never * in production
LoggingPino — redacts req.headers.authorization, body.password, body.token
Env ValidationZod-validated env.ts — fails fast on startup with missing vars

Frontend Design System

The public website implements the Linear/Vercel aesthetic — dark canvas, precision borders, accent glow — built entirely from scratch with CSS custom properties:

css
:root {
  --color-background:  #0A0A0A;  /* True black canvas */
  --color-surface:     #111111;  /* Card background */
  --color-accent:      #3B82F6;  /* Blue — primary CTAs */
  --color-text:        #FAFAFA;  /* Near-white primary */
  --color-text-muted:  #A3A3A3;  /* Secondary copy */
  --font-display: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-body:    'DM Sans', system-ui, sans-serif;
  --font-mono:    'Fira Code', 'Courier New', monospace;
}

Animation rules (from Framer Motion centralized config):

  • Entrance: fadeUp (0–24px, opacity 0→1, 0.6s spring easing)
  • Hero: Aurora mesh gradient (conic-gradient, hue-rotate CSS animation)
  • Hover: translateY(-2px) + glow box-shadow, 200ms
  • useReducedMotion() disables all JS animations for accessibility

WCAG AA compliance on all text — targeting AAA 7:1 for body copy in dark mode.


CI/CD Pipeline

GitHub Actions runs on every PR to main or develop:

yaml
# quality.yml — runs on every PR
steps:
  - TypeScript: pnpm -r tsc --noEmit           # All workspaces
  - Lint:       pnpm -r lint
  - Tests:      pnpm --filter api test:unit
  - Circular:   npx madge --circular apps/api/src
  - Build:      pnpm --filter website build    # Validates SSG
  - Build:      pnpm --filter admin build
  - Audit:      npm audit --audit-level=high

No merge to main without all checks green.


Deployment Topology

code
Vercel (Next.js SSGpublic website)
  ├── Global CDN edge nodes
  ├── Automatic builds on git push
  └── ISR for GitHub heatmap (1h TTL)

VPS (Ubuntu 22.04)
  ├── Traefik (reverse proxy + Let's Encrypt)
  │   ├── api-portfolio.aatmanova.inportfolio-api container (port 4000)
  │   └── access.aatmanova.inNginx serving Vite admin build
  ├── PM2 (Express API process management)
  │   ├── 1 instance, fork mode
  │   ├── max_memory_restart: 512M
  │   └── zero-downtime: pm2 reload --update-env
  └── PostgreSQL 16 (Docker container, no exposed ports)

Deploy to VPS with a single command:

bash
./deploy.sh "feat: add project case study"
# → Tests → git push → rsync → Docker rebuild → migration → health check

Engineering Proof

Real-world validation, system demonstrations, and interface captures of the execution states.

System Captures

Full Page Web Captures

Scrollable web preview simulations. Hover or scroll to preview the entire page. Use the maximize trigger to view the full resolution capture.

portfolio.aatmanova.in/projects/portfolio-nexus/full-capture-1
Full Webpage Simulation 1
portfolio.aatmanova.in/projects/portfolio-nexus/full-capture-2
Full Webpage Simulation 2

Architecture Feedback

Spotted a potential optimization or antipattern? Let me know.

Submit a Technical Suggestion