Skip to content

lifei6671/plaindoc

Repository files navigation

PlainDoc

一套面向中小团队的轻量级文档管理系统。
如果你熟悉 MinDoc,PlainDoc 的目标很直接:保留文档系统的核心价值,同时带来更现代的编辑体验和更省心的工程化部署。

开箱即可获得:

  • Go 后端(Gin + GORM)
  • React 前端编辑器(Vite + CodeMirror)
  • 首页/分类页 SSR
  • 空间阅读页 SSR(对 SEO 友好)
  • 后台管理(用户、空间、文档、主题、系统配置、审计)
页面 截图
后台概览页 Image
后台个人信息页 Image
后台用户管理页面 Image
空间管理 Image
新建空间 Image
空间分类 Image
空间成员 Image
文档管理 Image
附件管理 Image
图片管理 Image
主题管理 Image
审计日志 Image
文档编辑 Image
首页 Image
文档阅读 Image

产品定位

PlainDoc 是一个真正可落地的文档平台,而不是“仅能写 Markdown 的编辑器”。

我们希望它帮助团队实现三件事:

  • 用 Markdown 快速搭建团队知识库/技术文档库
  • 提供“编辑、阅读、管理”一体化能力,而不是单纯编辑器
  • 以最低维护成本长期运行(单体部署、权限治理、可观测)

适用场景:

  • 团队内部知识沉淀
  • 技术文档中心
  • 小中型项目文档门户
  • 运维手册/流程文档管理

核心功能与亮点

功能

  • 空间与文档树:支持空间、目录、文档的层级组织
  • Markdown 编辑:左树 + 中间编辑 + 右侧预览的工作台体验
  • 阅读系统:独立阅读页(/r/:spaceId/:docId),适合分享与访问
  • 权限模型:owner / collaborator / reader 多角色访问控制
  • 版本能力:文档版本号、冲突检测、修订记录
  • 图片链路:上传、鉴权、静态回源、Markdown 直接渲染
  • 后台治理:用户、空间、文档、主题、系统配置、审计管理

亮点

  • 轻量但完整:一套系统同时覆盖编辑、阅读、权限与后台治理
  • 单体部署体验:Go 主服务 + Node SSR Worker 子进程,无需独立 Node SSR 服务
  • 渲染一致性:阅读 SSR 与编辑器预览复用同一套 Markdown 渲染链路
  • 双 SSR 架构:
    • 首页/分类页:Go 模板 SSR
    • 阅读页:React SSR(由 Go 调度 Worker)
  • 开发和生产都顺手:前端统一走后端 API 模式(http),联调与生产一致
  • 工程化可维护:统一响应协议、错误码体系、Docker + Compose 开箱部署

1. 项目现状(截至 2026-02-23)

已落地核心能力:

  • 文档编辑器(左侧文档树 + 中间编辑 + 右侧预览)
  • 空间与文档权限模型(owner / collaborator / reader
  • 图片上传与本地静态回源(/uploads/*
  • 首页与分类页 SSR(//explore/:categoryId
  • 空间阅读页 SSR(/r/:spaceId/r/:spaceId/:docId
  • 阅读页友好错误页与登录重定向
  • 后台管理台与空间治理能力
  • 编辑与协作工作台:
    • 左侧文档树 + 中间编辑 + 右侧预览的一体化工作台
    • 文档版本号、冲突检测、修订记录
    • Markdown 模板能力,可在后台自定义模板场景和模板内容
  • 阅读与分享体验:
    • 独立阅读页 SSR,适合知识门户、SEO 收录与外部访问
    • 单页分享能力,支持阅读密码、过期时间与分享链路访问控制
    • 阅读页友好错误页、登录重定向与 Office 文档源文件下载
  • Office 文档支持:
    • 可配置 ONLYOFFICE,实现 Word / Excel 在线编辑
    • DOCX / XLSX 支持独立阅读页、本地 HTML 渲染与回退阅读方案
  • 附件与图片体系:
    • 编辑文档时可上传附件,阅读页支持下载鉴权与预览分流
    • 后台可管理附件资源、图片资源与引用状态
    • 对未引用图片可执行自动清理,降低存储冗余
  • 搜索与平台能力:
    • 基于 Golang 内置 Bleve 的全文索引,支持自定义词典
    • 支持对接邮箱,可用于找回密码等系统通知场景
    • 后台内置用户、空间、文档、主题、系统配置与审计治理能力

参考:

  • docs/DAILY_PROGRESS_2026-02-23.md
  • docs/HOMEPAGE_SSR_IMPLEMENTATION_PHASES.md
  • docs/SPACE_READER_SSR_SUBPROCESS_IMPLEMENTATION_PHASES.md

2. 技术栈

后端(apps/server

  • Go 1.26
  • Gin 1.11
  • GORM 1.31
  • 数据库驱动:SQLite / MySQL / PostgreSQL
  • 默认 SQLite 驱动:modernc.org/sqlite

前端(apps/web

  • React 19
  • Vite 7
  • TypeScript 5.9
  • CodeMirror 6
  • React Markdown + remark/rehype 渲染链
  • Mermaid / KaTeX / 语法高亮

SSR

  • 首页/分类页:Go html/template
  • 阅读页:Go 通过 stdin/stdout 调用 Node SSR Worker(非独立 Node 服务)

3. 仓库结构

.
├── apps
│   ├── server                    # Go 服务端
│   └── web                       # React 前端
├── docs                          # 方案、里程碑、日报、踩坑记录
├── Dockerfile                    # 多阶段构建镜像(web + ssr worker + go)
├── docker-compose.yml            # 单容器部署(含 SSR Worker)
└── README.md

4. 运行方式

4.1 方式 A:Docker Compose(推荐)

要求:

  • Docker Engine + Docker Compose v2

在仓库根目录执行:

docker compose build
docker compose up -d

访问地址:

  • http://localhost:8080

常用命令:

docker compose logs -f plaindoc
docker compose up -d --build
docker compose down
docker compose down -v

默认持久化卷:

  • plaindoc_data -> /app/data(SQLite 数据)
  • plaindoc_uploads -> /app/uploads(上传文件)

4.2 方式 B:本地开发(前后端分开启动)

前置要求:

  • Node.js >= 20(当前 Docker 使用 Node 24)
  • npm
  • Go 1.26+

1) 安装前端依赖

npm install

2) 启动后端

cd apps/server
cp .env.example .env
go mod tidy
go run ./cmd/server

默认后端地址:http://localhost:8080

3) 启动前端开发服务

# 回到仓库根目录
npm run web:dev

默认前端地址:http://localhost:3001

提示:开发时建议通过 Vite 反向代理访问后端,不要直接在浏览器跨端口访问 /api


5. 构建与发布

5.1 本地构建

npm run web:build

等价于执行:

  • build:client -> apps/web/dist
  • build:ssr-worker -> apps/web/dist-ssr

后端测试

cd apps/server
go test ./...

Docker 镜像(本地手动构建)

docker build -t plaindoc:latest .
docker run --rm -p 8080:8080 plaindoc:latest

5.2 GitHub Release 产物说明

当你推送 tag 后,Release 工作流会上传以下文件:

  • plaindoc-server-linux-amd64:Linux amd64 的后端可执行文件(Go 编译产物)。
  • plaindoc-server-linux-amd64-<tag>.tar.gz:一体化部署压缩包,包含后端可执行文件、apps/web/distapps/web/dist-ssr
  • plaindoc-web-<tag>.tar.gz:前端发布产物压缩包,包含 dist(前端静态资源)和 dist-ssr(阅读页 SSR Worker 产物)。
  • checksums-<tag>.txt:上述产物的 SHA256 校验清单。

5.3 使用 Release 产物部署(Linux 裸机/云主机)

默认账号admin@iminho.me 默认密码:123456

  1. 下载对应 tag 的核心文件: plaindoc-server-linux-amd64-<tag>.tar.gzchecksums-<tag>.txt
    plaindoc-web-<tag>.tar.gz 为可选文件(仅前端产物包,适合只替换前端时使用)。
  2. 校验文件完整性:
sha256sum -c checksums-<tag>.txt
  1. 解压到部署目录:
mkdir -p /opt/plaindoc/apps/web
tar -xzf plaindoc-server-linux-amd64-<tag>.tar.gz -C /opt/plaindoc
chmod +x /opt/plaindoc/plaindoc-server-linux-amd64
  1. 配置并启动(示例):
export APP_ENV=production
export APP_ADDR=:8080
export WEB_ORIGIN=http://your-domain-or-ip:8080
export WEB_DIST_DIR=/opt/plaindoc/apps/web/dist
export DB_DRIVER=sqlite
export DB_DSN='file:/opt/plaindoc/data/plaindoc.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)'
export SSR_WORKER_ENABLED=true
export SSR_WORKER_EXEC=node
export SSR_WORKER_ENTRY=/opt/plaindoc/apps/web/dist-ssr/worker-entry.js

/opt/plaindoc/plaindoc-server-linux-amd64

提示:阅读页 SSR 依赖 Node 子进程。若服务器未安装 Node,请先安装 Node,或临时设置 SSR_WORKER_ENABLED=false

5.4 DockerHub 部署(推荐)

说明:工作流会始终推送 <tag> 镜像标签;当 Git tag 以 v 开头时,额外推送 latest

拉取镜像:

docker pull lifei6671/plaindoc:latest

直接运行:

docker run -d \
  --name plaindoc \
  -p 8080:8080 \
  -e APP_ENV=production \
  -e WEB_ORIGIN=http://localhost:8080 \
  -e DB_DRIVER=sqlite \
  -e DB_DSN='file:/app/data/plaindoc.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)' \
  -v plaindoc_data:/app/data \
  -v plaindoc_uploads:/app/uploads \
  --restart unless-stopped \
  lifei6671/plaindoc:latest

5.5 Docker Compose(使用 DockerHub 镜像)

如果不想本地 build,可使用以下 compose:

services:
  plaindoc:
    image: lifei6671/plaindoc:latest
    container_name: plaindoc
    ports:
      - "8080:8080"
    environment:
      APP_ENV: "production"
      APP_ADDR: ":8080"
      WEB_ORIGIN: "http://localhost:8080"
      WEB_DIST_DIR: "/app/apps/web/dist"
      DB_DRIVER: "sqlite"
      DB_DSN: "file:/app/data/plaindoc.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)"
      DB_AUTO_MIGRATE: "true"
      SSR_WORKER_ENABLED: "true"
      SSR_WORKER_EXEC: "node"
      SSR_WORKER_ENTRY: "/app/apps/web/dist-ssr/worker-entry.js"
    volumes:
      - plaindoc_data:/app/data
      - plaindoc_uploads:/app/uploads
    restart: unless-stopped

volumes:
  plaindoc_data:
  plaindoc_uploads:

启动:

docker compose up -d

6. 路由与页面结构

页面路由(非 /api

  • /:首页 SSR
  • /explore/:categoryId:分类页 SSR
  • /r/:spaceId:空间阅读入口(跳转首篇可读文档)
  • /r/:spaceId/:docId:阅读页 SSR(Go -> Node Worker)
  • /login/register/editor/*/admin/*:Web SPA(生产由 Go 托管 WEB_DIST_DIR
  • /uploads/*path:本地上传文件公开访问

API 入口

  • /api/healthz
  • /api/auth/*
  • /api/spaces/*/api/nodes/*/api/docs/*
  • /api/admin/*
  • /api/uploads/images

完整注册点见:apps/server/internal/server/router.go


7. SSR 架构说明

7.1 首页/分类页 SSR

  • 由 Go 模板直接渲染
  • 模板静态资源走 /assets/*

7.2 阅读页 SSR(子进程模式)

流程:

  1. 浏览器请求 /r/:spaceId/:docId
  2. Go 侧聚合阅读数据并鉴权
  3. Go 通过 JSONL 协议把 payload 发给 Node Worker
  4. Node Worker 返回 HTML/head/metrics
  5. Go 输出完整页面

关键配置(服务端):

  • SSR_WORKER_ENABLED
  • SSR_WORKER_EXEC
  • SSR_WORKER_ENTRY
  • SSR_WORKER_COUNT
  • SSR_RENDER_TIMEOUT
  • SSR_WORKER_START_TIMEOUT
  • SSR_WORKER_MAX_PAYLOAD_BYTES
  • SSR_PROTOCOL_VERSION

当 Worker 不可用时,阅读页会降级到基础 HTML 兜底,而不是直接雪崩 500。


8. 统一响应协议(JsonResult)

后端 API 统一返回结构:

{
  "code": 0,
  "message": "success",
  "requestId": "xxxx",
  "data": {}
}

说明:

  • 业务成功:code = 0
  • 业务失败:code != 0(例如 3001 ROUTE_NOT_FOUND
  • 当前错误 HTTP 状态会收敛(认证类为 403,其它多为 200),前端应优先按 code 处理

定义见:

  • apps/server/internal/server/response/error.go
  • apps/server/internal/server/response/error_codes.go

9. 配置说明

后端环境变量

样例文件:apps/server/.env.example

常用项:

  • APP_ENVAPP_ADDR
  • WEB_ORIGIN(CORS)
  • WEB_DIST_DIR(生产托管 SPA 的 dist 目录)
  • DB_DRIVERDB_DSNDB_AUTO_MIGRATE
  • JWT_*
  • SSR_WORKER_*

.env 加载顺序(启动时自动读取):

  1. .env
  2. apps/server/.env
  3. cmd/server/.env
  4. apps/server/cmd/server/.env

且系统环境变量优先级更高,不会被 .env 覆盖。

前端环境变量

样例文件:apps/web/.env.example

核心项:

  • VITE_API_BASE_URL
  • VITE_DEV_PROXY_TARGET

10. 常见问题

1) 阅读页返回 “route not found” 或图片不显示

  • 检查是否走了正确路径:
    • 阅读:/r/...
    • 图片:/uploads/...
  • 开发模式确认 Vite 代理是否开启(/r/uploads/api

2) SSR Worker 启动失败

  • 检查 SSR_WORKER_ENTRY 是否存在
  • 检查 Node 可执行文件是否在 PATH(SSR_WORKER_EXEC
  • 检查协议版本是否一致(SSR_PROTOCOL_VERSION

3) 修改了 .env 但配置未生效

  • 重启服务
  • 查看 server starting 日志中的配置摘要

4) 阅读页样式与编辑预览不一致

  • 当前实现已把预览样式统一注入阅读 SSR
  • 如出现差异,优先检查 apps/web/src/ssr/render-space-reader.tsxapps/web/src/styles.css

11. 文档索引(docs)

当前主文档(建议优先阅读):

  1. docs/README.md(docs 导航总入口)
  2. docs/FRONTEND_DEVELOPER_GUIDE.md
  3. docs/BACKEND_DEVELOPER_GUIDE.md
  4. docs/ENGINEERING_STANDARDS.md

历史方案与阶段文档(用于追溯决策与实施细节):

  1. docs/BACKEND_IMPLEMENTATION_PHASES.md
  2. docs/HOMEPAGE_SSR_IMPLEMENTATION_PHASES.md
  3. docs/SPACE_READER_SSR_SUBPROCESS_TECHNICAL_PROPOSAL.md
  4. docs/SPACE_READER_SSR_SUBPROCESS_IMPLEMENTATION_PHASES.md
  5. docs/ADMIN_CONSOLE_IMPLEMENTATION_PHASES.md
  6. docs/ADMIN_CONSOLE_RELEASE_CHECKLIST.md
  7. docs/SPACE_CATEGORY_REFACTOR_NOTES.md
  8. docs/ADMIN_SPACE_CREATE_WITH_COVER_IMPLEMENTATION_PHASES.md
  9. docs/DAILY_PROGRESS_2026-02-22.md
  10. docs/DAILY_PROGRESS_2026-02-23.md
  11. docs/ai-handoff-pitfalls.md
  12. docs/backend-ai-handoff.md

12. License

本项目使用仓库根目录 LICENSE

About

PlainDoc 一个轻量级的开源企业知识分享和文档在线管理系统,可用于快速构建企业 Wiki 和团队知识分享平台。部署方便,使用简单,帮助团队构建一个信息共享、文档管理的协作环境。

Topics

Resources

License

Stars

45 stars

Watchers

3 watching

Forks

Packages

 
 
 

Contributors