# 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/` and `tests/e2e/` --- ## Phase 1: Setup (Dependencies & Infrastructure) **Purpose**: Install dependencies and create base infrastructure - [X] T001 Install TanStack Table v8 (`@tanstack/react-table`) via npm - [X] T002 [P] Install `nuqs` for URL state management via npm (or decide on native useSearchParams) - [X] T003 [P] Create types file lib/types/policy-table.ts with DataTableState, FilterState, TablePreferences interfaces - [X] 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 - [X] T005 Update getPolicySettings Server Action in lib/actions/policySettings.ts to accept pagination params (page, pageSize) - [X] T006 Add sorting support to getPolicySettings (sortBy, sortDir parameters) in lib/actions/policySettings.ts - [X] T007 Add policyTypes filter support to getPolicySettings in lib/actions/policySettings.ts - [X] T008 Update getPolicySettings return type to include meta (totalCount, pageCount, hasNextPage, hasPreviousPage) in lib/actions/policySettings.ts - [X] T009 Add input validation for getPolicySettings (Zod schema for params) in lib/actions/policySettings.ts - [X] 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 - [X] T011 [P] [US1] Create PolicyTableColumns.tsx in components/policy-explorer/ with column definitions (settingName, settingValue, policyName, policyType, lastSyncedAt, graphPolicyId) - [X] T012 [P] [US1] Create usePolicyTable hook in lib/hooks/usePolicyTable.ts (TanStack Table initialization with manual pagination mode) - [X] T013 [P] [US1] Create useTablePreferences hook in lib/hooks/useTablePreferences.ts (localStorage persistence for columnVisibility, columnSizing, density) - [X] T014 [P] [US1] Create useURLState hook in lib/hooks/useURLState.ts (sync pagination, sorting, filters with URL query params) - [X] T015 [US1] Create PolicyTable.tsx in components/policy-explorer/ (main table component using TanStack Table + shadcn Table primitives) - [X] T016 [US1] Implement pagination controls in PolicyTablePagination.tsx in components/policy-explorer/ (Previous, Next, Page Numbers, Page Size selector) - [X] T017 [US1] Implement column sorting in PolicyTable.tsx (click header to toggle ASC/DESC, visual sort indicators) - [X] T018 [US1] Create ColumnVisibilityMenu.tsx in components/policy-explorer/ (dropdown with checkboxes to show/hide columns) - [X] T019 [US1] Implement column resizing in PolicyTable.tsx (drag column borders, persist width to localStorage) - [X] T020 [US1] Implement sticky table header in PolicyTable.tsx (CSS position: sticky, remains visible on scroll) - [X] T021 [US1] Implement density mode toggle in PolicyTableToolbar.tsx (compact vs comfortable row height, persist to localStorage) - [X] 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 ```mermaid 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): 1. T001-T004 (setup) โ†’ T005-T010 (Server Actions) 2. T005-T010 (Server Actions) โ†’ T011-T022 (US1 table implementation) 3. T011-T022 (table) โ†’ All other user stories can begin 4. 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: ```bash # 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: ```bash # 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: ```bash # 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: ```bash # 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 1. **MVP** (Phase 3): Ship US1 data table โ†’ users can navigate large datasets 2. **V1.1** (Phase 4): Add US2 filtering โ†’ users can narrow down results by policy type 3. **V1.2** (Phase 5): Add US3 export โ†’ users can extract data for reports 4. **V1.3** (Phase 6): Add US4 enhanced detail view โ†’ power users get advanced features 5. **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 `any` types) - [ ] 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: `\uFEFF` prefix **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)