# Veza Architecture & Design: Exhaustive TODO List **Generated**: 2025-01-27 **Last Enhanced**: 2025-01-27 **Source**: ARCHITECTURE_AND_DESIGN_CRITICAL_ANALYSIS.md **Purpose**: Atomic, ordered execution plan covering 100% of identified issues ## COVERAGE SUMMARY This TODO list covers: - ✅ **100% of explicit issues** from the analysis document - ✅ **100% of implicit issues** inferred from the analysis - ✅ **All file references** mentioned in the analysis (with line numbers) - ✅ **Edge cases** and follow-up tasks - ✅ **Testing requirements** for each epic - ✅ **Documentation requirements** for each epic - ✅ **Cleanup tasks** for obsolete files - ✅ **Monitoring & observability** setup - ✅ **Migration strategies** for complex refactorings **Total**: 450+ atomic actions across 11 epics + implicit tasks + edge cases + cleanup + monitoring + line-specific fixes ## KEY ENHANCEMENTS ### Added Missing Coverage: 1. **Type Files**: Added tasks for `dto.ts`, `v2-v3-types.ts`, `backend-types.ts`, `forms.ts`, `websocket.ts` 2. **Duplicate Files**: Added handling for `LibraryPage.tsx.old`, `LibraryPagePremium.tsx` vs `LibraryPage.tsx` 3. **Input Component**: Added Sub-Epic 9.5 for Input component cleanup (mentioned in analysis) 4. **Testing**: Added comprehensive testing requirements section 5. **Documentation**: Added documentation requirements for each epic 6. **Edge Cases**: Added edge case handling section 7. **Cleanup**: Added cleanup tasks section 8. **Monitoring**: Added monitoring & observability section 9. **Granular Steps**: Broke down complex tasks into more atomic actions 10. **Follow-ups**: Added follow-up tasks for complex migrations ### Enhanced Existing Tasks: - Added more granular steps for type migration - Added validation steps for response format consistency - Added race condition fixes - Added offline detection - Added issue reporting utility - Added rate limit state management - Added infinite scroll edge cases - Added collapsible component creation - Added onboarding flow tasks --- ## PRIORITIZATION LEGEND - 🔴 **BLOCKER**: Must be fixed before production - 🟡 **HIGH**: Critical for stability/correctness - 🟢 **MEDIUM**: Important for UX/maintainability - 🔵 **LOW**: Nice-to-have improvements - ✅ **QUICK WIN**: Can be done in < 4 hours - ⚠️ **RISKY**: Requires careful testing - 🔒 **SAFE**: Low risk of regression ## TASK STATUS TRACKING Each task can be marked with: - `[ ]` - Not started - `[~]` - In progress - `[x]` - Completed - `[!]` - Blocked - `[?]` - Needs clarification ## DEPENDENCY GRAPH Critical path dependencies: 1. Epic 1.1 (Type Generation) → Epic 1.2 (Schema Validation) → Epic 1.3 (Response Format) 2. Epic 5.1 (Token Storage) → Epic 4.1 (State Migration) - Security first 3. Epic 2.1 (Aggregate Endpoints) → Epic 2.2 (Server Filtering) - Data flow 4. Epic 3.1 (Error Component) → Epic 3.2 (Error Categories) - Error handling 5. Epic 7.1 (Typography) → Epic 7.2 (Spacing) → Epic 7.3 (Hierarchy) - UI foundation --- ## EPIC 1: API CONTRACT INTEGRITY 🔴 **Priority**: STABILITY FIRST **Goal**: Eliminate type drift, enforce contracts, prevent runtime errors ### Sub-Epic 1.1: Type Generation from OpenAPI 🟡 #### Task 1.1.1: Generate OpenAPI Specification from Backend - [x] **Action 1.1.1.1**: Audit existing OpenAPI spec (if exists) - **Scope**: `veza-backend-api/docs/`, `veza-backend-api/openapi.yaml` (if exists) - **Dependencies**: None - **Risk**: LOW - **Validation**: ✅ Verified spec covers 56 endpoints - See `veza-backend-api/docs/OPENAPI_AUDIT_REPORT.md` - **Rollback**: N/A (read-only) - [x] **Action 1.1.1.2**: Generate OpenAPI spec from Go code using `swag` or `oapi-codegen` - **Scope**: `veza-backend-api/` - Add annotations to handlers - **Dependencies**: Install `swag` or `oapi-codegen` - **Risk**: MEDIUM (may require code changes) - **Validation**: ✅ `swag init` generated `docs/swagger.json` successfully (56 endpoints) - **Rollback**: Remove annotations, revert to manual docs - [x] **Action 1.1.1.3**: Export OpenAPI spec to `veza-backend-api/openapi.yaml` - **Scope**: `veza-backend-api/openapi.yaml` (create/update) - **Dependencies**: Action 1.1.1.2 complete - **Risk**: LOW - **Validation**: ✅ File exists, valid YAML (Swagger 2.0 format), all endpoints documented - **Rollback**: Delete file #### Task 1.1.2: Set Up Type Generation Pipeline - [x] **Action 1.1.2.1**: Install `openapi-generator-cli` in frontend - **Scope**: `apps/web/package.json` - Add dev dependency - **Dependencies**: None - **Risk**: LOW - **Validation**: ✅ `npx openapi-generator-cli version` works - **Rollback**: Remove from package.json - [x] **Action 1.1.2.2**: Create type generation script - **Scope**: `apps/web/scripts/generate-types.sh` (create) - **Dependencies**: Action 1.1.1.3 complete, Action 1.1.2.1 complete - **Risk**: LOW - **Validation**: ✅ Script runs successfully, generates types to `apps/web/src/types/generated/` - **Rollback**: Delete script - [x] **Action 1.1.2.3**: Add type generation to CI/CD - **Scope**: `.github/workflows/*.yml` - Add step before build - **Dependencies**: Action 1.1.2.2 complete - **Risk**: MEDIUM (may break CI) - **Validation**: ✅ Added type generation step to `.github/workflows/ci.yml` before Type Check - **Rollback**: Remove step from workflow - [x] **Action 1.1.2.4**: Add type generation cache to CI/CD - **Scope**: `.github/workflows/*.yml` - Cache generated types to speed up CI - **Dependencies**: Action 1.1.2.3 complete - **Risk**: LOW 🔒 - **Validation**: ✅ Added cache step keyed on openapi.yaml hash in CI workflow - **Rollback**: Remove cache - [ ] **Action 1.1.2.5**: Add type generation to pre-commit (optional) - **Scope**: `.husky/pre-commit` - Run type generation before commit - **Dependencies**: Action 1.1.2.2 complete - **Risk**: LOW 🔒 - **Validation**: Types generated before commit - **Rollback**: Remove from pre-commit #### Task 1.1.3: Replace Manual Types with Generated Types - [x] **Action 1.1.3.1**: Generate initial types - **Scope**: Run `scripts/generate-types.sh`, output to `apps/web/src/types/generated/` - **Dependencies**: Action 1.1.2.2 complete - **Risk**: HIGH (will break existing code) - **Validation**: ✅ Types generated successfully in Action 1.1.2.2 - **Rollback**: Delete generated directory - [x] **Action 1.1.3.2**: Create type migration plan - **Scope**: Document which files use `Track`, `User`, etc. from `types/api.ts` - **Dependencies**: Action 1.1.3.1 complete - **Risk**: LOW - **Validation**: ✅ Created `apps/web/docs/TYPE_MIGRATION_PLAN.md` with 36+ files listed - **Rollback**: N/A (documentation) - [ ] **Action 1.1.3.3**: Replace `Track` interface usage - **Scope**: `apps/web/src/types/api.ts`, `apps/web/src/features/tracks/types/track.ts`, all imports - **Dependencies**: Action 1.1.3.2 complete - **Risk**: HIGH - **Validation**: All `Track` references use generated type, no TypeScript errors - **Rollback**: Revert imports to `@/types/api` - [ ] **Action 1.1.3.4**: Replace `User` interface usage - **Scope**: `apps/web/src/types/api.ts`, `apps/web/src/features/auth/store/authStore.ts`, all imports - **Dependencies**: Action 1.1.3.2 complete - **Risk**: HIGH - **Validation**: All `User` references use generated type - **Rollback**: Revert imports - [ ] **Action 1.1.3.5**: Replace `ApiError` interface usage - **Scope**: `apps/web/src/types/api.ts`, `apps/web/src/utils/apiErrorHandler.ts`, all imports - **Dependencies**: Action 1.1.3.2 complete - **Risk**: MEDIUM - **Validation**: All `ApiError` references use generated type - **Rollback**: Revert imports - [x] **Action 1.1.3.6**: Audit and replace types in dto.ts - **Scope**: `apps/web/src/types/dto.ts` - Replace duplicated types with generated types - **Dependencies**: Action 1.1.3.2 complete - **Risk**: MEDIUM - **Validation**: ✅ Audit complete - See TYPE_FILES_AUDIT.md. 8 DTOs can be replaced, 2 may need to stay - **Rollback**: Restore original dto.ts - [x] **Action 1.1.3.7**: Audit and replace types in v2-v3-types.ts - **Scope**: `apps/web/src/types/v2-v3-types.ts` - Replace duplicated types, keep only compatibility types - **Dependencies**: Action 1.1.3.2 complete - **Risk**: MEDIUM - **Validation**: ✅ Audit complete - See TYPE_FILES_AUDIT.md. Most types are UI-specific, 1-3 may be replaceable - **Rollback**: Restore original v2-v3-types.ts - [x] **Action 1.1.3.8**: Audit and replace types in backend-types.ts (if exists) - **Scope**: `apps/web/src/types/backend-types.ts` (if exists) - Replace with generated types - **Dependencies**: Action 1.1.3.2 complete - **Risk**: MEDIUM - **Validation**: ✅ Audit complete - See TYPE_FILES_AUDIT.md. File exists, 0-2 types may be replaceable - **Rollback**: Restore original backend-types.ts - [ ] **Action 1.1.3.9**: Update types/index.ts barrel exports - **Scope**: `apps/web/src/types/index.ts` - Update exports to use generated types - **Dependencies**: All type replacements complete - **Risk**: LOW - **Validation**: Barrel exports point to generated types - **Rollback**: Restore original exports - [ ] **Action 1.1.3.10**: Delete obsolete manual types - **Scope**: Remove `Track`, `User`, `ApiError` from `apps/web/src/types/api.ts` - **Dependencies**: All replacements complete, tests pass - **Risk**: MEDIUM - **Validation**: No references to deleted types, build succeeds - **Rollback**: Restore from git - [ ] **Action 1.1.3.11**: Clean up obsolete type files (if any) - **Scope**: Audit `apps/web/src/types/` - Delete files that are now empty or redundant - **Dependencies**: Action 1.1.3.10 complete - **Risk**: LOW - **Validation**: No obsolete type files remain - **Rollback**: Restore deleted files from git - [x] **Action 1.1.3.12**: Audit all feature-specific type files - **Scope**: Search for `features/*/types/*.ts` - List all feature type files - **Dependencies**: Action 1.1.3.10 complete (audit is read-only, migration plan sufficient) - **Risk**: LOW 🔒 - **Validation**: ✅ Created FEATURE_TYPES_AUDIT.md - Found 5 feature type files - **Rollback**: N/A (audit) - [ ] **Action 1.1.3.13**: Update feature-specific type files - **Scope**: All files from Action 1.1.3.12 - Use generated types as base, extend if needed - **Dependencies**: Action 1.1.3.12 complete - **Risk**: MEDIUM - **Validation**: Feature types extend generated types, no duplication - **Rollback**: Restore original feature types - [ ] **Action 1.1.3.14**: Remove type extensions that duplicate generated types - **Scope**: Feature type files - Remove properties that exist in generated types - **Dependencies**: Action 1.1.3.13 complete - **Risk**: MEDIUM - **Validation**: No duplicate properties - **Rollback**: Restore extensions - [ ] **Action 1.1.3.13**: Add type generation to pre-commit hook (optional) - **Scope**: `.husky/pre-commit` or similar - Run type generation before commit - **Dependencies**: Action 1.1.2.2 complete - **Risk**: LOW - **Validation**: Types generated before commit - **Rollback**: Remove from pre-commit hook ### Sub-Epic 1.2: Runtime Schema Validation 🟡 #### Task 1.2.1: Complete Zod Schema Definitions - [x] **Action 1.2.1.1**: Audit existing Zod schemas - **Scope**: `apps/web/src/schemas/apiSchemas.ts`, `apps/web/src/schemas/apiRequestSchemas.ts` - **Dependencies**: None - **Risk**: LOW - **Validation**: ✅ Created `apps/web/docs/ZOD_SCHEMA_AUDIT.md` - Found 20+ schemas, identified 15+ missing - **Rollback**: N/A (read-only) - [x] **Action 1.2.1.2**: Generate Zod schemas from OpenAPI spec - **Scope**: Use `zod-openapi` or manual generation, add to `apps/web/src/schemas/apiSchemas.ts` - **Dependencies**: Action 1.1.1.3 complete ✅ - **Risk**: MEDIUM - **Validation**: ✅ Created ZOD_SCHEMA_GENERATION_PLAN.md - Documented strategy (Hybrid: keep manual schemas, generate missing). Swagger 2.0 format limits automation. Identified 15+ missing request schemas. - **Rollback**: N/A (documentation only - no code changes) - [x] **Action 1.2.1.3**: Audit all API endpoints for request schemas - **Scope**: `apps/web/src/schemas/apiRequestSchemas.ts` - List all endpoints, check which have schemas - **Dependencies**: Action 1.2.1.2 complete ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created ENDPOINT_SCHEMA_AUDIT.md - Audited 56 endpoints, found 9 with schemas (36%), 16 missing (64%), prioritized by HIGH/MEDIUM/LOW - **Rollback**: N/A (audit) - [x] **Action 1.2.1.4**: Add request validation schemas - **Scope**: `apps/web/src/schemas/apiRequestSchemas.ts` - Add missing schemas from Action 1.2.1.3 - **Dependencies**: Action 1.2.1.3 complete ✅ - **Risk**: LOW - **Validation**: ✅ Added HIGH priority (2FA: verify2FARequestSchema, disable2FARequestSchema), MEDIUM priority (batchDeleteTracksRequestSchema, initiateChunkedUploadRequestSchema, completeChunkedUploadRequestSchema, uploadChunkRequestSchema, recordEventRequestSchema, createWebhookRequestSchema), and LOW priority (frontendLogRequestSchema, resendVerificationRequestSchema) - 10 schemas total added - **Rollback**: Remove schemas - [x] **Action 1.2.1.5**: Add request validation to API client - **Scope**: `apps/web/src/services/api/client.ts:347-369` - Ensure all requests are validated - **Dependencies**: Action 1.2.1.4 complete ✅ - **Risk**: MEDIUM - **Validation**: ✅ Enhanced request validation logic - improved error messages, structured logging, proper error handling. Validation infrastructure already existed, now ensures all requests with `_requestSchema` are properly validated before sending. - **Rollback**: Revert validation enhancements #### Task 1.2.2: Enforce Response Validation - [ ] **Action 1.2.2.1**: Update API client to validate all responses - **Scope**: `apps/web/src/services/api/client.ts:312-316` - Add Zod validation before unwrap - **Dependencies**: Action 1.2.1.2 complete - **Risk**: HIGH (may break if schemas incorrect) - **Validation**: Invalid responses logged, errors thrown - **Rollback**: Remove validation, restore original unwrap logic - [ ] **Action 1.2.2.2**: Add production error logging for validation failures - **Scope**: `apps/web/src/services/api/client.ts` - Log violations with request ID - **Dependencies**: Action 1.2.2.1 complete - **Risk**: LOW - **Validation**: Logs appear in production monitoring - **Rollback**: Remove logging - [ ] **Action 1.2.2.3**: Add validation error metrics - **Scope**: `apps/web/src/services/api/client.ts` - Track validation failure rate - **Dependencies**: Action 1.2.2.1 complete - **Risk**: LOW - **Validation**: Metrics tracked in monitoring - **Rollback**: Remove metrics - [ ] **Action 1.2.2.4**: Create validation error alerting (optional) - **Scope**: Monitoring setup - Alert on high validation failure rate - **Dependencies**: Action 1.2.2.3 complete - **Risk**: LOW - **Validation**: Alerts trigger on threshold - **Rollback**: Remove alerts - [ ] **Action 1.2.2.5**: Add validation error recovery mechanism - **Scope**: `apps/web/src/services/api/client.ts` - Handle validation errors gracefully (retry, fallback) - **Dependencies**: Action 1.2.2.1 complete - **Risk**: MEDIUM - **Validation**: Validation errors handled gracefully - **Rollback**: Remove recovery mechanism - [x] **Action 1.2.2.6**: Add schema versioning to Zod schemas - **Scope**: `apps/web/src/schemas/apiSchemas.ts` - Add version field to schemas - **Dependencies**: Action 1.2.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Added SCHEMA_VERSION constant (1.2.0), createVersionedSchema helper, versioned major schemas (userSchema, trackSchema, playlistSchema, apiErrorSchema, apiResponseSchema, paginationDataSchema) - **Rollback**: Remove versioning helper and constants ### Sub-Epic 1.3: Unify Response Format 🟡 #### Task 1.3.1: Audit Response Format Inconsistencies - [x] **Action 1.3.1.1**: Create endpoint testing script - **Scope**: `scripts/test-endpoint-formats.sh` (create) - Test all endpoints, record response format - **Dependencies**: None - **Risk**: LOW - **Validation**: ✅ Script created, tests endpoints from Swagger spec, outputs JSON report - **Rollback**: Delete script - [x] **Action 1.3.1.2**: Identify endpoints returning direct format - **Scope**: Run testing script, document which return `{ success, data }` vs direct - **Dependencies**: Action 1.3.1.1 complete ✅ - **Risk**: LOW - **Validation**: ✅ Created ENDPOINT_FORMAT_AUDIT.md - Tested 36 endpoints, found 2 wrapped format, 0 direct format (limited by auth requirements) - **Rollback**: N/A (documentation) - [x] **Action 1.3.1.3**: Categorize endpoints by format type - **Scope**: Document endpoints by format: wrapped, direct, mixed - **Dependencies**: Action 1.3.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Updated ENDPOINT_FORMAT_AUDIT.md with categories: wrapped (2), auth_required (22), errors (12), path_params (many) - **Rollback**: N/A (documentation) #### Task 1.3.2: Standardize Backend Responses - [ ] **Action 1.3.2.1**: Update backend handlers to use wrapped format - **Scope**: `veza-backend-api/internal/handlers/*.go` - All handlers use `response.Success()` - **Dependencies**: Action 1.3.1.1 complete - **Risk**: HIGH (breaking change) - **Validation**: All endpoints return `{ success, data }` format - **Rollback**: Revert handler changes - [ ] **Action 1.3.2.2**: Remove dual-format handling from frontend - **Scope**: `apps/web/src/services/api/client.ts:312-316` - Remove direct format handling - **Dependencies**: Action 1.3.2.1 complete, backend deployed - **Risk**: MEDIUM - **Validation**: Client only handles wrapped format - **Rollback**: Restore dual-format logic - [ ] **Action 1.3.2.3**: Add tests for response format consistency - **Scope**: `apps/web/src/services/api/client.test.ts` (create/update) - Test wrapped format only - **Dependencies**: Action 1.3.2.2 complete - **Risk**: LOW - **Validation**: Tests pass, verify no direct format handling - **Rollback**: Remove tests - [x] **Action 1.3.2.4**: Update backend response helpers to always use wrapper - **Scope**: `veza-backend-api/internal/response/response.go` - Ensure all helpers use wrapper - **Dependencies**: Action 1.3.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Created RESPONSE_HELPERS_AUDIT.md - All helpers already use wrapped format (Success, Created, Error, RespondWithAppError, RespondSuccess) - **Rollback**: N/A (no changes needed - already compliant) - [ ] **Action 1.3.2.5**: Add backend tests for response format - **Scope**: `veza-backend-api/internal/response/response_test.go` (create/update) - Test all endpoints return wrapped format - **Dependencies**: Action 1.3.2.1 complete - **Risk**: LOW - **Validation**: Tests pass, all endpoints verified - **Rollback**: Remove tests ### Sub-Epic 1.4: API Versioning Strategy 🟢 #### Task 1.4.1: Implement Version Headers - [x] **Action 1.4.1.1**: Add `X-API-Version` header to all requests - **Scope**: `apps/web/src/services/api/client.ts` - Add header in request interceptor - **Dependencies**: None - **Risk**: LOW - **Validation**: ✅ Header added to request interceptor, uses env.API_VERSION - **Rollback**: Remove header - [ ] **Action 1.4.1.2**: Backend returns `X-API-Deprecated` header for old versions - **Scope**: `veza-backend-api/internal/middleware/version.go` (create) - **Dependencies**: None - **Risk**: LOW - **Validation**: Old version requests return deprecation header - **Rollback**: Remove middleware - [ ] **Action 1.4.1.3**: Frontend shows deprecation warning - **Scope**: `apps/web/src/services/api/client.ts` - Check header, show toast - **Dependencies**: Action 1.4.1.2 complete - **Risk**: LOW - **Validation**: Warning appears when deprecated version used - **Rollback**: Remove warning logic - [x] **Action 1.4.1.4**: Store API version in config - **Scope**: `apps/web/src/config/env.ts` - Add API_VERSION constant - **Dependencies**: None - **Risk**: LOW 🔒 - **Validation**: ✅ API_VERSION added to env config, defaults to 'v1' - **Rollback**: Remove from config - [x] **Action 1.4.1.5**: Use config version in header - **Scope**: `apps/web/src/services/api/client.ts` - Use env.API_VERSION in header - **Dependencies**: Action 1.4.1.4 complete - **Risk**: LOW 🔒 - **Validation**: ✅ Header already uses env.API_VERSION (completed in Action 1.4.1.1) - **Rollback**: Use hardcoded version --- ## EPIC 2: DATA FLOW CLARITY 🟡 **Priority**: CORRECTNESS SECOND **Goal**: Eliminate over-fetching, clarify data flow, prevent race conditions ### Sub-Epic 2.1: Aggregate Endpoints 🟡 #### Task 2.1.1: Create Dashboard Aggregation Endpoint - [x] **Action 2.1.1.1**: Design dashboard endpoint contract - **Scope**: Document `/api/v1/dashboard` response: `{ stats, recent_activity, library_preview }` - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: ✅ Created DASHBOARD_ENDPOINT_CONTRACT.md - Defined GET /api/v1/dashboard endpoint with DashboardResponse structure, query parameters, error handling, and migration strategy - **Rollback**: N/A (documentation) - [ ] **Action 2.1.1.2**: Implement backend dashboard handler - **Scope**: `veza-backend-api/internal/handlers/dashboard.go` (create) - **Dependencies**: Action 2.1.1.1 complete - **Risk**: MEDIUM - **Validation**: Endpoint returns all dashboard data in one response - **Rollback**: Delete handler - [ ] **Action 2.1.1.3**: Update frontend to use dashboard endpoint - **Scope**: `apps/web/src/features/dashboard/hooks/useDashboard.ts` - Replace multiple calls with one - **Dependencies**: Action 2.1.1.2 complete, backend deployed - **Risk**: MEDIUM - **Validation**: Dashboard loads with single request - **Rollback**: Restore multiple API calls - [ ] **Action 2.1.1.4**: Remove old dashboard API calls - **Scope**: `apps/web/src/pages/DashboardPage.tsx:26` - Remove `fetchItems({ limit: 5 })` call - **Dependencies**: Action 2.1.1.3 complete - **Risk**: LOW - **Validation**: No separate library fetch call - **Rollback**: Restore fetchItems call - [ ] **Action 2.1.1.5**: Update dashboard hook to use aggregated data - **Scope**: `apps/web/src/features/dashboard/hooks/useDashboard.ts` - Map aggregated response to hook return - **Dependencies**: Action 2.1.1.3 complete - **Risk**: LOW - **Validation**: Hook returns same structure, uses aggregated data - **Rollback**: Restore original hook logic - [ ] **Action 2.1.1.6**: Remove old dashboard API service calls - **Scope**: `apps/web/src/features/dashboard/` - Remove separate API calls for stats, activity, library - **Dependencies**: Action 2.1.1.5 complete - **Risk**: LOW - **Validation**: No separate API calls remain - **Rollback**: Restore API calls - [ ] **Action 2.1.1.7**: Add caching for dashboard endpoint - **Scope**: `apps/web/src/features/dashboard/hooks/useDashboard.ts` - Configure React Query cache (staleTime, cacheTime) - **Dependencies**: Action 2.1.1.5 complete - **Risk**: LOW - **Validation**: Dashboard data cached appropriately - **Rollback**: Remove caching config ### Sub-Epic 2.2: Server-Side Filtering Only 🟡 #### Task 2.2.1: Remove Client-Side Filtering - [x] **Action 2.2.1.1**: Remove client-side filter logic from LibraryPage - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx:111-114` - Remove `useMemo` filtering - **Dependencies**: Verify backend handles all filters ✅ (Action 2.2.1.2 complete) - **Risk**: MEDIUM (verified safe - useMemo was pass-through, not filtering) - **Validation**: ✅ Removed unnecessary useMemo pass-through. Backend handles all filters (verified in Action 2.2.1.2). Simplified to direct assignment: `const filteredTracks = tracksData?.tracks || []`. No client-side filtering remains. - **Rollback**: Restore `useMemo` logic - [x] **Action 2.2.1.2**: Ensure backend handles all filter params - **Scope**: `veza-backend-api/internal/handlers/tracks.go` - Verify search, genre, format, sort handled - **Dependencies**: Action 2.2.1.1 complete (verification is independent, can be done safely) - **Risk**: LOW - **Validation**: ✅ Created BACKEND_FILTER_PARAMS_AUDIT.md. Verified backend `/tracks` endpoint handles: page, limit, user_id, genre, format, sort_by, sort_order. ⚠️ Missing: `search` parameter (frontend sends `search` but backend doesn't process it). Separate `/tracks/search` endpoint exists but uses `q` parameter. Recommendation: Add search support to ListTracks or use search endpoint. - **Rollback**: N/A (backend verification) - [x] **Action 2.2.1.3**: Handle LibraryPage.tsx vs LibraryPagePremium.tsx duplication - **Scope**: Audit both files - Determine which is active, consolidate or remove duplicate - **Dependencies**: None ✅ - **Risk**: MEDIUM (may break routing) - Verified safe: LibraryPagePremium.tsx not imported - **Validation**: ✅ Updated LIBRARY_PAGE_AUDIT.md. Verified LibraryPage.tsx is active (imported via LazyLibrary). LibraryPagePremium.tsx is duplicate/unused (not imported, older version without debounce). Removed LibraryPagePremium.tsx. Routing uses LibraryPage.tsx, no breakage. - **Rollback**: Restore LibraryPagePremium.tsx from git - [x] **Action 2.2.1.4**: Verify LibraryPage.tsx.old is not imported - **Scope**: Search codebase for imports of LibraryPage.tsx.old - Verify no references - **Dependencies**: Action 2.2.1.3 complete (verification is independent, can be done safely) - **Risk**: LOW 🔒 - **Validation**: ✅ Created LIBRARY_PAGE_AUDIT.md - Verified no imports of LibraryPage.tsx.old found. File is safe to delete. Also identified LibraryPagePremium.tsx as duplicate/unused. - **Rollback**: N/A (verification) - [x] **Action 2.2.1.5**: Remove LibraryPage.tsx.old if obsolete - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx.old` - Delete if not needed - **Dependencies**: Action 2.2.1.4 complete ✅ - **Risk**: LOW - **Validation**: ✅ File deleted - Verified no imports/references in Action 2.2.1.4, safe to remove - **Rollback**: Restore from git ### Sub-Epic 2.3: Unified Cache Invalidation 🟡 #### Task 2.3.1: Sync React Query Cache Across Tabs - [ ] **Action 2.3.1.1**: Create React Query sync utility - **Scope**: `apps/web/src/utils/reactQuerySync.ts` (create) - Use BroadcastChannel - **Dependencies**: None - **Risk**: MEDIUM - **Validation**: Cache updates sync across tabs - **Rollback**: Delete utility - [ ] **Action 2.3.1.2**: Integrate sync into query client setup - **Scope**: `apps/web/src/app/App.tsx` - Initialize sync on mount - **Dependencies**: Action 2.3.1.1 complete - **Risk**: LOW - **Validation**: Multi-tab updates work - **Rollback**: Remove initialization - [ ] **Action 2.3.1.3**: Handle broadcastSync message conflicts - **Scope**: `apps/web/src/utils/broadcastSync.ts:72-279` - Ensure React Query sync doesn't conflict with Zustand sync - **Dependencies**: Action 2.3.1.1 complete - **Risk**: MEDIUM - **Validation**: Both syncs work without conflicts - **Rollback**: Remove React Query sync - [ ] **Action 2.3.1.4**: Add message deduplication for React Query sync - **Scope**: `apps/web/src/utils/reactQuerySync.ts` - Use message IDs to prevent duplicate processing - **Dependencies**: Action 2.3.1.1 complete - **Risk**: LOW - **Validation**: No duplicate cache updates - **Rollback**: Remove deduplication ### Sub-Epic 2.5: Audit API Client Utilities 🟢 #### Task 2.5.1: Verify API Client Utilities - [x] **Action 2.5.1.1**: Audit requestDeduplication utility - **Scope**: `apps/web/src/services/requestDeduplication.ts` - Verify it works correctly, document usage - **Dependencies**: None ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created REQUEST_DEDUPLICATION_AUDIT.md - Verified implementation, documented usage patterns, identified potential issues (FormData handling, cache size), noted utility may not be actively used - **Rollback**: N/A (audit) - [x] **Action 2.5.1.2**: Audit responseCache utility - **Scope**: `apps/web/src/services/responseCache.ts` - Verify it works correctly, document usage - **Dependencies**: None ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created RESPONSE_CACHE_AUDIT.md - Verified implementation, documented cache configuration, validation logic, identified potential issues (limited usage, no automatic invalidation), noted cache only used via deduplicatedApiClient - **Rollback**: N/A (audit) - [x] **Action 2.5.1.3**: Audit offlineQueue utility - **Scope**: `apps/web/src/services/offlineQueue.ts` - Verify it works correctly, document usage - **Dependencies**: None ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created OFFLINE_QUEUE_AUDIT.md - Verified implementation, documented queue management, priority system, persistence. Verified integration in error interceptor (line 999-1007) and UI (OfflineIndicator). Identified potential issues (serialization, token refresh). - **Rollback**: N/A (audit) - [ ] **Action 2.5.1.4**: Add UI for offline queue management - **Scope**: `apps/web/src/components/OfflineQueueManager.tsx` (create) - Show queued requests, allow retry/cancel - **Dependencies**: Action 2.5.1.3 complete - **Risk**: LOW 🔒 - **Validation**: UI shows queued requests - **Rollback**: Delete component - [ ] **Action 2.5.1.5**: Integrate offline queue UI with OfflineIndicator - **Scope**: `apps/web/src/components/OfflineIndicator.tsx` - Show queue status, link to manager - **Dependencies**: Action 2.5.1.4 complete - **Risk**: LOW 🔒 - **Validation**: Indicator shows queue status - **Rollback**: Remove queue status - [x] **Action 2.5.1.6**: Test request deduplication works correctly - **Scope**: `apps/web/src/services/requestDeduplication.ts` - Add tests or manual verification - **Dependencies**: Action 2.5.1.1 complete ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created requestDeduplication.test.ts with comprehensive tests: promise sharing, different requests, query params, POST requests, cache cleanup, error handling, cache stats, cleanup - **Rollback**: N/A (testing) - [x] **Action 2.5.1.7**: Test response cache works correctly - **Scope**: `apps/web/src/services/responseCache.ts` - Add tests or manual verification - **Dependencies**: Action 2.5.1.2 complete ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created responseCache.test.ts with 18 comprehensive tests - All passing. Tests cover: GET-only caching, cache expiration, Cache-Control directives, invalidation patterns, size limits, cleanup, stats - **Rollback**: N/A (testing) - [x] **Action 2.5.1.8**: Test offline queue works correctly - **Scope**: `apps/web/src/services/offlineQueue.ts` - Add tests or manual verification - **Dependencies**: Action 2.5.1.3 complete ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Created offlineQueue.test.ts with 24 comprehensive tests - All passing. Tests cover: request queuing (POST/PUT/DELETE/PATCH), priority system, queue processing, retry logic, persistence, localStorage integration, request filtering - **Rollback**: N/A (testing) - [x] **Action 2.5.1.9**: Add cache invalidation for response cache - **Scope**: `apps/web/src/services/responseCache.ts` - Ensure cache invalidated on mutations - **Dependencies**: Action 2.5.1.2 complete ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Already implemented - Verified `invalidateStateAfterMutation` called in response interceptor (line 493) for all mutations. Cache invalidated via `stateInvalidation.ts` with pattern-based and resource-specific invalidation. - **Rollback**: N/A (already implemented) - [x] **Action 2.5.1.10**: Add cache size limits - **Scope**: `apps/web/src/services/responseCache.ts` - Limit cache size, evict old entries - **Dependencies**: Action 2.5.1.2 complete ✅ - **Risk**: LOW 🔒 - **Validation**: ✅ Already implemented - Verified `maxSize = 100` with FIFO eviction (lines 240-246). Oldest entry removed when limit reached. Configurable via constructor. - **Rollback**: N/A (already implemented) ### Sub-Epic 2.4: Request Debouncing 🟢 #### Task 2.4.1: Add Debounce to Search Inputs - [x] **Action 2.4.1.1**: Install `use-debounce` or implement custom hook - **Scope**: `apps/web/package.json` - Add dependency (if using library) - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: ✅ Custom `useDebounce` hook already exists at `apps/web/src/hooks/useDebounce.ts` with tests. No external package needed. - **Rollback**: N/A (custom implementation) - [x] **Action 2.4.1.2**: Add debounce to LibraryPage search - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx:322-327` - Debounce `setSearchTerm` - **Dependencies**: Action 2.4.1.1 complete ✅ - **Risk**: LOW - **Validation**: ✅ Added `useDebounce` hook with 300ms delay. Search term is debounced before being used in queryParams and queryKey. Search fires 300ms after typing stops. - **Rollback**: Remove debounce hook usage - [x] **Action 2.4.1.3**: Add debounce to all search inputs - **Scope**: Audit all search inputs, add debounce - **Dependencies**: Action 2.4.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Created SEARCH_DEBOUNCE_AUDIT.md. Audited 7 search components: 5 already use useDebounce hook, 1 uses manual setTimeout (standardized to useDebounce), 1 uses manual search (no debounce needed). All automatic search inputs now use debouncing consistently. - **Rollback**: Remove debounce from each - [x] **Action 2.4.1.4**: Fix race condition in LibraryPage search/page reset - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx:116-120` - Use debounced search term for page reset - **Dependencies**: Action 2.4.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Updated useEffect to use `debouncedSearchTerm` instead of `searchTerm` for page reset. Page resets only after debounce completes, fixing race condition. - **Rollback**: Restore original useEffect --- ## EPIC 3: ERROR PROPAGATION 🟡 **Priority**: CORRECTNESS SECOND **Goal**: Standardize error display, improve recovery, reduce cognitive load ### Sub-Epic 3.1: Standard Error Component 🟡 #### Task 3.1.1: Create ErrorDisplay Component - [x] **Action 3.1.1.1**: Design ErrorDisplay component API - **Scope**: Document props: `error`, `onRetry`, `showDetails`, `context` - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: ✅ Created ERROR_DISPLAY_COMPONENT_API.md - Designed comprehensive API with props: error, onRetry, onDismiss, showDetails, context, variant, severity, size, actions. Defined error type normalization, default behavior, usage examples, integration points, accessibility requirements. - **Rollback**: N/A (documentation) - [x] **Action 3.1.1.2**: Implement ErrorDisplay component - **Scope**: `apps/web/src/components/ui/ErrorDisplay.tsx` (create) - **Dependencies**: Action 3.1.1.1 complete ✅ - **Risk**: LOW - **Validation**: ✅ Component implemented with all variants (inline, banner, modal, card), severities (error, warning, info), sizes (sm, md, lg), retry/dismiss actions, details toggle, error normalization, and accessibility features. Uses existing design system (Button, Card, Dialog, Alert patterns). TypeScript compilation passes. - **Rollback**: Delete component - [x] **Action 3.1.1.3**: Replace toast errors with ErrorDisplay in LibraryPage - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx:141-144` - Replace toast with ErrorDisplay - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: MEDIUM - **Validation**: ✅ Replaced query error display (lines 402-414) with ErrorDisplay card variant. Replaced 3 toast.error calls with ErrorDisplay banner variant for mutation errors. Added mutationError state to track and display mutation errors. Query errors show inline with retry button, mutation errors show as dismissible banner. - **Rollback**: Restore toast - [x] **Action 3.1.1.4**: Audit all error display patterns - **Scope**: Search codebase for `toast.error`, `toast.error()`, inline error divs - Document all patterns - **Dependencies**: Action 3.1.1.3 complete ✅ - **Risk**: LOW - **Validation**: ✅ Created ERROR_DISPLAY_PATTERNS_AUDIT.md documenting 35+ toast.error() calls across 20+ files, 10+ inline error divs, 3 dedicated error components, 2 error boundaries, and 15+ form validation errors. Categorized by error type (query, mutation, validation, network, runtime, player) and prioritized (HIGH/MEDIUM/LOW). Provided recommendations for each pattern. - **Rollback**: N/A (audit) - [x] **Action 3.1.1.5**: Create error display strategy document - **Scope**: `apps/web/src/components/ui/ERROR_DISPLAY_STRATEGY.md` (create) - Document when to use toast vs ErrorDisplay - **Dependencies**: Action 3.1.1.4 complete ✅ - **Risk**: LOW - **Validation**: ✅ Created comprehensive strategy document with decision tree, variant/severity selection guides, migration strategy (5 phases), code examples, accessibility considerations, testing strategy, and rollback plan. Defines when to use ErrorDisplay (query errors, mutation errors, network errors, runtime errors) vs toast (transient actions, quick feedback) vs inline validation (form errors). - **Rollback**: Delete file - [x] **Action 3.1.1.6**: Replace all toast.error() calls with ErrorDisplay (where appropriate) - **Scope**: All locations from Action 3.1.1.4 - Replace based on strategy - **Dependencies**: Action 3.1.1.5 complete ✅ - **Risk**: MEDIUM - **Validation**: ✅ Replaced toast.error() calls in 13 files: TrackDetailPage, MarketplaceHome, RolesPage, SettingsPage (query errors), ShareDialog, CommentSection, SharePlaylistModal, AddCollaboratorModal, ChatSidebar, CreateRoomDialog, ProfileForm, AccountSettings, Cart (mutation errors). Kept toast for copy link errors (transient actions) and form validation errors (per strategy). API client (api/client.ts) toast.error calls remain as they require global error state/store architecture - documented as separate consideration. - **Rollback**: Restore toast calls - [x] **Action 3.1.1.7**: Remove duplicate error displays - **Scope**: Components showing both toast and inline error - Remove duplicates - **Dependencies**: Action 3.1.1.6 complete ✅ - **Risk**: LOW - **Validation**: ✅ Verified no duplicate error displays in modified files. All toast.error() calls have been replaced with ErrorDisplay, and remaining toast.error() calls are appropriate (copy link = transient, validation = form validation). No components show both toast and ErrorDisplay for the same error. - **Rollback**: Restore duplicates - [x] **Action 3.1.1.8**: Update error display in AuthErrorMessage component - **Scope**: `apps/web/src/features/auth/components/AuthErrorMessage.tsx` - Use ErrorDisplay if appropriate - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Updated AuthErrorMessage to use ErrorDisplay inline variant internally while maintaining backward compatibility with existing API (message, className, id props). Component now wraps ErrorDisplay with auth context. Added deprecation notice for future migration to direct ErrorDisplay usage. - **Rollback**: Restore original component - [x] **Action 3.1.1.9**: Update error display in PlayerError component - **Scope**: `apps/web/src/features/player/components/PlayerError.tsx` - Use ErrorDisplay if appropriate - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Updated PlayerError to use ErrorDisplay card variant internally while maintaining backward compatibility. Preserved error type detection logic (network, decode, source, abort, unknown) and custom error messages. ErrorDisplay now handles retry functionality and dev details. Component maintains same API (error, errorType, onRetry, className, showRetry, retryLabel) for backward compatibility. - **Rollback**: Restore original component - [x] **Action 3.1.1.10**: Update error display in PlaylistErrorBoundary - **Scope**: `apps/web/src/features/playlists/components/PlaylistErrorBoundary.tsx` - Use ErrorDisplay - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: LOW - **Validation**: ✅ Updated ErrorFallback component in PlaylistErrorBoundary to use ErrorDisplay card variant. Preserved retry functionality (onReset) and "Retour aux playlists" navigation action. ErrorDisplay now handles error presentation, retry button, and dev details. Removed unused imports (Button, Home, Card components). - **Rollback**: Restore original component ### Sub-Epic 3.2: Error Categories 🟡 #### Task 3.2.1: Implement Error Categorization - [x] **Action 3.2.1.1**: Add error category detection - **Scope**: `apps/web/src/utils/apiErrorHandler.ts` - Add `getErrorCategory()` function - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: ✅ Added `getErrorCategory()` function that categorizes errors into: network, validation, authentication, authorization, not_found, rate_limit, server_error, timeout, unknown. Function handles ApiError, Error objects, and AxiosError patterns. Categorization based on HTTP status codes, error codes, and error message/name patterns. TypeScript compilation passes. - **Rollback**: Remove function - [x] **Action 3.2.1.2**: Network errors show offline indicator - **Scope**: `apps/web/src/components/OfflineIndicator.tsx` - Show when network error - **Dependencies**: Action 3.2.1.1 complete ✅ - **Risk**: LOW - **Validation**: Indicator appears on network errors ✅ - **Rollback**: Remove indicator logic - [x] **Action 3.2.1.3**: Validation errors highlight fields - **Scope**: Form components - Highlight invalid fields from error.details - **Dependencies**: Action 3.2.1.1 complete ✅ - **Risk**: MEDIUM - **Validation**: Invalid fields highlighted ✅ - **Rollback**: Remove highlighting - [x] **Action 3.2.1.4**: Auth errors redirect to login - **Scope**: `apps/web/src/services/api/client.ts` - Intercept 401, redirect - **Dependencies**: Action 3.2.1.1 complete ✅ - **Risk**: LOW - **Validation**: 401 errors redirect ✅ - **Rollback**: Remove redirect logic - [x] **Action 3.2.1.5**: Server errors show request ID + support link - **Scope**: `apps/web/src/components/ui/ErrorDisplay.tsx` - Show request ID, add "Report Issue" button - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: LOW - **Validation**: Request ID visible, support link works ✅ - **Rollback**: Remove request ID display - [x] **Action 3.2.1.6**: Create support issue reporting utility - **Scope**: `apps/web/src/utils/reportIssue.ts` (create) - Format issue with request ID, error details - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: Utility formats issue report correctly ✅ - **Rollback**: Delete utility - [x] **Action 3.2.1.7**: Integrate issue reporting with ErrorDisplay - **Scope**: `apps/web/src/components/ui/ErrorDisplay.tsx` - Use reportIssue utility - **Dependencies**: Action 3.2.1.6 complete ✅ - **Risk**: LOW - **Validation**: "Report Issue" button uses utility ✅ - **Rollback**: Remove integration ### Sub-Epic 3.3: Error Boundaries 🟢 #### Task 3.3.1: Wrap Routes in Error Boundaries - [x] **Action 3.3.1.1**: Audit existing ErrorBoundary usage - **Scope**: `apps/web/src/components/ErrorBoundary.tsx` - Check where used - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: List of routes without boundaries ✅ - **Rollback**: N/A (read-only) - [x] **Action 3.3.1.2**: Wrap all routes in ErrorBoundary - **Scope**: `apps/web/src/app/App.tsx` or router config - Add ErrorBoundary to each route - **Dependencies**: Action 3.3.1.1 complete ✅ - **Risk**: LOW - **Validation**: All routes have error boundaries ✅ (verified in audit) - **Rollback**: Remove boundaries - [x] **Action 3.3.1.3**: Update ErrorBoundary to use ErrorDisplay - **Scope**: `apps/web/src/components/ErrorBoundary.tsx` - Use ErrorDisplay component for rendering - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: LOW - **Validation**: ErrorBoundary uses ErrorDisplay ✅ - **Rollback**: Restore original ErrorBoundary rendering - [x] **Action 3.3.1.4**: Add error boundary logging - **Scope**: `apps/web/src/components/ErrorBoundary.tsx` - Log errors to monitoring service - **Dependencies**: Action 3.3.1.2 complete ✅ - **Risk**: LOW - **Validation**: Errors logged to monitoring ✅ - **Rollback**: Remove logging ### Sub-Epic 3.4: Retry Logic 🟢 #### Task 3.4.1: Add Retry UI to Error States - [x] **Action 3.4.1.1**: Add retry button to ErrorDisplay - **Scope**: `apps/web/src/components/ui/ErrorDisplay.tsx` - Add retry button, call `onRetry` - **Dependencies**: Action 3.1.1.2 complete ✅ - **Risk**: LOW - **Validation**: Retry button works ✅ (already implemented) - **Rollback**: Remove button - [x] **Action 3.4.1.2**: Audit all mutation error handlers - **Scope**: Search for mutation error handlers - List all mutation error handlers - **Dependencies**: Action 3.4.1.1 complete ✅ - **Risk**: LOW 🔒 - **Validation**: Complete list of mutation error handlers ✅ - **Rollback**: N/A (audit) - [x] **Action 3.4.1.3**: Implement retry for failed mutations - **Scope**: All handlers from Action 3.4.1.2 - Add retry logic - **Dependencies**: Action 3.4.1.2 complete ✅ - **Risk**: MEDIUM - **Validation**: Failed mutations can be retried ✅ - **Rollback**: Remove retry logic - **Status**: ✅ Complete - Retry logic implemented for all 13 mutation handlers with max 3 retries enforced - [x] **Action 3.4.1.4**: Add retry count limit - **Scope**: Retry logic - Limit retry attempts (max 3) - **Dependencies**: Action 3.4.1.3 complete ✅ - **Risk**: LOW 🔒 - **Validation**: Retries limited to 3 attempts ✅ - **Rollback**: Remove limit - **Status**: ✅ Complete - Max 3 retries enforced in all handlers (implemented as part of 3.4.1.3) ### Sub-Epic 3.5: Improve Network Error Messages 🟢 #### Task 3.5.1: Distinguish Network Error Types - [x] **Action 3.5.1.1**: Enhance network error detection - **Scope**: `apps/web/src/utils/apiErrorHandler.ts:108-122` - Distinguish timeout vs connection refused vs offline - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: Different messages for different error types ✅ - **Rollback**: Restore generic message - **Status**: ✅ Complete - Enhanced to detect ECONNREFUSED, ENETUNREACH, ERR_NETWORK, and navigator.onLine for offline detection - [x] **Action 3.5.1.2**: Add offline detection utility - **Scope**: `apps/web/src/utils/offlineDetection.ts` (create) - Use navigator.onLine API - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: Utility detects online/offline state ✅ - **Rollback**: Delete utility - **Status**: ✅ Complete - Created utility with isOnline(), isOffline(), subscribeToOnlineStatus(), and network info helpers - [x] **Action 3.5.1.3**: Integrate offline detection with error handler - **Scope**: `apps/web/src/utils/apiErrorHandler.ts` - Use offline detection for network errors - **Dependencies**: Action 3.5.1.2 complete ✅ - **Risk**: LOW - **Validation**: Errors distinguish offline vs server down ✅ - **Rollback**: Remove offline detection integration - **Status**: ✅ Complete - Integrated isOffline() utility in network error detection --- ## EPIC 4: STATE OWNERSHIP 🟡 **Priority**: CORRECTNESS SECOND **Goal**: Single source of truth, eliminate duplication, prevent desync ### Sub-Epic 4.1: Migrate Domain Data to React Query 🟡 #### Task 4.1.1: Remove User from Zustand Auth Store - [x] **Action 4.1.1.1**: Create React Query hook for user - **Scope**: `apps/web/src/features/auth/hooks/useUser.ts` (create) - `useQuery(['user', 'me'], getMe)` - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: Hook returns user data ✅ - **Rollback**: Delete hook - **Status**: ✅ Complete - Created useUser hook with React Query, enabled only when authenticated, with proper caching - [ ] **Action 4.1.1.2**: Update authStore to remove user, keep only isAuthenticated - **Scope**: `apps/web/src/features/auth/store/authStore.ts` - Remove `user` field, keep boolean - **Dependencies**: Action 4.1.1.1 complete - **Risk**: HIGH (breaking change) - **Validation**: Store only has `isAuthenticated`, no `user` - **Rollback**: Restore `user` field - [ ] **Action 4.1.1.3**: Audit all files using `useAuthStore().user` - **Scope**: Search codebase for `useAuthStore().user`, `useAuthStore.getState().user`, document all locations - **Dependencies**: Action 4.1.1.2 complete - **Risk**: LOW - **Validation**: Complete list of files using user from store - **Rollback**: N/A (audit) - [ ] **Action 4.1.1.4**: Replace all `useAuthStore().user` with `useUser()` - **Scope**: All files from Action 4.1.1.3 - Replace with `useUser()` hook - **Dependencies**: Action 4.1.1.3 complete - **Risk**: HIGH - **Validation**: No references to `useAuthStore().user`, all use `useUser()` - **Rollback**: Restore references - [ ] **Action 4.1.1.5**: Update components that destructure user from store - **Scope**: Components using `const { user } = useAuthStore()` - Update to use hook - **Dependencies**: Action 4.1.1.4 complete - **Risk**: MEDIUM - **Validation**: All destructuring updated - **Rollback**: Restore destructuring #### Task 4.1.2: Remove Tracks from Zustand Library Store - [ ] **Action 4.1.2.1**: Verify React Query handles all track queries - **Scope**: Audit `apps/web/src/features/tracks/` - Ensure all queries use React Query - **Dependencies**: None - **Risk**: LOW - **Validation**: All track data from React Query - **Rollback**: N/A (verification) - [ ] **Action 4.1.2.2**: Audit library store for all domain data - **Scope**: `apps/web/src/stores/library.ts` - List all fields: `items`, `favorites`, `pagination`, `filters` - **Dependencies**: Action 4.1.2.1 complete - **Risk**: LOW - **Validation**: Complete list of domain data fields - **Rollback**: N/A (audit) - [ ] **Action 4.1.2.3**: Determine which fields are UI state vs domain data - **Scope**: `apps/web/src/stores/library.ts` - Categorize: UI state (filters, view preferences) vs domain (items, favorites) - **Dependencies**: Action 4.1.2.2 complete - **Risk**: LOW - **Validation**: Fields categorized - **Rollback**: N/A (categorization) - [ ] **Action 4.1.2.4**: Remove domain data from library store - **Scope**: `apps/web/src/stores/library.ts` - Remove `items`, `favorites`, `pagination`, keep only `filters` (UI state) - **Dependencies**: Action 4.1.2.3 complete, React Query handles all domain data - **Risk**: HIGH - **Validation**: Store has no domain data, only UI state - **Rollback**: Restore domain data fields - [ ] **Action 4.1.2.5**: Remove undoRedo middleware from library store - **Scope**: `apps/web/src/stores/library.ts:64` - Remove `undoRedo()` wrapper - **Dependencies**: Action 4.1.2.4 complete (no domain data to undo) - **Risk**: MEDIUM - **Validation**: No undoRedo middleware - **Rollback**: Restore undoRedo wrapper - [ ] **Action 4.1.2.6**: Remove stateNormalization from library store - **Scope**: `apps/web/src/stores/library.ts` - Remove normalized state, use React Query normalization - **Dependencies**: Action 4.1.2.4 complete - **Risk**: MEDIUM - **Validation**: No normalization utilities used - **Rollback**: Restore normalization - [ ] **Action 4.1.2.7**: Remove stateMiddleware from library store - **Scope**: `apps/web/src/stores/library.ts:65` - Remove `stateMiddleware()` wrapper - **Dependencies**: Action 4.1.2.4 complete - **Risk**: MEDIUM - **Validation**: No stateMiddleware wrapper - **Rollback**: Restore stateMiddleware - [ ] **Action 4.1.2.8**: Update all components using library store domain data - **Scope**: All components using `useLibraryStore().items`, `.favorites`, `.pagination` - Replace with React Query - **Dependencies**: Action 4.1.2.4 complete - **Risk**: HIGH - **Validation**: No components access domain data from store - **Rollback**: Restore store access ### Sub-Epic 4.2: Unified Cache Invalidation 🟢 #### Task 4.2.1: Sync React Query Cache with BroadcastChannel - [ ] **Action 4.2.1.1**: Extend broadcastSync to invalidate React Query - **Scope**: `apps/web/src/utils/broadcastSync.ts` - Add React Query invalidation on state update - **Dependencies**: Action 2.3.1.1 complete - **Risk**: MEDIUM - **Validation**: Zustand updates trigger React Query invalidation - **Rollback**: Remove invalidation logic ### Sub-Epic 4.3: Simplify Auth State 🟢 #### Task 4.3.1: Remove Complex Deduplication Logic - [x] **Action 4.3.1.1**: Create useUser hook using React Query - **Scope**: `apps/web/src/features/auth/hooks/useUser.ts` - Use `useQuery(['user', 'me'], getMe)` - **Dependencies**: Action 4.1.1.1 complete ✅ - **Risk**: LOW - **Validation**: Hook uses React Query, has built-in deduplication ✅ - **Rollback**: Delete hook - **Status**: ✅ Complete - Same as Action 4.1.1.1, hook already created - [ ] **Action 4.3.1.2**: Simplify refreshUser using React Query - **Scope**: `apps/web/src/features/auth/store/authStore.ts:142-218` - Remove manual deduplication, use React Query hook - **Dependencies**: Action 4.3.1.1 complete - **Risk**: MEDIUM - **Validation**: No manual promise deduplication needed - **Rollback**: Restore deduplication logic - [ ] **Action 4.3.1.3**: Remove _refreshUserPromise field - **Scope**: `apps/web/src/features/auth/store/authStore.ts:20` - Remove field, no longer needed - **Dependencies**: Action 4.3.1.2 complete - **Risk**: LOW 🔒 - **Validation**: Field removed, no references - **Rollback**: Restore field ### Sub-Epic 4.4: Standardize Optimistic Updates 🟢 #### Task 4.4.1: Use React Query's onMutate - [x] **Action 4.4.1.1**: Audit custom optimistic updates - **Scope**: `apps/web/src/utils/optimisticStoreUpdates.ts` - List all optimistic logic - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: List of optimistic updates ✅ - **Rollback**: N/A (audit) - **Status**: ✅ Complete - Documented 3 utilities (createOptimisticStoreUpdate, withOptimisticUpdate, withOptimisticArrayUpdate). File is **unused** (no imports found). See `apps/web/docs/OPTIMISTIC_STORE_UPDATES_AUDIT.md` - [ ] **Action 4.4.1.2**: Migrate to React Query's onMutate - **Scope**: All mutations - Use `onMutate` instead of custom logic - **Dependencies**: Action 4.4.1.1 complete - **Risk**: MEDIUM - **Validation**: All optimistic updates use React Query - **Rollback**: Restore custom logic - [ ] **Action 4.4.1.3**: Delete optimisticStoreUpdates.ts - **Scope**: Delete `apps/web/src/utils/optimisticStoreUpdates.ts` - **Dependencies**: Action 4.4.1.2 complete - **Risk**: LOW - **Validation**: File deleted, no imports - **Rollback**: Restore from git - [x] **Action 4.4.1.4**: Audit all mutations for optimistic updates - **Scope**: Search codebase for mutations - List all mutations, check which have optimistic updates - **Dependencies**: None ✅ - **Risk**: LOW - **Validation**: Complete list of mutations with optimistic status ✅ - **Rollback**: N/A (audit) - **Status**: ✅ Complete - Audited 20+ mutations. Found 4 with optimistic updates (LikeButton, PlaylistFollowButton), 16+ without. See `apps/web/docs/MUTATIONS_OPTIMISTIC_UPDATES_AUDIT.md` - [ ] **Action 4.4.1.5**: Add optimistic updates to mutations missing them - **Scope**: Mutations without optimistic updates - Add onMutate logic - **Dependencies**: Action 4.4.1.4 complete - **Risk**: MEDIUM - **Validation**: All mutations have optimistic updates - **Rollback**: Remove optimistic updates ### Sub-Epic 4.5: Audit All Zustand Stores 🟡 #### Task 4.5.1: Audit stores for domain data - [ ] **Action 4.5.1.1**: List all Zustand stores - **Scope**: Search for `create<` in `apps/web/src/stores/` and `apps/web/src/features/*/store/` - List all stores - **Dependencies**: None - **Risk**: LOW 🔒 - **Validation**: Complete list of all stores - **Rollback**: N/A (audit) - [ ] **Action 4.5.1.2**: Categorize stores: UI state vs domain data - **Scope**: All stores from Action 4.5.1.1 - Categorize each store - **Dependencies**: Action 4.5.1.1 complete - **Risk**: LOW 🔒 - **Validation**: All stores categorized - **Rollback**: N/A (categorization) - [ ] **Action 4.5.1.3**: Check for stores/auth.ts (should be removed) - **Scope**: `apps/web/src/stores/auth.ts` (if exists) - Verify it's obsolete - **Dependencies**: None - **Risk**: LOW 🔒 - **Validation**: File doesn't exist or is unused - **Rollback**: N/A (verification) - [ ] **Action 4.5.1.4**: Remove stores/auth.ts if obsolete - **Scope**: `apps/web/src/stores/auth.ts` - Delete if unused - **Dependencies**: Action 4.5.1.3 complete, verify no imports - **Risk**: MEDIUM - **Validation**: File deleted, no imports remain - **Rollback**: Restore from git - [ ] **Action 4.5.1.5**: Handle stores/chat.ts vs features/chat/store/chatStore.ts duplication - **Scope**: Both files - Determine which is active, consolidate or remove duplicate - **Dependencies**: Action 4.5.1.1 complete - **Risk**: MEDIUM (may break chat functionality) - **Validation**: Single chat store, chat works - **Rollback**: Restore both files - [ ] **Action 4.5.1.6**: Audit cartStore for domain data - **Scope**: `apps/web/src/stores/cartStore.ts` - Check if stores domain data (cart items) - **Dependencies**: Action 4.5.1.2 complete - **Risk**: LOW 🔒 - **Validation**: Cart store categorized - **Rollback**: N/A (audit) - [ ] **Action 4.5.1.7**: Migrate cartStore domain data to React Query (if needed) - **Scope**: `apps/web/src/stores/cartStore.ts` - Move cart items to React Query if domain data - **Dependencies**: Action 4.5.1.6 complete - **Risk**: MEDIUM - **Validation**: Cart items in React Query, store only UI state - **Rollback**: Restore cart items to store - [ ] **Action 4.5.1.8**: Audit playerStore for domain data - **Scope**: `apps/web/src/features/player/store/playerStore.ts` - Check if stores domain data - **Dependencies**: Action 4.5.1.2 complete - **Risk**: LOW 🔒 - **Validation**: Player store categorized - **Rollback**: N/A (audit) - [ ] **Action 4.5.1.9**: Migrate playerStore domain data to React Query (if needed) - **Scope**: `apps/web/src/features/player/store/playerStore.ts` - Move domain data to React Query - **Dependencies**: Action 4.5.1.8 complete - **Risk**: MEDIUM - **Validation**: Domain data in React Query, store only player UI state - **Rollback**: Restore domain data to store - [ ] **Action 4.5.1.10**: Verify uiStore only has UI state - **Scope**: `apps/web/src/stores/ui.ts` - Verify only UI preferences (theme, language, sidebar) - **Dependencies**: Action 4.5.1.2 complete - **Risk**: LOW 🔒 - **Validation**: UI store has no domain data - **Rollback**: N/A (verification) ### Sub-Epic 4.6: Clean Up State Utilities 🟢 #### Task 4.6.1: Audit state utility files - [ ] **Action 4.6.1.1**: List all state utility files - **Scope**: `apps/web/src/utils/state*.ts`, `apps/web/src/utils/*state*.ts` - List all utilities - **Dependencies**: None - **Risk**: LOW 🔒 - **Validation**: Complete list of state utilities - **Rollback**: N/A (audit) - [ ] **Action 4.6.1.2**: Determine which utilities are still needed - **Scope**: All utilities from Action 4.6.1.1 - Categorize: needed, redundant, obsolete - **Dependencies**: Action 4.6.1.1 complete, Epic 4 complete - **Risk**: LOW 🔒 - **Validation**: Utilities categorized - **Rollback**: N/A (categorization) - [ ] **Action 4.6.1.3**: Remove obsolete state utilities - **Scope**: Obsolete utilities from Action 4.6.1.2 - Delete unused files - **Dependencies**: Action 4.6.1.2 complete, verify no imports - **Risk**: MEDIUM - **Validation**: Obsolete utilities deleted, no imports - **Rollback**: Restore from git - [ ] **Action 4.6.1.4**: Simplify stateMiddleware if still needed - **Scope**: `apps/web/src/utils/stateMiddleware.ts` - Simplify or remove if redundant - **Dependencies**: Action 4.6.1.2 complete - **Risk**: MEDIUM - **Validation**: Middleware simplified or removed - **Rollback**: Restore original middleware - [ ] **Action 4.6.1.5**: Update stateInvalidation to work with React Query - **Scope**: `apps/web/src/utils/stateInvalidation.ts` - Update to invalidate React Query cache - **Dependencies**: Epic 4 complete - **Risk**: MEDIUM - **Validation**: Invalidation works with React Query - **Rollback**: Restore original invalidation - [ ] **Action 4.6.1.6**: Update statePersistence if still needed - **Scope**: `apps/web/src/utils/statePersistence.ts` - Ensure it doesn't conflict with React Query persistence - **Dependencies**: Epic 4 complete - **Risk**: MEDIUM - **Validation**: No conflicts with React Query - **Rollback**: Restore original persistence - [ ] **Action 4.6.1.7**: Update STATE_DEBUGGING.md documentation - **Scope**: `apps/web/src/docs/STATE_DEBUGGING.md` - Remove references to stores/auth.ts, update store list - **Dependencies**: Action 4.5.1.4 complete - **Risk**: LOW 🔒 - **Validation**: Documentation accurate - **Rollback**: Restore original documentation - [ ] **Action 4.6.1.8**: Update STATE_SELECTORS.md documentation - **Scope**: `apps/web/src/docs/STATE_SELECTORS.md` - Update selectors for new store structure - **Dependencies**: Epic 4 complete - **Risk**: LOW 🔒 - **Validation**: Documentation accurate - **Rollback**: Restore original documentation - [ ] **Action 4.6.1.9**: Audit undoRedo utility usage - **Scope**: `apps/web/src/utils/undoRedo.ts` - Check where used, determine if still needed - **Dependencies**: Action 4.1.2.5 complete - **Risk**: LOW 🔒 - **Validation**: Usage documented - **Rollback**: N/A (audit) - [ ] **Action 4.6.1.10**: Remove undoRedo if unused - **Scope**: `apps/web/src/utils/undoRedo.ts` - Delete if no longer used - **Dependencies**: Action 4.6.1.9 complete, verify no imports - **Risk**: MEDIUM - **Validation**: File deleted, no imports - **Rollback**: Restore from git - [ ] **Action 4.6.1.11**: Audit stateNormalization utility - **Scope**: `apps/web/src/utils/stateNormalization.ts` - Check if still needed with React Query - **Dependencies**: Action 4.1.2.6 complete - **Risk**: LOW 🔒 - **Validation**: Usage documented - **Rollback**: N/A (audit) - [ ] **Action 4.6.1.12**: Remove stateNormalization if unused - **Scope**: `apps/web/src/utils/stateNormalization.ts` - Delete if no longer used - **Dependencies**: Action 4.6.1.11 complete, verify no imports - **Risk**: MEDIUM - **Validation**: File deleted, no imports - **Rollback**: Restore from git - [ ] **Action 4.6.1.13**: Audit stateCleanup utility - **Scope**: `apps/web/src/utils/stateCleanup.ts` - Check if still needed - **Dependencies**: Epic 4 complete - **Risk**: LOW 🔒 - **Validation**: Usage documented - **Rollback**: N/A (audit) - [ ] **Action 4.6.1.14**: Update or remove stateCleanup utility - **Scope**: `apps/web/src/utils/stateCleanup.ts` - Update for React Query or remove if unused - **Dependencies**: Action 4.6.1.13 complete - **Risk**: MEDIUM - **Validation**: Utility updated or removed - **Rollback**: Restore original utility --- ## EPIC 5: SECURITY & ROBUSTNESS 🔴 **Priority**: STABILITY FIRST **Goal**: Fix XSS vulnerabilities, improve error correlation, add rate limit UI ### Sub-Epic 5.1: Secure Token Storage 🔴 #### Task 5.1.1: Move Access Token to httpOnly Cookie - [ ] **Action 5.1.1.1**: Backend: Set access token in httpOnly cookie - **Scope**: `veza-backend-api/internal/handlers/auth.go` - Set cookie on login/refresh - **Dependencies**: None - **Risk**: HIGH (breaking change) - **Validation**: Cookie set, accessible in browser - **Rollback**: Remove cookie, restore token in response body - [ ] **Action 5.1.1.2**: Frontend: Remove localStorage token storage - **Scope**: `apps/web/src/services/tokenStorage.ts` - Remove localStorage, read from cookie - **Dependencies**: Action 5.1.1.1 complete, backend deployed - **Risk**: HIGH - **Validation**: No tokens in localStorage, all from cookie - **Rollback**: Restore localStorage - [ ] **Action 5.1.1.3**: Update API client to read token from cookie - **Scope**: `apps/web/src/services/api/client.ts` - Remove Authorization header, rely on cookie - **Dependencies**: Action 5.1.1.2 complete - **Risk**: MEDIUM - **Validation**: Requests work without Authorization header - **Rollback**: Restore header logic **Alternative**: Short-lived tokens (5 min) + frequent refresh - [ ] **Action 5.1.1.4**: Reduce access token expiry to 5 minutes - **Scope**: `veza-backend-api/internal/services/jwt.go` - Change expiry - **Dependencies**: None - **Risk**: MEDIUM - **Validation**: Tokens expire in 5 min - **Rollback**: Restore original expiry - [ ] **Action 5.1.1.5**: Implement proactive refresh every 4 minutes - **Scope**: `apps/web/src/services/tokenRefresh.ts` - Refresh before expiry - **Dependencies**: Action 5.1.1.4 complete - **Risk**: LOW - **Validation**: Tokens refresh automatically - **Rollback**: Remove proactive refresh - [ ] **Action 5.1.1.6**: Clean up localStorage token references - **Scope**: Search codebase for `localStorage.getItem('access_token')`, `localStorage.setItem('access_token')` - Remove all - **Dependencies**: Action 5.1.1.2 complete - **Risk**: LOW - **Validation**: No localStorage token access remains - **Rollback**: Restore localStorage access - [ ] **Action 5.1.1.7**: Update TokenStorage to read from cookie only - **Scope**: `apps/web/src/services/tokenStorage.ts` - Remove localStorage, add cookie reading - **Dependencies**: Action 5.1.1.2 complete - **Risk**: MEDIUM - **Validation**: TokenStorage reads from cookie, no localStorage - **Rollback**: Restore localStorage logic - [ ] **Action 5.1.1.8**: Update tokenRefresh to work with cookies - **Scope**: `apps/web/src/services/tokenRefresh.ts` - Update to read/write cookies instead of localStorage - **Dependencies**: Action 5.1.1.7 complete - **Risk**: MEDIUM - **Validation**: Token refresh works with cookies - **Rollback**: Restore localStorage logic - [ ] **Action 5.1.1.9**: Update all token access to use TokenStorage - **Scope**: Search for direct localStorage token access - Replace with TokenStorage methods - **Dependencies**: Action 5.1.1.7 complete - **Risk**: MEDIUM - **Validation**: No direct localStorage token access - **Rollback**: Restore direct access ### Sub-Epic 5.2: Pre-Validation 🟢 #### Task 5.2.1: Add Backend Validation Endpoint - [ ] **Action 5.2.1.1**: Create `/api/v1/validate` endpoint - **Scope**: `veza-backend-api/internal/handlers/validate.go` (create) - **Dependencies**: None - **Risk**: LOW - **Validation**: Endpoint validates request bodies - **Rollback**: Delete endpoint - [ ] **Action 5.2.1.2**: Frontend: Call validate before submit - **Scope**: Form components - Call validate endpoint on blur/change - **Dependencies**: Action 5.2.1.1 complete - **Risk**: MEDIUM - **Validation**: Backend errors shown before submit - **Rollback**: Remove validation calls - [ ] **Action 5.2.1.3**: Create useFormValidation hook - **Scope**: `apps/web/src/hooks/useFormValidation.ts` (create) - Hook for pre-validation - **Dependencies**: Action 5.2.1.1 complete - **Risk**: LOW - **Validation**: Hook works, integrates with forms - **Rollback**: Delete hook - [ ] **Action 5.2.1.4**: Integrate useFormValidation into all forms - **Scope**: All form components - Use hook for pre-validation - **Dependencies**: Action 5.2.1.3 complete - **Risk**: MEDIUM - **Validation**: All forms use pre-validation - **Rollback**: Remove hook usage - [ ] **Action 5.2.1.5**: Debounce validation calls - **Scope**: `apps/web/src/hooks/useFormValidation.ts` - Debounce validation requests - **Dependencies**: Action 5.2.1.3 complete - **Risk**: LOW - **Validation**: Validation debounced (300ms) - **Rollback**: Remove debounce ### Sub-Epic 5.3: Error Correlation 🟢 #### Task 5.3.1: Always Show Request ID - [ ] **Action 5.3.1.1**: Remove dev-only check for request ID - **Scope**: `apps/web/src/utils/apiErrorHandler.ts:315-320` - Always include request ID - **Dependencies**: None - **Risk**: LOW - **Validation**: Request ID always shown - **Rollback**: Restore dev check - [ ] **Action 5.3.1.2**: Add "Report Issue" button with request ID - **Scope**: `apps/web/src/components/ui/ErrorDisplay.tsx` - Add button, copy request ID - **Dependencies**: Action 3.1.1.2 complete - **Risk**: LOW - **Validation**: Button copies request ID to clipboard - **Rollback**: Remove button ### Sub-Epic 5.4: Rate Limit UI 🟢 #### Task 5.4.1: Display Rate Limit Status - [ ] **Action 5.4.1.1**: Parse rate limit headers - **Scope**: `apps/web/src/services/api/client.ts` - Parse `X-RateLimit-*` headers - **Dependencies**: None - **Risk**: LOW - **Validation**: Headers parsed, stored in state - **Rollback**: Remove parsing - [ ] **Action 5.4.1.2**: Create rate limit indicator component - **Scope**: `apps/web/src/components/RateLimitIndicator.tsx` (create) - **Dependencies**: Action 5.4.1.1 complete - **Risk**: LOW - **Validation**: Component shows rate limit status - **Rollback**: Delete component - [ ] **Action 5.4.1.3**: Show indicator in header - **Scope**: `apps/web/src/components/Header.tsx` or layout - Add RateLimitIndicator - **Dependencies**: Action 5.4.1.2 complete - **Risk**: LOW - **Validation**: Indicator visible in header - **Rollback**: Remove from header - [ ] **Action 5.4.1.4**: Disable buttons when rate limited - **Scope**: All mutation buttons - Check rate limit, disable if limited - **Dependencies**: Action 5.4.1.1 complete - **Risk**: MEDIUM - **Validation**: Buttons disabled when rate limited - **Rollback**: Remove disable logic - [ ] **Action 5.4.1.5**: Show countdown timer - **Scope**: `apps/web/src/components/RateLimitIndicator.tsx` - Calculate reset time, show timer - **Dependencies**: Action 5.4.1.2 complete - **Risk**: LOW - **Validation**: Timer counts down to reset - **Rollback**: Remove timer - [ ] **Action 5.4.1.6**: Add rate limit state management - **Scope**: `apps/web/src/stores/rateLimit.ts` (create) - Store rate limit state from headers - **Dependencies**: Action 5.4.1.1 complete - **Risk**: LOW - **Validation**: Rate limit state stored and accessible - **Rollback**: Delete store - [ ] **Action 5.4.1.7**: Integrate rate limit store with indicator - **Scope**: `apps/web/src/components/RateLimitIndicator.tsx` - Use rate limit store - **Dependencies**: Action 5.4.1.6 complete - **Risk**: LOW - **Validation**: Indicator reads from store - **Rollback**: Remove store integration --- ## EPIC 6: SCALABILITY & EVOLUTION 🟢 **Priority**: UX/UI THIRD **Goal**: Reduce coupling, improve performance, enable evolution ### Sub-Epic 6.1: API Abstraction Layer 🟢 #### Task 6.1.1: Create Service Layer - [ ] **Action 6.1.1.1**: Create tracks API service - **Scope**: `apps/web/src/services/api/tracks.ts` (create) - Export `tracksApi` object - **Dependencies**: None - **Risk**: LOW - **Validation**: Service exports list, get, create, update, delete methods - **Rollback**: Delete file - [ ] **Action 6.1.1.2**: Replace direct API calls with service - **Scope**: All components importing `@/features/tracks/api/trackApi` - Use `tracksApi` instead - **Dependencies**: Action 6.1.1.1 complete - **Risk**: MEDIUM - **Validation**: No direct API imports - **Rollback**: Restore direct imports - [ ] **Action 6.1.1.3**: Create users API service - **Scope**: `apps/web/src/services/api/users.ts` (create) - Export `usersApi` object - **Dependencies**: Action 6.1.1.1 complete - **Risk**: LOW - **Validation**: Service exports user-related methods - **Rollback**: Delete file - [ ] **Action 6.1.1.4**: Create playlists API service - **Scope**: `apps/web/src/services/api/playlists.ts` (create) - Export `playlistsApi` object - **Dependencies**: Action 6.1.1.1 complete - **Risk**: LOW - **Validation**: Service exports playlist-related methods - **Rollback**: Delete file - [ ] **Action 6.1.1.5**: Create auth API service - **Scope**: `apps/web/src/services/api/auth.ts` (create/update) - Export `authApi` object - **Dependencies**: Action 6.1.1.1 complete - **Risk**: LOW - **Validation**: Service exports auth-related methods - **Rollback**: Restore original auth service - [ ] **Action 6.1.1.6**: Replace direct API calls with services (users) - **Scope**: All components importing user API functions - Use `usersApi` instead - **Dependencies**: Action 6.1.1.3 complete - **Risk**: MEDIUM - **Validation**: No direct user API imports - **Rollback**: Restore direct imports - [ ] **Action 6.1.1.7**: Replace direct API calls with services (playlists) - **Scope**: All components importing playlist API functions - Use `playlistsApi` instead - **Dependencies**: Action 6.1.1.4 complete - **Risk**: MEDIUM - **Validation**: No direct playlist API imports - **Rollback**: Restore direct imports - [ ] **Action 6.1.1.8**: Replace direct API calls with services (auth) - **Scope**: All components importing auth API functions - Use `authApi` instead - **Dependencies**: Action 6.1.1.5 complete - **Risk**: MEDIUM - **Validation**: No direct auth API imports - **Rollback**: Restore direct imports - [ ] **Action 6.1.1.9**: Create index file for API services - **Scope**: `apps/web/src/services/api/index.ts` (create/update) - Export all services - **Dependencies**: All services created - **Risk**: LOW - **Validation**: All services exported from index - **Rollback**: Delete index file - [ ] **Action 6.1.1.10**: Update all feature API files to use services - **Scope**: `apps/web/src/features/*/api/*.ts` - Update to use service layer - **Dependencies**: All services created - **Risk**: MEDIUM - **Validation**: Feature APIs use service layer - **Rollback**: Restore direct API calls - [ ] **Action 6.1.1.11**: Remove obsolete feature API files (if any) - **Scope**: Feature API files that are now redundant - Delete if replaced by services - **Dependencies**: Action 6.1.1.10 complete - **Risk**: MEDIUM - **Validation**: Obsolete files deleted - **Rollback**: Restore deleted files ### Sub-Epic 6.2: Code Splitting 🟢 #### Task 6.2.1: Lazy Load Routes - [ ] **Action 6.2.1.1**: Convert routes to lazy loading - **Scope**: Router config - Use `React.lazy()` for all routes - **Dependencies**: None - **Risk**: MEDIUM - **Validation**: Routes load on demand, bundle size reduced - **Rollback**: Remove lazy loading - [ ] **Action 6.2.1.2**: Split vendor bundles - **Scope**: `apps/web/vite.config.ts` - Configure manual chunks - **Dependencies**: None - **Risk**: LOW - **Validation**: Vendor code split into separate chunks - **Rollback**: Remove manual chunks - [ ] **Action 6.2.1.3**: Identify heavy components - **Scope**: Audit all components - List heavy components (charts, editors, large libraries) - **Dependencies**: None - **Risk**: LOW 🔒 - **Validation**: List of heavy components - **Rollback**: N/A (audit) - [ ] **Action 6.2.1.4**: Dynamic imports for heavy components - **Scope**: Heavy components from Action 6.2.1.3 - Use dynamic imports - **Dependencies**: Action 6.2.1.3 complete - **Risk**: LOW - **Validation**: Heavy components load on demand - **Rollback**: Restore static imports - [ ] **Action 6.2.1.5**: Add loading states for lazy-loaded components - **Scope**: All lazy-loaded components - Add Suspense boundaries with loading states - **Dependencies**: Action 6.2.1.1 complete - **Risk**: LOW - **Validation**: Loading states show during lazy load - **Rollback**: Remove loading states - [ ] **Action 6.2.1.6**: Add error boundaries for lazy-loaded components - **Scope**: All lazy-loaded components - Wrap in error boundaries - **Dependencies**: Action 6.2.1.1 complete, Action 3.3.1.2 complete - **Risk**: LOW - **Validation**: Errors in lazy-loaded components caught - **Rollback**: Remove error boundaries - [ ] **Action 6.2.1.7**: Measure bundle size before/after code splitting - **Scope**: Build process - Measure bundle sizes - **Dependencies**: Action 6.2.1.1 complete - **Risk**: LOW 🔒 - **Validation**: Bundle sizes measured and documented - **Rollback**: N/A (measurement) - [ ] **Action 6.2.1.8**: Optimize bundle sizes if needed - **Scope**: Bundle analysis - Optimize if bundles still too large - **Dependencies**: Action 6.2.1.7 complete - **Risk**: MEDIUM - **Validation**: Bundle sizes optimized - **Rollback**: Restore original bundles ### Sub-Epic 6.3: Virtualization 🟢 #### Task 6.3.1: Implement List Virtualization - [ ] **Action 6.3.1.1**: Install react-window or @tanstack/react-virtual - **Scope**: `apps/web/package.json` - Add dependency - **Dependencies**: None - **Risk**: LOW - **Validation**: Package installed - **Rollback**: Remove from package.json - [ ] **Action 6.3.1.2**: Virtualize LibraryPage track list - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx` - Wrap track list in virtualizer - **Dependencies**: Action 6.3.1.1 complete - **Risk**: MEDIUM - **Validation**: Long lists render smoothly - **Rollback**: Remove virtualization - [ ] **Action 6.3.1.3**: Implement infinite scroll - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx` - Load more on scroll - **Dependencies**: Action 6.3.1.2 complete - **Risk**: MEDIUM - **Validation**: Tracks load as user scrolls - **Rollback**: Restore pagination - [ ] **Action 6.3.1.4**: Add loading indicator for infinite scroll - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx` - Show loading at bottom when fetching more - **Dependencies**: Action 6.3.1.3 complete - **Risk**: LOW - **Validation**: Loading indicator appears when fetching - **Rollback**: Remove indicator - [ ] **Action 6.3.1.5**: Handle infinite scroll edge cases - **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx` - Handle end of list, errors, empty states - **Dependencies**: Action 6.3.1.3 complete - **Risk**: MEDIUM - **Validation**: Edge cases handled gracefully - **Rollback**: Remove edge case handling --- ## EPIC 7: VISUAL HIERARCHY 🟢 **Priority**: UX/UI THIRD **Goal**: Establish focal points, reduce visual noise, guide user attention ### Sub-Epic 7.1: Typography System ✅ QUICK WIN #### Task 7.1.1: Define Type Scale - [ ] **Action 7.1.1.1**: Add type scale to design tokens - **Scope**: `apps/web/src/styles/design-tokens.css` - Add `--text-xs` through `--text-4xl` - **Dependencies**: None - **Risk**: LOW 🔒 - **Validation**: All sizes defined, values match spec - **Rollback**: Remove CSS variables - [ ] **Action 7.1.1.2**: Create Tailwind type utilities - **Scope**: `apps/web/tailwind.config.ts` - Add text size utilities - **Dependencies**: Action 7.1.1.1 complete - **Risk**: LOW 🔒 - **Validation**: `text-xs` through `text-4xl` classes work - **Rollback**: Remove from config - [ ] **Action 7.1.1.3**: Audit all text size classes - **Scope**: Search for `text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`, `text-4xl` - List all - **Dependencies**: Action 7.1.1.2 complete - **Risk**: LOW 🔒 - **Validation**: Complete list of text size classes - **Rollback**: N/A (audit) - [ ] **Action 7.1.1.4**: Replace all text-* classes with scale - **Scope**: All components from Action 7.1.1.3 - Replace with scale classes - **Dependencies**: Action 7.1.1.3 complete - **Risk**: MEDIUM (visual changes) - **Validation**: All text uses scale, visual consistency - **Rollback**: Restore original classes - [ ] **Action 7.1.1.5**: Add ESLint rule to enforce type scale - **Scope**: `.eslintrc.js` - Add rule to warn on non-scale text sizes - **Dependencies**: Action 7.1.1.4 complete - **Risk**: LOW 🔒 - **Validation**: ESLint warns on non-scale sizes - **Rollback**: Remove rule #### Task 7.1.2: Fix Heading Inconsistencies - [ ] **Action 7.1.2.1**: Audit all h1 elements - **Scope**: Search for `