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