diff --git a/.cursor/rules/backend-architecture.mdc b/.cursor/rules/backend-architecture.mdc deleted file mode 100644 index 90ad60f100..0000000000 --- a/.cursor/rules/backend-architecture.mdc +++ /dev/null @@ -1,176 +0,0 @@ ---- -description: -globs: src/services/**/*,src/database/**/*,src/server/**/* -alwaysApply: false ---- - -# LobeChat 后端技术架构指南 - -本指南旨在阐述 LobeChat 项目的后端分层架构,重点介绍各核心目录的职责以及它们之间的协作方式。 - -## 目录结构映射 - -``` -src/ -├── server/ -│ ├── routers/ # tRPC API 路由定义 -│ └── services/ # 业务逻辑服务层 -│ └── */impls/ # 平台特定实现 -├── database/ -│ ├── models/ # 数据模型 (单表 CRUD) -│ ├── repositories/ # 仓库层 (复杂查询/聚合) -│ └── schemas/ # Drizzle ORM 表定义 -└── services/ # 客户端服务 (调用 tRPC 或直接访问 Model) -``` - -## 核心架构分层 - -LobeChat 的后端设计注重模块化、可测试性和灵活性,以适应不同的运行环境(如浏览器端 PGLite、服务端远程 PostgreSQL 以及 Electron 桌面应用)。 - -其主要分层如下: - -1. 客户端服务层 (`src/services`): - - 位于 src/services/。 - - 这是客户端业务逻辑的核心层,负责封装各种业务操作和数据处理逻辑。 - - 环境适配: 根据不同的运行环境,服务层会选择合适的数据访问方式: - - 本地数据库模式: 直接调用 `Model` 层进行数据操作,适用于浏览器 PGLite 和本地 Electron 应用。 - - 远程数据库模式: 通过 `tRPC` 客户端调用服务端 API,适用于需要云同步的场景。 - - 类型转换: 对于简单的数据类型转换,直接在此层进行类型断言,如 `this.pluginModel.query() as Promise` - - 每个服务模块通常包含 `client.ts`(本地模式)、`server.ts`(远程模式)和 `type.ts`(接口定义)文件,在实现时应该确保本地模式和远程模式业务逻辑实现一致,只是数据库不同。 - -2. API 接口层 (`TRPC`): - - 位于 src/server/routers/ - - 使用 `tRPC` 构建类型安全的 API。Router 根据运行时环境(如 Edge Functions, Node.js Lambda)进行组织。 - - 负责接收客户端请求,并将其路由到相应的 `Service` 层进行处理。 - - 新建 lambda 端点时可以参考 src/server/routers/lambda/\_template.ts - -3. 仓库层 (`Repositories`): - - 位于 src/database/repositories/。 - - 主要处理复杂的跨表查询和数据聚合逻辑,特别是当需要从多个 `Model` 获取数据并进行组合时。 - - 与 `Model` 层不同,`Repository` 层专注于复杂的业务查询场景,而不涉及简单的领域模型转换。 - - 当业务逻辑涉及多表关联、复杂的数据统计或需要事务处理时,会使用 `Repository` 层。 - - 如果数据操作简单(仅涉及单个 `Model`),则通常直接在 `src/services` 层调用 `Model` 并进行简单的类型断言。 - -4. 模型层 (`Models`): - - 位于 src/database/models/ (例如 src/database/models/plugin.ts 和 src/database/models/document.ts)。 - - 提供对数据库中各个表(由 src/database/schemas/ 中的 Drizzle ORM schema 定义)的基本 CRUD (创建、读取、更新、删除) 操作和简单的查询能力。 - - `Model` 类专注于单个数据表的直接操作,不涉及复杂的领域模型转换,这些转换通常在上层的 `src/services` 中通过类型断言完成。 - - model(例如 Topic) 层接口经常需要从对应的 schema 层导入 NewTopic 和 TopicItem - - 创建新的 model 时可以参考 src/database/models/\_template.ts - -5. 数据库 (`Database`): - - 客户端模式 (浏览器/PWA): 使用 PGLite (基于 WASM 的 PostgreSQL),数据存储在用户浏览器本地。 - - 服务端模式 (云部署): 使用远程 PostgreSQL 数据库。 - - Electron 桌面应用: - - Electron 客户端会启动一个本地 Node.js 服务。 - - 本地服务通过 `tRPC` 与 Electron 的渲染进程通信。 - - 数据库选择依赖于是否开启云同步功能: - - 云同步开启: 连接到远程 PostgreSQL 数据库。 - - 云同步关闭: 使用 PGLite (通过 Node.js 的 WASM 实现) 在本地存储数据。 - -## 数据流向说明 - -### 浏览器/PWA 模式 - -``` -UI (React) → Zustand action -> Client Service → Model Layer → PGLite (本地数据库) -``` - -### 服务端模式 - -``` -UI (React) → Zustand action → Client Service -> TRPC Client → TRPC Routers → Repositories/Models → Remote PostgreSQL -``` - -### Electron 桌面应用模式 - -``` -UI (Electron Renderer) → Zustand action → Client Service -> TRPC Client → 本地 Node.js 服务 → TRPC Routers → Repositories/Models → PGLite/Remote PostgreSQL (取决于云同步设置) -``` - -## 服务层 (Server Services) - -- 位于 src/server/services/。 -- 核心职责是封装独立的、可复用的业务逻辑单元。这些服务应易于测试。 -- 平台差异抽象: 一个关键特性是通过其内部的 `impls` 子目录(例如 src/server/services/file/impls 包含 s3.ts 和 local.ts)来抹平不同运行环境带来的差异(例如云端使用 S3 存储,桌面版使用本地文件系统)。这使得上层(如 `tRPC` routers)无需关心底层具体实现。 -- 目标是使 `tRPC` router 层的逻辑尽可能纯粹,专注于请求处理和业务流程编排。 -- 服务可能会调用 `Repository` 层或直接调用 `Model` 层进行数据持久化和检索,也可能调用其他服务。 - -## 最佳实践 (Best Practices) - -### 数据库操作封装原则 - -**连续的数据库操作应该封装到 Model 层** - -当业务逻辑涉及多个相关的数据库操作时,建议将这些操作封装到 Model 层中,而不是在上层(Service 或 Router 层)中进行多次数据库调用。 - -**优势:** - -- **代码复用**: Client DB 环境的 service 实现和 Server DB 的 lambda 层实现可以复用相同的 Model 方法 -- **事务一致性**: 相关的数据库操作可以在同一个方法中管理,便于维护数据一致性 -- **性能优化**: 减少数据库连接次数,提高查询效率 -- **职责清晰**: Model 层专注数据访问,上层专注业务协调 - -**示例:** - -```typescript -// ✅ 推荐:在 Model 层封装连续的数据库操作 -class GenerationBatchModel { - async delete(id: string): Promise<{ deletedBatch: BatchItem; thumbnailUrls: string[] }> { - // 1. 查询相关数据 - const batchWithGenerations = await this.db.query.generationBatches.findFirst({...}); - - // 2. 收集需要处理的数据 - const thumbnailUrls = [...]; - - // 3. 执行删除操作 - const [deletedBatch] = await this.db.delete(generationBatches)...; - - return { deletedBatch, thumbnailUrls }; - } -} - -// ✅ 上层使用简洁 -const { thumbnailUrls } = await model.delete(id); -await fileService.deleteFiles(thumbnailUrls); -``` - -### 文件操作与数据库操作的执行顺序 - -**删除操作原则:数据库删除在前,文件删除在后** - -当业务逻辑同时涉及数据库记录和文件系统操作时,应该遵循"数据库优先"的原则。 - -**原因:** - -- **用户体验优先**: 如果先删除文件再删除数据库记录,可能出现文件已删除但数据库记录仍存在的情况,用户访问时会遇到文件不存在的错误 -- **影响程度较小**: 如果先删除数据库记录再删除文件,即使文件删除失败,用户也看不到这个记录,只是造成一些存储空间浪费,对用户体验影响更小 -- **数据一致性**: 数据库记录是业务逻辑的核心,应该优先保证其一致性 - -**示例:** - -```typescript -// ✅ 推荐:先删除数据库记录,再删除文件 -async deleteGeneration(id: string) { - // 1. 先删除数据库记录 - const deletedGeneration = await generationModel.delete(id); - - // 2. 再删除相关文件 - if (deletedGeneration.asset?.thumbnailUrl) { - await fileService.deleteFile(deletedGeneration.asset.thumbnailUrl); - } -} - -// ❌ 不推荐:先删除文件 -async deleteGeneration(id: string) { - const generation = await generationModel.findById(id); - - // 如果这里删除成功,但后面数据库删除失败,用户会遇到访问错误 - await fileService.deleteFile(generation.asset.thumbnailUrl); - await generationModel.delete(id); // 可能失败 -} -``` - -**创建操作原则:数据库创建在前,文件操作在后** - -创建操作同样应该优先处理数据库记录,确保数据的一致性和完整性。 diff --git a/.cursor/rules/code-review.mdc b/.cursor/rules/code-review.mdc deleted file mode 100644 index 24cb027378..0000000000 --- a/.cursor/rules/code-review.mdc +++ /dev/null @@ -1,58 +0,0 @@ ---- -description: How to code review -globs: -alwaysApply: false ---- - -# Role Description - -- You are a senior full-stack engineer skilled in performance optimization, security, and design systems. -- You excel at reviewing code and providing constructive feedback. -- Your task is to review submitted Git diffs **in Chinese** and return a structured review report. -- Review style: concise, direct, focused on what matters most, with actionable suggestions. - -## Before the Review - -Gather the modified code and context. Please strictly follow the process below: - -1. Use `read_file` to read [package.json](mdc:package.json) -2. Use terminal to run command `git diff HEAD | cat` to obtain the diff and list the changed files. If you recieived empty result, run the same command once more. -3. Use `read_file` to open each changed file. -4. Use `read_file` to read [rules-attach.mdc](mdc:.cursor/rules/rules-attach.mdc). Even if you think it's unnecessary, you must read it. -5. combine changed files, step3 and `agent_requestable_workspace_rules`, list the rules which need to read -6. Use `read_file` to read the rules list in step 5 - -## Review - -### Code Style - -read [typescript.mdc](mdc:.cursor/rules/typescript.mdc) for the consolidated project code style and optimization rules. - -### Code Optimization - -The optimization checklist has been consolidated into [typescript.mdc](mdc:.cursor/rules/typescript.mdc): loops, debouncing/throttling, design system components, theming tokens, concurrency with `Promise.*`, minimal DB column selection, and package reuse. - -### Obvious Bugs - -- Do not silently swallow errors in `catch` blocks; at minimum, log them. -- Revert temporary code used only for testing (e.g., debug logs, temporary configs). -- Remove empty handlers (e.g., an empty `onClick`). -- Confirm the UI degrades gracefully for unauthenticated users. -- Don't leave any debug logs in the code (except when using the `debug` module properly). - - When using the `debug` module, avoid `import { log } from 'debug'` as it logs directly to console. Use proper debug namespaces instead. -- Check logs for sensitive information like api key, etc - -## After the Review: output - -1. Summary - - Start with a brief explanation of what the change set does. - - Summarize the changes for each modified file (or logical group). -2. Comments Issues - - List the most critical issues first. - - Use an ordered list, which will be convenient for me to reference later. - - For each issue: - - Mark severity tag (`❌ Must fix`, `⚠️ Should fix`, `💅 Nitpick`) - - Provode file path to the relevant file. - - Provide recommended fix - - End with a **git commit** command, instruct the author to run it. - - We use gitmoji to label commit messages, format: [emoji] (): diff --git a/.cursor/rules/cursor-ux.mdc b/.cursor/rules/cursor-ux.mdc deleted file mode 100644 index 2de2c535e9..0000000000 --- a/.cursor/rules/cursor-ux.mdc +++ /dev/null @@ -1,32 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- - -# Guide to Optimize Output(Response) Rendering - -## File Path and Code Symbol Rendering - -- When rendering file paths, use backtick wrapping instead of markdown links so they can be parsed as clickable links in Cursor IDE. - - Good: `src/components/Button.tsx` - - Bad: [src/components/Button.tsx](src/components/Button.tsx) - -- Don't use line and column number in file path, this will make file path not clickable in Cursor IDE. - - Good: `src/components/Button.tsx` `10:20` (add a space between the file path and the line and column number) - - Bad: `src/components/Button.tsx:10:20` - -- When rendering functions, variables, or other code symbols, use backtick wrapping so they can be parsed as navigable links in Cursor IDE - - Good: The `useState` hook in `MyComponent` - - Bad: The useState hook in MyComponent - -## Markdown Render - -- don't use br tag to wrap in table cell - -## Terminal Command Output - -- If terminal commands don't produce output, it's likely due to paging issues. Try piping the command to `cat` to ensure full output is displayed. - - Good: `git show commit_hash -- file.txt | cat` - - Good: `git log --oneline | cat` - - Reason: Some git commands use pagers by default, which may prevent output from being captured properly diff --git a/.cursor/rules/define-database-model.mdc b/.cursor/rules/define-database-model.mdc deleted file mode 100644 index 79da8332d7..0000000000 --- a/.cursor/rules/define-database-model.mdc +++ /dev/null @@ -1,8 +0,0 @@ ---- -description: -globs: src/database/models/**/* -alwaysApply: false ---- -1. first read [lobe-chat-backend-architecture.mdc](mdc:.cursor/rules/lobe-chat-backend-architecture.mdc) -2. refer to the [_template.ts](mdc:src/database/models/_template.ts) to create new model -3. if an operation involves multiple models or complex queries, consider defining it in the `repositories` layer under `src/database/repositories/` diff --git a/.cursor/rules/project-introduce.mdc b/.cursor/rules/project-introduce.mdc index c4f4a7fe3d..ce9bde6bc8 100644 --- a/.cursor/rules/project-introduce.mdc +++ b/.cursor/rules/project-introduce.mdc @@ -4,41 +4,35 @@ alwaysApply: true ## Project Description -You are developing an open-source, modern-design AI chat framework: lobe chat. +You are developing an open-source, modern-design AI chat framework: lobehub(previous lobe-chat). -Emoji logo: 🤯 +support platforms: + +- web desktop/mobile +- desktop(electron) +- mobile app(react native). coming soon + +logo emoji: 🤯 ## Project Technologies Stack read [package.json](mdc:package.json) to know all npm packages you can use. -The project uses the following technologies: - -- pnpm as package manager -- Next.js 15 for frontend and backend, using app router instead of pages router -- react 19, using hooks, functional components, react server components -- TypeScript programming language -- antd, `@lobehub/ui` for component framework +- Next.js 15 +- react 19 +- TypeScript +- `@lobehub/ui`, antd for component framework - antd-style for css-in-js framework -- react-layout-kit for flex layout -- react-i18next for i18n - lucide-react, `@ant-design/icons` for icons -- `@lobehub/icons` for AI provider/model logo icon -- `@formkit/auto-animate` for react list animation -- zustand for global state management -- nuqs for type-safe search params state manager -- SWR for react data fetch +- react-layout-kit for flex layout component +- react-i18next for i18n +- zustand for state management +- nuqs for search params management +- SWR for data fetch - aHooks for react hooks library -- dayjs for date and time library +- dayjs for time library - lodash-es for utility library -- fast-deep-equal for deep comparison of JavaScript objects -- zod for data validation - TRPC for type safe backend - PGLite for client DB and PostgreSQL for backend DB - Drizzle ORM -- Vitest for testing, testing-library for react component test -- Prettier for code formatting -- ESLint for code linting -- Cursor AI for code editing and AI coding assistance - -Note: All tools and libraries used are the latest versions. The application only needs to be compatible with the latest browsers; +- Vitest for testing diff --git a/.cursor/rules/project-structure.mdc b/.cursor/rules/project-structure.mdc index 534fd50264..801496c990 100644 --- a/.cursor/rules/project-structure.mdc +++ b/.cursor/rules/project-structure.mdc @@ -5,235 +5,116 @@ alwaysApply: false # LobeChat Project Structure -## Directory Structure +note: some not very important files are not shown for simplicity. -note: some files are not shown for simplicity. +## Complete Project Structure + +this project use common monorepo structure. The workspace packages name use `@lobechat/` namespace. ```plaintext lobe-chat/ -├── apps/ # Applications directory -│ └── desktop/ # Electron desktop application -│ ├── src/ # Desktop app source code -│ └── resources/ # Desktop app resources -├── docs/ # Project documentation -│ ├── development/ # Development docs -│ ├── self-hosting/ # Self-hosting docs -│ └── usage/ # Usage guides -├── locales/ # Internationalization files (multiple locales) -│ ├── en-US/ # English (example) -│ └── zh-CN/ # Simplified Chinese (example) -├── packages/ # Monorepo packages directory -│ ├── const/ # Constants definition package -│ ├── database/ # Database related package -│ ├── electron-client-ipc/ # Electron renderer ↔ main IPC client -│ ├── electron-server-ipc/ # Electron main process IPC server -│ ├── model-bank/ # Built-in model presets/catalog exports -│ ├── model-runtime/ # AI model runtime package -│ ├── types/ # TypeScript type definitions -│ ├── utils/ # Utility functions package -│ ├── file-loaders/ # File processing packages -│ ├── prompts/ # AI prompt management -│ └── web-crawler/ # Web crawling functionality -├── public/ # Static assets -│ ├── icons/ # Application icons -│ ├── images/ # Image resources -│ └── screenshots/ # Application screenshots -├── scripts/ # Build and tool scripts -├── src/ # Main application source code (see below) -├── .cursor/ # Cursor AI configuration -├── docker-compose/ # Docker configuration -├── package.json # Project dependencies -├── pnpm-workspace.yaml # pnpm monorepo configuration -├── next.config.ts # Next.js configuration -├── drizzle.config.ts # Drizzle ORM configuration -└── tsconfig.json # TypeScript configuration -``` - -## Core Source Directory (`src/`) - -```plaintext -src/ -├── app/ # Next.js App Router routes -│ ├── (backend)/ # Backend API routes -│ │ ├── api/ # REST API endpoints -│ │ │ ├── auth/ # Authentication endpoints -│ │ │ └── webhooks/ # Webhook handlers for various auth providers -│ │ ├── middleware/ # Request middleware -│ │ ├── oidc/ # OpenID Connect endpoints -│ │ ├── trpc/ # tRPC API routes -│ │ │ ├── async/ # Async tRPC endpoints -│ │ │ ├── desktop/ # Desktop runtime endpoints -│ │ │ ├── edge/ # Edge runtime endpoints -│ │ │ ├── lambda/ # Lambda runtime endpoints -│ │ │ └── tools/ # Tools-specific endpoints -│ │ └── webapi/ # Web API endpoints -│ │ ├── chat/ # Chat-related APIs for various providers -│ │ ├── models/ # Model management APIs -│ │ ├── plugin/ # Plugin system APIs -│ │ ├── stt/ # Speech-to-text APIs -│ │ ├── text-to-image/ # Image generation APIs -│ │ └── tts/ # Text-to-speech APIs -│ ├── [variants]/ # Page route variants -│ │ ├── (main)/ # Main application routes -│ │ │ ├── chat/ # Chat interface and workspace -│ │ │ ├── discover/ # Discover page (assistants, models, providers) -│ │ │ ├── files/ # File management interface -│ │ │ ├── image/ # Image generation interface -│ │ │ ├── profile/ # User profile and stats -│ │ │ ├── repos/ # Knowledge base repositories -│ │ │ └── settings/ # Application settings -│ │ └── @modal/ # Modal routes -│ └── manifest.ts # PWA configuration -├── components/ # Global shared components -│ ├── Analytics/ # Analytics tracking components -│ ├── Error/ # Error handling components -│ └── Loading/ # Loading state components -├── config/ # Application configuration -│ ├── featureFlags/ # Feature flags & experiments -│ └── modelProviders/ # Model provider configurations -├── features/ # Feature components (UI Layer) -│ ├── AgentSetting/ # Agent configuration and management -│ ├── ChatInput/ # Chat input with file upload and tools -│ ├── Conversation/ # Message display and interaction -│ ├── FileManager/ # File upload and knowledge base -│ └── PluginStore/ # Plugin marketplace and management -├── hooks/ # Custom React hooks -├── layout/ # Global layout components -│ ├── AuthProvider/ # Authentication provider -│ └── GlobalProvider/ # Global state provider -├── libs/ # External library integrations -│ ├── analytics/ # Analytics services integration -│ ├── next-auth/ # NextAuth.js configuration -│ └── oidc-provider/ # OIDC provider implementation -├── locales/ # Internationalization resources -│ └── default/ # Default language definitions -├── migrations/ # Client-side data migrations -├── server/ # Server-side code -│ ├── modules/ # Server modules -│ ├── routers/ # tRPC routers -│ └── services/ # Server services -├── services/ # Service layer (per-domain, client/server split) -│ ├── user/ # User services -│ │ ├── client.ts # Client DB (PGLite) implementation -│ │ └── server.ts # Server DB implementation (via tRPC) -│ ├── aiModel/ # AI model services -│ ├── session/ # Session services -│ └── message/ # Message services -├── store/ # Zustand state management -│ ├── agent/ # Agent state -│ ├── chat/ # Chat state -│ └── user/ # User state -├── styles/ # Global styles -├── tools/ # Built-in tool system -│ ├── artifacts/ # Code artifacts and preview -│ └── web-browsing/ # Web search and browsing -├── types/ # TypeScript type definitions -└── utils/ # Utility functions - ├── client/ # Client-side utilities - └── server/ # Server-side utilities -``` - -## Key Monorepo Packages - -```plaintext -packages/ -├── const/ # Global constants and configurations -├── database/ # Database schemas and models -│ ├── src/models/ # Data models (CRUD operations) -│ ├── src/schemas/ # Drizzle database schemas -│ ├── src/repositories/ # Complex query layer -│ └── migrations/ # Database migration files -├── model-runtime/ # AI model runtime -│ └── src/ -│ ├── openai/ # OpenAI provider integration -│ ├── anthropic/ # Anthropic provider integration -│ ├── google/ # Google AI provider integration -│ ├── ollama/ # Ollama local model integration -│ ├── types/ # Runtime type definitions -│ └── utils/ # Runtime utilities -├── types/ # Shared TypeScript type definitions -│ └── src/ -│ ├── agent/ # Agent-related types -│ ├── message/ # Message and chat types -│ ├── user/ # User and session types -│ └── tool/ # Tool and plugin types -├── utils/ # Shared utility functions -│ └── src/ -│ ├── client/ # Client-side utilities -│ ├── server/ # Server-side utilities -│ ├── fetch/ # HTTP request utilities -│ └── tokenizer/ # Token counting utilities -├── file-loaders/ # File loaders (PDF, DOCX, etc.) -├── prompts/ # AI prompt management -└── web-crawler/ # Web crawling functionality +├── apps/ +│ └── desktop/ +├── docs/ +├── locales/ +│ ├── en-US/ +│ └── zh-CN/ +├── packages/ +│ ├── const/ +│ ├── context-engine/ +│ ├── database/ +│ │ ├── src/ +│ │ │ ├── models/ +│ │ │ ├── schemas/ +│ │ │ └── repositories/ +│ ├── model-bank/ +│ ├── model-runtime/ +│ │ └── src/ +│ │ ├── openai/ +│ │ └── anthropic/ +│ ├── types/ +│ │ └── src/ +│ │ ├── message/ +│ │ └── user/ +│ └── utils/ +├── public/ +├── scripts/ +├── src/ +│ ├── app/ +│ │ ├── (backend)/ +│ │ │ ├── api/ +│ │ │ │ ├── auth/ +│ │ │ │ └── webhooks/ +│ │ │ ├── middleware/ +│ │ │ ├── oidc/ +│ │ │ ├── trpc/ +│ │ │ └── webapi/ +│ │ │ ├── chat/ +│ │ │ └── tts/ +│ │ ├── [variants]/ +│ │ │ ├── (main)/ +│ │ │ │ ├── chat/ +│ │ │ │ └── settings/ +│ │ │ └── @modal/ +│ │ └── manifest.ts +│ ├── components/ +│ ├── config/ +│ ├── features/ +│ │ └── ChatInput/ +│ ├── hooks/ +│ ├── layout/ +│ │ ├── AuthProvider/ +│ │ └── GlobalProvider/ +│ ├── libs/ +│ │ └── oidc-provider/ +│ ├── locales/ +│ │ └── default/ +│ ├── server/ +│ │ ├── modules/ +│ │ ├── routers/ +│ │ │ ├── async/ +│ │ │ ├── desktop/ +│ │ │ ├── edge/ +│ │ │ └── lambda/ +│ │ └── services/ +│ ├── services/ +│ │ ├── user/ +│ │ │ ├── client.ts +│ │ │ └── server.ts +│ │ └── message/ +│ ├── store/ +│ │ ├── agent/ +│ │ ├── chat/ +│ │ └── user/ +│ ├── styles/ +│ └── utils/ +└── package.json ``` ## Architecture Map -- Presentation: `src/features`, `src/components`, `src/layout` — UI composition, global providers -- State: `src/store` — Zustand slices, selectors, middleware -- Client Services: `src/services//{client|server}.ts` — client: PGLite; server: tRPC bridge -- API Routers: `src/app/(backend)/webapi` (REST), `src/app/(backend)/trpc/{edge|lambda|async|desktop|tools}`; Lambda router triggers Async router for long-running tasks (e.g., image) -- Server Services: `src/server/services` (business logic), `src/server/modules` (infra adapters) -- Data Access: `packages/database/src/{schemas,models,repositories}` — Schema (Drizzle), Model (CRUD), Repository (complex queries) -- Integrations: `src/libs` — analytics, auth, trpc, logging, runtime helpers +- UI Components: `src/components`, `src/features` +- Global providers: `src/layout` +- Zustand stores: `src/store` +- Client Services: `src/services/` + - clientDB: `src/services//client.ts` + - serverDB: `src/services//server.ts` +- API Routers: + - `src/app/(backend)/webapi` (REST) + - `src/server/routers/{edge|lambda|async|desktop|tools}` (tRPC) +- Server: + - Services(can access serverDB): `src/server/services` + - Modules(can't access db): `src/server/modules` (Server only Third-party Service Module) +- Database: + - Schema (Drizzle): `packages/database/src/schemas` + - Model (CRUD): `packages/database/src/models` + - Repository (bff-queries): `packages/database/src/repositories` +- Third-party Integrations: `src/libs` — analytics, oidc etc. ## Data Flow Architecture -### Unified Flow Pattern - -``` -UI Layer → State Management → Client Service → [Environment Branch] → Database - ↓ ↓ ↓ ↓ ↓ - React Zustand Environment Local/Remote PGLite/ -Components Store Adaptation Routing PostgreSQL -``` - -### Environment-Specific Routing - -| Mode | UI | Service Route | Database | -| --------------- | -------- | ---------------------- | ------------------- | -| **Browser/PWA** | React | Direct Model Access | PGLite (Local) | -| **Server** | React | tRPC → Server Services | PostgreSQL (Remote) | -| **Desktop** | Electron | tRPC → Local Node.js | PGLite/PostgreSQL\* | - -_\*Depends on cloud sync configuration_ - -### Key Characteristics - -- **Type Safety**: End-to-end type safety via tRPC and Drizzle ORM -- **Local/Remote Dual Mode**: PGLite enables user data ownership and local control - -## Quick Map - -- App Routes: `src/app` — UI routes (App Router) and backend routes under `(backend)` -- Web API: `src/app/(backend)/webapi` — REST-like endpoints -- tRPC Routers: `src/server/routers` — typed RPC endpoints by runtime -- Client Services: `src/services` — environment-adaptive client-side business logic -- Server Services: `src/server/services` — platform-agnostic business logic -- Database: `packages/database` — schemas/models/repositories/migrations -- State: `src/store` — Zustand stores and slices -- Integrations: `src/libs` — analytics/auth/trpc/logging/runtime helpers -- Tools: `src/tools` — built-in tool system - -## Common Tasks - -- Add Web API route: `src/app/(backend)/webapi//route.ts` -- Add tRPC endpoint: `src/server/routers/{edge|lambda|desktop}/...` -- Add client/server service: `src/services//{client|server}.ts` (client: PGLite; server: tRPC) -- Add server service: `src/server/services/` -- Add a new model/provider: `src/config/modelProviders/.ts` + `packages/model-bank/src/aiModels/.ts` + `packages/model-runtime/src//index.ts` -- Add DB schema/model/repository: `packages/database/src/{schemas|models|repositories}` -- Add Zustand slice: `src/store//slices` - -## Env Modes - -- `NEXT_PUBLIC_CLIENT_DB`: selects client DB mode (e.g., `pglite`) vs server-backed -- `NEXT_PUBLIC_IS_DESKTOP_APP`: enables desktop-specific routes and behavior -- `NEXT_PUBLIC_SERVICE_MODE`: controls service routing preference (client/server) - -## Boundaries - -- Keep client logic in `src/services`; server-only logic stays in `src/server/services` -- Don’t mix Web API (`webapi/`) with tRPC (`src/server/routers/`) -- Place business UI under `src/features`, global reusable UI under `src/components` +- **Browser/PWA**: React UI → Client Service → Direct Model Access → PGLite (Web WASM) +- **Server**: React UI → Client Service → tRPC Lambda → Server Services → PostgreSQL (Remote) +- **Desktop**: + - Cloud sync disabled: Electron UI → Client Service → tRPC Lambda → Local Server Services → PGLite (Node WASM) + - Cloud sync enabled: Electron UI → Client Service → tRPC Lambda → Cloud Server Services → PostgreSQL (Remote) diff --git a/.cursor/rules/rules-attach.mdc b/.cursor/rules/rules-index.mdc similarity index 72% rename from .cursor/rules/rules-attach.mdc rename to .cursor/rules/rules-index.mdc index 0850e5d392..a6e6bf0108 100644 --- a/.cursor/rules/rules-attach.mdc +++ b/.cursor/rules/rules-index.mdc @@ -4,20 +4,12 @@ globs: alwaysApply: true --- -# 📋 Available Rules Index +# Available project rules index -The following rules are available via `read_file` from the `.cursor/rules/` directory: - -## General - -- `project-introduce.mdc` – Project description and tech stack -- `cursor-rules.mdc` – Cursor rules authoring and optimization guide -- `code-review.mdc` – How to code review +All following rules are saved under `.cursor/rules/` directory: ## Backend -- `backend-architecture.mdc` – Backend layer architecture and design guidelines -- `define-database-model.mdc` – Database model definition guidelines - `drizzle-schema-style-guide.mdc` – Style guide for defining Drizzle ORM schemas ## Frontend @@ -42,7 +34,6 @@ The following rules are available via `read_file` from the `.cursor/rules/` dire ## Debugging -- `debug.mdc` – General debugging guide - `debug-usage.mdc` – Using the debug package and namespace conventions ## Testing diff --git a/.cursor/rules/system-role.mdc b/.cursor/rules/system-role.mdc deleted file mode 100644 index 636e11c8f3..0000000000 --- a/.cursor/rules/system-role.mdc +++ /dev/null @@ -1,31 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- - -## System Role - -You are an expert in full-stack Web development, proficient in JavaScript, TypeScript, CSS, React, Node.js, Next.js, Postgresql, Redis, S3, all kinds of network protocols. - -You are an LLM expert, you are familiar with all kinds of LLM models, ai agents, ai workflow, prompt engineering and context engineering. - -You are an expert in Ai art. In Ai image generation, you are proficient in Stable Diffusion and ComfyUI's architectural principles, workflows, model structures, parameter configurations, training methods, and inference optimization. - -You are an expert in UI/UX design, proficient in web interaction patterns, responsive design, accessibility, and user behavior optimization. You excel at improving user retention and paid conversion rates through various interaction details. - -## Problem Solving - -- When modifying existing code, clearly describe the differences and reasons for the changes -- Provide alternative solutions that may be better overall or superior in specific aspects -- Provide optimization suggestions for deprecated API usage -- Cite sources whenever possible at the end, not inline -- When you provide multiple solutions, provide the recommended solution first, and note it as `Recommended` -- Express uncertainty when there might not be a correct answer, instead of take action by guessing and assuming - -## Code Implementation - -- Focus on maintainable over being performant -- Be sure to reference file path -- If doc links or required files are missing, ask for them before proceeding with the task rather than making assumptions -- If you're unable to get valid result when using tools, please clearly state in the output diff --git a/.cursor/rules/typescript.mdc b/.cursor/rules/typescript.mdc index afe73ddfd6..5f8037e6aa 100644 --- a/.cursor/rules/typescript.mdc +++ b/.cursor/rules/typescript.mdc @@ -10,61 +10,11 @@ alwaysApply: false - avoid explicit type annotations when TypeScript can infer types. - avoid implicitly `any` variables; explicitly type when necessary (e.g., `let a: number` instead of `let a`). -- use the most accurate type possible (e.g., prefer `Record` over `object`). +- use the most accurate type possible (e.g., prefer `Record` over `object` and `any`). - prefer `interface` over `type` for object shapes (e.g., React component props). Keep `type` for unions, intersections, and utility types. - prefer `as const satisfies XyzInterface` over plain `as const` when suitable. -- prefer `@ts-expect-error` over `@ts-ignore` -- prefer `Record` over `any` - -- **Avoid unnecessary null checks**: Before adding `xxx !== null`, `?.`, `??`, or `!.`, read the type definition to confirm the necessary. **Example:** - - ```typescript - // ❌ Wrong: budget.spend and budget.maxBudget is number, not number | null - if (budget.spend !== null && budget.maxBudget !== null && budget.spend >= budget.maxBudget) { - // ... - } - - // ✅ Right - if (budget.spend >= budget.maxBudget) { - // ... - } - ``` - -- **Avoid redundant runtime checks**: Don't add runtime validation for conditions already guaranteed by types or previous checks. Trust the type system and calling contract. **Example:** - - ```typescript - // ❌ Wrong: Adding impossible-to-fail checks - const due = await db.query.budgets.findMany({ - where: and(isNotNull(budgets.budgetDuration)), // Already filtered non-null - }); - const result = due.map(b => { - const nextReset = computeNextResetAt(b.budgetResetAt!, b.budgetDuration!); - if (!nextReset) { // This check is impossible to fail - throw new Error(`Unexpected null nextResetAt`); - } - return nextReset; - }); - - // ✅ Right: Trust the contract - const due = await db.query.budgets.findMany({ - where: and(isNotNull(budgets.budgetDuration)), - }); - const result = due.map(b => computeNextResetAt(b.budgetResetAt!, b.budgetDuration!)); - ``` - -- **Avoid meaningless null/undefined parameters**: Don't accept null/undefined for parameters that have no business meaning when null. Design strict function contracts. **Example:** - - ```typescript - // ❌ Wrong: Function accepts meaningless null input - function computeNextResetAt(currentResetAt: Date, durationStr: string | null): Date | null { - if (!durationStr) return null; // Why accept null if it just returns null? - } - - // ✅ Right: Strict contract, clear responsibility - function computeNextResetAt(currentResetAt: Date, durationStr: string): Date { - // Function has single clear purpose, caller ensures valid input - } - ``` +- prefer `@ts-expect-error` over `@ts-ignore` over `as any` +- Avoid meaningless null/undefined parameters; design strict function contracts. ## Imports and Modules diff --git a/.vscode/settings.json b/.vscode/settings.json index 974498a9c7..fe66f84d76 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,7 @@ { "rule": "prettier/prettier", "severity": "off" }, { "rule": "react/jsx-sort-props", "severity": "off" }, { "rule": "sort-keys-fix/sort-keys-fix", "severity": "off" }, + { "rule": "simple-import-sort/exports", "severity": "off" }, { "rule": "typescript-sort-keys/interface", "severity": "off" } ], "eslint.validate": [ @@ -81,7 +82,7 @@ "**/src/config/modelProviders/*.ts": "${filename} • provider", "**/packages/model-bank/src/aiModels/*.ts": "${filename} • model", - "**/packages/model-runtime/src/*/index.ts": "${dirname} • runtime", + "**/packages/model-runtime/src/providers/*/index.ts": "${dirname} • runtime", "**/src/server/services/*/index.ts": "${dirname} • server/service", "**/src/server/routers/lambda/*.ts": "${filename} • lambda", diff --git a/AGENTS.md b/AGENTS.md index 07018a6e71..82e88a4609 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,21 +44,7 @@ The project follows a well-organized monorepo structure: #### TypeScript -- Follow strict TypeScript practices for type safety and code quality -- Use proper type annotations - Prefer interfaces over types for object shapes -- Use generics for reusable components - -#### React Components - -- Use functional components with hooks - -#### Database Schema - -- Follow Drizzle ORM naming conventions -- Use plural snake_case for table names -- Implement proper foreign key relationships -- Follow the schema style guide ### Testing Strategy @@ -67,64 +53,57 @@ The project follows a well-organized monorepo structure: **Commands**: - Web: `bunx vitest run --silent='passed-only' '[file-path-pattern]'` -- Packages: `cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path-pattern]'` +- Packages: `cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path-pattern]'` (each subpackage contains its own vitest.config.mts) **Important Notes**: - Wrap file paths in single quotes to avoid shell expansion -- Never run `bun run test` - this runs all tests and takes ~10 minutes -- If a test fails twice, stop and ask for help -- Always add tests for new code +- Never run `bun run test` - this runs all tests and takes \~10 minutes ### Type Checking - Use `bun run type-check` to check for type errors -- Ensure all TypeScript errors are resolved before committing -### Internationalization +### i18n -- Add new keys to `src/locales/default/namespace.ts` -- Translate at least `zh-CN` files for development preview -- Use hierarchical nested objects, not flat keys -- Don't run `pnpm i18n` manually (handled by CI) +- **Keys**: Add to `src/locales/default/namespace.ts` +- **Dev**: Translate `locales/zh-CN/namespace.json` locale file only for preview +- DON'T run `pnpm i18n`, let CI auto handle it -## Available Development Rules +## Project Rules Index -The project provides comprehensive rules in `.cursor/rules/` directory: +All following rules are saved under `.cursor/rules/` directory: -### Core Development +### Backend -- `backend-architecture.mdc` - Three-layer architecture and data flow -- `react-component.mdc` - Component patterns and UI library usage -- `drizzle-schema-style-guide.mdc` - Database schema conventions -- `define-database-model.mdc` - Model templates and CRUD patterns -- `i18n.mdc` - Internationalization workflow +- `drizzle-schema-style-guide.mdc` – Style guide for defining Drizzle ORM schemas -### State Management & UI +### Frontend -- `zustand-slice-organization.mdc` - Store organization patterns -- `zustand-action-patterns.mdc` - Action implementation patterns -- `packages/react-layout-kit.mdc` - Flex layout component usage +- `react-component.mdc` – React component style guide and conventions +- `i18n.mdc` – Internationalization guide using react-i18next +- `typescript.mdc` – TypeScript code style guide +- `packages/react-layout-kit.mdc` – Usage guide for react-layout-kit -### Testing & Quality +### State Management -- `testing-guide/testing-guide.mdc` - Comprehensive testing strategy -- `code-review.mdc` - Code review process and standards +- `zustand-action-patterns.mdc` – Recommended patterns for organizing Zustand actions +- `zustand-slice-organization.mdc` – Best practices for structuring Zustand slices ### Desktop (Electron) -- `desktop-feature-implementation.mdc` - Main/renderer process patterns -- `desktop-local-tools-implement.mdc` - Tool integration workflow -- `desktop-menu-configuration.mdc` - Menu system configuration -- `desktop-window-management.mdc` - Window management patterns -- `desktop-controller-tests.mdc` - Controller testing guide +- `desktop-feature-implementation.mdc` – Implementing new Electron desktop features +- `desktop-controller-tests.mdc` – Desktop controller unit testing guide +- `desktop-local-tools-implement.mdc` – Workflow to add new desktop local tools +- `desktop-menu-configuration.mdc` – Desktop menu configuration guide +- `desktop-window-management.mdc` – Desktop window management guide -## Best Practices +### Debugging -- **Conservative for existing code, modern approaches for new features** -- **Code Language**: Use Chinese for files with existing Chinese comments, American English for new files -- Always add tests for new functionality -- Follow the established patterns in the codebase -- Use proper error handling and logging -- Implement proper accessibility features -- Consider internationalization from the start +- `debug-usage.mdc` – Using the debug package and namespace conventions + +### Testing + +- `testing-guide/testing-guide.mdc` – Comprehensive testing guide for Vitest +- `testing-guide/electron-ipc-test.mdc` – Electron IPC interface testing strategy +- `testing-guide/db-model-test.mdc` – Database Model testing guide diff --git a/CLAUDE.md b/CLAUDE.md index 8447e20956..5af69f2029 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -72,29 +72,4 @@ Some useful rules of this project. Read them when needed. ### 📋 Complete Rule Files -**Core Development** - -- `backend-architecture.mdc` - Three-layer architecture, data flow -- `react-component.mdc` - antd-style, Lobe UI usage -- `drizzle-schema-style-guide.mdc` - Schema naming, patterns -- `define-database-model.mdc` - Model templates, CRUD patterns -- `i18n.mdc` - Internationalization workflow - -**State & UI** - -- `zustand-slice-organization.mdc` - Store organization -- `zustand-action-patterns.mdc` - Action patterns -- `packages/react-layout-kit.mdc` - flex layout components usage - -**Testing & Quality** - -- `testing-guide/testing-guide.mdc` - Test strategy, mock patterns -- `code-review.mdc` - Review process and standards - -**Desktop (Electron)** - -- `desktop-feature-implementation.mdc` - Main/renderer process patterns -- `desktop-local-tools-implement.mdc` - Tool integration workflow -- `desktop-menu-configuration.mdc` - App menu, context menu, tray menu -- `desktop-window-management.mdc` - Window creation, state management, multi-window -- `desktop-controller-tests.mdc` - Controller unit testing guide +Some useful project rules are listed in @.cursor/rules/rules-index.mdc