学术出版,不必从零再来一遍

一套开箱即用的开源基座——投稿 → 审稿 → 录用 → 发表 → 阅读 → 订阅,一个代码库跑通全流程。

5 分钟跑起来 → ⭐ 去看源码 ▶ 60 秒演示
11
后端领域模块
644
后端测试用例
84%
行覆盖率(硬门槛 80%)
66
Playwright 端到端用例

为什么会有这个项目

大多数团队都在反复从头搭同一套期刊脚手架——投稿表单、审稿人分配、一个装已发表文章的 CMS。 ScholarHUB 把它打包成一个真正的多角色产品,而不是又一次定制 CMS 的重复劳动。

👥 一个平台,四种身份

作者投稿、编辑分配并裁决、审稿人出意见、读者浏览关注——它们在同一个系统里,不再需要胶水代码互相缝。

🔁 完整闭环,不是 demo

稿件元数据、单盲/双盲审稿、带版本的修改稿、DOI 注册、卷期目录、浏览器内阅读且进度跨设备同步、订阅、推荐——全部打通并落到测试里。

🔒 默认安全

Passkey(WebAuthn)+ TOTP 双因素、带服务端 denylist 且可在线轮换的 JWT、注册验证码、逐操作审计日志。安全是默认值,不是 checklist。

⏱️ 几分钟自托管

一条 docker compose up 单节点起全栈。生产用 PostgreSQL 17,开发/CI 用 SQLite——不需要为本地开发准备重型环境。

一张图看懂全流程

从作者点"提交"到读者点"收藏",中间每一环都是真实可用的界面,不是流程图上的箭头。

📝
投稿
完整元数据录入、文件上传、状态可见
⚖️
审稿
单盲/双盲、审稿人分配、带版本修改稿
录用
编辑裁决、终态守卫、卷期编排
🔗
发表
DataCite 注册 DOI、进入可检索目录
📖
阅读
浏览器内 PDF、进度跨设备同步、订阅与推荐
端到端可验证:66 个 Playwright 用例跑的正是这条完整旅程——不是对着 mock 断言,而是在 Playwright 自己拉起的真实前后端上走一遍(SQLite + test 模式,注入 dev-only email-outbox 以走通注册验证链路)。

界面实拍

全部是真实运行截图,桌面 1440×900、移动端 390×844,没有设计稿占位。

ScholarHUB 界面总览:目录、审稿工作台、发表、推荐、阅读列表与阅读器
界面总览 —— 目录 · 审稿工作台 · 发表 · 推荐 · 阅读列表 · 阅读器,共 19 张截图

核心能力

每个领域能力都是独立模块,可以单独启用、替换或扩展,不需要碰 core。

能力亮点
投稿与审稿完整元数据录入、单盲/双盲工作流、审稿人分配、带版本管理的修改稿、编辑裁决、终态守卫
发表与目录卷期管理、可检索的已发表目录、通过 DataCite 注册 DOI
元数据抓取从 Crossref、arXiv、PubMed、OpenAlex、Semantic Scholar 拉取权威记录,外加 BibTeX / RIS / CSV 导入
阅读体验浏览器内 PDF 阅读、跨设备阅读进度同步、个人阅读列表、关注作者与学科
鉴权与安全WebAuthn Passkey、TOTP 双因素、JWT denylist + 密钥轮换、验证码、RBAC(作者/编辑/审稿人/读者/admin)
多租户一个部署托管多个期刊,基于 host 解析租户并带路由缓存
发现关注关系图、个性化推荐、邮件 + 站内通知、引用导出(BibTeX / RIS / CSL)

默认角色

启动时 core 自动创建,之后可在 admin 后台再分配。

角色范围
admin全部权限——admin 后台、用户管理、审计日志
editor分配审稿人、组织卷期、录用/拒稿、推到「已发表」
reviewer查看分配给自己的稿件、提交审稿意见
author投递稿件、查看自己稿件状态、上传修改稿
member阅读、收藏、订阅、查看推荐

系统架构

FastAPI async 后端 + React 19 前端,全程严格类型,模块化到 core 几乎不动。

ScholarHUB 系统架构
系统架构 —— 模块注册表驱动的后端 + 端到端类型安全的前端

🛡️ 双层租户隔离

每个领域表都带 tenant_id:应用层在每条查询上追加过滤,PostgreSQL 行级安全(RLS)即使应用层漏写也会拒掉跨租户行。是纵深防御,不是靠祈祷。

🧩 模块注册表

app.core.modules.load_all() 按依赖顺序加载模块、注册 ORM 表、挂载路由、加入健康检查。新能力 = 一处注册,core 零改动。

快速开始

三种方式,按你的场景挑一种。推荐第一条——一条命令起全栈。

🐳 Docker Compose 推荐

Postgres + 后端 + 前端全部拉起来,包含自动 TLS 的 Caddy。

# 生成强密钥
echo "SCHOLARHUB_SECRET_KEY=$(openssl rand -hex 32)" > .env
echo "SCHOLARHUB_ADMIN_PASSWORD=$(openssl rand -base64 18)" >> .env

# 启动 dev 栈
docker compose -f infra/docker-compose.yml up --build

💻 本地裸跑

需要 Python 3.12+、Node 20+,以及一个 PostgreSQL 17 实例。

# 后端
cd apps/backend && uv sync
uv run alembic upgrade head
uv run uvicorn app.main:app --reload

# 前端(另开一个终端)
cd apps/frontend && npm install && npm run dev

下载与镜像

四个远端保持同步(分支、标签、HEAD 均一致)。

GitHub · 主仓库
X33834/scholarhub
Issues / PR 都在这里
GitHub · 镜像
Morningstar202604/scholarhub
同内容镜像
GitCode
badhope/scholarhub
国内访问更快
Gitee
badhope/scholarhub
国内访问更快

质量与安全

由 CI 兜底,不是嘴上说说。

🧪 测试

后端 —— 644 个 pytest 用例,行覆盖率 84%,硬性门槛 --cov-fail-under=80mypy --strictruff 全绿。

前端 —— vitest 单元 + 组件测试,严格 tsc 下 100 个用例。

E2E —— 66 个 Playwright 用例跑完整业务旅程。

迁移 —— 独立 job 在真实 PostgreSQL 17 上跑迁移并用 alembic check 比对元数据,专门抓单元测试(内存 SQLite)永远抓不到的模型/迁移漂移。

🔐 安全

认证 —— bcrypt 哈希;短有效期 JWT access + httpOnly 刷新 Cookie + 每用户 token_version

双因素 —— RFC 6238 TOTP,每用户密钥 Fernet 加密存储,10 个一次性备份码。

Passkey —— WebAuthn 注册/认证状态机,挑战一次性且带 TTL。

密钥轮换 —— 有序密钥链,POST /api/admin/reload-secret-keys 零停机轮换。

扫描门禁 —— bandit 以 LOW+ 为门槛(历史 9 处 LOW 已清零),依赖漏洞走 pip-audit 审计锁定的依赖集。

版本一致性守卫:CI 里有个脚本四路比对 VERSION / pyproject / package.json / __version__,任何一处漂移都会直接失败 —— 避免"文档说 0.2.0、实际装的是 0.1.0"这种事。