A self-hosted personal blogging platform built for self-reflection. Write entries in Markdown, tag them, track your mood, and keep your thoughts in a quiet, parchment-toned space that you control.
The app is deployed on Vercel: personal-blog-delta-one.vercel.app
- Authentication — Login/register gate so only you can access your entries
- Profile panel — Editable keeper's profile (name, location, bio) beside your entries
- Markdown editing — Full GitHub Flavored Markdown support (tables, task lists, strikethrough, code blocks)
- Live preview — Toggle between edit and preview modes while writing
- Mood tracking — Tag each entry with a mood (Reflective, Grateful, Anxious, Calm, Inspired, Sad)
- Tags — Add comma-separated tags to organize entries
- Pin entries — Pin important posts to the top of the list
- Search — Filter entries by title, content, or tags
- Delete with confirmation — Inline confirm before removing an entry
- Vintage theme — Warm parchment palette with serif typography and typewriter accents (see design.md)
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Database | MongoDB (Atlas or local) |
| Styling | Tailwind CSS 4 |
| Auth | JWT (httpOnly cookies) |
| Markdown | react-markdown + remark-gfm |
| Passwords | bcryptjs |
| Hosting | Vercel-ready |
- Node.js 18+ (recommended 20+)
- MongoDB running locally on the default port (
27017)
-
Clone the repository
git clone git@github.com:htetoowai219/personal-blog.git cd personal-blog -
Install dependencies
npm install
-
Start MongoDB
Make sure
mongodis running. On macOS with Homebrew:brew services start mongodb-community
-
Run the dev server
npm run dev
-
Open the app
Navigate to http://localhost:3000. You'll be redirected to the login page. Create an account and start writing.
src/
├── lib/
│ ├── mongodb.ts # MongoDB connection singleton
│ ├── auth.ts # JWT sign/verify, cookie helpers
│ └── models.ts # TypeScript interfaces (User, Blog)
├── app/
│ ├── layout.tsx # Root layout with fonts
│ ├── globals.css # Dark theme + prose styles
│ ├── page.tsx # Root redirect (→ /auth or /home)
│ ├── auth/
│ │ ├── page.tsx
│ │ └── auth-client.tsx # Login/register client component
│ ├── home/
│ │ └── page.tsx # Blog list, create, edit, read
│ └── api/
│ ├── auth/
│ │ ├── login/route.ts
│ │ ├── register/route.ts
│ │ ├── logout/route.ts
│ │ └── me/route.ts
│ └── blogs/
│ ├── route.ts # GET (list/search), POST (create)
│ └── [id]/route.ts # GET, PUT, DELETE single entry
Copy .env.example to .env.local and fill in the values. Defaults are set for local development:
| Variable | Required in production | Default | Description |
|---|---|---|---|
MONGODB_URI |
Yes | mongodb://localhost:27017/ |
MongoDB connection string |
MONGODB_DB |
No | personal_blog |
Database name |
JWT_SECRET |
Yes | (dev-only fallback) | Secret for JWT signing |
NEXT_PUBLIC_SITE_URL |
Recommended | — | Public URL, used for metadata/social cards |
Generate a strong JWT_SECRET with:
openssl rand -base64 32The app refuses to boot in production if
MONGODB_URIorJWT_SECRETare missing, so misconfigurations surface immediately instead of failing silently.
npm run build
npm startThe app will start on port 3000 by default.
-
Create a MongoDB Atlas database (free tier works fine)
- Create a cluster at mongodb.com/cloud/atlas
- Add a database user and allow access from anywhere (
0.0.0.0/0) under Network Access — Vercel functions use ephemeral IPs, so IP allowlists won't work - Grab the SRV connection string (
mongodb+srv://user:password@cluster...)
-
Push the repository to GitHub, then import it on vercel.com/new
Vercel auto-detects Next.js — no build settings needed.
-
Add environment variables in your Vercel project (Settings → Environment Variables):
Variable Value MONGODB_URIYour Atlas connection string MONGODB_DBpersonal_blogJWT_SECRETOutput of openssl rand -base64 32NEXT_PUBLIC_SITE_URLhttps://your-domain.vercel.app -
Deploy
Every push to the main branch triggers a new deployment.
Alternatively, deploy straight from the CLI:
npx vercel --prodThe app ships with complete SEO/social metadata:
- Title template (
Sign in · Personal Blog, etc.) per route - Open Graph image generated at build time (
src/app/opengraph-image.tsx) - Parchment-toned favicon (
src/app/icon.svg) and browser theme color - Search engines are told not to index the site by default since all content is private.
To make it indexable, change the
robotsentry insrc/app/layout.tsx.
This project is licensed under the MIT License. See LICENSE for details.
