4. 项目初始化与代码仓库搭建:Git仓库创建、分支策略(Git Flow/Trunk Based)、项目目录结构设计

本章是实战课程的基石。一个多租户SaaS鉴权拦截链路项目,从第一天起就需要在代码仓库、分支策略和目录结构上做出正确决策。错误的仓库初始化会导致后续CI/CD流水线频繁冲突、部署混乱,甚至安全漏洞。我们将从零开始,搭建一个符合企业级标准的Git仓库,并设计一套既能支撑快速迭代、又能保障多租户隔离的目录结构。

4.1 Git仓库创建与初始化

我们采用单仓库多模块(Monorepo)策略,将鉴权核心、租户管理、网关拦截、公共库等所有组件放在同一个Git仓库中。这有利于统一版本管理、原子化提交和跨组件重构。

选型建议: 对于多租户SaaS项目,Monorepo比多仓库(Multi-Repo)更适合,因为租户上下文、鉴权策略、共享模型频繁跨模块变更,单仓库可避免“依赖地狱”和版本漂移。

4.1.1 初始化步骤

  1. 创建远程仓库(以GitLab为例):在GitLab上新建空白项目,命名为 saas-auth-gateway,可见性设为 Private。
  2. 克隆到本地:git clone git@gitlab.example.com:devops/saas-auth-gateway.git
  3. 初始化README和.gitignore:创建标准 .gitignore(Java/Maven/Node.js混合模板),并写入项目简介。
  4. 创建初始提交:git add . && git commit -m "chore: initial project scaffold"
  5. 推送主干:git push origin main
关键配置: 在仓库设置中开启 “仅允许通过Merge Request合并” 和 “删除源分支”,确保主干分支受保护,防止直接推送。

4.2 分支策略:Git Flow vs Trunk Based

分支策略直接影响CI/CD流水线的触发频率、部署节奏和团队协作效率。下表对比了两种主流策略在本项目中的适用性。

维度 Git Flow Trunk Based (主干开发)
分支数量 多(develop, release, hotfix, feature) 少(main + 短期特性分支)
合并频率 低(按版本合并) 高(每日多次合并到主干)
CI/CD触发 按分支类型触发不同流水线 每次提交到主干即触发全量流水线
多租户热修复 从主干拉hotfix分支,修复后合并回主干和release 直接在主干修复,通过特性开关控制发布
推荐场景 固定版本发布、有长期支持分支 持续部署、SaaS高频迭代

本项目选择Trunk Based + 短期特性分支策略。原因:多租户SaaS需要每天多次部署,主干开发配合特性开关(Feature Toggle)可以快速上线租户特定功能,同时保持主干始终可发布。

4.2.1 分支命名规范

  • 主干:main(受保护,始终可部署)
  • 特性分支:feat/租户ID-简短描述,例如 feat/tenant-abc-oidc-support
  • 修复分支:fix/issue-id-简短描述,例如 fix/1234-token-expiry
  • 配置分支:config/租户ID-环境,例如 config/tenant-abc-staging
避坑提示: 不要将租户特定配置直接提交到 main 分支的默认配置文件中。应使用配置分支 + 环境变量注入,避免租户A的配置泄露到租户B的部署中。

4.3 项目目录结构设计

目录结构需要同时满足模块化、多租户隔离和CI/CD流水线可读性。我们采用分层+领域驱动设计(DDD)风格。

saas-auth-gateway/
├── .gitlab-ci.yml              # GitLab CI/CD 主流水线定义
├── .gitignore
├── README.md
├── pom.xml                     # 父POM(Maven多模块聚合)
│
├── saas-auth-core/             # 鉴权核心库(JWT、OAuth2、Session管理)
│   ├── pom.xml
│   └── src/
│       ├── main/java/com/saas/auth/core/
│       │   ├── token/          # Token生成与验证
│       │   ├── tenant/         # 租户上下文解析
│       │   └── policy/         # 鉴权策略接口
│       └── test/
│
├── saas-tenant-manager/        # 租户管理服务(CRUD、配置、密钥)
│   ├── pom.xml
│   └── src/
│       ├── main/java/com/saas/tenant/
│       │   ├── controller/     # REST API
│       │   ├── service/        # 租户注册、密钥轮换
│       │   └── repository/     # 数据库访问
│       └── test/
│
├── saas-gateway/               # API网关(拦截、路由、限流)
│   ├── pom.xml
│   └── src/
│       ├── main/java/com/saas/gateway/
│       │   ├── filter/         # 鉴权过滤器链
│       │   ├── route/          # 动态路由(按租户)
│       │   └── rate-limit/     # 租户级限流
│       └── test/
│
├── saas-common/                # 公共工具库(DTO、异常、常量)
│   ├── pom.xml
│   └── src/main/java/com/saas/common/
│       ├── dto/                # 统一响应体
│       ├── exception/          # 全局异常定义
│       └── util/               # 加密、日期工具
│
├── deploy/                     # 部署与配置
│   ├── docker/                 # Dockerfile(每个模块一个子目录)
│   │   ├── gateway.Dockerfile
│   │   ├── tenant-manager.Dockerfile
│   │   └── ...
│   ├── k8s/                    # Kubernetes 清单
│   │   ├── base/               # 基础资源(Namespace、ServiceAccount)
│   │   └── overlays/           # 环境差异(dev/staging/prod)
│   └── scripts/                # 数据库迁移、密钥初始化脚本
│
└── docs/                       # 架构文档、API手册、流水线说明
    ├── architecture.md
    └── ci-cd-pipeline.md

4.3.1 目录设计原则

原则 说明 示例
按领域拆分模块 每个Maven模块对应一个独立部署单元 saas-gateway 可独立构建镜像
租户配置外置 租户密钥、限流阈值不硬编码在代码中 通过 deploy/k8s/overlays/ 的ConfigMap注入
流水线文件根级 .gitlab-ci.yml 放在根目录,便于CI发现 流水线可引用 deploy/scripts/ 下的脚本
测试与源码同级 每个模块内 src/test/ 与 src/main/ 并列 便于Maven标准构建生命周期

4.4 分支策略与目录结构的协同关系

下图展示了Trunk Based分支策略下,特性分支如何与目录结构交互,最终触发CI/CD流水线。

Trunk Based分支与目录协同流程 Trunk Based 分支与目录协同流程 main (主干) feat/tenant-abc-oidc fix/1234-token-expiry config/tenant-abc-stg 目录结构影响区域(变更范围) saas-auth-core/ saas-gateway/ deploy/k8s/ docs/ Merge Request → CI/CD 流水线自动触发

4.5 初始化后的验证清单

完成仓库搭建后,执行以下验证确保基础正确:

  • 分支保护:确认 main 分支已开启“不允许直接推送”、“必须通过MR合并”、“至少1名审批人”。
  • CI触发测试:推送一个空特性分支,确认 .gitlab-ci.yml 被解析且流水线进入pending状态。
  • 目录可构建性:在根目录执行 mvn clean compile -pl saas-auth-core -am,确认模块依赖正确。
  • Dockerfile可访问:确认 deploy/docker/gateway.Dockerfile 能正确引用 saas-gateway/target/*.jar。
最佳实践: 在仓库根目录添加 .editorconfig 和 .pre-commit-config.yaml,统一缩进、编码格式,并在提交前自动运行静态检查(如Checkstyle、ESLint),从源头减少流水线失败。

至此,项目初始化与代码仓库搭建完成。下一阶段我们将基于此仓库结构,编写多租户鉴权核心代码,并配置第一版CI流水线。