Skip to content

Projects

Doan Ngoc Gioi
← All projects

Lean Portfolio

My earlier dngioi.com: a service-first portfolio for freelance work, with a services carousel, a work archive, a blog, reviews, a Start a Project form and its own admin CMS. Built with Next.js and MongoDB.

About the project

Lean Portfolio was the first version of dngioi.com, a freelance and business site for individuals, small businesses and teams that need practical software help. The homepage sells services through a full-screen banner carousel, Work is the proof library of projects, solutions and products, and Contact is a structured Start a Project form. A blog, an About page and visitor reviews round it out, and everything is managed from a custom admin area.

It started as a Vite and React app and moved to Next.js with a MongoDB backend, then grew in tracked milestones: the admin CMS, an image pipeline on Cloudflare R2, a product catalog, the home carousel, the work archive with service banners, and a light and dark theme. It was later replaced on dngioi.com by Personal Hub.

The screenshots show the app running locally with demo content.

Features

  • Service banners: a full-screen home carousel, each banner with its audience, headline, summary and calls to action.
  • Work archive: projects, solutions and products with type filters, image galleries, key features and a link to start a similar project.
  • Start a Project: a structured inquiry form (business type, budget, timeline, preferred contact) that lands in the admin inbox.
  • Blog with rich-text editing, tags and pagination; reviews from visitors; an About page with skills and experience.
  • Admin CMS for the profile, skills, experience, posts, work, banners and messages.
  • Light and dark themes built on semantic colour tokens, without a flash on load.

Screenshots

Home: a full-screen carousel of service banners with Start a Project and See the work
Work: the archive of projects, solutions and products, with type filters
A work item: summary, images, key features and a Start a Similar Project call to action
About: profile, location and links, then skills by category
The Work archive in the dark theme
Admin: managing work items (view, edit, delete) in the built-in CMS
The home carousel on a phone

Architecture

  • Next.js App Router with server components for public pages and route handlers for the JSON API.
  • MongoDB through the official driver (it ran on Firestore's MongoDB-compatible API); request bodies validated with Zod schemas.
  • Admin sign-in: a password exchanged for a JWT in an HTTP-only cookie (signed with jose); every write route checks it.
  • Images compressed on the server with sharp and stored on Cloudflare R2.
  • Shipped as a standalone Docker image and auto-deployed to Firebase App Hosting from GitHub Actions.

Challenges & what I learned

  • Moving from a Vite single-page app to the Next.js App Router without losing content or URLs (old product pages redirect to Work).
  • Keeping partial updates from wiping fields: Zod's .partial() still applies defaults, so updates keep only the fields the caller sent.
  • Stopping spam on public forms with a honeypot, a minimum fill time and a rate limit per visitor.
  • Reaching AA contrast in both themes by moving every colour to semantic tokens.
  • A small CMS covers most of what a personal site needs, and owning it makes changes fast.
  • Validation schemas need care at the edges: defaults and partial updates behave differently than they look.
  • Tracking work as issues with a spec and a plan per change keeps a side project moving; that habit carried over to Personal Hub.