docs(15-01): complete consolidation data model plan
- Add 15-01-SUMMARY.md with task commits, decisions, and next phase readiness - Update STATE.md with decisions and session position - Update ROADMAP.md phase 15 progress (1/2 plans complete) - Mark requirement RPT-04 complete in REQUIREMENTS.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,7 @@ Requirements for v2.3 Tenant Management & Report Enhancements. Each maps to road
|
|||||||
- [ ] **RPT-01**: User can expand SharePoint groups in HTML reports to see group members
|
- [ ] **RPT-01**: User can expand SharePoint groups in HTML reports to see group members
|
||||||
- [ ] **RPT-02**: Group member resolution uses transitive membership to include nested group members
|
- [ ] **RPT-02**: Group member resolution uses transitive membership to include nested group members
|
||||||
- [ ] **RPT-03**: User can enable/disable entry consolidation per export (toggle in export settings)
|
- [ ] **RPT-03**: User can enable/disable entry consolidation per export (toggle in export settings)
|
||||||
- [ ] **RPT-04**: Consolidated reports merge rows for the same user with identical access levels across multiple locations into a single row
|
- [x] **RPT-04**: Consolidated reports merge rows for the same user with identical access levels across multiple locations into a single row
|
||||||
|
|
||||||
## Future Requirements
|
## Future Requirements
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ Requirements for v2.3 Tenant Management & Report Enhancements. Each maps to road
|
|||||||
| RPT-01 | Phase 17 | Pending |
|
| RPT-01 | Phase 17 | Pending |
|
||||||
| RPT-02 | Phase 17 | Pending |
|
| RPT-02 | Phase 17 | Pending |
|
||||||
| RPT-03 | Phase 16 | Pending |
|
| RPT-03 | Phase 16 | Pending |
|
||||||
| RPT-04 | Phase 15 | Pending |
|
| RPT-04 | Phase 15 | Complete |
|
||||||
|
|
||||||
**Coverage:**
|
**Coverage:**
|
||||||
- v2.3 requirements: 12 total
|
- v2.3 requirements: 12 total
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
### v2.3 Tenant Management & Report Enhancements (Phases 15-19)
|
### v2.3 Tenant Management & Report Enhancements (Phases 15-19)
|
||||||
|
|
||||||
- [ ] **Phase 15: Consolidation Data Model** — PermissionConsolidator service and merged-row model; zero API calls, pure data shapes
|
- [ ] **Phase 15: Consolidation Data Model** (2 plans) — PermissionConsolidator service and merged-row model; zero API calls, pure data shapes
|
||||||
- [ ] **Phase 16: Report Consolidation Toggle** — Export settings toggle wired to PermissionConsolidator; first user-visible consolidation behavior
|
- [ ] **Phase 16: Report Consolidation Toggle** — Export settings toggle wired to PermissionConsolidator; first user-visible consolidation behavior
|
||||||
- [ ] **Phase 17: Group Expansion in HTML Reports** — Clickable group expansion in HTML exports with transitive membership resolution
|
- [ ] **Phase 17: Group Expansion in HTML Reports** — Clickable group expansion in HTML exports with transitive membership resolution
|
||||||
- [ ] **Phase 18: Auto-Take Ownership** — Global toggle and automatic site collection admin elevation on access denied
|
- [ ] **Phase 18: Auto-Take Ownership** — Global toggle and automatic site collection admin elevation on access denied
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
2. A `PermissionConsolidator` service accepts a flat list of permission rows and returns a consolidated list where duplicate user+level rows are merged
|
2. A `PermissionConsolidator` service accepts a flat list of permission rows and returns a consolidated list where duplicate user+level rows are merged
|
||||||
3. Consolidation logic has unit test coverage — a known 10-row input with 3 duplicate pairs produces the expected 7-row output
|
3. Consolidation logic has unit test coverage — a known 10-row input with 3 duplicate pairs produces the expected 7-row output
|
||||||
4. Existing HTML export services compile and produce identical output when consolidation is not applied (opt-in, defaults off)
|
4. Existing HTML export services compile and produce identical output when consolidation is not applied (opt-in, defaults off)
|
||||||
**Plans:** 2 plans
|
**Plans:** 1/2 plans executed
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 15-01-PLAN.md — Models (LocationInfo, ConsolidatedPermissionEntry) + PermissionConsolidator service
|
- [ ] 15-01-PLAN.md — Models (LocationInfo, ConsolidatedPermissionEntry) + PermissionConsolidator service
|
||||||
- [ ] 15-02-PLAN.md — Unit tests (10 test cases) + full solution build verification
|
- [ ] 15-02-PLAN.md — Unit tests (10 test cases) + full solution build verification
|
||||||
@@ -108,7 +108,7 @@ Plans:
|
|||||||
3. Registration creates the Azure AD application, service principal, and grants all required API permissions in a single atomic operation — if any step fails, all partial changes are rolled back and the user sees a specific error explaining what failed and why
|
3. Registration creates the Azure AD application, service principal, and grants all required API permissions in a single atomic operation — if any step fails, all partial changes are rolled back and the user sees a specific error explaining what failed and why
|
||||||
4. A "Remove App" action in the profile dialog removes the Azure AD application registration from the target tenant
|
4. A "Remove App" action in the profile dialog removes the Azure AD application registration from the target tenant
|
||||||
5. After removal, all cached MSAL tokens and session state for that tenant are cleared, and subsequent operations require re-authentication
|
5. After removal, all cached MSAL tokens and session state for that tenant are cleared, and subsequent operations require re-authentication
|
||||||
**Plans**: TBD
|
**Plans**: 15-01 (Models + Consolidator), 15-02 (Tests + Build Verification)
|
||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ Plans:
|
|||||||
| 1-5 | v1.0 | 36/36 | Shipped | 2026-04-07 |
|
| 1-5 | v1.0 | 36/36 | Shipped | 2026-04-07 |
|
||||||
| 6-9 | v1.1 | 25/25 | Shipped | 2026-04-08 |
|
| 6-9 | v1.1 | 25/25 | Shipped | 2026-04-08 |
|
||||||
| 10-14 | v2.2 | 14/14 | Shipped | 2026-04-09 |
|
| 10-14 | v2.2 | 14/14 | Shipped | 2026-04-09 |
|
||||||
| 15. Consolidation Data Model | v2.3 | 0/2 | Planning | — |
|
| 15. Consolidation Data Model | 1/2 | In Progress| | — |
|
||||||
| 16. Report Consolidation Toggle | v2.3 | 0/? | Not started | — |
|
| 16. Report Consolidation Toggle | v2.3 | 0/? | Not started | — |
|
||||||
| 17. Group Expansion in HTML Reports | v2.3 | 0/? | Not started | — |
|
| 17. Group Expansion in HTML Reports | v2.3 | 0/? | Not started | — |
|
||||||
| 18. Auto-Take Ownership | v2.3 | 0/? | Not started | — |
|
| 18. Auto-Take Ownership | v2.3 | 0/? | Not started | — |
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v2.3
|
milestone: v2.3
|
||||||
milestone_name: Tenant Management & Report Enhancements
|
milestone_name: Tenant Management & Report Enhancements
|
||||||
status: roadmap-ready
|
status: planning
|
||||||
stopped_at: roadmap created — ready for phase 15 planning
|
stopped_at: Completed 15-01-PLAN.md
|
||||||
last_updated: "2026-04-09"
|
last_updated: "2026-04-09T09:42:37.151Z"
|
||||||
last_activity: 2026-04-09 — Roadmap created for v2.3 (phases 15-19)
|
last_activity: 2026-04-09 — Roadmap created for v2.3 (phases 15-19)
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 0
|
completed_phases: 0
|
||||||
total_plans: 0
|
total_plans: 2
|
||||||
completed_plans: 0
|
completed_plans: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -61,6 +61,8 @@ Decisions are logged in PROJECT.md Key Decisions table.
|
|||||||
- Group expansion (Phase 17) calls Graph at export time, not at scan time — scan pipeline unchanged
|
- Group expansion (Phase 17) calls Graph at export time, not at scan time — scan pipeline unchanged
|
||||||
- Auto-take ownership uses PnP `Tenant.SetSiteAdmin` — requires Tenant Admin scope
|
- Auto-take ownership uses PnP `Tenant.SetSiteAdmin` — requires Tenant Admin scope
|
||||||
- App registration must be atomic with rollback; partial Entra state is worse than no state
|
- App registration must be atomic with rollback; partial Entra state is worse than no state
|
||||||
|
- [Phase 15]: MakeKey declared internal for test access via InternalsVisibleTo without exposing as public API
|
||||||
|
- [Phase 15]: LINQ GroupBy+Select for consolidation merge instead of mutable dictionary — consistent with functional codebase style
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -72,7 +74,7 @@ None.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-09
|
Last session: 2026-04-09T09:42:37.149Z
|
||||||
Stopped at: Roadmap created — ready to plan Phase 15
|
Stopped at: Completed 15-01-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
Next step: `/gsd:plan-phase 15`
|
Next step: `/gsd:plan-phase 15`
|
||||||
|
|||||||
103
.planning/phases/15-consolidation-data-model/15-01-SUMMARY.md
Normal file
103
.planning/phases/15-consolidation-data-model/15-01-SUMMARY.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
---
|
||||||
|
phase: 15-consolidation-data-model
|
||||||
|
plan: "01"
|
||||||
|
subsystem: api
|
||||||
|
tags: [csharp, records, linq, permission-consolidation]
|
||||||
|
|
||||||
|
requires: []
|
||||||
|
provides:
|
||||||
|
- LocationInfo record with five location fields (SiteUrl, SiteTitle, ObjectTitle, ObjectUrl, ObjectType)
|
||||||
|
- ConsolidatedPermissionEntry record grouping key fields with IReadOnlyList<LocationInfo> Locations
|
||||||
|
- PermissionConsolidator.Consolidate — pure static method merging UserAccessEntry list by composite key
|
||||||
|
- PermissionConsolidator.MakeKey — pipe-delimited case-insensitive key from UserLogin+PermissionLevel+AccessType+GrantedThrough
|
||||||
|
affects: [16-report-consolidation-toggle]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Positional C# records for immutable data shapes"
|
||||||
|
- "LINQ GroupBy+Select for pure-function merge without mutable state"
|
||||||
|
- "Internal MakeKey for composite key generation (pipe-delimited, ToLowerInvariant)"
|
||||||
|
- "Array.Empty<T>() short-circuit on empty input"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- SharepointToolbox/Core/Models/LocationInfo.cs
|
||||||
|
- SharepointToolbox/Core/Models/ConsolidatedPermissionEntry.cs
|
||||||
|
- SharepointToolbox/Core/Helpers/PermissionConsolidator.cs
|
||||||
|
modified: []
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "MakeKey is internal (not private) to allow test access via InternalsVisibleTo without exposing as public API"
|
||||||
|
- "LINQ GroupBy+Select chosen over mutable Dictionary to match existing codebase functional style"
|
||||||
|
- "OrderBy UserLogin then PermissionLevel ensures deterministic output order for consistent exports"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Consolidation key: pipe-delimited lowercase composite of UserLogin|PermissionLevel|AccessType|GrantedThrough"
|
||||||
|
- "LocationInfo is the extraction unit — one per original UserAccessEntry row in a consolidated group"
|
||||||
|
|
||||||
|
requirements-completed: [RPT-04]
|
||||||
|
|
||||||
|
duration: 1min
|
||||||
|
completed: "2026-04-09"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 15 Plan 01: Consolidation Data Model Summary
|
||||||
|
|
||||||
|
**LocationInfo + ConsolidatedPermissionEntry records and PermissionConsolidator.Consolidate pure-function merge service using LINQ GroupBy over pipe-delimited composite key**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** ~1 min
|
||||||
|
- **Started:** 2026-04-09T09:40:40Z
|
||||||
|
- **Completed:** 2026-04-09T09:41:37Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 3
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- LocationInfo positional record extracts five location fields from UserAccessEntry during consolidation
|
||||||
|
- ConsolidatedPermissionEntry record holds key fields plus computed LocationCount convenience property
|
||||||
|
- PermissionConsolidator.Consolidate groups a flat UserAccessEntry list by (UserLogin, PermissionLevel, AccessType, GrantedThrough) composite key, returning deterministically ordered consolidated rows
|
||||||
|
- Empty input short-circuits cleanly to Array.Empty without allocating
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically:
|
||||||
|
|
||||||
|
1. **Task 1: Create LocationInfo and ConsolidatedPermissionEntry model records** - `270329b` (feat)
|
||||||
|
2. **Task 2: Create PermissionConsolidator static helper** - `440b247` (feat)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `SharepointToolbox/Core/Models/LocationInfo.cs` - Lightweight record holding five location fields extracted from UserAccessEntry when rows are merged
|
||||||
|
- `SharepointToolbox/Core/Models/ConsolidatedPermissionEntry.cs` - Consolidated permission record with key fields, Locations list, and computed LocationCount property
|
||||||
|
- `SharepointToolbox/Core/Helpers/PermissionConsolidator.cs` - Static helper with MakeKey (internal) and Consolidate (public) for pure-function merge logic
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- `MakeKey` declared `internal` (not `private`) so test projects can access it via `[InternalsVisibleTo]` without exposing as public API surface
|
||||||
|
- LINQ GroupBy+Select pattern used instead of mutable dictionary — consistent with functional style seen elsewhere in the codebase
|
||||||
|
- Output ordered by UserLogin then PermissionLevel for deterministic, predictable export row ordering
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan executed exactly as written.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None - no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- Phase 16 (Report Consolidation Toggle) can now wire PermissionConsolidator.Consolidate into the export pipeline
|
||||||
|
- All three files exist, compile without errors, and no existing files were modified
|
||||||
|
- MakeKey is accessible to Phase 16 test projects via InternalsVisibleTo if needed
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 15-consolidation-data-model*
|
||||||
|
*Completed: 2026-04-09*
|
||||||
Reference in New Issue
Block a user