DoraMate这个项目走到第11期正好处在最微妙的阶段——6个月路线图里的MVP开发计划开始从纸面文档逐步收口成一段可以实实在在交付的代码。规划MVP这件事我在项目早期犯过典型错误先打开IDE写代码再反推产品边界。放在Rust全栈项目里这个顺序基本是灾难因为Rust的编译期检查、类型体系和重构成本决定了你很难像写动态语言那样快速换方向。这篇就把DoraMate从6个月路线图到MVP收口的完整思路拆开讲包括阶段划分、技术选型里哪些决定必须提前拍板、功能怎么砍、以及收口阶段真正会翻车的几个地方。如果你正在做Rust全栈项目或者正打算给自己第一个产品规划MVP这篇应该能帮你少走不少弯路。1. 先定MVP边界DoraMate要验证的不是功能而是假设1.1 为什么Rust全栈项目尤其怕边做边想先聊一个容易被忽视的前提技术栈决定了规划方式。Node、Python这类动态语言项目改数据模型、换接口路径成本相对低跑起来再说往往可行。但Rust项目里一次领域模型的调整会牵动struct定义、数据库映射、序列化反序列化、错误处理一整条链路加上增量编译的耗时每次方向修正的代价都是分钟级起步。我最早给DoraMate规划的功能清单有17项包括任务看板、文件共享、AI摘要、通知中心、多端同步。如果按这个范围排期6个月根本做不完更糟的是没有任何一项能做得足够深用户无法形成这个工具有用的判断。所以第二周我就做了一件事把MVP的定义从做完17个功能改成验证3个假设。这个转变很关键。MVP的英文全称是Minimum Viable Product重点从来不在Product而在Minimum和Viable的组合——用最小的成本跑通一个能验证核心价值的版本。对Rust全栈项目来说这个边界尤其重要因为每次方向性修改都要付出更高的编译和重构代价范围越模糊沉没成本越高。1.2 三个核心假设与验证方式DoraMate的定位是面向个人和小团队的效率协作工具核心场景是围绕项目资料和任务的轻量协作。基于这个定位MVP阶段我只保留了三个需要验证的假设假设它到底在问什么DoraMate的验证方式使用假设用户是否愿意把真实项目资料迁入DoraMate管理内测阶段是否产生连续3天以上的活跃使用记录技术假设Rust全栈能否以可控成本支撑核心链路核心接口的端到端响应时间与构建发布耗时是否可接受迭代假设个人/小团队能否维持6个月的持续交付节奏每个里程碑是否按时产出可演示的版本这三个假设对应着一个朴素的判断如果用户不愿意迁移资料功能再多也没用如果Rust全栈在MVP阶段就让构建和维护成本失控后面的路线图就是空中楼阁如果节奏维持不住前两条都没有意义。在定这三个假设时我给自己加了一条硬约束每一项都要有对应到具体数据的验证方式而不是感觉好像可以。比如使用假设的验证数据就是内测环境的每日活跃数、资料创建数和任务流转完成率这三个数字直接能在仪表盘上看到。没有数据回路的假设本质上只是愿望。2. 6个月路线图拆解四阶段里程碑与可验收的交付物2.1 整体节奏为什么是6个月6个月不是拍脑袋定的。对一个单人维护的Rust全栈项目来说3个月内搞定技术验证和主链路再用3个月做闭环打磨和收口是比较现实的配比。少于这个周期Rust生态里那些绕不开的工程问题构建配置、跨平台、异步调试会来不及消化多于这个周期项目很容易在漫长的完善中失去焦点进入永远发布不了的死循环。DoraMate的6个月路线图分成四个阶段技术预研、主链路骨架、闭环内测、收口冻结。每阶段之间有明确的门禁——上一个阶段的验收标准没过就不进入下一阶段。我用一张表把这四阶段钉在项目文档首页任何时刻打开仓库都能看到当前处于哪个阶段、在为什么目标努力。阶段时间跨度核心交付物验收标准技术预研第1个月竖向切片Demo、技术选型决策记录跑通创建项目→创建任务→任务状态流转的完整竖切接口响应时间达标主链路骨架第2-3个月认证授权、项目/任务主模块、基础协作能力内测用户能完成核心工作流的全部操作数据不丢闭环内测第4-5个月内测环境、数据仪表盘、问题修复连续两周内测用户活跃数据稳定核心流程无阻断性Bug收口冻结第6个月部署文档、用户指南、MVP版本标签达到功能冻结标准核心链路上无已知严重问题2.2 第1个月技术预研与竖向切片预研阶段最容易踩的坑是把它当成用Rust写个Hello World或者搭个能跑的脚手架。这不是预研这是自我安慰。DoraMate在预研阶段的目标很明确用最小的代码量跑通一条从浏览器到数据库再返回的完整竖切链路。我当时选的是创建项目→创建任务→任务状态流转这条链路别看功能简单它把Rust全栈项目里最关键的几个节点全部覆盖到了路由和参数提取、数据库连接与事务、错误处理、前后端数据交互、构建与热更新。竖切链路跑通说明整个技术骨架是成立的跑不通说明某个环节选型有问题这时候换方案成本最低。这个阶段我留下了一份技术选型决策记录把每项选择的理由、备选方案和当时放弃的原因都写清楚。后面遇到问题回头翻这份记录能省掉大量重复调研的时间。人很容易在三个月后忘记当初为什么不用某个框架这份记录就是防止重复做决策的最好工具。2.3 第2-3个月主链路骨架第二阶段的目标是让内测用户能走完核心工作流。DoraMate这个阶段交付的是认证授权体系、项目与任务的增删改查、成员和基础权限、简单的操作审计日志。在这个阶段我强制自己遵守一条原则只做主链路必需的功能所有顺便加一下的需求全部扔进一个叫Backlog的文档里。这里有个很具体的心得主链路骨架阶段要特别留意数据结构变更的连锁反应。Rust的类型系统会把所有变更点都暴露在编译错误里这其实是好事但它也会让你在改一个字段时面对十几个文件的修改。所以这个阶段每次涉及数据库结构调整我都会先在迁移文件里把改动写清楚再动手改代码避免反复迁移带来的混乱。另外主链路骨架阶段就要开始写测试不能等收口再补。我给核心业务逻辑都补了单元测试给API接口补了集成测试。Rust的测试体系和所有权模型配合起来相当舒服很多在动态语言里需要mock才能测的东西在Rust里直接构造真实数据就能测。2.4 第4-5个月闭环内测内测阶段的核心不是加功能而是建立反馈回路。DoraMate在第4个月部署了独立的内测环境接入了简单的使用数据统计并且规定内测用户的问题必须通过固定渠道反馈方便归集和追踪。我见过太多项目栽在内测环节用户反馈散落在各个聊天群和口头对话里根本没法分类和处理最后只能靠开发者的记忆补丁式修复。这个阶段最值得说的指标是核心流程无阻断性Bug。我把Bug分成三类阻断核心流程的、影响体验但不阻断的、纯视觉或文案问题。MVP收口的底线是第一类Bug清零第二类Bug有明确的临时规避方案第三类Bug在收口阶段直接容忍不修。没有这种分级你会被无休止的细节问题拖进泥潭。内测阶段还需要留意一个数据用户是从哪个环节流失的。如果用户创建了项目但很少创建任务说明任务创建的入口或交互有问题如果用户导入了资料但第二天不再打开说明资料的二次价值没有体现。这些观察会直接影响收口阶段要不要调整某些小交互比任何用户访谈都真实。3. Rust全栈选型哪些决定必须在MVP阶段就拍板3.1 后端基础设施axum tokio SQLxDoraMate后端选型是axum加tokio运行时数据访问用SQLx数据库用MySQL。这套组合在Rust生态里算是最主流的方案之一选择逻辑有三个。第一axum作为Web框架和tokio、tower生态无缝衔接middleware、状态注入、WebSocket这些能力都是体系化的不需要自己拼积木。第二SQLx不是传统ORM它最核心的价值是编译期检查SQL语句与类型映射SQL写错了会在编译阶段被拦下来而不是等线上请求打过来才暴露。第三MySQL作为MVP阶段的数据库足够广泛部署资料多遇到问题容易查到解决方案。实际代码里axum的入口非常简洁核心就几块状态注入、路由注册、中间件链。Cargo.toml里的依赖也保持克制[dependencies] axum 0.7 tokio { version 1, features [full] } sqlx { version 0.8, features [runtime-tokio, tls-rustls, mysql, migrate] } serde { version 1, features [derive] } tracing 0.1 tracing-subscriber { version 0.3, features [fmt] }入口处建立一个AppState把连接池放进去所有handler通过提取器访问use axum::{routing::get, Router}; use sqlx::MySqlPool; #[derive(Clone)] struct AppState { pool: MySqlPool, } async fn health() - static str { ok } pub fn build_router(pool: MySqlPool) - Router { Router::new() .route(/api/health, get(health)) .with_state(AppState { pool }) }用axum写业务接口时我体会最深的是状态注入和提取器的配合。把数据库连接池放到AppState里每个handler只拿自己需要的部分代码结构清晰也方便写集成测试。Rust全栈的全不是靠一个框架包打天下而是靠生态里这些组件彼此咬合减少你自行维护胶水代码的负担。3.2 前端与桌面端Tauri的取舍DoraMate的界面层我在MVP阶段做过一个比较痛苦的取舍。最初方案是上Tauri做桌面端理由很充分Tauri是Rust生态里呼声很高的桌面框架WebView渲染加Rust后端包体小、内存占用低和Rust全栈的定位非常契合。但真正评估之后我把它降级了。原因是Tauri引入了第二套复杂度你需要同时维护Web前端的构建流程和Tauri壳层涉及IPC通信、资源打包、跨平台签名这些东西在MVP阶段都是额外负担。对一个需要快速验证产品假设的项目来说Web端才是最短路径。所以DoraMate的MVP前端选择了一个轻量SPA直接调用axum暴露的REST接口。等产品验证完成、到了需要桌面端场景的时候再在现有Web前端外面套Tauri壳层。Rust后端和Web前端之间的数据模型保持一致迁移成本是可控的。这个决策我特别想说一句全栈不是什么技术热门就全上而是核心链路上每一环都在帮你降低验证成本。Tauri本身是好东西但它在DoraMate的MVP阶段不服务于核心假设所以先放一放。等哪天需要系统级能力、需要离线桌面应用的时候它自然会回到路线图里。3.3 异步任务与后台处理的MVP方案效率协作工具里必然有异步任务比如生成项目摘要、发送通知、导出资料包。这类需求在MVP阶段如果直接引入消息队列属于明显过度设计。DoraMate的做法是先用tokio::spawn加一个任务状态表解决。思路大概是请求进来后把异步任务的信息写入任务表接口立刻返回任务已创建后台用tokio::spawn跑实际处理逻辑完成后更新任务状态。前端轮询或者提供查询接口来获取结果。这套方案不需要额外部署任何中间件能覆盖绝大多数MVP阶段的异步场景。选这个方案还有一个考虑Rust的异步生态本身就有学习曲线tokio的JoinSet、CancellationToken这些工具在MVP阶段不一定都用得上。先用最简单的spawn把链路打通遇到真正的取消、超时、批量控制需求时再逐步引入更复杂的并发原语这样不会在预研阶段就被并发问题劝退。等任务量真的上来了再考虑把任务表改成消息队列的消费模式这条演进路径是平滑的不会因为MVP阶段选了简单方案而卡住后续扩展。4. 功能收口把想要的功能砍成该做的功能4.1 用MoSCoW做功能优先级排序功能收口是MVP阶段最难的一部分难不在技术在心。DoraMate在功能优先级排序上用了MoSCoW方法把功能分成四类Must have、Should have、Could have、Wont have。这四类的资源分配不应该是平均的MVP阶段至少七成精力必须压在Must have上。分类DoraMate的实际功能示例处理策略Must have项目创建、任务流转、成员邀请、基础权限、数据导出必须完整交付纳入验收范围Should have操作日志、批量操作、任务标签尽力交付时间不够可降级Could haveAI摘要、文件在线预览、深色模式有精力就做但绝不能挤占主线Wont have多端同步、插件市场、开放API本期明确不做写进Backlog做完排序以后我做的第一件事是给Wont have里的功能发了死亡证明。这不是说以后不做而是明确告诉自己和协作的人这些东西在MVP阶段不占任何资源。最消耗意志力的其实是那些看起来顺手就能做的小功能比如加个按钮、加个提示。它们单个只花半小时但累积起来会彻底瓦解里程碑节奏。我给自己定过一个规矩每次想新功能时先把它写成一段话贴在Backlog里放三天再回来看。三天后如果还是觉得必须做再进入评估流程。这个冷却期帮我过滤掉了至少一半的情绪性需求。4.2 数据库设计的MVP策略瘦Schema与迁移纪律DoraMate的数据库设计遵循一个原则MVP阶段的Schema只表达当前已验证的业务关系不提前设计未来可能存在的复杂度。比如任务表一开始就只有项目ID、标题、描述、状态、负责人、截止时间这些字段没有预留什么扩展字段也不做复杂的软删除和版本号机制。这个策略可能会让一些有后端经验的朋友不太习惯但我实际跑下来发现在Rust全栈项目里瘦Schema反而让SQLx的编译期检查发挥最大价值。字段越少类型映射越简单查询逻辑越不容易出错。等到业务验证了再加字段配合SQLx的migrate工具成本和一开始就做复杂设计差不多。每次Schema变更我都走一遍固定的迁移流程新写一个迁移文件、在本地数据库执行验证、跑一遍核心链路测试、再提交代码。这个流程看起来朴素但它保证了数据库结构变更永远不会偷偷跳过测试环境。SQLx的migrate功能会自动记录每次迁移的执行状态每台机器上执行过的迁移保持一致这一点在收口阶段帮了大忙——干净环境部署时数据库结构能完全复现。4.3 部署、可观测性与交付的最小闭环MVP收口时部署和可观测性容易被当成以后的事这是个危险的幻觉。没有可重复的部署流程你连收口都说不清——因为没有一个环境能让别人稳定地使用你的产品。DoraMate在收口阶段做的最小闭环包含三件事Docker化部署、结构化日志、健康检查接口。Docker化保证环境一致性日志基础用tracing和tracing-subscriber统一输出到标准输出方便后面接日志收集系统。健康检查接口就是上面代码示例里的/api/health顺手再暴露一个简单的/metrics记录关键接口的请求量和耗时。这套闭环的成本很低但收益很大。收口阶段的大量时间其实花在复现问题上有了一套可观察性的基础复现问题的速度会快很多。我甚至可以说没有这个最小闭环DoraMate的收口至少要多花两周。另外部署流程一定要文档化而且要按从零开始的标准写。收口阶段的部署文档不是给别人看的是给三周后的自己看的。我经历过太多次当时明明配置好了换台机器就起不来的尴尬后来把所有环境变量、启动命令、迁移步骤都写进README才真正消除了这类问题。5. 收口阶段最该盯住的四个控制点5.1 编译时间失控会让团队回避重构Rust项目做到后期增量编译时间会明显增长这是避不开的。DoraMate在收口阶段吃过这个亏有一次改一个公共结构体全量重新编译花了将近四分钟加上测试跑完一轮改动的反馈周期直奔十分钟。这个节奏会严重消耗耐心导致人开始回避重构代码质量随之下降。我后来做了几件事一是把Release配置里的增量编译和LTO设置调好开发环境开增量编译发布环境做全量优化二是定期用cargo bloat之类的工具检查依赖体积把明显膨胀的依赖换成更轻量的替代三是把测试拆成单元测试和集成测试日常开发只跑单元测试集成测试留给CI。这一套组合下来反馈周期从十分钟降到了两分钟内开发体验有明显改善。这里要特别提醒编译性能问题要提前预防不要等收口阶段才处理。我在预研阶段就养成了一个习惯——每次加依赖之前先问一句这个依赖值不值这几秒编译时间。有些功能明明几十行代码就能实现却为了省事引入一个重型crate后期每次编译都要为它买单。5.2 SQLx连接池与事务的隐性坑SQLx的Pool用起来简单但有几个坑值得提前说。第一连接池大小和数据库配置要匹配默认值往往不是最优的。我遇到过连接数打满导致接口超时的问题后来把连接池上限调小、加上获取连接的超时时间情况就好多了。MySQL服务端的max_connections要和连接池大小配合连接池设置成50而数据库只允许100个连接一旦有多个服务实例就很容易撞上限。第二事务使用后必须正确提交或回滚。Rust的所有权机制会在编译期帮你避免很多忘了提交的低级错误这也是我选择SQLx而不是自己封装连接管理的原因之一。但在异步代码里事务对象跨await传递时要特别注意生命周期一个事务在多个异步任务间共享很容易出现死锁或连接被意外回收的问题。第三SQLx的编译期检查依赖环境变量。DATABASE_URL在编译时必须可达否则编译报错。这在本地没问题但在CI里要额外配置好数据库连接串还要用sqlx的离线模式prepare缓存让编译脱离数据库环境cargo sqlx prepare --workspace生成的sqlx-data.json提交到仓库后CI里即使没有真实数据库也能完成编译检查。这个细节我在CI上卡了大半天提前了解能省不少事。5.3 功能冻结期的手痒问题到了第6个月功能冻结是收口成功的关键动作。功能冻结不是说不能碰代码而是不能新增影响数据结构和接口协议的改动。我在这个阶段给自己定了几条纪律Bug修复优先且修复必须附带回归验证文案和样式调整集中在一个时间窗口统一做一切新想法只记入Backlog不进当前代码库。说实话功能冻结期的最大敌人就是手痒。看到某个地方不完美就想顺手改掉改着改着就偏离了收口范围。我的应对方式是把所有想改但收口阶段不该改的条目写进技术债登记册每一条都标注了位置、问题和期望的处理时间。这个登记册的存在不是为了还债而是为了让你能安心地不还债把注意力留在收口上。我在技术债登记册里会记录三列问题描述、影响范围、预计处理时机。比如AI摘要模块的prompt模板硬编码在代码里这一条影响是后续调整prompt要发版处理时机是MVP上线后第一批迭代。有了这个清单收口阶段就可以心安理得地跳过那些将来再优化的事因为它们已经有了明确归宿。5.4 收口的完成标准五条硬性指标最后一项是给收口下一个可执行的标准否则项目永远收不了。DoraMate的MVP完成定义包含五条核心链路所有Must have功能无阻断性Bug部署流程能从零开始完整执行数据迁移在干净环境可重复执行核心操作响应时间在可接受范围内基础使用文档和部署文档存在且能指导新用户上手。这五条全部满足我才给代码库打上MVP版本的标签。当时我还在文档里补了一句备注打标签不是终点是第一个完整版本的起点。标签之后的第一件事不是继续加功能而是回到内测用户的反馈里去找出用户实际怎么用和我设想的怎么用之间的差距。说到这我个人的一个习惯是在打标签那天把6个月前的技术选型决策记录翻出来逐条对照当时的预判和实际结果。哪些选型对了哪些选型给自己挖了坑全都写进项目复盘。这个习惯比任何代码审查都更能帮助下一个项目因为它逼着你面对自己当初的决策质量。DoraMate的MVP收口最终交付的不只是代码和新版本号还有这份写满了真实取舍的复盘笔记。