ALPAMobile.Domain ← Pure business rules, no external dependencies
ALPAMobile.Application ← Service interfaces (contracts), orchestration/use-cases
ALPAMobile.Infrastructure ← API clients, auth, storage, caching (implements Application interfaces)
ALPAMobile.Presentation ← Pages, ViewModels, controls (depends on Application interfaces only)
ALPAMobile (MAUI host) ← Composition root only — MauiProgram.cs wires everything via DI
Dependency rule (enforced by NetArchTest):
Domain ← Application ← Infrastructure
Domain ← Application ← Presentation
NEVER: Domain → anything, Application → Infrastructure/Presentation, Infrastructure → Presentation
| Gap WI | Title | Resolved In Phase |
|---|---|---|
| WI-2105 | Replace Service Locator anti-pattern (280+ hits of Handler?.MauiContext?.Services.GetService<T>()) | Phase 3 + Phase 6 |
| WI-2106 | Modernize 204 new Command() usages to RelayCommand/AsyncRelayCommand | Phase 5 |
| WI-2107 | Replace custom BindableBase with MVVM Toolkit ObservableObject | Phase 5 |
| WI-2108 | Move FTDTCalculator & FTDTValidator from ALPAMobile/BusinessLogic/ to Domain layer | Phase 2 |
| WI-2109 | Break up DataManager.cs (2813 lines) and RestService.cs (2048 lines) | Phase 4 |
| WI-2110 | Implement IValidationRule<T> / per-property error binding validation infrastructure | Phase 7 |
| WI-2111 | Introduce INavigationService abstraction (replace Shell.Current in BasePageViewModel) | Phase 3 |
| WI-2112 | Extract ISettingsService interface from AppProperties concrete class | Phase 3 |
Active Resolves Gap: WI-2108
FTDTRecord and related entities own their own behavior (CalculateLimits(), IsValid(), etc.). FTDT is the core product, targeted as a shared library.ALPAMobile.FTDT.Domain).ALPAMobile/BusinessLogic/FTDTCalculator_USA.cs — migrate as rich domain behaviorALPAMobile/BusinessLogic/FTDTCalculator_CAN.cs — sameALPAMobile/BusinessLogic/FTDTCalculator_Shared.cs — sameALPAMobile/BusinessLogic/FTDTValidator.cs — sameModels/ — identify which are domain entities vs. DTOs vs. API response modelsMicrosoft.Maui, Preferences, Shell, or any service[JsonProperty] or serialization attributes on Domain entitiesNew Resolves Gaps: WI-2105 (partial), WI-2111, WI-2112
| Batch | Feature Area | Notes |
|---|---|---|
| 1 | Auth / Login / Session | BasePageViewModel first — all others inherit from it. Wires INavigationService, ISettingsService. |
| 2 | My Pilot Group — MEC / LEC | Actively undergoing major ViewModel refactoring. Coordinate with UI Refresh intersection. |
| 3 | Flight Data / FTDT + Jumpseat / PilotComms | Follows Phase 2 Domain extraction. FTDT is core product. |
| 4 | Navigation / UI / Remaining | Shell nav, flyout, menus, banners, misc ViewModels. Final Shell.Current cleanup. |
INavigationService (Application) — wraps Shell.Current navigation methodsISettingsService (Application) — user preferences that survive logoutIUserAppDataService (Application) — runtime user app state, cleared on logoutIDevDiagnosticsService (Application) — diagnostic mode, DEBUG builds onlyIDeviceTokenStore (Infrastructure) — Firebase/APNS tokensIInstallationService (Infrastructure) — installation keyNew Resolves Gap: WI-2109
| Target Service | Responsibility |
|---|---|
IAuthService / AuthService | Token management, refresh |
IFlightDataService / FlightDataService | FTDT-specific API calls |
IJumpseatService / JumpseatService | Jumpseat API |
IPilotCommsService / PilotCommsService | PilotComms API |
IMobileMenuService / MobileMenuService | Mobile menu API |
ILocalStorageService / LiteDbStorageService | LiteDB operations |
ICacheService / MemoryCacheService | In-memory caching |
IPushNotificationService / PushNotificationService | Push token registration |
New Resolves Gaps: WI-2106, WI-2107
This phase is a prerequisite for the UI Refresh (new component library + design system will be built on this clean surface).
new Command() across ViewModels → migrate to [RelayCommand] source-generated or explicit RelayCommand / AsyncRelayCommandALPAMobile/Helpers/BindableBase.cs → migrate all ViewModels to ObservableObject from CommunityToolkit.MvvmNew Resolves Gap: WI-2105 (final closure)
Consolidate ALL DI registration into MauiProgram.cs. Remove ALL remaining service locator patterns.
builder.Services.AddDomainServices();
builder.Services.AddApplicationServices();
builder.Services.AddInfrastructureServices(builder.Configuration);
builder.Services.AddPresentationServices();
New Resolves Gap: WI-2110
Validation infrastructure target:
// Application layer
public interface IValidationRule<T> { bool Check(T value); string ValidationMessage { get; } }
public class ValidatableObject<T> : ObservableObject { ... } // INotifyDataErrorInfo
New
| Layer | Coverage Target | Approach |
|---|---|---|
| Domain | 90%+ | Pure logic, no mocks needed |
| Application | 80%+ | Mock Infrastructure interfaces |
| Infrastructure | 60%+ | Integration tests, not unit |
| Presentation/VMs | 70%+ | Mock Application interfaces |
Tooling: NUnit 4.x + NSubstitute + Coverlet (unit) / NUnit 4.x + Appium v8 (UI) / NetArchTest.Rules (architecture)
Action required: Add NSubstitute NuGet reference to UnitTest.csproj
Phase 0 ✅ → Phase 1 ✅ → Phase 2 → Phase 3 → Phase 4
↓ ↓
Phase 5 Phase 6
↓
Phase 7
↓
Phase 8
Critical path: Phase 3 (Application/DI) unlocks Phase 5 (Presentation) and Phase 6 (Composition Root). Phase 2 (Domain) can partially run in parallel with Phase 3.
UI Refresh intersection: Phase 5 is the gateway. The new component library / design system work should NOT begin until Phase 5 is complete.
DotNet10feat: extract INavigationService and wire DI AB#2085 AB#2111imp/blazor-hybrid branch always (was DotNet10 when this plan was written)| WI | Title | State | Phase |
|---|---|---|---|
| 2081 | N-Tier Architecture Refactor — Foundation for Testability (Epic) | New | — |
| 2082 | Phase 0 — Guardrails & Architecture Tests | ✅ Resolved | 0 |
| 2083 | Phase 1 — Layer Projects Scaffolding | ✅ Resolved | 1 |
| 2084 | Phase 2 — Domain Extraction | Active | 2 |
| 2085 | Phase 3 — Application Layer & Interface Extraction | New | 3 |
| 2086 | Phase 4 — Infrastructure Layer | New | 4 |
| 2087 | Phase 5 — Presentation Extraction | New | 5 |
| 2088 | Phase 6 — Composition Root Cleanup | New | 6 |
| 2089 | Phase 7 — SOLID Hardening | New | 7 |
| 2090 | Phase 8 — Test Coverage Strategy | New | 8 |
| 2105 | GAP-1: Replace Service Locator (280+ hits) | Active | Ph3+6 |
| 2106 | GAP-2: Modernize 204 new Command() usages | Active | Ph5 |
| 2107 | GAP-3: Replace BindableBase with ObservableObject | Active | Ph5 |
| 2108 | GAP-4: Move FTDTCalculator/Validator to Domain | Active | Ph2 |
| 2109 | GAP-5: Break up DataManager (2813L) + RestService (2048L) | Active | Ph4 |
| 2110 | GAP-6: IValidationRule<T> / per-property validation | Active | Ph7 |
| 2111 | GAP-7: INavigationService (decouple from Shell.Current) | Active | Ph3 |
| 2112 | GAP-8: ISettingsService interface from AppProperties | Active | Ph3 |
Analysis confirmed: AppProperties is NOT a settings class — it mixes three distinct concerns:
| Bucket | Interface Target | Storage |
|---|---|---|
| User-defined preferences (survive logout) | ISettingsService | Preferences API |
| Runtime user app state (cleared on logout) | IUserAppDataService | LiteDB |
| Diagnostic controls (DEBUG only) | IDevDiagnosticsService | Preferences API |
| Device push tokens | IDeviceTokenStore (Infrastructure) | SecureStorage |
| Installation key | IInstallationService (Infrastructure) | Preferences API |
| Auth tokens (already handled) | ITokenStore (already exists) | SecureStorage |
Sequencing note: IUserAppDataService interface is defined in Phase 3, but its LiteDB-backed implementation requires WI-2109 (Phase 4) to be complete first.