Add plugin platform with modular backend and frontend registry.

Split graph/import/meta into Django apps, add API v1 with OpenAPI and pytest, and introduce plugin registry with the tags reference plugin on both FE and BE.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-25 09:35:51 +03:00
co-authored by Cursor
parent b694a596b8
commit cafc7335ad
77 changed files with 1801 additions and 490 deletions
+1
View File
@@ -0,0 +1 @@
+9
View File
@@ -0,0 +1,9 @@
from django.apps import AppConfig
class PluginsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'plugins'
def ready(self):
import plugins.registry # noqa: F401
+48
View File
@@ -0,0 +1,48 @@
"""Plugin platform base classes and registry."""
from abc import ABC, abstractmethod
from typing import List
from django.conf import settings
from django.urls import URLPattern
class Plugin(ABC):
id: str = ''
version: str = '1.0.0'
min_core_version: str = '1.0.0'
permissions: List[str] = []
@abstractmethod
def urlpatterns(self) -> List[URLPattern]:
pass
def installed_apps(self) -> List[str]:
return []
_REGISTRY: dict[str, Plugin] = {}
def register_plugin(plugin: Plugin) -> None:
_REGISTRY[plugin.id] = plugin
def get_plugin(plugin_id: str) -> Plugin | None:
return _REGISTRY.get(plugin_id)
def get_enabled_plugins() -> List[Plugin]:
enabled = getattr(settings, 'ENABLED_PLUGINS', [])
return [_REGISTRY[pid] for pid in enabled if pid in _REGISTRY]
def plugin_urlpatterns() -> List[URLPattern]:
from django.urls import path, include
patterns: List[URLPattern] = []
for plugin in get_enabled_plugins():
patterns.append(
path(f'plugins/{plugin.id}/', include((plugin.urlpatterns(), plugin.id)))
)
return patterns
+6
View File
@@ -0,0 +1,6 @@
"""Register built-in plugins."""
from plugins.base import register_plugin
from plugins_tags.plugin import TagsPlugin
register_plugin(TagsPlugin())
+9
View File
@@ -0,0 +1,9 @@
from django.urls import path
from . import views
from .base import plugin_urlpatterns
urlpatterns = [
path('plugins/', views.plugin_manifest, name='plugin-manifest'),
*plugin_urlpatterns(),
]
+19
View File
@@ -0,0 +1,19 @@
from django.urls import path
from rest_framework.decorators import api_view
from rest_framework.response import Response
from plugins.base import get_enabled_plugins
@api_view(['GET'])
def plugin_manifest(request):
"""List enabled plugins and their metadata."""
return Response([
{
'id': p.id,
'version': p.version,
'min_core_version': p.min_core_version,
'permissions': p.permissions,
}
for p in get_enabled_plugins()
])