docs(07-04): complete UserAccessAuditViewModel plan

- Add 07-04-SUMMARY.md with task commits and decisions
- Update STATE.md: progress 77%, session record, decisions
- Update ROADMAP.md: phase 7 plan count updated to 5/8 summaries
This commit is contained in:
Dev
2026-04-07 12:45:14 +02:00
parent 3de737ac3f
commit 72349d8415
3 changed files with 113 additions and 7 deletions

View File

@@ -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:** 4/8 plans executed
**Plans:** 5/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 | 4/8 | In Progress| | - |
| 7. User Access Audit | 5/8 | In Progress| | - |
| 8. Simplified Permissions | v1.1 | 0/? | Not started | - |
| 9. Storage Visualization | v1.1 | 0/? | Not started | - |

View File

@@ -3,14 +3,14 @@ gsd_state_version: 1.0
milestone: v1.0
milestone_name: milestone
status: completed
stopped_at: Completed 07-06-PLAN.md
last_updated: "2026-04-07T10:41:47.594Z"
stopped_at: Completed 07-04-PLAN.md
last_updated: "2026-04-07T10:45:02.830Z"
last_activity: 2026-04-07 — Roadmap created (Phases 6-9), 10/10 requirements mapped
progress:
total_phases: 4
completed_phases: 1
total_plans: 13
completed_plans: 9
completed_plans: 10
---
# Project State
@@ -51,6 +51,7 @@ Phase 6 [ ] → Phase 7 [ ] → Phase 8 [ ] → Phase 9 [ ]
| Phase 07-user-access-audit P03 | 2 | 1 tasks | 1 files |
| Phase 07-user-access-audit P02 | 1 | 1 tasks | 1 files |
| Phase 07-user-access-audit P06 | 2 | 2 tasks | 2 files |
| Phase 07-user-access-audit P04 | 2 | 1 tasks | 1 files |
## Accumulated Context
@@ -82,6 +83,8 @@ Decisions are logged in PROJECT.md Key Decisions table.
- [Phase 07-user-access-audit]: Bidirectional contains matching for user login — handles both plain email and full SharePoint claim formats
- [Phase 07-user-access-audit]: UserAccessCsvExportService has two write modes: WriteAsync (per-user files to directory) and WriteSingleFileAsync (combined for SaveFileDialog)
- [Phase 07-user-access-audit]: HTML sortTable() scoped per group so sorting in by-user view keeps each user's rows together
- [Phase 07-04]: CollectionViewSource bound at construction; ApplyGrouping() swaps PropertyGroupDescription between UserLogin/SiteUrl on IsGroupByUser toggle
- [Phase 07-04]: ExportCsvAsync uses WriteSingleFileAsync (combined file) not WriteAsync (per-user directory) to match SaveFileDialog single-path UX
### Pending Todos
@@ -93,6 +96,6 @@ None.
## Session Continuity
Last session: 2026-04-07T10:41:47.591Z
Stopped at: Completed 07-06-PLAN.md
Last session: 2026-04-07T10:45:02.828Z
Stopped at: Completed 07-04-PLAN.md
Resume file: None

View File

@@ -0,0 +1,103 @@
---
phase: 07-user-access-audit
plan: 04
subsystem: viewmodel
tags: [viewmodel, wpf, people-picker, debounce, collectionview, grouping, filtering, export, mvvm]
requires:
- phase: 07-01
provides: [UserAccessEntry, AccessType, IUserAccessAuditService, IGraphUserSearchService, GraphUserResult]
- phase: 07-02
provides: [UserAccessAuditService]
- phase: 07-03
provides: [GraphUserSearchService]
- phase: 07-06
provides: [UserAccessCsvExportService, UserAccessHtmlExportService]
provides:
- UserAccessAuditViewModel with full orchestration of people picker, site selection, audit execution, grouping, filtering, summary banner, export
affects: [07-05, 07-07, 07-08]
tech-stack:
added: []
patterns: [CollectionViewSource grouping toggle, debounced CancellationTokenSource search, FeatureViewModelBase extension, dual-constructor pattern, _hasLocalSiteOverride site override]
key-files:
created:
- SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs
modified: []
key-decisions:
- "CollectionViewSource is created over Results in constructor; ApplyGrouping() clears and re-adds PropertyGroupDescription on IsGroupByUser toggle (UserLogin or SiteUrl)"
- "Debounced search uses _searchCts CancellationTokenSource cancelled on each SearchQuery change; Task.Delay(300, ct) pattern with OperationCanceledException swallowed"
- "OnResultsChanged partial rebuilds grouping/filter when Results collection reference is replaced after RunOperationAsync"
- "ExportCsvAsync calls WriteSingleFileAsync (combined single-file export) rather than WriteAsync (per-user directory) to match SaveFileDialog single-path UX"
patterns-established:
- "UserAccessAuditViewModel: same _hasLocalSiteOverride + OnGlobalSitesChanged guard as PermissionsViewModel"
- "Dual constructor: full DI constructor + internal test constructor omitting export services — both initialize all commands and wire collection events"
- "Summary properties (TotalAccessCount, SitesCount, HighPrivilegeCount) are computed getters calling Results LINQ — NotifySummaryProperties() triggers all three"
requirements-completed: [UACC-01, UACC-02]
duration: 2min
completed: 2026-04-07
---
# Phase 7 Plan 04: UserAccessAuditViewModel Summary
**UserAccessAuditViewModel wires people-picker (300ms debounced Graph search), multi-site selection with override guard, IUserAccessAuditService.AuditUsersAsync execution, CollectionViewSource group-by-user/site toggle with real-time filter, computed summary banner (TotalAccessCount, SitesCount, HighPrivilegeCount), and CSV/HTML export commands — zero-error build.**
## Performance
- **Duration:** ~2 min
- **Started:** 2026-04-07T10:42:51Z
- **Completed:** 2026-04-07T10:44:56Z
- **Tasks:** 1
- **Files modified:** 1
## Accomplishments
- UserAccessAuditViewModel.cs (~300 lines) extends FeatureViewModelBase and implements all 10 observable properties, 5 commands, CollectionViewSource grouping/filtering, and dual constructors
- Debounced people-picker: _searchCts cancelled/recreated on SearchQuery change, 300ms Task.Delay, IsSearching spinner, 2-char minimum guard consistent with GraphUserSearchService
- CollectionViewSource grouping: ApplyGrouping() swaps PropertyGroupDescription between UserLogin and SiteUrl; FilterPredicate applies to 6 fields case-insensitively
- Summary banner computed properties (TotalAccessCount, SitesCount, HighPrivilegeCount) notified via NotifySummaryProperties() after each RunOperationAsync and tenant switch
## Task Commits
1. **Task 1: Implement UserAccessAuditViewModel** - `3de737a` (feat)
**Plan metadata:** (docs commit pending)
## Files Created/Modified
- `SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs` — Full orchestration ViewModel for User Access Audit tab
## Decisions Made
1. **CollectionViewSource bound at construction** — ResultsView is created from a `new CollectionViewSource { Source = Results }` in the constructor. When Results is replaced by a new collection in RunOperationAsync, OnResultsChanged re-applies grouping and filter. This avoids ICollectionView rebinding complexity in XAML.
2. **WriteSingleFileAsync for CSV export** — UserAccessCsvExportService has two modes: WriteAsync (per-user files to directory) and WriteSingleFileAsync (combined). The ViewModel uses WriteSingleFileAsync since the SaveFileDialog returns a single file path — the per-directory mode is for batch export scenarios.
3. **SelectedUsers UPNs as login keys** — AuditUsersAsync receives `SelectedUsers.Select(u => u.UserPrincipalName)` as the targetUserLogins parameter, matching the UPN-based bidirectional matching in UserAccessAuditService.
## Deviations from Plan
None — plan executed exactly as written.
## Issues Encountered
None.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- UserAccessAuditViewModel ready for XAML binding in 07-05 (View)
- All observable properties, commands, and ResultsView ICollectionView available for DataGrid/ComboBox/AutoComplete binding
- Export commands wired to UserAccessCsvExportService.WriteSingleFileAsync and UserAccessHtmlExportService.WriteAsync
---
*Phase: 07-user-access-audit*
*Completed: 2026-04-07*