星轨平台 MVP 用于验证学生发现竞赛/科研机会、发布组队招募、申请科研项目和维护证书记录的核心流程。
public/: 静态页面和样式src/: 领域逻辑、浏览器交互、前端请求模块、配置加载、SQLite 存储、文件存储和服务端操作模块tests/: 领域、服务端操作、配置、SQLite、文件存储、前端请求和 UI 行为测试scripts/: 本地启动、种子数据、Tunelo 预览、Android 资源同步和运维脚本mobile/: Android App 构建时配置、打包说明和生成的 Web 资源目录android/: Capacitor 生成的 Android 原生工程MVP/: 课程要求的优先级清单和验证反馈报告CONTEXT.md: 项目领域词汇表
- Node.js 20 或更高版本
- npm 10 或更高版本
正式化后的本地服务使用 Node 内置 node:sqlite,推荐 Node.js 24 或更高版本。Node 当前会提示 SQLite 是实验特性,不影响本地运行;如果要部署生产环境,建议后续切换到稳定 SQLite 驱动或服务端数据库驱动。
在仓库根目录执行:
git clone <仓库地址>
cd final
npm install
npm start启动后访问:
http://localhost:4173
如需换端口:
PORT=4300 npm startWindows PowerShell:
$env:PORT=4300; npm start也可以在仓库根目录创建 .env 保存本地配置。.env 中的配置会被读取,命令行环境变量会覆盖 .env:
PORT=4300
SMTP_HOST=smtp.163.com
SMTP_PORT=465
SMTP_USER=your-email@163.com
SMTP_PASS=163 邮箱 SMTP 授权码
SMTP_FROM=星轨平台 <your-email@163.com>
MOBILE_ALLOWED_ORIGINS=https://localhost,http://localhost,capacitor://localhost
注册新账号时需要先发送并填写 6 位邮箱验证码。验证码 10 分钟内有效,同一邮箱 60 秒内不能重复发送,最多允许输错 5 次。
如果没有配置 SMTP,验证码会输出在运行 npm start 的服务端控制台,适合本地演示:
[邮箱验证码] user@example.com: 493812,10 分钟内有效
如果需要真实发送邮件,推荐在 config/smtp.json 填写 163 邮箱 SMTP 配置:
{
"host": "smtp.163.com",
"port": 465,
"user": "your-email@163.com",
"pass": "163 邮箱 SMTP 授权码",
"from": "星轨平台 <your-email@163.com>"
}config/smtp.json 已加入 .gitignore,不要提交真实授权码。仓库里保留了 config/smtp.example.json 作为模板。
也可以启动前配置这些环境变量,环境变量会覆盖配置文件:
SMTP_HOST=smtp.163.com
SMTP_PORT=465
SMTP_USER=your-email@163.com
SMTP_PASS=163 邮箱 SMTP 授权码
SMTP_FROM="星轨平台 <your-email@163.com>"
npm startWindows PowerShell:
$env:SMTP_HOST="smtp.163.com"
$env:SMTP_PORT="465"
$env:SMTP_USER="your-email@163.com"
$env:SMTP_PASS="163 邮箱 SMTP 授权码"
$env:SMTP_FROM="星轨平台 <your-email@163.com>"
npm startSMTP_PASS 通常不是邮箱登录密码,而是在邮箱设置里开启 SMTP/POP3/IMAP 后生成的授权码。常见获取方式:
- QQ 邮箱:设置 -> 账号 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务 -> 开启 SMTP 服务 -> 生成授权码。
- 163 邮箱:设置 -> POP3/SMTP/IMAP -> 开启服务 -> 新增客户端授权密码。
- 企业邮箱或学校邮箱:在邮箱后台开启 SMTP 服务,或向邮箱管理员申请 SMTP 主机、端口、账号和授权码。
当前本地邮件发送器支持 SMTP_PORT=465 的 SSL SMTP。
邮件发送使用 Nodemailer。发送失败时,页面会显示明确错误提示和错误码,例如 SMTP 授权码错误、SMTP 服务未开启或本地服务未连接。
已验证 jiweiyuan/tunelo 适合这个 MVP:它可以用 tunelo port 4173 把本地 npm start 服务通过 tunelo.net 公共中继暴露成公网 URL。
本地已将 Tunelo 源码 clone 到 tools/tunelo/,该目录已加入 .gitignore,不会提交到 GitHub。脚本找不到 tunelo 时会自动运行对应平台的官方安装脚本。
Linux/macOS Bash 一行命令:
./scripts/expose-tunelo.shWindows PowerShell 一行命令:
.\scripts\expose-tunelo.ps1脚本路径是 scripts/expose-tunelo.sh 和 scripts/expose-tunelo.ps1。它们会自动选择可用端口并运行 tunelo port <端口> -- npm start,Tunelo 输出的 Public URL: https://... 就是可分享给其他人访问的地址。默认公开访问,所有拿到链接的人都能和你一样在网页里选择学生、导师、证书收集者或管理员等角色。
需要指定端口时:
./scripts/expose-tunelo.sh --port 4173.\scripts\expose-tunelo.ps1 -Port 4173需要临时加访问密码时:
./scripts/expose-tunelo.sh --port 4173 --password.\scripts\expose-tunelo.ps1 -Port 4173 -Password当前支持把网页封装成 Android App,后端仍运行在这台电脑上,通过 Tunelo 暴露 HTTPS 地址。把 Tunelo 地址填入 mobile/app.config.json 后,执行:
npm run android:sync
cd android
./gradlew assembleDebug首次创建原生工程时使用 npm run android:init;当前仓库已经包含 android/ 工程,后续网页或 Tunelo 地址变更后执行 android:sync 同步资源,再用 Gradle 重新生成 APK。Debug 安装包输出到 android/app/build/outputs/apk/debug/app-debug.apk。详细步骤见 mobile/README.md。
在仓库根目录执行:
npm test测试覆盖:
- 学生注册与登录
- 竞赛/科研机会浏览与筛选
- 组队招募发布与竞赛详情展示
- 科研项目申请与导师侧查看
- 证书记录上传校验与列表展示
- 服务端登录/注册接口行为和公开状态脱敏
- SQLite 持久化、配置加载、证书文件存储和前端请求模块
- 管理员软删除和审计日志
- 管理员注册待审核、初始管理员种子和演示数据种子
- Android App 封装、构建时后端地址配置和同步脚本
已完成:
- 学生本地注册登录
- 登录前只显示居中的大登录页;登录后隐藏登录区,右上角提供退出登录
- 注册时选择权限身份:学生、导师、证书收集者、管理员
- 管理员注册后默认为待审核,需要已有管理员通过后才能登录
- 注册时支持邮箱验证码验证;未配置 SMTP 时在服务端控制台输出验证码,配置后可真实发送邮件
- 邮箱验证码通过 Nodemailer 发送;发送失败时会在页面显示可读错误提示
- 机会大厅,支持分页浏览机会列表,每页 6 条
- 学生、导师、证书、管理员和反馈等陈列列表均支持分页
- 竞赛组队招募,支持学生结束招募、重新招募或二次确认后删除自己的招募
- 科研申请、导师发布/删除科研项目、导师审批申请
- 学生可查看科研申请结果;通过后显示后续联系方式,未通过显示导师反馈
- 学生可删除自己的科研申请和证书记录
- 独立证书中心,支持图片证书预览、学生证书记录保存、证书收集者汇总查看
- 证书收集者可按竞赛折叠查看、下载单份证书,并一键导出竞赛证书 zip 合集
- 管理员模式,可查看注册用户、封禁或删除用户、查看可读数据库视图,并软删除竞赛、科研项目和测试记录
- 管理员删除数据库记录时会写入审计日志,业务列表会过滤已软删除记录
- 管理员可新增竞赛和科研项目,新增内容会进入机会大厅
- 初始管理员种子可只创建一个管理员,演示数据种子可写入课堂展示数据
- 使用信息记录与手动反馈收集
- 演示数据:几十名用户、口语化组队招募、科研申请、证书记录、使用记录和手动反馈
- SQLite 本地数据库持久化,运行本地服务时数据保存到
data/xinggui.sqlite - 新注册账号使用带盐
scrypt密码哈希;旧演示账号保持兼容登录 - 证书文件上传后保存到
data/uploads/certificates/,业务数据只保存文件访问 URL - Android App 通过 Capacitor 封装,
mobile/app.config.json在构建时指定后端 HTTPS 地址
暂不包含:
- 生产级后端数据库部署
- 真实文件上传到对象存储
- PDF 证书缩略图渲染
- 身份真实性核验
运行 npm start 时,本地服务会通过 SQLite 读写 data/xinggui.sqlite。证书文件保存到 data/uploads/certificates/。整个 data/ 目录是本地数据目录,已加入 .gitignore,不会提交到 GitHub。
当前服务默认使用初始管理员种子。首次启动空数据库时会得到一个可登录管理员,不会自动写入完整演示项目数据。管理员账号:
邮箱:admin@whu.edu.cn
密码:admin12345
身份:管理员
需要重置为只有初始管理员时:
npm run seed:initial-admin需要写入课堂演示数据时:
npm run seed:demo注意:seed:demo 会用演示状态覆盖当前数据库,演示管理员密码是 admin。如果要保留 admin12345 的初始管理员并只合并演示项目数据,需要使用领域合并函数处理,不能直接运行 seed:demo。
页面仍会把数据同步到浏览器 localStorage 作为兜底。需要清空数据时,可删除 data/xinggui.sqlite 和 data/uploads/,也可在浏览器开发者工具中删除 xinggui_mvp_state_v1 和 xinggui_mvp_session_v1。ok