Commit Graph

84 Commits

Author SHA1 Message Date
iven
0c9ada242a perf(diary): mood_stats 改用 SQL GROUP BY 替代全量加载 — 8a-C01
- get_mood_stats: SELECT mood, COUNT(*) GROUP BY 替代 all() + Rust 迭代
- calculate_streak: 仅查 date 列 + DISTINCT + 366天窗口裁剪
- 新增 mood_counts_map_aggregation 单元测试
- 测试 78/78 通过
2026-06-03 15:37:09 +08:00
iven
99db8e5cb0 fix(app): 家长同意验证流程 — PIPL 第28条合规
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- 新增 ParentalConsentPage: 显示隐私政策要点 + 双重确认复选框
- 角色选择流程: 学生 → 家长同意确认 → 班级码输入
- Authenticated 状态: 添加 needsParentalConsent/parentalConsentAt/selectedRole
- ParentalConsentAccepted 事件: 记录同意时间戳
- 路由守卫: 注册 /parental-consent 路径和重定向逻辑
- 非学生角色(老师/家长/独立用户)不需要经过同意流程

审计 ID: S-03
2026-06-03 10:25:23 +08:00
iven
a34c9fd176 fix(app): 强制 HTTPS — Android 网络安全配置 + 生产默认 HTTPS
- Android: 添加 network_security_config.xml,默认禁止明文流量
- Android: 仅允许 localhost/127.0.0.1/10.0.2.2 明文(开发调试)
- Android: 更新 AndroidManifest 引用网络安全配置
- ApiClient: 默认 URL 改为 https://api.nuanji.app/api/v1
- AppConfig: fromEnvironment 默认值改为 HTTPS 生产地址
- AppConfig: dev 常量保留 localhost(仅用于本地开发)
- iOS: ATS 默认已强制 HTTPS,无需修改

审计 ID: 6b-C01
2026-06-03 10:13:20 +08:00
iven
45949e3ed0 fix(app): Token 自动刷新拦截器 — 401 时自动刷新 + 重试原请求
- ApiClient: 添加 onRefreshToken 回调,401 时自动调用刷新
- ApiClient: 并发保护(_isRefreshing),防止多个 401 触发多次刷新
- ApiClient: 跳过 /auth/refresh 自身的 401(避免无限循环)
- ApiClient: 刷新成功后自动重试原始请求
- AuthRepository: 注册 _handleAutoRefresh 回调
- 使用回调模式避免 ApiClient ↔ AuthRepository 循环依赖

审计 ID: 9a-AUTH-01
2026-06-03 10:07:33 +08:00
iven
c4b2de8294 fix(diary): 家长绑定改为两步验证 — 孩子确认后才生效
- bind_child: 创建 pending 状态绑定(不再自动 verified)
- validate_child_user: 验证目标用户存在且有 student 角色
- confirm_binding: 孩子确认后状态变为 verified,家长获得访问权限
- reject_binding: 孩子拒绝绑定请求
- list_pending_for_child: 孩子查看待确认绑定列表
- 新增 3 个 API 端点: /parent/pending, /bindings/{id}/confirm, /bindings/{id}/reject
- 防止未授权绑定(任何人不验证即可绑定孩子的漏洞)

审计 ID: S-10
2026-06-03 10:03:50 +08:00
iven
cca2d77ea2 fix(diary): 班级码改用字母数字混合 — 16^6 提升到 62^6(568 亿组合)
- 从 UUID hex 后 6 位(0-9a-f,16^6 ≈ 1677 万)改为字母数字混合
- 字符集: 0-9A-Za-z(62 字符,62^6 ≈ 568 亿)
- 使用 UUID v7 后 8 字节随机部分作为熵源,避免同毫秒碰撞
- 符合 CLAUDE.md 设计规格要求

审计 ID: 7b-C01
2026-06-03 09:56:24 +08:00
iven
6d7ac05d0f fix(auth): Token 黑名单改用 SHA-256 替代 SipHash
- access token 黑名单 hash 函数从 std::collections::DefaultHasher (SipHash)
  改为 sha2::Sha256,与 refresh token 存储一致
- SipHash 是非密码学 hash,理论上可被构造碰撞绕过黑名单检查
- SHA-256 提供密码学安全保证,且 sha2 已在 Cargo.toml 依赖中

审计 ID: S-01
2026-06-03 09:51:47 +08:00
iven
11d0971a67 feat(app): pnpm 一键启动 + Flutter Web 编译修复
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
1. 新增 pnpm start:dev / pnpm start:stop 命令
   - scripts/dev.mjs: 跨平台启动脚本(后端+管理端+学生端)
   - scripts/stop.mjs: 端口清理停止脚本
   - 根 package.json 定义 pnpm 脚本

2. 修复 Flutter Web 编译(Isar 3.x + flutter_secure_storage 不兼容)
   - isar_database: 条件导出,Web 用空 stub
   - isar_journal_repository: 条件导出,Web 用空 stub
   - sync_engine: 条件导出,Web 用内存队列(无 Isar 持久化)
   - 移除 flutter_secure_storage(v9 web 插件用 dart:html)
   - 新增 SecureTokenStore 接口 + shared_preferences 实现
   - auth_repository 改用 SecureTokenStore 接口
2026-06-03 09:50:19 +08:00
iven
b81a972245 fix(diary): 为所有 DTO 添加 Validate derive + handler 调用 validate()
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
DTO 验证规则:
- CreateJournalReq: title 1-200, tags ≤20
- UpdateJournalReq: title 1-200, tags ≤20
- CreateClassReq: name 1-50, school_name ≤100
- JoinClassReq: class_code = 6位
- UpdateClassReq: name 1-50, school_name ≤100
- SyncReq: changes ≤100 条
- CreateTopicReq: title 1-200, description ≤2000
- UpdateTopicReq: title 1-200, description ≤2000
- CreateCommentReq: content 1-1000
- CreateStickerPackReq: name 1-50, description ≤500
- UpdateStickerPackReq: name 1-50, description ≤500
- CreateStickerReq: name 1-30, image_url 1-500
- BindChildReq/DeleteChildDataReq: Validate derive (Uuid 已由 serde 验证)

Handler 调用: validate() 放在 require_permission() 之前(先验证输入再检查权限)

审计 ID: 5a-C01, 5a-C02, 5a-C03
2026-06-03 01:14:23 +08:00
iven
af7d3f65fd fix(diary): 修复日记列表 IDOR — 非管理角色只能查看自己的日记
- list_journals: 学生/家长等非管理角色强制 author_id = ctx.user_id
- get_journal: 非管理角色查看他人日记返回 404(避免信息泄露)
- 老师/管理员角色保留查看任意日记的能力(点评/管理需要)
- 家长应通过 parent_service 专用端点查看孩子日记

审计 ID: S-07
2026-06-03 01:08:00 +08:00
iven
9ce300ddb9 fix(app): 修复笔画缓存 use-after-dispose — 移除增量合成时的提前 dispose
- _compositeIncremental 中不再 dispose strokeImage,因为 _cache 持有同一引用
- 提前 dispose 导致 syncStrokes/clear/dispose 时 double-dispose(use-after-free)
- 单笔画 image 生命周期由缓存统一管理:移除/清除/销毁时释放
- 更新 _rebuildComposite 注释,移除过时说明

审计 ID: 8b-R01
2026-06-03 01:06:34 +08:00
iven
e0052ea99b fix(diary): 添加事务 — create_class/join_class/parent 删除原子化
- create_class: 班级创建 + 老师成员插入包裹在 db.transaction() 中
- join_class: 成员插入 + member_count 更新包裹在事务中
- delete_child_data: PIPL 删除权 — 逐条软删除包裹在事务中(避免部分删除)
- DiaryError: 添加 From<TransactionError<DiaryError>> 支持事务闭包

审计 ID: B-07, B-11, 8a-C03
2026-06-03 01:03:57 +08:00
iven
1750f17f41 fix(diary): 修复 class_service unwrap() — 改为从 Model 安全取值
- join_class 中 member_count.unwrap() 和 version.unwrap() 替换为
  在 Model → ActiveModel 转换前直接读取 model 字段值
- 消除潜在的 panic 风险,保持代码可读性

审计 ID: B-01
2026-06-03 00:58:58 +08:00
iven
5f06056d26 fix(server): 添加权限守卫 — 审计日志 + 文件上传 + diary.comment.delete 种子
- audit_log handler: 添加 require_permission("audit.log.list") 守卫
- upload handler: 添加 require_permission("file.upload") 守卫
- 种子数据: 新增 audit.log.list / file.upload / diary.comment.delete 权限定义
- 角色种子: admin 获得 audit.log.list + file.upload + diary.comment.delete 权限
- diary.comment.delete 已在 teacher 列表中(种子定义之前缺失)

审计 ID: 5b-C01, 5b-C02, 4a-C02
2026-06-03 00:57:39 +08:00
iven
935918c9ab fix(server): 修复 RLS 变量名 bug — app.current_tenant → app.current_tenant_id + 空值保护
- 变量名从不存在的 app.current_tenant 修正为 app.current_tenant_id(与中间件一致)
- 添加空值保护:current_setting(...) != '' AND tenant_id = ...(与基座 m000088 严格模式一致)
- 移除 FORCE ROW LEVEL SECURITY,与基座表保持一致(允许迁移/管理操作绕过)
- 添加 DROP POLICY IF EXISTS 幂等保护

审计 ID: 4a-C01, 4b-C01, 4b-C02
2026-06-03 00:55:00 +08:00
iven
d482497e49 fix(app): 修复 smoke test — 改为验证主题构建,避免 Isar 依赖
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
2026-06-03 00:00:15 +08:00
iven
45530616ee feat(diary): 添加贴纸包 UpdateStickerPackReq DTO + update service/handler — Task 13
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
2026-06-02 23:54:04 +08:00
iven
d6dd017155 feat(web): 贴纸包 CRUD UI + 主题编辑/停用 — Task 14-15 完成
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
Task 14: StickerPackList 补全 CRUD UI
- stickers.ts: 添加 createPack/deletePack/createSticker API
- StickerPackList: 新建贴纸包按钮 + 创建表单 Modal
- StickerPackList: 卡片添加删除按钮 (Popconfirm)

Task 15: TopicList 补全编辑/停用
- topics.ts: 添加 update/deactivate API
- TopicList: 编辑 Modal (标题/描述/截止日期)
- TopicList: 卡片添加编辑+停用按钮

附带修复:
- types.ts: SchoolClass/TopicAssignment 添加 version 字段
- ClassList.tsx: 修复 onUpdate 回调参数签名
- tsconfig.app.json: 排除 src/test 避免缺失模块编译错误
2026-06-02 23:40:46 +08:00
iven
f0741450bc feat(app): 家长端数据导出 — 添加 JSON 文件下载 + 预览
- 新建 file_download.dart 跨平台下载工具(conditional import)
- download_impl_web.dart: Web 平台通过 html.AnchorElement + Blob 下载
- download_impl.dart: 非 Web 平台 stub(Phase 2 扩展 path_provider)
- _ExportDataView: 添加下载按钮 + JSON 折叠预览 + PIPL 提示
- 移除 'Phase 1 预览' 占位文案,替换为完整下载功能
2026-06-02 23:36:35 +08:00
iven
c9a69d0be1 feat(app): 添加评论列表展示组件 — FutureBuilder 轮询模式 2026-06-02 23:26:54 +08:00
iven
9e53ca8555 feat(app): EditorPage 顶栏添加评语入口 — 仅已有日记显示
- 添加评语图标按钮(仅 journalId != null 时显示)
- 实现 _showComments 方法打开 CommentListSheet
- 补充 api_client + comment_list_sheet imports
2026-06-02 23:26:24 +08:00
iven
6c9a38b27b feat(app): 添加 EditorBloc.LoadJournal event — 加载已有日记数据
- LoadJournal event: 原子加载 title/mood/tags/strokes/elements/lastSavedAt
- _onLoadJournal handler: 不触发 auto-save (isDirty=false)
- 单元测试: 验证 LoadJournal 正确还原所有状态字段
- mood_bloc: linter 补充 foundation.dart import
2026-06-02 23:23:17 +08:00
iven
e57c3427a4 fix(app): 18 处 catch(e) 添加 debugPrint 异常日志
- parent_bloc: 6 处 (LoadChildren/BindChild/ViewJournals/ExportData/DeleteData/UnbindChild)
- search_bloc: 3 处 (SearchByMood/SearchByTag/SearchByKeyword)
- achievement_bloc: 1 处 (_fetchAchievements)
- sticker_bloc: 2 处 (_fetchPacks/fetchStickersInPack)
- template_bloc: 1 处 (_fetchTemplates)
- mood_bloc: 1 处 (_loadStats)
- home_bloc: 1 处 (_onLoadData)
- calendar_bloc: 1 处 (_onMonthChanged)
- sync_engine: 1 处 (trySync)
- weekly_page: 已有 debugPrint,无需修改
2026-06-02 23:21:16 +08:00
iven
c92ead60e3 feat(app): EditorPage 加载已有日记 — 替换为 LoadJournal 原子事件
- _loadExistingJournal 改用单一 LoadJournal event 替代多个细粒度事件
- 添加 _titleController 同步,确保 LoadJournal 后标题输入框正确显示
- 不触发 auto-save (isDirty=false),因为这是加载而非用户编辑
2026-06-02 23:16:58 +08:00
iven
ab45f40cc8 docs: 修订实施计划 — 修复 EditorView 目标类/apiClient.data/主题后端已存在 2026-06-02 23:06:11 +08:00
iven
8ea1032c9d feat(diary): Phase 1.3 完善修复 — 贴纸/主题 CRUD + 管理端对接 + HMS 清理
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
H7 贴纸 CRUD:
- POST /diary/sticker-packs — 创建贴纸包
- DELETE /diary/sticker-packs/:id — 软删除贴纸包
- POST /diary/sticker-packs/:id/stickers — 添加贴纸

H8 主题编辑/停用:
- PUT /diary/topics/:id — 编辑主题 (标题/描述/截止日期)
- PATCH /diary/topics/:id/deactivate — 停用主题

管理端前端:
- ClassList.tsx 对接 update/deactivate/reset-code (含 Popconfirm 确认)
- JournalList.tsx 班级筛选改用 classApi.listAll()
- classes.ts 新增 listAll/update/deactivate/resetCode API

M2 HMS 遗留清理:
- 删除 copilot.ts, healthFixtures.ts, healthHandlers.ts
- AuditLogViewer 资源类型 → 日记模块
- auth.test.ts / renderWithProviders health.* → diary.*

M4 编辑器加载:
- EditorPage journalId 非空时从 Isar 恢复笔画/元素/标签/心情/标题

77 tests passed, cargo check , tsc , flutter analyze 
2026-06-02 23:01:13 +08:00
iven
94bfb3297a docs: 添加课堂试点就绪实施计划 — 4 Phase 16 Task 2026-06-02 22:59:16 +08:00
iven
85d6781372 fix: Phase 1.3 完善修复 — 管理端对接 + HMS清理 + 编辑器加载
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- feat(web): ClassList.tsx 对接 update/deactivate/reset-code API
  - 编辑班级: PUT /diary/classes/:id
  - 停用班级: PATCH /diary/classes/:id/deactivate (Popconfirm 确认)
  - 重置班级码: POST /diary/classes/:id/reset-code (Popconfirm 确认)
  - 数据源改用 listAll() 获取所有班级
- fix(web): JournalList.tsx 班级筛选改用 classApi.listAll()
- fix(app): EditorPage 加载已有日记数据 (journalId 非空时)
  - 从 Isar 恢复笔画/元素/标签/心情/标题
  - _EditorView 改为 StatefulWidget + initState 加载
- chore(web): HMS 遗留代码清理
  - 删除 api/copilot.ts, healthFixtures.ts, healthHandlers.ts
  - AuditLogViewer 资源类型替换为日记模块类型
  - auth.test.ts / renderWithProviders 权限码 health.* → diary.*
- docs: 确认 M6 NotificationService 为误报 (已在 3 处调用)
2026-06-02 22:54:09 +08:00
iven
860844a399 docs: 修订课堂试点设计规格 v1.1 — 修正 API 路径/已存在功能/测试标准 2026-06-02 22:49:17 +08:00
iven
4d5ddf35a7 docs: 添加课堂试点就绪设计规格 — 四角色闭环 + 跨角色链路 2026-06-02 22:40:11 +08:00
iven
a83909dd24 fix(server): Phase 1.2 核心功能修复 — C1/C2/H4/H6
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- feat(diary): 新增 list_all_classes 管理端 API (GET /diary/classes/all)
- feat(diary): 新增班级更新 API (PUT /diary/classes/{id}) — 名称/学校名编辑
- feat(diary): 新增班级停用 API (PATCH /diary/classes/{id}/deactivate)
- feat(diary): 新增班级码重置 API (POST /diary/classes/{id}/reset-code)
- fix(db): 补充权限 seed — student 获得 update/delete, teacher 获得 comment.delete
- refactor(diary): 删除 comment_service 中废弃的 contains_sensitive_words 死代码
- test(diary): 77 测试全部通过
2026-06-02 21:33:47 +08:00
iven
49d4aa36a7 fix(app): Phase 1.1 紧急修复 — SyncEngine 接入 + authorId + catch 异常处理
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- feat(sync): SyncEngine 接入 EditorPage, 保存时 enqueue + 网络恢复自动 trySync
- fix(editor): authorId 从 AuthBloc 获取, 替代硬编码 'local'
- fix(bloc): class_bloc/calendar/profile/parent catch(_).全部改为 debugPrint
- feat(editor): 编辑器工具栏拆分 (brush_panel/tag_panel/text_format_bar/dot_grid_painter)
- feat(editor): EditorBloc 扩展 + EditorPage 增强
- feat(search): SearchBloc 扩展搜索功能
- feat(home): HomeBloc/HomePage 增强
- feat(auth): LoginPage 增强
- feat(templates): TemplateGalleryPage 重构
- fix(web): 管理端班级/日记页面修复
- fix(server): comment_service + theme_handler 修复
- docs: 添加全链路审计报告和验证截图
2026-06-02 21:21:43 +08:00
iven
7e928ae1e1 fix(app): 修复 P2~P4 共 10 项前端问题
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
P2 必须修复:
- 教师布置主题 classId 从硬编码改为班级下拉选择器
- 班级日记墙使用服务端 classId 过滤替代前端过滤
- Profile 统计栏接入 JournalRepository 真实数据
- WeeklyPage 从全硬编码改为 JournalRepository 数据驱动

P3 建议改进:
- 提取 mood_utils.dart 公共函数,消除 4 处重复定义
- 贴纸库搜索框连接 StickerBloc 按名称过滤

P4 细节打磨:
- 家长页多孩子时显示 DropdownButton 选择器
- 搜索结果日记卡片点击跳转 /editor?id=
- MonthlyPage 照片数量从 JournalElement 统计
- calendar_page/mood_page/search_page 统一使用 moodToEmoji/moodToLabel
2026-06-02 20:21:51 +08:00
iven
75db6a7eb7 fix(server): 修复菜单种子迁移 — 使用动态 tenant 查询替代 nil UUID
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
2026-06-02 14:13:32 +08:00
iven
74551d48e6 feat(server): 添加暖记日记管理菜单种子数据 + 图标注册
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- 新增迁移 m20260602_000301_diary_menu_seed
- 插入'日记管理'目录菜单 (BookOutlined, sort=50)
- 子菜单: 班级管理/日记审核/主题管理/贴纸管理
- 关联 admin + teacher 角色 (menu_roles)
- 图标注册: BookOutlined, ScheduleOutlined, SmileOutlined
2026-06-02 12:24:29 +08:00
iven
78018a9a64 feat(app): 管理端 Web 基座→暖记品牌迁移 + 日记管理页面
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
Phase 1 — 品牌替换:
- BRAND_DEFAULTS 回退值改为暖记品牌 (themes.ts)
- 登录页/侧边栏/底部回退文字 → 暖记 (Login, MainLayout)
- index.html title/meta/favicon → 暖记
- localStorage key → nuanji-theme, 默认主题 → warm
- 4 套主题色适配暖记设计系统 (珊瑚 #E07A5F / 蓝 / 深色 / 鼠尾草绿)
- 品牌信息通过系统设置配置,不硬编码

Phase 2 — 清理 HMS 模块:
- 删除 health/ai 页面 (~55+2)、API (~30+9)、组件、stores、hooks
- 重写 Home.tsx 为暖记 Dashboard
- 重写 NotificationPanel/MediaPicker 移除 health 依赖
- 清理 routeConfig 移除所有 health/ai 路由权限

Phase 3 — 暖记管理页面:
- API 层: api/diary/{types,journals,classes,topics,comments,stickers}.ts
- 班级管理: 班级列表+创建+成员查看+班级码复制 (ClassList)
- 日记审核: 日记列表+筛选+详情+老师点评 (JournalList)
- 主题管理: 班级选择+主题卡片+创建+过期标记 (TopicList)
- 贴纸管理: 贴纸包卡片+贴纸详情网格 (StickerPackList)
- 路由注册: /diary/classes, /diary/journals, /diary/topics, /diary/stickers

验证: tsc 0 error, vite build ✓, vitest 226/226 pass
2026-06-02 12:16:44 +08:00
iven
0a9e5b1cb3 docs: 更新 wiki + CLAUDE.md — 三端架构和管理端集成
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- wiki/index.md: 更新关键数字、三端架构图、启动命令、症状导航
- wiki/architecture.md: 补充三端架构、来源追溯、活跃问题更新
- wiki/admin-web.md: 新建管理端文档 — 结构/API代理/功能映射/品牌定制清单
- CLAUDE.md: 补充 apps/web 目录、管理端场景化指令、三端启动命令
2026-06-02 10:11:03 +08:00
iven
8111471e93 feat: 添加管理端前端 (HMS 基座 React 管理面板)
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
- 从 HMS 基座复制 apps/web/ (React + Ant Design + Vite + TypeScript)
- 管理端自动代理 API 到 localhost:3000 (vite.config.ts)
- 更新 scripts/dev.sh 支持三端启动: backend/admin/app
- 登录验证通过, 用户管理/角色权限/审计日志等页面正常
- 添加 .gitignore 排除 node_modules/dist
2026-06-02 10:03:13 +08:00
iven
181bfb1f3e fix(app): 对齐 Open Design spec — 字体/Token/首页/Tab栏/路由/Discover页
针对 docs/opendesign/warm-notes-design-spec.md 全面审查的修复:

## 🔴 阻断级修复(商用合规)
- 下载真实 Quicksand/Nunito 字体文件(原 0 字节)
- 添加 OFL.txt 许可证文件,履行 SIL Open Font License 分发义务

## 🟠 设计 Token 偏差
- AppRadius: 删除非规范的 xs=8px,所有引用迁移至 sm=10px
- AppColors.moodColors: 对齐 spec §3.6
  - happy #FFD93D → secondary #81B29A
  - calm #81B29A → tertiary #F2CC8F
  - sad #7B9CC4 → #5B7DB1
  - thinking #B8A9C9(淡紫,spec 无)→ #8B7E74
- AppShadows: blurRadius/alpha 精确对齐 spec §1 (12/20/32 + 0.06/0.08/0.12)
- DesignTokens: 补 spacing40 + 新增 safe-top/safe-bottom/tab-height/touch-min 常量

## 🟠 首页 §3.4 完全重构
- 新增问候语头部(xx好,小暖 + accent 色高亮名字)
- 新增 streak-badge pill 徽章(tertiary-soft + #B8860B 暖金)
- 心情选择器卡片背景从 primaryContainer 改为 surface(spec 规定 #FFFFFF)
- 心情卡片圆角 lg(22) → md(16) 对齐 spec
- 新增 today-card 渐变卡片 + 浮动右下圆形写按钮
- 新增 quick-stats 三栏统计(本月日记/连续天数/总日记数)
- 移除 AppBar 多余的贴纸/模板按钮,搜索按钮改路由到 /search
- HomeBloc 扩展 monthCount/totalCount 字段
- 日记卡片:72×72 预览图 + 标签摘要 + 心情圆点

## 🟠 路由 §3.12 + §3.13 拆分
- 新建 DiscoverPage (features/discover/views/discover_page.dart)
  - 搜索框(跳转 /search)
  - 每日推荐渐变卡片
  - 热门话题横向 chips(前 3 个 accent 高亮)
  - 精选模板 2 列网格
  - 达人日记列表
- /discover 路由从指向 SearchPage 改为 DiscoverPage
- 新增 /search 路由(全屏无 Tab)指向 SearchPage

## 🟠 Tab 栏 §2.2 重构
- 高度从 64px 改为 56+bottomPadding(含 safe-bottom,约 90px)
- 中心按钮从 CircularNotchedRectangle 凹槽改为 margin-top:-16px 凸起
- FAB 尺寸从默认改为 48×48 spec 规格
- FAB 图标从 edit_rounded 改为 add_rounded(spec §2.2)
- 删除未使用的 _navItems 旧常量

## 🟡 登录页圆角统一
- 移除 3 处 InputBorder 显式 mdBorder(16px) 覆盖
- 全局主题 smBorder(10px) 生效,对齐 spec
- 提交按钮圆角改为 pill(spec §2.6 Primary 按钮)

## 验证
- flutter analyze: 0 errors (剩余 40 个 warning/info 全为预存)
- flutter test: 84/85 通过(widget smoke test 预存失败,与本次无关)
2026-06-02 09:11:46 +08:00
iven
b320641d9c fix(app): 全链路验证修复 — 编译错误/CORS/迁移/启动脚本
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
前端修复:
- calendar_page: 移除不存在的 JournalEntry.content getter
- responsive_scaffold: 移除不存在的 notchThickness 参数
- splash_page: SingleTickerProvider → TickerProvider (多 AnimationController)
- profile_page: UserRoleType.name → .code (修复运行时崩溃)
- 导入缺失的 user.dart

后端修复:
- class_service: generate_class_code 取 UUID 后6位(随机部分)避免碰撞
- diary_role_seed: 移除不存在的 id 列,使用复合主键 ON CONFLICT

基础设施:
- config/default.toml: CORS 改为通配符(开发模式)
- scripts/dev.sh: 统一启动脚本(自动清理端口)
- docs/opendesign/: Open Design 设计规格 HTML 原型稿

验证结果: flutter analyze 0 error, cargo test 77/77 通过, 17个页面全部渲染正常
2026-06-02 01:03:58 +08:00
iven
749ef55b89 feat: Week 4 收尾 + 架构治理 — 搜索/家长中心/Feature Flag/Docker/环境配置
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
架构治理:
- Feature Flag 落地: Cargo.toml [features] default=["diary"] + main.rs cfg 条件编译
- 环境配置统一: AppConfig 类 + --dart-define 注入 + SSE 端口 8080→3000 修复

搜索替代方案 (无 FTS):
- SearchBloc + 标签/心情筛选接入后端 API
- JournalRepository 扩展 mood/tag 筛选参数
- 搜索页 UI 接入实际数据(替换占位文本)

家长中心最小集 (PIPL 合规):
- 后端: parent_service (绑定/查看/导出/删除/解绑) + parent_handler (6 个 API 端点)
- 前端: ParentBloc + ParentPage 功能完整实现
- 绑定孩子、只读查看日记、导出数据、删除数据、解绑

Docker 部署:
- verify.sh 健康检查脚本 (Axum/PG/Redis/OpenAPI 四项检查)

测试修复:
- home_bloc_test / calendar_bloc_test 适配 JournalRepository 新参数

验证: flutter test 84/84 pass, cargo test 76/76 pass, cargo check pass
2026-06-01 23:53:34 +08:00
iven
ffde0c9e77 feat(test): Week 3 质量保障体系 — 55 新增测试 + CI/CD 流水线
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
前端第二批测试 (42 用例):
- AuthBloc: 16 用例 (启动恢复/登录/注册/角色选择/班级码/登出)
- HomeBloc: 8 用例 (数据加载/今日检测/心情统计/连续天数/离线容错)
- CalendarBloc: 10 用例 (月份切换/日期选择/视图模式/状态保持)
- MoodBloc: 8 用例 (统计加载/周期切换/API解析/错误处理)

后端 P0 单元测试 (13 用例):
- journal_service: 5 用例 (model_to_resp 转换/mood回退/weather回退/tags解析)
- sync_service: 8 用例 (冲突收集/DTO构造/序列化roundtrip/非冲突排除)

CI/CD:
- pr-check.yml: PR 触发 cargo fmt+check+clippy+test + flutter analyze+test
- main-merge.yml: main push 触发完整检查 + cargo audit 安全审计

测试统计: 前端 84 通过, 后端 73 通过 (全部通过)
2026-06-01 23:20:18 +08:00
iven
f0921d554c fix(app): 修复 ShareBottomSheet nullable 检查 2026-06-01 23:06:39 +08:00
iven
4c743e150e test(app): 前端第一批测试 — EditorBloc 19用例 + JournalElement 11用例 + InMemoryRepo 12用例
添加 mocktail 测试依赖 + 字体文件占位
总计 42 测试通过,覆盖工具/笔画/元素/撤销/重做/序列化/乐观锁/CRUD
2026-06-01 23:02:14 +08:00
iven
3eaf83c79a feat(app): 老师点评功能 — CommentCreate事件 + CommentBottomSheet + 日记墙点评按钮 2026-06-01 22:49:56 +08:00
iven
973bb56af6 feat(app): 编辑器完成按钮接入分享面板 — ShareBottomSheet + sharedToClass更新 2026-06-01 22:45:56 +08:00
iven
55285b57a7 feat(app): 班级码验证前后端联调 — AuthBloc接入API + 错误计数锁定UI 2026-06-01 22:42:33 +08:00
iven
b3fc066aac feat(db): 添加 student/teacher/parent 角色种子 — 日记权限分配 2026-06-01 22:37:52 +08:00
iven
6cb288b4f2 feat(diary): 班级码验证添加5次错误锁定 — Redis计数 + 30分钟冷却 2026-06-01 22:34:02 +08:00
iven
0c6a33d96b chore(app): linter 格式化 + image_picker 自动生成插件注册 2026-06-01 21:44:07 +08:00