# Phase 0：基础设施骨架

## 目标

建好管道，不改现有功能。验证编译通过 + API 可调用。

**不包含**：无 UI 变化、无真实插件注册、无设置面板。

---

## 文件清单与实施顺序

### Step 1：核心接口定义

**新建** `internal/plugin/plugin.go`

内容：PluginID、PluginSource、PluginMetadata、PluginCapability、Plugin 接口、TabProvider、FilePreviewHandler、PreviewInfo、TabDef、CoreServices 接口定义。

依赖：无

---

### Step 2：适配器（避免方法泄漏）

**新建** `internal/plugin/adapter.go`

内容：`adapter` 结构体实现 `CoreServices` 接口的 6 个方法。构造函数 `NewAdapter(app *App) CoreServices`。

关键设计：不在 App 上直接实现 CoreServices（会导致 6 个内部方法被 Wails v3 自动暴露为前端 API），而是通过独立 adapter 封装。

依赖：Step 1

---

### Step 3：Tab 注册表

**新建** `internal/plugin/tab_registry.go`

内容：
- `TabRegistry` struct（mu + entries map）
- Register（冲突检测）、GetByTabKey、GetAllDefinitions（按 Order 排序）、GetAllProviders、Count

依赖：Step 1

---

### Step 4：预览注册表

**新建** `internal/plugin/preview_registry.go`

内容：
- `PreviewRegistry` struct（mu + handlers 切片，按 priority 降序）
- Register（自动排序）、Resolve（遍历匹配第一个 canHandle）、GetAllHandlers、Count

依赖：Step 1

---

### Step 5：PluginManager

**新建** `internal/plugin/manager.go`

内容：
- `Manager` struct（plugins map + core + tabReg + previewReg + ctx + initialized）
- NewManager、Register（自动分发到子注册表 + 回滚）、InitAll、StartByTabKey
- GetPluginInfos、ResolvePreview（附加 PluginID 到响应）、GetTabDefinitions、Shutdown

依赖：Step 1 ~ 4 全部

---

### Step 6：前端类型定义

**新建** `frontend/src/plugin/types.ts`

内容：PluginCapability enum、PluginMetadata、TabPluginDefinition、FilePreviewHandlerDefinition、RenderConfig 接口。

依赖：无

---

### Step 7：前端注册中心

**新建** `frontend/src/plugin/registry.ts`

内容：
- Vue reactive state（tabPlugins Map + previewHandlers 数组）
- Tab API：registerTabPlugin / getTabComponent / getAllTabDefinitions / hasTabPlugin
- Preview API：registerPreviewHandler（按 priority 插入）/ resolvePreviewHandler / getAllPreviewHandlers
- 调试工具：getRegistryStats

依赖：Step 6

---

### Step 8：集成到 App

**修改** `app.go`

改动点：

1. **新增字段**：`pluginMgr *plugin.Manager`（在 `mu` 字段之后）
2. **ServiceStartup 中**（步骤 4 之后）：初始化 pluginMgr
   ```go
   fmt.Println("[启动] 初始化插件管理器...")
   a.pluginMgr = plugin.NewManager(plugin.NewAdapter(a))
   ```
3. **ServiceShutdown 末尾**：关闭 pluginMgr
   ```go
   if a.pluginMgr != nil { a.pluginMgr.Shutdown() }
   ```
4. **新增绑定方法**（Wails v3 自动暴露前端）：
   - `GetPluginInfos() ([]map[string]interface{}, error)` — 返回空数组或插件列表
   - `ResolvePreview(req ResolvePreviewRequest) (map[string]interface{}, error)` — 解析文件预览处理器
   - `ResolvePreviewRequest{Filename string}` 请求结构体

依赖：Step 5

---

## 验证方案

### 编译验证

```bash
go build ./internal/plugin/
go build .
cd frontend && npx vue-tsc --noEmit
```

### 运行时验证

| # | 操作 | 预期结果 |
|---|------|---------|
| V1 | 运行应用 | 日志出现 `[启动] 初始化插件管理器...` |
| V2 | 关闭应用 | 日志出现 `[插件管理器] 已关闭` |
| V3 | DevTools: `GetPluginInfos()` | 返回 `{success:true, data:[]}` |
| V4 | DevTools: `ResolvePreview({filename:'test'})` | 返回 `{success:false, message:"no preview handler..."}` |
| V5 | 前端 import registry | 无 TS 错误 |

### 边界情况

| 场景 | 预期行为 |
|------|---------|
| pluginMgr 为 nil 调用 GetPluginInfos | 返回空数组，不 panic |
| pluginMgr 为 nil 调用 ResolvePreview | 返回 success:false，不 panic |
| TabRegistry.Register 同一 TabKey 两次 | 返回冲突错误 |
| PreviewRegistry.Resolve 无匹配文件 | 返回 nil, "" |
| Manager.Shutdown 无插件注册 | 正常返回 nil |
