Agent skill
recovery-coach-patterns
Follow Recovery Coach codebase patterns and conventions. Use when writing new code, components, API routes, or database queries. Activates for general development, code organization, styling, and architectural decisions in this project.
Install this agent skill to your Project
npx add-skill https://github.com/curiositech/some_claude_skills/tree/main/.claude/skills/recovery-coach-patterns
Metadata
Additional technical details for this skill
- tags
-
recovery patterns next-js
- category
- Lifestyle & Personal
- pairs with
-
[ { "skill": "recovery-social-features", "reason": "Social features follow the same Recovery Coach codebase patterns and conventions" }, { "skill": "recovery-app-onboarding", "reason": "Onboarding components must follow Recovery Coach coding patterns and API conventions" }, { "skill": "vitest-testing-patterns", "reason": "Recovery Coach components need unit tests following established testing patterns" } ]
SKILL.md
Recovery Coach Development Patterns
This skill helps you follow the established patterns and conventions in the Recovery Coach codebase.
When to Use
✅ USE this skill for:
- Writing new components, pages, or API routes in Recovery Coach
- Following established code organization patterns
- Implementing database queries with Drizzle ORM
- Understanding project architecture and conventions
- Styling components to match the design system
❌ DO NOT use for:
- Crisis intervention implementation → use
crisis-response-protocol - General Next.js questions → use Next.js docs
- AI/LLM integration patterns → use
modern-drug-rehab-computer - Content moderation → use
recovery-community-moderator
Project Structure
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes (REST endpoints)
│ │ ├── auth/ # Authentication endpoints
│ │ ├── check-in/ # Daily check-in endpoints
│ │ ├── chat/ # AI coaching endpoints
│ │ └── admin/ # Admin-only endpoints
│ ├── admin/ # Admin dashboard page
│ ├── settings/ # User settings page
│ └── page.tsx # Home page
├── components/ # React components
│ ├── ui/ # Base UI components (Button, Card, etc.)
│ └── *.tsx # Feature components
├── lib/ # Core business logic
│ ├── ai/ # Anthropic integration
│ ├── hipaa/ # HIPAA compliance utilities
│ ├── auth.ts # Authentication
│ ├── db.ts # Database connection
│ └── rate-limit.ts # Rate limiting
├── db/ # Database schema (Drizzle ORM)
│ ├── schema.ts # Table definitions
│ └── secure-db.ts # RLS-enforced queries
└── test/ # Test utilities
features/ # Feature manifests (YAML)
docs/ # Documentation
scripts/ # Build and utility scripts
API Route Pattern
// src/app/api/[feature]/route.ts
import { NextResponse } from 'next/server';
import { getSession } from '@/lib/auth';
import { createRateLimiter } from '@/lib/rate-limit';
import { logPHIAccess } from '@/lib/hipaa/audit';
import { z } from 'zod';
// 1. Define rate limiter
const rateLimiter = createRateLimiter({
windowMs: 60000,
maxRequests: 30,
keyPrefix: 'api:feature'
});
// 2. Define input schema
const RequestSchema = z.object({
field: z.string().min(1).max(1000),
});
export async function POST(request: Request) {
// 3. Check authentication
const session = await getSession();
if (!session) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
// 4. Apply rate limiting
const rateLimitResult = await rateLimiter.check(session.userId);
if (!rateLimitResult.allowed) {
return NextResponse.json(
{ error: 'Rate limit exceeded' },
{ status: 429, headers: rateLimitResult.headers }
);
}
// 5. Parse and validate input
const body = await request.json();
const parsed = RequestSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: 'Invalid input', details: parsed.error.issues },
{ status: 400 }
);
}
// 6. Perform operation
const result = await performOperation(session.userId, parsed.data);
// 7. Audit log (if PHI)
await logPHIAccess(session.userId, 'feature', result.id, 'CREATE');
// 8. Return response
return NextResponse.json(result);
}
React Component Pattern
// src/components/FeatureComponent.tsx
'use client';
import { useState, useEffect } from 'react';
import { Button } from '@/components/ui/Button';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
interface FeatureProps {
id: string;
initialData?: FeatureData;
onComplete?: (result: Result) => void;
}
export function FeatureComponent({
id,
initialData,
onComplete
}: FeatureProps) {
const [data, setData] = useState<FeatureData | null>(initialData ?? null);
const [loading, setLoading] = useState(!initialData);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!initialData) {
fetchData();
}
}, [id]);
async function fetchData() {
try {
setLoading(true);
const res = await fetch(`/api/feature/${id}`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
setData(data);
} catch (e) {
setError(e instanceof Error ? e.message : 'Unknown error');
} finally {
setLoading(false);
}
}
if (loading) {
return <div className="animate-pulse">Loading...</div>;
}
if (error) {
return (
<Card className="border-destructive">
<CardContent>Error: {error}</CardContent>
</Card>
);
}
return (
<Card>
<CardHeader>Feature Title</CardHeader>
<CardContent>
{/* Content */}
</CardContent>
</Card>
);
}
Database Query Pattern
// Use secure-db for user data (RLS enforced)
import { db, users, checkIns } from '@/db/secure-db';
import { eq, desc } from 'drizzle-orm';
// Get user's own data (RLS automatically filters)
async function getUserCheckIns(userId: string) {
return db
.select()
.from(checkIns)
.where(eq(checkIns.userId, userId))
.orderBy(desc(checkIns.createdAt))
.limit(30);
}
// For admin queries, use requireAdmin
import { requireAdmin } from '@/db/secure-db';
async function getAdminStats() {
const admin = await requireAdmin();
if (!admin) throw new Error('Admin required');
// Now can query across all users
return db.select({ count: count() }).from(users);
}
Design System
Color Palette (Therapeutic)
/* From globals.css */
--navy: #1a365d; /* Primary - trust, stability */
--teal: #319795; /* Secondary - calm, healing */
--coral: #ed8936; /* Accent - warmth, energy */
--cream: #fffaf0; /* Background - comfort */
Time-Based Themes
function getTimeTheme(): 'dawn' | 'day' | 'dusk' | 'night' {
const hour = new Date().getHours();
if (hour >= 5 && hour < 9) return 'dawn';
if (hour >= 9 && hour < 17) return 'day';
if (hour >= 17 && hour < 21) return 'dusk';
return 'night';
}
Component Styling
// Use Tailwind with design tokens
<Button
className="bg-navy hover:bg-navy/90 text-white"
variant="default"
>
Primary Action
</Button>
<Card className="bg-cream border-teal/20">
<CardContent className="text-navy">
Therapeutic content
</CardContent>
</Card>
Testing Pattern
// src/lib/__tests__/feature.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
describe('Feature', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('loads and displays data', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ data: 'test' })
} as Response);
render(<FeatureComponent id="123" />);
await waitFor(() => {
expect(screen.getByText('test')).toBeInTheDocument();
});
});
it('handles errors gracefully', async () => {
vi.mocked(fetch).mockRejectedValueOnce(new Error('Network error'));
render(<FeatureComponent id="123" />);
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});
});
Error Handling
// Use structured error responses
interface APIError {
error: string;
code?: string;
details?: unknown;
}
// In API routes
return NextResponse.json<APIError>(
{
error: 'Validation failed',
code: 'VALIDATION_ERROR',
details: zodError.issues
},
{ status: 400 }
);
// In components
try {
await submitData();
} catch (e) {
if (e instanceof APIError) {
toast.error(e.message);
} else {
toast.error('An unexpected error occurred');
console.error(e); // Log for debugging, not shown to user
}
}
Environment Variables
Required variables (validated at startup):
# Authentication
SESSION_SECRET= # 32+ random characters
# AI Integration
ANTHROPIC_API_KEY= # Claude API key
# Database
DATABASE_URL= # SQLite path or connection string
# Optional
VAPID_PUBLIC_KEY= # Push notifications
VAPID_PRIVATE_KEY=
Pre-Commit Checklist
Before committing any changes:
-
npm run lintpasses -
npm run testpasses -
npm run feature:validatepasses - Feature manifest updated (if applicable)
- No secrets in code
- HIPAA compliance maintained (audit logs)
- Accessibility considered (semantic HTML, ARIA)
Common Imports
// Authentication
import { getSession, requireAuth } from '@/lib/auth';
// Database
import { db } from '@/db/secure-db';
import { eq, desc, and } from 'drizzle-orm';
// Audit
import { logPHIAccess, logSecurityEvent } from '@/lib/hipaa/audit';
// Rate limiting
import { createRateLimiter } from '@/lib/rate-limit';
// Validation
import { z } from 'zod';
// UI Components
import { Button } from '@/components/ui/Button';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { Input } from '@/components/ui/Input';
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
3d-cv-labeling-2026
Expert in 3D computer vision labeling tools, workflows, and AI-assisted annotation for LiDAR, point clouds, and sensor fusion. Covers SAM4D/Point-SAM, human-in-the-loop architectures, and vertical-specific training strategies. Activate on '3D labeling', 'point cloud annotation', 'LiDAR labeling', 'SAM 3D', 'SAM4D', 'sensor fusion annotation', '3D bounding box', 'semantic segmentation point cloud'. NOT for 2D image labeling (use clip-aware-embeddings), general ML training (use ml-engineer), video annotation without 3D (use computer-vision-pipeline), or VLM prompt engineering (use prompt-engineer).
project-management-guru-adhd
Expert project manager for ADHD engineers managing multiple concurrent projects. Specializes in hyperfocus management, context-switching minimization, and parakeet-style gentle reminders. Activate on 'ADHD project management', 'context switching', 'hyperfocus', 'task prioritization', 'multiple projects', 'productivity for ADHD', 'task chunking', 'deadline management'. NOT for neurotypical project management, rigid waterfall processes, or general productivity advice without ADHD context.
large-scale-map-visualization
Master of high-performance web map implementations handling 5,000-100,000+ geographic data points. Specializes in Leaflet.js optimization, Supercluster algorithms, viewport-based loading, canvas rendering, and progressive disclosure UX patterns.
adhd-design-expert
Designs digital experiences for ADHD brains using neuroscience research and UX principles. Expert in reducing cognitive load, time blindness solutions, dopamine-driven engagement, and compassionate design patterns. Activate on 'ADHD design', 'cognitive load', 'accessibility', 'neurodivergent UX', 'time blindness', 'dopamine-driven', 'executive function'. NOT for general accessibility (WCAG only), neurotypical UX design, or simple UI styling without ADHD context.
liaison
Translate multi-agent ecosystem activity into human-readable status briefings, decision requests, and progress summaries. Use for 'status update', 'brief me', 'what happened', 'summarize progress'. NOT for project planning (use project-management-guru-adhd), code review, or technical documentation.
windows-95-web-designer
Modern web applications with authentic Windows 95 aesthetic. Gradient title bars, Start menu paradigm, taskbar patterns, 3D beveled chrome. Extrapolates Win95 to AI chatbots, mobile UIs, responsive layouts. Activate on 'windows 95', 'win95', 'start menu', 'taskbar', 'retro desktop', '95 aesthetic', 'clippy'. NOT for Windows 3.1 (use windows-3-1-web-designer), vaporwave/synthwave, macOS, flat design.
Didn't find tool you were looking for?