Files
wiki/研发型企业AI转型方案/报告/ai-dev-workflow-v2.html
T

1316 lines
88 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>研发型企业 AI 开发流程 V2.0 — 新项目脚手架驱动 + 老项目维护双轨制</title>
<style>
:root {
--color-primary: #1677FF; --color-primary-bg: #E6F4FF;
--color-success: #52C41A; --color-success-bg: #F6FFED; --color-success-border: #B7EB8F;
--color-warning: #FAAD14; --color-warning-bg: #FFFBE6; --color-warning-border: #FFE58F;
--color-error: #FF4D4F; --color-error-bg: #FFF2F0; --color-error-border: #FFCCC7;
--bg: #F5F5F5; --bg-container: #FFFFFF; --bg-elevated: #FAFAFA;
--border: #D9D9D9; --border-light: #F0F0F0;
--text-primary: #141414; --text-secondary: #595959; --text-tertiary: #8C8C8C;
--radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.03), 0 1px 6px -1px rgba(0,0,0,0.02);
--shadow-md: 0 2px 4px rgba(0,0,0,0.04), 0 4px 12px -2px rgba(0,0,0,0.04);
--sidebar-w: 260px; --header-h: 64px;
}
*{margin:0;padding:0;box-sizing:border-box;}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;background:var(--bg);color:var(--text-primary);line-height:1.57;font-size:15px;}
::-webkit-scrollbar{width:6px;height:6px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px;}
.header{position:fixed;top:0;left:0;right:0;height:var(--header-h);background:rgba(255,255,255,0.88);backdrop-filter:blur(12px);border-bottom:1px solid var(--border-light);display:flex;align-items:center;padding:0 2rem;z-index:100;}
.header h1{font-size:18px;font-weight:700;background:linear-gradient(135deg,var(--color-primary),#722ED1);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;}
.header .back-link{margin-right:16px;font-size:13px;color:var(--color-primary);text-decoration:none;flex-shrink:0;}
.header .back-link:hover{text-decoration:underline;}
.header .version{margin-left:auto;font-size:12px;color:var(--text-tertiary);font-family:'SF Mono',Monaco,monospace;}
.sidebar{position:fixed;top:var(--header-h);left:0;bottom:0;width:var(--sidebar-w);background:var(--bg-container);border-right:1px solid var(--border);overflow-y:auto;padding:1.25rem 0;z-index:90;}
.sidebar .toc-label{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--text-tertiary);padding:0 1.25rem;margin-bottom:.75rem;font-weight:600;}
.sidebar nav ol{list-style:none;counter-reset:toc;}
.sidebar nav li{counter-increment:toc;}
.sidebar nav a{display:block;padding:.5rem 1.25rem;color:var(--text-secondary);text-decoration:none;font-size:13px;line-height:1.4;border-left:2px solid transparent;transition:all .15s;}
.sidebar nav a::before{content:counter(toc)". ";color:var(--color-primary);font-weight:600;font-size:12px;margin-right:.4rem;}
.sidebar nav a:hover,.sidebar nav a.active{color:var(--color-primary);background:var(--color-primary-bg);}
.sidebar nav a.active{border-left-color:var(--color-primary);font-weight:600;}
.sidebar nav a.sub{padding-left:2.5rem;font-size:12px;}
.sidebar nav a.sub::before{content:"· ";font-weight:700;}
.main{margin-left:var(--sidebar-w);margin-top:var(--header-h);padding:36px 48px 64px;min-height:calc(100vh - var(--header-h));max-width:1100px;}
section{margin:48px 0;scroll-margin-top:calc(var(--header-h) + 1rem);}
section h2{font-size:24px;line-height:32px;padding-bottom:8px;border-bottom:1px solid var(--border);margin-bottom:20px;color:var(--color-primary);}
section h3{font-size:20px;line-height:28px;margin:24px 0 12px;color:#722ED1;}
section h4{font-size:16px;line-height:24px;margin:16px 0 8px;color:var(--color-success);}
p{color:var(--text-secondary);font-size:14px;margin:10px 0;text-align:justify;}
p.no-indent{text-indent:0;}
p.lead{font-size:16px;color:var(--text-primary);text-indent:0;line-height:1.9;}
strong{color:var(--text-primary);}
.box{border-radius:var(--radius-md);padding:20px 24px;margin:18px 0;}
.box-info{background:var(--color-primary-bg);border:1px solid #91CAFF;}
.box-idea{background:#F9F0FF;border:1px solid #D3ADF7;}
.box-good{background:var(--color-success-bg);border:1px solid var(--color-success-border);}
.box-warn{background:var(--color-warning-bg);border:1px solid var(--color-warning-border);}
.box-danger{background:var(--color-error-bg);border:1px solid var(--color-error-border);}
.box h4{margin:0 0 8px;font-size:14px;font-weight:700;}
.box-info h4{color:var(--color-primary);}.box-idea h4{color:#722ED1;}.box-good h4{color:var(--color-success);}.box-warn h4{color:var(--color-warning);}.box-danger h4{color:var(--color-error);}
.box p{font-size:14px;margin:4px 0;text-indent:0;}
.box ul,.box ol{margin:4px 0 4px 16px;}
.box li{font-size:13px;margin:4px 0;}
.table-wrap{overflow-x:auto;margin:20px 0;}
.table-caption{font-size:13px;font-weight:700;color:var(--text-primary);margin-bottom:8px;}
table{width:100%;border-collapse:collapse;font-size:13px;}
th,td{padding:10px 14px;border:1px solid var(--border);text-align:left;vertical-align:top;}
th{background:var(--bg-elevated);font-weight:700;color:var(--text-primary);white-space:nowrap;}
td{background:var(--bg-container);color:var(--text-secondary);}
tbody tr:hover td{background:var(--color-primary-bg);}
.tag{display:inline-block;padding:2px 10px;border-radius:12px;font-size:11px;font-weight:600;margin-right:4px;}
.tag-green{background:var(--color-success-bg);color:var(--color-success);border:1px solid var(--color-success-border);}
.tag-blue{background:var(--color-primary-bg);color:var(--color-primary);border:1px solid #91CAFF;}
.tag-warn{background:var(--color-warning-bg);color:var(--color-warning);border:1px solid var(--color-warning-border);}
.tag-red{background:var(--color-error-bg);color:var(--color-error);border:1px solid var(--color-error-border);}
.tag-purple{background:#F9F0FF;color:#722ED1;border:1px solid #D3ADF7;}
.code-snippet{background:#1E1E1E;color:#D4D4D4;border-radius:var(--radius-md);padding:16px 20px;margin:14px 0;font-family:'SF Mono',Monaco,monospace;font-size:13px;line-height:1.7;overflow-x:auto;}
.code-snippet .kw{color:#569CD6;}.code-snippet .str{color:#CE9178;}.code-snippet .cm{color:#6A9955;}.code-snippet .fn{color:#DCDCAA;}
.code-snippet .num{color:#B5CEA8;}.code-snippet .op{color:#D4D4D4;}
.flow-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:16px;margin:18px 0;}
.flow-step{background:var(--bg-container);border:1px solid var(--border);border-radius:var(--radius-md);padding:20px 22px;position:relative;transition:all .2s;}
.flow-step:hover{border-color:var(--color-primary);box-shadow:var(--shadow-md);}
.flow-step .step-num{display:inline-block;width:28px;height:28px;line-height:28px;text-align:center;border-radius:50%;background:linear-gradient(135deg,var(--color-primary),#722ED1);color:#fff;font-size:13px;font-weight:700;margin-bottom:10px;}
.flow-step.legacy .step-num{background:linear-gradient(135deg,#FAAD14,#FA541C);}
.flow-step h4{margin:0 0 8px;font-size:15px;color:var(--text-primary);}
.flow-step p{font-size:12px;color:var(--text-tertiary);text-indent:0;line-height:1.6;}
.flow-step .tool-tag{display:inline-block;padding:1px 8px;border-radius:10px;font-size:10px;font-weight:600;margin:2px 3px 0 0;}
.tool-tag.primary{background:var(--color-primary-bg);color:var(--color-primary);}
.tool-tag.secondary{background:var(--color-success-bg);color:var(--color-success);}
.tool-tag.warn{background:var(--color-warning-bg);color:var(--color-warning);}
.arch-diagram{background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--radius-md);padding:28px 24px;margin:18px 0;text-align:center;overflow-x:auto;}
.arch-layer{display:flex;align-items:center;justify-content:center;gap:12px;margin:8px 0;flex-wrap:wrap;}
.arch-box{display:inline-flex;flex-direction:column;align-items:center;padding:12px 18px;border-radius:var(--radius-sm);font-size:12px;font-weight:600;min-width:120px;text-align:center;}
.arch-box.core{background:linear-gradient(135deg,#1677FF,#722ED1);color:#fff;}
.arch-box.model{background:var(--color-primary-bg);border:2px solid var(--color-primary);}
.arch-box.tool{background:var(--color-success-bg);border:2px solid var(--color-success);}
.arch-box.data{background:#FFFBE6;border:2px solid #FAAD14;}
.arch-box.legacy{background:#FFF2F0;border:2px solid #FF4D4F;}
.arch-box .sub{font-size:10px;font-weight:400;opacity:0.8;margin-top:2px;}
.arch-arrow{font-size:18px;color:var(--text-tertiary);}
ul,ol{margin:8px 0 8px 20px;}
li{margin:6px 0;color:var(--text-secondary);font-size:14px;}
.kpi-row{display:flex;flex-wrap:wrap;gap:12px;margin:16px 0;}
.kpi{flex:1;min-width:110px;background:var(--color-primary-bg);border-radius:var(--radius-md);padding:14px 12px;text-align:center;}
.kpi .num{font-size:20px;font-weight:800;color:var(--color-primary);line-height:1.2;}
.kpi .label{font-size:10px;color:var(--text-tertiary);margin-top:4px;}
.kpi.warn{background:var(--color-warning-bg);}.kpi.warn .num{color:#D48806;}
.kpi.danger{background:var(--color-error-bg);}.kpi.danger .num{color:var(--color-error);}
.compare-table td:first-child{font-weight:600;color:var(--text-primary);white-space:nowrap;background:var(--bg-elevated);}
.footer{text-align:center;padding:28px 0;color:var(--text-tertiary);font-size:13px;border-top:1px solid var(--border-light);margin-top:40px;}
.menu-btn{display:none;width:40px;height:40px;border:none;background:none;cursor:pointer;border-radius:var(--radius-sm);font-size:20px;margin-right:12px;flex-shrink:0;transition:background .15s;}
.menu-btn:hover{background:var(--bg-elevated);}
.drawer-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:200;opacity:0;transition:opacity .25s;}
.drawer-overlay.show{display:block;opacity:1;}
.back-to-top{display:none;position:fixed;bottom:24px;right:24px;width:48px;height:48px;border-radius:50%;background:var(--color-primary);color:#fff;border:none;cursor:pointer;font-size:20px;box-shadow:var(--shadow-md);z-index:80;transition:all .2s;}
.back-to-top:hover{transform:scale(1.1);}
.back-to-top.show{display:flex;align-items:center;justify-content:center;}
@media(max-width:768px){.menu-btn{display:flex;align-items:center;justify-content:center;}.sidebar{display:block;position:fixed;top:0;left:0;bottom:0;width:280px;max-width:85vw;transform:translateX(-100%);transition:transform .25s ease;z-index:201;padding-top:60px;}.drawer-overlay.show .sidebar{transform:translateX(0);}.sidebar nav a{font-size:14px;padding:0.6rem 1.5rem;}.main{margin-left:0;padding:20px 16px 40px;}.flow-grid{grid-template-columns:1fr;}.arch-layer{flex-direction:column;}.arch-arrow{transform:rotate(90deg);}.header h1{font-size:15px;}}
</style>
</head>
<body>
<div class="drawer-overlay" id="drawerOverlay"></div>
<header class="header">
<button class="menu-btn" id="menuBtn" aria-label="打开目录"></button>
<a href="../../index.html" class="back-link">← 返回知识库</a>
<h1>AI 开发流程 V2.0:新项目脚手架驱动 + 老项目维护双轨</h1>
<span class="version">V2.0 · 2026-05-31</span>
</header>
<aside class="sidebar">
<div class="toc-label">报告目录</div>
<nav>
<ol>
<li><a href="#s0">阅读指南:如何使用本报告</a></li>
<li><a href="#s1">前置判断:5 秒分流决策</a></li>
<li><a href="#s2">开发脚手架体系(新项目基础)</a></li>
<li><a href="#s3">企业内部基础设施层(共用底座)</a></li>
<li><a href="#s4" style="color:#1677FF;font-weight:600;">🆕 Part A:新项目开发</a></li>
<li><a href="#s4a" class="sub">A.1 脚手架初始化</a></li>
<li><a href="#s4b" class="sub">A.2 需求→模块映射</a></li>
<li><a href="#s4c" class="sub">A.3 Plan Mode 编码计划</a></li>
<li><a href="#s4d" class="sub">A.4 全量代码生成</a></li>
<li><a href="#s4e" class="sub">A.5 测试生成与审查</a></li>
<li><a href="#s4f" class="sub">A.6 部署与记忆沉淀</a></li>
<li><a href="#s5" style="color:#FAAD14;font-weight:600;">🔧 Part B:老项目维护</a></li>
<li><a href="#s5a" class="sub">B.1 代码考古:理解现状</a></li>
<li><a href="#s5b" class="sub">B.2 影响分析:修改范围评估</a></li>
<li><a href="#s5c" class="sub">B.3 增量修改:测试先行</a></li>
<li><a href="#s5d" class="sub">B.4 回归验证与合并</a></li>
<li><a href="#s5e" class="sub">B.5 知识沉淀:文档补全</a></li>
<li><a href="#s6">工具链配置速查</a></li>
<li><a href="#s7">落地建议:从哪类项目开始</a></li>
</ol>
</nav>
</aside>
<main class="main">
<!-- ===== 〇、阅读指南 ===== -->
<section id="s0">
<h2>〇、阅读指南:如何使用本报告</h2>
<p class="lead">本报告为研发团队提供<strong>两套完整的、可直接操作的 AI 开发工作流</strong>——一套用于从零开始的新项目(脚手架驱动),一套用于已有代码库的老项目维护(代码考古驱动)。每套工作流均包含完整的操作步骤、实际 Prompt 示例、工具配置和检查清单。</p>
<div class="box box-info">
<h4>📖 阅读路径建议</h4>
<p><strong>所有人必读</strong>:第 1 节(前置判断)→ 第 2 节(脚手架体系)</p>
<p><strong>正在启动新项目的团队</strong>:第 1-2 节 → <strong>Part A</strong>(第 3 节)</p>
<p><strong>维护遗留系统的团队</strong>:第 1-2 节 → <strong>Part B</strong>(第 4 节)</p>
<p><strong>技术管理者</strong>:全文通读 → 第 5 节(配置速查)→ 第 6 节(落地建议)</p>
</div>
</section>
<!-- ===== 一、前置判断 ===== -->
<section id="s1">
<h2>一、前置判断:5 秒分流决策</h2>
<p class="lead">接受任何开发任务后,第一个动作不是打开 IDE,而是<strong>回答一个问题</strong>。这个问题的答案决定了你接下来几小时/几天使用完全不同的 AI 工作流。</p>
<div class="arch-diagram">
<div class="table-caption" style="margin-bottom:14px;">图:任务分流决策树</div>
<div class="arch-layer">
<div class="arch-box core" style="min-width:280px;">📋 接到开发任务</div>
</div>
<div class="arch-layer">
<span class="arch-arrow"></span>
</div>
<div class="arch-layer">
<div class="arch-box model" style="min-width:320px;">❓ 是否需要新建 Git 仓库?</div>
</div>
<div class="arch-layer">
<span class="arch-arrow">↙ YES(新项目)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NO(老项目)↘</span>
</div>
<div class="arch-layer">
<div class="arch-box core" style="min-width:220px;">🆕 <strong>Part A:脚手架驱动</strong><span class="sub">克隆脚手架 → 需求映射 → AI 全量生成</span></div>
<div class="arch-box legacy" style="min-width:220px;">🔧 <strong>Part B:代码考古驱动</strong><span class="sub">批量分析 → 影响评估 → 增量修改</span></div>
</div>
</div>
<h3>1.1 判断标准</h3>
<div class="table-wrap">
<table>
<tr><th style="width:14%;">判断维度</th><th style="width:38%;">🆕 新项目(Part A</th><th style="width:38%;">🔧 老项目维护(Part B</th></tr>
<tr><td>Git 仓库</td><td>新建空仓库 或 从脚手架模板克隆</td><td>已有仓库,含提交历史</td></tr>
<tr><td>代码基数</td><td>0 行(仅脚手架骨架)</td><td>1 万 ~ 100 万+ 行</td></tr>
<tr><td>AI 生成占比</td><td><span class="tag tag-blue">70-90%</span> 代码由 AI 生成</td><td><span class="tag tag-warn">15-40%</span> 仅修改区域由 AI 生成</td></tr>
<tr><td>典型场景</td><td>新客户项目、新产品线、独立微服务、POC</td><td>Bug 修复、功能增强、技术栈升级、性能优化</td></tr>
<tr><td>核心风险</td><td>AI 生成的代码风格不一致</td><td>AI 不理解历史约定、引入回归 Bug</td></tr>
<tr><td>关键工具</td><td>Claude Code(主力生成)+ open-code-review(规范守护)</td><td>DeepSeek(考古)+ Qwen(解读)+ Claude Code(精准修改)</td></tr>
</table>
</div>
<h3>1.2 边界情况处理</h3>
<div class="table-wrap">
<table>
<tr><th>场景</th><th>判定</th><th>理由</th></tr>
<tr><td>在现有项目中新增一个独立微服务模块,有自己的 build.gradle/pom.xml</td><td><span class="tag tag-blue">Part A</span></td><td>虽然仓库是老的,但模块完全独立,可以从脚手架起</td></tr>
<tr><td>从零开发但需要对接 3 个现有内部系统</td><td><span class="tag tag-blue">Part A</span></td><td>代码库是新的,集成通过 API 契约管理</td></tr>
<tr><td>在现有模块中新增一个功能(涉及新增表 + API + 页面)</td><td><span class="tag tag-warn">Part B</span></td><td>虽然功能是新的,但代码要插入现有模块,必须遵循现有约定</td></tr>
<tr><td>将 Spring Boot 2.x 升级到 3.x</td><td><span class="tag tag-warn">Part B</span></td><td>全局变更,需理解所有受影响代码</td></tr>
<tr><td>重构一个 5000 行的 God Class</td><td><span class="tag tag-warn">Part B</span></td><td>先考古(理解所有调用方),再动手</td></tr>
</table>
</div>
</section>
<!-- ===== 二、脚手架体系 ===== -->
<section id="s2">
<h2>二、开发脚手架体系(新项目的基础设施)</h2>
<p class="lead">新项目工作流的起点不是空白目录,而是<strong>一个预置了团队全部约定的脚手架仓库</strong>。这是 Part A 能够高效运转的前提——没有脚手架,AI 生成的代码将缺乏一致性约束。</p>
<h3>2.1 脚手架的四层结构</h3>
<div class="table-wrap">
<table>
<tr><th style="width:10%;">层次</th><th style="width:16%;">名称</th><th style="width:30%;">包含内容</th><th>AI 如何使用</th></tr>
<tr>
<td><span class="tag tag-blue">L1</span></td>
<td><strong>项目骨架</strong></td>
<td>目录结构、Maven/Gradle 配置、Dockerfile、CI 流水线(.gitea/workflows/)、Helm Chart、application.yml 多环境配置、logback 配置</td>
<td>Claude Code 启动时 <code>Read</code> 这些文件,确保生成代码的包路径、依赖版本、配置命名完全对齐</td>
</tr>
<tr>
<td><span class="tag tag-green">L2</span></td>
<td><strong>架构基类</strong></td>
<td>BaseController、BaseService、BaseEntity(含审计字段自动填充)、Result&lt;T&gt; 统一返回体、PageQuery 分页基类、GlobalExceptionHandler、AuthInterceptor</td>
<td>生成的每个 Controller 必须继承 BaseController、每个 Service 必须继承 BaseService、返回类型必须是 Result&lt;T&gt;。基类 = 代码的"法律"</td>
</tr>
<tr>
<td><span class="tag tag-purple">L3</span></td>
<td><strong>规范文件</strong></td>
<td>CLAUDE.md(编码规范+架构约定+Git 工作流)、.claude/design-tokens.mdUI 设计规范)、checkstyle.xml / .eslintrc.js、open-code-review 规则配置</td>
<td>Claude Code <strong>自动加载</strong> CLAUDE.md 作为系统提示。CI 阶段 open-code-review 二次校验</td>
</tr>
<tr>
<td><span class="tag tag-warn">L4</span></td>
<td><strong>示例模块</strong></td>
<td>一个完整的 UserModuleEntity → Mapper → Service → Controller → Test → Vue 页面),含 CRUD + 分页 + 权限校验的完整实现</td>
<td>开发者说"参照 UserModule 的模式实现 XxxModule",AI 自动对齐:包结构、命名风格、异常处理、测试模式</td>
</tr>
</table>
</div>
<h3>2.2 脚手架的三种落地形式</h3>
<div class="table-wrap">
<table>
<tr><th>形式</th><th>适用团队</th><th>操作方式</th><th>优势</th></tr>
<tr><td><strong>Git 模板仓库</strong></td><td>所有团队(推荐)</td><td>Gitea 上维护一个 <code>spring-boot-scaffold</code> 模板仓库,新项目通过 Gitea「使用模板」创建(仓库设置→勾选"模板仓库")</td><td>零工具依赖、版本可追溯、PR 方式演进、代码不出企业内网</td></tr>
<tr><td><strong>Maven Archetype</strong></td><td>纯 Java 团队</td><td><code>mvn archetype:generate</code> 交互式生成项目</td><td>与 Java 工具链无缝集成</td></tr>
<tr><td><strong>自定义 CLI</strong></td><td>多技术栈大团队</td><td><code>scaffold create spring-boot my-project</code> 一键生成</td><td>支持多技术栈、交互式选项、自动注册到 CI</td></tr>
</table>
</div>
<div class="box box-info">
<h4>📐 脚手架的最小可行内容</h4>
<p>如果一个团队今天还没有脚手架,<strong>一周内可以建好</strong></p>
<ol>
<li><strong>Day 1-2</strong>:选一个最近做过的、架构最满意的项目,删除所有业务代码,保留骨架 → 这就是 L1+L2</li>
<li><strong>Day 3-4</strong>:写 CLAUDE.md(参考本知识库的 CLAUDE.md 模板)+ 配置 open-code-review → L3</li>
<li><strong>Day 5-7</strong>:在骨架中手工写一个 UserModule 的完整实现 → L4。这个动作虽然手动,但<strong>一次投入,永久复用</strong></li>
</ol>
</div>
<h3>2.3 脚手架如何约束 AI 的代码风格</h3>
<p>AI 的本质是"模式匹配器"。给出正确的模式,它就能稳定输出正确风格的代码。脚手架通过三种机制确保 AI 生成的代码一致:</p>
<div class="table-wrap">
<table>
<tr><th>机制</th><th>原理</th><th>示例</th></tr>
<tr><td><strong>继承约束</strong></td><td>基类定义了必须遵循的接口。AI 生成的类必须继承基类,自然继承了行为模式</td><td>Controller 必须继承 BaseController → 自动获得统一的异常处理、日志格式、权限校验入口</td></tr>
<tr><td><strong>示例对齐</strong></td><td>示例模块提供了"正确答案"。AI 被要求参照示例模块的结构来生成同类代码</td><td>"参照 UserController 的结构生成 RoleController" → 生成的代码在分页处理、参数校验、返回格式上与 UserController 一致</td></tr>
<tr><td><strong>CI 守护</strong></td><td>open-code-review 在 CI 阶段检查代码是否符合团队规范。不合规的代码无法合并</td><td>有人让 AI 写了不带 rollbackFor 的 @Transactional → open-code-review 报错 → 代码无法合并 → 开发者被迫修正</td></tr>
</table>
</div>
</section>
<!-- ===== 三、企业内部基础设施层 ===== -->
<section id="s3">
<h2>三、企业内部基础设施层(双轨共用底座)</h2>
<p class="lead">在开始任何开发工作流之前,团队依赖一套<strong>内部基础设施</strong>来支撑代码管理、构建、测试、部署的全链路。以下基础设施是 Part A 和 Part B 的<strong>共用底座</strong>——没有它们,AI 工作流只能在开发者本地单机运行,无法发挥团队协作和自动化优势。</p>
<h3>3.1 基础设施全景</h3>
<div class="arch-diagram">
<div class="table-caption" style="margin-bottom:14px;">图:企业开发基础设施层架构</div>
<div class="arch-layer">
<div class="arch-box core" style="min-width:140px;">📋 <strong>Gitea</strong><span class="sub">代码托管 · PR审查 · Wiki</span></div>
<div class="arch-box core" style="min-width:140px;">🔄 <strong>Gitea Actions</strong><span class="sub">CI/CD 流水线</span></div>
<div class="arch-box core" style="min-width:140px;">📦 <strong>Harbor</strong><span class="sub">Docker 镜像仓库</span></div>
</div>
<div class="arch-layer">
<span class="arch-arrow">↕ ↕ ↕</span>
</div>
<div class="arch-layer">
<div class="arch-box tool" style="min-width:140px;">📚 <strong>Verdaccio</strong><span class="sub">npm 私服</span></div>
<div class="arch-box tool" style="min-width:140px;">🗄️ <strong>开发数据库</strong><span class="sub">MySQL · PG · Redis</span></div>
<div class="arch-box tool" style="min-width:140px;">☸️ <strong>K8s 集群</strong><span class="sub">测试/预发/生产</span></div>
</div>
<div class="arch-layer">
<span class="arch-arrow">↕ ↕ ↕</span>
</div>
<div class="arch-layer">
<div class="arch-box data" style="min-width:140px;">🔐 <strong>VPN / 内网</strong><span class="sub">安全访问 · 堡垒机</span></div>
<div class="arch-box data" style="min-width:140px;">📋 <strong>知识库</strong><span class="sub">Dify RAG · Wiki</span></div>
<div class="arch-box data" style="min-width:140px;">🧩 <strong>Memory</strong><span class="sub">Claude Code 个人记忆</span></div>
</div>
</div>
<h3>3.2 Gitea — 企业内部代码托管平台</h3>
<p>Gitea 是轻量级自托管 Git 服务,<strong>替代 GitHub/GitLab 在企业内网部署</strong>,代码不出企业网络。同时作为 AI 工作流的"协作中枢"——PR 审查、CI 触发、脚手架模板分发都围绕 Gitea 进行。</p>
<div class="table-wrap">
<table>
<tr><th style="width:14%;">功能</th><th style="width:34%;">在工作流中的作用</th><th>配置要点</th></tr>
<tr>
<td><strong>脚手架模板仓库</strong></td>
<td>维护 <code>spring-boot-scaffold</code> 等模板仓库。新项目通过 Gitea 的"使用模板"功能创建</td>
<td>仓库设置中勾选"模板仓库"选项;模板仓库的 README 需包含首次使用指南</td>
</tr>
<tr>
<td><strong>PR 代码审查</strong></td>
<td>所有代码变更通过 Pull Request 提交。Gitea 的 PR 页面是 open-code-reviewL1)和人工 ReviewL3)的操作界面</td>
<td>分支保护规则:main 分支禁止直接 push,必须通过 PR + 至少 1 人 Approve + CI 通过</td>
</tr>
<tr>
<td><strong>CI 触发器</strong></td>
<td>Push / PR 事件触发 Gitea Actions 运行 CI 流水线(lint → test → build → deploy</td>
<td>配置文件位于 <code>.gitea/workflows/ci.yml</code>(语法兼容 GitHub Actions</td>
</tr>
<tr>
<td><strong>Wiki / 文档</strong></td>
<td>每个仓库内置 Wiki,存放项目级文档(架构设计、ADR、API 文档)</td>
<td>Wiki 与代码仓库在同一 Gitea 实例中,权限统一管理</td>
</tr>
</table>
</div>
<div class="box box-info">
<h4>🔗 Gitea Actions CI 配置(与 GitHub Actions 兼容)</h4>
<div class="code-snippet">
<span class="cm"># .gitea/workflows/ci.yml —— 语法与 GitHub Actions 完全兼容</span><br>
<span class="kw">name</span>: CI Pipeline<br>
<span class="kw">on</span>:<br>
&nbsp;&nbsp;<span class="kw">push</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">branches</span>: [main, develop]<br>
&nbsp;&nbsp;<span class="kw">pull_request</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">branches</span>: [main]<br>
<br>
<span class="kw">jobs</span>:<br>
&nbsp;&nbsp;<span class="cm"># Job 1: 代码规范检查</span><br>
&nbsp;&nbsp;<span class="kw">lint</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">runs-on</span>: ubuntu-latest<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">steps</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="kw">uses</span>: actions/checkout@v4<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="kw">uses</span>: alibaba-group/open-code-review@v1<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">with</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">languages</span>: <span class="str">java,javascript,typescript,vue</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">severity</span>: <span class="str">error,warning</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">filter</span>: <span class="str">changed</span><br>
<br>
&nbsp;&nbsp;<span class="cm"># Job 2: 构建 + 单元测试</span><br>
&nbsp;&nbsp;<span class="kw">build</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">needs</span>: lint<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">runs-on</span>: ubuntu-latest<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">services</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">mysql</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: harbor.internal.com/library/mysql:8.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">env</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">MYSQL_ROOT_PASSWORD</span>: test123<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">steps</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="kw">uses</span>: actions/checkout@v4<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="kw">name</span>: Build & Test<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">run</span>: mvn -s .gitea/settings.xml clean test<br>
<br>
&nbsp;&nbsp;<span class="cm"># Job 3: 构建镜像 + 推送</span><br>
&nbsp;&nbsp;<span class="kw">docker</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">needs</span>: build<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">if</span>: github.ref == 'refs/heads/main'<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">steps</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="kw">name</span>: Build & Push Image<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">run</span>: |<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;docker build -t harbor.internal.com/$&#123;&#123; github.repository &#125;&#125;:latest .<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;docker push harbor.internal.com/$&#123;&#123; github.repository &#125;&#125;:latest
</div>
</div>
<h4>Gitea 部署与配置</h4>
<div class="table-wrap">
<div class="table-caption">表:Gitea 部署方式选型</div>
<table>
<tr><th style="width:14%;">部署方式</th><th style="width:20%;">命令</th><th style="width:20%;">适用场景</th><th>说明</th></tr>
<tr><td><strong>Docker(推荐)</strong></td><td><code>docker run -d --name gitea -p 3000:3000 -p 2222:22 -v /data/gitea:/data gitea/gitea:latest</code></td><td>10-200 人团队</td><td>5 分钟部署,内置 SQLite(可外挂 MySQL)。数据持久化到 /data/gitea</td></tr>
<tr><td><strong>Docker Compose</strong></td><td>gitea + mysql + redis 三容器编排(见下方完整配置)</td><td>需要高可用的团队(>50 人)</td><td>MySQL 替代 SQLite 提升并发,Redis 加速 Session 和缓存</td></tr>
<tr><td><strong>二进制安装</strong></td><td><code>wget dl.gitea.com/gitea/1.22/gitea-1.22-linux-amd64 && chmod +x gitea && ./gitea web</code></td><td>离线环境 / 无 Docker 环境</td><td>单文件运行,适合在内网堡垒机上部署</td></tr>
</table>
</div>
<div class="box box-info">
<h4>🐳 推荐:Docker Compose 完整部署(Gitea + MySQL + Redis</h4>
<div class="code-snippet">
<span class="cm"># docker-compose.yml — Gitea 生产环境部署</span><br>
<span class="kw">version</span>: <span class="str">'3.8'</span><br>
<span class="kw">services</span>:<br>
&nbsp;&nbsp;<span class="kw">gitea</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: gitea/gitea:latest<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">container_name</span>: gitea<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">environment</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- USER_UID=1000<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- USER_GID=1000<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__database__DB_TYPE=mysql<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__database__HOST=mysql:3306<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__database__NAME=gitea<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__database__USER=gitea<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__database__PASSWD=gitea123<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__server__DOMAIN=gitea.internal.com<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__server__ROOT_URL=https://gitea.internal.com<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- GITEA__actions__ENABLED=true<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">ports</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="str">"3000:3000"</span> <span class="cm"># Web UI</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="str">"2222:22"</span> <span class="cm"># SSH Git 克隆</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">volumes</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- /data/gitea:/data<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- /etc/timezone:/etc/timezone:ro<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">depends_on</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- mysql<br>
<br>
&nbsp;&nbsp;<span class="kw">mysql</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: mysql:8.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">environment</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- MYSQL_ROOT_PASSWORD=root123<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- MYSQL_DATABASE=gitea<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- MYSQL_USER=gitea<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- MYSQL_PASSWORD=gitea123<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">volumes</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- /data/gitea-mysql:/var/lib/mysql<br>
<br>
&nbsp;&nbsp;<span class="kw">redis</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: redis:7-alpine<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">restart</span>: always
</div>
</div>
<div class="table-wrap">
<div class="table-caption">表:Gitea 首次使用必须配置的 5 项设置</div>
<table>
<tr><th style="width:16%;">配置项</th><th style="width:14%;">位置</th><th>建议值</th><th>原因</th></tr>
<tr><td><strong>Gitea Actions</strong></td><td>app.ini</td><td><code>[actions] ENABLED = true</code></td><td>启用内置 CI/CD。这是 AI 工作流自动化的核心开关——没有它,open-code-review 无法在 PR 时自动运行</td></tr>
<tr><td><strong>分支保护</strong></td><td>仓库设置</td><td>main 分支:禁止直接 push、必须 1 人 Approve、必须 CI 通过</td><td>确保 AI 生成的代码必须经过审查+CI 验证才能合并</td></tr>
<tr><td><strong>模板仓库</strong></td><td>仓库设置</td><td>脚手架仓库勾选「模板仓库」</td><td>新项目可通过"使用模板"一键创建,继承全部脚手架配置</td></tr>
<tr><td><strong>Webhook</strong></td><td>仓库设置</td><td>Push 事件 → 通知企业微信/钉钉</td><td>团队感知代码变更,特别是 AI 批量提交时避免"不知道仓库在变化"</td></tr>
<tr><td><strong>Runner</strong></td><td>Site Admin</td><td>至少部署 2 个 Gitea Actions Runner1 个 linux/amd64 + 1 个用于前端构建)</td><td>Runner 是执行 CI Job 的工作节点。注册命令:<code>./act_runner register --instance https://gitea.internal.com --token &lt;TOKEN&gt;</code></td></tr>
</table>
</div>
<h3>3.3 内部制品仓库(Nexus / Harbor / Verdaccio</h3>
<div class="table-wrap">
<table>
<tr><th style="width:14%;">仓库类型</th><th style="width:16%;">推荐产品</th><th style="width:32%;">作用</th><th>配置要点</th></tr>
<tr>
<td><strong>Maven 私服</strong></td>
<td>Nexus Repository OSS</td>
<td>① 缓存外部依赖(加速构建、离线可用)② 发布内部公共库(如公司自研的 common-utils)③ 避免从外网下载不可信依赖</td>
<td>脚手架 settings.xml 中配置 Nexus 镜像;<code>mvn -s .gitea/settings.xml</code> 指向内部私服</td>
</tr>
<tr>
<td><strong>npm 私服</strong></td>
<td>Verdaccionpm.ycbat.com</td>
<td>缓存 npm 依赖,发布内部前端组件库</td>
<td>项目根目录 <code>.npmrc</code> 指向 <code>http://npm.ycbat.com/</code></td>
</tr>
<tr>
<td><strong>Docker 镜像仓库</strong></td>
<td>Harbor</td>
<td>① 存储 CI 构建的 Docker 镜像 ② 镜像安全扫描(Trivy)③ 作为 K8s 部署的镜像源</td>
<td>CI Job 构建镜像后 <code>docker push</code> 到 HarborK8s 的 imagePullSecret 指向 Harbor</td>
</tr>
</table>
</div>
<h4>npm 私服详解:Verdaccio vs Nexus</h4>
<div class="table-wrap">
<div class="table-caption">表:npm 私服方案选型</div>
<table>
<tr><th style="width:14%;">方案</th><th style="width:18%;">适用规模</th><th style="width:16%;">部署耗时</th><th>优势</th><th>劣势</th></tr>
<tr><td><strong>Verdaccio</strong></td><td>10-50 人前端团队</td><td><span class="tag tag-green">5 分钟</span></td><td>零配置、轻量(Node.js 单进程)、支持代理阿里云 npm 镜像 + 私有包发布、自带 Web UI 浏览包</td><td>只管理 npm,不覆盖 Maven/Docker 等</td></tr>
<tr><td><strong>Nexus Repository</strong></td><td>全公司统一制品管理</td><td><span class="tag tag-warn">30 分钟</span></td><td>一站式管理 Maven + npm + Docker + PyPI + Helm、LDAP 集成、权限精细控制</td><td>资源消耗大(最低 2GB 内存)、配置复杂</td></tr>
</table>
</div>
<div class="box box-info">
<h4>📦 Verdaccio 安装与配置(推荐小团队快速起步)</h4>
<div class="code-snippet">
<span class="cm"># 方式一:全局安装(适合单机快速验证)</span><br>
npm install -g verdaccio<br>
verdaccio <span class="cm"># 启动 → http://localhost:4873</span><br>
<br>
<span class="cm"># 方式二:Docker 部署(推荐,适合团队共享)</span><br>
docker run -d --name verdaccio \<br>
&nbsp;&nbsp;-p 4873:4873 \<br>
&nbsp;&nbsp;-v /data/verdaccio/storage:/verdaccio/storage \<br>
&nbsp;&nbsp;-v /data/verdaccio/config:/verdaccio/conf \<br>
&nbsp;&nbsp;verdaccio/verdaccio<br>
<br>
<span class="cm"># 方式三:Docker Compose(含 Nginx 反代 + HTTPS</span><br>
<span class="cm"># 见下方完整配置</span>
</div>
</div>
<div class="box box-good">
<h4>🐳 Verdaccio Docker Compose 生产部署(含 HTTPS</h4>
<div class="code-snippet">
<span class="cm"># docker-compose.yml — Verdaccio + Nginx 反代</span><br>
<span class="kw">version</span>: <span class="str">'3.8'</span><br>
<span class="kw">services</span>:<br>
&nbsp;&nbsp;<span class="kw">verdaccio</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: verdaccio/verdaccio:latest<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">container_name</span>: verdaccio<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">ports</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- <span class="str">"4873:4873"</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">volumes</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- /data/verdaccio/storage:/verdaccio/storage<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- /data/verdaccio/conf:/verdaccio/conf<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- ./config.yaml:/verdaccio/conf/config.yaml:ro<br>
<br>
<span class="cm"># Verdaccio 配置文件 config.yaml</span><br>
<span class="kw">storage</span>: /verdaccio/storage<br>
<span class="kw">uplinks</span>:<br>
&nbsp;&nbsp;<span class="kw">npmjs</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">url</span>: https://registry.npmmirror.com/ <span class="cm"># 阿里云镜像</span><br>
<span class="kw">packages</span>:<br>
&nbsp;&nbsp;<span class="str">'@mycompany/*'</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">access</span>: $all<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">publish</span>: $authenticated <span class="cm"># 仅登录用户可发布私有包</span><br>
&nbsp;&nbsp;<span class="str">'**'</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">access</span>: $all<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">proxy</span>: npmjs <span class="cm"># 其他包全部代理到阿里云镜像</span>
</div>
</div>
<h4>如何使用 npm 私服</h4>
<div class="table-wrap">
<div class="table-caption">表:开发者三步接入指南</div>
<table>
<tr><th style="width:8%;">步骤</th><th style="width:24%;">操作</th><th style="width:28%;">命令/配置</th><th>效果</th></tr>
<tr>
<td><span class="tag tag-blue">1</span></td>
<td><strong>配置私服地址</strong></td>
<td>项目根目录创建 <code>.npmrc</code><br><code>registry=http://npm.ycbat.com/</code><br>或全局设置:<br><code>npm config set registry http://npm.ycbat.com/</code></td>
<td>此后 npm install 全部走过私服,首次从阿里云镜像拉取并缓存,后续从私服秒级获取</td>
</tr>
<tr>
<td><span class="tag tag-green">2</span></td>
<td><strong>发布私有包</strong></td>
<td><code>npm login --registry=http://npm.ycbat.com/</code><br><code>npm publish --registry=http://npm.ycbat.com/</code></td>
<td>公司内部组件库(如 @mycompany/ui-kit、@mycompany/utils)发布到私服,全员 npm install 即可使用,告别 npm link 和 file:../</td>
</tr>
<tr>
<td><span class="tag tag-purple">3</span></td>
<td><strong>脚手架预置</strong></td>
<td>在脚手架模板仓库的根目录预置 <code>.npmrc</code> 文件,指向内部 Verdaccionpm.ycbat.com</td>
<td>新项目克隆后直接 npm install,无需每个开发者手动配置。这是<strong>新项目 Part A 开箱即用</strong>的基础保障</td>
</tr>
</table>
</div>
<div class="box box-idea">
<h4>🔑 npm 私服在 AI 工作流中的实际价值</h4>
<p><strong>场景 1 — 新项目 Part A</strong>Claude Code 生成前端代码,引入 Element Plus、ECharts 等依赖。安装时所有包从内网 Verdaccio 缓存拉取,<code>npm install</code> 从 3 分钟缩短到 15 秒。</p>
<p><strong>场景 2 — 内部组件复用</strong>:团队自研的通用组件(权限选择器、审批流面板)发布为 <code>@mycompany/*</code> 包。Claude Code 生成新模块时可以直接 import:<code>import { ApprovalPanel } from '@mycompany/approval-widget'</code>,不再需要复制粘贴代码。</p>
<p><strong>场景 3 — CI 加速</strong>Gitea Actions 的 CI Job 中 <code>npm ci</code> 从私服拉取,速度比从外网快 10-50 倍。对于频繁触发 CI 的新项目(每次 push 都跑),累计节省时间显著。</p>
</div>
<h3>3.4 开发数据库环境</h3>
<div class="table-wrap">
<div class="table-caption">表:开发数据库的三环境策略</div>
<table>
<tr><th style="width:14%;">环境</th><th style="width:16%;">用途</th><th style="width:34%;">配置</th><th>AI 工作流关联</th></tr>
<tr>
<td><strong>本地开发库</strong></td>
<td>开发者本机测试</td>
<td>Docker Compose 一键启动(MySQL + Redis),数据目录挂载到本地。<code>docker-compose -f .gitea/dev-services.yml up -d</code></td>
<td>Claude Code 执行 <code>mvn test</code> 时连接此数据库。脚手架自带 <code>dev-services.yml</code></td>
</tr>
<tr>
<td><strong>CI 测试库</strong></td>
<td>Gitea Actions 中运行集成测试</td>
<td>Gitea Actions 的 <code>services</code> 块定义(临时容器,Job 结束后销毁)。每个 PR 独立创建</td>
<td>open-code-review 通过后自动触发。数据库初始数据来自 Flyway/Liquibase 迁移脚本</td>
</tr>
<tr>
<td><strong>共享测试库</strong></td>
<td>测试环境持久化数据库</td>
<td>部署在 K8s 测试 Namespace 中的 StatefulSet。含脱敏的生产数据子集(从生产库脱敏导入)</td>
<td>E2E 测试和手工验收时使用。Claude Code 可连接此库进行"真实数据下的查询验证"</td>
</tr>
</table>
</div>
<div class="box box-good">
<h4>🐳 脚手架中的 dev-services.yml(示例)</h4>
<div class="code-snippet">
<span class="cm"># .gitea/dev-services.yml — 开发者本地一键启动</span><br>
<span class="kw">version</span>: <span class="str">'3.8'</span><br>
<span class="kw">services</span>:<br>
&nbsp;&nbsp;<span class="kw">mysql</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: harbor.internal.com/library/mysql:8.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">environment</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">MYSQL_ROOT_PASSWORD</span>: dev123<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">MYSQL_DATABASE</span>: srm_dev<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">ports</span>: [<span class="str">"3306:3306"</span>]<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">volumes</span>: [<span class="str">"./.gitea/init.sql:/docker-entrypoint-initdb.d/init.sql"</span>]<br>
<br>
&nbsp;&nbsp;<span class="kw">redis</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: harbor.internal.com/library/redis:7-alpine<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">ports</span>: [<span class="str">"6379:6379"</span>]<br>
<br>
&nbsp;&nbsp;<span class="kw">minio</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">image</span>: harbor.internal.com/library/minio:latest<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">environment</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">MINIO_ROOT_USER</span>: minioadmin<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">MINIO_ROOT_PASSWORD</span>: minioadmin<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">ports</span>: [<span class="str">"9000:9000"</span>, <span class="str">"9001:9001"</span>]
</div>
<p>开发者克隆项目后只需一条命令:<code>docker compose -f .gitea/dev-services.yml up -d</code>,即可获得完整的本地开发环境。这是<strong>新人 10 分钟上手</strong>的基础保障。</p>
</div>
<h3>3.5 基础设施在双轨工作流中的角色</h3>
<div class="table-wrap">
<table>
<tr><th style="width:16%;">基础设施</th><th style="width:38%;">🆕 新项目(Part A)中的角色</th><th style="width:38%;">🔧 老项目(Part B)中的角色</th></tr>
<tr>
<td><strong>Gitea</strong></td>
<td>① 从模板仓库创建新项目 ② 脚手架代码的版本控制 ③ PR 审查 + CI 自动触发</td>
<td>① 分析 Commit 历史(考古 L2 的数据源)② 精确的 Blame 追溯 ③ PR 中对比新旧行为</td>
</tr>
<tr>
<td><strong>Gitea Actions</strong></td>
<td>脚手架自带的完整 CI 流水线(lint → test → build → deploy),从第一次提交即生效</td>
<td>在现有 CI 中增量添加 open-code-review 步骤。老项目 CI 可能用 Jenkins,需做适配</td>
</tr>
<tr>
<td><strong>Nexus</strong></td>
<td>脚手架 pom.xml 已配置 Nexus 地址。AI 生成代码时引入的依赖从 Nexus 拉取,确保版本受控</td>
<td>老项目 pom.xml 可能直连 Maven Central——修改为走 Nexus 代理,增加私服缓存和版本管控</td>
</tr>
<tr>
<td><strong>Harbor</strong></td>
<td>CI 构建的镜像推送到 HarborK8s 从 Harbor 拉取部署</td>
<td>老项目可能用的是手动 docker save/load 方式——引入 Harbor 实现标准化镜像管理</td>
</tr>
<tr>
<td><strong>开发数据库</strong></td>
<td>脚手架自带 Flyway 迁移脚本 + <code>dev-services.yml</code>,本地环境和 CI 环境一致</td>
<td>老项目的数据库可能没有版本管理(Flyway/Liquibase)——考古阶段需要导出当前 Schema 作为基线</td>
</tr>
<tr>
<td><strong>VPN / 内网</strong></td>
<td>脚手架中配置的所有内部地址(Gitea/Nexus/Harbor)均通过内网访问。VPN 确保远程办公可达</td>
<td>DeepSeek/Qwen 调用的 API Key 和内部 LLM 网关地址只能在内网访问。代码分析不离开内网</td>
</tr>
</table>
</div>
<div class="box box-warn">
<h4>⚠️ 老项目接入基础设施的常见阻力与对策</h4>
<p><strong>阻力 1:"老项目的数据库没有 FlywaySchema 是手管的"</strong> → 对策:考古阶段用 <code>mysqldump --no-data</code> 导出当前 Schema 作为基线 V1__baseline.sql,后续变更用 Flyway 管理。不需要一次性改造全部历史。</p>
<p><strong>阻力 2"老项目用的是 Jenkins,不是 Gitea Actions"</strong> → 对策:不需要替换。在 Jenkinsfile 中新增一个 Stage 调用 open-code-review。核心是"CI 中有自动审查",不是"必须用某个 CI 工具"。</p>
<p><strong>阻力 3:"老项目的依赖直接从 Maven Central 拉,没有 Nexus"</strong> → 对策:配置 Nexus 为 Mirror Of Central(代理模式)——对老项目透明,不需要改 pom.xml,只要改 settings.xml。</p>
</div>
</section>
<!-- ================================================ -->
<!-- PART A: 新项目开发工作流(四) -->
<!-- ================================================ -->
<section id="s4">
<h2>🆕 Part A:新项目开发工作流(脚手架驱动)</h2>
<p class="lead">以下是从脚手架初始化到部署上线的<strong>完整 6 步工作流</strong>。每一步都包含操作指南、AI Prompt 示例、预期产出和检查点。整套流程以"供应商管理系统(SRM)"为实操案例贯穿始终。</p>
<div class="kpi-row">
<div class="kpi"><div class="num">6</div><div class="label">工作流步骤</div></div>
<div class="kpi"><div class="num">70-90%</div><div class="label">AI 代码生成占比</div></div>
<div class="kpi"><div class="num">3-5 天</div><div class="label">中型模块周期</div></div>
<div class="kpi"><div class="num">90%+</div><div class="label">首次 CI 通过率</div></div>
</div>
<!-- A.1 -->
<h3 id="s4a">A.1 脚手架初始化(5 分钟)</h3>
<div class="table-wrap">
<div class="table-caption">操作步骤</div>
<table>
<tr><th style="width:8%;">步骤</th><th style="width:35%;">操作</th><th>工具</th><th style="width:10%;">耗时</th></tr>
<tr><td>1</td><td>从团队 Gitea 模板仓库创建新项目:在模板仓库页面点击「使用模板」→ 填入新项目名称 → 自动生成新仓库(或 <code>git clone</code> 模板仓库后删除 .git 重新 init)</td><td>Gitea / Git CLI</td><td>2 分钟</td></tr>
<tr><td>2</td><td>修改项目级配置:artifact ID、application name、数据库名、K8s namespace</td><td>IDE 批量替换</td><td>2 分钟</td></tr>
<tr><td>3</td><td>验证脚手架完整性:<code>mvn clean test</code>(或等效命令)确保 L4 示例模块的测试能跑通</td><td>Maven / Gradle</td><td>1 分钟</td></tr>
</table>
</div>
<div class="box box-good">
<h4>✅ 检查点</h4>
<ul>
<li><code>mvn clean test</code> 通过(脚手架自带测试全绿)</li>
<li>☑ CLAUDE.md 已存在于项目根目录</li>
<li>☑ .gitea/workflows/ci.yml 已就绪(open-code-review + 测试)</li>
<li>☑ UserModule 示例可以正常访问(/api/users 返回分页数据)</li>
</ul>
</div>
<!-- A.2 -->
<h3 id="s4b">A.2 需求 → 脚手架模块映射(20-30 分钟)</h3>
<p>这一步的核心工作是<strong>将需求文档中的功能点,映射到脚手架已有模块的扩展点</strong>。不做从零设计,做"参照+差异"分析。</p>
<div class="box box-idea">
<h4>💬 对 Claude Code 的 Prompt</h4>
<div class="code-snippet">
<span class="cm"># 启动 Claude Code,在项目根目录下输入:</span><br>
我正在进行一个供应商管理系统(SRM)项目,需求文档在 docs/requirements/srm-v1.md。<br>
项目已从脚手架初始化,脚手架结构参考 CLAUDE.md 和 UserModule 示例。<br>
<br>
请帮我完成以下工作:<br>
<br>
<span class="kw">1. 需求模块化拆解</span><br>
&nbsp;&nbsp;读取需求文档,将功能拆解为独立模块。每个模块标注:<br>
&nbsp;&nbsp;- 是否可以直接复用脚手架模式(如 CRUD 类模块参照 UserModule<br>
&nbsp;&nbsp;- 是否需要新增脚手架不包含的能力(如审批流、文件上传)<br>
&nbsp;&nbsp;- 预估需要多少 Entity / Service / Controller / 前端页面<br>
<br>
<span class="kw">2. 模块优先级排序</span><br>
&nbsp;&nbsp;按依赖关系和交付价值排列开发顺序<br>
<br>
<span class="kw">3. 输出开发计划</span><br>
&nbsp;&nbsp;生成 docs/plan/module-plan.md,包含:<br>
&nbsp;&nbsp;- 模块清单 + 复用度评估 + 开发顺序<br>
&nbsp;&nbsp;- 每个模块与 UserModule 的差异点(只需描述"不同之处")<br>
&nbsp;&nbsp;- 需要脚手架新增的通用能力(如审批流引擎)<br>
<br>
请先进入 Plan Mode。
</div>
</div>
<div class="box box-good">
<h4>✅ 预期产出示例(SRM 项目)</h4>
<div class="table-wrap">
<table>
<tr><th>模块</th><th>复用度</th><th>参照</th><th>差异点</th><th>优先级</th></tr>
<tr><td>供应商主数据</td><td><span class="tag tag-green">90%</span></td><td>UserModule</td><td>多一个"供应商分类"字段、营业执照附件上传</td><td>P0</td></tr>
<tr><td>供应商评估</td><td><span class="tag tag-blue">60%</span></td><td>UserModule + 自定义评分逻辑</td><td>评分模型(KPI 加权)、评估历史时间线</td><td>P1</td></tr>
<tr><td>采购询价</td><td><span class="tag tag-warn">30%</span></td><td>需新增审批流</td><td>询价单→报价→比价→审批流程、报价附件对比</td><td>P1</td></tr>
<tr><td>合同管理</td><td><span class="tag tag-blue">50%</span></td><td>UserModule + 审批流</td><td>合同模板、电子签章集成、到期提醒</td><td>P2</td></tr>
</table>
</div>
</div>
<!-- A.3 -->
<h3 id="s4c">A.3 Plan Mode:生成编码计划(15 分钟/模块)</h3>
<p>对每个模块,在动手编码前,<strong>必须先让 Claude Code 输出 Plan 并获得确认</strong>。Plan 阶段不写代码,只设计"要写哪些文件、每个文件做什么"。</p>
<div class="box box-idea">
<h4>💬 对 Claude Code 的 Prompt(以"供应商主数据"模块为例)</h4>
<div class="code-snippet">
<span class="cm"># 需求</span><br>
实现供应商主数据模块(FR-SUP-001),参照 UserModule 的模式。<br>
<br>
<span class="kw">差异点</span><br>
1. Supplier 比 User 多一个 supplierCategory(供应商分类)字段<br>
2. 需要支持营业执照附件上传(脚手架目前没有文件上传能力)<br>
3. 查询接口需要按供应商分类和状态筛选<br>
<br>
<span class="kw">参照文件</span><br>
- entity/User.java<br>
- mapper/UserMapper.java<br>
- service/UserService.java<br>
- controller/UserController.java<br>
- vue/views/user/UserList.vue<br>
<br>
请进入 Plan Mode,告诉我你计划创建/修改哪些文件,<br>
每个文件的作用是什么。先用 Read 工具读取参照文件,<br>
然后输出计划。
</div>
</div>
<div class="box box-good">
<h4>✅ Claude Code Plan 输出示例</h4>
<div class="code-snippet">
<span class="kw">Plan</span>: 供应商主数据模块 FR-SUP-001<br>
<br>
<span class="kw">Step 1 - 数据层</span>:<br>
&nbsp;&nbsp;READ: entity/User.java, entity/BaseEntity.java<br>
&nbsp;&nbsp;WRITE: entity/Supplier.java (extends BaseEntity, add supplierCategory)<br>
&nbsp;&nbsp;WRITE: mapper/SupplierMapper.java (extends BaseMapper&lt;Supplier&gt;)<br>
&nbsp;&nbsp;WRITE: src/main/resources/db/migration/V1.1__supplier.sql<br>
<br>
<span class="kw">Step 2 - 业务层</span>:<br>
&nbsp;&nbsp;READ: service/UserService.java<br>
&nbsp;&nbsp;WRITE: service/SupplierService.java (extends BaseService&lt;Supplier&gt;)<br>
&nbsp;&nbsp;WRITE: dto/SupplierQuery.java (extends PageQuery, add category/status)<br>
&nbsp;&nbsp;WRITE: dto/SupplierDTO.java<br>
<br>
<span class="kw">Step 3 - 接口层</span>:<br>
&nbsp;&nbsp;READ: controller/UserController.java<br>
&nbsp;&nbsp;WRITE: controller/SupplierController.java (extends BaseController)<br>
&nbsp;&nbsp;接口: GET /api/suppliers (分页), GET /api/suppliers/{id},<br>
&nbsp;&nbsp;POST /api/suppliers, PUT /api/suppliers/{id}, DELETE /api/suppliers/{id}<br>
<br>
<span class="kw">Step 4 - 文件上传</span>:<br>
&nbsp;&nbsp;脚手架缺少文件上传能力。计划:<br>
&nbsp;&nbsp;WRITE: config/FileUploadConfig.java<br>
&nbsp;&nbsp;WRITE: util/FileUploadUtil.java<br>
&nbsp;&nbsp;WRITE: controller/FileController.java<br>
&nbsp;&nbsp;(此为通用能力,放在 common 包下,未来其他模块可复用)<br>
<br>
<span class="kw">Step 5 - 前端</span>:<br>
&nbsp;&nbsp;READ: vue/views/user/UserList.vue<br>
&nbsp;&nbsp;WRITE: vue/views/supplier/SupplierList.vue<br>
&nbsp;&nbsp;WRITE: vue/views/supplier/SupplierForm.vue<br>
&nbsp;&nbsp;WRITE: vue/api/supplier.js<br>
<br>
<span class="kw">Step 6 - 测试</span>:<br>
&nbsp;&nbsp;READ: test/.../UserServiceTest.java<br>
&nbsp;&nbsp;WRITE: test/.../SupplierServiceTest.java<br>
&nbsp;&nbsp;WRITE: test/.../SupplierControllerTest.java<br>
<br>
<span class="kw">涉及文件</span>: 14 个文件(10 新 + 4 读)<br>
<span class="kw">预计 Claude Code 编码时间</span>: 20-25 分钟<br>
<br>
确认后我开始执行。是否需要调整?
</div>
</div>
<!-- A.4 -->
<h3 id="s4d">A.4 全量代码生成(20-30 分钟/模块)</h3>
<p>Plan 确认后,Claude Code 按计划逐文件生成代码。开发者在此阶段的核心职责是<strong>引导方向,而非逐行审查</strong></p>
<div class="table-wrap">
<div class="table-caption">开发者在此阶段的 4 个引导动作</div>
<table>
<tr><th style="width:12%;">动作</th><th style="width:38%;">不好的说法</th><th>好的说法</th></tr>
<tr><td><strong>引用基类</strong></td><td>"写个 SupplierController"</td><td>"写 SupplierController,继承 BaseController,返回类型用 Result&lt;T&gt; 包装,异常不要 try-catch(交给 GlobalExceptionHandler"</td></tr>
<tr><td><strong>给出参照</strong></td><td>"加个供应商列表页面"</td><td>"加 SupplierList.vue,表格列、搜索栏、分页组件的用法参照 UserList.vue 的写法,用相同的 <code>&lt;page-table&gt;</code> 组件"</td></tr>
<tr><td><strong>边界前置</strong></td><td>"供应商分类用下拉框"</td><td>"供应商分类用下拉框,数据从字典表 sys_dict 的 supplier_category 类型加载。下拉框组件参照 UserForm.vue 中角色选择器的用法"</td></tr>
<tr><td><strong>纠偏</strong></td><td>"这个不对,重写"</td><td>"我看到 SupplierController 里你手动写了 try-catch——基类 BaseController 已经统一处理了异常,请去掉这些 try-catch,让它抛出去给 GlobalExceptionHandler"</td></tr>
</table>
</div>
<div class="box box-warn">
<h4>⚠️ 新项目编码阶段的常见陷阱</h4>
<p><strong>陷阱 1AI 绕过基类。</strong>Claude Code 有时会"忘记"继承 BaseController/BaseService,自己写一套。开发者发现后应立即纠正:"请继承 BaseController,不要自己写异常处理"。纠正 2-3 次后,AI 会形成习惯。</p>
<p><strong>陷阱 2AI 发明新的返回格式。</strong>脚手架统一用 Result&lt;T&gt;,但 AI 可能返回 Map 或自定义对象。纠正方式:"所有接口返回值必须是 Result&lt;T&gt;,参照 UserController 的写法"。</p>
<p><strong>陷阱 3:过度生成。</strong>AI 有时会在一个模块中加入不属于该模块的功能。纠正方式:"这个功能属于下一个模块,现在只需要实现 FR-SUP-001 范围的代码"。</p>
</div>
<h4>示例:Claude Code 生成的 SupplierController.java</h4>
<div class="code-snippet">
<span class="cm">// ===== Claude Code 自动生成:SupplierController.java =====</span><br>
<span class="kw">@RestController</span><br>
<span class="kw">@RequestMapping</span>(<span class="str">"/api/suppliers"</span>)<br>
<span class="kw">@Slf4j</span><br>
<span class="kw">@RequiredArgsConstructor</span><br>
<span class="kw">public class</span> <span class="fn">SupplierController</span> <span class="kw">extends</span> BaseController {<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">private final</span> SupplierService <span class="fn">supplierService</span>;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">@GetMapping</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">public</span> Result&lt;PageResult&lt;SupplierDTO&gt;&gt; <span class="fn">list</span>(<span class="kw">@Valid</span> SupplierQuery query) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">return</span> Result.success(supplierService.page(query));<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">@GetMapping</span>(<span class="str">"/{id}"</span>)<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">public</span> Result&lt;SupplierDTO&gt; <span class="fn">getById</span>(<span class="kw">@PathVariable</span> Long id) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">return</span> Result.success(supplierService.getDetailById(id));<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">@PostMapping</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">public</span> Result&lt;Long&gt; <span class="fn">create</span>(<span class="kw">@Valid @RequestBody</span> SupplierCreateDTO dto) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">return</span> Result.success(supplierService.create(dto));<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">@PutMapping</span>(<span class="str">"/{id}"</span>)<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">public</span> Result&lt;Void&gt; <span class="fn">update</span>(<span class="kw">@PathVariable</span> Long id, <span class="kw">@Valid @RequestBody</span> SupplierUpdateDTO dto) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supplierService.update(id, dto);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">return</span> Result.success();<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
}
<span class="cm">// 注意:无 try-catch(由 BaseController 的 GlobalExceptionHandler 统一处理)</span><br>
<span class="cm">// 注意:所有返回值用 Result&lt;T&gt; 包装(与 UserController 完全一致)</span><br>
<span class="cm">// 注意:分页查询用 SupplierQuery extends PageQuery(与 UserQuery 模式一致)</span>
</div>
<!-- A.5 -->
<h3 id="s4e">A.5 测试生成与代码审查(15 分钟/模块)</h3>
<div class="table-wrap">
<div class="table-caption">测试生成 + 审查的 4 个步骤</div>
<table>
<tr><th style="width:8%;">步骤</th><th style="width:35%;">操作</th><th>工具</th></tr>
<tr><td><strong>1. 生成测试</strong></td><td>对 Claude Code 说:"为 SupplierService 生成单元测试,参照 UserServiceTest 的风格。覆盖:正常 CRUD、参数校验失败、供应商名称重复、分类不存在"</td><td>Claude Code</td></tr>
<tr><td><strong>2. 运行测试</strong></td><td>Claude Code 自动执行 <code>mvn test -pl supplier</code>,验证生成的测试通过</td><td>Maven</td></tr>
<tr><td><strong>3. L1 审查</strong></td><td><code>git push</code> → CI 自动触发 open-code-review。检查代码是否符合阿里规约+团队自定义规则</td><td>open-code-review (CI)</td></tr>
<tr><td><strong>4. L2 审查</strong></td><td>对 Claude Code 说:"<code>/code-review</code>,审查本次 Supplier 模块的 diff。重点关注:是否绕过了基类、是否有 SQL 注入风险、文件上传的大小限制是否合理"</td><td>Claude Code</td></tr>
</table>
</div>
<div class="box box-good">
<h4>✅ 新项目代码审查的特殊关注点</h4>
<ul>
<li>☑ 每个 Controller 是否继承了 BaseController</li>
<li>☑ 每个 Service 是否继承了 BaseService</li>
<li>☑ 所有接口返回值是否使用 Result&lt;T&gt;</li>
<li>☑ 分页查询是否继承了 PageQuery?</li>
<li>☑ 新增的通用能力(如文件上传)是否放在了 common/util 包而非业务包里?</li>
<li>☑ 数据库 DDL 的命名风格是否与脚手架现有表一致(下划线、create_time、update_time、is_deleted)?</li>
</ul>
</div>
<!-- A.6 -->
<h3 id="s4f">A.6 部署上线 + 记忆沉淀(10 分钟)</h3>
<div class="table-wrap">
<table>
<tr><th style="width:8%;">步骤</th><th style="width:35%;">操作</th><th>工具</th></tr>
<tr><td><strong>1. CI 通过</strong></td><td>PR 合并到 main → Gitea Actions 自动构建 Docker 镜像并推送 Harbor → 自动部署到 K8s 测试环境</td><td>Gitea Actions + Docker + Harbor + K8s</td></tr>
<tr><td><strong>2. 冒烟测试</strong></td><td>对 Claude Code 说:"为 Supplier 模块生成一个冒烟测试 checklist,覆盖 API 接口的 happy path"</td><td>Claude Code</td></tr>
<tr><td><strong>3. API 文档</strong></td><td>对 Claude Code 说:"读取 SupplierController 的注解和代码,生成 docs/api/supplier-api.mdMarkdown 表格格式)"</td><td>Claude Code</td></tr>
<tr><td><strong>4. 记忆沉淀</strong></td><td>对 Claude Code 说:"帮我记住:① 供应商分类从 sys_dict 表加载 ② 营业执照上传限制 5MB、仅支持 jpg/png/pdf ③ 供应商编码规则:SUP-{年份}-{4位序号}"</td><td>Claude Code Memory</td></tr>
<tr><td><strong>5. 脚手架反哺</strong></td><td>如果在开发中新增了通用能力(如 FileUploadUtil),评估是否应该合并回脚手架模板仓库,让后续新项目直接受益</td><td>人工决策 → PR to scaffold repo</td></tr>
</table>
</div>
<div class="box box-idea">
<h4>🔑 脚手架反哺机制</h4>
<p>新项目开发中发现的通用能力,应<strong>回流到脚手架</strong>。示例:SRM 项目开发中新增了 FileUploadUtil + FileController 作为通用文件上传方案。如果团队确认这个方案足够通用,应发 PR 合并到 <code>spring-boot-scaffold</code> 模板仓库。下一个新项目创建时,就自带文件上传能力了。</p>
<p>反哺频率:每个项目结项时,至少提出 1 个脚手架改进 PR。</p>
</div>
</section>
<!-- ================================================ -->
<!-- PART B: 老项目维护工作流(五) -->
<!-- ================================================ -->
<section id="s5">
<h2>🔧 Part B:老项目维护工作流(代码考古驱动)</h2>
<p class="lead">老项目的核心挑战不是"写代码",而是<strong>"知道改哪里不会出事"</strong>。以下 5 步工作流的核心思想是:<strong>先理解、再计划、后动手、必验证</strong>。以在一个遗留 MES 系统中新增"工单审批流"为实操案例。</p>
<div class="kpi-row">
<div class="kpi warn"><div class="num">5</div><div class="label">工作流步骤</div></div>
<div class="kpi warn"><div class="num">15-40%</div><div class="label">AI 代码生成占比</div></div>
<div class="kpi warn"><div class="num">1-3 天</div><div class="label">中型改动周期</div></div>
<div class="kpi danger"><div class="num">≤200行</div><div class="label">单次 diff 上限</div></div>
</div>
<!-- B.1 -->
<h3 id="s5a">B.1 代码考古:理解现状(30-60 分钟)</h3>
<p class="lead">在修改任何代码之前,必须先<strong>搞清楚三件事</strong>:目标区域现在怎么工作的、谁依赖它、有哪些隐式约定(代码里没写但大家都知道的规则)。</p>
<h4>考古的三层递进</h4>
<div class="table-wrap">
<table>
<tr><th style="width:10%;">层级</th><th style="width:18%;">分析内容</th><th style="width:25%;">使用工具</th><th>具体方法</th></tr>
<tr>
<td><span class="tag tag-blue">L1</span></td>
<td><strong>模块边界</strong></td>
<td>DeepSeek(零成本批量分析)</td>
<td>将整个模块的 Java 文件列表发给 DeepSeek,让它分析:类之间的依赖关系、循环依赖、God Class 识别、死代码标记</td>
</tr>
<tr>
<td><span class="tag tag-purple">L2</span></td>
<td><strong>业务逻辑</strong></td>
<td>Qwen(百万 Token 上下文)</td>
<td>将目标模块的所有源码 + 注释 + 最近 50 条 Commit Message 一次性发给 Qwen,让它输出:模块职责描述、核心业务流程、隐式约定清单</td>
</tr>
<tr>
<td><span class="tag tag-green">L3</span></td>
<td><strong>精确理解</strong></td>
<td>Claude Code</td>
<td>Read 目标文件和所有调用方/被调用方文件,进行精确的代码级理解。输出:修改影响分析报告</td>
</tr>
</table>
</div>
<div class="box box-info">
<h4>🔍 DeepSeek 考古 PromptL1</h4>
<div class="code-snippet">
<span class="cm"># 将目标模块的文件列表发送给 DeepSeek:</span><br>
你是一位 Java 遗留系统分析专家。以下是 MES 系统中"工单管理"模块<br>
com.xxx.mes.workorder)下的所有 Java 文件列表:<br>
<br>
[列出所有 .java 文件的完整路径,约 30-80 个文件]<br>
<br>
请分析:<br>
1. <span class="kw">模块依赖图</span>:这个模块依赖了哪些其他模块?被哪些模块依赖?<br>
2. <span class="kw">循环依赖</span>:有没有 A→B→A 的循环?<br>
3. <span class="kw">God Class</span>:有没有超过 500 行的类?标注其职责是否过于臃肿<br>
4. <span class="kw">死代码</span>:有没有明显不再使用的类/方法?(根据命名判断)<br>
5. <span class="kw">重构优先级</span>:如果只能改一个类来改善可维护性,改哪个?<br>
<br>
不需要读取文件内容,仅根据文件路径和类名分析。
</div>
</div>
<div class="box box-idea">
<h4>📖 Qwen 深层解读 PromptL2</h4>
<div class="code-snippet">
<span class="cm"># 将目标模块的全部源码 + Commit 历史发给 Qwen</span><br>
你是一位资深 MES 系统架构师。以下是一个遗留 MES 系统"工单管理"模块<br>
的完整源码和最近提交历史。请通读后回答:<br>
<br>
1. <span class="kw">模块职责</span>:这个模块到底负责什么?(用一段话总结)<br>
2. <span class="kw">核心流程</span>:工单从创建到关闭经历了哪些状态?<br>
&nbsp;&nbsp;&nbsp;状态转换的触发条件是什么?<br>
3. <span class="kw">隐式约定</span>:代码中有哪些"大家都懂但没写文档"的规则?<br>
&nbsp;&nbsp;&nbsp;(例如:工单状态字段虽然存的是 String,但只有 4 个合法值)<br>
4. <span class="kw">已知坑点</span>:从 Commit Message 中分析,最近修复了哪些 Bug?<br>
&nbsp;&nbsp;&nbsp;这些 Bug 的根因是什么?有没有反复出现的模式?<br>
<br>
[粘贴全部源码 + Commit 历史]
</div>
</div>
<h4>Claude Code 精确理解(L3</h4>
<div class="box box-good">
<h4>💬 对 Claude Code 的精确理解 Prompt</h4>
<div class="code-snippet">
<span class="cm"># 在 Claude Code 中输入:</span><br>
我需要在这个遗留 MES 系统的工单模块中新增审批流功能。<br>
在我动手之前,请帮我做一次"修改前影响分析":<br>
<br>
1. READ: com/xxx/mes/workorder/entity/WorkOrder.java<br>
2. READ: com/xxx/mes/workorder/service/WorkOrderService.java<br>
3. READ: com/xxx/mes/workorder/controller/WorkOrderController.java<br>
4. 搜索所有引用 WorkOrder.status 字段的代码<br>
5. 搜索所有调用 WorkOrderService.updateStatus() 方法的代码<br>
6. 搜索项目中是否已有 Flowable/Activiti 依赖<br>
<br>
输出:<br>
- <span class="kw">现状描述</span>:工单模块现在的状态流转逻辑<br>
- <span class="kw">调用方清单</span>:所有会修改工单状态的入口(Controller/定时任务/消息监听器)<br>
- <span class="kw">风险点</span>:修改状态流转逻辑后,哪些地方可能被破坏?<br>
- <span class="kw">改造方案</span>:如何以最小侵入性加入审批流?<br>
<br>
请先 Read 所有相关文件,然后输出分析报告到 docs/impact/approval-flow.md
</div>
</div>
<!-- B.2 -->
<h3 id="s5b">B.2 影响分析:修改范围评估(20 分钟)</h3>
<div class="table-wrap">
<div class="table-caption">影响分析报告的关键内容(Claude Code 输出)</div>
<table>
<tr><th style="width:16%;">分析维度</th><th>内容</th><th>示例(MES 工单审批流)</th></tr>
<tr><td><strong>修改文件清单</strong></td><td>需要改哪些文件,每个文件的改动原因</td><td>WorkOrder.java(新增 2 个状态值)、WorkOrderService.java(修改 updateStatus 方法)、新增 ApprovalService.java、新增 1 张审批记录表</td></tr>
<tr><td><strong>调用方影响</strong></td><td>改了方法签名/行为后,哪些调用方需要适配</td><td>WorkOrderController.completeWorkOrder() → 改为提交审批而非直接完成;ScheduledTasks.autoCloseExpiredOrders() → 定时任务需要跳过"审批中"的工单</td></tr>
<tr><td><strong>数据库影响</strong></td><td>新增/修改表、是否影响现有查询</td><td>新增 approval_record 表;work_order 表新增 process_instance_id 字段(可为 null,兼容旧数据);无现有查询受影响</td></tr>
<tr><td><strong>API 兼容性</strong></td><td>是否改变现有 API 的请求/响应格式</td><td>POST /api/workorder/{id}/complete → 语义变更(从"直接完成"变为"提交审批")。建议新增 POST /api/workorder/{id}/submit-approval,保留旧接口兼容</td></tr>
<tr><td><strong>测试影响</strong></td><td>哪些现有测试可能失败</td><td>WorkOrderServiceTest.testCompleteWorkOrder() → 现在不会直接改变状态,需更新测试断言</td></tr>
</table>
</div>
<div class="box box-warn">
<h4>⚠️ 影响分析中的"红灯信号"</h4>
<p>如果在分析中发现以下情况,<strong>不要继续往下走</strong>,先和 Tech Lead 讨论方案:</p>
<ul>
<li>🔴 需要修改的调用方超过 10 个</li>
<li>🔴 目标代码没有单元测试,且无法在不改代码的情况下补充(即"不可测试代码")</li>
<li>🔴 数据库变更会影响超过 100 万行数据的表(需评估锁表风险)</li>
<li>🔴 存在未文档化的外部系统直接读数据库(可能被报表/BI 系统依赖)</li>
</ul>
</div>
<!-- B.3 -->
<h3 id="s5c">B.3 增量修改:测试先行 + 小步提交(1-4 小时)</h3>
<p class="lead">这是 Part B 最关键的步骤。<strong>铁律:先写测试,再改代码;单次 diff 不超过 200 行。</strong></p>
<h4>B.3.1 测试先行(保护网)</h4>
<div class="box box-info">
<h4>💬 对 Claude Code 说</h4>
<div class="code-snippet">
<span class="cm"># Step 1: 为即将修改的代码补充测试(如果缺失)</span><br>
我需要修改 WorkOrderService.updateStatus() 方法,加入审批流逻辑。<br>
在修改之前,请先为这个方法生成完整的单元测试,覆盖:<br>
<br>
1. <span class="kw">正常路径</span>:每种合法的状态转换<br>
2. <span class="kw">异常路径</span>:非法状态转换(如"已完成→生产中")<br>
3. <span class="kw">边界条件</span>:工单不存在、状态字段为 null<br>
<br>
<span class="kw">限制</span><br>
- 测试必须与现有测试风格一致(使用相同的基类和 Mock 方式)<br>
- 先用 --dry-run 模式跑一遍,确保测试能通过<br>
- 如果现有的 updateStatus() 方法逻辑太复杂导致无法测试,<br>
&nbsp;&nbsp;先告诉我,不要强行 Mock<br>
<br>
请在 Plan Mode 中先展示你的测试计划。
</div>
</div>
<div class="box box-good">
<h4>✅ 测试先行的好处</h4>
<p>① 如果现有代码无法测试(如 500 行的 God Method),<strong>你会先知道</strong>——这本身就是重要的风险信号</p>
<p>② 测试是"安全网"。后续修改代码时,<code>mvn test</code> 一跑就知道有没有破坏原有行为</p>
<p>③ 测试本身就是文档。后来者(包括 3 个月后的你自己)看测试就能理解这段代码应该怎么工作</p>
</div>
<h4>B.3.2 小步修改(每步一个 PR</h4>
<div class="table-wrap">
<div class="table-caption">将审批流改造拆分为 4 个小 PR</div>
<table>
<tr><th style="width:10%;">PR</th><th style="width:22%;">内容</th><th style="width:15%;">文件数</th><th style="width:15%;">Diff 行数</th><th>依赖</th><th>可独立验证?</th></tr>
<tr>
<td><span class="tag tag-blue">PR1</span></td>
<td>数据库 DDL(新增 approval_record 表 + work_order 表加字段)+ Entity 类更新</td>
<td>3 个</td>
<td>~50 行</td>
<td></td>
<td>✅ DDL 可独立执行</td>
</tr>
<tr>
<td><span class="tag tag-blue">PR2</span></td>
<td>新增 ApprovalService + ApprovalRecord(纯新增,不修改现有代码)</td>
<td>4 个</td>
<td>~150 行</td>
<td>PR1</td>
<td>✅ 新类无副作用</td>
</tr>
<tr>
<td><span class="tag tag-blue">PR3</span></td>
<td>修改 WorkOrderService.updateStatus() 接入审批流(核心改动)</td>
<td>2 个</td>
<td>~80 行</td>
<td>PR2</td>
<td>✅ 测试已前置</td>
</tr>
<tr>
<td><span class="tag tag-blue">PR4</span></td>
<td>修改定时任务 + Controller 适配新流程</td>
<td>3 个</td>
<td>~100 行</td>
<td>PR3</td>
<td>✅ 独立功能点</td>
</tr>
</table>
</div>
<div class="box box-warn">
<h4>⚠️ 老项目修改的"三个绝不"</h4>
<p><strong>绝不 1:绝不在一个 PR 中同时"重构+新功能"。</strong>重构(改善现有代码结构)和新功能(改变系统行为)必须分开。这是老项目 Bug 的头号来源。</p>
<p><strong>绝不 2:绝不修改超过 5 个文件而不做回归测试。</strong>如果改动涉及 6+ 个文件,拆成两个 PR。</p>
<p><strong>绝不 3:绝不绕过现有测试直接改逻辑。</strong>如果目标代码没有测试,先补测试(B.3.1),再改代码。没有测试的修改 = 盲飞。</p>
</div>
<!-- B.4 -->
<h3 id="s5d">B.4 回归验证与合并(15-30 分钟)</h3>
<div class="table-wrap">
<table>
<tr><th style="width:8%;">步骤</th><th style="width:35%;">操作</th><th>工具</th></tr>
<tr><td><strong>1. 全量测试</strong></td><td><code>mvn clean test</code>(确保所有现有测试 + 新增测试全部通过)</td><td>Maven</td></tr>
<tr><td><strong>2. L1 增量审查</strong></td><td>open-code-review 在 CI 中只检查本次修改的文件(<code>filter=changed</code>),避免对遗留代码的"历史债务"产生噪音</td><td>open-code-review (CI)</td></tr>
<tr><td><strong>3. L2 语义审查</strong></td><td>对 Claude Code 说:"<code>/code-review</code>,审查 PR3 的 diff。重点检查:原有状态转换逻辑是否被完整保留?新增的审批流是否与现有定时任务产生竞态条件?"</td><td>Claude Code</td></tr>
<tr><td><strong>4. L3 人工审查</strong></td><td>Tech Lead 审查,聚焦业务正确性和架构影响。代码风格已在 L1/L2 阶段解决</td><td>人工</td></tr>
<tr><td><strong>5. 合并</strong></td><td>Squash merge to main4 个 PR 的 commit 被 squash 为 1 个干净的 commit</td><td>Git</td></tr>
</table>
</div>
<div class="box box-info">
<h4>⚙️ 老项目 open-code-review 的增量模式配置</h4>
<div class="code-snippet">
<span class="cm"># .gitea/workflows/ci.yml 中针对老项目的配置</span><br>
<span class="kw">- uses</span>: alibaba-group/open-code-review@v1<br>
&nbsp;&nbsp;<span class="kw">with</span>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">languages</span>: <span class="str">java,javascript</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">severity</span>: <span class="str">error,warning</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">filter</span>: <span class="str">changed</span> <span class="cm"># ← 关键:只检查本次 diff 的文件</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">baseline</span>: <span class="str">main</span> <span class="cm"># ← 与 main 分支对比</span>
</div>
<p>注:如果对整个仓库做全量检查,老项目可能产生几百个 Warning——这些"历史债务"淹没了真正需要关注的新问题。增量模式让团队专注在本次改动上。</p>
</div>
<!-- B.5 -->
<h3 id="s5e">B.5 知识沉淀:文档补全 + 记忆更新(10 分钟)</h3>
<p>老项目的知识往往在"老人"的脑子里。每次修改都是<strong>将隐性知识显性化</strong>的机会。</p>
<div class="table-wrap">
<table>
<tr><th style="width:12%;">沉淀内容</th><th style="width:30%;">操作</th><th>示例</th></tr>
<tr><td><strong>ADR</strong></td><td>对 Claude Code 说:"生成 ADR:在遗留 MES 系统中集成 Flowable 审批流。格式:上下文→决策→后果→备选方案"</td><td>为什么选 Flowable 而不是自研状态机?因为项目已有 Flowable 依赖(历史原因),且审批流复杂度已超出状态机能处理的范围</td></tr>
<tr><td><strong>隐式约定文档化</strong></td><td>对 Claude Code 说:"把今天发现的隐式约定写入 docs/architecture/implicit-rules.md"</td><td>"工单状态字段是 String 类型,但只有 5 个合法值(DRAFT/RELEASED/IN_PROGRESS/COMPLETED/CANCELLED),虽然数据库没有 CHECK 约束"</td></tr>
<tr><td><strong>更新 CLAUDE.md</strong></td><td>对 Claude Code 说:"在 CLAUDE.md 中补充:工单模块的状态流转已改为审批流驱动,修改工单状态必须通过 ApprovalService,禁止直接 update work_order 表"</td><td>CLAUDE.md 新增一条规则 → 下次 Claude Code 修改这个模块时会自动遵守</td></tr>
<tr><td><strong>个人记忆</strong></td><td>对 Claude Code 说:"帮我记住:① MES 系统的 work_order 表用了 GBK 编码(历史原因),写 SQL 时注意 ② 生产环境的 work_order 表有 2000 万行,任何 DDL 操作都需要在凌晨 2-4 点执行"</td><td>Memory → 下次改这个系统时自动加载</td></tr>
</table>
</div>
<div class="box box-idea">
<h4>🔑 老项目知识沉淀的"1% 原则"</h4>
<p>每次修改,至少将 <strong>1 个隐式约定</strong>写下来(ADR/CLAUDE.md/注释/文档)。不要追求一次性补全所有文档——这做不到。但每次改代码时顺手补一个约定,一年后这个项目的文档覆盖率将远超行业平均水平。</p>
</div>
</section>
<!-- ===== 六、工具链配置速查 ===== -->
<section id="s6">
<h2>六、工具链配置速查</h2>
<div class="table-wrap">
<div class="table-caption">表:双轨工作流的工具配置差异</div>
<table>
<tr><th style="width:14%;">配置项</th><th style="width:38%;">🆕 新项目</th><th style="width:38%;">🔧 老项目</th></tr>
<tr><td><strong>CLAUDE.md</strong></td><td>脚手架自带,含完整编码规范 + 架构约定 + Git 工作流</td><td>需手动创建,至少包含:项目技术栈、非标准约定、已知坑点清单</td></tr>
<tr><td><strong>open-code-review</strong></td><td>全量检查模式(<code>filter=all</code>),从第一次提交即启用</td><td>增量检查模式(<code>filter=changed</code>, <code>baseline=main</code>),避免历史债务噪音</td></tr>
<tr><td><strong>DeepSeek</strong></td><td>仅作为架构方案的"反方辩手"(与 Claude Code 并行评审)</td><td>作为"代码考古学家":批量分析模块依赖、识别死代码和 God Class</td></tr>
<tr><td><strong>Qwen</strong></td><td>处理超长招标/需求文档(百万 Token 窗口)</td><td>解读遗留模块:一次性加载全部源码 + Commit 历史,输出模块职责描述</td></tr>
<tr><td><strong>Claude Code Memory</strong></td><td>记录新发现的通用模式(供未来项目复用)</td><td>记录该项目的隐式约定和踩坑经验(供后续维护者使用)</td></tr>
<tr><td><strong>CI 流水线</strong></td><td>脚手架自带完整 CIlint → test → build → deploy</td><td>在现有 CI 中新增 open-code-review 步骤(不影响现有步骤)</td></tr>
</table>
</div>
</section>
<!-- ===== 七、落地建议 ===== -->
<section id="s7">
<h2>七、落地建议:从哪类项目开始</h2>
<div class="table-wrap">
<div class="table-caption">表:建议的推行顺序</div>
<table>
<tr><th style="width:8%;">阶段</th><th style="width:12%;">项目类型</th><th style="width:18%;">动作</th><th>原因</th></tr>
<tr><td><span class="tag tag-blue">第 1-2 周</span></td><td><strong>新项目(POC</strong></td><td>选一个内部工具/POC 项目,用 Part A 全流程跑一遍</td><td>新项目风险低、AI 占比高、可见效快。适合建立团队信心</td></tr>
<tr><td><span class="tag tag-blue">第 3-4 周</span></td><td><strong>新项目(客户交付)</strong></td><td>选一个正式客户新项目,严格走 Part A 流程</td><td>验证脚手架和流程在真实交付压力下是否可行</td></tr>
<tr><td><span class="tag tag-warn">第 5-6 周</span></td><td><strong>老项目(小改动)</strong></td><td>选一个 Bug 修复或小规模功能增强,走 Part B 流程</td><td>先在小改动上验证"考古→影响分析→小步修改"模式</td></tr>
<tr><td><span class="tag tag-warn">第 7-8 周</span></td><td><strong>老项目(中改动)</strong></td><td>选一个 3-5 文件、<500 diff 的功能增强</td><td>验证小步提交和回归验证流程的有效性</td></tr>
<tr><td><span class="tag tag-red">第 9-12 周</span></td><td><strong>全面推广</strong></td><td>所有新项目默认走 Part A,所有老项目改动默认走 Part B</td><td>流程已验证,进入常态化</td></tr>
</table>
</div>
<div class="box box-warn">
<h4>⚠️ 不建议从老项目大改动开始</h4>
<p>AI 辅助开发最容易失败的模式:<strong>在没人完全理解的 10 年老系统上,让 AI 做一个涉及 20+ 个文件的"大重构"</strong>。这不是 AI 的问题——人类在这个场景下也会失败。</p>
<p>正确的顺序:先在新项目上建立信心(Part A),再在小改动上验证老项目模式(Part B 的小步),最后才挑战复杂改动。</p>
</div>
</section>
<div class="footer">
<p>研发型企业 AI 转型方案 · 第五篇章:AI 驱动开发流程 V2.0 — 新项目脚手架驱动 + 老项目维护双轨制</p>
<p>编制:大客户及解决方案中心 · 2026 年 5 月 · V2.0</p>
<p style="margin-top:8px;font-size:11px;">工具链版本:Claude Code(主力 Agent)· DeepSeek API · 通义千问(百炼)· alibaba-group/open-code-review · Claude Memory</p>
</div>
</main>
<button class="back-to-top" id="backToTop" aria-label="返回顶部"></button>
<script>
(function(){
var menuBtn=document.getElementById('menuBtn');
var overlay=document.getElementById('drawerOverlay');
var sidebar=document.querySelector('.sidebar');
if(menuBtn&&overlay&&sidebar){
function setup(){if(window.innerWidth<=768){if(!overlay.contains(sidebar))overlay.appendChild(sidebar);}else{if(overlay.contains(sidebar))document.body.insertBefore(sidebar,document.querySelector('.main'));overlay.classList.remove('show');document.body.style.overflow='';}}
setup();window.addEventListener('resize',setup);
menuBtn.addEventListener('click',function(){overlay.classList.add('show');document.body.style.overflow='hidden';});
overlay.addEventListener('click',function(e){if(e.target===overlay){overlay.classList.remove('show');document.body.style.overflow='';}});
sidebar.querySelectorAll('a').forEach(function(l){l.addEventListener('click',function(){if(window.innerWidth<=768){overlay.classList.remove('show');document.body.style.overflow='';}});});
}
var btt=document.getElementById('backToTop');
if(btt){window.addEventListener('scroll',function(){btt.classList.toggle('show',window.scrollY>400);});btt.addEventListener('click',function(){window.scrollTo({top:0,behavior:'smooth'});});}
var links=document.querySelectorAll('.sidebar nav a');
var secs=[];links.forEach(function(l){var id=l.getAttribute('href');if(id&&id.startsWith('#')){var el=document.querySelector(id);if(el)secs.push({el:el,link:l});}});
function onScroll(){var sy=window.scrollY+120;var cur=null;for(var i=0;i<secs.length;i++){if(secs[i].el.offsetTop<=sy)cur=secs[i];}links.forEach(function(l){l.classList.remove('active');});if(cur)cur.link.classList.add('active');}
window.addEventListener('scroll',onScroll);
document.querySelectorAll('.sidebar nav a').forEach(function(l){l.addEventListener('click',function(e){e.preventDefault();var id=this.getAttribute('href');if(id&&id.startsWith('#')){var el=document.querySelector(id);if(el){el.scrollIntoView({behavior:'smooth'});if(window.innerWidth<=768){var o=document.getElementById('drawerOverlay');if(o)o.classList.remove('show');document.body.style.overflow='';}}}});});
})();
</script>
</body>
</html>