From 773393c4c050b7c57fb297c69b0f9ff284d08bef Mon Sep 17 00:00:00 2001 From: Dev Date: Fri, 3 Apr 2026 10:06:37 +0200 Subject: [PATCH] =?UTF-8?q?docs(04-04):=20complete=20BulkMemberService=20p?= =?UTF-8?q?lan=20=E2=80=94=20Graph=20API=20member=20addition=20with=20CSOM?= =?UTF-8?q?=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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) --- .planning/REQUIREMENTS.md | 4 +- .planning/STATE.md | 26 ++-- .../04-04-SUMMARY.md | 144 ++++++++++++++++++ 3 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 .planning/phases/04-bulk-operations-and-provisioning/04-04-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index ded04b5..b3b8ddd 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -68,7 +68,7 @@ Requirements for initial release. Each maps to roadmap phases. ### Bulk Operations - [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-04**: All bulk operations support cancellation mid-execution - [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-02 | Phase 4 | Complete | | BULK-01 | Phase 4 | Complete | -| BULK-02 | Phase 4 | Pending | +| BULK-02 | Phase 4 | Complete | | BULK-03 | Phase 4 | Complete | | BULK-04 | Phase 4 | Complete | | BULK-05 | Phase 4 | Complete | diff --git a/.planning/STATE.md b/.planning/STATE.md index 1766062..e307542 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,15 +3,15 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: planning -stopped_at: Completed 04-bulk-operations-and-provisioning-04-02-PLAN.md -last_updated: "2026-04-03T08:04:56.158Z" -last_activity: 2026-04-02 — Plan 03-08 complete — SearchViewModel + DuplicatesViewModel + Views visual checkpoint approved +stopped_at: Completed 04-bulk-operations-and-provisioning-04-04-PLAN.md +last_updated: "2026-04-03T08:10:00.000Z" +last_activity: 2026-04-03 — Plan 04-04 complete — BulkMemberService with Graph API and CSOM fallback progress: total_phases: 5 completed_phases: 3 total_plans: 33 - completed_plans: 28 - percent: 65 + completed_plans: 29 + percent: 88 --- # Project State @@ -25,10 +25,10 @@ See: .planning/PROJECT.md (updated 2026-04-02) ## Current Position -Phase: 3 of 5 (Storage and File Operations) — COMPLETE -Plan: 8 of 8 in phase 03 — all plans complete, visual checkpoint approved -Status: Ready for Phase 4 planning -Last activity: 2026-04-02 — Plan 03-08 complete — SearchViewModel + DuplicatesViewModel + Views visual checkpoint approved +Phase: 4 of 5 (Bulk Operations and Provisioning) — IN PROGRESS +Plan: 4 of 10 in phase 04 — BulkMemberService complete +Status: Executing Phase 4 plans +Last activity: 2026-04-03 — Plan 04-04 complete — BulkMemberService with Graph API and CSOM fallback 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 P03 | 7min | 2 tasks | 2 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 @@ -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]: 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 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 @@ -173,6 +177,6 @@ None yet. ## Session Continuity -Last session: 2026-04-03T08:04:56.156Z -Stopped at: Completed 04-bulk-operations-and-provisioning-04-02-PLAN.md +Last session: 2026-04-03T08:10:00.000Z +Stopped at: Completed 04-bulk-operations-and-provisioning-04-04-PLAN.md Resume file: None diff --git a/.planning/phases/04-bulk-operations-and-provisioning/04-04-SUMMARY.md b/.planning/phases/04-bulk-operations-and-provisioning/04-04-SUMMARY.md new file mode 100644 index 0000000..4b197ec --- /dev/null +++ b/.planning/phases/04-bulk-operations-and-provisioning/04-04-SUMMARY.md @@ -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*