Documentation Index
Fetch the complete documentation index at: https://grantmaster.dev/llms.txt
Use this file to discover all available pages before exploring further.
Extension Development Guide
This guide covers everything you need to build, test, and ship a GrantMaster extension.Quick Start
/<your-extension>/dashboard to see your scaffolded page.
Architecture Overview
Extensions are self-contained feature modules that register with the platform at activation time and cleanly deregister on deactivation. Each extension declares its capabilities in a manifest and provides components, services, and hooks in a standard directory structure.Directory Structure
Lifecycle
lifecycle.onActivate
On deactivate: call lifecycle.onDeactivate → unregister contributions → clean up subscriptions
Manifest Reference
The manifest is the single source of truth for your extension’s metadata, routing, and contribution declarations.Contribution Types
Extensions can contribute to 5 extension points. All contributions are declared inmanifest.contributions and automatically registered/unregistered during activation/deactivation.
1. Widgets
Dashboard widgets that appear in the widget grid.2. Commands
Command palette actions accessible viaCmd+K.
3. Event Handlers
Declare event subscriptions that the platform manages. Handler functions are resolved at activation time from the declared path. Each handler can subscribe to multiple event types.handlers/onGrantEvent.ts):
4. Settings Panels
Panels rendered in the Settings page when the extension is active.5. Agent Tools
AI agent tools that become available when the extension is active.Lifecycle Hooks
Lifecycle hooks let your extension execute code at key transitions. Declare them as relative paths (prefixed with./) in your manifest:
Extension API
Extensions should import from@/shared/extension-api rather than internal modules. This facade provides a stable contract.
Available Imports
Scoped Event Bus
UsecreateExtensionEventBus() instead of the raw eventBus singleton. This ensures subscriptions are tracked and cleaned up on deactivation:
Extension Base Service
ExtendExtensionBaseService<T> for Firestore operations. It enforces organization scoping and auto-includes extensionId in audit logs. The class is generic and uses abstract protected fields instead of constructor arguments:
Data Migrations
When upgrading an extension’s data schema, declare migrations in the manifest:fromVersion). If a migration fails, the extension is suspended.
Dependency Validation
Declare dependencies on other extensions:- On install: All required extensions must be active
- On deactivate: Cannot deactivate if other active extensions depend on you
- On uninstall: Cannot uninstall if other installed extensions depend on you
Error Handling
Route Error Boundaries
Every extension’s route group is wrapped in an<ErrorBoundary>. If your extension crashes:
- The error is caught — the app shell remains functional
- The error is reported to
ExtensionHealthService - After 3 crashes in 5 minutes, the extension is auto-suspended
- An
EXTENSION_AUTO_DISABLEDevent is emitted
Best Practices
- Wrap risky operations in try/catch
- Use
ExtensionBaseService.withErrorBoundary()for service methods - Event handler failures are tracked — 5 consecutive throws auto-unsubscribes the handler
- Widget crashes show a placeholder, not a broken dashboard
Testing
Use the test harness atsrc/tests/utils/extensionTestHarness.ts:
Admin Monitoring
Extension health is visible in Configuration > Extensions (PlatformManagement). Admins can:- View active extensions and their contribution counts
- See per-extension EventBus metrics (emit counts, error counts)
- Monitor auto-disabled extensions and re-enable them
- Check health records and error history
Registered Extensions
The following extensions are registered inMANIFEST_LOADERS (as of this writing):
| Extension ID | Category |
|---|---|
impact | Impact measurement & M&E |
grant-calendar | Grant deadline tracking |
donor-wallet | Donor management |
virtual-giving-card | Giving cards |
corporate-csr-hub | Corporate social responsibility |
board-portal | Board management |
budget-forecaster | Budget analytics |
compliance-vault | Compliance document storage |
event-fundraiser | Event-based fundraising |
funder-crm | Funder relationship management |
grant-writer | AI-assisted grant writing |
volunteer-coordinator | Volunteer management |
Checklist
Before shipping your extension:- Manifest has all required fields (
id,name,version,basePath,routes) - Extension registered in
src/shared/platform/ExtensionRegistry.tsMANIFEST_LOADERS - Layout component renders
<Outlet />for child routes - Imports use
@/shared/extension-api(not@/core/*) - Event subscriptions use
createExtensionEventBus()(not raweventBus) - Services extend
ExtensionBaseService(notBaseService) - Data collections declared with appropriate
uninstallPolicy - Dependencies listed in
requiredModulesif applicable - Migrations declared for schema changes between versions
- Tests written using
extensionTestHarness - No TypeScript errors in extension files (
npx tsc --noEmit)