---
phase: 07-user-access-audit
plan: 01
subsystem: core-models-interfaces
tags: [models, interfaces, contracts, user-access-audit]
dependency_graph:
  requires: []
  provides: [UserAccessEntry, AccessType, IUserAccessAuditService, IGraphUserSearchService, GraphUserResult]
  affects: [07-02, 07-03, 07-04, 07-05, 07-06, 07-07, 07-08]
tech_stack:
  added: []
  patterns: [record types, interface contracts, C# nullable annotations]
key_files:
  created:
    - SharepointToolbox/Core/Models/UserAccessEntry.cs
    - SharepointToolbox/Services/IUserAccessAuditService.cs
    - SharepointToolbox/Services/IGraphUserSearchService.cs
  modified: []
decisions:
  - "UserAccessEntry is fully denormalized (one row = one user + one object + one permission) for direct DataGrid binding without post-processing"
  - "IsHighPrivilege and IsExternalUser are pre-computed at scan time so the grid can show icons without re-evaluating strings"
  - "GraphUserResult is defined in IGraphUserSearchService.cs (same file as interface) since it is only used by that interface"
metrics:
  duration_minutes: 5
  completed_date: "2026-04-07"
  tasks_completed: 2
  files_created: 3
  files_modified: 0
---

# Phase 7 Plan 01: Data Models and Service Interfaces Summary

**One-liner:** Contract layer with UserAccessEntry record (12-field denormalized model), AccessType enum, IUserAccessAuditService, IGraphUserSearchService, and GraphUserResult — zero-error foundation for all downstream Phase 7 plans.

## What Was Built

Three files establishing the Wave 1 contract layer for the User Access Audit feature:

1. **UserAccessEntry.cs** — C# record with 12 positional properties representing one row in the audit results grid. Includes AccessType enum (Direct/Group/Inherited), pre-computed IsHighPrivilege and IsExternalUser flags, and SiteUrl/SiteTitle for multi-site grouping.

2. **IUserAccessAuditService.cs** — Service interface with single method `AuditUsersAsync` that accepts a session manager, list of target user login names, list of sites, scan options, progress reporter, and cancellation token. Returns `IReadOnlyList<UserAccessEntry>`.

3. **IGraphUserSearchService.cs** — Service interface with `SearchUsersAsync` for Graph API people-picker autocomplete, plus the `GraphUserResult` record (DisplayName, UserPrincipalName, nullable Mail).

## Tasks

| # | Task | Status | Commit |
|---|------|--------|--------|
| 1 | Create UserAccessEntry model and AccessType enum | Done | e08df0f |
| 2 | Create IUserAccessAuditService and IGraphUserSearchService interfaces | Done | 1a6989a |

## Decisions Made

1. **Denormalized record design** — Each UserAccessEntry row represents one user + one object + one permission level. This avoids nested object graphs and allows direct DataGrid binding and CSV export without flattening logic.

2. **Pre-computed flags** — IsHighPrivilege (Full Control, Site Collection Administrator) and IsExternalUser (#EXT# in login) are computed during the scan pass, not at display time. This keeps the ViewModel simple and the grid row data self-contained.

3. **GraphUserResult co-located with interface** — Defined in the same file as IGraphUserSearchService since it is exclusively used as the return type of that interface. No separate file needed.

## Deviations from Plan

None — plan executed exactly as written.

## Verification

- `dotnet build SharepointToolbox/SharepointToolbox.csproj` — 0 errors, 0 warnings
- UserAccessEntry.cs: record with 12 fields + AccessType enum confirmed
- IUserAccessAuditService.cs: AuditUsersAsync with correct 6-parameter signature confirmed
- IGraphUserSearchService.cs: SearchUsersAsync with 4 parameters + GraphUserResult record confirmed

## Self-Check: PASSED

Files confirmed present:
- FOUND: SharepointToolbox/Core/Models/UserAccessEntry.cs
- FOUND: SharepointToolbox/Services/IUserAccessAuditService.cs
- FOUND: SharepointToolbox/Services/IGraphUserSearchService.cs

Commits confirmed:
- FOUND: e08df0f
- FOUND: 1a6989a
