---
phase: 06-global-site-selection
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs
  - SharepointToolbox/ViewModels/FeatureViewModelBase.cs
autonomous: true
requirements:
  - SITE-01
must_haves:
  truths:
    - "GlobalSitesChangedMessage exists and follows the same ValueChangedMessage pattern as TenantSwitchedMessage"
    - "FeatureViewModelBase registers for GlobalSitesChangedMessage in OnActivated and exposes a protected GlobalSites property"
    - "Derived tab VMs can override OnGlobalSitesChanged to react to global site selection changes"
    - "Existing TenantSwitchedMessage registration still works (no regression)"
  artifacts:
    - path: "SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs"
      provides: "Messenger message for global site selection changes"
      contains: "GlobalSitesChangedMessage"
    - path: "SharepointToolbox/ViewModels/FeatureViewModelBase.cs"
      provides: "Base class with GlobalSites property and OnGlobalSitesChanged virtual method"
      contains: "GlobalSites"
  key_links:
    - from: "SharepointToolbox/ViewModels/FeatureViewModelBase.cs"
      to: "SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs"
      via: "Messenger.Register<GlobalSitesChangedMessage> in OnActivated"
      pattern: "Register<GlobalSitesChangedMessage>"
---

<objective>
Create the GlobalSitesChangedMessage and extend FeatureViewModelBase to receive and store global site selections. This establishes the messaging contract that all tab VMs and MainWindowViewModel depend on.

Purpose: Foundation contract — every other plan in this phase builds on this message class and base class extension.
Output: GlobalSitesChangedMessage.cs, updated FeatureViewModelBase.cs
</objective>

<execution_context>
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-global-site-selection/06-CONTEXT.md

<interfaces>
<!-- Existing message pattern to follow exactly -->
From SharepointToolbox/Core/Messages/TenantSwitchedMessage.cs:
```csharp
using CommunityToolkit.Mvvm.Messaging.Messages;
using SharepointToolbox.Core.Models;

namespace SharepointToolbox.Core.Messages;

public sealed class TenantSwitchedMessage : ValueChangedMessage<TenantProfile>
{
    public TenantSwitchedMessage(TenantProfile profile) : base(profile) { }
}
```

From SharepointToolbox/Core/Models/SiteInfo.cs:
```csharp
namespace SharepointToolbox.Core.Models;
public record SiteInfo(string Url, string Title);
```

From SharepointToolbox/ViewModels/FeatureViewModelBase.cs (OnActivated — extend this):
```csharp
protected override void OnActivated()
{
    Messenger.Register<TenantSwitchedMessage>(this, (r, m) => ((FeatureViewModelBase)r).OnTenantSwitched(m.Value));
}

protected virtual void OnTenantSwitched(TenantProfile profile)
{
    // Derived classes override to reset their state
}
```
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create GlobalSitesChangedMessage</name>
  <files>SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs</files>
  <action>
    Create a new message class following the exact same pattern as TenantSwitchedMessage.

    File: `SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs`
    ```csharp
    using CommunityToolkit.Mvvm.Messaging.Messages;
    using SharepointToolbox.Core.Models;

    namespace SharepointToolbox.Core.Messages;

    public sealed class GlobalSitesChangedMessage : ValueChangedMessage<IReadOnlyList<SiteInfo>>
    {
        public GlobalSitesChangedMessage(IReadOnlyList<SiteInfo> sites) : base(sites) { }
    }
    ```

    The value type is `IReadOnlyList<SiteInfo>` (not ObservableCollection) because the message carries a snapshot of the current selection — receivers should not mutate the sender's collection.
  </action>
  <verify>
    <automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5</automated>
  </verify>
  <done>GlobalSitesChangedMessage.cs exists in Core/Messages/, compiles without errors, follows the ValueChangedMessage pattern.</done>
</task>

<task type="auto">
  <name>Task 2: Extend FeatureViewModelBase with GlobalSites support</name>
  <files>SharepointToolbox/ViewModels/FeatureViewModelBase.cs</files>
  <action>
    Modify FeatureViewModelBase to register for GlobalSitesChangedMessage and store the global sites.

    1. Add using directive: `using SharepointToolbox.Core.Models;` (SiteInfo is in Core.Models).

    2. Add a protected property to store the global sites (after the existing fields, before RunCommand):
    ```csharp
    /// <summary>
    /// Sites selected in the global toolbar picker. Updated via GlobalSitesChangedMessage.
    /// Derived VMs check this in RunOperationAsync before falling back to per-tab SiteUrl.
    /// </summary>
    protected IReadOnlyList<SiteInfo> GlobalSites { get; private set; } = Array.Empty<SiteInfo>();
    ```

    3. In `OnActivated()`, add a second Messenger.Register call for GlobalSitesChangedMessage, right after the existing TenantSwitchedMessage registration:
    ```csharp
    protected override void OnActivated()
    {
        Messenger.Register<TenantSwitchedMessage>(this, (r, m) => ((FeatureViewModelBase)r).OnTenantSwitched(m.Value));
        Messenger.Register<GlobalSitesChangedMessage>(this, (r, m) => ((FeatureViewModelBase)r).OnGlobalSitesReceived(m.Value));
    }
    ```

    4. Add a private method that updates the property and calls the virtual hook:
    ```csharp
    private void OnGlobalSitesReceived(IReadOnlyList<SiteInfo> sites)
    {
        GlobalSites = sites;
        OnGlobalSitesChanged(sites);
    }
    ```

    5. Add a protected virtual method for derived classes to override:
    ```csharp
    /// <summary>
    /// Called when the global site selection changes. Override in derived VMs
    /// to update UI state (e.g., pre-fill SiteUrl from first global site).
    /// </summary>
    protected virtual void OnGlobalSitesChanged(IReadOnlyList<SiteInfo> sites)
    {
        // Derived classes override to react to global site changes
    }
    ```

    Do NOT modify anything in the ExecuteAsync, RunCommand, CancelCommand, or OnTenantSwitched areas. Only add the new GlobalSites infrastructure.
  </action>
  <verify>
    <automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 && dotnet test SharepointToolbox.Tests/SharepointToolbox.Tests.csproj --no-build 2>&1 | tail -5</automated>
  </verify>
  <done>FeatureViewModelBase compiles with GlobalSites property, OnGlobalSitesChanged virtual method, and GlobalSitesChangedMessage registration in OnActivated. All existing tests still pass (no regression).</done>
</task>

</tasks>

<verification>
- `dotnet build SharepointToolbox/SharepointToolbox.csproj` succeeds with 0 errors
- `dotnet test` shows no new failures (existing tests unaffected)
- GlobalSitesChangedMessage.cs exists in Core/Messages/
- FeatureViewModelBase.cs contains `GlobalSites` property and `OnGlobalSitesChanged` virtual method
- OnActivated registers for both TenantSwitchedMessage and GlobalSitesChangedMessage
</verification>

<success_criteria>
The messaging contract is established: GlobalSitesChangedMessage can be sent by any publisher and received by all FeatureViewModelBase subclasses. The protected GlobalSites property and virtual OnGlobalSitesChanged hook are available for tab VMs to override in plan 06-04.
</success_criteria>

<output>
After completion, create `.planning/phases/06-global-site-selection/06-01-SUMMARY.md`
</output>
