Portfolio CMS (avnishyadav.com)
This site and its back office in one Next.js app
The Next.js site you are reading and its admin CMS: one content layer with design-copy fallback, four AI providers, and SQL changes tested before release.
Solo build
The problem
I write posts, ship projects and run a newsletter, and I wanted one place to do all of it: the public site and the back office in the same codebase, with AI help where it saves time. I also needed every page to render even when the database has nothing for it, and every database change to be checked before it reaches production.
What I built
The site you are reading. It is one Next.js App Router application with a public side (portfolio, blog, series,
projects, offers) and a password-protected admin at /admin where I edit content, draft posts and social copy with
AI, manage leads and send newsletters. As of October 2026 it has 43 editable content sections, 4 AI text providers
and 92 API routes. The code is private; this page describes how it is put together.
See it running
A recorded walkthrough of Portfolio CMS (avnishyadav.com) is on the way. Until then, the write-up and the diagram below show how it works.
How it fits together
One content layer for the site and its admin
- BrowserPublic pages and /admin behind loginPosts, projects, seriesNewslettersrequests
- Next.js serverNetlify: pages and 92 API routesCached with tagsAI: 4 text providersgetSection
- Content layer43 sections: DB row firstDesign copy fills gapsrow wins
- Tursolibsql/SQLite through Prisma 7SQL files applied twice first
How it works
Public pages read content through a single content layer. A registry lists each section, where it is stored (its
own table or a row in a generic content table) and which design copy it falls back to. The rule is simple: the
database row wins and the design copy fills whatever is missing, so a new section looks right before anyone edits
it. Reads are cached with tags, and saving a section invalidates its tag.
The AI module wraps four text providers, Anthropic, Google Gemini, OpenAI and DeepSeek, with Claude as the default and a fallback chain through the others. Images come from Gemini, OpenAI or Pollinations. Media lives in Cloudflare R2, email goes out through Resend, and the app runs on Netlify.
Production data lives in Turso. I don't use migrations against it: every schema or content change is a hand-written SQL file. Before I apply one, a script copies production into a local read-only replica, applies the file twice to a throwaway copy and compares the result, so a file that isn't safe to re-run is caught. A production build then runs on that copy and a link checker crawls it. CI repeats the apply-twice check on every push. Long-form series, like the Salesforce Headless 360 series (coming soon), are Markdown files in the repo built into the same kind of SQL file.
Status and links
Live at avnishyadav.com and in active development. The repository is private, so there is no code link. The counts above are taken from the code as of October 2026 and will change as the site grows.
Need something like this built?
I build AI automations, agents and Salesforce solutions for teams. Tell me what you want to automate and I’ll tell you honestly whether it’s a fit.
Comments
Loading comments...