--- phase: 04-bulk-operations-and-provisioning plan: 05 subsystem: bulk-site-creation tags: [pnp-framework, bulk-operations, sharepoint-site-creation, team-site, communication-site] # Dependency graph requires: - phase: 04-01 provides: "IBulkSiteService, BulkSiteRow, BulkOperationRunner" - phase: 01-foundation provides: "ExecuteQueryRetryHelper for throttle-safe CSOM calls" provides: - "BulkSiteService implementing IBulkSiteService via PnP Framework CreateSiteAsync" - "Team site creation with alias + owners array via TeamSiteCollectionCreationInformation" - "Communication site creation with auto-generated URL via CommunicationSiteCollectionCreationInformation" - "Member/owner assignment post-creation via CSOM AssociatedMemberGroup/AssociatedOwnerGroup" - "SanitizeAlias helper: removes special chars, replaces spaces with dashes, lowercases" affects: [04-09, 04-10] # Tech tracking tech-stack: added: [] patterns: - "BulkSiteService.CreateSingleSiteAsync — type dispatch (Team vs Communication) before PnP call" - "Communication site URL construction: https://{tenantHost}/sites/{alias}" - "Post-creation member add: EnsureUser + AssociatedMemberGroup.Users.AddUser per email" - "ParseEmails: Split(',', RemoveEmptyEntries | TrimEntries) from comma-separated CSV field" - "SanitizeAlias: keep letters/digits/spaces/dashes, replace space with dash, lowercase" key-files: created: - "SharepointToolbox/Services/BulkSiteService.cs" - "SharepointToolbox.Tests/Services/BulkSiteServiceTests.cs" modified: - "SharepointToolbox/Services/BulkMemberService.cs" key-decisions: - "BulkSiteService uses SharepointToolbox.Core.Helpers.ExecuteQueryRetryHelper (not Infrastructure.Auth) — plan had wrong using; correct namespace is Core.Helpers (established pattern from Phase 2/3 services)" - "Communication site URL built from adminCtx.Url host — ensures correct tenant hostname without hardcoding" # Metrics duration: 6min completed: 2026-04-03 --- # Phase 04 Plan 05: BulkSiteService Implementation Summary **BulkSiteService implements IBulkSiteService using PnP Framework CreateSiteAsync for Team and Communication site bulk creation with per-site error handling** ## Performance - **Duration:** 6 min - **Started:** 2026-04-03T07:57:03Z - **Completed:** 2026-04-03T08:02:15Z - **Tasks:** 2 (both committed together) - **Files modified:** 3 ## Accomplishments - Implemented `BulkSiteService` with full `IBulkSiteService` contract - Team site creation via `TeamSiteCollectionCreationInformation` with `Alias`, `DisplayName`, `IsPublic=false`, and `Owners[]` - Communication site creation via `CommunicationSiteCollectionCreationInformation` with auto-generated URL from `adminCtx.Url` host - Post-creation member/owner assignment via `EnsureUser` + `AssociatedMemberGroup/OwnerGroup.Users.AddUser` - Per-site error handling delegates to `BulkOperationRunner.RunAsync` with continue-on-error semantics - `ParseEmails` helper splits comma-separated owner/member CSV fields - `SanitizeAlias` generates URL-safe aliases from display names - 3 passing tests (interface check, default values, CSV field inspection) + 3 skipped (live SP required) ## Task Commits 1. **Task 1+2: Implement BulkSiteService + BulkSiteServiceTests** - `b0956ad` (feat) ## Files Created/Modified - `SharepointToolbox/Services/BulkSiteService.cs` — Full IBulkSiteService implementation with PnP Framework - `SharepointToolbox.Tests/Services/BulkSiteServiceTests.cs` — 3 passing + 3 skipped unit tests - `SharepointToolbox/Services/BulkMemberService.cs` — Fixed pre-existing Group type ambiguity (Rule 1) ## Decisions Made - `BulkSiteService` imports `SharepointToolbox.Core.Helpers` not `SharepointToolbox.Infrastructure.Auth` — plan listed wrong using directive; `ExecuteQueryRetryHelper` lives in `Core.Helpers` as established by all Phase 2/3 services - Communication site URL is constructed from `adminCtx.Url` hostname to ensure tenant-correct URLs without hardcoding ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Fixed wrong using directive in BulkSiteService** - **Found during:** Task 1 (implementation) - **Issue:** Plan code had `using SharepointToolbox.Infrastructure.Auth;` — `ExecuteQueryRetryHelper` is in `SharepointToolbox.Core.Helpers` - **Fix:** Replaced `using SharepointToolbox.Infrastructure.Auth;` with `using SharepointToolbox.Core.Helpers;` - **Files modified:** `SharepointToolbox/Services/BulkSiteService.cs` - **Commit:** `b0956ad` **2. [Rule 1 - Bug] Fixed BulkMemberService.cs Group type ambiguity** - **Found during:** Task 1 (build verification) - **Issue:** `Group? targetGroup = null;` on line 164 was ambiguous between `Microsoft.SharePoint.Client.Group` and `Microsoft.Graph.Models.Group` — CS0104 compile error - **Fix:** Linter auto-applied `using SpGroup = Microsoft.SharePoint.Client.Group;` alias + used `SpGroup?` - **Files modified:** `SharepointToolbox/Services/BulkMemberService.cs` - **Commit:** `b0956ad` --- **Total deviations:** 2 auto-fixed (2 x Rule 1 - compile bugs) **Impact:** Both fixes were required for compilation. No scope creep. BulkMemberService fix is out-of-scope (from a previous plan) but was blocking the build entirely. ## Issues Encountered The WPF temp project build lock (`MainWindow.g.cs` locked by another process) prevented `dotnet build SharepointToolbox.slnx` from completing. The test project build (`dotnet build SharepointToolbox.Tests`) succeeds normally and was used for verification. ## User Setup Required None — no external service configuration required. ## Next Phase Readiness - `BulkSiteService` is ready for use by BulkSiteViewModel (Plan 04-09) and BulkSiteView (Plan 04-10) - All 3 non-skip tests pass; live integration tests remain skipped pending live SP admin context - Build: `dotnet build SharepointToolbox.Tests` succeeds with 0 errors, 0 warnings ## Self-Check: PASSED - BulkSiteService.cs: FOUND at `SharepointToolbox/Services/BulkSiteService.cs` - BulkSiteServiceTests.cs: FOUND at `SharepointToolbox.Tests/Services/BulkSiteServiceTests.cs` - 04-05-SUMMARY.md: FOUND (this file) - Commit b0956ad: FOUND --- *Phase: 04-bulk-operations-and-provisioning* *Completed: 2026-04-03*