Files
ColaFlow/docs/plans/SPRINT_3_IMPLEMENTATION_GUIDE.md
Yaojia Wang b11c6447b5
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Sync
2025-11-08 18:13:48 +01:00

29 KiB

Sprint 3: Frontend Code Quality Optimization - Complete Implementation Guide

Sprint ID: Sprint 3 Duration: 2 weeks (2025-11-05 to 2025-11-19) Goal: Complete frontend code quality optimization based on code review findings Priority: High (M1 Quality Improvement)


Overview

This Sprint focuses on addressing code quality issues identified in the Frontend Code Review Report (FRONTEND_CODE_REVIEW_REPORT.md). The work is organized into 6 Stories with 35 total tasks.

Success Metrics:

  • Code Quality: 7.1/10 → 9.0/10
  • Type Safety: 6/10 → 9/10
  • Performance: 6/10 → 8/10
  • Accessibility: 7/10 → 9/10

Story Summary

Story Title Priority Estimated Tasks Status
Story 1 Complete Logging Utility Migration P1 High 1-2 days 6 not_started
Story 2 Component Performance Optimization P1 High 2-3 days 6 not_started
Story 3 Next.js 15 Async Params Migration P0 Critical 1 day 5 not_started
Story 4 Error Handling Improvements P1 High 2 days 6 not_started
Story 5 Accessibility Enhancements P2 Medium 2-3 days 6 not_started
Story 6 Code Quality Tooling P2 Medium 1 day 6 not_started

Total: 6 Stories, 35 Tasks, 9-12 days estimated


Story 1: Complete Logging Utility Migration

Priority: P1 (High) Estimated: 1-2 days Story Points: 3

Description

Replace all remaining console.log statements in the frontend codebase with the unified logger utility. This eliminates production console spam, enables environment-aware logging, and provides foundation for error tracking integration.

Acceptance Criteria

  • No console.log in lib/hooks/ directory
  • No console.log in lib/signalr/ directory
  • All logging uses logger.debug(), logger.info(), or logger.error()
  • Development logs are verbose
  • Production logs are minimal (errors only)
  • Verification: grep -r "console.log" lib/ returns zero results

Tasks

Task 1.1: Replace console.log in use-projects.ts

File: lib/hooks/use-projects.ts Estimated: 30 minutes

Steps:

  1. Import logger: import { logger } from '@/lib/utils/logger';
  2. Replace all console.log with logger.debug()
  3. Replace all console.error with logger.error()
  4. Test in development mode

Before:

console.log('[useProjects] Fetching projects...', { page, pageSize });
console.error('[useProjects] Fetch failed:', error);

After:

logger.debug('Fetching projects', { page, pageSize });
logger.error('Failed to fetch projects', error);

Task 1.2: Replace console.log in use-stories.ts

File: lib/hooks/use-stories.ts Estimated: 30 minutes

Same pattern as Task 1.1.

Task 1.3: Replace console.log in use-tasks.ts

File: lib/hooks/use-tasks.ts Estimated: 30 minutes

Same pattern as Task 1.1.

Task 1.4: Replace console.log in other React Query hooks

Files: lib/hooks/use-epics.ts, lib/hooks/use-sprints.ts, etc. Estimated: 1 hour

Steps:

  1. List all hook files: ls lib/hooks/use-*.ts
  2. For each file with console.log:
    • Import logger
    • Replace console statements
    • Test functionality

Task 1.5: Replace console.log in SignalR files

Files: lib/signalr/ConnectionManager.ts, lib/signalr/ProjectHub.ts Estimated: 1 hour

Steps:

  1. Import logger in SignalR files
  2. Replace connection logging
  3. Replace error logging
  4. Test SignalR connection and events

Before:

console.log('[SignalR] Connection state changed:', state);
console.error('[SignalR] Connection error:', error);

After:

logger.debug('SignalR connection state changed', { state });
logger.error('SignalR connection error', error);

Task 1.6: Verify no console.log remains

Estimated: 30 minutes

Verification:

# Should return zero results
grep -r "console.log" lib/hooks/
grep -r "console.log" lib/signalr/
grep -r "console.error" lib/hooks/ | grep -v logger

Test:

  1. Run dev server: npm run dev
  2. Use application and check console
  3. Build for production: npm run build
  4. Verify minimal production logs

Story 2: Component Performance Optimization

Priority: P1 (High) Estimated: 2-3 days Story Points: 5

Description

Add React.memo, useCallback, and useMemo optimizations to presentational components to reduce unnecessary re-renders and improve application performance, especially for kanban boards with many cards.

Acceptance Criteria

  • All list/card components wrapped with React.memo
  • All event handlers use useCallback
  • Expensive computations use useMemo
  • Performance improvement verified (React DevTools Profiler)
  • No performance regressions
  • Lighthouse performance score >= 90

Tasks

Task 2.1: Add React.memo to IssueCard

File: components/features/kanban/IssueCard.tsx Estimated: 1 hour

Before:

export function IssueCard({ issue }: IssueCardProps) {
  // Component code
}

After:

import { memo } from 'react';

export const IssueCard = memo(function IssueCard({ issue }: IssueCardProps) {
  // Component code
});

Verification:

  • Use React DevTools Profiler
  • Move a card in kanban
  • Verify other cards don't re-render

Task 2.2: Add React.memo to ProjectCard

File: components/features/projects/ProjectCard.tsx Estimated: 45 minutes

Same pattern as Task 2.1.

Task 2.3: Add React.memo to SprintCard

File: components/features/sprints/SprintCard.tsx Estimated: 45 minutes

Same pattern as Task 2.1.

Task 2.4: Add React.memo to TaskCard

File: components/features/kanban/TaskCard.tsx (if exists separately) Estimated: 45 minutes

Same pattern as Task 2.1.

Task 2.5: Add useCallback to list component event handlers

Files: Various list components Estimated: 2 hours

Pattern:

import { useCallback } from 'react';

// Before
const handleClick = (id: string) => {
  // handler code
};

// After
const handleClick = useCallback((id: string) => {
  // handler code
}, [/* dependencies */]);

Files to update:

  • components/features/projects/ProjectList.tsx
  • components/features/sprints/SprintList.tsx
  • components/features/kanban/KanbanBoard.tsx
  • Dialog components with onSubmit handlers

Task 2.6: Performance testing and benchmarking

Estimated: 2 hours

Steps:

  1. Before optimization:

    • Open React DevTools Profiler
    • Record interaction (e.g., drag card)
    • Note number of component re-renders
    • Run Lighthouse audit
    • Save baseline scores
  2. After optimization:

    • Repeat same interactions
    • Compare render counts
    • Run Lighthouse audit
    • Document improvements

Expected Results:

  • 30-50% reduction in re-renders
  • Lighthouse performance >= 90
  • Faster interaction times

Documentation: Create docs/PERFORMANCE_METRICS.md:

# Performance Optimization Results

## Before
- Kanban card drag: 25 component re-renders
- Lighthouse Performance: 78
- Time to Interactive: 3.8s

## After
- Kanban card drag: 8 component re-renders (-68%)
- Lighthouse Performance: 92 (+14)
- Time to Interactive: 2.1s (-45%)

Story 3: Next.js 15 Async Params Migration

Priority: P0 (Critical) Estimated: 1 day Story Points: 3

Description

Update all dynamic route pages to use Next.js 15's async params pattern. This ensures compatibility with Next.js 15+ and prevents future deprecation warnings.

Acceptance Criteria

  • All pages with [id] params use async pattern
  • No TypeScript errors
  • All routes work correctly
  • No hydration warnings
  • Documentation updated

Tasks

Task 3.1: Fix app/projects/[id]/page.tsx

File: app/projects/[id]/page.tsx Estimated: 1 hour

Before:

export default function ProjectPage({ params }: { params: { id: string } }) {
  const projectId = params.id;
  // ...
}

After:

interface PageProps {
  params: Promise<{ id: string }>;
}

export default async function ProjectPage({ params }: PageProps) {
  const { id } = await params;
  // ...
}

Testing:

  • Navigate to /projects/123
  • Verify page loads
  • Check no console warnings

Task 3.2: Fix app/projects/[id]/sprints/[sprintId]/page.tsx

File: app/projects/[id]/sprints/[sprintId]/page.tsx Estimated: 1 hour

Pattern for nested params:

interface PageProps {
  params: Promise<{ id: string; sprintId: string }>;
}

export default async function SprintPage({ params }: PageProps) {
  const { id, sprintId } = await params;
  // ...
}

Task 3.3: Find and fix other dynamic route pages

Estimated: 2 hours

Discovery:

# Find all dynamic route pages
find app -name "\[*\]" -type d
find app -path "*/\[*\]/page.tsx"

Update each file:

  1. Change params type to Promise
  2. Make component async
  3. Await params before use
  4. Update TypeScript interfaces

Typical files:

  • app/projects/[id]/epics/[epicId]/page.tsx
  • app/projects/[id]/stories/[storyId]/page.tsx
  • Any other [param]/page.tsx files

Task 3.4: Update TypeScript types for async params

File: types/page.ts (create if doesn't exist) Estimated: 30 minutes

// types/page.ts
export interface PageProps<T extends Record<string, string> = Record<string, string>> {
  params: Promise<T>;
  searchParams?: Promise<Record<string, string | string[]>>;
}

// Usage in pages
import { PageProps } from '@/types/page';

export default async function ProjectPage({ params }: PageProps<{ id: string }>) {
  const { id } = await params;
  // ...
}

Task 3.5: Test all dynamic routes

Estimated: 1 hour

Test matrix:

Route Test Case Expected
/projects/[id] Navigate to project detail Page loads, no warnings
/projects/[id]/sprints/[sprintId] Navigate to sprint detail Page loads, params correct
/projects/[id]/epics/[epicId] Navigate to epic detail Page loads
Direct URL access Type URL in browser No hydration errors
Back/forward navigation Use browser navigation Params maintained

Verification checklist:

  • No console warnings
  • No TypeScript errors
  • Pages load correctly
  • Params are accessible
  • No hydration mismatches

Story 4: Error Handling Improvements

Priority: P1 (High) Estimated: 2 days Story Points: 5

Description

Improve error handling across the application by adding Error Boundaries, better error messages in forms, improved loading states, and helpful empty states.

Acceptance Criteria

  • Error boundaries catch and display errors gracefully
  • All forms show clear error messages
  • All data fetching shows loading states
  • Empty states provide helpful guidance
  • Error tracking integration ready

Tasks

Task 4.1: Create global Error Boundary component

File: components/ErrorBoundary.tsx Estimated: 2 hours

'use client';

import React from 'react';
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { AlertTriangle } from 'lucide-react';

interface Props {
  children: React.ReactNode;
}

interface State {
  hasError: boolean;
  error: Error | null;
}

export class ErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    // Log to error tracking service (e.g., Sentry)
    console.error('Error boundary caught:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="flex items-center justify-center min-h-screen p-4">
          <Card className="w-full max-w-md">
            <CardHeader>
              <div className="flex items-center gap-2">
                <AlertTriangle className="h-5 w-5 text-destructive" />
                <CardTitle>Something went wrong</CardTitle>
              </div>
              <CardDescription>
                We're sorry, but something unexpected happened.
              </CardDescription>
            </CardHeader>
            <CardContent>
              <p className="text-sm text-muted-foreground mb-4">
                {this.state.error?.message}
              </p>
              <div className="flex gap-2">
                <Button onClick={() => window.location.reload()}>
                  Reload Page
                </Button>
                <Button variant="outline" onClick={() => window.history.back()}>
                  Go Back
                </Button>
              </div>
            </CardContent>
          </Card>
        </div>
      );
    }

    return this.props.children;
  }
}

Task 4.2: Add Error Boundary to root layout

File: app/layout.tsx Estimated: 30 minutes

import { ErrorBoundary } from '@/components/ErrorBoundary';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ErrorBoundary>
          <QueryProvider>
            <SignalRProvider>
              {children}
            </SignalRProvider>
          </QueryProvider>
        </ErrorBoundary>
      </body>
    </html>
  );
}

Task 4.3: Improve form error messages

Files: All form components Estimated: 3 hours

Pattern for better error messages:

// Before: Generic error
toast.error('Failed to create project');

// After: Specific, actionable error
const handleError = (error: ApiError) => {
  const message = error.response?.data?.message || 'Failed to create project';
  const details = error.response?.data?.errors;

  if (details) {
    Object.entries(details).forEach(([field, messages]) => {
      form.setError(field as any, {
        message: (messages as string[]).join(', ')
      });
    });
  }

  toast.error(message, {
    description: 'Please check the form and try again.'
  });
};

Files to update:

  • components/features/projects/CreateProjectDialog.tsx
  • components/features/epics/EpicForm.tsx
  • components/features/stories/StoryForm.tsx
  • components/features/tasks/TaskForm.tsx

Task 4.4: Add loading state improvements

Estimated: 2 hours

Create Skeleton components:

// components/ui/skeleton.tsx (if not exists)
export function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
  return (
    <div
      className={cn("animate-pulse rounded-md bg-muted", className)}
      {...props}
    />
  );
}

// Usage in components
function ProjectList() {
  const { data, isLoading } = useProjects();

  if (isLoading) {
    return (
      <div className="grid gap-4">
        {[...Array(3)].map((_, i) => (
          <Card key={i}>
            <CardHeader>
              <Skeleton className="h-4 w-[250px]" />
              <Skeleton className="h-4 w-[200px]" />
            </CardHeader>
          </Card>
        ))}
      </div>
    );
  }

  // ... rest of component
}

Files to update:

  • components/features/projects/ProjectList.tsx
  • components/features/kanban/KanbanBoard.tsx
  • Any component that fetches data

Task 4.5: Add empty state components

File: components/EmptyState.tsx Estimated: 1.5 hours

interface EmptyStateProps {
  icon?: React.ReactNode;
  title: string;
  description: string;
  action?: {
    label: string;
    onClick: () => void;
  };
}

export function EmptyState({ icon, title, description, action }: EmptyStateProps) {
  return (
    <div className="flex flex-col items-center justify-center p-8 text-center">
      {icon && <div className="mb-4">{icon}</div>}
      <h3 className="text-lg font-semibold">{title}</h3>
      <p className="text-sm text-muted-foreground mb-4">{description}</p>
      {action && (
        <Button onClick={action.onClick}>{action.label}</Button>
      )}
    </div>
  );
}

// Usage
function ProjectList() {
  const { data } = useProjects();

  if (!data || data.length === 0) {
    return (
      <EmptyState
        icon={<FolderPlus className="h-12 w-12 text-muted-foreground" />}
        title="No projects yet"
        description="Create your first project to get started"
        action={{
          label: "Create Project",
          onClick: () => setCreateDialogOpen(true)
        }}
      />
    );
  }

  // ... rest of component
}

Task 4.6: Test error scenarios

Estimated: 1 hour

Test matrix:

Scenario Expected Behavior
Network error Toast with "Network error" + retry button
400 Bad Request Form field errors displayed
401 Unauthorized Redirect to login
403 Forbidden "Access denied" message
404 Not Found "Resource not found" with back button
500 Server Error "Server error" with reload button
Component error Error boundary catches, shows fallback UI
Empty data Empty state with helpful CTA

Testing steps:

  1. Use Network tab to throttle/block requests
  2. Trigger validation errors
  3. Test with expired token
  4. Throw error in component render
  5. Load page with no data

Story 5: Accessibility Enhancements

Priority: P2 (Medium) Estimated: 2-3 days Story Points: 5

Description

Improve application accessibility to meet WCAG 2.1 Level AA standards by adding proper ARIA labels, improving keyboard navigation, and ensuring screen reader compatibility.

Acceptance Criteria

  • All interactive elements have proper ARIA labels
  • Keyboard navigation works for all features
  • Tab order is logical
  • Screen reader announces changes properly
  • WCAG 2.1 Level AA compliant
  • Lighthouse accessibility score >= 95

Tasks

Task 5.1: Add ARIA labels to interactive cards

Files: Card components Estimated: 2 hours

IssueCard example:

<Card
  ref={setNodeRef}
  style={style}
  {...attributes}
  {...listeners}
  className="cursor-grab active:cursor-grabbing"
  role="button"
  aria-label={`${issue.type}: ${issue.title}, priority ${issue.priority}, status ${issue.status}`}
  tabIndex={0}
>
  {/* Card content */}
</Card>

Files to update:

  • components/features/kanban/IssueCard.tsx
  • components/features/projects/ProjectCard.tsx
  • components/features/sprints/SprintCard.tsx

Task 5.2: Improve keyboard navigation in kanban board

File: components/features/kanban/KanbanBoard.tsx Estimated: 3 hours

Add keyboard handlers:

const handleKeyDown = (e: React.KeyboardEvent, issue: Issue) => {
  switch (e.key) {
    case 'Enter':
    case ' ':
      e.preventDefault();
      openIssueDialog(issue);
      break;
    case 'ArrowRight':
      e.preventDefault();
      focusNextCard();
      break;
    case 'ArrowLeft':
      e.preventDefault();
      focusPreviousCard();
      break;
    case 'ArrowDown':
      e.preventDefault();
      focusCardBelow();
      break;
    case 'ArrowUp':
      e.preventDefault();
      focusCardAbove();
      break;
  }
};

Features to implement:

  • Arrow key navigation between cards
  • Enter/Space to open card details
  • Tab to move between columns
  • Escape to close dialogs
  • Focus indicators

Task 5.3: Add focus management for dialogs

Files: Dialog components Estimated: 2 hours

Focus trap implementation:

import { useEffect, useRef } from 'react';

function CreateProjectDialog({ open, onOpenChange }: Props) {
  const firstFocusableRef = useRef<HTMLInputElement>(null);
  const previousFocusRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (open) {
      // Save current focus
      previousFocusRef.current = document.activeElement as HTMLElement;
      // Focus first input
      firstFocusableRef.current?.focus();
    } else {
      // Restore focus when closed
      previousFocusRef.current?.focus();
    }
  }, [open]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Create Project</DialogTitle>
        </DialogHeader>
        <Form>
          <Input ref={firstFocusableRef} {...} />
          {/* Other fields */}
        </Form>
      </DialogContent>
    </Dialog>
  );
}

File: app/layout.tsx Estimated: 1 hour

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <a
          href="#main-content"
          className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-primary focus:text-primary-foreground"
        >
          Skip to main content
        </a>
        <Header />
        <main id="main-content" className="flex-1">
          {children}
        </main>
      </body>
    </html>
  );
}

Task 5.5: Test with screen reader

Estimated: 2 hours

Testing procedure:

Windows (NVDA/JAWS):

  1. Install NVDA (free) or JAWS
  2. Navigate through application
  3. Verify announcements for:
    • Page titles
    • Form labels
    • Button purposes
    • Error messages
    • Dynamic updates

macOS (VoiceOver):

  1. Enable VoiceOver (Cmd+F5)
  2. Navigate using VO+Arrow keys
  3. Test form filling
  4. Test kanban board navigation

Checklist:

  • All form fields have labels
  • Buttons have descriptive text
  • Images have alt text
  • Status changes are announced
  • Error messages are announced
  • Dialogs trap focus properly

Task 5.6: Run accessibility audit

Estimated: 1 hour

Tools:

  1. Lighthouse (Chrome DevTools)

    • Run audit
    • Target score >= 95
    • Fix all issues
  2. axe DevTools (Browser extension)

    • Install extension
    • Run scan on each page
    • Fix Critical and Serious issues
  3. WAVE (Web accessibility evaluation tool)

    • Scan pages
    • Review errors and alerts

Create audit report:

# Accessibility Audit Results

## Lighthouse Score: 96/100

## Issues Fixed
- Added 15 missing ARIA labels
- Fixed 8 color contrast issues
- Added keyboard navigation to kanban
- Implemented focus management for dialogs

## Remaining Issues
- None (all Critical and Serious issues resolved)

## WCAG 2.1 Level AA Compliance: ✅

Story 6: Code Quality Tooling

Priority: P2 (Medium) Estimated: 1 day Story Points: 3

Description

Configure code quality tools (ESLint, Prettier, Husky) to prevent code quality issues from being committed and ensure consistent code style across the team.

Acceptance Criteria

  • ESLint fails on any type usage
  • Pre-commit hooks prevent bad code
  • Code is auto-formatted on commit
  • TypeScript strict mode enforced
  • Team has consistent VS Code settings

Tasks

Task 6.1: Configure ESLint to prohibit 'any' type

File: .eslintrc.json or eslint.config.js Estimated: 30 minutes

{
  "extends": ["next/core-web-vitals"],
  "rules": {
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/no-unsafe-assignment": "warn",
    "@typescript-eslint/no-unsafe-member-access": "warn",
    "@typescript-eslint/no-unsafe-call": "warn",
    "no-console": ["warn", { "allow": ["warn", "error"] }]
  }
}

Test:

npm run lint
# Should show errors for any 'any' types

Task 6.2: Configure pre-commit hooks with Husky

Estimated: 1 hour

Setup:

# Install Husky
npm install -D husky

# Initialize Husky
npx husky init

# Create pre-commit hook
npx husky add .husky/pre-commit "npm run lint-staged"

File: .husky/pre-commit

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint-staged

Task 6.3: Add TypeScript strict checks to pre-commit

File: package.json Estimated: 30 minutes

{
  "scripts": {
    "type-check": "tsc --noEmit",
    "lint-staged": "lint-staged"
  }
}

File: .lintstagedrc.js

module.exports = {
  '*.{ts,tsx}': [
    'eslint --fix',
    'tsc-files --noEmit'
  ],
};

Task 6.4: Add Prettier formatting check

Estimated: 45 minutes

Install:

npm install -D prettier

File: .prettierrc

{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 100,
  "tabWidth": 2
}

File: .prettierignore

node_modules
.next
dist
build
*.min.js

Update lint-staged:

module.exports = {
  '*.{ts,tsx}': [
    'prettier --write',
    'eslint --fix',
    'tsc-files --noEmit'
  ],
  '*.{json,md}': 'prettier --write'
};

Task 6.5: Add lint-staged for faster checks

Estimated: 30 minutes

Install:

npm install -D lint-staged

Configuration already added in Task 6.4

Test:

# Make a change
git add .
git commit -m "test"
# Should run lint-staged before commit

Task 6.6: Document code quality standards

File: CONTRIBUTING.md Estimated: 1 hour

# Contributing to ColaFlow

## Code Quality Standards

### TypeScript
- No `any` types (ESLint will error)
- Use strict type checking
- Define interfaces for all data structures

### Code Style
- Prettier for formatting (auto-formats on commit)
- ESLint for code quality
- Follow existing patterns

### Before Committing
Pre-commit hooks will automatically:
1. Format code with Prettier
2. Run ESLint and fix auto-fixable issues
3. Run TypeScript type checking

If checks fail, fix errors before committing.

### Running Checks Manually
```bash
npm run lint        # Run ESLint
npm run type-check  # Run TypeScript
npm run format      # Format with Prettier

Component Guidelines

  • Use React.memo for presentational components
  • Use useCallback for event handlers
  • Use useMemo for expensive computations
  • Add proper TypeScript types
  • Include ARIA labels for accessibility

Testing

  • Write tests for complex logic
  • Test accessibility with screen readers
  • Test keyboard navigation

---

## Sprint Timeline

### Week 1 (Nov 5-8)

**Day 1-2: Story 1 + Story 3**
- Complete logging utility migration
- Fix Next.js 15 async params
- High priority, quick wins

**Day 3: Story 6**
- Set up code quality tools
- Enables prevention of future issues

### Week 2 (Nov 11-15)

**Day 4-6: Story 2**
- Performance optimization
- Critical for user experience

**Day 7-8: Story 4**
- Error handling improvements
- Important for production readiness

### Week 3 (Nov 18-19)

**Day 9-10: Story 5**
- Accessibility enhancements
- Important but not blocking

**Day 11: Buffer + Sprint Review**
- Handle any overrun
- Final testing
- Sprint retrospective

---

## Testing & Verification

### Story 1: Logging
```bash
grep -r "console.log" lib/ | wc -l  # Should be 0
npm run build  # Verify no console spam in production

Story 2: Performance

  • React DevTools Profiler (re-render count)
  • Lighthouse audit (score >= 90)
  • Manual testing (app feels faster)

Story 3: Next.js 15

  • All routes load without errors
  • No TypeScript errors
  • No console warnings

Story 4: Error Handling

  • Trigger network error → shows proper message
  • Fill invalid form → shows field errors
  • Throw component error → error boundary catches

Story 5: Accessibility

  • Lighthouse accessibility score >= 95
  • axe DevTools scan (0 Critical issues)
  • Screen reader testing (all content announced)

Story 6: Code Quality

  • Try to commit any type → blocked by ESLint
  • Commit with formatting issues → auto-formatted
  • TypeScript errors → commit blocked

Success Criteria

Code Quality Metrics

Before Sprint 3:

  • Type Safety: 6/10
  • Performance: 6/10
  • Accessibility: 7/10
  • Overall: 7.1/10

After Sprint 3 (Target):

  • Type Safety: 9/10
  • Performance: 8/10
  • Accessibility: 9/10
  • Overall: 9.0/10

Specific Metrics

  • Zero any types in production code
  • Zero console.log in production code
  • All components use React.memo where appropriate
  • All dynamic routes use async params
  • Error boundaries implemented
  • WCAG 2.1 Level AA compliant
  • Lighthouse scores: Performance >= 90, Accessibility >= 95
  • Pre-commit hooks active

Risks & Mitigation

Risk Impact Probability Mitigation
React.memo breaks functionality High Low Thorough testing, use React DevTools
Performance optimization takes longer Medium Medium Prioritize critical components first
Async params migration breaks routes High Low Test all routes systematically
Pre-commit hooks slow workflow Low Medium Optimize hook performance, use lint-staged

Notes

Why This Sprint Matters:

  • Foundation for M2 (MCP Server)
  • Improves developer experience
  • Reduces technical debt
  • Better user experience
  • Production-ready quality

Quick Wins:

  • Story 1 (Logging): Simple find-replace
  • Story 3 (Async Params): Pattern-based fixes
  • Story 6 (Tooling): One-time setup

Challenging Parts:

  • Story 2 (Performance): Requires careful testing
  • Story 5 (Accessibility): Requires screen reader testing

Created: 2025-11-05 Sprint Owner: Frontend Team Review Date: 2025-11-12 (Mid-sprint) Target Completion: 2025-11-19