Focalboard v1.0 路线图深度解析:从开源看板到 Trello / Notion / Asana 自托管替代品的演进路径
【免费下载链接】focalboardFocalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.项目地址: https://gitcode.com/GitHub_Trending/fo/focalboard
本文基于 Focalboard 团队 2021 年 5 月发布的官方路线图博客(《Focalboard: The road to v1.0》),结合当前仓库源码,逐项拆解 Focalboard 从 v0.6.5 走向 v1.0 的功能规划:视图体系完善、属性类型扩充、内容类型扩展、侧边栏与个人仪表盘,以及它与 Mattermost 的深度集成方向。读完本文,你将完整掌握 Focalboard 的核心数据模型(Board / View / Card / Block)、各类视图的源码实现结构,以及官方在 2021 年对 v1.0 功能边界的定义。
一、背景:为什么 Focalboard 需要一份明确的 v1.0 路线图
2021 年 5 月,Focalboard 在经历了 GitHub Trending、Hacker News、Reddit 与 Product Hunt 的社区爆发之后(v0.6.5 发布时仓库已从 40 星增长到 3200+ 星),由核心维护者 Chen Lim 发布了这篇路线图博客。文章开篇点明了项目的北极星定位:
Focalboard 要成为一个有吸引力的开源、自托管、可替代 Trello、Notion 和 Asana的产品。
这个定位直接体现在当前仓库根目录 README 的项目描述中("Focalboard is an open source, self-hosted alternative to Trello, Notion, and Asana."),也贯穿了整份路线图的所有条目——每一项规划都指向"80% 用户关心的通用功能"这一目标。
路线图声明了即时目标:先把这三个参考产品中的共性功能补齐,即"80% 用户"都会用到的功能集合。同时文档也明确说明,这只是"当前计划",许多条目仍处于探索阶段,不构成任何承诺——这是官方对社区预期的负责任表述。
二、产品差异化核心:与 Mattermost 的深度集成
路线图明确指出,Focalboard 的主要差异化优势之一是与 Mattermost 的紧密集成。这一方向在仓库中对应的早期预览博客(《Mattermost-Focalboard Early Preview》,2021-04-27 发布)中有详细描述:
- 每个 Mattermost 频道(公开与私密)关联一个对应的 Focalboard workspace,仅该频道的成员可以访问;
- 通过频道头部的 Focalboard 图标即可打开对应 workspace;
- 立即可获得的好处是继承 Mattermost 的安全与访问控制系统,例如按 workspace 粒度配置权限的能力;
- 当时的早期预览仅支持 Web 浏览器访问,桌面端与移动端暂不支持,且官方明确警告属于"bleeding edge",不要存放关键或敏感数据。
路线图还预告了后续计划中的两类集成能力:
- 卡片链接 unfurling:在 Mattermost 中预览 Focalboard 卡片链接的摘要信息;
- Slash 命令创建卡片:通过 Mattermost 的斜杠命令直接新建卡片。
这两项能力在仓库中由server目录下的插件适配层支撑——例如 server/ws/plugin_adapter.go 与 server/ws/plugin_adapter_client.go 构成了 Focalboard 以 Mattermost 插件形态运行时的 WebSocket 适配通道,从源码结构可以推断,卡片创建、实时更新等操作正是通过这套适配层与 Mattermost 端到端打通。
三、核心功能规划:补齐并完善现有视图
路线图的第一大块规划是"完成 / 更新现有视图",涵盖 Board、Table、Gallery、Card 四种视图。这些视图在当前的 webapp/src/components 目录中均有独立实现目录,并配有各自的单元测试与快照测试。
3.1 Board 视图(看板)
规划中的两项关键补强是看板导出 / 导入与键盘支持。看板视图的源码实现位于 webapp/src/components/kanban/kanban.tsx,从代码结构看,它的核心机制是:
- 以
groupByProperty(分组属性)驱动列结构,每一列对应属性中的一个 option(kanbanColumn.tsx); - 通过
onDropToColumn/onDropToCard回调实现拖拽换列、拖拽排序,并调用mutator.changePropertyValue与mutator.changeViewCardOrder持久化变更; - 支持隐藏列(
hiddenGroups)、折叠列、列内计算(kanbanCalculations)以及按defaultTemplateId从模板快速新建卡片。
关于导出/导入,仓库 webapp/src/archiver.ts 实现了 archive 的导出与导入逻辑,服务端对应 server/api/archive.go 提供 API;而键盘支持(issue #29)在后来的迭代中逐步落地为卡片操作快捷键。
3.2 Table 视图(表格)
规划条目为分组表格 / 列表视图与键盘支持。Table 视图实现在 webapp/src/components/table 目录,其中的 tableGroup.tsx 与 tableGroupHeaderRow.tsx 正是"分组表格"能力的载体——Table 视图可以根据分组属性把行按组渲染,这一能力后来也演化为独立的 List 视图的基础。
3.3 Gallery 视图(画廊)与 Card 视图
Gallery 视图在 v0.6.5 版本中作为新特性发布(见 《Focalboard v0.6.5 发布说明》),用于以矩形网格展示带图片元素的卡片。路线图中对 Gallery 和 Card 的规划主要是"各类 bug 修复"。当前实现 webapp/src/components/gallery/gallery.tsx 展示了其核心能力:按visiblePropertyIds过滤显示属性、通过onDropToCard支持拖拽排序、配合HiddenCardCount显示被过滤隐藏的卡片数量。
四、新增视图:List、Calendar 与 Pages
4.1 List 视图:基于 Table 分组的延伸
路线图明确说明 List 视图的当前计划是扩展 Table 视图以支持分组,而非另起炉灶。这与源码实现吻合:Table 目录中的tableGroup系列组件已具备分组渲染能力,List 视图正是它的进一步产品化形态。
4.2 Calendar 视图:按日期属性排布卡片
Calendar 视图(issue #338)的规划在仓库中已落地为完整实现:webapp/src/components/calendar/fullCalendar.tsx 基于@fullcalendar/react构建,结合@fullcalendar/daygrid与@fullcalendar/interaction插件实现月视图与拖拽交互。从源码结构看:
- 通过
dateDisplayProperty(日期显示属性)确定卡片在日历上的位置; createDatePropertyFromCalendarDate将日历选择结果转换为DateProperty(含from/to起止时间戳);- 拖拽卡片会调用
mutator.changePropertyValue更新卡片的日期属性值; - 仅当用户具备
Permission.ManageBoardCards权限时才允许新建卡片。
4.3 Pages:与卡片内容块同构
Pages 的规划是"基础实现与卡片上的内容块相同",并预告了高级内容编辑器(issue #166)。内容块体系在源码中有清晰定义:webapp/src/blocks/block.ts 声明了内容块类型列表['text', 'image', 'divider', 'checkbox', 'h1', 'h2', 'h3', 'list-item', 'attachment', 'quote', 'video'],每种类型都有对应的块组件,例如 textBlock.ts、imageBlock.ts、checkboxBlock.ts、dividerBlock.ts 与 attachmentBlock.tsx。Pages 与卡片共享这套内容块体系,正是"基本实现相同"的代码级印证。
五、新增属性类型:Date、User 与 Multi-select
路线图规划了三种新属性类型,如今全部已在仓库中实现。属性类型的完整枚举定义在 webapp/src/blocks/board.ts:
type PropertyTypeEnum = 'text' | 'number' | 'select' | 'multiSelect' | 'date' | 'person' | 'multiPerson' | 'file' | 'checkbox' | 'url' | 'email' | 'phone' | 'createdTime' | 'createdBy' | 'updatedTime' | 'updatedBy' | 'unknown'属性类型的注册中心在 webapp/src/properties/index.tsx,registry.register()依次注册了 Text、Number、Email、Phone、Url、Select、MultiSelect、Date、Person、MultiPerson、Checkbox、CreatedTime、CreatedBy、UpdatedTime、UpdatedBy 等类型,每种类型对应 webapp/src/properties 下的一个子目录(如date/、person/、multiselect/、multiperson/)。对照路线图:
| 路线图规划 | 当前仓库实现 | 源码位置 |
|---|---|---|
| Date 属性(issue #38) | date/createdTime/updatedTime | webapp/src/properties/date |
| User 属性(issue #185) | person/multiperson,并衍生createdBy/updatedBy | webapp/src/properties/person |
| Multi-select(issue #110) | multiSelect | webapp/src/properties/multiselect |
其中 Date 属性在 Calendar 视图中扮演核心角色,其from/to时间戳结构直接参与日历事件的生成(见 fullCalendar.tsx 中的DateProperty处理逻辑)。
六、新增内容类型:卡片互链
路线图规划的"链接到另一张卡片"(issue #324)内容类型,目标是让卡片之间可以互相引用。这属于内容块(Content Block)体系的扩展方向。当前内容块类型清单(见 webapp/src/blocks/block.ts)已包含文本、图片、分割线、复选框、标题、列表项、附件、引用、视频等多种类型,卡片互链将作为新的块类型加入这一体系。卡片间的关系在数据层通过 card 的parentId字段关联(卡片可以嵌套在卡片内容中),这一点在 webapp/src/blocks/card.ts 与 server/model/block.go 的 Block 结构定义中可以找到支撑。
七、侧边栏改进与个人仪表盘
7.1 侧边栏:手动排序与键盘导航
路线图规划了侧边栏的手动排序(issue #299)与键盘导航(issue #28)。当前侧边栏实现在 webapp/src/components/sidebar 目录,包含 13 个 tsx 组件与配套的 scss / snap 快照测试。从组件结构可以推断,侧边栏管理着分类(Category)、看板列表与工作区导航,手动排序能力依赖 webapp/src/store 中的状态管理与mutator的持久化写入。
7.2 个人仪表盘:状态页
规划中的 Personal Dashboard 包含一个状态页(issue #305),作为用户的个人工作总览入口。该能力与后来社区讨论中的"个人待办 / 个人项目"定位一脉相承——这与 Personal Desktop Edition(个人桌面版)的场景相呼应,桌面端代码位于 mac/Focalboard 与 win-wpf/Focalboard。
八、关于视图与数据模型:一张视图的完整字段画像
理解上述所有视图规划,绕不开 Focalboard 的核心数据模型:一切皆 Block。视图(View)本身也是一个 Block,其字段结构定义在 webapp/src/blocks/boardView.ts:
type IViewType = 'board' | 'table' | 'gallery' | 'calendar' type BoardViewFields = { viewType: IViewType groupById?: string dateDisplayPropertyId?: string sortOptions: ISortOption[] visiblePropertyIds: string[] visibleOptionIds: string[] hiddenOptionIds: string[] collapsedOptionIds: string[] filter: FilterGroup cardOrder: string[] columnWidths: Record<string, number> columnCalculations: Record<string, string> kanbanCalculations: Record<string, KanbanCalculationFields> defaultTemplateId: string }这份字段清单恰好解释了路线图中几乎所有视图相关条目:
viewType区分 Board / Table / Gallery / Calendar 四种视图类型,新增的 List 视图沿用 Table 的分组能力,Calendar 视图则额外依赖dateDisplayPropertyId;groupById驱动看板分组与表格分组(对应"分组表格 / 列表视图");sortOptions、cardOrder分别对应自动排序与手动拖拽排序(Gallery 视图中isManualSort = activeView.fields.sortOptions.length === 0即"未配置排序时允许手动排序");filter(FilterGroup,定义于 webapp/src/blocks/filterGroup.ts)与visibleOptionIds/hiddenOptionIds支撑视图级筛选与隐藏列;visiblePropertyIds决定每张卡片 / 每一行展示哪些属性(Kanban 与 Gallery 组件均通过它过滤属性模板)。
九、参与共建:反馈、贡献与后续演进
路线图在最后向社区发出两项号召,这也是理解 Focalboard 开源协作模式的关键:
- 持续反馈:特性建议与 Bug 报告是产品方向的重要输入。仓库的 CONTRIBUTING.md 与 pull_request_template.md 提供了完整的贡献流程说明,docs/contribution-checklist.md 与 docs/contributions-without-ticket.md 分别给出了合入前检查清单与免工单贡献的说明;
- 认领任务:社区可以在带有 "up for grabs" 标签的 issue 中挑选适合自己的任务——仓库的 docs/core-committers.md 也记录了核心提交者的协作机制。
从后续发展看,这份路线图上的大部分条目都在随后的版本中陆续落地:Calendar 视图、Date / Person / Multi-select 属性、导出导入、侧边栏排序等均已出现在当前仓库源码中,印证了官方"以 80% 用户共需功能为优先"的推进节奏。对于希望深入了解 Focalboard 内部实现、或想为开源项目做贡献的开发者,这份路线图连同仓库源码(尤其是 webapp/src/blocks、webapp/src/properties 与 webapp/src/components 三个目录)构成了从产品规划到代码实现的最佳对照读本。
【免费下载链接】focalboardFocalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.项目地址: https://gitcode.com/GitHub_Trending/fo/focalboard
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考