Vibe Coding with Structure: How I Tamed Chaos in PersonalFlow CRM Using Claude Code
A 6-month journey from 157 handlers to 10, and what it taught me about AI-assisted development
Table of Contents
Quick Summary (30 seconds)
Part I: The Descent into Chaos (5 min)
Part II: Discovery & Enlightenment (7 min)
Part III: The Transformation (10 min)
Part IV: Patterns That Scale (8 min)
Part V: Tools & Workflows (5 min)
Part VI: Your Action Plan (3 min)
Estimated reading time: 38 minutes | Quick scan: 8 minutes
Quick Summary
🎯 The Problem: AI writes code faster than humans can organize it
💡 The Solution: Structured methodologies that amplify AI capabilities
📊 The Result: 87% less code, 2x faster development, 5,000+ MAU
If you only read one section, jump to The Handler Factory Pattern — it’s the transformation that changed everything.
Part I: The Descent into Chaos
The Intoxicating Beginning
“AI can write code at the speed of thought — but without structure, you’ll end up lost in your own codebase.”
Three months ago, I started building PersonalFlow CRM, an AI-native personal relationship manager. Like many developers caught up in the AI revolution, I dove headfirst into vibe coding — letting Claude help me build at unprecedented speed.
The initial velocity was intoxicating:
✨ Features appeared in minutes, not hours
🚀 Complex algorithms materialized from simple prompts
💫 Boilerplate vanished with a few keystrokes
The Hidden Cost of Speed
But within three weeks, my codebase had turned into a labyrinth:
📁 PersonalFlow/
├── 📄 157 IPC handlers across 15 files
├── 📄 3,000 lines of nearly identical code
├── 📄 15+ services with duplicate initialization
└── 🔥 One very confused developer (me)
🚨 The Wake-Up Call: When adding a simple “delete contact” feature required modifying 7 files and I couldn’t remember which ones, I knew something had to change.
Part II: Discovery & Enlightenment
Standing on the Shoulders of Giants
My transformation began when I discovered the pioneers who had already solved these problems:
<div style=”background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; margin: 20px 0;”>
🏆 The Vibe Coding Hall of Fame
Gabriel Sena’s “Claude Code + SubAgents”
Taught me that tiny helpers deliver massive resultsLatinXinAI’s Complete Guide to Claude Code Templates
Showed me how to formalize templates and patternsThe AITMPL Project
Demonstrated the power of agents, commands, and hooks working in harmony“Read These 4 Claude Code Resources or You’re Using It Wrong”
Hammered home the importance of structure over speedVibe-Kanban
Became my task orchestrator, managing agent workflows like a pro
</div>
These resources didn’t just provide solutions — they fundamentally changed how I think about AI-assisted development.
Part III: The Transformation
🚦 Lesson 1: Everything Starts With claude.md
The AITMPL project’s emphasis on context files became my north star. Every feature now begins with a single source of truth:
<details> <summary><strong>📄 Click to see my `claude.md` structure</strong></summary>
# PersonalFlow CRM - Development Context
## Architecture Principles
PersonalFlow CRM follows these core architectural principles:
### 1. Service-Oriented Architecture
- Clear separation between main process, renderer, and business logic
- Services follow hierarchical initialization with dependency injection
- Graceful degradation for optional services
### 2. Type Safety
- Strict TypeScript typing throughout
- Consistent error handling with `ServiceResult<T>` interface
- Comprehensive type definitions in `src/types/`
### 3. IPC Communication
- Structured IPC pattern with type-safe handlers
- Domain-organized handlers (contact, organization, AI, etc.)
- Error handling at IPC boundaries
</details>
💡 Key Insight: “Context is king.” Without it, different AI sessions invent their own patterns. With it, every prompt stays aligned.
🧩 Lesson 2: SubAgents Are Your Team
Gabriel Sena’s revelation changed everything: “SubAgents aren’t just prompts — they’re specialized team members.”
<div style=”background: #f7f9fc; border-left: 4px solid #4F46E5; padding: 20px; margin: 20px 0;”>
My SubAgent Squad:
Agent Responsibility Saves Software Architect Service design, patterns 10 hrs/week Code Reviewer Architecture violations, security 15 hrs/week Test Engineer Test patterns, coverage 8 hrs/week Performance Optimizer Query optimization, caching 5 hrs/week
</div> <details> <summary><strong>👁️ See the Reviewer Agent in action</strong></summary>
You are a Code Reviewer for PersonalFlow CRM. Check for:
## Architecture Violations
- Services not extending BaseService
- Duplicate initialization patterns
- Missing error handling
## Security Issues
- SQL injection vulnerabilities
- Missing input validation
- Exposed sensitive data
</details>
Without the reviewer agent, inconsistency creeps in within days.
🎯 Lesson 3: Task Orchestration with Vibe-Kanban
The missing piece was task orchestration. Enter Vibe-Kanban — the ultimate agent task orchestrator:
<div style=”background: #EFF6FF; border: 2px solid #3B82F6; border-radius: 8px; padding: 20px; margin: 20px 0;”>
📊 Vibe-Kanban Magic:
# Automatically creates feature branches with AI context
$ vibe-kanban task create “Implement Company Intelligence”
✅ Creating branch: feature/company-intelligence
✅ Initializing AI context...
✅ Assigning to agents: [Architect, Backend, Frontend]
# Context follows when switching tasks
$ vibe-kanban task switch “Gmail Integration”
✅ Switching to branch: feature/gmail-oauth
✅ Loading context for 3 active agents...
✅ Resuming from: OAuth implementation step 3 of 5
Results:
🔄 Branch conflicts: Down 90%
⚡ Context switching: Instant
🚀 Feature completion: 3x faster
</div>
🔌 Lesson 4: MCP Servers - The Power Tools
Model Context Protocol (MCP) servers gave Claude direct access to my development environment. Here’s my actual stack that transformed how I work:
<div style=”background: #EFF6FF; border: 2px solid #3B82F6; border-radius: 8px; padding: 20px; margin: 20px 0;”>
🚀 My MCP Server Arsenal:
Server Purpose Game-Changing Feature context7 Code context management Intelligent library documentation & API references Playwright Browser automation E2E testing directly from Claude DeepGraph TypeScript TypeScript analysis Deep code understanding & refactoring DeepGraph React React component analysis Component dependency mapping
</div> <details> <summary><strong>⚙️ View my actual MCP configuration</strong></summary>
// .mcp.json - My complete MCP setup
{
“mcpServers”: {
“playwright”: {
“command”: “npx”,
“args”: [”-y”, “@automatalabs/mcp-server-playwright”]
},
“DeepGraph TypeScript MCP”: {
“command”: “npx”,
“args”: [”-y”, “mcp-code-graph@latest”, “microsoft/TypeScript”]
},
“DeepGraph React MCP”: {
“command”: “npx”,
“args”: [”-y”, “mcp-code-graph@latest”, “facebook/react”]
},
“context7”: {
“command”: “npx”,
“args”: [”-y”, “@upstash/context7-mcp”]
}
}
}
</details>
The context7 Revolution
<div style=”background: linear-gradient(135deg, #8B5CF6 0%, #EC4899 100%); color: white; padding: 20px; border-radius: 10px; margin: 20px 0;”>
⚡ Why context7 Changed Everything
Most developers don’t realize how much time they waste switching between documentation and code. context7 by Upstash solved this:
📚 Instant library docs: Claude gets real-time library documentation
🔍 API reference lookup: No more googling method signatures
🧠 Context preservation: Maintains code context across sessions
🚀 Zero config: Works immediately with any TypeScript/React project
Before context7: “Claude, how do I use React Query’s useMutation?”
Claude gives generic, possibly outdated answer
With context7: Claude has the exact, current API documentation and can generate perfect implementation code instantly.
</div>
Real MCP Usage Examples
<details> <summary><strong>🔧 See how these MCP servers work together</strong></summary>
// context7: Claude fetches the exact API docs
const { data, error } = await context7.getLibraryDocs(’react-query’, ‘useMutation’);
// DeepGraph TypeScript: Analyzes your codebase structure
const dependencies = await deepgraphTS.analyzeDependencies(’./src/services/ContactService.ts’);
// DeepGraph React: Maps component relationships
const componentTree = await deepgraphReact.getComponentHierarchy(’./src/components’);
// Playwright: Runs E2E tests directly
await playwright.test(’Contact creation flow’, async ({ page }) => {
await page.goto(’http://localhost:3000’);
await page.click(’button:has-text(”Add Contact”)’);
await page.fill(’input[name=”email”]’, ‘test@example.com’);
await page.click(’button:has-text(”Save”)’);
await expect(page.locator(’.contact-card’)).toContainText(’test@example.com’);
});
</details>
The Compound Effect
What makes this combination powerful isn’t just the individual tools — it’s how they work together:
context7 provides accurate library documentation
DeepGraph TypeScript understands your codebase structure
DeepGraph React maps your component relationships
Playwright validates everything actually works
🎮 The Result: Claude becomes a full-stack development environment that understands your code, has access to all documentation, and can test its own changes. No more copy-paste, no more context switching, no more “let me look that up.”
⚠️ Lesson 5: The Handler Explosion (150+ Handlers → 10)
This was my biggest transformation. Here’s the before and after:
<div style=”display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin: 20px 0;”> <div style=”background: #FEF2F2; border: 2px solid #EF4444; border-radius: 8px; padding: 15px;”>
❌ BEFORE: The 3,000-Line Nightmare
// contactHandlers.ts - One of 15 files
export function registerContactHandlers(
ipcMain: IpcMain,
services: Services
): string[] {
// 400+ lines just for contacts!
// Repeated for EVERY entity type
// Total: 3,000+ lines
}
157 handlers across 15 files
20 lines of boilerplate each
380ms registration time
</div> <div style=”background: #F0FDF4; border: 2px solid #22C55E; border-radius: 8px; padding: 15px;”>
✅ AFTER: The Knowledge Graph Solution
// HandlerFactory.ts - One abstraction to rule them all
export class HandlerFactory {
static createCrudHandlers(
ipcMain: IpcMain,
service: BaseService,
config: EntityConfig
): string[] {
// Just 10 universal handlers!
// Works for ALL entity types
// Total: 400 lines
}
}
10 universal handlers
87% less code
45ms registration time
</div> </div>
The Handler Factory Pattern
<details> <summary><strong>🏭 See the complete Handler Factory implementation</strong></summary>
export class HandlerFactory {
static createCrudHandlers(
ipcMain: IpcMain,
service: BaseService,
config: EntityConfig
): string[] {
const operations = [’create’, ‘update’, ‘delete’, ‘getById’, ‘getAll’];
return operations.map(op => {
const eventName = `${config.eventPrefix}:${op}`;
ipcMain.handle(eventName, async (event, ...args) => {
try {
const result = await service[op](...args);
return { success: true, data: result };
} catch (error) {
logger.error(`${config.entityName} ${op} failed`, error);
return { success: false, error: error.message };
}
});
return eventName;
});
}
}
</details>
Impact:
📉 Code reduction: 3,000 → 400 lines (87% less!)
📉 Handler count: 157 → 55 handlers (65% less!)
⚡ Registration time: 380ms → 45ms
😌 Maintenance: From nightmare to trivial
Part IV: Patterns That Scale
🛡️ The TypeScript Advantage for AI Coding
Here’s a crucial insight I discovered: TypeScript isn’t just for type safety — it’s a structural guide for AI.
<div style=”background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%); color: white; padding: 20px; border-radius: 10px; margin: 20px 0;”>
🎯 Pro Tip: TypeScript as AI Rails
When you define strict TypeScript interfaces, Claude and other LLMs:
Generate consistent code that matches your types
Catch errors before runtime
Suggest appropriate methods and properties
Maintain architectural patterns across sessions
// This interface becomes Claude’s blueprint
interface ServiceResult<T> {
success: boolean;
data?: T;
error?: string;
metadata?: Record<string, any>;
}
// Claude will ALWAYS follow this pattern
class ContactService {
async createContact(data: ContactData): Promise<ServiceResult<Contact>> {
// Claude knows exactly what to return
}
}
</div>
🎨 The Tailwind Revolution for LLM Development
Another game-changer: Tailwind CSS with inline styling descriptions.
<div style=”background: #FEFCE8; border: 2px solid #FDE047; border-radius: 10px; padding: 20px; margin: 20px 0;”>
💡 Critical Insight: Why Tailwind is Perfect for AI
Traditional CSS requires LLMs to:
Check the HTML structure
Navigate to CSS files
Understand cascading rules
Merge styles mentally
Result: Massive token consumption, context switching
With Tailwind:
// Everything Claude needs is RIGHT HERE
<div className=”flex items-center justify-between p-4 bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow”>
<span className=”text-gray-800 font-semibold”>Contact Name</span>
<button className=”px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600”>
Edit
</button>
</div>
Benefits:
🎯 Self-documenting styling
💾 70% fewer tokens used
🚀 Instant understanding of visual hierarchy
🔄 Consistent styling patterns
❌ No context switching to CSS files
</div>
🧱 Lesson 6: Guardrails Saved My Sanity
Following the “constraints enable creativity” mantra:
// .eslintrc.js
module.exports = {
rules: {
‘max-lines-per-function’: [’error’, { max: 50 }],
‘complexity’: [’error’, 10],
‘max-depth’: [’error’, 4],
‘@typescript-eslint/no-explicit-any’: ‘error’
}
}
# GitHub Actions
- name: Quality Gates
run: |
if [ $(jq ‘.total.lines.pct’ coverage/coverage-summary.json) -lt 70 ]; then
exit 1
fi
🎨 Creativity Through Constraints: These limits forced both me and Claude to write better, more modular code.
📖 Lesson 7: Logging Is Your Lifeline
One pattern that saved countless debugging hours:
<details> <summary><strong>📊 View the Logger Factory pattern</strong></summary>
class LoggerFactory {
private static instance: LoggerFactory;
private loggers: Map<string, winston.Logger> = new Map();
getLogger(service: string): winston.Logger {
if (!this.loggers.has(service)) {
const serviceLogger = winston.createLogger({
level: process.env.LOG_LEVEL || ‘info’,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({
filename: path.join(app.getPath(’logs’), `${service}.log`),
level: ‘error’
})
]
});
this.loggers.set(service, serviceLogger.child({ service }));
}
return this.loggers.get(service)!;
}
}
</details>
Why This Matters for AI Development:
🔍 AI-generated code often has subtle bugs
📍 Service-specific logs isolate issues quickly
⏱️ Performance metrics reveal AI-generated bottlenecks
🔄 Helps Claude understand system state in future sessions
📝 Lesson 8: Documentation as Code with VEST
Taking inspiration from LatinXinAI’s template-driven approach:
<div style=”background: #F3F4F6; border-radius: 10px; padding: 20px; margin: 20px 0;”>
The VEST Flow:
Vision → Epics → Stories → Tech Specs
## Vision
Enable automatic company tracking from professional networks
## Epics
1. Company Detection: Auto-extract from signatures
2. Industry Classification: LLM-powered categorization
3. Company Enrichment: Domain analysis
## User Stories
As a sales professional, I want:
- Automatic company change detection
- 85%+ classification confidence
- Company size estimation
## Tech Specs
- Transformers.js for local classification
- SQLite schema: companies, employments
- Confidence scoring (0-100 scale)
</div>
♻️ Lesson 9: The BaseService Pattern
The AITMPL project’s command patterns inspired this abstraction:
<details> <summary><strong>🏗️ View the BaseService implementation</strong></summary>
abstract class BaseService {
protected logger: Logger;
constructor(protected serviceName: string, protected db: DatabaseServiceType) {
this.logger = getLogger(serviceName);
this.initialize();
}
private async initialize(): Promise<void> {
try {
this.logger.info(’Starting initialization...’);
if (!this.db.isConnected()) {
this.logger.warn(’Database not connected, deferring initialization’);
return;
}
await this.initializeService();
this.logger.info(’Initialization complete’);
} catch (error) {
this.logger.error(’Initialization failed:’, error);
throw error;
}
}
protected abstract initializeService(): Promise<void>;
protected async withErrorHandling<T>(
operation: () => Promise<T>,
operationName: string
): Promise<ServiceResult<T>> {
try {
const result = await operation();
return { success: true, data: result };
} catch (error) {
this.logger.error(`Failed to ${operationName}:`, error);
return { success: false, error: error.message };
}
}
}
</details>
Eliminated: 675 lines of duplicated initialization code across services
Part V: Tools & Workflows
🛠️ The Essential Toolkit
<div style=”background: #F9FAFB; border: 1px solid #E5E7EB; border-radius: 10px; padding: 20px; margin: 20px 0;”>
Core Tools for Structured Vibe Coding:
Tool Purpose Impact claude.md Context persistence 100% consistency SubAgents Specialized expertise 38 hrs/week saved Vibe-Kanban Task orchestration 90% fewer conflicts context7 Library docs & API refs 80% less doc searching DeepGraph Code structure analysis 70% better refactoring Playwright E2E testing 95% test confidence TypeScript Structural rails for AI 75% fewer type errors Tailwind CSS Inline styling for LLMs 70% token savings ESLint Automated quality gates 60% bug reduction Logger Factory Debugging AI code 80% faster debugging
</div>
Part VI: Your Action Plan
⚡ Real Results After Implementation
<div style=”background: linear-gradient(135deg, #10B981 0%, #3B82F6 100%); color: white; padding: 25px; border-radius: 10px; margin: 30px 0;”>
📈 The Numbers Don’t Lie:
Metric Before After Change Code duplication 60% 24% ⬇️ 60% reduction Bug rate 12/week 3/week ⬇️ 75% reduction Development speed Baseline 2x ⬆️ 100% increase Test coverage 10% 70% ⬆️ 600% increase Debugging time 8 hrs/week 1.6 hrs/week ⬇️ 80% reduction Handler count 157 55 ⬇️ 65% reduction Branch conflicts 10/week 1/week ⬇️ 90% reduction </div>
📚 Essential Resources to Get Started
Gabriel Sena’s SubAgents Guide - Start here for agent patterns
LatinXinAI Templates - Complete template library
AITMPL Project - Battle-tested patterns
Vibe-Kanban - Task orchestration
context7 by Upstash - Library documentation MCP
MCP Documentation - Environment integration
TypeScript Strict Mode Guide - Type safety setup
Tailwind CSS - Inline styling system
🎯 Key Takeaways
<div style=”background: #FEF3C7; border: 2px solid #F59E0B; border-radius: 10px; padding: 20px; margin: 30px 0;”>
The 10 Commandments of Structured Vibe Coding:
Start with context (
claude.md) — it’s your north starUse TypeScript strictly — it guides AI toward consistent patterns
Embrace Tailwind CSS — inline styles save 70% of tokens
Create specialized SubAgents — tiny helpers, massive results
Orchestrate with tools — Vibe-Kanban prevents chaos
Connect with MCP servers — direct environment access
Log comprehensively — you’ll need it for AI-generated bugs
Implement guardrails — constraints enable creativity
Abstract aggressively — patterns like HandlerFactory scale
Refactor continuously — complexity creeps in daily
</div>
🤔 The Million Dollar Question
“Does structure constrain AI creativity?”
No. Structure gives AI:
🎯 Clear patterns to follow
🚀 Consistent context across sessions
🛡️ Guardrails preventing dangerous patterns
📈 Ability to build on previous work
⚡ Faster generation through templates
Structure amplifies AI. Chaos constrains it.
💬 Join the Conversation
What patterns have you discovered in your AI-assisted development? Have you experienced the handler explosion or discovered powerful MCP server workflows?
<div style=”background: #F3F4F6; padding: 20px; border-radius: 10px; margin-top: 40px;”>
About PersonalFlow CRM
An AI-native, privacy-first personal CRM built with Electron, React, and TypeScript.
🛠️ Tech Stack: Electron + React + TypeScript + SQLite + Transformers.js + Claude Code
🔗 GitHub: soon to be opened.
🎯 Mission: Empower professionals with intelligent, private relationship management
</div>
Did this help you tame your AI-generated chaos? Hit the ❤️ button and share with your fellow vibe coders!

