一个由成员共同维护的非官方日历、重要事项与回放中心。
查找会议、关注 PPA 与比赛安排、订阅关键日期,也让有价值的回放更容易被再次找到。
会议通知、PPA 主题、比赛周期和奖金日期常常散落在聊天记录、群公告和临时链接中:容易错过,也很难在结束后重新找到资料。
WQ Calendar 将会议安排、重要事项、成员投稿、管理员审批、个人日历订阅和会议回放集中在一处。成员可以补充会议、PPA、比赛与回放来源,管理员负责确认内容和维护奖金日程,形成一份持续更新、方便查找的共享日历。
- 登录页和主导航可切换中文 / English,选择保存在当前浏览器,切换不会清空正在填写的表单。
- 未手动选择时,登录前使用浏览器语言;普通成员登录后按成员名单中的
country默认选择 CN/HK 中文、其他地区英文。会议标题、说明及成员投稿原文不自动翻译,时间仍为北京时间。 - CN/HK 成员可访问全部会议语言、回放及排行榜;其他地区成员仅可查看和投稿英文会议,隐藏中文、双语及
other会议、整个回放栏目和全部排行榜。管理员不受此限制。 - 限制由后端执行,覆盖列表、详情、单场
.ics、个人订阅及自己的投稿列表;切换界面语言或直接打开 URL 不会绕过。国家读取当前成员记录,不根据 WQ_ID 字母、IP 或浏览器语言猜测。 - 旧订阅下次刷新也按最新国家过滤。已被第三方日历缓存或单次下载的历史内容无法远程删除。
- 管理后台“使用统计”按国家 / 地区展示导入总人数、有效成员、使用人数、近 30 天活跃和有效订阅。
- 使用人数依据现有登录记录:至少成功登录一次的成员按成员 ID 去重,包含后来停用的成员;不是登录次数,也不把仅导入但未登录的成员计入。
- 近 30 天活跃和有效订阅仅统计当前有效成员。国家以名单当前记录为准,不是历史登录所在地。
- 点击“查看 WQ_ID”自动切换为该国家的已登录成员明细,支持分页及完整 WQ_ID 精确查询;完整 ID 仅管理员可见。旧数据无法解密完整 ID 时保留脱敏提示,不猜测或补造 ID。
- 本次新增
0011_member_country_index.sql,仅添加国家索引。发布时先执行待应用迁移,再发布后端和前端;不重建或删除成员数据。
- 以近期议程或月历方式查看会议
- 所有时间统一换算并显示为北京时间
- 按标题、类别、语言和会议形式筛选
- 直接打开注册链接,或先查看会议详情
- 周期会议在议程中只展示最近一次,月历保留具体场次
- 通过时间线或月历查看 PPA 主题、比赛主题和奖金日程
- PPA 与比赛支持跨日范围以及安全的基础 Markdown 内容
- 奖金卡片显示适用周期;月历和订阅只使用公布日期与账单日期,不按周期占位
- 历史及已取消事项永久保留,年度日期可直接在后台修改
- 成员可以投稿会议、PPA、比赛和回放来源
- 投稿通过前不会出现在公开列表
- 管理员可以审核、修正、拒绝或发布投稿
- “我的投稿”集中展示会议、重要事项与回放的审核状态及反馈
- 奖金日程仅由管理员维护
- 支持百度网盘、夸克网盘、阿里云盘、OneDrive、Google Drive、Dropbox、微云及其他 HTTPS 来源
- 同一场会议可以由多名成员补充多个不同回放链接
- 每个来源可附带提取码和简短备注
- 成员可以反馈链接失效,管理员决定处理、下架或恢复
- 生成个人私密的 iCalendar 订阅地址
- 支持不提醒、提前 10 分钟、30 分钟、1 小时或 1 天
- 可将单场会议加入 Google、Outlook 或 Apple Calendar
- 会议改期、取消和周期例外会通过订阅源同步
- 可分别选择同步会议、PPA、比赛和奖金日程,默认全部开启
- 只有会议使用所选提前提醒;重要事项始终不写入提醒
- 会议投稿、回放贡献和重要事项投稿分别排名
- 展示投稿次数、通过次数、通过率和回放贡献会议数
- 成员可以选择显示完整 WQ_ID,或隐藏为开头两个字母
- 管理员账号不参与排行榜
- 使用已导入名单中的 WQ_ID 和日历站点密码登录;初始密码为自己的 WQ_ID,登录后请及时在“设置”修改。
- 在“会议日历”中查找会议、注册或提交新的会议信息。
- 在“回放”中浏览、补充回放来源或反馈失效链接。
- 在“重要事项”中查看 PPA、比赛和奖金日期,或投稿 PPA/比赛内容。
- 在“设置”中选择同步内容和会议提前提醒,再生成个人订阅地址。
- 在“我的投稿”查看审核进度和管理员反馈。
- 导入并维护成员名单。
- 在统一的“待审”页面处理会议、重要事项与回放投稿。
- 管理会议系列、重要事项、奖金适用周期及关键日期、单次改期、取消和回放来源。
- 查看成员使用情况、投稿排行和审计记录。
- 会议、重要事项和成员数据保存在 Cloudflare D1,不进入前端构建产物。
- 登录使用随机不透明令牌,数据库只保存令牌哈希。
- 登录 Cookie 设置为
HttpOnly + Secure + SameSite=Strict。 - 成员自定义密码使用随机盐 PBKDF2-SHA256(100,000 次)与服务端 pepper 保存,密码和密码哈希均不会通过管理接口返回。
- 修改请求同时验证会话、CSRF 和允许的前端来源。
- WQ_ID 使用带服务端密钥的索引,并加密保存管理员所需的身份数据。
- 私密日历订阅地址可以随时旋转或撤销。
- 外部回放链接只做记录和人工审批,服务端不会主动访问网盘内容。
请勿提交会议密码、个人专属入会链接、内部文件或参与者名单。
- 普通成员登录必须填写密码。已有成员和新导入成员的初始密码为本人的 WQ_ID(初始密码字母不区分大小写);自定义密码严格区分大小写,保留空格。
- 使用初始密码登录后跳转“成员设置”,并在站内持续提醒修改。提醒不强制阻止浏览或投稿;WQ_ID 可被他人知晓,因此应尽快改为独立密码,勿复用 BRAIN 平台密码。
- 在“设置 → 修改登录密码”输入当前密码、新密码及确认密码。新密码须为 12–128 位,不能等于 WQ_ID 或当前密码。
- 管理员在“管理 → 使用统计”按 WQ_ID 查询成员,点击该行“管理密码”,可以设置新密码或重置为 WQ_ID。操作需二次确认,仅影响所选成员,不能读取其原密码;重置停用成员不会重新启用账号。
- 成员自行改密、管理员改密或重置后,该成员所有设备的旧登录会话立即失效;投稿、隐私偏好与日历订阅不变。忘记密码需联系管理员。
- 手动名单导入及 Actions 平台同步不会覆盖既有密码,新成员仍以 WQ_ID 初始化。密码管理接口必须通过对应角色的会话、CSRF 和 Origin 校验,同步机器令牌不能使用。
- 登录及改密有服务端限流,密码更新、审计日志与会话失效在同一数据库事务内完成;凭据版本防止并发登录重新启用旧密码会话。
上线时先应用 0010_member_passwords.sql 并部署 Worker,再更新前端。迁移会一次性清除旧版无密码登录产生的成员会话,需重新输入 WQ_ID 和初始密码登录;管理员会话与日历订阅保留。迁移无需接触 BRAIN 账号密码,也不需批量解密旧成员 ID;初始密码通过原有加密索引验证,自定义密码单独保存加盐哈希。服务端 pepper 使用现有 WQ_ID_HMAC_SECRET,不得随意轮换该身份密钥。
支持所有地区的两位字母代码(如 CN、HK、US、IN、GB),不再按 CN/HK 限制导入或登录。
- 手动导入:后台“成员导入”上传表头为
wq_id,country的 CSV;保留原有整体替换行为,缺失成员会停用,其会话与订阅会被撤销。 - 自动同步:GitHub Actions 使用 BRAIN 账号密码登录,复用会话 Cookie,分页读取
/consultant/boards/genius?aggregate=user;仅新增、更新抓到的成员,不停用名单外成员,不撤销已有会话、投稿或订阅。再次出现在榜单中的停用成员会重新启用。
在仓库 Settings → Secrets and variables → Actions 配置:
| 类型 | 名称 | 内容 |
|---|---|---|
| Secret | WQ_USERNAME |
有权访问 genius 榜单的 BRAIN 登录账号(通常为邮箱) |
| Secret | WQ_PASSWORD |
该账号的登录密码 |
| Secret | MEMBER_SYNC_TOKEN |
独立的随机同步令牌,建议 32 随机字节的十六进制值;不能使用 BRAIN 密码或管理员密码 |
| Variable | VITE_API_BASE_URL |
已部署 Worker 的 HTTPS 根地址,沿用前端部署配置,不含 /v1 |
| Variable | MEMBER_SYNC_ENABLED |
设置为 true 才启用定时执行;手动 Run workflow 不受此开关限制 |
| Variable | WQ_BOARD_DATE |
可选,YYYY-MM-DD;默认北京时间昨天。填写后每次同步都会抓取该固定历史日期 |
| Variable | WQ_USER_FIELD |
可选,默认 user;若 ID 位于嵌套对象,可设为 user.id |
| Variable | WQ_COUNTRY_FIELD |
可选,默认 country;支持点分隔字段路径,如 user.country |
- 配好 Secret 后先运行 Deploy Cloudflare Worker,应用
0009_global_members.sql并将同名MEMBER_SYNC_TOKEN安全注入 Worker。未设置该 Secret 时同步接口关闭,原有手动导入仍可用。平台账号密码只提供给同步任务,不会传给 Worker。 - 运行 Deploy GitHub Pages 更新前端(取消 CSV 地区限制及更新说明)。
- 在 Actions 手动运行 Sync platform members,可输入一次性的榜单日期覆盖仓库变量。确认成功后再设置
MEMBER_SYNC_ENABLED=true。 - 默认每周一 北京时间 12:43(UTC 04:43) 执行,可修改
.github/workflows/sync-members.yml的 cron;仍可通过 Run workflow 手动触发。定时任务使用默认分支上的工作流,GitHub 可能延迟调度。
脚本参照 WQCode/src/wq_mining/worldquant/client.py:Basic Auth POST /authentication,成功后保留 Cookie;分页遇到 401 重新登录一次;网络错误、429 和临时服务错误会有限重试并遵守 Retry-After。需要人工验证或账号无榜单权限时任务失败,不尝试绕过验证。
分页按 count 动态校验人数,不写死 5980;无 count 时读至空页或明确的 next: null。遇到字段缺失、重复 ID、空榜单、分页人数不一致或请求失败会终止。不会静默跳过非法记录,也不会跟随平台提供的任意外部 URL。脚本完整抓取后才上传,每批最多 100 人;服务端暂存人数与预期人数一致才原子提交,可安全重试。失败的暂存批次不会修改有效成员名单,24 小时后由现有清理任务标记为 abandoned。
服务端机器令牌仅开放 /v1/automation/member-imports,不能访问其他管理接口;手动管理仍要求管理员会话、CSRF 与允许的 Origin。同步只发送 WQ_ID 和地区,不持久化排名等额外平台信息;日志只记录人数、状态及日期,不输出密码、Cookie、完整名单,也不生成名单 artifact。成功后审计日志记录 sync_members、榜单日期、人数和 merge 模式。
首次上线前建议按既有备份流程备份 D1。新迁移保留已有 ID、加密身份、隐私设置及关联数据,不修改旧迁移文件。同步脚本使用 Python 3.12;本地测试不需要任何真实凭据:
python -m pip install -r scripts/requirements.txt
python -m unittest discover -s scripts/tests -vweb/:Vue 3 + TypeScript 前端,发布到 GitHub Pagesworker/:Cloudflare Worker API、D1 数据库与 iCalendar 输出packages/shared/:前后端共用的数据类型和校验规则
现有 Worker、D1、包名和 ICS UID 中仍保留 wq-meeting-calendar 作为兼容性标识。它们不是对外品牌名称,不应直接改名,否则可能影响部署、既有订阅或加密数据。
pnpm install
pnpm typecheck
pnpm test
pnpm build
pnpm --filter @wq-calendar/worker test:passwords:runtime最后一项在临时本地 workerd/D1 中使用虚构账号验证成员密码迁移、登录、自行改密、管理员修改/重置、会话撤销及订阅保留,不读取 .dev.vars,不访问线上数据库或 BRAIN。
项目仍在持续完善中,欢迎通过 Issue 提交问题和改进建议。
