SurfSense 开源贡献指南:从分支工作流到代码评审的完整实战手册
【免费下载链接】SurfSenseOpen-source NotebookLM alternative. Research the open web with live data(Reddit, YT, IG, TikTok, Indeed, Google Search, Maps etc) through one platform, API or MCP server. Join our Discord: https://discord.gg/ejRNvftDp9项目地址: https://gitcode.com/GitHub_Trending/su/SurfSense
这篇指南面向想要为 SurfSense(开源 NotebookLM 替代方案,可通过一个平台、API 或 MCP Server 研究实时开放的互联网数据)贡献代码、文档或想法的开发者。你将掌握该项目的贡献全流程:三种贡献路径、main/dev分支保护模型、Docker 与手动两种开发环境搭建方式、pre-commit 自动化质量闸门(Ruff、Biome、Bandit、Commitizen 等)的真实配置,以及从提 Issue 到 PR 合并的完整规范。所有结论均以本仓库实际文件(CONTRIBUTING.md、.pre-commit-config.yaml、surfsense_backend/pyproject.toml、docker/docker-compose.dev.yml 等)为事实依据。
贡献前的准备:三种主流参与路径
在动手写代码之前,SurfSense 建议你先加入官方社区保持同步(Discord 社区承接最新动态、内部讨论与协作沟通),随后根据自身情况选择下面三种路径之一:
1. 从 Roadmap 认领任务
项目维护了一个公开 Roadmap,上面有划分清晰的问题(Issue)与功能点可供认领。建议优先查找状态为Backlog或Ready的任务,这两类通常是已确认可行、等待实现的工作项。
2. 提议新功能
如果你的想法不在 Roadmap 上,按以下顺序推进:
- 先检索是否已有相同或相似的 Issue;
- 不存在则新建 Issue,清楚描述功能或改进点;
- 等待维护者反馈与批准;
- 批准后即可开始准备 PR。
3. 报告 Bug 或修复 Bug
发现缺陷后,创建 Issue 时务必包含四类关键信息:
- 复现步骤(Steps to reproduce)
- 期望行为与实际行为(Expected vs actual behavior)
- 环境详情(操作系统、浏览器、版本号)
- 相关日志或截图(logs / screenshots)
如果想直接动手修复,同样欢迎——只需在 PR 中关联对应 Issue 即可。
分支工作流:main 由谁更新,PR 必须打向哪里
SurfSense 采用分支保护模型(branch protection model)保证main分支始终稳定:
| 分支 | 用途 | 谁可以合并 |
|---|---|---|
main | 稳定 / 发布分支 | 仅维护者(从dev合并而来) |
dev | 活跃开发与集成分支 | 通过 contributor 的已批准 PR |
feature/*、fix/*等 | 个人工作分支 | 贡献者向dev发起 PR |
三条必须遵守的铁律:
- 所有贡献者 PR 必须指向
dev分支,指向main的 PR 不会被接受; main仅由维护者在准备发布时从dev合并更新;- 创建功能/修复分支时,始终基于最新的
dev,而不是main。
从源码结构看,这套模型配合后文介绍的自动化质量闸门(pre-commit、CI),共同构成了"个人分支自由开发 →dev集成验证 → 维护者发布到main"的渐进式发布链路。
开发环境搭建:前置条件与两种启动方式
前置条件
| 组件 | 要求 | 仓库中的实际依据 |
|---|---|---|
| Docker & Docker Compose | 推荐使用,或手动安装 | docker/docker-compose.dev.yml |
| Node.js | 文档要求 v18+ | 实际surfsense_web使用 Next.js 16 + pnpm 10,需要更新的 Node 版本,见 surfsense_web/package.json |
| Python | 文档要求 3.11+ | 实际pyproject.toml声明requires-python = ">=3.12",见 surfsense_backend/pyproject.toml |
| PostgreSQL | 需安装PGVector扩展 | compose 直接使用pgvector/pgvector:pg17镜像 |
| API Keys | 测试外部服务所需 | 各连接器(Reddit、YouTube、Instagram 等)相关模块 |
版本提示:CONTRIBUTING.md 中写的 "Node v18+ / Python 3.11+" 是宽松下限;仓库实际代码基于 Python 3.12 与 Next.js 16 构建,配置项以仓库实际内容为准(见 surfsense_backend/pyproject.toml)。
标准开发流程
# 1. Fork 并克隆仓库 git clone https://github.com/<your-username>/SurfSense.git cd SurfSense # 2. 从 dev 创建自己的分支 git checkout dev git pull origin dev git checkout -b feature/your-feature-name方式 A:Docker Compose 从源码构建(推荐贡献者使用)
仓库根目录提供一套专门面向开发者的 compose 文件 docker/docker-compose.dev.yml,它会从源码构建镜像,并内置 pgAdmin、可观测性栈(otel-lgtm)等开发辅助工具,与生产用的 docker/docker-compose.yml(预构建镜像)区分开:
docker compose -f docker/docker-compose.dev.yml up --build启动的关键服务及其职责(来自 docker/docker-compose.dev.yml):
| 服务 | 作用 |
|---|---|
db | pgvector/pgvector:pg17,挂载 docker/postgresql.conf,健康检查pg_isready |
migrations | 短生命周期迁移容器,执行alembic upgrade head并校验zero_publication逻辑复制 publication 与预期形状一致,成功后退出 0 |
redis | redis:8-alpine,Celery 的消息代理与结果后端 |
backend | FastAPI 后端(端口 8000),热挂载surfsense_backend/app源码到容器 |
celery_worker/celery_beat | 后台任务 worker 与定时调度 |
zero-cache | Zero 实时同步缓存(端口 4848),依赖zero_publication已存在 |
frontend | Next.js 前端(端口 3000) |
pgadmin | 数据库管理面板(端口 5050) |
otel-lgtm | Grafana + Tempo + Loki 一体化可观测性(端口 3001) |
值得注意的依赖顺序:backend、celery_worker、celery_beat、zero-cache都通过depends_on ... condition: service_completed_successfully等待migrations成功,迁移失败会中断整个栈,避免 zero-cache 因 publication 漂移而崩溃重启。
方式 B:仅启动依赖,服务跑在宿主机
仓库还提供 docker/docker-compose.deps-only.yml,只启动 Postgres、Redis、pgAdmin、Zero 与可选的 Azurite(Azure Blob 存储模拟器),API、前端与 Celery 在宿主机运行:
# 从仓库根目录 docker compose -f docker/docker-compose.deps-only.yml up -d该文件头部注释还给出了宿主机侧的配置要点与本地 Celery 启动命令(来自 docker/docker-compose.deps-only.yml):
- 后端
.env:DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/surfsense - 后端
.env:CELERY_BROKER_URL/REDIS_APP_URL→redis://localhost:6379/0 - Web
.env:NEXT_PUBLIC_ZERO_CACHE_URL=http://localhost:${ZERO_CACHE_PORT:-4848}
# 本地 Celery(Redis 起来后,在 surfsense_backend/ 下执行) uv run celery -A celery_worker.celery_app worker --loglevel=info --concurrency=1 --pool=solo --queues=surfsense,surfsense.connectors uv run celery -A celery_worker.celery_app beat --loglevel=info⚠️ 关键注意事项:deps-only 栈不构建后端镜像、也没有 migrations 服务。首次启动或拉取更新后,必须先在本机执行
cd surfsense_backend && uv run alembic upgrade head再启动 zero-cache,否则 zero-cache 会因找不到zero_publication发布而 crash-loop。
配置服务
- 配置 PostgreSQL 与 PGVector(用上述 Docker 方式可免手动安装);
- 配置文件 ETL 服务:
Unstructured.io或LlamaIndex(仓库pyproject.toml同时依赖unstructured[all-docs]、unstructured-client、langchain-unstructured与docling,且 compose 中ETL_SERVICE默认值为DOCLING); - 为要测试的外部服务添加 API Keys。
项目结构:三个核心组件与更多
CONTRIBUTING.md 明确了 SurfSense 的三个主组件:
surfsense_backend/— Python/FastAPI 后端服务(含 ETL 管道、索引管道、连接器、Agent、网关等,见 surfsense_backend/app)surfsense_web/— Next.js Web 应用(surfsense_web/app)surfsense_browser_extension/— 用于数据采集的浏览器扩展(surfsense_browser_extension)
从仓库实际目录看,项目远不止这三部分:还包括surfsense_desktop/(Electron 桌面端)、surfsense_mcp/(MCP Server)、surfsense_obsidian/(Obsidian 插件)、surfsense_evals/(评测脚本与数据)以及docker/(全套编排文件)与scripts/(版本号 bump 等工具)。贡献前建议先通读对应子目录,保持改动与既有模式一致。
开发规范:pre-commit 自动化质量闸门
CONTRIBUTING.md 强调在开发前安装并配置 pre-commit hooks,并理解提交时自动运行的检查。文档引用的独立指南文件(./PRE_COMMIT.md)在当前仓库中不存在,实际的 pre-commit 配置位于仓库根目录 .pre-commit-config.yaml,直接pre-commit install即可生效。它按阶段组织了一整套检查:
通用文件质量检查(pre-commit/pre-commit-hooksv5.0.0)
check-yaml(--multi --unsafe)、check-json(排除tsconfig.json与.vscode/*.json)、check-tomlcheck-merge-conflict:防止提交带冲突标记的文件check-added-large-files:默认阈值--maxkb=10240(10MB),防止误提交大文件debug-statements、check-case-conflict
密钥泄露检测(Yelp/detect-secretsv1.5.0)
使用--baseline .secrets.baseline基线文件,并排除了*.env.example、tests/、alembic/versions/*.py、.github/workflows/*.yml、pnpm-lock.yaml、*.mdx、messages/*.json等白名单路径。
Python 后端:Ruff(v0.12.5)+ Bandit(1.8.6)
ruff与ruff-format只作用于^surfsense_backend/路径并排除测试文件,lint 会自动--fix;- Bandit 以 JSON 格式、
--severity-level high --confidence-level high扫描安全缺陷,排除tests/与alembic/。
Ruff 的规则集在 surfsense_backend/pyproject.toml 中定义:启用 pycodestyle(E4/E7/E9)、Pyflakes(F)、isort(I)、pep8-naming(N)、pyupgrade(UP)、bugbear(B)、comprehensions(C4)、print(T20)、simplify(SIM)与 Ruff 专属规则(RUF);行宽 88、目标 Python 3.12、格式化使用双引号。这与 CONTRIBUTING.md 要求的 "PEP 8 + Black 格式" 在仓库中已演进为Ruff(兼作 linter 与 formatter),以实际配置为准。
前端:Biome 2.4.6
以local hook方式运行(见 .pre-commit-config.yaml):
cd surfsense_web && npx @biomejs/biome@2.4.6 check --diagnostic-level=error .格式化与 lint 规则集中在 biome.json:tab 缩进、行宽 100、LF 换行、双引号、强制分号(semicolons: always)、开启 import 自动排序(organizeImports: on)。注意surfsense_browser_extension的 Biome hook 当前在配置中以注释形式停用。
提交信息校验(commitizen-tools/commitizenv4.8.3)
commit-msg阶段强制使用Conventional Commits格式,即 CONTRIBUTING.md 中的提交信息示例所对应的规范:
feat: add document search functionality fix: resolve pagination issue in chat history docs: update installation guide refactor: improve error handling in connectors全局配置default_stages: [pre-commit]、fail_fast: false,意味着所有检查默认在 pre-commit 阶段执行,但某一项失败不会阻止其余检查运行。Hook 的旁路(--no-verify)仅在必要时使用。
代码风格速查
- 后端:Python PEP 8(仓库实际以 Ruff 为准,行宽 88)
- 前端:TypeScript,遵循现有代码模式(Biome 强制格式)
- 格式化:Ruff 负责 Python,Biome(替代文档所述的 Prettier)负责 TypeScript/JS/JSON/CSS
测试要求
- 新功能与 Bug 修复必须编写测试;
- 提交前确保既有测试全部通过;
- API 端点需包含集成测试。
仓库的测试体系佐证了这一点:
- 后端
pyproject.toml配置 pytest:testpaths = ["tests"]、asyncio_mode = "auto",并声明了unit(纯逻辑,无需 DB/外部服务)与integration(需要真实 PostgreSQL)两类 marker;测试代码分布在 surfsense_backend/tests/unit 与 surfsense_backend/tests/integration; - 前端使用 Playwright 做端到端测试,脚本见 surfsense_web/package.json(
test:e2e、test:e2e:ui等),配置在 surfsense_web/playwright.config.ts。
分支命名
从dev创建、名称有描述性:
feature/add-document-search fix/pagination-issue docs/update-contributing-guidePull Request 流程:提交前检查清单与硬性要求
提交 PR 之前
- 先创建 Issue(除非是微小修复);
- Fork 仓库并从
dev创建分支; - 按开发规范完成修改;
- 充分测试;
- 如需更新文档;
- 打开指向
dev分支的 PR。
再次强调:指向
main的 PR 不会被评审或合并。若误开,请将其 retarget 到dev。
PR 的硬性要求
- 目标分支必须是
dev(强制); - 一个 PR 只做一个功能或修复,保持聚焦;
- 在 PR 描述中关联相关 Issue;
- UI 改动需附带截图或演示;
- PR 标题与描述要清晰有信息量;
- 请求评审前确保CI 通过。
代码评审:从提交到合并的完整链路
- 自动化检查必须通过(CI/CD 流水线,即上文 pre-commit 覆盖的质量关卡在 CI 中的延续);
- 至少一位维护者评审你的 PR;
- 及时、专业地处理反馈;
- 如被要求,squash 提交以保持历史整洁;
- 合并成功即完成一次贡献。
文档与代码注释的要求
贡献时请同步维护文档资产:
- 新功能更新对应文档(仓库文档集中在 docs 与 surfsense_web/content/docs);
- 复杂逻辑补充或更新代码注释;
- 后端改动同步更新 API 文档;
- 新功能提供示例。
获取帮助与其他贡献方式
遇到困难时按顺序尝试:
- 检索已有 Issue(你的问题可能已有答案);
- 查阅官方文档;
- 在 Discord 社区提问;
- 若是 Bug 或功能请求,创建 Issue。
如果暂时不打算写代码,仍有多种非代码贡献方式:分享 SurfSense、在社区提供反馈、帮助 triage Issue 并验证 Bug 报告、改进文档与示例、撰写教程或博文。
贡献者认可与 License
所有贡献者都会获得认可:出现在 release notes、列入贡献者名单、受邀加入贡献者专属 Discord 频道,并有资格获得贡献者徽章。
License 约定:向 SurfSense 贡献即表示你的贡献将采用与项目相同的许可证(LICENSE)授权。
至此,从"在哪认领任务"到"PR 如何被合并"的完整贡献链路已经清晰。核心动作可以总结为一句话:Fork → 从dev建分支 → 遵循 Ruff/Biome/Commitizen 等 pre-commit 关卡 → 写好测试 → 提交指向dev的 PR → 通过评审与 CI 后合入dev,再由维护者发布到main。
【免费下载链接】SurfSenseOpen-source NotebookLM alternative. Research the open web with live data(Reddit, YT, IG, TikTok, Indeed, Google Search, Maps etc) through one platform, API or MCP server. Join our Discord: https://discord.gg/ejRNvftDp9项目地址: https://gitcode.com/GitHub_Trending/su/SurfSense
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考