Part 1: Building PhysicianTechnologist - Discovery and Initial Learning
A developer's journey from idea to production with AI pair programming. How a simple blog became a full-featured CMS with Claude Code.

Dr. Chad Okay
NHS Resident Doctor & Physician-Technologist
The Genesis: Why Another Blog Platform?
In March 2025, I found myself at a crossroads. As a physician-technologist passionate about clinical AI, I needed a platform to share insights about implementing AI in NHS settings. Medium felt too generic. WordPress too bloated. Ghost too expensive for what I needed. I wanted something that felt mine - a platform that could grow with my needs, showcase technical depth, and still be approachable for healthcare professionals.
Enter Claude Code - Anthropic's coding assistant that promised to accelerate development. Little did I know this would transform from a simple blog project into a masterclass in AI-assisted development, over-engineering, and the art of knowing when to stop.
The Initial Vision vs Reality
What I Thought I Was Building
A simple blog with markdown support, basic author profiles, maybe some search functionality. Deploy and forget. The usual developer fantasy of a weekend project that stays a weekend project.
What I Actually Built
Instead, I ended up with a full-featured CMS with role-based access control, AI-powered semantic search with vector embeddings, automated newsletter system with queue management, real-time analytics dashboard, content recommendation engine, and UK-localised healthcare platform with NHS compliance considerations.
The scope creep was real, but each addition taught valuable lessons about modern web development and AI collaboration.
First Steps: Learning Claude Code's Personality
Working with Claude Code felt different from traditional development or even GitHub Copilot. It wasn't just autocomplete on steroids - it was like having a senior developer who remembered context across sessions through the CLAUDE.md file, made architectural decisions (sometimes brilliant, sometimes overengineered), had strong opinions about TypeScript, testing, and code organisation, and could refactor entire systems with surprisingly few mistakes.
The Learning Curve
The first week was humbling. I'd ask for a "simple blog post component" and receive a fully typed React component, Zod validation schemas, API endpoint with standardised error handling, database migrations, RLS policies for Supabase, and test specifications that we never actually implemented.
Initially overwhelming, but I learned to embrace the thoroughness. Claude Code wasn't just writing code - it was teaching best practices by example.
Early Challenges: The "Simple" Blog Post
Creating the first blog post functionality revealed the complexity beneath simplicity.
Challenge 1: State Management Confusion
My initial approach was the classic useState and useEffect combo. Fetch posts, set state, render. Simple, right?
// My initial approach
const [posts, setPosts] = useState([]);
useEffect(() => { fetchPosts() }, []);
Claude suggested React Query with server-side rendering instead:
// Claude's suggestion - React Query with SSR
const { data: posts = initialPosts } = useQuery({
queryKey: ['posts'],
queryFn: postsQueries.all,
initialData: initialPosts, // From getServerSideProps
staleTime: 5 * 60 * 1000,
});
The shift from basic state management to React Query with server-side rendering was enlightening. Suddenly I had automatic caching, background refetching, optimistic updates, and proper loading states. It was like upgrading from a bicycle to a Tesla - overwhelming at first, but you quickly wonder how you lived without it.
Challenge 2: The Database Migration Dance
What started as a simple posts table evolved into something much more complex. Version 1 had three columns: id, title, and content. By version 8, we had 12 columns including slug management, status workflows, publication timestamps, and newsletter tracking fields.
-- Version 8: Reality
CREATE TABLE posts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
content TEXT NOT NULL,
excerpt TEXT,
image TEXT,
status TEXT CHECK (status IN ('draft', 'pending_review', 'published', 'archived')),
author_id UUID REFERENCES authors(id),
published_at TIMESTAMPTZ,
first_published_at TIMESTAMPTZ,
newsletter_sent_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
Each field told a story of a requirement discovered, a bug fixed, or a feature requested. The newsletter_sent_at field? Added after accidentally sending the same post three times. The first_published_at that never changes? Learned that one the hard way when republishing updated a post's publication date and broke the RSS feed chronology.
The Authentication Rabbit Hole
"Just add simple authentication," I said. Three days later, I emerged with Supabase Auth integration, JWT token management, role-based access control with super_admin, editor, and author roles, Row Level Security policies that took hours to debug, protected API routes, session management, and auth middleware patterns.
Claude Code implemented authentication like it was building for a Fortune 500 company. Overkill? Perhaps. But when I needed to add contributor roles later, the infrastructure was already there. Sometimes over-engineering is just future-proofing in disguise.
Key Learning: Embrace the Over-Engineering (Sometimes)
The platform is undeniably over-engineered for a personal blog. But this over-engineering taught me production patterns like error boundaries and proper logging, type safety that eliminated runtime surprises, scalability thinking with database indexes and caching strategies, and a security mindset around input validation and XSS protection.
The UK Localisation Surprise
One of Claude Code's most impressive moments was handling UK localisation. When I mentioned the platform was for UK healthcare, it automatically implemented British English spelling throughout (authorised not authorized, organisation not organization), proper date formatting showing "1 March 2025" not "March 1, 2025", and even added references to NHS, GMC, and NICE guidelines in comments.
// Automatically implemented throughout:
const formattedDate = new Date().toLocaleDateString('en-GB');
// "1 March 2025" not "March 1, 2025"
This attention to detail was beyond what I'd have thought to specify. It understood context in a way that felt almost human.
Reflections on Part 1
Looking back at the first phase, the journey from "I need a blog" to "I have a CMS" was both exhilarating and exhausting. Claude Code pushed me to build better than I would have alone, but also more than I needed.
What worked was the rapid prototyping with immediate feedback, learning modern patterns through implementation, and having a "senior developer" available 24/7. What didn't work as well was Claude's occasional tendency toward unnecessary complexity, inconsistencies that required manual fixes, and the constant temptation to add "just one more feature."
The surprise? Building with Claude Code wasn't just about writing code faster. It was about discovering what's possible when you remove the friction between idea and implementation. The real challenge became knowing when to stop building and start shipping.
Next in Part 2: I dive deep into architecture decisions, the database design that grew like a living organism, and why I chose Supabase over other solutions. Plus, the story of how vector embeddings entered a "simple blog" and why that actually made sense.
Navigate This Series
→ Next: Part 2: Architecture Decisions and Database Design
The Complete Series:
- •Part 1: Discovery and Initial Learning (You are here)
- •Part 2: Architecture Decisions and Database Design
- •Part 3: Claude Code Acceleration and Development
- •Part 4: Deployment, First Posts, and Future Vision
Stay tuned for:
- •Part 2: Architecture Decisions and Database Design
- •Part 3: Claude Code Acceleration and Development Workflow
- •Part 4: Deployment, First Posts, and Future Vision
Navigate This Series
→ Next: Part 2: Architecture Decisions and Database Design
The Complete Series:
- •Part 1: Discovery and Initial Learning (You are here)
- •Part 2: Architecture Decisions and Database Design
- •Part 3: Claude Code Acceleration and Development
- •Part 4: Deployment, First Posts, and Future Vision
Share this article

Dr. Chad Okay
I am a London‑based NHS Resident Doctor with 8+ years' experience in primary care, emergency and intensive care medicine. I'm developing an AI‑native wearable to tackle metabolic disease. I combine bedside insight with end‑to‑end tech skills, from sensor integration to data visualisation, to deliver practical tools that extend healthy years.