- Rust 69.9%
- TypeScript 19.6%
- CSS 8.2%
- JavaScript 1.4%
- PowerShell 0.9%
| .config | ||
| .github | ||
| app | ||
| crates | ||
| data/meta | ||
| docs | ||
| libs | ||
| scripts | ||
| testdata/scenarios/api | ||
| .dockerignore | ||
| .gitignore | ||
| .gitleaksignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| compose.production.yaml | ||
| deny.toml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| osv-scanner.toml | ||
| README.md | ||
LitRadar
LitRadar 是一个面向学术期刊的自托管检索与订阅平台。它从 Crossref、OpenAlex、Semantic Scholar 和 CNKI 获取元数据,构建 SQLite 全文检索库,并通过 Web 界面提供检索、收藏、每周更新、文献追踪和后台管理。
能力概览
- 多数据源索引:英文期刊使用 scholarly 流程,中文期刊使用 CNKI 流程
- SQLite 检索:基于 FTS5,可自动加载仓库内置的
simple中文分词扩展 - 用户工作区:账号、邀请码、访问令牌、收藏夹和引用导出
- 文献追踪:OpenAI 兼容模型筛选、PushPlus 通知或追踪文件夹写入
- 管理后台:用户、运行配置、类型化定时任务、服务状态和公告
- 外部接入:REST API、OpenAPI/Swagger UI 和 Streamable HTTP MCP
运行组成
LitRadar 只发布一个可执行文件 litradar。litradar serve 是应用组合根:一个常驻进程同时承载 Web、REST、Swagger/OpenAPI、MCP 和持久化调度。计划任务需要隔离时,由该进程使用当前 litradar 可执行文件启动短生命周期的 index、notify 或 push 子进程;这些子进程不是独立服务。
| 组件 | 职责 |
|---|---|
crates/litradar/ |
唯一二进制、命令分发、HTTP/调度生命周期、信号和失败耦合 |
litradar serve |
唯一常驻应用进程 |
litradar <command> |
管理、索引、投递、手动调度和 OpenAPI 等按需命令 |
app/ |
Next.js 前端源码;构建为静态资源后由同一 Rust 进程提供,不是运行服务 |
完整的模块边界和数据流见系统架构。
Docker 快速开始
前提:
- Docker Engine 或 Docker Desktop
- Docker Compose
- 可生成 32 字节随机文件的
openssl
1. 准备数据目录和部署密钥
mkdir -p secrets
openssl rand -out secrets/litradar.key 32
chmod 600 secrets/litradar.key
Linux 原生 Docker Engine 还需要让容器内固定账号 10001:10001 读写数据目录:
sudo chown -R 10001:10001 data
密钥必须恰好为 32 个原始字节,并与数据库备份分开保管。已有明文集成凭据的部署应先阅读安全说明,不要直接启动。
2. 启动服务
Compose 只运行一个名为 litradar 的容器,镜像为 ghcr.io/qianfuv/litradar:latest。使用已发布镜像:
docker compose pull
docker compose up -d --remove-orphans
需要从当前源码构建时,改用 docker compose up -d --build --remove-orphans。
镜像把官方期刊目录作为不可变 bundle 放在 /usr/share/litradar/meta,持久副本位于挂载卷的 /app/data/meta。Docker bind mount 和 Kubernetes PVC 都不会把镜像目录与挂载目录合并;serve 和普通 index 会在数据库迁移后自动准备持久副本,因此不需要手工首次复制。空卷会获得官方文件,已知旧版官方文件会升级,内容相同的当前文件会被接管;同名自定义文件和清单之外的文件会保留,并产生汇总的 storage.managed_meta.prepared 事件。完整生命周期、镜像回滚限制和退役文件清理要求见 Docker 部署。
3. 初始化首个管理员
公开注册不能创建首个管理员。请从安全输入或密码管理器向 stdin 提供密码:
printf '%s\n' "$ADMIN_PASSWORD" |
docker compose run --rm -T litradar admin bootstrap \
--username admin \
--password-stdin
密码至少需要 12 个 Unicode 字符,不要把实际值写入参数、Compose 文件或命令历史。
4. 准备索引
发布镜像自带上述官方 bundle,并在命令开始时同步到持久的 data/meta/*.csv。CNKI 元数据索引不需要 scholarly API key,可先执行日常增量更新:
docker compose run --rm litradar index \
--secret-key-file /run/secrets/litradar_key \
--file chinese_journals.csv \
--update
--update 从远端当前头部扫描到上一次整刊成功的期次边界,并完整包含该边界期次;首次运行、Provider 切换或没有可复用 anchor 时会安全执行完整覆盖。只有 --update 发布 data/push_state/*.changes.json。周期性核对历史回填或旧元数据时使用独立的全量模式:
docker compose run --rm litradar index \
--secret-key-file /run/secrets/litradar_key \
--file chinese_journals.csv \
--full-rescan
--update 与 --full-rescan 互斥。两种模式默认都恢复同一模式下的冻结运行窗口;--no-resume 只清除本次 traversal checkpoint,保留上一次完整成功 anchor。删除可丢弃的 data/index-control 会失去 anchor 和恢复进度,下一次运行安全退回完整扫描,但不会改变内容 ID。
索引默认使用 --processes 1 --workers 6 --issue-batch 8,以控制容器峰值内存。--workers 限制每个期刊子进程的 CNKI 文章详情工作和 OpenAlex DOI 增强并发;Scholarly 索引最多接受 6 个 worker。--processes 启动相互独立的期刊子进程;Scholarly 索引最多接受 3 个进程,并让 Crossref 和 Semantic Scholar 的每次请求尝试(包括重试)按共同调度 epoch 错峰。可以在 Provider 约束内显式覆盖这些参数,但这不保证上游吞吐提升,也不再保证约 100 MiB 的索引内存目标。admin、index、notify、push、scheduler 和 openapi 是同步短生命周期命令,不会创建 Tokio 工作线程池;只有常驻的 serve 使用小型异步运行时。
索引 english_journals.csv 或 ccf_computer_journals.csv 前,先登录管理后台,在“运行配置”中填写 OpenAlex 和 Semantic Scholar API key。所有命令和参数见 CLI 参考,配置来源与默认值见运行配置参考。
5. 访问服务
- Web:
http://localhost:8000/ - REST API:
http://localhost:8000/api - Swagger UI:
http://localhost:8000/docs/ - OpenAPI JSON:
http://localhost:8000/openapi.json - Streamable HTTP MCP:
http://localhost:8000/mcp
生产发布、反向代理、健康检查和权限要求见 Docker 部署。
本地开发
项目使用 Rust 1.96、Node.js 24 和 pnpm 10.32.0。开发环境、代码生成和检查命令统一记录在开发指南,前端包的内部结构见前端说明。
文档
从文档中心按目标查找资料:
License
本项目使用 MIT License。