--- phase: 04-bulk-operations-and-provisioning plan: 06 subsystem: bulk-operations tags: [csom, pnp-framework, template, folder-structure, sharepoint, dotnet] # Dependency graph requires: - phase: 04-bulk-operations-and-provisioning plan: 01 provides: "SiteTemplate, SiteTemplateOptions, TemplateLibraryInfo, TemplateFolderInfo, TemplatePermissionGroup, FolderStructureRow models and ITemplateService, IFolderStructureService interfaces" provides: - "TemplateService: CSOM site template capture (libraries, folders, permission groups, logo, settings) and apply via PnP Framework site creation" - "FolderStructureService: folder hierarchy creation from CSV rows with parent-first ordering via BulkOperationRunner" - "FolderStructureServiceTests: 4 unit tests (BuildUniquePaths logic) + 1 live-skip" - "TemplateServiceTests: 3 unit tests (interface impl, model defaults) + 2 live-skip" affects: [04-07, 04-08, 04-09, 04-10] # Tech tracking tech-stack: added: [] patterns: - "TemplateService.CaptureTemplateAsync — reads Web properties, filters hidden+system lists, enumerates folders recursively, captures SiteGroups with role assignments" - "TemplateService.ApplyTemplateAsync — creates Team or Communication site via PnP Framework CreateSiteAsync, then recreates libraries/folders/groups via CSOM" - "FolderStructureService.BuildUniquePaths — deduplicates and sorts CSV-derived folder paths parent-first by counting '/' separators" - "System list filter via HashSet — normalized comparison against known system list names (Style Library, Form Templates, etc.)" - "ModelSiteTemplate alias — resolves CSOM SiteTemplate vs Core.Models.SiteTemplate ambiguity" key-files: created: - "SharepointToolbox/Services/TemplateService.cs" - "SharepointToolbox/Services/FolderStructureService.cs" - "SharepointToolbox.Tests/Services/FolderStructureServiceTests.cs" - "SharepointToolbox.Tests/Services/TemplateServiceTests.cs" modified: [] key-decisions: - "TemplateService uses ModelSiteTemplate alias — same pattern as ITemplateService; CSOM SiteTemplate and Core.Models.SiteTemplate are both in scope" - "FolderStructureService.BuildUniquePaths sorts by slash count for parent-first ordering — ensures intermediate folders exist before children when using Folders.Add" - "System list filter uses HashSet with OrdinalIgnoreCase — fast O(1) lookup, handles case differences in SharePoint list names" - "TemplateService.ApplyTemplateAsync creates new ClientContext for new site URL — adminCtx.Url points to admin site, new site needs separate context" patterns-established: - "BuildUniquePaths internal static — enables direct unit testing without ClientContext mock" - "Parent-first folder ordering via depth sort — critical for Folders.Add which does not create intermediates automatically" requirements-completed: [TMPL-01, TMPL-02, FOLD-01] # Metrics duration: 10min completed: 2026-04-03 --- # Phase 04 Plan 06: TemplateService + FolderStructureService Implementation Summary **CSOM site template capture/apply (libraries, folders, permission groups, logo) and CSV-driven folder hierarchy creation with parent-first BulkOperationRunner integration** ## Performance - **Duration:** 10 min - **Started:** 2026-04-03T09:57:13Z - **Completed:** 2026-04-03T10:07:13Z - **Tasks:** 2 - **Files modified:** 4 ## Accomplishments - Implemented TemplateService with CaptureTemplateAsync (reads site structure via CSOM) and ApplyTemplateAsync (creates site via PnP Framework, recreates structure via CSOM) - Implemented FolderStructureService with BuildUniquePaths (parent-first deduplication) and CreateFoldersAsync using BulkOperationRunner - Created unit tests: 4 FolderStructureService tests (all pass) + 3 TemplateService tests (all pass), 3 live-SharePoint tests marked Skip ## Task Commits Each task was committed atomically: 1. **Task 1: Implement TemplateService** — already committed prior to this plan execution (verified via `git log`) 2. **Task 2: FolderStructureService + tests** - `84cd569` (feat) **Plan metadata:** (added in final commit) ## Files Created/Modified - `SharepointToolbox/Services/TemplateService.cs` — Site template capture (reads Web, lists, folders, groups) and apply (PnP Framework site creation + CSOM structure recreation) - `SharepointToolbox/Services/FolderStructureService.cs` — CSV row to folder hierarchy via BuildUniquePaths + BulkOperationRunner.RunAsync - `SharepointToolbox.Tests/Services/FolderStructureServiceTests.cs` — 4 unit tests: interface impl, parent-first ordering, deduplication, empty levels - `SharepointToolbox.Tests/Services/TemplateServiceTests.cs` — 3 unit tests: interface impl, SiteTemplate defaults, SiteTemplateOptions defaults ## Decisions Made - TemplateService uses `using ModelSiteTemplate = SharepointToolbox.Core.Models.SiteTemplate` alias — consistent with ITemplateService.cs established in Plan 04-01 - FolderStructureService.BuildUniquePaths sorts by slash depth (fewer slashes = shallower path = parent) — guarantees parent folders are created before children when SharePoint's Folders.Add does not create intermediates - ApplyTemplateAsync creates a new ClientContext(siteUrl) for the newly created site — the adminCtx.Url is the admin site URL, not the new site ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Plan's BuildUniquePaths_DuplicateRows_Deduplicated expected count was incorrect** - **Found during:** Task 2 (writing unit tests) - **Issue:** Plan specified `Assert.Equal(4, paths.Count)` for rows `{A,B}`, `{A,B}`, `{A,C}` which produces 3 unique paths: "A", "A/B", "A/C" - **Fix:** Changed expected count from 4 to 3 to match correct deduplication behavior - **Files modified:** `SharepointToolbox.Tests/Services/FolderStructureServiceTests.cs` - **Verification:** Test passes with correct assertion - **Committed in:** `84cd569` (Task 2 commit) --- **Total deviations:** 1 auto-fixed (1 x Rule 1 - plan spec bug in test expectation) **Impact on plan:** Corrected incorrect test expectation; actual BuildUniquePaths behavior is correct. No scope creep. ## Issues Encountered - Transient WPF build file locking (`.msCoverageSourceRootsMapping_*`, `CoverletSourceRootsMapping_*`) required deleting locked coverage files and creating root `obj/` directory before builds succeeded. This is an established environment issue unrelated to code changes. - TemplateService.cs was already committed in a prior plan agent's docs commit — verified content matches plan spec exactly (372 lines, full implementation). ## User Setup Required None - no external service configuration required. ## Next Phase Readiness - TemplateService and FolderStructureService are ready for Plan 04-07 (ViewModels for template and folder operations) - Both services use BulkOperationRunner for per-item error handling, consistent with Plans 04-03 to 04-05 - All 122 tests pass (0 failures) across the full test suite ## Self-Check: PASSED All files found, all commits verified. --- *Phase: 04-bulk-operations-and-provisioning* *Completed: 2026-04-03*