企业级软件项目文件结构布局指南(含包结构图)


这是提供企业级软件项目文件结构布局指南,通过严格分离纯业务逻辑与基础设施代码,实现高可维护性与可测试性,并支持按项目规模灵活简化。点击标题

项目结构终极参考

刚打开一个新项目,脑袋里嗡的一声——“这代码我该往哪儿放?” 文件夹一层套一层,文件名起得神神秘秘,改一行代码要翻三四个目录,最后干脆新建个 tmp.ts 先写着,结果三天后连自己都找不到那行救命逻辑了?

大型软件项目就像盖摩天大楼,地基打歪了,再牛的程序员也救不回来。

这份布局指南就是那个帮你把钢筋水泥摆对位置的施工图,专治各种“代码乱葬岗”晚期患者。

为什么要有这个布局?

写代码不是写日记,不能想到哪写到哪。当项目从一个人的小玩具变成十个人一起维护的企业级系统,混乱的结构会像病毒一样传染——今天你把数据库操作塞进业务逻辑,明天他把 HTTP 处理混进核心算法,后天新人接手直接原地爆炸。

这套布局的核心使命就一条:让每一行代码都知道自己该待在哪个“房间”,绝不串门乱跑。它不是强迫症的产物,而是用无数个深夜加班和线上事故换来的血泪经验包,专治“改一处崩三处”的绝症。

核心思想
这套结构最狠的地方在于它把代码世界划成了两个平行宇宙:干净的纯逻辑宇宙(core) 和 脏兮兮的现实世界接口宇宙(infrastructure)。

想象你是个天才科学家,只负责发明永动机原理(这就是 core),而你的助手团队负责买零件、接电线、防雷击、应付环保局(这就是 infrastructure)。科学家永远不用碰螺丝刀,助手也绝不干涉公式推导。

src/
  core/
  inbound/
  infrastructure/

这种隔离让核心逻辑像数学定理一样稳定可靠,不管外面是用 MySQL 还是 MongoDB,是 HTTP 还是 WebSocket,永动机原理纹丝不动。测试的时候更爽——不用启动数据库,不用连网络,直接给纯函数喂数据,秒出结果,稳如老狗。

完整包结构

.                                           // 项目根目录
├── css                                    
// 主样式文件夹,由Tailwind CLI自动生成
│   └── style.css                          
// 主样式文件
├── db                                      
// 数据库相关文件夹,用纯SQL写数据库结构(跟源代码分开)
│   ├── core                                
// 核心数据库结构,所有环境都用这个;支持一个业务领域用多个数据库
│   │   ├── cache                          
// 缓存数据(丢了能重建,可有可无)
│   │   │   └── migrations                  
// 比如:AI回复的缓存、会话查询表
│   │   ├── var                            
// 持久化数据(真正的数据,不能丢)
│   │   │   ├── migrations                  
// 比如:用户信息、交易记录
│   │   │   └── seeds                      
// 种子数据(初始数据)
│   │   │       └── user-roles.sql          
// 用户角色初始数据
│   │   └── tmp                            
// 临时数据(几秒到几分钟就过期)
│   │       └── migrations                  
// 比如:限流计数器、临时锁、离线锁
│   ├── environments                        
// 特定环境的数据库扩展
│   │   ├── project-E                      
// 项目E的数据库扩展
│   │   │   ├── migrations                  
// 项目E特有的扩展表
│   │   │   │   └── 001_project_e_extensions.sql
│   │   │   └── seeds                      
// 项目E的初始数据
│   │   │       └── default_admin_user.sql  
// 默认管理员账号
│   │   └── customer-F                      
// 客户F的数据库扩展
│   │       ├── migrations
│   │       └── seeds
│   └── scripts                            
// 数据库维护脚本(备份、恢复、数据脱敏)
├── scripts                                
// 运维和自动化脚本(bash/python/ts)
│   └── ...                                
// 其他脚本
├── src                                    
// 源代码
│   ├── index.ts                            
// 运行时调度器(选哪个项目启动;不推荐用,因为没有进程隔离)
│   ├── environments                        
// 组合根目录(每个客户/租户/开发配置一个文件夹);依赖基础设施层和核心层
│   │   ├── shared                          
// 跨环境共享的库(配置逻辑太具体,不适合放核心层)
│   │   │   └── templates                  
// 所有环境共用的模板
│   │   │       ├── sms-notification.eta    
// 短信通知模板
│   │   │       ├── email-body-text.eta    
// 邮件正文纯文本版
│   │   │       └── email-body-html.eta    
// 邮件正文HTML版
│   │   ├── project-E                      
// 项目E的环境配置
│   │   │   ├── delivery                    
// 项目E特有的UI/协议覆盖
│   │   │   │   ├── templates              
// 项目E独有的Eta模板
│   │   │   │   ├── http                    
// 项目E特有的路由定义
│   │   │   │   │   ├── controllers        
// 控制器
│   │   │   │   │   └── route.ts            
// 路由文件
│   │   │   │   └── websocket              
// WebSocket配置
│   │   │   ├── env.ts                      
// 项目E的配置实现
│   │   │   └── index.ts                    
// 接线文件:启动项目E的业务领域+基础设施+环境配置
│   │   ├── customer-F                      
// 客户F的环境配置
│   │   │   ├── env.ts
│   │   │   └── index.ts
│   │   └── dev-shell                      
// 开发环境,当成一个项目来处理;包含开发工具UI
│   │       ├── infrastructure
│   │       │   ├── reload.ts              
// 热重载逻辑
│   │       │   ├── time-mock.ts            
// 测试用的模拟时间
│   │       │   └── watch.ts                
// 文件监听器配置
│   │       ├── delivery                    
// 交付层
│   │       │   └── overview.eta            
// 开发状态面板模板
│   │       ├── env.ts                      
// 仅开发用的配置
│   │       └── index.ts                    
// 接线文件:启动目标项目+开发工具
│   ├── infrastructure                      
// 实现细节;依赖核心层和外部库(SQLite、AWS S3、文件系统等)
│   │   ├── shared                          
// 通用技术能力
│   │   │   ├── time                        
// 横切关注点(到处都用)
│   │   │   │   └── time-real.ts            
// 系统时钟实现
│   │   │   ├── log                        
// 横切关注点
│   │   │   │   └── log-winston.ts          
// 日志实现
│   │   │   ├── inbound                    
// 输入传输(入口)
│   │   │   │   ├── http                    
// Express/Fastify设置,全局中间件
│   │   │   │   ├── cli                    
// 命令行参数解析逻辑
│   │   │   │   ├── websocket              
// Socket.io/ws服务器设置
│   │   │   │   └── tcp                    
// 原始net.Server逻辑
│   │   │   ├── outbound                    
// 输出传输(出口)
│   │   │   │   ├── persistence            
// 数据存储适配器
│   │   │   │   │   ├── sqlite              
// SQLite适配器
│   │   │   │   │   ├── mongodb            
// MongoDB适配器
│   │   │   │   │   └── s3                  
// S3适配器
│   │   │   │   └── gateways                
// 外部服务客户端
│   │   │   │       ├── smtp                
// NodeMailer / SES包装器
│   │   │   │       ├── sms                
// Twilio / MessageBird包装器
│   │   │   │       └── push                
// Firebase / 苹果推送逻辑
│   │   │   ├── serialization              
// 转换层(翻译器)
│   │   │   │   ├── templates              
// 模板引擎设置
│   │   │   │   │   └── parent.eta
│   │   │   │   ├── json                    
// 自定义解析器(处理日期、大整数)
│   │   │   │   ├── protobuf                
// Proto定义和编码器
│   │   │   │   ├── xml                    
// XML格式化器
│   │   │   │   ├── html                    
// HTML清理/格式化
│   │   │   │   └── formatters              
// 技术格式化(比如字节转MB)
│   │   │   └── security                    
// 认证、JWT、加密驱动
│   │   ├── bounded-context-A              
// 业务领域A的基础设施(应用服务)
│   │   │   ├── app.ts                      
// 该领域的入口
│   │   │   ├── persistence                
// 仓库实现(原始SQL、ORM等)
│   │   │   │   └── customer-repository.ts  
// 实现核心层的接口
│   │   │   ├── queries                    
// 查询实现(原始SQL、ORM等)
│   │   │   │   └── customer-queries.ts
│   │   │   ├── commands                    
// 写操作编排
│   │   │   │   └── customer-evaluation.ts
│   │   │   └── scripts                    
// 领域A特有的维护脚本
│   │   ├── bounded-context-B              
// 业务领域B的基础设施
│   │   └── runner.ts                      
// 应用编排器
│   └── core                                
// 纯业务逻辑,没有副作用;不依赖任何东西(除了少量工具函数)
│       ├── shared-kernel                  
// 共享领域(多个业务领域共用的业务逻辑;少用)
│       │   ├── types.ts                    
// 共享值对象(比如货币、邮箱)
│       │   └── constants.ts                
// 常量
│       ├── bounded-context-A              
// 纯领域逻辑(领域A)
│       │   ├── events                      
// 比如:用户注册、订单下单
│       │   ├── queries                    
// 读模型
│       │   └── domain                      
// 写模型(实体、值对象)
│       │       └── customer.ts
│       ├── bounded-context-B              
// 纯领域逻辑(领域B)
│       │   └── ...
│       ├── utils.ts                        
// 通用TS辅助函数
│       └── utils.test.ts                  
// 工具函数测试
├── static                                  
// 静态文件
│   ├── dev                                
// 开发用的浏览器文件(比如dev-ws.js)
│   └── main                                
// 生产环境资源(图片、编译后的CSS/JS)
│       └── style.css
├── test-integration                        
// 跨领域测试(端到端流程)
│   ├── project-e.test.ts                  
// 测试完整装配好的项目E
│   └── xyz.test.ts
├── tmp                                    
// 本地开发文件(版本控制忽略)
│   ├── dev.state.db                        
// 本地沙盒数据库
│   └── ...
├── eslint.config.mjs                      
// ESLint配置
├── package.json                            
// 包配置
├── prettier.config.cjs                    
// Prettier配置
├── tailwind.config.ts                      
// Tailwind配置
├── tsconfig.json                          
// TypeScript配置
└── yarn.lock                              
// Yarn锁定文件

主要文件夹说明(大白话)

先看 db 文件夹,这里存的是数据库的“户型图”。core 子目录放所有客户通用的基础表结构,比如用户表、订单表这些谁都要用的标配;environments 则是 VIP 客户的定制装修方案,比如某银行需要额外加个风控字段,某电商要多存个优惠券历史,全塞这儿互不干扰;scripts 里躺着各种数据库急救包——一键重建测试库、紧急清理垃圾数据、半夜自动备份,全是保命用的硬核脚本。记住,db 里只有“图纸”,没有一行代码,真正的建表操作由 infrastructure 里的工具执行。

scripts 文件夹是项目的“自动化管家”。部署新版本?运行 scripts/deploy.sh。生成 API 文档?敲 scripts/gen-docs.sh。甚至每天凌晨三点自动给老板发周报?也能塞这儿。所有重复性体力活全交给脚本,人类只负责动脑子。这玩意儿看着不起眼,但团队效率能翻倍——新人第一天入职,不用问“怎么打包”,直接 ./scripts/build 就完事,省下八百个微信群消息。

src 才是真正的战场,分三大战区。inbound 是项目的“外交部门”,专门处理外界骚扰:HTTP 请求来了转成内部格式,WebSocket 消息到了解包成事件,命令行指令输入了翻译成操作码。这里只干一件事:把五花八门的外部信号统一成项目内部能听懂的普通话,绝不掺和业务判断。比如用户注册请求进来,inbound 只负责检查 JSON 格式对不对,邮箱是不是字符串,密码长度够不够——至于密码强度规则?那是 core 的事,inbound 连问都不问。

infrastructure 是“后勤保障部”,负责跟现实世界肉搏。数据库连接池在这儿管理,Redis 缓存策略在这儿配置,文件上传到 AWS S3 的代码也藏这儿。所有带副作用的操作——读写磁盘、调用第三方 API、发短信——全归 infrastructure 管。它像个翻译官,把 core 的纯逻辑指令(比如“保存用户”)转换成具体的数据库 INSERT 语句,再把数据库返回的原始数据包装成 core 能理解的对象。关键原则:infrastructure 可以依赖 core,但 core 绝不反向依赖 infrastructure,保证核心逻辑永远干净。

core 是项目的“大脑中枢”,只存放最纯粹的业务规则。用户密码必须包含大小写字母和数字?订单金额不能为负数?优惠券只能用一次?这些铁律全写在 core 的 domain 实体里。这里的代码有个变态要求:不能 import 任何外部库,不能调用任何 I/O 操作,甚至不能获取当前时间(时间必须作为参数传入)。听起来反人类?但正是这种极端洁癖,让核心逻辑能像乐高积木一样随意组合测试——想验证密码规则?直接 new User("test", "weak"),看它抛不抛异常,0.001 秒出结果,不用等数据库连接。

static 文件夹简单粗暴,就是前端资源的垃圾桶。CSS、JS、图片、字体文件全扔这儿,构建工具会自动压缩合并。test-integration 则是项目的“压力测试场”,专门模拟真实用户操作流程:从 HTTP 请求入口开始,一路穿透 inbound → infrastructure → core → infrastructure → 数据库,最后验证返回结果是否符合预期。这种端到端测试虽然慢,但能抓住各模块衔接时的隐藏 bug,比如 core 返回了正确数据,但 infrastructure 忘了序列化某个字段。

一个真实流程长啥样?

用户点下“注册”按钮的瞬间,一场精密的接力赛就开始了。

HTTP 请求先撞进 src/infrastructure/inbound/http/controllers/auth.ts,这里像安检门一样扫描请求格式,把 JSON 转成内部 DTO 对象。
接着接力棒传给 src/infrastructure/bounded-context-A/app.ts,这个协调器像乐队指挥,调用 core 里的用户实体进行规则校验。
src/core/bounded-context-A/domain/user.ts 接过棒,冷酷执行“密码必须8位以上含特殊字符”的铁律——如果不合格,直接抛异常中断流程。
校验通过后,协调器把干净的用户对象塞给 src/infrastructure/bounded-context-A/persistence/user-repository.ts,这里才真正接触数据库,把对象转成 SQL 插入。
最后结果沿原路返回,HTTP 控制器吐出 201 Created。

全程 core 不知道有 HTTP,数据库不知道有密码规则,各司其职,稳如泰山。

总结一下

这套布局的本质是用空间换秩序。多建几个文件夹,多写几层转发,换来的是代码的绝对清晰和可维护性。当项目膨胀到百万行代码时,新人依然能靠目录结构猜出功能位置;当需要替换数据库时,只需重写 infrastructure 层,core 逻辑纹丝不动;当老板突然要加个 CLI 命令行入口,直接在 inbound 下新建个 cli 目录,其他代码完全不用动。它不是银弹,但绝对是大型项目的防弹衣——穿上可能有点闷,但能让你在需求海啸中活下来。

如何折叠层次结构(按比例缩小)

别被吓到!这套结构像变形金刚,能大能小。如果你在搞个人小项目,用下面四招立刻瘦身:

第一招:单租户模式直接砍掉 environments。所有环境配置一股脑塞进 src/app,省去三层嵌套。
第二招:CRUD 项目大胆合并 core 和 infrastructure。比如用户模块直接搞个 src/modules/users/service.ts,里面既有业务规则又有数据库操作——牺牲一点纯洁性,换来开发速度起飞。
第三招:纯 HTTP 项目干掉 inbound 目录。Express 或 Fastify 的路由配置直接写在 src/app.ts,少一层抽象多十分痛快。
第四招:用 TypeORM 这种同步神器?db/migrations 可以删了,让 ORM 自动建表,但记得保留 db/seeds 存测试数据。

记住,架构是仆人不是主人,该简化时就简化,别被教条绑架。

顺口溜快板:
代码分区如军营,纯脏分离保太平;
入口基建各司职,核心逻辑永纯净,永纯净!