docs(04-06): complete TemplateService + FolderStructureService plan — CSOM template capture/apply and CSV folder hierarchy creation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,14 +55,14 @@ Requirements for initial release. Each maps to roadmap phases.
|
|||||||
|
|
||||||
### Site Templates
|
### Site Templates
|
||||||
|
|
||||||
- [ ] **TMPL-01**: User can capture site structure (libraries, folders, permission groups, logo, settings) as a template
|
- [x] **TMPL-01**: User can capture site structure (libraries, folders, permission groups, logo, settings) as a template
|
||||||
- [ ] **TMPL-02**: User can apply template to create new Communication or Teams site
|
- [x] **TMPL-02**: User can apply template to create new Communication or Teams site
|
||||||
- [x] **TMPL-03**: Templates persist locally as JSON
|
- [x] **TMPL-03**: Templates persist locally as JSON
|
||||||
- [x] **TMPL-04**: User can manage templates (create, rename, delete)
|
- [x] **TMPL-04**: User can manage templates (create, rename, delete)
|
||||||
|
|
||||||
### Folder Structure
|
### Folder Structure
|
||||||
|
|
||||||
- [ ] **FOLD-01**: User can create folder structures on a site from a CSV template
|
- [x] **FOLD-01**: User can create folder structures on a site from a CSV template
|
||||||
- [x] **FOLD-02**: Example CSV templates provided for common structures
|
- [x] **FOLD-02**: Example CSV templates provided for common structures
|
||||||
|
|
||||||
### Bulk Operations
|
### Bulk Operations
|
||||||
@@ -146,11 +146,11 @@ Which phases cover which requirements. Updated during roadmap creation.
|
|||||||
| DUPL-01 | Phase 3 | Complete |
|
| DUPL-01 | Phase 3 | Complete |
|
||||||
| DUPL-02 | Phase 3 | Complete |
|
| DUPL-02 | Phase 3 | Complete |
|
||||||
| DUPL-03 | Phase 3 | Complete |
|
| DUPL-03 | Phase 3 | Complete |
|
||||||
| TMPL-01 | Phase 4 | Pending |
|
| TMPL-01 | Phase 4 | Complete |
|
||||||
| TMPL-02 | Phase 4 | Pending |
|
| TMPL-02 | Phase 4 | Complete |
|
||||||
| TMPL-03 | Phase 4 | Complete |
|
| TMPL-03 | Phase 4 | Complete |
|
||||||
| TMPL-04 | Phase 4 | Complete |
|
| TMPL-04 | Phase 4 | Complete |
|
||||||
| FOLD-01 | Phase 4 | Pending |
|
| FOLD-01 | Phase 4 | Complete |
|
||||||
| FOLD-02 | Phase 4 | Complete |
|
| FOLD-02 | Phase 4 | Complete |
|
||||||
| BULK-01 | Phase 4 | Complete |
|
| BULK-01 | Phase 4 | Complete |
|
||||||
| BULK-02 | Phase 4 | Complete |
|
| BULK-02 | Phase 4 | Complete |
|
||||||
|
|||||||
@@ -138,5 +138,5 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
|
|||||||
| 1. Foundation | 8/8 | Complete | 2026-04-02 |
|
| 1. Foundation | 8/8 | Complete | 2026-04-02 |
|
||||||
| 2. Permissions | 7/7 | Complete | 2026-04-02 |
|
| 2. Permissions | 7/7 | Complete | 2026-04-02 |
|
||||||
| 3. Storage and File Operations | 8/8 | Complete | 2026-04-02 |
|
| 3. Storage and File Operations | 8/8 | Complete | 2026-04-02 |
|
||||||
| 4. Bulk Operations and Provisioning | 5/10 | In Progress| |
|
| 4. Bulk Operations and Provisioning | 6/10 | In Progress| |
|
||||||
| 5. Distribution and Hardening | 0/? | Not started | - |
|
| 5. Distribution and Hardening | 0/? | Not started | - |
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: planning
|
status: executing
|
||||||
stopped_at: Completed 04-bulk-operations-and-provisioning-04-04-PLAN.md
|
stopped_at: Completed 04-bulk-operations-and-provisioning-04-06-PLAN.md
|
||||||
last_updated: "2026-04-03T08:10:00.000Z"
|
last_updated: "2026-04-03T08:09:18.086Z"
|
||||||
last_activity: 2026-04-03 — Plan 04-04 complete — BulkMemberService with Graph API and CSOM fallback
|
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: 29
|
completed_plans: 29
|
||||||
percent: 88
|
percent: 65
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -88,6 +88,7 @@ Progress: [██████░░░░] 65%
|
|||||||
| 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 |
|
| Phase 04-bulk-operations-and-provisioning P04 | 7min | 2 tasks | 3 files |
|
||||||
|
| Phase 04-bulk-operations-and-provisioning P06 | 10min | 2 tasks | 4 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -165,6 +166,9 @@ Recent decisions affecting current work:
|
|||||||
- [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]: 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]: 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
|
- [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
|
||||||
|
- [Phase 04-bulk-operations-and-provisioning]: TemplateService uses ModelSiteTemplate alias — consistent with ITemplateService; CSOM SiteTemplate and Core.Models.SiteTemplate are both in scope
|
||||||
|
- [Phase 04-bulk-operations-and-provisioning]: FolderStructureService.BuildUniquePaths sorts by slash count for parent-first ordering — ensures intermediate folders exist before children when using Folders.Add
|
||||||
|
- [Phase 04-bulk-operations-and-provisioning]: TemplateService.ApplyTemplateAsync creates new ClientContext for new site URL — adminCtx.Url points to admin site, new site needs separate context
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -177,6 +181,6 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-03T08:10:00.000Z
|
Last session: 2026-04-03T08:09:18.084Z
|
||||||
Stopped at: Completed 04-bulk-operations-and-provisioning-04-04-PLAN.md
|
Stopped at: Completed 04-bulk-operations-and-provisioning-04-06-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
---
|
||||||
|
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<string> — 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<string> 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*
|
||||||
Reference in New Issue
Block a user