Rapid Full-Stack Prototyping
Build working full-stack web apps quickly (1-4 hours). Design first, code second, test third.
When to Use
- •User says "WEBAPP", "PROTOTYPE", "full-stack app", or "build a web application"
- •Need both backend API + frontend UI
- •Want speed + quality
What You'll Build
- •Stack: React + Vite + RESTful API (FastAPI/Express) + SQLite
- •Timeline: 1-4 hours from idea to working app
- •Output: Polished, functional prototype with keyboard shortcuts and clean UI
The 3-Step Process
Step 1: Design (5-10 min)
Create a text-based design showing:
UI LAYOUT:
[Header with Logo, Nav, Actions]
[Main Content - Left Sidebar | Center Panel | Right Info]
[Footer with Status]
USER INTERACTIONS:
1. Click "New" → Opens editor
2. Type text → Updates state
3. Press ⌘S → Saves via API
4. Click "History" → Opens panel
DATA MODELS:
- Item: {id, content, created_at}
- Revision: {id, item_id, content, timestamp}
API ENDPOINTS:
GET /api/items → List all
POST /api/items → Create new
GET /api/items/:id → Get one
PUT /api/items/:id → Update
GET /api/history/:id → Get revisions
Step 2: Get Approval (30 sec)
Show the design → User says "looks good" → Start coding
Step 3: Build (1-3 hours)
Use this stack (don't ask, just use):
- •Frontend: React + Vite
- •Backend: FastAPI (Python) or Express (Node)
- •Database: SQLite
- •State: useState + useEffect
Build in order:
- •Backend skeleton (30 min)
- •Core features (1-2 hours)
- •Polish + keyboard shortcuts (30 min)
- •Test with WEBTEST
Rules for Claude
✅ DO:
- •Design mock UI before any code
- •Use React + RESTful API (default)
- •Start coding immediately after approval
- •Add keyboard shortcuts (⌘S, ⌘/, etc.)
❌ DON'T:
- •Ask user to choose frameworks
- •Skip the design phase
- •Spend 30+ min researching simple features
- •Build custom solutions for standard problems
Core Principles
- •Design Before Code - Mock UI + interactions first, then build
- •Use What You Know - Familiar tools > "perfect" tools you don't know
- •Single Source of Truth - One state for each piece of data, sync explicitly
- •Right Tool for Job - Fighting a component's design? Wrong component
- •Test Early - Automated tests + real user feedback before launch
Default Stack (Use This)
Frontend: React + Vite Backend: FastAPI (Python) or Express (Node) Database: SQLite State: useState + useEffect Styling: Vanilla CSS
Why? Fast setup, familiar patterns, good docs, zero config database.
When to deviate:
- •User explicitly requests different stack → use their choice
- •User needs SEO/SSR → use Next.js instead of Vite
- •User says "no code" → suggest Bubble/Retool (explain trade-offs)
Choosing Libraries
When to add a library:
- •✅ Would take > 1 hour to build from scratch
- •✅ Well-maintained (updated in last 6 months)
- •✅ You need > 30% of its features
When to build it yourself:
- •✅ Can be done in < 30 lines of code
- •✅ Only need 10% of library features
- •✅ Fighting the library's design
Quick research (spend max 15 min):
# 1. Search WebSearch: "best [feature] library react 2025" # 2. Check npm npm info [package-name] # Look at: downloads/week, last publish, dependencies count # 3. Test # Try basic example - works in 15 min? Keep it. Doesn't? Try next option.
Examples:
// ❌ Don't need library for: fetch() // axios is overkill <textarea /> // don't force WYSIWYG when plain text works Intl.DateTimeFormat // moment.js is heavy // ✅ Use library for: <MarkdownEditor /> // complex parsing + preview <DiffViewer /> // diff algorithm is non-trivial <CodeEditor /> // syntax highlighting + LSP
Project Structure
project/ ├── backend/ │ ├── server.py # FastAPI app │ └── requirements.txt # Python deps ├── frontend/ │ ├── src/ │ │ ├── App.jsx # Main component │ │ ├── App.css # Styles │ │ └── main.jsx # Entry point │ ├── package.json │ └── vite.config.js # Vite config with proxy ├── launcher-script # CLI to start both servers ├── install.sh # Setup script └── README.md # Documentation
Build Workflow
Phase 0: Design (15-30 min)
See "The 3-Step Process" above - create text-based design with UI layout, interactions, data models, and API endpoints. Show to user → get approval → start coding.
Phase 1: Backend + Frontend Skeleton (30 min)
Backend:
# Define models → Create CRUD endpoints → Test with curl
# FastAPI example:
@app.get("/api/items")
async def list_items(): ...
@app.post("/api/items")
async def create_item(item: Item): ...
Frontend:
npm create vite@latest my-app -- --template react cd my-app && npm install # Configure vite.config.js proxy to backend # Test connection with /api/health endpoint
Phase 2: Core Features (1-2 hours)
- •Build one feature at a time
- •useState for local state, useEffect for side effects
- •Single source of truth (one canonical state, sync others from it)
- •Test each feature before moving to next
Phase 3: Polish (30 min)
// Add keyboard shortcuts
useEffect(() => {
const handleKeyDown = (e) => {
if (e.metaKey) {
if (e.key === 's') { e.preventDefault(); save(); }
if (e.key === '/') { e.preventDefault(); showHelp(); }
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
- •Add help modal (⌘/)
- •Add button active states
- •Add status feedback ("✓ Saved")
- •Add tooltips with keyboard shortcuts
Phase 4: Test (Use WEBTEST)
# Run automated tests WEBTEST # Triggers testing-webapps skill # Manual checks: # - All buttons work # - Data persists after save # - No console errors # - Keyboard shortcuts work
Common Mistakes
1. Multiple Sources of Truth
// ❌ Bad: Three states for same data
const [editorContent, setEditorContent] = useState('');
const [diffContent, setDiffContent] = useState('');
const [previewContent, setPreviewContent] = useState('');
// ✅ Good: One source, sync to views
const [content, setContent] = useState('');
useEffect(() => {
editorRef.current?.setContent(content);
}, [viewMode, content]);
2. Fighting Component Design
// ❌ Bad: Complex CSS to hide UI elements
.editor .toolbar { display: none !important; }
.editor .tabs { visibility: hidden !important; }
// ✅ Good: Use simpler component
<textarea value={content} onChange={e => setContent(e.target.value)} />
3. Hardcoded Config
// ❌ Bad
target: 'http://127.0.0.1:8765'
// ✅ Good
const port = process.env.VITE_BACKEND_PORT || '8765';
target: `http://127.0.0.1:${port}`
4. CORS Issues
# ✅ FastAPI CORS setup
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)
Code Patterns
Button States
.btn { background: #007bff; transition: 0.2s; }
.btn:hover { background: #0056b3; }
.btn.active { background: #28a745; box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
Status Feedback
const save = async () => {
try {
await saveToBackend();
setStatus('✓ Saved');
setTimeout(() => setStatus(''), 2000);
} catch (error) {
setStatus('❌ Error');
}
};
Help Modal
{helpOpen && (
<div className="modal" onClick={() => setHelpOpen(false)}>
<div className="content" onClick={e => e.stopPropagation()}>
<h3>⌨️ Shortcuts</h3>
<kbd>⌘ S</kbd> Save
<kbd>⌘ /</kbd> Help
</div>
</div>
)}
Launcher Script
Create a simple script to start both servers:
#!/usr/bin/env python3
import subprocess, webbrowser, time
# Start backend
backend = subprocess.Popen(
["uvicorn", "server:app", "--port", "8000"],
cwd="./backend"
)
# Start frontend
frontend = subprocess.Popen(
["npm", "run", "dev"],
cwd="./frontend"
)
time.sleep(2)
webbrowser.open("http://localhost:5173")
try:
backend.wait()
except KeyboardInterrupt:
backend.terminate()
frontend.terminate()
Make executable: chmod +x launcher
Quick Reference
Testing Checklist
# Automated WEBTEST # Use testing-webapps skill # Manual - [ ] All buttons work - [ ] Keyboard shortcuts (⌘S, ⌘/) - [ ] Data persists - [ ] No console errors
When to Add a Feature
- •Solves real problem? ✓
- •Can be done simply? ✓
- •Fits core purpose? ✓
If any = no → defer it
When to Refactor
- •Code duplicated 3+ times
- •Fighting component design
- •Adding features getting harder
View Modes Pattern
const [viewMode, setViewMode] = useState('edit');
const [content, setContent] = useState('');
{viewMode === 'edit' && <Editor value={content} onChange={setContent} />}
{viewMode === 'diff' && <DiffView content={content} previous={prev} />}
{viewMode === 'preview' && <Preview content={content} />}
Debugging
- •Console errors (browser + terminal)
- •Network tab (API responses)
- •React DevTools (state flow)
- •Use right component for the job?
Success Criteria
- •✅ Core features work end-to-end
- •✅ Keyboard shortcuts (⌘S, ⌘/)
- •✅ No console errors
- •✅ Data persists
- •✅ Clean UI, no glitches
Real Example: mdedit (3 hours total)
Stack: React + Vite + FastAPI + SQLite Features: 4 view modes, version history, visual diff, keyboard shortcuts
Key Decisions (38 min research):
- •FastAPI > Flask (type hints, async)
- •SQLite > Postgres (zero config)
- •Toast UI Editor for rich editing, but textarea for diff mode (fighting component = wrong tool)
- •react-diff-viewer (GitHub-style, simple)
- •marked for preview (lightweight)
Lesson: Don't fight components with CSS. Use simpler alternatives when needed.
Key Reminders
Design → Code → Test
- •Mock UI + interactions first
- •Use defaults (React + RESTful)
- •WEBTEST when done
Red Flags:
- •Complex CSS hiding → wrong component
- •Multiple states for same data → refactor
- •Fighting a library → use different one
- •
30 min on one bug → rethink approach
Best Prototypes Are:
- •Fast (1-4 hours)
- •Simple (easy to change)
- •Polished (shortcuts + help)
- •Tested (no errors)