9.3 KiB
| description |
|---|
| Task list for implementing Entra Group Directory Cache (Groups v1) |
Tasks: Entra Group Directory Cache (Groups v1)
Input: Design documents from /specs/051-entra-group-directory-cache/
Prerequisites: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
Tests: Required (Pest), per FR-012 in spec.md.
Organization: Tasks are grouped by user story so each story can be implemented and tested independently.
Format: - [ ] T### [P?] [US#?] Description (with file path)
- [P]: Can run in parallel (different files, no dependencies)
- [US#]: User story mapping (US1/US2/US3)
Path Conventions (Laravel)
- App code:
app/ - Config:
config/ - DB:
database/migrations/,database/factories/ - Filament admin:
app/Filament/Resources/ - Console + scheduler wiring:
app/Console/Commands/,routes/console.php - Tests (Pest):
tests/Feature/,tests/Unit/
Phase 1: Setup (Shared Infrastructure)
Purpose: Introduce feature configuration and permission metadata.
- T001 Create feature config defaults in config/directory_groups.php (staleness_days=30, retention_days=90, schedule enabled/interval, page_size)
- T002 Update Group.Read.All feature tagging in config/intune_permissions.php (include directory-groups / group-directory-cache)
Phase 2: Foundational (Blocking Prerequisites)
Purpose: Database schema + core domain objects required by all user stories.
⚠️ CRITICAL: No user story work can begin until this phase is complete.
- T003 Create migrations for Entra groups + sync runs in database/migrations/_create_entra_groups_table.php and database/migrations/_create_entra_group_sync_runs_table.php
- T004 [P] Create EntraGroup model in app/Models/EntraGroup.php (tenant-scoped, casts for group_types)
- T005 [P] Create EntraGroupSyncRun model in app/Models/EntraGroupSyncRun.php (status constants, counters, safe error fields)
- T006 [P] Create EntraGroup factory in database/factories/EntraGroupFactory.php
- T007 [P] Create EntraGroupSyncRun factory in database/factories/EntraGroupSyncRunFactory.php
- T008 Add tenant relationships in app/Models/Tenant.php (entraGroups(), entraGroupSyncRuns())
- T009 Add directory-groups contract metadata in config/graph_contracts.php and accessor(s) in app/Services/Graph/GraphContractRegistry.php (select fields + base path for /groups)
Checkpoint: Foundation ready — user stories can now proceed.
Phase 3: User Story 1 - Sync groups into a tenant-scoped cache (Priority: P1) 🎯 MVP
Goal: Manual + scheduled async sync writes tenant-scoped group cache and run records (including safe error summaries).
Independent Test: Trigger a sync for a tenant and verify a run record exists and group rows are populated for that tenant.
Tests for User Story 1 (REQUIRED) ⚠️
Write these tests FIRST and ensure they fail before implementation.
-
T010 [P] [US1] Add test for manual sync creating a run + dispatching a job in tests/Feature/DirectoryGroups/StartSyncTest.php
-
T011 [P] [US1] Add test that sync job upserts groups + updates counters in tests/Feature/DirectoryGroups/SyncJobUpsertsGroupsTest.php
-
T012 [P] [US1] Add test that retention purge deletes groups older than retention window in tests/Feature/DirectoryGroups/SyncRetentionPurgeTest.php
-
T013 [P] [US1] Add test that scheduled dispatcher creates a run without a user initiator in tests/Feature/DirectoryGroups/ScheduledSyncDispatchTest.php
-
T014 [P] [US1] Implement deterministic selection key helper in app/Services/Directory/EntraGroupSelection.php
-
T015 [US1] Implement sync service in app/Services/Directory/EntraGroupSyncService.php (Graph paging via GraphClientInterface, upsert, counters, retention purge)
-
T016 [US1] Implement queued job in app/Jobs/EntraGroupSyncJob.php (run lifecycle: pending→running→succeeded/failed; safe error_category + error_summary)
-
T017 [US1] Add audit logging for sync start/completion in app/Jobs/EntraGroupSyncJob.php using app/Services/Intune/AuditLogger.php
-
T018 [P] [US1] Create Filament run resource in app/Filament/Resources/EntraGroupSyncRunResource.php and app/Filament/Resources/EntraGroupSyncRunResource/Pages/{ListEntraGroupSyncRuns,ViewEntraGroupSyncRun}.php
-
T019 [US1] Add “Sync Groups” action on List page in app/Filament/Resources/EntraGroupSyncRunResource/Pages/ListEntraGroupSyncRuns.php (creates run, dispatches job, shows notification)
-
T020 [US1] Implement scheduled dispatcher command in app/Console/Commands/TenantpilotDispatchDirectoryGroupsSync.php (idempotent per tenant + minute-slot, respects config/directory_groups.php)
-
T021 [US1] Register scheduler entry in routes/console.php for tenantpilot:directory-groups:dispatch (every minute)
Checkpoint: US1 complete — cache population works, runs are visible, and scheduled runs can be observed.
Phase 4: User Story 2 - Browse groups (Priority: P2)
Goal: Provide a cached-only “Directory → Groups” browse/search/filter/detail UI.
Independent Test: After a sync run, open the groups list and verify search/filter/detail views work using only cached data.
Tests for User Story 2 (REQUIRED) ⚠️
- T022 [P] [US2] Add test for listing/searching/filtering cached groups in tests/Feature/DirectoryGroups/BrowseGroupsTest.php
Implementation for User Story 2
- T023 [P] [US2] Create Filament groups resource in app/Filament/Resources/EntraGroupResource.php and app/Filament/Resources/EntraGroupResource/Pages/{ListEntraGroups,ViewEntraGroup}.php
- T024 [US2] Implement list query + filters (q search, stale filter, group type filter) in app/Filament/Resources/EntraGroupResource.php
- T025 [US2] Add “Sync Groups” header action that links to run list or starts a sync in app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php
Checkpoint: US2 complete — operators can browse/search cached groups and triage staleness.
Phase 5: User Story 3 - Name resolution across the suite (Priority: P3)
Goal: Any UI that displays group IDs shows a friendly cached label (or unresolved fallback) without live directory calls during render.
Independent Test: Load a page that includes group GUID references and verify it renders with names from DB cache (and fallbacks when missing) without calling Graph.
Tests for User Story 3 (REQUIRED) ⚠️
- T026 [P] [US3] Add unit test for label resolver formatting + fallbacks in tests/Unit/DirectoryGroups/EntraGroupLabelResolverTest.php
- T027 [P] [US3] Add feature test ensuring Tenant/Restore/PolicyVersion UI renders without Graph calls during render in tests/Feature/DirectoryGroups/NoLiveGraphOnRenderTest.php
Implementation for User Story 3
- T028 [US3] Implement DB-backed label resolver in app/Services/Directory/EntraGroupLabelResolver.php (resolveOne/resolveMany, tenant-scoped, stable formatting)
- T029 [US3] Refactor group label rendering in app/Filament/Resources/TenantResource.php to use EntraGroupLabelResolver instead of Graph lookups
- T030 [US3] Refactor Livewire assignments widget to use cached labels: app/Livewire/PolicyVersionAssignmentsWidget.php and resources/views/livewire/policy-version-assignments-widget.blade.php
- T031 [US3] Refactor restore results to show cached labels where possible: resources/views/filament/infolists/entries/restore-results.blade.php
- T032 [US3] Refactor restore group-mapping inputs/labels to prefer cached labels: app/Filament/Resources/RestoreRunResource.php
Checkpoint: US3 complete — name resolution is consistent and render-safe across key pages.
Phase 6: Polish & Cross-Cutting Concerns
Purpose: Validation, cleanup, and operational readiness.
- T033 [P] Run formatting on changed files with vendor/bin/pint --dirty
- T034 Run targeted Pest suite for this feature (e.g., php artisan test tests/Feature/DirectoryGroups and tests/Unit/DirectoryGroups)
- T035 Validate operator workflow against specs/051-entra-group-directory-cache/quickstart.md
Dependencies & Execution Order
Phase Dependencies
- Setup (Phase 1) → blocks nothing, but should be done first.
- Foundational (Phase 2) → BLOCKS all user stories.
- User Stories (Phase 3–5) → depend on Foundational; proceed in priority order (US1 → US2 → US3).
- Polish (Phase 6) → depends on all desired user stories.
User Story Dependencies
- US1 (P1): Depends on Phase 2 only.
- US2 (P2): Depends on US1 (needs data to browse).
- US3 (P3): Depends on US1 (needs cache populated); can begin in parallel with US2 once US1 is stable.
Parallel Execution Examples
US1
- Parallel tests: T010–T013
- Parallel foundational code: T014 and T018 can be developed alongside T015–T016 once schema/models exist.
US2
- T023 can start while T022 is being written (different files).
US3
- T028 can start while T026/T027 are being written; integration tasks T029–T032 can be split across different files.
Implementation Strategy
MVP (US1 only)
- Phase 1 → Phase 2
- Phase 3 (US1): tests → sync service/job → run UI → scheduler
- Stop and validate via quickstart workflow
Incremental Delivery
- Add US2 (browse) after US1 is stable.
- Add US3 (name resolution) after US1, then refactor page-by-page.