skills/recovery-coach-patterns/SKILL.md
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.
npx skillsauth add curiositech/windags-skills recovery-coach-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Is this component handling user data?
├─ YES: Does it need real-time updates?
│ ├─ YES: Use Client Component with useEffect + fetch
│ └─ NO: Use Server Component with direct DB query
└─ NO: Is it interactive (forms, buttons, state)?
├─ YES: Use Client Component
└─ NO: Use Server Component
What data does this route access?
├─ Public data only → Basic rate limiting (100/min)
├─ User's own data → Auth + RLS + moderate rate limiting (30/min)
├─ Cross-user data → Auth + explicit permission check + PHI audit
└─ Admin data → requireAdmin() + strict rate limiting (10/min) + security audit
Who can access this data?
├─ User's own data only
│ └─ Use secure-db with RLS (filters automatically)
├─ Admin accessing any data
│ ├─ Call requireAdmin() first
│ └─ Log admin access with logSecurityEvent()
└─ System/background job
└─ Use regular db connection with explicit WHERE clauses
Symptoms: Using regular db instead of secure-db for user data queries
Detection: import { db } from '@/lib/db' in user-facing code
Fix:
import { db } from '@/db/secure-db'Symptoms: API route accepts unlimited requests, potential DoS
Detection: No createRateLimiter call in route handler
Fix:
rateLimitResult check before processingSymptoms: User health data appears in console.log or error messages
Detection: console.log or throw new Error containing user data
Fix:
logPHIAccess() for legitimate audit trailsSymptoms: API accepts malformed data, causing runtime errors
Detection: Missing z.object() schema or .safeParse() call
Fix:
.safeParse() and check success propertySymptoms: Component crashes when user logs out mid-session Detection: Assuming session exists without null checks Fix:
if (!session) before using session dataScenario: Add endpoint for users to submit daily wellness check-ins with mood and notes.
Expert Decision Process:
Implementation:
// src/app/api/check-in/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 { db, checkIns } from '@/db/secure-db';
import { z } from 'zod';
const rateLimiter = createRateLimiter({
windowMs: 60000,
maxRequests: 30, // Health data = moderate limit
keyPrefix: 'api:check-in'
});
const CheckInSchema = z.object({
mood: z.number().min(1).max(10),
notes: z.string().max(1000).optional(),
symptoms: z.array(z.string()).max(10)
});
export async function POST(request: Request) {
// Auth check (required for user data)
const session = await getSession();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Rate limiting (prevent abuse)
const rateLimitResult = await rateLimiter.check(session.userId);
if (!rateLimitResult.allowed) {
return NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 });
}
// Input validation (prevent bad data)
const body = await request.json();
const parsed = CheckInSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json({
error: 'Invalid input',
details: parsed.error.issues
}, { status: 400 });
}
// Database operation (RLS auto-filters to user's data)
const checkIn = await db.insert(checkIns).values({
userId: session.userId,
mood: parsed.data.mood,
notes: parsed.data.notes,
symptoms: parsed.data.symptoms,
createdAt: new Date()
}).returning();
// PHI audit log (required for health data)
await logPHIAccess(session.userId, 'check-in', checkIn[0].id, 'CREATE');
return NextResponse.json(checkIn[0]);
}
What novices miss: Skip rate limiting, forget PHI audit logging, use console.log for debugging user data What experts catch: Health data needs all security layers, RLS handles user isolation automatically
Pre-submit checklist for all code changes:
getSession() called for protected routes.safeParse() usedsecure-db for user data querieslogPHIAccess() called for health data operationsany typesDO NOT use this skill for:
crisis-response-protocol insteadrecovery-community-moderator insteadmodern-drug-rehab-computer insteadWhen to delegate:
crisis-response-protocolrecovery-community-moderatormodern-drug-rehab-computertools
Building resilient distributed systems with circuit breakers, retries with full-jitter exponential backoff, retry budgets (per-request 3-attempt + per-client 10% ratio per Google SRE), deadline propagation, and the cascading-failure math (4 layers × 3 retries = 64x amplification). Grounded in Resilience4j, Microsoft Cloud Patterns, AWS Architecture Blog (Marc Brooker), and Google SRE Book.
testing
Designing HTTP cache headers that work correctly across browsers, CDNs, and shared proxies — `Cache-Control` directives per RFC 9111, `stale-while-revalidate` and `stale-if-error` per RFC 5861, the Vary header for varying responses, and surrogate keys for tag-based purging. Grounded in IETF RFCs and Cloudflare/Fastly docs.
development
Use when designing or fixing a Content Security Policy on a real site, choosing between nonce-based and hash-based CSP, adding strict-dynamic, debugging "Refused to execute inline script" errors, deploying CSP in report-only mode first, configuring report-to / report-uri, or auditing an existing policy for unsafe-inline / unsafe-eval / wildcards. Triggers: "CSP blocks legitimate inline script", strict-dynamic, nonce-{RANDOM}, sha256-{HASH}, object-src none, base-uri none, frame-ancestors, Trusted Types, X-Content-Security-Policy obsolete, report-only vs enforced. NOT for general HTTP security headers (HSTS, COOP/COEP), Trusted Types deep dive, CORS configuration, or building a WAF.
tools
Choosing and operating an HTTP API versioning strategy that doesn't break clients — Stripe's date-based pinned versions, the Deprecation/Sunset header pair (RFC 9745 + RFC 8594), URI vs header vs media-type approaches, and the version-transformer pattern. Grounded in Stripe's published architecture and IETF RFCs.