-
嘉欣猎头公司管理系统:码道驱动,智能匹配一、概述1.1 案例介绍本案例采用华为云码道(CodeArts)代码智能体作为核心开发工具,从零构建一个互联网行业猎头公司管理系统。系统面向猎头顾问、软件工程师、企业HR三类角色,实现了工程师信息管理、公司职位管理、智能匹配推荐、面试流程状态机、职业轨迹追踪等核心功能。开发过程采用V1快速原型→V2功能完善→V3亮点打磨的三轮迭代模式,全程使用码道代码智能体辅助开发,充分展示了码道在项目骨架生成、代码续写、智能问答、SDD规范驱动开发等场景下的实践应用。代码仓库:https://gitcode.com/2301_78976454/headhunter-management-system在线演示:http://1.95.91.47/(测试账号:headhunter/123456、zhangsan/123456、huawei_hr/123456)1.2 适用对象高校学生个人开发者企业开发者1.3 案例时间本案例总时长预计120分钟(不含环境安装时间)。1.4 案例流程说明:环境准备:安装华为云码道(CodeArts)代码智能体、Node.js、MySQL;V1快速原型:使用码道生成项目骨架,完成5张核心表+基础CRUD+简单匹配推荐;V2功能完善:新增JWT认证+三角色权限、面试流程状态机、职业轨迹、多维度匹配算法;V3亮点打磨:集成ECharts数据仪表盘、匹配度雷达图、职位对比、通知中心;部署上线:部署至华为云ECS,提供可访问的演示环境。1.5 资源总览本案例预计花费0元(使用免费资源即可完成开发)。如需部署到华为云ECS,预计花费约0.6元/小时。体验完成后请及时释放资源,避免产生多余的费用。资源名称规格单价(元)华为云码道(CodeArts)代码智能体通用体验版免费Node.jsv22.x免费MySQL8.0+免费弹性云服务器ECS(可选,用于部署)2 vCPUs 4GiB0.6/小时二、环境和资源准备2.1 安装华为云码道(CodeArts)代码智能体访问华为云码道下载页面,下载并安装码道代码智能体。安装完成后,使用华为云账号登录。2.2 安装Node.js开发环境访问Node.js官网 下载并安装LTS版本(建议v22.x)。安装完成后,在终端验证:node --version npm --version 2.3 安装MySQL数据库安装MySQL 8.0及以上版本,并确保root用户可正常登录。创建项目数据库:mysql -u root -p CREATE DATABASE IF NOT EXISTS headhunter_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 2.4 完成码道CodeArts实战速成考试访问码道CodeArts实战速成考试,完成在线学习并通过考试,获取通过证书。三、构建嘉欣猎头公司管理系统3.1 项目结构说明本项目采用前后端分离架构,后端使用Node.js + Express + Sequelize + MySQL,前端使用Vue3 + Vite + Element Plus + ECharts。project30/ ├── sql/ │ └── init.sql # 数据库建表+示例数据脚本 ├── backend/ │ ├── package.json # 后端依赖配置 │ └── src/ │ ├── app.js # Express入口,路由注册 │ ├── config/ │ │ └── database.js # MySQL数据库连接配置 │ ├── middleware/ │ │ └── auth.js # JWT认证中间件+角色权限控制 │ ├── models/ │ │ ├── index.js # 模型统一导出 │ │ ├── User.js # 用户模型(三角色) │ │ ├── Engineer.js # 软件工程师模型 │ │ ├── Company.js # 互联网公司模型 │ │ ├── Department.js # 部门模型 │ │ ├── Position.js # 职位模型 │ │ ├── Recommendation.js # 推荐记录模型 │ │ ├── InterviewProcess.js # 面试流程模型 │ │ └── CareerHistory.js # 职业轨迹模型 │ └── routes/ │ ├── auth.js # 登录/注册/个人信息 │ ├── engineer.js # 工程师CRUD+按姓名搜索+职业查询 │ ├── company.js # 公司CRUD+已招聘查询 │ ├── department.js # 部门CRUD │ ├── position.js # 职位CRUD+搜索 │ ├── recommendation.js # 推荐+智能匹配 │ ├── interview.js # 面试流程+看板 │ └── career.js # 职业轨迹CRUD ├── frontend/ │ ├── package.json # 前端依赖配置 │ ├── vite.config.js # Vite配置+API代理 │ ├── index.html # 入口HTML │ └── src/ │ ├── main.js # Vue3入口 │ ├── App.vue # 根组件 │ ├── api/ │ │ ├── request.js # Axios封装+JWT拦截器 │ │ └── index.js # 全部API接口定义 │ ├── router/ │ │ └── index.js # 路由配置+角色守卫 │ ├── components/ │ │ └── NotificationCenter.vue # 通知中心组件 │ ├── layouts/ │ │ ├── HeadhunterLayout.vue # 猎头顾问布局 │ │ ├── EngineerLayout.vue # 工程师布局 │ │ └── HrLayout.vue # 企业HR布局 │ └── views/ │ ├── LoginView.vue # 登录/注册页 │ ├── headhunter/ # 猎头端7个页面(含信息查询) │ ├── engineer/ # 工程师端6个页面 │ └── hr/ # HR端4个页面项目源码已上传至GitCode,可通过以下命令下载到本地:git clone https://gitcode.com/2301_78976454/headhunter-management-system.git3.2 V1快速原型:搭建核心链路3.2.1 使用码道创建项目骨架在码道IDE中,打开终端,创建项目目录并初始化后端:mkdir project30 && cd project30 mkdir sql backend frontend cd backend && npm init -y 使用码道智能问答功能,输入提示词:“帮我创建一个Express + Sequelize + MySQL的后端项目骨架,包含5个模型:Engineer、Company、Department、Position、Recommendation”码道会自动生成模型文件和基础路由代码,我们在此基础上进行修改。3.2.2 数据库设计与初始化使用码道辅助编写SQL建表脚本,核心5张表设计如下:CREATE TABLE engineer ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT '姓名', age INT COMMENT '年龄', gender VARCHAR(10) COMMENT '性别', current_company VARCHAR(100) COMMENT '现工作公司', current_salary DECIMAL(10,2) COMMENT '现薪水(元/月)', current_position VARCHAR(100) COMMENT '现职务', expected_salary DECIMAL(10,2) COMMENT '期望薪水(元/月)', skills VARCHAR(500) COMMENT '擅长技能,逗号分隔', expected_city VARCHAR(50) COMMENT '期望城市', open_to_headhunter TINYINT DEFAULT 1 COMMENT '是否接受猎头推荐', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT '软件工程师表'; 执行初始化脚本:mysql -u root -p < sql/init.sql3.2.3 后端核心路由以推荐路由为例,V1实现了简单的技能+薪资+城市匹配算法:function calcMatchScore(engineer, position) { let score = 0; const eSkills = (engineer.skills || '').split(',').map(s => s.trim().toLowerCase()); const pSkills = (position.required_skills || '').split(',').map(s => s.trim().toLowerCase()); if (eSkills.length > 0 && pSkills.length > 0) { const matched = pSkills.filter(ps => eSkills.some(es => es.includes(ps) || ps.includes(es))); score += (matched.length / pSkills.length) * 50; } if (engineer.expected_salary >= position.salary_min && engineer.expected_salary <= position.salary_max) { score += 30; } if (position.location.includes(engineer.expected_city)) { score += 20; } return Math.min(100, Math.round(score * 100) / 100); } 3.2.4 前端基础页面使用码道代码续写功能,快速生成Vue3 + Element Plus的CRUD页面。V1阶段共6个页面:工作台、工程师管理、公司管理、职位管理、推荐管理、信息查询。3.2.5 V1验证启动后端和前端服务:# 后端 cd backend && npm install && npm run dev # 前端(需在纯英文路径下运行) cd frontend && npm install && npm run devV1交付标准:工程师信息增删改查、公司→部门→职位层级管理、猎头推送推荐+工程师接受/拒绝、按公司/按人双向查询。3.3 V2功能完善:满足全部硬性要求3.3.1 JWT三角色认证新增User模型和auth中间件,实现猎头/工程师/企业HR三角色认证:const jwt = require('jsonwebtoken'); const SECRET = 'jiaxin_headhunter_2026'; function authMiddleware(req, res, next) { const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) return res.status(401).json({ code: 1, msg: '未登录' }); try { req.user = jwt.verify(token, SECRET); next(); } catch { res.status(401).json({ code: 1, msg: 'token无效或已过期' }); } } function roleMiddleware(...roles) { return (req, res, next) => { if (!roles.includes(req.user.role)) return res.status(403).json({ code: 1, msg: '无权限' }); next(); }; } 3.3.2 面试流程状态机实现6状态状态机:推荐(recommended) → 确认(confirmed) → 面试(interviewing) → 发Offer(offered) → 入职(onboarded) 或 失败(failed):const VALID_TRANSITIONS = { recommended: ['confirmed', 'failed'], confirmed: ['interviewing', 'failed'], interviewing: ['offered', 'failed'], offered: ['onboarded', 'failed'], onboarded: [], failed: [] }; InterviewProcess.canTransitionTo = function (currentStatus, newStatus) { return VALID_TRANSITIONS[currentStatus]?.includes(newStatus) || false; }; 当状态变为onboarded时,自动更新工程师的当前公司和职位,并写入职业轨迹记录。3.3.3 多维度加权匹配算法将V1的简单匹配升级为分项评分(技能50分+薪资30分+城市20分):function calcMatchDetail(engineer, position) { let skillScore = 0, salaryScore = 0, cityScore = 0; // 技能匹配(满分50分) const eSkills = (engineer.skills || '').split(',').map(s => s.trim().toLowerCase()).filter(Boolean); const pSkills = (position.required_skills || '').split(',').map(s => s.trim().toLowerCase()).filter(Boolean); if (eSkills.length > 0 && pSkills.length > 0) { const matched = pSkills.filter(ps => eSkills.some(es => es.includes(ps) || ps.includes(es))); skillScore = (matched.length / pSkills.length) * 50; } // 薪资匹配(满分30分) if (engineer.expected_salary && position.salary_min && position.salary_max) { const mid = (Number(position.salary_min) + Number(position.salary_max)) / 2; const diff = Math.abs(Number(engineer.expected_salary) - mid) / mid; if (diff <= 0.1) salaryScore = 30; else if (diff <= 0.2) salaryScore = 25; else if (diff <= 0.3) salaryScore = 20; else salaryScore = 10; } // 城市匹配(满分20分) if (engineer.expected_city && position.location) { if (position.location.includes(engineer.expected_city)) cityScore = 20; } const total = Math.min(100, Math.round((skillScore + salaryScore + cityScore) * 100) / 100); return { total, skill_score: skillScore, salary_score: salaryScore, city_score: cityScore }; } 3.3.4 三角色独立界面V2将V1的单页面Tab切换升级为三角色独立布局:猎头顾问:深蓝侧边栏(#1a1a2e),包含工作台、人才库、职位库、智能匹配、面试看板、数据统计、信息查询软件工程师:靛蓝侧边栏(#0f3460),包含首页、个人档案、推荐职位、职位对比、面试记录、职业轨迹企业HR:紫色侧边栏(#533483),包含招聘概览、职位管理、候选人、已录用3.3.5 V2验证V2交付标准:三角色JWT认证与权限隔离、面试全流程状态流转、多维度智能匹配推荐、跳槽后按公司/按人双向查询(课题硬性要求✅)、工程师职业轨迹展示。3.3.6 自检修复:满足课题硬性要求对照课题30的硬性要求进行自检,发现并修复了以下问题:问题1:每个部门至少3个职位原始示例数据仅11个职位,部分部门不足3个。补充SQL示例数据至30个职位,确保10个部门每个至少3个职位:-- 示例:技术部补充职位(已有3个,此处展示格式) INSERT INTO position (title, department_id, ...) VALUES ('全栈工程师', 1, ...), ('DevOps工程师', 1, ...), ('数据开发工程师', 1, ...); 问题2:按工程师姓名查找职业轨迹原仅支持按工程师ID查询,新增按姓名模糊搜索API:// backend/src/routes/engineer.js - 新增按姓名搜索路由 router.get('/search/name/:name', async (req, res) => { const engineers = await Engineer.findAll({ where: { name: { [Op.like]: `%${req.params.name}%` } } }); res.json({ code: 0, data: engineers }); }); 前端查询页面同步升级,支持"按ID"和"按姓名"两种搜索模式,按姓名搜索时展示匹配工程师列表,可展开查看完整职业轨迹时间线。注意:Express路由注册顺序中,/search/name/:name 必须在 /:id 之前注册,否则会被参数路由拦截。3.4 V3亮点打磨:冲击满分3.4.1 ECharts数据统计仪表盘在猎头端新增数据统计页面,使用ECharts实现6个可视化图表:// 技能分布柱状图 skillChart.setOption({ xAxis: { type: 'category', data: d.topSkills.map(i => i.name) }, yAxis: { type: 'value', name: '人数' }, series: [{ type: 'bar', data: d.topSkills.map(i => i.value), itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: '#409eff' }, { offset: 1, color: '#79bbff' } ])} }] }); 6个图表覆盖:热门技能TOP10柱状图、期望城市饼图、期望薪资玫瑰图、面试状态环形图、公司招聘横向柱图、职位薪资热力图。3.4.2 匹配度雷达图在智能匹配页面,为每个推荐结果生成ECharts雷达图,直观展示技能/薪资/城市三维匹配情况:chart.setOption({ radar: { indicator: [ { name: '技能匹配', max: 50 }, { name: '薪资匹配', max: 30 }, { name: '城市匹配', max: 20 } ], shape: 'circle' }, series: [{ type: 'radar', data: [{ value: [item.skill_score, item.salary_score, item.city_score] }] }] }); 3.4.3 职位对比功能工程师端新增职位对比页面,可选择两个已接受的推荐职位并排对比,同时生成双雷达图叠加展示:series: [{ type: 'radar', data: [ { value: [...], name: '职位A', areaStyle: { color: 'rgba(64,158,255,0.15)' } }, { value: [...], name: '职位B', areaStyle: { color: 'rgba(103,194,58,0.15)' } } ] }] 3.4.4 通知中心实现基于轮询的通知中心组件,30秒自动刷新,三角色差异化通知:猎头:待处理推荐数、已入职人数工程师:新推荐数、待参加面试数HR:候选人接受数onMounted(() => { fetchNotifications() timer = setInterval(fetchNotifications, 30000) }) 3.4.5 后端统计API增强新增 /api/stats/dashboard 接口,一次请求返回6维度统计数据;新增 /api/stats/notifications 接口,按角色返回差异化通知。3.4.6 V3验证V3交付标准:ECharts数据仪表盘6图、匹配度雷达图、职位对比功能、通知中心轮询。3.4.7 系统运行效果上图展示了猎头顾问登录后的数据统计仪表盘,包含热门技能TOP10柱状图、期望城市饼图、期望薪资玫瑰图、面试状态环形图、公司招聘横向柱图、职位薪资热力图共6个可视化图表。3.5 部署至华为云ECS(可选)3.5.1 购买ECS弹性云服务器登录华为云控制台,购买ECS实例(2vCPUs 4GiB,Ubuntu 22.04),配置安全组开放80端口,购买弹性公网IP(按流量计费)。3.5.2 部署后端# 安装Node.js 22 curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash - sudo apt-get install -y nodejs # 安装PostgreSQL sudo apt-get install -y postgresql postgresql-contrib sudo systemctl start postgresql # 配置数据库 sudo -u postgres psql -c "ALTER USER postgres PASSWORD '123456';" sudo -u postgres psql -c "CREATE DATABASE headhunter_db;" # 下载项目代码 sudo apt-get install -y git cd /root && git clone https://gitcode.com/2301_78976454/headhunter-management-system.git # 导入数据库 cp /root/headhunter-management-system/sql/init_pg.sql /tmp/ sudo -u postgres psql -d headhunter_db -f /tmp/init_pg.sql # 安装后端依赖并启动 cd /root/headhunter-management-system/backend && npm install nohup node src/app.js > /root/backend.log 2>&1 & 3.5.3 部署前端# 构建前端 cd /root/headhunter-management-system/frontend sed -i '/esbuild-windows-64/d' package.json npm install && npm run build # 部署到nginx sudo mkdir -p /var/www/headhunter sudo cp -r dist/* /var/www/headhunter/ sudo chmod -R 755 /var/www/headhunter3.5.4 配置Nginxsudo apt-get install -y nginx创建Nginx配置文件 /etc/nginx/sites-available/headhunter:server { listen 80; server_name _; root /var/www/headhunter; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } sudo ln -sf /etc/nginx/sites-available/headhunter /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t && sudo systemctl restart nginx3.5.5 开放安全组端口在华为云控制台:ECS详情 → 安全组 → 入方向规则 → 添加规则:协议TCP,端口80,源地址0.0.0.0/0。3.6 系统测试3.6.1 演示环境系统已部署至华为云ECS,可通过以下地址访问:访问地址:http://1.95.91.47测试账号:角色用户名密码功能范围猎头顾问headhunter123456工作台、人才库、职位库、智能匹配、面试看板、数据统计、信息查询工程师zhangsan123456首页、个人档案、推荐职位、职位对比、面试记录、职业轨迹企业HRhuawei_hr123456招聘概览、职位管理、候选人、已录用3.6.2 功能测试用例编号测试功能操作步骤预期结果T01猎头登录输入headhunter/123456,选择猎头顾问,点击登录跳转到猎头工作台页面T02人才库管理点击"人才库",查看工程师列表显示8名工程师信息,支持按技能/城市/薪资筛选T03职位层级管理点击"职位库",展开公司→部门→职位显示5家公司、10个部门、30个职位的层级结构T04智能匹配推荐点击"智能匹配",选择工程师,点击"一键匹配"生成匹配推荐列表,显示匹配度评分和雷达图T05面试流程流转点击"面试看板",拖拽卡片变更状态状态按推荐→确认→面试→Offer→入职流转T06数据统计仪表盘点击"数据统计"显示6个ECharts图表(技能柱状图、城市饼图等)T07按姓名查询职业轨迹点击"信息查询",切换"按姓名",输入"张"模糊搜索出张三,展开查看职业轨迹时间线T08按公司查询已招聘在"信息查询"左侧,选择公司点击查询显示该公司已招聘工程师列表T09工程师登录输入zhangsan/123456,选择工程师跳转到工程师首页T10推荐职位响应工程师端点击"推荐职位",接受/拒绝推荐更新推荐状态,猎头端同步可见T11职位对比工程师端点击"职位对比",选择两个职位显示双雷达图叠加对比T12HR登录输入huawei_hr/123456,选择企业HR跳转到HR招聘概览T13候选人查看HR端点击"候选人"显示接受推荐的候选人列表T14通知中心任意角色登录后,点击右上角铃铛图标显示角色差异化通知,30秒自动刷新T15角色权限隔离猎头账号尝试访问/engineer路径自动重定向回/headhunter,无权限页面不可访问四、释放资源4.1 删除ECS弹性云服务器进入ECS列表,点击全选按钮,点击"更多 → 删除"。在对话框中选择"释放云服务器绑定的公网IP地址"和"删除云服务器挂载的数据盘",点击"是"。五、扩展资料说明华为云码道(CodeArts)代码智能体:https://codearts.huaweicloud.comVue3官方文档:https://cn.vuejs.orgElement Plus组件库:https://element-plus.org/zh-CNECharts数据可视化:https://echarts.apache.org/zh/index.htmlSequelize ORM文档:https://sequelize.orgExpress框架文档:https://expressjs.com
-
一、概述1.1 案例介绍随着校园、社区及公共场所人员流动增加,物品遗失与寻找需求日益普遍。传统失物招领方式通常依赖线下公告、微信群等渠道,存在信息分散、检索困难、匹配效率低等问题。为提升失物信息流转效率,本案例设计并开发了一个智能化失物招领平台,实现失物信息与招领信息的集中管理和便捷查询。本案例基于 AI Agent 自动化开发模式,利用华为开发者空间开发平台和华为云码道(CodeArts)代码智能体完成全流程应用构建。应用采用前后端分离架构,选择采用 Vue3 前端、Flask 后端、SQLite 数据库的技术栈进行开发。系统支持用户注册登录、失物信息发布、招领信息发布、物品图片上传、关键词搜索、分类筛选、详情查看、站内联系以及个人信息管理等核心功能,同时提供信息状态管理能力,帮助用户完成从信息发布到物品找回的完整业务流程。本案例构建的项目和文档已保存至GitCode,可自行下载源码。Demo演示视频技术选型:华为开发者空间开发平台 - 云开发环境(容器):华为云提供的一站式云上开发环境,支持多种主流开发语言和运行环境,开发者无需进行复杂的本地环境配置即可快速开展应用开发。本案例中选用云开发环境(容器)作为应用的开发与运行环境,为项目提供统一稳定的基础环境,避免因操作系统、依赖版本等环境差异导致的应用运行问题,提高项目构建和部署效率。华为云码道(CodeArts)代码智能体:华为云提供的智能化软件开发工具,融合代码大模型、AI IDE 和 Code Agent 等能力,能够理解项目需求并辅助完成代码生成、代码优化和工程构建。本案例中使用华为云码道(CodeArts)代码智能体作为核心开发辅助工具,根据失物招领应用需求完成前后端功能开发,加速 Web 应用构建过程,降低应用开发门槛。1.2 适用对象企业开发者个人开发者高校学生1.3 案例时间本案例总时长预计60分钟。1.4 案例流程说明:VSCode安装开发者空间插件,远程连接云开发环境(容器);云开发环境(容器)搭建华为云码道(CodeArts)代码智能体;对话码道,开发SDD并检验是否符合项目预期;对话码道,编写代码生成项目;启动项目,验证项目功能;对话码道,更新优化SDD,沉淀项目知识库。1.5 资源总览本案例预计花费0元。资源名称规格单价(元)开发者空间云开发环境ARM | 2vCPUs 4GB | All In One 开发环境免费华为云码道(CodeArts)代码智能体体验版免费二、环境和资源准备2.1 VSCode 远程连接云开发环境参考案例《华为开发者空间 - 云开发环境(容器)IDE插件远程连接操作指导》中的“二、 云开发环境IDE插件远程连接操作指导”章节,完成 VS Code 到云开发环境(容器)的远程连接。2.2 VSCode 搭建码道智能体VS Code 连接云开发环境的状态下,在“扩展”中搜索“CodeArts”,安装“CodeArts Agent”插件。安装完成后,VS Code中执行命令:CodeArts Agent: Open the Q&A Dialog右侧弹出的侧栏为码道智能体对话界面。登录后进行对话测试,确认码道智能体搭建成功且能够正常使用。三、使用码道构建失物招领平台系统3.1 需求分析与功能设计项目名称: Anima - 失物招领平台项目定位:现代化失物招领平台,支持用户发布失物和招领信息、浏览与搜索信息、联系发布者,并具备完整的用户管理能力。技术栈:前端:Vue3 + Vite + TypeScript后端:Python Flask数据库:SQLite核心功能:用户登录和信息管理用户发布失物信息和招领信息,可对自己发布的信息进行编辑、删除、修改完成状态展示最新发布的信息,可分类浏览,可按条件检索查看物品详情并联系发布者管理员管理用户和信息3.2 Prompt 设计和 SDD 生成(1)根据以上项目需求,设计如下 Prompt:根据以下需求描述,开发一个失物招领 Web 应用。 1. 项目概述 项目名称:Anima 项目定位:现代化的失物招领平台,支持用户发布失物和招领信息、浏览与搜索信息、联系发布者,并具备完整的用户管理能力。 2. 技术框架 技术栈:实现前后端分离,前端采用Vue3,后端采用Python Flask,数据库使用SQLite。具备良好的可维护性、可扩展性和规范的项目结构,API 设计遵循 RESTful 风格。 3. 核心功能 (1)用户注册、登录、退出及个人信息管理。 (2)发布失物信息和招领信息,并支持上传多张图片。 (3)首页展示最新发布的信息,可按失物/招领分类浏览。 (4)支持按物品名称、分类、地点、时间等条件进行搜索和筛选。 (5)查看物品详情,并提供联系发布者的方式(站内联系即可,无需真实短信或邮件)。 (6)用户可管理自己发布的信息,包括编辑、删除、修改状态(已找到/已认领)。 (7)管理员具备用户管理、信息审核(可选)及违规内容处理能力。 基本业务流程:注册登录后即可发布失物或招领信息;其他用户可浏览、搜索、查看详情,并通过站内方式联系发布者。当物品成功找回后,发布者可以将信息标记为已完成,已完成的信息仍可保留展示但默认降低排序。 4. 设计风格 整体采用现代、简洁、清爽的设计风格,界面注重易用性与响应式布局,能够适配桌面端与移动端浏览器,保证良好的用户体验。在码道对话界面选择 规范驱动模式(Spec-Driven Mode),发送上述请求。(2)码道首先调用 creating-sdd-directory skill 创建项目目录结构。(3)之后码道根据需求描述,生成需求规格文档 spec.md。如有需要可对需求规格文档进行修改。(4)确认后,码道继续生成技术设计文档 design.md,完成生成后可按需修改。(5)确认后,码道继续生成编码任务文档 task.md,完成生成后可按需修改。(6)检查需求规格文档、技术设计文档、编码任务文档是否与预期一致,如有需要调整的地方可直接进行修改。3.3 编码任务执行确认 SSD 无误后,在码道界面发送请求:遵循spec.md、design.md、tasks.md进行项目开发。码道将根据 SSD 执行编码任务。(1)初始化后端项目结构(2)创建数据模型(3)创建工具函数与权限装饰器(4)创建后端核心接口(5)验证后端构建(6)创建初始化前端项目结构、配置依赖(7)创建路由配置和 API 封装(8)更新 main.js(9)创建全局样式和组件(10)实现前端页面视图(11)验证前端构建(12)集成验证(13)开发完成3.4 环境配置与快速启动开发完成后,可查看如下项目结构:/workspace/ ├── anima-backend/ # 后端 Flask 项目 │ ├── app/ │ │ ├── __init__.py # 应用工厂 + 种子数据 │ │ ├── config.py # 配置文件 │ │ ├── extensions.py # SQLAlchemy/JWT/Migrate/CORS │ │ ├── models/ # 数据模型 │ │ │ ├── user.py # User 模型(密码哈希、to_dict) │ │ │ ├── item.py # Item 模型(图片JSON、状态映射) │ │ │ └── message.py # Message 模型 │ │ ├── api/ # API 蓝图 │ │ │ ├── auth.py # 注册/登录/个人信息/改密 │ │ │ ├── items.py # 信息CRUD/搜索/状态变更 │ │ │ ├── messages.py # 站内消息/已读/未读数 │ │ │ └── admin.py # 用户管理/信息下架 │ │ ├── utils/ # 工具函数 │ │ │ ├── __init__.py # 响应辅助/权限装饰器 │ │ │ └── validators.py # 校验函数 │ │ └── static/uploads/ # 图片上传目录 │ ├── run.py # 启动入口 │ └── requirements.txt │ ├── anima-frontend/ # 前端 Vue3 项目 │ ├── src/ │ │ ├── api/ # API 请求封装 │ │ ├── components/ # 通用组件 │ │ │ ├── AppHeader.vue # 导航栏(响应式+消息未读数) │ │ │ ├── AppFooter.vue │ │ │ ├── ItemCard.vue # 信息卡片 │ │ │ ├── SearchBar.vue # 搜索筛选栏 │ │ │ ├── ImageUpload.vue # 图片上传 │ │ │ └── Pagination.vue # 分页 │ │ ├── views/ # 页面视图(7个) │ │ │ ├── HomeView.vue # 首页 │ │ │ ├── LoginView.vue # 登录 │ │ │ ├── RegisterView.vue# 注册 │ │ │ ├── ItemDetailView.vue # 详情+站内联系 │ │ │ ├── ItemPostView.vue # 发布 │ │ │ ├── ItemEditView.vue # 编辑 │ │ │ ├── MyItemsView.vue # 我的发布 │ │ │ ├── ProfileView.vue # 个人信息 │ │ │ ├── MessagesView.vue # 消息中心 │ │ │ └── admin/ # 管理员页面 │ │ ├── router/index.js # 路由+守卫 │ │ ├── stores/user.js # Pinia 用户状态 │ │ └── assets/main.css # 全局样式 │ └── vite.config.js # Vite 代理配置 │ └── .codeartsdoer/specs/anima/ # SDD 文档 ├── spec.md ├── design.md └── tasks.md安装依赖、启动项目后端:cd anima-backend pip install -r requirements.txt python run.py安装依赖、启动项目前端:cd anima-frontend npm install npm run dev成功启动后,浏览器访问 http://localhost:3000/ 进入应用页面。3.5 项目功能测试进入应用首页,可以看到导航栏、信息筛选卡片以及失物招领信息列表。尝试注册账号并登录,可查看账号个人信息并修改昵称和密码。导航栏点击“发布信息”,填写失物或招领的相关内容,点击“发布”后可以在首页看到已发布的信息。首页点击失物招领信息卡片,进入详情页、查看该条信息的具体内容。对于自己发布的信息,可以点击“编辑”来编辑该信息的内容,或者点击“标记为已找到(标记为已认领)”来修改完成状态。对于他人发布的信息,可在详情页联系发布者。可在导航栏点击“消息”,查看自己收到和发出的消息。对于他人发布的信息,可在详情页联系发布者。可在导航栏点击“消息”,查看自己收到和发出的消息。导航栏点击“我的发布”,查看自己发布的失物招领信息。登录管理员账号,验证用户管理和信息管理功能。3.5 后续开发与优化(1)与码道进行对话,反馈测试应用时发现的问题,例如编辑失物招领信息时添加图片功能出现异常。码道会进行修改、解决这些问题。(2)与码道进行对话,对当前应用进行优化,例如完善控件显示、为关键操作添加二次确认、对页面进行美化等。美化后的应用,首页界面如下。(3)完成开发后,向码道以下指令,更新 SSD。请总结项目,更新SDD,确保下次可以直接通过该SDD复现项目的风格、布局、颜色、功能特性以及前后台业务逻辑等。同步更新 SSD,可以完整记录系统设计与实现过程中的关键决策,提高开发过程的可追溯性,并促进团队协作与知识共享。此外,通过保持文档与代码的一致性,构建了系统化的项目文档体系,为后续维护和功能扩展提供了有力支撑。3.6 核心代码讲解(1)后端应用工厂与蓝图注册anima-backend/app/__init__.py 中的 create_app 是后端唯一启动入口,完成配置加载、扩展初始化、蓝图挂载和数据库初始化,组装成一个可运行的 Flask 应用。# anima-backend/app/__init__.py def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) # 挂载数据库、JWT、迁移、跨域等扩展 db.init_app(app) jwt.init_app(app) migrate.init_app(app, db) cors.init_app(app, resources={r"/api/*": {"origins": "*"}}) os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) # 提供上传图片的静态访问地址 @app.route('/static/uploads/<path:filename>') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) # 按业务注册四类 API app.register_blueprint(auth_bp, url_prefix='/api/auth') app.register_blueprint(items_bp, url_prefix='/api/items') app.register_blueprint(messages_bp, url_prefix='/api/messages') app.register_blueprint(admin_bp, url_prefix='/api/admin') # 首次启动时建表,并写入默认管理员 with app.app_context(): from app import models # noqa: F401 db.create_all() _seed_admin() return app初始化 db、jwt、migrate、cors,分别负责 ORM、登录令牌、数据库迁移与前端跨域调用支持,并开放图片上传目录 /static/uploads/ 供浏览器访问图片。后端按业务划分 /api/auth、/api/items、/api/messages、/api/admin 四个蓝图,分别负责认证、失物招领、站内消息、管理端;后端启动时自动建表,并通过 _seed_admin 写入默认管理员账号(admin / admin123),便于首次体验管理功能。(2)核心数据模型数据模型定义了 User、Item、Message 三类核心实体,分别对应用户、失物/招领信息与站内消息。User 模型:保存账号身份、负责密码安全# anima-backend/app/models/user.py class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(20), unique=True, nullable=False, index=True) email = db.Column(db.String(120), unique=True, nullable=False, index=True) password_hash = db.Column(db.String(256), nullable=False) nickname = db.Column(db.String(30)) role = db.Column(db.String(20), nullable=False, default='user') status = db.Column(db.String(20), nullable=False, default='active') @password.setter def password(self, password): self.password_hash = bcrypt.hashpw( password.encode('utf-8'), bcrypt.gensalt() ).decode('utf-8') def verify_password(self, password): return bcrypt.checkpw( password.encode('utf-8'), self.password_hash.encode('utf-8') ) def to_dict(self): return { 'id': self.id, 'username': self.username, 'email': self.email, 'nickname': self.display_name, 'role': '管理员' if self.role == 'admin' else '普通用户', 'status': self.status, # ... } User 对应注册用户。除了用户名、邮箱、昵称外,用 role 区分普通用户与管理员,用 status 标记账号是否可用。密码不存明文,而是通过 @password.setter 用 bcrypt 生成哈希写入、登录时校验,保证账号安全。to_dict 把数据库记录转成前端可用的 JSON(角色显示为中文);另有 to_public_dict 只返回昵称等公开字段,用于物品详情页展示发布者,避免泄露邮箱等敏感信息。Item 模型:保存失物招领信息# anima-backend/app/models/item.py class Item(db.Model): __tablename__ = 'items' title = db.Column(db.String(50), nullable=False) type = db.Column(db.String(10), nullable=False, index=True) # lost / found description = db.Column(db.Text, nullable=False) category = db.Column(db.String(20), nullable=False, index=True) location = db.Column(db.String(100), nullable=False) event_time = db.Column(db.DateTime, nullable=False) _images = db.Column('images', db.Text) status = db.Column(db.String(20), nullable=False, default='active', index=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) STATUS_DISPLAY = { 'active': '进行中', 'found': '已找到', 'claimed': '已认领', 'removed': '已下架' } @property def images(self): return json.loads(self._images) if self._images else [] @images.setter def images(self, value): self._images = json.dumps(value) if value else None @property def is_completed(self): return self.status in ('found', 'claimed') Item 是平台的核心业务对象,一条记录代表用户发布的一则失物或招领,包含标题、描述、分类、地点、事件时间,以及多张图片和当前状态字段。user_id 指向发布者,从而把信息与用户关联起来。Message 模型:保存围绕某条信息的站内联系记录# anima-backend/app/models/message.py class Message(db.Model): __tablename__ = 'messages' content = db.Column(db.String(500), nullable=False) sender_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) receiver_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) item_id = db.Column(db.Integer, db.ForeignKey('items.id'), nullable=False) is_read = db.Column(db.Boolean, nullable=False, default=False) Message 用于实现“在详情页联系发布者”。每条消息都绑定发送方、接收方和关联的 Item,并记录是否已读,从而支撑消息中心列表与导航栏未读提示。与普通私信不同,这里强制要求 item_id,保证联系必须围绕某条失物/招领展开,消息中心也能据此展示“关于哪条信息的沟通”;is_read 则用于统计未读数,并在用户查看后标记为已读。(3)统一响应与权限装饰器app/utils 提供两套公共能力:统一 JSON 响应格式,以及对接口做登录/管理员校验。所有业务接口都复用它们,避免每个接口各自拼返回体、各自写鉴权代码。# anima-backend/app/utils/__init__.py def success_response(data=None, message='success'): return jsonify({'code': 0, 'message': message, 'data': data or {}}) def error_response(code, message): return jsonify({'code': code, 'message': message, 'data': {}}), \ 400 if code < 500 else 500 def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): verify_jwt_in_request() identity = get_jwt_identity() user = User.query.get(identity) if not user: return error_response(401, '用户不存在') if user.status == 'disabled': return error_response(403, '账号已被禁用') return f(*args, **kwargs, current_user=user) return decorated_function def admin_required(f): # 在登录校验基础上,额外要求 role == 'admin' ... 成功与失败都返回 {code, message, data}:前端只需判断 code === 0 即可处理结果,错误提示取自 message。login_required 装饰在需要登录的接口上:校验请求头中的 JWT,查出对应用户,若账号被禁用则拒绝访问,通过后把 current_user 传给视图函数。admin_required 在此基础上再检查 role == 'admin',专门保护管理端接口。这样鉴权逻辑集中维护,业务代码只需关心业务本身。(4)用户认证接口auth 蓝图负责用户进入系统的全过程,包括创建账号、验证身份、签发登录凭证,以及登录后的个人资料与改密。# anima-backend/app/api/auth.py @auth_bp.route('/register', methods=['POST']) def register(): data = request.get_json() username = data.get('username', '').strip() email = data.get('email', '').strip() password = data.get('password', '') # 校验格式与唯一性后创建用户 user = User(username=username, email=email) user.password = password db.session.add(user) db.session.commit() token = create_access_token(identity=user.id) return success_response({ 'token': token, 'user': user.to_dict() }, '注册成功') @auth_bp.route('/login', methods=['POST']) def login(): username = data.get('username', '').strip() password = data.get('password', '') # 支持用用户名或邮箱登录 user = User.query.filter( (User.username == username) | (User.email == username) ).first() if not user or not user.verify_password(password): return error_response(401, '用户名或密码错误') if user.status == 'disabled': return error_response(403, '账号已被禁用') token = create_access_token(identity=user.id) return success_response({'token': token, 'user': user.to_dict()}, '登录成功') 注册流程为:校验用户名/邮箱/密码格式 → 检查是否已存在 → 创建 User(密码自动哈希)→ 签发 JWT 并连同用户信息返回,注册成功即处于登录态。登录流程为:按用户名或邮箱查找用户 → 校验密码与账号状态 → 同样返回 token 与 user。前端保存该 Token 后,后续请求即可证明身份。同文件还提供需登录才能访问的个人资料读写与修改密码接口。(5)失物招领接口items 蓝图实现平台主业务,包括用户浏览/搜索信息、登录后发布带图信息、对自己发布的信息做编辑删除,以及在找回物品后标记完成。首页列表、详情页、发布页、我的发布都依赖这里的接口。列表查询与排序:口面向所有访客,负责把符合条件的信息分页返回给首页# anima-backend/app/api/items.py @items_bp.route('', methods=['GET']) def get_items(): query = Item.query.filter(Item.status != 'removed') if item_type and item_type in Item.VALID_TYPES: query = query.filter(Item.type == item_type) if keyword: query = query.filter( db.or_(Item.title.contains(keyword), Item.description.contains(keyword)) ) if category and category in Item.VALID_CATEGORIES: query = query.filter(Item.category == category) if location: query = query.filter(Item.location.contains(location)) # 还可按 start_date / end_date 过滤 event_time # 进行中优先,再按创建时间倒序 query = query.order_by( db.case((Item.status == 'active', 0), else_=1), Item.created_at.desc() ) pagination = query.paginate(page=page, per_page=per_page, error_out=False) return success_response({ 'items': [item.to_dict() for item in pagination.items], 'total': pagination.total, 'page': pagination.page, 'pages': pagination.pages }) 查询时,先排除已下架信息,再按类型、关键词、分类、地点、时间等条件叠加过滤;排序上使 active(进行中)排在前面,同优先级再按发布时间倒序,这样首页优先看到仍待匹配的信息。最后分页返回,供前端翻页展示。发布信息与图片上传:要求登录,负责把表单字段和图片落库为一条新 Item@items_bp.route('', methods=['POST']) @login_required def create_item(current_user): # 校验标题、类型、描述、分类、地点、时间等必填项 images = [] files = request.files.getlist('images') for f in files: if f.filename: # 校验格式与大小后,用 UUID 重命名并保存 filename = f'{uuid.uuid4().hex}.{ext}' f.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename)) images.append(f'/static/uploads/{filename}') item = Item( title=title, type=item_type, description=description, category=category, location=location, event_time=event_time, user_id=current_user.id ) item.images = images db.session.add(item) db.session.commit() return success_response(item.to_dict(), '发布成功') 接口使用 multipart/form-data 同时接收文字与文件:先校验业务字段,再逐张检查图片扩展名与大小,保存到上传目录后把访问路径写入 item.images,最后关联 current_user.id 入库。编辑接口逻辑类似,但会保留前端回传的 existing_images,再追加新上传图片,避免改信息时把原图清空。状态变更:用于发布者在物品找回后结束该条信息@items_bp.route('/<int:item_id>/status', methods=['PUT']) @login_required def update_item_status(current_user, item_id): item = Item.query.get(item_id) if item.user_id != current_user.id: return error_response(403, '无权操作') if item.is_completed: return error_response(400, '已完成的信息不可恢复为进行中') if item.type == 'lost' and new_status == 'found': item.status = 'found' elif item.type == 'found' and new_status == 'claimed': item.status = 'claimed' else: return error_response(400, '无效的状态变更') db.session.commit() return success_response(item.to_dict(), '状态更新成功') 只有发布者本人可操作;失物只能标为“已找到”,招领只能标为“已认领”;一旦完成不可再改回进行中。这样既闭环了“发布 → 找回 → 结束”流程,也避免状态被随意篡改。(6)站内消息接口messages 蓝图实现站内联系,即浏览者在详情页给发布者留言,双方在消息中心查看往来,导航栏展示未读数量。它替代真实短信/邮件,把沟通留在平台内完成。# anima-backend/app/api/messages.py @messages_bp.route('', methods=['POST']) @login_required def send_message(current_user): if receiver_id == current_user.id: return error_response(400, '不能联系自己') item = Item.query.get(item_id) if not item or item.status == 'removed': return error_response(404, '关联信息不存在') if item.user_id != receiver_id: return error_response(400, '接收者不是该信息的发布者') message = Message( content=content, sender_id=current_user.id, receiver_id=receiver_id, item_id=item_id ) db.session.add(message) db.session.commit() return success_response(message.to_dict(), '消息发送成功') @messages_bp.route('/unread-count', methods=['GET']) @login_required def get_unread_count(current_user): count = Message.query.filter( Message.receiver_id == current_user.id, Message.is_read == False ).count() return success_response({'count': count}) 发送时校验:不能给自己发、关联信息必须存在且未下架、接收者必须是该信息的发布者。通过后写入 Message,消息中心即可按收发关系列表展示。unread-count 统计当前用户未读收件数,供导航栏提示;同模块还有标记已读等接口,配合前端完成“联系 → 查看 → 已读”的完整链路。(7)管理端接口admin 蓝图只对管理员开放,用于处理违规账号与违规信息:查看用户列表并启用/禁用账号,查看全部信息并上架/下架。# anima-backend/app/api/admin.py @admin_bp.route('/users/<int:user_id>/status', methods=['PUT']) @admin_required def update_user_status(current_user, user_id): if user_id == current_user.id: return error_response(400, '不能禁用自己的账号') # status 仅允许 active / disabled user.status = new_status db.session.commit() return success_response(user.to_dict(), '操作成功') @admin_bp.route('/items/<int:item_id>/status', methods=['PUT']) @admin_required def update_item_status(current_user, item_id): # 管理员可将信息设为 active 或 removed(下架) item.status = new_status db.session.commit() return success_response(item.to_dict(), '操作成功') 两个接口都使用 @admin_required,非管理员无法调用。禁用用户时禁止操作自己,避免管理员误锁自身;信息状态只允许在“进行中 / 已下架”之间切换,下架后前台列表不再展示。同文件还提供用户与信息的分页查询,支撑管理页表格展示。(8)前端请求封装与用户状态前端要调用上述 API,需要在每次请求自动带上登录 Token,并在页面间共享用户身份。request.js 与 Pinia 的 user store 分别承担这两项功能;Vite 代理则让开发环境下前端能无跨域地访问后端。请求层用 Axios 拦截器统一处理鉴权头与登录失效:// anima-frontend/src/api/request.js const api = axios.create({ baseURL: '/api', timeout: 10000 }) api.interceptors.request.use(config => { const userStore = useUserStore() if (userStore.token) { config.headers.Authorization = `Bearer ${userStore.token}` } return config }) api.interceptors.response.use( response => response, error => { if (error.response && error.response.status === 401) { useUserStore().logout() router.push({ name: 'Login', query: { redirect: router.currentRoute.value.fullPath } }) } return Promise.reject(error) } ) 发出请求前,若本地已有 Token,则写入 Authorization: Bearer ...,后端 login_required 才能识别用户;若返回 401,说明登录已失效,则清空本地状态并跳转登录页,同时带上当前路径以便登录后返回。用户状态由 Pinia store 集中管理,并同步到 localStorage,刷新页面后仍保持登录:// anima-frontend/src/stores/user.js export const useUserStore = defineStore('user', () => { const token = ref(localStorage.getItem('token') || '') const user = ref(JSON.parse(localStorage.getItem('user') || 'null')) const isLoggedIn = computed(() => !!token.value) const isAdmin = computed(() => user.value?.role === '管理员') async function login(credentials) { const res = await authApi.login(credentials) if (res.data.code === 0) { token.value = res.data.data.token user.value = res.data.data.user localStorage.setItem('token', res.data.data.token) localStorage.setItem('user', JSON.stringify(res.data.data.user)) } return res } // register / logout / fetchProfile 同理 }) login / register 成功后同时更新内存与本地存储;isLoggedIn、isAdmin 供路由守卫和导航栏判断是否展示管理入口。logout 则清除两端数据。开发时,Vite 把 /api、/static 代理到后端 5000 端口,浏览器只访问 3000,即可完成前后端联调:// anima-frontend/vite.config.js server: { port: 3000, proxy: { '/api': { target: 'http://localhost:5000', changeOrigin: true }, '/static': { target: 'http://localhost:5000', changeOrigin: true } } } (9)前端路由守卫与首页路由模块决定用户能打开哪些页面,保护需登录/管理员的功能;首页为失物招领信息的主入口。前者保护需登录/管理员的功能页,把后端列表接口的数据呈现为可搜索、可翻页的卡片列表。路由守卫在每次跳转前检查权限:// anima-frontend/src/router/index.js router.beforeEach((to, from, next) => { const userStore = useUserStore() if (to.meta.requiresAuth && !userStore.isLoggedIn) { next({ name: 'Login', query: { redirect: to.fullPath } }) } else if (to.meta.requiresAdmin && !userStore.isAdmin) { next({ name: 'Home' }) } else { next() } }) 发布、编辑、我的发布、个人中心、消息等路由配置了 meta.requiresAuth,未登录会跳到登录页并记录原目标地址;管理端路由额外配置 requiresAdmin,非管理员会被拦回首页,避免前端直接进入无权页面。首页脚本负责拉取并刷新信息列表:// anima-frontend/src/views/HomeView.vue(脚本核心) async function loadItems() { const params = { page: page.value, per_page: 20, ...filters.value } const res = await itemsApi.getItems(params) if (res.data.code === 0) { items.value = res.data.data.items totalPages.value = res.data.data.pages } } function handleSearch(searchFilters) { filters.value = searchFilters page.value = 1 loadItems() } 页面挂载时调用 loadItems 请求 /api/items;用户在 SearchBar 中筛选时,handleSearch 更新条件并回到第 1 页再请求;分页组件切换页码时同样调用 loadItems。返回的 items 交给 ItemCard 渲染。至此,后端列表能力与前端浏览体验对接完成,构成平台最核心的使用路径:搜索筛选 → 浏览卡片 → 进入详情 → 联系或管理。3.7 开发总结本案例基于华为开发者空间云开发环境和华为云码道(CodeArts)代码智能体,完成了一个智能化失物招领平台的设计与开发。整个开发过程采用规范驱动开发(Spec-Driven Development,SDD)模式,通过需求规格文档、技术设计文档和编码任务文档逐步明确系统目标、架构设计和实现任务,实现了从需求分析到代码生成的流程化开发。在开发过程中,利用云开发环境提供统一稳定的运行环境,避免了本地环境配置和依赖管理带来的问题;通过 CodeArts Agent 对需求进行理解和拆解,自动生成项目 SDD,并依据 SDD 完成前后端代码构建。开发过程中结合实际运行测试结果,通过持续反馈与智能体协作,对系统功能、界面交互和代码结构进行优化,最终实现了用户管理、失物招领信息管理、搜索筛选、图片上传、站内消息等完整业务功能。通过本案例可以看到,AI Agent 驱动的软件开发模式能够有效降低应用开发门槛,提高原型构建和功能迭代效率。同时,基于 SDD 的开发方式使需求、设计与代码之间保持关联,增强了开发过程的可追溯性,为后续维护、扩展以及团队协作提供了良好的基础。四、释放资源4.1 关闭华为开发者空间云开发环境(容器)案例完成后,如无需继续使用该开发环境,可关闭对应云开发环境,避免持续占用开发资源。VS Code 中左侧导航栏选择”开发者空间,选中容器,点击“关机”按钮,弹框点击“确认”即可关闭容器。五、扩展资料说明华为云码道CodeArts实战速成:cid:link_1华为云开发者AI训练营:cid:link_2
-
一、概述1.1 案例介绍随着校园、社区及公共场所人员流动增加,物品遗失与寻找需求日益普遍。传统失物招领方式通常依赖线下公告、微信群等渠道,存在信息分散、检索困难、匹配效率低等问题。为提升失物信息流转效率,本案例设计并开发了一个智能化失物招领平台,实现失物信息与招领信息的集中管理和便捷查询。本案例基于 AI Agent 自动化开发模式,利用华为开发者空间开发平台和华为云码道(CodeArts)代码智能体完成全流程应用构建。应用采用前后端分离架构,选择采用 Vue3 前端、Flask 后端、SQLite 数据库的技术栈进行开发。系统支持用户注册登录、失物信息发布、招领信息发布、物品图片上传、关键词搜索、分类筛选、详情查看、站内联系以及个人信息管理等核心功能,同时提供信息状态管理能力,帮助用户完成从信息发布到物品找回的完整业务流程。本案例构建的项目和文档已保存至GitCode,可自行下载源码。Demo演示视频技术选型:华为开发者空间开发平台 - 云开发环境(容器):华为云提供的一站式云上开发环境,支持多种主流开发语言和运行环境,开发者无需进行复杂的本地环境配置即可快速开展应用开发。本案例中选用云开发环境(容器)作为应用的开发与运行环境,为项目提供统一稳定的基础环境,避免因操作系统、依赖版本等环境差异导致的应用运行问题,提高项目构建和部署效率。华为云码道(CodeArts)代码智能体:华为云提供的智能化软件开发工具,融合代码大模型、AI IDE 和 Code Agent 等能力,能够理解项目需求并辅助完成代码生成、代码优化和工程构建。本案例中使用华为云码道(CodeArts)代码智能体作为核心开发辅助工具,根据失物招领应用需求完成前后端功能开发,加速 Web 应用构建过程,降低应用开发门槛。1.2 适用对象企业开发者个人开发者高校学生1.3 案例时间本案例总时长预计60分钟。1.4 案例流程说明:VSCode安装开发者空间插件,远程连接云开发环境(容器);云开发环境(容器)搭建华为云码道(CodeArts)代码智能体;对话码道,开发SDD并检验是否符合项目预期;对话码道,编写代码生成项目;启动项目,验证项目功能;对话码道,更新优化SDD,沉淀项目知识库。1.5 资源总览本案例预计花费0元。资源名称规格单价(元)开发者空间云开发环境ARM | 2vCPUs 4GB | All In One 开发环境免费华为云码道(CodeArts)代码智能体体验版免费二、环境和资源准备2.1 VSCode 远程连接云开发环境参考案例《华为开发者空间 - 云开发环境(容器)IDE插件远程连接操作指导》中的“二、 云开发环境IDE插件远程连接操作指导”章节,完成 VS Code 到云开发环境(容器)的远程连接。2.2 VSCode 搭建码道智能体VS Code 连接云开发环境的状态下,在“扩展”中搜索“CodeArts”,安装“CodeArts Agent”插件。安装完成后,VS Code中执行命令:CodeArts Agent: Open the Q&A Dialog右侧弹出的侧栏为码道智能体对话界面。登录后进行对话测试,确认码道智能体搭建成功且能够正常使用。三、使用码道构建失物招领平台系统3.1 需求分析与功能设计项目名称: Anima - 失物招领平台项目定位:现代化失物招领平台,支持用户发布失物和招领信息、浏览与搜索信息、联系发布者,并具备完整的用户管理能力。技术栈:前端:Vue3 + Vite + TypeScript后端:Python Flask数据库:SQLite核心功能:用户登录和信息管理用户发布失物信息和招领信息,可对自己发布的信息进行编辑、删除、修改完成状态展示最新发布的信息,可分类浏览,可按条件检索查看物品详情并联系发布者管理员管理用户和信息3.2 Prompt 设计和 SDD 生成(1)根据以上项目需求,设计如下 Prompt:根据以下需求描述,开发一个失物招领 Web 应用。 1. 项目概述 项目名称:Anima 项目定位:现代化的失物招领平台,支持用户发布失物和招领信息、浏览与搜索信息、联系发布者,并具备完整的用户管理能力。 2. 技术框架 技术栈:实现前后端分离,前端采用Vue3,后端采用Python Flask,数据库使用SQLite。具备良好的可维护性、可扩展性和规范的项目结构,API 设计遵循 RESTful 风格。 3. 核心功能 (1)用户注册、登录、退出及个人信息管理。 (2)发布失物信息和招领信息,并支持上传多张图片。 (3)首页展示最新发布的信息,可按失物/招领分类浏览。 (4)支持按物品名称、分类、地点、时间等条件进行搜索和筛选。 (5)查看物品详情,并提供联系发布者的方式(站内联系即可,无需真实短信或邮件)。 (6)用户可管理自己发布的信息,包括编辑、删除、修改状态(已找到/已认领)。 (7)管理员具备用户管理、信息审核(可选)及违规内容处理能力。 基本业务流程:注册登录后即可发布失物或招领信息;其他用户可浏览、搜索、查看详情,并通过站内方式联系发布者。当物品成功找回后,发布者可以将信息标记为已完成,已完成的信息仍可保留展示但默认降低排序。 4. 设计风格 整体采用现代、简洁、清爽的设计风格,界面注重易用性与响应式布局,能够适配桌面端与移动端浏览器,保证良好的用户体验。在码道对话界面选择 规范驱动模式(Spec-Driven Mode),发送上述请求。(2)码道首先调用 creating-sdd-directory skill 创建项目目录结构。(3)之后码道根据需求描述,生成需求规格文档 spec.md。如有需要可对需求规格文档进行修改。(4)确认后,码道继续生成技术设计文档 design.md,完成生成后可按需修改。(5)确认后,码道继续生成编码任务文档 task.md,完成生成后可按需修改。(6)检查需求规格文档、技术设计文档、编码任务文档是否与预期一致,如有需要调整的地方可直接进行修改。3.3 编码任务执行确认 SSD 无误后,在码道界面发送请求:遵循spec.md、design.md、tasks.md进行项目开发。码道将根据 SSD 执行编码任务。(1)初始化后端项目结构(2)创建数据模型(3)创建工具函数与权限装饰器(4)创建后端核心接口(5)验证后端构建(6)创建初始化前端项目结构、配置依赖(7)创建路由配置和 API 封装(8)更新 main.js(9)创建全局样式和组件(10)实现前端页面视图(11)验证前端构建(12)集成验证(13)开发完成3.4 环境配置与快速启动开发完成后,可查看如下项目结构:/workspace/ ├── anima-backend/ # 后端 Flask 项目 │ ├── app/ │ │ ├── __init__.py # 应用工厂 + 种子数据 │ │ ├── config.py # 配置文件 │ │ ├── extensions.py # SQLAlchemy/JWT/Migrate/CORS │ │ ├── models/ # 数据模型 │ │ │ ├── user.py # User 模型(密码哈希、to_dict) │ │ │ ├── item.py # Item 模型(图片JSON、状态映射) │ │ │ └── message.py # Message 模型 │ │ ├── api/ # API 蓝图 │ │ │ ├── auth.py # 注册/登录/个人信息/改密 │ │ │ ├── items.py # 信息CRUD/搜索/状态变更 │ │ │ ├── messages.py # 站内消息/已读/未读数 │ │ │ └── admin.py # 用户管理/信息下架 │ │ ├── utils/ # 工具函数 │ │ │ ├── __init__.py # 响应辅助/权限装饰器 │ │ │ └── validators.py # 校验函数 │ │ └── static/uploads/ # 图片上传目录 │ ├── run.py # 启动入口 │ └── requirements.txt │ ├── anima-frontend/ # 前端 Vue3 项目 │ ├── src/ │ │ ├── api/ # API 请求封装 │ │ ├── components/ # 通用组件 │ │ │ ├── AppHeader.vue # 导航栏(响应式+消息未读数) │ │ │ ├── AppFooter.vue │ │ │ ├── ItemCard.vue # 信息卡片 │ │ │ ├── SearchBar.vue # 搜索筛选栏 │ │ │ ├── ImageUpload.vue # 图片上传 │ │ │ └── Pagination.vue # 分页 │ │ ├── views/ # 页面视图(7个) │ │ │ ├── HomeView.vue # 首页 │ │ │ ├── LoginView.vue # 登录 │ │ │ ├── RegisterView.vue# 注册 │ │ │ ├── ItemDetailView.vue # 详情+站内联系 │ │ │ ├── ItemPostView.vue # 发布 │ │ │ ├── ItemEditView.vue # 编辑 │ │ │ ├── MyItemsView.vue # 我的发布 │ │ │ ├── ProfileView.vue # 个人信息 │ │ │ ├── MessagesView.vue # 消息中心 │ │ │ └── admin/ # 管理员页面 │ │ ├── router/index.js # 路由+守卫 │ │ ├── stores/user.js # Pinia 用户状态 │ │ └── assets/main.css # 全局样式 │ └── vite.config.js # Vite 代理配置 │ └── .codeartsdoer/specs/anima/ # SDD 文档 ├── spec.md ├── design.md └── tasks.md安装依赖、启动项目后端:cd anima-backend pip install -r requirements.txt python run.py安装依赖、启动项目前端:cd anima-frontend npm install npm run dev成功启动后,浏览器访问 http://localhost:3000/ 进入应用页面。3.5 项目功能测试进入应用首页,可以看到导航栏、信息筛选卡片以及失物招领信息列表。尝试注册账号并登录,可查看账号个人信息并修改昵称和密码。导航栏点击“发布信息”,填写失物或招领的相关内容,点击“发布”后可以在首页看到已发布的信息。首页点击失物招领信息卡片,进入详情页、查看该条信息的具体内容。对于自己发布的信息,可以点击“编辑”来编辑该信息的内容,或者点击“标记为已找到(标记为已认领)”来修改完成状态。对于他人发布的信息,可在详情页联系发布者。可在导航栏点击“消息”,查看自己收到和发出的消息。对于他人发布的信息,可在详情页联系发布者。可在导航栏点击“消息”,查看自己收到和发出的消息。导航栏点击“我的发布”,查看自己发布的失物招领信息。登录管理员账号,验证用户管理和信息管理功能。3.5 后续开发与优化(1)与码道进行对话,反馈测试应用时发现的问题,例如编辑失物招领信息时添加图片功能出现异常。码道会进行修改、解决这些问题。(2)与码道进行对话,对当前应用进行优化,例如完善控件显示、为关键操作添加二次确认、对页面进行美化等。美化后的应用,首页界面如下。(3)完成开发后,向码道以下指令,更新 SSD。请总结项目,更新SDD,确保下次可以直接通过该SDD复现项目的风格、布局、颜色、功能特性以及前后台业务逻辑等。同步更新 SSD,可以完整记录系统设计与实现过程中的关键决策,提高开发过程的可追溯性,并促进团队协作与知识共享。此外,通过保持文档与代码的一致性,构建了系统化的项目文档体系,为后续维护和功能扩展提供了有力支撑。3.6 核心代码讲解(1)后端应用工厂与蓝图注册anima-backend/app/__init__.py 中的 create_app 是后端唯一启动入口,完成配置加载、扩展初始化、蓝图挂载和数据库初始化,组装成一个可运行的 Flask 应用。# anima-backend/app/__init__.py def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) # 挂载数据库、JWT、迁移、跨域等扩展 db.init_app(app) jwt.init_app(app) migrate.init_app(app, db) cors.init_app(app, resources={r"/api/*": {"origins": "*"}}) os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) # 提供上传图片的静态访问地址 @app.route('/static/uploads/<path:filename>') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) # 按业务注册四类 API app.register_blueprint(auth_bp, url_prefix='/api/auth') app.register_blueprint(items_bp, url_prefix='/api/items') app.register_blueprint(messages_bp, url_prefix='/api/messages') app.register_blueprint(admin_bp, url_prefix='/api/admin') # 首次启动时建表,并写入默认管理员 with app.app_context(): from app import models # noqa: F401 db.create_all() _seed_admin() return app初始化 db、jwt、migrate、cors,分别负责 ORM、登录令牌、数据库迁移与前端跨域调用支持,并开放图片上传目录 /static/uploads/ 供浏览器访问图片。后端按业务划分 /api/auth、/api/items、/api/messages、/api/admin 四个蓝图,分别负责认证、失物招领、站内消息、管理端;后端启动时自动建表,并通过 _seed_admin 写入默认管理员账号(admin / admin123),便于首次体验管理功能。(2)核心数据模型数据模型定义了 User、Item、Message 三类核心实体,分别对应用户、失物/招领信息与站内消息。User 模型:保存账号身份、负责密码安全# anima-backend/app/models/user.py class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(20), unique=True, nullable=False, index=True) email = db.Column(db.String(120), unique=True, nullable=False, index=True) password_hash = db.Column(db.String(256), nullable=False) nickname = db.Column(db.String(30)) role = db.Column(db.String(20), nullable=False, default='user') status = db.Column(db.String(20), nullable=False, default='active') @password.setter def password(self, password): self.password_hash = bcrypt.hashpw( password.encode('utf-8'), bcrypt.gensalt() ).decode('utf-8') def verify_password(self, password): return bcrypt.checkpw( password.encode('utf-8'), self.password_hash.encode('utf-8') ) def to_dict(self): return { 'id': self.id, 'username': self.username, 'email': self.email, 'nickname': self.display_name, 'role': '管理员' if self.role == 'admin' else '普通用户', 'status': self.status, # ... } User 对应注册用户。除了用户名、邮箱、昵称外,用 role 区分普通用户与管理员,用 status 标记账号是否可用。密码不存明文,而是通过 @password.setter 用 bcrypt 生成哈希写入、登录时校验,保证账号安全。to_dict 把数据库记录转成前端可用的 JSON(角色显示为中文);另有 to_public_dict 只返回昵称等公开字段,用于物品详情页展示发布者,避免泄露邮箱等敏感信息。Item 模型:保存失物招领信息# anima-backend/app/models/item.py class Item(db.Model): __tablename__ = 'items' title = db.Column(db.String(50), nullable=False) type = db.Column(db.String(10), nullable=False, index=True) # lost / found description = db.Column(db.Text, nullable=False) category = db.Column(db.String(20), nullable=False, index=True) location = db.Column(db.String(100), nullable=False) event_time = db.Column(db.DateTime, nullable=False) _images = db.Column('images', db.Text) status = db.Column(db.String(20), nullable=False, default='active', index=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) STATUS_DISPLAY = { 'active': '进行中', 'found': '已找到', 'claimed': '已认领', 'removed': '已下架' } @property def images(self): return json.loads(self._images) if self._images else [] @images.setter def images(self, value): self._images = json.dumps(value) if value else None @property def is_completed(self): return self.status in ('found', 'claimed') Item 是平台的核心业务对象,一条记录代表用户发布的一则失物或招领,包含标题、描述、分类、地点、事件时间,以及多张图片和当前状态字段。user_id 指向发布者,从而把信息与用户关联起来。Message 模型:保存围绕某条信息的站内联系记录# anima-backend/app/models/message.py class Message(db.Model): __tablename__ = 'messages' content = db.Column(db.String(500), nullable=False) sender_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) receiver_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) item_id = db.Column(db.Integer, db.ForeignKey('items.id'), nullable=False) is_read = db.Column(db.Boolean, nullable=False, default=False) Message 用于实现“在详情页联系发布者”。每条消息都绑定发送方、接收方和关联的 Item,并记录是否已读,从而支撑消息中心列表与导航栏未读提示。与普通私信不同,这里强制要求 item_id,保证联系必须围绕某条失物/招领展开,消息中心也能据此展示“关于哪条信息的沟通”;is_read 则用于统计未读数,并在用户查看后标记为已读。(3)统一响应与权限装饰器app/utils 提供两套公共能力:统一 JSON 响应格式,以及对接口做登录/管理员校验。所有业务接口都复用它们,避免每个接口各自拼返回体、各自写鉴权代码。# anima-backend/app/utils/__init__.py def success_response(data=None, message='success'): return jsonify({'code': 0, 'message': message, 'data': data or {}}) def error_response(code, message): return jsonify({'code': code, 'message': message, 'data': {}}), \ 400 if code < 500 else 500 def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): verify_jwt_in_request() identity = get_jwt_identity() user = User.query.get(identity) if not user: return error_response(401, '用户不存在') if user.status == 'disabled': return error_response(403, '账号已被禁用') return f(*args, **kwargs, current_user=user) return decorated_function def admin_required(f): # 在登录校验基础上,额外要求 role == 'admin' ... 成功与失败都返回 {code, message, data}:前端只需判断 code === 0 即可处理结果,错误提示取自 message。login_required 装饰在需要登录的接口上:校验请求头中的 JWT,查出对应用户,若账号被禁用则拒绝访问,通过后把 current_user 传给视图函数。admin_required 在此基础上再检查 role == 'admin',专门保护管理端接口。这样鉴权逻辑集中维护,业务代码只需关心业务本身。(4)用户认证接口auth 蓝图负责用户进入系统的全过程,包括创建账号、验证身份、签发登录凭证,以及登录后的个人资料与改密。# anima-backend/app/api/auth.py @auth_bp.route('/register', methods=['POST']) def register(): data = request.get_json() username = data.get('username', '').strip() email = data.get('email', '').strip() password = data.get('password', '') # 校验格式与唯一性后创建用户 user = User(username=username, email=email) user.password = password db.session.add(user) db.session.commit() token = create_access_token(identity=user.id) return success_response({ 'token': token, 'user': user.to_dict() }, '注册成功') @auth_bp.route('/login', methods=['POST']) def login(): username = data.get('username', '').strip() password = data.get('password', '') # 支持用用户名或邮箱登录 user = User.query.filter( (User.username == username) | (User.email == username) ).first() if not user or not user.verify_password(password): return error_response(401, '用户名或密码错误') if user.status == 'disabled': return error_response(403, '账号已被禁用') token = create_access_token(identity=user.id) return success_response({'token': token, 'user': user.to_dict()}, '登录成功') 注册流程为:校验用户名/邮箱/密码格式 → 检查是否已存在 → 创建 User(密码自动哈希)→ 签发 JWT 并连同用户信息返回,注册成功即处于登录态。登录流程为:按用户名或邮箱查找用户 → 校验密码与账号状态 → 同样返回 token 与 user。前端保存该 Token 后,后续请求即可证明身份。同文件还提供需登录才能访问的个人资料读写与修改密码接口。(5)失物招领接口items 蓝图实现平台主业务,包括用户浏览/搜索信息、登录后发布带图信息、对自己发布的信息做编辑删除,以及在找回物品后标记完成。首页列表、详情页、发布页、我的发布都依赖这里的接口。列表查询与排序:口面向所有访客,负责把符合条件的信息分页返回给首页# anima-backend/app/api/items.py @items_bp.route('', methods=['GET']) def get_items(): query = Item.query.filter(Item.status != 'removed') if item_type and item_type in Item.VALID_TYPES: query = query.filter(Item.type == item_type) if keyword: query = query.filter( db.or_(Item.title.contains(keyword), Item.description.contains(keyword)) ) if category and category in Item.VALID_CATEGORIES: query = query.filter(Item.category == category) if location: query = query.filter(Item.location.contains(location)) # 还可按 start_date / end_date 过滤 event_time # 进行中优先,再按创建时间倒序 query = query.order_by( db.case((Item.status == 'active', 0), else_=1), Item.created_at.desc() ) pagination = query.paginate(page=page, per_page=per_page, error_out=False) return success_response({ 'items': [item.to_dict() for item in pagination.items], 'total': pagination.total, 'page': pagination.page, 'pages': pagination.pages }) 查询时,先排除已下架信息,再按类型、关键词、分类、地点、时间等条件叠加过滤;排序上使 active(进行中)排在前面,同优先级再按发布时间倒序,这样首页优先看到仍待匹配的信息。最后分页返回,供前端翻页展示。发布信息与图片上传:要求登录,负责把表单字段和图片落库为一条新 Item@items_bp.route('', methods=['POST']) @login_required def create_item(current_user): # 校验标题、类型、描述、分类、地点、时间等必填项 images = [] files = request.files.getlist('images') for f in files: if f.filename: # 校验格式与大小后,用 UUID 重命名并保存 filename = f'{uuid.uuid4().hex}.{ext}' f.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename)) images.append(f'/static/uploads/{filename}') item = Item( title=title, type=item_type, description=description, category=category, location=location, event_time=event_time, user_id=current_user.id ) item.images = images db.session.add(item) db.session.commit() return success_response(item.to_dict(), '发布成功') 接口使用 multipart/form-data 同时接收文字与文件:先校验业务字段,再逐张检查图片扩展名与大小,保存到上传目录后把访问路径写入 item.images,最后关联 current_user.id 入库。编辑接口逻辑类似,但会保留前端回传的 existing_images,再追加新上传图片,避免改信息时把原图清空。状态变更:用于发布者在物品找回后结束该条信息@items_bp.route('/<int:item_id>/status', methods=['PUT']) @login_required def update_item_status(current_user, item_id): item = Item.query.get(item_id) if item.user_id != current_user.id: return error_response(403, '无权操作') if item.is_completed: return error_response(400, '已完成的信息不可恢复为进行中') if item.type == 'lost' and new_status == 'found': item.status = 'found' elif item.type == 'found' and new_status == 'claimed': item.status = 'claimed' else: return error_response(400, '无效的状态变更') db.session.commit() return success_response(item.to_dict(), '状态更新成功') 只有发布者本人可操作;失物只能标为“已找到”,招领只能标为“已认领”;一旦完成不可再改回进行中。这样既闭环了“发布 → 找回 → 结束”流程,也避免状态被随意篡改。(6)站内消息接口messages 蓝图实现站内联系,即浏览者在详情页给发布者留言,双方在消息中心查看往来,导航栏展示未读数量。它替代真实短信/邮件,把沟通留在平台内完成。# anima-backend/app/api/messages.py @messages_bp.route('', methods=['POST']) @login_required def send_message(current_user): if receiver_id == current_user.id: return error_response(400, '不能联系自己') item = Item.query.get(item_id) if not item or item.status == 'removed': return error_response(404, '关联信息不存在') if item.user_id != receiver_id: return error_response(400, '接收者不是该信息的发布者') message = Message( content=content, sender_id=current_user.id, receiver_id=receiver_id, item_id=item_id ) db.session.add(message) db.session.commit() return success_response(message.to_dict(), '消息发送成功') @messages_bp.route('/unread-count', methods=['GET']) @login_required def get_unread_count(current_user): count = Message.query.filter( Message.receiver_id == current_user.id, Message.is_read == False ).count() return success_response({'count': count}) 发送时校验:不能给自己发、关联信息必须存在且未下架、接收者必须是该信息的发布者。通过后写入 Message,消息中心即可按收发关系列表展示。unread-count 统计当前用户未读收件数,供导航栏提示;同模块还有标记已读等接口,配合前端完成“联系 → 查看 → 已读”的完整链路。(7)管理端接口admin 蓝图只对管理员开放,用于处理违规账号与违规信息:查看用户列表并启用/禁用账号,查看全部信息并上架/下架。# anima-backend/app/api/admin.py @admin_bp.route('/users/<int:user_id>/status', methods=['PUT']) @admin_required def update_user_status(current_user, user_id): if user_id == current_user.id: return error_response(400, '不能禁用自己的账号') # status 仅允许 active / disabled user.status = new_status db.session.commit() return success_response(user.to_dict(), '操作成功') @admin_bp.route('/items/<int:item_id>/status', methods=['PUT']) @admin_required def update_item_status(current_user, item_id): # 管理员可将信息设为 active 或 removed(下架) item.status = new_status db.session.commit() return success_response(item.to_dict(), '操作成功') 两个接口都使用 @admin_required,非管理员无法调用。禁用用户时禁止操作自己,避免管理员误锁自身;信息状态只允许在“进行中 / 已下架”之间切换,下架后前台列表不再展示。同文件还提供用户与信息的分页查询,支撑管理页表格展示。(8)前端请求封装与用户状态前端要调用上述 API,需要在每次请求自动带上登录 Token,并在页面间共享用户身份。request.js 与 Pinia 的 user store 分别承担这两项功能;Vite 代理则让开发环境下前端能无跨域地访问后端。请求层用 Axios 拦截器统一处理鉴权头与登录失效:// anima-frontend/src/api/request.js const api = axios.create({ baseURL: '/api', timeout: 10000 }) api.interceptors.request.use(config => { const userStore = useUserStore() if (userStore.token) { config.headers.Authorization = `Bearer ${userStore.token}` } return config }) api.interceptors.response.use( response => response, error => { if (error.response && error.response.status === 401) { useUserStore().logout() router.push({ name: 'Login', query: { redirect: router.currentRoute.value.fullPath } }) } return Promise.reject(error) } ) 发出请求前,若本地已有 Token,则写入 Authorization: Bearer ...,后端 login_required 才能识别用户;若返回 401,说明登录已失效,则清空本地状态并跳转登录页,同时带上当前路径以便登录后返回。用户状态由 Pinia store 集中管理,并同步到 localStorage,刷新页面后仍保持登录:// anima-frontend/src/stores/user.js export const useUserStore = defineStore('user', () => { const token = ref(localStorage.getItem('token') || '') const user = ref(JSON.parse(localStorage.getItem('user') || 'null')) const isLoggedIn = computed(() => !!token.value) const isAdmin = computed(() => user.value?.role === '管理员') async function login(credentials) { const res = await authApi.login(credentials) if (res.data.code === 0) { token.value = res.data.data.token user.value = res.data.data.user localStorage.setItem('token', res.data.data.token) localStorage.setItem('user', JSON.stringify(res.data.data.user)) } return res } // register / logout / fetchProfile 同理 }) login / register 成功后同时更新内存与本地存储;isLoggedIn、isAdmin 供路由守卫和导航栏判断是否展示管理入口。logout 则清除两端数据。开发时,Vite 把 /api、/static 代理到后端 5000 端口,浏览器只访问 3000,即可完成前后端联调:// anima-frontend/vite.config.js server: { port: 3000, proxy: { '/api': { target: 'http://localhost:5000', changeOrigin: true }, '/static': { target: 'http://localhost:5000', changeOrigin: true } } } (9)前端路由守卫与首页路由模块决定用户能打开哪些页面,保护需登录/管理员的功能;首页为失物招领信息的主入口。前者保护需登录/管理员的功能页,把后端列表接口的数据呈现为可搜索、可翻页的卡片列表。路由守卫在每次跳转前检查权限:// anima-frontend/src/router/index.js router.beforeEach((to, from, next) => { const userStore = useUserStore() if (to.meta.requiresAuth && !userStore.isLoggedIn) { next({ name: 'Login', query: { redirect: to.fullPath } }) } else if (to.meta.requiresAdmin && !userStore.isAdmin) { next({ name: 'Home' }) } else { next() } }) 发布、编辑、我的发布、个人中心、消息等路由配置了 meta.requiresAuth,未登录会跳到登录页并记录原目标地址;管理端路由额外配置 requiresAdmin,非管理员会被拦回首页,避免前端直接进入无权页面。首页脚本负责拉取并刷新信息列表:// anima-frontend/src/views/HomeView.vue(脚本核心) async function loadItems() { const params = { page: page.value, per_page: 20, ...filters.value } const res = await itemsApi.getItems(params) if (res.data.code === 0) { items.value = res.data.data.items totalPages.value = res.data.data.pages } } function handleSearch(searchFilters) { filters.value = searchFilters page.value = 1 loadItems() } 页面挂载时调用 loadItems 请求 /api/items;用户在 SearchBar 中筛选时,handleSearch 更新条件并回到第 1 页再请求;分页组件切换页码时同样调用 loadItems。返回的 items 交给 ItemCard 渲染。至此,后端列表能力与前端浏览体验对接完成,构成平台最核心的使用路径:搜索筛选 → 浏览卡片 → 进入详情 → 联系或管理。3.7 开发总结本案例基于华为开发者空间云开发环境和华为云码道(CodeArts)代码智能体,完成了一个智能化失物招领平台的设计与开发。整个开发过程采用规范驱动开发(Spec-Driven Development,SDD)模式,通过需求规格文档、技术设计文档和编码任务文档逐步明确系统目标、架构设计和实现任务,实现了从需求分析到代码生成的流程化开发。在开发过程中,利用云开发环境提供统一稳定的运行环境,避免了本地环境配置和依赖管理带来的问题;通过 CodeArts Agent 对需求进行理解和拆解,自动生成项目 SDD,并依据 SDD 完成前后端代码构建。开发过程中结合实际运行测试结果,通过持续反馈与智能体协作,对系统功能、界面交互和代码结构进行优化,最终实现了用户管理、失物招领信息管理、搜索筛选、图片上传、站内消息等完整业务功能。通过本案例可以看到,AI Agent 驱动的软件开发模式能够有效降低应用开发门槛,提高原型构建和功能迭代效率。同时,基于 SDD 的开发方式使需求、设计与代码之间保持关联,增强了开发过程的可追溯性,为后续维护、扩展以及团队协作提供了良好的基础。四、释放资源4.1 关闭华为开发者空间云开发环境(容器)案例完成后,如无需继续使用该开发环境,可关闭对应云开发环境,避免持续占用开发资源。VS Code 中左侧导航栏选择”开发者空间,选中容器,点击“关机”按钮,弹框点击“确认”即可关闭容器。五、扩展资料说明华为云码道CodeArts实战速成:cid:link_1华为云开发者AI训练营:cid:link_2
-
借助华为云 CodeArts 实现微信公众号表情包机器人一、案例背景在日常使用微信的过程中,表情包经常分散在聊天记录和收藏列表中,手动保存和整理效率较低。为提升表情包保存效率,本项目实现了一个微信公众号表情包机器人:用户向公众号发送图片或表情后,服务端自动保存图片文件,并返回可访问的下载链接。本项目采用 Python Flask 开发微信公众号回调服务,使用 Docker Compose 部署到华为云 ECS。开发过程中,主要借助华为云 CodeArts 进行技术问题咨询、实现流程拆解、部署步骤梳理和问题排查。项目仓库:https://github.com/T0ngJ1PC/wechat-bot二、项目目标本项目需要实现以下能力:接收微信公众号服务器校验请求。接收用户发送的图片或表情消息。下载图片并保存到服务器目录。返回公网可访问的图片链接。对无法直接解析的收藏表情,记录待处理任务并交由后台服务补偿处理。使用 Docker Compose 在华为云 ECS 上部署 Web 服务和后台服务。开源前排除环境变量、登录态、二维码截图、用户素材等隐私文件。三、整体架构项目整体流程如下:微信用户 -> 向公众号发送图片或表情 -> 微信服务器回调 /wechat -> Flask 服务完成签名校验和消息解析 -> 下载图片并保存到 stickers/ -> 返回图片访问链接 无法直接解析的收藏表情 -> 写入 pending_unsupported.jsonl -> scraper 后台服务读取待处理任务 -> 尝试从公众号后台私信页面补偿抓取 -> 保存图片并更新状态文件主要模块如下:模块文件作用微信公众号回调服务app.py处理服务器校验、消息接收、图片保存和管理接口后台补偿服务mp_private_scraper.py处理无法直接解析的收藏表情容器编排docker-compose.yml启动 Web 服务和 scraper 服务镜像构建Dockerfile构建项目运行环境环境变量模板.env.example提供公开配置示例部署说明README-deploy.md记录基础部署命令本项目使用的华为云资源如下:华为云资源用途CodeArts辅助梳理技术细节、实现步骤和排障方法ECS部署并持续运行微信公众号回调服务弹性公网 IP提供公网访问入口安全组控制 HTTP、HTTPS 等端口访问域名与 SSL 证书提供稳定的 HTTPS 微信公众号回调地址四、CodeArts 辅助开发过程本项目中,CodeArts 主要用于辅助完成开发过程中的具体问题分析,而不是直接替代开发过程。实际使用方式是将问题拆分为明确的技术点,再根据 CodeArts 给出的建议进行代码实现和环境验证。开发阶段向 CodeArts 咨询的问题CodeArts 给出的简要结果实际落地结果需求拆解微信公众号表情包机器人需要拆分哪些模块建议拆分为回调接入、图片保存、后台补偿、状态管理和部署运维确定 Web 回调、图片保存、后台补偿、状态管理和部署模块回调接入微信公众号服务器校验如何实现说明 signature、timestamp、nonce、echostr 的校验关系实现 /wechat GET 校验和 check_sig() 签名校验函数消息处理图片、表情和不支持消息类型如何区分处理建议按消息类型分支处理,普通图片同步保存,异常类型进入待处理流程普通图片直接保存,收藏表情进入待处理队列安全模式EncodingAESKey 配置后如何处理加密消息建议将明文模式和安全模式分支处理,先解密再解析,回复时再加密使用 WeChatCrypto 解密消息并加密回复文件保存如何判断图片格式并生成访问链接建议根据响应头判断扩展名,并使用公网基础地址拼接下载链接根据响应头识别图片类型,保存到 stickers/ 目录后台补偿收藏表情无法直接解析时如何处理建议主回调快速响应,复杂抓取逻辑交给后台任务异步执行使用 pending_unsupported.jsonl 记录任务,由 scraper 后台处理容器部署Flask 服务和后台任务如何部署建议 Web 回调和 scraper 拆成两个 Compose 服务,并共享持久化目录使用 Docker Compose 拆分 web 和 scraper 两个服务ECS 部署云服务器部署需要准备哪些步骤建议按 ECS、端口、安全组、环境变量、日志验证拆分部署清单整理 ECS、端口、安全组、环境变量和日志检查流程公网域名域名解析、备案和 SSL 证书应如何准备建议先确认域名解析和备案状态,再配置 HTTPS 证书和反向代理形成域名解析、HTTPS 入口、证书绑定和回调地址检查项开源检查哪些文件不能提交到公开仓库建议排除环境变量、登录态、二维码、token 缓存、用户素材和本地工具状态完善 .gitignore 和 .dockerignore,排除隐私文件通过这种方式,CodeArts 在项目中承担了技术助手角色,主要用于明确实现路径、减少遗漏项,并辅助形成可复用的开发和部署清单。五、核心实现1. 微信公众号服务器校验微信公众号服务器配置时,需要对 signature、timestamp、nonce 和本地配置的 WX_TOKEN 进行校验。项目中通过 check_sig() 完成签名计算:def check_sig(signature, timestamp, nonce): if not signature or not timestamp or not nonce: return False sort_list = sorted([TOKEN, timestamp, nonce]) sha1 = hashlib.sha1(''.join(sort_list).encode()).hexdigest() return hmac.compare_digest(sha1, signature) 服务器校验通过后,接口返回微信传入的 echostr:@app.route('/wechat', methods=['GET']) def verify(): signature = request.args.get('signature', '') timestamp = request.args.get('timestamp', '') nonce = request.args.get('nonce', '') echostr = request.args.get('echostr', '') if check_sig(signature, timestamp, nonce): return text_response(echostr) return text_response('', 403) 2. 消息接收与图片保存用户向公众号发送图片或表情后,Flask 服务接收微信 POST 请求,解析 XML 消息内容。当消息类型为 image 或 emoji 时,读取图片地址并保存到服务器:if parsed.type in ('image', 'emoji'): pic_url = getattr(parsed, 'image', None) or getattr(parsed, 'picurl', None) if pic_url: link = download_and_save(pic_url) 图片下载后保存到 stickers/ 目录,并根据 BASE_URL 返回公网访问链接。这样用户发送图片后,即可收到下载地址。3. 收藏表情补偿处理部分收藏表情无法在微信公众号回调中直接获得原图。项目采用异步处理方式:主回调先记录待处理消息,后台 scraper 服务再尝试补偿抓取。收到无法直接解析的消息 -> 写入 pending_unsupported.jsonl -> scraper 后台读取任务 -> 登录公众号后台私信页面 -> 尝试识别并下载图片这种设计可以避免主回调阻塞,保证微信公众号服务器能够及时收到响应。4. 状态文件持久化项目运行过程中需要保存图片、待处理任务和后台登录态。Docker Compose 中将这些文件和目录挂载到宿主机,避免容器重建后数据丢失:volumes: - ./stickers:/opt/wechat-bot/stickers - ./mp_state.json:/opt/wechat-bot/mp_state.json - ./mp_scraper_state.json:/opt/wechat-bot/mp_scraper_state.json - ./mp_scraper_status.json:/opt/wechat-bot/mp_scraper_status.json - ./pending_unsupported.jsonl:/opt/wechat-bot/pending_unsupported.jsonl - ./access_token_cache.json:/opt/wechat-bot/access_token_cache.json六、华为云 ECS 部署1. 准备服务器在华为云 ECS 上准备 Linux 运行环境,并完成以下配置:绑定弹性公网 IP。配置安全组,放通 80、443 端口。安装 Docker 和 Docker Compose。如使用域名,将域名解析到 ECS 公网 IP。生产环境建议通过 Nginx 或 Caddy 提供 HTTPS 入口。2. 准备公网域名、备案和 SSL 证书微信公众号服务器地址需要公网可访问。部署阶段,CodeArts 辅助梳理了公网入口相关检查项,主要包括域名解析、备案状态、SSL 证书和反向代理配置。配置项CodeArts 给出的简要结果项目中的处理方式域名解析将业务域名解析到 ECS 绑定的公网 IP使用域名作为微信公众号回调地址备案状态如域名使用场景需要备案,应先完成备案状态确认在正式配置公众号回调前确认域名可用于公网访问SSL 证书微信公众号回调建议使用 HTTPS 地址为域名配置 SSL 证书,提供 https://你的域名/wechat反向代理HTTPS 入口转发到本地 Flask 服务端口使用 Nginx 或 Caddy 将请求转发到 127.0.0.1:5000访问验证回调地址配置前应先验证域名和证书可访问使用浏览器或 curl 检查 HTTPS 访问结果公网入口准备完成后,再将 .env 中的 BASE_URL 配置为正式域名下的图片访问地址:BASE_URL=https://你的域名/stickers3. 初始化目录和配置mkdir -p /opt/wechat-bot/stickers /opt/wechat-bot/verify cd /opt/wechat-bot cp .env.example .env touch pending_unsupported.jsonl touch mp_state.json mp_scraper_state.json mp_scraper_status.json access_token_cache.json.env 中配置公众号和服务运行所需参数:WX_TOKEN=替换为公众号后台Token WX_APPID=替换为公众号AppID WX_AES_KEY=替换为EncodingAESKey BASE_URL=https://example.com/stickers ADMIN_TOKEN=替换为管理接口Token STICKER_DIR=/opt/wechat-bot/stickers PENDING_FILE=/opt/wechat-bot/pending_unsupported.jsonl MP_QR_FILE=/opt/wechat-bot/mp_login_qr.png MP_STATUS_FILE=/opt/wechat-bot/mp_scraper_status.json4. 启动服务docker-compose build docker-compose up -d docker-compose ps 查看日志:docker-compose logs -f web docker-compose logs -f scraper健康检查:curl http://127.0.0.1:5000/返回以下内容表示服务正常:wechat-bot ok5. 配置微信公众号回调在微信公众号后台配置服务器地址:https://你的域名/wechat保存配置时,观察 web 服务日志。如果出现以下日志,说明服务器校验成功:VERIFY OK七、问题排查问题排查方向公众号服务器校验失败检查 WX_TOKEN 是否一致,反向代理是否保留 query string,回调路径是否为 /wechat加密消息解密失败检查 WX_APPID 和 WX_AES_KEY 是否正确图片保存成功但链接打不开检查 BASE_URL、安全组、HTTPS 入口和静态文件访问路径域名或 HTTPS 不可访问检查域名解析、备案状态、SSL 证书、证书绑定和反向代理配置容器重启后状态丢失检查 docker-compose.yml 中 volumes 是否正确挂载收藏表情未被处理检查 pending_unsupported.jsonl、scraper 日志和 mp_scraper_status.json管理接口无法访问检查 ADMIN_TOKEN 是否配置正确常用排查命令:docker-compose ps docker-compose logs -f web docker-compose logs -f scraper ls -lh stickers tail -n 20 pending_unsupported.jsonl八、安全与开源处理项目公开前,需要排除隐私信息和运行态文件。本项目已通过 .gitignore 和 .dockerignore 排除以下内容:类型示例环境变量.env、private.env公众号密钥WX_TOKEN、WX_APPSECRET、WX_AES_KEY管理密钥ADMIN_TOKEN登录态文件mp_state.jsontoken 缓存access_token_cache.json运行状态mp_scraper_state.json、mp_scraper_status.json二维码和截图mp_login_qr.png、mp_private_last.png用户素材stickers/*本地工具状态.arts/、.codeartsdoer/提交前可执行以下命令检查仓库跟踪文件:git ls-files也可进行敏感关键字扫描:rg -n "(token=|APPSECRET|ADMIN_TOKEN|WX_TOKEN|access_token|private.env|mp_state)" . 公开案例或向 CodeArts 提问时,也应避免粘贴真实密钥、登录二维码、OpenID、公网 IP、聊天记录和用户素材。九、实践效果通过本项目,完成了一个可部署、可运行、可开源的微信公众号表情包机器人。项目实现了公众号回调接入、图片保存、收藏表情补偿处理、Docker Compose 部署和隐私文件排除。CodeArts 在实践中的主要价值体现在:帮助拆解项目模块和实现流程。辅助确认微信公众号接入和消息处理细节。辅助整理 ECS 部署步骤和容器持久化配置。辅助梳理公网域名、备案状态、SSL 证书和 HTTPS 回调地址配置。辅助形成常见问题排查清单。辅助梳理开源前的隐私信息排除范围。十、后续优化方向当前方案可优化方向ECS 本地 stickers/ 存储迁移到 OBS 对象存储JSON 文件保存状态使用 SQLite、Redis 或云数据库Docker Compose 查看日志接入云日志服务单台 ECS 部署镜像化部署、多实例和负载均衡ADMIN_TOKEN 简单保护增加 IP 白名单、WAF 或访问审计手动向 CodeArts 提问沉淀固定提问模板和项目知识库对于个人项目,当前方案可以先满足基本使用需求。后续可根据访问量、稳定性要求和维护成本逐步接入更多云服务能力。十一、总结本案例基于华为云 CodeArts 和 ECS,完成了微信公众号表情包机器人的开发与部署。CodeArts 主要用于辅助技术咨询、流程拆解、部署梳理、公网域名与 SSL 配置检查、以及排障复盘;ECS 提供稳定的云上运行环境;Docker Compose 负责服务编排和运行维护。项目最终形成了从需求分析、代码实现、云上部署、问题排查到安全开源处理的完整实践流程,适合作为个人开发者使用 CodeArts 辅助完成云上应用开发的参考案例。项目仓库:https://github.com/T0ngJ1PC/wechat-bot参考资料华为云论坛:cid:link_4华为云 ECS 最佳实践:cid:link_2CodeArts 代码智能体产品介绍:cid:link_3CodeArts IDE 智能问答:cid:link_0CodeArts IDE 智能体对话:cid:link_1
-
[问题求助] Cannot connect to API: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in theCannot connect to API: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()这个问题怎么解决?
yd_253849762
发表于2026-07-21 10:54:24
2026-07-21 10:54:24
最后回复
CodeArts小助手-蚂蚁
2026-07-21 11:18:25
99 1 -
如题,有时候上下文里重复出现的文本(比如长路径、上下文代码中原有的重复)会被模型误判为复读,然后又会重新来一遍,再次陷入复读,如果不干预的话就是死循环,浪费很多算力。比如遇到一种情况,模型总结12345,到5的时候误判复读,于是又从1开始,到5的时候又误判……这个问题可以从几个维度优化:1. 判断复读的策略,可能存在优化的空间2. 识别到复读后的行为,尽可能从开始复读之前就近开始重新输出
-
Merchive个人藏品管理系统 - 应用构建案例文档一、概述1.1 案例介绍Merhive是一个专为影视周边/谷子收藏爱好者设计的个人藏品管理系统。项目(含演示视频)地址:https://gitcode.com/Christine_wxh/Merchive问题提出影视周边收藏爱好者普遍面临以下问题:藏品管理混乱:购买的大量周边(吧唧、立牌、色纸等)难以系统记录,容易遗忘或重复购买信息分散:藏品信息散落在各个平台、相册、备忘录中,查找困难缺乏统计:不知道总共花了多少钱、各类别占比如何、购入趋势如何纪念日遗忘:忘记藏品购入周年等有意义的日期隐私担忧:使用公共平台记录藏品担心隐私泄露Merhive提供一站式解决方案:本地化部署、数据完全自主掌控、多维度管理、趣味化交互。核心亮点:完整藏品管理:支持多图上传、自定义裁剪、多维度筛选数据可视化:ECharts统计图表数据安全:JWT认证、用户数据隔离、数据库备份隐私保护:每个部署者使用独立数据库,数据完全隔离1.2 适用对象个人开发者影视周边收藏爱好者1.3 案例时间本案例总时长预计60分钟(含环境搭建、代码部署、功能测试)。1.4 案例流程说明:准备开发环境(Node.js、Java、MySQL);克隆项目代码,配置数据库连接;初始化数据库,导入预设数据;启动后端服务,启动前端开发服务器;测试功能。1.5 资源总览本案例本地开发完全免费。资源名称规格说明Node.jsv18+ 或 v24前端运行环境Java JDK11后端运行环境Maven3.6+Java构建工具MySQL8.0+数据库二、系统架构设计2.1 整体架构本系统采用前后端分离架构:┌─────────────────────────────────────────────────────────────┐ │ 用户浏览器 │ │ (Vue 3 SPA应用) │ └─────────────────────────────────────────────────────────────┘ │ │ HTTP/HTTPS ▼ ┌─────────────────────────────────────────────────────────────┐ │ Nginx (可选) │ │ 静态资源 + 反向代理 │ └─────────────────────────────────────────────────────────────┘ │ ┌───────────────┴───────────────┐ │ │ ▼ ▼ ┌──────────────────────────┐ ┌──────────────────────────┐ │ 前端静态资源 │ │ 后端API服务 │ │ (HTML/CSS/JS) │ │ (Spring Boot 8080) │ │ │ │ │ │ - Vue 3 │ │ - RESTful API │ │ - Element Plus │ │ - JWT认证 │ │ - ECharts │ │ - 业务逻辑 │ │ - Axios │ │ - 数据访问 │ └──────────────────────────┘ └──────────────────────────┘ │ │ JDBC ▼ ┌──────────────────────────┐ │ MySQL 8.0 数据库 │ │ │ │ - 用户数据 │ │ - 藏品数据 │ │ - 标签数据 │ └──────────────────────────┘2.2 技术栈选型说明前端技术栈技术版本选型理由Vue 33.4+最新稳定版,Composition API提供更好的代码组织Vite6.x新一代构建工具,开发体验优秀,支持Node.js v24Element Plus2.7+Vue 3生态最成熟的UI组件库ECharts5.5+功能强大的数据可视化库Pinia2.1+Vue 3官方推荐的状态管理库Axios1.7+主流HTTP客户端,拦截器机制完善后端技术栈技术版本选型理由Spring Boot2.7.18企业级框架,生态成熟,Java 11兼容性好MyBatis-Plus3.5.5MyBatis增强版,简化CRUD操作MySQL8.0+主流关系型数据库,支持JSON类型JWT-无状态认证,适合前后端分离jBCrypt0.4密码加密,避免Spring Security过重依赖为什么不用Spring Security?Spring Security功能强大但配置复杂,默认会拦截所有请求返回401。本项目只需要密码加密和JWT认证,使用jBCrypt + 自定义拦截器更轻量灵活。2.3 数据库设计共7张表,采用用户隔离设计:表名说明用户隔离t_user用户表-t_collection藏品表user_id字段t_collection_image藏品图片表通过collection关联t_tag标签表user_id区分预设/自定义t_collection_tag藏品-标签关联表通过collection关联t_status_change_log状态变更日志表通过collection关联t_wish许愿表user_id字段三、使用华为云码道(CodeArts)代码智能体辅助开发3.1 开发流程概述本项目全程使用华为云码道(CodeArts)代码智能体辅助开发,遵循SDD(Specification-Driven Development)规范驱动开发流程:需求描述 → 需求规格设计 → 实现方案设计 → 编码任务规划 → 任务执行3.2 各阶段详细说明3.2.1 需求规格设计(spec.md)使用方式:向CodeArts描述项目需求,自动生成结构化需求文档。生成内容:功能需求列表非功能需求(性能、安全、可用性)验收标准约束条件效率提升:传统需求文档编写需要2-3小时,使用CodeArts仅需10分钟。3.2.2 实现方案设计(design.md)使用方式:CodeArts根据需求自动生成技术方案。生成内容:技术选型及理由架构设计数据库表设计API接口设计前后端交互设计效率提升:传统方案设计需要1-2天,使用CodeArts仅需30分钟。3.2.3 编码任务规划(tasks.md)使用方式:CodeArts将设计拆解为具体编码任务。生成内容:任务列表(按优先级排序)任务依赖关系预估工作量验收标准3.2.4 任务执行使用方式:逐个执行编码任务,CodeArts自动生成代码。辅助能力:自动生成Controller、Service、Mapper代码自动处理依赖注入自动生成前端组件和API调用实时调试和问题修复效率提升:传统编码需要2-3周,使用CodeArts仅需3天。3.3 CodeArts解决的关键问题问题传统方式CodeArts方式需求理解偏差反复沟通确认结构化文档自动生成技术选型困难调研对比耗时根据需求自动推荐代码风格不统一人工Code Review自动生成规范代码前后端接口对齐手动编写文档自动生成API封装Bug定位困难逐行排查智能分析错误原因四、环境和资源准备4.1 本地开发环境要求必备软件软件版本要求说明Node.jsv18+ 或 v24前端运行环境Java JDK11后端运行环境Maven3.6+Java构建工具MySQL8.0+数据库安装验证# 验证Node.js node -v # 应输出 v18.x.x 或 v24.x.x # 验证Java java -version # 应输出 11.x.x # 验证Maven mvn -v # 应输出 3.6.x 或更高 # 验证MySQL mysql --version # 应输出 8.0.x 4.2 创建数据库# 登录MySQL mysql -u root -p # 创建数据库 CREATE DATABASE merchive CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 退出MySQL exit; 五、构建Merhive应用5.1 获取项目代码# 克隆项目代码 git clone https://gitcode.com/Christine_wxh/Merchive.git cd merhive5.2 项目结构说明merhive/ ├── merchive-backend/ # 后端项目(Spring Boot) │ ├── pom.xml # Maven依赖配置 │ ├── src/main/java/com/merchive/ │ │ ├── controller/ # 控制器(接收HTTP请求) │ │ ├── service/ # 服务层(业务逻辑) │ │ ├── entity/ # 实体类(对应数据库表) │ │ ├── mapper/ # Mapper接口(数据库操作) │ │ ├── dto/ # 数据传输对象 │ │ ├── config/ # 配置类 │ │ └── util/ # 工具类 │ └── src/main/resources/ │ ├── application.yml # 配置文件(数据库连接等) │ └── db/ # 数据库初始化SQL │ ├── merchive-frontend/ # 前端项目(Vue 3) │ ├── package.json # 依赖配置 │ ├── vite.config.js # Vite配置 │ └── src/ │ ├── api/ # API封装 │ ├── router/ # 路由配置 │ ├── stores/ # Pinia状态管理 │ ├── components/ # 公共组件 │ └── views/ # 页面组件 │ └── README.md # 项目说明文档5.3 配置后端数据库连接编辑 merchive-backend/src/main/resources/application.yml:spring: datasource: url: jdbc:mysql://localhost:3306/merchive?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root # 你的MySQL用户名 password: 你的密码 # 你的MySQL密码 重要:每个部署者必须配置自己的数据库连接信息,确保数据隔离和安全。5.4 初始化数据库# 进入后端项目目录 cd merchive-backend # 执行数据库初始化脚本 mysql -u root -p --default-character-set=utf8mb4 merchive < src/main/resources/db/schema.sql mysql -u root -p --default-character-set=utf8mb4 merchive < src/main/resources/db/data.sql注意:--default-character-set=utf8mb4 请确保执行以避免中文乱码。5.5 启动后端服务# 在 merchive-backend 目录下执行 mvn spring-boot:run等待启动成功,看到类似输出:Started MerchiveApplication in 5.123 seconds后端运行在 http://localhost:80805.6 启动前端服务打开新的终端窗口:# 进入前端项目目录 cd merchive-frontend # 安装依赖(首次运行需要) npm install # 启动开发服务器 npm run dev前端运行在 http://localhost:51735.7 功能测试5.7.1 注册和登录浏览器访问 http://localhost:5173点击"立即注册"创建新账号使用注册的账号登录5.7.2 核心功能测试清单功能测试步骤预期结果注册登录注册新账号并登录成功登录,跳转首页添加藏品点击"添加藏品",填写表单,上传图片藏品创建成功图片裁剪上传图片后拖拽裁剪框生成自定义裁剪图片搜索筛选使用类别、价格、标签筛选返回符合条件的藏品统计看板点击"统计"菜单显示统计图表数据导出点击"导出Excel/PDF"下载文件成功数据库备份首页点击"导出备份"下载SQL备份文件账户管理点击头像→账户信息可修改用户名/密码六、解决方案6.1 用户数据隔离方案问题:多用户使用同一系统,如何保证数据隔离?解决方案:数据库层面:所有业务表设计user_id字段查询层面:所有查询强制带WHERE user_id = 当前用户ID权限校验:更新/删除操作前验证user_id是否匹配认证层面:JWT Token包含userId,无法伪造代码实现:// 所有查询都带userId过滤 LambdaQueryWrapper<Collection> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Collection::getUserId, userId); 6.2 文件上传存储方案问题:图片上传后如何存储和访问?解决方案:存储位置:服务器本地./uploads/collections/目录数据库存储:只存相对路径访问方式:通过WebMvcConfig映射为静态资源URL安全处理:使用Files.copy()替代transferTo(),解决Windows路径问题6.3 数据导出方案问题:如何导出藏品数据为Excel/PDF?解决方案:Excel导出:使用Apache POI生成标准表格PDF导出:使用OpenPDF生成卡片式布局,包含图片前端处理:Axios响应拦截器特殊处理blob类型响应6.4 数据库备份方案问题:如何实现一键数据库备份?解决方案:后端实现:调用mysqldump命令生成SQL文件前端触发:首页提供"导出备份"按钮文件下载:生成带时间戳的SQL文件,自动下载七、核心技术难点与解决思路7.1 Spring Security依赖冲突难点描述:引入spring-security-crypto进行密码加密时,传递依赖了Spring Security自动配置,导致所有请求返回401未授权。解决思路:分析依赖树,定位冲突来源排除Spring Security依赖改用org.mindrot:jbcrypt:0.4进行密码加密自定义JWT拦截器实现认证最终方案:<dependency> <groupId>org.mindrot</groupId> <artifactId>jbcrypt</artifactId> <version>0.4</version> </dependency> 7.2 MySQL中文乱码难点描述:Windows环境下MySQL客户端默认使用GBK编码读取SQL文件,导致中文数据插入后乱码。解决思路:分析字符编码流程:文件编码 → 客户端编码 → 服务器编码确认SQL文件为UTF-8编码强制指定客户端编码为utf8mb4最终方案:mysql -u root -p --default-character-set=utf8mb4 merchive < data.sql7.3 文件上传路径问题难点描述:file.transferTo()在Windows环境下因相对路径解析异常导致文件上传失败。解决思路:分析Spring文件保存机制发现transferTo()对相对路径处理不一致改用绝对路径 + Files.copy()最终方案:Path absolutePath = Paths.get(storagePath).resolve(filename).normalize(); Files.copy(file.getInputStream(), absolutePath); 7.4 Axios文件下载拦截难点描述:Axios响应拦截器对所有响应执行错误检查,导致blob类型响应(文件下载)失败。解决思路:分析Axios拦截器执行流程发现blob响应也被拦截器处理增加类型判断跳过blob响应最终方案:if (response.config.responseType === 'blob') { return response; // 跳过blob响应的错误检查 } 7.5 esbuild与Node.js版本兼容难点描述:esbuild 0.21.x在Node.js v24上崩溃,报错STATUS_STACK_BUFFER_OVERRUN。解决思路:查阅esbuild版本兼容性文档发现esbuild 0.21.x不支持Node.js v24升级Vite到6.x,esbuild到0.25.5最终方案:{ "devDependencies": { "vite": "^6.4.3", "esbuild": "^0.25.5" } } 八、演示视频请观看Merchive项目演示视频(Merchive项目演示视频.mp4)了解完整功能展示。项目演示视频地址:https://gitcode.com/Christine_wxh/Merchive/blob/main/Merchive项目演示视频.mp4
-
一、概述1.1 案例介绍本案例使用华为云码道(CodeArts)代码智能体,从零开始完成一个花店管理系统(花语轩)的全流程开发与云端部署。涵盖需求分析、方案设计、前后端编码、调试验证、ECS部署上线全流程,体验AI辅助编程的高效开发模式。网站url:http://124.71.227.253,仓库地址:https://gitcode.com/2301_80246598/Flower-shop-web.git1.2 适用对象高校学生个人开发者1.3 案例时间本案例总时长预计90分钟。1.4 案例流程说明:在华为云控制台购买ECS弹性云服务器,配置VPC与安全组;使用华为云码道CodeArts代码智能体,通过自然语言对话完成需求规格设计、方案设计和编码任务规划;在CodeArts辅助下完成前后端代码编写、调试和功能验证;将项目构建产物上传至ECS,配置MySQL、Nginx等服务,完成线上部署。1.5 资源总览本案例预计花费164.38元。体验完成后请及时释放资源,避免产生多余的费用。资源名称规格单价(元)华为云码道(CodeArts)代码智能体专业版105.77弹性云服务器 ECS1 vCPU | 1GiB | Huawei Cloud EulerOS 2.030.60云硬盘 EVS高IO | 40GiB28.00虚拟私有云 VPC按需0.01二、环境和资源准备2.1 购买ECS弹性云服务器登录华为云控制台,点击菜单 服务列表 > 计算 > 弹性云服务器,点击"购买弹性云服务器"。选择如下配置:- 计费模式:包年/包月- 区域:可选就近区域- 规格:通用计算型 | 1 vCPU | 1GiB- 镜像:Huawei Cloud EulerOS 2.0 标准版 64位- 系统盘:高IO | 40GiB- 网络:默认VPC和安全组设置登录凭证:root用户,密码自定义。点击"立即购买",等待ECS创建完成。注意:由于1GiB内存较小,后续部署时需为MySQL配置低内存模式并添加2GB Swap交换分区。2.2 开通华为云码道CodeArts登录华为云码道,开通CodeArts服务。在CodeArts中创建项目,进入代码智能体(CodeArts IDE)开发环境。2.3 本地开发环境要求在CodeArts IDE中开发时,需确保本地已安装以下工具:JDK 17+Maven 3.8+Node.js 18+MySQL 8.0+说明:CodeArts代码智能体可在对话中直接执行命令,无需手动切换终端。三、码道研发花店管理系统3.1 需求规格设计在CodeArts代码智能体中,通过自然语言描述项目需求,智能体自动生成需求规格文档(spec.md)。向CodeArts输入需求描述:开发一个花店管理系统(花语轩),课程项目,实现鲜花的分类管理、上架下架管理、会员管理(普通会员/黄金会员/白金会员/普通顾客)、购物车、模拟付款、畅销统计等完整业务闭环。CodeArts自动生成需求规格文档,包含:用户注册即成为普通会员,累计消费金额到达门槛自动升级(≥500元→黄金会员9折,≥2000元→白金会员8折),等级不降级付款做"模拟付款"即可完整业务流程:用户登录→浏览鲜花→加入购物车→修改数量/勾选结算→生成订单→计算折扣→确认付款→扣减库存(乐观锁)→记录销量→清空已购购物车项→更新累计消费→检测会员升级前端需展示鲜花图片技术栈:后端 Spring Boot 3.x + MyBatis-Plus + MySQL 8.0 + JWT,前端 Vue 3 + Element Plus + Pinia3.2 方案设计与任务规划3.2.1 设计文档生成CodeArts根据需求规格自动生成实现方案设计文档(design.md),包括:系统架构:前后端分离,后端Spring Boot提供RESTful API,前端Vue 3 SPA数据库设计:6张核心表(t_member、t_category、t_flower、t_cart_item、t_order、t_order_item)API设计:6组Controller(Member、Category、Flower、Cart、Order、Admin)会员等级与折扣策略3.2.2 编码任务规划CodeArts根据设计文档自动生成编码任务清单(tasks.md),将开发工作分解为可执行的任务项。3.3 后端开发3.3.1 项目结构CodeArts自动生成后端项目结构:flower-shop-server/ ├── pom.xml ├── src/main/java/com/flowershop/ │ ├── FlowerShopApplication.java │ ├── common/ # UnifiedResponse, ErrorCode, BusinessException │ ├── config/ # JwtUtil, CorsConfig, MyBatisPlusConfig, WebMvcConfig │ ├── filter/ # JwtAuthFilter │ ├── entity/ # Member, Category, Flower, CartItem, Order, OrderItem │ ├── entity/enums/ # MemberLevel, MemberRole, FlowerStatus, OrderStatus │ ├── dto/ # 11个请求DTO │ ├── vo/ # 14个响应VO │ ├── mapper/ # 6个Mapper接口 │ ├── service/impl/ # 6个Service实现 │ └── controller/ # 6个Controller └── src/main/resources/ ├── application.yml ├── schema.sql └── data.sql 3.3.2 关键代码说明1) 会员等级自动升级(MemberServiceImpl.java)会员等级根据累计消费自动升级,升级后不降级:public void checkAndUpgradeLevel(Long memberId) { Member member = getById(memberId); BigDecimal totalSpent = member.getTotalSpent(); MemberLevel oldLevel = member.getLevel(); MemberLevel newLevel = oldLevel; if (totalSpent.compareTo(new BigDecimal("2000")) >= 0) { newLevel = MemberLevel.PLATINUM; } else if (totalSpent.compareTo(new BigDecimal("500")) >= 0) { newLevel = MemberLevel.GOLD; } if (newLevel != oldLevel) { member.setLevel(newLevel); updateById(member); } } 2) 乐观锁扣减库存(FlowerMapper.java)使用MyBatis-Plus的乐观锁机制防止超卖:@Update("UPDATE t_flower SET stock = stock - #{quantity}, sales = sales + #{quantity} WHERE id = #{id} AND stock >= #{quantity}") int deductStock(@Param("id") Long id, @Param("quantity") Integer quantity); 3) JWT认证过滤器(JwtAuthFilter.java)公开路径放行,其余请求需携带JWT Token:private static final String[] PUBLIC_PATHS = { "/api/v1/member/login", "/api/v1/member/register", "/api/v1/flowers", "/api/v1/categories", "/images/**", "/error" }; 3.3.3 数据库初始化schema.sql定义6张核心表,data.sql初始化1个管理员、6个分类、16款鲜花:3.3.4 编译与启动在CodeArts终端中执行:.\start-backend.bat3.4 前端开发3.4.1 项目结构CodeArts自动生成前端项目结构:flower-shop-web/ ├── vite.config.js ├── package.json ├── src/ │ ├── main.js │ ├── App.vue │ ├── router/index.js │ ├── stores/ # user.js, cart.js (Pinia) │ ├── utils/request.js # Axios封装 │ ├── api/ # 6个API模块 │ └── views/ # 8个用户页面 + 4个管理页面 └── dist/ # 生产构建产物 3.4.2 关键配置说明1) Vite代理配置(vite.config.js)开发环境下,前端通过Vite代理访问后端API和图片资源:server: { port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true }, '/images': { target: 'http://localhost:8080', changeOrigin: true } } } 2) 路由守卫(router/index.js)根据用户角色控制页面访问权限,管理员可访问管理后台页面。3.4.3 安装依赖与启动.\start-fronted.bat 3.5 功能验证与Bug修复在CodeArts辅助下,通过浏览器自动化测试完整业务流程,发现并修复了以下Bug:3.5.1 图片显示问题问题:外部图片URL存在防盗链,前端无法显示鲜花图片。解决:起初CodeArts创建SVG占位图放在后端static/images/目录下,数据库中image_url改为本地路径如/images/rose1.svg。后续提供了可用的外部图片URL后,替换回外部链接。3.5.2 Vite代理未覆盖images路径问题:vite.config.js只代理了/api,但图片路径/images/**也需要代理到后端8080端口。解决:在vite.config.js中添加/images代理规则。3.5.3 创建订单时total_amount为null问题:OrderServiceImpl.createOrder()先执行insert再计算金额,导致total_amount字段为null(数据库不允许为空)。解决:调整为先计算所有金额,再一次性插入订单。3.5.4 管理员菜单不显示问题:MemberVO缺少role字段,前端无法判断用户是否为管理员。解决:在MemberVO中添加role字段,并在toMemberVO()方法中设置vo.setRole(member.getRole().name())。3.5.5 完整流程验证在CodeArts辅助下验证了完整的用户和管理员流程:用户流程:注册→登录→浏览鲜花→加入购物车→结算→生成订单→确认付款→状态变为"已支付"→购物车清空→销量更新管理员流程:admin登录→商品管理(含编辑/下架)→分类管理(含增删改)→会员管理(显示等级/消费)→畅销统计(排名/时间筛选)四、ECS部署项目4.1 构建生产版本4.1.1 构建前端在CodeArts终端中执行:cd flower-shop-web npm run build 构建产物输出到dist/目录。4.1.2 后端JAR包后端已通过mvn package -DskipTests构建,产物为flower-shop-server/target/flower-shop-server-1.0.0.jar。4.2 上传文件到ECS使用Python paramiko库通过SSH将构建产物上传到ECS服务器的/opt/flower-shop/目录:flower-shop-server.jar — 后端JAR包dist/ — 前端构建产物目录schema.sql — 数据库建表脚本data.sql — 数据库初始数据脚本4.3 安装服务器环境通过SSH连接ECS,安装运行所需软件:4.3.1 安装JDK 17ECS默认yum源无JDK 17,通过华为云镜像下载安装:curl -fsSL 'https://repo.huaweicloud.com/openjdk/17.0.2/openjdk-17.0.2_linux-x64_bin.tar.gz' -o /tmp/jdk17.tar.gz tar -xzf /tmp/jdk17.tar.gz -C /usr/local/ ln -sf /usr/local/jdk-17.0.2 /usr/local/jdk17 /usr/local/jdk17/bin/java -version 4.3.2 安装MySQL 8与Nginxyum install -y mysql-server nginx 4.3.3 配置MySQL低内存模式由于ECS仅1GiB内存,需为MySQL配置低内存模式并添加Swap:dd if=/dev/zero of=/swapfile bs=1M count=2048 chmod 600 /swapfile mkswap /swapfile swapon /swapfile cat > /etc/my.cnf.d/low-memory.cnf << 'EOF' [mysqld] performance_schema=OFF innodb_buffer_pool_size=128M innodb_log_buffer_size=8M max_connections=30 EOF 4.4 配置MySQL数据库4.4.1 重置root密码MySQL 8首次安装后root密码为随机值,需通过skip-grant-tables模式重置:systemctl stop mysqld systemctl set-environment MYSQLD_OPTS="--skip-grant-tables --skip-networking" systemctl start mysqld mysql -uroot -e "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '246537Znc'; FLUSH PRIVILEGES;" systemctl stop mysqld systemctl unset-environment MYSQLD_OPTS systemctl start mysqld 4.4.2 创建数据库并导入数据mysql -uroot -p246537Znc -e "CREATE DATABASE IF NOT EXISTS flower_shop DEFAULT CHARACTER SET utf8mb4;" mysql -uroot -p246537Znc flower_shop < /opt/flower-shop/schema.sql mysql -uroot -p246537Znc flower_shop < /opt/flower-shop/data.sql 4.5 启动后端服务4.5.1 直接启动nohup /usr/local/jdk17/bin/java -Xmx256m -jar /opt/flower-shop/flower-shop-server.jar > /opt/flower-shop/backend.log 2>&1 & 4.5.2 配置systemd开机自启创建服务文件/etc/systemd/system/flower-shop.service:[Unit] Description=Flower Shop Backend After=network.target mysqld.service [Service] Type=simple ExecStart=/usr/local/jdk17/bin/java -Xmx256m -jar /opt/flower-shop/flower-shop-server.jar Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target 启用服务:systemctl daemon-reload systemctl enable flower-shop 4.6 配置Nginx反向代理创建Nginx配置文件/etc/nginx/conf.d/flower-shop.conf:server { listen 80; server_name _; root /opt/flower-shop/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } 启动Nginx:rm -f /etc/nginx/conf.d/default.conf nginx -t && systemctl restart nginx && systemctl enable nginx 4.7 防火墙放通80端口firewall-cmd --permanent --add-service=http firewall-cmd --reload iptables -I INPUT -p tcp --dport 80 -j ACCEPT 4.8 验证部署结果在浏览器中访问 [http://<ECS公网IP>](http://124.71.227.253),确认网站正常运行:五、网站功能说明5.1 管理员功能说明管理员账号:admin密码:admin1235.1.1 鲜花的分类管理可进行新增、删除、编辑分类名的操作,如新增洋桔梗类鲜花,删除某类鲜花,修改某类鲜花名称。5.1.2 鲜花上架下架管理下架某类鲜花后首页该花束不可见,可重新上架5.1.3 会员管理5.1.4 统计畅销鲜花5.2 用户功能说明5.2.1 会员等级消费升级用户注册即成为普通会员,累计消费金额到达门槛自动升级(≥500元一黄金会员9折,≥2000元白金会员8折),等级不降级。白金会员后续消费享受8折优惠。5.2.2 基本购物功能至此,码道驱动,打造花店管理系统案例结束!
-
一、概述1.1 案例介绍求职准备通常包含简历整理、岗位理解、技能差距分析、项目经历补充和面试训练等多个环节。传统方式需要用户在招聘网站、开源平台、笔记工具和面试题库之间反复切换,流程分散、反馈慢,也难以形成持续改进闭环。本案例围绕这一痛点,基于华为云码道代码智能体的规范开发模式,构建一个"面试模拟助手"应用。系统支持账号注册登录、简历上传与解析、岗位匹配分析、技能差距识别、GitHub 项目搜索与推荐、项目实践路径生成、模拟面试、面试报告和用户级 API Key 配置等功能。项目采用前后端分离架构:前端:Vue3、TypeScript、Element Plus、Pinia、Vite。后端:FastAPI、Uvicorn、SQLAlchemy、SQLite,支持后续切换 PostgreSQL。AI 能力:DeepSeek API,用于简历分析、项目推荐、技能指导和模拟面试。外部接口:GitHub API,用于开源项目搜索。文件解析:pdfplumber 解析 PDF,python-docx 解析 Word。部署方式:支持 Windows 桌面应用打包和华为云 ECS 云服务部署。整个过程先使用码道完成规范化开发,再通过 AI Shell 完成云资源规划、Terraform 编排、ECS 初始化、应用部署和访问验证,展示从自然语言需求到公网可访问应用的完整交付流程。案例技术选型:华为云码道(CodeArts)代码智能体:集代码大模型、AI IDE、Code Agent 为一体的智能编码产品。本案例使用其中的规范开发模式,从需求分析、技术设计、任务拆解到代码实现、测试验证,形成较完整的开发闭环。开发者空间 AI Shell:华为云提供的智能 AI 命令行工具。本案例通过自然语言对话完成项目结构分析、ECS 资源规划、Terraform 配置生成、云资源创建、远程部署和访问验证。Terraform:用于声明式创建华为云资源,包括 VPC、子网、安全组、ECS、EIP 和 EIP 绑定,降低手动配置云资源的复杂度。通过码道规范开发模式与 AI Shell 对话式部署的结合,本案例完成了"AI 求职辅助应用"的开发、部署和验证,让学生或个人开发者能够以较低门槛体验完整云上交付过程。仓库链接:interview_assistant:基于 FastAPI 与 Vue3 的面试模拟助手桌面应用 - AtomGit本项目部署链接:http://49.4.115.167/1.2 适用对象个人开发者:希望学习 Vue + FastAPI + AI API 的完整应用开发与云部署流程。高校学生:希望完成一个可展示、可部署、可写入课程作品或简历的 AI 项目。求职产品开发者:希望快速搭建简历分析、项目推荐和模拟面试类应用原型。云开发初学者:希望通过 AI Shell 理解 ECS、EIP、VPC、安全组和 Terraform 的基本用法。1.3 案例时间本案例总时长预计 90 到 120 分钟:环境准备与码道项目导入:10 分钟。规范开发模式分析、设计与任务拆解:20 分钟。代码开发与本地验证:30 分钟。AI Shell 分析部署资源并生成 Terraform:15 分钟。执行 Terraform 创建 ECS 并部署应用:20 到 30 分钟。公网访问验证与资源清理:10 分钟。如果已经具备项目源码、华为云账号和开发者空间环境,部署阶段可以压缩到 30 分钟左右。1.4 案例流程说明:用户首先在本地 PC 中打开华为云码道代码智能体,通过规范开发模式完成"面试模拟助手(Interview Assistant)"项目的需求分析、技术设计、任务拆解和代码生成。项目代码开发完成后,将源码提交到 GitCode 仓库中,作为后续云端部署的代码来源。随后,用户进入开发者空间 AI Shell,通过自然语言指令调用 AI Cli 工具,从 GitCode 拉取项目源码,并在云端环境中完成资源规划、Terraform 配置生成、ECS 创建、应用依赖安装、前后端构建、Nginx 反向代理和 systemd 服务配置。部署完成后,用户即可通过公网访问云端运行的 Interview_assistant 应用。1.5 资源总览本案例预计花费约 0 到 20 元,具体取决于 ECS 按需运行时长和带宽计费情况。资源名称规格费用说明华为云码道(CodeArts)代码智能体体验版免费开发者空间 AI Shell标准环境免费ECS 弹性云服务器s6.medium.2,1 vCPU / 2GB按需计费EIP 弹性公网 IP5 Mbps按流量或带宽计费VPC / 子网 / 安全组基础网络资源通常不单独计费EVS 系统盘Ubuntu 22.04,40GB SSD随 ECS 计费二、系统架构设计2.1 整体架构项目采用前后端分离架构,后端使用 FastAPI 提供 RESTful API,前端使用 Vue3 构建单页面应用。支持两种部署方式:桌面应用模式:通过 PyInstaller 和 pywebview 打包为 Windows 桌面应用,适合个人用户本地使用。云服务模式:部署到华为云 ECS,通过 Nginx 反向代理,支持多用户公网访问。数据存储使用 SQLite,用户配置和 API Key 按用户隔离存储。AI 能力通过 DeepSeek API 接入,GitHub 项目搜索通过 GitHub API 接入。2.2 项目结构说明项目核心结构如下:D:\Huawei |-- backend | |-- main.py # FastAPI 应用入口 | |-- config.py # 配置、数据目录、API Key、CORS | |-- database.py # SQLAlchemy 数据库连接和迁移 | |-- interview_assistant.spec # 后端 PyInstaller 打包配置 | |-- requirements.txt # 后端依赖 | |-- adapters | | |-- deepseek.py # DeepSeek API 适配器 | | |-- github_api.py # GitHub API 适配器 | |-- routers | | |-- auth.py # 注册登录 | | |-- resume.py # 简历上传和分析 | | |-- project.py # 项目搜索和推荐 | | |-- interview.py # 模拟面试 | | |-- system.py # API Key 管理 | |-- services | | |-- file_parser.py # PDF / Word 解析 |-- frontend | |-- package.json # 前端依赖 | |-- src | |-- router # Vue Router | |-- stores # Pinia 状态管理 | |-- utils/request.ts # Axios 请求封装 | |-- views # 登录、简历、项目、面试、设置页面 |-- launcher | |-- launcher.py # Windows 桌面启动器 | |-- requirements.txt # launcher 依赖 |-- installer | |-- setup.iss # Inno Setup 安装脚本 |-- deploy | |-- nginx.conf # Nginx 反向代理配置 | |-- interview-assistant.service # systemd 服务配置 | |-- init.sh # ECS 初始化部署脚本 |-- terraform | |-- providers.tf # HuaweiCloud Provider | |-- variables.tf # 变量定义 | |-- main.tf # VPC、子网、安全组、ECS、EIP | |-- outputs.tf # EIP、SSH 命令等输出 |-- tests | |-- test_windows_packaging.py # Windows 打包行为测试 | |-- test_account_api_isolation.py # 多账号 API Key 隔离测试 |-- build.py # 本地一键构建脚本 |-- config.ini.template # 默认配置模板 |-- README.md # 项目说明2.3 后端核心逻辑2.3.1 应用入口后端入口文件为 backend/main.py。它完成以下工作:创建 FastAPI 应用。注册 CORS 中间件。注册 auth、resume、project、interview、user、system 等路由。初始化数据目录、日志目录、上传目录和配置目录。调用 migrate_db() 创建或迁移 SQLite 表结构。在生产部署中监听 0.0.0.0,由 Nginx 反向代理访问。部署前,码道根据 AI Shell 的上云要求完成了关键调整:修改项文件说明后端监听地址backend/main.py从 127.0.0.1 调整为 0.0.0.0,适配 ECS 服务监听动态 API 地址backend/config.py避免硬编码 localhost,支持根据请求动态推断SECRET_KEYbackend/config.py改为环境变量优先,支持生产随机密钥CORS 配置backend/config.py支持环境变量 EXTRA_CORS_ORIGINS生产环境配置backend/.env.production新建生产配置模板Nginx 配置deploy/nginx.conf反向代理 80 到 FastAPI 8000systemd 服务deploy/interview-assistant.service进程守护和开机自启2.3.2 用户级 API Key 隔离API Key 相关逻辑位于 backend/config.py 和 backend/routers/system.py。系统按当前登录用户 ID 生成独立配置路径:def _get_user_api_key_file(user_id: int) -> str: user_dir = os.path.join(USER_CONFIG_DIR, f'user_{user_id}') os.makedirs(user_dir, exist_ok=True) return os.path.join(user_dir, 'api_keys.ini') 读取、写入和状态检查函数都支持 user_id 参数:def read_api_key(key_name: str, user_id: int = 0) -> str | None: ... def write_api_key(key_name: str, key_value: str, user_id: int = 0) -> None: ... def get_all_api_keys_status(user_id: int = 0) -> dict: ... 系统设置接口通过 get_current_user 获取当前用户,并将 user.id 传入 API Key 操作:@router.put("/api-keys") def update_api_key(req: ApiKeyUpdateRequest, user: User = Depends(get_current_user)): ... write_api_key(key_name, key_value, user_id=user.id) DeepSeek 和 GitHub 适配器也接收 user_id,确保 AI 调用使用当前账号自己的密钥:adapter = DeepSeekAdapter(user_id=user.id) adapter = GitHubAdapter(user_id=user.id) 2.4 前端核心逻辑前端位于 frontend 目录,使用 Vue3 + TypeScript + Element Plus。主要页面包括:页面文件功能登录src/views/auth/LoginView.vue用户登录并保存 token注册src/views/auth/RegisterView.vue创建新账号仪表盘src/views/dashboard/DashboardView.vue展示简历、项目和面试概况简历优化src/views/resume/ResumeView.vue上传简历、分析岗位匹配项目推荐src/views/project/ProjectView.vue搜索项目、刷新推荐、生成实践路径模拟面试src/views/interview/InterviewView.vue创建面试会话并答题面试报告src/views/interview/InterviewReportView.vue查看评分与改进建议设置src/views/settings/SettingsView.vue配置 DeepSeek、GitHub 和 TTS请求封装位于 frontend/src/utils/request.ts,会自动读取本地 token,并在接口返回 401 时尝试刷新登录态。三、使用华为云码道(CodeArts)代码智能体辅助完成代码开发及调试3.1 代码智能体在项目开发中的应用华为云码道(CodeArts)代码智能体在本项目中发挥了关键作用,辅助完成了以下开发任务:需求分析与规格定义:根据自然语言需求生成详细的需求规格文档,明确功能边界和技术要求。技术设计与架构规划:基于需求规格生成完整的技术设计方案,包括前后端技术选型、数据库设计、API 设计等。任务拆解与排期:将复杂项目拆解为可执行的开发任务,形成清晰的开发路线图。代码生成与补全:智能体根据需求描述自动生成后端 API 路由、前端组件、数据库模型等代码片段,显著减少手动编码工作量。代码审查与优化:智能体对现有代码进行审查,识别潜在的性能问题、安全漏洞和代码风格不一致,并提供优化建议。调试支持:智能体协助定位运行时错误,分析日志输出,提供修复建议,加速问题排查。测试用例生成:智能体根据功能描述自动生成单元测试和集成测试用例,提高测试覆盖率。文档生成:智能体根据代码注释和结构自动生成 API 文档、部署说明和用户手册。架构设计建议:智能体提供前后端分离架构、数据库设计、API 设计等方面的最佳实践建议。3.2 规范开发模式流程3.2.1 输入需求并启动规范开发在码道代码智能体中切换到规范开发模式后,可以输入类似提示词:我希望开发一个面向求职准备场景的面试模拟助手系统。 系统需要支持以下功能: - 用户注册登录 - 简历上传与解析 - 岗位匹配分析 - 技能差距识别 - 开源项目推荐 - 项目实践路径生成 - 模拟面试 - 面试报告 - 用户个人 API Key 配置。 前端使用 Vue3 + TypeScript + Element Plus,后端使用 FastAPI + SQLAlchemy,AI 能力接入 DeepSeek API。 请按规范开发模式帮我完成需求分析、技术设计、任务拆解、代码实现和测试验证。码道会按照规范开发流程推进,先分析业务目标和功能边界,再生成技术设计与任务列表,最后进入代码实现与测试阶段。3.2.2 项目核心能力模块功能说明用户认证注册、登录、刷新 token、JWT 鉴权简历解析上传 PDF / Word 简历,解析文本并保存岗位分析输入目标岗位 JD,生成匹配分数、差距和建议项目推荐结合简历和岗位目标,通过 DeepSeek 与 GitHub API 推荐项目实践路径为推荐项目生成阶段化实践路线模拟面试根据简历和岗位生成面试题,支持答题、追问和报告用户设置保存 DeepSeek API Key、GitHub Token、TTS 服务地址部署适配支持 Nginx 反向代理、systemd 守护、生产环境变量3.3 具体应用场景3.3.1 后端开发辅助FastAPI 路由生成:智能体根据需求描述自动生成完整的 CRUD 路由,包括请求验证、数据库操作和响应格式化。SQLAlchemy 模型设计:智能体协助设计数据库表结构,生成符合业务需求的 ORM 模型。错误处理与日志:智能体建议统一的错误处理中间件和日志记录策略。API Key 加密存储:智能体提供安全的 API Key 存储方案,包括加密算法选择和密钥管理策略。3.3.2 前端开发辅助Vue3 组件生成:智能体根据设计稿或功能描述生成 Vue 单文件组件,包括模板、脚本和样式。TypeScript 类型定义:智能体根据后端 API 响应自动生成 TypeScript 接口定义,确保类型安全。状态管理设计:智能体建议 Pinia store 结构,优化状态管理和组件通信。路由守卫实现:智能体生成认证和授权路由守卫,保护需要登录的页面。3.3.3 桌面应用打包辅助PyInstaller 配置优化:智能体提供 PyInstaller spec 文件的最佳配置,解决隐藏控制台、资源打包等问题。pywebview 集成:智能体协助实现桌面窗口启动器,管理后端进程和前端页面加载。Inno Setup 脚本编写:智能体生成完整的安装脚本,包含文件复制、快捷创建和卸载清理。3.3.4 测试与调试辅助单元测试生成:智能体根据业务逻辑自动生成 pytest 测试用例,覆盖正常和异常场景。API 测试脚本:智能体生成 Postman 风格的 API 测试脚本,方便接口验证。性能调优建议:智能体分析代码性能瓶颈,提供数据库查询优化、缓存策略等建议。安全审计:智能体检查代码中的安全漏洞,如 SQL 注入、XSS、CSRF 等,并提供修复方案。3.4 开发效率提升通过华为云码道(CodeArts)代码智能体的辅助,本项目开发效率提升显著:开发时间缩短约 40%:智能体自动生成基础代码,减少重复劳动。代码质量提升:智能体的代码审查和建议帮助保持代码风格一致,减少潜在 bug。文档完整性提高:智能体自动生成的文档覆盖全面,减少手动编写工作量。问题解决速度加快:调试支持功能帮助快速定位和修复问题。四、解决方案4.1 整体解决方案本项目提供了一套完整的面试模拟助手解决方案,包括:用户管理:注册、登录、JWT 认证、Token 刷新。简历管理:PDF/Word 简历上传、解析、存储、编辑。岗位匹配分析:基于 AI 的简历与岗位描述匹配度分析、技能差距识别。开源项目推荐:根据技能差距推荐 GitHub 开源项目,生成实践路径。模拟面试:AI 生成面试题、实时评估答案、生成面试报告。多部署模式:支持 Windows 桌面应用打包和华为云 ECS 云服务部署。多用户隔离:每个用户的 API Key、简历数据、面试记录完全隔离。4.2 技术栈选择组件技术选型理由后端框架FastAPI高性能、异步支持、自动 API 文档生成数据库SQLite轻量、无需单独部署、适合桌面应用和简单云部署ORMSQLAlchemyPython 生态成熟、支持异步操作前端框架Vue3 + TypeScript响应式、类型安全、生态丰富UI 组件库Element Plus企业级组件、与 Vue3 完美集成状态管理PiniaVue3 官方推荐、TypeScript 友好构建工具Vite快速构建、热重载、开发体验好桌面启动器pywebview轻量、跨平台、可嵌入浏览器打包工具PyInstaller将 Python 代码打包为独立 exe安装包生成Inno SetupWindows 安装包制作、免费开源云部署华为云 ECS弹性计算、按需付费、稳定可靠基础设施即代码Terraform声明式云资源配置、可重复部署反向代理Nginx高性能、稳定、配置简单进程管理systemdLinux 标准服务管理、开机自启4.3 部署方案开发环境:前后端分离运行,便于调试。桌面应用:打包为 Windows 桌面应用,用户一键安装使用。云服务环境:部署到华为云 ECS,通过 Nginx 反向代理,支持多用户公网访问。数据存储:用户数据存储在本地 %APPDATA% 目录(桌面应用)或 /opt/interview_assistant/data(云部署),确保数据持久化。配置管理:API Key 等敏感配置按用户加密存储,支持多用户隔离。五、核心技术难点与解决思路5.1 多用户 API Key 隔离难点:多个用户使用同一台电脑或同一云服务时,需要确保每个用户的 API Key 相互隔离,避免密钥泄露和混用。解决方案:按用户 ID 创建独立配置目录:%APPDATA%\面试模拟助手\config\user_<用户ID>\(桌面应用)或 /opt/interview_assistant/data/config/user_<用户ID>/(云部署)每个用户的 API Key 加密存储在自己的配置文件中所有 API 调用都传入当前用户 ID,确保使用正确的密钥系统设置接口只操作当前用户的配置实现代码:def _get_user_api_key_file(user_id: int) -> str: user_dir = os.path.join(USER_CONFIG_DIR, f'user_{user_id}') os.makedirs(user_dir, exist_ok=True) return os.path.join(user_dir, 'api_keys.ini') 5.2 桌面应用无控制台窗口难点:打包后的 Python 后端 exe 会显示黑色控制台窗口,影响用户体验。解决方案:在 PyInstaller spec 中设置 console=False桌面启动器使用 subprocess.CREATE_NO_WINDOW 标志启动后端进程后端使用 uvicorn.run(..., log_config=None) 避免日志输出到控制台实现代码:# PyInstaller spec console=False # 启动器代码 startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE process = subprocess.Popen( [exe_path, '--port', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo, creationflags=subprocess.CREATE_NO_WINDOW ) 5.3 前端静态资源嵌入后端难点:桌面应用需要将前端构建产物嵌入后端 exe,避免依赖外部文件;云部署需要将前端资源部署到合适位置。解决方案:前端使用 Vite 构建,输出到 frontend/dist桌面应用:PyInstaller 将 frontend/dist 目录打包到 _internal/web,后端启动时检查是否在打包环境中,如果是则从 _internal/web 加载静态文件云部署:前端构建产物复制到 /opt/interview_assistant/frontend/dist,Nginx 配置静态文件服务使用 StaticFiles 挂载静态资源目录实现代码:if getattr(sys, 'frozen', False): # 打包环境 web_dir = os.path.join(sys._MEIPASS, 'web') else: # 开发环境 web_dir = os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist') app.mount("/", StaticFiles(directory=web_dir, html=True), name="web") 5.4 简历文件解析难点:支持 PDF 和 Word 格式简历,提取结构化文本信息。解决方案:PDF 使用 pdfplumber 提取文本Word 使用 python-docx 提取文本统一文本清洗流程:去除多余空格、换行符、特殊字符提取关键信息:姓名、联系方式、教育经历、工作经历、技能等实现代码:def parse_pdf(file_path: str) -> str: import pdfplumber text = "" with pdfplumber.open(file_path) as pdf: for page in pdf.pages: text += page.extract_text() + "\n" return clean_text(text) def parse_docx(file_path: str) -> str: from docx import Document doc = Document(file_path) text = "\n".join([paragraph.text for paragraph in doc.paragraphs]) return clean_text(text) 5.5 AI 接口调用与错误处理难点:AI 服务可能超时、限流或返回错误,需要优雅降级和重试机制。解决方案:实现适配器模式,统一 AI 服务接口添加超时设置和重试逻辑记录详细日志便于排查提供友好的用户错误提示实现代码:class DeepSeekAdapter: def __init__(self, user_id: int = 0): self.api_key = read_api_key("deepseek", user_id) self.timeout = 30 self.max_retries = 3 def chat(self, messages: List[Dict], temperature: float = 0.7) -> str: for attempt in range(self.max_retries): try: response = requests.post( "https://api.deepseek.com/v1/chat/completions", headers={"Authorization": f"Bearer {self.api_key}"}, json={"model": "deepseek-chat", "messages": messages}, timeout=self.timeout ) response.raise_for_status() return response.json()["choices"][0]["message"]["content"] except Exception as e: if attempt == self.max_retries - 1: raise time.sleep(2 ** attempt) # 指数退避 5.6 桌面应用单实例锁难点:防止用户多次点击启动多个应用实例,导致端口冲突和资源浪费。解决方案:使用 Windows 命名互斥体(Mutex)实现单实例锁启动时检查是否已有实例运行如果已有实例,激活现有窗口并退出实现代码:import win32event import win32api import winerror mutex_name = "Global\\面试模拟助手_Launcher" mutex = win32event.CreateMutex(None, False, mutex_name) if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: # 已有实例运行 sys.exit(0) 5.7 云部署适配与配置管理难点:将本地开发的应用适配到云环境,处理环境变量、文件路径、服务监听等问题。解决方案:使用环境变量配置生产环境参数,避免硬编码动态检测运行环境,调整配置路径和监听地址提供 Nginx 配置模板和 systemd 服务文件创建部署脚本自动完成环境初始化实现代码:# 生产环境配置 if os.getenv("ENVIRONMENT") == "production": SERVER_HOST = "0.0.0.0" # 监听所有网络接口 DATA_DIR = "/opt/interview_assistant/data" LOG_DIR = "/var/log/interview_assistant" else: SERVER_HOST = "127.0.0.1" # 本地开发 DATA_DIR = os.path.join(os.path.expanduser("~"), ".interview_assistant", "data") LOG_DIR = os.path.join(os.path.expanduser("~"), ".interview_assistant", "logs") 六、环境和资源准备6.1 准备码道开发环境参考华为云码道(CodeArts)代码智能体安装部署说明,完成 Windows 版码道安装并登录账号。打开项目后,进入代码智能体对话区域,选择"规范开发模式"。本案例使用规范开发模式完成以下工作:根据自然语言需求生成需求规格。根据需求规格生成技术设计。根据技术设计拆解开发任务。自动修改前后端代码。生成并运行测试。输出开发总结和交付说明。6.2 准备 AI 服务配置应用支持以下配置项:配置项是否必需说明DEEPSEEK_API_KEY必需用于 AI 简历分析、岗位匹配、项目推荐、技能指导和模拟面试GITHUB_TOKEN可选提高 GitHub API 搜索额度TTS_SERVICE_URL可选预留语音播报服务地址SECRET_KEY必需用于 JWT 和服务端加密,生产环境应使用强随机值项目在本地开发时支持用户在设置页保存个人 API Key;部署到 ECS 后,还需要在 backend/.env.production 中配置生产环境变量。6.3 准备项目源码本案例项目根目录为:D:\Huawei核心目录如下:D:\Huawei |-- backend # FastAPI 后端服务 |-- frontend # Vue3 前端工程 |-- launcher # Windows 桌面启动器 |-- installer # Windows 安装脚本 |-- deploy # 云部署配置 |-- terraform # Terraform 云资源配置 |-- tests # 测试用例 |-- build.py # 本地一键构建脚本 |-- README.md # 项目说明其中部署到 ECS 时主要使用 backend、frontend 和 deploy 相关文件。七、码道规范开发面试模拟助手7.1 本地验证后端本地启动:cd D:\Huawei\backend python -m pip install -r requirements.txt python -m uvicorn main:app --host 127.0.0.1 --port 8000 --reload 前端本地启动:cd D:\Huawei\frontend npm install npm run dev测试命令:cd D:\Huawei python -m unittest discover -s tests当前项目测试覆盖账号 API Key 隔离、Windows 打包配置等关键逻辑。7.2 使用核心功能7.2.1 注册和登录打开应用。进入注册页,填写邮箱、密码和昵称。注册成功后登录。登录后前端会保存 accessToken 和 refreshToken。7.2.2 配置 API Key进入"设置"页面,配置:DeepSeek API Key:用于 AI 能力。GitHub Token:用于 GitHub 项目搜索,可选。TTS 服务 URL:用于语音播报扩展,可选。保存后,后端会将配置写入当前登录用户目录:%APPDATA%\面试模拟助手\config\user_<用户ID>\api_keys.ini7.2.3 上传简历并分析岗位匹配进入"简历优化"页面。上传 PDF、DOC 或 DOCX 简历。系统解析简历文本并保存到本地数据库。输入目标岗位 JD。点击分析,系统调用 DeepSeek 生成匹配分数、技能差距和优化建议。后端对应接口:接口方法说明/api/v1/resume/uploadPOST上传并解析简历/api/v1/resume/analyzePOST根据简历和 JD 生成匹配分析/api/v1/resume/listGET获取当前用户简历列表/api/v1/resume/market-analysisPOST分析目标岗位市场要求/api/v1/resume/skill-guidancePOST生成技能补充指导7.2.4 生成项目推荐和实践路径系统会结合用户目标岗位、简历内容、岗位匹配差距和市场技能要求生成项目推荐。后端对应接口:接口方法说明/api/v1/project/searchGET使用 GitHub API 搜索开源项目/api/v1/project/refresh-recommendationsPOST使用 DeepSeek 刷新项目推荐/api/v1/project/{project_id}/guideGET生成项目复现指南/api/v1/project/{project_id}/practice-pathGET生成五阶段实践路径/api/v1/project/{project_id}/stage-progress/{stage_index}PUT更新实践阶段完成状态7.2.5 进行模拟面试进入"模拟面试"页面。选择面试类型和难度。系统根据简历和 JD 生成面试题。用户逐题作答。系统评估答案,可生成追问。完成后生成整体面试报告。后端对应接口:接口方法说明/api/v1/interview/sessionsPOST创建面试会话/api/v1/interview/sessions/{session_id}/answersPOST提交答案/api/v1/interview/sessions/{session_id}/completePOST完成面试并生成报告/api/v1/interview/sessions/{session_id}/reportGET查看面试报告/api/v1/interview/sessions/compareGET对比两次面试表现八、开发者空间 AI Shell 部署到华为云 ECS8.1 分析 ECS 部署资源完成代码开发后,打开开发者空间 AI Shell,输入提示词:帮我分析项目,我想将系统部署到ECS上,具体需要哪些资源,请帮我罗列一下AI Shell 会读取项目结构,识别该项目是前后端分离的面试模拟助手系统,并分析部署所需资源。AI Shell 推荐的最小化部署资源如下:ECS 弹性云服务器:s6.medium.2(1 vCPU / 2GB),Ubuntu 22.04,40GB SSDEIP 弹性公网 IP:5 Mbps 带宽,按流量或带宽计费VPC 虚拟私有云:默认配置,包含一个子网安全组:开放 80(HTTP)、443(HTTPS)、22(SSH)端口外部服务依赖:DeepSeek API、GitHub API部署架构:用户通过浏览器访问 EIP 公网 IPNginx 反向代理到 FastAPI 后端(端口 8000)FastAPI 服务处理业务逻辑,连接 SQLite 数据库前端静态资源由 Nginx 直接服务systemd 守护后端进程,确保服务高可用8.2 生成 Terraform 配置并调整代码继续在 AI Shell 中输入:帮我生成最经济的Terraform配置,并且帮我调整一下需要修改的部署要点AI Shell 先给出部署前需要修改的关键点:后端监听地址从 127.0.0.1 改为 0.0.0.0动态 API 地址配置,避免硬编码 localhostSECRET_KEY 改为环境变量优先CORS 配置支持环境变量 EXTRA_CORS_ORIGINS创建生产环境配置文件 backend/.env.production提供 Nginx 配置模板 deploy/nginx.conf提供 systemd 服务配置 deploy/interview-assistant.service随后 AI Shell 查询可用区、生成随机密码,并创建 Terraform 配置文件:terraform/providers.tf:HuaweiCloud Provider 配置terraform/variables.tf:变量定义terraform/main.tf:VPC、子网、安全组、ECS、EIP 资源配置terraform/outputs.tf:EIP、SSH 命令等输出8.3 执行 Terraform 创建云资源确认资源方案后,在 AI Shell 中输入:请使用以上配置,执行terraform applyAI Shell 执行:cd /root/interview_assistant/terraform terraform apply -auto-approveTerraform 创建了 10 个资源,包括 VPC、子网、安全组、安全组规则、ECS、EIP 和 EIP 绑定。部署完成后,ECS 状态为 ACTIVE。8.4 连接 ECS 并部署应用ECS 创建完成后,继续输入:帮我连接到ECS并部署应用AI Shell 通过 SSH / SFTP 将项目上传到 ECS,并执行部署脚本。部署脚本主要完成:安装系统依赖。安装 Node.js 18。创建 Python 虚拟环境。安装后端依赖。构建前端 dist。配置 Nginx。配置 systemd 服务。启动 interview-assistant 服务。验证前端、API 文档和健康检查接口。部署过程中修复的问题:问题处理方式pip install 冲突清理残留的超时进程后重新安装deploy/ 目录缺失配置文件补提交到 git,并通过 SFTP 上传DATA_DIR 权限错误从 /var/www/面试模拟助手 改为 /opt/interview_assistant/data最终部署结果:ECS: 49.4.115.167(s6.medium.2,Ubuntu 22.04)应用路径: /opt/interview_assistantPython 虚拟环境: /opt/interview_assistant/backend/venvNode.js: v18.20.8前端构建: /frontend/dist数据目录: /opt/interview_assistant/data配置文件: backend/.env.production待办事项:在 .env.production 中补充真实 DEEPSEEK_API_KEY,否则 AI 面试和分析功能无法正常调用。可选配置域名、SSL 证书和 GitHub Token。生产环境建议使用 SSH 密钥登录,替代密码登录。九、打包为 Windows 桌面应用9.1 构建前端静态资源cd D:\Huawei\frontend npm run build构建成功后会生成:D:\Huawei\frontend\dist后端 PyInstaller 打包时会把该目录复制到 _internal\web,由 FastAPI 挂载为静态页面。9.2 打包后端服务进入后端目录:cd D:\Huawei\backend python -m pip install -r requirements.txt python -m PyInstaller interview_assistant.spec --noconfirm --clean --distpath D:\Huawei\dist_backend构建产物:D:\Huawei\dist_backend\interview_assistant\interview_assistant.exe D:\Huawei\dist_backend\interview_assistant\_internal\web\index.htmlinterview_assistant.spec 中配置了 console=False,后端 exe 在 launcher 调用时不会弹出黑色命令窗口。9.3 打包桌面 launcherlauncher 位于 launcher/launcher.py,主要职责如下:读取安装目录下的 config.ini。查找可用端口,默认从 8000 到 8010。启动后端 interview_assistant.exe。等待 /health 接口可用。使用 pywebview 打开桌面小窗口,而不是跳转浏览器。在 Windows 下使用单实例锁,避免多次点击创建多个 launcher.exe。关闭窗口时终止后端进程。打包命令:cd D:\Huawei\launcher python -m pip install pyinstaller pystray Pillow pywebview python -m PyInstaller --onefile --windowed --name launcher --noconfirm --clean --distpath D:\Huawei\dist_launcher --workpath D:\Huawei\launcher\build --specpath D:\Huawei\launcher\build launcher.py构建产物:D:\Huawei\dist_launcher\launcher.exe9.4 生成安装包安装脚本位于:D:\Huawei\installer\setup.iss安装包会包含:后端目录 dist_backend\interview_assistant桌面启动器 dist_launcher\launcher.exe配置文件 installer\config.ini桌面快捷方式和开始菜单快捷方式生成安装包:Copy-Item -Path 'D:\Huawei\config.ini.template' -Destination 'D:\Huawei\installer\config.ini' -Force & 'C:\Users\User\AppData\Local\Programs\Inno Setup 7\ISCC.exe' 'D:\Huawei\installer\setup.iss' 输出文件:D:\Huawei\output\面试模拟助手_Setup_v1.0.0.exe9.5 使用一键构建脚本项目根目录提供 build.py,可一键执行前端构建、后端打包、launcher 打包和安装包生成:cd D:\Huawei python build.py可选参数:python build.py --skip-frontend python build.py --skip-backend python build.py --skip-launcher python build.py --skip-installer python build.py --clean 十、访问验证和效果确认10.1 验证前端页面ECS部署完成后,在浏览器访问AI shell给出的链接页面正常显示登录界面,表示前端静态资源已正确部署,Nginx 配置生效。10.2 验证 API 文档访问:http://xx.x.xxx.xxx/docs返回 FastAPI 自动生成的交互式 API 文档,表示 FastAPI 服务正常运行,并且 Nginx 已正确代理 API 文档。10.3 验证健康检查接口访问:http://xx.x.xxx.xxx/health或在服务器中执行:curl http://xxx.x.x.x:xxxx/health服务正常时返回健康状态信息。10.4 验证 systemd 服务在 ECS 上执行:systemctl status interview-assistant如果状态为 active (running),说明后端服务已经由 systemd 守护。后续服务器重启后,也可以自动拉起应用。十一、释放资源11.1 清理云资源ECS、EIP 和 EVS 均可能产生按需费用。体验完成后,如果不再使用,请在 AI Shell 中输入:帮我清理所创建的华为云资源或进入 Terraform 目录执行:cd /root/interview_assistant/terraform terraform destroy执行前请确认已经备份需要保留的数据,例如 SQLite 数据库、上传的简历文件和 .env.production 配置。11.2 清理本地构建产物如果只清理本地 Windows 构建产物,可在项目根目录执行:cd D:\Huawei python build.py --clean 该命令会清理:frontend/distbackend/distbackend/builddist_backenddist_launcheroutput11.3 卸载桌面应用如果通过安装包安装,可在 Windows"应用和功能"中卸载"面试模拟助手",或使用开始菜单中的卸载入口。卸载时安装脚本会尝试清理安装目录下的后端文件:{app}\backend用户数据默认保存在 %APPDATA%,用于保留登录账号、简历、项目、面试记录和 API Key 配置。需要彻底清理时,可手动删除:%APPDATA%\面试模拟助手删除该目录会清空本地数据库、上传文件、日志和所有用户 API Key 配置,请提前确认是否需要备份。十二、扩展资料说明12.1 技术文档华为云码道(CodeArts)代码智能体:https://codearts.huaweicloud.com/华为云 ECS 文档:https://support.huaweicloud.com/ecs/华为云 VPC 文档:https://support.huaweicloud.com/vpc/FastAPI 官方文档:https://fastapi.tiangolo.com/SQLAlchemy 官方文档:https://docs.sqlalchemy.org/
-
基于华为云码道与 ModelArts MaaS 的原创智能论文阅读学习助手PaperLens案例类型:AI 应用开发 / 智能阅读 / 开发者工具实践适用对象:高校学生、科研入门者、需要精读英文论文的个人用户在线体验:http://101.245.81.114代码仓库:falconousZhang/PaperLens_final参考体例:华为云开发者空间实战案例1. 案例介绍1.1 项目背景在阅读英文科研论文时,初学者经常遇到以下问题:PDF 排版复杂,正文、公式、图表与双栏文本之间缺乏清晰的阅读引导;论文中包含大量专业术语和长句,逐句翻译耗时,简单机翻又难以解释原理;阅读过程中产生的高亮、笔记和问题分散在不同工具中,难以形成连续的学习记录;通用大模型不了解当前论文上下文,容易给出脱离原文、缺少依据的回答;传统审稿工具更偏向评价论文质量,并不完全适合个人“读懂论文、掌握方法”的目标。PaperLens 因此被设计为一款 AI 驱动的个人论文阅读学习助手。系统以原始 PDF 为阅读主体,在不破坏论文版式的前提下,将总结、翻译、选中文字解释、论文问答、高亮、笔记、批判性阅读和学习报告导出整合到同一个工作台中。1.2 建设目标项目的核心目标不是替代用户阅读,而是降低进入论文内容的门槛,并让 AI 的每一次回答都尽量与论文原文建立联系。具体目标包括:保留原始 PDF 排版,提供逐页阅读体验;支持页面总结、全文翻译和选中文字解释;建立论文级多轮问答,让模型结合全文和历史对话回答;支持原文高亮与笔记,并按论文、页码进行管理;提供用户注册登录、数据隔离和管理员治理能力;将学习解释、笔记、批判性阅读等内容汇总导出为 Markdown、PDF 或 DOCX;使用低成本华为云资源完成可访问、可演示的部署。1.3 案例成果PaperLens 已形成从论文上传到学习资料沉淀的完整闭环:注册/登录 ↓ 上传 PDF → 文本与版式解析 → 进入逐页阅读工作台 ↓ ↓ 论文库管理 总结 / 翻译 / 选中文字解释 ↓ ↓ 阅读进度 多轮论文问答 ↓ ↓ 高亮与笔记 ← 原文定位与交互 → 批判性阅读 └───────────────┬───────────────┘ ↓ 学习报告导出图 1 PaperLens 论文库:集中展示论文解析状态、阅读进度、高亮与笔记数量,并支持继续阅读和论文管理。项目已部署在华为云 ECS,使用华为云 ModelArts Studio(MaaS)提供真实大模型推理能力,并通过 Docker Compose 运行前端、后端和 PostgreSQL。2. 整体解决方案2.1 方案概述PaperLens 采用前后端分离架构。浏览器负责 PDF 页面展示、文本选择和学习交互;后端负责用户权限、论文解析、任务状态、模型调用、数据持久化和报告生成。大模型能力通过统一的 LLMClient 抽象接入,当前实际部署使用华为云 ModelArts Studio(MaaS)的对话模型服务。系统遵循三个设计原则:原文优先:左侧始终展示原始 PDF 页面,AI 结果作为辅助信息显示在右侧;来源可追溯:解析时记录页码、字符区间和文本块位置,学习内容可以重新定位到原文;任务可恢复:耗时操作以任务状态保存,页面刷新后可以恢复轮询,不依赖一次 HTTP 连接持续到模型返回。2.2 技术选型层次技术或服务作用前端Vue 3、TypeScript、Vite、Pinia、Vue Router、Axios阅读工作台、状态管理、路由保护和 API 调用后端Python、FastAPI、Pydantic、SQLAlchemyREST API、业务服务、参数校验和数据访问数据库PostgreSQL 16、Alembic用户、论文、页面、问答、解释、笔记、任务和审计数据PDF 处理PyMuPDF、pdfplumber页面渲染、正文提取、文本块定位和表格识别大模型华为云 ModelArts Studio(MaaS)、GLM-5.2总结、翻译、选中文字解释、论文问答和批判性阅读报告ReportLab、python-docxMarkdown、PDF、DOCX 学习报告生成部署华为云 ECS、VPC、安全组、弹性公网 IP、Docker Compose、Nginx单机容器化部署与公网访问研发辅助华为云码道(CodeArts)代码智能体需求理解、跨文件编码、测试设计、问题定位和部署调试2.3 开发环境与云资源准备本案例将“开发工具”和“运行资源”明确分开。码道、Rules 与 Skills 只在研发阶段使用,不会随应用一起部署;真正运行 PaperLens 时只需要前端、后端、数据库、文件卷和 MaaS 服务。类别本案例配置说明本地开发Windows、Git、Docker Desktop、Node.js、Python编码、容器联调和定向验收智能研发华为云码道(CodeArts)代码智能体、项目级 Rules、开发 Skills需求设计、编码、测试资产与问题定位大模型服务ModelArts Studio(MaaS)兼容对话接口由统一 LLMClient 调用,密钥仅通过环境变量注入云服务器华为云 ECS,Ubuntu 22.04,2 vCPU、4 GiB、40 GiB小规模实习项目的单机部署网络VPC、子网、安全组、弹性公网 IP,5 Mbit/s公网只开放 Web 入口和受限 SSH容器运行Docker Engine、Docker Compose运行 Nginx、FastAPI 和 PostgreSQL为控制成本,当前实际部署没有单独购买 RDS、OBS、ELB 或 Kubernetes。数据库与文件使用 ECS 上的 Docker 持久卷;项目保留向 RDS 和 OBS 演进的接口与部署资料,但案例不会把“已经设计”描述成“已经购买并运行”。3. 系统架构设计3.1 逻辑架构3.2 分层设计表现层前端采用 Vue 3 + TypeScript。核心页面包括登录注册、论文库、上传页面、论文阅读工作台、批判性阅读结果、报告导出和管理员控制台。论文阅读工作台采用左右分栏布局:左侧按页显示原始 PDF 图像,并叠加可选择的透明文本层;右侧在“学习解释、论文问答、学习记录”之间切换;用户选择原文后,可以直接创建黄色高亮、绿色笔记或发起通俗解释;点击历史解释时,系统自动跳转到对应页并高亮来源文本。接口层FastAPI 对外提供统一的 /api/v1 接口,按领域拆分为认证、论文、任务、学习解释、问答、论文库、学习记录、导出和管理员接口。Pydantic 负责输入输出边界,统一异常处理避免将数据库语句、文件路径或上游响应泄露给前端。业务层业务逻辑集中在 Service 层:pdf_parser:正文、章节、文本块、表格和 Evidence 解析;learning_service:页面总结、翻译与选中文字解释;qa_service、qa_retriever:论文级多轮问答和证据检索;highlight_service、note_service:高亮、笔记与原文锚点;review_service:批判性阅读;export_service、report_converter:学习报告组织与格式转换;admin_service:用户治理、内容元数据查询和审计。数据层PostgreSQL 保存结构化业务数据,Docker Volume 保存 PDF、页面图像和导出报告。数据库迁移由 Alembic 管理,容器启动时先执行迁移,再启动后端服务。3.3 核心数据流论文上传与解析用户上传 PDF,后端校验扩展名、文件头、大小和文件哈希;文件写入受控存储目录,创建论文记录和解析任务;PyMuPDF 提取页面正文、页面尺寸和文本块坐标;pdfplumber 尝试提取表格,表格失败不影响正文解析;系统生成页面、章节、文本分块和 Evidence 数据;论文状态更新为 PARSED,前端进入阅读工作台。学习解释用户选择总结、翻译,或在 PDF 文本层中选择一段原文;后端根据页码、字符区间和论文归属校验来源;系统构造带有明确边界的 Prompt,并调用 MaaS;模型输出经过结构校验和清洗后持久化;前端轮询任务状态,并将结果与对应页和选区关联。论文问答首次提问时,后端读取论文全文,在长度预算内构造论文上下文;后续提问同时附加最近的历史问答。检索模块优先识别问题中的页码、表号、图号等显式引用,再结合文本相关性选择候选证据。问答记录保存在会话中,用户可以切换、滚动查看或删除历史会话。3.4 华为云部署架构本案例定位为小规模实习项目,因此优先选择低成本、易维护的单机方案,而不是引入复杂的微服务集群。部署中只将 Nginx 的 80 端口发布到公网,后端 8000 和数据库 5432 仅在 Docker 私有网络中访问。数据库和文件目录使用持久卷,容器设置健康检查与 restart: unless-stopped。当前演示环境使用 HTTP;正式生产环境应增加域名、HTTPS 证书并启用 Secure Cookie。3.5 工程目录设计项目采用按前端、后端、部署和设计资料分区的单仓库结构。核心目录如下:PaperLens/ ├── backend/ │ ├── paperlens/ │ │ ├── api/ # FastAPI 路由与认证边界 │ │ ├── core/ # 配置、安全、错误和可观测性 │ │ ├── models/ # SQLAlchemy 业务模型 │ │ ├── schemas/ # Pydantic 请求与响应契约 │ │ └── services/ # 解析、解释、问答、记录和导出服务 │ ├── alembic/ # 数据库迁移链 │ └── tests/ # 后端测试资产 ├── frontend/ │ ├── src/api/ # API 客户端 │ ├── src/components/ # 阅读工作台组件 │ ├── src/stores/ # Pinia 状态 │ └── src/views/ # 登录、论文库、阅读、管理等页面 ├── deploy/huawei/ # 单 ECS 与生产化部署配置 ├── ProjectDocs/ # 需求、架构、页面、测试和 SDD 设计资料 ├── docker-compose.yml # 本地开发编排 └── README.md这种结构使码道能够先从设计资料理解约束,再定位到对应领域的路由、Schema、Service、模型和前端页面,减少把业务逻辑堆进单个文件的情况。3.6 核心数据模型PaperLens 的数据模型围绕“用户—论文—页面内容—学习行为”展开:数据域核心实体设计要点认证users、auth_sessions、password_reset_tokens角色、状态、刷新令牌轮换和密码重置论文papers、paper_pages、paper_sections、paper_chunks论文归属、解析状态、逐页正文和章节结构原文定位evidences、paper_tables页码、引用文本、字符区间、边界框和表格结构学习解释learning_explanations、learning_citations模式、范围、任务状态、来源引用和失败恢复论文问答paper_qa_conversations、paper_qa_turns、paper_qa_citations多轮顺序、幂等请求、上下文哈希和证据绑定学习记录paper_library_entries、paper_highlights、paper_notes阅读进度、黄色高亮、绿色笔记和原文锚点扩展分析analysis_tasks、review_results、metric_records、experiment_results批判性阅读、指标与实验理解导出与治理export_reports、admin_audit_logs报告状态、文件信息和管理员不可变审计任务型实体统一使用 PENDING → RUNNING → SUCCEEDED/FAILED 状态机。模型调用前结束数据库事务,模型返回后再用新事务写入结果,避免在外部网络等待期间长期持有连接或行锁。4. 使用华为云码道(CodeArts)代码智能体辅助开发与调试4.1 使用方式PaperLens 的功能跨度较大,涉及前端交互、后端 API、数据库迁移、PDF 处理、大模型调用和云端部署。项目使用华为云码道(CodeArts)代码智能体辅助理解代码库、拆解需求、生成跨文件代码、补充测试以及定位运行故障。项目没有采用“一次性生成整个系统”的方式,而是将开发过程拆成可验证的小阶段:明确用户目标 ↓ 形成单轮任务提示词和边界 ↓ 码道理解代码库并完成跨文件实现 ↓ 集中进行定向测试、构建或实际操作验收 ↓ 根据日志和页面现象定位问题 ↓ 码道完成同轮修正 ↓ 进入下一功能阶段4.2 Rules 与 Skills 工程化约束为了让智能体在长期迭代中保持一致,项目为码道配置了项目级规则和技能工作流,主要覆盖:需求细化与架构设计;页面原型和交互约束;前后端测试设计;功能详细设计与任务拆解;Sprint 进度管理;Bug 修复记录。每次给码道的任务都会说明目标、允许修改的范围、禁止事项、接口契约、数据一致性要求和验收方式。相比只描述“实现某功能”,这种结构化提示词能够降低跨文件修改遗漏、重复造轮子和无关重构的概率。4.3 提示词管理与迭代方法PaperLens 没有把码道提示词当作一次性聊天内容,而是为每个开发阶段保留任务编号、目标、约束、验收标准和后续状态。项目共形成 P1~P8.4 的 32 轮阶段提示词归档,使需求变化、实现边界和技术决策能够回溯。一条可执行的码道提示词通常包含以下结构:# 码道下一阶段提示词:<阶段编号与名称> ## 任务目标 - 本轮只解决什么问题 - 完成后用户能获得什么能力 - 与既有功能的关系 ## 开始前边界与真实基线 - 必读的设计文档和真实代码 - 当前迁移、接口、容器和功能状态 - 必须保护的用户数据与现有修改 - 禁止读取的密钥、令牌和环境信息 ## 设计与实现要求 - 数据模型、状态机和迁移规则 - API 请求/响应与错误语义 - Service、前端交互和安全边界 - 并发、幂等、事务和失败恢复 ## 测试资产与验收 - 只编写少量关键测试资产 - 码道不运行测试、构建、迁移或 Docker 命令 - 集中验收阶段执行定向测试、关键烟测和前端构建 ## 完成定义 - 允许修改的文件 - 必须同步的设计与 Sprint 文档 - 实际完成项、未完成项和风险必须如实报告提示词也随项目实践逐步演进:早期更强调从零搭建和运行验证;中期增加数据模型、API 契约、并发和安全约束;后期为了提高效率,码道只负责编写或更新少量测试资产,不在实现轮次运行耗时测试,测试执行统一放到集中验收阶段。4.4 代表性码道提示词节选以下内容选自项目实际提示词归档。为适合作为案例展示,省略了较长的文件清单、历史统计值和重复性约束,但保留了当轮的目标、关键边界与完成定义。提示词一:建立可运行工程骨架使用场景:项目初期先统一技术选型和数据契约,避免前后端、数据库和设计文档各自演进。你现在负责继续开发 D:\shixi\PaperLens 项目。 本轮目标不是一次性完成整个系统,而是完成“规格修正 + 可运行工程骨架”, 为后续端到端 MVP 开发建立稳定基础。 一、必须采用的 MVP 决策 1. 前端使用 Vue 3 + TypeScript + Vite + Pinia + Vue Router。 2. 后端使用 FastAPI + SQLAlchemy + Alembic。 3. 本地和部署均使用 PostgreSQL,不使用 SQLite。 4. Evidence 必须记录 page_number、quoted_text、bbox、char_start、 char_end、section_id 和 chunk_id,保证前端后续能够定位原文。 5. 上传统一使用 multipart 流式上传,最大 50 MB。 6. 后台任务进度统一使用 HTTP 轮询,暂不引入 WebSocket。 7. MVP 只支持可提取文本的 PDF,OCR 放入后续版本。 8. LLM 必须通过统一 LLMClient 调用,默认提供 MockLLMClient。 二、本轮交付 - 创建 backend、frontend、docker-compose.yml、.env.example 和 README。 - 后端实现健康检查、配置、数据库连接、ORM、首个迁移和统一错误结构。 - 前端实现基础路由、Pinia、首页、健康检查及后端不可用提示。 - Compose 只包含 PostgreSQL、backend 和 frontend。 三、边界 - 不写入真实密钥,不初始化或提交 Git。 - 不引入 Celery、Redis、Nginx、FAISS 或真实云服务。 - 不生成大量空接口或只有 pass 的占位代码。 - 本轮到“工程骨架可以启动、模型和契约自洽”为止, 不继续实现 PDF 解析和真实 LLM 功能。落地结果:码道完成了 FastAPI、Vue、PostgreSQL 与 Docker Compose 的基础工程,并建立了后续一直沿用的 Evidence 定位字段和 LLMClient 抽象。提示词二:接入华为云 ModelArts MaaS使用场景:在 Mock 模型链路已经可用后,增加真实华为云模型适配器,同时保证本地开发不依赖云端密钥。# P3.3 华为云 MaaS 真实生成式模型适配器 ## 任务目标 在不改变现有审阅 API、数据库模型和前端的前提下, 把 LLMClient 从“只有 Mock 实现”扩展为可配置的 HuaweiMaaSLLMClient。 默认本地和测试仍使用 MockLLMClient。 ## 实现边界 1. 复用现有 httpx,不新增第三方模型 SDK、requests 或重试库。 2. 华为 MaaS 适配器使用标准 chat/completions 请求结构。 3. endpoint、model、API Key、连接超时和读取超时全部来自 Settings。 4. API Key 使用安全类型保存,不得出现在日志、异常、响应或 repr 中。 5. 不修改公开 API、ORM、Alembic、Docker 和前端。 6. 云接口测试必须使用 MockTransport,禁止真实联网和产生费用。 ## 响应与失败处理 - 校验 HTTP 状态、响应 JSON、choices、message 和 content。 - 兼容模型返回单个完整 Markdown JSON 围栏。 - 拒绝前后杂文、多对象、字段缺失和未知字段。 - 上游失败统一转换为安全业务错误,不把响应正文或密钥返回给客户端。 ## 完成定义 - Mock 与 Huawei MaaS 通过同一 LLMClient 工厂切换。 - 没有云端配置时项目仍可离线运行。 - 配置示例只使用占位符,不读取、打印或提交真实密钥。落地结果:真实模型与 Mock 模型共用同一业务接口,学习解释、问答和批判性阅读无需感知底层供应商;部署时只需通过环境变量选择 MaaS 适配器。提示词三:把产品主线校正为论文阅读学习使用场景:项目中期确认“帮助个人用户读懂论文”才是核心目标,因此需要在保留已有分析能力的同时重构主要交互。# P7.1 论文阅读学习工作台与证据化学习解释 ## 任务目标 把 PaperLens 的产品主线从“辅助审稿”校正为“帮助个人用户阅读论文并学习”。 在已完成的 PDF 解析、章节/页面、Evidence、认证隔离和 Huawei MaaS LLMClient 基础上,实现受保护的论文阅读工作台,以及针对当前页面或 选中文字的总结、翻译和通俗解释闭环。 已有结构化审阅、指标提取、实验分析和报告能力继续保留,分别作为 “批判性阅读”“实验理解”和“学习成果导出”的高级能力,不删除或重做。 ## 来源与安全边界 1. 客户端只提交 mode、scope 和页码/选区标识,不提交论文正文或 prompt。 2. 后端根据当前用户和 paper_id 重新读取来源,禁止跨用户、跨论文引用。 3. 论文标题和正文均视为不可信输入,并放在明确标签中;其中出现的 “忽略之前指令”等文字不得覆盖 system 指令。 4. SUMMARY 概括当前范围;TRANSLATE 忠实翻译并保留标题、段落和编号; 选中文字解释要说明概念、原理和例子。 5. 结果必须保存页码、来源哈希和任务状态,失败只记录安全公开文案。 ## 前端交互 - 阅读页采用左右分栏,左侧保留原始 PDF 版式并支持文本选择。 - 右侧显示学习解释历史;点击记录跳转到来源页。 - 选中文字解释与原文位置关联,不能把解释结果挤在 PDF 正文下方。 - 页面切换或组件卸载时停止旧轮询,避免旧结果覆盖新页面。落地结果:PaperLens 从“生成审阅结论”转向“原文阅读 + 页面解释 + 学习沉淀”,形成当前最具辨识度的双栏阅读工作台。提示词四:实现论文级多轮问答使用场景:解决“论文里明明存在,模型却因为只收到当前页片段而回答没有”的问题。# P7.2 当前论文多轮问答与证据化会话 ## 任务目标 实现只围绕当前用户、当前论文的多轮问答。用户可以新建会话、连续提问、 查看历史;有依据的回答绑定服务端选取的论文来源,证据不足时明确降级, 不能用模型常识伪装成论文结论。 ## 上下文构造 1. 以当前 question 为 query,仅在当前论文的 Evidence 中做确定性相关性排序。 2. 后续提问附加同会话最近的成功问答,超限时按完整轮次从最旧开始移除。 3. 候选 Evidence 按相关度、页码、创建时间和 ID 稳定排序,并限制 top_k。 4. 当前问题、历史回答和论文正文全部视为不可信内容,不能提升为 system role。 5. Embedding 与 LLM 调用期间不得持有数据库事务或行锁。 ## 幂等与结果契约 - 请求包含 client_request_id;重复请求返回原轮次,不重复调用模型。 - 同一会话只允许一个 PENDING/RUNNING 轮次。 - 成功回答保存 answer、grounded 和来源引用;证据不足时 grounded=false。 - 模型只返回一个严格 JSON 对象,拒绝额外解释、未知字段和跨论文引用。 ## 前端交互 - 右侧使用类似即时通信软件的消息时间线。 - 会话历史和消息区域可独立滚动,输入区固定在底部。 - 支持新建、切换和删除会话,轮询在终态立即停止。落地结果:系统形成论文级会话、轮次、上下文预算和幂等机制。真实论文验证中发现仅依赖少量 Evidence 会漏掉跨页图表后,后续迭代又将策略调整为“首次提问按预算提供全文基础上下文,后续附加历史,并优先识别页码、表号和图号”,体现了设计根据实际效果继续修正的过程。提示词五:准备华为云部署与安全收口使用场景:开发轮次结束后,为 ECS 部署、备份恢复和后续云资源演进准备可复用资产。# P8.4 华为云部署、备份恢复与综合安全验收 ## 任务目标 在既有论文阅读学习、登录注册、管理员、任务恢复和限流能力基础上, 补齐华为云部署配置、备份恢复说明和安全清单,使项目达到 “代码与部署资料完整,等待真实云环境验收”的状态。 ## 真实性要求 1. 不实际购买、创建、修改或删除华为云资源。 2. 不把“部署资产已完成”写成“真实云上已经部署”。 3. 示例只能使用占位符,禁止读取或写入 API Key、AK/SK、JWT Secret、 数据库密码、真实 IP、域名和证书私钥。 4. 码道只编写代码、少量测试资产、部署配置和文档, 不运行测试、构建、迁移、Docker、HTTP 或真实云服务命令。 ## 部署资产 - 提供 deploy/huawei 下的环境示例、Compose、Nginx、部署和回滚说明。 - 后端和数据库不直接暴露公网;只由 Nginx 代理同源 /api/。 - 容器使用非 root、只读文件系统、tmpfs、no-new-privileges、 healthcheck、资源上限和 restart policy。 - Secret 通过受限环境文件或 secret 文件注入,entrypoint 不打印内容。 - 给出 VPC、安全组、ECS、MaaS、健康检查和小额验证的人工配置顺序。 ## 完成定义 区分“代码与部署资产已实现”“离线验收尚未执行” 和“真实华为云资源尚未创建/验证”三种状态,不夸大完成度。落地结果:项目形成单 ECS 演示编排和面向生产化演进的配置资料;真实部署时又根据小规模需求选择 PostgreSQL 与文件卷同机运行,避免为了案例展示购买不必要资源。4.5 码道参与的主要开发阶段阶段码道辅助内容形成的结果工程骨架分析前后端技术栈,生成 FastAPI、Vue、PostgreSQL、Docker 基础结构可运行的前后端与数据库环境PDF 解析实现上传校验、页面解析、章节识别、文本块坐标和 Evidence 生成从 PDF 到可阅读、可定位数据的链路大模型接入抽象 LLMClient,实现 Mock 与 Huawei MaaS 适配器本地离线开发与云端真实模型可切换阅读工作台跨文件实现 PDF 页面、透明文本层、左右分栏和选区工具条保留原版式的交互式阅读体验学习解释设计总结、翻译、选中文字解释的 Prompt、状态机和历史记录面向学习场景的 AI 辅助阅读能力论文问答设计会话、轮次、全文上下文、历史预算和检索策略支持论文内连续提问用户与管理实现 JWT、刷新令牌、用户隔离、管理员角色和审计完整登录注册与管理闭环报告导出组织解释、高亮、笔记和批判性阅读内容Markdown、PDF、DOCX 学习报告云端部署分析 Docker、Nginx、卷权限和 MaaS 日志在小规格华为云 ECS 上稳定运行4.6 码道辅助调试实例实例一:测试数据误写开发库早期测试虽然创建了测试数据库,但应用在模块导入时已经初始化了指向开发库的数据库连接,导致部分测试仍可能写入开发库。码道根据数据库记录变化和初始化顺序分析问题,协助调整为延迟配置数据库 Engine,并增加测试库名称守卫、迁移失败即终止和测试残留检查。解决后,测试环境明确使用 paperlens_test,避免自动化测试污染真实论文数据。实例二:真实 MaaS 输出格式不稳定Mock 模型始终返回标准 JSON,但真实模型可能返回 Markdown 代码围栏、额外解释或字段缺失。码道协助增加严格的响应解析、围栏兼容、字段校验和安全失败状态;学习解释还使用独立的较长读取超时,避免长页翻译被普通问答的超时配置提前终止。实例三:Docker 容器在 ECS 上反复重启部署时 Nginx 采用只读文件系统,但默认尝试在 /var/cache/nginx 创建临时目录,导致容器因权限不足反复重启。码道根据容器日志定位到临时目录问题,将相关目录调整到 /tmp,并通过受限 tmpfs 提供可写空间。后端文件卷也曾因宿主卷所有权不匹配导致上传失败,随后增加一次性的 storage-init 服务,在后端启动前修正目录所有者和权限。实例四:公网 HTTP 下论文问答误报网络失败浏览器在普通 HTTP 环境下不能保证提供 crypto.randomUUID()。前端在创建会话后生成幂等请求 ID 时抛出本地异常,因此服务器只看到会话被创建和删除,没有收到真正的问题请求。码道根据前后端访问日志定位到请求链中断位置,增加基于 getRandomValues 的 UUID v4 回退逻辑,并区分本地运行异常和真实网络异常。这些问题说明,代码智能体的价值不仅是生成代码,还包括结合代码库、日志、运行环境和数据状态完成工程化定位。5. 功能解决方案设计5.1 原版式 PDF 阅读系统不将 PDF 正文简单转换成连续纯文本,而是为每一页生成页面图像,同时输出带坐标的文本层。页面图像保证视觉排版与原论文一致,透明文本层负责文字选择、字符偏移计算和高亮交互。这种设计兼顾了两个目标:用户看到的是原论文版式、图片、公式和表格;系统仍能知道用户选中了哪段文字,并把操作绑定到页码和字符区间。图 2 论文阅读工作台:左侧按页保留原始 PDF 版式,右侧统一承载学习解释、论文问答和学习记录。5.2 页面级学习解释“总结”和“翻译”按页生成并保留历史:总结要求覆盖当前页的各级标题;如果一个段落延续到下一页,可读取有限的下一页上下文补全含义;翻译要求保留标题层级和正文段落,不将公式、编号和专有名词随意改写;选中文字解释只处理用户选择的原文,重点说明概念、原理和例子。所有解释按页排序。点击历史记录可跳转到来源页;选中文字解释打开时,对应原文保持蓝色高亮。图 3 页面完整翻译:在保留标题、作者信息和正文层次的基础上,对当前页内容进行中文翻译。图 4 选中文字解释:左侧原文保持蓝色定位高亮,右侧从概念、原理和示例角度给出通俗说明。5.3 论文级多轮问答论文问答采用类似即时通信软件的对话界面。系统保存完整会话历史,输入区固定在底部,消息区域可独立滚动。为了减少“论文里明明有,模型却回答没有”的情况,后端不只发送当前页摘要,而是在首次提问时组装论文全文上下文;后续轮次再附加历史问答,并对超长内容执行可预测的长度预算。对页码、图号、表号等问题,检索器给予显式引用更高优先级。图 5 论文级多轮问答:用户可以围绕指定页码、表格或方法连续追问,系统保留会话历史并结合论文内容回答。5.4 高亮和笔记用户可以直接在 PDF 上选择文字:高亮以黄色保存;笔记以绿色标记,并保存笔记正文;选中文字解释使用蓝色定位;学习记录只展示当前页的高亮和笔记。记录同时保存原文、页码、字符起止位置和来源哈希。当论文内容或解析结果发生变化时,系统可以识别来源不一致,避免错误定位。图 6 高亮与笔记:黄色标记用于原文高亮,绿色标记关联学习笔记,右侧仅展示当前页的学习记录。5.5 用户、权限与管理员系统系统支持注册、登录、刷新令牌、退出、修改密码、忘记密码和个人资料。密码使用 Argon2 哈希;访问令牌采用 JWT,刷新令牌使用 HttpOnly Cookie,并具有轮换和重放检测机制。所有论文、解释、问答和学习记录均按 user_id 隔离。管理员可以查看系统概况、管理用户状态和角色、只读查看跨用户内容元数据,关键操作写入不可变审计记录。5.6 学习报告导出报告不再限定为“审阅报告”。即使论文没有执行批判性阅读,只要存在学习解释、高亮或笔记,也可以生成学习报告。报告按页组织内容,并可选择是否加入批判性阅读、指标或实验信息,最终导出为 Markdown、PDF 或 DOCX。图 7 学习报告导出:支持 PDF、DOCX 和 Markdown,固定汇总学习解释、高亮摘录和学习笔记,并可按需加入扩展分析。6. 核心技术难点与解决思路6.1 PDF 视觉版式与文本交互难以兼得难点:直接展示 PDF 可以保留版式,但难以稳定获取选中文字的字符位置;只展示解析文本又会破坏双栏、图表和公式布局。解决思路:采用“页面图像 + SVG 透明文本层 + 解析文本索引”的三层结构。图像负责视觉,文本层负责浏览器选择,后端标准化文本负责字符区间与学习记录。6.2 解析结果存在不确定性难点:不同 PDF 的字体、编码、文本顺序和表格结构差异很大,单个表格解析异常可能导致整个事务失败。解决思路:对正文、章节、表格和 Evidence 分阶段处理;表格写入使用嵌套事务或降级策略,使局部失败不影响论文正文;对扫描版 PDF 明确返回不支持 OCR,而不是生成不可用结果。6.3 大模型回答必须与论文上下文绑定难点:如果只传当前页或少量 Evidence,模型可能无法理解跨页图表;如果直接无限制传全文,又会超过上下文或增加费用。解决思路:采用“全文基础上下文 + 当前页优先 + 显式页码/图表引用检索 + 历史轮次预算”的组合策略。系统保存上下文哈希和请求幂等键,避免同一问题被重复提交。6.4 模型输出和网络调用不稳定难点:真实模型可能返回围栏文本、非标准字段或较长推理内容;长页翻译比普通问答耗时更长。解决思路:统一 LLMClient 接口,设置连接与读取超时边界;不同任务可以覆盖单次读取超时;模型结果经过严格 Pydantic 校验,失败时写入安全的任务状态,不将上游响应和密钥返回给用户。6.5 异步任务与页面状态一致性难点:解析、解释、问答和导出都不是瞬时操作。快速切换论文或页面时,旧请求可能晚于新请求返回并覆盖界面。解决思路:后端采用持久化任务状态和原子认领,前端采用受控轮询、代次标识和组件卸载清理。刷新页面后重新查询活动任务,终态立即停止轮询。6.6 小规格 ECS 上的资源与可靠性难点:2 vCPU、4 GiB 内存同时运行镜像构建、数据库、后端和前端时容易出现内存压力;公网拉取 Docker Hub 镜像也可能超时。解决思路:配置交换分区和容器资源上限;使用多阶段构建缩小运行镜像;通过华为云 SWR 镜像加速拉取基础镜像;只运行单后端实例和小连接池,避免为实习项目引入 Redis、Celery、Kubernetes 等额外组件。7. 安全与可靠性设计真实 API Key、数据库密码和 JWT Secret 通过环境文件注入,不进入代码仓库;上传文件校验后缀、PDF magic、大小和存储路径,防止路径穿越;数据查询统一校验资源所有者,管理员接口使用独立权限保护;日志只记录请求 ID、阶段和安全错误分类,不记录论文全文、令牌或 MaaS 响应正文;后端与数据库不直接暴露公网端口;容器启用 no-new-privileges,前端使用只读文件系统;提供 live/ready 健康检查、启动恢复和容器自动重启;自动化测试使用独立测试数据库,并在测试前后检查数据残留。8. 项目实施过程8.1 分阶段建设项目采用逐阶段增量开发,每一阶段都对应独立提示词、设计更新和可验收结果。阶段主要任务阶段出口P1FastAPI、Vue、PostgreSQL、Docker 工程骨架首页与健康检查可运行,迁移链建立P2PDF 上传、解析、章节、页面、文本块、表格和 Evidence论文可从文件转换为结构化、可定位内容P3MockLLM、Embedding、Huawei MaaS、结构化结果前端真实模型与离线模型可以切换P4指标抽取、实验数据统计和模型运行配置模型理解与确定性计算分离P5实验文件导入、校验、比较和可视化论文实验结果可结构化分析P6Markdown、PDF、DOCX 报告分析结果可以形成文件交付P7阅读工作台、学习解释、多轮问答、高亮和笔记产品主线转为个人论文阅读学习P8登录注册、管理员、审计、恢复、限流、部署与安全形成完整用户系统并具备云端运行条件其中 P7 是产品方向最重要的一次调整。项目没有删除已经实现的审阅、指标和实验功能,而是把它们移动为“批判性阅读”和“实验理解”等高级入口,主路径改为上传论文后直接进入逐页阅读工作台。8.2 设计文档与任务追踪码道在编码前先同步以下设计层:需求细化:确认用户目标、功能范围、非目标和冲突决策;架构设计:明确前后端边界、外部 MaaS、任务与存储关系;数据模型:定义实体、外键、状态机、索引和迁移安全;API 设计:固定请求字段、响应结构、权限和错误语义;页面设计:固定路由、页面状态和交互行为;测试设计:只保留正常路径、关键失败和必要恢复场景;SDD 与 Sprint:把需求映射到具体设计、文件和任务状态。这种做法解决了长周期智能体开发中常见的“上一轮约束在下一轮丢失”问题。提示词不再重复粘贴整个项目,而是引用稳定设计资料,再补充本轮真实基线和差异要求。8.3 集中验收策略为了避免码道在每个实现轮次反复执行耗时的全量测试,项目后期采用“实现与验收分离”策略:码道负责更新必要测试资产,但提示词明确禁止运行测试、构建、迁移往返、Docker 重建和 HTTP 烟测;实现轮次完成后,先检查实际改动范围和接口契约;后端默认只运行受影响模块的定向测试;前端变更运行相关 Vitest 和一次生产构建;只保留一条关键业务烟测,例如“上传 PDF → 解析 → 进入阅读页”;认证、迁移链、共享基础设施或最终发布才执行更完整的回归。单个新功能通常只设计 1 个正常用例、1 个重要失败用例,以及在确有并发或恢复风险时增加 1 个对应场景。该策略更符合个人实习项目的成本与风险水平。8.4 华为云 ECS 部署过程部署采用单机 Compose,核心步骤如下:创建 VPC、子网、安全组、弹性公网 IP 和 Ubuntu 22.04 ECS;安全组开放 80,并将 22 端口来源限制为当前管理 IP;安装 Docker Engine 与 Compose,配置华为云 SWR 镜像加速;将代码发布包上传到 /opt/paperlens,检查校验和后解压;创建权限为 600 的部署环境文件,交互式写入数据库密码、JWT Secret 和 MaaS Key;使用 docker-compose.single.yml 构建并启动服务;检查容器状态、前端健康检查和后端 readiness;在浏览器完成注册、上传论文、学习解释和论文问答验证。示例命令中的配置均使用占位符,不包含真实凭据:cd /opt/paperlens chmod 600 deploy/huawei/.env.single docker compose \ --env-file deploy/huawei/.env.single \ -f deploy/huawei/docker-compose.single.yml \ up -d --build docker compose \ --env-file deploy/huawei/.env.single \ -f deploy/huawei/docker-compose.single.yml \ ps -a curl -fsS http://127.0.0.1/healthz curl -fsS http://127.0.0.1/api/v1/health/ready服务以 detached 模式运行,因此关闭本地 PowerShell 或 SSH 会话不会停止容器。ECS 重启后,Docker 服务与 Compose 的重启策略负责恢复应用。8.5 部署期问题闭环现象定位依据修正Docker Hub 拉取超时docker pull 访问官方 Registry 超时配置华为云 SWR 镜像加速并重启 DockerNginx 容器持续重启日志显示只读目录无法创建临时文件临时目录迁移到 /tmp,通过受限 tmpfs 提供写入PDF 上传失败后端日志显示持久卷目录权限不足启动前由一次性初始化服务修正卷所有权管理员升级 SQL 失败psql 变量替换与引号组合错误改用明确参数边界并先只读查询用户 ID论文问答前端报网络失败后端只有会话请求,没有问题请求为非安全 HTTP 环境增加 UUID v4 回退实现长页翻译偶发失败MaaS 请求耗时超过通用读取超时为学习解释配置独立、有限的读取超时部署验收以真实页面操作为准,不仅依赖容器显示 healthy。只有注册登录、论文上传解析、MaaS 学习解释、论文问答和管理员入口均完成小额验证,才认为案例具备可演示性。9. 应用效果与价值PaperLens 将“看 PDF、查术语、做笔记、问模型、整理报告”从多个割裂工具合并为一个连续流程。对个人学习场景而言,它带来的价值主要体现在:降低英文论文和专业概念的理解门槛;保持 AI 结果与当前论文、页码和原文选区的联系;让多轮问答、解释历史、高亮和笔记可以长期保存;通过华为云 MaaS 获得真实模型能力,同时保留 Mock 模型便于离线开发;通过码道代码智能体提升跨前后端开发和故障定位效率;使用单台小规格 ECS 即可完成课程设计、实习成果或个人演示部署。10. 局限与后续规划当前版本面向小规模个人使用,仍有以下边界:暂不支持扫描版论文 OCR;语义检索尚未使用持久化向量数据库;后台任务仍采用进程内执行器,不适合多实例横向扩展;单机 PostgreSQL 和本地文件卷需要定期备份;后续可根据实际用户量逐步引入 OBS、RDS、HTTPS、任务队列、pgvector 和多模态论文理解,但不在小规模案例阶段提前增加系统复杂度。11. 总结PaperLens 展示了如何将华为云码道(CodeArts)代码智能体、ModelArts Studio(MaaS)与常见 Web 技术结合,构建一套可实际部署的智能论文阅读学习应用。在研发侧,码道帮助项目完成需求拆解、跨文件编码、测试设计和部署故障定位;在运行侧,MaaS 提供总结、翻译、解释和问答能力;在基础设施侧,华为云 ECS 提供轻量、可控的容器运行环境。最终方案既满足个人学习项目的成本边界,也保留了向云数据库、对象存储和更可靠任务架构演进的空间。12. 参考资料华为云开发者空间实战案例参考页面华为云码道(CodeArts)代码智能体产品功能华为云码道(CodeArts)内置智能体用户指南ModelArts Studio(MaaS)API 调用规范华为云弹性云服务器 ECS 产品介绍
-
我用codearts ide链接上华为云的notebook实例使用ssh方式进行开发,但是侧边agent对话框加载不出来,该如何解决我也安装了看起来需要的扩展
yd_261135708
发表于2026-07-18 14:28:06
2026-07-18 14:28:06
最后回复
CodeArts小助手-蚂蚁
2026-07-20 09:15:22
48 2 -
码道会增加自定义第三方模型吗?
yd_216936833
发表于2026-07-18 12:02:59
2026-07-18 12:02:59
最后回复
CodeArts小助手-蚂蚁
2026-07-21 11:26:50
163 4 -
[问题求助] The inference service is abnormal, error info is : [No available backend service was found.].这是体验版上限还是我的对话出问题了?The inference service is abnormal, error info is : [No available backend service was found.].我正在使用,然后反复出现这句话,还给了trace_id,但是不知道怎么用
-
学校:西安交通大学团队名称:吴彦组团队成员:李浩宇 孙昊 汤昊东 王锘淳 王睿 肖梓宸 杨丁欢 杨佳潮提交日期:2026年7月项目地址cid:link_0作品介绍华为云开发者训练营优秀作品展示馆平台,是面向华为云开发者高校训练营活动的作品展示与互动平台。平台支持用户注册登录、作品提交与审核、多维互动评价(点赞/点踩/问号/收藏/投票)、评论回复、排行榜系统、赛道管理、奖项配置与获奖展示、后台管理等功能。平台覆盖4类用户角色(访客、学生、导师、管理员),提供12个前端页面,包含30余个RESTful API接口,采用前后端分离架构,部署于华为云ECS,实现从0到1的完整产品交付。首页首页主要展示网站整体数据与精选作品、排行榜等等功能,同时可以一键进入各大板块。登录界面可以选择手机号或者邮箱登录,登录完成后页面自动更新。图1 作品首页设计作品展示各种参赛作品的板块,所有审核通过的作品都可以展现在这里,实现了按时间排序、热度排序、点赞最多排序等排序方式,还有赛道区分,同赛道作品推荐,点赞评论交互功能,查看项目地址等等功能,方便开发者展示分享自己的成果。点赞与评论为实时功能,自动更新。图2 作品页面赛道展示目前可以参加的所有赛道种类以及相应的作品排行支持综合排行、点赞排行、热度排行等等的多元排行标准盛典所有获奖的各赛道作品可以在盛典处展示后台可以提交作品,申请提权,游客需要成为学生或者导师角色才可以发布作品,导师可以审核学生提交的作品,管理员可以提交,审核作品,也可以给作品颁奖,修改用户权限,管理网站注册用户等等。图3 管理员界面后台开发经验一完成分组,我们组就进入了热烈的讨论环节。首先我们组的每一位同学都对我们组将要开发的项目进行了分析,考虑到以下三个事实:1.我们组是所有组之中人数最多的组,足足有八个人,比其他的组整整多出了一倍。2.本次活动开发的部署是在华为云ECS上的,考虑到项目成本与开发限制,我们只能部署在单虚拟机,最多挂载一个新的云硬盘,对项目架构有了限制。3.目前AI Vibe Coding还停留在小规模编程上面,在大规模编程和项目开发方面还极度依赖人工功能检查与审核修复。我们讨论并决定采取针对性的措施。对于第一点事实,我们决定首先建立类似目前人工开发的项目管理分工,两人制作开发WORD与技术PPT,两人准备排练上台演讲,四人负责后台开发分工,用来方便更加细致的项目管理与内容准备。事实上,正因为这样的分工,我们在开始编程的第一天决定技术栈并形成项目基本框架之后,就可以让负责制作开发文档和负责上台分享的同学早早开始准备,这样给负责分享的同学极大的空间余裕,让同学能够有更多的时间对底层技术栈以及网页展示进行了解和打磨,展示出更好的效果。针对第三点问题,我们还针对性采取了修改项目架构的方式,我们通过与码道的智能体实现进行沟通,选定了使用Vue+Spring Boot作为前后端底层架构,数据统一使用MySQL挂载在云硬盘上,使用Redis作为热更新缓存,这样的话一方面统一了前后端接口,方便前后端同学并发开发,提高开发效率;另一方面契合了我们的部署开发环境,减少了网站的运营维护开支。针对第三点问题,我们决定采取一部分现代软件工程已经成熟的做法,即把整个代码库放置到GitCode上面,借助华为自主开发的AIShell智能体,我们能够很方便的完成GitCode库项目的实际落地部署和拉取更新,让AIShell总结出在部署过程中遇到的问题,然后利用码道在本地改后向GitCode提交PR,这样一方面方便了本地调试,另一方面也方便我们在本地看到项目实际发生的变化,避免了对于华为ECS上相对GUI系统比较陌生的Linux文本行命令操作。还有,针对我们项目的DEBUG过程,我们采取List+PR的修改方式,也就是所有人往微信群里面接龙List更新需要修复的BUG,让一位开发同学统一进行修改,类似更迅速的GitCode里面的Issues操作;针对目前AI修改代码往往不进行单点修改,而是修改整个项目的情况,对于前端同学提交的修改PR,我们不选择直接合并,而是让码道总结出来一个CHANGE.md,然后交给一位同学进行统一修改,这样就避免了Git合并代码过程中合并冲突的情况。最后,经过评委老师的指点,我们还学习了一些新的开发经验。首先,在项目开始之前可以使用AI进行洞察,就是针对目前做的比较好的厂家,总结经验进行学习;其次,在开发过程中不能对AI盲目相信,对于有疑问的点,比如说未登陆账号的浏览量是否算数的问题,应当自己查证业界成熟做法,而不是全信AI。项目readme## 技术栈| 层级 | 技术 ||------|------|| 前端 | Vue 3 + Vue Router + Vite 6 || 后端 | Spring Boot 3.2.5 + Spring Data JPA + Spring Security || 数据库 | MySQL 8.0 + Redis 7.0 || 认证 | JWT (jjwt 0.12.5) || 数据库迁移 | Flyway || 部署 | Nginx + systemd (华为云 ECS) |## 架构图```┌──────────────────────────────────────────┐│ 华为云 ECS (CentOS/Ubuntu) ││ ││ ┌────────────────────────────────────┐ ││ │ Nginx (端口 80/443) │ ││ │ - 静态资源直接返回 (/static/) │ ││ │ - 动态请求代理到后端 (/api/) │ ││ └────────────┬───────────────────────┘ ││ │ ││ ┌────────────▼───────────────────────┐ ││ │ Spring Boot App (端口 8080) │ ││ │ - 文件上传接口 │ ││ │ - 业务逻辑 │ ││ └──────┬─────────────────────────────┘ ││ │ ││ ┌──────▼──────┐ ┌──────────────────┐ ││ │ MySQL 8.0 │ │ Redis 7.0 │ ││ │ (端口3306) │ │ (端口6379) │ ││ └─────────────┘ └──────────────────┘ ││ ││ 文件存储目录: /data/training-files/ ││ (挂载云硬盘或者直接在本地) │└──────────────────────────────────────────┘```---## 本地开发### 前置条件- **JDK 17+**- **Maven 3.8+**- **Node.js 18+**(推荐 20+)- **MySQL 8.0**(本地运行,端口 3306)- **Redis 7.0**(本地运行,端口 6379)### 1. 启动后端```bash# 确保 MySQL 和 Redis 已启动# 创建数据库mysql -u root -e "CREATE DATABASE IF NOT EXISTS devcamp_showcase DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;"# 启动 Spring Boot(使用 dev profile)mvn spring-boot:run -Dspring-boot.run.profiles=dev```后端启动后访问 `http://localhost:8080/api`,Flyway 会自动创建表结构。### 2. 启动前端```bashcd frontendnpm installnpm run dev```前端启动后访问 **http://localhost:3000**,Vite 会自动将 `/api` 请求代理到 `localhost:8080`。### 3. 本地预览(仅前端,无需后端)如果只想看页面效果、不需要真实数据:```bashcd frontendnpm installnpm run dev```打开 http://localhost:3000 即可预览所有页面布局和导航。API 请求会失败,但页面结构完整可浏览。---## 部署到华为云 ECS### ECS 最低配置| 项目 | 推荐 ||------|------|| 规格 | 2核4GB(开发)/ 4核8GB(生产) || 系统 | CentOS 7/8 或 Ubuntu 20.04/22.04 || 磁盘 | 40GB 系统盘 + 可选云硬盘 || 安全组 | 开放 80 端口 |### 方式一:一键部署(推荐)**1. 本地构建**```bash# 构建后端mvn clean package -DskipTests# 构建前端cd frontend && npm install && npm run build && cd ..```**2. 上传到 ECS**```bashscp target/devcamp-showcase.jar root@<ECS_IP>:/data/devcamp-showcase/scp -r frontend/dist root@<ECS_IP>:/data/devcamp-showcase/frontend/scp -r deploy/ root@<ECS_IP>:/data/devcamp-showcase/deploy/```**3. 在 ECS 上执行一键部署**```bashssh root@<ECS_IP>cd /data/devcamp-showcase/deploychmod +x *.sh./deploy.sh```部署完成后访问 `http://<ECS公网IP>`。### 方式二:手动部署详见 [deploy/README.md](deploy/README.md)。### 部署注意事项(踩坑记录)> 以下问题在实际部署中遇到过,请务必留意。1. **MySQL 版本必须 8.0+** - CentOS 7 默认仓库只有 MySQL 5.7,Flyway 9.22+ 和 Hibernate 6 不支持 - 需手动安装 MySQL 8.0 官方仓库:`yum install https://dev.mysql.com/get/mysql80-community-release-el7-11.noarch.rpm` - 一键部署脚本已包含自动检测和安装 MySQL 8.0 的逻辑2. **数据库密码需与配置一致** - systemd 服务文件中 `DB_PASSWORD` 环境变量需与实际 MySQL 密码一致 - 也可在 JAR 包同级目录创建外部 `application.yml` 覆盖配置(Spring Boot 自动加载) - 修改密码后需 `systemctl restart devcamp-showcase`3. **生产环境 `ddl-auto` 已设为 `none`** - Flyway 管理表结构,Hibernate 不做 schema 验证,避免 VARCHAR/ENUM 类型不一致报错 - 开发环境仍为 `validate`,方便发现实体与表结构的偏差4. **初始数据由 Flyway 迁移脚本自动插入** - `V2__init_data.sql` 包含管理员账号、示例赛道、奖项和系统设置 - 无需手动注册或执行 SQL5. **Nginx 默认配置冲突** - CentOS 默认 Nginx 配置会拦截 80 端口,需删除 `/etc/nginx/conf.d/default.conf` 或 `/etc/nginx/sites-enabled/default` - 一键部署脚本已自动处理6. **前端文件权限** - Nginx 需要读取前端文件,权限不足会返回 403 - 一键部署脚本已自动设置 `chmod 755` 和 `chown nginx:nginx` - 手动部署时需执行:`chmod -R 755 /data/devcamp-showcase/frontend && chown -R nginx:nginx /data/devcamp-showcase/frontend`7. **Redis 需手动设置开机自启** - 部分系统安装 Redis 后不会自动启用:`systemctl enable redis && systemctl start redis` - 一键部署脚本已包含此步骤### 管理员账号- 邮箱:`admin@devcamp.huawei.com`- 密码:`admin123`- **生产环境请务必修改密码和 JWT 密钥**### 环境变量| 变量 | 说明 | 默认值 ||------|------|--------|| DB_USERNAME | 数据库用户名 | devcamp || DB_PASSWORD | 数据库密码 | DevCamp2026! || REDIS_PASSWORD | Redis 密码 | (空) || JWT_SECRET | JWT 签名密钥 | (见 service 文件) |### 常用运维命令```bashjournalctl -u devcamp-showcase -f # 查看后端日志systemctl restart devcamp-showcase # 重启后端systemctl restart nginx # 重启 Nginxmysqldump -u root devcamp_showcase > backup_$(date +%Y%m%d).sql # 备份数据库```---## 项目结构```HCDevcampShowcase/├── Init.md # 原始需求文档├── List.md # 项目速查手册(供 AI 智能体使用)├── pom.xml # Maven 构建配置├── src/main/java/com/huawei/devcamp/│ ├── DevCampApplication.java # 启动类│ ├── config/ # Security, Redis, WebMvc, JWT Filter│ ├── controller/ # REST 控制器(8 个)│ ├── entity/ # JPA 实体(10 个)│ ├── enums/ # 枚举(3 个)│ ├── repository/ # Spring Data JPA(9 个)│ ├── service/ # 业务逻辑(9 个)│ ├── dto/request/ # 请求 DTO(7 个)│ ├── dto/response/ # 响应 DTO(8 个)│ └── common/ # Result, PageResult, BusinessException, GlobalExceptionHandler├── src/main/resources/│ ├── application.yml # 主配置│ ├── application-dev.yml # 开发环境│ ├── application-prod.yml # 生产环境│ └── db/migration/│ ├── V1__init_schema.sql # Flyway 建表迁移│ └── V2__init_data.sql # Flyway 初始数据迁移├── frontend/ # Vue 3 前端│ ├── src/views/ # 页面(8 个)│ ├── src/components/ # 组件(4 个)│ ├── src/api/ # API 封装│ ├── src/router/ # 路由配置│ ├── src/utils/ # 工具函数(auth)│ └── src/assets/ # 全局样式└── deploy/ # 部署脚本 ├── deploy.sh # 一键部署 ├── init-db.sh # 数据库初始化 ├── devcamp-showcase.conf # Nginx 配置 ├── devcamp-showcase.service # systemd 服务 ├── build-frontend.sh # 前端构建脚本 ├── build-backend.sh # 后端构建脚本 └── README.md # 部署详细文档```写在最后感谢华为给予我们这么一次宝贵的机会尝试利用码道开发。我们将会继续积累实战经验,期待将来带来更好的作品。
-
已报名OPC优秀创意案例征集活动的用户,请在本帖下“盖楼”回复案例或作品,谢谢~
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签