This repository contains the plugin marketplace for VerifyWise, including plugin registry, implementations, and documentation for building new plugins.
| Document | Description |
|---|---|
| Plugin Development Guide | Complete guide to building plugins |
| Framework Plugins Guide | Compliance framework plugin guide |
| Plugin UI Guide | Building dynamic plugin UIs |
| Architecture Overview | System architecture and data flow |
| API Reference | Plugin interface specifications |
plugin-marketplace/
βββ plugins.json # Plugin registry (marketplace manifest)
βββ package.json # Build scripts
βββ plugins/ # Plugin implementations
β βββ mlflow/ # MLflow integration plugin
β β βββ index.ts # Backend plugin code
β β βββ package.json # Backend dependencies
β β βββ README.md # Plugin documentation
β β βββ ui/ # Frontend UI components
β β βββ src/ # React components
β β βββ vite.config.ts
β β βββ package.json
β βββ azure-ai-foundry/ # Azure AI Foundry plugin
β βββ risk-import/ # Risk Import plugin
β βββ slack/ # Slack integration plugin
β β
β β # Framework plugins (compliance frameworks)
β βββ gdpr/ # GDPR framework
β β βββ template.json # Framework definition (chapters, sections)
β β βββ index.ts # Auto-generated from template
β β βββ dist/ # Compiled backend
β β βββ ui/dist/ # Shared UI bundle (copied from packages/)
β βββ soc2/
β βββ hipaa/
β βββ ... # 18 framework plugins total
β
βββ packages/ # Shared packages
β βββ custom-framework-ui/ # Shared UI for all framework plugins
β β βββ src/ # React components
β β βββ dist/ # Compiled bundle (index.esm.js)
β β βββ vite.config.ts
β βββ custom-framework-base/ # Shared backend for framework plugins
β
βββ scripts/ # Build scripts
β βββ build-framework-plugins.js # Builds all framework plugins
β βββ add-framework.js # Helper to add new frameworks
β
βββ docs/ # Documentation
β βββ PLUGIN_DEVELOPMENT_GUIDE.md
β βββ PLUGIN_UI_GUIDE.md
β βββ ARCHITECTURE.md
β βββ API_REFERENCE.md
βββ README.md # This file
mkdir -p plugins/my-plugin/ui/src// Types for plugin routing
interface PluginRouteContext {
tenantId: string;
userId: number;
organizationId: number;
method: string;
path: string;
params: Record<string, string>;
query: Record<string, any>;
body: any;
sequelize: any;
configuration: Record<string, any>;
}
interface PluginRouteResponse {
status?: number;
data?: any;
buffer?: any; // For binary data (files)
filename?: string;
contentType?: string;
headers?: Record<string, string>;
}
// Required exports
export async function install(userId: number, tenantId: string, config: any, context: any) {
// Create tables, initialize resources
return { success: true, message: "Installed", installedAt: new Date().toISOString() };
}
export async function uninstall(userId: number, tenantId: string, context: any) {
// Clean up tables, resources
return { success: true, message: "Uninstalled", uninstalledAt: new Date().toISOString() };
}
export function validateConfig(config: any) {
// Validate configuration
return { valid: true, errors: [] };
}
export const metadata = {
name: "My Plugin",
version: "1.0.0",
author: "Your Name",
description: "Plugin description"
};
// Plugin Router - Define custom API endpoints
export const router: Record<string, (ctx: PluginRouteContext) => Promise<PluginRouteResponse>> = {
"GET /items": async (ctx) => {
// Handle GET /api/plugins/my-plugin/items
return { data: { items: [] } };
},
"POST /items": async (ctx) => {
// Handle POST /api/plugins/my-plugin/items
return { status: 201, data: { created: true } };
},
"GET /items/:itemId": async (ctx) => {
// ctx.params.itemId contains the URL parameter
return { data: { id: ctx.params.itemId } };
},
};{
"key": "my-plugin",
"name": "My Plugin",
"displayName": "My Plugin",
"description": "Short description",
"version": "1.0.0",
"category": "data_management",
"pluginPath": "plugins/my-plugin",
"entryPoint": "index.ts",
"requiresConfiguration": true,
"ui": {
"bundleUrl": "/api/plugins/my-plugin/ui/dist/index.esm.js",
"globalName": "PluginMyPlugin",
"slots": [...]
}
}cd plugins/my-plugin/ui
npm install
npm run buildSee Plugin Development Guide for complete instructions.
| Type | Description | Example |
|---|---|---|
| Standard | Simple plugins without database tables | Slack |
| Tenant-Scoped | Plugins with per-tenant database tables | MLflow, Risk Import |
| OAuth | Plugins requiring OAuth authentication | Slack |
Plugins can define custom API endpoints via the router export. All requests to /api/plugins/:pluginKey/* are automatically forwarded to the plugin's router.
Routes are defined as "METHOD /path" keys:
export const router = {
"GET /models": handleGetModels, // GET /api/plugins/my-plugin/models
"POST /sync": handleSync, // POST /api/plugins/my-plugin/sync
"GET /models/:modelId": handleGetModel, // GET /api/plugins/my-plugin/models/123
"DELETE /items/:id": handleDelete, // DELETE /api/plugins/my-plugin/items/456
};Each handler receives a PluginRouteContext with:
| Property | Type | Description |
|---|---|---|
tenantId |
string | Current tenant identifier |
userId |
number | Authenticated user ID |
organizationId |
number | User's organization ID |
method |
string | HTTP method (GET, POST, etc.) |
path |
string | Request path after plugin key |
params |
object | URL parameters (e.g., :modelId) |
query |
object | Query string parameters |
body |
any | Request body (for POST/PUT/PATCH) |
sequelize |
any | Database connection |
configuration |
object | Plugin's stored configuration |
Handlers return a PluginRouteResponse:
// JSON response
return { data: { items: [...] } };
// Custom status code
return { status: 201, data: { created: true } };
// File download
return {
buffer: fileBuffer,
filename: "export.xlsx",
contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
};
// Custom headers
return { data: {...}, headers: { "X-Custom": "value" } };Plugins can inject UI at these locations:
| Slot ID | Location | Render Types |
|---|---|---|
page.risks.actions |
Risk Management "Insert From" menu | menuitem, modal |
page.models.tabs |
Model Inventory tabs | tab |
page.plugin.config |
Plugin configuration panel | card, inline |
page.settings.tabs |
Settings page tabs | tab |
modal.framework.selection |
Add Framework modal | card |
page.framework-dashboard.custom |
Organizational Framework Dashboard | card |
page.controls.custom-framework |
Organizational Controls tab | card |
page.project-controls.custom-framework |
Project Controls tab | card |
page.dashboard.widgets |
Dashboard (future) | widget |
layout.sidebar.items |
Sidebar (future) | menuitem |
VerifyWise reads from local plugins.json and plugins/ directory.
VerifyWise fetches from remote Git repository:
PLUGIN_MARKETPLACE_URL=https://raw.githubusercontent.com/org/plugin-marketplace/main/plugins.json| Plugin | Category | Description |
|---|---|---|
| Slack | Communication | Real-time notifications via Slack |
| MLflow | ML Operations | ML model tracking and sync |
| Azure AI Foundry | ML Operations | Azure ML model tracking and sync |
| Risk Import | Data Management | Bulk import risks from Excel |
Framework plugins provide compliance frameworks grouped by geographic region. All framework plugins share a common UI bundle from packages/custom-framework-ui/.
| Region | Frameworks |
|---|---|
| π International | ISO 27001, PCI-DSS, CIS Controls v8, AI Ethics, Data Governance, OECD AI Principles |
| πΊπΈ United States | SOC 2 Type II, HIPAA, CCPA, NIST CSF, Texas AI Act, Colorado AI Act, FTC AI Guidelines, NYC Local Law 144 |
| π¨π¦ Canada | Quebec Law 25 |
| πͺπΊ European Union | GDPR, DORA, ALTAI |
| π¦πͺ United Arab Emirates | UAE PDPL |
| πΈπ¦ Saudi Arabia | Saudi PDPL |
| πΆπ¦ Qatar | Qatar PDPL |
| π§π Bahrain | Bahrain PDPL |
# Build shared UI (if UI code changed)
npm run build:custom-framework-ui
# Build all framework plugins (compiles backend + copies UI bundle)
npm run build:framework-plugins
# Or build everything at once
npm run build:allThe build script:
- Auto-discovers framework plugins by looking for
template.jsonfiles - Generates
index.tsfrom eachtemplate.json - Compiles backend to
dist/index.js - Copies shared UI from
packages/custom-framework-ui/dist/to each plugin'sui/dist/
- Create
plugins/<framework-key>/template.jsonwith framework definition - Run
npm run build:framework-plugins - Add entry to
plugins.json - Commit and push (including
ui/dist/folder)
See Framework Plugins Guide for details.
{
"key": "gdpr",
"name": "GDPR Compliance",
"category": "compliance",
"region": "European Union",
"iconUrl": "plugins/gdpr/icon.svg",
...
}Key fields for framework plugins:
category: Must be"compliance"or have compliance/framework tagsregion: Geographic region (displayed with flag in UI)iconUrl: Local SVG icon path
Plugins can communicate with the main app using custom DOM events for decoupled integration:
// Plugin emits event
window.dispatchEvent(
new CustomEvent("myPluginEvent", {
detail: { projectId: 123, data: {...} }
})
);
// App listens (in React component)
useEffect(() => {
const handler = (event: CustomEvent) => {
if (event.detail?.projectId === project.id) {
// Handle event
}
};
window.addEventListener("myPluginEvent", handler);
return () => window.removeEventListener("myPluginEvent", handler);
}, [project.id]);- Use camelCase:
customFrameworkCountChanged - Include context:
projectId,userId, etc. - Be descriptive:
Changed,Added,Removed
See Custom Framework Import README for a complete example.
- Fork this repository
- Create plugin in
plugins/directory - Add entry to
plugins.json - Submit pull request
See Plugin Development Guide for detailed instructions.
MIT License - See LICENSE file for details.