Skip to main content

Plugin Architecture

Understanding how DebaterHub plugins work.

Overview

┌─────────────────────────────────────────────────────────────┐
│ Dashboard Shell │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Feed │ │ Write │ │ Detail │ Shells │
│ │ Shell │ │ Shell │ │ Shell │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ JobCard │ │ AcademicEd │ │ JobDetail │ Plugin │
│ │ LibCard │ │ │ │ LibDetail │ Comps │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘

Backend API

┌────────────┴────────────┐
│ │
PluginRepository Plugin Handlers
(Weaviate) (Python)

Key Concepts

1. Plugin Manifest

Every plugin starts with a manifest.ts that defines:

// apps/front/plugins/my-plugin/manifest.ts
import type { PluginManifest } from '@/lib/plugins/types';

export const manifest: PluginManifest = {
id: 'my-plugin',
name: 'My Plugin',
description: 'What my plugin does',
icon: 'Star',
version: '1.0.0',
author: 'Your Name',

// Navigation entry
nav: {
label: 'My Plugin',
icon: 'Star',
views: [
{ id: 'feed', label: 'Items', path: '/feed?plugin=my-plugin.feed' },
],
},

// Shell configurations
shells: {
feed: {
callable: 'list_items', // Backend handler to call
card: 'ItemCard', // Component to render each item
detail: 'ItemDetail', // Component for detail view
filters: ['status', 'date'],
},
},

// Dashboard widget (optional)
widget: {
component: 'MyWidget',
defaultSize: 'medium',
},
};

2. Shells

Shells are pre-built UI containers that host your components:

ShellPurposeComponents You Provide
feedList/grid of itemsCard, Detail
writeEditor viewCustom editor component
detailFull-page detailDetail component

The shell handles:

  • Data fetching (calls your backend handler)
  • Pagination
  • Filtering
  • Loading states
  • Error handling

3. Backend Handlers

Handlers are Python functions that process data:

# packages/plugins/installed/my-plugin/handler.py

from services.weaviate.plugin_repository import PluginRepository

repo = PluginRepository()

def list_items(user_id: str, filters: dict = None) -> list:
"""Called by the feed shell to get items."""
return repo.list_by_user(
plugin_id="my-plugin",
user_id=user_id,
data_type="item",
filters=filters,
)

def get_item(user_id: str, item_id: str) -> dict:
"""Called by the detail shell to get a single item."""
return repo.get(
plugin_id="my-plugin",
item_id=item_id,
)

4. PluginData Storage

All plugin data is stored in a generic Weaviate collection:

# PluginData schema
{
"id": "uuid",
"plugin_id": "my-plugin",
"user_id": "user-uuid",
"data_type": "item", # Your custom type
"content": { # Your custom data
"title": "Example",
"description": "...",
},
"metadata": {
"created_at": "2024-01-01T00:00:00Z",
"status": "active",
},
"embedding": [...] # Auto-generated for search
}

File Structure

apps/front/plugins/my-plugin/
├── manifest.ts # Plugin definition
├── index.ts # Component exports
└── components/
├── ItemCard.tsx # Feed card component
├── ItemDetail.tsx # Detail view component
└── MyWidget.tsx # Dashboard widget

packages/plugins/installed/my-plugin/
├── __init__.py
├── handler.py # Backend handlers
└── models.py # Pydantic models (optional)

Component Props

Card Component

interface CardProps {
item: PluginData;
onClick: () => void;
}

export function ItemCard({ item, onClick }: CardProps) {
return (
<div onClick={onClick}>
<h3>{item.content.title}</h3>
<p>{item.content.description}</p>
</div>
);
}

Detail Component

interface DetailProps {
item: PluginData;
onClose: () => void;
onUpdate: (data: Partial<PluginData>) => void;
}

export function ItemDetail({ item, onClose, onUpdate }: DetailProps) {
// Full detail view with edit capabilities
}

Next Steps