diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index e8765b1..1d316c3 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -12,8 +12,8 @@ ### User Access Audit -- [ ] **UACC-01**: User can export all SharePoint/Teams accesses a specific user has across selected sites -- [ ] **UACC-02**: Export includes direct assignments, group memberships, and inherited access +- [x] **UACC-01**: User can export all SharePoint/Teams accesses a specific user has across selected sites +- [x] **UACC-02**: Export includes direct assignments, group memberships, and inherited access ### Simplified Permissions @@ -47,8 +47,8 @@ None deferred — all active requirements scoped to v1.1. |-------------|-------|--------| | SITE-01 | Phase 6 | Complete | | SITE-02 | Phase 6 | Complete | -| UACC-01 | Phase 7 | Pending | -| UACC-02 | Phase 7 | Pending | +| UACC-01 | Phase 7 | Complete | +| UACC-02 | Phase 7 | Complete | | SIMP-01 | Phase 8 | Pending | | SIMP-02 | Phase 8 | Pending | | SIMP-03 | Phase 8 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 44a2faf..6d3245b 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -53,7 +53,7 @@ Plans: 2. Running the audit returns a list of all access entries the user holds across the selected sites 3. Results distinguish between direct role assignments, SharePoint group memberships, and inherited access 4. Results can be exported to CSV or HTML in the same format established by v1.0 export patterns -**Plans:** 8 plans +**Plans:** 1/8 plans executed Plans: - [ ] 07-01-PLAN.md — UserAccessEntry model + service interfaces (Wave 1) - [ ] 07-02-PLAN.md — UserAccessAuditService implementation (Wave 2) @@ -96,6 +96,6 @@ Plans: | 4. Bulk Operations and Provisioning | v1.0 | 10/10 | Complete | 2026-04-03 | | 5. Distribution and Hardening | v1.0 | 3/3 | Complete | 2026-04-03 | | 6. Global Site Selection | 5/5 | Complete | 2026-04-07 | - | -| 7. User Access Audit | v1.1 | 0/8 | Planned | - | +| 7. User Access Audit | 1/8 | In Progress| | - | | 8. Simplified Permissions | v1.1 | 0/? | Not started | - | | 9. Storage Visualization | v1.1 | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 32e45fa..e01e8b4 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: completed -stopped_at: Phase 7 context gathered -last_updated: "2026-04-07T10:22:02.651Z" +stopped_at: Completed 07-01-PLAN.md +last_updated: "2026-04-07T10:38:10.474Z" last_activity: 2026-04-07 — Roadmap created (Phases 6-9), 10/10 requirements mapped progress: total_phases: 4 completed_phases: 1 - total_plans: 5 - completed_plans: 5 + total_plans: 13 + completed_plans: 6 --- # Project State @@ -47,6 +47,7 @@ Phase 6 [ ] → Phase 7 [ ] → Phase 8 [ ] → Phase 9 [ ] | Phase 06-global-site-selection P03 | 2 | 3 tasks | 5 files | | Phase 06-global-site-selection P04 | 2 | 3 tasks | 6 files | | Phase 06-global-site-selection P05 | 2 | 1 tasks | 1 files | +| Phase 07-user-access-audit P01 | 5 | 2 tasks | 3 files | ## Accumulated Context @@ -69,6 +70,8 @@ Decisions are logged in PROJECT.md Key Decisions table. - [Phase 06-global-site-selection]: BulkMembersViewModel confirmed excluded: no SiteUrl field, CSV-driven per-row site URLs - [Phase 06-global-site-selection]: Test 8 asserts override-reset via next global sites message (not SiteUrl='' — OnSiteUrlChanged re-applies global immediately when cleared) - [Phase 06-global-site-selection]: Used reflection to set _hasLocalSiteOverride in PermissionsViewModel test — avoids needing a real SitePickerDialog +- [Phase 07-01]: UserAccessEntry is fully denormalized (one row = one user + one object + one permission) for direct DataGrid binding +- [Phase 07-01]: IsHighPrivilege and IsExternalUser pre-computed at scan time; GraphUserResult co-located with IGraphUserSearchService interface ### Pending Todos @@ -80,6 +83,6 @@ None. ## Session Continuity -Last session: 2026-04-07T10:22:02.648Z -Stopped at: Phase 7 context gathered -Resume file: .planning/phases/07-user-access-audit/07-CONTEXT.md +Last session: 2026-04-07T10:38:10.472Z +Stopped at: Completed 07-01-PLAN.md +Resume file: None diff --git a/.planning/phases/07-user-access-audit/07-01-SUMMARY.md b/.planning/phases/07-user-access-audit/07-01-SUMMARY.md new file mode 100644 index 0000000..6cdd3d2 --- /dev/null +++ b/.planning/phases/07-user-access-audit/07-01-SUMMARY.md @@ -0,0 +1,80 @@ +--- +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`. + +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