Skip to content

Latest commit

Β 

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Portfolio Platform

A production-grade monorepo portfolio platform built with PERN stack (PostgreSQL, Express, React, Node.js) + TypeScript, Redis caching, BullMQ job queue, and admin dashboard.

πŸ—οΈ Architecture

Tech Stack

  • Backend: Node.js 20 + Express.js + TypeScript (strict mode)
  • Database: PostgreSQL with Prisma ORM
  • Caching & Sessions: Redis with ioredis
  • Frontend: React 18 + Vite + TypeScript
  • Admin Dashboard: React 18 + Vite + TypeScript (with JWT auth)
  • Styling: Tailwind CSS with CSS variables for theming
  • Validation: Zod schemas on all boundaries
  • Background Jobs: BullMQ with Redis queue
  • Email: Nodemailer with SMTP
  • API Documentation: Swagger/OpenAPI 3.0
  • Rate Limiting: express-rate-limit with Redis store
  • Logging: Pino (structured) + Morgan (HTTP)
  • Containerization: Docker multi-stage builds + docker-compose

Project Structure

portfolio-platform/
β”œβ”€β”€ backend/                  # Node.js API server
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ config/          # Environment, DB, Redis, Mail configs
β”‚   β”‚   β”œβ”€β”€ middleware/      # Auth, rate-limit, error handling
β”‚   β”‚   β”œβ”€β”€ services/        # Cache, mail services
β”‚   β”‚   β”œβ”€β”€ jobs/            # BullMQ queue and workers
β”‚   β”‚   β”œβ”€β”€ utils/           # Helpers, error codes, logger
β”‚   β”‚   β”œβ”€β”€ modules/         # Feature modules (8 total)
β”‚   β”‚   β”‚   β”œβ”€β”€ auth/        # JWT, bcryptjs, token rotation
β”‚   β”‚   β”‚   β”œβ”€β”€ blog/        # CRUD with Redis caching
β”‚   β”‚   β”‚   β”œβ”€β”€ articles/    # CRUD with Redis caching
β”‚   β”‚   β”‚   β”œβ”€β”€ books/       # CRUD with pricing
β”‚   β”‚   β”‚   β”œβ”€β”€ career/      # Timeline with type enums
β”‚   β”‚   β”‚   β”œβ”€β”€ achievements/
β”‚   β”‚   β”‚   β”œβ”€β”€ downloads/   # Counter tracking
β”‚   β”‚   β”‚   β”œβ”€β”€ contact/     # Form submission + email
β”‚   β”‚   β”‚   └── newsletter/  # Subscribe/unsubscribe
β”‚   β”‚   β”œβ”€β”€ routes/v1/       # API route aggregation
β”‚   β”‚   β”œβ”€β”€ docs/            # Swagger setup
β”‚   β”‚   β”œβ”€β”€ app.ts           # Express app factory
β”‚   β”‚   └── server.ts        # Entry point
β”‚   β”œβ”€β”€ prisma/
β”‚   β”‚   β”œβ”€β”€ schema.prisma    # Database schema (11 models)
β”‚   β”‚   └── seed.ts          # Initial data seeding
β”‚   └── Dockerfile           # Multi-stage build
β”‚
β”œβ”€β”€ frontend/                 # Public portfolio website
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ lib/             # Axios instance, React Query client
β”‚   β”‚   β”œβ”€β”€ routes/          # 11 lazy-loaded routes
β”‚   β”‚   β”œβ”€β”€ features/        # Feature hooks (blog, articles, etc.)
β”‚   β”‚   β”œβ”€β”€ pages/           # Page components
β”‚   β”‚   β”œβ”€β”€ components/      # Reusable UI components
β”‚   β”‚   β”œβ”€β”€ types/           # TypeScript interfaces
β”‚   β”‚   β”œβ”€β”€ utils/           # Utilities
β”‚   β”‚   β”œβ”€β”€ App.tsx          # Root component
β”‚   β”‚   β”œβ”€β”€ main.tsx         # React entry point
β”‚   β”‚   └── index.css        # Tailwind directives
β”‚   └── Dockerfile           # Multi-stage build
β”‚
β”œβ”€β”€ dashboard/               # Admin panel
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ lib/             # Axios instance, React Query client
β”‚   β”‚   β”œβ”€β”€ routes/          # Protected routes + login
β”‚   β”‚   β”œβ”€β”€ pages/           # Admin pages (CRUD, messages)
β”‚   β”‚   β”œβ”€β”€ components/      # Admin UI components
β”‚   β”‚   β”œβ”€β”€ types/
β”‚   β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ App.tsx
β”‚   β”‚   β”œβ”€β”€ main.tsx
β”‚   β”‚   └── index.css
β”‚   └── Dockerfile           # Multi-stage build
β”‚
β”œβ”€β”€ docker-compose.yml       # Multi-service orchestration
β”œβ”€β”€ .dockerignore             # Docker build exclude patterns
└── .github/workflows/ci.yml # GitHub Actions CI pipeline

API Modules

Module Features Rate Limit
auth Register, login, refresh token, logout 5 req/min
blog CRUD blogs. Cached: lists (5min), posts (10min) 100 req/min
articles CRUD articles. Same caching as blog 100 req/min
books CRUD books with pricing (Decimal type) 100 req/min
career Timeline entries with type enum (JOB, EDUCATION, etc.) 100 req/min
achievements Badge/achievement tracking 100 req/min
downloads Resource management with counter 100 req/min
contact Form submission with admin email 3 req/hour
newsletter Subscribe/unsubscribe with welcome email 100 req/min

πŸš€ Getting Started

Prerequisites

  • Node.js 20+ (or Docker)
  • PostgreSQL 16+
  • Redis 7+
  • npm 10+ or pnpm

Installation

Local Development

  1. Clone and setup root:

    git clone <repo>
    cd portfolio-platform
    npm install
  2. Environment setup:

    cp .env.example .env
    # Edit .env with your PostgreSQL, Redis, SMTP credentials
  3. Database migration:

    npm run db:migrate --workspace=backend
    npm run db:seed --workspace=backend
  4. Start all services (concurrent):

    npm run dev

    Or start individually:

    npm run dev --workspace=backend      # http://localhost:4000
    npm run dev --workspace=frontend     # http://localhost:3000
    npm run dev --workspace=dashboard    # http://localhost:3001
  5. Access the stack:

Docker Compose

  1. Build and start all services:

    docker-compose up -d

    First-time only, run migrations:

    docker-compose exec backend npm run db:migrate
    docker-compose exec backend npm run db:seed
  2. Access:

  3. View logs:

    docker-compose logs -f backend
    docker-compose logs -f frontend
    docker-compose logs -f dashboard
  4. Shutdown gracefully:

    docker-compose down

πŸ§ͺ Testing & Validation

# Type check all workspaces
npm run typecheck

# Lint all workspaces
npm run lint

# Test backend
npm run test --workspace=backend

# Build all workspaces
npm run build

# Build Docker images
docker-compose build

πŸ“š API Reference

Authentication

Register:

POST /api/v1/auth/register
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secure123"
}

Login:

POST /api/v1/auth/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secure123"
}

Response:

{
  "success": true,
  "data": {
    "accessToken": "jwt...",
    "refreshToken": "jwt...",
    "user": { "id": "...", "email": "..." }
  }
}

Refresh Token:

POST /api/v1/auth/refresh
Content-Type: application/json

{
  "refreshToken": "jwt..."
}

Blog (Public)

List blogs (paginated):

GET /api/v1/blog?page=1&limit=10

Get blog by slug:

GET /api/v1/blog/:slug

For admin: All CRUD operations at POST, PUT, DELETE /api/v1/blog/:id require JWT admin token.

Full API Documentation

Swagger UI available at: http://localhost:4000/api/docs

πŸ” Security Features

  • JWT Authentication: Short-lived access tokens (15min) + long-lived refresh tokens (7d)
  • Password Hashing: bcryptjs with 12 salt rounds
  • Rate Limiting: Graduated limits (100/min general, 5/min auth, 3/hr contact)
  • CORS: Configurable origin whitelist
  • Helmet: Security headers on all HTTP responses
  • Input Validation: Zod schemas on every endpoint
  • Idempotency Keys: 30s cache on POST requests to prevent duplicates
  • Error Handling: Centralized middleware, no stack traces in production

🎨 Customization

Environment Variables

Create .env file from .env.example:

# Critical
DATABASE_URL=postgresql://user:pass@localhost/portfolio_dev
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-secret-key
JWT_REFRESH_SECRET=your-refresh-secret

# Email (Gmail example)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
ADMIN_EMAIL=admin@portfolio.dev

# CORS
CORS_ORIGIN=http://localhost:3000,http://localhost:3001

# Frontend
VITE_API_URL=http://localhost:4000/api

Tailwind Theming

Edit frontend/tailwind.config.ts and dashboard/tailwind.config.ts:

theme: {
  extend: {
    colors: {
      primary: 'var(--color-primary)',
    },
    fontFamily: {
      display: 'var(--font-display)',
    },
  },
}

CSS variables in src/index.css:

:root {
  --color-primary: #3b82f6;
  --font-display: "Inter", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-primary: #1e40af;
  }
}

πŸ“Š Database Schema

Key Models

  • User: Profiles, roles (USER, ADMIN), token tracking
  • Blog: Post content, slug-based routing, view counting
  • Article: Similar to Blog, separate table for organization
  • Book: Metadata, pricing (Decimal), file URLs
  • CareerTimeline: Type enum (JOB, EDUCATION, etc.), date range
  • Achievement: Badges, date tracking
  • Download: Resource tracking with counter
  • Contact: Form submissions, read status, admin replies
  • NewsletterSubscriber: Email list with unsubscribe tracking
  • RefreshToken: JWT revocation, device tracking
  • AuditLog: Admin action tracking (optional, not in initial schema)

All models use:

  • UUID primary keys
  • createdAt / updatedAt timestamps
  • Proper indexes for common queries (slug, email, etc.)

πŸ› Debugging

Backend Logs

Enable debug mode:

DEBUG=portfolio:* npm run dev --workspace=backend

Frontend React DevTools

Install React Developer Tools browser extension, then:

npm run dev --workspace=frontend

Database Queries

View Prisma Studio:

npm run prisma:studio --workspace=backend

🚒 Deployment

Using Docker

  1. Build images:

    docker-compose build
  2. Push to registry (optional):

    docker tag portfolio-backend:latest your-registry/portfolio-backend:latest
    docker push your-registry/portfolio-backend:latest
  3. Deploy (see your infrastructure provider's docs for:

    • Kubernetes YAML
    • AWS ECS task definitions
    • Heroku procfile
    • DigitalOcean app spec

Environment Variables for Production

Use a secure secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.) and inject:

DATABASE_URL=postgresql://prod_user:prod_pass@prod-db:5432/portfolio
REDIS_URL=redis://:password@prod-redis:6379
JWT_SECRET=<random-64-char-key>
SMTP_HOST=smtp.sendgrid.net
# ... others

πŸ“ Contributing

  1. Fork and create feature branch: git checkout -b feature/my-feature
  2. Make changes following the architecture patterns
  3. Run linting and type checks: npm run lint && npm run typecheck
  4. Test your changes: npm run test
  5. Push and create a pull request

πŸ“„ License

MIT License - see LICENSE file for details

πŸ‘€ Author

Edeh Chinedu Daniel - Portfolio & Contact Platform


Questions or issues? Open an issue on GitHub or contact admin@portfolio.dev

About

Production-grade portfolio platform showcasing full-stack engineering, 3D web experiences, and IoT projects. Built with the PERN stack, React Three Fiber, GSAP, and deployed on Vercel and Render.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages