mirror of
https://github.com/lobehub/lobe-chat.git
synced 2025-12-20 01:12:52 +08:00
📝 docs: add some cursor rules & optimize codebase indexing (#7999)
* 📝 docs: add some cursor rules & optimize codebase indexing * 📝 docs: some code reviews issue by greptile
This commit is contained in:
94
.cursor/rules/backend-architecture.mdc
Normal file
94
.cursor/rules/backend-architecture.mdc
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
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/](mdc:src/services)。
|
||||
* 这是客户端业务逻辑的核心层,负责封装各种业务操作和数据处理逻辑。
|
||||
* **环境适配**: 根据不同的运行环境,服务层会选择合适的数据访问方式:
|
||||
* **本地数据库模式**: 直接调用 `Model` 层进行数据操作,适用于浏览器 PGLite 和本地 Electron 应用。
|
||||
* **远程数据库模式**: 通过 `tRPC` 客户端调用服务端 API,适用于需要云同步的场景。
|
||||
* **类型转换**: 对于简单的数据类型转换,直接在此层进行类型断言,如 `this.pluginModel.query() as Promise<LobeTool[]>`(参见 [src/services/plugin/client.ts](mdc:src/services/plugin/client.ts))。
|
||||
* 每个服务模块通常包含 `client.ts`(本地模式)、`server.ts`(远程模式)和 `type.ts`(接口定义)文件。
|
||||
|
||||
2. **API 接口层 (`TRPC`)**:
|
||||
* 位于 [src/server/routers/](mdc:src/server/routers)。
|
||||
* 使用 `tRPC` 构建类型安全的 API。Router 根据运行时环境(如 Edge Functions, Node.js Lambda)进行组织。
|
||||
* 负责接收客户端请求,并将其路由到相应的 `Service` 层进行处理。
|
||||
|
||||
3. **服务端服务层 (`server/services`)**:
|
||||
* 位于 [src/server/services/](mdc:src/server/services)。
|
||||
* 核心职责是封装独立的、可复用的业务逻辑单元。这些服务应易于测试。
|
||||
* **平台差异抽象**: 一个关键特性是通过其内部的 `impls` 子目录(例如 [src/server/services/file/impls/](mdc:src/server/services/file/impls) 包含 `s3.ts` 和 `local.ts`)来抹平不同运行环境带来的差异(例如云端使用 S3 存储,桌面版使用本地文件系统)。这使得上层(如 `tRPC` routers)无需关心底层具体实现。
|
||||
* 目标是使 `tRPC` router 层的逻辑尽可能纯粹,专注于请求处理和业务流程编排。
|
||||
* 服务会调用 `Repository` 层或直接调用 `Model` 层进行数据持久化和检索,也可能调用其他服务。
|
||||
|
||||
4. **仓库层 (`Repositories`)**:
|
||||
* 位于 [src/database/repositories/](mdc:src/database/repositories)。
|
||||
* 主要处理**复杂的跨表查询和数据聚合**逻辑,特别是当需要从**多个 `Model`** 获取数据并进行组合时。
|
||||
* 与 `Model` 层不同,`Repository` 层专注于复杂的业务查询场景,而不涉及简单的领域模型转换。
|
||||
* 当业务逻辑涉及多表关联、复杂的数据统计或需要事务处理时,会使用 `Repository` 层。
|
||||
* 如果数据操作简单(仅涉及单个 `Model`),则通常直接在 `src/services` 层调用 `Model` 并进行简单的类型断言。
|
||||
|
||||
5. **模型层 (`Models`)**:
|
||||
* 位于 [src/database/models/](mdc:src/database/models) (例如 [src/database/models/plugin.ts](mdc:src/database/models/plugin.ts) 和 [src/database/models/document.ts](mdc:src/database/models/document.ts))。
|
||||
* 提供对数据库中各个表(由 [src/database/schemas/](mdc:src/database/schemas) 中的 Drizzle ORM schema 定义)的基本 CRUD (创建、读取、更新、删除) 操作和简单的查询能力。
|
||||
* `Model` 类专注于单个数据表的直接操作,**不涉及复杂的领域模型转换**,这些转换通常在上层的 `src/services` 中通过类型断言完成。
|
||||
|
||||
6. **数据库 (`Database`)**:
|
||||
* **客户端模式 (浏览器/PWA)**: 使用 PGLite (基于 WASM 的 PostgreSQL),数据存储在用户浏览器本地。
|
||||
* **服务端模式 (云部署)**: 使用远程 PostgreSQL 数据库。
|
||||
* **Electron 桌面应用**:
|
||||
* Electron 客户端会启动一个本地 Node.js 服务。
|
||||
* 本地服务通过 `tRPC` 与 Electron 的渲染进程通信。
|
||||
* 数据库选择依赖于是否开启**云同步**功能:
|
||||
* **云同步开启**: 连接到远程 PostgreSQL 数据库。
|
||||
* **云同步关闭**: 使用 PGLite (通过 Node.js 的 WASM 实现) 在本地存储数据。
|
||||
|
||||
## 数据流向说明
|
||||
|
||||
### 浏览器/PWA 模式
|
||||
```
|
||||
UI (React) → Zustand State → Model Layer → PGLite (本地数据库)
|
||||
```
|
||||
|
||||
### 服务端模式
|
||||
```
|
||||
UI (React) → Zustand State → tRPC Client → tRPC Routers → Services → Repositories/Models → Remote PostgreSQL
|
||||
```
|
||||
|
||||
### Electron 桌面应用模式
|
||||
```
|
||||
UI (Electron Renderer) → Zustand State → tRPC Client → 本地 Node.js 服务 → tRPC Routers → Services → Repositories/Models → PGLite/Remote PostgreSQL (取决于云同步设置)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
27
.cursor/rules/cursor-ux-optimize.mdc
Normal file
27
.cursor/rules/cursor-ux-optimize.mdc
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
## Formatting Response
|
||||
|
||||
This is about how you should format your responses.
|
||||
|
||||
### Render Markdown Table
|
||||
|
||||
- Be aware that the cursor chat you are in can't render markdown table correctly.
|
||||
- IMPORTANT: Tables need to be rendered in plain text and not markdown
|
||||
|
||||
When rendering tables, do not use markdown table syntax or plain text alone. Instead, place the entire table inside a code/text block (using triple backticks). This ensures the table formatting is preserved and readable in the chat interface.
|
||||
|
||||
Example:
|
||||
|
||||
```plaintext
|
||||
+----+---------+-----------+
|
||||
| ID | Name | Role |
|
||||
+----+---------+-----------+
|
||||
| 1 | Alice | Admin |
|
||||
| 2 | Bob | User |
|
||||
| 3 | Charlie | Moderator |
|
||||
+----+---------+-----------+
|
||||
```
|
||||
8
.cursor/rules/define-database-model.mdc
Normal file
8
.cursor/rules/define-database-model.mdc
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
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/`
|
||||
202
.cursor/rules/drizzle-schema-style-guide.mdc
Normal file
202
.cursor/rules/drizzle-schema-style-guide.mdc
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
description:
|
||||
globs: src/database/schemas/*
|
||||
alwaysApply: false
|
||||
---
|
||||
# Drizzle ORM Schema Style Guide for lobe-chat
|
||||
|
||||
This document outlines the conventions and best practices for defining PostgreSQL Drizzle ORM schemas within the lobe-chat project.
|
||||
|
||||
## Configuration
|
||||
|
||||
- Drizzle configuration is managed in [drizzle.config.ts](mdc:drizzle.config.ts)
|
||||
- Schema files are located in the src/database/schemas/ directory
|
||||
- Migration files are output to `src/database/migrations/`
|
||||
- The project uses `postgresql` dialect with `strict: true`
|
||||
|
||||
## Helper Functions
|
||||
|
||||
Commonly used column definitions, especially for timestamps, are centralized in [src/database/schemas/_helpers.ts](mdc:src/database/schemas/_helpers.ts):
|
||||
- `timestamptz(name: string)`: Creates a timestamp column with timezone
|
||||
- `createdAt()`, `updatedAt()`, `accessedAt()`: Helper functions for standard timestamp columns
|
||||
- `timestamps`: An object `{ createdAt, updatedAt, accessedAt }` for easy inclusion in table definitions
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- **Table Names**: Use plural snake_case (e.g., `users`, `agents`, `session_groups`)
|
||||
- **Column Names**: Use snake_case (e.g., `user_id`, `created_at`, `background_color`)
|
||||
|
||||
## Column Definitions
|
||||
|
||||
### Primary Keys (PKs)
|
||||
- Typically `text('id')` (or `varchar('id')` for some OIDC tables)
|
||||
- Often use `.$defaultFn(() => idGenerator('table_name'))` for automatic ID generation with meaningful prefixes
|
||||
- **ID Prefix Purpose**: Makes it easy for users and developers to distinguish different entity types at a glance
|
||||
- For internal/system tables that users don't need to see, can use `uuid` or auto-increment keys
|
||||
- Composite PKs are defined using `primaryKey({ columns: [t.colA, t.colB] })`
|
||||
|
||||
### Foreign Keys (FKs)
|
||||
- Defined using `.references(() => otherTable.id, { onDelete: 'cascade' | 'set null' | 'no action' })`
|
||||
- FK columns are usually named `related_table_singular_name_id` (e.g., `user_id` references `users.id`)
|
||||
- Most tables include a `user_id` column referencing `users.id` with `onDelete: 'cascade'`
|
||||
|
||||
### Timestamps
|
||||
- Consistently use the `...timestamps` spread from [_helpers.ts](mdc:src/database/schemas/_helpers.ts) for `created_at`, `updated_at`, and `accessed_at` columns
|
||||
|
||||
### Default Values
|
||||
- `.$defaultFn(() => expression)` for dynamic defaults (e.g., `idGenerator()`, `randomSlug()`)
|
||||
- `.default(staticValue)` for static defaults (e.g., `boolean('enabled').default(true)`)
|
||||
|
||||
### Indexes
|
||||
- Defined in the table's second argument: `pgTable('name', {...columns}, (t) => ({ indexName: indexType().on(...) }))`
|
||||
- Use `uniqueIndex()` for unique constraints and `index()` for non-unique indexes
|
||||
- Naming pattern: `table_name_column(s)_idx` or `table_name_column(s)_unique`
|
||||
- Many tables feature a `clientId: text('client_id')` column, often part of a composite unique index with `user_id`
|
||||
|
||||
### Data Types
|
||||
- Common types: `text`, `varchar`, `jsonb`, `boolean`, `integer`, `uuid`, `pgTable`
|
||||
- For `jsonb` fields, specify the TypeScript type using `.$type<MyType>()` for better type safety
|
||||
|
||||
## Zod Schemas & Type Inference
|
||||
|
||||
- Utilize `drizzle-zod` to generate Zod schemas for validation:
|
||||
- `createInsertSchema(tableName)`
|
||||
- `createSelectSchema(tableName)` (less common)
|
||||
- Export inferred types: `export type NewEntity = typeof tableName.$inferInsert;` and `export type EntityItem = typeof tableName.$inferSelect;`
|
||||
|
||||
## Relations
|
||||
|
||||
- Table relationships are defined centrally in [src/database/schemas/relations.ts](mdc:src/database/schemas/relations.ts) using the `relations()` utility from `drizzle-orm`
|
||||
|
||||
## Code Style & Structure
|
||||
|
||||
- **File Organization**: Each main database entity typically has its own schema file (e.g., [user.ts](mdc:src/database/schemas/user.ts), [agent.ts](mdc:src/database/schemas/agent.ts))
|
||||
- All schemas are re-exported from [src/database/schemas/index.ts](mdc:src/database/schemas/index.ts)
|
||||
- **ESLint**: Files often start with `/* eslint-disable sort-keys-fix/sort-keys-fix */`
|
||||
- **Comments**: Use JSDoc-style comments to explain the purpose of tables and complex columns, fields that are self-explanatory do not require jsdoc explanations, such as id, user_id, etc.
|
||||
|
||||
## Example Pattern
|
||||
|
||||
```typescript
|
||||
// From src/database/schemas/agent.ts
|
||||
export const agents = pgTable(
|
||||
'agents',
|
||||
{
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => idGenerator('agents'))
|
||||
.notNull(),
|
||||
slug: varchar('slug', { length: 100 })
|
||||
.$defaultFn(() => randomSlug(4))
|
||||
.unique(),
|
||||
userId: text('user_id')
|
||||
.references(() => users.id, { onDelete: 'cascade' })
|
||||
.notNull(),
|
||||
clientId: text('client_id'),
|
||||
chatConfig: jsonb('chat_config').$type<LobeAgentChatConfig>(),
|
||||
...timestamps,
|
||||
},
|
||||
// return array instead of object, the object style is deprecated
|
||||
(t) => [
|
||||
uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId),
|
||||
],
|
||||
);
|
||||
|
||||
export const insertAgentSchema = createInsertSchema(agents);
|
||||
export type NewAgent = typeof agents.$inferInsert;
|
||||
export type AgentItem = typeof agents.$inferSelect;
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### 1. userId + clientId Pattern (Legacy)
|
||||
Some existing tables include both fields for different purposes:
|
||||
|
||||
```typescript
|
||||
// Example from agents table (legacy pattern)
|
||||
userId: text('user_id')
|
||||
.references(() => users.id, { onDelete: 'cascade' })
|
||||
.notNull(),
|
||||
clientId: text('client_id'),
|
||||
|
||||
// Usually with a composite unique index
|
||||
clientIdUnique: uniqueIndex('agents_client_id_user_id_unique').on(t.clientId, t.userId),
|
||||
```
|
||||
|
||||
- **`userId`**: Server-side user association, ensures data belongs to specific user
|
||||
- **`clientId`**: Unique key for import/export operations, supports data migration between instances
|
||||
- **Current Status**: New tables should NOT include `clientId` unless specifically needed for import/export functionality
|
||||
- **Note**: This pattern is being phased out for new features to simplify the schema
|
||||
|
||||
### 2. Junction Tables (Many-to-Many Relationships)
|
||||
Use composite primary keys for relationship tables:
|
||||
|
||||
```typescript
|
||||
// Example: agents_knowledge_bases (from agent.ts)
|
||||
export const agentsKnowledgeBases = pgTable(
|
||||
'agents_knowledge_bases',
|
||||
{
|
||||
agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }).notNull(),
|
||||
knowledgeBaseId: text('knowledge_base_id').references(() => knowledgeBases.id, { onDelete: 'cascade' }).notNull(),
|
||||
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||
enabled: boolean('enabled').default(true),
|
||||
...timestamps,
|
||||
},
|
||||
(t) => [
|
||||
primaryKey({ columns: [t.agentId, t.knowledgeBaseId] }),
|
||||
],
|
||||
);
|
||||
```
|
||||
|
||||
**Pattern**: `{entity1}Id` + `{entity2}Id` as composite PK, plus `userId` for ownership
|
||||
|
||||
### 3. OIDC Tables Special Patterns
|
||||
OIDC tables use `varchar` IDs instead of `text` with custom generators:
|
||||
|
||||
```typescript
|
||||
// Example from oidc.ts
|
||||
export const oidcAuthorizationCodes = pgTable('oidc_authorization_codes', {
|
||||
id: varchar('id', { length: 255 }).primaryKey(), // varchar not text
|
||||
data: jsonb('data').notNull(),
|
||||
expiresAt: timestamptz('expires_at').notNull(),
|
||||
// ... other fields
|
||||
});
|
||||
```
|
||||
|
||||
**Reason**: OIDC standards expect specific ID formats and lengths
|
||||
|
||||
### 4. File Processing with Async Tasks
|
||||
File-related tables reference async task IDs for background processing:
|
||||
|
||||
```typescript
|
||||
// Example from files table
|
||||
export const files = pgTable('files', {
|
||||
// ... other fields
|
||||
chunkTaskId: uuid('chunk_task_id').references(() => asyncTasks.id, { onDelete: 'set null' }),
|
||||
embeddingTaskId: uuid('embedding_task_id').references(() => asyncTasks.id, { onDelete: 'set null' }),
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
**Purpose**:
|
||||
- Track file chunking progress (breaking files into smaller pieces)
|
||||
- Track embedding generation progress (converting text to vectors)
|
||||
- Allow querying task status and handling failures
|
||||
|
||||
### 5. Slug Pattern (Legacy)
|
||||
Some entities include auto-generated slugs - this is legacy code:
|
||||
|
||||
```typescript
|
||||
slug: varchar('slug', { length: 100 })
|
||||
.$defaultFn(() => randomSlug(4))
|
||||
.unique(),
|
||||
|
||||
// Often with composite unique constraint
|
||||
slugUserIdUnique: uniqueIndex('slug_user_id_unique').on(t.slug, t.userId),
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
By following these guidelines, maintain consistency, type safety, and maintainability across database schema definitions.
|
||||
6
.cursor/rules/i18n/i18n-auto-attached.mdc
Normal file
6
.cursor/rules/i18n/i18n-auto-attached.mdc
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
description:
|
||||
globs: src/locales/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
read [i18n.mdc](mdc:.cursor/rules/i18n/i18n.mdc)
|
||||
183
.cursor/rules/i18n/i18n.mdc
Normal file
183
.cursor/rules/i18n/i18n.mdc
Normal file
@@ -0,0 +1,183 @@
|
||||
---
|
||||
description: i18n workflow and troubleshooting
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# LobeChat Internationalization (i18n) Guide
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
LobeChat uses **react-i18next** for internationalization with a well-structured namespace approach:
|
||||
|
||||
- **Default language**: Chinese (zh-CN) - serves as the source language
|
||||
- **Supported locales**: 18 languages including English, Japanese, Korean, Arabic, etc.
|
||||
- **Framework**: react-i18next with Next.js app router
|
||||
- **Translation automation**: [@lobehub/i18n-cli](mdc:package.json) for automated translations, config file: .i18nrc.js
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
src/locales/
|
||||
├── default/ # Source language files (zh-CN)
|
||||
│ ├── index.ts # Namespace exports
|
||||
│ ├── common.ts # Common translations
|
||||
│ ├── chat.ts # Chat-related translations
|
||||
│ ├── setting.ts # Settings translations
|
||||
│ └── ... # Other namespace files
|
||||
└── resources.ts # Type definitions and locale config
|
||||
|
||||
locales/ # Translated files
|
||||
├── en-US/ # English translations
|
||||
│ ├── common.json # Common translations
|
||||
│ ├── chat.json # Chat translations
|
||||
│ ├── setting.json # Settings translations
|
||||
│ └── ... # Other namespace JSON files
|
||||
├── ja-JP/ # Japanese translations
|
||||
│ ├── common.json
|
||||
│ ├── chat.json
|
||||
│ └── ...
|
||||
└── ... # Other language folders
|
||||
```
|
||||
|
||||
## Workflow for Adding New Translations
|
||||
|
||||
### 1. Add New Translation Keys
|
||||
|
||||
**Step 1**: Add translation key to the appropriate namespace file in [src/locales/default/](mdc:src/locales/default)
|
||||
|
||||
```typescript
|
||||
// Example: src/locales/default/common.ts
|
||||
export default {
|
||||
// ... existing keys
|
||||
newFeature: {
|
||||
title: "新功能标题",
|
||||
description: "功能描述文案",
|
||||
button: "操作按钮",
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
**Step 2**: If creating a new namespace, export it in [src/locales/default/index.ts](mdc:src/locales/default/index.ts)
|
||||
|
||||
```typescript
|
||||
import newNamespace from "./newNamespace";
|
||||
|
||||
const resources = {
|
||||
// ... existing namespaces
|
||||
newNamespace,
|
||||
} as const;
|
||||
```
|
||||
|
||||
### 2. Translation Process
|
||||
|
||||
**Development Mode** (Recommended):
|
||||
|
||||
- Manually add Chinese translations to corresponding JSON files in `locales/zh-CN/namespace.json`, this avoids running slow automation during development
|
||||
- Don't auto add translations for other language like English etc, most of developer is Chinese,
|
||||
|
||||
**Production Mode**:
|
||||
|
||||
```bash
|
||||
# Generate translations for all languages
|
||||
npm run i18n
|
||||
```
|
||||
|
||||
## Usage in Components
|
||||
|
||||
### Basic Usage with Hooks
|
||||
|
||||
```tsx
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const MyComponent = () => {
|
||||
const { t } = useTranslation("common"); // namespace
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{t("newFeature.title")}</h1>
|
||||
<p>{t("newFeature.description")}</p>
|
||||
<button>{t("newFeature.button")}</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### With Parameters
|
||||
|
||||
```tsx
|
||||
const { t } = useTranslation("common");
|
||||
|
||||
// Translation key with interpolation
|
||||
<p>{t("welcome.message", { name: "John" })}</p>;
|
||||
|
||||
// Corresponding locale file:
|
||||
// welcome: { message: '欢迎 {{name}} 使用!' }
|
||||
```
|
||||
|
||||
### Multiple Namespaces
|
||||
|
||||
```tsx
|
||||
const { t } = useTranslation(['common', 'chat']);
|
||||
|
||||
// Access different namespaces
|
||||
<button>{t('common:save')}</button>
|
||||
<span>{t('chat:typing')}</span>
|
||||
```
|
||||
|
||||
## Type Safety
|
||||
|
||||
The project uses TypeScript for type-safe translations with auto-generated types from [src/locales/resources.ts](mdc:src/locales/resources.ts):
|
||||
|
||||
```typescript
|
||||
import type { DefaultResources, NS, Locales } from "@/locales/resources";
|
||||
|
||||
// Available types:
|
||||
// - NS: Available namespace keys ('common' | 'chat' | 'setting' | ...)
|
||||
// - Locales: Supported locale codes ('en-US' | 'zh-CN' | 'ja-JP' | ...)
|
||||
|
||||
// Type-safe namespace usage
|
||||
const namespace: NS = "common"; // ✅ Valid
|
||||
const locale: Locales = "en-US"; // ✅ Valid
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Namespace Organization
|
||||
|
||||
- **common**: Shared UI elements (buttons, labels, actions)
|
||||
- **chat**: Chat-specific features
|
||||
- **setting**: Configuration and settings
|
||||
- **error**: Error messages and handling
|
||||
- **[feature]**: Feature-specific or page specific namespaces
|
||||
|
||||
### 2. Key Naming Conventions
|
||||
|
||||
```typescript
|
||||
// ✅ Good: Hierarchical structure
|
||||
export default {
|
||||
modal: {
|
||||
confirm: {
|
||||
title: "确认操作",
|
||||
message: "确定要执行此操作吗?",
|
||||
actions: {
|
||||
confirm: "确认",
|
||||
cancel: "取消",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// ❌ Avoid: Flat structure
|
||||
export default {
|
||||
modalConfirmTitle: "确认操作",
|
||||
modalConfirmMessage: "确定要执行此操作吗?",
|
||||
};
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Missing Translation Keys
|
||||
|
||||
- Check if the key exists in src/locales/default/namespace.ts
|
||||
- Ensure proper namespace import in component
|
||||
- Ensure new namespaces are exported in [src/locales/default/index.ts](mdc:src/locales/default/index.ts)
|
||||
72
.cursor/rules/packages/lobe-ui.mdc
Normal file
72
.cursor/rules/packages/lobe-ui.mdc
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
description: @lobehub/ui components list
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
## @lobehub/ui Components
|
||||
|
||||
- General
|
||||
ActionIcon
|
||||
ActionIconGroup
|
||||
Block
|
||||
Button
|
||||
Icon
|
||||
- Data Display
|
||||
Avatar
|
||||
Collapse
|
||||
FileTypeIcon
|
||||
FluentEmoji
|
||||
GuideCard
|
||||
Highlighter
|
||||
Hotkey
|
||||
Image
|
||||
List
|
||||
Markdown
|
||||
MaterialFileTypeIcon
|
||||
Mermaid
|
||||
Segmented
|
||||
Snippet
|
||||
SortableList
|
||||
Tag
|
||||
Tooltip
|
||||
Video
|
||||
- Data Entry
|
||||
AutoComplete
|
||||
CodeEditor
|
||||
ColorSwatches
|
||||
CopyButton
|
||||
DatePicker
|
||||
EditableText
|
||||
EmojiPicker
|
||||
Form
|
||||
FormModal
|
||||
HotkeyInput
|
||||
ImageSelect
|
||||
Input
|
||||
SearchBar
|
||||
Select
|
||||
SliderWithInput
|
||||
ThemeSwitch
|
||||
- Feedback
|
||||
Alert
|
||||
Drawer
|
||||
Modal
|
||||
- Layout
|
||||
DraggablePanel
|
||||
Footer
|
||||
Grid
|
||||
Header
|
||||
Layout
|
||||
MaskShadow
|
||||
ScrollShadow
|
||||
- Navigation
|
||||
Burger
|
||||
Dropdown
|
||||
Menu
|
||||
SideNav
|
||||
Tabs
|
||||
Toc
|
||||
- Theme
|
||||
ConfigProvider
|
||||
FontLoader
|
||||
ThemeProvider
|
||||
126
.cursor/rules/packages/react-layout-kit.mdc
Normal file
126
.cursor/rules/packages/react-layout-kit.mdc
Normal file
@@ -0,0 +1,126 @@
|
||||
---
|
||||
description: react flex layout package `react-layout-kit` usage
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# React Layout Kit 使用指南
|
||||
|
||||
`react-layout-kit` 是一个功能丰富的 React flex 布局组件库,在 lobe-chat 项目中被广泛使用。以下是重点组件的使用方法:
|
||||
|
||||
## Flexbox 组件
|
||||
|
||||
Flexbox 是最常用的布局组件,用于创建弹性布局,类似于 CSS 的 `display: flex`。
|
||||
|
||||
### 基本用法
|
||||
|
||||
```jsx
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
// 默认垂直布局
|
||||
<Flexbox>
|
||||
<div>子元素1</div>
|
||||
<div>子元素2</div>
|
||||
</Flexbox>
|
||||
|
||||
// 水平布局
|
||||
<Flexbox horizontal>
|
||||
<div>左侧元素</div>
|
||||
<div>右侧元素</div>
|
||||
</Flexbox>
|
||||
```
|
||||
|
||||
### 常用属性
|
||||
|
||||
- `horizontal`: 布尔值,设置为水平方向布局
|
||||
- `flex`: 数值或字符串,控制 flex 属性
|
||||
- `gap`: 数值,设置子元素之间的间距
|
||||
- `align`: 对齐方式,如 'center', 'flex-start' 等
|
||||
- `justify`: 主轴对齐方式,如 'space-between', 'center' 等
|
||||
- `padding`: 内边距值
|
||||
- `paddingInline`: 水平内边距值
|
||||
- `paddingBlock`: 垂直内边距值
|
||||
- `width/height`: 设置宽高,通常用 `'100%'` 或具体像素值
|
||||
- `style`: 自定义样式对象
|
||||
|
||||
### 实际应用示例
|
||||
|
||||
```jsx
|
||||
// 经典三栏布局
|
||||
<Flexbox horizontal height={'100%'} width={'100%'}>
|
||||
{/* 左侧边栏 */}
|
||||
<Flexbox
|
||||
width={260}
|
||||
style={{
|
||||
borderRight: `1px solid ${theme.colorBorderSecondary}`,
|
||||
height: '100%',
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
>
|
||||
<SidebarContent />
|
||||
</Flexbox>
|
||||
|
||||
{/* 中间内容区 */}
|
||||
<Flexbox
|
||||
flex={1}
|
||||
style={{
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
{/* 主要内容 */}
|
||||
<Flexbox flex={1} padding={24} style={{ overflowY: 'auto' }}>
|
||||
<MainContent />
|
||||
</Flexbox>
|
||||
|
||||
{/* 底部区域 */}
|
||||
<Flexbox
|
||||
style={{
|
||||
borderTop: `1px solid ${theme.colorBorderSecondary}`,
|
||||
padding: '16px 24px',
|
||||
}}
|
||||
>
|
||||
<Footer />
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
```
|
||||
|
||||
## Center 组件
|
||||
|
||||
Center 是对 Flexbox 的封装,使子元素水平和垂直居中。
|
||||
|
||||
### 基本用法
|
||||
|
||||
```jsx
|
||||
import { Center } from 'react-layout-kit';
|
||||
|
||||
<Center width={'100%'} height={'100%'}>
|
||||
<Content />
|
||||
</Center>
|
||||
```
|
||||
|
||||
Center 组件继承了 Flexbox 的所有属性,同时默认设置了居中对齐。主要用于快速创建居中布局。
|
||||
|
||||
### 实际应用示例
|
||||
|
||||
```jsx
|
||||
// 登录页面居中布局
|
||||
<Flexbox height={'100%'} width={'100%'}>
|
||||
<Center height={'100%'} width={'100%'}>
|
||||
<LoginForm />
|
||||
</Center>
|
||||
</Flexbox>
|
||||
|
||||
// 图标居中显示
|
||||
<Center className={styles.icon} flex={'none'} height={40} width={40}>
|
||||
<Icon icon={icon} size={24} />
|
||||
</Center>
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. 使用 `flex={1}` 让组件填充可用空间
|
||||
2. 使用 `gap` 代替传统的 margin 设置元素间距
|
||||
3. 嵌套 Flexbox 创建复杂布局
|
||||
4. 设置 `overflow: 'auto'` 使内容可滚动
|
||||
5. 使用 `horizontal` 创建水平布局,默认为垂直布局
|
||||
6. 与 `antd-style` 的 `useTheme` hook 配合使用创建主题响应式的布局
|
||||
46
.cursor/rules/project-introduce.mdc
Normal file
46
.cursor/rules/project-introduce.mdc
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
## Project Description
|
||||
|
||||
You are developing an open-source, modern-design AI chat framework: lobe chat.
|
||||
|
||||
Emoji logo: 🤯
|
||||
|
||||
|
||||
## Project Technologies Stack
|
||||
|
||||
read [package.json](mdc:package.json) to know all npm packages you can use.
|
||||
read [folder-structure.mdx](mdc:docs/development/basic/folder-structure.mdx) to learn project structure.
|
||||
|
||||
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
|
||||
- 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
|
||||
- aHooks for react hooks library
|
||||
- dayjs for date and time library
|
||||
- lodash-es for utility library
|
||||
- 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;
|
||||
68
.cursor/rules/react-component.mdc
Normal file
68
.cursor/rules/react-component.mdc
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
description:
|
||||
globs: *.tsx
|
||||
alwaysApply: false
|
||||
---
|
||||
# react component 编写指南
|
||||
|
||||
- 如果要写复杂样式的话用 antd-style ,简单的话可以用 style 属性直接写内联样式
|
||||
- 如果需要 flex 布局或者居中布局应该使用 react-layout-kit
|
||||
- 选择组件库中的组件时优先使用 [lobe-ui.mdc](mdc:.cursor/rules/package-usage/lobe-ui.mdc) 有的,然后才是 antd 的,不知道 @lobehub/ui 的组件怎么用,有哪些属性,就自己搜下这个项目其它地方怎么用的,不要瞎猜
|
||||
|
||||
## 访问 theme 的两种方式
|
||||
|
||||
### 使用 antd-style 的 useTheme hook
|
||||
|
||||
```tsx
|
||||
import { useTheme } from 'antd-style';
|
||||
|
||||
const MyComponent = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
color: theme.colorPrimary,
|
||||
backgroundColor: theme.colorBgContainer,
|
||||
padding: theme.padding,
|
||||
borderRadius: theme.borderRadius
|
||||
}}>
|
||||
使用主题 token 的组件
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 使用 antd-style 的 createStyles
|
||||
|
||||
```tsx
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
return {
|
||||
container: css`
|
||||
background-color: ${token.colorBgContainer};
|
||||
border-radius: ${token.borderRadius}px;
|
||||
padding: ${token.padding}px;
|
||||
color: ${token.colorText};
|
||||
`,
|
||||
title: css`
|
||||
font-size: ${token.fontSizeLG}px;
|
||||
font-weight: ${token.fontWeightStrong};
|
||||
margin-bottom: ${token.marginSM}px;
|
||||
`,
|
||||
content: css`
|
||||
font-size: ${token.fontSize}px;
|
||||
line-height: ${token.lineHeight};
|
||||
`
|
||||
};
|
||||
});
|
||||
|
||||
const Card: FC<CardProps> = ({ title, content }) => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<Flexbox className={styles.container}>
|
||||
<div className={styles.title}>{title}</div>
|
||||
<div className={styles.content}>{content}</div>
|
||||
</Flexbox>
|
||||
);
|
||||
};
|
||||
```
|
||||
6
.cursorindexingignore
Normal file
6
.cursorindexingignore
Normal file
@@ -0,0 +1,6 @@
|
||||
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
|
||||
locales/
|
||||
apps/desktop/resources/locales/
|
||||
**/__snapshots__/
|
||||
**/fixtures/
|
||||
src/database/migrations/
|
||||
Reference in New Issue
Block a user