Skip to content

[Critical] Add pagination to feature endpoints to prevent performance issues #1908

@tomsmith8

Description

@tomsmith8

Problem

Currently, GET /api/features/[featureId] returns the entire feature with ALL phases and ALL tasks in a single response. This creates several issues:

  • Unbounded response size: A feature with 200 tasks results in a multi-MB JSON response
  • Browser performance: React rendering hundreds of task rows can freeze the UI
  • Network timeouts: Large responses timeout on slow connections
  • Scale ceiling: System will break at ~200 tasks per feature

Current Implementation

API Route: /src/app/api/features/[featureId]/route.ts

// Returns everything at once
const feature = await getFeature(featureId, userId);
// Includes: feature.phases[].tasks[] - unbounded arrays

Type Definition: /src/types/roadmap.tsx

export interface FeatureDetail {
  phases: PhaseWithTasks[];  // Each phase has tasks: TicketListItem[]
  // No pagination metadata
}

Frontend: /src/app/w/[slug]/roadmap/[featureId]/page.tsx

  • Fetches entire feature on mount
  • Passes all tasks to TicketsList component
  • No virtualization or windowing

Proposed Solution

Lazy-load tasks when user navigates to Tasks tab

Phase 1: Separate endpoints

GET /api/features/[featureId]  // Feature + phases metadata only (no tasks)
GET /api/features/[featureId]/tasks?page=1&limit=50  // Paginated tasks

Phase 2: Frontend changes

  • Feature detail page fetches feature without tasks
  • Tasks tab triggers separate fetch when user clicks "Tasks"
  • Add virtual scrolling with react-window for task list rendering

Phase 3: Backend optimization

  • Add cursor-based pagination for efficient queries
  • Return pagination metadata: { data: [], pagination: { total, page, limit, hasMore } }

Alternative: Query parameter approach

GET /api/features/[featureId]?includeTasks=false  // Default: exclude tasks
GET /api/features/[featureId]?includeTasks=true&tasksPage=1&tasksLimit=50

Success Criteria

  • Feature with 500 tasks loads in <2 seconds
  • Browser doesn't freeze when rendering task list
  • API response size stays under 1MB regardless of task count
  • Tasks are fetched only when user navigates to Tasks tab

Code References

  • /src/app/api/features/[featureId]/route.ts - API route handler
  • /src/services/roadmap/features.ts - getFeature service function
  • /src/types/roadmap.tsx - FeatureDetail type (lines 620-640)
  • /src/components/features/TicketsList/index.tsx - Frontend component that renders tasks

Effort Estimate

2-3 weeks

  • Backend API changes: 3-4 days
  • Frontend refactoring: 4-5 days
  • Virtual scrolling implementation: 2-3 days
  • Testing and optimization: 3-4 days

Priority

Critical - This will become a blocker as features grow beyond 50-100 tasks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions