资讯动态

Kaneo 本地端到端验证指南:启动服务、操作数据库与驱动到期提醒流程

发布时间:2026/9/16 13:09:55 来源:尧图企业网站定制
Kaneo 本地端到端验证指南启动服务、操作数据库与驱动到期提醒流程【免费下载链接】app All you need. Nothing you dont. Open source project management that works for you, not against you.项目地址: https://gitcode.com/GitHub_Trending/app116/app本指南基于仓库内.claude/skills/verify/SKILL.md技能文档展开系统讲解如何在 Kaneo 本地开发实例上完成「构建—启动—驱动—断言」的端到端验证流程。你将掌握pnpm dev多服务启动与热重载边界、用psql直连 Postgres 断言数据、避开 Drizzle 字段映射陷阱以及如何在一个会话内快速触发到期提醒due-date reminder与通知投递的完整方法。一、验证工作流总览Kaneo 是一个前后端分离的开源项目管理应用API 与 Web 前端分别是独立进程。验证任何功能改动本质上是围绕「API1337→ Web5173→ 数据库 → 调度器scheduler→ 通知投递」这条链路做闭环确认。整个验证流程可以拆成四个环节环节关键操作验证目标启动pnpm devAPI 与 Web 同时就绪迁移自动执行数据库访问psqlDATABASE_URL直接断言notification、task_reminder_sent等表的行数据驱动界面浏览器操作 Web UI通过真实交互触发业务流如设置到期提醒偏好观察结果通知铃铛 调度器日志确认通知实时投递、提醒按窗口触发下文按此顺序逐一展开。二、启动本地开发实例2.1 一条命令拉起 API 与 Web仓库根目录使用 pnpm Turborepo 管理多包工程根package.json中的dev脚本为turbo dev它会并行拉起各子包API 包apps/api/package.jsondev脚本为tsx watch src/index.ts监听 1337 端口Web 包apps/web/package.jsondev脚本为vite监听 5173 端口。因此执行pnpm dev即可同时启动 API1337与 Web5173两个服务。2.2 启动前先检查端口占用SKILL.md 特别强调用户本地往往已经跑着这两个服务。所以在执行pnpm dev之前先用lsof确认端口是否被占用避免重复起进程或误以为启动失败lsof -nP -iTCP:1337 -sTCP:LISTEN lsof -nP -iTCP:5173 -sTCP:LISTEN-nP禁用主机名与端口名解析输出更干净-sTCP:LISTEN只列出处于监听状态的连接1337 对应 APIHono/Node 服务5173 对应 Vite Dev Server。若两个端口都已有进程在监听说明开发环境已在运行直接复用即可无需再起一份。2.3 热重载的边界.ts与.sql的区别API 进程由tsx watch驱动理解它的重载边界对验证效率至关重要tsx watch会在任何被 import 的.ts文件变更后自动热重启因此修改 API 业务代码如控制器、调度器、schema 的 TS 部分后无需手动重启但apps/api/drizzle/*.sql迁移文件不在热重载监听范围内——编辑迁移 SQL 后必须手动重启 API 进程否则新的迁移不会生效。这一边界在源码中也有印证API 的 dev 入口只指向src/index.ts见apps/api/package.json的dev: tsx watch src/index.ts而迁移文件是独立于该入口的磁盘资产tsx watch不会感知其变化。2.4 迁移自动执行与失败行为Kaneo 的迁移在API 启动时自动运行无需手动执行drizzle-kit migrate。相关逻辑位于 apps/api/src/database/prepare-database-startup.tstests/api/database/prepare-database-startup.test.ts中有对应测试。因此正常启动时apps/api/drizzle/目录下尚未应用的迁移会被依次执行一旦某个迁移失败进程会直接退出1337 端口随之「死亡」。所以验证时若发现 API 连不上第一反应应是查看启动日志中的迁移报错而不是怀疑代码改动本身。三、直连数据库断言数据3.1 从.env提取连接串并进入 psqlSKILL.md 提供了一条非常实用的命令直接从本地.env文件读取DATABASE_URL并进入psql交互式终端DATABASE_URL$(grep ^DATABASE_URL .env | cut -d -f2-); psql $DATABASE_URL命令拆解grep ^DATABASE_URL .env只匹配以DATABASE_URL开头的行避免命中DATABASE_URL_*之类的其他变量cut -d -f2-以为分隔符截取第二个字段及之后的所有内容-f2-而非-f2防止连接串中本身含时被截断最终以该连接串启动psql。进入 psql 后就可以针对通知与提醒链路的核心表做行级断言notification用户收到的通知记录验证通知是否被创建task_reminder_sent提醒去重表验证提醒是否「只发送一次」见下文 3.3user_notification_preference用户通知偏好验证due_date_reminder_enabled、due_date_reminder_lead_time_minutes等字段值。3.2 陷阱Drizzle 字段名与数据库列名不一致SKILL.md 明确指出一个高频陷阱task.userId在 Drizzle 中映射到数据库列assignee_id而不是user_id。在 apps/api/src/database/schema.ts 中可以找到依据taskTable的userId字段定义了assigneeId索引index(task_assigneeId_idx).on(table.userId)说明任务表的负责人列在物理数据库中名为assignee_id。因此在Drizzle/TS 代码中访问任务负责人要写taskTable.userId在psql/SQL中查询task表时对应列是assignee_id不能写user_id会报列不存在。这种命名差异源于「user」在 SQL 中接近保留词的现实考量验证时务必区分两套命名。3.3 时间语义naive UTC 与SET timezone调度器相关时间戳都是naive UTC不带时区的 UTC 时间。因此当你在 psql 里手工复刻调度器的 SQL 逻辑时SKILL.md 要求先执行SET timezone UTC;否则你本地的TimeZone设置如Asia/Shanghai会让now()、BETWEEN等时间比较偏离调度器的真实语义导致验证结果失真。这一点在调度器实现中也有体现due-date-reminders.ts的查询直接使用toISOString()产生的 UTC 字符串与due_date列做BETWEEN比较隐含假设所有时间都是 UTC 语义。四、驱动 Web UI 与触发业务流程4.1 用浏览器自动化驱动界面SKILL.md 建议用claude-in-chrome驱动localhost:5173上的 Web UI——本地会话通常已处于登录态可以直接操作界面而无需处理认证。这一步的价值在于通过真实用户路径触发业务流如修改通知偏好、调整任务截止日期比只改数据库更能验证端到端行为。4.2 通知铃铛实时 WebSocket 投递通知铃铛位于左上角、工作区切换器旁边。它的关键特性是徽标数量通过 WebSocket 实时更新无需刷新页面即可观察到新通知到达。源码层面apps/api/src/ws/ 目录下的广播适配器broadcast-adapter.ts、redis-broadcast-adapter.ts、in-memory-broadcast-adapter.ts提供了通知实时推送的基础设施tests/api/ws/user-broadcast.test.ts等测试覆盖了广播行为。因此验证通知投递时保持页面打开触发操作后直接看铃铛角标即可不需要手动刷新。4.3 到期日期选择器date-only 与本地午夜Kaneo 的到期日期选择器只选日期、不选时间选择某天后会存为该日期对应的本地午夜local midnight以 naive UTC 存储。这意味着在 UI 上选「今天」或「明天」落库的due_date是一个整点午夜时间手工用 psql 改task.due_date时要记住这个语义不要带时区偏移。五、触发到期提醒调度器原理与验证技巧这是 SKILL.md 中最核心的实战环节——如何在一个开发会话内不等待数小时就让到期提醒按预期触发并投递。5.1 调度器节奏与时间窗调度器由 apps/api/src/scheduler/index.ts 初始化其中到期提醒的 cron 表达式为*/5 * * * *每 5 分钟一次并带10 分钟的回看窗口lookback window。窗口常量定义在 apps/api/src/scheduler/reminder-timing.tsexport const REMINDER_WINDOW_MINUTES 10;配合单元测试 tests/api/scheduler/reminder-timing.test.ts 可以精确理解窗口语义isReminderDue只接受「目标时刻已过且未超过 10 分钟」的任务——早于窗口不触发、晚于窗口也不再补发。提醒分两类窗口见 due-date-reminders.ts 的buildWindows提醒类型通知类型判定条件configured_before到期前due_date_reminderdue_date - lead_time落在 [now-10min, now] 窗口内overdue已逾期task_overduedue_date落在 [now-10min, now] 窗口内5.2 推导触发公式到期前提醒的触发时刻为触发窗口 [due_date - lead_time - 10min, due_date - lead_time]其中lead_time来自用户的due_date_reminder_lead_time_minutes偏好默认 1440 分钟即 24 小时见 schema.ts 与迁移 0027_chilly_namorita.sql、0033_public_patriot.sql。SQL 层面调度器用due_date - (lead_time * interval 1 minute) BETWEEN window_start AND window_end实现configured_before分支。5.3 两种加速触发手段要在会话内快速触发提醒SKILL.md 给出两种手段可二选一或组合手段 A通过 UI 设置 lead-time 偏好进入Settings Account Notifications把负责人的 lead-time小时设为一个较小的值。偏好保存后调度器下一次 tick最多 5 分钟后就会按新 lead-time 计算触发窗口。手段 B用 psql 微调 due_dateSET timezone UTC; UPDATE task SET due_date now() interval 2 minutes (lead_time_minutes * interval 1 minute) WHERE id task_id;目标是让due_date - lead落在未来 23 分钟内这样下一个 5 分钟 tick 必然落入 10 分钟回看窗口。注意这里手写 SQL 时要带上 5.3 节的SET timezone并用真实的 lead 值推算。5.4 验证要点去重与发送条件processReminder的逻辑揭示了两个必须验证的行为去重发送前先向task_reminder_sent插入(task_id, reminder_type)记录利用唯一约束task_reminder_sent_task_type_unique见迁移 0027_chilly_namorita.sql做onConflictDoNothing若插入未返回行则跳过通知——保证同一任务的同一类提醒只发一次发送条件过滤查询结果还会排除以下任务见getTasksNeedingReminder没有 assigneeuserId为空或无 due date 的任务位于**终态列isFinal**的任务视为已完成status archived的已归档任务用户显式关闭了dueDateReminderEnabled的任务未设置偏好时默认视为开启默认值 1440/true。验证时如果你改了 due date 却迟迟不触发优先排查任务是否落在终态列、是否已归档或用户偏好是否被关闭。5.5 观察通知投递结果触发成功后断言链路为UI通知铃铛左上角角标 1无需刷新数据库notification表出现due_date_reminder或task_overdue记录task_reminder_sent表出现对应(task_id, reminder_type)去重记录投递如果用户配置了 email / ntfy / Gotify / webhook 任一渠道deliverNotification见 apps/api/src/notification-preferences/delivery.ts会按偏好与工作区规则user_notification_workspace_rule并行投递。邮件标题「Task due soon」/「Task overdue」中的文案由buildDeliveryContent根据leadTimeMinutes动态生成如in 2 hours、in 1 day。六、一个完整的验证演练示例把上述步骤串成一次可复现的端到端验证# 1. 检查端口复用已有实例 lsof -nP -iTCP:1337 -sTCP:LISTEN # 2. 若未启动则拉起开发环境 pnpm dev # 3. 确认 API 就绪迁移成功、端口存活 curl -s http://localhost:1337/ | head -20 # 4. 直连数据库查看当前偏好与任务 DATABASE_URL$(grep ^DATABASE_URL .env | cut -d -f2-); psql $DATABASE_URL在 psql 中SET timezone UTC; -- 注意列名assignee_id 而非 user_id SELECT id, title, assignee_id, due_date, status FROM task WHERE due_date IS NOT NULL ORDER BY due_date LIMIT 5; -- 将某任务的 due_date 拨到未来 23 分钟假设 lead 24h UPDATE task SET due_date now() interval 2 minutes interval 24 hours WHERE id task_id;回到浏览器保持通知铃铛可见等待下一个 5 分钟 tick-- 断言通知已创建 SELECT id, type, user_id, created_at FROM notification WHERE type due_date_reminder; -- 断言去重记录已写入 SELECT * FROM task_reminder_sent;若断言通过且铃铛角标已更新即完成了对「调度器触发 → 去重 → 通知创建 → 实时推送」全链路的验证。七、总结与注意事项启动pnpm dev同时起 API(1337) 与 Web(5173)改.ts自动重启改drizzle/*.sql需手动重启迁移失败会导致端口死掉。数据库用grepcut从.env提取DATABASE_URL记住task.userId 列assignee_id手工 SQL 前先SET timezone UTC。界面通知铃铛在左上角、WebSocket 实时更新due-date 选择器按「本地午夜 naive UTC」落库。提醒触发每 5 分钟 cron 10 分钟回看窗口通过「调小 lead-time」或「psql 拨 due_date」把due_date - lead放到未来 23 分钟即可在会话内触发去重与终态/归档过滤是排查不触发的首要检查点。断言以notification、task_reminder_sent、user_notification_preference三张表为核心配合 UI 铃铛做双端确认。按照这份流程你可以在不改动任何生产配置的前提下快速、可重复地验证 Kaneo 的通知与提醒链路让每次功能改动的验证都在几分钟内闭环。【免费下载链接】app All you need. Nothing you dont. Open source project management that works for you, not against you.项目地址: https://gitcode.com/GitHub_Trending/app116/app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价