SpringBoot3+Vue3+MySQL:手把手拆解个人财务管理系统全栈开发

发布时间:2026/9/5 18:09:49
SpringBoot3+Vue3+MySQL:手把手拆解个人财务管理系统全栈开发 当“记账”不再只是记一笔收支而是一个需要支撑未来决策的财务系统时它就不再是一个简单的课设题目而是一面能照出你全栈开发基本功的镜子。很多人在学习 JAVA SpringBoot3 Vue.js3 MySQL 这条路上最痛苦的不是语法不够熟而是学完了不知道从哪里开始把知识“焊”成一个完整的项目。个人财务管理系统恰好是这样一类项目它比图书管理、学生管理系统复杂一点又比电商系统简单很多能覆盖从建表到接口再到前端联调的完整链路。你可以把它当课设、毕设、练习项目但从成长角度看它真正带给你的不是“我会写一个记账Web”而是“我能把一个真实应用从零跑通”。这篇文章不会只给你贴满全篇的代码截图我会把它当成一次完整的工程拆解来写。我们先建立判断个人财务管理系统表面上让你管理收入、支出和账单实际它让你完整经历一次全栈工程的流程——需求建模、数据库设计、接口分层、前端交互、联调排查、部署上线。这个流程才是你从“会写代码”走向“会做项目”的关键门槛。1. 个人财务管理系统真正练的是“从需求到数据库再到接口”的建模能力1.1 为什么这个项目很适合做全栈练习先想一个问题如果让你用 Excel 记账你会怎么设计表格大概率是几个分类 Sheet、一个流水 Sheet再加几个汇总公式。换成 Web 系统核心逻辑是类似的但难点变成了“如何把现实记账需求翻译成数据库表结构和接口”。我见过不少初学者一上来就写用户表、账单表、分类表然后做完一个简单的收支 CRUD 就当成项目完成了。这样确实能应付演示但很难支撑真正的使用场景。个人财务管理系统如果要做得有质感至少要回答下面几个问题收入和支出是否需要分开处理还是统一记录之后再靠类型字段区分分类是多级分类还是一级分类用户是否允许自定义账单查询需要支持按日期范围、按分类、按账户筛选这些条件怎么组合统计报表是按月汇总、按年汇总还是需要自定义时间段余额是实时计算还是每次记录流水后更新账户表里的余额多个用户之间的数据如何隔离个人财务管理系统真正的难点从来不是写接口而是你第一次发现“一个看起来简单的业务做起来要考虑各种边界情况”。前端从列表页做起来不难难在你把整套资产、负债、收支、统计的模型搭得有逻辑。1.2 先学会用“能跑通的最小闭环”去校验你的设计在动手写完整代码之前先别急着建十几个表。我建议的路径是用一张 paper 手画主要页面比如登录页、主页、账单页、统计页。抽出核心实体用户、账户、分类、账单流水。设计核心接口不要一上来就分析五六个模块先把“记账”这个主流程跑通。写最小示例验证登录、记录一条账单、查看列表。这条链路通了再往周边扩展。从工程经验来讲个人财务管理系统适合当作“先跑通、再优化、最后工程化”的最好演练场。初期版本不必复杂但接口、数据库、目录结构要为未来的扩展留出空间。另一个容易被忽略的点是项目正文如果留空或者信息不全最容易失去的不是分数而是目标感。你自己做项目时一定要先给自己写一份“一句话需求”否则很容易写着写着开始堆功能。提示不要把“个人财务管理系统”做成只能用固定测试账号登录的 Demo。哪怕只做单用户版也要先把“用户身份”的边界定义清楚否则之后想加多用户会非常痛苦。2. 用 SpringBoot3 Vue3 MySQL 这套组合到底是新瓶装旧酒还是技术栈升级的红利2.1 为什么 SpringBoot3 不只是 SpringBoot2 的小版本升级SpringBoot3 是基于 Spring Framework 6 构建的一个关键变化是它把 javax 命名空间迁移到了 jakarta。这个变化直接带来一个坑很多老教程里的import javax.servlet.*、javax.persistence.*在 SpringBoot3 项目里会编译报错。如果你正在照着 SpringBoot2 的项目改造第一件事就是把依赖包名改掉。另一个重要变化是版本基线的提升。SpringBoot3 要求 Java 17 及以上如果你机器上还是 Java 8那么本地环境需要先升级。很多人第一次试 SpringBoot3 失败不是代码有问题而是 JDK 版本没配对。更多情况下SpringBoot3 对个人项目的提升体现在起步依赖更规整依赖冲突减少。内嵌容器、Starter 和配置处理的体验更成熟。Spring Security 6 的配置写法和老版本差异很大如果项目要加登录鉴权容易在这里卡住。把 SpringBoot3 作为一个起点去学习并不算“为了新而新”。它更接近当前 Java 后端新项目的主流朝向越早适应越省力。2.2 Vue3 Element Plus Vite 的选型逻辑Vue3 的组合式 API 和 Vue2 的选项式 API 相比最大的价值不是写法变酷而是组件的逻辑复用变得更自然。个人财务系统里记账表单、账单列表、统计图表、弹窗校验等模块之间有不少共享逻辑用组合式函数会把代码组织得更干净。体验下来建议你使用 Vite 而不是 Vue CLI因为 Vite 的开发启动速度和热更新明显更快。如果你在搜 Vue3 项目大量新项目都会默认用 Vite Vue3 Element Plus这套组合对中后台项目非常合适。需要说明的是Element Plus 只是组件库不是强制要求。但如果你的目标是在短时间内做出看上去可用的后台管理界面直接用现成组件库是值得的。你用组件库时还要注意你装的是 Vue3 版本的 Element Plus不是 Element UI否则会提示版本不兼容。2.3 MySQL 依然是个人项目里数据侧的稳妥选择MySQL 在个人项目里几乎是默认配置理由很直接资料多、免费版够用、管理工具成熟、和 SpringBoot 的整合资料丰富。个人财务系统不会遇到高并发难题核心瓶颈往往在设计层面而不是数据库引擎层面。我遇到过不少人纠结要不要上 NoSQL或者要不要引入更复杂的中间件。这里直接给结论做个人财务管理类系统先使用 MySQL 就行。你需要把精力花在表结构设计、索引设计和事务上不要为了技术复杂度而提高门槛。你只需要掌握几件事字符集选择 utf8mb4而不是 utf8因为 MySQL 的 utf8 无法完整存储一些特殊字符和 Emoji。存储引擎用 InnoDB。金额字段用 DECIMAL不要用 FLOAT 和 DOUBLE避免精度问题。时间字段按需选择 DATETIME 或 TIMESTAMP并考虑时区。这些点在初学阶段看起来像“规范”等你的系统真实跑起来就会发现它们是让你少返工的关键。3. 从建表开始把系统的“骨架”立起来3.1 核心数据表的参考设计个人财务管理系统虽然叫“个人”但数据表至少要体现一组基本概念。建议从这四张表起步。用户表sys_user是系统的前提保存登录账号、密码、昵称和状态。密码永远不要明文保存推荐使用 BCrypt 加密。这张表和后续所有数据表都需要关联目的是让每个人只看到自己的账目。账户表account表示某种资金容器比如现金、银行卡、微信、支付宝。它至少应包含所属用户、账户名称、账户类型、初始余额。是否设计“当前余额”字段取决于你的刷新策略。两种方案各有取舍每次记录流水后通过事务更新账户余额查询时直接取余额。不维护余额查询时实时汇总流水计算余额。后一种方案第一次做时更简单但如果账目增长查询性能会下降。通常我建议先维护余额字段并依靠事务保证一致性。分类表category解决收入支出归类问题。分类最好设计为包含类型字段比如 1 代表支出、2 代表收入然后再接分类名称。是否支持多级分类可以根据自己的设计目标决定。个人系统一级分类往往已经够用比如餐饮、交通、购物、工资、理财等。账单流水表bill是系统的核心。每条账单需要包含用户、账户、分类、类型收入或支出、金额、发生时间、备注。金额类型必须使用DECIMAL(10,2)要避免使用浮点类型。账单日期最好独立存储而不是用系统当前时间因为用户经常需要补录历史账目。下面是一个简化版建表脚本不是生产级完整脚本只是帮你理解结构CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, nickname VARCHAR(50), status TINYINT DEFAULT 1, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE InnoDB DEFAULT CHARSET utf8mb4; CREATE TABLE account ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, account_name VARCHAR(50) NOT NULL, account_type VARCHAR(20) NOT NULL, balance DECIMAL(12, 2) DEFAULT 0.00, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE InnoDB DEFAULT CHARSET utf8mb4; CREATE TABLE category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, category_name VARCHAR(50) NOT NULL, type TINYINT NOT NULL COMMENT 1-支出 2-收入, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE InnoDB DEFAULT CHARSET utf8mb4; CREATE TABLE bill ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, account_id BIGINT NOT NULL, category_id BIGINT NOT NULL, type TINYINT NOT NULL COMMENT 1-支出 2-收入, amount DECIMAL(12, 2) NOT NULL, bill_date DATE NOT NULL, remark VARCHAR(255), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE InnoDB DEFAULT CHARSET utf8mb4;看起来很简单但要理解几个细节账单中的type和分类中的type应该保持一致。有的设计会把分类挂在类型下面有的设计会直接用类型字段冗余存储两条路都可以但接口逻辑里必须统一。账单表要建索引至少给user_id bill_date建一个联合索引因为最常见的查询是按用户查看某段日期的账单。amount字段只存正数用type区分收入还是支出。如果允许负数就意味着把所有逻辑的判断复杂度往后端和前端传。3.2 事务是记账功能里最容易被忽略的一条线个人财务系统看起来不涉及复杂的并发写操作但只要涉及“记录一条支出同时扣减账户余额”就必须考虑事务。如果第一步插入账单成功第二步更新余额失败用户的金额显示就会和流水对不上。在 SpringBoot3 中可以给 Service 层方法标注Transactional。当方法中任何一个步骤抛异常整个事务都会回滚避免数据不一致。有一种常见错误是把所有操作写进 controller或者在多个 service 方法里手动调用却忘了统一事务边界。更合适的做法是把“记账”这个动作收敛到一个 service 方法里里面只做三件事——插入账单、更新账户余额、返回最新流水。这种做法才是可验证的。如果账单逻辑分散后面排查问题时你看不到明确的事务边界会很难受。个人财务管理系统的数据量通常不大事务性能不会成为瓶颈但“是否在正确的位置使用事务”却是面试官或评审很看重的工程素养。3.3 统计查询要掌握的 MySQL 写法报表功能是个人财务系统的点睛之笔。月度总支出、单项分类占比、收入趋势这些都是有真实价值的统计。最常用的 SQL 技术是按日期范围加类型过滤再按月或分类聚合。一个实用的思路是不要把所有统计都交给前端。前端拿到全量流水后自己 sum在数据量小的时候也能用但一旦数据量增长前端部分就会卡且维护困难。更稳妥的设计是把统计聚合放在 SQL 层后端只返回汇总以后的数据。下面展示一个参考逻辑按月份统计当前用户每个月的总支出。注意这不是可以直接复制的完整代码而是一个思路示范。SELECT DATE_FORMAT(bill_date, %Y-%m) AS month, SUM(amount) AS total_amount FROM bill WHERE user_id ? AND type 1 AND bill_date BETWEEN ? AND ? GROUP BY DATE_FORMAT(bill_date, %Y-%m) ORDER BY month;在做这类统计时最容易踩的坑有两个第一是日期边界BETWEEN在查询月份时要先确定是包含端点还是不包含第二是时区如果数据库时区与本地时区不一致日期转换可能出现偏差。4. 后端接口拆解一个功能模块和一套演进式的设计方法4.1 目录结构要能体现“按功能划分而不是按技术类型堆文件”个人财务管理系统的后端目录不需要刻意模仿企业级微服务架构但至少要具备一个清晰的层次结构。大多数 SpringBoot 个人项目可以这样组织controller接收前端请求参数校验后调用 service。service写业务逻辑和事务流程。mapper负责数据库访问。entity或domain数据库实体映射。dto接口出入参对象避免直接把实体暴露给前端。config跨域、安全、拦截器配置等。common统一返回结果、异常处理、常量。我之所以强调 DTO是因为很多个人项目直接把 Entity 当成接口返回对象在项目初期确实快但后面一旦实体字段变化接口响应也可能跟着变化前后端联调就容易互相影响。推荐在后端维护一个统一返回结构例如包含code、message、data。这样前端只需处理一种固定格式判断成功与否也变得简单。给个常见示例{ code: 200, message: success, data: {} }4.2 接口清单应该围绕“用户操作”而不是“数据表”如果按“给每张表都做一套增删改查”的思路设计后端结果会变成接口看起来很齐全但前端写起来非常难受因为很多业务动作并不是单纯的某一张表增删改。个人财务管理系统的核心接口建议这样考虑用户相关注册、登录、获取当前用户信息、修改密码、退出登录。账户相关查询账户列表、新增账户、修改账户、删除账户。分类相关查询分类列表、新增分类、修改分类、删除分类。账单相关分页查询账单、按条件筛选账单、新增账单、修改账单、删除账单。统计相关统计某时间段内收入总金额、支出总金额、收支趋势、分类占比。当你把“删除账户”这个动作和“账户下已有账单记录”放到一起时就会发现问题账户被删除后历史账单如何展示是拒绝删除还是把账单迁移到默认账户还是做逻辑删除这些问题比单纯写 SQL 更值得花时间思考。真实个人项目里“硬删除”往往不是最优解。你可以给核心表增加deleted字段例如用逻辑删除来保留历史数据。这样一定程度上能避免误删事故但注意查询时记得统一过滤否则会导致数据串味。4.3 分页查询和条件筛选要一起设计避免最后返工个人财务系统的账单列表一般会面临日期范围、分类、类型、关键字备注等筛选需求。后端接口入参可以做一个 query 对象而不是把每个参数都拆散传进去。参考参数结构{ pageNum: 1, pageSize: 10, startDate: 2025-01-01, endDate: 2025-12-31, categoryId: 2, type: 1, keyword: , accountId: 3 }后端查询时使用 MyBatis 的动态 SQL 或 MyBatis-Plus 的 Wrapper 做条件拼接注意以下场景startDate传了而endDate没传时要处理“查某天以后”。分类筛选传 0 时通常代表“全部分类”不能直接拼到 SQL 里。分页默认值要放在代码里不要把为空的情况漏掉。统计总数最好不要在数据量很大时临时用 count 扫大表但在个人项目阶段这个优化可以先不看。MyBatis 和 MyBatis-Plus 是两种常见选择。MyBatis-Plus 对个人项目确实更省事但如果你想扎实理解 SQL 和 ORM 的关系可以直接先用 MyBatis 手写一些核心 SQL。学习路线不是二选一你可以先跑通简单的查询再逐步引入插件。5. 前端工程化思路从登录页到记账表单怎么把页面组件化5.1 路由权限和登录状态要先设计好个人财务系统是带用户体系的前端的第一个难点往往不是页面美观度而是路由守卫。Vue Router 提供全局前置守卫可以在进入路由前检查本地是否存有 token。如果不存在就引导去登录页存在则放行也可以根据当前用户信息动态加载菜单。推荐的简单流程用户输入账号密码前端调用登录接口。登录成功后后端返回 token 和用户基本信息。前端把 token 存到 localStorage、sessionStorage 或者内存变量中。Axios 请求拦截器自动在请求头携带 token。响应拦截器统一处理 401 等未登录状态跳到登录页。这个链路看起来不复杂但新手经常遇到的问题包括刷新页面后 token 存在但用户信息丢了路由守卫不知道怎么恢复用户状态。对应方案一般是在刷新后根据 token 调用一次“获取当前用户信息”的接口把用户状态重新拉回来。5.2 记账表单要比想象中多考虑交互细节记账页面是整个系统最核心的界面不只是三个输入框加一个提交按钮。在实际操作中往往需要处理选择账户和分类数据来自接口而不是写死。金额输入限制为数字通常保留两位小数。收入支出的切换会决定分类列表变化比如切换支出时只显示支出分类。日期默认给当天但允许用户选择历史日期。修改账单时表单要回显原有数据。分类数据建议做成前端能直接使用的树形或列表结构如果只有一级分类用普通下拉框选择即可。如果以后扩展多级分类就需要把分类数据组织成父子层级。记账表单还有一个需要注意的点编辑历史账单时账户余额要如何处理。因为原账单已经影响过一次账户余额修改后的金额差异也要同步更新账户。这个逻辑如果放在前端做很容易出错如果放在后端一个带事务的 service 方法里处理会比较清晰。5.3 统计页图表是视觉加分项但不是先做核心功能饼图、柱状图、折线图会让人觉得系统变得完整且高级。个人项目里常见选择是 ECharts社区资源和示例丰富Vue3 里可以通过封装组件来使用。但我的建议是别一开始就在图表上花时间先把列表流、记账流、登录身份流做通再考虑用 ECharts 展示月度收支或分类占比。如果你直接在控制台看 ECharts 官网示例复制到项目里发现不显示通常是容器高度没设置。因为 ECharts 图表必须要求容器有明确尺寸否则会渲染异常。这是很常见的一个小问题排查方向应是先检查 DOM 容器高度。个人财务系统的统计页核心价值是让用户直观看到“这个月支出是否超预算”“哪一类支出占比最高”。你的后端返回什么样的结构前端就直接决定图表长成什么样。我建议后端先返回“按月份聚合的收入/支出汇总”以及“按分类聚合的支出金额”前端再根据数据绘制折线图和饼图。5.4 前后端联调时常见的问题在 SpringBoot3 Vue3 项目里联调最常见的问题就是跨域和请求格式不匹配。跨域通常表现得非常直接前端请求接口后在浏览器控制台看到 CORS 错误。解决方式有两种常见路径一是在后端添加跨域配置二是在前端开发环境下配置 Vite proxy。个人开发时我更倾向于项目部署环境统一同源开发阶段用 Vite proxy 解决。Vite 代理配置大概长这样server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }如果后端接口本身就是/api/user/login前端在开发时请求/api路径就会由 Vite 把请求转发到 SpringBoot 服务。上线后则可考虑把前端打包产物放在后端静态目录下或使用 Nginx 统一转发这样基本可以绕开跨域问题。请求格式不匹配的表现很典型比如POST提交时后端用RequestBody接对象前端却用了application/x-www-form-urlencoded的方式提交表单。这会导致后端参数接收不到。我的经验是前后端约定统一用 JSON 数据交互。后端 DTO 用对象接收前端请求头里使用 axios 默认的 JSON 序列化即可。6. 工程化补全日志、异常、校验、版本管理决定项目能不能长期用6.1 统一异常处理应尽早引入一个没有全局异常处理的 SpringBoot 项目联调时很容易直接返回一堆堆栈信息既不够安全也不够易读。合理做法是使用RestControllerAdvice定义全局异常处理器对不同异常类型做统一包装。实践建议的分类参数校验异常一般对应 400 或自定义业务码。业务异常比如账户不存在、金额不合法、分类被删除等。未登录或 token 失效返回 401。服务器未知异常统一返回通用错误信息详情记录到日志。当项目规模扩展到一定程度携带明确错误码的返回结构会带来很多收益。个人财务系统可以把业务码做成常量或枚举集中管理。6.2 校验强度要适度不要所有参数都堆在 ControllerSpringBoot3 validation 可以给 DTO 字段加NotBlank、NotNull、DecimalMin等注解在 Controller 中使用Validated触发校验能减少手写 if 判断。例如新增账单时至少校验金额不为空且大于 0日期不为空分类不能为空账户不能为空有几个校验点是新手经常犯迷糊的金额等于 0 的账单有没有意义日期能不能填未来时间备注最长长度是多少。这些都应该明确规则后写入校验逻辑不要等到用户乱输才发现漏了。6.3 日志、Git 提交和 README 是容易被低估的产出物个人财务系统如果只是自己练习日志和 Git 规范可以松散一些。但如果你想把它放进简历或作为求职作品信息就会很关键。评审者不只看代码功能还会看你的项目管理习惯。推荐至少在项目里做这几件事后端输出请求日志或关键业务日志至少要能追踪一次记账请求在哪个环节失败。使用 Git 提交把完整开发过程按模块拆分提交不要等到全部写完才一次性上传。写一份能跑起来的 README包含技术栈、环境要求、初始化数据库脚本说明、默认账号如果有、启动步骤和常见问题。个人财务系统的价值不只是代码能运行而是项目本身能展示你如何把技术文档、业务规则和工程质量组织到一起。6.4 如果还要继续扩展这个项目能长出什么先给一个判断个人财务管理系统从 0 到 1 比较简单从 1 到 100 才会暴露出架构和工程能力的差距。扩展方向大概有这几类预算管理给分类设置月度预算超支时提醒。账单导入支持导入支付宝、微信或银行导出的账单文件。资产视图展示总资产、总负债、净资产变化。重复账单支持房租、话费等周期性自动生成账单。多端接入把接口封装好后做小程序端或移动端。数据定时备份把 MySQL 数据定期导出。如果一开始就在表结构和接口设计上留出扩展点后面接入这些能力会更顺。比如分类表和账户表都带上user_id就很容易扩展多用户账单表有独立的bill_date就很容易做月度统计。7. 排查链路当“登录成功但列表加载不出来”时你会不会慌做完整全栈项目时问题通常不是一次出现而是链条式出现。前端认为后端没返回后端认为前端没传对参数最后发现是 token 忘了加。这里整理一套适合个人财务系统的排查顺序先看浏览器 Network 面板。请求是否发出请求 URL 是否正确请求状态码是什么响应内容里有没有具体报错再看后端控制台日志。请求是否到达 Controller 层Service 层是否报错SQL 是否能正常执行异常堆栈是在哪一行抛出的再做接口直接测试。在浏览器或接口调试工具里手动调用一次确认是否复现。可以临时绕过前端直接携带 token 请求判断是前端问题还是后端问题。检查参数和业务状态。当前用户是否有权限访问这个账户或分类删除的数据是否在数据库里还存在分类 type 是否和账单 type 匹配这个顺序看起来是常识但很多人忙半天是因为直接去看代码忽略了先确认请求有没有发出去、有没有到后端。全栈开发里网络面板和后端日志是最有效的边界证据能快速把问题定位到某一侧。另一种高发问题是环境变量和依赖。例如后端连接 MySQL 时报错信息提到Public Key Retrieval is not allowed或时区错误这通常与 JDBC URL 配置有关。检查包含以下几个点是否安装 MySQL 并启动。数据库地址、端口、用户名、密码是否正确。JDBC URL 是否带useSSLfalseserverTimezoneAsia/Shanghai。使用的 MySQL 驱动版本是否与 MySQL 服务端版本兼容。依赖导入是否完整比如 mysql-connector-j 是否添加。在做接口测试时我建议先单独验证登录接口能返回 token再验证携带 token 的查询接口能返回数据。链路越短越容易排查这也叫“最小可运行验证”。注意如果后端报错是“白页”或 500先不要急着改代码。先在控制台找到异常类型和堆栈来源再看具体行号不要凭经验乱删配置。8. 写在最后别追求一次做成“大系统”把主流程跑透比堆积功能更重要个人财务管理系统看起来是一个常见的 Java 全栈练手项目但做好它需要的不是更多功能而是更完整的工程意识。从数据库建模、后端接口分层、前端组件拆分到联调与部署每一步都能在真实项目中体现出来。它能锻炼的能力和你以后做真正的商用系统非常接近。你可以按照一个顺序往下走先确认项目需求再初始化前后端工程先实现用户注册和登录再做账户和分类再做账单主流程最后加统计图表等主链路全部稳定之后再考虑预算、周期账单、导出等进阶扩展。如果现在让我给一个最重要建议那就是不要先把五六个模块全部写一遍再从第一个模块开始调错。先把“用户登录 → 进入系统 → 选择账户和分类 → 新增一笔账单 → 列表能看到 → 统计能汇总”这条最小闭环跑通你才真正理解了这套技术栈是怎么协作的。项目本身不小但把它拆成一条条流程去推进时每一步都足够具体也更容易验证结果。