Skip to main content

Development Workflow

Standard workflow for building features in the Mo app with two-phase testing approach.


Related Documentation:

  • Quality Gates & Deployment - 27 automated quality gates
  • See .claude/WORKFLOW_GUIDE.md in mo-app for git commands and troubleshooting

Workflow Overview​

1. Research
2. Plan Architecture (if complex)
3. Write Behavior Tests (Phase 1) ← Define expected behavior
4. Build ← Implement to pass tests
5. Write Implementation Tests (Phase 2) ← Verify details
6. Review
7. Verify
8. Document
9. Commit

Phase 1 vs Phase 2 Testing​

Why Two Phases?​

PhaseWhenPurposeExample
Phase 1Before buildingDefine expected behaviorUser can complete workout
Phase 2After buildingVerify implementationAPI correctly calculates volume

Phase 1 (Behavior Tests):

  • Written before implementation
  • Defines user requirements
  • Tests will fail initially (expected)
  • Acts as acceptance criteria

Phase 2 (Implementation Tests):

  • Written after implementation
  • Tests internal logic
  • Verifies edge cases
  • Ensures code coverage

Detailed Steps​

1. Research​

Goal: Understand what exists and what's needed.

Tasks:

  • Explore existing codebase for similar patterns
  • Identify files that need changes
  • Research dependencies or libraries needed
  • Check for existing solutions/components
  • Read project context (CLAUDE.md, MEMORY.md)

Tools:

  • Explore agent for codebase exploration
  • researcher agent for web/docs research
  • Glob/Grep for finding files

Duration: 5-30 min depending on complexity


2. Plan Architecture​

Goal: Design the solution before coding.

When to do this:

  • ✅ Complex features (multiple files)
  • ✅ New system components
  • ✅ Database schema changes
  • ✅ Major refactoring
  • ❌ Simple bug fixes
  • ❌ One-file changes

Tasks:

  • Design component/module structure
  • Identify all files to create/modify
  • Plan data flow and API contracts
  • Consider edge cases and error handling
  • Get user approval for complex changes

Tools:

  • Plan agent for complex features
  • Use Opus model for architectural decisions

Deliverable: Implementation plan with file list


3. Write Behavior Tests (Phase 1)​

Goal: Define expected behavior before building.

Test Types:

  • User workflow tests (E2E scenarios)
  • API contract tests (request/response)
  • Component behavior tests (user interactions)

Example - API Test:

// tests/api/workout.behavior.test.ts
describe('Workout API - User Behavior', () => {
it('should allow user to start a workout', async () => {
const response = await POST('/api/ppl/session', {
templateDayId: 'push-a',
exercises: [...]
});

expect(response.status).toBe(201);
expect(response.body).toHaveProperty('session');
expect(response.body.session.status).toBe('in_progress');
});

it('should reject workout without exercises', async () => {
const response = await POST('/api/ppl/session', {
templateDayId: 'push-a',
exercises: []
});

expect(response.status).toBe(400);
expect(response.body.error).toContain('exercises');
});

it('should prevent duplicate active sessions', async () => {
await POST('/api/ppl/session', { ... }); // First session

const response = await POST('/api/ppl/session', { ... }); // Duplicate

expect(response.status).toBe(400);
expect(response.body.error).toContain('active session');
});
});

Example - Component Test:

// tests/components/workout-page.behavior.test.tsx
describe('Workout Page - User Behavior', () => {
it('should display today\'s workout template', async () => {
render(<WorkoutPage />);

await waitFor(() => {
expect(screen.getByText('Push Day A')).toBeInTheDocument();
});
});

it('should allow user to start workout', async () => {
const user = userEvent.setup();
render(<WorkoutPage />);

const startButton = await screen.findByRole('button', { name: /start workout/i });
await user.click(startButton);

await waitFor(() => {
expect(screen.getByText(/exercise 1 of/i)).toBeInTheDocument();
});
});

it('should show error if API fails', async () => {
mockFetch.mockRejectedValue(new Error('API Error'));
render(<WorkoutPage />);

await waitFor(() => {
expect(screen.getByText(/failed to load/i)).toBeInTheDocument();
});
});
});

Important:

  • ✅ Tests will fail at this stage - that's expected
  • ✅ Focus on what should happen, not how
  • ✅ Write tests for happy paths AND error cases
  • ❌ Don't test implementation details yet

Deliverable: Failing tests that define requirements


4. Build​

Goal: Implement to make Phase 1 tests pass.

TDD Loop:

1. Run Phase 1 test → RED (fails)
2. Write minimal code to pass
3. Run test again → GREEN (passes)
4. Refactor if needed
5. Move to next test

Patterns to follow:

  • Components: Follow React patterns in .claude/rules/react.md
  • API routes: Follow API patterns in .claude/rules/api.md
  • TypeScript: No any, proper types

Auto-applied:

  • ESLint fixes (via hooks)
  • Prettier formatting (via hooks)
  • Type checking (TypeScript compiler)

Model: Use Sonnet for implementation

Implementation is done when: All Phase 1 tests pass


5. Write Implementation Tests (Phase 2)​

Goal: Verify implementation details and edge cases.

Test Types:

  • Unit tests: Pure functions, utilities, helpers
  • Integration tests: API + database interactions
  • Component tests: Rendering, state management
  • E2E tests: Full user flows (optional)

Example - Unit Test:

// tests/lib/fatigue.test.ts
describe('calculateFatigue', () => {
it('should calculate fatigue score from factors', () => {
const score = calculateFatigue({
volumeLoad: 0.8,
intensityFactor: 0.9,
frequency: 6,
recovery: { sleep: 7, energy: 3 }
});

expect(score).toBeGreaterThan(0);
expect(score).toBeLessThan(10);
});

it('should return 0 for no training load', () => {
const score = calculateFatigue({
volumeLoad: 0,
intensityFactor: 0,
frequency: 0,
recovery: { sleep: 8, energy: 5 }
});

expect(score).toBe(0);
});
});

Example - Integration Test:

// tests/api/progression.integration.test.ts
describe('Progression API Integration', () => {
beforeEach(async () => {
await resetTestDatabase();
await seedTestData();
});

it('should calculate fatigue from real sessions', async () => {
const response = await GET('/api/progression?days=14');

expect(response.status).toBe(200);
expect(response.body.fatigueScore).toBeGreaterThan(0);
expect(response.body.fatigueHistory).toHaveLength(14);
});

it('should return ready-to-progress exercises', async () => {
// Create sessions with consistent progress
await createProgressingSessions('bench-press', 5);

const response = await GET('/api/progression');

expect(response.body.readyToProgress).toContainEqual(
expect.objectContaining({ exerciseName: 'Bench Press' })
);
});
});

Coverage Goals:

  • ✅ 100% line coverage (enforced by pre-push gates)
  • ✅ All edge cases covered
  • ✅ Error paths tested
  • ✅ Happy paths verified

Why 100%?

  • Fitness data is sensitive - bugs can cause injury
  • Solo developer - need automated safety net
  • Prevents regressions during rapid development

Tools:

  • /test command to run tests
  • test-runner agent for analysis
  • Coverage reports in CI

6. Review​

Goal: Ensure code quality.

Checklist:

  • No TypeScript any types
  • Proper error handling
  • Auth checks in API routes
  • Zod validation for API inputs
  • Accessible UI (semantic HTML, ARIA labels)
  • No security vulnerabilities
  • Follows project patterns

Tools:

  • code-reviewer agent
  • /review command
  • ui-improver agent (for UI)
  • performance-analyzer agent (if critical)

7. Verify​

Goal: Confirm everything builds and works.

Tasks:

a) Run Build Pipeline

/build  # Runs: lint → typecheck → test → build

b) E2E Critical Flows (Required)

Pre-push hook runs these automatically (Gate 2.16):

npm run test:e2e:critical

Critical flows tested:

  • Auth: Sign in, sign out, session persistence
  • Onboarding: Complete flow, data persistence
  • Workout: Start session, log sets, complete
  • Progress: View history, see trends

Why required: UI bugs can cause injury - E2E tests prevent regressions

c) Accessibility Testing (Required)

Pre-push hook runs these automatically (Gate 2.17):

npm run test:axe

Pages tested:

  • All pages checked for WCAG 2.1 Level A & AA compliance
  • Color contrast, keyboard navigation, screen reader compatibility

Why required: App must be usable by everyone, including users with disabilities

d) Manual Browser Testing

  • Test in browser (localhost:3000)
  • Test on mobile (if UI changes)
  • Check console for errors
  • Verify data persists correctly

8. Document​

Goal: Capture knowledge for future.

What to document:

TypeWhenWhere
Inline commentsComplex logicCode files
JSDocPublic APIsCode files
Architecture decisionsMajor changesmo-arch/docs/architecture
API docsNew endpointsmo-arch/docs/api
Feature docsNew featuresmo-arch/docs/features

Tools:

  • doc-writer agent for extensive docs
  • /docs command

9. Commit​

Goal: Version control and create PR.

Commit Message Format:

<type>: <short description>

<detailed description if needed>

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

Types: feat, fix, refactor, docs, test, chore

Before committing:

  • Review staged changes: /review staged
  • All tests pass
  • Build succeeds

Quick Reference by Feature Size​

Simple (< 30 min)​

1. Research (5 min)
2. Build (15 min)
3. Quick test (5 min)
4. Commit (5 min)

Medium (1-3 hrs)​

1. Research (15 min)
2. Plan (15 min)
3. Phase 1 Tests (30 min)
4. Build (1-2 hrs)
5. Phase 2 Tests (30 min)
6. Review (15 min)
7. Document + Commit (15 min)

Complex (> 3 hrs)​

1. Research (30 min)
2. Plan + Approval (1 hr)
3. Phase 1 Tests (1 hr)
4. Build (2-4 hrs)
5. Phase 2 Tests (1 hr)
6. Review (30 min)
7. Verify (30 min)
8. Document (30 min)
9. Commit (15 min)

Model Selection​

TaskModelWhy
ResearchSonnetFast exploration
Simple planningSonnetStandard patterns
Complex architectureOpusDeep reasoning needed
Database designOpusCritical decisions
Difficult debuggingOpusMulti-file complexity
BuildingSonnetEfficient implementation
TestingSonnetStandard patterns
ReviewSonnetCode analysis

Anti-Patterns to Avoid​

❌ Skip Phase 1 tests - leads to unclear requirements ❌ Document before building - documentation becomes stale ❌ No review step - quality issues slip through ❌ Test only happy paths - bugs in production ❌ Commit without running tests - breaks main branch ❌ Skip planning for complex features - requires rewrites


Example: Full Workflow​

Feature: Add rest timer to workout page

1. Research (10 min)​

  • Found existing timer state in workout page
  • No visual timer component exists
  • Need to add countdown display and auto-start

2. Plan (15 min)​

  • Add timer state to workout page
  • Create RestTimer component
  • Auto-start after logging set
  • Allow manual dismiss

3. Phase 1 Tests (30 min)​

it('should show timer after logging set', async () => {
// Define expected behavior
});

it('should countdown from rest duration', async () => {
// Define expected behavior
});

it('should allow dismissing timer early', async () => {
// Define expected behavior
});

4. Build (1 hr)​

  • Create RestTimer component
  • Add timer state to workout page
  • Implement auto-start logic
  • All Phase 1 tests now pass ✅

5. Phase 2 Tests (30 min)​

it('should format time correctly', () => {
// Test implementation detail
});

it('should cleanup interval on unmount', () => {
// Test React internals
});

6. Review (10 min)​

  • Run /review
  • No issues found

7. Verify (10 min)​

  • Run /build - passes
  • Test in browser - works

8. Document (5 min)​

  • Add JSDoc to RestTimer component

9. Commit​

feat: add rest timer to workout page

Displays countdown timer after logging each set.
Auto-starts with configurable duration, can be dismissed early.

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

Total time: ~2.5 hours