iBoard V0.2 需求文档 — 打卡 / 日历 / 清单
版本:V0.2 · 分支:dev-0.2 · 日期:2026-10-22
目标项目:iboard(Tauri 2 + React 18 + antd-mobile + Express + Prisma/MariaDB,移动端优先)
基线版本:V0.1(dev-0.1)
1. 总体描述
在 iBoard 移动端新增一个「打卡」模块一个「清单」模块,满足两类日常需求:
打卡
- 周期性打卡(习惯养成):用户定义"每天 n 次 / 每周 n 次 / 每月 n 次 / 每年 n 次"的目标,
每次打卡后卡片上的环形进度按
已完成次数 / 目标次数 增长,达标时环形闭合并播放完成特效;
- 日历回看:以日历为载体,快速查看今天(要做什么)、昨天(做得怎样)、
明天(计划做什么),日期上以圆点/实心标记完成情况;
清单
- 清单(场景化一次性事项):面向出差、回老家等临时场景,逐条勾选确认,
避免遗漏;清单可复用为模板,下次一键生成。
1.1 本期范围
- 单用户使用,数据按登录用户隔离(复用现有 JWT 鉴权)。
- 移动端优先(
MobileShell + 底部 TabBar 体系),桌面浏览器兼容可用即可。
- 数据落库 MariaDB,通过现有 Express
/api/* 提供接口。
1.2 不在本期范围(明确排除)
- 多人协作 / 共享打卡 / 打卡排行榜。
- 系统通知、推送提醒、定时提醒(V0.2 不引入通知能力)。
- 复杂统计报表(周报/月报/趋势图),本期只提供完成率概览。
- 桌面端专用布局、横屏适配。
- 清单的周期性重复(如"每次出差都生成"),本期只做临时清单 + 模板手动复用。
2. 术语与概念定义
| 术语 |
定义 |
| 打卡项(Habit) |
一个被跟踪的周期性目标,如"喝水 每天 8 次""健身 每周 3 次" |
| 周期类型 |
day / week / month / year,决定进度统计窗口 |
| 目标次数 n |
一个周期内需要完成的打卡次数,n ≥ 1 |
| 周期窗口 |
日=自然日;周=自然周(周一 00:00 至周日 23:59);月=自然月;年=自然年。时区统一 Asia/Shanghai |
| 打卡记录(CheckIn) |
一次打卡动作,归属到某个本地日历日(可补打到过去日期) |
| 环形进度 |
卡片上的圆环组件,进度 = min(已完成次数 / n, 1);达标=闭合 |
| 清单(CheckList) |
一次性检查清单,如"出差 · 10月杭州",含若干检查项 |
| 检查项(CheckItem) |
清单中的单条待检查事项,勾选即完成 |
| 模板(Template) |
可被复用的清单结构(一组检查项标题),用于一键生成新清单 |
| 日期状态 |
某日的打卡完成情况:全部完成 / 部分完成 / 未开始 / 超额完成 |
3. 需求点
编号规则:类型-模块-序号。类型:F=功能需求、U=交互与体验、D=数据、N=非功能、E=异常与边界。
模块:CK=打卡、CL=日历、LS=清单、SY=通用。
优先级:P0 = 本期必须有;P1 = 本期应该有;P2 = 有则更好(可延后)。
3.1 功能需求 — 打卡(F-CK)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| F-CK-01 |
支持新建打卡项:名称、周期类型、目标次数 n、颜色、图标、备注 |
表单校验:名称必填且 ≤ 20 字;n 为 ≥1 的整数 |
P0 |
| F-CK-02 |
周期类型支持每天 n 次 / 每周 n 次 / 每月 n 次 / 每年 n 次四种 |
四种类型均可创建并正确统计 |
P0 |
| F-CK-03 |
卡片以环形进度展示当前周期完成情况,环中心显示 已完成/n |
进度 = 已完成次数 / n,上限 100% |
P0 |
| F-CK-04 |
每天 1 次的打卡项:打卡后环形直接闭合(100%),卡片进入"已完成"态 |
一次点击即闭合,不出现 50% 之类的中间态 |
P0 |
| F-CK-05 |
每周 n 次(及月/年):每打卡一次环形闭合对应百分比(如 n=3,打 1 次=33.3%、2 次=66.7%、3 次=100% 闭合) |
进度随每次打卡实时刷新,带过渡动画 |
P0 |
| F-CK-06 |
打卡主操作:点击卡片上的打卡按钮即完成一次打卡 |
单击即生效,响应 < 300ms(乐观更新) |
P0 |
| F-CK-07 |
打卡完成特效:达标(进度达 100%)时播放特效——环形闭合动画 + 光晕/粒子扩散 + 轻量触感反馈 |
特效时长 ≤ 800ms,不阻塞后续操作 |
P0 |
| F-CK-08 |
打卡记录需记录发生日期(本地日历日)与时间戳 |
支持按日回看,跨零点归属正确 |
P0 |
| F-CK-09 |
支持撤销:可撤销本周期内最近一次打卡(主要是误触场景) |
撤销后进度回退,记录物理删除或标记撤销 |
P1 |
| F-CK-10 |
支持补打卡:对过去日期补记一次打卡,默认允许回溯 7 天 |
补打后对应日期的状态与进度同步更新 |
P1 |
| F-CK-11 |
不允许提前打卡(未来日期不可打卡) |
明天的项只展示为"计划",按钮置灰 |
P0 |
| F-CK-12 |
展示连续完成天数/周期数(streak) |
如"已连续 5 天",断签归零 |
P1 |
| F-CK-13 |
打卡项可编辑(改名/改 n/改颜色/改周期)与停用(归档) |
归档后不出现在今日待办,历史保留 |
P1 |
| F-CK-14 |
修改目标次数 n 后,当前周期进度按新 n 重算展示,不改写历史记录 |
例如 n 由 3 改 5,已完成 3 次 → 显示 3/5(60%) |
P1 |
| F-CK-15 |
超额打卡:周期内超过 n 仍可继续打卡,环形保持闭合,中心显示 n+k(如 3+1) |
不清零、不报错 |
P2 |
| F-CK-16 |
打卡项支持排序(拖动或置顶)与分组展示 |
今日列表按"未完成在前、已完成在后"默认排序 |
P2 |
| F-CK-17 |
打卡时可附带备注(可选,纯文本) |
列表详情中可查看 |
P2 |
3.2 功能需求 — 日历(F-CL)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| F-CL-01 |
提供月历视图:当月日历网格,可切换上/下月,点击日期查看当日详情 |
周一起始,周一~周日七列 |
P0 |
| F-CL-02 |
今天视图(默认):列出今天应打卡的项及完成状态,可直接打卡 |
打开页面默认定位今天 |
P0 |
| F-CL-03 |
昨天视图:展示昨天各打卡项的已完成结果(完成/未完成/超额),未完成项可进行补打 |
以回看为主,标记为"已完成的历史" |
P0 |
| F-CL-04 |
明天视图:展示明天计划要打卡的项(按周期规则推算),只读,不可打卡 |
明确标注"计划",打卡按钮不可用 |
P0 |
| F-CL-05 |
今天/昨天/明天快捷切换(顶部 Segmented 或左右滑动) |
一键切换,切换有过渡动画 |
P0 |
| F-CL-06 |
日期标记:月历中每个日期按完成情况标记——全部完成(实心)、部分完成(半填充)、未开始(空心/无标记)、超额完成(特殊标记) |
一眼能看出当月坚持情况 |
P0 |
| F-CL-07 |
日期详情:点击某日期,展示当天每个打卡项的"目标次数 / 已完成次数 / 状态" |
过去日期可补打,未来日期只读 |
P0 |
| F-CL-08 |
日历与打卡数据同源:打卡操作在日历视图与打卡列表视图中即时一致 |
任一处打卡,另一处刷新 |
P0 |
| F-CL-09 |
月历顶部展示当月完成率(完成次数 / 应完成次数) |
百分比展示 |
P1 |
| F-CL-10 |
支持左右滑动手势切换月份 |
与按钮切换等价 |
P2 |
| F-CL-11 |
月视图支持简单的完成热力(按完成率深浅着色) |
可选展示,默认关闭 |
P2 |
3.3 功能需求 — 清单(F-LS)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| F-LS-01 |
支持新建检查清单:名称、场景标签(出差 / 回老家 / 自定义)、备注 |
名称必填,场景标签可空 |
P0 |
| F-LS-02 |
清单内可增删改检查项,支持排序 |
单条 ≤ 40 字 |
P0 |
| F-LS-03 |
勾选完成:点击检查项前的复选框即打勾,已完成项置灰 + 删除线;可取消勾选 |
单击切换,状态即时保存 |
P0 |
| F-LS-04 |
清单头部显示进度:已完成 / 总数 + 进度条;全部完成时显示完成态 |
全部勾完触发完成提示 |
P0 |
| F-LS-05 |
清单全部完成时播放完成特效(与 F-CK-07 同一套特效组件) |
复用,风格统一 |
P1 |
| F-LS-06 |
模板:系统预置常用模板(出差、回老家),一键基于模板生成新清单 |
至少 2 个预置模板 |
P1 |
| F-LS-07 |
另存为模板:用户可将自己的清单保存为自定义模板,后续复用 |
自定义模板可删除 |
P1 |
| F-LS-08 |
复用历史清单:从历史清单复制生成一份新清单(勾选状态重置) |
原清单保持不变 |
P1 |
| F-LS-09 |
清单归档/删除:完成的清单可归档(不出现在进行中列表),可查看历史 |
删除需二次确认 |
P1 |
| F-LS-10 |
清单项支持备注/数量说明(如"充电器 ×1") |
展示在标题下方,弱色小字 |
P2 |
| F-LS-11 |
清单支持一键全部勾选 / 全部取消 |
批量操作入口 |
P2 |
3.4 功能需求 — 通用(F-SY)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| F-SY-01 |
底部 TabBar 新增**「打卡」页**,并作为默认首页放在最左;「清单」不单独占 Tab,作为打卡页内的第三个子视图 |
图标风格与现有 TabIcon 一致;启动即进入 /checkin |
P0 |
| F-SY-02 |
「打卡」页内集成 打卡/日历 两个功能,日历放在上半截,默认显示一行为周视图,下拉显示为月视图。 |
日历中选择时间与下部打卡任务联动 |
P0 |
| F-SY-03 |
所有接口复用现有鉴权(authRequired,JWT),数据按 userId 隔离 |
未登录跳转 /login |
P0 |
| F-SY-04 |
后端新增 REST 路由(建议 /api/checkin/*、/api/checklist/*),挂载到 server/index.js |
与现有路由风格一致 |
P0 |
| F-SY-05 |
时间处理统一 Asia/Shanghai,前端与后端对"日历日"的判定一致 |
跨零点打卡归属当天 |
P0 |
| F-SY-06 |
打卡/勾选操作采用乐观更新,接口失败时回滚并 Toast 提示 |
失败可见、状态不失真 |
P1 |
| F-SY-07 |
写接口幂等/防抖:同一打卡项 1 秒内重复点击只记一次 |
前端防抖 + 后端唯一约束双保险 |
P1 |
| F-SY-08 |
页面可见性变化时刷新数据(复用 useRefreshOnVisible) |
从后台切回自动同步 |
P1 |
3.5 交互与体验需求(U)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| U-01 |
环形进度组件:SVG 圆环,背景环 + 进度环,进度变化带 400ms ease-out 动画 |
组件可复用(打卡卡片、清单进度共用) |
P0 |
| U-02 |
完成特效:达标瞬间环形闭合 + 光晕/粒子扩散,约 600ms;可重复观看不烦扰 |
不阻塞操作,动画结束自动清理 |
P0 |
| U-03 |
触感反馈:完成打卡时轻量震动(Web Vibration API / Tauri) |
固定开启,与特效一同触发 |
P1 |
| U-04 |
移动端适配:375~430px 视口,复用 globals.css 的 .card 体系,安全区与底部 TabBar 不遮挡内容 |
真机无横向滚动、无遮挡 |
P0 |
| U-05 |
空态 / 加载态 / 错误态三态齐全(首次使用引导"创建第一个打卡项") |
空态有明确 CTA |
P0 |
| U-06 |
打卡按钮足够大(点击热区 ≥ 44×44),符合移动端触控规范 |
误触率低 |
P1 |
| U-07 |
动效性能降级:特效保持轻量(单次 ≤900ms、pointer-events:none),不给低端机造成卡顿 |
不卡顿、不阻塞操作 |
P1 |
| U-08 |
深浅色:跟随现有浅色主题,卡片/分割线风格与首页、监控页一致 |
视觉统一 |
P1 |
| U-09 |
清单勾选有明确的勾选动画(勾形描边动画) |
反馈即时 |
P2 |
3.6 数据需求(D)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| D-01 |
新增 Prisma 模型:Habit(打卡项)、CheckIn(打卡记录) |
字段见附录 A |
P0 |
| D-02 |
新增 Prisma 模型:CheckList(清单)、CheckListItem(检查项)、CheckListTemplate(模板,P1) |
字段见附录 A |
P0 |
| D-03 |
Habit / CheckList 均带 userId 外键,删除用户级联删除 |
数据隔离 |
P0 |
| D-04 |
CheckIn 建立 (habitId, date) 索引,支持按日期范围查询 |
日历月查询走索引 |
P0 |
| D-05 |
提供迁移 SQL 并纳入 prisma migrate deploy 流程 |
与 V0.1 迁移流程一致 |
P0 |
| D-06 |
软删除语义:Habit.archived、CheckList.archived,历史记录保留 |
不物理删除历史 |
P1 |
3.7 非功能需求(N)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| N-01 |
页面首屏数据加载 < 1.5s(内网/正常网络),交互响应 < 300ms(乐观更新) |
真机可感知流畅 |
P0 |
| N-02 |
兼容 Android WebView(Tauri 打包)与移动端浏览器,不依赖桌面专有 API |
真机验证 |
P0 |
| N-03 |
单用户数据量按"千级记录/年"设计,无需分表;月查询一次请求返回 |
日历切月无等待感 |
P1 |
| N-04 |
所有接口 authRequired,越权访问返回 401 |
安全基线 |
P0 |
| N-05 |
前端代码组织遵循现有约定:src/pages/checkin/* + src/components/* + server/routes/* |
结构一致 |
P0 |
3.8 异常与边界需求(E)
| 编号 |
需求描述 |
处理约定 |
优先级 |
| E-01 |
重复点击打卡 |
前端防抖 + 后端唯一约束,只记一次 |
P0 |
| E-02 |
接口失败 / 断网 |
乐观更新回滚 + Toast 提示,可重试 |
P0 |
| E-03 |
周期中途新建打卡项(如周三创建"每周 3 次") |
本期按完整目标 n 计算,不按剩余天数折算 |
P1 |
| E-04 |
每月 n 次在天数不同的月份 |
按自然月窗口,不折算 |
P0 |
| E-05 |
每年 n 次跨年 |
按自然年窗口,年末清零 |
P0 |
| E-06 |
删除打卡项 |
归档(软删除)为主;硬删除需二次确认并提示"历史记录将一并删除" |
P1 |
| E-07 |
清单项全部删除后清单进度为 0/0 |
显示空清单,不显示 100% |
P1 |
| E-08 |
跨零点打卡(23:59 → 00:00) |
以提交时刻的本地日历日归属 |
P0 |
3.9 功能需求 — 版本与升级(F-OT,2026-10-22 追加)
| 编号 |
需求描述 |
验收要点 |
优先级 |
| F-OT-01 |
OTA 包版本必须与分支对应:dev-0.2 分支上 OTA 包版本应为 0.2.0-ota |
GET /api/ota/check/0 返回 version = 0.2.0-ota |
P0 |
| F-OT-01a |
APK 版本与 OTA 版本同源:APK(含桌面包)版本为裸版本号 0.2.0,无后缀;OTA 版本为同一版本号加 -ota。两者都跟代码分支保持一致 |
APK 系统信息里 versionName=0.2.0(versionCode=2000),OTA manifest=0.2.0-ota |
P0 |
| F-OT-02 |
版本号错位在 CI 阶段就拦住:①package.json/tauri.conf.json/Cargo.toml/Cargo.lock 四处必须完全一致且不含 -ota;②分支名 dev-x.y 与版本主次号不一致时构建失败 |
CI 输出明确报错并中断 |
P0 |
| F-OT-03 |
「我」页 OTA 组内新增**「开发版本」开关**,默认关闭 |
关闭=按版本号比较;打开=按 build sequence 比较 |
P0 |
| F-OT-04 |
开关值持久化在设备端,重启 App 后保持上次选择 |
杀进程重进仍为上次状态 |
P0 |
| F-OT-05 |
版本号比较规则:按非数字字符切成数字字段,逐段比较大小(0.2.0 > 0.1.0,0.10 > 0.9) |
单测覆盖后缀/前缀/缺位/多位段 |
P0 |
| F-OT-06 |
切换开关后清空上一次的检查结果,避免误判 |
切换即回到「未检查」状态 |
P1 |
4. 优先级汇总(本期交付范围)
- P0(必须):F-CK-01
08、F-CK-11;F-CL-0108;F-LS-0104;F-SY-0105;F-OT-01、F-OT-01a、F-OT-0205;U-01、U-02、U-04、U-05;D-0105;N-01、N-02、N-04、N-05;E-01、E-02、E-04、E-05、E-08。
- P1(应该):F-CK-09、10、12
14;F-CL-09;F-LS-0509;F-SY-0608;F-OT-06;U-03、U-0608;D-06;N-03;E-03、E-06、E-07。
- P2(可选/延后):F-CK-15~17;F-CL-10、11;F-LS-10、11;U-09。
5. 里程碑建议
| 里程碑 |
内容 |
| M1 数据与接口 |
Prisma 模型 + 迁移;server/routes/checkin.js、checklist.js;周期进度计算与日期查询 |
| M2 打卡视图 |
环形进度组件 + 打卡卡片列表 + 打卡/撤销/补打 + 完成特效 |
| M3 日历视图 |
月历网格 + 今天/昨天/明天三视图 + 日期标记 + 日期详情 |
| M4 清单视图 |
清单 CRUD + 勾选交互 + 进度条 + 模板与复用 |
| M5 联调打磨 |
真机验证、动效降级、空态/错误态、性能与跨天边界 |
6. 待确认问题(评审时决策)
| # |
问题 |
建议 |
| 1 |
是否新增第 5 个底部 Tab「打卡」,还是放在首页入口? |
✅ 已决策(2026-10-22):「打卡」作为默认首页放在最左;原来的「首页」取消,报警/新闻并入宏观 |
| 2 |
周起始日是周一还是周日? |
建议周一(国内习惯) |
| 3 |
是否允许"明天提前打卡"? |
建议不允许(F-CK-11),保持统计口径干净 |
| 4 |
删除打卡项时历史是否保留? |
建议默认归档保留,硬删除才清历史 |
| 5 |
预置模板具体包含哪些项? |
评审时列出"出差/回老家"各 8~12 条初始项 |
| 6 |
完成特效是否可全局关闭? |
✅ 已决策(2026-10-22):不提供关闭入口,特效永远打开;页面内不再有特效开关 |
附录 A:核心实体草案(供设计阶段参考,非最终表结构)
说明:周期进度由 CheckIn 按周期窗口现场聚合(不冗余计数字段),避免并发与修改 n 后的一致性问题。
附录 B:实现约定(开发期补充,用于消除口径歧义)
| # |
约定 |
说明 |
| B-1 |
周期窗口 |
日=自然日;周=周一 00:00 ~ 周日 23:59;月=自然月;年=自然年;时区 Asia/Shanghai |
| B-2 |
环形进度 |
周期完成度 = 周期内累计打卡次数 / n(每周 n 次:打 1 次=1/n 环;每天 1 次:打 1 次直接闭合) |
| B-3 |
日历日期标记 |
用"当日完成度":当日次数 / 日均期望次数(每天 n 次→n;每周 n 次→ceil(n/7);每月→ceil(n/当月天数);每年→ceil(n/365))。全完成=实心绿点,部分=黄点,超额=紫点,无记录=不显示 |
| B-4 |
streak |
从当前周期往回数连续达标的周期数;当前周期未结束且未达标不算断签(跳过继续往前数) |
| B-5 |
补打限制 |
只能补打最近 7 天(BACKFILL_DAYS),未来日期禁止打卡 |
| B-6 |
撤销语义 |
撤销删除本周期内"最近一次"打卡(按 date desc、seq desc 取第一条) |
| B-7 |
删除打卡项 |
默认归档(archived=true,历史保留);?hard=1 才物理删除并清记录 |
| B-8 |
接口前缀 |
打卡 /api/checkin/*、清单 /api/checklists/*,全部 authRequired,数据按 userId 隔离 |
| B-9 |
前端入口 |
底部 Tab 4 个:打卡(最左,默认选中) / 宏观 / 监控 / 我;/ 重定向到 /checkin,页内三视图:打卡 / 日历 / 清单。原「首页」取消,报警/新闻并入宏观 |
| B-10 |
特效 |
完成特效 + 触感反馈恒开,页面内不提供开关(2026-10-22 变更,原 localStorage iboard_celebrate 机制已移除) |
| B-11 |
OTA 版本 |
OTA 包 version = package.json.version + '-ota',必须与分支一致(dev-0.2 → 0.2.0-ota),CI 有强校验 |
| B-12 |
OTA 判新 |
我的页「开发版本」开关(默认关,持久化 localStorage.iboard_ota_dev_mode):关=版本号字段比较,开=build sequence 比较 |
接口清单
| 方法 |
路径 |
说明 |
| GET |
/api/checkin/habits?date= |
打卡项列表 + 当前周期进度 + streak |
| POST |
/api/checkin/habits |
新建打卡项 |
| PUT |
/api/checkin/habits/:id |
编辑(改 n / 周期 / 归档) |
| DELETE |
/api/checkin/habits/:id?hard=1 |
归档(默认)/ 物理删除 |
| POST |
/api/checkin/habits/:id/check |
打卡一次(可带 date 补打、note) |
| DELETE |
/api/checkin/habits/:id/check?date= |
撤销本周期最近一次 |
| GET |
/api/checkin/day?date= |
某日详情(今天可打卡 / 昨天可补打 / 明天只读) |
| GET |
/api/checkin/calendar?month=YYYY-MM |
月历:每日状态 + 当月完成率 |
| GET |
/api/checklists?archived=0|1 |
清单列表(含进度) |
| POST |
/api/checklists |
新建清单(可带 templateId 从模板生成) |
| GET/PUT/DELETE |
/api/checklists/:id |
详情 / 编辑 / 删除 |
| POST |
/api/checklists/:id/duplicate |
复制为新清单(勾选重置) |
| POST |
/api/checklists/:id/items |
新增检查项 |
| PUT/DELETE |
/api/checklists/items/:id |
改标题 / 勾选(done) / 删除 |
| POST |
/api/checklists/:id/check-all |
一键全选 / 全不选 |
| GET/POST |
/api/checklists/templates |
模板列表(含系统预置)/ 另存为模板 |
| DELETE |
/api/checklists/templates/:id |
删除自定义模板 |