Overview
Codapult ships with a plugin system that lets you extend the platform without modifying core code. Plugins can add sidebar navigation, settings panels, API routes, and react to lifecycle events.
All plugins implement the CodapultPlugin interface from src/lib/plugins/types and are registered in codapult.plugins.ts.
Extension Points
| Extension | Description |
|---|---|
navItems | Adds items to the dashboard sidebar (icon, label, href, sort order) |
settingsPanels | Adds tabs to the settings page (lazy-loaded React component) |
apiRoutes | Mounts API routes at /api/plugins/<name>/ (GET, POST, PUT, PATCH, DELETE) |
onInit | One-time setup hook, called when the plugin is first loaded |
onUserCreated | Fired after a new user registers |
onUserDeleted | Fired after a user is deleted |
onSubscriptionChanged | Fired when a subscription status changes |
onPaymentCompleted | Fired when a one-time payment completes |
Creating a Plugin
Step 1: Create the Plugin Directory
mkdir -p plugins/my-plugin/components
Plugin names must be kebab-case and match the directory name.
Step 2: Implement the Interface
Create plugins/my-plugin/index.ts:
import type { CodapultPlugin } from '@/lib/plugins/types';
const myPlugin: CodapultPlugin = {
name: 'my-plugin',
version: '1.0.0',
description: 'Adds custom analytics to the dashboard',
navItems: [
{
id: 'my-analytics',
label: 'My Analytics',
href: '/dashboard/my-analytics',
icon: 'BarChart3',
order: 50,
},
],
settingsPanels: [
{
id: 'my-plugin-settings',
label: 'My Plugin',
component: './components/Settings',
order: 100,
},
],
apiRoutes: [
{
method: 'GET',
path: '/stats',
handler: async (req) => {
return new Response(JSON.stringify({ visits: 42 }), {
headers: { 'Content-Type': 'application/json' },
});
},
},
],
async onInit() {
console.log('My plugin initialized');
},
async onUserCreated({ user }) {
console.log(`New user: ${user.email}`);
},
async onSubscriptionChanged({ userId, plan, status }) {
console.log(`Subscription changed: ${userId} → ${plan} (${status})`);
},
async onPaymentCompleted({ userId, amount, currency }) {
console.log(`Payment received: ${amount} ${currency} from ${userId}`);
},
};
export default myPlugin;
Step 3: Register the Plugin
Add your plugin to codapult.plugins.ts:
import { registerPlugin } from '@/lib/plugins';
import myPlugin from './plugins/my-plugin';
registerPlugin(myPlugin);
The plugin's nav items, settings panels, and API routes are now live. API routes are accessible at /api/plugins/my-plugin/stats.
Bundled Example
Codapult includes a reference plugin at plugins/example-analytics/ that demonstrates all extension points. Use it as a starting point for your own plugins.
Plugin Rules
- Plugin name must be kebab-case and match the directory name.
- API routes are automatically prefixed with
/api/plugins/<name>/. - Never import plugin code from core — plugins depend on core, not the other way around.
- Handle errors in hooks — the registry wraps
onInitin try/catch, but lifecycle hooks should handle their own errors gracefully. - Settings panels are lazy-loaded — the
componentpath is resolved relative to the plugin directory.
Testing Plugins
Co-locate unit tests with your plugin code:
plugins/my-plugin/
├── index.ts
├── index.test.ts ← test the plugin
└── components/
└── Settings.tsx
Test lifecycle hooks and API route handlers in isolation using Vitest. Mock core dependencies (db, getAppSession) as needed. The dev server picks up plugin changes on reload — no restart required.
Upgrading Codapult with Plugins Installed
When upgrading Codapult to a new version, premium plugin schema patches may need re-applying. After merging the upstream update, run:
npx @codapult/cli plugins migrate
This re-checks all installed plugins against the current schema.ts and generates any needed migration files.
Premium Plugins
Four premium plugins are available separately. Each adds a full-featured module with its own UI, API routes, database tables, and AI capabilities. See the dedicated documentation for each plugin:
| Plugin | Package | Description | Docs |
|---|---|---|---|
| AI Starter Kit | @codapult/plugin-ai-kit | AI gateway, prompt management, tool framework, guardrails | AI Kit → |
| CRM | @codapult/plugin-crm | Companies, contacts, deals pipeline, AI lead scoring | CRM → |
| Helpdesk | @codapult/plugin-helpdesk | AI-native support tickets, SLA policies, auto-resolve via RAG | Helpdesk → |
| Email Marketing | @codapult/plugin-email-marketing | Subscriber lists, segmentation, broadcast campaigns, AI content | Email Marketing → |
Installation
Install any premium plugin via the Codapult CLI:
npx @codapult/cli plugins add @codapult/plugin-ai-kit
Each plugin ships with its own README.md and INSTALL.md containing step-by-step installation instructions, required environment variables, and database migration commands.
Updating
When a plugin releases a new version with schema changes, update the package and run migrations:
pnpm update @codapult/plugin-ai-kit
npx @codapult/cli plugins migrate ai-kit
The migrate command compares the plugin's latest schema with what's currently in your schema.ts, patches the difference, and generates a migration file via drizzle-kit. You can then review and apply the migration. Use --push for development (calls db:push directly).
To migrate all installed plugins at once:
npx @codapult/cli plugins migrate
Removal
Remove a premium plugin with:
npx @codapult/cli plugins remove @codapult/plugin-ai-kit
The CLI removes the plugin's files, unregisters it from codapult.plugins.ts, and cleans up database tables.