tenantpilot/specs/001-global-policy-search/tasks.md
2025-12-05 22:06:22 +01:00

240 lines
9.2 KiB
Markdown

# Tasks: Global Policy Search
**Feature**: 001-global-policy-search
**Branch**: `001-global-policy-search`
**Prerequisites**: plan.md, spec.md, data-model.md, contracts/
## Format: `- [ ] [ID] [P?] [Story?] Description with file path`
- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (US1, US2, US3)
---
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Project initialization and environment setup
- [X] T001 Add POLICY_API_SECRET to .env file with secure random value (use openssl rand -base64 32)
- [X] T002 Add POLICY_API_SECRET to lib/env.mjs as optional string validation
---
## 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] T003 Create PolicySetting Drizzle schema in lib/db/schema/policySettings.ts
- [X] T004 Export policySettings from lib/db/schema/index.ts (if exists) or lib/db/index.ts
- [X] T005 Run npm run db:push to create policy_settings table
- [X] T006 [P] Create Zod validators in lib/validators/policySettings.ts (policySettingSchema, bulkPolicySettingsSchema)
- [X] T007 [P] Extend NextAuth session to include tenantId from Azure AD tid claim in lib/auth/utils.ts
- [X] T008 Add POLICY_TYPES constant array to lib/db/schema/policySettings.ts
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
---
## Phase 3: User Story 1 - Search Policy Settings (Priority: P1) 🎯 MVP
**Goal**: Enable admins to search for policy settings by keyword (e.g., "USB", "Camera") across their tenant's policies
**Independent Test**: Insert test data for a tenant, login as that tenant's user, search for a keyword, verify results show only that tenant's matching policies
### Implementation for User Story 1
- [X] T009 [P] [US1] Create searchPolicySettings Server Action in lib/actions/policySettings.ts
- [X] T010 [P] [US1] Create getPolicySettingById Server Action in lib/actions/policySettings.ts
- [X] T011 [P] [US1] Create getRecentPolicySettings Server Action in lib/actions/policySettings.ts
- [X] T012 [US1] Create search page at app/(app)/search/page.tsx with search input and results table
- [X] T013 [P] [US1] Create SearchInput component in components/search/SearchInput.tsx with debounce
- [X] T014 [P] [US1] Create ResultsTable component in components/search/ResultsTable.tsx with columns: Setting Name, Setting Value, Policy Name, Policy Type
- [X] T015 [P] [US1] Create EmptyState component in components/search/EmptyState.tsx for no results
- [X] T016 [US1] Add search route to config/nav.ts with Search icon
**Checkpoint**: User Story 1 complete - Admins can search their tenant's policy settings independently
---
## Phase 4: User Story 2 - Tenant-Isolated Results (Priority: P1)
**Goal**: Ensure admins ONLY see policy settings from their own tenant, never data from other customers
**Independent Test**: Create test data for two different tenants, login as tenant A, verify search only returns tenant A's data, verify tenant B's data is never visible
### Implementation for User Story 2
**Note**: This user story is implemented through security measures in User Story 1 tasks. The tenant isolation logic is baked into:
- T007: Session with tenantId extraction
- T009: Server Actions filter by tenantId
- T012: Search page uses tenant-filtered actions
**Additional Security Validation**:
- [X] T017 [US2] Add explicit tenantId WHERE clause to ALL database queries in lib/actions/policySettings.ts
- [X] T018 [US2] Add security tests: verify getUserAuth returns tenantId, verify queries include tenantId filter
- [X] T019 [US2] Add error handling for missing tenantId in session (return Unauthorized error)
**Checkpoint**: User Stories 1 AND 2 complete - Search works AND is fully tenant-isolated
---
## Phase 5: User Story 3 - Data Ingestion API (Priority: P2)
**Goal**: Enable n8n workflows to ingest policy settings via API so search data stays up-to-date
**Independent Test**: Send POST request with policy data to /api/policy-settings with valid API_SECRET, verify data appears in database and is searchable
### Implementation for User Story 3
- [X] T020 [US3] Create POST handler in app/api/policy-settings/route.ts with X-API-SECRET validation
- [X] T021 [US3] Implement bulk upsert logic using db.insert().onConflictDoUpdate() in app/api/policy-settings/route.ts
- [X] T022 [US3] Add request body validation using bulkPolicySettingsSchema in app/api/policy-settings/route.ts
- [X] T023 [US3] Add error responses: 401 for invalid secret, 400 for validation errors, 500 for DB errors
- [X] T024 [P] [US3] Create DELETE handler in app/api/policy-settings/route.ts for tenant cleanup (query param: tenantId)
- [ ] T025 [US3] Test API endpoint with curl: POST with valid secret should return 200, POST without secret should return 401
**Checkpoint**: All user stories complete - Search works, is tenant-isolated, AND can ingest data from n8n
---
## Phase 6: Polish & Cross-Cutting Concerns
**Purpose**: Improvements that affect multiple user stories
- [X] T026 [P] Add loading states with Suspense boundaries to app/(app)/search/page.tsx
- [X] T027 [P] Add toast notifications for search errors using Shadcn Sonner
- [ ] T028 Add rate limiting to API route (optional: check if needed for production)
- [ ] T029 Run through quickstart.md validation steps to verify complete setup
- [ ] T030 [P] Add JSDoc comments to all Server Actions in lib/actions/policySettings.ts
- [ ] T031 Test edge cases: empty search, very long search terms (>200 chars), special characters, SQL injection attempts
---
## Dependencies & Execution Order
### Phase Dependencies
```
Phase 1 (Setup)
Phase 2 (Foundational) ← BLOCKS all user stories
├─→ Phase 3 (US1 - Search) ← MVP: Can deploy after this
├─→ Phase 4 (US2 - Tenant Isolation) ← Implemented within US1
└─→ Phase 5 (US3 - Ingestion API)
Phase 6 (Polish)
```
### User Story Dependencies
- **US1 (Search)**: Depends on Foundational phase (T003-T008) - No dependencies on other stories
- **US2 (Tenant Isolation)**: Security measures integrated into US1 - Implemented through T007, T009, T012, plus additional validation T017-T019
- **US3 (Ingestion API)**: Depends on Foundational phase (T003-T008) - Independent from US1/US2 (different files/endpoints)
### Within Each Phase
**Phase 2 (Foundational)**:
```
T001-T002 (Environment)
T003 (Schema) → T004 (Export) → T005 (Migration)
T006 (Validators) [P] ← Can run parallel with T007-T008
T007 (Auth Session) [P] ← Can run parallel with T006
T008 (Constants) [P] ← Can run parallel with T006-T007
```
**Phase 3 (US1)**:
```
After Foundational:
T009-T011 (Server Actions) [P] ← All can run in parallel (different functions)
T012 (Search Page) ← Needs T009-T011
T013-T015 (Components) [P] ← All can run in parallel (different files)
T016 (Navigation) ← Needs T012
```
**Phase 5 (US3)**:
```
After Foundational:
T020-T024 (API Route) ← Sequential in same file
T025 (Testing)
```
### Parallel Opportunities
- **Setup Phase**: T001 and T002 can run in parallel
- **Foundational Phase**: T006, T007, T008 can all run in parallel after T005
- **US1 Phase**: T009-T011 can run in parallel, then T013-T015 can run in parallel
- **US3 and US1**: Can be worked on by different developers in parallel (different files)
- **Polish Phase**: T026, T027, T030 can all run in parallel
---
## Parallel Example: Starting Multiple User Stories
If you have multiple developers, after Phase 2 completes:
```bash
# Developer 1: User Story 1 (Search UI)
git checkout -b US1-search-ui
# Work on T009-T016
# Developer 2: User Story 3 (Ingestion API)
git checkout -b US3-ingestion-api
# Work on T020-T025
# Both can work independently and merge when complete
```
---
## Suggested MVP Scope (Minimum Viable Product)
**For fastest time-to-value, implement in this order:**
1. **Phase 1 + Phase 2**: Setup and Foundation (T001-T008) - ~2 hours
2. **Phase 3 (US1)**: Search functionality (T009-T016) - ~3 hours
3. **Phase 4 (US2)**: Security validation (T017-T019) - ~1 hour
**Total MVP**: ~6 hours of focused work
**Result**: Working search with full tenant isolation. Data can be added manually to DB for testing.
**Later**: Add Phase 5 (US3) for n8n ingestion when ready to automate data collection.
---
## Implementation Strategy
1. **MVP First**: Complete Phases 1-4 (Setup, Foundation, US1, US2) for immediate value
2. **Incremental Delivery**: Each user story is independently testable and deployable
3. **Parallel Work**: US1 and US3 can be developed simultaneously by different team members
4. **Test As You Go**: Verify each checkpoint before proceeding to next phase
---
## Task Count Summary
- **Setup**: 2 tasks
- **Foundational**: 6 tasks (blocking)
- **User Story 1**: 8 tasks
- **User Story 2**: 3 tasks (security validation)
- **User Story 3**: 6 tasks
- **Polish**: 6 tasks
**Total**: 31 tasks
**Parallel Opportunities**: 12 tasks can run in parallel (marked with [P])
**Independent Test Criteria**:
- US1: Search returns results, filtered by tenant
- US2: Tenant A cannot see Tenant B's data
- US3: POST to API with secret writes data to DB