除 Docker 镜像外,每个版本还提供以下安装包,均可在 GitHub Releases 下载(npm 包发布到 npm 仓库)。
| 平台 | 文件 | 说明 |
|---|---|---|
| npm | npm install -g wrong-notebook |
需要 Node.js 22.15 及以上,适合服务器或已有 Node 环境 |
| Windows | WrongNotebook-Win-Setup-<版本>-x64.exe / WrongNotebook-Win-Portable-<版本>-x64.exe |
安装版 / 免安装版 |
| macOS | WrongNotebook-Mac-<版本>-arm64.dmg(Apple 芯片)/ -x64.dmg(Intel),另有同名 .zip |
本地自签名(ad-hoc),未经 Apple 公证;首次打开需到「系统设置 → 隐私与安全性」点击「仍要打开」 |
| Linux | WrongNotebook-Linux-<版本>-<架构>.AppImage / .deb |
x86_64 与 arm64 |
| 飞牛OS | WrongNotebook-FnOS-<版本>-x86.fpk / -arm.fpk |
在应用中心手动安装,依赖应用中心的 Node.js v24 |
| 群晖 DSM | WrongNotebook-Synology-<版本>-x86_64.spk / -arm64.spk |
套件中心手动安装;内置镜像的 Docker 套件,需 Container Manager |
| 威联通 QTS | WrongNotebook-QNAP-<版本>-x86_64.qpkg / -arm64.qpkg |
App Center 手动安装;内置镜像的 Docker 套件,需 Container Station |
| 安卓手机 | WrongNotebook-Android-Phone-<版本>.apk |
单机版,内置服务端,无需部署服务器;锁定竖屏 |
| 安卓平板 | WrongNotebook-Android-Tablet-<版本>.apk |
单机版,内置服务端,无需部署服务器;横竖屏自动旋转 |
| 安卓手机 / 平板(客户端) | WrongNotebook-Android-Client-Phone-<版本>.apk / -Client-Tablet-<版本>.apk |
客户端版,连接已部署的服务器 |
校验和见 Release 中的 SHA256SUMS.txt。
除安卓客户端版和群晖/威联通 Docker 套件外,所有安装包(含安卓单机版)运行同一个服务端(Next.js standalone 构建)和启动器 packaging/runtime/launcher.js,行为与 Docker 镜像一致;群晖/威联通套件直接运行同版本 Docker 镜像:
- 首次启动复制预置数据库(含系统标签,不含管理员)。服务启动后在日志中打印一次性初始化链接,令牌同时保存在数据目录的
config/setup-token;打开链接设置管理员账号后令牌即删除。桌面版和安卓单机版会自动打开该链接。 - 每次启动执行
prisma migrate deploy,只做增量迁移,升级保留已有数据。 - 启动时增量补齐小学、初中和高中语文的内置章节与知识点,并补齐大学各学科的年级根节点(大一 ~ 大四,不含知识点,供 AI 生成的标签挂载);不删除已有标签,保留标签 ID、题目关联、自定义标签和其他标签体系;重复启动不会重复创建。
- 数据库、
config/app-config.json和自动生成的 NextAuth 密钥都在数据目录,安装目录可以只读。
npm install -g wrong-notebook
wrong-notebook --port 3000 --host 0.0.0.0 --data-dir ~/.wrong-notebook- 数据目录默认
~/.wrong-notebook,也可用环境变量WRONG_NOTEBOOK_HOME。 - 安装时由 postinstall 按本机平台生成 Prisma Client 并下载引擎。国内网络可设置
PRISMA_ENGINES_MIRROR=https://registry.npmmirror.com/-/binary/prisma。 - 需要后台常驻时可交给 systemd、pm2 等进程管理工具。
桌面版基于 Electron,内置服务端,打开即用:
- 服务只监听
127.0.0.1,默认端口 39300,被占用时自动顺延。 - 数据目录:Windows
%APPDATA%\WrongNotebook\data,macOS~/Library/Application Support/WrongNotebook/data,Linux~/.config/WrongNotebook/data。服务日志在数据目录的logs/server.log。 - 卸载不会删除数据目录。
- 当前 Windows 安装包仍未签名,可能出现 SmartScreen 提示,选择「仍要运行」。项目已通过 SignPath Foundation 审核,正在用测试证书接入,取得生产证书后按 Windows 签名配置启用;实际签名范围和职责见 Code signing policy,数据处理见隐私说明。
- macOS 安装包在打包时做了 ad-hoc 签名(
packaging/desktop/package.json中mac.identity为-,并关闭 hardened runtime),整个.app能通过codesign --verify --deep --strict,但未经 Apple 公证,Gatekeeper 仍会拦截首次打开。在「系统设置 → 隐私与安全性」点击「仍要打开」即可;若仍提示「已损坏」(旧版本安装包常见),执行xattr -cr /Applications/WrongNotebook.app和codesign --force --deep --sign - /Applications/WrongNotebook.app(移除隔离属性并在本机重新自签名)。 - Linux 的 Prisma 引擎需要 OpenSSL 3(Ubuntu 22.04、Debian 12 及更新版本)。
- 在应用中心安装 Node.js v24。
- 应用中心 →「手动安装」,选择与设备架构对应的
.fpk。安装向导中设置管理员邮箱和密码(至少 6 位,不能是123456);安装脚本只保存密码的 bcrypt 哈希(config/initial-admin.json),服务首次启动时据此创建管理员后删除该文件。向导最后一步须勾选同意使用协议,同意的版本一并写入该文件,首次启动时记为管理员已同意并默认开启匿名遥测外发(可在设置中关闭)。 - 安装后从桌面图标打开,用向导中设置的账号登录,服务端口 39300,局域网内其他设备也可通过
http://<NAS 地址>:39300访问。
数据保存在应用数据目录(@appdata/wrongnotebook),日志为其中的 wrong-notebook.log。保留旧数据重装时沿用原有账号,向导中填写的管理员会被忽略;向导设置失败时(见 install.log),改用 wrong-notebook.log 中的初始化链接。
- 先在套件中心安装 Container Manager(20.10.23-1432 及以上)。
- 套件中心 →「手动安装」,按 NAS 的处理器选择
WrongNotebook-Synology-<版本>-x86_64.spk(Intel / AMD)或-arm64.spk(64 位 ARM);需要 DSM 7.2.1 及以上,不依赖 NAS 的 Node.js。 - 套件在 Container Manager 中创建项目
wrong-notebook,加载内置的ghcr.io/margrop/wrong-notebook:<版本>镜像并映射主机端口39300→ 容器3000;安装时无需联网拉取镜像。 - 从 DSM 主菜单的「错题本」图标或
http://<NAS>:39300进入应用,首次启动按页面提示设置管理员。升级套件会按新镜像重建容器并保留数据;卸载套件会移除容器和镜像,保留数据目录,重装后可继续使用。
数据在套件数据目录 /volumeN/@appdata/wrongnotebook(数据库、config/ 和自动生成的会话密钥 .nextauth_secret)。该目录在 File Station 中不可见,备份请用应用内的数据导出,或通过 SSH 复制。
套件只管理容器,不内置 Node.js;需保持 Container Manager 运行。实现上有几点由 DSM 7 决定:
- SPK 外层是未压缩的 tar;用 gzip 压缩时套件中心提示「套件文件格式不正确」,
build.mjs打包后会检查。 - 第三方套件不能以 root 运行(
conf/privilege为run-as: package),套件脚本无法调用 docker。容器由conf/resource的docker-project资源按package/compose/compose.yaml创建,并随套件启停;start-stop-status只按端口是否响应报告状态。 docker-project会强制容器以套件用户运行,镜像入口脚本在非 root 下不改属主、不降权;数据卷因此使用套件用户可写的套件数据目录,配置经CONFIG_DIR放在其中。INFO不声明adminport:Container Manager 会为容器端口登记服务,卸载后登记仍在,声明同一端口会让重装报端口冲突。入口改由dsmuidir(package/ui/config)提供主菜单图标。
- 先在 App Center 安装 Container Station。
- App Center →「手动安装」,按 NAS 的处理器选择
WrongNotebook-QNAP-<版本>-x86_64.qpkg(Intel / AMD)或-arm64.qpkg(64 位 ARM);不依赖 NAS 的 Node.js。 - 套件脚本检查 Docker、加载内置的同版本镜像(本地已有该版本时直接使用,归档不可用时才联网拉取)、生成
NEXTAUTH_SECRET、映射主机端口39300→ 容器3000,数据放在/share/Container/wrong-notebook/{data,config}。 - App Center 的打开链接进入应用,首次启动按页面提示设置管理员。升级套件会按新镜像重建容器并保留数据;卸载套件保留数据目录,重装后可继续使用。
套件只管理容器,不内置 Node.js;需保持 Container Station 运行。
安卓 App(packaging/android)分两种,各有手机版(Phone,锁定竖屏)和平板版(Tablet,横竖屏自动旋转)。安装时需允许「安装未知来源应用」。
单机版 WrongNotebook-Android-<Phone|Tablet>-<版本>.apk |
客户端版 WrongNotebook-Android-Client-<Phone|Tablet>-<版本>.apk |
|
|---|---|---|
| 服务端 | 内置,在手机上运行 | 需先用 Docker 或其他安装包部署 |
| 数据 | 保存在本机,卸载 App 时删除 | 保存在服务器 |
| 安装包大小 | 约 75MB | 约 2MB |
| 系统要求 | Android 8.0 及以上,64 位 ARM(arm64-v8a) | Android 7.0 及以上 |
| 系统 WebView | Android System WebView 111 及以上,过旧时页面顶部提示升级 | 同左 |
| 包名 | com.margrop.wrongnotebook.standalone |
com.margrop.wrongnotebook |
两种 App 包名不同,可以同时安装;同一种的手机版和平板版包名相同,可以互相覆盖安装。
APK 内置 Node.js、Prisma 引擎和与其他安装包相同的服务端:
- 打开 App 时在本机启动服务端(只监听
127.0.0.1,其他设备无法访问)。首次启动或升级后需要先解压服务端并初始化数据库,会稍慢一些。 - 首次启动自动打开初始化页,设置管理员邮箱和密码后进入安装向导,配置 AI 渠道并创建第一个错题本。
- 数据库、配置和日志保存在 App 私有目录(
files/data),卸载 App 会删除全部数据。数据中含 API Key 等敏感信息,两种 App 都不参与系统备份(allowBackup=false),卸载或换机前请在「设置」中导出备份,到新设备上再导入。
App 切到后台后系统可能结束服务端进程,回到前台时会自动重新启动。
客户端版是原生 WebView 外壳,不内置服务端:
- 首次打开填写服务器地址,如
http://192.168.1.10:3000,省略协议时默认http://。客户端会请求/api/health确认是错题本服务器;检查失败(如自签名证书)时可选择仍然使用。 - 之后在「设置 → 关于」中可查看当前服务器并更换;连接失败的页面上也有「更换服务器」按钮。
局域网部署通常使用 HTTP,客户端允许明文连接。使用自签名证书的 HTTPS 时,首次访问会提示证书不受信任,确认后在本次运行中信任;也可以在系统中安装该证书的 CA,之后不再提示。
两种 App 都补齐了 WebView 默认不具备的能力:
- 网页的「拍照」「相册」「从文件选择」分别打开系统相机、照片选择器(Android 13 起为系统照片选择器)和文件选择器;拍照调用系统相机应用,App 不申请相机权限,相机不可用时提示改用相册或文件。「从文件选择」不限类型,图片类入口额外列出 HEIC/HEIF 类型,便于选到被系统标成未知类型的照片。
- 导出备份、下载试卷等文件通过系统「另存为」保存;保存完成后提示「已保存到 <文件名>」,取消时不误报导出成功。导出文件可能很大(含题目原图、云端语音),网页分块写入 App 目录的临时文件后再复制到用户选择的位置,保存对话框期间 App 被系统回收也不会丢失内容。
- 打印预览中的「打印」调用系统打印,可另存为 PDF。
- 错题本以外的链接(项目主页、AI 服务商控制台等)用系统浏览器打开。
网页可以通过 User-Agent 中的 WrongNotebookAndroid/<版本> (phone|tablet) 识别 App,App 向网页提供的接口见 src/lib/android-app.ts。
需要 Node.js 22.15 及以上。Prisma 引擎与构建机平台一致,桌面版和飞牛OS 包须在目标平台(及架构)上构建;群晖/威联通套件为 Docker 套件,可在任意 Linux 构建。
npm ci
node scripts/package/build.mjs bundle # 构建通用服务端包 dist/bundle
node scripts/package/build.mjs npm # dist/wrong-notebook-<版本>.tgz
node scripts/package/build.mjs desktop --mac --arm64 # 参数原样传给 electron-builder
node scripts/package/build.mjs fnos --arch x86 # 需要 PATH 中有 fnpack
node scripts/package/build.mjs synology # 群晖 SPK(noarch,安装时在线拉取镜像),无需 bundle
node scripts/package/build.mjs synology --arch x86_64 --image image.tar.gz # 内置镜像的群晖 SPK,qnap 同
node scripts/package/build.mjs qnap # 威联通 QPKG,需要 PATH 中有 QDK qbuild
bash scripts/package/build-android-prisma-engines.sh dist/android-prisma-engines # 安卓单机版需要的 Prisma 引擎
node scripts/package/build.mjs android # 单机版和客户端版 APK,可加 --mode standalone|client、--flavor phone|tablet群晖 SPK 和威联通 QPKG 是 Docker 套件,不打包 Node.js 或 Prisma 引擎;构建时只生成 compose 项目(群晖)或容器控制脚本(威联通)、INFO/qpkg.cfg 和图标。发版时 Packages 工作流等同一标签的镜像推送到 ghcr.io 后,用 skopeo 按架构导出为 docker save 格式的归档(--image,gzip 压缩,镜像名须为 ghcr.io/margrop/wrong-notebook:<版本>),内置进套件并按 --arch x86_64 / arm64 分别出包(每个约 120 MB):群晖经 docker-project 的 preload-image 加载,威联通把归档放进 QDK 的架构目录,启动时 docker load。不传 --image 时生成安装时在线拉取镜像的 noarch 套件,用于本地调试。qnap 需要 QDK 2.5.3:/usr/share/QDK/bin 加入 PATH,qbuild 生成自解压 .qpkg。
桌面版使用 Electron 45(内置 Node.js 24)和 electron-builder 26,服务端由 Electron 自带的 Node 运行。electron-builder 26 复制 extraResources 时总会跳过来源目录根层的 node_modules,因此 packaging/desktop/package.json 把 server/node_modules 单独列为一项;打包后 build.mjs 会检查 Prisma Client 等关键文件是否进入安装包。
PDF 导入的浏览器端解析需要 pdfjs-dist 的 CMap 与标准字体数据(public/pdfjs/),npm run build 前会通过 prebuild 自动从 pdfjs-dist 包内复制到 public/pdfjs/(约 2.5MB),无需手动处理。
安卓 APK 构建需要 JDK 17、Android SDK(ANDROID_HOME,compileSdk 35、build-tools 35.0.0)和 Gradle 8.11(PATH 中的 gradle,或用环境变量 GRADLE 指定)。客户端版不依赖 bundle;单机版还需要:
dist/bundle:与其他安装包相同的服务端。- 安卓 Prisma 引擎:Prisma 不提供安卓版本,
build-android-prisma-engines.sh按项目安装的 Prisma 版本下载对应提交的 prisma-engines 源码,用 Android NDK(ANDROID_NDK_HOME)和 rustup 交叉编译查询引擎与迁移引擎,约需 15–30 分钟。输出目录默认dist/android-prisma-engines,可用ANDROID_PRISMA_ENGINES_DIR指定。 patchelf(可用PATCHELF指定路径)和zip。
单机版内置的 Node.js 取自 Termux 软件源的 nodejs(当前 26.x,依赖 libicu 79;nodejs-lts 24.22 仍依赖 libicu 78,与软件源已更新的 libicu 79.1 不兼容)及其依赖库(构建时按软件源索引校验 SHA256,可用 TERMUX_MIRROR 指定镜像)。安卓只允许执行 nativeLibraryDir 中的程序,因此 Node.js、依赖库和引擎都以 lib*.so 的形式放进 jniLibs/arm64-v8a,由 scripts/package/android-runtime.mjs 改名并用 patchelf 改写依赖;服务端打包为 assets/server.zip,首次启动时解压。各组件的许可证随 APK 放在 assets/licenses/。网页端按需加载的 HEIC/HEIF 转换组件(heic-to 及其包含的 libheif、libde265)的第三方说明与许可证位于 public/third-party-licenses/heic-to/,随服务端 public/ 目录进入 Docker 镜像、npm 包、桌面版、飞牛OS 安装包和单机版的 server.zip。
versionCode 由版本号换算(scripts/package/android-version.mjs):预览版 2026.10.22-3 为 2026102203,正式版 2026.10.22 为 2026102299,保证升级时递增。
签名密钥通过环境变量传入:ANDROID_KEYSTORE_FILE(密钥库路径)、ANDROID_KEYSTORE_PASSWORD、ANDROID_KEY_ALIAS、ANDROID_KEY_PASSWORD(缺省与密钥库密码相同)。未提供时使用调试签名,只能用于测试。
- 版本号依次取
--version、环境变量PACKAGE_VERSION、package.json。 bundle会构建 Next.js;只改了打包脚本时可加--skip-build复用已有的.next。- 产物全部输出到
dist/(已加入.gitignore)。打包时会移除 standalone 带入的.env、config/和数据库文件,避免把本机密钥打进安装包。
推送 v* 标签后,.github/workflows/packages.yml 在各平台 Runner 上构建全部安装包并上传到对应的 GitHub Release;也可以在 Actions 页面手动运行,只生成构建产物。安卓 Prisma 引擎按引擎提交缓存,只有升级 Prisma 或修改编译脚本后才需要重新编译。
安卓 APK 必须一直使用同一个密钥签名,否则用户无法覆盖安装升级。需要在仓库 Settings → Secrets and variables → Actions 中配置:
| Secret | 说明 |
|---|---|
ANDROID_KEYSTORE_BASE64 |
密钥库文件的 Base64(base64 -i release.jks) |
ANDROID_KEYSTORE_PASSWORD |
密钥库密码 |
ANDROID_KEY_ALIAS |
密钥别名 |
ANDROID_KEY_PASSWORD |
密钥密码,与密钥库密码相同时可不配置 |
推送标签时未配置这些 Secret,安卓构建会失败,Release 也不会上传安装包;手动运行时使用调试签名。密钥库须妥善备份,丢失后已安装的用户只能卸载重装。
npm 使用 Trusted Publishing(OIDC)发布,不需要 NPM_TOKEN。npmjs.com 上 wrong-notebook 包的 Settings → Trusted Publisher 已登记 GitHub Actions:margrop/wrong-notebook、工作流 packages.yml;重命名该工作流文件时需同步修改登记。带 - 的预发布标签发布到 npm 的 next 标签。npm 发布在独立的 Job 中,失败不影响安装包上传到 Release。
| 路径 | 说明 |
|---|---|
scripts/package/build.mjs |
构建脚本 |
packaging/runtime/launcher.js |
各安装包共用的启动器 |
packaging/npm/ |
npm 命令行入口与 README |
packaging/desktop/ |
Electron 桌面壳与 electron-builder 配置 |
packaging/fnos/ |
飞牛OS manifest、生命周期脚本、安装向导和图标 |
packaging/android/ |
安卓 App Gradle 工程(单机版 / 客户端版 × 手机版 / 平板版) |
scripts/package/android-runtime.mjs |
组装安卓单机版内置的 Node.js、Prisma 引擎和服务端 |
scripts/package/build-android-prisma-engines.sh |
交叉编译安卓 Prisma 引擎 |
各安装包的启动器设置环境变量 WN_PLATFORM,用于匿名遥测的 instance_alive 事件区分部署形态:Docker 镜像为 docker,直接运行 npm 包为 npm,桌面版为 desktop,飞牛OS 为 fnos,安卓单机版为 android,其他方式缺省为 other。该值只取以上枚举,不包含任何实例标识;设置 TELEMETRY_DISABLED=true 可关闭全部遥测,见隐私说明。