Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
e5828ff
feat: 添加架构与设计文档,详细描述系统结构、功能与设计原则
kooksee Apr 30, 2026
2ea3084
feat: 更新文档中的术语与描述,提升可读性与一致性
kooksee Apr 30, 2026
d4cbf28
feat: 添加 Markdown 能力清单文档,更新 MarkdownViewer 组件以处理链接打开错误提示
kooksee Apr 30, 2026
7859dc3
feat: 增强图表渲染错误提示,提供详细错误信息与回退机制
kooksee Apr 30, 2026
88eb3ff
feat: 添加 PlantUML 渲染失败时的重试功能与测试用例
kooksee Apr 30, 2026
ccfbec0
feat: 添加大纲笔记模式,支持左侧思维导图与右侧文档联动浏览
kooksee Apr 30, 2026
2689233
feat: 添加项目来源与版权说明,更新 NOTICE 文件以包含上游信息
kooksee Apr 30, 2026
b56ca2d
feat: 添加大纲笔记面板,支持可编辑条目与从文档导入标题功能
kooksee Apr 30, 2026
9f141dd
feat: 增强大纲笔记模式,支持子项折叠/展开、上下移动条目功能
kooksee Apr 30, 2026
dc22ad8
feat: 更新大纲笔记模式,支持基于文档标题解析的思维导图与大纲笔记视图
kooksee Apr 30, 2026
0eb3a60
feat: 添加可折叠标题组件,支持在 Markdown 视图中折叠/展开章节内容
kooksee Apr 30, 2026
6d76201
feat: 添加文档思维导图功能,支持从 Markdown 标题生成思维导图并渲染
kooksee Apr 30, 2026
91d7c76
feat: 添加交互式思维导图功能,支持基于文档标题生成图形树结构
kooksee Apr 30, 2026
e03256b
feat: 添加思维导图切换组件,支持在界面中显示和隐藏思维导图
kooksee Apr 30, 2026
9defcb5
feat: 添加缩放功能,支持通过按钮和滚轮调整思维导图的缩放级别
kooksee Apr 30, 2026
6e6be4b
Merge branch 'master' of github.com:kooksee/markview into sprint/1
kooksee Apr 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
markview NOTICE
===============

This project includes work derived from:

- Project: k1LoW/mo
- Repository: https://github.com/k1LoW/mo
- License: MIT License
- Upstream copyright:
Copyright © 2026 Ken'ichiro Oyama <k1lowxb@gmail.com>

markview is maintained as a derivative project with additional modifications.
Please refer to LICENSE and CREDITS/CREDITS_FRONTEND for detailed license texts
of this repository and third-party dependencies.
298 changes: 173 additions & 125 deletions README.md

Large diffs are not rendered by default.

136 changes: 136 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# markview 架构文档

## 1. 架构总览

`markview` 采用 **Go 后端 + React 前端 + 单二进制分发** 的架构:

```mermaid
flowchart LR
CLI[命令行入口 / cmd/root.go] -->|启动/复用| HTTP[Go 网络服务]
HTTP --> STATE[状态中心\n(groups/files/patterns)]
HTTP --> WATCH[fsnotify]
WATCH --> SSE[服务端事件流 /_/events]
SSE --> SPA[React 前端界面]
SPA --> API[/_/api/*]
API --> STATE
STATE --> BACKUP[会话备份 JSON\nXDG_STATE_HOME]
SPA --> STATIC[前端静态资源]
STATIC --> HTTP
```

核心特征:

- **单实例复用**:同端口优先复用已有进程。
- **服务端状态中心**:分组、文件、watch 模式统一由后端维护。
- **前后端松耦合**:通过 HTTP 接口 + 服务端事件流通信。
- **内嵌前端静态资源**:最终交付为单可执行文件。

## 2. 目录与模块职责

| 模块 | 路径 | 职责 |
| --------------- | -------------------------------------------- | ------------------------------------------ |
| 命令行入口 | `cmd/root.go` | 参数解析、单实例探测、前后台启动、状态命令 |
| 服务状态与路由 | `internal/server/server.go` | HTTP 接口、事件流、文件监听、状态管理 |
| 链接/大纲图构建 | `internal/server/graph.go` | 从 Markdown 内容提取关系并输出图数据 |
| 分组名规范 | `internal/server/group.go` | 分组名归一化与安全校验 |
| 备份存储 | `internal/backup/backup.go` | 会话快照读写(原子写) |
| 静态资源嵌入 | `internal/static/static.go` | 触发前端构建并 `go:embed` 嵌入 |
| 前端主流程 | `frontend/src/App.tsx` | 路由状态、分组/文件选择、SSE 刷新 |
| 前端渲染核心 | `frontend/src/components/MarkdownViewer.tsx` | Markdown 渲染与图表增强 |
| 接口封装 | `frontend/src/hooks/useApi.ts` | 前端到后端接口调用 |
| 事件流订阅 | `frontend/src/hooks/useSSE.ts` | 实时事件与断线重连 |

## 3. 关键运行时序

## 3.1 启动与复用

```mermaid
sequenceDiagram
participant U as 用户
participant C as 命令行
participant S as 已运行服务

U->>C: markview README.md
C->>S: GET /_/api/status
alt 服务已存在
C->>S: POST /_/api/files
C-->>U: 输出 URL 并退出
else 服务未找到
C->>C: 启动新服务进程
C-->>U: 输出 URL
end
```

## 3.2 文件变更到页面刷新

```mermaid
sequenceDiagram
participant FS as 文件系统
participant W as fsnotify
participant ST as 状态中心
participant FE as 前端(服务端事件流)

FS->>W: 文件写入/重命名
W->>ST: 变更事件
ST->>FE: 事件流推送(file-changed)
FE->>FE: 拉取 /_/api/files/{id}/content
FE-->>FE: 重新渲染 Markdown
```

## 4. 数据与状态模型

## 4.1 服务端状态

- `groups`: 当前分组及文件列表
- `patterns`: 当前监听通配模式集合
- `watchedDirs`: 被监听目录的引用计数
- `subscribers`: SSE 订阅者集合

通过 `RWMutex` 保护并发读写。

## 4.2 持久化模型

`RestoreData` 结构包含:

- `Groups`: 分组到文件路径列表
- `Patterns`: 分组到 watch 模式列表
- `UploadedFiles`: 内存上传文件快照

状态在变更后触发去抖保存;启动时读取并合并 CLI 参数。

## 5. API 边界

内部接口统一使用 `/_/api/*` 前缀,避免与用户分组路由冲突:

- 文件管理:`POST /_/api/files`、`DELETE /_/api/files/{id}`
- 内容读取:`GET /_/api/files/{id}/content`
- 分组与排序:`PUT /_/api/files/{id}/group`、`PUT /_/api/reorder`
- 模式管理:`POST/DELETE /_/api/patterns`
- 运行控制:`POST /_/api/restart`、`POST /_/api/shutdown`
- 状态检查:`GET /_/api/status`、`GET /_/api/version`
- 实时事件:`GET /_/events`

## 6. 构建与发布架构

## 6.1 本地构建

- `go generate ./internal/static/`:构建前端产物到 `internal/static/dist`
- `go build`:打包 Go 服务 + 内嵌静态资源

## 6.2 持续集成与发布

- 持续集成:前端 lint/format、Go lint、测试覆盖率
- 发布:`tagpr` 管理版本,`goreleaser` 产出多平台二进制
- 许可证检查:Trivy 扫描许可证风险

## 7. 安全与边界

1. 默认本地网络使用;非回环地址绑定需显式确认。
2. 内部 API 无认证,面向本机可信环境。
3. 文件原始资源访问路径带目录边界校验,防止目录穿越。

## 8. 可扩展建议

1. 鉴权与访问控制:为远程协作模式增加 token/ACL。
2. 文档规模扩展:搜索与解析任务可进一步 Worker 化。
3. 模块拆分:继续降低 `MarkdownViewer` 复杂度,提升前端可维护性。
124 changes: 124 additions & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# markview 设计文档

## 1. 背景与目标

`markview` 是一个本地运行的 Markdown 工作台,目标是把「编辑器中的多个 Markdown 文件」快速投射到浏览器中,以更高可读性和更强交互能力进行阅读、导航和组织。

核心目标:

1. **零心智负担启动**:一条命令即可打开预览。
2. **多文件协同阅读**:支持分组、重排、树视图、全文搜索、链接跳转。
3. **实时反馈**:文件保存后自动刷新内容。
4. **会话可恢复**:关闭后可恢复上次状态。

## 2. 设计原则

1. **本地优先**
- 服务默认运行在本机端口,数据不依赖云端存储。
2. **单实例优先**
- 同端口已有服务时复用现有服务,而非重复拉起进程。
3. **渐进增强**
- 基础 Markdown 浏览可用;图表、搜索、图谱等能力按需增强。
4. **状态可追溯**
- 重要状态持久化,重启与故障恢复后可继续工作。

## 3. 用户与使用场景

### 3.1 目标用户

- 文档驱动开发者(README、ADR、设计文档维护)
- 技术写作者(教程、知识库、研究笔记)
- AI 辅助编码工作流用户(需要稳定的本地文档视图)

### 3.2 典型场景

1. 打开多个文档并分组查看(例如 `design` / `notes`)
2. 监听目录内新增 Markdown 文件并自动加入
3. 在文档中点击相对链接自动打开目标文件
4. 关闭服务后再次启动,恢复上次文件与分组

## 4. 功能设计

## 4.1 文件与分组模型

- 文件以 `FileEntry` 表示,核心字段:`id`、`name`、`path`。
- 分组以 `Group` 表示,映射到 URL 路径(如 `/design`)。
- 默认分组名为 `default`。

文件 ID 设计:

- 常规文件:基于绝对路径的 SHA-256 前 8 位,稳定且可深链。
- 上传文件:基于内容哈希生成上传 ID(`uxxxxxxx`)。

## 4.2 单实例复用策略

命令行启动时先探测 `/_/api/status`:

- 若服务存在:通过接口将文件或模式加入现有会话。
- 若服务不存在:启动新服务并打开浏览器。

这可避免同端口多进程竞争,并让命令行调用天然支持“追加文件”。

## 4.3 实时刷新设计

- 后端使用 `fsnotify` 监听文件变化。
- 前端通过服务端事件流 (`/_/events`) 订阅事件:
- `update`:文件集或分组变化
- `file-changed`:文件内容变化
- `started`:服务进程身份(PID)

当进程 PID 变化时,前端自动刷新页面,保证重启后的会话一致性。

## 4.4 会话持久化设计

- 存储位置:`$XDG_STATE_HOME/markview/backup/markview-<port>.json`
- 保存内容:分组、文件路径、监听模式、上传文件内容
- 写入策略:原子写入(临时文件 + rename)
- 触发策略:状态变更后去抖保存

## 4.5 前端交互设计

主要交互能力:

- 侧边栏平铺/树形视图切换
- 分组切换与文件拖拽重排
- 目录树折叠状态记忆
- 目录面板(ToC)、原文视图(Raw)、宽窄阅读模式
- 全局全文搜索与命中跳转
- 图谱与大纲视图(链接关系可视化)

持久化策略:

- 前端 UI 偏好写入 `localStorage`(统一 `markview-` 前缀)

## 5. 非功能设计

## 5.1 性能

- 单实例减少资源浪费
- 前端按需加载/分包(Shiki/Mermaid/D3/PDF 等)
- 搜索与图谱构建以当前打开文件范围为边界

## 5.2 可维护性

- Go 后端与 React 前端边界清晰
- API 路由统一 `/_/api/` 前缀,避免与 SPA 路径冲突
- 测试覆盖 Go 单测与前端 Vitest

## 5.3 安全

- 默认本地使用;非回环地址绑定会给出风险确认
- 对路径访问进行基本约束(如原始文件访问防目录穿越)

## 6. 已知边界

1. 上传文件为内存态,不支持文件系统实时刷新。
2. 监听与搜索范围是“已加入会话的文件集合”,不是全盘索引。
3. 远程可访问模式(非 loopback 绑定)需用户明确确认,适合可信网络。

## 7. 后续演进方向

1. 搜索键盘导航和防抖优化
2. 大文件/大规模文档场景下的工作线程(Worker)化搜索
3. `MarkdownViewer` 继续拆分,降低单文件复杂度
4. 远程访问模式的鉴权与更细粒度权限控制
40 changes: 20 additions & 20 deletions docs/global-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

## 搜索行为

- 搜索范围:所有分组(group)下的所有文件内容
- 搜索范围:所有分组下的所有文件内容
- 匹配方式:大小写不敏感的子串匹配
- 结果上限:默认最多 200 条命中
- 结果信息:文件名、所属分组、行号、命中片段(关键词高亮)
Expand All @@ -24,23 +24,23 @@

```mermaid
sequenceDiagram
participant User
participant App
participant GlobalSearchModal
participant fullTextSearch
participant API

User->>App: ⌘+Shift+F
App->>GlobalSearchModal: isOpen=true
GlobalSearchModal->>API: fetchFileContent (并发拉取所有文件)
API-->>GlobalSearchModal: 文件内容 (带缓存)
User->>GlobalSearchModal: 输入关键词
GlobalSearchModal->>fullTextSearch: searchInFiles(files, query)
fullTextSearch-->>GlobalSearchModal: FullTextSearchHit[]
GlobalSearchModal-->>User: 展示匹配结果列表
User->>GlobalSearchModal: 点击某条结果
GlobalSearchModal->>App: onSelect(groupName, fileId)
App->>App: 切换分组 + 激活文件
participant 用户
participant 应用
participant 搜索弹窗
participant 检索模块
participant 接口层

用户->>应用: ⌘+Shift+F
应用->>搜索弹窗: isOpen=true
搜索弹窗->>接口层: fetchFileContent并发拉取所有文件
接口层-->>搜索弹窗: 文件内容带缓存
用户->>搜索弹窗: 输入关键词
搜索弹窗->>检索模块: searchInFiles(files, query)
检索模块-->>搜索弹窗: FullTextSearchHit[]
搜索弹窗-->>用户: 展示匹配结果列表
用户->>搜索弹窗: 点击某条结果
搜索弹窗->>应用: onSelect(groupName, fileId)
应用->>应用: 切换分组 + 激活文件
```

## 涉及文件
Expand All @@ -57,13 +57,13 @@ sequenceDiagram
### 交互体验

1. **键盘导航** — 上下方向键选择结果、Enter 打开选中项,减少鼠标依赖
2. **防抖输入** — 文件较多时加 ~150ms debounce,避免每次按键都触发搜索
2. **防抖输入** — 文件较多时增加约 150ms 输入防抖,避免每次按键都触发搜索
3. **每行多处匹配** — 当前每行只取第一个命中,长行中后续匹配会被遗漏

### 性能

4. **增量缓存** — 当前每次打开弹窗都重新拉取所有文件内容;可改为只拉新增/变更文件(结合 SSE `file-changed` 事件清除对应缓存)
5. **Web Worker 搜索** — 文件数量很大时搜索会阻塞主线程,可移至 Worker 执行
5. **工作线程搜索** — 文件数量很大时搜索会阻塞主线程,可移至 Worker 执行

### 功能增强

Expand Down
Loading
Loading