Skip to content

[Architecture] プラグインシステムの導入(サーバーサイド拡張ポイント + 独自APIルート) #692

Description

@hmjn023

概要

solid-imager にプラグインシステムを導入する。サーバーサイドの拡張ポイント(job handler / イベントフック / サービス差し替え / storage・import provider)と、プラグイン独自の oRPC API ルート公開を可能にする。

方針(決定済み)

  • 対象範囲: サーバーサイド + APIルート(UI拡張は対象外・将来的な Phase 3)
  • 信頼モデル: ローカル/自作プラグインのみ(サンドボックスなし、capabilities 宣言は将来用にスキーマだけ確保)
  • 反映方法: サーバー再起動でロード(ホットリロード不要)

現状の継ぎ目(seam)調査結果

領域 現状 結合度
Jobディスパッチ processJob が string の if/else 鎖 (apps/server/src/infrastructure/services/job-dispatch-service.ts:36-79)。Job.type は自由文字列 低コストで registry 化可能
サービス登録 ServiceRegistry は手書きの register/get 17スロット + bootstrap.ts が composition root 汎用化可能
ストレージドライバ MediaSourceDriver IF あり、factory が switch (infrastructure/storage/factory.ts:21-31)。s3/sftp 宣言のみ ドライバ登録所の出番
AI IAiClient 単一スロット (core/domain/interfaces/ai-client.ts) 差し替えポイント
イベント RealtimeEventBus の subscribe は完全オープン そのままフック可能
取り込み 3経路が MediaProcessingService.registerAndProcess (application ポート) に集約 importer の委譲先として自然
API appContract / appRouter は静的オブジェクト (contract/index.ts:45-64) 動的追加は要設計

設計

パッケージ構成

plugins/<id>/                     # プラグイン置き場(デフォルト、設定で変更可)
  plugin.json                     # マニフェスト: id, version, entry, capabilities
  index.ts                        # definePlugin({...}) を default export

packages/core/src/domain/plugins/schemas.ts   # マニフェスト/寄稿の Zod スキーマ (SDD)
packages/plugin-sdk/              # 新パッケージ(依存は core + @orpc/contract 型のみ)
apps/server/src/infrastructure/plugins/       # PluginManager / Context / Registry

プラグインが寄稿できるもの(definePlugin のフィールド)

フィールド 内容 実装の土台
jobHandlers { [jobType]: handler } + プール種別 job dispatch の if/else を registry 化
hooks onMediaRegistered / onImportCompleted / onJobEvent RealtimeEventBus subscribe + DeferredActions 拡張
services IAiClient / IImageProcessor 等の置き換え ServiceRegistry をトークンベース汎用化
sourceDrivers MediaSourceDriver 実装(s3/sftp 等) factory の switch を registry 化
importers ファイル+メタデータを registerAndProcess へ委譲 既存集約ポイントを利用
contract + router 独自の oRPC 手続き(oc で定義) 起動時に plugins.<pluginId>.* 名前空間へ合成

起動シーケンス

  1. bootstrap.ts で設定(plugins.dir)からディレクトリをスキャン
  2. マニフェストを Zod 検証 → import() でロード → activate(ctx) を呼ぶ
  3. 寄稿を各種 registry に登録(job handler / driver / hook)
  4. contract 寄稿を集約し、appContract とマージしてから implement()app-router.ts は静的部分 + プラグイン部分の合成に変更
  5. ロード失敗したプラグインはログ出力してスキップ(サーバーは起動継続)
  6. PluginManager は globalThis 保持で HMR 耐性(既存パターン踏襲)

プラグインに渡す PluginContext(ファサード)

  • logger(ILogger)
  • configplugins.<id>.* 名前空間のみ)
  • jobs.enqueue
  • events.publish(名前空間付き)
  • storage(下記 KV テーブル)
  • services(上級者用の生アクセス、ローカル信頼なので許可)

DB(plugins ドメイン追加)

  • plugins テーブル: UUID v4, id 一意, manifest jsonb, enabled, config jsonb
  • plugin_storage テーブル: plugin_id + key の KV(プラグインごとのスキーマ変更を不要にする)

実装ステップ

  • 1. job dispatch の registry 化(挙動不変リファクタ + テスト)— 全工程の地盤
  • 2. service-registry.ts トークンベース汎用化(既存型付き getter はラッパー維持)
  • 3. packages/core/src/domain/plugins/ にマニフェストスキーマ、packages/plugin-sdk 新規作成
  • 4. PluginManager + PluginContext + bootstrap 組み込み + 設定スキーマ
  • 5. DB 2 テーブル + リポジトリ(mapper 明示ルール準拠)
  • 6. app-router.ts の動的合成対応 + OpenAPI 反映
  • 7. リファレンスプラグイン 1 個(例: job イベントを webhook 通知 + 独自 API ルート公開)
  • 8. 検証: bun run check / bun run test

割り切り・留意事項

  • プラグインの API は静的 AppContract 型に含まれないため、Tauri/CLI の型付きクライアントからは直接呼べない(プラグイン SDK が独自の contract 型を輸出する形)。ローカル用途なら許容。
  • サンドボックスなし(ローカル信頼モデル)。
  • UI 拡張(Tauri SPA へのパネル/アクション contribution)は Phase 3 として別途 issue 化。

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestinfraインフラ・DB基盤

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions