Compare commits

..

36 Commits

Author SHA1 Message Date
smallbailangui a689e09de2 docs:更新部署文档与注意事项
4 weeks ago
smallbailangui b96e0b6ea0 docs(project): 删除项目文档 README 索引文件
4 weeks ago
smallbailangui b3b16d31d1 docs: 更新UML文档
4 weeks ago
hnu202326010328 0357d9339d docs:提交用户手册
1 month ago
hnu202326010328 ef2964a046 上传文件至 'doc/project/05-测试报告'
1 month ago
hnu202326010328 c64bdd7d62 删除 'doc/project/05-测试报告/测试报告.pdf'
1 month ago
hnu202326010328 d95af47ebc docs:提交测试报告
1 month ago
smallbailangui e365930b32 docs: 更新UML顺序图
1 month ago
smallbailangui 82c73043f9 docs: 更新UML顺序图
1 month ago
smallbailangui 77626a979b test(backend): 重命名测试文件并删除 ddl 生成脚本
1 month ago
Teptao f7bcdafb07 Merge branch 'develop' of https://bdgit.educoder.net/hnu202326010328/202326010 into develop
1 month ago
Teptao 1efac00aa2 下拉框
1 month ago
smallbailangui df5ae7543f Merge remote-tracking branch 'origin/develop' into develop
1 month ago
smallbailangui 34da277dd8 fix: 更改已登出为登出
1 month ago
Teptao 58760f24f7 修改布局
1 month ago
Teptao 07e31768b9 修改布局
1 month ago
Teptao 501a77b5e5 用户详情界面优化
1 month ago
smallbailangui ada01300de Merge remote-tracking branch 'origin/develop' into develop
1 month ago
smallbailangui dc28610821 fix(admin): 优化API密钥和URL格式验证逻辑
1 month ago
Teptao 6d5a302b85 修复近期登录历史栏
1 month ago
smallbailangui cd29ced4ad feat(dashboard): 添加项目创建表单字段长度验证和显示
1 month ago
smallbailangui f1120aa371 fix(admin): 添加 AI 模型连接测试的 400 错误处理
1 month ago
smallbailangui cb488d4c06 fix(dashboard): 优化项目创建失败错误处理
1 month ago
smallbailangui c370f5d9aa fix(auth): 修复密码验证和用户信息显示问题
1 month ago
smallbailangui cb81ad91f1 refactor(user): 更新邮箱验证实现
1 month ago
ymr fa6747c3c3 docs: 提交第十五周个人周总结
1 month ago
lsbp 3873821a0d Merge remote-tracking branch 'origin/develop' into develop
1 month ago
lsbp 344b91a472 docs:添加梁峻耀第十五周周总结文档
1 month ago
hnu202326010328 778fc95c41 docs:提交第十五周小组会议纪要
1 month ago
hnu202326010328 c212f045db docs: 提交第十五周周总结文档
1 month ago
hnu202326010328 93f2722724 docs:提交王利蓉第十五周周总结文档
1 month ago
smallbailangui 7bdf0a72d4 docs: 添加李果霖第十五周周总结文档
1 month ago
Teptao 57ad5a88cf docs:提交李文韬15周周总结
1 month ago
smallbailangui 05f2c52caa chore(docker): 配置容器时区为上海时区
1 month ago
smallbailangui 3d43928fe7 fix(admin): 修复今日活跃用户文本显示
1 month ago
smallbailangui fce25c3601 feat(AdminStatus): 更新今日查询量标签为今日业务强度
1 month ago

@ -0,0 +1,120 @@
# 小组会议纪要-第15周
## 会议记录概要
**团队名称:** 3班-葫芦娃救bug
**指导老师:** 李友焕
**主 持 人:** 项目经理
**记录人员:** 王利蓉
**会议主题:** 项目收尾阶段工作部署与总结
**会议地点:** 线上会议
**会议时间:** 2026-01-03 19:00-20:00
**记录时间:** 2026-01-03 21:00
**参与人员:** 全体成员
---
## 会议内容
### 1. 项目收尾阶段工作进展同步
- **系统集成测试完成情况**
- 全系统集成测试已按计划完成,各模块功能验证通过
- 核心业务逻辑严密,模块间联动无冲突
- 测试中发现的主要问题已记录并修复
- **云端部署状态确认**
- 系统已成功部署至云服务器,运行环境稳定
- 云端环境下各项功能测试通过,性能符合预期
- 部署文档和运维说明已整理完成
- **文档编制工作进展**
- 用户手册编写完成,涵盖所有功能模块的操作指南
- 测试报告编写完成,包含测试用例和结果汇总
- 技术文档更新同步,确保与最终实现一致
### 2. 下一阶段工作安排
- **最终评审准备**
- 整理所有交付物,包括代码、文档、演示材料等
- 准备项目总结汇报材料
- 安排最终演示彩排
- **代码仓库整理**
- 清理临时分支,合并主分支
- 完善代码注释和README文档
- 整理依赖包和配置文件
- **项目经验总结**
- 各成员整理个人工作经验和收获
- 团队总结项目开发过程中的经验教训
### 3. 质量保证措施确认
- **代码质量复核**
- 全员进行代码规范性最终检查
- 确保符合Google编码规范要求
- 清理所有硬编码和不规范写法
- **系统稳定性验证**
- 进行压力测试和性能测试
- 验证云端环境下的系统稳定性
- 准备应急预案和问题排查
- **文档完整性检查**
- 确认所有文档格式规范、内容完整
- 检查文档与实际实现的一致性
- 确保文档可读性和实用性
### 4. 团队协作与交流
- **沟通协调机制**
- 保持团队成员间及时沟通
- 建立问题快速响应机制
- 确保信息同步和资源共享
- **责任分工确认**
- 各成员明确收尾阶段职责
- 确保工作按时保质完成
---
## 问题总结
### 已解决问题:
1. 系统集成测试顺利完成,发现的问题已修复
2. 云端部署成功,系统运行稳定
3. 用户手册和测试报告编制完成
4. 代码规范性得到进一步提升
### 待解决问题:
1. 最终评审材料的完善和优化
2. 项目经验总结的深度挖掘
3. 代码仓库的最终整理和归档
---
## 小组协作情况总结
**协作情况:** 本周团队在项目收尾阶段协作高效,各成员认真负责,积极配合,确保了各项收尾工作的顺利进行。在测试、部署和文档工作中展现了良好的团队协作精神。
## 一周纪律情况总结
**纪律情况:** 全体成员按时参加会议,认真参与讨论,工作态度端正。在时间紧张的情况下,能够合理安排工作,保证项目进度。
---
## 备注
1. 本周是项目开发的最后冲刺阶段,需要全体成员保持高度专注和责任心
2. 各项收尾工作需按计划推进,确保项目顺利交付
3. 建议团队成员及时总结经验,为今后项目开发积累宝贵经验
---
## 【注】
1. 本文档为"葫芦娃救bug"小组第15周会议记录记录了项目收尾阶段的工作部署情况
2. 会议决议和任务安排已明确,各成员需按时完成分配的工作
3. 下周将进行项目最终评审,请全体成员做好准备
4. 文档已按要求整理并提交,相关材料已同步至代码托管平台

@ -0,0 +1,35 @@
# 小组周总结-第15周
## 团队名称和起止时间
**团队名称:** 3班-葫芦娃救bug
**开始时间:** 2025-12-29
**结束时间:** 2026-01-04
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|------|----------|----------|----------|
| 1 | 完善风控模块 | 完成 | 伊木然完成系统自动风险用户判断功能,管理员可基于系统判断进行手动封禁操作 |
| 2 | 全系统集成测试 | 完成 | 全体成员参与系统集成测试,覆盖所有已完成模块,核心业务链路验证通过 |
| 3 | 修复前端BUG | 完成 | 前端人员解决界面布局适配问题及测试发现的UI交互缺陷提升系统可用性 |
| 4 | 修复后端BUG | 完成 | 后端人员修复测试过程中发现的业务逻辑漏洞,系统稳定性显著提升 |
| 5 | 部署云服务器 | 完成 | 李文韬完成云端环境配置和系统部署,系统在云端运行稳定 |
| 6 | 用户手册编写 | 完成 | 李果霖、伊木然完成用户手册编写,涵盖功能说明和常见问题处理,为操作提供清晰指引 |
| 7 | 测试报告编写 | 完成 | 梁峻耀、李文韬、王利蓉完成测试用例编写和集成测试结果汇总 |
## 小结
1. **系统稳定性达标**通过全面的集成测试和BUG修复系统各功能模块在联动时业务逻辑严密、运行稳定
2. **云端部署成功**:系统成功从本地开发环境迁移至云服务器,在真实云运行环境下表现稳定可靠;
3. **文档成果丰富**:用户手册和测试报告同步完成,为软件交付提供完整的技术和用户文档支持;
4. **遗留问题解决**:前端历史遗留的组件变形、布局错乱等问题得到有效解决,系统视觉稳定性大幅提升;
5. **团队协作高效**:全体成员在测试、修复和文档编写过程中密切配合,展现了良好的团队协作精神。
---
## 【注】
1. 集成测试过程中发现的BUG已及时记录并修复系统整体质量符合预期
2. 用户手册编写充分考虑了非技术背景用户的需求,操作指南清晰易懂;
3. 云服务器部署为系统正式上线运行提供了可靠的环境保障;

@ -0,0 +1,22 @@
# 个人周总结 - 第15周
**姓  名**:梁峻耀
**团队名称**3班-葫芦娃救bug
**开始时间**2025-12-29
**结束时间**2026-01-04
## 本周任务完成情况
| 序号 | 计划内容 | 是否完成 | 情况说明 |
| ---- | -------------- | -------- | ------------------------------------------------------------ |
| 1 | 测试报告编写 | 完成 | 与李文韬、王利蓉协作编写了覆盖12+核心接口的测试用例设计了结构化的测试报告模板包含本地vs云端性能对比数据针对风控模块、AI队列等核心功能进行了全面验证测试问题闭环率达95%。 |
| 2 | 后端BUG修复 | 进行中 | 重点解决了数据库适配后的兼容性问题修复了3处双数据库环境下的逻辑漏洞优化了全局异常处理模块在极端情况下的响应机制重构了2处缓存失效逻辑确保Redis与Celery任务状态一致性。 |
| 3 | 全系统集成测试 | 完成 | 主导设计了多场景集成测试用例覆盖用户注册到AI分析完整业务链路验证了Sqlite/PostgreSQL双数据库环境下的系统稳定性针对测试发现的5项关键问题提出了解决方案并完成修复。 |
## 小结
**核心进展**
- 高质量完成测试报告,包含详尽的性能对比数据和问题追踪,为系统上线提供质量保障;
- 系统性地解决了多数据库适配后的遗留问题,提升了系统在不同环境下的兼容性和稳定性;
- 建立了完善的测试验证体系,为后续版本迭代奠定了质量基础。

@ -0,0 +1,27 @@
# 个人周总结-第15周
## 姓名与起止时间
姓名:李果霖
团队名称3班-葫芦娃救bug
开始时间2025-12-29
结束时间2026-01-04
## 本周任务完成情况
| **序号** | **计划内容** | **完成情况** | **情况说明** |
| -------- | ------------------------ | ------------ | ------------ |
| 1 | **用户手册编写** | **已完成** | 与伊木然联合完成核心业务功能的用户手册章节补充RAG检索、AI对话、ER图导出等操作指引按交付要求整理上线。 |
| 2 | **云端部署技术支持** | **已完成** | 配合李文韬完成云服务器Celery异步任务队列与PostgreSQL/SQLite多数据库配置校验确认本地高级特性在云端稳定运行。 |
| 3 | **全系统集成测试** | **已完成** | 参与全链路测试重点验证RAG检索准确性、ER图生成与异步调度在云端表现测试结果与预期一致。 |
| 4 | **后端BUG修复** | **已完成** | 针对集成测试发现的异步任务与多库适配问题进行修复与回归验证,确保业务链路稳定。 |
| 5 | **代码规范最终审查** | **已完成** | 对负责模块执行收尾自查,清理临时调试代码与冗余注释,核对配置与文档一致性,符合代码规范要求。 |
## 小结
1. **交付收口**:完成核心功能的用户手册输出,并对文档与实现进行一致性核对,为最终评审提供可落地的用户指引。
2. **云端稳定性验证**:协助云端部署与多数据库、异步任务运行验证,确保核心特性在云环境无功能缺口。
3. **质量闭环**:通过集成测试与针对性修复消除异步和适配类问题,结合规范自查,整体模块在性能与质量上达到收尾标准。

@ -0,0 +1,31 @@
# 个人周总结-第15周
## 姓名与起止时间
**姓 名**:李文韬
**团队名称**3班-葫芦娃救bug
**开始时间**2025-12-29
**结束时间**2026-01-04
## 本周任务完成情况
| **序号** | **任务内容** | **是否完成** | **情况说明** |
| -------- | -------------- | ------------ | ------------------------------------------------------------ |
| 1 | 部署云服务器 | 已完成 | 完成云端环境配置和系统部署,确保系统在云端运行稳定。 |
| 2 | 测试报告编写 | 已完成 | 参与完成测试用例编写,并对集成测试结果进行了汇总。 |
| 3 | 全系统集成测试 | 已完成 | 全程参与系统集成测试,覆盖所有已完成模块,验证核心业务链路。 |
| 4 | 前后端BUG修复 | 已完成 | 配合团队解决界面布局适配问题及业务逻辑漏洞,提升系统稳定性。 |
| 5 | 一周总结 | 已完成 | 整理本周部署与测试成果,汇总集成测试报告,并完成了本份周总结。 |
## 小结
1. **部署任务达成:** 顺利完成从本地开发环境到云服务器的迁移,系统在真实云运行环境下表现稳定可靠,为正式上线提供了保障。
2. **质量全面把控:** 通过深度参与全系统集成测试与文档编写,及时修复了遗留的组件变形与布局错乱问题,系统整体质量符合预期。
## 【注】
1. **工作成果:** 云服务器配置已全部完成,目前系统运行环境稳定。
2. **团队协作:** 本周与团队成员在测试、修复和文档编写过程中密切配合,展现了高效的协作精神。

@ -0,0 +1,43 @@
# 个人周总结-第15周
## 姓名和起止时间
**姓  名:** 王利蓉
**团队名称:** 3班-葫芦娃救bug
**开始时间:** 2025-12-29
**结束时间:** 2026-01-04
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|------|----------|----------|----------|
| 1 | 全系统集成测试参与 | 完成 | 积极参与系统集成测试重点验证了RAG检索、会话管理、报表和公告功能在集成环境下的稳定性和正确性所有核心流程测试通过 |
| 2 | 测试报告编写(核心模块) | 完成 | 完成了RAG检索、会话管理、报表、公告等核心模块的测试用例编写详细记录了测试步骤、预期结果和实际结果并汇总了集成测试结果 |
| 3 | 后端BUG修复支持 | 完成 | 协助修复了测试中发现的与负责模块相关的业务逻辑问题特别是优化了RAG检索的性能和准确性 |
| 4 | 风控模块测试支持 | 完成 | 配合伊木然完成了风控模块与现有功能的集成测试,确保风险用户判断逻辑不影响正常的用户业务流程 |
| 5 | 用户手册技术内容审核 | 完成 | 认真审核了用户手册中关于RAG检索、报表功能等复杂功能的技术描述确保表述准确、清晰易于用户理解 |
| 6 | 云端部署验证测试 | 完成 | 在李文韬完成云服务器部署后,及时对负责的功能模块进行了云端环境验证测试,确认功能运行稳定,数据交互正常 |
| 7 | 代码规范性最终检查 | 完成 | 对负责模块的代码进行了全面规范性检查,清理了遗留的硬编码和格式问题,确保代码质量符合项目评审要求 |
## 对团队工作的建议
1. **经验总结制度化:** 建议团队建立项目经验总结机制,将本次开发过程中的技术难点、解决方案和最佳实践进行系统整理,形成团队知识库;
2. **文档持续维护:** 建议建立文档定期更新和维护机制,确保技术文档、用户手册等随着系统迭代保持同步更新;
3. **代码审查常态化:** 建议在今后的项目中推行定期的代码交叉审查,持续提升团队的代码质量和协作效率;
## 小结
1. **测试工作完成:** 成功完成核心模块的集成测试和测试报告编写工作,为项目质量提供了有力保障;
2. **问题修复及时有效:** 积极配合团队修复测试中发现的问题特别是对RAG检索模块进行了性能优化
3. **文档质量严格把关:** 认真审核技术文档,确保用户手册内容准确、易懂;
4. **云端验证顺利通过:** 负责的功能模块在云端环境中运行稳定,满足部署要求;
5. **代码质量显著提升:** 通过最终代码规范性检查,个人负责模块的代码质量达到评审标准;
6. **团队协作高效顺畅:** 与团队成员在测试、修复和文档工作中配合默契,展现了良好的团队协作精神;
7. **项目收获丰富:** 通过本次项目,不仅提升了技术能力,还积累了宝贵的项目管理和团队协作经验。
---
## 【注】
1. **技术能力提升:** 希望未来能有机会参与更多关于系统性能优化和云端架构设计的专题学习;

@ -0,0 +1,27 @@
# 个人周总结-第15周
## 姓名与起止时间
**姓  名:** 伊木然
**团队名称:** 3班-葫芦娃救bug
**开始时间:** 2025-12-29
**结束时间:** 2026-01-04
## 本周任务完成情况
| **序号** | **计划内容** | **完成情况** | **情况说明** |
| -------- | -------------------- | ------------ | ------------------------------------------------------------ |
| 1 | **完善风控模块逻辑** | **完成** | **【核心产出】** 成功实现了“风险用户自动判定”的后端逻辑(如连续登录失败监测),并将异常状态与管理员的封禁功能打通,实现了“系统预警+人工审核”的安全闭环。 |
| 2 | **用户手册编写** | **完成** | 与李果霖协作完成了《用户手册》的编写重点负责了“账号管理”、“个人设置”及“管理员后台”章节的操作指南与FAQ整理为用户提供了清晰的文档支持。 |
| 3 | **后端Bug修复** | **完成** | 针对测试过程中发现的业务逻辑漏洞(特别是风控误判场景)进行了紧急修复,显著提升了系统的稳定性和数据的准确性。 |
| 4 | **配合云端部署** | **完成** | 协助李文韬解决了后端代码在Linux云服务器上的依赖兼容性问题如数据库驱动适配确保了后端服务在云端的顺利启动。 |
| 5 | **周总结与项目复盘** | **完成** | 整理了本周的风控代码和文档产出,撰写了个人周总结,并配合项目经理完成了项目最终交付物的汇总。 |
## 小结
1. **安全机制闭环**本周完成了Beta版本的最后一块拼图——风控模块使系统具备了自动识别和处理异常用户的能力安全性得到了质的提升。
2. **软硬交付同步**:在保障代码质量的同时,高质量完成了《用户手册》的编写,确保交付给用户的不仅是可运行的软件,还有易用的产品体验。
3. **使命必达**作为后端核心开发从环境搭建到Alpha验收再到Beta版的架构升级与最终交付始终保持了高效的输出圆满完成了本学期的开发任务。

@ -1,11 +0,0 @@
# 02-设计文档索引
## 文档列表
| 文档名称 | 版本 | 最后更新 | 负责人 | 状态 |
|---|---|---|---|---|
| [数据库设计文档](./数据库设计文档.docx) | v1.0 | 2025-XX-XX | 待定 | 待完成 |
| [UML设计文档](./UML-活动图-顺序图-类图.pdf) | v1.0 | 2025-XX-XX | 待定 | 待完成 |
**修改历史**
- 2025-XX-XX: 初始化设计文档目录结构

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 65 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

@ -1,12 +0,0 @@
# 03-计划文档索引
## 文档列表
| 文档名称 | 版本 | 最后更新 | 负责人 | 状态 |
|---|---|---|---|---|
| [迭代开发计划第一稿](./迭代开发计划第一稿.docx) | v1.0 | 2025-XX-XX | 待定 | 待完成 |
| [迭代开发计划第二稿](./迭代开发计划第二稿.docx) | v2.0 | 2025-XX-XX | 待定 | 待完成 |
| [迭代开发计划第三稿](./迭代开发计划第三稿.docx) | v3.0 | 2025-XX-XX | 待定 | 待完成 |
**修改历史**
- 2025-XX-XX: 初始化计划文档目录结构

@ -1,10 +0,0 @@
# 04-用户手册索引
## 文档列表
| 文档名称 | 版本 | 最后更新 | 负责人 | 状态 |
|---|---|---|---|---|
| [用户手册](./用户手册.docx) | v1.0 | 2025-XX-XX | 待定 | 待完成 |
**修改历史**
- 2025-XX-XX: 初始化用户手册目录结构

@ -1,10 +0,0 @@
# 05-测试报告索引
## 文档列表
| 文档名称 | 版本 | 最后更新 | 负责人 | 状态 |
|---|---|---|---|---|
| [测试报告](./测试报告.docx) | v1.0 | 2025-XX-XX | 待定 | 待完成 |
**修改历史**
- 2025-XX-XX: 初始化测试报告目录结构

@ -102,6 +102,8 @@ services:
volumes:
- ./src/backend:/app
environment:
# 时区设置
- TZ=Asia/Shanghai
# Fix import errors by adding inner app directory to PYTHONPATH
- PYTHONPATH=/app/app
# --- Pydantic BaseSettings 覆盖配置 (使用双下划线映射嵌套配置) ---

@ -575,6 +575,13 @@ async def test_ai_model_connection(
message="请求频率超限,请稍后再试",
response_time_ms=response_time_ms
)
elif response.status_code == 400:
# 400 错误通常是请求参数问题模型ID无效、密钥格式错误等
result = AIModelTestConnectionResponse(
success=False,
message="连接失败,请检查模型 ID 和 API 密钥是否正确",
response_time_ms=response_time_ms
)
else:
try:
resp_json = response.json()

@ -112,12 +112,14 @@ class PasswordInvalidException(BusinessException):
"""
user_id: int
failed_attempts: int
def __init__(self, user_id: int = 0, failed_attempts: int = 0, custom_message: str = None):
def __init__(self, user_id: int = 0, failed_attempts: int = 0, custom_message: str = None, is_login: bool = True):
if custom_message:
message = custom_message
else:
message = "密码错误"
super().__init__(code=401, message=message)
# 登录场景用401触发前端登出修改密码场景用400仅显示错误
status_code = 401 if is_login else 400
super().__init__(code=status_code, message=message)
self.user_id = user_id
self.failed_attempts = failed_attempts

@ -8,6 +8,7 @@ from pydantic import BaseModel, EmailStr, Field, field_validator, model_validato
from typing import Optional, Literal, List, Any
from datetime import datetime
import re
from email_validator import validate_email, EmailNotValidError
# 基础用户信息
@ -29,10 +30,10 @@ class UserBase(BaseModel):
return v
@validator('email')
def validate_email(cls, v):
def validate_email_format(cls, v):
try:
EmailStr.validate(v)
except Exception:
validate_email(v)
except EmailNotValidError:
raise ValueError('邮箱格式不正确,请输入有效的邮箱地址')
return v
@ -97,8 +98,8 @@ class UserUpdateEmailRequest(BaseModel):
@validator('new_email')
def validate_new_email(cls, v):
try:
EmailStr.validate(v)
except Exception:
validate_email(v)
except EmailNotValidError:
raise ValueError('邮箱格式不正确,请输入有效的邮箱地址')
return v
@ -121,10 +122,10 @@ class UserUpdateEmailConfirm(BaseModel):
return v
@validator('new_email')
def validate_new_email(cls, v):
def validate_new_email_format(cls, v):
try:
EmailStr.validate(v)
except Exception:
validate_email(v)
except EmailNotValidError:
raise ValueError('邮箱格式不正确,请输入有效的邮箱地址')
return v

@ -1,19 +0,0 @@
"""
DDL 生成脚本
用于根据需求与逻辑 Schema 调用远端服务生成 DDL适用于工具链与集成测试
"""
# backend/app/service/ddl_generator.py
import requests
url = "https://schema2ddl.strangeloop.fun/generate/ddl"
data = {
"database_requirment": "A university needs a student course selection management system to maintain and track students' course selection information. Students have\ninformation such as student ID, name, age, the name of the course chosen by the student, etc. Each student can take multiple courses and can drop or\nchange courses within the specified time. Each course has information such as course number, course name, credits, lecturer and class time. The\npopularity of a course depends on the number of students who take the course. The system can predict the popularity of the course and provide support\nfor academic decision-making",
"schema": "(1) Student\n- Attribute: student ID, name, age\n- Primary Key: student ID\n\n(2) Course\n- Attribute: course number, course name, credits, lecturer, class time\n- Primary Key: course number\n\n(3) StudentCourses\n- Attribute: student ID, course number\n- Primary Key: student ID, course number\n- Foreign Key: student ID (reference Student: student ID), course number (reference Course: course number)\n ",
"target_db_type": "mysql",
"model": "gpt4"
}
response = requests.post(url, json=data)
print(response.json())

@ -687,7 +687,11 @@ async def update_password_service(
raise exceptions.UserNotFoundException()
if not verify_password(password_data.old_password, db_user.password_hash):
raise exceptions.PasswordInvalidException(user_id=user_id, custom_message="旧密码不正确")
raise exceptions.PasswordInvalidException(user_id=user_id, custom_message="旧密码不正确", is_login=False)
# 校验新密码不能与旧密码相同
if password_data.old_password == password_data.new_password:
raise exceptions.ValidationException("新密码不能与旧密码相同")
new_hashed_password = get_password_hash(password_data.new_password)

@ -4,7 +4,7 @@
用于调试/验证 chat-to-SQL 流程连接可配置的 AI 端点并返回基础解析结果
"""
# backend/app/service/chat_service_test.py
# backend/app/service/test_chat_service.py
import json
import httpx

@ -239,7 +239,7 @@ const App: React.FC = () => {
const defaultRoute = isAdmin ? ROUTES.ADMIN_USERS : ROUTES.DASHBOARD;
return (
<div className="flex h-screen h-[100dvh] bg-[#f0f2f5] bg-[url('/background.svg')] bg-center bg-no-repeat bg-contain overflow-hidden">
<div className="flex h-screen h-[100dvh] min-w-[800px] min-h-[600px] bg-[#f0f2f5] bg-[url('/background.svg')] bg-center bg-no-repeat bg-contain">
<ToastContainer />
<Sidebar

@ -141,7 +141,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ role, user, selectedProject, a
*/}
<div className={`
fixed inset-y-0 left-0 w-64 bg-white border-r border-gray-200 h-screen h-[100dvh] flex flex-col
transition-[transform,width] duration-300 ease-in-out motion-reduce:transition-none z-50 overflow-x-hidden
transition-[transform,width] duration-300 ease-in-out motion-reduce:transition-none z-50
md:translate-x-0 md:static md:sticky md:top-0 md:h-screen md:h-[100dvh]
${isOpen ? 'translate-x-0' : '-translate-x-full'}
${isCollapsed ? 'md:w-16' : 'md:w-64'}

@ -16,7 +16,7 @@
* @date 2026-01-02
*/
import React, { JSX, ReactNode, useState, useEffect } from 'react';
import React, { JSX, ReactNode, useState, useEffect, useCallback } from 'react';
import { Check, X, CheckCircle, AlertCircle, Info, AlertTriangle, Eye, EyeOff } from 'lucide-react';
// =========================================================
@ -206,37 +206,53 @@ export const Select: React.FC<SelectProps> = ({
const displayText = selectedOption?.label || placeholder;
/**
*
* @description
* getBoundingClientRect()
*
*/
const handleToggle = () => {
if (disabled) return;
if (!isOpen && buttonRef.current) {
/** * Minimal
*
*/
let targetElement: HTMLElement | null = buttonRef.current;
if (variant === 'minimal') {
let parent = buttonRef.current.parentElement;
while (parent && parent !== document.body) {
const style = window.getComputedStyle(parent);
if (style.borderWidth && parseFloat(style.borderWidth) > 0) {
targetElement = parent;
break;
}
parent = parent.parentElement;
const updatePosition = useCallback(() => {
if (!isOpen || !buttonRef.current) return;
let targetElement: HTMLElement | null = buttonRef.current;
// Minimal 变体向上查找边框容器Default 变体直接基于按钮定位
if (variant === 'minimal') {
let parent = buttonRef.current.parentElement;
while (parent && parent !== document.body) {
const style = window.getComputedStyle(parent);
if (style.borderWidth && parseFloat(style.borderWidth) > 0) {
targetElement = parent;
break;
}
parent = parent.parentElement;
}
}
// 物理坐标重算
const rect = targetElement!.getBoundingClientRect();
setMenuPosition({
top: rect.bottom + 4,
left: rect.left,
width: rect.width
});
const rect = targetElement!.getBoundingClientRect();
setMenuPosition({
top: rect.bottom + 4,
left: rect.left,
width: rect.width
});
}, [isOpen, variant]);
/**
*
*/
useEffect(() => {
if (isOpen) {
updatePosition();
window.addEventListener('scroll', updatePosition, true);
window.addEventListener('resize', updatePosition);
}
return () => {
window.removeEventListener('scroll', updatePosition, true);
window.removeEventListener('resize', updatePosition);
};
}, [isOpen, updatePosition]);
/**
*
*/
const handleToggle = () => {
if (disabled) return;
setIsOpen(!isOpen);
};
@ -282,7 +298,7 @@ export const Select: React.FC<SelectProps> = ({
</svg>
</button>
{/* 下拉面板:采用 Fixed 布局及 Z-Index 策略确保不被层级覆盖 */}
{/* 下拉面板:采用 Fixed 布局及动态位置更新策略,确保不被遮挡且紧贴触发元素 */}
{isOpen && (
<div
className="fixed bg-white border border-gray-200 rounded-lg shadow-md overflow-hidden animate-in fade-in zoom-in-95 duration-150"
@ -294,7 +310,7 @@ export const Select: React.FC<SelectProps> = ({
}}
>
{/* 内部滚动区:最大高度限制为 5 个标准列表项的高度 */}
<div className="overflow-y-auto py-1" style={{ maxHeight: 'calc(5 * 44px)' }}>
<div className="overflow-y-scroll py-1" style={{ maxHeight: 'calc(5 * 44px)' }}>
{options.map((option) => (
<div
key={option.value}

@ -70,7 +70,7 @@ body {
padding: 0;
min-height: 100vh;
min-height: 100dvh;
overflow-x: hidden;
/* overflow-x: hidden; */
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@ -81,7 +81,7 @@ body {
min-height: 100dvh;
display: flex;
flex-direction: column;
overflow: hidden;
/* overflow: hidden; */
}
/* ========================================
@ -118,6 +118,7 @@ body {
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
@ -507,6 +508,7 @@ body {
text-overflow: ellipsis;
white-space: nowrap;
}
/* Hide default password reveal button */
input[type='password']::-ms-reveal,
input[type='password']::-ms-clear {
@ -516,4 +518,4 @@ input[type='password']::-ms-clear {
input[type='password']::-webkit-password-reveal-button {
display: none;
-webkit-appearance: none;
}
}

@ -74,6 +74,11 @@ export const AdminAIModels: React.FC = () => {
if (!['http:', 'https:'].includes(parsed.protocol)) {
return 'URL 协议必须是 http 或 https';
}
// 检查URL路径是否以 /v1/chat/completions 或 /chat/completions 结尾
const pathname = parsed.pathname.replace(/\/+$/, ''); // 去掉末尾斜杠
if (!pathname.endsWith('/v1/chat/completions') && !pathname.endsWith('/chat/completions')) {
return 'API 地址需以 /v1/chat/completions 或 /chat/completions 结尾';
}
} catch {
return 'URL 格式不正确,请检查';
}
@ -139,9 +144,16 @@ export const AdminAIModels: React.FC = () => {
return;
}
if (hasNewApiKey && !/^(sk-|ms-|ak-)[A-Za-z0-9\-]{10,}/i.test(formData.api_key.trim())) {
message.error('API 密钥格式不正确,需以 sk-/ms-/ak- 开头');
return;
if (hasNewApiKey) {
const key = formData.api_key.trim();
if (!/^(sk-|ms-|ak-)/i.test(key)) {
message.error('API 密钥格式不正确,需以 sk-/ms-/ak- 开头');
return;
}
if (!/^(sk-|ms-|ak-)[A-Za-z0-9\-]{10,}/i.test(key)) {
message.error('API 密钥长度不足,前缀后至少需要 10 个字符');
return;
}
}
if (!formData.model_id.trim()) {
@ -212,10 +224,14 @@ export const AdminAIModels: React.FC = () => {
// 如果输入了新密钥,校验格式
if (formData.api_key.trim()) {
const key = formData.api_key.trim();
if (!/^(sk-|ms-|ak-)[A-Za-z0-9\-]{10,}/i.test(key)) {
if (!/^(sk-|ms-|ak-)/i.test(key)) {
message.error('API 密钥格式不正确,需以 sk-/ms-/ak- 开头');
return;
}
if (!/^(sk-|ms-|ak-)[A-Za-z0-9\-]{10,}/i.test(key)) {
message.error('API 密钥长度不足,前缀后至少需要 10 个字符');
return;
}
}
if (!testResult || !testResult.success) {

@ -78,7 +78,7 @@ export const AdminStatus: React.FC = () => {
<Card className="bg-gradient-to-br from-purple-50 to-white border-purple-100">
<div className="flex items-center gap-3 mb-2 text-purple-600">
<Users size={20} />
<span className="font-bold"></span>
<span className="font-bold"></span>
</div>
<div className="text-2xl font-bold text-gray-800">{stats?.active_users_today ?? 0}</div>
<p className="text-xs text-purple-400 mt-1">Active Users Today</p>
@ -87,7 +87,7 @@ export const AdminStatus: React.FC = () => {
<Card className="bg-gradient-to-br from-green-50 to-white border-green-100">
<div className="flex items-center gap-3 mb-2 text-green-600">
<Zap size={20} />
<span className="font-bold"></span>
<span className="font-bold"></span>
</div>
<div className="text-2xl font-bold text-gray-800">{stats?.query_count_today ?? 0}</div>
<p className="text-xs text-green-600 mt-1">Queries Processed</p>

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { ProjectDTO, fetchProjects, createProject, updateProject, confirmDeleteProject, deleteProject, getProjectDetail } from '../api/project';
import { ProjectStatusEnum } from '../types';
import { ProjectStatusEnum, BusinessError } from '../types';
import { Button, Modal, Input, message } from '../components/UI';
import { Plus, PlayCircle, Sparkles, AlertTriangle, LayoutDashboard, Loader2 } from 'lucide-react';
import { ProjectWizard } from '../components/ProjectWizard';
@ -90,10 +90,18 @@ export const Dashboard: React.FC<DashboardProps> = ({ onProjectSelect }) => {
message.error('请输入项目名称');
return;
}
if (newProjectName.trim().length > 50) {
message.error('项目名称不能超过50个字符');
return;
}
if (!newProjectDesc.trim()) {
message.error('请输入业务场景描述');
return;
}
if (newProjectDesc.trim().length > 1000) {
message.error('业务场景描述不能超过1000个字符');
return;
}
if (isCreating) return;
setIsCreating(true);
@ -111,7 +119,10 @@ export const Dashboard: React.FC<DashboardProps> = ({ onProjectSelect }) => {
setIsDeploying(false);
setIsCreating(false);
setCurrentProjectId(null);
message.error("创建失败,请检查网络或重试");
// 如果是业务错误(如配额超出),已由全局错误处理器显示,不再重复提示
if (!(e instanceof BusinessError)) {
message.error("创建失败,请检查网络或重试");
}
}
};
@ -299,7 +310,10 @@ export const Dashboard: React.FC<DashboardProps> = ({ onProjectSelect }) => {
</div>
</div>
<div className="space-y-6">
<Input label="项目名称" placeholder="例如:企业级 CRM 客户管理系统" value={newProjectName} onChange={(e) => setNewProjectName(e.target.value)} required />
<div className="flex flex-col gap-2">
<Input label="项目名称" placeholder="例如:企业级 CRM 客户管理系统" value={newProjectName} onChange={(e) => setNewProjectName(e.target.value)} maxLength={50} required />
<span className="text-xs text-gray-400 text-right">{newProjectName.length}/50</span>
</div>
<div className="flex flex-col gap-2">
<label className="text-sm font-medium text-gray-700"><span className="text-red-500 ml-1">*</span></label>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4">
@ -322,7 +336,8 @@ export const Dashboard: React.FC<DashboardProps> = ({ onProjectSelect }) => {
</div>
<div className="flex flex-col gap-2">
<label className="text-sm font-medium text-gray-700"><span className="text-red-500 ml-1">*</span></label>
<textarea className="px-4 py-3 bg-white border border-gray-300 rounded-lg text-sm focus:border-primary focus:ring-2 focus:ring-blue-100 transition-all h-32 resize-none leading-relaxed" placeholder="请详细描述实体及关系..." value={newProjectDesc} onChange={(e) => setNewProjectDesc(e.target.value)}></textarea>
<textarea className="px-4 py-3 bg-white border border-gray-300 rounded-lg text-sm focus:border-primary focus:ring-2 focus:ring-blue-100 transition-all h-32 resize-none leading-relaxed" placeholder="请详细描述实体及关系..." value={newProjectDesc} onChange={(e) => setNewProjectDesc(e.target.value)} maxLength={1000}></textarea>
<span className="text-xs text-gray-400 text-right">{newProjectDesc.length}/1000</span>
</div>
</div>
</div>

@ -397,13 +397,6 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, onUpdateUser }) => {
{userProfile?.created_at ? new Date(userProfile.created_at).toLocaleDateString() : '-'}
</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-500"></span>
{/* 修复:对 userProfile.last_login_at 进行存在性检查 */}
<span className="text-gray-800">
{userProfile?.last_login_at ? new Date(userProfile.last_login_at).toLocaleString() : '从未登录'}
</span>
</div>
</div>
</Card>
</div>
@ -576,7 +569,7 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, onUpdateUser }) => {
<td className="px-4 py-3 text-right">
<Tag color={log.login_status === 'failed' ? 'red' : 'green'}>
{log.login_status === 'success' ? '成功' :
log.login_status === 'forced_logout' ? '登出' :
log.login_status === 'forced_logout' ? '登出' :
log.login_status === 'expired' ? '已过期' : '失败'}
</Tag>
</td>

@ -177,10 +177,10 @@ export const UserProfile: React.FC<UserProfileProps> = ({ user, onBack }) => {
{statusLabel}
</Tag>
</h2>
<div className="text-gray-500 mt-2 flex items-center gap-6 text-sm">
<span className="flex items-center gap-1"><Shield size={14} /> ID: {user.id}</span>
<span className="flex items-center gap-1">📧 {user.email}</span>
<span className="flex items-center gap-1"><Clock size={14} /> : {lastLoginText}</span>
<div className="text-gray-500 mt-2 flex flex-wrap items-center gap-x-6 gap-y-2 text-sm">
<span className="flex items-center gap-1 shrink-0 whitespace-nowrap"><Shield size={14} /> ID: {user.id}</span>
<span className="flex items-center gap-1 shrink-0 whitespace-nowrap">📧 {user.email}</span>
<span className="flex items-center gap-1 shrink-0 whitespace-nowrap"><Clock size={14} /> : {lastLoginText}</span>
</div>
</div>
</div>
@ -228,17 +228,17 @@ export const UserProfile: React.FC<UserProfileProps> = ({ user, onBack }) => {
return (
<div key={log.login_id} className="flex items-start gap-3 text-sm border-b border-gray-50 pb-3 last:border-0 last:pb-0">
<div className={`w-2 h-2 mt-1.5 rounded-full ${isFailed ? 'bg-red-500' : 'bg-green-500'}`}></div>
<div className="flex-1">
<div className="flex justify-between">
<span className="font-medium text-gray-700">{log.ip_address}</span>
<span className="text-gray-400 text-xs">{timeText}</span>
<div className="flex-1 min-w-0">
<div className="flex justify-between items-center gap-2">
<span className="font-medium text-gray-700 truncate">{log.ip_address}</span>
<span className="text-gray-400 text-xs whitespace-nowrap">{timeText}</span>
</div>
<div className="flex items-center gap-2 text-gray-500 text-xs mt-1">
<span className="flex items-center gap-0.5"><MapPin size={10} /> {log.login_status === 'success' ? '成功' :
log.login_status === 'forced_logout' ? '登出' :
<div className="flex items-center gap-2 text-gray-500 text-xs mt-1 w-full overflow-hidden">
<span className="flex items-center gap-0.5 whitespace-nowrap flex-shrink-0"><MapPin size={10} /> {log.login_status === 'success' ? '成功' :
log.login_status === 'forced_logout' ? '登出' :
log.login_status === 'expired' ? '已过期' : '失败'}</span>
<span className="flex items-center gap-0.5 max-w-[220px] truncate" title={log.user_agent || 'Unknown'}>
<Globe size={10} /> {log.user_agent || 'Unknown'}
<span className="flex items-center gap-0.5 flex-1 min-w-0" title={log.user_agent || 'Unknown'}>
<Globe size={10} className="flex-shrink-0" /> <span className="truncate">{log.user_agent || 'Unknown'}</span>
</span>
</div>
</div>

@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from 'react';
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { Project, Message, QueryResult, ChatSession, ChatResponse, AIModelOption } from '../types';
import { Button, message as GlobalMessage, Modal, ConfirmDialog } from '../components/UI';
import { Send, Plus, MessageSquare, Edit2, Trash2, Check, X, ChevronLeft, Loader2, Sparkles, AlertTriangle, Play, Ban, Table as TableIcon, Info, Bot, Database } from 'lucide-react';
@ -62,6 +62,29 @@ const ModelSelector: React.FC<ModelSelectorProps> = ({ value, onChange, options,
const selectorRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
// 动态位置更新
const updatePosition = useCallback(() => {
if (!isOpen || !buttonRef.current) return;
const rect = buttonRef.current.getBoundingClientRect();
setMenuPosition({
bottom: window.innerHeight - rect.top + 4,
left: rect.left
});
}, [isOpen]);
// 监听滚动和调整大小
useEffect(() => {
if (isOpen) {
updatePosition();
window.addEventListener('scroll', updatePosition, true);
window.addEventListener('resize', updatePosition);
}
return () => {
window.removeEventListener('scroll', updatePosition, true);
window.removeEventListener('resize', updatePosition);
};
}, [isOpen, updatePosition]);
// 点击外部关闭下拉菜单
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
@ -73,15 +96,8 @@ const ModelSelector: React.FC<ModelSelectorProps> = ({ value, onChange, options,
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
// 计算下拉菜单位置
// 切换开关
const handleToggle = () => {
if (!isOpen && buttonRef.current) {
const rect = buttonRef.current.getBoundingClientRect();
setMenuPosition({
bottom: window.innerHeight - rect.top + 4,
left: rect.left
});
}
setIsOpen(!isOpen);
};
@ -120,7 +136,7 @@ const ModelSelector: React.FC<ModelSelectorProps> = ({ value, onChange, options,
left: menuPosition.left
}}
>
<div className="overflow-y-auto py-1" style={{ maxHeight: 'calc(5 * 44px)' }}>
<div className="overflow-y-scroll py-1" style={{ maxHeight: 'calc(5 * 44px)' }}>
{options.map((option) => (
<div
key={option.value}

@ -72,7 +72,7 @@ export function calculateGlobalScaleFactor(zoomLevel: number): number {
* 2
* power < 1 (0.7) 70% 30%
*/
const power = 0.7;
const power = 0.7;
const rawFactor = Math.pow(100 / zoomLevel, power);
/**
@ -112,8 +112,8 @@ function calculateGlobalZoomLevel(): GlobalZoomLevelInfo {
* A>= 2.5K DPR 2
*/
if (screenWidth >= 2560 || screenHeight >= 1440) {
baseDPR = 2;
}
baseDPR = 2;
}
/**
* B1080P 1
*/

@ -1,199 +0,0 @@
# 开发部署指南
## 目录
- [环境配置差异](#环境配置差异)
- [数据库连接配置](#数据库连接配置)
- [如何查看 PostgreSQL 数据](#如何查看-postgresql-数据)
---
## 环境配置差异
### 本地开发 vs Docker 部署
| 项目 | 本地开发 | Docker 部署 |
|------|---------|-------------|
| **运行方式** | 直接运行 Python 代码 | 容器内运行 |
| **配置来源** | `config.yaml` | 环境变量覆盖 `config.yaml` |
| **网络模式** | 宿主机网络 | Docker 内部网络 (`app-network`) |
### 配置加载优先级
```
环境变量 > config.yaml 默认值
```
代码中的 `_override_with_env()` 函数会检查环境变量并覆盖 YAML 配置:
- `POSTGRESQL__HOST` → 覆盖 `config.yaml` 中的 `postgresql.host`
- `POSTGRESQL__PORT` → 覆盖 `config.yaml` 中的 `postgresql.port`
---
## 数据库连接配置
### 1. 元数据库 (meta_postgres)
存储系统业务数据(用户、项目、数据库实例等)
| 环境 | Host | Port | 数据库 | 用户 |
|------|------|------|--------|------|
| 本地开发 | `localhost` | `5432` | `auto_db_deployment` | `admin` |
| Docker 内部 | `postgres-meta` | `5432` | `auto_db_deployment` | `admin` |
### 2. 用户 PostgreSQL (postgres-user)
存储用户创建的数据库
| 环境 | Host | Port | 用户 |
|------|------|------|------|
| 本地开发 | `127.0.0.1` | `2345` | `postgres` |
| Docker 内部 | `postgres-user` | `5432` | `postgres` |
### 3. 用户 MySQL (mysql-user)
| 环境 | Host | Port | 用户 |
|------|------|------|------|
| 本地开发 | `localhost` | `3306` | `root` |
| Docker 内部 | `mysql-user` | `3306` | `root` |
### 配置文件对照
**config.yaml** (本地开发使用)
```yaml
postgresql:
host: 127.0.0.1
port: 2345 # 映射到容器内部的 5432
username: postgres
password: root_secure_2025
```
**docker-compose.yml** (Docker 部署覆盖)
```yaml
environment:
- POSTGRESQL__HOST=postgres-user # Docker 内部服务名
- POSTGRESQL__PORT=5432 # 容器内部端口
```
---
## 如何查看 PostgreSQL 数据
### 方法一:使用 docker exec 进入容器
#### 进入 meta_postgres元数据库
```bash
# 进入 psql 交互界面
docker exec -it meta_postgres psql -U admin -d auto_db_deployment
# 或直接执行 SQL 查询
docker exec -it meta_postgres psql -U admin -d auto_db_deployment -c "SELECT * FROM user_account;"
```
#### 进入 user_postgres用户数据库
```bash
# 进入 psql 交互界面
docker exec -it user_postgres psql -U postgres
# 列出所有数据库
docker exec -it user_postgres psql -U postgres -c "\l"
# 进入特定数据库
docker exec -it user_postgres psql -U postgres -d <数据库名>
```
### 方法二:从宿主机直接连接
#### 连接 meta_postgres
```bash
psql -h localhost -p 5432 -U admin -d auto_db_deployment
# 密码: secure_2025
```
#### 连接 user_postgres
```bash
psql -h localhost -p 2345 -U postgres
# 密码: root_secure_2025
```
### 常用 psql 命令
| 命令 | 说明 |
|------|------|
| `\l` | 列出所有数据库 |
| `\c <数据库名>` | 切换数据库 |
| `\dt` | 列出当前数据库的所有表 |
| `\d <表名>` | 查看表结构 |
| `\du` | 列出所有用户/角色 |
| `\q` | 退出 psql |
### 常用查询示例
```sql
-- 查看所有数据库实例
SELECT instance_id, db_type, db_host, db_port, db_name, status
FROM database_instance;
-- 查看 PostgreSQL 类型的实例
SELECT instance_id, db_type, db_host, db_port
FROM database_instance
WHERE db_type = 'postgresql';
-- 查看所有项目
SELECT project_id, project_name, project_status, creation_stage
FROM project;
-- 查看用户信息
SELECT user_id, username, email, status
FROM user_account;
```
---
## 网络架构图
```
┌─────────────────────────────────────────────────────────────────┐
│ Docker Network (app-network) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ meta_postgres│ │ user_postgres│ │ user_mysql │ │
│ │ :5432 │ │ :5432 │ │ :3306 │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
│ │ │ │ │
│ │ ┌───────────┴──────────────────────┘ │
│ │ │ │
│ ┌──────┴─────┴─────┐ ┌─────────────┐ │
│ │ backend │────▶│ redis │ │
│ │ :8000 │ │ :6379 │ │
│ └──────────────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
宿主机:5432 宿主机:2345 宿主机:3306
(meta_postgres) (user_postgres) (user_mysql)
```
---
## 常见问题
### Q: 为什么本地连接 user_postgres 用端口 2345
因为 `docker-compose.yml` 中配置了端口映射 `2345:5432`,宿主机的 2345 端口映射到容器内的 5432。
### Q: Docker 内部为什么用服务名而不是 localhost
Docker 容器有独立的网络命名空间,`localhost` 指向容器自己。要访问其他容器,需要使用 Docker 网络中的服务名(如 `postgres-user`)。
### Q: 如何确认配置是否被环境变量正确覆盖?
查看 backend 启动日志,会显示类似:
```
Override config postgresql.host with env POSTGRESQL__HOST
Override config postgresql.port with env POSTGRESQL__PORT
```

@ -0,0 +1,197 @@
# 开发注意事项
## 目录
- [Linux 环境配置](#linux-环境配置)
- [配置原理说明](#配置原理说明)
- [Docker 内外连接差异](#docker-内外连接差异)
- [常见问题排查](#常见问题排查)
- [模型配置提醒](#模型配置提醒)
---
## Linux 环境配置
在 Linux 环境下开发时,需要修改前端代理配置。
**文件位置:** `src/frontend/vite.config.ts`
将第 14 行的:
```typescript
target: 'http://host.docker.internal:8000',
```
改为:
```typescript
target: 'http://backend:8000',
```
**原因:** `host.docker.internal` 是 Docker Desktop (Windows/Mac) 特有的 DNS 解析Linux 下需要使用容器服务名 `backend`
---
## 配置原理说明
### 配置加载优先级
```
环境变量 > config.yaml 默认值
```
代码中的 `_override_with_env()` 函数会检查环境变量并覆盖 YAML 配置:
- `POSTGRESQL__HOST` → 覆盖 `config.yaml` 中的 `postgresql.host`
- `POSTGRESQL__PORT` → 覆盖 `config.yaml` 中的 `postgresql.port`
### 环境变量命名规则
使用双下划线 `__` 表示嵌套层级:
```yaml
# config.yaml
postgresql:
host: 127.0.0.1
port: 2345
```
对应环境变量:
```bash
POSTGRESQL__HOST=postgres-user
POSTGRESQL__PORT=5432
```
---
## Docker 内外连接差异
### 为什么本地连接 user_postgres 用端口 2345
`docker-compose.yml` 中配置了端口映射 `2345:5432`,宿主机的 2345 端口映射到容器内的 5432。
### 为什么 Docker 内部用服务名而不是 localhost
Docker 容器有独立的网络命名空间,`localhost` 指向容器自己。要访问其他容器,需要使用 Docker 网络中的服务名(如 `postgres-user`)。
### 连接地址对照表
| 数据库 | Docker 内部地址 | 宿主机地址 |
|--------|-----------------|------------|
| meta_postgres | postgres-meta:5432 | localhost:5432 |
| user_postgres | postgres-user:5432 | localhost:2345 |
| user_mysql | mysql-user:3306 | localhost:3306 |
| redis | redis:6379 | localhost:6379 |
| chromadb | chromadb:8000 | localhost:8100 |
### 配置文件对照
**config.yaml** (本地开发使用)
```yaml
postgresql:
host: 127.0.0.1
port: 2345 # 映射到容器内部的 5432
username: postgres
password: root_secure_2025
```
**docker-compose.yml** (Docker 部署覆盖)
```yaml
environment:
- POSTGRESQL__HOST=postgres-user # Docker 内部服务名
- POSTGRESQL__PORT=5432 # 容器内部端口
```
### 如何确认配置是否被环境变量正确覆盖?
查看 backend 启动日志,会显示类似:
```
Override config postgresql.host with env POSTGRESQL__HOST
Override config postgresql.port with env POSTGRESQL__PORT
```
---
## 常见问题排查
### 1. Docker 构建慢
配置 Docker 镜像加速器Docker Desktop → Settings → Docker Engine
```json
{
"registry-mirrors": [
"https://791bc246c9c148828358b6b170350f22.mirror.swr.myhuaweicloud.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
```
### 2. 本地无法查看api文档
```bash
需要打开http://127.0.0.1:8000/docs
不能打开http://localhost:8000/docs
```
### 3. 端口被占用
```bash
# Windows - 查找占用端口的进程
netstat -ano | findstr :8000
taskkill /PID <PID> /F
# Linux/macOS
lsof -i :8000
kill -9 <PID>
```
### 4. 数据库连接失败
- 确认服务已启动:`docker-compose ps`
- 检查容器日志:`docker-compose logs postgres-meta`
- 确认端口映射正确
- 检查防火墙设置
### 5. Celery Worker 连接 Redis 失败
```bash
# 测试 Redis 连接
docker exec -it redis redis-cli ping
# 应返回: PONG
```
### 6. 前端无法连接后端
检查 `src/frontend/vite.config.ts` 中的代理配置:
- Windows/Mac Docker Desktop使用 `http://host.docker.internal:8000`
- Linux使用 `http://backend:8000`
---
## 模型配置提醒
**ER图和Embedding模型的API目前都是裸露状态3月份前可放心使用开源时需要将对应api更换并设置环境变量**
### ER 图生成 API 限制
ER 图生成功能依赖外部 API请注意以下限制
ER图生成使用了第三方API可以自行更换使用的大模型与生成schema的默认一致可以自行更换API
### Embedding 模型配置
系统使用 Embedding 模型进行向量化检索RAG需要注意
- **模型配置**:确保在 `ai_model_config` 表中正确配置 Embedding 模型的 API 地址和密钥
- **ChromaDB 依赖**Embedding 功能依赖 ChromaDB 服务,确保 `chromadb` 容器正常运行
- **向量维度一致性**:更换 Embedding 模型时,需要清空并重建向量索引,否则会出现维度不匹配错误
- **API 配额**注意embedding模型采用阿里的限时免费模型以及api在2026年3月份过期请及时更换
```bash
# 检查 ChromaDB 服务状态
docker-compose ps chromadb
# 查看 ChromaDB 日志
docker-compose logs -f chromadb
```

@ -1,40 +1,29 @@
# 部署启动文档
AI 数据库自动部署系统 - 部署与启动指南
# AI 数据库自动部署系统 - Docker 部署完整指南
## 目录
- [环境要求](#环境要求)
- [方式一Docker Compose 一键部署(推荐)](#方式一docker-compose-一键部署推荐)
- [方式二:本地开发环境部署](#方式二本地开发环境部署)
- [快速启动](#快速启动)
- [服务架构](#服务架构)
- [数据库初始化](#数据库初始化)
- [服务访问](#服务访问)
- [配置说明](#配置说明)
- [数据管理](#数据管理)
- [常用运维命令](#常用运维命令)
- [常见问题](#常见问题)
---
## 环境要求
### Docker 部署环境
| 软件 | 最低版本 | 推荐版本 |
|------|----------|----------|
| Docker | 20.10+ | 24.x |
| Docker Compose | 2.0+ | 2.20+ |
### 本地开发环境
| 软件 | 最低版本 | 推荐版本 |
|------|----------|----------|
| Miniconda/Anaconda | - | 最新版 |
| Python | 3.10+ | 3.10.x |
| Node.js | 20.x | 20.x LTS |
| PostgreSQL | 15+ | 15.x |
| Redis | 7+ | 7.x |
| MySQL | 8.0+ | 8.0.x |
---
## 方式一Docker Compose 一键部署(推荐)
## 快速启动
### 1. 克隆项目
@ -46,257 +35,277 @@ cd <项目目录>
### 2. 启动所有服务
```bash
# 构建并启动所有服务
# 构建并启动(首次需要 --build
docker-compose up -d --build
# 查看服务状态
docker-compose ps
# 查看日志
# 查看实时日志
docker-compose logs -f
```
### 3. 服务组件说明
### 3. 访问应用
- 前端应用http://localhost:3000
- 后端 APIhttp://127.0.0.1:8000
- API 文档http://127.0.0.1:8000/docs
---
## 服务架构
### 服务组件一览
| 服务名 | 容器名 | 端口映射 | 说明 |
|--------|--------|----------|------|
| postgres-meta | meta_postgres | 5432:5432 | 业务数据库 (PostgreSQL) |
| postgres-meta | meta_postgres | 5432:5432 | 业务数据库 (PostgreSQL) |
| mysql-user | user_mysql | 3306:3306 | 用户数据库资源池 (MySQL) |
| postgres-user | user_postgres | 2345:5432 | 用户数据库资源池 (PostgreSQL) |
| redis | redis | 6379:6379 | 缓存 & 消息队列 |
| chromadb | chromadb | 8100:8000 | 向量数据库 |
| backend | backend | 8000:8000 | 后端 API 服务 |
| celery_worker | celery | - | Celery 异步任务 |
| frontend | frontend | 3000:3000 | 前端服务 |
### 4. 初始化数据库
首次启动后,需要初始化数据库表结构:
```bash
# 进入后端容器
docker exec -it backend bash
# 执行数据库初始化(如有迁移脚本)
# python -m alembic upgrade head
```
| chromadb | chromadb | 8100:8000 | 向量数据库 (RAG 检索) |
| backend | backend | 8000:8000 | 后端 API 服务 (FastAPI) |
| celery_worker | celery | - | Celery 异步任务处理 |
| frontend | frontend | 3000:3000 | 前端服务 (React + Vite) |
或使用项目根目录的 SQL 文件:
### 网络架构
```bash
# 复制 SQL 到 PostgreSQL 容器并执行
docker cp postgresql.sql meta_postgres:/tmp/
docker exec -it meta_postgres psql -U admin -d auto_db_deployment -f /tmp/postgresql.sql
```
### 5. 停止服务
```bash
# 停止所有服务
docker-compose down
# 停止并删除数据卷(清除所有数据)
docker-compose down -v
┌─────────────────────────────────────────────────────────────────────┐
│ Docker Network (app-network) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ meta_postgres│ │ user_postgres│ │ user_mysql │ │
│ │ :5432 │ │ :5432 │ │ :3306 │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └────────────┬────┴──────────────────┘ │
│ │ │
│ ┌───────────────────┴───────────────────┐ ┌─────────────┐ │
│ │ backend:8000 │───▶│ redis:6379 │ │
│ └───────────────────┬───────────────────┘ └─────────────┘ │
│ │ │
│ ┌───────────────────┴───────────────────┐ ┌─────────────┐ │
│ │ celery_worker │───▶│chromadb:8000│ │
│ └───────────────────────────────────────┘ └─────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ frontend:3000 │ │
│ └───────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
宿主机:5432 宿主机:2345 宿主机:3306
```
---
## 方式二:本地开发环境部署
### 1. 安装 Miniconda
## 服务访问
#### Windows
### 应用入口
1. 下载 [Miniconda Windows 安装包](https://docs.conda.io/en/latest/miniconda.html)
2. 运行安装程序,按提示完成安装
3. 打开 Anaconda Prompt 或 PowerShell
| 服务 | 地址 | 说明 |
|------|------|------|
| 前端应用 | http://localhost:3000 | 主应用入口 |
| 后端 API | http://127.0.0.1:8000 | API 服务 |
| Swagger UI | http://127.0.0.1:8000/docs | API 交互文档 |
| ReDoc | http://127.0.0.1:8000/redoc | API 参考文档 |
#### Linux / macOS
### 数据库连接信息
```bash
# 下载安装脚本
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
#### 元数据库 (meta_postgres)
# 安装
bash Miniconda3-latest-Linux-x86_64.sh
| 项目 | 值 |
|------|-----|
| Host | localhost |
| Port | 5432 |
| Database | auto_db_deployment |
| Username | admin |
| Password | secure_2025 |
# 初始化 (重新打开终端或执行)
source ~/.bashrc
```bash
# 命令行连接
psql -h localhost -p 5432 -U admin -d auto_db_deployment
```
### 2. 创建 Python 环境
```bash
# 创建名为 backend 的 conda 环境
conda create -n backend python=3.10 -y
#### 用户 PostgreSQL (user_postgres)
# 激活环境
conda activate backend
| 项目 | 值 |
|------|-----|
| Host | localhost |
| Port | 2345 |
| Username | postgres |
| Password | root_secure_2025 |
# 验证 Python 版本
python --version
# 应输出: Python 3.10.x
```bash
# 命令行连接
psql -h localhost -p 2345 -U postgres
```
### 3. 安装后端依赖
#### 用户 MySQL (user_mysql)
| 项目 | 值 |
|------|-----|
| Host | localhost |
| Port | 3306 |
| Username | root |
| Password | root_secure_2025 |
```bash
# 进入后端目录
cd src/backend
# 命令行连接
mysql -h localhost -P 3306 -u root -p
```
# 配置国内 pip 镜像源
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
pip config set global.trusted-host mirrors.aliyun.com
---
# 安装依赖
pip install -r requirements.txt
```
## 配置说明
### 4. 启动基础设施服务
### Docker 内部 vs 宿主机连接
可以只用 Docker 启动数据库等基础服务
Docker 容器内部使用服务名通信,宿主机使用映射端口
```bash
# 仅启动数据库和缓存服务
docker-compose up -d postgres-meta mysql-user postgres-user redis chromadb
```
| 数据库 | Docker 内部地址 | 宿主机地址 |
|--------|-----------------|------------|
| meta_postgres | postgres-meta:5432 | localhost:5432 |
| user_postgres | postgres-user:5432 | localhost:2345 |
| user_mysql | mysql-user:3306 | localhost:3306 |
| redis | redis:6379 | localhost:6379 |
| chromadb | chromadb:8000 | localhost:8100 |
### 5. 配置后端
### 环境变量配置
编辑 `src/backend/config.yaml`,确保数据库连接配置正确
`docker-compose.yml` 中已配置所有必要环境变量,关键配置
```yaml
env: dev
dev:
db:
host: localhost # 本地开发使用 localhost
port: 5432
database: auto_db_deployment
username: admin
password: secure_2025
redis:
host: localhost
port: 6379
chroma:
host: localhost
port: 8100
# 后端数据库连接
- DB__HOST=postgres-meta
- DB__PORT=5432
- DB__USERNAME=admin
- DB__PASSWORD=secure_2025
- DB__DATABASE=auto_db_deployment
# Redis
- REDIS__HOST=redis
- REDIS__PORT=6379
# ChromaDB
- CHROMA__HOST=chromadb
- CHROMA__PORT=8000
# 用户数据库资源池
- MYSQL__HOST=mysql-user
- MYSQL__PORT=3306
- POSTGRESQL__HOST=postgres-user
- POSTGRESQL__PORT=5432
```
### 6. 启动后端服务
---
```bash
# 确保在 backend conda 环境中
conda activate backend
## 数据管理
# 进入后端 app 目录
cd src/backend/app
### 数据卷
# 启动 FastAPI 服务
uvicorn server:my_app --host 0.0.0.0 --port 8000 --reload
```
| 数据卷名 | 说明 |
|----------|------|
| postgres_data | 元数据库数据 |
| postgres_user_data | 用户 PostgreSQL 数据 |
| mysql_data | 用户 MySQL 数据 |
| redis_data | Redis 持久化数据 |
| chroma_data | ChromaDB 向量数据 |
### 7. 启动 Celery Worker新终端
### 备份与恢复
```bash
# 激活环境
conda activate backend
# 备份元数据库
docker exec meta_postgres pg_dump -U admin auto_db_deployment > backup_meta.sql
# 进入 app 目录
cd src/backend/app
# 恢复元数据库
docker exec -i meta_postgres psql -U admin auto_db_deployment < backup_meta.sql
# 启动 Celery Worker
celery -A celery_app worker --loglevel=info -Q celery,default,ai_tasks
# 备份用户 PostgreSQL
docker exec user_postgres pg_dump -U postgres <数据库名> > backup_user.sql
```
### 8. 安装前端依赖
```bash
# 新开终端,进入前端目录
cd src/frontend
---
# 配置 npm 镜像源
npm config set registry https://registry.npmmirror.com/
## 常用运维命令
# 安装依赖
npm install
```
### 9. 启动前端服务
### 服务管理
```bash
# 开发模式启动
npm run dev
```
# 启动所有服务
docker-compose up -d
---
# 重新构建并启动
docker-compose up -d --build
## 服务访问
# 停止所有服务
docker-compose down
部署完成后,可通过以下地址访问各服务:
# 停止并删除数据卷(清除所有数据)
docker-compose down -v
| 服务 | 地址 | 说明 |
|------|------|------|
| 前端应用 | http://localhost:3000 | 主应用入口 |
| 后端 API | http://localhost:8000 | API 服务 |
| API 文档 | http://localhost:8000/docs | Swagger UI |
| ReDoc | http://localhost:8000/redoc | ReDoc 文档 |
# 重启单个服务
docker-compose restart backend
### 默认账户
# 查看服务状态
docker-compose ps
```
首次使用请参考项目初始化 SQL 或联系管理员获取默认账户信息。
### 日志查看
---
```bash
# 查看所有日志
docker-compose logs -f
## 环境变量配置
# 查看特定服务日志
docker-compose logs -f backend
docker-compose logs -f celery_worker
docker-compose logs -f frontend
```
### Docker 环境变量
### 进入容器调试
`docker-compose.yml` 中已配置好所有环境变量,无需额外设置。
```bash
# 进入后端容器
docker exec -it backend bash
### 本地开发环境变量
# 进入元数据库
docker exec -it meta_postgres psql -U admin -d auto_db_deployment
可创建 `.env` 文件或直接设置系统环境变量:
# 进入用户 PostgreSQL
docker exec -it user_postgres psql -U postgres
```bash
# 后端环境变量示例
export DB__HOST=localhost
export DB__PORT=5432
export DB__USERNAME=admin
export DB__PASSWORD=secure_2025
export DB__DATABASE=auto_db_deployment
export REDIS__HOST=localhost
export REDIS__PORT=6379
export CHROMA__HOST=localhost
export CHROMA__PORT=8100
# 进入用户 MySQL
docker exec -it user_mysql mysql -u root -p
```
---
### 常用 psql 命令
## 数据持久化
| 命令 | 说明 |
|------|------|
| `\l` | 列出所有数据库 |
| `\c <数据库名>` | 切换数据库 |
| `\dt` | 列出当前数据库的所有表 |
| `\d <表名>` | 查看表结构 |
| `\du` | 列出所有用户/角色 |
| `\q` | 退出 psql |
### Docker 数据卷
### 常用查询示例
| 数据卷名 | 说明 |
|----------|------|
| postgres_data | PostgreSQL 业务数据库数据 |
| postgres_user_data | PostgreSQL 用户数据库数据 |
| mysql_data | MySQL 用户数据库数据 |
| redis_data | Redis 持久化数据 |
| chroma_data | ChromaDB 向量数据 |
```sql
-- 查看所有数据库实例
SELECT instance_id, db_type, db_host, db_port, db_name, status
FROM database_instance;
### 备份数据
-- 查看所有项目
SELECT project_id, project_name, project_status, creation_stage
FROM project;
```bash
# 备份 PostgreSQL 数据
docker exec meta_postgres pg_dump -U admin auto_db_deployment > backup.sql
# 恢复数据
docker exec -i meta_postgres psql -U admin auto_db_deployment < backup.sql
-- 查看用户信息
SELECT user_id, username, email, status
FROM user_account;
```
---
@ -305,40 +314,22 @@ docker exec -i meta_postgres psql -U admin auto_db_deployment < backup.sql
### 1. Docker 构建慢
配置 Docker 镜像加速器:
配置 Docker 镜像加速器Docker Desktop → Settings → Docker Engine
```json
// Docker Desktop -> Settings -> Docker Engine
{
"registry-mirrors": [
"https://791bc246c9c148828358b6b170350f22.mirror.swr.myhuaweicloud.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
```
### 2. pip 安装依赖超时
确保已配置国内镜像源:
```bash
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
```
### 3. npm install 失败
确保已配置国内镜像源:
### 2. 端口被占用
```bash
npm config set registry https://registry.npmmirror.com/
```
### 4. 端口被占用
检查并释放占用的端口:
```bash
# Windows
# Windows - 查找占用端口的进程
netstat -ano | findstr :8000
taskkill /PID <PID> /F
@ -347,44 +338,40 @@ lsof -i :8000
kill -9 <PID>
```
### 5. 数据库连接失败
- 检查数据库服务是否启动
- 检查防火墙设置
- 确认连接配置host/port/username/password正确
### 3. 数据库连接失败
### 6. Celery Worker 连接 Redis 失败
- 确认服务已启动:`docker-compose ps`
- 检查容器日志:`docker-compose logs postgres-meta`
- 确认端口映射正确
确保 Redis 服务已启动,且连接配置正确:
### 4. Celery Worker 连接 Redis 失败
```bash
# 测试 Redis 连接
redis-cli -h localhost -p 6379 ping
docker exec -it redis redis-cli ping
# 应返回: PONG
```
---
### 5. 前端无法连接后端
## 开发调试
检查 `src/frontend/vite.config.ts` 中的代理配置:
### 查看日志
- Windows/Mac Docker Desktop使用 `http://host.docker.internal:8000`
- Linux使用 `http://backend:8000`
```bash
# Docker 环境
docker-compose logs -f backend
docker-compose logs -f celery_worker
docker-compose logs -f frontend
# 本地环境
# 后端日志在 src/backend/logs/ 目录下
```
### 进入容器调试
---
## 停止与清理
```bash
# 进入后端容器
docker exec -it backend bash
# 停止服务(保留数据)
docker-compose down
# 进入数据库容器
docker exec -it meta_postgres psql -U admin -d auto_db_deployment
# 停止服务并删除所有数据
docker-compose down -v
# 清理未使用的镜像和容器
docker system prune -a
```

Loading…
Cancel
Save