# Data Model — Intune RBAC Inventory & Backup v1 (127) ## Entities ### Foundation Type Metadata Config-defined support metadata for RBAC foundations. - Source: `config/tenantpilot.php` - New keys: - `intuneRoleDefinition` - `intuneRoleAssignment` - Required attributes: - `type` - `label` - `category = RBAC` - `platform = all` - `endpoint` - `backup` - `restore = preview-only` - `risk` ### Graph Contract Definition Config-defined Graph fetch contract for inventory-grade RBAC capture. - Source: `config/graph_contracts.php` - New contract keys: - `intuneRoleDefinition` - `intuneRoleAssignment` - Required fields: - `resource` - `allowed_select` - `allowed_expand` - `type_family` when available - optional `hydration` or follow-up fetch hints if full assignment fidelity requires them - Compatibility rule: - Existing `directoryRoleDefinitions` and `rbacRoleAssignment` keys remain unchanged for current health/onboarding flows. ### InventoryItem (tenant-owned observed state) Represents the latest observed RBAC inventory row per tenant and external object. - Existing model/table: `InventoryItem` - Ownership: - `workspace_id` NOT NULL - `tenant_id` NOT NULL - Identity: - unique by `tenant_id + policy_type + external_id` - Relevant fields for RBAC: - `policy_type` = `intuneRoleDefinition` or `intuneRoleAssignment` - `external_id` - `display_name` - `category = RBAC` - `platform = all` - `meta_jsonb` sanitized, metadata-only - `last_seen_at` - `last_seen_operation_run_id` - `meta_jsonb` for Role Definitions should include only safe observed metadata such as: - OData type - built-in versus custom state - summary counts or identifiers needed for inventory surfaces - `meta_jsonb` for Role Assignments should include only safe observed metadata such as: - linked role definition identifier or display name if available - assignment target counts or scope counts - warnings and sanitized support-state metadata ### Inventory Coverage Payload Canonical coverage status written into `OperationRun.context.inventory.coverage.foundation_types`. - Existing source: `App\Support\Inventory\InventoryCoverage` - New keys: - `foundation_types.intuneRoleDefinition` - `foundation_types.intuneRoleAssignment` - Per-type fields: - `status` in `succeeded | failed | skipped` - optional `item_count` - optional `error_code` ### BackupItem (tenant-owned immutable RBAC payload snapshot) Represents a captured RBAC foundation snapshot inside a backup set. - Existing model/table: `BackupItem` - Ownership: - `tenant_id` NOT NULL - workspace derived via tenant relationship - RBAC foundation shape: - `policy_id` = synthetic tenant-scoped policy anchor for `intuneRoleDefinition` and `intuneRoleAssignment` - `policy_version_id` = immutable snapshot row created or reused for the captured RBAC payload - `policy_type` = `intuneRoleDefinition` or `intuneRoleAssignment` - `policy_identifier` = source Graph object id - `payload` = full immutable RBAC payload - `metadata.displayName` - `metadata.kind` - `metadata.graph.resource` - additional metadata warnings or capture details ### Policy / PolicyVersion linkage for RBAC foundations RBAC foundations reuse the existing policy-version review surfaces by creating synthetic policy anchors. - Existing models/tables: `Policy`, `PolicyVersion` - RBAC anchor shape: - `Policy.external_id` = RBAC source Graph object id - `Policy.policy_type` = `intuneRoleDefinition` or `intuneRoleAssignment` - `Policy.metadata.foundation_anchor = true` - `Policy.metadata.capture_mode = immutable_backup` - RBAC version shape: - `PolicyVersion.snapshot` = immutable RBAC payload - `PolicyVersion.capture_purpose = backup` - identical protected snapshots are reused for the same synthetic policy instead of creating duplicate versions ### Normalized RBAC Snapshot View Model Human-readable representation produced for backup/version display and future diff-safe reuse. #### Role Definition normalized fields - `name` - `description` - `is_built_in` - `role_permissions` - normalized permission blocks - ordered for diff stability - optional warnings when payload is incomplete or partially expanded #### Role Assignment normalized fields - `assignment_name` - `role_definition` - preferred: readable name + stable id - `members` - readable names when known, ids as fallback - `scope_members` - readable names when known, ids as fallback - `resource_scopes` - stable ordered values - optional warnings when referenced objects are unresolved ### Verification Check Row Provider or tenant verification result describing RBAC permission readiness. - Existing source pattern: `TenantPermissionCheckClusters` - Relevant fields: - `key` - `title` - `status = pass | warn | fail` - `severity` - `blocking` - `reason_code` - `message` - `evidence[]` - `next_steps[]` - RBAC v1 target behavior: - Missing `DeviceManagementRBAC.Read.All` produces a clear warning or failure reason with actionable next steps. - The rest of the inventory pipeline remains able to complete partially. ## Relationships - A `Tenant` has many `InventoryItem` rows, including RBAC foundation rows. - A `Tenant` has many `BackupSet` rows. - A `BackupSet` has many `BackupItem` rows, including RBAC foundation payload snapshots. - A synthetic RBAC `Policy` has many immutable `PolicyVersion` rows and can be referenced by RBAC `BackupItem` rows. - An `OperationRun` for inventory sync carries coverage status for RBAC foundation types in `context.inventory.coverage.foundation_types`. - Verification rows and provider reason codes describe permission posture for the same tenant and workspace scope. ## Invariants - `intuneRoleDefinition` and `intuneRoleAssignment` are separate foundation types everywhere: config, contracts, inventory, backup, coverage, and normalization. - Inventory rows remain metadata-only and tenant-scoped. - Full RBAC payloads are stored only in immutable backup/version artifacts. - Restore mode for both RBAC foundation types is always `preview-only` in v1. - Non-members must not be able to infer RBAC object existence across workspace or tenant boundaries. - Missing `DeviceManagementRBAC.Read.All` must produce a stable reason path rather than an opaque exception. - Role Definitions and Role Assignments must normalize in a stable, ordered, diff-safe manner. ## State Transitions ### Inventory coverage state - `skipped` - when foundations are excluded from a run or a type is not attempted - `failed` - when the RBAC fetch for that type fails or returns a permission/problem reason - `succeeded` - when the RBAC type is fetched and inventory rows are updated successfully ### Backup capture state for RBAC foundations - not present in backup set - created as immutable `BackupItem` plus synthetic `Policy` / `PolicyVersion` linkage for version-detail review - restored from soft-delete if already present in the same backup set and previously archived ### Verification state for RBAC permission readiness - `pass` - all required RBAC read permissions are present - `warn` - delegated refresh or adjacent non-blocking permission posture issue exists - `fail` - required application permission is missing or permission fetch errored in a blocking way ## Validation Rules - Foundation type config rows must include deterministic `restore` and `risk` metadata. - RBAC Graph contracts must only request fields allowed by the contract registry. - Inventory updates require non-empty Graph `id` values. - Backup foundation snapshots require non-empty `source_id` values. - Normalizers must preserve identifiers when readable expansions are absent.