Skip to main content

Module system

Purpose

Explain how Mnemo discovers and loads feature modules: routes, sidebar entries, DI, translations, AI tools, widgets, and keybind manifests—without hard-coding every feature in one startup file.

Code location

  • Contract: Mnemo.Core/Services/IModule.cs
  • Discovery + orchestration: Mnemo.UI/Services/Bootstrapper.cs (DiscoverModules, module loops)
  • Implementations: Mnemo.UI/Modules/**/*.cs (e.g. NotesModule, MindmapModule, CoreUIModule)

Key concepts

ConceptMeaning
Module contractIModule — feature package entry point
Auto-discoveryReflection scan for assignable types in loaded Mnemo.* assemblies
DI registrationConfigureServices(IServiceRegistrar) adds VMs/services
Navigation integrationRegisterRoutes(INavigationRegistry) maps route keys → view model types
Sidebar integrationRegisterSidebarItems(ISidebarService) supplies icons, order, grouping
AI tools / widgetsRegisterTools, RegisterWidgets after IServiceProvider exists

Main interfaces / classes

// Mnemo.Core/Services/IModule.cs (conceptual summary)
public interface IModule
{
void ConfigureServices(IServiceRegistrar services);
void RegisterTranslationSources(ITranslationSourceRegistry registry);
void RegisterRoutes(INavigationRegistry registry);
void RegisterSidebarItems(ISidebarService sidebarService);
void RegisterTools(IFunctionRegistry registry, IServiceProvider services);
void RegisterWidgets(IWidgetRegistry registry, IServiceProvider services);
void RegisterKeybindManifest(IKeybindManifestRegistry registry);
}

Reference implementation pattern: Mnemo.UI/Modules/Notes/NotesModule.cs.

Lifecycle

  1. App starts → Bootstrapper.Build().
  2. Core/Infrastructure/UI shell services register.
  3. DiscoverModules() collects IModule instances.
  4. RegisterTranslationSources → localization provider registers.
  5. ConfigureServices for each module → VMs/providers available at resolve time.
  6. RegisterKeybindManifest aggregates chords.
  7. BuildServiceProvider().
  8. RegisterRoutes, RegisterSidebarItems, RegisterTools, RegisterWidgets.
  9. UI shows MainWindow; NavigationService drives workspace VM from route IDs.

Adding a new module

  1. Create Mnemo.UI/Modules/YourFeature/YourFeatureModule.cs implementing IModule (public class, parameterless ctor).
  2. ConfigureServices: AddTransient for view models; register ISearchProvider or other interfaces if the feature participates in global search.
  3. RegisterTranslationSources: embed JSON resources if localized strings live with the module (see NotesModule).
  4. RegisterRoutes: registry.RegisterRoute("your-route", typeof(YourViewModel)) — key must stay stable for deep links and navigation statistics.
  5. RegisterSidebarItems: supply localized title key, route id, avares:// icon path, section name, sort order.
  6. RegisterTools: optional—delegate to a registrar class pattern (NotesToolRegistrar) to keep module lean.
  7. RegisterWidgets: optional dashboard tiles.
  8. RegisterKeybindManifest: optional static chord declarations for user-editable binds.
  9. Build—discovery picks up any new IModule in Mnemo.UI assembly automatically.

Gotchas

  • Silent ctor failures: exceptions inside Activator.CreateInstance are swallowed during discovery—your module simply never loads.
  • Order: route IDs must not collide; last registration wins depends on registry implementation—avoid duplicate keys.
  • Sidebar vs routes: mismatch between sidebar route argument and RegisterRoute key breaks navigation clicks.
  • Plugins: comment in DiscoverModules mentions loading plugin assemblies into AppDomain before scan—external modules must be loaded early enough to appear in assembly set.

Related: Startup flow, UI