API 基址为当前站点的 /api。成功响应使用 JSON,删除成功返回 204 No Content;失败通常返回 { "error": "..." }。请求体默认限制为 256 KB。
公开读取和提交问卷不需要 Token。管理接口使用以下任一方式:
Authorization: Bearer <Admin Token>也兼容 x-admin-token 请求头、?token= 查询参数和会话 Cookie。首次初始化后,浏览器推荐使用账号密码登录,服务器签发 7 天 HttpOnly 会话 Cookie。Admin Token 应只通过受保护的启动横幅、环境变量或数据目录管理,不要放进公开链接、日志或源码。
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/api/health |
检查进程和数据库连接 |
GET |
/api/config |
获取站点名称、图标、主题和页脚配置 |
GET |
/api/setup/status |
查询是否完成初始化 |
POST |
/api/setup |
首次创建唯一管理员和站点设置 |
POST |
/api/auth/login |
账号密码登录 |
GET |
/api/auth/me |
获取当前认证用户 |
POST |
/api/auth/logout |
注销当前会话 |
GET |
/api/surveys/:id |
获取有效公开问卷,不含标准答案 |
POST |
/api/surveys/:id/responses |
提交答卷并返回结果 |
健康检查正常时返回 200:
{
"status": "ok",
"database": "ok",
"uptime": 12.34,
"timestamp": "2026-08-28T12:00:00.000Z"
}提交示例:
curl -X POST http://localhost:3000/api/surveys/<survey-id>/responses \
-H 'Content-Type: application/json' \
-d '{"answers":{"<survey-question-id>":"VS Code"}}'提交成功返回 id、message、kind、score 和 maxScore。服务器会重新校验题目 ID、必填项、选项和文本长度;考试分数由服务器计算。
普通用户使用独立的 questra_user_session HttpOnly Cookie,与管理员会话和 Admin Token 不互通。注册、登录、验证和密码重置的写请求要求同源,并受独立限流保护。
| 方法 | 路径 | 用途 |
|---|---|---|
POST |
/api/user/auth/register |
注册并发送验证邮件 |
POST |
/api/user/auth/verify |
消费邮箱验证 Token |
POST |
/api/user/auth/resend-verification |
重发验证邮件 |
POST |
/api/user/auth/login |
邮箱密码登录 |
GET |
/api/user/auth/me |
获取当前普通用户 |
POST |
/api/user/auth/logout |
注销普通用户会话 |
POST |
/api/user/auth/forgot-password |
请求重置密码邮件 |
POST |
/api/user/auth/reset-password |
使用 Token 设置密码 |
PUT |
/api/user/profile |
修改显示名称 |
PUT |
/api/user/password |
修改当前密码 |
注册、重发和找回密码接口使用不暴露账户是否存在的统一响应。未验证用户可以登录,但访问 verified_email 问卷时返回 403。
所有 /api/admin/* 接口都需要管理认证。
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/api/admin/dashboard |
仪表盘指标、按实例趋势和最新回收流水 |
GET |
/api/admin/settings |
站点和管理员资料 |
PUT |
/api/admin/settings/site |
修改站点标识、主题和页脚配置 |
PUT |
/api/admin/settings/account |
修改唯一管理员昵称、账号或密码 |
GET |
/api/admin/update/status |
查询当前版本的安装来源和更新能力 |
GET |
/api/admin/update |
从 GitHub Releases 检测最新正式版本 |
POST |
/api/admin/update/install |
使用 npm 全局安装服务端校验后的最新版本 |
GET |
/api/admin/questions |
查询题库,包含标准答案 |
POST |
/api/admin/questions |
创建题目 |
PUT |
/api/admin/questions/:id |
更新题目 |
DELETE |
/api/admin/questions/:id |
删除题目 |
GET |
/api/admin/groups |
查询分组 |
POST |
/api/admin/groups |
创建分组 |
PUT |
/api/admin/groups/:id |
重命名分组 |
DELETE |
/api/admin/groups/:id |
删除分组 |
GET |
/api/admin/surveys |
查询问卷和考试列表 |
POST |
/api/admin/surveys |
从题库生成问卷或考试 |
GET |
/api/admin/surveys/:id |
查看实例和题目快照 |
PUT |
/api/admin/surveys/:id |
修改实例类型、基本信息、题目和计分结构 |
GET |
/api/admin/surveys/:id/access |
查看问卷访问与限制策略 |
PUT |
/api/admin/surveys/:id/access |
修改问卷访问与限制策略 |
GET |
/api/admin/user-settings |
查看普通用户注册和邮件配置状态 |
PUT |
/api/admin/user-settings |
开关普通用户注册 |
GET |
/api/admin/users |
查询普通用户(仅管理员) |
PUT |
/api/admin/users/:id/status |
启用或禁用用户 |
POST |
/api/admin/users/:id/revoke-sessions |
撤销用户全部会话 |
DELETE |
/api/admin/users/:id |
删除用户并匿名化历史答卷 |
DELETE |
/api/admin/surveys/:id |
删除实例及其答卷 |
GET |
/api/admin/surveys/:id/responses |
查看答卷与逐题判分 |
GET |
/api/admin/surveys/:id/export |
导出 CSV 或 JSON;includePersonalInfo=1 时显式包含完整邮箱,默认不包含 |
站点设置中的 footerCopyright 是最长 300 个字符的纯文本模板,支持 {year} 和 {siteName} 占位符,并继续兼容历史保存的 {{year}}、{{siteName}} 写法;去除首尾空白后为空表示页脚不显示版权文字。footerProgram 只接受 powered_by、built_with 或 open_source。GET /api/config、GET /api/setup/status 和公开问卷响应会返回当前页脚配置,前端不得把模板作为 HTML 执行。
GET /api/admin/dashboard 默认查询包含当前 UTC 日期在内的近 7 天趋势。range=month 查询近 30 天;range=custom&startDate=2026-08-01&endDate=2026-08-31 按 YYYY-MM-DD 指定包含首尾的 UTC 自然日范围。自定义范围最长 366 天,日期缺失、无效、倒置或超过上限时返回 400。
响应中的 totals 提供题库题量、实例总量、有效活跃实例数、累计答卷数和近 7 天考试平均得分率。考试平均分按每份答卷的 score / maxScore * 100 标准化;没有可计分答卷时为 null。trend 是每日总量,trendBySurvey 是每日按实例分组的数据,surveyTotals 是所选范围内各实例汇总,recentResponses 是全站最近 20 条真实答卷流水,并包含 participant.displayName 或 null。todayOverview 提供当天回收量、考试提交数和通过率;通过率按已评分考试中得分率不低于 60% 的比例计算,无已评分考试时为 null。alerts.highErrorQuestions 是至少 3 次作答且错误率不低于 50% 的题目,alerts.expiringSurveys 是未来 7 天内到期的活跃实例。流水状态只包含已成功写入的 submitted 和已完成计分的 graded。原有 active_surveys 与 recentSurveys 字段继续保留以兼容已有调用。
更新状态接口返回 installationType(source 或 global)、sourceBuild 和 updateSupported,用于在联网前识别源码构建版。源码构建版不会访问 GitHub,检测和安装操作均被禁用,并提供源码仓库入口。
更新检测会读取 GitHub Releases 中所有已发布且非草稿、非预发布的正式版本。只有当前版本号确实存在于该列表时才算合规;合规版本返回最新正式版本、versionsBehind(落后版本数量)、updateAvailable、Releases 总入口、发布时间和更新说明。不在列表中的版本返回 invalidVersion: true,检测和安装均不可用,页面会提示重新安装最新正式版。安装接口不接受包名或版本参数,会重新读取并校验 Release,只执行固定包名的全局 npm 安装;成功响应包含 installedVersion、restartRequired: true 和截断后的 npm 输出。安装成功不会自动重启当前进程。
更新接口需要管理认证。安装操作还要求服务器能够访问 GitHub 与 npm,并拥有 npm 全局目录写权限;重复安装任务返回 409,外部服务或 npm 失败会返回可读错误。源码目录不会被此接口修改。
创建单选题:
{
"title": "你使用什么编辑器?",
"type": "single",
"options": ["VS Code", "Vim"],
"correctAnswer": "VS Code",
"groupIds": [2]
}type 可为 single、multiple、judgment、text(填空)或 open_text(开放文本)。判断题选项固定为“正确”和“错误”;多选标准答案为数组;填空题可配置多个可接受答案。开放文本不保存标准答案,在考试中不参与自动计分。题库仍接受旧请求中的 required 以保持兼容,但新的管理界面会在实例中设置是否必填。
手动生成普通问卷:
{
"kind": "survey",
"title": "产品反馈",
"description": "请用两分钟完成",
"questionIds": [1, 2, 3],
"questionRequired": {"1": true, "2": false, "3": true},
"selectionMode": "manual",
"expiresAt": "2026-12-31T16:00:00.000Z"
}questionRequired 按题库题目 ID 设置实例快照的必填状态;未提供时沿用题库的历史默认值。随机生成时使用 selectionMode: "random"、可选 sourceGroupId 和按题型的 randomCounts:
{
"kind": "exam",
"title": "随机练习",
"selectionMode": "random",
"sourceGroupId": "type:single",
"randomCounts": {"single": 5, "multiple": 0, "judgment": 0, "text": 0, "open_text": 0},
"scoringMode": "weighted",
"totalScore": 100,
"typeWeights": {"single": 50, "multiple": 30, "judgment": 20}
}sourceGroupId 可以是自定义分组 ID,也可以是 type:single、type:multiple、type:judgment、type:text 或 type:open_text 虚拟题型分组。考试中除开放文本外的每道题必须已有标准答案。scoringMode 为 weighted 时可自动评分题型的权重总和必须为 100;为 per_question 时传入 questionScores 对象。实例生成后题目、必填状态和计分配置会保存为快照。
编辑实例可提交与创建时相同的结构字段,并可额外提交 status。即使实例已有答卷,也可以更换题目、选题方式、实例类型和计分配置;新结构用于后续提交,已有答卷引用的旧题目快照和提交时分数继续保留。答卷接口中的历史题目带有 archived: true。当 expiresAt 不为空且已到期时,服务端始终将 status 保存为 closed;只有同一次请求把截止时间改到未来,status: active 才会生效。
创建或编辑实例时可以提交 accessPolicy:
{
"accessMode": "verified_email",
"maxSubmissionsPerUser": 1,
"maxSubmissionsTotal": 500,
"cooldownSeconds": 60
}accessMode 可为 anonymous、account 或 verified_email。匿名模式不能设置按用户限制;次数、总量和冷却限制由服务端在写入答卷的 SQLite 事务内检查。
GET /api/admin/surveys/:id/responses 返回 { survey, responses }。每条答卷包含 id、submittedAt、score、maxScore 和按问卷题目 ID 索引的 answers;每个答案包含 value、isCorrect 和 awardedScore。普通问卷的判分字段为 null。
导出默认为 CSV:
GET /api/admin/surveys/<survey-id>/export
GET /api/admin/surveys/<survey-id>/export?format=json
CSV 使用 UTF-8 BOM 以兼容 Excel;JSON 返回实例和答卷数组。
常见状态码:400 输入无效,401 未认证,404 资源不存在,409 初始化或结构冲突,410 问卷关闭/过期,429 请求过频,500 服务内部错误。初始化、登录、管理写操作和公开提交均使用进程内固定窗口限流;限流状态不会持久化,不应替代长期审计系统。
公开接口永远不返回考试标准答案。反向代理部署时应限制管理 API 的网络可达范围、启用 HTTPS,并避免将数据库目录和 Token 文件暴露为静态资源。