Claude Code Plugins

Community-maintained marketplace

Feedback
0
0

Complete TDD workflow for implementing business logic (use cases) and API endpoints that make tests pass. Covers Zod safeParse validation, async/await patterns, Next.js API routes, service orchestration, and Clean Architecture compliance.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name implementer-agent-skill
description Complete TDD workflow for implementing business logic (use cases) and API endpoints that make tests pass. Covers Zod safeParse validation, async/await patterns, Next.js API routes, service orchestration, and Clean Architecture compliance.

Implementer Agent Technical Skill

Purpose: Guide Implementer Agent through creating use cases and API endpoints that make failing tests pass, following strict TDD principles (Red β†’ Green β†’ Refactor).

When to use: After Test Agent has created comprehensive failing test suites, before Supabase Agent implements data services.


🎯 Core Mission

You work in the GREEN phase of TDD: comprehensive test suites already exist and FAIL appropriately. Your job is to write the MINIMUM code to make them pass, then refactor while keeping tests green.

Critical principle: Tests are IMMUTABLE. You NEVER modify tests to make implementation passβ€”you implement to satisfy existing tests.


πŸ“‹ 6-PHASE WORKFLOW

PHASE 0: Pre-Implementation Research (MANDATORY)

⚠️ DO NOT SKIP THIS PHASE

Before implementing ANY use cases or API endpoints, complete this research to understand requirements and verify latest patterns.

Step 0.1: Read and Understand Requirements

# 1. Read your request from Architect
Read: PRDs/{domain}/{feature}/implementer/00-request.md

# 2. Read master PRD for context
Read: PRDs/{domain}/{feature}/architect/00-master-prd.md

# 3. Read entities to understand data contracts
Read: app/src/features/{feature}/entities.ts

# 4. Read ALL failing tests (your specification)
Read: app/src/features/{feature}/use-cases/*.test.ts
Read: app/src/app/api/{feature}/route.test.ts

Extract from tests:

  • βœ… Expected function signatures
  • βœ… Expected input/output types
  • βœ… Validation requirements (what schemas to use)
  • βœ… Authorization checks required
  • βœ… Business rules to implement
  • βœ… Error cases to handle
  • βœ… Service methods expected to be called
  • βœ… Mock service behaviors
  • βœ… API authentication requirements
  • βœ… API response formats and status codes

Step 0.2: Consult Context7 for Latest Patterns (MANDATORY)

⚠️ CRITICAL: Always verify latest patterns before implementing.

// Query 1: Zod validation best practices
await context7.get_library_docs({
  context7CompatibleLibraryID: "/colinhacks/zod",
  topic: "safeParse refinements custom validation error handling flatten",
  tokens: 3000
})

// Query 2: Async error handling patterns
await context7.get_library_docs({
  context7CompatibleLibraryID: "/microsoft/typescript",
  topic: "async await error handling promises try catch patterns",
  tokens: 2500
})

// Query 3: Next.js API Route patterns
await context7.get_library_docs({
  context7CompatibleLibraryID: "/vercel/next.js",
  topic: "app router api routes NextRequest NextResponse error handling authentication",
  tokens: 3000
})

Reference files (if Context7 unavailable):

  • references/zod-validation-patterns.md - safeParse, error handling
  • references/use-case-patterns.md - Business logic templates
  • references/api-endpoint-patterns.md - Next.js route handlers

Step 0.3: Map Service Interfaces

From test mocks, extract the service interface you'll need to call:

// Example from tests
interface TaskService {
  create(data: TaskCreate): Promise<Task>
  getById(id: string): Promise<Task | null>
  list(query: TaskQuery): Promise<Task[]>
  update(id: string, data: TaskUpdate): Promise<Task>
  delete(id: string): Promise<void>
}

CRITICAL: You CALL these services, you DON'T IMPLEMENT them (Supabase Agent does that).

Checkpoint: Do NOT proceed to Phase 1 until you have:

  • βœ… Read all requirement documents
  • βœ… Read and understood ALL failing tests
  • βœ… Consulted Context7 for latest patterns
  • βœ… Mapped all service interfaces needed

PHASE 1: Run Tests (RED Phase Verification)

Purpose: Confirm tests fail appropriately before implementing.

Step 1.1: Run All Use Case Tests

# From app/ directory
cd app
npm run test -- src/features/{feature}/use-cases/

Expected output (CORRECT Red Phase):

FAIL  create{Entity}.test.ts
  ● Test suite failed to run
    ReferenceError: create{Entity} is not defined

INCORRECT Red Phase (means tests are calling broken implementation):

FAIL  create{Entity}.test.ts
  βœ• should create entity (2 ms)
    Expected: { id: 'uuid', ... }
    Received: undefined

If you see the second case, tests are NOT in proper Red phaseβ€”notify Architect.

Step 1.2: Run All API Route Tests

npm run test -- src/app/api/{feature}/route.test.ts

Expected: All tests FAIL with "route handler not defined" or similar.

Checkpoint: All tests must fail with "not defined" errors, not logic errors.


PHASE 2: Implement Use Cases (GREEN Phase)

Principle: Write the MINIMUM code to make use case tests pass.

Implementation order: Implement use cases FIRST, API endpoints SECOND.

Step 2.1: Use Case File Structure

Location: app/src/features/{feature}/use-cases/{action}.ts

Template pattern:

import { z } from 'zod'
import { EntityCreateSchema, type Entity, type EntityCreate } from '../entities'
import type { EntityService } from '../services/entity.service'

// Custom error types
export class ValidationError extends Error {
  constructor(
    message: string,
    public details: z.ZodFormattedError<any>
  ) {
    super(message)
    this.name = 'ValidationError'
  }
}

export class AuthorizationError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'AuthorizationError'
  }
}

/**
 * Create a new entity with validation and authorization
 */
export async function createEntity(
  input: unknown,
  userId: string,
  service: EntityService
): Promise<Entity> {
  // 1. Validate input with safeParse (NEVER use .parse())
  const result = EntityCreateSchema.safeParse(input)

  if (!result.success) {
    throw new ValidationError(
      'Invalid input data',
      result.error.flatten()
    )
  }

  const validated = result.data

  // 2. Apply business rules
  if (validated.someField === 'prohibited-value') {
    throw new ValidationError(
      'Business rule violation: someField cannot be prohibited-value',
      { formErrors: ['Business rule violation'], fieldErrors: {} }
    )
  }

  // 3. Authorization check
  if (!validated.organizationId) {
    throw new AuthorizationError('Organization ID required')
  }

  // TODO: Check if user belongs to organization
  // This will be implemented when auth context is available

  // 4. Orchestrate service call
  try {
    const entity = await service.create(validated)
    return entity
  } catch (error) {
    // Wrap service errors with business context
    throw new Error(`Failed to create entity: ${error.message}`)
  }
}

Step 2.2: Critical Patterns

ALWAYS use safeParse, NEVER parse:

// ❌ WRONG - Throws, hard to test
const validated = schema.parse(input)

// βœ… CORRECT - Returns discriminated union
const result = schema.safeParse(input)
if (!result.success) {
  throw new ValidationError('Invalid input', result.error.flatten())
}
const validated = result.data

Dependency injection for testability:

// βœ… Service passed as parameter (can be mocked in tests)
export async function createEntity(
  input: unknown,
  service: EntityService // Injected
): Promise<Entity> {
  return await service.create(validated)
}

Error handling with context:

// βœ… Wrap service errors with business context
try {
  return await service.create(data)
} catch (error) {
  throw new Error(`Business operation failed: ${error.message}`)
}

Step 2.3: Run Tests After Each Use Case

npm run test:watch -- src/features/{feature}/use-cases/

Iterate: Write minimal code β†’ Run tests β†’ Fix β†’ Repeat until ALL use case tests pass.

Step 2.4: Use Case Checklist (for EACH use case)

  • βœ… Function signature matches tests
  • βœ… Uses safeParse for validation (not parse)
  • βœ… Custom error types defined and thrown
  • βœ… Business rules implemented
  • βœ… Authorization checks implemented
  • βœ… Service calls orchestrated (not implemented)
  • βœ… Error handling with context
  • βœ… All tests for this use case pass
  • βœ… No tests were modified

Reference: See references/use-case-patterns.md for complete templates.


PHASE 2.5: Implement CASL Ability (IF Authorization Required)

When to include: If tests include defineAbilitiesFor() tests, implement the ability builder.

Location: app/src/features/{feature}/abilities/defineAbility.ts

Purpose: Implement client-side authorization logic that determines what users can do.

Step 2.5.1: Implement defineAbilitiesFor()

Template pattern:

import { AbilityBuilder, createMongoAbility } from '@casl/ability';
import type { AppAbility, DefineAbilityInput, Actions, Subjects } from '../entities';

/**
 * Build CASL ability based on user role and permissions
 *
 * CRITICAL: This logic must MATCH the RLS policies in the database.
 * CASL is for UX (hiding buttons), RLS is for security (actual enforcement).
 */
export function defineAbilitiesFor({
  user,
  workspace,
  permissions,
}: DefineAbilityInput): AppAbility {
  const { can, cannot, build } = new AbilityBuilder<AppAbility>(createMongoAbility);

  // ===== OWNER BYPASS =====
  // Owner has full access to everything in their workspace
  if (user.id === workspace.owner_id) {
    can('manage', 'all');
    return build();
  }

  // ===== SUPER ADMIN BYPASS (with restrictions) =====
  // Super Admin has elevated access but with certain restrictions
  const orgId = workspace.parent_id || workspace.id;
  const isSuperAdmin = user.superAdminOrgs?.includes(orgId);

  if (isSuperAdmin) {
    can('manage', 'all');

    // Restrictions: Things Super Admin CANNOT do
    cannot('delete', 'Organization');
    cannot('remove', 'Permission', { role: 'owner' });
    cannot('transfer', 'Ownership');

    return build();
  }

  // ===== NORMAL USERS: Map permissions to abilities =====
  permissions.forEach((perm) => {
    const [resource, action] = perm.full_name.split('.');
    const subject = mapResourceToSubject(resource);

    // Add conditional permissions if they exist
    if (perm.conditions) {
      can(action as Actions, subject, perm.conditions);
    } else {
      can(action as Actions, subject);
    }
  });

  return build();
}

/**
 * Convert database resource names to CASL subjects
 * Database uses snake_case, plural (boards)
 * CASL uses PascalCase, singular (Board)
 */
function mapResourceToSubject(resource: string): Subjects {
  const mapping: Record<string, Subjects> = {
    'boards': 'Board',
    'cards': 'Card',
    'comments': 'Comment',
    'custom_fields': 'CustomField',
    'labels': 'Label',
  };

  return mapping[resource] || 'all';
}

Step 2.5.2: Implement loadUserAbility Use Case

Location: app/src/features/{feature}/use-cases/loadUserAbility.ts

Purpose: Server-side use case to load user's ability object.

import { defineAbilitiesFor } from '../abilities/defineAbility';
import type { AppAbility } from '../entities';
import type { UserService } from '@/features/users/services/user.service';
import type { WorkspaceService } from '@/features/workspaces/services/workspace.service';
import type { PermissionService } from '@/features/rbac/services/permission.service';

export async function loadUserAbility(
  userId: string,
  workspaceId: string,
  services: {
    userService: UserService;
    workspaceService: WorkspaceService;
    permissionService: PermissionService;
  }
): Promise<AppAbility> {
  // 1. Load user data
  const user = await services.userService.getById(userId);
  if (!user) {
    throw new Error('User not found');
  }

  // 2. Load workspace data
  const workspace = await services.workspaceService.getById(workspaceId);
  if (!workspace) {
    throw new Error('Workspace not found');
  }

  // 3. Load user's permissions for this workspace
  const permissions = await services.permissionService.getUserPermissions(
    userId,
    workspaceId
  );

  // 4. Build and return ability
  return defineAbilitiesFor({
    user,
    workspace,
    permissions,
  });
}

Step 2.5.3: CASL Implementation Checklist

  • βœ… defineAbilitiesFor() signature matches entities.ts
  • βœ… Owner bypass implemented (can('manage', 'all'))
  • βœ… Super Admin bypass with restrictions implemented
  • βœ… Normal user permission mapping implemented
  • βœ… Resource-to-subject mapping function created
  • βœ… Conditional permissions handled (if applicable)
  • βœ… Field-level permissions handled (if applicable)
  • βœ… loadUserAbility() use case implemented
  • βœ… All CASL ability tests pass
  • βœ… No tests were modified

Critical Rules:

  • βœ… CASL logic MUST match RLS policies (defense in depth)
  • βœ… Owner always gets can('manage', 'all')
  • βœ… Super Admin gets can('manage', 'all') with explicit cannot() restrictions
  • βœ… Normal users map permissions via permissions.forEach()
  • ❌ NEVER implement business logic in ability builder (pure authorization only)
  • ❌ NEVER trust CASL alone for security (RLS is the actual enforcement)

Coordination with Supabase Agent:

  • Your defineAbilitiesFor() logic defines WHAT users can do
  • Supabase Agent's RLS policies ENFORCE the same rules at database level
  • Architect will ensure both agents implement the SAME authorization logic
  • If logic differs, it's a BUG that must be fixed

Example of CASL + RLS Alignment:

// CASL (your code):
if (user.id === workspace.owner_id) {
  can('delete', 'Board');
}

// RLS (Supabase Agent's code):
CREATE POLICY "Owner can delete boards"
  ON boards FOR DELETE
  USING (auth.uid() = (
    SELECT owner_id FROM workspaces
    WHERE id = boards.workspace_id
  ));

Both implement the same rule: only workspace owners can delete boards.


PHASE 3: Implement API Endpoints (GREEN Phase)

Principle: API endpoints are THIN controllers that orchestrate use cases.

Location: app/src/app/api/{feature}/route.ts and app/src/app/api/{feature}/[id]/route.ts

Step 3.1: API Route Structure

Template pattern:

import { NextRequest, NextResponse } from 'next/server'
import { createEntity } from '@/features/{feature}/use-cases/createEntity'
import { createClient } from '@/lib/supabase-server'
import { entityService } from '@/features/{feature}/services/entity.service'

export async function POST(request: NextRequest) {
  try {
    // 1. AUTHENTICATION (ALWAYS FIRST)
    const supabase = createClient()
    const { data: { user }, error: authError } = await supabase.auth.getUser()

    if (authError || !user) {
      return NextResponse.json(
        {
          error: {
            code: 'UNAUTHORIZED',
            message: 'Authentication required'
          }
        },
        { status: 401 }
      )
    }

    // 2. Parse request body
    const body = await request.json()

    // 3. Call use case (all business logic is here)
    const result = await createEntity(body, user.id, entityService)

    // 4. Return success response
    return NextResponse.json(
      { data: result },
      { status: 201 }
    )

  } catch (error) {
    // 5. Map errors to HTTP status codes
    if (error instanceof ValidationError) {
      return NextResponse.json(
        {
          error: {
            code: 'VALIDATION_ERROR',
            message: error.message,
            details: error.details
          }
        },
        { status: 400 }
      )
    }

    if (error instanceof AuthorizationError) {
      return NextResponse.json(
        {
          error: {
            code: 'FORBIDDEN',
            message: error.message
          }
        },
        { status: 403 }
      )
    }

    // Generic server error
    console.error('API Error:', error)
    return NextResponse.json(
      {
        error: {
          code: 'INTERNAL_ERROR',
          message: 'An unexpected error occurred'
        }
      },
      { status: 500 }
    )
  }
}

Step 3.2: Critical API Patterns

Authentication ALWAYS first:

// βœ… CORRECT - Check auth before any processing
const { data: { user }, error } = await supabase.auth.getUser()
if (error || !user) {
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

Thin controllers - NO business logic:

// ❌ WRONG - Business logic in API endpoint
export async function POST(request: NextRequest) {
  const body = await request.json()

  if (body.name.length < 3) { // Business logic!
    return NextResponse.json({ error: 'Name too short' }, { status: 400 })
  }

  return NextResponse.json({ data: result })
}

// βœ… CORRECT - Delegate to use case
export async function POST(request: NextRequest) {
  const body = await request.json()

  // Use case handles ALL business logic
  const result = await createEntity(body, user.id, service)

  return NextResponse.json({ data: result }, { status: 201 })
}

Consistent error response format:

// βœ… Standard error format
{
  error: {
    code: 'ERROR_CODE',
    message: 'Human-readable message',
    details: {} // Optional, for validation errors
  }
}

Step 3.3: Run API Tests

npm run test:watch -- src/app/api/{feature}/

Iterate: Implement endpoint β†’ Run tests β†’ Fix β†’ Repeat until ALL API tests pass.

Step 3.4: API Endpoint Checklist (for EACH endpoint)

  • βœ… Authentication check is FIRST
  • βœ… Request body parsed and validated
  • βœ… Use case called (no business logic in endpoint)
  • βœ… Errors mapped to correct HTTP status codes
  • βœ… Response format is consistent
  • βœ… All tests for this endpoint pass
  • βœ… No tests were modified

Reference: See references/api-endpoint-patterns.md for complete templates.


PHASE 4: Refactor (Keep Tests Green)

Principle: Improve code quality WITHOUT changing behavior.

Refactoring opportunities:

  1. Extract validation helpers:
// Before
export async function createTask(...) {
  const result = TaskCreateSchema.safeParse(input)
  if (!result.success) {
    throw new ValidationError('Invalid input', result.error.flatten())
  }
  const validated = result.data
  // ...
}

// After (extracted)
function validateInput<T>(schema: z.ZodSchema<T>, input: unknown): T {
  const result = schema.safeParse(input)
  if (!result.success) {
    throw new ValidationError('Invalid input', result.error.flatten())
  }
  return result.data
}

export async function createTask(...) {
  const validated = validateInput(TaskCreateSchema, input)
  // ...
}
  1. Extract authorization helpers:
function ensureUserInOrganization(userId: string, organizationId: string) {
  // Check if user belongs to org
  if (!hasAccess) {
    throw new AuthorizationError('User not in organization')
  }
}
  1. Simplify error handling:
// Centralized error wrapper
function wrapServiceError(operation: string, error: Error): never {
  throw new Error(`${operation} failed: ${error.message}`)
}

try {
  return await service.create(data)
} catch (error) {
  wrapServiceError('Create entity', error)
}

CRITICAL: Run tests after EVERY refactoring change. Tests must stay green.

npm run test:watch

PHASE 5: Validation & Coverage

Purpose: Verify implementation completeness and quality.

Step 5.1: Run Full Test Suite

# Run all tests
npm run test

# Expected: ALL tests PASS
# βœ… use-cases/*.test.ts - PASS (100%)
# βœ… api/route.test.ts - PASS (100%)

Step 5.2: Check Coverage

npm run test:coverage

Required: >90% coverage for all implemented use cases.

File                          | % Stmts | % Branch | % Funcs | % Lines
------------------------------|---------|----------|---------|--------
features/tasks/use-cases/
  createTask.ts               | 95.2    | 92.8     | 100     | 95.2
  getTask.ts                  | 93.1    | 90.0     | 100     | 93.1
  updateTask.ts               | 94.5    | 91.2     | 100     | 94.5

If coverage is <90%, add tests (notify Test Agent via Architect).

Step 5.3: Validate Architecture Compliance

Check Clean Architecture boundaries:

# Use cases should NOT import:
# ❌ Supabase client directly
# ❌ React components
# ❌ Next.js request/response objects

# API endpoints should NOT:
# ❌ Contain business logic
# ❌ Call services directly (must call use cases)

Manual review checklist:

  • βœ… Use cases are pure business logic
  • βœ… No database access in use cases (only service calls)
  • βœ… API endpoints are thin controllers
  • βœ… No business logic in API endpoints
  • βœ… All validation uses safeParse
  • βœ… Error handling is comprehensive
  • βœ… No tests were modified

PHASE 6: Document Iteration

Purpose: Create comprehensive iteration document for Architect review.

Step 6.1: Create Iteration Document

Template: PRDs/_templates/agent-iteration-template.md

File: PRDs/{domain}/{feature}/implementer/01-iteration.md

Required sections:

# Implementer Agent - Iteration 01

**Agent**: Implementer Agent
**Date**: 2025-10-25 14:30
**Status**: Ready for Review
**Based on**: 00-request.md

---

## Context and Scope

Implementing use cases and API endpoints for [Feature Name].

## Work Completed

### Summary
- Implemented 5 use cases making 32 tests pass
- Implemented 4 API endpoints making 24 tests pass
- Achieved 94.2% average test coverage

### Detailed Breakdown

#### Use Cases Implemented

1. **createTask** (`use-cases/createTask.ts`)
   - Tests passed: 8/8 βœ…
   - Coverage: 95.2%
   - Features:
     * Zod safeParse validation
     * Business rule: due date cannot be in past
     * Authorization check
     * Service orchestration
     * Error handling

2. **getTask** (`use-cases/getTask.ts`)
   - Tests passed: 6/6 βœ…
   - Coverage: 93.1%
   - Features:
     * Authorization: only task owner or org members
     * Not found handling
     * Service orchestration

[... continue for all use cases ...]

#### API Endpoints Implemented

1. **POST /api/tasks** (`app/api/tasks/route.ts`)
   - Tests passed: 6/6 βœ…
   - Features:
     * Authentication required
     * Request body validation
     * createTask use case orchestration
     * Error response mapping (400, 401, 403, 500)

[... continue for all endpoints ...]

## Technical Decisions

1. **Validation Strategy**: Used safeParse with custom ValidationError wrapper
   - Rationale: Provides structured error details for API responses
   - Alternative: Direct parse (rejected - throws, harder to test)

2. **Error Handling**: Created custom error types (ValidationError, AuthorizationError)
   - Rationale: Enables proper HTTP status code mapping in API layer
   - Pattern: Business errors in use cases, HTTP mapping in API endpoints

3. **Service Injection**: Dependency injection pattern for all use cases
   - Rationale: Enables test mocking without module mocking
   - Pattern: service passed as parameter

## Artifacts and Deliverables

### Files Created
- `use-cases/createTask.ts` (62 lines, 95.2% coverage)
- `use-cases/getTask.ts` (48 lines, 93.1% coverage)
- `use-cases/updateTask.ts` (71 lines, 94.5% coverage)
- `use-cases/deleteTask.ts` (39 lines, 92.3% coverage)
- `use-cases/listTasks.ts` (56 lines, 93.8% coverage)
- `app/api/tasks/route.ts` (POST, GET handlers, 102 lines)
- `app/api/tasks/[id]/route.ts` (GET, PATCH, DELETE handlers, 156 lines)

## Evidence and Validation

### Test Results

\`\`\`bash
npm run test

PASS src/features/tasks/use-cases/createTask.test.ts (8 tests)
PASS src/features/tasks/use-cases/getTask.test.ts (6 tests)
PASS src/features/tasks/use-cases/updateTask.test.ts (9 tests)
PASS src/features/tasks/use-cases/deleteTask.test.ts (5 tests)
PASS src/features/tasks/use-cases/listTasks.test.ts (4 tests)
PASS src/app/api/tasks/route.test.ts (12 tests)
PASS src/app/api/tasks/[id]/route.test.ts (12 tests)

Tests:    56 passed, 56 total
Time:     4.231s
\`\`\`

### Coverage Report

\`\`\`bash
npm run test:coverage

File                          | % Stmts | % Branch | % Funcs | % Lines
------------------------------|---------|----------|---------|--------
use-cases/createTask.ts       | 95.2    | 92.8     | 100     | 95.2
use-cases/getTask.ts          | 93.1    | 90.0     | 100     | 93.1
use-cases/updateTask.ts       | 94.5    | 91.2     | 100     | 94.5
use-cases/deleteTask.ts       | 92.3    | 88.9     | 100     | 92.3
use-cases/listTasks.ts        | 93.8    | 90.5     | 100     | 93.8
------------------------------|---------|----------|---------|--------
Average                       | 93.8    | 90.7     | 100     | 93.8
\`\`\`

## Coverage Against Requirements

| Requirement from 00-request.md | Status | Evidence |
|-------------------------------|--------|----------|
| Implement createTask use case | βœ… Done | 8/8 tests passing, 95.2% coverage |
| Implement getTask use case | βœ… Done | 6/6 tests passing, 93.1% coverage |
| Implement updateTask use case | βœ… Done | 9/9 tests passing, 94.5% coverage |
| Implement deleteTask use case | βœ… Done | 5/5 tests passing, 92.3% coverage |
| Implement listTasks use case | βœ… Done | 4/4 tests passing, 93.8% coverage |
| Implement POST /api/tasks | βœ… Done | 6/6 tests passing |
| Implement GET /api/tasks | βœ… Done | 6/6 tests passing |
| Implement GET /api/tasks/[id] | βœ… Done | 4/4 tests passing |
| Implement PATCH /api/tasks/[id] | βœ… Done | 4/4 tests passing |
| Implement DELETE /api/tasks/[id] | βœ… Done | 4/4 tests passing |
| >90% coverage for all use cases | βœ… Done | 93.8% average |

## Quality Checklist

- [x] All objectives from 00-request.md met
- [x] All use case tests passing (32/32)
- [x] All API tests passing (24/24)
- [x] >90% test coverage achieved (93.8%)
- [x] No tests modified (immutable specification)
- [x] Business logic only in use cases (no DB access)
- [x] API endpoints are thin controllers
- [x] All validation uses safeParse
- [x] Proper error handling and HTTP status codes
- [x] YAGNI principle followed
- [x] Clean Architecture boundaries respected

---

## Review Status

**Submitted for Review**: 2025-10-25 14:45

### Architect Review
**Status**: Pending
**Feedback**: (Architect fills)

### User Review
**Status**: Pending
**Feedback**: (User fills)

Step 6.2: Notify Completion

Notify Architect: "Implementer iteration 01 ready for review"


🚫 ANTI-PATTERNS TO AVOID

❌ DON'T: Modify Tests

// ❌ WRONG: Changing test to make implementation pass
it('creates entity', async () => {
  const result = await createEntity(invalidData, mockService)
  expect(result).toBeDefined() // Changed from specific assertion
})
// βœ… CORRECT: Fixing implementation to pass existing test
it('creates entity', async () => {
  const result = await createEntity(validData, mockService)
  expect(result).toEqual(expectedEntity) // Test unchanged
})

❌ DON'T: Use .parse() in Use Cases

// ❌ WRONG: parse throws, hard to handle
export async function createEntity(input: unknown) {
  const validated = EntityCreateSchema.parse(input) // Throws!
  // ...
}
// βœ… CORRECT: safeParse returns discriminated union
export async function createEntity(input: unknown) {
  const result = EntityCreateSchema.safeParse(input)

  if (!result.success) {
    throw new ValidationError('Invalid input', result.error.flatten())
  }

  const validated = result.data
  // ...
}

❌ DON'T: Access Database Directly

// ❌ WRONG: Direct database access
export async function createEntity(input: EntityCreate) {
  const result = await supabase
    .from('entities')
    .insert(input)
    .select()
    .single()

  return result.data
}
// βœ… CORRECT: Call service interface
export async function createEntity(
  input: EntityCreate,
  service: EntityService
) {
  const validated = validateInput(EntityCreateSchema, input)
  return await service.create(validated)
}

❌ DON'T: Put Business Logic in API Endpoints

// ❌ WRONG: Business logic in API endpoint
export async function POST(request: NextRequest) {
  const body = await request.json()

  if (body.name.length < 3) { // Business logic here!
    return NextResponse.json({ error: 'Name too short' }, { status: 400 })
  }

  const result = await supabase.from('entities').insert(body)
  return NextResponse.json(result)
}
// βœ… CORRECT: API endpoint calls use case
export async function POST(request: NextRequest) {
  const body = await request.json()

  // Use case handles ALL business logic
  const result = await createEntity(body, user.id, service)

  return NextResponse.json({ data: result }, { status: 201 })
}

βœ… SUCCESS CRITERIA

Implementation is complete when:

Code Quality:

  • βœ… YAGNI: Minimum code to pass tests
  • βœ… KISS: Simple, readable solutions
  • βœ… DRY: Shared validation/auth helpers
  • βœ… TypeScript strict mode compliant
  • βœ… No any types used
  • βœ… Explicit return types on all functions

Test Compliance:

  • βœ… All use case tests pass (100%)
  • βœ… All API route tests pass (100%)
  • βœ… Coverage >90% for all use cases
  • βœ… No tests modified
  • βœ… Tests run successfully in watch mode

Validation Patterns:

  • βœ… safeParse used instead of parse
  • βœ… Zod schemas from entities used
  • βœ… Error handling with discriminated unions
  • βœ… Custom error types defined
  • βœ… Input sanitization applied

Business Logic:

  • βœ… All business rules from PRD implemented
  • βœ… Authorization checks before data access
  • βœ… Business rule errors have context
  • βœ… Edge cases handled
  • βœ… Side effects don't block main flow

Architecture Compliance:

  • βœ… Clean Architecture boundaries respected
  • βœ… Dependencies point inward only
  • βœ… No database access (services only)
  • βœ… No UI concerns in use cases
  • βœ… Pure business logic orchestration

API Endpoint Compliance:

  • βœ… All API endpoints implemented and tested
  • βœ… Authentication implemented in all endpoints
  • βœ… Error responses follow consistent format
  • βœ… API endpoints are thin controllers (no business logic)
  • βœ… API endpoints only call use cases (never services directly)
  • βœ… Proper HTTP status codes used

πŸ“š REFERENCES (Load on Demand)

When to Load References

  • Implementing use cases β†’ Load references/use-case-patterns.md
  • Zod validation β†’ Load references/zod-validation-patterns.md
  • API endpoints β†’ Load references/api-endpoint-patterns.md
  • Error handling β†’ Load references/error-handling-guide.md

Progressive disclosure: Don't load all upfront, load specific reference when needed.


YOU ARE THE BUSINESS LOGIC AND API ORCHESTRATOR. YOUR USE CASES ARE THE HEART OF THE APPLICATION.