# LESSONS.md - RateRight Growth Engine

> Hard-won knowledge from 30 years construction + 4 months coding. Read before every session.

Last Updated: Feb 2, 2026 (Cleaned & Organized by Rivet)

---

## Table of Contents

1. [Critical Rules](#-critical-rules)
2. [VPS & Infrastructure](#-vps--infrastructure)
3. [Database / Supabase](#-database--supabase)
4. [Frontend / React](#-frontend--react)
5. [AI Features](#-ai-features)
6. [Twilio / Voice](#-twilio--voice)
7. [Deployment / Railway](#-deployment--railway)
8. [Agent Orchestration](#-agent-orchestration)
9. [Build Protocol](#-build-protocol)
10. [Debugging](#-debugging)
11. [What NOT to Do](#-what-not-to-do)

---

## 🚨 Critical Rules

### Self-Improvement Protocol
- **AUTOMATIC: "Is there a lesson here?"** - After EVERY fix, immediately document
- **Three-layer capture:** (1) Fix in system, (2) Document in LESSONS.md, (3) Log to Notion
- **Agents share knowledge** - CC and Clawdbot sync via git every 30 min

### Context Management
- **Small batches only** - 4-5 fixes max per prompt
- **Push after each step** - Commit after each completed step
- **Plan files save you** - Always save state before context compacts
- **Never trust "I'll remember"** - Write it down or lose it

### The 200 Hour Rule
- Document everything as you go
- If it's not in a .md file, it doesn't exist
- Evidence archive before fixes

---

## 🖥️ VPS & Infrastructure

### Claude Code Setup
- **Can't run as root** - Use non-root user `ccuser`
- **User:** `ccuser` at `/home/ccuser`
- **Binary:** `/home/ccuser/.local/bin/claude`
- **Repo:** `/home/ccuser/rateright-growth`

### Clawdbot Config
- **Don't invent keys** - Use documented format only
- **Model format:** `"anthropic/claude-sonnet-4-20250514"`
- **Always backup:** `cp clawdbot.json clawdbot.json.bak`
- **Restart after changes:** `systemctl restart clawdbot-gateway`

### Memory Management
- **4GB RAM + 2GB swap** minimum for CC + MCP
- If CC freezes: check `free -h`

---

## 🗄️ Database / Supabase

### Patterns That Work
- Soft deletes: `deleted_at` column, filter with `WHERE deleted_at IS NULL`
- Phone numbers: E.164 Australian format (+614...)
- `supabaseAdmin` client for backend operations (bypasses RLS)
- `IF NOT EXISTS` on every CREATE/ALTER

### Critical Gotchas
- **RLS blocks backend reads AND writes** - Use `supabaseAdmin || supabase` pattern
- **Phone lookup must filter deleted** - Add `.is('deleted_at', null)` before `.maybeSingle()`
- **Supabase silently returns empty on non-existent columns** - Verify column names
- **Division by zero in UI** - Always check denominator > 0
- **Type field conventions** - Use `type: 'sms_outbound'` NOT `type: 'sms'`

### Migration Protocol (CLI)
```bash
npx supabase migration new [name]      # Create migration
npx supabase db push --linked          # Apply to remote
npx supabase migration list --linked   # Verify
```

---

## ⚛️ Frontend / React

### Patterns That Work
- `ErrorBoundary` wrapper on App.jsx
- React Query for caching
- Code splitting with lazy imports
- 44px minimum tap targets for mobile
- `useClickOutside` hook for dropdowns

### Critical Gotchas
- **Tailwind: Use `gap-*` not `space-y-*`** for Flex containers
- **NEVER use dynamic classes** - `bg-${color}-500` won't compile
- **NEVER use `<a href>` for internal links** - Use `<NavLink>`
- **Production build can be stale** - Rebuild after frontend changes
- **Use `100dvh` not `100vh`** on mobile

### Mobile
- **BottomNav is 80px** - Use `pb-24` minimum
- **Floating buttons** - Position `bottom-20` to clear nav
- **Touch scroll** - Track scroll distance to prevent accidental clicks

### Timezone (AEST)
- Server runs UTC, users in AEST (UTC+10)
- Use `getTodayStartAEST()` helper for "today" calculations

---

## 🤖 AI Features

### Rate Limits (Cost Control)
- Expensive AI ops: 5/min
- SMS sending: 100/hour
- Always add timeouts to external API calls

### Models
| Task | Model |
|------|-------|
| Complex reasoning | gpt-4o |
| Simple tasks | gpt-4o-mini |
| Transcription | whisper-1 |
| Live streaming | Deepgram Nova-2 |

### Gotchas
- **Never expose Deepgram key to frontend** - Use backend proxy
- **Cache AI content** - 2-hour cache, check `ai_last_analyzed_at`

---

## 📞 Twilio / Voice

### Setup
- Webhook URL must be HTTPS and public
- Phone numbers need country code (+61)
- Sydney edge server for Australian dial tones

### Gotchas
- **Inbound calls need recording config too**
- **Track duration through CallContext**
- **Deepgram can't access Twilio recordings directly** - Fetch with auth first

---

## 🚀 Deployment / Railway

### Deploy Process
```bash
cd admin && npm run build    # Build frontend
# Copy dist/* to public/
git add . && git commit -m "Deploy"
git push                      # Railway auto-deploys
```

### Gotchas
- **VITE_* vars needed at BUILD time** - Set in Railway dashboard
- **Railway auto-runs `npm run build`** - May need explicit buildCommand
- Check Railway logs immediately after deploy

---

## 🤖 Agent Orchestration

### CC Can Spawn Sub-Agents
- **Method:** `claude-cli --agent "task"` or programmatic
- **Use cases:** Parallel research, testing, documentation

### Hybrid Protocol Hierarchy
```
Michael (Reports bug)
    ↓
Rivet (COO) ← Approves/Rejects
    ↓  
Claude Code (Executor) ← Can spawn sub-agents
```

### Rules
1. CC maintains ownership - sub-agents assist
2. Small, focused tasks - 15-30 min work
3. Results aggregation before review request
4. Cost awareness - sub-agents increase tokens

---

## 🔧 Build Protocol

### Phases
1. **Investigate** - Read code, report gaps (don't write code yet)
2. **Plan** - Design solution, save to `docs/[feature]-plan.md`, wait for approval
3. **Execute** - One step at a time, push after each
4. **Test** - End-to-end, report results
5. **Document** - Update SYSTEM-INTEL.md, BUILD-GUIDE.md, LESSONS.md

### 0.1% Quality Check
- Would the best CRM do it this way?
- Is there any friction?
- Could AI make it smarter?
- One click when could be zero?

---

## 🐛 Debugging

### Before Fixing
1. Screenshot current state
2. Save evidence to archive
3. Write hypothesis
4. Get approval before changing

### Common Issues
| Symptom | Cause | Fix |
|---------|-------|-----|
| White screen | Auth crash | Mock client fallback |
| Missing data | Realtime disconnected | Check subscription |
| Slow loads | Too many API calls | Batch + cache |
| Build fails | Dynamic Tailwind | Static classes |

---

## ❌ What NOT to Do

- Big prompts with 8+ fixes (context loss)
- Dynamic Tailwind classes (won't compile)
- Hardcoded URLs (breaks deploys)
- Missing error handling on DB ops
- Exposing API keys to frontend
- Hard deleting data (use soft delete)
- Using `req.headers['x-user-id']` instead of `req.user?.id`
- Trusting memory over documentation
- Skipping the plan phase
- Deploying without testing build

---

*This file is updated by both CC and Rivet. Check git history for recent additions.*
