TenantAtlas/specs/006-sot-foundations-assignments/research.md
ahmido b9c47e7973 feat/006-sot-foundations-assignments (#6)
## Summary
<!-- Kurz: Was ändert sich und warum? -->

## Spec-Driven Development (SDD)
- [ ] Es gibt eine Spec unter `specs/<NNN>-<feature>/`
- [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md`
- [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation)
- [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert

## Implementation
- [ ] Implementierung entspricht der Spec
- [ ] Edge cases / Fehlerfälle berücksichtigt
- [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes

## Tests
- [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit)
- [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`)

## Migration / Config / Ops (falls relevant)
- [ ] Migration(en) enthalten und getestet
- [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration)
- [ ] Neue Env Vars dokumentiert (`.env.example` / Doku)
- [ ] Queue/cron/storage Auswirkungen geprüft

## UI (Filament/Livewire) (falls relevant)
- [ ] UI-Flows geprüft
- [ ] Screenshots/Notizen hinzugefügt

## Notes
<!-- Links, Screenshots, Follow-ups, offene Punkte -->

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #6
2025-12-25 14:25:16 +00:00

87 lines
5.2 KiB
Markdown

# Research: SoT Foundations & Assignments (006)
This document resolves planning unknowns and records decisions for implementing foundations-first backup/restore and assignment-aware restore.
## Decision: Foundation object endpoints and permissions
- **Decision**: Implement “foundation” backup/restore for:
- Assignment Filters via `deviceManagement/assignmentFilters` (permission: `DeviceManagementConfiguration.ReadWrite.All`).
- Scope Tags via `deviceManagement/roleScopeTags` (permission: `DeviceManagementRBAC.ReadWrite.All`).
- Notification Message Templates via `deviceManagement/notificationMessageTemplates` (permission: `DeviceManagementServiceConfig.ReadWrite.All`, with `localizedNotificationMessages` treated as a future enhancement).
- **Rationale**: These are explicitly called out as SoT foundations and appear as dependencies in the IntuneManagement reference implementation.
- **Alternatives considered**:
- Treat foundations as “manual prerequisites” only (no backup/restore) → rejected because it blocks safe assignment restore.
- Store only names (no full payload) → rejected because restore needs full object definitions.
## Decision: Assignment apply mechanism (Graph)
- **Decision**: Apply assignments using a per-resource `.../{id}/assign` Graph action (default), with request body shape:
```json
{
"assignments": [
{
"target": {
"@odata.type": "...",
"groupId": "...",
"deviceAndAppManagementAssignmentFilterId": "...",
"deviceAndAppManagementAssignmentFilterType": "Include|Exclude"
}
}
]
}
```
and support type-specific overrides if needed.
- **Rationale**: Matches the IntuneManagement import approach and aligns with SoT “apply assignments after foundations exist”.
- **Alternatives considered**:
- PATCH the resource with an `assignments` property → rejected because many Intune resources do not support assignment updates via PATCH.
- Only restore object payloads, never assignments → rejected (SoT requires assignment-aware restore).
## Decision: Mapping strategy (deterministic, safe)
- **Decision**: Produce and persist an “old → new” mapping for foundation objects by matching primarily on `displayName` (or name-equivalent), with collision handling:
- If a unique match exists in the target tenant by name: reuse (map old → existing).
- If no match exists: create (map old → created).
- If multiple matches exist: create a copy with a predictable suffix and record “created_copy” in the report.
- **Rationale**: SoT requires determinism and auditability; mapping by opaque IDs is impossible across tenants.
- **Alternatives considered**:
- Always create new objects regardless of matches → rejected due to duplication and name collision risk.
- Hash-based matching (normalize and compare multiple fields) → deferred; start with name-based plus explicit collision handling.
## Decision: Where to store mappings and restore decision report
- **Decision**: Store mapping + decisions in `restore_runs.preview` (dry-run) and `restore_runs.results` (execute), optionally mirrored into `restore_runs.metadata` for fast access.
- **Rationale**: The schema already supports JSON `preview`/`results`; this keeps the first iteration simple and audit-friendly.
- **Alternatives considered**:
- Dedicated `restore_mappings` table → deferred until querying/reporting requirements demand it.
## Decision: How to represent foundation snapshots in storage
- **Decision**: Store foundation snapshots as `backup_items` rows with:
- `policy_id = null`
- `policy_type` set to a dedicated type key (e.g. `assignmentFilter`, `roleScopeTag`, `notificationMessageTemplate`)
- `policy_identifier` set to the Graph object `id`
- `payload` containing the raw Graph resource
- `metadata` containing normalized identifiers used for matching (e.g. `displayName`).
- **Rationale**: `backup_items.policy_id` is nullable; reusing the same snapshot container avoids schema churn.
- **Alternatives considered**:
- New “foundation_snapshots” table → rejected for MVP due to extra migrations and duplication.
## Decision: Conditional Access restore behavior (safety)
- **Decision**: Keep Conditional Access restore as **preview-only**, even in execute mode.
- **Rationale**: CA depends on identity objects (e.g., named locations) and is security-critical; SoT explicitly allows preview-first for risky items.
- **Alternatives considered**:
- Allow CA restore with best-effort group/user mapping → rejected as too risky without complete dependency mapping.
## Decision: Scope for assignment-aware restore (initial)
- **Decision**: Apply assignment mapping for existing supported configuration objects (policy types already in `config/tenantpilot.php`), focusing first on targets that include:
- group targeting (`groupId`)
- assignment filters (`deviceAndAppManagementAssignmentFilterId`/Type)
- role scope tags (`roleScopeTagIds`) where applicable.
- **Rationale**: Incrementally delivers value without requiring support for all object classes in SoT.
- **Alternatives considered**:
- Expand to named locations / terms of use / authentication strengths immediately → deferred (separate dependency set).