@lobehub/lobehub 2.0.0-next.173 → 2.0.0-next.175

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/.cursor/rules/db-migrations.mdc +10 -4
  2. package/.cursor/rules/drizzle-schema-style-guide.mdc +33 -17
  3. package/.cursor/rules/hotkey.mdc +161 -0
  4. package/.cursor/rules/i18n.mdc +2 -5
  5. package/.cursor/rules/project-introduce.mdc +3 -2
  6. package/.cursor/rules/project-structure.mdc +33 -37
  7. package/.cursor/rules/react.mdc +155 -0
  8. package/.cursor/rules/recent-data-usage.mdc +138 -0
  9. package/.cursor/rules/rules-index.mdc +1 -1
  10. package/.cursor/rules/testing-guide/agent-runtime-e2e.mdc +285 -0
  11. package/.cursor/rules/testing-guide/zustand-store-action-test.mdc +11 -16
  12. package/.cursor/rules/typescript.mdc +0 -4
  13. package/.cursor/rules/zustand-action-patterns.mdc +137 -169
  14. package/.cursor/rules/zustand-slice-organization.mdc +16 -8
  15. package/.husky/pre-commit +1 -1
  16. package/.i18nrc.js +3 -1
  17. package/AGENTS.md +3 -2
  18. package/CHANGELOG.md +42 -0
  19. package/CLAUDE.md +10 -3
  20. package/GEMINI.md +2 -1
  21. package/README.md +9 -9
  22. package/README.zh-CN.md +12 -12
  23. package/changelog/v1.json +14 -0
  24. package/docs/development/database-schema.dbml +18 -3
  25. package/docs/development/state-management/state-management-selectors.mdx +1 -1
  26. package/glossary.json +8 -0
  27. package/package.json +3 -3
  28. package/packages/database/migrations/0063_add_columns_for_several_tables.sql +30 -0
  29. package/packages/database/migrations/0064_add_agents_session_group_id.sql +7 -0
  30. package/packages/database/migrations/meta/0063_snapshot.json +9113 -0
  31. package/packages/database/migrations/meta/0064_snapshot.json +9143 -0
  32. package/packages/database/migrations/meta/_journal.json +14 -0
  33. package/packages/database/src/core/migrations.json +39 -0
  34. package/packages/database/src/schemas/_helpers.ts +5 -1
  35. package/packages/database/src/schemas/agent.ts +8 -1
  36. package/packages/database/src/schemas/aiInfra.ts +18 -3
  37. package/packages/database/src/schemas/message.ts +11 -6
  38. package/packages/database/src/schemas/topic.ts +17 -2
  39. package/packages/database/src/schemas/user.ts +5 -2
  40. package/packages/database/src/schemas/userMemories.ts +9 -8
  41. package/packages/types/src/topic/thread.ts +24 -0
  42. package/packages/types/src/user/index.ts +1 -0
  43. package/packages/types/src/user/onboarding.ts +16 -0
  44. package/vitest.config.mts +3 -0
  45. package/.cursor/rules/group-chat.mdc +0 -35
  46. package/.cursor/rules/react-component.mdc +0 -173
@@ -5,20 +5,26 @@ alwaysApply: false
5
5
 
6
6
  # Database Migrations Guide
7
7
 
8
- ## Step1: Generate migrations:
8
+ ## Step1: Generate migrations
9
9
 
10
10
  ```bash
11
11
  bun run db:generate
12
12
  ```
13
13
 
14
- this step will generate or update the following files:
14
+ this step will generate following files:
15
+
16
+ - packages/database/migrations/0046_meaningless_file_name.sql
17
+ - packages/database/migrations/0046_meaningless_file_name.sql
18
+
19
+ and update the following files:
15
20
 
16
- - packages/database/migrations/0046_xxx.sql
17
21
  - packages/database/migrations/meta/\_journal.json
22
+ - packages/database/src/core/migrations.json
23
+ - docs/development/database-schema.dbml
18
24
 
19
25
  ## Step2: optimize the migration sql fileName
20
26
 
21
- the migration sql file name is randomly generated, we need to optimize the file name to make it more readable and meaningful. For example, `0046_xxx.sql` -> `0046_better_auth.sql`
27
+ the migration sql file name is randomly generated, we need to optimize the file name to make it more readable and meaningful. For example, `0046_meaningless_file_name.sql` -> `0046_user_add_avatar_column.sql`
22
28
 
23
29
  ## Step3: Defensive Programming - Use Idempotent Clauses
24
30
 
@@ -1,8 +1,9 @@
1
1
  ---
2
- description:
2
+ description:
3
3
  globs: src/database/schemas/*
4
4
  alwaysApply: false
5
5
  ---
6
+
6
7
  # Drizzle ORM Schema Style Guide for lobe-chat
7
8
 
8
9
  This document outlines the conventions and best practices for defining PostgreSQL Drizzle ORM schemas within the lobe-chat project.
@@ -16,7 +17,8 @@ This document outlines the conventions and best practices for defining PostgreSQ
16
17
 
17
18
  ## Helper Functions
18
19
 
19
- Commonly used column definitions, especially for timestamps, are centralized in [src/database/schemas/_helpers.ts](mdc:src/database/schemas/_helpers.ts):
20
+ Commonly used column definitions, especially for timestamps, are centralized in [src/database/schemas/\_helpers.ts](mdc:src/database/schemas/_helpers.ts):
21
+
20
22
  - `timestamptz(name: string)`: Creates a timestamp column with timezone
21
23
  - `createdAt()`, `updatedAt()`, `accessedAt()`: Helper functions for standard timestamp columns
22
24
  - `timestamps`: An object `{ createdAt, updatedAt, accessedAt }` for easy inclusion in table definitions
@@ -29,6 +31,7 @@ Commonly used column definitions, especially for timestamps, are centralized in
29
31
  ## Column Definitions
30
32
 
31
33
  ### Primary Keys (PKs)
34
+
32
35
  - Typically `text('id')` (or `varchar('id')` for some OIDC tables)
33
36
  - Often use `.$defaultFn(() => idGenerator('table_name'))` for automatic ID generation with meaningful prefixes
34
37
  - **ID Prefix Purpose**: Makes it easy for users and developers to distinguish different entity types at a glance
@@ -36,24 +39,29 @@ Commonly used column definitions, especially for timestamps, are centralized in
36
39
  - Composite PKs are defined using `primaryKey({ columns: [t.colA, t.colB] })`
37
40
 
38
41
  ### Foreign Keys (FKs)
42
+
39
43
  - Defined using `.references(() => otherTable.id, { onDelete: 'cascade' | 'set null' | 'no action' })`
40
44
  - FK columns are usually named `related_table_singular_name_id` (e.g., `user_id` references `users.id`)
41
45
  - Most tables include a `user_id` column referencing `users.id` with `onDelete: 'cascade'`
42
46
 
43
47
  ### Timestamps
44
- - Consistently use the `...timestamps` spread from [_helpers.ts](mdc:src/database/schemas/_helpers.ts) for `created_at`, `updated_at`, and `accessed_at` columns
48
+
49
+ - Consistently use the `...timestamps` spread from [\_helpers.ts](mdc:src/database/schemas/_helpers.ts) for `created_at`, `updated_at`, and `accessed_at` columns
45
50
 
46
51
  ### Default Values
52
+
47
53
  - `.$defaultFn(() => expression)` for dynamic defaults (e.g., `idGenerator()`, `randomSlug()`)
48
54
  - `.default(staticValue)` for static defaults (e.g., `boolean('enabled').default(true)`)
49
55
 
50
56
  ### Indexes
57
+
51
58
  - Defined in the table's second argument: `pgTable('name', {...columns}, (t) => ({ indexName: indexType().on(...) }))`
52
59
  - Use `uniqueIndex()` for unique constraints and `index()` for non-unique indexes
53
60
  - Naming pattern: `table_name_column(s)_idx` or `table_name_column(s)_unique`
54
61
  - Many tables feature a `clientId: text('client_id')` column, often part of a composite unique index with `user_id`
55
62
 
56
63
  ### Data Types
64
+
57
65
  - Common types: `text`, `varchar`, `jsonb`, `boolean`, `integer`, `uuid`, `pgTable`
58
66
  - For `jsonb` fields, specify the TypeScript type using `.$type<MyType>()` for better type safety
59
67
 
@@ -97,9 +105,7 @@ export const agents = pgTable(
97
105
  ...timestamps,
98
106
  },
99
107
  // return array instead of object, the object style is deprecated
100
- (t) => [
101
- uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId),
102
- ],
108
+ (t) => [uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId)],
103
109
  );
104
110
 
105
111
  export const insertAgentSchema = createInsertSchema(agents);
@@ -110,6 +116,7 @@ export type AgentItem = typeof agents.$inferSelect;
110
116
  ## Common Patterns
111
117
 
112
118
  ### 1. userId + clientId Pattern (Legacy)
119
+
113
120
  Some existing tables include both fields for different purposes:
114
121
 
115
122
  ```typescript
@@ -129,6 +136,7 @@ clientIdUnique: uniqueIndex('agents_client_id_user_id_unique').on(t.clientId, t.
129
136
  - **Note**: This pattern is being phased out for new features to simplify the schema
130
137
 
131
138
  ### 2. Junction Tables (Many-to-Many Relationships)
139
+
132
140
  Use composite primary keys for relationship tables:
133
141
 
134
142
  ```typescript
@@ -136,21 +144,26 @@ Use composite primary keys for relationship tables:
136
144
  export const agentsKnowledgeBases = pgTable(
137
145
  'agents_knowledge_bases',
138
146
  {
139
- agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }).notNull(),
140
- knowledgeBaseId: text('knowledge_base_id').references(() => knowledgeBases.id, { onDelete: 'cascade' }).notNull(),
141
- userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
147
+ agentId: text('agent_id')
148
+ .references(() => agents.id, { onDelete: 'cascade' })
149
+ .notNull(),
150
+ knowledgeBaseId: text('knowledge_base_id')
151
+ .references(() => knowledgeBases.id, { onDelete: 'cascade' })
152
+ .notNull(),
153
+ userId: text('user_id')
154
+ .references(() => users.id, { onDelete: 'cascade' })
155
+ .notNull(),
142
156
  enabled: boolean('enabled').default(true),
143
157
  ...timestamps,
144
158
  },
145
- (t) => [
146
- primaryKey({ columns: [t.agentId, t.knowledgeBaseId] }),
147
- ],
159
+ (t) => [primaryKey({ columns: [t.agentId, t.knowledgeBaseId] })],
148
160
  );
149
161
  ```
150
162
 
151
163
  **Pattern**: `{entity1}Id` + `{entity2}Id` as composite PK, plus `userId` for ownership
152
164
 
153
165
  ### 3. OIDC Tables Special Patterns
166
+
154
167
  OIDC tables use `varchar` IDs instead of `text` with custom generators:
155
168
 
156
169
  ```typescript
@@ -166,6 +179,7 @@ export const oidcAuthorizationCodes = pgTable('oidc_authorization_codes', {
166
179
  **Reason**: OIDC standards expect specific ID formats and lengths
167
180
 
168
181
  ### 4. File Processing with Async Tasks
182
+
169
183
  File-related tables reference async task IDs for background processing:
170
184
 
171
185
  ```typescript
@@ -173,17 +187,21 @@ File-related tables reference async task IDs for background processing:
173
187
  export const files = pgTable('files', {
174
188
  // ... other fields
175
189
  chunkTaskId: uuid('chunk_task_id').references(() => asyncTasks.id, { onDelete: 'set null' }),
176
- embeddingTaskId: uuid('embedding_task_id').references(() => asyncTasks.id, { onDelete: 'set null' }),
190
+ embeddingTaskId: uuid('embedding_task_id').references(() => asyncTasks.id, {
191
+ onDelete: 'set null',
192
+ }),
177
193
  // ...
178
194
  });
179
195
  ```
180
196
 
181
- **Purpose**:
197
+ **Purpose**:
198
+
182
199
  - Track file chunking progress (breaking files into smaller pieces)
183
200
  - Track embedding generation progress (converting text to vectors)
184
201
  - Allow querying task status and handling failures
185
202
 
186
203
  ### 5. Slug Pattern (Legacy)
204
+
187
205
  Some entities include auto-generated slugs - this is legacy code:
188
206
 
189
207
  ```typescript
@@ -195,8 +213,6 @@ slug: varchar('slug', { length: 100 })
195
213
  slugUserIdUnique: uniqueIndex('slug_user_id_unique').on(t.slug, t.userId),
196
214
  ```
197
215
 
198
- **Current usage**: Only used to identify default agents/sessions (legacy pattern)
199
- **Future refactor**: Will likely be replaced with `isDefault: boolean()` field
200
- **Note**: Avoid using slugs for new features - prefer explicit boolean flags for status tracking
216
+ **Current usage**: Only used to identify default agents/sessions (legacy pattern) **Future refactor**: Will likely be replaced with `isDefault: boolean()` field **Note**: Avoid using slugs for new features - prefer explicit boolean flags for status tracking
201
217
 
202
218
  By following these guidelines, maintain consistency, type safety, and maintainability across database schema definitions.
@@ -0,0 +1,161 @@
1
+ ---
2
+ alwaysApply: false
3
+ ---
4
+ # 如何添加新的快捷键:开发者指南
5
+
6
+ 本指南将带您一步步地向 LobeChat 添加一个新的快捷键功能。我们将通过一个完整示例,演示从定义到实现的整个过程。
7
+
8
+ ## 示例场景
9
+
10
+ 假设我们要添加一个新的快捷键功能:**快速清空聊天记录**,快捷键为 `Mod+Shift+Backspace`。
11
+
12
+ ## 步骤 1:更新快捷键常量定义
13
+
14
+ 首先,在 `src/types/hotkey.ts` 中更新 `HotkeyEnum`:
15
+
16
+ ```typescript
17
+ export const HotkeyEnum = {
18
+ // 已有的快捷键...
19
+ AddUserMessage: 'addUserMessage',
20
+ EditMessage: 'editMessage',
21
+
22
+ // 新增快捷键
23
+ ClearChat: 'clearChat', // 添加这一行
24
+
25
+ // 其他已有快捷键...
26
+ } as const;
27
+ ```
28
+
29
+ ## 步骤 2:注册默认快捷键
30
+
31
+ 在 `src/const/hotkeys.ts` 中添加快捷键的默认配置:
32
+
33
+ ```typescript
34
+ import { KeyMapEnum as Key, combineKeys } from '@lobehub/ui';
35
+
36
+ // ...现有代码
37
+
38
+ export const HOTKEYS_REGISTRATION: HotkeyRegistration = [
39
+ // 现有的快捷键配置...
40
+
41
+ // 添加新的快捷键配置
42
+ {
43
+ group: HotkeyGroupEnum.Conversation, // 归类到会话操作组
44
+ id: HotkeyEnum.ClearChat,
45
+ keys: combineKeys([Key.Mod, Key.Shift, Key.Backspace]),
46
+ scopes: [HotkeyScopeEnum.Chat], // 在聊天作用域下生效
47
+ },
48
+
49
+ // 其他现有快捷键...
50
+ ];
51
+ ```
52
+
53
+ ## 步骤 3:添加国际化翻译
54
+
55
+ 在 `src/locales/default/hotkey.ts` 中添加对应的文本描述:
56
+
57
+ ```typescript
58
+ import { HotkeyI18nTranslations } from '@/types/hotkey';
59
+
60
+ const hotkey: HotkeyI18nTranslations = {
61
+ // 现有翻译...
62
+
63
+ // 添加新快捷键的翻译
64
+ clearChat: {
65
+ desc: '清空当前会话的所有消息记录',
66
+ title: '清空聊天记录',
67
+ },
68
+
69
+ // 其他现有翻译...
70
+ };
71
+
72
+ export default hotkey;
73
+ ```
74
+
75
+ 如需支持其他语言,还需要在相应的语言文件中添加对应翻译。
76
+
77
+ ## 步骤 4:创建并注册快捷键 Hook
78
+
79
+ 在 `src/hooks/useHotkeys/chatScope.ts` 中添加新的 Hook:
80
+
81
+ ```typescript
82
+ export const useClearChatHotkey = () => {
83
+ const clearMessages = useChatStore((s) => s.clearMessages);
84
+ const { t } = useTranslation();
85
+
86
+ return useHotkeyById(HotkeyEnum.ClearChat, showConfirm);
87
+ };
88
+
89
+ // 注册聚合
90
+
91
+ export const useRegisterChatHotkeys = () => {
92
+ const { enableScope, disableScope } = useHotkeysContext();
93
+
94
+ useOpenChatSettingsHotkey();
95
+ // ...其他快捷键
96
+ useClearChatHotkey();
97
+
98
+ useEffect(() => {
99
+ enableScope(HotkeyScopeEnum.Chat);
100
+ return () => disableScope(HotkeyScopeEnum.Chat);
101
+ }, []);
102
+
103
+ return null;
104
+ };
105
+ ```
106
+
107
+ ## 步骤 5:给相应 UI 元素添加 Tooltip 提示(可选)
108
+
109
+ 如果有对应的 UI 按钮,可以添加快捷键提示:
110
+
111
+ ```tsx
112
+ import { DeleteOutlined } from '@ant-design/icons';
113
+ import { Tooltip } from '@lobehub/ui';
114
+ import { Button } from 'antd';
115
+ import { useTranslation } from 'react-i18next';
116
+
117
+ import { useUserStore } from '@/store/user';
118
+ import { settingsSelectors } from '@/store/user/selectors';
119
+ import { HotkeyEnum } from '@/types/hotkey';
120
+
121
+ const ClearChatButton = () => {
122
+ const { t } = useTranslation(['hotkey', 'chat']);
123
+ const clearChatHotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.ClearChat));
124
+
125
+ // 获取清空聊天的方法
126
+ const clearMessages = useChatStore((s) => s.clearMessages);
127
+
128
+ return (
129
+ <Tooltip hotkey={clearChatHotkey} title={t('clearChat.title', { ns: 'hotkey' })}>
130
+ <Button icon={<DeleteOutlined />} onClick={clearMessages} />
131
+ </Tooltip>
132
+ );
133
+ };
134
+ ```
135
+
136
+ ## 步骤 6:测试新快捷键
137
+
138
+ 1. 启动开发服务器
139
+ 2. 打开聊天页面
140
+ 3. 按下设置的快捷键组合(`Cmd+Shift+Backspace` 或 `Ctrl+Shift+Backspace`)
141
+ 4. 确认功能正常工作
142
+ 5. 检查快捷键设置面板中是否正确显示了新快捷键
143
+
144
+ ## 最佳实践
145
+
146
+ 1. **作用域考虑**:根据功能决定快捷键应属于全局作用域还是聊天作用域
147
+ 2. **分组合理**:将快捷键放在合适的功能组中(System/Layout/Conversation)
148
+ 3. **冲突检查**:确保新快捷键不会与现有系统、浏览器或应用快捷键冲突
149
+ 4. **平台适配**:使用 `Key.Mod` 而非硬编码 `Ctrl` 或 `Cmd`,以适配不同平台
150
+ 5. **提供清晰描述**:为快捷键添加明确的标题和描述,帮助用户理解功能
151
+
152
+ 按照以上步骤,您可以轻松地向系统添加新的快捷键功能,提升用户体验。如有特殊需求,如桌面专属快捷键,可以通过 `isDesktop` 标记进行区分处理。
153
+
154
+ ## 常见问题排查
155
+
156
+ - **快捷键未生效**:检查作用域是否正确,以及是否在 RegisterHotkeys 中调用了对应的 hook
157
+ - **快捷键设置面板未显示**:确认在 HOTKEYS_REGISTRATION 中正确配置了快捷键
158
+ - **快捷键冲突**:在 HotkeyInput 组件中可以检测到冲突,用户会看到警告
159
+ - **功能在某些页面失效**:确认是否注册在了正确的作用域,以及相关页面是否激活了该作用域
160
+
161
+ 通过这些步骤,您可以确保新添加的快捷键功能稳定、可靠且用户友好。
@@ -2,6 +2,7 @@
2
2
  globs: *.tsx
3
3
  alwaysApply: false
4
4
  ---
5
+
5
6
  # LobeChat Internationalization Guide
6
7
 
7
8
  ## Key Points
@@ -14,7 +15,7 @@ alwaysApply: false
14
15
 
15
16
  ## Directory Structure
16
17
 
17
- ```
18
+ ```plaintext
18
19
  src/locales/
19
20
  ├── default/ # Source language files (zh-CN)
20
21
  │ ├── index.ts # Namespace exports
@@ -176,7 +177,3 @@ export default {
176
177
  - Check if the key exists in src/locales/default/namespace.ts
177
178
  - Ensure the namespace is correctly imported in the component
178
179
  - Ensure new namespaces are exported in src/locales/default/index.ts
179
-
180
- - 检查键是否存在于 src/locales/default/namespace.ts 中
181
- - 确保在组件中正确导入命名空间
182
- - 确保新命名空间已在 src/locales/default/index.ts 中导出
@@ -17,6 +17,7 @@ logo emoji: 🤯
17
17
  ## Project Technologies Stack
18
18
 
19
19
  - Next.js 16
20
+ - implement spa inside nextjs with `react-router-dom`
20
21
  - react 19
21
22
  - TypeScript
22
23
  - `@lobehub/ui`, antd for component framework
@@ -29,8 +30,8 @@ logo emoji: 🤯
29
30
  - SWR for data fetch
30
31
  - aHooks for react hooks library
31
32
  - dayjs for time library
32
- - lodash-es for utility library
33
+ - es-toolkit for utility library
33
34
  - TRPC for type safe backend
34
- - PGLite for client DB and Neon PostgreSQL for backend DB
35
+ - Neon PostgreSQL for backend DB
35
36
  - Drizzle ORM
36
37
  - Vitest for testing
@@ -25,22 +25,23 @@ lobe-chat/
25
25
  │ └── zh-CN/
26
26
  ├── packages/
27
27
  │ ├── agent-runtime/
28
+ │ ├── builtin-agents/
29
+ │ ├── builtin-tool-*/ # builtin tool packages
28
30
  │ ├── const/
29
31
  │ ├── context-engine/
30
32
  │ ├── conversation-flow/
31
33
  │ ├── database/
32
- │ │ ├── src/
33
- │ │├── models/
34
- │ │├── schemas/
35
- │ │└── repositories/
34
+ │ │ └── src/
35
+ │ │ ├── models/
36
+ │ │ ├── schemas/
37
+ │ │ └── repositories/
38
+ │ ├── desktop-bridge/
36
39
  │ ├── electron-client-ipc/
37
40
  │ ├── electron-server-ipc/
38
41
  │ ├── fetch-sse/
39
42
  │ ├── file-loaders/
40
- │ ├── memory-extract/
43
+ │ ├── memory-user-memory/
41
44
  │ ├── model-bank/
42
- │ │ └── src/
43
- │ │ └── aiModels/
44
45
  │ ├── model-runtime/
45
46
  │ │ └── src/
46
47
  │ │ ├── core/
@@ -50,9 +51,6 @@ lobe-chat/
50
51
  │ ├── python-interpreter/
51
52
  │ ├── ssrf-safe-fetch/
52
53
  │ ├── types/
53
- │ │ └── src/
54
- │ │ ├── message/
55
- │ │ └── user/
56
54
  │ ├── utils/
57
55
  │ └── web-crawler/
58
56
  ├── public/
@@ -61,24 +59,25 @@ lobe-chat/
61
59
  │ ├── app/
62
60
  │ │ ├── (backend)/
63
61
  │ │ │ ├── api/
64
- │ │ │ ├── auth/
65
- │ │ │ │ └── webhooks/
62
+ │ │ │ ├── f/
63
+ │ │ │ ├── market/
66
64
  │ │ │ ├── middleware/
67
65
  │ │ │ ├── oidc/
68
66
  │ │ │ ├── trpc/
69
67
  │ │ │ └── webapi/
70
- │ │ │ ├── chat/
71
- │ │ │ └── tts/
72
68
  │ │ ├── [variants]/
69
+ │ │ │ ├── (auth)/
73
70
  │ │ │ ├── (main)/
74
- │ │ │ ├── chat/
75
- │ │ │ │ └── settings/
76
- │ │ │ └── @modal/
77
- │ │ └── manifest.ts
71
+ │ │ │ ├── (mobile)/
72
+ │ │ │ ├── onboarding/
73
+ │ │ │ └── router/
74
+ │ │ └── desktop/
78
75
  │ ├── components/
79
76
  │ ├── config/
77
+ │ ├── const/
78
+ │ ├── envs/
80
79
  │ ├── features/
81
- │ └── ChatInput/
80
+ ├── helpers/
82
81
  │ ├── hooks/
83
82
  │ ├── layout/
84
83
  │ │ ├── AuthProvider/
@@ -90,23 +89,23 @@ lobe-chat/
90
89
  │ ├── locales/
91
90
  │ │ └── default/
92
91
  │ ├── server/
92
+ │ │ ├── featureFlags/
93
+ │ │ ├── globalConfig/
93
94
  │ │ ├── modules/
94
95
  │ │ ├── routers/
95
96
  │ │ │ ├── async/
96
- │ │ │ ├── desktop/
97
- │ │ │ ├── edge/
98
- │ │ │ └── lambda/
97
+ │ │ │ ├── lambda/
98
+ │ │ │ ├── mobile/
99
+ │ │ │ └── tools/
99
100
  │ │ └── services/
100
101
  │ ├── services/
101
- │ │ ├── user/
102
- │ │ │ ├── client.ts
103
- │ │ │ └── server.ts
104
- │ │ └── message/
105
102
  │ ├── store/
106
103
  │ │ ├── agent/
107
104
  │ │ ├── chat/
108
105
  │ │ └── user/
109
106
  │ ├── styles/
107
+ │ ├── tools/
108
+ │ ├── types/
110
109
  │ └── utils/
111
110
  └── package.json
112
111
  ```
@@ -116,25 +115,22 @@ lobe-chat/
116
115
  - UI Components: `src/components`, `src/features`
117
116
  - Global providers: `src/layout`
118
117
  - Zustand stores: `src/store`
119
- - Client Services: `src/services/` cross-platform services
120
- - clientDB: `src/services/<domain>/client.ts`
121
- - serverDB: `src/services/<domain>/server.ts`
118
+ - Client Services: `src/services/`
122
119
  - API Routers:
123
120
  - `src/app/(backend)/webapi` (REST)
124
- - `src/server/routers/{edge|lambda|async|desktop|tools}` (tRPC)
121
+ - `src/server/routers/{async|lambda|mobile|tools}` (tRPC)
125
122
  - Server:
126
- - Services(can access serverDB): `src/server/services` server-used-only services
127
- - Modules(can't access db): `src/server/modules` (Server only Third-party Service Module)
123
+ - Services (can access serverDB): `src/server/services`
124
+ - Modules (can't access db): `src/server/modules`
125
+ - Feature Flags: `src/server/featureFlags`
126
+ - Global Config: `src/server/globalConfig`
128
127
  - Database:
129
128
  - Schema (Drizzle): `packages/database/src/schemas`
130
129
  - Model (CRUD): `packages/database/src/models`
131
130
  - Repository (bff-queries): `packages/database/src/repositories`
132
131
  - Third-party Integrations: `src/libs` — analytics, oidc etc.
132
+ - Builtin Tools: `src/tools`, `packages/builtin-tool-*`
133
133
 
134
134
  ## Data Flow Architecture
135
135
 
136
- - **Web with ClientDB**: React UI → Client Service → Direct Model Access PGLite (Web WASM)
137
- - **Web with ServerDB**: React UI → Client Service → tRPC Lambda → Server Services → PostgreSQL (Remote)
138
- - **Desktop**:
139
- - Cloud sync disabled: Electron UI → Client Service → tRPC Lambda → Local Server Services → PGLite (Node WASM)
140
- - Cloud sync enabled: Electron UI → Client Service → tRPC Lambda → Cloud Server Services → PostgreSQL (Remote)
136
+ React UI Store Actions → Client Service → TRPC Lambda → Server Services -> DB Model → PostgreSQL (Remote)
@@ -0,0 +1,155 @@
1
+ ---
2
+ description:
3
+ globs: *.tsx
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # React Component Writing Guide
8
+
9
+ - Use antd-style for complex styles; for simple cases, use the `style` attribute for inline styles
10
+ - Use `Flexbox` and `Center` components from react-layout-kit for flex and centered layouts
11
+ - Component selection priority: src/components > installed component packages > lobe-ui > antd
12
+ - Use selectors to access zustand store data instead of accessing the store directly
13
+
14
+ ## Lobe UI Components
15
+
16
+ - If unsure how to use `@lobehub/ui` components or what props they accept, search for existing usage in this project instead of guessing. Most components extend antd components with additional props
17
+ - For specific usage, search online. For example, for ActionIcon visit <https://ui.lobehub.com/components/action-icon>
18
+ - Read `node_modules/@lobehub/ui/es/index.js` to see all available components and their props
19
+
20
+ - General
21
+ - ActionIcon
22
+ - ActionIconGroup
23
+ - Block
24
+ - Button
25
+ - Icon
26
+ - Data Display
27
+ - Accordion
28
+ - Avatar
29
+ - Collapse
30
+ - Empty
31
+ - FileTypeIcon
32
+ - FluentEmoji
33
+ - GroupAvatar
34
+ - GuideCard
35
+ - Highlighter
36
+ - Hotkey
37
+ - Image
38
+ - List
39
+ - Markdown
40
+ - MaterialFileTypeIcon
41
+ - Mermaid
42
+ - Segmented
43
+ - Skeleton
44
+ - Snippet
45
+ - SortableList
46
+ - Tag
47
+ - Tooltip
48
+ - Video
49
+ - Data Entry
50
+ - AutoComplete
51
+ - CodeEditor
52
+ - ColorSwatches
53
+ - CopyButton
54
+ - DatePicker
55
+ - DownloadButton
56
+ - EditableText
57
+ - EmojiPicker
58
+ - Form
59
+ - FormModal
60
+ - HotkeyInput
61
+ - ImageSelect
62
+ - Input
63
+ - SearchBar
64
+ - Select
65
+ - SliderWithInput
66
+ - ThemeSwitch
67
+ - Feedback
68
+ - Alert
69
+ - Drawer
70
+ - Modal
71
+ - Layout
72
+ - DraggablePanel
73
+ - Footer
74
+ - Grid
75
+ - Header
76
+ - Layout
77
+ - MaskShadow
78
+ - ScrollShadow
79
+ - Navigation
80
+ - Burger
81
+ - DraggableSideNav
82
+ - Dropdown
83
+ - Menu
84
+ - SideNav
85
+ - Tabs
86
+ - Toc
87
+ - Theme
88
+ - ConfigProvider
89
+ - FontLoader
90
+ - ThemeProvider
91
+ - Typography
92
+ - Text
93
+
94
+ ## Routing Architecture
95
+
96
+ This project uses a **hybrid routing architecture**: Next.js App Router for static pages + React Router DOM for the main SPA.
97
+
98
+ ### Route Types
99
+
100
+ ```plaintext
101
+ +------------------+--------------------------------+--------------------------------+
102
+ | Route Type | Use Case | Implementation |
103
+ +------------------+--------------------------------+--------------------------------+
104
+ | Next.js App | Auth pages (login, signup, | page.tsx file convention |
105
+ | Router | oauth, reset-password, etc.) | src/app/[variants]/(auth)/ |
106
+ +------------------+--------------------------------+--------------------------------+
107
+ | React Router | Main SPA features | BrowserRouter + Routes |
108
+ | DOM | (chat, discover, settings) | desktopRouter.config.tsx |
109
+ | | | mobileRouter.config.tsx |
110
+ +------------------+--------------------------------+--------------------------------+
111
+ ```
112
+
113
+ ### Key Files
114
+
115
+ - Entry point: `src/app/[variants]/page.tsx` - Routes to Desktop or Mobile based on device
116
+ - Desktop router: `src/app/[variants]/router/desktopRouter.config.tsx`
117
+ - Mobile router: `src/app/[variants]/(mobile)/router/mobileRouter.config.tsx`
118
+ - Router utilities: `src/utils/router.tsx`
119
+
120
+ ### Router Utilities
121
+
122
+ ```tsx
123
+ import { dynamicElement, redirectElement, ErrorBoundary, RouteConfig } from '@/utils/router';
124
+
125
+ // Lazy load a page component
126
+ element: dynamicElement(() => import('./chat'), 'Desktop > Chat')
127
+
128
+ // Create a redirect
129
+ element: redirectElement('/settings/profile')
130
+
131
+ // Error boundary for route
132
+ errorElement: <ErrorBoundary resetPath="/chat" />
133
+ ```
134
+
135
+ ### Adding New Routes
136
+
137
+ 1. Add route config to `desktopRouter.config.tsx` or `mobileRouter.config.tsx`
138
+ 2. Create page component in the corresponding directory under `(main)/`
139
+ 3. Use `dynamicElement()` for lazy loading
140
+
141
+ ### Navigation
142
+
143
+ ```tsx
144
+ // In components - use react-router-dom hooks
145
+ import { useNavigate, useParams } from 'react-router-dom';
146
+
147
+ const navigate = useNavigate();
148
+ navigate('/chat');
149
+
150
+ // From stores - use global navigate
151
+ import { useGlobalStore } from '@/store/global';
152
+
153
+ const navigate = useGlobalStore.getState().navigate;
154
+ navigate?.('/settings');
155
+ ```