Fizzy Cards API 实战指南:看板卡片的全生命周期管理

发布时间:2026/9/16 21:22:45
Fizzy Cards API 实战指南:看板卡片的全生命周期管理 Fizzy Cards API 实战指南看板卡片的全生命周期管理【免费下载链接】fizzyKanban as it should be. Not as it has been.项目地址: https://gitcode.com/GitHub_Trending/fizzy2/fizzy卡片Card是 Fizzy 看板中任务与工作项的基本单元——它们可以被组织进工作流列Column、打上标签、指派给用户、附加评论还可以经历从草稿、分诊Triage、关闭到 Golden 标记的完整状态流转。本文以 Cards API 参考 为骨架逐端点讲解如何通过 HTTP 接口完成卡片的查询、创建、更新、删除与状态操作并结合本仓库的 路由定义、CardsController、JSON 序列化模板 与 Filter 模型 源码说明每个参数背后的真实实现。读完本文你将能够独立编写脚本或机器人对 Fizzy 卡片做完整的读写与控制。一、前置知识认证、Base URL 与通用机制所有 Cards 端点都隶属于 Fizzy API统一使用/:account_slug作为路径前缀例如示例中的897362094并以 JSON 格式交换数据。调用前请先阅读 API 总览 与 认证指南掌握以下通用约定认证方式使用Authorization: Bearer token头携带个人访问令牌Personal Access Token适用于脚本与集成或使用 Magic Link 会话令牌Cookie适用于原生应用。令牌分为Read与Read Write两种权限写操作创建、更新、删除等要求具有写权限。ETag 缓存大多数端点返回ETag与Cache-Control头后续请求带上If-None-Match可获得304 Not Modified避免重复下载未变化的数据。分页所有列表端点均分页页面大小是动态的靠前页返回更少结果若有更多数据响应头会给出Link: ...?page2; relnext。列表参数凡是接受多值列表的参数都以[]结尾可重复传参例如?tag_ids[]tag1tag_ids[]tag2。文件上传image等文件字段需改用multipart/form-data请求且可与普通参数混用。富文本description接受经过清洗sanitize的 HTML 输入具体直传流程见 Rich Text 指南。在 api_test.rb 中可以看到完整认证链路的集成测试Bearer令牌通过HTTP_AUTHORIZATION请求头注入bearer_token_env无效令牌返回401 Unauthorized而只读令牌执行写操作同样返回401。二、列出卡片GET /:account_slug/cards该端点返回当前身份有权限访问的卡片分页列表并通过查询参数进行多维筛选。这是 Cards API 最强大的端点对应 Filter#cards 中的查询构建逻辑。2.1 查询参数表参数说明board_ids[]按看板 ID 筛选tag_ids[]按标签 ID 筛选assignee_ids[]按指派用户 ID 筛选creator_ids[]按卡片创建者 ID 筛选closer_ids[]按关闭卡片的用户 ID 筛选card_ids[]精确到指定卡片 ID 列表column_ids[]按工作流列 ID 筛选indexed_by筛选索引all默认、maybe、closed、not_now、stalled、postponing_soon、goldensorted_by排序方式latest默认、newest、oldestassignment_status按指派状态筛选unassignedcreation按创建时间筛选today、yesterday、thisweek、lastweek、thismonth、lastmonth、thisyear、lastyearclosure按关闭时间筛选取值同上terms[]搜索关键词用于全文检索过滤卡片组合语义重复的column_ids[]值之间是OR关系例如?column_ids[]acolumn_ids[]b表示列 a 或列 b 中的卡片其余筛选条件之间以AND组合。示例column_ids[]03f...— 返回指定工作流列中的卡片。2.2 参数背后的源码实现从源码看这些参数与 Filter::Params::PERMITTED_PARAMS 中声明的内容一一对应PERMITTED_PARAMS [ :assignment_status, :indexed_by, :sorted_by, :creation, :closure, card_ids: [], column_ids: [], assignee_ids: [], creator_ids: [], closer_ids: [], board_ids: [], tag_ids: [], terms: [] ]筛选链在 Filter#cards 中按固定顺序叠加先限定creator.accessible_cards.preloaded.published再依次应用indexed_by、sorted_by、显式卡片 ID、Not Now/关闭状态、未指派、指派者、创建者、看板、标签、时间窗口、关闭者、搜索词与列 ID最后distinct去重。这意味着接口的筛选能力与实际看板 UI 的筛选能力同源——同一个 Filter 模型同时服务于页面与 API。indexed_by与sorted_by的取值映射见 Card#indexed_by / Card#sorted_byscope :indexed_by, -(index) do case index when stalled then stalled when postponing_soon then postponing_soon when closed then closed when maybe then awaiting_triage when not_now then postponed.latest when golden then golden when draft then drafted else all end end scope :sorted_by, -(sort) do case sort when newest then reverse_chronologically # created_at DESC when oldest then chronologically # created_at ASC when latest then latest # last_active_at DESC else latest end end可见newest/oldest依据创建时间latest依据最近活跃时间last_active_atmaybe实际是“待分诊”awaiting triagenot_now则是“已推迟且按活跃度排序”。这些枚举定义在 Filter::Fields 中INDEXES %w[ all closed not_now stalled postponing_soon golden ]SORTED_BY %w[ newest oldest latest ]默认值{ indexed_by: all, sorted_by: latest }。creation/closure时间窗由 TimeWindowParser 解析为起止时间范围。2.3 响应结构[ { id: 03f5vaeq985jlvwv3arl4srq2, number: 1, title: First!, status: published, description: Hello, World!, description_html: div class\action-text-content\pHello, World!/p/div, image_url: null, has_attachments: false, tags: [programming], golden: false, last_active_at: 2025-12-05T19:38:48.553Z, created_at: 2025-12-05T19:38:48.540Z, url: http://app.fizzy.localhost:3006/897362094/cards/4, board: { id: 03f5v9zkft4hj9qq0lsn9ohcm, name: Fizzy, all_access: true, created_at: 2025-12-05T19:36:35.534Z, auto_postpone_period_in_days: 30, url: http://app.fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm, creator: { id: 03f5v9zjw7pz8717a4no1h8a7, name: David Heinemeier Hansson, role: owner, active: true, email_address: davidexample.com, created_at: 2025-12-05T19:36:35.401Z, url: http://app.fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7 } }, creator: { id: 03f5v9zjw7pz8717a4no1h8a7, name: David Heinemeier Hansson, role: owner, active: true, email_address: davidexample.com, created_at: 2025-12-05T19:36:35.401Z, url: http://app.fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7 }, comments_url: http://app.fizzy.localhost:3006/897362094/cards/4/comments, reactions_url: http://app.fizzy.localhost:3006/897362094/cards/4/reactions } ]列表项序列化模板见 app/views/cards/_card.json.jbuilderdescription输出纯文本to_plain_textdescription_html输出富文本 HTMLimage_url在有头图时给出 URLtags为标签标题排序后的数组assignees会附带最多 5 个指派用户并给出has_more_assignees标记该字段在文档示例中未展示但列表响应中实际存在可据此判断是否需要额外拉取。url、comments_url、reactions_url提供后续操作的导航入口。三、获取单张卡片GET /:account_slug/cards/:card_number通过卡片编号number获取单张卡片的完整信息。注意 URL 中不是 UUID而是递增的短编号——从源码看 Card#to_param 返回number.to_s且 CardsController#set_card 使用Current.user.accessible_cards.find_by!(number: params[:id])按编号查询同时受访问控制约束。{ id: 03f5vaeq985jlvwv3arl4srq2, number: 1, title: First!, status: published, description: Hello, World!, description_html: div class\action-text-content\pHello, World!/p/div, image_url: null, has_attachments: false, tags: [programming], closed: false, golden: false, last_active_at: 2025-12-05T19:38:48.553Z, created_at: 2025-12-05T19:38:48.540Z, url: http://app.fizzy.localhost:3006/897362094/cards/4, board: { id: 03f5v9zkft4hj9qq0lsn9ohcm, name: Fizzy, all_access: true, created_at: 2025-12-05T19:36:35.534Z, auto_postpone_period_in_days: 30, url: http://app.fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm, creator: { id: 03f5v9zjw7pz8717a4no1h8a7, name: David Heinemeier Hansson, role: owner, active: true, email_address: davidexample.com, created_at: 2025-12-05T19:36:35.401Z, url: http://app.fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7 } }, column: { id: 03f5v9zkft4hj9qq0lsn9ohcn, name: In Progress, color: { name: Lime, value: var(--color-card-4) }, created_at: 2025-12-05T19:36:35.534Z }, creator: { id: 03f5v9zjw7pz8717a4no1h8a7, name: David Heinemeier Hansson, role: owner, active: true, email_address: davidexample.com, created_at: 2025-12-05T19:36:35.401Z, url: http://app.fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7 }, comments_url: http://app.fizzy.localhost:3006/897362094/cards/4/comments, reactions_url: http://app.fizzy.localhost:3006/897362094/cards/4/reactions, steps: [ { id: 03f8huu0sog76g3s975963b5e, content: This is the first step, completed: false }, { id: 03f8huu0sog76g3s975969734, content: This is the second step, completed: false } ] }注意closed字段表示卡片是否处于“Done”状态。column字段仅在卡片已分诊进某工作流列时出现处于 Maybe?、Not Now 或 Done 状态的卡片不会有该字段。这一点在序列化模板中也有印证app/views/cards/_card.json.jbuilder 中json.column ... if card.column为条件输出。单卡片响应还额外包含steps步骤清单标题、是否完成card.steps通过Multistep模块关联。四、创建卡片POST /:account_slug/boards/:board_id/cards在指定看板中创建新卡片。与其它端点不同创建动作挂在看板资源下见 routes.rb 中resources :boards do resources :cards, only: :create end。参数类型必填说明titlestring是卡片标题descriptionstring否富文本描述statusstring否初始状态published默认、draftedimagefile否卡片头图tag_idsarray否应用到卡片的标签 ID 数组created_atdatetime否覆盖创建时间戳ISO 8601 格式last_active_atdatetime否覆盖最近活跃时间戳ISO 8601 格式请求示例{ card: { title: Add dark mode support, description: We need to add dark mode to the app } }响应返回201 Created响应头Location指向新创建的卡片。源码印证请求体必须包在card键下这是因为 CardsController 开头声明了wrap_parameters :card, include: %i[ title description image created_at last_active_at ]允许顶层扁平参数自动包装最终通过card_paramsparams.expect(card: [ :title, :description, :image, :created_at, :last_active_at ])做强校验Strong Parameters。created_at与last_active_at的覆盖能力支持数据迁移与历史数据导入场景。注意从源码结构看JSON 分支创建时状态被固定为publishedHTML 分支则进入草稿流程因此若需要drafted状态的卡片可先创建后再用更新端点调整status。五、更新卡片PUT /:account_slug/cards/:card_number更新已有卡片请求体同样包在card键下。参数类型必填说明titlestring否卡片标题descriptionstring否富文本描述statusstring否卡片状态drafted、publishedimagefile否卡片头图tag_idsarray否应用到卡片的标签 ID 数组last_active_atdatetime否覆盖最近活跃时间戳ISO 8601 格式请求示例{ card: { title: Add dark mode support (Updated) } }响应返回更新后的完整卡片结构同单卡片响应。控制器侧 update 执行card.update! card_paramsJSON 格式下渲染:show模板草稿发布/回退为草稿的status流转另有 publishes_controller.rb 与路由resource :publish支持。六、删除与头图操作6.1 删除卡片DELETE /:account_slug/cards/:card_number删除一张卡片。权限约束只有卡片创建者或看板管理员可以删除。响应成功返回204 No Content。源码中权限检查在 CardsController#ensure_permission_to_administer_carddef ensure_permission_to_administer_card head :forbidden unless Current.user.can_administer_card?(card) end即无权限时返回403 Forbidden与 API 总览 的错误码约定一致。6.2 移除头图DELETE /:account_slug/cards/:card_number/image移除卡片的头图对应 images_controller.rb路由resource :image。成功返回204 No Content。七、状态流转关闭、重新打开与 Not NowFizzy 卡片存在多种非列状态通过独立子资源端点切换操作端点效果关闭卡片POST /:account_slug/cards/:card_number/closure进入 Done 状态closed为true重新打开DELETE /:account_slug/cards/:card_number/closure移出 Done 状态移入 Not NowPOST /:account_slug/cards/:card_number/not_now推迟到 “Not Now” 列表三者成功均返回204 No Content。对应控制器为 closures_controller.rb 与 not_nows_controller.rb路由在 routes.rb 中声明为resource :closure、resource :not_now。卡片关闭能力由Closeable、推迟能力由Postponable模块提供这也解释了列表筛选里indexed_byclosed与indexed_bynot_now的含义。八、移动与组织换板、分诊、标签与指派8.1 移动到其他看板PUT /:account_slug/cards/:card_number/board参数类型必填说明board_idstring是目标看板 ID请求示例{ board_id: 03f5v9zkft4hj9qq0lsn9ohcm }响应返回200 OK与移动后的卡片结构与单卡片响应一致board字段反映新看板。对应 boards_controller.rb底层逻辑见 Card#move_to它在一个事务中同时迁移卡片、卡片事件与评论事件到新看板保证活动历史的连贯性。8.2 分诊TriagePOST / DELETE /:account_slug/cards/:card_number/triagePOST将卡片移入指定工作流列参数column_idstring必填为目标列 ID成功返回204 No Content。DELETE将卡片送回“待分诊”Maybe?状态成功返回204 No Content。分诊对应 triages_controller.rb卡片列归属由Triageable模块管理。8.3 切换标签POST /:account_slug/cards/:card_number/taggings在卡片上切换toggle一个标签若标签不存在则自动创建。参数类型必填说明tag_titlestring是标签标题开头的#会被剥除成功返回204 No Content。对应 taggings_controller.rb实际响应由 app/views/cards/taggings/create.turbo_stream.erb 等模板驱动HTTP 层面返回空响应。8.4 切换指派POST /:account_slug/cards/:card_number/assignments切换某用户与卡片的指派关系指派/取消指派。参数类型必填说明assignee_idstring是要指派/取消指派的用户 ID成功返回204 No Content。对应 assignments_controller.rb未指派筛选assignment_statusunassigned即判断卡片当前没有任何指派者。九、关注与特殊标记Watch 与 Golden9.1 关注/取消关注POST / DELETE /:account_slug/cards/:card_number/watchPOST当前用户订阅该卡片的通知成功返回204 No Content。DELETE当前用户取消订阅该卡片的通知成功返回204 No Content。对应 watches_controller.rb 与Watchable模块UI 侧的按钮状态由 app/views/cards/watches/_watch_button.html.erb 渲染。关注后卡片上的后续活动评论、指派等会触发通知。9.2 Golden 标记POST / DELETE /:account_slug/cards/:card_number/goldnessPOST将卡片标记为 Golden金票成功返回204 No Content。DELETE移除 Golden 标记成功返回204 No Content。对应 goldnesses_controller.rb 与Golden模块响应中的golden布尔字段即由此而来列表筛选的indexed_bygolden也只返回被标记的卡片。十、实战建议与调用要点善用 ETag 做增量同步定时轮询GET /:account_slug/cards/:card_number时把上次响应的ETag放入If-None-Match未变化时得到304避免无谓的带宽与解析开销参考 API 总览 的缓存章节。列表端点优先于逐个抓取一次GET /:account_slug/cards即可按看板、标签、指派者、时间窗等多维条件批量取卡再通过Link: relnext分页翻完动态页大小意味着前几页结果较少属正常现象。写操作注意令牌权限创建、更新、删除及所有状态切换端点都需要Read Write令牌权限不足会得到401见 api_test.rb 中“changing data requires a write-endowed access token”测试。组合筛选的语义边界只有column_ids[]的多个值是 OR 关系其余全部 AND若需要“列 A 或列 B”直接重复传参即可无需构造复杂查询。上传文件走 multipartimage字段请用-F card[image]/path/to/cover.jpg形式提交参考 API 总览 的文件上传章节description富文本如需附带内嵌附件请先阅读 Rich Text 指南 的直传流程。通过以上 17 个端点你可以完整覆盖 Fizzy 卡片的“创建 → 分诊 → 流转 → 指派/打标 → 关闭 → 删除”全生命周期并将其嵌入自动化脚本、外部工具或机器人流程中。【免费下载链接】fizzyKanban as it should be. Not as it has been.项目地址: https://gitcode.com/GitHub_Trending/fizzy2/fizzy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考