Files
Sharepoint-Toolbox/.planning/phases/01-foundation/01-CONTEXT.md
2026-04-02 11:29:00 +02:00

9.0 KiB
Raw Blame History

phase, title, status, created
phase title status created
1 Foundation ready-for-planning 2026-04-02

Phase 1 Context: Foundation

Decided Areas (from prior research + STATE.md)

These are locked — do not re-litigate during planning or execution.

Decision Value
Runtime .NET 10 LTS + WPF
MVVM framework CommunityToolkit.Mvvm 8.4.2
SharePoint library PnP.Framework 1.18.0
Auth MSAL.NET 4.83.1 + Extensions.Msal 4.83.3 + Desktop 4.82.1
Token cache MsalCacheHelper — one IPublicClientApplication per ClientId
DI host Microsoft.Extensions.Hosting 10.x
Logging Serilog 4.3.1 + rolling file sink → %AppData%\SharepointToolbox\logs\
JSON System.Text.Json (built-in)
JSON persistence Write-then-replace (file.tmp → validate → File.Move) + SemaphoreSlim(1) per file
Async pattern AsyncRelayCommand everywhere — zero async void handlers
Trimming PublishTrimmed=false — accept ~150200 MB EXE
Architecture 4-layer MVVM: View → ViewModel → Service → Infrastructure
Cross-VM messaging WeakReferenceMessenger for tenant-switched events
Session holder Singleton SessionManager — only class that holds ClientContext objects
Localization .resx resource files (EN default, FR overlay)

Gray Areas — Defaults Applied (user skipped discussion)

1. Shell Layout

Default: Mirror the existing tool's spatial contract — users are already trained on it.

  • Window structure: MainWindow with a top ToolBar, a center TabControl (feature tabs), and a bottom docked log panel.
  • Log panel: Always visible, 150 px tall, not collapsible in Phase 1 (collapsibility is cosmetic — defer to a later phase). Uses a RichTextBox-equivalent (RichTextBox XAML control) with color-coded entries.
  • Tab strip: TabControl with one TabItem per feature area. Phase 1 delivers a shell with placeholder tabs for all features so navigation is wired from day one.
  • Tabs to stub out: Permissions, Storage, File Search, Duplicates, Templates, Bulk Operations, Folder Structure, Settings — all stubbed with a "Coming soon" placeholder TextBlock except Settings (partially functional in Phase 1 for profile management and language switching).
  • Status bar: StatusBar at the very bottom (below the log panel) showing: current tenant display name | operation status text | progress percentage.

2. Tenant Selector Placement

Default: Prominent top-toolbar presence — tenant context is the most critical runtime state.

  • Toolbar layout (left to right): ComboBox (tenant display name list, ~220 px wide) → Button "Connect"Button "Manage Profiles..." → separator → Button "Clear Session".
  • ComboBox: Bound to MainWindowViewModel.TenantProfiles ObservableCollection. Selecting a different item triggers a tenant-switch command (WeakReferenceMessenger broadcast to reset all feature VMs).
  • "Manage Profiles..." button: Opens a modal ProfileManagementDialog (separate Window) for CRUD — create, rename, delete profiles. Inline editing in the toolbar would be too cramped.
  • "Clear Session" button: Clears the MSAL token cache for the currently selected tenant and resets connection state. Lives in the toolbar (not buried in settings) because MSP users need quick access when switching client accounts mid-session.
  • Profile fields: Name (display label), Tenant URL, Client ID — matches existing { name, tenantUrl, clientId } JSON schema exactly.

3. Progress + Cancel UX

Default: Per-tab pattern — each feature tab owns its progress state. No global progress bar.

  • Per-tab layout (bottom of each tab's content area): ProgressBar (indeterminate or 0100) + TextBlock (operation description, e.g. "Scanning site 3 of 12…") + Button "Cancel" — shown only when an operation is running (Visibility bound to IsRunning).
  • CancellationTokenSource: Owned by each ViewModel, recreated per operation. Cancel button calls _cts.Cancel().
  • IProgress<OperationProgress>: OperationProgress is a shared record { int Current, int Total, string Message } — defined in the Core/ layer and used by all feature services. Concrete implementation uses Progress<T> which marshals to the UI thread automatically.
  • Log panel as secondary channel: Every progress step that produces a meaningful event also writes a timestamped line to the log panel. The per-tab progress bar is the live indicator; the log is the audit trail.
  • Status bar: StatusBar at the bottom updates its operation text from the active tab's progress events via WeakReferenceMessenger — so the user sees progress even if they switch away from the running tab.

4. Error Surface UX

Default: Log panel as primary surface; modal dialog only for blocking errors.

  • Non-fatal errors (an operation failed, a SharePoint call returned an error): Written to log panel in red. The per-tab status area shows a brief summary (e.g. "Completed with 2 errors — see log"). No modal.
  • Fatal/blocking errors (auth failure, unhandled exception): MessageBox.Show modal with the error message and a "Copy to Clipboard" button for diagnostics. Keep it simple — no custom dialog in Phase 1.
  • No toasts in Phase 1: Toast/notification infrastructure is a cosmetic feature — defer. The log panel is always visible and sufficient.
  • Log entry format: HH:mm:ss [LEVEL] Message — color coded: green = info/success, orange = warning, red = error. LEVEL maps to Serilog severity.
  • Global exception handler: Application.DispatcherUnhandledException and TaskScheduler.UnobservedTaskException both funnel to the log panel + a fatal modal. Neither swallows the exception.
  • Empty catch block policy: Any catch block must do exactly one of: log-and-recover, log-and-rethrow, or log-and-surface. Empty catch = build defect. Enforce via code review on every PR in Phase 1.

JSON Compatibility

Existing file names and schema must be preserved exactly — users have live data in these files.

File Schema
Sharepoint_Export_profiles.json { "profiles": [{ "name": "...", "tenantUrl": "...", "clientId": "..." }] }
Sharepoint_Settings.json { "dataFolder": "...", "lang": "en" }

The C# SettingsService must read these files without migration — the field names are the contract.

Localization

  • EN strings are the default .resxStrings.resx (neutral/EN). FR is Strings.fr.resx.
  • Key naming: Mirror existing PowerShell key convention (tab.perms, btn.run.scan, menu.language, etc.) so the EN default content is easily auditable against the existing app.
  • Dynamic switching: CultureInfo.CurrentUICulture swap + WeakReferenceMessenger broadcast triggers all bound LocalizedString markup extensions to re-evaluate. No app restart needed.
  • FR completeness: FR strings will be stubbed with EN fallback in Phase 1 — FR completeness is a Phase 5 concern.

Infrastructure Patterns (Phase 1 Deliverables)

These are shared helpers that all feature phases reuse. They must be built and tested in Phase 1 before any feature work begins.

  1. SharePointPaginationHelper — static helper that wraps CamlQuery with RowLimit ≤ 2,000 and ListItemCollectionPosition looping. All list enumeration in the codebase must call this — never raw ExecuteQuery on a list.
  2. AsyncRelayCommand pattern — a thin base or example FeatureViewModel that demonstrates the canonical async command pattern: create CancellationTokenSource, bind IsRunning, bind IProgress<OperationProgress>, handle OperationCanceledException gracefully.
  3. ObservableCollection threading rule — results are accumulated in List<T> on a background thread, then assigned as new ObservableCollection<T>(list) via Dispatcher.InvokeAsync. Never modify an ObservableCollection from Task.Run.
  4. ExecuteQueryRetryAsync wrapper — wraps PnP Framework's retry logic. All CSOM calls use this; surface retry events as log + progress messages ("Throttled — retrying in 30s…").
  5. ClientContext disposal — always await using. Unit tests verify Dispose() is called on cancellation.

Deferred Ideas (out of scope for Phase 1)

  • Log panel collapsibility (cosmetic, Phase 3+)
  • Dark/light theme toggle (cosmetic, post-v1)
  • Toast/notification system (Phase 3+)
  • FR locale completeness (Phase 5)
  • User access export, storage charts, simplified permissions view (v1.x features, Phase 5)

code_context

Asset Path Notes
Existing profile JSON schema Sharepoint_ToolBox.ps1:6872 Save-Profiles shows exact field names
Existing settings JSON schema Sharepoint_ToolBox.ps1:147152 Save-Settings shows dataFolder + lang
Existing localization keys (EN) Sharepoint_ToolBox.ps1:27952870 (approx) Full EN key set for .resx migration
Existing tab names Sharepoint_ToolBox.ps1:3824 9 tabs: Perms, Storage, Templates, Search, Dupes, Transfer, Bulk, Struct, Versions
Log panel pattern Sharepoint_ToolBox.ps1:617 Color + timestamp format to mirror