diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d458d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.restore +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +.idea/ +*.iml +*.iws +.idea_modules/ + +# OS +.DS_Store +Thumbs.db diff --git a/.idea/misc.xml b/.idea/misc.xml index 6546f14..56c7380 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/doc/AGENT_HANDOFF.md b/doc/AGENT_HANDOFF.md new file mode 100644 index 0000000..66eac74 --- /dev/null +++ b/doc/AGENT_HANDOFF.md @@ -0,0 +1,56 @@ +# AI-Native CRM: Agent Handoff Guide + +> [!IMPORTANT] +> This document is for the AI Agent to quickly understand the project context, architecture, and current status during session resume. + +## 🎯 Project Vision +An **AI-Native CRM** where business modules and data are managed through AI-driven messages and tools, rather than traditional REST parameters. + +--- + +## 🏗️ Architecture Overview + +### Backend (`/backend`) +* **Env**: JDK 19 + Spring Boot 3.2.4 + PostgreSQL. +* **Key Logic**: + * `CrmTools.java`: **The Message Hub**. Contains `@Tool` methods for **Define, Save, and Delete**. Directly interacts with Repositories. + * `AgentController.java`: **Primary Entry Point**. Handles natural language commands or "Business Fact Reports". + * **AI-Only Policy**: Create/Update/Delete endpoints have been removed from traditional controllers to force AI-driven flows. + +### Frontend (`/frontend`) +* **Env**: Next.js 15 (App Router). +* **Components**: + * `DynamicForm.tsx`: Shared component supporting **Entity Associations (`x-link-entity`)**, Enums, and Format constraints. + * `EntityDataPage` (`/data/[entityCode]`): Full CRUD UI. Actions (Edit/Delete) route through AI messages. + +--- + +## 🛠️ Key File Responsibilities + +| File | Role | +| :--- | :--- | +| `backend/.../CrmTools.java` | **Source of Truth** for all data-changing tools. | +| `frontend/src/components/DynamicForm.tsx` | Reusable Form Renderer (Schema + AI messaging). | +| `frontend/src/app/data/[entityCode]/page.tsx` | Dynamic List View with Agent-driven Actions. | + +--- + +## 🔄 Core Conventions + +1. **AI-First Mutation**: DO NOT create manual REST services for data mutation. Use the AI Tool interface. +2. **Schema Extensions**: + * Associations: `x-link-entity: 'module_code'`. + * Constraints: `enum`, `pattern`, `format: 'date'`. +3. **Fact-Based Messaging**: Frontend should report business facts (e.g., "User filled form X") and let the AI decide the tool to call. + +--- + +## 🚀 Current Progress & Next Steps +- [x] AI-Native CRUD implemented (Agent-driven Insert/Update/Delete). +- [x] Entity Associations & Selectors supported. +- [x] Unified DynamicForm for Generation & Management. +- [ ] Next: Implement Advanced Search & Filtering via AI Query generation. +- [ ] Next: Dashboard Analytics module for dynamic data summary. + +--- +*Updated at: 2026-03-25. Follow this guide for AI-Native CRM development.* diff --git a/doc/Instruction.md b/doc/Instruction.md new file mode 100644 index 0000000..e25a492 --- /dev/null +++ b/doc/Instruction.md @@ -0,0 +1,49 @@ +# AI-Native CRM 系统开发手册 + +## 🎯 系统定位 (Core Vision) +本系统是一款 **AI-Native (原生 AI)** 的声明式 CRM。与传统 CRM 的本质区别在于: +* **非硬编码业务逻辑**:业务模块、字段定义和 UI 呈现均由 AI 动态生成并持久化。 +* **零研发排期**:业务专家通过自然语言描述需求,即可立刻生成生产可用的功能模块。 + +--- + +## 🚀 核心特性 (Key Features) + +### 1. 生成式 UI (Generative UI) +* 集成 **CopilotKit**,在前端实现 AI 对应用的深度操控。 +* 支持通过自然语言一键渲染(Render)基于 JSON Schema 的复杂表单。 +* **UniversalModuleRenderer**:万能组件渲染引擎,适配多种动态业务场景。 + +### 2. 动态多租户架构 +* 后端使用 `SysEntity` (元数据) 和 `SysDynamicData` (实例数据) 支撑无限扩展。 +* 支持不同租户、不同模块的字段在运行时动态注入,无需繁琐的数据库迁移动作。 + +### 3. AI 交互中枢 (AI Hub) +* **后端驱动**:基于 **LangChain4j** 构建 Java 原生 AI 逻辑,支持 RAG 及复杂工作流。 +* **会话持久化**:原生支持 AI 会话的数据库存储,重启不丢失交互上下文。 + +--- + +## 📋 技术基准 (Benchmarks & Tech Stack) + +### Backend (Java Ecosystem) +* **Runner**: OpenJDK 19 +* **Framework**: Spring Boot 3.2.4 (Latest Stable) +* **Persistence**: Spring Data JPA + Hibernate 6.x +* **Database**: PostgreSQL (Support JSONB for Dynamic Data) +* **AI SDK**: LangChain4j 0.30.0 +* **Build Tool**: Maven + +### Frontend (Modern Web) +* **Framework**: Next.js (App Router) +* **Language**: TypeScript +* **Styling**: Tailwind CSS + Shadcn UI (Visual Esthetics) +* **Copilot**: CopilotKit (React SDK + Popup UI) +* **Font**: Geist (Advanced Typography) + +--- + +## 🛠 开发规范 +1. **动态性优先**:任何新功能应考虑是否可通过配置或 AI 生成,而非硬编码 Controller。 +2. **Schema 为王**:业务定义必须严格遵循 JSON Schema 标准,以保证前后端渲染的一致性。 +3. **Prompt 工程**:系统 Prompt 存储于前端 `page.tsx` 或后端专用 AI 服务类中,需定期维护。 diff --git a/pom.xml b/pom.xml index b59ddcb..5e4e333 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.4 + 3.5.12 com.example @@ -14,8 +14,8 @@ ai-native-backend AI-Native CRM Backend - 21 - 0.30.0 + 19 + 1.12.2-beta22 diff --git a/src/main/java/com/example/ainative/ai/CrmAgent.java b/src/main/java/com/example/ainative/ai/CrmAgent.java index 4d6089d..f9e4588 100644 --- a/src/main/java/com/example/ainative/ai/CrmAgent.java +++ b/src/main/java/com/example/ainative/ai/CrmAgent.java @@ -6,16 +6,33 @@ import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; import dev.langchain4j.service.spring.AiService; -@AiService +@AiService(tools = "crmTools") public interface CrmAgent { @SystemMessage(""" - You are a smart AI assistant embedded within a modern enterprise CRM system. - Your goal is to help the user configure business modules, dynamic forms, and insert data. - You have tools to define database schema structures (JSON Schema) and manipulate dynamic data. - Always respond concisely. If you need to manipulate the UI, explain what you are doing. + ## 角色与愿景 + 你是一个 AI 原生 CRM 系统的核心引擎。你的任务是通过自然语言管理业务模块(Schema)和动态数据,替代传统的 REST 接口。 - Current User/Tenant context ID: {{userContext}} + ## 核心运行准则(严禁违反) + 1. **执行重于对话**:系统已禁用传统的增删改接口,所有数据变更必须通过调用工具实现。 + 2. **禁止虚假模拟**:严禁在未成功调用工具的情况下,回复任何暗示操作已完成的内容(如“已保存”、“已创建”)。 + 3. **事实驱动**:前端会报告“业务事实”(如:用户提交了表单内容),你必须根据事实判断该调用哪个工具(如:insertDynamicData)。 + + ## 建模协议 (defineDynamicModule) + 当定义或更新模块结构时,生成的 JSON Schema 需遵循: + - **实体关联**:若字段需关联其他实体,必须在属性中加入 `"x-link-entity": "目标实体Code"`。 + - **约束增强**:优先使用 `enum` (下拉选项)、`pattern` (正则校验)、`format: "date"` 等标准 JSON Schema 约束。 + - **命名规范**:entityCode 采用下划线命名法(如:student_course)。 + + ## 数据操作协议 + - **入库 (insert)**:将用户提供的或事实报告中的信息提取为 JSON 字符串。 + - **物理删除 (delete)**:仅在用户明确指令或业务流程需要时执行。 + + ## 输出风格 + - 保持简洁。 + - 必须在工具执行成功后,再简要反馈执行结果或后续 UI 操作建议。 + + 当前租户上下文 ID: {{userContext}} """) String chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("userContext") String userContext); } diff --git a/src/main/java/com/example/ainative/ai/CrmTools.java b/src/main/java/com/example/ainative/ai/CrmTools.java index 523a815..20d47d3 100644 --- a/src/main/java/com/example/ainative/ai/CrmTools.java +++ b/src/main/java/com/example/ainative/ai/CrmTools.java @@ -1,54 +1,99 @@ package com.example.ainative.ai; +import com.example.ainative.config.UserContextHolder; + +import com.example.ainative.entity.SysDynamicData; import com.example.ainative.entity.SysEntity; +import com.example.ainative.repository.SysDynamicDataRepository; import com.example.ainative.repository.SysEntityRepository; import dev.langchain4j.agent.tool.Tool; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; - -import java.util.UUID; +import org.springframework.transaction.annotation.Transactional; @Slf4j -@Component +@Component("crmTools") @RequiredArgsConstructor public class CrmTools { private final SysEntityRepository sysEntityRepository; + private final SysDynamicDataRepository sysDynamicDataRepository; - /** - * AI 工具:用于定义新的动态业务对象(Entity)。 - * 当用户试图创建新表单、新模块(比如“线索管理”、“合同管理”)时,大模型会自动决定调用本工具, - * 并将它根据系统指令生成的参数传入进来。 - * - * @param entityCode 模块唯一标识符,英文,比如 crm_lead (便于后期通过接口精确操作某模块) - * @param entityName 模块中文名称跨,比如 销售线索 - * @param jsonSchema 这里是大模型输出的最核心数据:一个合规的 JSON Schema (如属性定义、校验规则),由前端随后解析渲染 - * @return 返回一段让 AI 知道是否成功的指令结果,这个结果大模型能看到并进一步回答用户。 - */ - @Tool("创建一个新的业务表单模块,当你确定了用户创建新功能的意图后调用。参数包括:entityCode (英文唯一标识), entityName (中文名称), jsonSchema。") + @Transactional + @Tool("核心业务处理:根据消息意图定义或执行模型变更 (Schema)。支持以下高级能力:\n" + + "1. [实体关联]:若字段需要关联其他实体,需在 Schema 属性中加入 `x-link-entity: '目标实体Code'`。\n" + + "2. [值约束]:支持标准 JSON Schema 的 `enum` (下拉选择)、`pattern` (正则校验)、`format` (如 date, email)、`minLength` 等约束。\n" + + "3. [示例]:商品关联分类,分类字段可定义为 { 'type': 'string', 'x-link-entity': 'category' }") public String defineDynamicModule(String entityCode, String entityName, String jsonSchema) { - log.info("Agent 正在调用工具执行创建新模块: Code={}, Name={}", entityCode, entityName); - - // 1. 业务校验:防重和容错 - SysEntity existing = sysEntityRepository.findByEntityCode(entityCode); - if (existing != null) { - return "模块代码 [" + entityCode + "] 已存在,创建失败,请让用户考虑使用其他代码名称。"; - } - - // 2. 实体赋值与入库 + log.info("Agent Tool 正在处理消息:定义模块: Code={}, Name={}", entityCode, entityName); try { + SysEntity existing = sysEntityRepository.findByEntityCode(entityCode); + if (existing != null) { + existing.setSchemaDefinition(jsonSchema); + existing.setEntityName(entityName); + existing.setCreatorId(UserContextHolder.getCurrentUser()); + sysEntityRepository.save(existing); + return "AI 已更新现有模块 [" + entityName + "]。"; + } + SysEntity entity = new SysEntity(); entity.setEntityCode(entityCode); entity.setEntityName(entityName); - // 此处直接存储大模型生成的 JSON 字符串(PostgreSQL 的 Hibernate 驱动会将其封装为 JSONB) entity.setSchemaDefinition(jsonSchema); - + entity.setCreatorId(UserContextHolder.getCurrentUser()); SysEntity saved = sysEntityRepository.save(entity); - return "核心模块 [" + entityName + "] 已成功持久化并部署到系统中。后台对应的 Entity ID (UUID) 为: " + saved.getId(); + return "AI 已成功解析并持久化业务模块 [" + entityName + " (" + entityCode + ")],ID: " + saved.getId(); } catch (Exception e) { - log.error("保存 Schema 时出现异常", e); - return "数据库保存异常,请检查 JSON 结构是否合规。"; + log.error("AI 处理定义请求失败: {}", e.getMessage()); + return "处理失败: " + e.getMessage(); + } + } + + /** + * AI 工具封装:直接处理业务数据入库意图。 + */ + @Transactional + @Tool("核心业务处理:将业务消息中的动态数据持久化到指定模块。参数:entityCode (模块代码), jsonData (JSON 数据)。") + public String insertDynamicData(String entityCode, String jsonData) { + log.info("Agent Tool 正在处理消息:将数据保存至模块: Code={}", entityCode); + try { + SysEntity entity = sysEntityRepository.findByEntityCode(entityCode); + if (entity == null) { + return "AI 无法找到模块 [" + entityCode + "],请先下达创建模块的指令。"; + } + + SysDynamicData record = new SysDynamicData(); + record.setEntityId(entity.getId()); + record.setData(jsonData); + record.setCreatorId(UserContextHolder.getCurrentUser()); + SysDynamicData saved = sysDynamicDataRepository.save(record); + return "AI 已自动完成数据入库,记录主键 ID: " + saved.getId(); + } catch (Exception e) { + log.error("AI 自动化入库失败: {}", e.getMessage()); + return "入库失败: " + e.getMessage(); + } + } + + /** + * AI 工具封装:删除指定的业务数据。 + */ + @Transactional + @Tool("核心业务处理:根据 ID 物理删除指定的业务记录。参数:id (记录的唯一 UUID)。") + public String deleteDynamicData(String id) { + log.info("Agent Tool 正在处理消息:删除记录 ID: {}", id); + try { + java.util.UUID uuid = java.util.UUID.fromString(id); + if (!sysDynamicDataRepository.existsById(uuid)) { + return "AI 无法找到 ID 为 [" + id + "] 的记录,可能已被删除。"; + } + sysDynamicDataRepository.deleteById(uuid); + return "AI 已成功从系统中移除该条记录 (ID: " + id + ")。"; + } catch (Exception e) { + log.error("AI 物理删除失败: {}", e.getMessage()); + return "删除操作遇到技术故障: " + e.getMessage(); } } } + + diff --git a/src/main/java/com/example/ainative/controller/AgentController.java b/src/main/java/com/example/ainative/controller/AgentController.java index 81e1bc4..89eb3f9 100644 --- a/src/main/java/com/example/ainative/controller/AgentController.java +++ b/src/main/java/com/example/ainative/controller/AgentController.java @@ -3,11 +3,13 @@ package com.example.ainative.controller; import com.example.ainative.ai.CrmAgent; import com.example.ainative.config.UserContextHolder; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/agent") @RequiredArgsConstructor +@Slf4j public class AgentController { private final CrmAgent crmAgent; @@ -15,7 +17,7 @@ public class AgentController { /** * 对话交互核心入口 * 这里提供了一个传统的 REST 包装版本。当前端(如 CopilotKit 或测试客户端)发送自然语言时,会调用此处。 - * + * * @param sessionId 唯一会话识别(与底层的 ChatMemory 持久化紧密对应,确保 AI 能“记住”对话) * @param message 用户的原始需求 (比如:"帮我建一个客户关系系统的线索录入表,有姓名和手机号") * @return AI 所思所想或执行完 @Tool 后的结果字符串反馈 @@ -24,7 +26,7 @@ public class AgentController { public String chat(@RequestParam String sessionId, @RequestBody String message) { // 先从拦截器上下文中拿到刚才设置的调用者身份 String currentUser = UserContextHolder.getCurrentUser(); - + log.info("message:{}",message); // 传递给底层的 Agent:这背后的复杂工作流完全交由 Langchain4J 托管! // 如果用户的 message 意图命中“建表”,框架会在返回前自己拦截调去跑 CrmTools 里的 defineDynamicModule。 return crmAgent.chat(sessionId, message, currentUser); diff --git a/src/main/java/com/example/ainative/controller/DynamicDataController.java b/src/main/java/com/example/ainative/controller/DynamicDataController.java index 1404997..db5ca58 100644 --- a/src/main/java/com/example/ainative/controller/DynamicDataController.java +++ b/src/main/java/com/example/ainative/controller/DynamicDataController.java @@ -1,5 +1,6 @@ package com.example.ainative.controller; +import com.example.ainative.ai.CrmTools; import com.example.ainative.config.UserContextHolder; import com.example.ainative.entity.SysDynamicData; import com.example.ainative.entity.SysEntity; @@ -18,7 +19,7 @@ import java.util.UUID; @RestController @RequestMapping("/api/dynamic") @RequiredArgsConstructor -@CrossOrigin(origins = "*") // 允许前端 Next.js (通常是 3000 端口) 进行跨域调用 +@CrossOrigin(origins = "*") public class DynamicDataController { private final SysDynamicDataRepository dataRepository; @@ -29,88 +30,19 @@ public class DynamicDataController { */ @GetMapping("/{entityId}") public List getRecords(@PathVariable UUID entityId) { - return dataRepository.findByEntityId(entityId); + return dataRepository.findByEntityIdAndCreatorId(entityId, UserContextHolder.getCurrentUser()); } /** - * 根据模块 code 获取数据列表(前端动态表格主要用此接口方便查询) + * 根据模块 code 获取数据列表 */ @GetMapping("/code/{entityCode}") public List getRecordsByCode(@PathVariable String entityCode) { - SysEntity entity = entityRepository.findByEntityCode(entityCode); + SysEntity entity = entityRepository.findByEntityCodeAndCreatorId(entityCode, UserContextHolder.getCurrentUser()); if (entity != null) { - return dataRepository.findByEntityId(entity.getId()); + return dataRepository.findByEntityIdAndCreatorId(entity.getId(), UserContextHolder.getCurrentUser()); } return List.of(); } - - /** - * 自动注册/获取动态模块接口:解决前端渲染表单和后端实体记录未创建的时序问题 - * 允许前端在提交实际数据前,主动将推断出的模块结构注册到数据库。 - */ - @PostMapping("/schema") - public SysEntity defineSchema(@RequestBody SysEntity requestedEntity) { - SysEntity entity = entityRepository.findByEntityCode(requestedEntity.getEntityCode()); - if (entity == null) { - entity = new SysEntity(); - entity.setEntityCode(requestedEntity.getEntityCode()); - entity.setEntityName(requestedEntity.getEntityName()); - entity.setSchemaDefinition(requestedEntity.getSchemaDefinition()); - return entityRepository.save(entity); - } - return entity; - } - - /** - * 核心接口:按 entityCode 直接入库 - * 前端不需要知道复杂的 UUID,只需根据 AI 生成的 crm_lead 等 Code 即可提交。 - */ - @PostMapping("/code/{entityCode}") - public SysDynamicData createRecordByCode(@PathVariable String entityCode, @RequestBody String jsonData) { - // 1. 先通过 Code 找到模块定义的 ID - SysEntity entity = entityRepository.findByEntityCode(entityCode); - if (entity == null) { - throw new RuntimeException("模块 " + entityCode + " 尚未定义,无法入库。请先让 AI 创建该模块。"); - } - - // 2. 构造动态数据记录 - SysDynamicData record = new SysDynamicData(); - record.setEntityId(entity.getId()); - record.setData(jsonData); // 这里的 String 在 JSONB 映射下会自动存为二进制 JSON 格式 - record.setCreatorId(UserContextHolder.getCurrentUser()); - - return dataRepository.save(record); - } - - /** - * 原始的 UUID 入库接口 (保留备用) - */ - @PostMapping("/{entityId}") - public SysDynamicData createRecord(@PathVariable UUID entityId, @RequestBody String jsonData) { - SysDynamicData record = new SysDynamicData(); - record.setEntityId(entityId); - record.setData(jsonData); - record.setCreatorId(UserContextHolder.getCurrentUser()); - - return dataRepository.save(record); - } - - /** - * 修改现有记录 - */ - @PutMapping("/{id}") - public SysDynamicData updateRecord(@PathVariable UUID id, @RequestBody String jsonData) { - return dataRepository.findById(id).map(record -> { - record.setData(jsonData); - return dataRepository.save(record); - }).orElseThrow(() -> new RuntimeException("Record not found")); - } - - /** - * 删除现有记录 - */ - @DeleteMapping("/{id}") - public void deleteRecord(@PathVariable UUID id) { - dataRepository.deleteById(id); - } } + diff --git a/src/main/java/com/example/ainative/controller/SysEntityController.java b/src/main/java/com/example/ainative/controller/SysEntityController.java index 4ddbd11..680daea 100644 --- a/src/main/java/com/example/ainative/controller/SysEntityController.java +++ b/src/main/java/com/example/ainative/controller/SysEntityController.java @@ -10,24 +10,27 @@ import java.util.List; @RestController @RequestMapping("/api/entities") @RequiredArgsConstructor -@CrossOrigin(origins = "*") // Allow frontend to fetch menus +@CrossOrigin(origins = "*") public class SysEntityController { private final SysEntityRepository sysEntityRepository; /** * 获取所有已定义的模块列表,供左侧菜单动态渲染使用。 + * 该接口属于传统查询,用于 UI 展现。 */ @GetMapping public List getAllEntities() { - return sysEntityRepository.findAll(); + return sysEntityRepository.findByCreatorId(com.example.ainative.config.UserContextHolder.getCurrentUser()); } /** - * 根据 code 获取单一实体定义,方便前台表格按需渲染列等动态行为。 + * 根据 code 获取单一实体定义。 */ @GetMapping("/code/{entityCode}") public SysEntity getEntityByCode(@PathVariable String entityCode) { - return sysEntityRepository.findByEntityCode(entityCode); + return sysEntityRepository.findByEntityCodeAndCreatorId(entityCode, com.example.ainative.config.UserContextHolder.getCurrentUser()); } } + + diff --git a/src/main/java/com/example/ainative/entity/SysEntity.java b/src/main/java/com/example/ainative/entity/SysEntity.java index 25264e9..52c67a8 100644 --- a/src/main/java/com/example/ainative/entity/SysEntity.java +++ b/src/main/java/com/example/ainative/entity/SysEntity.java @@ -28,6 +28,9 @@ public class SysEntity { @Column(name = "schema_definition", columnDefinition = "jsonb", nullable = false) private String schemaDefinition; + @Column(name = "creator_id", length = 50) + private String creatorId; + @CreationTimestamp @Column(name = "created_at", updatable = false) private ZonedDateTime createdAt; diff --git a/src/main/java/com/example/ainative/repository/SysDynamicDataRepository.java b/src/main/java/com/example/ainative/repository/SysDynamicDataRepository.java index 8973ea7..ec59924 100644 --- a/src/main/java/com/example/ainative/repository/SysDynamicDataRepository.java +++ b/src/main/java/com/example/ainative/repository/SysDynamicDataRepository.java @@ -8,4 +8,5 @@ import java.util.UUID; public interface SysDynamicDataRepository extends JpaRepository { List findByEntityId(UUID entityId); + List findByEntityIdAndCreatorId(UUID entityId, String creatorId); } diff --git a/src/main/java/com/example/ainative/repository/SysEntityRepository.java b/src/main/java/com/example/ainative/repository/SysEntityRepository.java index 0c63d42..ce75695 100644 --- a/src/main/java/com/example/ainative/repository/SysEntityRepository.java +++ b/src/main/java/com/example/ainative/repository/SysEntityRepository.java @@ -3,8 +3,11 @@ package com.example.ainative.repository; import com.example.ainative.entity.SysEntity; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.UUID; public interface SysEntityRepository extends JpaRepository { SysEntity findByEntityCode(String entityCode); + List findByCreatorId(String creatorId); + SysEntity findByEntityCodeAndCreatorId(String entityCode, String creatorId); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index aea9df9..7ad2acb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,7 +9,7 @@ spring: jpa: hibernate: ddl-auto: none - show-sql: true + show-sql: false properties: hibernate: format_sql: true @@ -26,3 +26,8 @@ langchain4j: server: port: 8080 + +logging: + level: + dev.ai4j: debug + org.hibernate.sql: error diff --git a/target/classes/application.yml b/target/classes/application.yml index aea9df9..7ad2acb 100644 --- a/target/classes/application.yml +++ b/target/classes/application.yml @@ -9,7 +9,7 @@ spring: jpa: hibernate: ddl-auto: none - show-sql: true + show-sql: false properties: hibernate: format_sql: true @@ -26,3 +26,8 @@ langchain4j: server: port: 8080 + +logging: + level: + dev.ai4j: debug + org.hibernate.sql: error