# Feature 004: Assignments & Scope Tags - Implementation Plan

## Project Context

### Technical Foundation
- **Laravel**: 12 (latest stable)
- **PHP**: 8.4.15
- **Admin UI**: Filament v4
- **Interactive Components**: Livewire v3
- **Database**: PostgreSQL with JSONB
- **External API**: Microsoft Graph API (Intune endpoints)
- **Testing**: Pest v4 (unit, feature, browser tests)
- **Local Dev**: Laravel Sail (Docker)
- **Deployment**: Dokploy (VPS, staging + production)

### Constitution Check
✅ Spec reviewed: `specs/004-assignments-scope-tags/spec.md`  
✅ Constitution followed: `.specify/constitution.md`  
✅ SDD workflow: Feature branch → spec + code → PR to dev  
✅ Multi-agent coordination: Session branch pattern recommended

### Project Structure
```
app/
├── Models/
│   ├── BackupItem.php         # Add assignments column
│   ├── RestoreRun.php         # Add group_mapping column
│   └── Policy.php             # Add assignments relationship methods
├── Services/
│   ├── Graph/
│   │   ├── AssignmentFetcher.php      # NEW: Fetch assignments with fallback
│   │   ├── GroupResolver.php          # NEW: Resolve group IDs to names
│   │   └── ScopeTagResolver.php       # NEW: Resolve scope tag IDs with cache
│   ├── AssignmentBackupService.php    # NEW: Backup assignments logic
│   └── AssignmentRestoreService.php   # NEW: Restore assignments logic
├── Filament/
│   ├── Resources/
│   │   └── PolicyResource/
│   │       └── Pages/
│   │           └── ViewPolicy.php     # Add Assignments tab
│   └── Forms/Components/
│       └── GroupMappingWizard.php     # NEW: Multi-step group mapping
└── Jobs/
    ├── FetchAssignmentsJob.php        # NEW: Async assignment fetch
    └── RestoreAssignmentsJob.php      # NEW: Async assignment restore

database/migrations/
├── xxxx_add_assignments_to_backup_items.php
└── xxxx_add_group_mapping_to_restore_runs.php

tests/
├── Unit/
│   ├── AssignmentFetcherTest.php
│   ├── GroupResolverTest.php
│   └── ScopeTagResolverTest.php
├── Feature/
│   ├── BackupWithAssignmentsTest.php
│   ├── PolicyViewAssignmentsTabTest.php
│   ├── RestoreGroupMappingTest.php
│   └── RestoreAssignmentApplicationTest.php
└── Browser/
    └── GroupMappingWizardTest.php
```

---

## Implementation Phases

### Phase 1: Setup & Database (Foundation)
**Duration**: 2-3 hours  
**Goal**: Prepare data layer for storing assignments and group mappings

**Tasks**:
1. Create migration for `backup_items.assignments` JSONB column
2. Create migration for `restore_runs.group_mapping` JSONB column
3. Update `BackupItem` model with `assignments` cast and accessor methods
4. Update `RestoreRun` model with `group_mapping` cast and helper methods
5. Add Graph contract config for assignments endpoints in `config/graph_contracts.php`
6. Create unit tests for model methods

**Acceptance Criteria**:
- Migrations reversible and run cleanly on Sail
- Models have proper JSONB casts
- Unit tests pass for assignment/mapping accessors

---

### Phase 2: Graph API Integration (Core Services)
**Duration**: 4-6 hours  
**Goal**: Build reliable services to fetch/resolve assignments and scope tags

**Tasks**:
1. Create `AssignmentFetcher` service with fallback strategy:
   - Primary: GET `/assignments`
   - Fallback: GET with `$expand=assignments`
   - Error handling with fail-soft
2. Create `GroupResolver` service:
   - POST `/directoryObjects/getByIds` batch resolution
   - Handle orphaned IDs gracefully
   - Cache resolved groups (5 min TTL)
3. Create `ScopeTagResolver` service:
   - GET `/deviceManagement/roleScopeTags`
   - Cache scope tags (1 hour TTL)
   - Extract from policy payload's `roleScopeTagIds`
4. Write unit tests mocking Graph responses:
   - Success scenarios
   - Partial failures (some IDs not found)
   - Complete failures (API down)

**Acceptance Criteria**:
- Services handle all failure scenarios gracefully
- Tests achieve 90%+ coverage
- Fallback strategies proven with mocks
- Cache TTLs configurable via config

---

### Phase 3: US1 - Backup with Assignments (MVP Core)
**Duration**: 4-5 hours  
**Goal**: Allow admins to optionally include assignments in backups

**Tasks**:
1. Add "Include Assignments & Scope Tags" checkbox to Backup creation form
2. Create `AssignmentBackupService`:
   - Accept tenantId, policyId, includeAssignments flag
   - Call `AssignmentFetcher` if flag enabled
   - Resolve scope tag names via `ScopeTagResolver`
   - Update `backup_items.metadata` with assignment count
   - Store assignments in `backup_items.assignments` column
3. Dispatch async job `FetchAssignmentsJob` if checkbox enabled
4. Handle job failures: log warning, set `assignments_fetch_failed: true`
5. Create feature test: `BackupWithAssignmentsTest`
   - Test backup with checkbox enabled
   - Test backup with checkbox disabled
   - Test assignment fetch failure handling
6. Add audit log entry: `backup.assignments.included`

**Acceptance Criteria**:
- Checkbox appears on Settings Catalog backup forms only
- Assignments stored in JSONB with correct schema
- Metadata includes `assignment_count`, `scope_tag_ids`, `has_orphaned_assignments`
- Feature test passes with mocked Graph responses
- Audit log records decision

---

### Phase 4: US2 - Policy View with Assignments Tab
**Duration**: 3-4 hours  
**Goal**: Display assignments in read-only view for auditing

**Tasks**:
1. Add "Assignments" tab to `PolicyResource/ViewPolicy.php`
2. Create Filament Table for assignments:
   - Columns: Type, Name, Mode (Include/Exclude), ID
   - Handle orphaned IDs: "Unknown Group (ID: {id})" with warning icon
3. Create Scope Tags section (list with IDs)
4. Handle empty state: "No assignments found"
5. Update `BackupItem` detail view to show assignment summary in metadata card
6. Create feature test: `PolicyViewAssignmentsTabTest`
   - Test assignments table rendering
   - Test orphaned ID display
   - Test scope tags section
   - Test empty state

**Acceptance Criteria**:
- Tab visible only for Settings Catalog policies with assignments
- Orphaned IDs render with clear warning
- Scope tags display with names + IDs
- Feature test passes

---

### Phase 5: US3 - Restore with Group Mapping (Core Restore)
**Duration**: 6-8 hours  
**Goal**: Enable cross-tenant restores with group mapping wizard

**Tasks**:
1. Create `GroupMappingWizard` Filament multi-step form component:
   - Step 1: Restore Preview (existing)
   - Step 2: Group Mapping (NEW)
   - Step 3: Confirm (existing)
2. Implement Group Mapping step logic:
   - Detect unresolved groups via POST `/directoryObjects/getByIds`
   - Fetch target tenant groups (with caching, 5 min TTL)
   - Render table: Source Group | Target Group Dropdown | Skip Checkbox
   - Search/filter support for 500+ groups
3. Persist group mapping in `restore_runs.group_mapping` JSON
4. Create `AssignmentRestoreService`:
   - Accept policyId, assignments array, group_mapping object
   - Replace source group IDs with mapped target IDs
   - Skip assignments marked "Skip"
   - Execute DELETE-then-CREATE pattern:
     * GET existing assignments
     * DELETE each (204 No Content expected)
     * POST each new/mapped assignment (201 Created expected)
   - Handle per-assignment failures (fail-soft)
   - Log outcomes per assignment
5. Dispatch async job `RestoreAssignmentsJob`
6. Create feature test: `RestoreGroupMappingTest`
   - Test group mapping wizard flow
   - Test group ID resolution
   - Test mapping persistence
   - Test skip functionality
7. Add audit log entries:
   - `restore.group_mapping.applied`
   - `restore.assignment.created` (per assignment)
   - `restore.assignment.skipped`

**Acceptance Criteria**:
- Group mapping step appears only when unresolved groups exist
- Dropdown searchable with 500+ groups
- Mapping persisted and visible in audit logs
- Restore applies assignments correctly with mapped IDs
- Per-assignment outcomes logged
- Feature test passes

---

### Phase 6: US4 - Restore Preview with Assignment Diff
**Duration**: 2-3 hours  
**Goal**: Show admins what assignments will change before restore

**Tasks**:
1. Enhance Restore Preview step to show assignment diff:
   - Added assignments (green)
   - Removed assignments (red)
   - Unchanged assignments (gray)
2. Add scope tag diff: "Scope Tags: 2 matched, 1 not found in target"
3. Create diff algorithm:
   - Compare source assignments with target policy's current assignments
   - Group by change type (added/removed/unchanged)
4. Update feature test: `RestoreAssignmentApplicationTest` to verify diff display

**Acceptance Criteria**:
- Diff shows clear visual indicators (colors, icons)
- Scope tag warnings visible
- Diff accurate for all scenarios (same tenant, cross-tenant, empty target)

---

### Phase 7: Scope Tags (Full Support)
**Duration**: 2-3 hours  
**Goal**: Complete scope tag handling in backup/restore

**Tasks**:
1. Update `AssignmentBackupService` to extract `roleScopeTagIds` from policy payload
2. Resolve scope tag names via `ScopeTagResolver` during backup
3. Update restore logic to preserve scope tag IDs if they exist in target
4. Log warnings for missing scope tags (don't block restore)
5. Update unit test: `ScopeTagResolverTest`
6. Update feature test: Add scope tag scenarios to `RestoreAssignmentApplicationTest`

**Acceptance Criteria**:
- Scope tags captured during backup with names
- Restore preserves IDs when available in target
- Warnings logged for missing scope tags
- Tests pass with various scope tag scenarios

---

### Phase 8: Polish & Performance
**Duration**: 3-4 hours  
**Goal**: Optimize performance and improve UX

**Tasks**:
1. Add loading indicators to Group Mapping dropdown (wire:loading)
2. Implement group search debouncing (500ms)
3. Optimize Graph API calls:
   - Batch group resolution (max 100 IDs per batch)
   - Add 100ms delay between sequential assignment POST calls
4. Add cache warming for target tenant groups
5. Create performance test: Restore 50 policies with 10 assignments each
6. Add tooltips/help text:
   - Backup checkbox: "Captures group/user targeting and RBAC scope. Adds ~2-5 KB per policy."
   - Group Mapping: "Map source groups to target groups for cross-tenant migrations."
7. Update documentation: Add "Assignments & Scope Tags" section to README

**Acceptance Criteria**:
- Loading states visible during async operations
- Search responsive (no lag with 500+ groups)
- Performance benchmarks documented
- Tooltips clear and helpful
- README updated

---

### Phase 9: Testing & QA
**Duration**: 2-3 hours  
**Goal**: Comprehensive testing across all scenarios

**Tasks**:
1. Manual QA checklist:
   - ✅ Create backup with assignments checkbox (same tenant)
   - ✅ Create backup without assignments checkbox
   - ✅ View policy with assignments tab
   - ✅ Restore to same tenant (auto-match groups)
   - ✅ Restore to different tenant (group mapping wizard)
   - ✅ Handle orphaned group IDs gracefully
   - ✅ Skip assignments during group mapping
   - ✅ Handle Graph API failures (assignments fetch, group resolution)
2. Browser test: `GroupMappingWizardTest`
   - Navigate through multi-step wizard
   - Search groups in dropdown
   - Toggle skip checkboxes
   - Verify mapping persistence
3. Load testing: 100+ policies with 20 assignments each
4. Staging deployment validation

**Acceptance Criteria**:
- All manual QA scenarios pass
- Browser test passes on Chrome/Firefox
- Load test completes under 5 minutes
- Staging environment stable

---

### Phase 10: Deployment & Documentation
**Duration**: 1-2 hours  
**Goal**: Production-ready deployment

**Tasks**:
1. Create deployment checklist:
   - Run migrations on staging
   - Verify no data loss
   - Test on production-like data volume
2. Update `specs/004-assignments-scope-tags/spec.md` with implementation notes
3. Create migration guide for existing backups (no retroactive assignment capture)
4. Add monitoring alerts:
   - Assignment fetch failure rate > 10%
   - Group resolution failure rate > 5%
5. Production deployment:
   - Deploy to production via Dokploy
   - Monitor logs for 24 hours
   - Verify no Graph API rate limit issues

**Acceptance Criteria**:
- Production deployment successful
- No critical errors in 24-hour monitoring window
- Documentation complete and accurate

---

## Dependencies

### Hard Dependencies (Required)
- Feature 001: Backup/Restore core infrastructure ✅
- Graph Contract Registry ✅
- Filament multi-step forms (built-in) ✅

### Soft Dependencies (Nice to Have)
- Feature 005: Bulk Operations (for bulk assignment backup) 🚧

---

## Risk Management

| Risk | Likelihood | Impact | Mitigation |
|------|-----------|--------|-----------|
| Graph API assignments endpoint slow | Medium | Medium | Async fetch with fail-soft, cache groups |
| Target tenant has 1000+ groups | High | Medium | Searchable dropdown with pagination, cache |
| Group IDs change across tenants | High | High | Group name-based fallback matching (future) |
| Scope Tag IDs don't exist in target | Medium | Low | Log warning, allow policy creation |
| Assignment restore fails mid-process | Medium | High | Per-assignment error handling, audit log |

---

## Success Metrics

### Functional
- ✅ Backup checkbox functional, assignments captured
- ✅ Policy View shows assignments tab with accurate data
- ✅ Group Mapping wizard handles 100+ groups smoothly
- ✅ Restore applies assignments with 90%+ success rate
- ✅ Audit logs record all mapping decisions

### Technical
- ✅ Tests achieve 85%+ coverage for new code
- ✅ Graph API calls < 2 seconds average
- ✅ Group mapping UI responsive with 500+ groups
- ✅ Assignment restore completes in < 30 seconds for 20 policies

### User Experience
- ✅ Admins can backup/restore assignments without manual intervention
- ✅ Cross-tenant migrations supported with clear group mapping UX
- ✅ Orphaned IDs handled gracefully with clear warnings

---

## MVP Scope (Phases 1-4 + Core of Phase 5)

**Estimated Duration**: 16-22 hours

**Included**:
- US1: Backup with Assignments checkbox ✅
- US2: Policy View with Assignments tab ✅
- US3: Restore with Group Mapping (basic, same-tenant auto-match) ✅

**Excluded** (Post-MVP):
- US4: Restore Preview with detailed diff
- Scope Tags full support
- Performance optimizations
- Cross-tenant group mapping wizard

**Rationale**: MVP proves core value (backup/restore assignments) while deferring complex cross-tenant mapping for iteration.

---

## Full Implementation Estimate

**Total Duration**: 30-40 hours

**Phase Breakdown**:
- Phase 1: Setup & Database (2-3 hours)
- Phase 2: Graph API Integration (4-6 hours)
- Phase 3: US1 - Backup (4-5 hours)
- Phase 4: US2 - Policy View (3-4 hours)
- Phase 5: US3 - Group Mapping (6-8 hours)
- Phase 6: US4 - Restore Preview (2-3 hours)
- Phase 7: Scope Tags (2-3 hours)
- Phase 8: Polish (3-4 hours)
- Phase 9: Testing & QA (2-3 hours)
- Phase 10: Deployment (1-2 hours)

**Parallel Opportunities**:
- Phase 2 (Graph services) + Phase 3 (Backup) can be split across developers
- Phase 4 (Policy View) independent of Phase 5 (Restore)
- Phase 7 (Scope Tags) can be developed alongside Phase 6 (Restore Preview)

---

## Open Questions (For Review)

1. **Smart Matching**: Should we support "smart matching" (group name similarity) for group mapping?
   - **Recommendation**: Phase 2 feature, start with manual mapping MVP
   
2. **Dynamic Groups**: How to handle dynamic groups (membership rules) - copy rules or skip?
   - **Recommendation**: Skip initially, document as limitation, consider for future

3. **Scope Tag Blocking**: Should Scope Tag warnings block restore or just warn?
   - **Recommendation**: Warn only, allow restore to proceed (Graph API default behavior)

4. **Assignment Filters**: Should we preserve assignment filters (device/user filters)?
   - **Recommendation**: Yes, preserve all filter properties in JSON

---

## Next Steps

1. **Review**: Team review of plan.md, resolve open questions
2. **Research**: Create `research.md` with detailed technology decisions
3. **Data Model**: Create `data-model.md` with schema details
4. **Quickstart**: Create `quickstart.md` with developer setup
5. **Tasks**: Break down phases into granular tasks in `tasks.md`
6. **Implement**: Start with Phase 1 (Setup & Database)

---

**Status**: Ready for Review  
**Created**: 2025-12-22  
**Estimated Total Duration**: 30-40 hours (MVP: 16-22 hours)  
**Next Document**: `research.md`
