240 lines
9.2 KiB
Markdown
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
|