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

5.2 KiB

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:

    {
      "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).