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

1253 lines
29 KiB
Markdown

# 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**:
```typescript
console.log('[useProjects] Fetching projects...', { page, pageSize });
console.error('[useProjects] Fetch failed:', error);
```
**After**:
```typescript
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**:
```typescript
console.log('[SignalR] Connection state changed:', state);
console.error('[SignalR] Connection error:', error);
```
**After**:
```typescript
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**:
```bash
# 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**:
```typescript
export function IssueCard({ issue }: IssueCardProps) {
// Component code
}
```
**After**:
```typescript
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**:
```typescript
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`:
```markdown
# 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**:
```typescript
export default function ProjectPage({ params }: { params: { id: string } }) {
const projectId = params.id;
// ...
}
```
**After**:
```typescript
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**:
```typescript
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**:
```bash
# 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
```typescript
// 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
```typescript
'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
```typescript
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**:
```typescript
// 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**:
```typescript
// 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
```typescript
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**:
```typescript
<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**:
```typescript
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**:
```typescript
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>
);
}
```
### Task 5.4: Add skip navigation links
**File**: `app/layout.tsx`
**Estimated**: 1 hour
```typescript
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**:
```markdown
# 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
```json
{
"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**:
```bash
npm run lint
# Should show errors for any 'any' types
```
### Task 6.2: Configure pre-commit hooks with Husky
**Estimated**: 1 hour
**Setup**:
```bash
# 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`
```bash
#!/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
```json
{
"scripts": {
"type-check": "tsc --noEmit",
"lint-staged": "lint-staged"
}
}
```
**File**: `.lintstagedrc.js`
```javascript
module.exports = {
'*.{ts,tsx}': [
'eslint --fix',
'tsc-files --noEmit'
],
};
```
### Task 6.4: Add Prettier formatting check
**Estimated**: 45 minutes
**Install**:
```bash
npm install -D prettier
```
**File**: `.prettierrc`
```json
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2
}
```
**File**: `.prettierignore`
```
node_modules
.next
dist
build
*.min.js
```
**Update lint-staged**:
```javascript
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**:
```bash
npm install -D lint-staged
```
**Configuration already added in Task 6.4**
**Test**:
```bash
# 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
```markdown
# 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