### Local Development Setup Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/desktop/README.md Steps to install dependencies, sync the renderer, fetch the JRE, and start the application in local backend mode. ```bash cd desktop npm install npm run sync:renderer # 需先有 frontend/dist(在 frontend 下 npm run build) npm run fetch:jre # 下载当前平台 JRE CRM_BACKEND_MODE=local npm start # 本地后端模式(mac/linux 写法) # PowerShell: $env:CRM_BACKEND_MODE="local"; npm start ``` -------------------------------- ### Docker Installation Commands Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/README.md Commands to clone the repository and start the system using Docker Compose. ```bash git clone https://github.com/WuKongOpenSource/Wukong-AICRM.git cd Wukong-AICRM/docker docker-compose up -d ``` -------------------------------- ### Start Frontend Service Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/README.md Commands to install dependencies and start the Vue development server. ```bash cd frontend npm install npm run dev ``` -------------------------------- ### Clone Repository for Manual Installation Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/README.md Initial step to clone the source code for manual development setup. ```bash git clone https://github.com/WuKongOpenSource/Wukong-AICRM.git cd Wukong-AICRM ``` -------------------------------- ### Build Windows Distribution Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/desktop/README.md Command to bundle the application and generate Windows installers. ```bash cd desktop npm install npm run dist:win # = bundle + fetch:jre + make:icon + electron-builder --win ``` -------------------------------- ### Start Backend Service Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/README.md Commands to build and run the Spring Boot backend application. ```bash cd backend mvn clean install mvn spring-boot:run ``` -------------------------------- ### MCP Server Commands Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/AGENTS.md Commands for building and starting the MCP server, noting the required environment variables for authentication and API connectivity. ```bash npm install npm run build npm start ``` -------------------------------- ### Build Frontend with Docker Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase1c-frontend.md Command to build the frontend application using a Docker node container. This command assumes the project directory is mounted to /app and handles dependency installation and the build process. ```bash MSYS_NO_PATHCONV=1 docker run --rm -v "F:/projects/WUKONG/AI_CRM/frontend:/app" -w /app node:20 sh -c "npm install && npm run build" ``` -------------------------------- ### GET /im/channels/{id}/members Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/specs/2026-06-21-im-phase2-channels-design.md Lists all members of a specific channel. ```APIDOC ## GET /im/channels/{id}/members ### Description Lists all members of a specific channel. The caller must be a member of the channel. ### Method GET ### Endpoint /im/channels/{id}/members ### Path Parameters - **id** (string) - Required - The ID of the channel ``` -------------------------------- ### Package and deploy backend with new frontend Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase1c-frontend.md Copies the built frontend into the backend resources, packages the application with Maven, builds the Docker image, and restarts the CRM service. ```bash rm -rf backend/src/main/resources/public && mkdir -p backend/src/main/resources/public cp -r frontend/dist/. backend/src/main/resources/public/ MSYS_NO_PATHCONV=1 docker run --rm -v "F:/projects/WUKONG/AI_CRM:/work" -v aicrm_m2:/root/.m2 -w /work/backend maven:3.9.9-eclipse-temurin-21 mvn -q -DskipTests clean package MSYS_NO_PATHCONV=1 docker build -t wk_ai_crm:local-aiimport -f backend/Dockerfile backend/ cd docker && MSYS_NO_PATHCONV=1 docker compose up -d --force-recreate crm; cd /f/projects/WUKONG/AI_CRM rm -rf backend/src/main/resources/public ``` -------------------------------- ### GET /im/channels/public Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/specs/2026-06-21-im-phase2-channels-design.md Lists public channels that the current user is not a member of. ```APIDOC ## GET /im/channels/public ### Description Lists public channels that the current user is not a member of. ### Method GET ### Endpoint /im/channels/public ### Query Parameters - **keyword** (string) - Optional - Filter channels by name or description ``` -------------------------------- ### GET /im/contacts Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/specs/2026-06-21-im-phase1-design.md Retrieve a list of contacts available for direct messaging. ```APIDOC ## GET /im/contacts ### Description Address-book users I can DM, with presence. ### Method GET ### Endpoint /im/contacts ``` -------------------------------- ### GET /im/conversations/{conversationId}/messages Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase1c-frontend.md Fetches the message history for a specific conversation. ```APIDOC ## GET /im/conversations/{conversationId}/messages ### Description Fetches the message history for a specific conversation. ### Method GET ### Endpoint /im/conversations/{conversationId}/messages ### Parameters #### Path Parameters - **conversationId** (string) - Required - The ID of the conversation. #### Query Parameters - **beforeId** (string) - Optional - ID of the message to fetch history before. - **limit** (number) - Optional - Maximum number of messages to return (default 30). ### Response #### Success Response (200) - **ImMessage[]** (array) - List of message objects. ``` -------------------------------- ### Build and Deploy Application with Docker Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase2-channels.md Builds the frontend and backend, packages them into a Docker image, and restarts the CRM service. ```bash cd /f/projects/WUKONG/AI_CRM MSYS_NO_PATHCONV=1 docker run --rm -v "F:/projects/WUKONG/AI_CRM/frontend:/app" -w /app node:20 sh -c "npm install && npm run build" rm -rf backend/src/main/resources/public && mkdir -p backend/src/main/resources/public && cp -r frontend/dist/. backend/src/main/resources/public/ MSYS_NO_PATHCONV=1 docker run --rm -v "F:/projects/WUKONG/AI_CRM:/work" -v aicrm_m2:/root/.m2 -w /work/backend maven:3.9.9-eclipse-temurin-21 mvn -q -DskipTests clean package MSYS_NO_PATHCONV=1 docker build -t wk_ai_crm:local-aiimport -f backend/Dockerfile backend/ cd docker && MSYS_NO_PATHCONV=1 docker compose up -d --force-recreate crm; cd /f/projects/WUKONG/AI_CRM rm -rf backend/src/main/resources/public ``` -------------------------------- ### Common Development Commands Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/CLAUDE.md Standard commands for running, testing, and building the backend, frontend, data synchronization, and MCP server components. ```bash # backend/ mvn spring-boot:run # run (port 8088, API docs at /doc.html) mvn test # all tests mvn test -Dtest=ClassName#method # single test mvn clean install # frontend/ (imports use @ -> src/; TS is strict on unused vars) npm run dev npm run lint # auto-fixes npm run build # vue-tsc -b && vite build — NOT a default verification step; see AGENTS.md # sync_data/ mvn -DskipTests package && java -jar target/sync-data-1.0.0.jar --server.port=10456 # mcp_server/ (needs AICRM_TOKEN; AICRM_BASE_URL defaults to http://127.0.0.1:8088) npm run build && npm start ``` -------------------------------- ### Build Backend JAR Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/desktop/README.md Commands to build the backend JAR using the desktop profile in the backend directory. ```bash cd backend mvn -Pdesktop -DskipTests package # 产出 target/crm-1.0.0.jar(含 windows + macОS 两架构 PG 二进制) cp target/crm-1.0.0.jar ../desktop/resources/backend/crm-desktop.jar ``` -------------------------------- ### GET /im/channels/public Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase2-channels.md Retrieves a list of public IM channels, optionally filtered by a keyword. ```APIDOC ## GET /im/channels/public ### Description Browse available public channels. ### Method GET ### Endpoint /im/channels/public ### Query Parameters - **keyword** (string) - Optional - Search keyword to filter channels. ``` -------------------------------- ### GET /im/conversations/{id}/messages Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/specs/2026-06-21-im-phase1-design.md Retrieve paged message history for a specific conversation. ```APIDOC ## GET /im/conversations/{id}/messages ### Description Paged history (newest-first, scroll-up). ### Method GET ### Endpoint /im/conversations/{id}/messages ### Parameters #### Path Parameters - **id** (string) - Required - The conversation ID. #### Query Parameters - **beforeId** (string) - Optional - ID of the message to start paging before. - **limit** (integer) - Optional - Number of messages to return. ``` -------------------------------- ### Compile project with Maven Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-address-book-ai-import.md Run the compilation command to verify the changes. ```bash mvn -q compile ``` -------------------------------- ### Verify dependency resolution Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase1b-websocket.md Run this command to verify that the new dependency resolves correctly. ```bash MSYS_NO_PATHCONV=1 docker run --rm -v "F:/projects/WUKONG/AI_CRM:/work" -v aicrm_m2:/root/.m2 -w /work/backend maven:3.9.9-eclipse-temurin-21 mvn -q -DskipTests compile ``` -------------------------------- ### GET /im/messages/{rootId}/thread Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/specs/2026-06-22-im-phase3-threads-reactions-mentions-design.md Retrieves a message thread including the root message and all its replies. ```APIDOC ## GET /im/messages/{rootId}/thread ### Description Fetches the full thread associated with a root message, including the root message itself and all subsequent replies. ### Method GET ### Endpoint /im/messages/{rootId}/thread ### Parameters #### Path Parameters - **rootId** (string) - Required - The unique identifier of the root message. ``` -------------------------------- ### Knife4j API Documentation URL Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/README.md The URL to access the Knife4j API documentation after starting the backend service. ```text http://localhost:8088/doc.html ``` -------------------------------- ### Build macOS Distribution Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/desktop/README.md Command to bundle the application for macOS. ```bash cd desktop npm install npm run dist:mac # 自动拉 macOS JRE,产出 .dmg / .zip(Apple 芯片为 arm64) ``` -------------------------------- ### GET /messages/{id}/thread Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-22-im-phase3-threads-reactions-mentions.md Retrieves a message thread, including the root message and all associated replies. ```APIDOC ## GET /messages/{id}/thread ### Description Retrieves a message thread, including the root message and all associated replies. Requires 'im' permission. ### Method GET ### Endpoint /messages/{id}/thread ### Parameters #### Path Parameters - **id** (Long) - Required - The ID of the root message. ``` -------------------------------- ### Run Preview Tests Command Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-address-book-ai-import.md Command to execute the EmployeeToolsTest suite. ```bash mvn test -Dtest=EmployeeToolsTest ``` -------------------------------- ### Sync Service Build and Run Commands Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/AGENTS.md Commands to package and execute the sync_data Spring Boot service, which synchronizes MySQL data to PostgreSQL. ```bash mvn -DskipTests package java -jar target\sync-data-1.0.0.jar --server.port=10456 ``` -------------------------------- ### GET /im/conversations Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/specs/2026-06-21-im-phase1-design.md List all conversations for the authenticated user, including peer information, the last message, and unread counts. ```APIDOC ## GET /im/conversations ### Description List my conversations (with peer info, last message, unread). ### Method GET ### Endpoint /im/conversations ``` -------------------------------- ### Package backend Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-address-book-ai-import.md Compile and package the backend skipping tests. ```bash mvn -q -DskipTests package ``` -------------------------------- ### Docker Compose Command Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/AGENTS.md Command to start the full CRM stack including WeKnora, PostgreSQL, Redis, and MinIO using docker-compose. ```bash docker-compose up -d ``` -------------------------------- ### Run IM Reaction Service Tests Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-22-im-phase3-threads-reactions-mentions.md Command to execute the reaction service tests. ```bash mvn -q test -Dtest=ImReactionServiceTest ``` -------------------------------- ### Run PendingEmployeeImportStoreTest Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-address-book-ai-import.md Command to execute the unit tests for the store implementation. ```bash mvn test -Dtest=PendingEmployeeImportStoreTest ``` -------------------------------- ### ImView Component Logic Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase1c-frontend.md Vue script setup for managing conversation state, message sending, file uploads, and lifecycle hooks for the ImView component. ```typescript const draft = ref('') const openContacts = ref(false) const contactKeyword = ref('') const scrollEl = ref(null) const activeMessages = computed(() => im.activeConversationId ? im.messagesByConv[im.activeConversationId] || [] : []) function previewOf(m?: ImMessage | null) { if (!m) return '' if (m.status === 'recalled') return '该消息已撤回' return m.contentType === 'text' ? (m.content || '') : '[附件]' } function canRecall(m: ImMessage) { return Date.now() - new Date(m.createTime).getTime() < 2 * 60 * 1000 } async function onSend() { const text = draft.value.trim() if (!text || !im.activeConversationId) return draft.value = '' await im.send({ conversationId: im.activeConversationId, contentType: 'text', content: text }) } async function startChat(userId: string) { openContacts.value = false await im.openConversationWith(userId) } // Element Plus custom upload: upload to MinIO presigned, then send a message referencing it. async function doUpload(opt: { file: File }) { if (!im.activeConversationId) return const fd = new FormData() fd.append('file', opt.file) // Returns the stored object key + url; adapt to the FileController presigned-upload response shape. const res = await upload<{ objectKey: string; url?: string }>('/file/presigned-upload', fd) const isImage = opt.file.type.startsWith('image/') await im.send({ conversationId: im.activeConversationId, contentType: isImage ? 'image' : 'file', attachmentName: opt.file.name, attachmentPath: res.objectKey, attachmentSize: opt.file.size, attachmentMime: opt.file.type, }) } watch(activeMessages, async () => { await nextTick(); if (scrollEl.value) scrollEl.value.scrollTop = scrollEl.value.scrollHeight }, { deep: true }) onMounted(async () => { im.ensureNotificationPermission() im.connect() await im.refreshConversations() const peer = route.query.peer as string | undefined if (peer) await im.openConversationWith(peer) }) ``` -------------------------------- ### Add spring-boot-starter-websocket dependency Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase1b-websocket.md Add this dependency to the dependencies block in backend/pom.xml. ```xml org.springframework.boot spring-boot-starter-websocket ``` -------------------------------- ### Project Directory Structure Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/desktop/README.md The desktop client project layout, highlighting the Electron main process, build scripts, and resource folders. ```text desktop/ ├── electron/ │ ├── main.cjs # 主进程:内嵌反代 + 本地后端 spawn + 模式选择 + 托盘 │ ├── server.cjs # 静态伺服 + 反向代理(本地模式剥 /crmapi 前缀) │ ├── splash.html # 本地后端启动页 │ ├── prompt.html # 服务器地址设置弹窗 │ └── prompt-preload.cjs ├── scripts/ │ ├── sync-renderer.mjs # frontend/dist -> app/ │ ├── fetch-jre.mjs # 按系统/架构下载 Temurin 21 JRE -> resources/jre │ └── make-icon.mjs # 生成 build/icon.ico + icon.png ├── resources/ │ ├── backend/crm-desktop.jar # 后端 jar(git 忽略;mvn -Pdesktop 产出,见下) │ └── jre/ # 内置 JRE(git 忽略;fetch:jre 产出) ├── app/ # 打包进来的 SPA(git 忽略) └── package.json ``` -------------------------------- ### Implement Channel Service Methods Source: https://github.com/wukongopensource/wukong-aicrm/blob/main/docs/superpowers/plans/2026-06-21-im-phase2-channels.md Implement the channel creation, browsing, and joining logic within the ImConversationServiceImpl class. ```java @Override @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) public ImConversation createChannel(Long creatorId, String name, String description, String visibility, List memberIds) { String trimmed = StrUtil.trim(name); if (StrUtil.isBlank(trimmed)) { throw new BusinessException(SystemCodeEnum.SYSTEM_NO_VALID, "频道名称不能为空"); } String vis = "private".equalsIgnoreCase(StrUtil.trim(visibility)) ? "private" : "public"; ImConversation conv = new ImConversation(); conv.setType("channel"); conv.setName(trimmed); conv.setDescription(StrUtil.trim(description)); conv.setVisibility(vis); conv.setOwnerId(creatorId); Date now = new Date(); conv.setCreateTime(now); conv.setUpdateTime(now); save(conv); // creator + distinct members LinkedHashSet ids = new LinkedHashSet<>(); ids.add(creatorId); if (memberIds != null) { for (Long id : memberIds) { if (id != null) ids.add(id); } } for (Long uid : ids) { addMemberRow(conv.getId(), uid); } return conv; } @Override public List browsePublicChannels(Long userId, String keyword) { Set myConvIds = memberMapper.selectList(new LambdaQueryWrapper() .eq(ImConversationMember::getUserId, userId)).stream() .map(ImConversationMember::getConversationId).collect(java.util.stream.Collectors.toSet()); LambdaQueryWrapper w = new LambdaQueryWrapper() .eq(ImConversation::getType, "channel") .eq(ImConversation::getVisibility, "public") .orderByDesc(ImConversation::getUpdateTime); if (StrUtil.isNotBlank(keyword)) { w.like(ImConversation::getName, StrUtil.trim(keyword)); } List out = new ArrayList<>(); for (ImConversation c : list(w)) { if (myConvIds.contains(c.getId())) continue; out.add(toChannelVO(c)); } return out; } @Override @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) public void joinChannel(Long userId, Long channelId) { ImConversation conv = getById(channelId); if (conv == null || !"channel".equals(conv.getType())) { throw new BusinessException(SystemCodeEnum.SYSTEM_NO_VALID, "频道不存在"); } if (!"public".equals(conv.getVisibility())) { throw new BusinessException(SystemCodeEnum.SYSTEM_NO_VALID, "私有频道需被邀请加入"); } addMemberRow(channelId, userId); } ```