High-Level Architecture
Project Structure
Separation of Concerns
Core Library (Intune.Commander.Core):
- Platform-agnostic business logic
- Microsoft Graph API integration
- Authentication and multi-cloud support
- Data models and services
- Export/import functionality
- No UI dependencies
Intune.Commander.Desktop):
- Avalonia-based UI
- MVVM view models
- UI-specific services (logging, dialogs)
- Data binding and converters
- References Core library
Key Architecture Decisions
1. Azure.Identity over MSAL
Decision: UseAzure.Identity library instead of raw MSAL.
Rationale:
- Modern Microsoft-recommended approach
- Built-in multi-cloud support
TokenCredentialabstraction for multiple credential types- Cleaner API surface
- Automatic credential fallback chains
2. Direct Use of Microsoft.Graph.Beta SDK Models
Decision: UseMicrosoft.Graph.Beta SDK models directly instead of creating custom DTOs.
Rationale:
- Strongly typed models
- Automatic updates when Graph API changes
- No manual mapping code required
- Built-in serialization
- Reduced maintenance burden
- Export/Import DTOs when SDK models have non-serializable properties
- Custom wrapper models for specific UI binding requirements
3. Multi-Cloud Architecture
Decision: Support multiple Azure cloud environments with separate app registrations per cloud. Cloud Endpoints:| Cloud | Graph Endpoint | Authority Host |
|---|---|---|
| Commercial | https://graph.microsoft.com | AzureAuthorityHosts.AzurePublicCloud |
| GCC | https://graph.microsoft.com | AzureAuthorityHosts.AzurePublicCloud |
| GCC-High | https://graph.microsoft.us | AzureAuthorityHosts.AzureGovernment |
| DoD | https://dod-graph.microsoft.us | AzureAuthorityHosts.AzureGovernment |
- GCC-High and DoD require registrations in separate Azure portals
- Environment isolation and security
- Simpler permission management
- Avoids cross-cloud authentication errors
TenantProfile stores cloud-specific ClientId and the cloud type determines the correct endpoints.
See src/Intune.Commander.Core/Models/CloudEndpoints.cs for the implementation.
4. Graph Services Created Post-Authentication
Decision: Graph API services are NOT registered in dependency injection. They are instantiated inMainWindowViewModel after successful authentication.
Rationale:
- Services require an authenticated
GraphServiceClient - User may switch between multiple tenant profiles
- Services are tenant-specific, not application-wide
- Simpler lifecycle management
IConfigurationProfileService, ICompliancePolicyService, etc.) follow the same constructor pattern: new XxxService(GraphServiceClient graphClient).
5. Profile and Cache Encryption
Decision: UseMicrosoft.AspNetCore.DataProtection for encrypting sensitive data at rest.
Rationale:
- Cross-platform encryption using a single consistent API
- DPAPI-protected keys on Windows
- File-system protected keys on macOS/Linux
- Keys persist in user’s local app data directory
- No need to manage encryption keys manually
- Location:
%LOCALAPPDATA%\Intune.Commander\profiles.json - Encrypted with
INTUNEMANAGER_ENC:prefix - ClientSecret stored encrypted in the profile
- Plaintext files automatically migrated on next save
- Location:
%LOCALAPPDATA%\Intune.Commander\cache.db(LiteDB) - AES-encrypted database
- Password generated once and stored encrypted in
cache-key.bin - 24-hour default TTL per cache entry
- Keyed by tenant ID + data type
src/Intune.Commander.Core/Services/ProfileEncryptionService.cs and CacheService.cs.
6. Manual Pagination Pattern
Decision: Always manually implement pagination for Graph API list requests. Never usePageIterator.
Rationale:
PageIteratorsilently truncates results on some tenants- Large tenants require proper page size tuning
- Explicit control over
@odata.nextLinkhandling - Better error handling and retry logic
configurationPolicies(Settings Catalog):$top=100(Cosmos DB cursor stability)windowsQualityUpdateProfiles,windowsDriverUpdateProfiles:$top=200(hard API cap)- All other list endpoints:
$top=999
7. MVVM with CommunityToolkit.Mvvm
Decision: Use MVVM pattern with CommunityToolkit.Mvvm source generators. Rationale:- Industry standard for Avalonia/WPF applications
- Source generators eliminate boilerplate code
- Clean separation of UI and business logic
- Testable view models
- Compile-time safety with
x:DataTypebindings
[ObservableProperty] attribute generates the full property with INotifyPropertyChanged support. The [RelayCommand] attribute generates an ICommand implementation.
See src/Intune.Commander.Desktop/ViewModels/ for examples.
Error Handling Strategy
Graph API Errors
Common Graph API errors are translated to user-friendly messages:| Graph Error | User Message |
|---|---|
Forbidden (403) | “Missing permission: DeviceManagementConfiguration.ReadWrite.All” |
TooManyRequests (429) | “Request throttled. Retrying in X seconds…” |
Unauthorized (401) | “Session expired. Please sign in again.” |
NotFound (404) | “Object not found. It may have been deleted.” |
InternalServerError (500) | Cosmos DB skip-token cursor bug on large page requests; mitigated with smaller $top and exponential-backoff retry |
Retry Strategy
- Exponential backoff: 1s, 2s, 4s, 8s, 16s
- Respect
Retry-Afterheaders - Maximum 5 retries
- User cancellation support via
CancellationToken
Export/Import Format
Directory Structure
Decision: Maintain PowerShell JSON compatibility (read-only). Format:- Users may have existing PowerShell exports
- Migration path from PowerShell version
- Proven format structure
- .NET version can read PowerShell exports (backward compatibility)
- PowerShell version doesn’t need to read .NET exports (forward compatibility not required)
Performance Considerations
Graph API Optimization
- Batch requests where supported (future enhancement)
- Select queries - only request needed properties
- Filter queries - reduce payload size
- Parallel requests with concurrency limits
- LiteDB cache - 24-hour TTL reduces redundant API calls
UI Responsiveness
- Async/await for all I/O operations
- Background tasks for bulk operations
- Progress reporting via
IProgress<T> - Cancellation tokens for long operations
- Lazy loading - data loaded only when user navigates to a category
- Fire-and-forget for non-blocking UI loads:
_ = LoadDataAsync();
.Result, .Wait(), or .GetAwaiter().GetResult()
Memory Management
- Streaming for large exports (future enhancement)
- Dispose Graph clients properly
- ObservableCollection size limits (e.g., DebugLogService capped at 2000 entries)
Security Considerations
Token Storage
- Never log access tokens
- Clear tokens on logout
- Encrypted profile storage
- No secrets in config files or source code
Certificate Handling
- Certificate-based auth is deferred (not yet implemented)
- When implemented: store thumbprints only, not private keys
- Use Windows certificate store for private key storage
Network Security
- HTTPS only
- Certificate validation enabled
- No proxy credential storage
Technology Constraints
.NET Version
Decision: .NET 10 (LTS through November 2026) Rationale:- Long-term support
- Latest performance improvements
- Required for latest Avalonia versions
- C# 12 language features
C# Language Features Used
- Primary constructors:
public class MyService(GraphServiceClient client) - Collection expressions:
return response?.Value ?? []; - Required members:
required string TenantId { get; init; } - File-scoped namespaces:
namespace Intune.Commander.Core.Services; - Nullable reference types: Enabled everywhere
Minimum Requirements
OS: Windows 10 1809+ (initial target), Linux and macOS support via AvaloniaRAM: 512MB minimum, 1GB recommended
.NET Runtime: Bundled with app (self-contained deployment)
Logging Strategy
DebugLogService
Implementation:DebugLogService.InstancesingletonObservableCollection<string> Entries(capped at 2000)- All log dispatches to UI thread via
Dispatcher.UIThread.Post - Exposed in UI via
DebugLogWindow
src/Intune.Commander.Desktop/Services/DebugLogService.cs.
Related Documentation
- Technology Stack - Complete list of dependencies and versions
- Services - Service architecture and DI patterns
- Testing - Unit and integration test strategies
- Building - Build commands and development workflow