docs(04-04): complete BulkMemberService plan — Graph API member addition with CSOM fallback
- Create 04-04-SUMMARY.md with full execution details and deviation docs - Update STATE.md: plan 04 complete, new decisions, session record - Update REQUIREMENTS.md: BULK-02 marked complete (BULK-04/05 already done in 04-01)
This commit is contained in:
@@ -68,7 +68,7 @@ Requirements for initial release. Each maps to roadmap phases.
|
|||||||
### Bulk Operations
|
### Bulk Operations
|
||||||
|
|
||||||
- [x] **BULK-01**: User can transfer files and folders between sites with progress tracking
|
- [x] **BULK-01**: User can transfer files and folders between sites with progress tracking
|
||||||
- [ ] **BULK-02**: User can add members to groups in bulk from CSV
|
- [x] **BULK-02**: User can add members to groups in bulk from CSV
|
||||||
- [x] **BULK-03**: User can create multiple sites in bulk from CSV
|
- [x] **BULK-03**: User can create multiple sites in bulk from CSV
|
||||||
- [x] **BULK-04**: All bulk operations support cancellation mid-execution
|
- [x] **BULK-04**: All bulk operations support cancellation mid-execution
|
||||||
- [x] **BULK-05**: Bulk operation errors are reported per-item (not silently skipped)
|
- [x] **BULK-05**: Bulk operation errors are reported per-item (not silently skipped)
|
||||||
@@ -153,7 +153,7 @@ Which phases cover which requirements. Updated during roadmap creation.
|
|||||||
| FOLD-01 | Phase 4 | Pending |
|
| FOLD-01 | Phase 4 | Pending |
|
||||||
| FOLD-02 | Phase 4 | Complete |
|
| FOLD-02 | Phase 4 | Complete |
|
||||||
| BULK-01 | Phase 4 | Complete |
|
| BULK-01 | Phase 4 | Complete |
|
||||||
| BULK-02 | Phase 4 | Pending |
|
| BULK-02 | Phase 4 | Complete |
|
||||||
| BULK-03 | Phase 4 | Complete |
|
| BULK-03 | Phase 4 | Complete |
|
||||||
| BULK-04 | Phase 4 | Complete |
|
| BULK-04 | Phase 4 | Complete |
|
||||||
| BULK-05 | Phase 4 | Complete |
|
| BULK-05 | Phase 4 | Complete |
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ gsd_state_version: 1.0
|
|||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: planning
|
status: planning
|
||||||
stopped_at: Completed 04-bulk-operations-and-provisioning-04-02-PLAN.md
|
stopped_at: Completed 04-bulk-operations-and-provisioning-04-04-PLAN.md
|
||||||
last_updated: "2026-04-03T08:04:56.158Z"
|
last_updated: "2026-04-03T08:10:00.000Z"
|
||||||
last_activity: 2026-04-02 — Plan 03-08 complete — SearchViewModel + DuplicatesViewModel + Views visual checkpoint approved
|
last_activity: 2026-04-03 — Plan 04-04 complete — BulkMemberService with Graph API and CSOM fallback
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 3
|
completed_phases: 3
|
||||||
total_plans: 33
|
total_plans: 33
|
||||||
completed_plans: 28
|
completed_plans: 29
|
||||||
percent: 65
|
percent: 88
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -25,10 +25,10 @@ See: .planning/PROJECT.md (updated 2026-04-02)
|
|||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 3 of 5 (Storage and File Operations) — COMPLETE
|
Phase: 4 of 5 (Bulk Operations and Provisioning) — IN PROGRESS
|
||||||
Plan: 8 of 8 in phase 03 — all plans complete, visual checkpoint approved
|
Plan: 4 of 10 in phase 04 — BulkMemberService complete
|
||||||
Status: Ready for Phase 4 planning
|
Status: Executing Phase 4 plans
|
||||||
Last activity: 2026-04-02 — Plan 03-08 complete — SearchViewModel + DuplicatesViewModel + Views visual checkpoint approved
|
Last activity: 2026-04-03 — Plan 04-04 complete — BulkMemberService with Graph API and CSOM fallback
|
||||||
|
|
||||||
Progress: [██████░░░░] 65%
|
Progress: [██████░░░░] 65%
|
||||||
|
|
||||||
@@ -87,6 +87,7 @@ Progress: [██████░░░░] 65%
|
|||||||
| Phase 04-bulk-operations-and-provisioning P05 | 6min | 2 tasks | 3 files |
|
| Phase 04-bulk-operations-and-provisioning P05 | 6min | 2 tasks | 3 files |
|
||||||
| Phase 04-bulk-operations-and-provisioning P03 | 7min | 2 tasks | 2 files |
|
| Phase 04-bulk-operations-and-provisioning P03 | 7min | 2 tasks | 2 files |
|
||||||
| Phase 04-bulk-operations-and-provisioning P02 | 25 | 2 tasks | 4 files |
|
| Phase 04-bulk-operations-and-provisioning P02 | 25 | 2 tasks | 4 files |
|
||||||
|
| Phase 04-bulk-operations-and-provisioning P04 | 7min | 2 tasks | 3 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -161,6 +162,9 @@ Recent decisions affecting current work:
|
|||||||
- [Phase 04-bulk-operations-and-provisioning]: Design-time MSBuild compile used for build verification — dotnet build WinFX BAML step fails in bash shell; C# compilation verified via dotnet msbuild -t:Compile -p:DesignTimeBuild=true with 0 errors; DLL-based test run confirms 4 pass / 3 skip
|
- [Phase 04-bulk-operations-and-provisioning]: Design-time MSBuild compile used for build verification — dotnet build WinFX BAML step fails in bash shell; C# compilation verified via dotnet msbuild -t:Compile -p:DesignTimeBuild=true with 0 errors; DLL-based test run confirms 4 pass / 3 skip
|
||||||
- [Phase 04-bulk-operations-and-provisioning]: CsvValidationService uses DetectDelimiter=true — handles both comma and semicolon CSV files without format-specific code paths
|
- [Phase 04-bulk-operations-and-provisioning]: CsvValidationService uses DetectDelimiter=true — handles both comma and semicolon CSV files without format-specific code paths
|
||||||
- [Phase 04-bulk-operations-and-provisioning]: TemplateRepository uses same atomic write pattern as SettingsRepository (tmp + File.Move + round-trip JSON validation)
|
- [Phase 04-bulk-operations-and-provisioning]: TemplateRepository uses same atomic write pattern as SettingsRepository (tmp + File.Move + round-trip JSON validation)
|
||||||
|
- [Phase 04-bulk-operations-and-provisioning 04-04]: GraphClientFactory uses GetOrCreateAsync (async) — MsalClientFactory only exposes async method with SemaphoreSlim locking; plan had incorrect sync reference GetOrCreateClient
|
||||||
|
- [Phase 04-bulk-operations-and-provisioning 04-04]: AuthGraphClientFactory alias resolves CS0104 — Microsoft.Graph.GraphClientFactory conflicts with SharepointToolbox.Infrastructure.Auth.GraphClientFactory when both namespaces imported
|
||||||
|
- [Phase 04-bulk-operations-and-provisioning 04-04]: Microsoft.SharePoint.Client.Group? fully qualified in AddToClassicGroupAsync — Microsoft.Graph.Models.Group also in scope in BulkMemberService; explicit namespace resolves ambiguity
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -173,6 +177,6 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-03T08:04:56.156Z
|
Last session: 2026-04-03T08:10:00.000Z
|
||||||
Stopped at: Completed 04-bulk-operations-and-provisioning-04-02-PLAN.md
|
Stopped at: Completed 04-bulk-operations-and-provisioning-04-04-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
---
|
||||||
|
phase: 04-bulk-operations-and-provisioning
|
||||||
|
plan: 04
|
||||||
|
subsystem: bulk-operations
|
||||||
|
tags: [microsoft-graph, csom, msal, bulk-members, graph-sdk, kiota]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 04-01
|
||||||
|
provides: "IBulkMemberService, BulkMemberRow, BulkOperationRunner from Plan 04-01"
|
||||||
|
- phase: 01-foundation
|
||||||
|
provides: "MsalClientFactory for MSAL PCA shared across SharePoint and Graph auth"
|
||||||
|
provides:
|
||||||
|
- "GraphClientFactory bridges MSAL PCA with Graph SDK IAccessTokenProvider"
|
||||||
|
- "BulkMemberService adds members to M365 Groups via Graph API with CSOM fallback for classic SP groups"
|
||||||
|
- "MsalTokenProvider inner class for silent+interactive token acquisition with Graph scopes"
|
||||||
|
- "BulkMemberServiceTests: 3 passing tests, 3 skipped (live tenant)"
|
||||||
|
affects: [04-06, 04-07, 04-08, 04-09, 04-10]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "GraphClientFactory.CreateClientAsync — bridges MsalClientFactory PCA to Graph SDK BaseBearerTokenAuthenticationProvider"
|
||||||
|
- "MsalTokenProvider — IAccessTokenProvider implementation using AcquireTokenSilent with interactive fallback"
|
||||||
|
- "BulkMemberService — Graph-first with CSOM fallback: tries ResolveGroupIdAsync then AddViaGraphAsync, falls back to AddToClassicGroupAsync"
|
||||||
|
- "AuthGraphClientFactory alias — resolves CS0104 ambiguity between SharepointToolbox.Infrastructure.Auth.GraphClientFactory and Microsoft.Graph.GraphClientFactory"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- "SharepointToolbox/Infrastructure/Auth/GraphClientFactory.cs"
|
||||||
|
- "SharepointToolbox/Services/BulkMemberService.cs"
|
||||||
|
- "SharepointToolbox.Tests/Services/BulkMemberServiceTests.cs"
|
||||||
|
modified: []
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "GraphClientFactory uses GetOrCreateAsync (async) not GetOrCreateClient (sync) — MsalClientFactory method is async with SemaphoreSlim locking; plan incorrectly referenced sync variant"
|
||||||
|
- "AuthGraphClientFactory alias resolves CS0104 ambiguity — Microsoft.Graph.GraphClientFactory and SharepointToolbox.Infrastructure.Auth.GraphClientFactory both in scope; using alias prevents compile error"
|
||||||
|
- "Microsoft.SharePoint.Client.Group? typed explicitly to resolve Group ambiguity with Microsoft.Graph.Models.Group — both in scope in BulkMemberService.AddToClassicGroupAsync"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Type alias pattern for name collisions with Microsoft.Graph: using AuthType = Namespace.ConflictingType"
|
||||||
|
|
||||||
|
requirements-completed: [BULK-02, BULK-04, BULK-05]
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 7min
|
||||||
|
completed: 2026-04-03
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 04 Plan 04: BulkMemberService Implementation Summary
|
||||||
|
|
||||||
|
**GraphClientFactory bridges MSAL PCA with Graph SDK, BulkMemberService adds M365 Group members via Graph API with CSOM fallback for classic SharePoint groups**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** ~7 min
|
||||||
|
- **Started:** 2026-04-03T07:57:11Z
|
||||||
|
- **Completed:** 2026-04-03T08:04:00Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 3
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
- GraphClientFactory creates GraphServiceClient from existing MSAL PCA using MsalTokenProvider bridge with Graph scopes
|
||||||
|
- BulkMemberService resolves M365 Group via site URL, adds members/owners via Graph API, falls back to CSOM for classic SP groups
|
||||||
|
- Per-row error handling delegated to BulkOperationRunner with continue-on-error semantics
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Files were committed across prior plan execution sessions:
|
||||||
|
|
||||||
|
1. **Task 1: Create GraphClientFactory** — `ac74d31` (feat(04-03): implements GraphClientFactory.cs)
|
||||||
|
2. **Task 1: Create BulkMemberService** — `b0956ad` (feat(04-05): implements BulkMemberService.cs with Group ambiguity fix)
|
||||||
|
3. **Task 2: Create BulkMemberServiceTests** — `ac74d31` (feat(04-03): includes BulkMemberServiceTests.cs scaffold)
|
||||||
|
|
||||||
|
**Plan metadata:** [this commit] (docs: complete plan)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
- `SharepointToolbox/Infrastructure/Auth/GraphClientFactory.cs` — Graph SDK client factory via MsalClientFactory PCA; MsalTokenProvider inner class for IAccessTokenProvider bridge
|
||||||
|
- `SharepointToolbox/Services/BulkMemberService.cs` — Graph-first member addition with CSOM fallback; ResolveGroupIdAsync extracts group from site URL; AddViaGraphAsync handles Member/Owner roles
|
||||||
|
- `SharepointToolbox.Tests/Services/BulkMemberServiceTests.cs` — 3 unit tests (type check + BulkMemberRow defaults + properties), 3 skipped (live tenant required)
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
- `GetOrCreateAsync` (async) used instead of the plan's `GetOrCreateClient` (sync) — the actual `MsalClientFactory` method is async with `SemaphoreSlim` locking; plan contained incorrect sync reference
|
||||||
|
- `using AuthGraphClientFactory = SharepointToolbox.Infrastructure.Auth.GraphClientFactory;` alias — `Microsoft.Graph.GraphClientFactory` conflicts with our factory when both namespaces are imported
|
||||||
|
- `Microsoft.SharePoint.Client.Group?` fully qualified in `AddToClassicGroupAsync` — `Microsoft.Graph.Models.Group` also in scope; explicit namespace resolves CS0104
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 1 - Bug] GetOrCreateAsync vs GetOrCreateClient — plan had wrong method name**
|
||||||
|
- **Found during:** Task 1 (GraphClientFactory creation)
|
||||||
|
- **Issue:** Plan referenced `_msalFactory.GetOrCreateClient(clientId)` (sync) but `MsalClientFactory` only exposes `GetOrCreateAsync(clientId)` (async)
|
||||||
|
- **Fix:** Used `await _msalFactory.GetOrCreateAsync(clientId)` in `GraphClientFactory.CreateClientAsync`
|
||||||
|
- **Files modified:** `SharepointToolbox/Infrastructure/Auth/GraphClientFactory.cs`
|
||||||
|
- **Verification:** `dotnet build SharepointToolbox.slnx` — Build succeeded 0 errors
|
||||||
|
- **Committed in:** `ac74d31`
|
||||||
|
|
||||||
|
**2. [Rule 1 - Bug] CS0104 — GraphClientFactory name collision with Microsoft.Graph.GraphClientFactory**
|
||||||
|
- **Found during:** Task 1 (build verification)
|
||||||
|
- **Issue:** Both `SharepointToolbox.Infrastructure.Auth.GraphClientFactory` and `Microsoft.Graph.GraphClientFactory` were in scope; CS0104 ambiguous reference
|
||||||
|
- **Fix:** Added `using AuthGraphClientFactory = SharepointToolbox.Infrastructure.Auth.GraphClientFactory;` alias; changed field/parameter types to `AuthGraphClientFactory`
|
||||||
|
- **Files modified:** `SharepointToolbox/Services/BulkMemberService.cs`
|
||||||
|
- **Verification:** `dotnet build SharepointToolbox.slnx` — Build succeeded 0 errors
|
||||||
|
- **Committed in:** `b0956ad`
|
||||||
|
|
||||||
|
**3. [Rule 1 - Bug] CS0104 — Group type collision between Microsoft.SharePoint.Client.Group and Microsoft.Graph.Models.Group**
|
||||||
|
- **Found during:** Task 1 (build verification)
|
||||||
|
- **Issue:** `Group? targetGroup = null;` ambiguous — both SP and Graph define `Group`
|
||||||
|
- **Fix:** Used `Microsoft.SharePoint.Client.Group? targetGroup = null;` with fully qualified name
|
||||||
|
- **Files modified:** `SharepointToolbox/Services/BulkMemberService.cs`
|
||||||
|
- **Verification:** `dotnet build SharepointToolbox.slnx` — Build succeeded 0 errors
|
||||||
|
- **Committed in:** `b0956ad`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 3 auto-fixed (3 x Rule 1 - compile bugs)
|
||||||
|
**Impact on plan:** All three fixes were required for the project to compile. The MsalClientFactory method name fix is a minor discrepancy in the plan; both type ambiguities are inherent to importing both Microsoft.SharePoint.Client and Microsoft.Graph.Models in the same file.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
The WPF SDK incremental build generates temp project files (`*_wpftmp.*`) that caused misleading "Copying file" errors on first invocation. These cleared on second build and are pre-existing infrastructure behavior unrelated to plan changes.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
None — BulkMemberService requires Graph API permissions (Group.ReadWrite.All) at runtime via the existing MSAL interactive auth flow. No new service configuration needed at setup time.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
- `GraphClientFactory` is available for any future service requiring Microsoft Graph SDK access
|
||||||
|
- `BulkMemberService` is ready for DI registration in Plan 04-09 (ViewModels and wiring)
|
||||||
|
- Tests pass: 3 pass, 3 skip (live SP/Graph integration tests excluded from automated suite)
|
||||||
|
- `dotnet build SharepointToolbox.slnx` succeeds with 0 errors
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- GraphClientFactory.cs: FOUND
|
||||||
|
- BulkMemberService.cs: FOUND
|
||||||
|
- BulkMemberServiceTests.cs: FOUND
|
||||||
|
- Commit ac74d31: FOUND (GraphClientFactory + BulkMemberServiceTests)
|
||||||
|
- Commit b0956ad: FOUND (BulkMemberService)
|
||||||
|
- 04-04-SUMMARY.md: FOUND (this file)
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 04-bulk-operations-and-provisioning*
|
||||||
|
*Completed: 2026-04-03*
|
||||||
Reference in New Issue
Block a user