
Personal Website Admin Panel
My Personal Website Admin Panel is used to manage the aspects of my main personal site sairamsuresh.is-a.dev and my blog blog.sairamsuresh.is-a.dev
Portfolio Admin
A content management dashboard for my personal portfolio website. Built with Next.js, it provides a clean interface for managing every section of the portfolio — from blog posts and projects to achievements and certifications — all backed by Firebase Firestore.
Features
- Dashboard — central hub linking to all content sections
- Blog Posts — create and edit posts with full Markdown support, tags, and read-time estimates
- Projects — manage portfolio projects with descriptions, images, and links to GitHub, the App Store, Google Play, and Google Drive
- Events — log events attended or organised, with Markdown detail pages
- Certifications — track credentials and certifications
- Service Learning — record VIA/service learning activities in one table with a year column
- Achievements — catalogue awards and recognitions in one table with a year column
- Schools — maintain education history with institution logos and roles
- Drag-and-drop ordering — reorder table rows directly in the admin UI (year-based sections are constrained within year groups)
- Slug-aware image uploads — blog uploads require slug; non-blog uploads fall back to
<section>/<unique-name>.<ext>when slug is empty. With slug set, icon uploads use<section>/<slug>/icon.<ext>and markdown images use<section>/<slug>/<uuid>.<ext>
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 · Catppuccin Mocha theme |
| Database | Firebase Firestore (via firebase-admin) |
| Images | Cloudinary |
| Markdown | marked |
| Icons | Lucide React |
| Font | Geist |
| Container | Docker (multi-stage, Node.js 24 slim) |
Getting Started
Prerequisites
- Node.js 20+
- A Firebase project with Firestore enabled
- (Optional) A Cloudinary account for image hosting
Environment Variables
Create a .env.local file in the project root:
# Firebase — choose one of the two authentication methods
# Option A: individual environment variables
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=your-client-email
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n..."
# Option B: path to a service account JSON file (defaults to ./service-account.json)
FIREBASE_SERVICE_ACCOUNT_PATH=./service-account.json
# Firestore path config (optional — these are the defaults)
FIREBASE_PORTFOLIO_COLLECTION=portfolio
FIREBASE_GENERAL_DOCUMENT=general
# Cloudinary (optional for URL rewriting, required for in-editor uploads)
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
Running Locally
npm install
npm run dev
Open http://localhost:3000 to view the dashboard.
Deployment
A production-ready multi-stage Dockerfile is included. Build and run with:
docker build -t portfolio-admin .
docker run -p 3000:3000 --env-file .env.production portfolio-admin
Alternatively, for my workflow, I cross-compile on x64 for the ARM64 platform to run the application on the Pi.
# On Development Machine
podman build --platform="linux/arm64" -t www-admin .
podman save www-admin:latest | gzip > www-admin.tar.gz
# Then, after copying the image to the Pi:
podman load < www-admin.tar.gz
The image uses Next.js standalone output for a minimal runtime footprint.