Skip to content
recovery-coach-patterns logo

Recovery Coach Development Patterns

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,

SKILL.md

Full skill instructions

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:

  1. npm run lint passes
  2. npm run test passes
  3. npm run feature:validate passes
  4. Feature manifest updated (if applicable)
  5. No secrets in code
  6. HIPAA compliance maintained (audit logs)
  7. 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';

More skills from curiositech

cost-accrual-tracker logo
curiositech/some_claude_skills

cost-accrual-tracker

Track real-time API cost accrual during LLM execution. Activate on 'cost tracking', 'token usage', 'API costs', 'budget monitoring', 'usage metrics'. NOT for cost estimation, pricing tiers,

242 0
View
openapi-spec-writer logo
curiositech/some_claude_skills

openapi-spec-writer

Expert in writing OpenAPI 3.0/3.1 specifications for REST APIs. Specializes in schema design, documentation best practices, API-first development, and tooling integration. Generates comprehensive

242 0
View
websocket-streaming logo
curiositech/some_claude_skills

websocket-streaming

Implements real-time bidirectional communication between DAG execution engines and visualization dashboards via WebSocket. Covers connection management, typed event protocols, reconnection

242 0
View
windows-3-1-web-designer logo
curiositech/some_claude_skills

windows-3-1-web-designer

Modern web applications with authentic Windows 3.1 aesthetic. Solid navy title bars, Program Manager navigation, beveled borders, single window controls. Extrapolates Win31 to AI chatbots (Cue

242 0
View
drone-cv-expert logo
curiositech/some_claude_skills

drone-cv-expert

Expert in drone systems, computer vision, and autonomous navigation. Specializes in flight control, SLAM, object detection, sensor fusion, and path planning. Activate on "drone", "UAV", "SLAM",

242 0
View
logging-observability logo
curiositech/some_claude_skills

logging-observability

Structured logging, distributed tracing, and metrics for production applications. [What: OpenTelemetry setup, log level strategy, correlation IDs, SLI/SLO alerting thresholds, Grafana dashboard

242 0
View
form-validation-architect logo
curiositech/some_claude_skills

form-validation-architect

End-to-end form handling with react-hook-form, Zod schemas, validation patterns, error messaging, field arrays, and multi-step wizards. Use for complex forms, validation architecture, autosave,

242 0
View
code-review-checklist logo
curiositech/some_claude_skills

code-review-checklist

Generate context-aware code review checklists from PR diffs — tailored to language, codebase patterns, and team standards. Identifies what reviewers should focus on. NOT for automated code

242 0
View
recursive-synthesis logo
curiositech/some_claude_skills

recursive-synthesis

Orchestrate multi-agent collaborative document synthesis through 6 phases - Divergence, Synthesis, Commentary, Consolidation, Reality Check, Final Merge. Produces authoritative founding documents

242 0
View
sobriety-tools-guardian logo
curiositech/some_claude_skills

sobriety-tools-guardian

Performance optimization and continuous improvement for sobriety.tools recovery app. Use for load time optimization, offline capability, crisis detection, performance monitoring, automated

242 0
View
skill-coach logo
curiositech/some_claude_skills

skill-coach

Guides creation of high-quality Agent Skills with domain expertise, anti-pattern detection, and progressive disclosure best practices. Use when creating skills, reviewing existing skills, or when users mention improving skill quality, encoding expertise, or avoiding common AI tooling mistakes. Ac...

242 0
View
postgresql-optimization logo
curiositech/some_claude_skills

postgresql-optimization

Expert in PostgreSQL performance tuning, query optimization, and database administration. Specializes in EXPLAIN analysis, indexing strategies, connection pooling, partitioning, and production-grade

242 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View