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:
Dev
2026-04-07 15:16:16 +02:00
parent 666e918810
commit a63a698282
5 changed files with 1290 additions and 5 deletions

View 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>