Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions CODEX_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# StudyFlow Codex Handoff

## 交接日期与分支

- 交接环境:Ubuntu 22.04
- 交接分支:`feature/v3-meditation`
- 远端仓库:`https://github.com/MingLeeEatPy/studyflow.git`
- 目标:把 Ubuntu 中途停止的工作安全保存到 GitHub,随后在 Windows VS Code + Codex 继续。

## 本次开发新增内容

本地未提交工作包含 V3 Growth Garden + Meditation:

- IndexedDB schema version 3 与 V3 JSON backup。
- `GrowthRecord`、学习树、冥想花、Today 花园及稳定植物变体。
- `MeditationSession`、`MeditationInterval`、Meditation Repository 和页面。
- 定时/自由冥想、呼吸引导、暂停/恢复、到时后正计时、复盘、History 类型筛选。
- V3 单元测试、Playwright 测试和 Meditation 视觉快照。

## 已知未完成与风险

这不是已发布的 V3。最近的双重审查确认以下问题必须由 Windows Codex 继续处理:

- 点击结束后复盘填写期间仍可能继续计时,应先冻结并持久化结束时间。
- V3 导入的 Meditation 状态组合和成长记录一致性校验仍不够严格。
- 页面关闭后重新打开时,长时间间隔的休眠检测还需要持久化心跳支持。
- 多标签结束会话时,另一页需要可靠退出沉浸路由并清理旧复盘状态。
- Today/快速开始的 Meditation 入口、呼吸阶段轻提示音、冥想专用休眠文案和部分无障碍行为仍需补齐。

## 当前验证证据

上一次 Ubuntu 验证记录:

- `npm run typecheck`:通过。
- `npm run lint`:通过。
- `npm test -- --run`:92 tests passed。
- `npm run build`:通过。
- `npm run test:e2e`:26 tests passed。

这些结果证明当前本地流程可运行,但不代表上面的审查问题已经解决。Windows 接手后应先重新运行所有检查,再修复风险并新增回归测试。

## Ubuntu 上运行

项目路径:`/home/minglee/Projects/studyflow`

```bash
cd /home/minglee/Projects/studyflow
export PATH="$HOME/.local/opt/node-v24.19.0-linux-x64/bin:$PATH"
npm install
npm run dev
```

也可以使用:

```bash
./studyflow.sh
```

浏览器访问 `http://127.0.0.1:5173`。设计样板使用 `http://127.0.0.1:5173/?design-preview=1`。

## Windows Codex 接手顺序

1. 先执行 `git status`、`git branch -vv`,确认工作区和远端分支。
2. 阅读本文件、`PRODUCT.md`、`ROADMAP.md` 和最近提交记录。
3. 重新运行 typecheck、lint、unit、E2E 和 build。
4. 先修复“已知未完成与风险”,并为每个修复增加回归测试。
5. 再进行两次独立只读审查和完整本地验收。
6. 只在用户确认后创建 Draft PR;不要自动合并 `main` 或创建正式版本标签。
27 changes: 27 additions & 0 deletions PRODUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# StudyFlow 产品交接说明

## 当前版本

当前工作区位于 `feature/v3-meditation`,目标版本为 V3 开发中间态。V1 与 V2 的核心计划和执行功能已经进入可运行状态;V3 的成长花园和 Meditation 已在本地完成一轮实现,但尚未合并到 `main`,也尚未发布正式版本号。

## 产品定位

StudyFlow 是 Web-first、本地优先的个人学习计划与执行助手,核心闭环是:

`Plan → Execute → Record`

当前不包含账号、云同步、PWA、好友自习室、完整分析图表、白噪音课程或 AI Planner。

## 已完成能力

- 任务、分类、Today、四象限和本地 IndexedDB 持久化。
- Stopwatch、Pomodoro、Focus Mode、暂停/恢复/休息/超时正计时。
- 任务结果、未完成原因、总结、History 和带审计记录的修正。
- V1/V2 数据迁移与 JSON 备份导入导出。
- V3 数据库结构、`GrowthRecord`、五阶段学习成长树和 Today 花园。
- Meditation 的定时/自由模式、4-7-8/均衡/箱式/无引导、暂停恢复、复盘、冥想花和 History 类型筛选。
- 刷新恢复、BroadcastChannel 多标签同步、休眠时间确认的基础流程。

## 当前交接状态

本次 Ubuntu 任务的目标是安全保存并同步现有工作,不继续扩展 Roadmap。V3 代码保留为可供 Windows Codex 继续审查的开发中间态;不要把当前状态当作已发布的 V3 成品。
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# StudyFlow

## 视觉设计样板

当前的「自然沉浸与正念成长」视觉样板通过以下地址访问:

```text
http://127.0.0.1:5173/?design-preview=1
```

样板使用本地假数据,不读取或写入 StudyFlow 的 IndexedDB。Today、Plan、Focus、学习成长树和 Meditation 已分阶段接入正式界面;样板仍使用隔离的假数据。

StudyFlow 是一个 Web-first 的个人学习计划与执行助手。V2 已形成第一阶段的 `Plan → Execute → Record`:先安排学习任务,再用正计时或番茄钟执行,并把实际投入和结果保存为可审计的本地记录。

## 主要功能
Expand All @@ -19,7 +29,9 @@ StudyFlow 是一个 Web-first 的个人学习计划与执行助手。V2 已形
- 完成/部分完成/未完成、原因、总结和备注
- History 日期/分类/任务/结果筛选,以及保留修改前后值的时间线修正
- IndexedDB 本地持久化、`TaskEvent`、`StudyInterval` 和 `SessionRevision` 历史
- V2 完整 JSON 备份、V1 备份兼容导入和覆盖导入前安全备份
- V3 完整 JSON 备份、V1/V2 备份兼容导入和覆盖导入前安全备份
- 学习会话驱动的五阶段成长树与 Today 花园(不会补生成升级前的历史植物)
- Meditation 定时/自由模式、呼吸引导、冥想花和学习/冥想 History 隔离(当前仍处于 V3 交接中间态)

## 启动

Expand Down Expand Up @@ -73,8 +85,9 @@ npm install
## Roadmap

- V1 Plan:任务、Today、四象限、分类和本地历史(已完成)
- V2 Execution:Focus Mode、计时、番茄钟和实际学习记录(当前版本)
- V3 Experience + PWA:离线安装、环境音和主题体验
- V2 Execution:Focus Mode、计时、番茄钟和实际学习记录(已完成主要功能)
- V3 Growth Garden + Meditation:成长树、Today 花园和冥想流程(本地实现,待 Windows 继续收尾)
- V3 后续 Experience + PWA:离线安装、环境音和主题体验
- V4 Analytics + Sync:学习统计、完成率、趋势和可选同步
- V5 AI Planner:根据目标、可用时间和历史执行情况动态调整计划

Expand Down
23 changes: 23 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# StudyFlow Roadmap

## 当前交接点

- V1 Plan:已完成。
- V2 Execution:已完成主要功能,当前版本仍需在后续发布流程中确认版本号和合并目标。
- V3 Growth Garden + Meditation:本地分支已有实现和测试,但本次只完成安全交接,不继续添加新功能。

## V3 尚未完成或需要下一位 Agent 继续处理

1. 结束 Meditation 时需要先持久化冻结计时,再打开复盘;填写复盘的时间不能继续计入本次冥想。
2. V3 备份导入需要完整验证 Meditation 状态机、区间组合、`<60 秒` 丢弃规则和成长花记录的一致性。
3. 重新打开浏览器时,需要基于持久化心跳识别页面关闭期间的长时间休眠间隔。
4. 结束/切换标签页后的沉浸页面、复盘弹窗和活动会话状态需要更严格地按 session ID 清理。
5. Today 与快速开始需要增加 Meditation 快捷入口。
6. 呼吸阶段的轻提示音、冥想专用休眠提示文案以及 Meditation 的无障碍 live region/焦点管理仍需完善。
7. 完成上述修复后,再进行独立审查、提交、Draft PR、用户验收和正式合并;不要直接合并到 `main`。

## 后续路线

- V3 收尾:完成上述状态与交互边界后发布。
- V4:学习时长、完成率、预计/实际比较、周报趋势,以及按需要设计账号和同步。
- V5:基于目标、截止日期、可用时间和历史执行能力的 AI Planner。
38 changes: 38 additions & 0 deletions docs/design-preview/ASSET_PROMPTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 原创背景资产生成记录

生成方式:Codex 内置 `imagegen`,`photorealistic-natural` 模式。植物与花朵没有使用图片生成,均为项目内可维护的 SVG。

## Focus 雾林

输出:`src/assets/nature/focus-forest.webp`

```text
Use case: photorealistic-natural
Asset type: full-screen desktop web app Focus background
Primary request: an original quiet misty forest scene for a study focus timer, with softly blurred leaves and fine branches framing the scene and calm atmospheric depth
Scene/backdrop: early morning woodland with light fog, natural foliage, no buildings
Style/medium: photorealistic natural photography with subtle film texture, refined but not glossy
Composition/framing: wide landscape composition; generous uncluttered negative space through the center for an overlaid plant illustration, timer, and controls; foliage may frame the outer edges but must not create a strong focal object
Lighting/mood: soft diffused dawn light, meditative, quiet, restrained, low contrast
Color palette: deep ink green #10241E, moss green #294C40, muted sage #6F9280, small touches of warm gray; low saturation
Constraints: background image only; no UI; no people; no animals; no text; no logos; no watermark; suitable for a dark translucent overlay; original composition
Avoid: neon green, bright sun, fantasy glow, dramatic landscape, colorful flowers, high contrast, busy detail, obvious stock-photo polish
```

## Meditation 晨雾水面

输出:`src/assets/nature/meditation-water.webp`

```text
Use case: photorealistic-natural
Asset type: full-screen desktop web app Meditation background
Primary request: an original tranquil waterside dawn scene for a meditation timer, with still water, delicate mist, soft reeds and barely visible distant foliage
Scene/backdrop: quiet natural pond or slow lake at first light, no structures
Style/medium: photorealistic natural photography with subtle film texture, refined and understated
Composition/framing: wide landscape composition; calm uncluttered negative space through the center for an overlaid breathing halo, flower illustration, timer, and controls; subtle natural framing only at far edges
Lighting/mood: diffused pale morning light through mist, serene, contemplative, soft and low contrast
Color palette: muted warm gray, deep ink green #10241E, sage #6F9280, soft stone and a restrained trace of warm gold #D7B77A; low saturation
Materials/textures: gentle water reflection, realistic fine mist, soft organic reeds
Constraints: background image only; no UI; no people; no animals; no flowers as focal subjects; no text; no logos; no watermark; suitable for a dark translucent overlay; original composition
Avoid: vivid sunrise, orange sky, neon teal, dramatic mountains, fantasy glow, colorful flowers, busy detail, high contrast, obvious stock-photo polish
```
117 changes: 117 additions & 0 deletions docs/design-preview/DESIGN_SYSTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# StudyFlow「自然沉浸与正念成长」视觉设计系统

状态:视觉方向已确认,设计 token 已接入 Today、Plan、Focus、成长树和 Meditation 正式页面。该目录中的 `?design-preview=1` 仍使用完全隔离的假数据,不读写正式 IndexedDB。V3 Meditation 代码目前处于交接中间态,详见仓库根目录的 `CODEX_HANDOFF.md`。

## 1. 设计原则

StudyFlow 是一个安静、自然、克制、有呼吸感的学习与正念空间。

- 信息优先:任务标题、计时和主要操作始终比装饰更清晰。
- 自然但不拟物:自然照片只建立氛围,成长植物使用柔和分层 SVG,不模仿 Forest 的游戏视觉。
- 成长但不奖惩:植物记录真实投入,不枯萎、不用金币、连续签到或强烈庆祝制造压力。
- 沉浸但可退出:Focus 与 Meditation 可以降低视觉噪音,但暂停、结束和返回始终清晰可见。

## 2. Design tokens

| 用途 | Token | 值 |
| --- | --- | --- |
| 浅色主背景 | `--sf-mist` | `#F3F5F1` |
| 暖色辅助背景 | `--sf-warm` | `#F5F1E9` |
| 主文字 | `--sf-ink` | `#18231E` |
| 品牌鼠尾草绿 | `--sf-sage` | `#6F9280` |
| 柔光绿 | `--sf-sage-soft` | `#9AB9A8` |
| 深色沉浸背景 | `--sf-forest` | `#10241E` |
| 深色辅助层 | `--sf-moss` | `#294C40` |
| 到时与超时提示 | `--sf-gold` | `#D7B77A` |

圆角分为四级:控件 `12px`、任务卡 `18px`、主面板 `24px`、沉浸控制区 `32px`。不要为了“更圆”随意增加新级别。

## 3. 毛玻璃与背景边界

允许使用毛玻璃:

- Today 的主统计与今日花园
- Plan 的筛选工具栏
- 全局活动计时栏
- 弹窗
- Focus 与 Meditation 的沉浸控制区

不使用或只使用近实色:

- 任务卡和四象限内的密集内容
- 表单输入、选择器和长文本
- History 的记录列表
- 需要连续阅读的说明文字

浅色玻璃为约 62% 白色与 `18px` blur;深色玻璃为约 48% 黑绿与 `24px` blur。无 `backdrop-filter` 时分别降级为 `#F7F8F5` 与 `#18332A` 实色。

自然照片只用于 Focus、Meditation 和少量冥想入口 Hero。Today 与 Plan 使用抽象雾化渐变,避免装饰干扰优先级判断。

## 4. 代表页面

### Today

- 第一屏左侧显示计划、完成、剩余、实际专注和进行中的会话。
- 右侧“今日花园”直接显示最近植物,正式接入时最多 8 株。
- 任务列表保持近实色与高对比度。
- 移动端改为单列,主操作收成圆角图标按钮。

### Plan

- 四象限与列表切换、分类/状态/日期筛选保持现有能力。
- 筛选只使用一层玻璃;象限使用低饱和红、蓝、琥珀、绿。
- 象限任务卡保持近实色,不叠加多层透明效果。

### Focus

- 本地雾林背景上覆盖深绿渐变,保证中心文字对比。
- 植物、任务、计时和控制区沿同一视觉轴排列。
- 运行、暂停和超时都有明确文字;暖金只用于到时/超时提醒。
- 植物动画不遮挡计时,`prefers-reduced-motion` 下停止非必要动画。

### Meditation

- 本地晨雾水面背景比 Focus 更柔和、更开放。
- 设置、呼吸、冥想、复盘是四个连续但可跳过的状态。
- 呼吸光圈使用缓慢缩放和文字提示;声音提示应作为可选增强,不能成为理解阶段的唯一方式。
- 感受选择不使用“好/坏”评价,不强迫填写备注。

## 5. 成长系统

学习生成树,冥想生成花。五阶段为:

1. `<10%`:种子
2. `10–34%`:嫩芽
3. `35–64%`:幼苗
4. `65–99%`:小树或花苞
5. `≥100%`:成熟树或盛开

植物阶段跟随有效时间与目标快照动态计算。提前结束或未完成不会枯萎;成熟后超时只增加少量叶片或柔光。低饱和变体应由会话 ID 稳定生成,备份与刷新后不能改变。

## 6. Meditation 操作流程

```text
Today / 侧边栏 / 快速开始
→ 选择定时或自由计时
→ 选择意图
→ 选择呼吸引导
→ 呼吸引导(可跳过)
→ 冥想计时(暂停 / 恢复 / 提前结束)
→ 定时结束响铃
→ 超时正计时,直到主动结束
→ 五档感受与可选备注
→ 保存或跳过复盘并保存
→ 生成冥想花,并进入 History 与今日花园
```

呼吸引导阶段不计入核心冥想时长。正式实现必须复用现有通知、音量、多标签同步、刷新恢复与休眠确认能力,并保证全局只有一个学习或冥想活动会话。

## 7. 实施门禁

当前已完成设计确认样板和第 1 项正式视觉改造,后续依次实施:

1. ~~正式视觉 token 与 Today / Plan / Focus 改造~~
2. IndexedDB version 3、备份 version 3、成长记录与今日花园(已完成)
3. Meditation 状态边界、备份校验、异常恢复与无障碍收尾(待 Windows Codex 继续)

每阶段单独验收,禁止在视觉改造阶段顺带修改正式数据模型。
Binary file added docs/design-preview/screenshots/focus-desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/design-preview/screenshots/focus-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/design-preview/screenshots/plan-desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/design-preview/screenshots/plan-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/design-preview/screenshots/today-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions e2e/design-preview.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { expect, test } from "@playwright/test";

test.describe("隔离设计样板", () => {
test("可以浏览代表页面并且不会创建正式数据库", async ({ page }) => {
await page.goto("/?design-preview=1");

await expect(page.getByRole("heading", { name: "今天,按自己的节奏前进" })).toBeVisible();
await expect(page.getByText("今日花园")).toBeVisible();
expect(await page.evaluate(async () => (await indexedDB.databases()).length)).toBe(0);

await page.getByRole("button", { name: "Plan", exact: true }).first().click();
await expect(page.getByRole("heading", { name: "把精力放在真正重要的地方" })).toBeVisible();

await page.getByRole("button", { name: "Focus", exact: true }).first().click();
await page.getByRole("button", { name: "暂停", exact: true }).click();
await expect(page.getByText("已暂停 · 植物也在休息")).toBeVisible();
await page.getByRole("button", { name: "超时", exact: true }).click();
await expect(page.getByText("本轮已完成 · 超时专注")).toBeVisible();

await page.getByRole("button", { name: "Meditation", exact: true }).click();
await expect(page.getByRole("heading", { name: "此刻,你需要怎样的停留?" })).toBeVisible();
await page.getByRole("button", { name: "开始这次停留" }).click();
await expect(page.getByText("吸气")).toBeVisible();
await page.getByRole("button", { name: "冥想", exact: true }).click();
await expect(page.getByText("安静地停留")).toBeVisible();

expect(await page.evaluate(async () => (await indexedDB.databases()).length)).toBe(0);
});

test("手机预览使用 390×844 设计画布", async ({ page }) => {
await page.goto("/?design-preview=1&screen=today");
await page.getByRole("button", { name: "手机宽度" }).click();
const viewport = page.locator(".preview-viewport");
await expect(viewport).toHaveCSS("width", "390px");
await expect(viewport).toHaveCSS("height", "844px");
await expect(page.locator(".mobile-nav")).toBeVisible();
});
});
26 changes: 26 additions & 0 deletions e2e/execution.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@ test("不足一分钟的临时学习会话自动丢弃", async ({ page }) => {
await expect(page.getByText("误触计时")).toHaveCount(0);
});

test("Focus 按真实投入成长,结束后植物进入今日花园", async ({ page }) => {
await openAtFixedTime(page);
await page.getByRole("link", { name: "Plan" }).click();
await page.getByRole("button", { name: "新建任务" }).click();
await page.getByLabel("任务标题").fill("一分钟成长实验");
await page.getByLabel("预计完成时长").fill("1");
await page.getByLabel("截止日期").fill("2026-08-14");
await page.getByRole("button", { name: "保存" }).click();
await page.getByRole("article", { name: "一分钟成长实验" }).getByRole("button", { name: "开始学习" }).click();
await page.getByRole("button", { name: "进入 Focus" }).click();

await expect(page.locator(".focus-botanical .tree-stage")).toHaveClass(/stage-0/);
await page.clock.runFor(30_000);
await expect(page.locator(".focus-botanical .tree-stage")).toHaveClass(/stage-2/);
await page.clock.runFor(31_000);
await expect(page.locator(".focus-botanical .tree-stage")).toHaveClass(/stage-4/);
await page.getByRole("button", { name: "结束学习" }).click();
await page.getByRole("button", { name: "确认结束" }).click();
await page.getByRole("link", { name: "Today" }).click();

const garden = page.getByRole("list", { name: "今日成长植物" });
await expect(garden).toBeVisible();
await expect(garden.getByRole("listitem")).toHaveCount(1);
await expect(garden.getByRole("img", { name: "成熟树" })).toBeVisible();
});

test("番茄钟到时后等待确认,再进入休息阶段", async ({ page }) => {
await openAtFixedTime(page);
await page.getByRole("link", { name: "专注设置" }).click();
Expand Down
Loading
Loading