Plugin System Architecture
This document describes the architecture of the Talawa plugin system, including how plugins are loaded, managed, and integrated into the platform.
Overview
The Talawa plugin system is designed to be modular, extensible, and type-safe. It consists of two main parts:
- API Plugin System - Backend functionality (GraphQL, database, hooks)
- Admin Plugin System - Frontend components (pages, navigation, UI)
Core Architecture
Plugin Manager
The plugin manager is responsible for:
- Plugin Discovery: Scanning for available plugins
- Plugin Loading: Parsing manifests and loading components
- Plugin Activation: Registering extensions and initializing plugins
- Plugin Lifecycle: Managing plugin states (active, inactive, error)
- Error Handling: Graceful handling of plugin failures
Extension Points
The system provides specific extension points for different contexts:
Route Extensions
- RA1: Admin Global Routes - System-wide admin functionality
- RA2: Admin Organization Routes - Organization-specific admin features
- RU1: User Organization Routes - Organization-specific user features
- RU2: User Global Routes - System-wide user functionality
Drawer Extensions
- DA1: Admin Global Drawer - Menu items for global admins
- DA2: Admin Organization Drawer - Menu items for organization admins
- DU1: User Organization Drawer - Menu items for organization users
- DU2: User Global Drawer - Menu items for global users
Injector Extensions
- G1-G5: General Injectors - Code injection points for UI components
API Plugin System
GraphQL Extensions
The API plugin system uses a builder-first approach with Pothos GraphQL builder:
// Plugin manifest defines GraphQL extensions
{
"extensionPoints": {
"graphql": [
{
"type": "query",
"name": "myPluginQueries",
"file": "graphql/queries.ts",
"builderDefinition": "registerMyPluginQueries"
}
]
}
}
// Plugin implements builder functions
export function registerMyPluginQueries(builderInstance: typeof builder): void {
builderInstance.queryField("getMyData", (t) =>
t.field({
type: MyDataRef,
resolve: getMyDataResolver,
})
);
}
Database Extensions
Plugins can define database tables using Drizzle ORM:
// Plugin defines database schema
export const myPluginTable = pgTable("my_plugin_data", {
id: uuid("id").primaryKey().defaultRandom(),
name: text("name").notNull(),
createdAt: timestamp("created_at").defaultNow(),
});
// Plugin registers table in manifest
{
"extensionPoints": {
"database": [
{
"type": "table",
"name": "myPluginTable",
"file": "database/tables.ts"
}
]
}
}
Hook Extensions
Plugins can register event handlers for system events:
// Plugin defines hooks in manifest
{
"extensionPoints": {
"hooks": [
{
"type": "post",
"event": "plugin:activated",
"handler": "onPluginActivated"
}
]
}
}
// Plugin implements hook handlers
export async function onPluginActivated(context: IPluginContext): Promise<void> {
context.logger?.info("Plugin activated");
}
Plugin Lifecycle
API plugins follow a well-defined lifecycle:
- Loading: Plugin manifest is parsed and validated
- Initialization: Database tables and GraphQL schema are registered
- Activation: Plugin components are fully registered and available
- Runtime: Plugin serves requests and handles events
- Deactivation: Plugin components are unregistered
- Unloading: Plugin resources are cleaned up
Admin Plugin System
Route Extensions
Admin plugins can add new pages to the admin panel:
// Plugin defines routes in manifest
{
"extensionPoints": {
"RA1": [
{
"path": "/admin/my-plugin/dashboard",
"component": "MyPluginDashboard"
}
]
}
}
// Plugin implements React components
const MyPluginDashboard: React.FC = () => {
return <div>My Plugin Dashboard</div>;
};
Drawer Extensions
Plugins can add menu items to the navigation drawer:
// Plugin defines drawer items in manifest
{
"extensionPoints": {
"DA1": [
{
"label": "My Plugin",
"icon": "/src/assets/svgs/plugins.svg",
"path": "/admin/my-plugin/dashboard",
"order": 1
}
]
}
}
Injector Extensions
Plugins can inject code into existing components:
// Plugin defines injectors in manifest
{
"extensionPoints": {
"G1": [
{
"injector": "MyComponentInjector",
"description": "Inject custom component"
}
]
}
}
// Plugin implements injector components
const MyComponentInjector: React.FC = () => {
return <div>Injected Component</div>;
};
Plugin Context
Plugins receive a context object that provides access to system resources:
interface IPluginContext {
db: unknown; // Drizzle database instance
graphql: unknown; // GraphQL schema builder
pubsub: unknown; // PubSub instance
logger: ILogger; // Logger instance
pluginManager?: unknown; // Plugin manager instance
}
Type Safety
The plugin system is built with TypeScript for complete type safety:
Plugin Manifest Types
interface IPluginManifest {
name: string;
pluginId: string;
version: string;
description: string;
author: string;
main: string;
extensionPoints?: IExtensionPoints;
}
interface IExtensionPoints {
graphql?: IGraphQLExtension[];
database?: IDatabaseExtension[];
hooks?: IHookExtension[];
}
GraphQL Type Safety
Plugins use Pothos GraphQL builder for type-safe schema generation:
// Define GraphQL types
export const MyDataRef = builder.objectRef<{
id: string;
name: string;
}>("MyData");
MyDataRef.implement({
fields: (t) => ({
id: t.exposeID("id"),
name: t.exposeString("name"),
}),
});
Error Handling
The plugin system includes comprehensive error handling:
Plugin Loading Errors
- Invalid manifest files are rejected
- Missing dependencies are reported
- Type errors are caught during compilation
Runtime Errors
- GraphQL errors are properly formatted
- Database errors are logged and handled
- Plugin failures don't affect core system
Recovery Mechanisms
- Failed plugins are automatically deactivated
- Plugin errors are logged for debugging
- System continues to function even with plugin failures
Security
Plugin Isolation
- Plugins run in isolated contexts
- Plugin errors cannot crash the core system
- Plugin data is properly scoped
Permission System
- Plugins can define required permissions
- Access control is enforced at the GraphQL level
- User permissions are validated for all operations
Input Validation
- All plugin inputs are validated using Zod schemas
- GraphQL arguments are type-checked
- Database operations are parameterized
Performance
Lazy Loading
- Plugin components are loaded on demand
- GraphQL resolvers are registered only when needed
- Database tables are created only when plugins are activated
Caching
- Plugin manifests are cached after parsing
- GraphQL schema is built once and cached
- Database connections are reused
Optimization
- Plugin code is tree-shaken during build
- Unused plugin components are excluded
- GraphQL schema is optimized for performance
Development Workflow
Plugin Development
- Create Plugin Structure: Set up API and admin plugin directories
- Define Manifest: Create plugin manifest with extension points
- Implement Components: Build GraphQL, database, and UI components
- Test Locally: Use development mode for hot reloading
- Deploy: Install plugin in production environment
Plugin Management
- Installation: Plugin files are copied to the system
- Validation: Plugin manifest and dependencies are verified
- Activation: Plugin components are registered and initialized
- Monitoring: Plugin status and errors are tracked
- Updates: Plugin versions can be updated safely
Integration Points
Core System Integration
- GraphQL Schema: Plugins extend the main GraphQL schema
- Database: Plugins can create and manage database tables
- UI Components: Plugins can add pages and navigation items
- Event System: Plugins can listen to and emit system events
External Service Integration
- Payment Gateways: Plugins can integrate payment processors
- Analytics: Plugins can add tracking and analytics
- Third-party APIs: Plugins can connect to external services
- File Storage: Plugins can manage file uploads and storage
Monitoring and Debugging
Plugin Status
- Active plugins are tracked and displayed
- Plugin errors are logged and reported
- Plugin performance metrics are collected
Development Tools
- Plugin development mode with hot reloading
- GraphQL schema introspection for debugging
- Plugin testing utilities and frameworks
Production Monitoring
- Plugin health checks and status monitoring
- Error tracking and alerting
- Performance monitoring and optimization
This architecture provides a robust, extensible, and maintainable plugin system that allows organizations to customize Talawa to their specific needs while maintaining system stability and security.