Multi-profile Next.js 16 platform — portfolio surfaces + full admin OS underneath

The honest question every developer faces when building a portfolio: how much effort is justified for something that gets thirty seconds of a recruiter's attention? The default answer is minimal — a static site, a list of projects, a PDF resume link. I have seen hundreds of those. They are forgettable because they were designed to be fast to build, not to demonstrate anything.
I had a different calculation. A portfolio done seriously enough is also a ThemeForest-ready template — a product I can sell to other developers who want the same infrastructure without building it from scratch. Karmpath taught me this logic: if you are going to invest the time, design the output so it serves more than one purpose. So instead of a static site, I built a full-stack product that happens to be about me.
The scope that followed from that decision: a 27-page admin CMS so every project entry, blog post, and profile detail is live-editable from the browser. Three.js WebGL scenes for the hero sections. Real-time visitor presence via Soketi. Stripe-gated premium content for the ThemeForest upsell path. An AI chat assistant backed by RAG over my own project data. Zero hardcoded strings — every piece of content lives in the database and is editable without a deployment. The result is approximately 70,000 lines of code and a Lighthouse score of 100 across accessibility, best practices, and SEO.
That was the project at v1, around July 2025. Since then it has grown almost five-fold and changed shape.
The technically interesting decision in this project is the AI chat assistant, and the interesting part is not the chat interface — it is the retrieval layer underneath it.
Most developer AI chat integrations use a static system prompt: a description of who the developer is, what they have built, what their skills are. That works until the description goes stale, which it does the moment a new project ships and someone forgets to update the prompt. It also fails for specific queries — if someone asks "what projects has Karanveer built with Rust?" and Rust appears in three project descriptions but not the system prompt, the assistant has no way to answer accurately.
The solution was semantic retrieval via Qdrant over my project content. Every project description, tech stack, and milestone in the database is vectorised and indexed. When someone sends a message to the chat assistant, the query is vectorised and run against that index. The retrieved chunks are passed as context to the Claude API call alongside the user's question. The assistant does not hallucinate project details, because it retrieves them on demand rather than relying on a prompt I wrote once and may have forgotten to update.
The practical implication: the portfolio self-documents as I add projects. Every entry written in the admin CMS automatically becomes part of the retrieval corpus the next time the index syncs. The AI becomes more accurate as the portfolio grows, not less — which is the opposite of how a static system prompt ages. That is the difference between a retrieval system and a configuration file.
"Zero hardcoded data" was a constraint I set early and held to throughout the build. Every project entry, every tech tag, every metric and testimonial displayed on the homepage is read from the database at request time. The admin CMS — built with TipTap for rich-text editing — is the only interface through which content changes. No markdown files committed to git. No copy in environment variables. No JSON configuration to edit and redeploy.
The cost was real. This architecture requires a 27-page CMS that is genuinely usable, which means building a proper editor with image upload, rich-text formatting, slug generation, and live preview — not a textarea with a save button. That work took longer than the public-facing site.
The payoff was also real. When I needed to update a project description at 11pm without touching a deployment, I opened the admin panel and edited it. When the ThemeForest template is sold to another developer, they get the same live-edit capability over their own data. The constraint forced a better product because it eliminated the shortcut that would have made the template useless to anyone but me.
By early 2026 the project had crossed a line I did not plan for. The codebase was at roughly 325,000 lines across 505 commits. The admin surface had grown from 27 pages to 65+, covering not just content management but my entire working life: a resume builder I used to draft applications, a job tracker for ongoing applications, a client and project delivery tracker, invoicing and money-operations with GST-aware tax tracking, a content-health and audit dashboard, a backup pipeline, a newsletter and email system, AI-weight configuration and chat playgrounds, an editorial workflow with drafts and "currently thinking" notes, performance monitoring. Each of those started as a one-off feature; each grew until it deserved its own admin area.
At that point the code was no longer "my portfolio" — it was the substrate I ran my own engineering operation on. Calling it a portfolio undersold what it had become. The honest description was: a multi-profile Next.js platform where one of the profiles happens to be my public portfolio site.
The multi-profile architecture matters because it generalises the work. Profile content (project entries, blog posts, settings, design tokens, hero copy) lives under lib/profiles/<slug>/ as a self-contained tree — content data, MDX pages, settings, the lot. The platform code is profile-agnostic. A new profile is a new directory with the same shape; the routing layer reads the active profile slug and serves its content. A backup pipeline packs each profile into a .pack.zip portable bundle, which means a profile can be exported, edited externally, restored, or moved to another deployment. That is the difference between "my portfolio site" and "a platform that hosts profile sites."
The performance work that mattered most was the migration to Next.js 16's Cache Components model in late 2025 and into early 2026. The previous model — segment-level caching with revalidate exports and ad-hoc unstable_cache wrappers — had reached its limit. The newer model is finer-grained: 'use cache' directives at the function level, cacheLife profiles for TTL configuration, cacheTag for invalidation by tag rather than by path. The migration touched 227 files; the result is a warm TTFB on the homepage of 143–167 milliseconds, measured in production behind Cloudflare with the cache cold-started and then re-warmed.
The same migration enabled a separate piece of work — a shared <Canvas> for all r3f WebGL content. Earlier, each route with a 3D scene mounted its own Canvas, which meant a context recreation on every navigation and visible jitter under load. The route-aware chrome now holds a single Canvas at the layout level; individual scenes register as drei <View> portals pinned to specific DOM nodes. One WebGL context across every route. Memory pressure dropped sharply; navigation between scene-bearing pages is instant.
325,000 lines of code is a number that gets used as evidence of seriousness or as evidence of over-engineering, depending on who is reading. The question I ask honestly: does the complexity serve the story, or does it overshadow it?
My answer is that it serves it, because this platform is itself the most complete demonstration of how I work. The AI chat backed by Qdrant is not a gimmick — it is a retrieval system I designed, wired, and indexed against my own content. The zero-hardcoded-data architecture is not over-engineering — it is what makes the multi-profile model possible, which is what makes the platform a real platform rather than a custom website. The Lighthouse scores (a11y, best practices, and SEO at 100) are not vanity metrics — they reflect the same accessibility and performance standards I hold in client work. The 65+ admin surfaces are not scope creep — they are the answer to "what does it actually take to run a serious one-person engineering operation."
A simpler portfolio would tell you what I have built. This one shows you how I think about building things — including the bits I use every day to keep the rest of the work moving.
116 containers, one laptop, zero per-project setup
AI-Powered Blogging Platform
33-panel Tauri v2 + Svelte 5 macOS developer HUD with Rust sysinfo metrics, Docker management, and an embedded webhook server
Did this resonate?