600552c858
Replace the manual "read .claude/agents/*.md" workflow with native Claude Code features for a more efficient, scalable development experience: - **Skills** (.claude/skills/): 7 auto-discovered slash commands (/requirements, /architecture, /frontend, /backend, /qa, /deploy, /help) with forked sub-agents for heavy tasks and inline execution for interactive ones - **Rules** (.claude/rules/): 4 modular rule files (general, frontend, backend, security) auto-applied based on file context - **Sub-Agents** (.claude/agents/): Lightweight configs for frontend-dev, backend-dev, and qa-engineer with model, tool, and turn limit settings - **Context Engineering**: Layered context loading, context isolation via forked skills, built-in context recovery after compaction, and "always read, never guess" rules to prevent hallucinated code references - **CLAUDE.md**: Auto-loaded project context replacing PROJECT_CONTEXT.md - **Feature tracking**: features/INDEX.md as persistent state across sessions - **Production guides**: docs/production/ for error tracking, security, performance, database optimization, and rate limiting - **Init Mode**: /requirements detects empty PRD and bootstraps full project setup (PRD + all feature specs) from a single project description Removed: 6 monolithic agent files, PROJECT_CONTEXT.md, HOW_TO_USE_AGENTS.md, TEMPLATE_CHANGELOG.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
2.3 KiB
Markdown
92 lines
2.3 KiB
Markdown
# Database Optimization
|
|
|
|
## 1. Indexing
|
|
|
|
Create indexes on columns used in WHERE, ORDER BY, or JOIN clauses:
|
|
|
|
```sql
|
|
-- Without index: ~500ms at 100k rows
|
|
SELECT * FROM tasks WHERE user_id = 'abc123' ORDER BY created_at DESC;
|
|
|
|
-- After creating index: <10ms
|
|
CREATE INDEX idx_tasks_user_id_created ON tasks(user_id, created_at DESC);
|
|
```
|
|
|
|
**Rule of thumb:** If a column appears in WHERE or ORDER BY and the table will have >1000 rows, add an index.
|
|
|
|
Always include indexes in your migration SQL alongside CREATE TABLE.
|
|
|
|
## 2. Avoid N+1 Queries
|
|
|
|
The most common performance problem with ORMs and query builders:
|
|
|
|
```typescript
|
|
// Bad: N+1 (1 query for users + N queries for tasks)
|
|
const { data: users } = await supabase.from('users').select('*')
|
|
for (const user of users) {
|
|
const { data: tasks } = await supabase
|
|
.from('tasks')
|
|
.select('*')
|
|
.eq('user_id', user.id)
|
|
}
|
|
|
|
// Good: Single query with join (1 query total)
|
|
const { data } = await supabase
|
|
.from('users')
|
|
.select('*, tasks(*)')
|
|
```
|
|
|
|
## 3. Always Limit Results
|
|
|
|
Never return unbounded results from the database:
|
|
|
|
```typescript
|
|
// Bad: Returns ALL rows
|
|
const { data } = await supabase.from('tasks').select('*')
|
|
|
|
// Good: Returns max 50 rows
|
|
const { data } = await supabase.from('tasks').select('*').limit(50)
|
|
|
|
// Better: Paginated
|
|
const { data } = await supabase
|
|
.from('tasks')
|
|
.select('*')
|
|
.range(0, 49) // First 50 rows
|
|
```
|
|
|
|
## 4. Caching Strategy
|
|
|
|
For data that changes rarely (dashboard stats, config, categories):
|
|
|
|
```typescript
|
|
import { unstable_cache } from 'next/cache'
|
|
|
|
export const getCategories = unstable_cache(
|
|
async () => {
|
|
const { data } = await supabase.from('categories').select('*')
|
|
return data
|
|
},
|
|
['categories'], // Cache key
|
|
{ revalidate: 3600 } // Refresh every hour
|
|
)
|
|
```
|
|
|
|
**When to cache:**
|
|
- Data that changes less than once per hour
|
|
- Expensive aggregation queries
|
|
- Data shared across all users (not user-specific)
|
|
|
|
**When NOT to cache:**
|
|
- User-specific data that changes frequently
|
|
- Real-time data (use Supabase Realtime instead)
|
|
|
|
## 5. Select Only What You Need
|
|
|
|
```typescript
|
|
// Bad: Fetches all columns
|
|
const { data } = await supabase.from('users').select('*')
|
|
|
|
// Good: Fetches only needed columns
|
|
const { data } = await supabase.from('users').select('id, name, avatar_url')
|
|
```
|