✨ New Features - Advanced data table with TanStack Table v8 + Server Actions - Server-side pagination (10/25/50/100 rows per page) - Multi-column sorting with visual indicators - Column management (show/hide, resize) persisted to localStorage - URL state synchronization for shareable filtered views - Sticky header with compact/comfortable density modes 📦 Components Added - PolicyTableV2.tsx - Main table with TanStack integration - PolicyTableColumns.tsx - 7 column definitions with sorting - PolicyTablePagination.tsx - Pagination controls - PolicyTableToolbar.tsx - Density toggle + column visibility menu - ColumnVisibilityMenu.tsx - Show/hide columns dropdown 🔧 Hooks Added - usePolicyTable.ts - TanStack Table initialization - useURLState.ts - URL query param sync with nuqs - useTablePreferences.ts - localStorage persistence 🎨 Server Actions Updated - getPolicySettingsV2 - Pagination + sorting + filtering + Zod validation - exportPolicySettingsCSV - Server-side CSV generation (max 5000 rows) 📚 Documentation Added - Intune Migration Guide (1400+ lines) - Reverse engineering strategy - Intune Reference Version tracking - Tasks completed: 22/62 (Phase 1-3) ✅ Zero TypeScript compilation errors ✅ All MVP success criteria met (pagination, sorting, column management) ✅ Ready for Phase 4-7 (filtering, export, detail view, polish) Refs: specs/004-policy-explorer-v2/tasks.md
16 KiB
Tasks: Policy Explorer V2
Input: Design documents from /specs/004-policy-explorer-v2/
Prerequisites: plan.md (required), spec.md (required)
Tests: Unit tests for utilities, E2E tests for table interactions
Organization: Tasks are grouped by user story to enable independent implementation and testing.
Format: [ID] [P?] [Story] Description
- [P]: Can run in parallel (different files, no dependencies)
- [Story]: Which user story this task belongs to (e.g., US1, US2, US3, US4)
- Include exact file paths in descriptions
Path Conventions
- App routes:
app/(app)/search/ - Components:
components/policy-explorer/ - Server Actions:
lib/actions/policySettings.ts - Hooks:
lib/hooks/ - Utils:
lib/utils/ - Tests:
tests/unit/andtests/e2e/
Phase 1: Setup (Dependencies & Infrastructure)
Purpose: Install dependencies and create base infrastructure
- T001 Install TanStack Table v8 (
@tanstack/react-table) via npm - T002 [P] Install
nuqsfor URL state management via npm (or decide on native useSearchParams) - T003 [P] Create types file lib/types/policy-table.ts with DataTableState, FilterState, TablePreferences interfaces
- T004 [P] Add composite database index for performance: (tenantId, policyType, settingName) in lib/db/schema/policySettings.ts
Phase 2: Foundational (Server Actions & Data Layer)
Purpose: Update Server Actions to support pagination, sorting, filtering
⚠️ CRITICAL: This must be complete before ANY user story UI can be built
- T005 Update getPolicySettings Server Action in lib/actions/policySettings.ts to accept pagination params (page, pageSize)
- T006 Add sorting support to getPolicySettings (sortBy, sortDir parameters) in lib/actions/policySettings.ts
- T007 Add policyTypes filter support to getPolicySettings in lib/actions/policySettings.ts
- T008 Update getPolicySettings return type to include meta (totalCount, pageCount, hasNextPage, hasPreviousPage) in lib/actions/policySettings.ts
- T009 Add input validation for getPolicySettings (Zod schema for params) in lib/actions/policySettings.ts
- T010 Create exportPolicySettingsCSV Server Action in lib/actions/policySettings.ts (server-side CSV generation, max 5000 rows)
Checkpoint: Server Actions ready - UI implementation can begin
Phase 3: User Story 1 - Advanced Data Table Navigation (Priority: P1) 🎯 MVP
Goal: Implement pagination, sorting, column management, sticky header
Independent Test: Load 500+ settings, paginate, sort by different columns, hide/show columns, resize columns
Implementation for User Story 1
- T011 [P] [US1] Create PolicyTableColumns.tsx in components/policy-explorer/ with column definitions (settingName, settingValue, policyName, policyType, lastSyncedAt, graphPolicyId)
- T012 [P] [US1] Create usePolicyTable hook in lib/hooks/usePolicyTable.ts (TanStack Table initialization with manual pagination mode)
- T013 [P] [US1] Create useTablePreferences hook in lib/hooks/useTablePreferences.ts (localStorage persistence for columnVisibility, columnSizing, density)
- T014 [P] [US1] Create useURLState hook in lib/hooks/useURLState.ts (sync pagination, sorting, filters with URL query params)
- T015 [US1] Create PolicyTable.tsx in components/policy-explorer/ (main table component using TanStack Table + shadcn Table primitives)
- T016 [US1] Implement pagination controls in PolicyTablePagination.tsx in components/policy-explorer/ (Previous, Next, Page Numbers, Page Size selector)
- T017 [US1] Implement column sorting in PolicyTable.tsx (click header to toggle ASC/DESC, visual sort indicators)
- T018 [US1] Create ColumnVisibilityMenu.tsx in components/policy-explorer/ (dropdown with checkboxes to show/hide columns)
- T019 [US1] Implement column resizing in PolicyTable.tsx (drag column borders, persist width to localStorage)
- T020 [US1] Implement sticky table header in PolicyTable.tsx (CSS position: sticky, remains visible on scroll)
- T021 [US1] Implement density mode toggle in PolicyTableToolbar.tsx (compact vs comfortable row height, persist to localStorage)
- T022 [US1] Update app/(app)/search/page.tsx to fetch data with pagination/sorting params and pass to PolicyTable
Checkpoint: Data table with pagination, sorting, column management fully functional
Phase 4: User Story 2 - Enhanced Filtering (Priority: P1)
Goal: Implement PolicyType filter with multi-select checkboxes
Independent Test: Select policy types, verify filtered results, combine with search
Implementation for User Story 2
- T023 [P] [US2] Create PolicyTypeFilter component in components/policy-explorer/PolicyTypeFilter.tsx (multi-select checkbox dropdown)
- T024 [US2] Add PolicyTypeFilter to PolicyTableToolbar.tsx in components/policy-explorer/
- T025 [US2] Connect PolicyTypeFilter to useURLState hook (sync selected types with URL query param)
- T026 [US2] Update PolicyTable to trigger data refetch when policyTypes filter changes
- T027 [US2] Implement filter badge/chip display in PolicyTableToolbar showing active filters with clear button
- T028 [US2] Add "Clear All Filters" button to PolicyTableToolbar
Checkpoint: Filtering works, combines with search, persists in URL state
Phase 5: User Story 3 - Bulk Export (Priority: P1)
Goal: Implement CSV export for selected rows (client) and all filtered results (server)
Independent Test: Select rows, export CSV, open in Excel, verify content and escaping
Implementation for User Story 3
- T029 [P] [US3] Create csv-export.ts utility in lib/utils/ (client-side CSV generation with proper escaping)
- T030 [P] [US3] Add unit tests for CSV escaping (commas, quotes, newlines) in tests/unit/csv-export.test.ts
- T031 [US3] Implement row selection in PolicyTable.tsx (checkboxes for individual rows + Select All)
- T032 [US3] Create ExportButton component in components/policy-explorer/ExportButton.tsx (dropdown: "Export Selected" / "Export All Filtered")
- T033 [US3] Implement "Export Selected" action in ExportButton (client-side CSV generation, trigger download)
- T034 [US3] Implement "Export All Filtered" action in ExportButton (call exportPolicySettingsCSV Server Action, trigger download)
- T035 [US3] Add export button to PolicyTableToolbar with disabled state when no rows selected
- T036 [US3] Add warning UI when filtered results exceed 5000 rows ("Export limited to 5000 rows")
- T037 [US3] Add loading state for server-side CSV generation (spinner + progress indicator)
Checkpoint: CSV export works for both selected rows and filtered results with proper escaping
Phase 6: User Story 4 - Enhanced Detail View (Priority: P2)
Goal: Add copy-to-clipboard buttons, raw JSON view, "Open in Intune" link to detail sheet
Independent Test: Open detail sheet, test copy buttons, view raw JSON, click Intune link
Implementation for User Story 4
- T038 [P] [US4] Create useCopyToClipboard hook in lib/hooks/useCopyToClipboard.ts (wrapper for Clipboard API with success toast)
- T039 [P] [US4] Add unit tests for clipboard utility in tests/unit/clipboard.test.ts
- T040 [US4] Update PolicyDetailSheet.tsx in components/policy-explorer/ to add "Copy Policy ID" button
- T041 [US4] Add "Copy Setting Name" and "Copy Setting Value" buttons to PolicyDetailSheet.tsx
- T042 [US4] Add tabs to PolicyDetailSheet: "Details" and "Raw JSON"
- T043 [US4] Implement Raw JSON tab in PolicyDetailSheet showing formatted JSON with syntax highlighting
- T044 [US4] Create getIntunePortalLink utility in lib/utils/policy-table-helpers.ts (construct Intune URL by policy type)
- T045 [US4] Add "Open in Intune" button to PolicyDetailSheet (external link icon, opens in new tab)
- T046 [US4] Add fallback for "Open in Intune" when URL construction fails (copy policy ID instead)
Checkpoint: Detail sheet has enhanced functionality, all copy buttons work, raw JSON displays correctly
Phase 7: Polish & Cross-Cutting Concerns
Purpose: Meta info, truncation, edge cases, accessibility, testing
- T047 [P] Create PolicyTableMeta component in components/policy-explorer/PolicyTableMeta.tsx (displays "X settings · Y policies · Last sync")
- T048 [P] Add PolicyTableMeta above table in app/(app)/search/page.tsx
- T049 [P] Implement value truncation with tooltip in PolicyTableColumns.tsx (long settingValue, graphPolicyId)
- T050 [P] Add responsive behavior: disable column resizing on mobile (<768px) in PolicyTable.tsx
- T051 [P] Add horizontal scroll for wide tables with sticky first column in PolicyTable.tsx
- T052 Add ARIA labels for accessibility (table, pagination, filters, sort buttons)
- T053 Add keyboard navigation support (arrow keys for rows, Enter to open detail sheet)
- T054 Create E2E tests for pagination in tests/e2e/policy-explorer.spec.ts
- T055 Create E2E tests for sorting in tests/e2e/policy-explorer.spec.ts
- T056 Create E2E tests for filtering in tests/e2e/policy-explorer.spec.ts
- T057 Create E2E tests for CSV export in tests/e2e/policy-explorer.spec.ts
- T058 Create E2E tests for column management in tests/e2e/policy-explorer.spec.ts
- T059 Add loading skeleton states for table, filters, export
- T060 Add error boundary for table component with retry button
- T061 Performance optimization: Add React.memo to table rows if needed
- T062 Update README.md or documentation with Policy Explorer V2 features
Dependencies
User Story Completion Order
graph TD
Setup[Phase 1: Setup] --> Foundation[Phase 2: Foundation]
Foundation --> US1[Phase 3: US1 - Data Table]
Foundation --> US2[Phase 4: US2 - Filtering]
Foundation --> US3[Phase 5: US3 - Export]
US1 --> US4[Phase 6: US4 - Detail View]
US1 --> Polish[Phase 7: Polish]
US2 --> Polish
US3 --> Polish
US4 --> Polish
Explanation:
- Setup & Foundation must complete first (T001-T010)
- US1 (Data Table) is the foundation for all other user stories
- US2 (Filtering) depends on table being functional
- US3 (Export) depends on row selection from US1
- US4 (Detail View) extends existing sheet, can happen in parallel with US2/US3
- Polish comes last after all core features work
Task-Level Dependencies
Critical Path (must complete in order):
- T001-T004 (setup) → T005-T010 (Server Actions)
- T005-T010 (Server Actions) → T011-T022 (US1 table implementation)
- T011-T022 (table) → All other user stories can begin
- T031 (row selection) → T033-T037 (export features)
Parallel Opportunities:
- T001, T002, T003, T004 can run in parallel (setup tasks)
- T005-T010 can run in parallel after T004 (Server Action updates)
- T011, T012, T013, T014 can run in parallel (hooks and column definitions)
- T023, T029, T030, T038, T039, T047, T049 can run in parallel after table is functional
- T054-T058 can run in parallel during polish phase
Parallel Execution Examples
Phase 1 - Setup (All tasks in parallel)
Run these tasks simultaneously:
# Terminal 1: Install TanStack Table
npm install @tanstack/react-table
# Terminal 2: Install nuqs
npm install nuqs
# Terminal 3: Create types file
# T003 - Create lib/types/policy-table.ts
# Terminal 4: Add database index
# T004 - Update schema
Phase 2 - Server Actions (After T004 completes)
Run Server Action updates in parallel:
# All T005-T010 modify lib/actions/policySettings.ts
# Can be done together or split by developer
# T005-T009: Update getPolicySettings
# T010: Create exportPolicySettingsCSV
Phase 3 - US1 Foundation (After Phase 2)
Run these in parallel:
# Terminal 1: T011 - Column definitions
# Terminal 2: T012 - usePolicyTable hook
# Terminal 3: T013 - useTablePreferences hook
# Terminal 4: T014 - useURLState hook
Phase 7 - Polish (After Phase 3-6 complete)
Run tests and polish tasks in parallel:
# Terminal 1: T054-T058 - E2E tests
# Terminal 2: T047, T048 - Meta info component
# Terminal 3: T049, T050, T051 - Responsive behavior
# Terminal 4: T052, T053 - Accessibility
Implementation Strategy
MVP Scope (Ship This First)
Phase 3: User Story 1 - Advanced Data Table Navigation
- This is the core value: pagination, sorting, column management
- Includes: T011-T022 (12 tasks)
- Delivers SC-001, SC-002, SC-003: Fast pagination, sorting, persistent settings
- Can be shipped independently: Provides immediate value even without filtering/export
Incremental Delivery
- MVP (Phase 3): Ship US1 data table → users can navigate large datasets
- V1.1 (Phase 4): Add US2 filtering → users can narrow down results by policy type
- V1.2 (Phase 5): Add US3 export → users can extract data for reports
- V1.3 (Phase 6): Add US4 enhanced detail view → power users get advanced features
- V2.0 (Phase 7): Polish + complete testing → production-ready
Success Metrics (Track These)
- SC-001: Page load time <500ms (50 rows) → Measure with Lighthouse/DevTools
- SC-002: Sorting performance <200ms → Measure with Performance API
- SC-003: localStorage persistence → Test browser reload, verify settings restored
- SC-004: Client CSV export <2s (1000 rows) → Measure download trigger time
- SC-005: Server CSV export <5s (5000 rows) → Measure Server Action execution time
- SC-006: Filter + search AND logic → Verify result counts match expectations
- SC-007: URL state shareable → Copy URL, paste in new tab, verify identical view
- SC-008: Copy buttons work → Test in Chrome, Firefox, Safari, Edge
Validation Checklist
Before marking tasks complete, verify:
- All Server Actions have input validation (Zod schemas)
- All Server Actions enforce tenant isolation (check user session)
- Table pagination works with 0 results, 1 result, 1000+ results
- Sorting works correctly for strings, numbers, dates
- Column visibility changes persist after browser reload
- CSV export handles special characters (commas, quotes, newlines)
- CSV export is Excel-compatible (UTF-8 BOM, proper line endings)
- URL state works with browser back/forward buttons
- Sticky header works on different viewport sizes
- Row selection persists across page changes (or clears intentionally)
- All interactive elements have keyboard support
- All interactive elements have ARIA labels
- Loading states show for all async operations
- Error states show helpful messages with retry options
- TypeScript strict mode passes (no
anytypes) - All new components use Shadcn UI primitives
Notes
About TanStack Table Integration:
- Use "manual" pagination mode (table doesn't handle data fetching)
- Server Actions fetch data, table handles UI state only
- This keeps us constitution-compliant (server-first architecture)
About CSV Export:
- Client-side (<1000 rows): Fast, no server load, instant download
- Server-side (1000-5000 rows): Handles larger datasets, proper memory management
- Always include CSV header row with column names
- Use UTF-8 BOM for Excel compatibility:
\uFEFFprefix
About localStorage Schema:
- Version field enables migrations when adding new preferences
- Store only user preferences, never actual data
- Handle quota exceeded gracefully (clear old data, warn user)
About URL State:
- Keep URLs shareable (don't include sensitive data)
- Use short query param names (p=page, ps=pageSize, sb=sortBy)
- Handle malformed URLs gracefully (validate and reset to defaults)
Performance Considerations:
- Add database index on (tenantId, policyType, settingName) for sorting
- Use React.memo on table rows only if profiling shows re-render issues
- Debounce search input to avoid excessive Server Action calls
- Consider virtual scrolling if page size >100 causes jank
Tasks Version: 1.0
Last Updated: 2025-12-09
Total Tasks: 62
Estimated MVP Scope: T001-T022 (22 tasks)