docs(09-storage-visualization): create phase plan — 4 plans in 4 waves
Wave 1: LiveCharts2 NuGet + FileTypeMetric model + IStorageService extension Wave 2: StorageService file-type enumeration implementation Wave 3: ViewModel chart properties + View XAML + localization Wave 4: Unit tests for chart ViewModel behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
209
.planning/phases/09-storage-visualization/09-01-PLAN.md
Normal file
209
.planning/phases/09-storage-visualization/09-01-PLAN.md
Normal file
@@ -0,0 +1,209 @@
|
||||
---
|
||||
phase: 09-storage-visualization
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- SharepointToolbox/SharepointToolbox.csproj
|
||||
- SharepointToolbox/Core/Models/FileTypeMetric.cs
|
||||
- SharepointToolbox/Services/IStorageService.cs
|
||||
autonomous: true
|
||||
requirements:
|
||||
- VIZZ-01
|
||||
must_haves:
|
||||
truths:
|
||||
- "LiveCharts2 SkiaSharp WPF package is a NuGet dependency and the project compiles"
|
||||
- "FileTypeMetric record models file extension, total size, and file count"
|
||||
- "IStorageService declares CollectFileTypeMetricsAsync without breaking existing CollectStorageAsync"
|
||||
artifacts:
|
||||
- path: "SharepointToolbox/SharepointToolbox.csproj"
|
||||
provides: "LiveChartsCore.SkiaSharpView.WPF package reference"
|
||||
contains: "LiveChartsCore.SkiaSharpView.WPF"
|
||||
- path: "SharepointToolbox/Core/Models/FileTypeMetric.cs"
|
||||
provides: "Data model for file type breakdown"
|
||||
contains: "record FileTypeMetric"
|
||||
- path: "SharepointToolbox/Services/IStorageService.cs"
|
||||
provides: "Extended interface with file type metrics method"
|
||||
contains: "CollectFileTypeMetricsAsync"
|
||||
key_links:
|
||||
- from: "SharepointToolbox/Services/IStorageService.cs"
|
||||
to: "SharepointToolbox/Core/Models/FileTypeMetric.cs"
|
||||
via: "Return type of CollectFileTypeMetricsAsync"
|
||||
pattern: "IReadOnlyList<FileTypeMetric>"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Add LiveCharts2 NuGet dependency, create the FileTypeMetric data model, and extend IStorageService with a file-type metrics collection method signature.
|
||||
|
||||
Purpose: Establishes the charting library dependency (VIZZ-01) and the data contracts that all subsequent plans depend on. No implementation yet -- just the NuGet, the model, and the interface.
|
||||
Output: Updated csproj, FileTypeMetric.cs, updated IStorageService.cs
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@C:/Users/dev/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Existing IStorageService -- we ADD a method, do not change existing signature -->
|
||||
From SharepointToolbox/Services/IStorageService.cs:
|
||||
```csharp
|
||||
using Microsoft.SharePoint.Client;
|
||||
using SharepointToolbox.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Services;
|
||||
|
||||
public interface IStorageService
|
||||
{
|
||||
Task<IReadOnlyList<StorageNode>> CollectStorageAsync(
|
||||
ClientContext ctx,
|
||||
StorageScanOptions options,
|
||||
IProgress<OperationProgress> progress,
|
||||
CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
From SharepointToolbox/Core/Models/StorageScanOptions.cs:
|
||||
```csharp
|
||||
public record StorageScanOptions(bool PerLibrary = true, bool IncludeSubsites = false, int FolderDepth = 0);
|
||||
```
|
||||
|
||||
From SharepointToolbox/Core/Models/OperationProgress.cs:
|
||||
```csharp
|
||||
public record OperationProgress(int Current, int Total, string Message)
|
||||
{
|
||||
public static OperationProgress Indeterminate(string message) => new(0, 0, message);
|
||||
}
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add LiveCharts2 NuGet and create FileTypeMetric model</name>
|
||||
<files>SharepointToolbox/SharepointToolbox.csproj, SharepointToolbox/Core/Models/FileTypeMetric.cs</files>
|
||||
<action>
|
||||
**Step 1:** Add LiveCharts2 WPF NuGet package:
|
||||
|
||||
```bash
|
||||
cd "C:\Users\dev\Documents\projets\Sharepoint"
|
||||
dotnet add SharepointToolbox/SharepointToolbox.csproj package LiveChartsCore.SkiaSharpView.WPF --version 2.0.0-rc5.4
|
||||
```
|
||||
|
||||
This will add the package reference to the csproj. The `--version 2.0.0-rc5.4` is a pre-release RC, so the command may need `--prerelease` flag if it fails. Try with explicit version first; if that fails, use:
|
||||
```bash
|
||||
dotnet add SharepointToolbox/SharepointToolbox.csproj package LiveChartsCore.SkiaSharpView.WPF --prerelease
|
||||
```
|
||||
|
||||
**Step 2:** Create `SharepointToolbox/Core/Models/FileTypeMetric.cs`:
|
||||
|
||||
```csharp
|
||||
namespace SharepointToolbox.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents storage consumption for a single file extension across all scanned libraries.
|
||||
/// Produced by IStorageService.CollectFileTypeMetricsAsync and consumed by chart bindings.
|
||||
/// </summary>
|
||||
public record FileTypeMetric(
|
||||
/// <summary>File extension including dot, e.g. ".docx", ".pdf". Empty string for extensionless files.</summary>
|
||||
string Extension,
|
||||
/// <summary>Total size in bytes of all files with this extension.</summary>
|
||||
long TotalSizeBytes,
|
||||
/// <summary>Number of files with this extension.</summary>
|
||||
int FileCount)
|
||||
{
|
||||
/// <summary>
|
||||
/// Human-friendly display label: ".docx" becomes "DOCX", empty becomes "No Extension".
|
||||
/// </summary>
|
||||
public string DisplayLabel => string.IsNullOrEmpty(Extension)
|
||||
? "No Extension"
|
||||
: Extension.TrimStart('.').ToUpperInvariant();
|
||||
}
|
||||
```
|
||||
|
||||
Design notes:
|
||||
- Record type for value semantics (same as StorageScanOptions, PermissionSummary patterns)
|
||||
- Extension stored with dot prefix for consistency with Path.GetExtension
|
||||
- DisplayLabel computed property for chart label binding
|
||||
- TotalSizeBytes is long to match StorageNode.TotalSizeBytes type
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>LiveChartsCore.SkiaSharpView.WPF appears in csproj PackageReference. FileTypeMetric.cs exists with Extension, TotalSizeBytes, FileCount properties and DisplayLabel computed property. Project compiles with 0 errors.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Extend IStorageService with CollectFileTypeMetricsAsync</name>
|
||||
<files>SharepointToolbox/Services/IStorageService.cs</files>
|
||||
<action>
|
||||
Update `SharepointToolbox/Services/IStorageService.cs` to add a second method for file-type metrics collection. Do NOT modify the existing CollectStorageAsync signature.
|
||||
|
||||
Replace the file contents with:
|
||||
|
||||
```csharp
|
||||
using Microsoft.SharePoint.Client;
|
||||
using SharepointToolbox.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Services;
|
||||
|
||||
public interface IStorageService
|
||||
{
|
||||
/// <summary>
|
||||
/// Collects storage metrics per library/folder using SharePoint StorageMetrics API.
|
||||
/// Returns a tree of StorageNode objects with aggregate size data.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<StorageNode>> CollectStorageAsync(
|
||||
ClientContext ctx,
|
||||
StorageScanOptions options,
|
||||
IProgress<OperationProgress> progress,
|
||||
CancellationToken ct);
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates files across all non-hidden document libraries in the site
|
||||
/// and aggregates storage consumption grouped by file extension.
|
||||
/// Uses CSOM CamlQuery to retrieve FileLeafRef and File_x0020_Size per file.
|
||||
/// This is a separate operation from CollectStorageAsync -- it provides
|
||||
/// file-type breakdown data for chart visualization.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<FileTypeMetric>> CollectFileTypeMetricsAsync(
|
||||
ClientContext ctx,
|
||||
IProgress<OperationProgress> progress,
|
||||
CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
Design notes:
|
||||
- CollectFileTypeMetricsAsync does NOT take StorageScanOptions because file-type enumeration scans ALL non-hidden doc libraries (no per-library/subfolder filtering needed for chart aggregation)
|
||||
- Returns IReadOnlyList<FileTypeMetric> sorted by TotalSizeBytes descending (convention -- implementation will handle sorting)
|
||||
- Separate from CollectStorageAsync so existing storage scan flow is untouched
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>IStorageService.cs declares both CollectStorageAsync (unchanged) and CollectFileTypeMetricsAsync (new). Build fails with CS0535 in StorageService.cs (expected -- Plan 09-02 implements the method). If build succeeds, even better. Interface contract is established.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `dotnet restore SharepointToolbox/SharepointToolbox.csproj` succeeds and LiveChartsCore.SkiaSharpView.WPF is resolved
|
||||
- FileTypeMetric.cs exists in Core/Models with record definition
|
||||
- IStorageService.cs has both method signatures
|
||||
- Existing CollectStorageAsync signature is byte-identical to original
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
LiveCharts2 is a project dependency. FileTypeMetric data model is defined. IStorageService has the new CollectFileTypeMetricsAsync method signature. The project compiles (or fails only because StorageService doesn't implement the new method yet -- that is acceptable and expected).
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/09-storage-visualization/09-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user