diff --git a/specs/008-apps-app-management/plan.md b/specs/008-apps-app-management/plan.md new file mode 100644 index 0000000..41e8587 --- /dev/null +++ b/specs/008-apps-app-management/plan.md @@ -0,0 +1,26 @@ +# Implementation Plan: Apps (008) + +**Branch**: `feat/008-apps-app-management` +**Date**: 2025-12-29 +**Spec Source**: [spec.md](./spec.md) + +## Summary +Make `mobileApp` reliable in the existing Policy/Backup/Restore flows by: + +- Extending Graph contract registry with app assignment endpoints and a realistic `@odata.type` family. +- Enforcing metadata-only snapshots during capture (contract-driven filtering). +- Adding targeted Pest tests for contracts + snapshot behavior. + +## Execution Steps +1. Update `config/graph_contracts.php` for `mobileApp`: + - Add assignments list + assign action endpoints and payload key. + - Expand `type_family` using known app types. +2. Update `app/Services/Intune/PolicySnapshotService.php`: + - For metadata-only types, request/select and persist only metadata keys (even if Graph falls back). +3. Add/extend tests: + - `tests/Unit/GraphContractRegistryActualDataTest.php` for `mobileApp` contract coverage. + - `tests/Unit/PolicySnapshotServiceTest.php` for metadata-only filtering behavior. +4. Run formatting + tests: + - `./vendor/bin/pint --dirty` + - `./vendor/bin/sail artisan test tests/Unit/GraphContractRegistryActualDataTest.php tests/Unit/PolicySnapshotServiceTest.php` + diff --git a/specs/008-apps-app-management/spec.md b/specs/008-apps-app-management/spec.md new file mode 100644 index 0000000..f32e66b --- /dev/null +++ b/specs/008-apps-app-management/spec.md @@ -0,0 +1,59 @@ +# Feature Specification: Apps (Mobile Apps) Metadata-Only + Assignments + +**Feature Branch**: `feat/008-apps-app-management` +**Created**: 2025-12-29 +**Status**: Draft +**Input**: `.specify/spec.md` (mobileApp scope) + `references/IntuneManagement-master/Documentation/AppTypes.json` (known app @odata.type values). + +## Overview +Add reliable **mobile app** (`mobileApp`) coverage for inventory, backup/version capture, and restore: + +- Capture **metadata-only** snapshots for Intune apps (no content/binary workflows). +- Capture and restore **assignments** using the Intune `/assignments` and `/assign` endpoints. +- Accept common **derived `@odata.type`** values for apps to avoid false `odata_mismatch` failures. + +## In Scope +- Policy type: `mobileApp` (`deviceAppManagement/mobileApps`) in existing Policy/Backup/Restore flows. +- Backup/version capture stores only metadata fields + `@odata.type` (contract-driven). +- Restore updates metadata fields on existing apps and reapplies assignments (with group + assignment filter mapping). +- UI continues to use the existing Policies/Versions/Backup/Restore Filament experience. + +## Out of Scope (v1) +- Downloading or re-uploading app binaries/content (Win32 content versions, files, etc.). +- Creating complex missing apps from scratch (where Graph requires app-type-specific required fields). +- App relationships (dependencies/supersedence) beyond what is already present in metadata. + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Inventory and detail view for apps (Priority: P1) +As an admin, I can see Intune apps in the Policies list and inspect app metadata and assignments safely. + +**Independent Test**: Sync policies; open Policies list filtered to “Applications”; open an app and verify metadata is readable and assignments are shown (when captured). + +**Acceptance Scenarios**: +1. Given apps exist in Intune, when the admin syncs and opens Policies, then apps appear under type `Applications (Metadata only)`. +2. Given an app is a derived type (e.g. Win32, iOS VPP), when viewed/restored, then it is considered in-family for `mobileApp` (no `odata_mismatch`). + +### User Story 2 - Backup capture for apps (Priority: P1) +As an admin, I can capture backups/versions of apps with metadata-only payloads and optional assignments. + +**Independent Test**: Create a backup with assignments enabled including at least one app; confirm the stored payload is metadata-only and assignments are captured. + +**Acceptance Scenarios**: +1. Given app backup is configured as metadata-only, when a snapshot is captured, then only whitelisted metadata keys are persisted. +2. Given assignments are enabled, when capturing, then assignments are fetched via the configured assignments endpoint and stored alongside the snapshot. + +### User Story 3 - Restore assignments for apps (Priority: P1) +As an admin, I can restore app assignments (and metadata where supported) using group mapping with clear skip/failure reasons. + +**Independent Test**: Restore an app backup into a tenant where group IDs differ; verify assignments are created/skipped with the expected outcomes. + +**Acceptance Scenarios**: +1. Given an app exists in the target tenant, when restore executes, then metadata fields are patched and assignments are applied via `/assign`. +2. Given required group mappings are missing, when restore executes, then assignments are skipped with a human readable reason per assignment. +3. Given the app does not exist (404), when restore executes, then the item fails with a clear reason (no attempt to create complex apps from metadata-only snapshots). + +## Notes +- `@odata.type` matching uses `config/graph_contracts.php` as the safety gate for restore execution. +- App type-family values are sourced from `references/IntuneManagement-master/Documentation/AppTypes.json` and kept conservative. + diff --git a/specs/008-apps-app-management/tasks.md b/specs/008-apps-app-management/tasks.md new file mode 100644 index 0000000..9b9a734 --- /dev/null +++ b/specs/008-apps-app-management/tasks.md @@ -0,0 +1,17 @@ +# Tasks: Apps (Mobile Apps) Metadata-Only + Assignments (008) + +**Branch**: `feat/008-apps-app-management` | **Date**: 2025-12-29 +**Input**: [spec.md](./spec.md), [plan.md](./plan.md) + +## Phase 1: Contracts and Safety Gates +- [ ] T001 Expand `mobileApp` Graph contract in `config/graph_contracts.php` (assignments endpoints + payload key + type family). + +## Phase 2: Snapshot Capture (Metadata-Only) +- [ ] T002 Enforce metadata-only snapshot capture for apps in `app/Services/Intune/PolicySnapshotService.php`. + +## Phase 3: Tests and Verification +- [ ] T003 Add contract coverage tests in `tests/Unit/GraphContractRegistryActualDataTest.php`. +- [ ] T004 Add snapshot filtering tests in `tests/Unit/PolicySnapshotServiceTest.php`. +- [ ] T005 Run tests: `./vendor/bin/sail artisan test tests/Unit/GraphContractRegistryActualDataTest.php tests/Unit/PolicySnapshotServiceTest.php` +- [ ] T006 Run Pint: `./vendor/bin/pint --dirty` +