SD.
ReactNode.jsExpress.jsMongoDBTypeScriptViteTailwind CSS

Video Crew Portfolio

A full-stack video production portfolio website with a secure admin panel — built to showcase work, capture leads, and manage content and inquiries from one place.

·9 min read
Tenure

Aug 2025 – Nov 2025


Internal Company Project — Learning Crew This is a proprietary platform built for Learning Crew's video production division. Source code and live deployment links are not publicly available. All details are shared for portfolio purposes only.

Overview

Video Crew Portfolio is a full-stack web application serving as the central hub for Video Crew — a video production team within Learning Crew. The platform combines a polished public-facing portfolio site with a full content management system and admin dashboard, purpose-built for a non-technical team to manage work and client inquiries without touching code.

The system covers:

  • Public site — Showcase work (videos, thumbnails), explain the process, and capture leads
  • Admin panel — Manage portfolio items, track and respond to contact inquiries, view analytics
  • Supporting systems — Page visit tracking, database-backed notifications, media upload with persistent storage

The Problem

The team needed one place to present its work and handle inquiries:

  • Portfolio content (videos, thumbnails, metadata) needed a central home that didn't require technical effort to update
  • Contact inquiries needed tracking, a status workflow, and a centralized view instead of living in email
  • Hosting, forms, and media needed to sit behind one consistent, branded experience

The goal was a single, professional presence with a content management layer that any team member could operate — and enough visibility to make data-driven decisions.


My Role

I was responsible for the entire project from A to Z — concept, architecture, implementation, deployment, and documentation.

System Architecture

Defined the split between client, API, storage, and static assets. Chose REST over alternatives and designed all data models and API contracts from scratch.

Backend (Node.js + Express)

  • REST APIs — auth, portfolio CRUD, contact management, file uploads, page visits, notifications, and captcha
  • Auth middleware — JWT verification and role-based route protection
  • File upload handling — Multer-based type/size validation, unique filenames, environment-aware disk paths
  • MongoDB schema design — five data models (portfolio items, contact inquiries, admins, page visits, notifications), with indexes and TTL where needed

Frontend (React + Vite + TypeScript)

  • Public pages — Home, About, Portfolio (video grid + modal), Process, Differentiation, Contact
  • Admin dashboard — login, portfolio CRUD, contact manager, analytics, notifications
  • Custom UI — built with Tailwind, no third-party component library
  • Responsive layout — mobile-first throughout

Media & Storage

  • Media upload — image and video, with progress feedback, unique filename generation, and error handling
  • Environment-aware storage paths — switches between local disk and a persistent production volume through configuration

Security & Reliability

  • JWT authentication — for all admin routes
  • IP-based rate limiting — tracks failed login attempts per IP, blocks after threshold, cleanup job for expired entries
  • SVG captcha — on contact form to reduce spam
  • Dynamic CORS — allowed-origins list with rejection logging
  • Env validation — on server startup

DevOps & Deployment

  • Deployment — frontend and API deployed separately on managed platforms, with a persistent disk for uploads
  • Documentation — deployment/setup guides, API docs, and system-level documentation

Tech Stack

Frontend

React 18 · TypeScript · Vite 7 · Tailwind CSS 4 · React Router 7 · Axios · GSAP (animations) · Lucide React

PWA / UX

vite-plugin-pwa — service worker · install prompt · offline indicator

Backend

Node.js 20 · Express 5 · TypeScript

Database

MongoDB (Mongoose 8)

Auth

JWT (jsonwebtoken) · bcryptjs

Files

Multer — multipart/form-data · disk storage with env-based paths

Security

svg-captcha · express-rate-limit · custom IP-based login rate limiter · Nodemailer (SMTP)

Infra

Vercel · Render · MongoDB Atlas · persistent disk storage


Architecture

Client — React + Vite

Public: Home · About · Portfolio · Process · Differentiation · Contact

Admin: Login → Portfolio CRUD · Contact Manager · Analytics · Notifications

HTTPS / REST

API Layer — Express

auth · portfolio · contact · uploads · page visits · notifications · captcha — one route module per domain

↓

Auth Middleware

JWT verify · rate limiter

Multer

file type + size · disk storage

Business Logic

controllers · services · email · notifications

↓

Data & Storage

MongoDB: portfolio · inquiries · admins · visits · notifications

Disk: uploads — local dev or persistent production disk (env-aware path)

Key architectural decisions:

  • Modular REST API — Separate route modules per domain with shared auth middleware and centralized error handling
  • Environment-aware storage — Upload paths switch between local disk and a persistent production disk through configuration; both Multer and the static file handler use the same path helper
  • Database-driven notifications — Notification events (portfolio changes, new contacts, page-visit milestones) are stored in MongoDB and polled by the admin UI every 30s — no WebSocket complexity
  • SPA + API split — the React SPA is deployed separately from the API, which serves uploaded media from persistent storage

Key Features

  • Public website — Responsive, mobile-first: Home, About, Process, Differentiation, Portfolio (grid + video modal), Contact (form + validation + captcha)
  • Admin authentication — Email/password login, JWT-protected routes, IP-based login rate limiting with automatic expiry
  • Portfolio CRUD — Create, read, update, delete portfolio items: title, category, client, description, thumbnail, video, featured flag, display order
  • Media upload — Image and video upload with separate size caps, type validation, progress feedback, unique filenames, and persistent storage
  • Contact system — Public form submissions stored in MongoDB; admin can list, filter, update status (new / processing / completed), and add notes; optional SMTP email notification
  • Page visit tracking — Visit counts feeding admin analytics and milestone notifications
  • Universal notifications — Events triggered on portfolio create/update/delete, new contact, and page-visit milestones; list and mark-as-read (single and bulk); 20-day TTL for auto-cleanup
  • Captcha — SVG captcha (generate/verify) on contact form to reduce spam
  • PWA — Service worker, install prompt, offline indicator via vite-plugin-pwa
  • Custom UI — No third-party component library; all components built with Tailwind, composable and consistent

Selected Challenges & Solutions

File Uploads Disappearing After Deploy

The hosting platform's default filesystem is ephemeral — uploads were lost on every deploy. Introduced a persistent disk for uploads and pointed the app at it through configuration. Both Multer's destination and express.static use one environment-aware path helper, so they always resolve to the same directory — uploads survive deploys.

Brute Force on Admin Login

A simple email/password login with no throttling is a straightforward attack vector. Implemented IP-based rate limiting: failed attempts are tracked per IP, repeated failures trigger a temporary block, and a cleanup job removes expired entries. The frontend shows a generic blocked state, so nothing about the lockout logic is revealed to the client.

Admin Notifications Without WebSockets

The admin needs to know about new contacts, portfolio changes, and traffic milestones — but WebSockets would add significant complexity. Instead, notification events are written to MongoDB on each trigger, and the admin dashboard polls every 30 seconds. Unread count and mark-as-read (single and bulk) keep the UX clean. TTL-based expiry (20 days) handles cleanup. Works reliably with zero persistent connections.

Large Video Upload Reliability

Large video files need careful handling on both ends. Multer with configured size limits handles ingestion, generated unique filenames prevent collisions, and the client shows upload progress and clear error states. Stored media references live on the portfolio document and are served from the persistent disk.

CORS Across Multiple Origins

The system runs across several origins — local development plus separate production frontend and API hosts. Implemented dynamic CORS with an explicit allow list; requests from unlisted origins are rejected with a clear error. The config includes required methods and headers (e.g. Content-Type, Authorization) for API calls and file uploads.


Impact

  • Centralized portfolio management — The team can publish, update, and remove portfolio items with full media from one admin panel — no code changes required
  • Structured contact handling — All inquiries in one place with status and notes, replacing scattered emails and manual tracking
  • Better visibility — Page visit counts and milestone-based notifications give a simple but useful view of traffic and key events
  • Faster content updates — Media and content changes go live through the admin UI with persistent storage, shortening the cycle from idea to published
  • Security and reliability — JWT auth, rate limiting, captcha, env validation, and persistent disk make the system trustworthy in production
  • Single professional presence — One site for showcasing work and capturing leads, consistent across devices (PWA, responsive) and scalable as the portfolio grows