# huayuLearning **Repository Path**: xiaojy92/huayu-learning ## Basic Information - **Project Name**: huayuLearning - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-25 - **Last Updated**: 2026-10-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 深学智库 · 学习平台 > 春风化雨,润物无声 —— 面向考研 / CPA / 法考等人群的学习平台 > > 以 **文字知识库 + 题库 + 考试计划** 为核心,视频作为可选附件。 --- ## 一、项目结构 ```text LearningWithAI/ ├─ CLAUDE.md # 给 AI 助手的仓库约定(红线、已踩过的坑) ├─ README.md # 本文件:运维 / 上手手册 │ ├─ huayuLearning-frontend/ # ① 前端(React 18 + TypeScript + Vite + AntD 5) ├─ huayuLearning-gateway/ # ② 网关服务(Spring Cloud Gateway + Nacos) ├─ huayuLearning-java-backend/ # ③ Java 业务后端(模块化单体) ├─ huayuLearning-python-backend/ # ④ Python AI 服务(FastAPI + LangChain + LangGraph) │ ├─ sql/ # 数据库脚本 │ ├─ 01_schema.sql # 建表(43 张表 / 88 个索引) │ └─ 02_init_data.sql # 初始化数据(幂等,可重复执行) │ ├─ docker/ # 容器编排 │ ├─ docker-compose.yml # 一键启动全部依赖与应用 │ └─ .env.example # 环境变量模板 │ ├─ scripts/ # 开发脚本 │ ├─ build-java.sh # Java 构建(自动切换 JDK 17) │ ├─ start-python.sh # Python 启动(强制校验 conda 环境) │ ├─ start-all.sh # ★ 一键启动全部服务(推荐) │ └─ stop-all.sh # 停止全部服务 │ └─ docs/ # 各子模块开发文档(实现说明与规范正文,共 16 篇) ``` ### 三个后端的工程结构 ```text huayuLearning-java-backend/ # 模块化单体,最终打包为一个 Spring Boot 应用 ├─ core/ # 公共核心:响应 / 异常 / 配置 / 中间件 / 工具 ├─ module-auth/ # 账号权限 ├─ module-exam/ # 考试 · 科目 · 章节 · 知识点 ├─ module-content/ # 笔记 · 视频 ├─ module-question/ # 题库 · 题集 · 组卷 · 6 题型判分 ├─ module-study/ # 答题记录 · 错题本 · 复习 · 计划 · 统计 ├─ module-order/ # 商品 · 订单 · 支付 · 权益 ├─ module-sys/ # 系统管理(用户/角色/权限点/字典/参数/公告/日志/LLM 配置) ├─ module-admin/ # 后台管理聚合接口 ├─ module-ai/ # Feign 调用 Python AI 服务 └─ bootstrap/ # 启动聚合模块(唯一可执行入口) # 注:目录名不含项目前缀,Maven artifactId # 仍为 huayu-learning-*(仓库坐标需全局唯一) huayuLearning-python-backend/ ├─ core/ # 公共核心:配置 / 数据库 / 异常 / 中间件 / 响应 ├─ module_AIagents/ # AI 统一模块(LangChain + LangGraph) │ ├─ agents/ # 5 个子 Agent │ └─ graph/ # LangGraph 工作流编排 ├─ module_question_import/ # 题库导入(题目文本解析 / 导入批次登记) ├─ module_text_analysis/ # 文本分析(Markdown 目录 / 字数统计) └─ main.py # FastAPI 入口 ``` --- ## 二、技术栈 | 层 | 选型 | |---|---| | 前端 | React 18 · TypeScript 5.9 · Vite 5 · Ant Design 5 · Tailwind 3 | | 前端状态 | Zustand(客户端)+ TanStack Query(服务端) | | 网关 | Spring Cloud Gateway 4 + Nacos 2.3 + Resilience4j | | 业务后端 | Java 17 · Spring Boot 3.2.5 · Spring Cloud 2023.0.1 · MyBatis-Plus 3.5.5 | | AI 服务 | Python 3.12.9 · FastAPI · LangChain 1.2 · LangGraph 1.1 · DeepAgents | | 数据库 | PostgreSQL 16(43 张表) | | 缓存 | Redis 7 | | 对象存储 | MinIO | | 鉴权 | JWT(HS256)+ RBAC,网关统一验签 | | 接口文档 | Knife4j(Java)· OpenAPI 3(Python) | --- ## 三、快速开始 ### 3.1 前置要求 | 依赖 | 版本 | 说明 | |---|---|---| | JDK | **17+** | ⚠️ 见下方常见问题第 1 条 | | Maven | 3.8+ | | | Miniconda | 任意 | Python 环境由 conda 统一管理 | | Docker | 20+ | 运行 PostgreSQL / Redis / Nacos | | Node.js | 18+ | 仅在开发前端时需要 | ### 3.2 方式一:Docker 一键启动(推荐) ```bash cd docker cp .env.example .env # 生成 JWT 密钥并写入 .env(三方服务必须共用同一密钥) sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -base64 48)|" .env docker compose up -d docker compose ps # 等待各服务变为 healthy ``` 启动后: | 服务 | 地址 | 凭据 | |---|---|---| | **网关**(统一入口) | http://localhost:8080 | — | | Java 接口文档 | http://localhost:8080/api/doc.html | — | | Python 接口文档 | http://localhost:8080/py/docs | — | | Nacos 控制台 | http://localhost:8848/nacos | nacos / nacos | | MinIO 控制台 | http://localhost:9001 | minioadmin / minioadmin | ### 3.3 方式二:本地开发启动 ```bash ./scripts/start-all.sh # 一键启动:中间件 → Python → Java → 网关 → 前端 ./scripts/start-all.sh --follow # 启动并跟随日志 ./scripts/stop-all.sh # 停止(中间件容器保留) ``` 脚本按**刚性顺序**启动并逐项等待就绪,最后用**经网关的 `/py/health`** 做端到端探针 (一次验证「网关在跑 + Nacos 解析到实例 + Python 存活 + 白名单放行」)。 `Ctrl-C` 会连带杀掉 `spring-boot:run` fork 出的子 JVM,不留孤儿进程。 它还会统一导出 `JWT_SECRET`(打印 md5 指纹)——**手工分端启动最容易踩的坑就是 只重启一端、忘了带密钥**,症状是「`:8081` 直连正常而 `:8080` 走网关 401」。
需要单独起某个服务时(调试用) #### 第 1 步:启动依赖中间件 ```bash cd docker docker compose up -d postgres redis nacos minio ``` 数据库首次启动会自动执行 `sql/` 下的建表与初始化脚本。 #### 第 2 步:创建 Python conda 环境 ```bash conda create -n huayuLearning_env python=3.12.9 -y conda activate huayuLearning_env pip install -r huayuLearning-python-backend/requirements.txt \ -i https://pypi.tuna.tsinghua.edu.cn/simple ``` #### 第 3 步:启动三个后端服务 ```bash # 终端 1 —— 网关(:8080) cd huayuLearning-gateway && ../scripts/build-java.sh gateway spring-boot:run # 终端 2 —— Java 业务后端(:8081) cd huayuLearning-java-backend && ../scripts/build-java.sh spring-boot:run -pl bootstrap # 终端 3 —— Python AI 服务(:8082) ./scripts/start-python.sh ``` > `scripts/start-python.sh` 会**强制校验 conda 环境**:环境名不对、 > 解释器路径不对、Python 版本不是 3.12.9、依赖缺失,都会直接拒绝启动并给出修复指引。 #### 第 4 步:启动前端 ```bash cd huayuLearning-frontend npm install npm run dev # http://localhost:5173 ``` 前端开发服务器会把 `/api` 与 `/py` 代理到网关,因此**只需保证网关在 8080 运行**。 网关地址可在 `.env.development` 的 `VITE_GATEWAY_TARGET` 中修改。
### 3.4 内置账号 | 账号 | 密码 | 角色 | |---|---|---| | `admin` | `Admin@123456` | 管理员 | | `demo` | `Demo@123456` | 普通用户 + 内容编辑 | > ⚠️ **仅限本地开发**。生产环境部署后必须立即修改密码并删除演示账号。 ### 3.5 验证部署 ```bash # 健康检查 curl http://localhost:8080/actuator/health curl http://localhost:8080/py/health # 登录获取令牌 TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login \ -H 'Content-Type: application/json' \ -d '{"account":"admin","password":"Admin@123456"}' \ | python3 -c 'import sys,json; print(json.load(sys.stdin)["data"]["accessToken"])') # 带令牌访问业务接口 curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/auth/me # 查询考试列表(匿名可访问) curl http://localhost:8080/api/exam/list ``` --- ## 四、架构要点 ### 4.1 请求链路 ```text 前端 │ ▼ 网关 :8080 ──── JWT 验签 · 限流 · 熔断降级 · 链路追踪 │ ├── /api/** ──► Java 业务后端 :8081(模块化单体) │ │ │ └── Feign ──► Python AI 服务 :8082 │ └── /py/** ──► Python AI 服务 :8082 │ └── LangGraph 工作流 ``` ### 4.2 鉴权模型(重要) 本项目采用 **「网关统一鉴权 + 后端信任透传身份」** 模型,**未引入 Spring Security**: 1. 网关验签 JWT,验签通过后把用户身份写入 `X-User-Id` / `X-Username` / `X-User-Roles` 请求头; 2. 网关在转发前**剥离**客户端伪造的同名请求头(防越权), 其中也包含 `X-Real-IP`——它由网关按连接对端地址重新写入, 不剥离的话客户端每个请求换一个随机值就能把按 IP 的限流整体绕过去; 3. 下游服务的拦截器信任这些请求头,构造 `UserContext`; 4. Controller 上以注解声明权限:`@RequireLogin` / `@RequireRole` / `@RequirePerm`。 `@RequirePerm` 校验 `t_permission.code`,**只在注解出现时才查库**; 持有 `ROLE_ADMIN` 的账号在该注解处被短路豁免(理由见 `docs/14-module-sys.md`)。 > ⚠️ **部署前提**:业务后端与 AI 服务**必须只接受来自网关的流量** > (靠 K8s NetworkPolicy / 安全组 / 内网隔离保证)。 > 否则外部可直接伪造请求头冒充任意用户。 选择该模型而非 Spring Security 的原因:后端只被网关访问,Spring Security 的过滤器链与其职责重叠,却会引入两套安全上下文(`SecurityContext` 与 `UserContext`)并显著抬高配置复杂度。 ### 4.3 统一的响应结构 三个服务返回完全一致的 JSON 结构,前端只需一套解析逻辑: ```json { "code": 200, "message": "操作成功", "data": { }, "traceId": "a1b2c3d4...", "timestamp": 1790000000000 } ``` **HTTP 状态码约定**: - **协议级错误**(参数不合法 / 未认证 / 无权限 / 资源不存在):HTTP 状态码与业务码一致 - **业务规则错误**(业务码 ≥ 1000,如「题目已发布不可修改」):返回 HTTP 200,业务码在响应体中 ### 4.4 设计中用到模式的地方 README 第 5 节的设计模式规范要求「优先使用设计模式,但禁止为了模式而模式」。实际落地: | 场景 | 模式 | 位置 | |---|---|---| | 6 种题型判分 | 策略 + 工厂 | `module-question/grading/` | | 多支付渠道 | 策略 + 工厂 | `module-order/strategy/` | | 支付成功后发权益 | 观察者 | `module-order/observer/` | | 自由组卷 | 建造者 | `module-question/builder/` | | 订单状态流转 | 状态机 | `module-order/enums/OrderStatus` | | 知识点掌握度 | 状态机 | `module-study/enums/MasteryLevel` | | AI 出题审核流 | 工作流 | `module_AIagents/graph/workflow.py` | | AI 智学(8 个子 Agent · 流式会话 · 断点续传) | 多智能体 | `module_AIagents/`,见 `docs/15-ai-study.md` | | 数据访问 | DAO | 各模块 `dao/` | 每一处都在类 Javadoc 中写明了**为什么用**以及**不用会付出什么代价**。 --- ## 五、开发规范 **前端规范**是独立成篇的,正文在 [`docs/13-前端工程.md`](docs/13-前端工程.md) (该文件同时是前端上手手册与规范正文:命名、组件分层、状态管理、设计 Token、 代码质量、审查清单、工具链都在那里)。本节只写**跨端红线**与**后端规范**。 ### 5.1 红线(任何一端都适用) - **禁止**空 `catch`、`System.out`、`printStackTrace` - **禁止**用 `Executors` 创建线程池,必须显式 `ThreadPoolExecutor` - **禁止**硬编码密钥;敏感配置一律走环境变量 - **禁止**提交 `.env`(已在 `.gitignore` 中) - 新增自定义 SQL 必须显式带 `deleted = 0`(`@TableLogic` 不注入注解 SQL) - 提交信息遵循 `<类型>(<范围>): <描述>`,如 `feat(exam): 新增知识点掌握度标记接口` ### 5.2 Java - 4 空格缩进,**禁止 Tab**;单行不超过 120 字符 - POJO 必须写 `toString`;**禁止同时存在 `isXxx()` 与 `getXxx()`**(Jackson 会序列化出两个字段) - 异常必须记录日志或向上抛出,禁止吞掉 - 日志用 SLF4J,禁止 `System.out` / `printStackTrace` - 各业务模块统一放在 `module-` 前缀的包下,内部按 `controller / service / dao / entity / dto / converter` 分层 - ⚠️ **模块依赖图是 DAG**,编译期不会拦住反向依赖,靠人守(见 `CLAUDE.md`) ### 5.3 Python - 遵循 PEP 8,行宽 120;必须使用 type hints 与 Pydantic - 分层 `router → service → dao`;公共能力下沉到 `core/` - AI 调用必须设超时与重试;敏感配置走环境变量 - 运行环境 **Python 3.12.9 + FastAPI**,必须经 `scripts/start-python.sh` 启动 - 模块按**业务能力**划分,不按「是否调用大模型」—— `non_ai` 这类命名说明的是模块「不是什么」,会在新增能力时变成什么都往里塞的筐 ### 5.4 注释 - 类、接口、公开方法必须有 Javadoc / docstring - 行内注释解释**「为什么」**,不复述代码在做什么 - 禁止过时注释与无意义注释;删代码时连带删注释 ### 5.5 代码审查红线 1. 安全漏洞:SQL 注入、硬编码密钥、越权 2. 未处理异常导致服务崩溃 3. 命名严重不规范 4. 混合提交(一个 commit 只解决一个独立逻辑问题) > 本仓库目前**没有任何测试**(Java `src/test` 零文件、Python 只有 `tests/__init__.py`、 > 前端无测试框架),因此「测试未通过 / 覆盖率不足」暂时不作为门禁; > 引入测试基础设施后再把它加回上面的清单。 ### 5.6 将来引入协作者时 当前是**单人开发,直接 push 到 `master`**,不存在分支保护与 PR(约定见 `CLAUDE.md`)。 若将来加入协作者,再启用:`feature/* → develop → master` 的分支模型、 PR 必须审查 + CI 通过、`master` 设为保护分支、纳入代码质量门禁扫描。 --- ## 六、常见问题 ### 1. 构建报错 `Fatal error compiling: 无效的标记: --release` **原因**:本机全局 `JAVA_HOME` 指向 JDK 8,而项目要求 JDK 17。 注意 `java -version` 显示的可能是 17(PATH 里的),但 Maven 读的是 `JAVA_HOME`, 所以 `mvn -version` 会显示 `Java version: 1.8.0_202`。 **解决**:不要直接跑 `mvn`,用封装好的脚本: ```bash ./scripts/build-java.sh compile # 构建 Java 后端 ./scripts/build-java.sh gateway compile # 构建网关 ``` 脚本会自动把 `JAVA_HOME` 切到 JDK 17。若需手动指定: ```bash JAVA_HOME=/opt/modules/jdk17.0.20_8 mvn -B clean package ``` ### 2. Python 服务启动报错「conda 环境未激活」 **原因**:项目约定 Python 一律运行在 `huayuLearning_env`(Python 3.12.9)下。 **解决**:用启动脚本,它会自动激活并校验: ```bash ./scripts/start-python.sh # 开发模式 ./scripts/start-python.sh --prod # 生产模式 ./scripts/start-python.sh --check # 只校验环境,不启动 ``` ### 3. 服务启动报错「huayu.jwt.secret 长度不足 32 字节」 **原因**:HMAC-SHA256 要求密钥不短于 32 字节,服务在启动阶段就校验并拒绝启动 (这是有意的——让配置错误在启动时暴露,而不是等第一个请求进来才失败)。 **解决**:`openssl rand -base64 48` 生成后写入 `.env` 的 `JWT_SECRET`。 三个服务的该值必须完全一致。 ### 4. AI 接口返回「AI 助手暂时不可用」 **原因**:未配置大模型 API Key,或 Python 服务不可达。 **解决**:在 `docker/.env` 中设置 `LLM_API_KEY`。 未配置时服务仍可正常启动,`/health`、`/question-import/**` 与 `/text-analysis/**` 不受影响。 ### 5. 分页查询报错 `invalid value "20" for parameter "pageSize"` **原因**:`pageNum` / `pageSize` 校验失败。单页最大 200 条。 ### 6. 接口返回 401,但令牌明明是刚签发的 **排查顺序**: 1. 三个服务的 `JWT_SECRET` 是否完全一致? 2. 令牌是否已过期(默认 2 小时)? 3. 请求是否经过网关?后端只信任网关注入的身份头。 --- ## 七、下一阶段 按优先级排列。前两项是**上线阻塞项**。 - [ ] **实现支付回调验签**(阻塞):微信平台证书 RSA 验签 + APIv3 AES-256-GCM 解密; 支付宝公钥 RSA2 验签。完成后才能移除 fail-closed 开关。 - [ ] **删除 `POST /payment/mock/{orderId}`**(阻塞):当前绕过验签的调试接口, 接入真实渠道前必须删除,否则等同于留了一个后门。 - [ ] 前端工程(React 18 + TypeScript + Vite + Ant Design 5 + Tailwind) - [ ] 接入真实大模型并调优提示词 - [ ] 单元测试补全(当前聚焦架构完整性,测试覆盖不足) - [ ] 代码评审清单中的重复代码扫描与覆盖率门禁 ### 已知的架构性权衡(非缺陷,但需知晓) | 项 | 现状 | 何时需要处理 | |---|---|---| | 错题复习提醒与答题同事务 | 提醒写入失败会回滚整次作答 | 提醒逻辑变复杂前,迁到 `@TransactionalEventListener(AFTER_COMMIT)` | | 知识点搜索用 `LIKE` | 无索引,全文匹配 | 知识点上规模后换 PostgreSQL 全文检索 | | 章节树知识点计数逐个查询 | N+1,但章节在百级 | 上千级时改为一次 `group by` 后内存回填 | | `/auth/captcha` 在白名单但无实现 | 调用返回 404 | 需要验证码时补上 | --- ## 八、文档索引 各子模块的详细文档见 `docs/` 目录: | 文档 | 内容 | |---|---| | [架构总览](docs/00-架构总览.md) | 整体架构、模块依赖、数据流 | | [网关服务](docs/01-gateway.md) | 路由、鉴权、限流、熔断 | | [核心模块](docs/02-core.md) | 统一响应、异常、拦截器、数据源 | | [账号权限](docs/03-module-auth.md) | 注册登录、JWT、RBAC | | [考试内容](docs/04-module-exam.md) | 考试/科目/章节树/知识点 | | [笔记视频](docs/05-module-content.md) | 笔记、时间戳笔记、视频(后端保留;前端已下线笔记) | | [题库判分](docs/06-module-question.md) | 6 题型、判分策略、组卷 | | [学习统计](docs/07-module-study.md) | 错题本、艾宾浩斯、计划、统计 | | [订单支付](docs/08-module-order.md) | 支付策略、状态机、权益发放 | | [后台管理](docs/09-module-admin.md) | 聚合统计接口(看板) | | [系统管理](docs/14-module-sys.md) | 用户/角色/权限点、字典、参数、公告、日志、LLM 配置 | | [AI 集成](docs/10-module-ai.md) | Feign 调用与熔断降级 | | [Python AI 服务](docs/11-python-ai.md) | Agent、LangGraph 工作流 | | [数据库设计](docs/12-数据库设计.md) | 表结构、索引策略、设计取舍 | | [前端工程](docs/13-前端工程.md) | 目录结构、状态管理、导入规范、设计 Token、**前端规范正文** | | [AI 智学](docs/15-ai-study.md) | 主 Agent + 8 个子 Agent、SSE 事件协议、断点续传 | --- ## 许可 私有项目,未经授权禁止分发。