# Feature Specification: App Protection (MAM) Policy Type Coverage **Feature Branch**: `feat/009-app-protection-policy` **Created**: 2025-12-29 **Status**: Draft ## Overview Make **App Protection (MAM)** policies (`appProtectionPolicy`) reliable in TenantAtlas’ existing Policy/Backup/Restore flows by: - Preventing **non-policy objects** (Managed App Configurations) from being imported as policies during sync. - Capturing and restoring **assignments** for `managedAppPolicies`. - Expanding the accepted `@odata.type` family so restore/create flows don’t fail with false `odata_mismatch`. - Improving **admin readability** by normalizing key settings (booleans/durations) into Intune-like sections. ## In Scope - Policy type: `appProtectionPolicy` (`deviceAppManagement/managedAppPolicies`) - Policy sync: skip objects with `@odata.type == #microsoft.graph.targetedManagedAppConfiguration` - Backup/version capture: capture assignments when enabled - Restore: reapply assignments using `/assign` with group + assignment filter mapping (existing mapping UI) - UI: normalize App Protection snapshots for readability (bool/duration formatting + grouped sections) ## Out of Scope (v1) - “Target apps” (`/targetApps`) workflows for App Protection objects (showing the actual app list like Intune). - Full “create from scratch” for missing App Protection policies (beyond generic create fallback). - Separately modeling App Configurations (`targetedManagedAppConfigurations`) as their own policy type. ## User Scenarios & Testing *(mandatory)* ### User Story 1 — Clean Inventory (P1) As an admin, I want the App Protection policy list to only include actual protection policies (not app configurations), so inventory stays accurate. **Independent Test**: Run policy sync; confirm `targetedManagedAppConfiguration` objects do not appear as `appProtectionPolicy` records. **Acceptance Scenarios** 1. Given Graph returns mixed objects from `managedAppPolicies`, when sync runs, then items with `@odata.type == #microsoft.graph.targetedManagedAppConfiguration` are skipped. ### User Story 2 — Backup assignments (P1) As an admin, I can capture App Protection assignments during backup/version capture, so restore can reproduce targeting. **Independent Test**: Capture a backup set with assignments enabled; verify assignments are saved for App Protection policies. **Acceptance Scenarios** 1. Given assignments are enabled, when capturing an App Protection snapshot, then assignments are fetched via the configured assignments endpoint and stored on the version/item. ### User Story 3 — Restore assignments (P1) As an admin, I can restore App Protection assignments using group mapping with clear skip/failure reasons. **Independent Test**: Restore an App Protection backup into a tenant with different group IDs; verify assignments are created/skipped with expected outcomes. **Acceptance Scenarios** 1. Given group mapping is present, when restore executes, then assignments are applied via `/assign`. 2. Given group mapping is missing for a group, when restore executes, then that assignment is skipped with a clear reason. ## Notes - Filtering is implemented in code because Graph filtering does not reliably exclude `targetedManagedAppConfiguration` objects from the `managedAppPolicies` list response. - `@odata.type` matching uses `config/graph_contracts.php` as the safety gate for create flows. - Assignments restore uses derived endpoints (e.g. `/deviceAppManagement/androidManagedAppProtections/{id}/assign`) based on `@odata.type` for compatibility.