Files
Sharepoint-Toolbox/.planning/STATE.md
Dev 3c70884022 docs(08-01): complete Permission Data Models and Mapping Layer plan
- SUMMARY.md with self-check passed
- STATE.md updated to Phase 8, Plan 1 complete
- ROADMAP.md progress updated for Phase 8
- SIMP-01 and SIMP-02 requirements marked complete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:08:03 +02:00

115 lines
7.5 KiB
Markdown

---
gsd_state_version: 1.0
milestone: v1.0
milestone_name: milestone
status: in-progress
stopped_at: Completed 08-01-PLAN.md
last_updated: "2026-04-07T12:07:33.162Z"
last_activity: 2026-04-07 — Roadmap created (Phases 6-9), 10/10 requirements mapped
progress:
total_phases: 4
completed_phases: 2
total_plans: 21
completed_plans: 16
---
# Project State
## Project Reference
See: .planning/PROJECT.md (updated 2026-04-07)
**Core value:** Administrators can audit and manage SharePoint/Teams permissions and storage across multiple client tenants from a single, reliable desktop application.
**Current focus:** v1.1 Enhanced Reports — global site selection, user access audit, simplified permissions, storage visualization
## Current Position
Phase: 8 — Simplified Permissions
Plan: 1 of 6
Status: Plan 08-01 complete, advancing to 08-02
Last activity: 2026-04-07 — Completed 08-01 (Permission Data Models and Mapping Layer)
```
v1.1 Progress: [ ] 0%
Phase 6 [ ] → Phase 7 [ ] → Phase 8 [ ] → Phase 9 [ ]
```
## Performance Metrics
| Metric | v1.0 | v1.1 (running) |
|--------|------|----------------|
| Phases | 5 | 4 planned |
| Plans | 36 | TBD |
| Commits | 164 | 0 |
| Tests | 134 pass / 22 skip | — |
| Phase 06-global-site-selection P02 | 8 | 1 tasks | 1 files |
| Phase 06-global-site-selection P01 | 2 | 2 tasks | 3 files |
| 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 |
| 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 |
| Phase 07-user-access-audit P05 | 4 | 2 tasks | 2 files |
| Phase 07-user-access-audit P07 | 8 | 3 tasks | 7 files |
| Phase 07-user-access-audit P08 | 2 | 2 tasks | 4 files |
| Phase 07-user-access-audit P09 | 6 | 1 tasks | 1 files |
| Phase 07-user-access-audit P10 | 5 | 1 tasks | 1 files |
## Accumulated Context
### Decisions
Decisions are logged in PROJECT.md Key Decisions table.
**v1.1 architectural notes:**
- Global site selection (Phase 6) changes the toolbar; all tabs must bind to a shared `GlobalSiteSelectionViewModel` or equivalent. Use `WeakReferenceMessenger` for cross-tab site-changed notifications, consistent with v1.0 messenger usage.
- Per-tab override (SITE-02) means each `FeatureViewModelBase` subclass stores a nullable local site override; null means "use global".
- Storage Visualization (Phase 9) requires a WPF charting NuGet (LiveCharts2 recommended — actively maintained, WPF-native, self-contained friendly). Wire chart data binding to the existing storage scan result model.
- Self-contained EXE constraint: charting library must not require runtime DLLs outside the publish output.
- [Phase 06-02]: MainWindowViewModel uses Func<Window>? factory for SitePickerDialog and broadcasts GlobalSitesChangedMessage via WeakReferenceMessenger on collection change
- [Phase 06-01]: GlobalSitesChangedMessage uses IReadOnlyList<SiteInfo> (snapshot, not ObservableCollection) so receivers cannot mutate sender state
- [Phase 06-01]: FeatureViewModelBase.OnGlobalSitesReceived (private) updates GlobalSites then calls OnGlobalSitesChanged (protected virtual) — separates storage from derived class hooks
- [Phase 06-03]: Added using SharepointToolbox.Core.Models to MainWindow.xaml.cs for TenantProfile in SitePickerDialog factory lambda
- [Phase 06-03]: toolbar.selectSites.tooltipDisabled added to resources but not wired in XAML — WPF Button disabled tooltip requires style trigger (deferred)
- [Phase 06-global-site-selection]: PermissionsViewModel uses _hasLocalSiteOverride guard for SelectedSites; site picker sets flag, tenant switch resets it
- [Phase 06-global-site-selection]: Single-site VMs use partial void OnSiteUrlChanged to detect local typing; clearing field reverts to global
- [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
- [Phase 07-03]: Minimum 2-character query guard prevents overly broad Graph API requests
- [Phase 07-03]: OData single-quote escaping (replace apostrophe with two apostrophes) prevents injection in startsWith filter
- [Phase 07-03]: ConsistencyLevel=eventual and Count=true both required for startsWith on Graph directory objects
- [Phase 07-user-access-audit]: TenantProfile.ClientId empty in service — session pre-authenticated at ViewModel level; SessionManager returns cached context by URL key
- [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
- [Phase 07-05]: Autocomplete ListBox visibility managed via code-behind CollectionChanged — WPF DataTrigger cannot compare to non-zero Count without converter
- [Phase 07-05]: Simple ListBox autocomplete (not Popup) following plan's recommended simpler alternative — avoids Popup placement issues
- [Phase 07-user-access-audit]: Dialog factory wiring in MainWindow.xaml.cs by casting auditView.DataContext to UserAccessAuditViewModel — matches PermissionsView pattern
- [Phase 07-user-access-audit]: UserAccessAuditView created inline (Rule 3) when 07-05 found missing — follows 07-05 spec with two-panel layout
- [Phase 07-user-access-audit]: Used internal TestRunOperationAsync for ViewModel tests; Application.Current null in tests lets else branch run synchronously
- [Phase 07-user-access-audit]: WeakReferenceMessenger.Default.Reset() in test constructor prevents cross-test contamination from message registrations
- [Phase 07-09]: Guest badge (orange pill) and warning icon (⚠) use DataTrigger-driven Visibility on DataGridTemplateColumn cells — collapsed by default, visible only when IsExternalUser/IsHighPrivilege=True
- [Phase 07-10]: Extended CreateViewModel to 3-tuple (vm, auditMock, graphMock) so debounce test can verify SearchUsersAsync calls
### Pending Todos
1. Add global multi-site selection option (ui) — `todos/pending/2026-04-07-add-global-multi-site-selection-option.md`**addressed by Phase 6**
### Blockers/Concerns
None.
## Session Continuity
Last session: 2026-04-07T12:06:57Z
Stopped at: Completed 08-01-PLAN.md
Resume file: None