--- description: "Task list for Manual Policy Sync Button feature" --- # Tasks: Manual Policy Sync Button **Branch**: `002-manual-policy-sync` **Input**: [plan.md](./plan.md), [spec.md](./spec.md) **Status**: ✅ **COMPLETED** (Documenting for record) **Tests**: No test tasks included - manual testing only for this feature (as specified in plan.md) **Organization**: Tasks organized 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 (US1, US2, US3) - Paths are absolute from repository root --- ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Configure environment and prepare existing codebase - [x] T001 Add N8N_SYNC_WEBHOOK_URL to lib/env.mjs server schema with z.string().optional() - [x] T002 [P] Verify existing authentication extracts tenantId in lib/auth/utils.ts - [x] T003 [P] Confirm Shadcn Button and Toast (sonner) are available **Status**: ✅ Complete - No new project setup needed, leveraging existing infrastructure --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented **⚠️ CRITICAL**: No user story work can begin until this phase is complete - [x] T004 Verify NextAuth session includes tenantId field (already implemented in previous feature) - [x] T005 Verify getUserAuth() server action exists in lib/auth/utils.ts - [x] T006 Confirm fetch() is available for webhook calls (Node.js built-in) **Status**: ✅ Complete - All foundational pieces already exist from 001-global-policy-search feature **Checkpoint**: Foundation ready - user story implementation can now begin in parallel --- ## Phase 3: User Story 1 - Trigger Immediate Sync (Priority: P1) 🎯 MVP **Goal**: Admin can click button to trigger n8n webhook for immediate policy sync **Independent Test**: Login → /search page → Click "Sync Policies" → Success toast appears → n8n receives POST with tenantId ### Implementation for User Story 1 - [x] T007 [P] [US1] Create SyncButton component in components/search/SyncButton.tsx - [x] T008 [P] [US1] Implement triggerPolicySync() Server Action in lib/actions/policySettings.ts - [x] T009 [US1] Add authentication check with getUserAuth() in triggerPolicySync() - [x] T010 [US1] Extract tenantId from session with null check - [x] T011 [US1] Validate N8N_SYNC_WEBHOOK_URL environment variable exists - [x] T012 [US1] Implement fetch POST request to webhook with JSON body - [x] T013 [US1] Add useTransition() hook in SyncButton for loading state - [x] T014 [US1] Implement handleSync function calling Server Action - [x] T015 [US1] Add success toast notification "Policy sync triggered successfully" - [x] T016 [US1] Render Button with RefreshCw icon from lucide-react - [x] T017 [US1] Integrate SyncButton into app/(app)/search/page.tsx CardHeader - [x] T018 [US1] Position button right of title using flexbox (justify-between) **Files Modified**: - ✅ `lib/env.mjs` - Added N8N_SYNC_WEBHOOK_URL - ✅ `lib/actions/policySettings.ts` - Added triggerPolicySync() function - ✅ `components/search/SyncButton.tsx` - Created new component - ✅ `app/(app)/search/page.tsx` - Integrated SyncButton **Checkpoint**: ✅ User Story 1 is fully functional and testable independently --- ## Phase 4: User Story 2 - Handle Sync Errors Gracefully (Priority: P2) **Goal**: Admin receives clear error feedback when sync fails **Independent Test**: Simulate webhook failure (wrong URL, network error) → Error toast appears with user-friendly message ### Implementation for User Story 2 - [x] T019 [US2] Add try-catch block in triggerPolicySync() to handle network errors - [x] T020 [US2] Return error response when session.user is null ("Not authenticated") - [x] T021 [US2] Return error response when tenantId is null ("No tenant ID found in session") - [x] T022 [US2] Return error response when N8N_SYNC_WEBHOOK_URL is not configured ("Sync webhook not configured") - [x] T023 [US2] Check webhook response status and throw error if not ok - [x] T024 [US2] Add error toast notification in SyncButton handleSync catch block - [x] T025 [US2] Add console.error logging in triggerPolicySync() for debugging - [x] T026 [US2] Ensure button returns to normal state after error (useTransition handles this) **Files Modified**: - ✅ `lib/actions/policySettings.ts` - Added comprehensive error handling - ✅ `components/search/SyncButton.tsx` - Added error toast display **Checkpoint**: ✅ User Stories 1 AND 2 both work independently with proper error handling --- ## Phase 5: User Story 3 - Prevent Multiple Simultaneous Syncs (Priority: P3) **Goal**: Button prevents duplicate requests during sync operation **Independent Test**: Click button rapidly multiple times → Only one request sent, button stays disabled ### Implementation for User Story 3 - [x] T027 [US3] Add disabled prop to Button based on isPending state - [x] T028 [US3] Conditionally render "Syncing..." text when isPending is true - [x] T029 [US3] Add animate-spin class to RefreshCw icon when isPending is true - [x] T030 [US3] Verify useTransition() prevents multiple simultaneous calls **Files Modified**: - ✅ `components/search/SyncButton.tsx` - Added disabled state and loading UI **Checkpoint**: ✅ All user stories (1, 2, 3) are independently functional with proper UX --- ## Phase 6: Polish & Cross-Cutting Concerns **Purpose**: Final touches and production readiness - [x] T031 Test button on mobile responsive layout - [x] T032 Verify button styling matches existing search page design - [x] T033 Test with missing N8N_SYNC_WEBHOOK_URL → Error toast appears - [x] T034 Test with unauthenticated user → Error toast appears - [x] T035 Test with mock webhook success → Success toast appears - [x] T036 Document N8N_SYNC_WEBHOOK_URL in deployment notes - [x] T037 Commit changes to 002-manual-policy-sync branch - [x] T038 Create specification and plan documentation **Status**: ✅ Complete - All polish tasks finished --- ## Deployment Checklist - [x] All tasks completed (T001-T038) - [x] Code committed to feature branch - [x] Specification (spec.md) created - [x] Implementation plan (plan.md) created - [x] Tasks (tasks.md) documented - [ ] **TODO**: Configure N8N_SYNC_WEBHOOK_URL in Dokploy environment variables - [ ] **TODO**: Merge 002-manual-policy-sync → main - [ ] **TODO**: Deploy to production - [ ] **TODO**: Verify button appears on /search page in production - [ ] **TODO**: Test manual sync trigger with real n8n webhook --- ## Dependencies Between Tasks **Legend**: `→` means "depends on" ```text Setup Phase: T001, T002, T003 → [Can run in parallel] Foundational Phase: T004, T005, T006 → [Already complete from previous work] User Story 1 (Core Sync): T007 [SyncButton UI] → T013-T018 [UI refinements] T008 [Server Action] → T009-T012 [Action logic] T007, T008 → T017 [Page integration] User Story 2 (Error Handling): T008 complete → T019-T025 [Add error cases] T007 complete → T024, T026 [Error UI feedback] User Story 3 (Prevent Duplicates): T007, T013 complete → T027-T030 [Loading state enhancements] ``` **Parallel Opportunities**: - Phase 1: All tasks (T001-T003) can run in parallel - User Story 1: T007 (UI) and T008 (Server Action) can be built in parallel - User Story 2: Error handling can be added to both files simultaneously --- ## Parallel Execution Examples ### Example 1: User Story 1 (Two Developers) **Developer A** (Frontend): ```bash # Create SyncButton component - T007: components/search/SyncButton.tsx (stub Server Action call) - T013-T016: Add loading state, toast, button rendering - T017-T018: Integrate into search page ``` **Developer B** (Backend): ```bash # Create Server Action - T008: lib/actions/policySettings.ts (stub return success) - T009-T012: Add auth check, tenant ID extraction, webhook call ``` **Integration**: Once both T007 and T008 are complete, connect them together ### Example 2: User Story 2 (One Developer) ```bash # Add error handling after US1 is complete - T019-T023: Server Action error cases (5 min each) - T024-T026: UI error handling (5 min each) - Total time: ~30 minutes ``` --- ## Implementation Strategy ### MVP-First Approach **MVP = User Story 1 ONLY (P1)**: - Admin can click button - Button shows loading state - Success toast appears - n8n receives webhook This delivers immediate value and can be shipped independently. ### Incremental Delivery **Release 1**: User Story 1 (P1) - Core sync functionality **Release 2**: Add User Story 2 (P2) - Error handling **Release 3**: Add User Story 3 (P3) - UX polish Each release is independently valuable and deployable. --- ## Testing Notes **Manual Testing Checklist** (from plan.md): ✅ **Happy Path**: - [x] Login → /search → Click "Sync Policies" → Loading state → Success toast - [x] Verify n8n receives POST with correct tenantId ✅ **Error Cases**: - [x] Not authenticated → Error toast - [x] No tenantId in session → Error toast - [x] Webhook URL not configured → Error toast - [x] Network error → Error toast - [x] Webhook returns 500 → Error toast ✅ **UI/UX**: - [x] Button shows spinner during sync - [x] Button disabled during sync - [x] Rapid clicks don't send duplicates - [x] Mobile responsive **No automated tests for this feature** - manual testing deemed sufficient for MVP (as per plan.md). --- ## Task Summary **Total Tasks**: 38 **Completed**: 38 ✅ **Remaining**: 0 **Tasks by User Story**: - Setup: 3 tasks - Foundational: 3 tasks - User Story 1 (P1): 12 tasks - User Story 2 (P2): 8 tasks - User Story 3 (P3): 4 tasks - Polish: 8 tasks **Parallel Opportunities**: 15 tasks marked [P] can run in parallel **Critical Path**: Setup → Foundational → US1 core (T007-T012) → US2 errors → US3 UX → Polish **Estimated Implementation Time** (if starting from scratch): - Setup: 15 minutes - Foundational: 0 minutes (already done) - User Story 1: 2 hours - User Story 2: 30 minutes - User Story 3: 20 minutes - Polish: 30 minutes - **Total**: ~3.5 hours **Actual Time**: Already completed ✅ --- ## Next Feature Recommendations Based on this implementation, consider these follow-up features: 1. **Sync History Tracking** (new spec) - Track when syncs were triggered - Display last sync timestamp on search page - Show sync status (pending, success, failed) 2. **Rate Limiting** (enhancement to 002) - Prevent syncs more frequently than once per 5 minutes - Show countdown timer until next sync allowed 3. **Bulk Tenant Sync** (admin feature) - Allow platform admins to trigger sync for all tenants - New admin dashboard page - Requires admin role system These can each be separate feature specs following the same workflow.