1316 lines
88 KiB
HTML
1316 lines
88 KiB
HTML
<!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: #767676;
|
||
--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(新项目) 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<T> 统一返回体、PageQuery 分页基类、GlobalExceptionHandler、AuthInterceptor</td>
|
||
<td>生成的每个 Controller 必须继承 BaseController、每个 Service 必须继承 BaseService、返回类型必须是 Result<T>。基类 = 代码的"法律"</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="tag tag-purple">L3</span></td>
|
||
<td><strong>规范文件</strong></td>
|
||
<td>CLAUDE.md(编码规范+架构约定+Git 工作流)、.claude/design-tokens.md(UI 设计规范)、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>一个完整的 UserModule(Entity → 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-review(L1)和人工 Review(L3)的操作界面</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>
|
||
<span class="kw">push</span>:<br>
|
||
<span class="kw">branches</span>: [main, develop]<br>
|
||
<span class="kw">pull_request</span>:<br>
|
||
<span class="kw">branches</span>: [main]<br>
|
||
<br>
|
||
<span class="kw">jobs</span>:<br>
|
||
<span class="cm"># Job 1: 代码规范检查</span><br>
|
||
<span class="kw">lint</span>:<br>
|
||
<span class="kw">runs-on</span>: ubuntu-latest<br>
|
||
<span class="kw">steps</span>:<br>
|
||
- <span class="kw">uses</span>: actions/checkout@v4<br>
|
||
- <span class="kw">uses</span>: alibaba-group/open-code-review@v1<br>
|
||
<span class="kw">with</span>:<br>
|
||
<span class="kw">languages</span>: <span class="str">java,javascript,typescript,vue</span><br>
|
||
<span class="kw">severity</span>: <span class="str">error,warning</span><br>
|
||
<span class="kw">filter</span>: <span class="str">changed</span><br>
|
||
<br>
|
||
<span class="cm"># Job 2: 构建 + 单元测试</span><br>
|
||
<span class="kw">build</span>:<br>
|
||
<span class="kw">needs</span>: lint<br>
|
||
<span class="kw">runs-on</span>: ubuntu-latest<br>
|
||
<span class="kw">services</span>:<br>
|
||
<span class="kw">mysql</span>:<br>
|
||
<span class="kw">image</span>: harbor.internal.com/library/mysql:8.0<br>
|
||
<span class="kw">env</span>:<br>
|
||
<span class="kw">MYSQL_ROOT_PASSWORD</span>: test123<br>
|
||
<span class="kw">steps</span>:<br>
|
||
- <span class="kw">uses</span>: actions/checkout@v4<br>
|
||
- <span class="kw">name</span>: Build & Test<br>
|
||
<span class="kw">run</span>: mvn -s .gitea/settings.xml clean test<br>
|
||
<br>
|
||
<span class="cm"># Job 3: 构建镜像 + 推送</span><br>
|
||
<span class="kw">docker</span>:<br>
|
||
<span class="kw">needs</span>: build<br>
|
||
<span class="kw">if</span>: github.ref == 'refs/heads/main'<br>
|
||
<span class="kw">steps</span>:<br>
|
||
- <span class="kw">name</span>: Build & Push Image<br>
|
||
<span class="kw">run</span>: |<br>
|
||
docker build -t harbor.internal.com/${{ github.repository }}:latest .<br>
|
||
docker push harbor.internal.com/${{ github.repository }}: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>
|
||
<span class="kw">gitea</span>:<br>
|
||
<span class="kw">image</span>: gitea/gitea:latest<br>
|
||
<span class="kw">container_name</span>: gitea<br>
|
||
<span class="kw">environment</span>:<br>
|
||
- USER_UID=1000<br>
|
||
- USER_GID=1000<br>
|
||
- GITEA__database__DB_TYPE=mysql<br>
|
||
- GITEA__database__HOST=mysql:3306<br>
|
||
- GITEA__database__NAME=gitea<br>
|
||
- GITEA__database__USER=gitea<br>
|
||
- GITEA__database__PASSWD=gitea123<br>
|
||
- GITEA__server__DOMAIN=gitea.internal.com<br>
|
||
- GITEA__server__ROOT_URL=https://gitea.internal.com<br>
|
||
- GITEA__actions__ENABLED=true<br>
|
||
<span class="kw">ports</span>:<br>
|
||
- <span class="str">"3000:3000"</span> <span class="cm"># Web UI</span><br>
|
||
- <span class="str">"2222:22"</span> <span class="cm"># SSH Git 克隆</span><br>
|
||
<span class="kw">volumes</span>:<br>
|
||
- /data/gitea:/data<br>
|
||
- /etc/timezone:/etc/timezone:ro<br>
|
||
<span class="kw">depends_on</span>:<br>
|
||
- mysql<br>
|
||
<br>
|
||
<span class="kw">mysql</span>:<br>
|
||
<span class="kw">image</span>: mysql:8.0<br>
|
||
<span class="kw">environment</span>:<br>
|
||
- MYSQL_ROOT_PASSWORD=root123<br>
|
||
- MYSQL_DATABASE=gitea<br>
|
||
- MYSQL_USER=gitea<br>
|
||
- MYSQL_PASSWORD=gitea123<br>
|
||
<span class="kw">volumes</span>:<br>
|
||
- /data/gitea-mysql:/var/lib/mysql<br>
|
||
<br>
|
||
<span class="kw">redis</span>:<br>
|
||
<span class="kw">image</span>: redis:7-alpine<br>
|
||
<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 Runner(1 个 linux/amd64 + 1 个用于前端构建)</td><td>Runner 是执行 CI Job 的工作节点。注册命令:<code>./act_runner register --instance https://gitea.internal.com --token <TOKEN></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>Verdaccio(npm.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> 到 Harbor;K8s 的 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>
|
||
-p 4873:4873 \<br>
|
||
-v /data/verdaccio/storage:/verdaccio/storage \<br>
|
||
-v /data/verdaccio/config:/verdaccio/conf \<br>
|
||
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>
|
||
<span class="kw">verdaccio</span>:<br>
|
||
<span class="kw">image</span>: verdaccio/verdaccio:latest<br>
|
||
<span class="kw">container_name</span>: verdaccio<br>
|
||
<span class="kw">ports</span>:<br>
|
||
- <span class="str">"4873:4873"</span><br>
|
||
<span class="kw">volumes</span>:<br>
|
||
- /data/verdaccio/storage:/verdaccio/storage<br>
|
||
- /data/verdaccio/conf:/verdaccio/conf<br>
|
||
- ./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>
|
||
<span class="kw">npmjs</span>:<br>
|
||
<span class="kw">url</span>: https://registry.npmmirror.com/ <span class="cm"># 阿里云镜像</span><br>
|
||
<span class="kw">packages</span>:<br>
|
||
<span class="str">'@mycompany/*'</span>:<br>
|
||
<span class="kw">access</span>: $all<br>
|
||
<span class="kw">publish</span>: $authenticated <span class="cm"># 仅登录用户可发布私有包</span><br>
|
||
<span class="str">'**'</span>:<br>
|
||
<span class="kw">access</span>: $all<br>
|
||
<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> 文件,指向内部 Verdaccio(npm.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>
|
||
<span class="kw">mysql</span>:<br>
|
||
<span class="kw">image</span>: harbor.internal.com/library/mysql:8.0<br>
|
||
<span class="kw">environment</span>:<br>
|
||
<span class="kw">MYSQL_ROOT_PASSWORD</span>: dev123<br>
|
||
<span class="kw">MYSQL_DATABASE</span>: srm_dev<br>
|
||
<span class="kw">ports</span>: [<span class="str">"3306:3306"</span>]<br>
|
||
<span class="kw">volumes</span>: [<span class="str">"./.gitea/init.sql:/docker-entrypoint-initdb.d/init.sql"</span>]<br>
|
||
<br>
|
||
<span class="kw">redis</span>:<br>
|
||
<span class="kw">image</span>: harbor.internal.com/library/redis:7-alpine<br>
|
||
<span class="kw">ports</span>: [<span class="str">"6379:6379"</span>]<br>
|
||
<br>
|
||
<span class="kw">minio</span>:<br>
|
||
<span class="kw">image</span>: harbor.internal.com/library/minio:latest<br>
|
||
<span class="kw">environment</span>:<br>
|
||
<span class="kw">MINIO_ROOT_USER</span>: minioadmin<br>
|
||
<span class="kw">MINIO_ROOT_PASSWORD</span>: minioadmin<br>
|
||
<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 构建的镜像推送到 Harbor,K8s 从 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:"老项目的数据库没有 Flyway,Schema 是手管的"</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>
|
||
读取需求文档,将功能拆解为独立模块。每个模块标注:<br>
|
||
- 是否可以直接复用脚手架模式(如 CRUD 类模块参照 UserModule)<br>
|
||
- 是否需要新增脚手架不包含的能力(如审批流、文件上传)<br>
|
||
- 预估需要多少 Entity / Service / Controller / 前端页面<br>
|
||
<br>
|
||
<span class="kw">2. 模块优先级排序</span><br>
|
||
按依赖关系和交付价值排列开发顺序<br>
|
||
<br>
|
||
<span class="kw">3. 输出开发计划</span><br>
|
||
生成 docs/plan/module-plan.md,包含:<br>
|
||
- 模块清单 + 复用度评估 + 开发顺序<br>
|
||
- 每个模块与 UserModule 的差异点(只需描述"不同之处")<br>
|
||
- 需要脚手架新增的通用能力(如审批流引擎)<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>
|
||
READ: entity/User.java, entity/BaseEntity.java<br>
|
||
WRITE: entity/Supplier.java (extends BaseEntity, add supplierCategory)<br>
|
||
WRITE: mapper/SupplierMapper.java (extends BaseMapper<Supplier>)<br>
|
||
WRITE: src/main/resources/db/migration/V1.1__supplier.sql<br>
|
||
<br>
|
||
<span class="kw">Step 2 - 业务层</span>:<br>
|
||
READ: service/UserService.java<br>
|
||
WRITE: service/SupplierService.java (extends BaseService<Supplier>)<br>
|
||
WRITE: dto/SupplierQuery.java (extends PageQuery, add category/status)<br>
|
||
WRITE: dto/SupplierDTO.java<br>
|
||
<br>
|
||
<span class="kw">Step 3 - 接口层</span>:<br>
|
||
READ: controller/UserController.java<br>
|
||
WRITE: controller/SupplierController.java (extends BaseController)<br>
|
||
接口: GET /api/suppliers (分页), GET /api/suppliers/{id},<br>
|
||
POST /api/suppliers, PUT /api/suppliers/{id}, DELETE /api/suppliers/{id}<br>
|
||
<br>
|
||
<span class="kw">Step 4 - 文件上传</span>:<br>
|
||
脚手架缺少文件上传能力。计划:<br>
|
||
WRITE: config/FileUploadConfig.java<br>
|
||
WRITE: util/FileUploadUtil.java<br>
|
||
WRITE: controller/FileController.java<br>
|
||
(此为通用能力,放在 common 包下,未来其他模块可复用)<br>
|
||
<br>
|
||
<span class="kw">Step 5 - 前端</span>:<br>
|
||
READ: vue/views/user/UserList.vue<br>
|
||
WRITE: vue/views/supplier/SupplierList.vue<br>
|
||
WRITE: vue/views/supplier/SupplierForm.vue<br>
|
||
WRITE: vue/api/supplier.js<br>
|
||
<br>
|
||
<span class="kw">Step 6 - 测试</span>:<br>
|
||
READ: test/.../UserServiceTest.java<br>
|
||
WRITE: test/.../SupplierServiceTest.java<br>
|
||
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<T> 包装,异常不要 try-catch(交给 GlobalExceptionHandler)"</td></tr>
|
||
<tr><td><strong>给出参照</strong></td><td>"加个供应商列表页面"</td><td>"加 SupplierList.vue,表格列、搜索栏、分页组件的用法参照 UserList.vue 的写法,用相同的 <code><page-table></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>陷阱 1:AI 绕过基类。</strong>Claude Code 有时会"忘记"继承 BaseController/BaseService,自己写一套。开发者发现后应立即纠正:"请继承 BaseController,不要自己写异常处理"。纠正 2-3 次后,AI 会形成习惯。</p>
|
||
<p><strong>陷阱 2:AI 发明新的返回格式。</strong>脚手架统一用 Result<T>,但 AI 可能返回 Map 或自定义对象。纠正方式:"所有接口返回值必须是 Result<T>,参照 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>
|
||
<span class="kw">private final</span> SupplierService <span class="fn">supplierService</span>;<br>
|
||
<br>
|
||
<span class="kw">@GetMapping</span><br>
|
||
<span class="kw">public</span> Result<PageResult<SupplierDTO>> <span class="fn">list</span>(<span class="kw">@Valid</span> SupplierQuery query) {<br>
|
||
<span class="kw">return</span> Result.success(supplierService.page(query));<br>
|
||
}<br>
|
||
<br>
|
||
<span class="kw">@GetMapping</span>(<span class="str">"/{id}"</span>)<br>
|
||
<span class="kw">public</span> Result<SupplierDTO> <span class="fn">getById</span>(<span class="kw">@PathVariable</span> Long id) {<br>
|
||
<span class="kw">return</span> Result.success(supplierService.getDetailById(id));<br>
|
||
}<br>
|
||
<br>
|
||
<span class="kw">@PostMapping</span><br>
|
||
<span class="kw">public</span> Result<Long> <span class="fn">create</span>(<span class="kw">@Valid @RequestBody</span> SupplierCreateDTO dto) {<br>
|
||
<span class="kw">return</span> Result.success(supplierService.create(dto));<br>
|
||
}<br>
|
||
<br>
|
||
<span class="kw">@PutMapping</span>(<span class="str">"/{id}"</span>)<br>
|
||
<span class="kw">public</span> Result<Void> <span class="fn">update</span>(<span class="kw">@PathVariable</span> Long id, <span class="kw">@Valid @RequestBody</span> SupplierUpdateDTO dto) {<br>
|
||
supplierService.update(id, dto);<br>
|
||
<span class="kw">return</span> Result.success();<br>
|
||
}<br>
|
||
}
|
||
<span class="cm">// 注意:无 try-catch(由 BaseController 的 GlobalExceptionHandler 统一处理)</span><br>
|
||
<span class="cm">// 注意:所有返回值用 Result<T> 包装(与 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<T>?</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.md(Markdown 表格格式)"</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 考古 Prompt(L1)</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 深层解读 Prompt(L2)</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>
|
||
状态转换的触发条件是什么?<br>
|
||
3. <span class="kw">隐式约定</span>:代码中有哪些"大家都懂但没写文档"的规则?<br>
|
||
(例如:工单状态字段虽然存的是 String,但只有 4 个合法值)<br>
|
||
4. <span class="kw">已知坑点</span>:从 Commit Message 中分析,最近修复了哪些 Bug?<br>
|
||
这些 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>
|
||
先告诉我,不要强行 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 main(4 个 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>
|
||
<span class="kw">with</span>:<br>
|
||
<span class="kw">languages</span>: <span class="str">java,javascript</span><br>
|
||
<span class="kw">severity</span>: <span class="str">error,warning</span><br>
|
||
<span class="kw">filter</span>: <span class="str">changed</span> <span class="cm"># ← 关键:只检查本次 diff 的文件</span><br>
|
||
<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>脚手架自带完整 CI(lint → 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> |