A minimal, beautiful personal blog platform with a hidden single-admin CMS.
- Public blog pages: home, blogs, blog detail, tags, about
- Hidden admin area (
/admin/*) with 404 behavior for unauthenticated access - One-time admin bootstrap flow (
/admin/bootstrap?token=...) - Post CRUD (draft/publish), featured posts, tags, views, site settings
- Tiptap editor with rich formatting + code blocks
- Catppuccin themes (Mocha dark / Latte light)
- Convex backend (schema, queries, mutations, auth)
| Technology | Purpose |
|---|---|
| Next.js 16.1.6 | App Router frontend |
| React 19 | UI runtime |
| Convex | Database + backend functions |
| Convex Auth | Password auth (single admin) |
| Tailwind CSS v4 | Styling |
| shadcn/ui | UI primitives |
| Framer Motion | Animations |
| Tiptap | Rich text editor |
- Node.js 20.9+
- npm
- Convex account
- Clone and install
git clone https://github.com/SharifdotG/blogsdotg.git
cd blogsdotg
npm install- Create local env file
cp .env.example .env.localUpdate .env.local values
- Generate auth keys for Convex Auth
node generateKeys.mjsCopy the printed JWT_PRIVATE_KEY and JWKS values.
- Create
ADMIN_BOOTSTRAP_SECRET(one-time)
Generate a secure one-time token and store it in your local .env.local, Convex, and Vercel environment variables. Examples (pick one):
- Node (cross-platform):
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"- PowerShell (Windows):
$b=New-Object byte[] 32; (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($b); [System.BitConverter]::ToString($b).Replace('-','').ToLower()- OpenSSL (macOS / Linux):
openssl rand -hex 32- Python:
python -c "import secrets; print(secrets.token_urlsafe(32))"Add the generated value to your .env.local (and the same value in Convex/Vercel):
ADMIN_BOOTSTRAP_SECRET=your-generated-secret
ADMIN_BOOTSTRAP_ENABLED=trueVisit the bootstrap page to create the first admin:
http://localhost:3000/admin/bootstrap?token=your-generated-secret
Important: after creating the admin, set ADMIN_BOOTSTRAP_ENABLED=false in .env.local, Convex, and Vercel and restart/redeploy. Treat ADMIN_BOOTSTRAP_SECRET as sensitive — do not commit it to source control.
- Set Convex environment variables
Set these in your Convex deployment (Dashboard > Settings > Environment Variables):
ADMIN_EMAILADMIN_BOOTSTRAP_SECRETADMIN_BOOTSTRAP_ENABLED(settruefor first bootstrap)CONVEX_SITE_URL(usehttp://localhost:3000for local dev)JWT_PRIVATE_KEY(fromgenerateKeys.mjs)JWKS(fromgenerateKeys.mjs)
- Run Convex and Next.js (two terminals)
# terminal 1
npx convex dev
# terminal 2
npm run dev- Bootstrap the admin account (first time only)
Open:
http://localhost:3000/admin/bootstrap?token=YOUR_ADMIN_BOOTSTRAP_SECRET
Create the admin with the same email as ADMIN_EMAIL.
- Disable bootstrap after admin is created
Set ADMIN_BOOTSTRAP_ENABLED=false in both:
.env.local- Convex environment variables
Then restart dev servers.
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_CONVEX_URL |
Yes | Convex deployment URL used by the React client |
ADMIN_EMAIL |
Yes | Allowed admin email |
ADMIN_BOOTSTRAP_SECRET |
Yes | One-time bootstrap token |
ADMIN_BOOTSTRAP_ENABLED |
Yes | Enable/disable bootstrap route (true/false) |
| Variable | Required | Purpose |
|---|---|---|
ADMIN_EMAIL |
Yes | Server-side admin authorization |
ADMIN_BOOTSTRAP_SECRET |
Yes (during bootstrap) | Protect sign-up bootstrap flow |
ADMIN_BOOTSTRAP_ENABLED |
Yes | Allow/disallow sign-up flow |
CONVEX_SITE_URL |
Yes | Auth domain for Convex Auth config |
JWT_PRIVATE_KEY |
Yes | Convex Auth JWT signing key |
JWKS |
Yes | Public JWK set for auth verification |
npm run dev— start Next.js dev servernpm run build— production buildnpm run start— run production server locallynpm run lint— run ESLint
blogsdotg/
├── convex/ # Convex schema, auth, queries, mutations
├── src/
│ ├── app/
│ │ ├── admin/ # Hidden admin area
│ │ ├── blogs/ # Blog list + detail pages
│ │ ├── tags/ # Tag discovery page
│ │ └── about/ # About page
│ ├── components/
│ │ ├── editor/ # Tiptap editor
│ │ ├── providers/ # Theme + Convex providers
│ │ ├── animations/ # Framer Motion wrappers
│ │ └── ui/ # shadcn/ui components
│ └── lib/ # Constants, helpers, utilities
├── generateKeys.mjs # JWT/JWKS key generator
└── README.md
- Fork this repository
- Clone your fork
- Add upstream remote
git remote add upstream https://github.com/SharifdotG/blogsdotg.git- Create a feature branch
git checkout -b feat/your-change- Make changes and validate
npm run lint
npm run build- Push and open a PR from your fork
Before opening PRs, sync with upstream:
git fetch upstream
git rebase upstream/mainThis repository now includes dedicated GitHub community files:
CONTRIBUTING.md— contribution workflow and expectationsCODE_OF_CONDUCT.md— collaboration standardsSECURITY.md— vulnerability reporting policyLICENSE— MIT licenseCODEOWNERS— default code ownership.github/PULL_REQUEST_TEMPLATE.md— standardized PR format.github/ISSUE_TEMPLATE/*— bug/feature issue templates
This project uses Convex + Next.js. Recommended deployment flow follows Convex official Vercel guidance.
- Create a new Vercel project from this GitHub repository
Set Build Command to:
npx convex deploy --cmd 'npm run build'At minimum:
CONVEX_DEPLOY_KEY(Production deploy key from Convex Dashboard)ADMIN_EMAILADMIN_BOOTSTRAP_SECRETADMIN_BOOTSTRAP_ENABLED
Notes:
- Keep
ADMIN_BOOTSTRAP_ENABLED=trueonly until first admin is created in production. - After bootstrap, set it to
falseand redeploy. - If using preview deployments with Convex preview backends, configure a Preview
CONVEX_DEPLOY_KEYas documented by Convex.
In your Convex production deployment, set:
ADMIN_EMAILADMIN_BOOTSTRAP_SECRETADMIN_BOOTSTRAP_ENABLEDCONVEX_SITE_URL(your production URL, e.g.https://your-domain.com)JWT_PRIVATE_KEYJWKS
After first successful deploy:
- Visit
https://your-domain.com/admin/bootstrap?token=... - Create admin account
- Disable bootstrap (
ADMIN_BOOTSTRAP_ENABLED=false) in Vercel + Convex - Redeploy
-
npm run lintpasses -
npm run buildpasses - Convex production env vars are configured
- Vercel build command overridden to Convex deploy wrapper
-
CONVEX_DEPLOY_KEYadded in Vercel - Bootstrap disabled after admin creation
MIT
© 2026 Sharif Md. Yousuf. dotG for Life (≧∇≦)ノ