From 1f6cb1a48f5fb12ba5be3f35dd165d7486a001d0 Mon Sep 17 00:00:00 2001 From: qzl Date: Fri, 6 Mar 2026 18:25:18 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20api=5Fexternal=5Furl=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=B9=B6=E5=AE=8C=E5=96=84=20runtime=20=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 SupabaseSettings 中未使用的 api_external_url computed field - 更新测试文件移除相关测试用例 - backend/AGENTS.md 新增软删除设计规则 - runtime-database.md 更新表结构(删除 user_agents,表名更新为 agent_chat_sessions/messages,system_agents) - runtime-frontend.md 补充路由结构和功能模块说明 - 根 AGENTS.md 清理过时技能路径引用 --- AGENTS.md | 3 - backend/AGENTS.md | 20 + backend/src/core/config/settings.py | 5 - .../tests/unit/test_settings_supabase_env.py | 14 - docs/runtime/runtime-database.md | 634 ++++++++++-------- docs/runtime/runtime-frontend.md | 167 ++++- 6 files changed, 523 insertions(+), 320 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index dea73e0..07e7112 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,7 +17,6 @@ social-app/ Follow this hierarchy when developing: ``` -~/.config/opencode/AGENTS.md # Global core rules (skills, agents, process) ├── This file (root AGENTS.md) # Project-level entry │ ├── backend/AGENTS.md # Backend-specific rules │ └── apps/AGENTS.md # Frontend-specific rules @@ -41,8 +40,6 @@ Follow this hierarchy when developing: ## Skills (Domain Knowledge) -Project-specific skills are available in `.opencode/skills/`: - | Skill | Purpose | When to Use | |-------|---------|-------------| | **ag-ui** | AG-UI protocol for agent-user interaction | Agent chat, streaming events, tool calls, state sync | diff --git a/backend/AGENTS.md b/backend/AGENTS.md index 5b71280..df8539c 100644 --- a/backend/AGENTS.md +++ b/backend/AGENTS.md @@ -164,6 +164,26 @@ Use `schemas / repository / service` pattern: - service_role key is backend-only; never expose credentials - Prohibit calling Supabase Admin API (service_role key) from repository/service layers +### Soft Delete + +**Soft delete marks data as invisible, not cascade delete.** + +- Use `deleted_at: datetime | None` column (via `SoftDeleteMixin`) +- **Query filtering**: Repository `_apply_soft_delete_filter()` auto-excludes deleted records +- **No automatic cascade**: Related data stays intact; visibility controlled by JOIN filtering +- **Cascade only for strong dependencies**: When parent deletion must invalidate children, implement in Service layer explicitly +- **Recovery**: Only restore the record itself; related data visibility restored automatically via queries +- **Unique constraints**: Use partial indexes excluding `deleted_at IS NOT NULL` to allow re-creation + +```python +# Partial unique index in migration +op.execute(""" + CREATE UNIQUE INDEX ux_user_email + ON users(email) + WHERE deleted_at IS NULL +""") +``` + ### Migrations - **Alembic is the single source of truth** for schema migrations diff --git a/backend/src/core/config/settings.py b/backend/src/core/config/settings.py index 4e5d016..718fc9e 100644 --- a/backend/src/core/config/settings.py +++ b/backend/src/core/config/settings.py @@ -128,11 +128,6 @@ class SupabaseSettings(BaseModel): def public_url(self) -> str: return f"{self.public_scheme}://{self.public_host}:{self.kong_http_port}" - @computed_field - @property - def api_external_url(self) -> str: - return self.public_url - @computed_field @property def url(self) -> str: diff --git a/backend/tests/unit/test_settings_supabase_env.py b/backend/tests/unit/test_settings_supabase_env.py index 9bfec42..7e5d755 100644 --- a/backend/tests/unit/test_settings_supabase_env.py +++ b/backend/tests/unit/test_settings_supabase_env.py @@ -23,27 +23,13 @@ def test_social_prefixed_supabase_env_populates_settings( settings = Settings() assert settings.supabase.public_url == "https://public.example:8443" - assert settings.supabase.api_external_url == "https://public.example:8443" assert settings.supabase.anon_key == "anon-key" assert settings.supabase.service_role_key == "service-key" assert settings.supabase.jwt_secret == "jwt-secret" supabase_settings = settings.model_dump()["supabase"] assert supabase_settings["public_url"] == "https://public.example:8443" - assert supabase_settings["api_external_url"] == "https://public.example:8443" assert supabase_settings["anon_key"] == "anon-key" assert supabase_settings["service_role_key"] == "service-key" assert supabase_settings["jwt_secret"] == "jwt-secret" assert settings.database_url == "postgresql+asyncpg://user:pass@db:5432/app" - - -def test_social_prefixed_api_external_url_is_loaded( - monkeypatch: MonkeyPatch, -) -> None: - monkeypatch.setenv("SOCIAL_SUPABASE__PUBLIC_SCHEME", "https") - monkeypatch.setenv("SOCIAL_SUPABASE__PUBLIC_HOST", "api.example") - monkeypatch.setenv("SOCIAL_SUPABASE__KONG_HTTP_PORT", "8443") - - settings = Settings() - - assert settings.supabase.api_external_url == "https://api.example:8443" diff --git a/docs/runtime/runtime-database.md b/docs/runtime/runtime-database.md index f0f1e1f..4731bb1 100644 --- a/docs/runtime/runtime-database.md +++ b/docs/runtime/runtime-database.md @@ -1,64 +1,106 @@ # Database Schema -**Status:** Active -**Reference:** [Plan: social-app 数据模型重设计](../plans/2026-02-26-social-data-model-redesign.md) +**Status:** Active +**Last Updated:** 2026-03-06 --- -## 枚举约定 +## 架构概览 + +### 数据库层职责 + +- **Supabase**: 认证(JWT 签发与验证) +- **Backend**: 业务授权(Service 层)、数据访问(Repository 层) +- **ORM**: SQLAlchemy(async + asyncpg,使用 service_role 连接) + +### 核心模块 + +| 模块 | 路径 | 说明 | +|------|------|------| +| Base Classes | `backend/src/core/db/` | ORM 基类、Session 管理、Repository 基类 | +| Models | `backend/src/models/` | 数据模型定义 | +| Migrations | `backend/alembic/versions/` | 数据库迁移脚本 | + +--- + +## 设计约定 + +### 枚举存储 + +**所有枚举使用字符串存储,不使用整数值:** -所有枚举使用字符串存储,不使用整数值: - Database: `VARCHAR(20)` + `CHECK` 约束 - Code: Python `Enum` 继承 `str` +```python +class AgentType(str, Enum): + INTENT_RECOGNITION = "INTENT_RECOGNITION" + TASK_EXECUTION = "TASK_EXECUTION" + RESULT_REPORTING = "RESULT_REPORTING" +``` + +### 软删除 + +**软删除标记数据为不可见,不级联删除:** + +- 使用 `deleted_at: datetime | None` 列(通过 `SoftDeleteMixin`) +- 查询过滤:Repository `_apply_soft_delete_filter()` 自动排除已删除记录 +- 级联策略:默认不级联,强依赖关系在 Service 层手动处理 +- 恢复策略:只恢复记录本身,关联数据通过查询自动恢复可见 +- 唯一约束:使用 partial index 排除 `deleted_at IS NOT NULL` + +```sql +-- Partial unique index in migration +CREATE UNIQUE INDEX ux_user_email +ON users(email) +WHERE deleted_at IS NULL +``` + --- ## 表清单 -| 表名 | 说明 | -|------|------| -| `profiles` | 用户资料(含 settings JSONB) | -| `user_agents` | 用户专属 Agent | -| `memories` | 用户/工作记忆 | -| `friendships` | 好友关系 | -| `groups` | 群组 | -| `group_members` | 群组成员 | -| `schedule_items` | 日程事项 | -| `schedule_subscriptions` | 日程订阅与权限 | -| `inbox_messages` | 待处理消息 | -| `todos` | 待办 | -| `todo_sources` | 待办与日程来源关联 | -| `automation_jobs` | 定时任务 | -| `sessions` | Agent 对话会话 | -| `messages` | 会话消息记录 | -| `llm_factory` | LLM 工厂配置 | -| `llms` | LLM 模型实例 | -| `user_agent_catalog` | Agent 类型目录 | -| `invite_codes` | 邀请码 | +| 表名 | 说明 | 状态 | +|------|------|------| +| `profiles` | 用户资料(含 settings JSONB) | Active | +| `memories` | 用户记忆 | Active | +| `friendships` | 好友关系 | Active | +| `groups` | 群组 | Active | +| `group_members` | 群组成员 | Active | +| `schedule_items` | 日程事项 | Active | +| `schedule_subscriptions` | 日程订阅与权限 | Active | +| `inbox_messages` | 待处理消息 | Active | +| `todos` | 待办 | Active | +| `todo_sources` | 待办与日程来源关联 | Active | +| `automation_jobs` | 定时任务 | Active | +| `agent_chat_sessions` | Agent 对话会话 | Active | +| `agent_chat_messages` | 会话消息记录 | Active | +| `llm_factory` | LLM 工厂配置 | Active | +| `llms` | LLM 模型实例 | Active | +| `system_agents` | 系统级 Agent 配置 | Active | +| `invite_codes` | 邀请码 | Active | --- -## 表结构 +## 表结构详细 ### profiles -用户资料表,含内置设置。 +用户资料表,含用户设置。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK,`auth.users.id` | -| `username` | VARCHAR(30) | 用户名 | -| `avatar_url` | TEXT | 头像 URL | -| `bio` | VARCHAR(200) | 个人简介 | -| `settings` | JSONB | 用户设置 | -| `referred_by` | UUID | 邀请人 ID | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK, FK → auth.users.id | 用户 ID | +| `username` | VARCHAR(30) | UNIQUE, NOT NULL | 用户名 | +| `avatar_url` | TEXT | NULLABLE | 头像 URL | +| `bio` | VARCHAR(200) | NULLABLE | 个人简介 | +| `settings` | JSONB | NOT NULL, DEFAULT '{}' | 用户设置 | +| `referred_by` | UUID | NULLABLE, FK → profiles.id | 邀请人 ID | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**约束:** `username` 唯一 - -**settings JSONB 默认结构:** +**settings JSONB 结构:** ```json { "version": 1, @@ -67,6 +109,10 @@ "ai_language": "zh-CN", "timezone": "Asia/Shanghai" }, + "agent_prompts": { + "INTENT_RECOGNITION": "自定义提示词...", + "TASK_EXECUTION": "自定义提示词..." + }, "privacy": {}, "notification": {} } @@ -74,46 +120,21 @@ --- -### user_agents - -用户专属 Agent 配置。 - -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `user_id` | UUID | 用户 ID | -| `llm_id` | UUID | 关联的 LLM 模型 | -| `agent_type` | VARCHAR(20) | 枚举:`INTENT_RECOGNITION`, `TASK_EXECUTION`, `RESULT_REPORTING` | -| `config` | JSONB | Agent 配置参数 | -| `status` | VARCHAR(20) | 状态:`active`, `paused`, `migrating` | -| `created_by` | UUID | 创建者 | -| `updated_by` | UUID | 更新者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | - -**约束:** `(user_id, agent_type)` 唯一 - ---- - ### memories -用户与工作记忆。 +用户记忆。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `owner_id` | UUID | 用户 ID | -| `agent_id` | UUID | Agent ID(work 类型必填) | -| `memory_type` | VARCHAR(20) | 枚举:`user`, `work` | -| `title` | VARCHAR(255) | 标题 | -| `content` | JSONB | 记忆内容 | -| `source` | VARCHAR(20) | 来源:`manual`, `agent`, `imported` | -| `status` | VARCHAR(20) | 状态:`active`, `disabled` | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | - -**约束:** work 类型必须有 agent_id,user 类型必须无 agent_id +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 记忆 ID | +| `owner_id` | UUID | NOT NULL, FK → profiles.id | 所有者 ID | +| `memory_type` | VARCHAR(20) | NOT NULL, CHECK | 枚举:`user`, `work` | +| `title` | VARCHAR(255) | NOT NULL | 标题 | +| `content` | JSONB | NOT NULL | 记忆内容 | +| `source` | VARCHAR(20) | NOT NULL | 来源:`manual`, `agent`, `imported` | +| `status` | VARCHAR(20) | NOT NULL | 状态:`active`, `disabled` | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | **content JSONB 示例:** ```json @@ -130,23 +151,25 @@ 好友关系(双向规范化)。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `user_low_id` | UUID | 较小 UUID | -| `user_high_id` | UUID | 较大 UUID | -| `initiator_id` | UUID | 发起方用户 ID | -| `status` | VARCHAR(20) | 状态:`pending`, `accepted`, `blocked`, `declined`, `canceled` | -| `requested_at` | TIMESTAMPTZ | 请求时间 | -| `accepted_at` | TIMESTAMPTZ | 接受时间 | -| `blocked_by` | UUID | 阻止者用户 ID | -| `created_by` | UUID | 创建者 | -| `updated_by` | UUID | 更新者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 关系 ID | +| `user_low_id` | UUID | NOT NULL | 较小 UUID | +| `user_high_id` | UUID | NOT NULL | 较大 UUID | +| `initiator_id` | UUID | NOT NULL | 发起方用户 ID | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`pending`, `accepted`, `blocked`, `declined`, `canceled` | +| `requested_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 请求时间 | +| `accepted_at` | TIMESTAMPTZ | NULLABLE | 接受时间 | +| `blocked_by` | UUID | NULLABLE | 阻止者用户 ID | +| `created_by` | UUID | NULLABLE | 创建者 | +| `updated_by` | UUID | NULLABLE | 更新者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**约束:** `user_low_id < user_high_id`,`(user_low_id, user_high_id)` 唯一 +**约束:** +- `user_low_id < user_high_id` +- `UNIQUE(user_low_id, user_high_id)` --- @@ -154,18 +177,18 @@ 群组。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `name` | VARCHAR(100) | 群组名称 | -| `description` | TEXT | 群组描述 | -| `owner_id` | UUID | 创建者 ID | -| `status` | VARCHAR(20) | 状态:`active`, `archived` | -| `created_by` | UUID | 创建者 | -| `updated_by` | UUID | 更新者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 群组 ID | +| `name` | VARCHAR(100) | NOT NULL | 群组名称 | +| `description` | TEXT | NULLABLE | 群组描述 | +| `owner_id` | UUID | NOT NULL, FK → profiles.id | 创建者 ID | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`active`, `archived` | +| `created_by` | UUID | NULLABLE | 创建者 | +| `updated_by` | UUID | NULLABLE | 更新者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | --- @@ -173,24 +196,24 @@ 群组成员。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `group_id` | UUID | 群组 ID | -| `user_id` | UUID | 用户 ID | -| `role` | VARCHAR(20) | 角色:`owner`, `admin`, `member` | -| `join_source` | VARCHAR(20) | 加入方式:`invited`, `joined` | -| `invited_by` | UUID | 邀请人 ID | -| `joined_at` | TIMESTAMPTZ | 加入时间 | -| `removed_at` | TIMESTAMPTZ | 移除时间 | -| `status` | VARCHAR(20) | 状态:`active`, `muted`, `removed` | -| `created_by` | UUID | 创建者 | -| `updated_by` | UUID | 更新者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 成员 ID | +| `group_id` | UUID | NOT NULL, FK → groups.id | 群组 ID | +| `user_id` | UUID | NOT NULL, FK → profiles.id | 用户 ID | +| `role` | VARCHAR(20) | NOT NULL, CHECK | 角色:`owner`, `admin`, `member` | +| `join_source` | VARCHAR(20) | NOT NULL | 加入方式:`invited`, `joined` | +| `invited_by` | UUID | NULLABLE, FK → profiles.id | 邀请人 ID | +| `joined_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 加入时间 | +| `removed_at` | TIMESTAMPTZ | NULLABLE | 移除时间 | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`active`, `muted`, `removed` | +| `created_by` | UUID | NULLABLE | 创建者 | +| `updated_by` | UUID | NULLABLE | 更新者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**约束:** `(group_id, user_id)` 唯一 +**约束:** `UNIQUE(group_id, user_id)` --- @@ -198,25 +221,25 @@ 日程事项。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `owner_id` | UUID | 所有者 ID | -| `title` | VARCHAR(255) | 标题 | -| `description` | TEXT | 描述 | -| `start_at` | TIMESTAMPTZ | 开始时间 | -| `end_at` | TIMESTAMPTZ | 结束时间 | -| `timezone` | VARCHAR(50) | 时区 | -| `metadata` | JSONB | 扩展字段 | -| `recurrence_rule` | VARCHAR(255) | 循环规则 | -| `source_type` | VARCHAR(20) | 来源:`manual`, `imported`, `agent_generated` | -| `status` | VARCHAR(20) | 状态:`active`, `completed`, `canceled`, `archived` | -| `created_by` | UUID | 创建者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 事项 ID | +| `owner_id` | UUID | NOT NULL, FK → profiles.id | 所有者 ID | +| `title` | VARCHAR(255) | NOT NULL | 标题 | +| `description` | TEXT | NULLABLE | 描述 | +| `start_at` | TIMESTAMPTZ | NOT NULL | 开始时间 | +| `end_at` | TIMESTAMPTZ | NULLABLE | 结束时间 | +| `timezone` | VARCHAR(50) | NOT NULL, DEFAULT 'UTC' | 时区 | +| `metadata` | JSONB | NOT NULL, DEFAULT '{}' | 扩展字段 | +| `recurrence_rule` | VARCHAR(255) | NULLABLE | 循环规则 | +| `source_type` | VARCHAR(20) | NOT NULL, CHECK | 来源:`manual`, `imported`, `agent_generated` | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`active`, `completed`, `canceled`, `archived` | +| `created_by` | UUID | NULLABLE | 创建者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**metadata JSONB 默认结构:** +**metadata JSONB 结构:** ```json { "color": "#FF6B6B", @@ -246,19 +269,21 @@ 日程订阅与权限。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `item_id` | UUID | 日程事项 ID | -| `subscriber_id` | UUID | 订阅者 ID | -| `permission` | INTEGER | 权限位图(view=1, invite=2, edit=4),默认 1 | -| `notify_level` | VARCHAR(20) | 通知级别:`all`, `mentions`, `none`,默认 `all` | -| `status` | VARCHAR(20) | 状态:`active`, `paused`, `unsubscribed`,默认 `active` | -| `created_by` | UUID | 创建者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 订阅 ID | +| `item_id` | UUID | NOT NULL, FK → schedule_items.id | 日程事项 ID | +| `subscriber_id` | UUID | NOT NULL, FK → profiles.id | 订阅者 ID | +| `permission` | INTEGER | NOT NULL, CHECK, DEFAULT 1 | 权限位图(view=1, invite=2, edit=4) | +| `notify_level` | VARCHAR(20) | NOT NULL, DEFAULT 'all' | 通知级别:`all`, `mentions`, `none` | +| `status` | VARCHAR(20) | NOT NULL, DEFAULT 'active' | 状态:`active`, `paused`, `unsubscribed` | +| `created_by` | UUID | NULLABLE | 创建者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | -**约束:** `(item_id, subscriber_id)` 唯一,`permission BETWEEN 0 AND 7` +**约束:** +- `UNIQUE(item_id, subscriber_id)` +- `permission BETWEEN 0 AND 7` --- @@ -266,21 +291,21 @@ 待处理消息(接收者视角)。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `recipient_id` | UUID | 接收者 ID | -| `sender_id` | UUID | 发送者 ID(系统消息可为 NULL) | -| `message_type` | VARCHAR(20) | 类型:`friend_request`, `calendar`, `system`, `group` | -| `friendship_id` | UUID | 好友请求关联(friend_request 时必填) | -| `schedule_item_id` | UUID | 日程关联(calendar 时必填) | -| `group_id` | UUID | 群组关联(group 时必填) | -| `content` | TEXT | 消息内容(system 用) | -| `is_read` | BOOLEAN | 是否已读,默认 false | -| `status` | VARCHAR(20) | 状态:`pending`, `accepted`, `rejected`, `dismissed` | -| `created_by` | UUID | 创建者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 消息 ID | +| `recipient_id` | UUID | NOT NULL, FK → profiles.id | 接收者 ID | +| `sender_id` | UUID | NULLABLE, FK → profiles.id | 发送者 ID(系统消息可为 NULL) | +| `message_type` | VARCHAR(20) | NOT NULL, CHECK | 类型:`friend_request`, `calendar`, `system`, `group` | +| `friendship_id` | UUID | NULLABLE, FK → friendships.id | 好友请求关联(friend_request 时必填) | +| `schedule_item_id` | UUID | NULLABLE, FK → schedule_items.id | 日程关联(calendar 时必填) | +| `group_id` | UUID | NULLABLE, FK → groups.id | 群组关联(group 时必填) | +| `content` | TEXT | NULLABLE | 消息内容(system 用) | +| `is_read` | BOOLEAN | NOT NULL, DEFAULT false | 是否已读 | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`pending`, `accepted`, `rejected`, `dismissed` | +| `created_by` | UUID | NULLABLE | 创建者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | **message_type 与业务字段对应:** | message_type | 必填字段 | @@ -298,20 +323,20 @@ 待办事项。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `owner_id` | UUID | 所有者 ID | -| `title` | VARCHAR(255) | 标题 | -| `description` | VARCHAR(1000) | 描述 | -| `due_at` | TIMESTAMPTZ | 截止时间 | -| `priority` | INTEGER | 优先级(1-4,1=重要且紧急) | -| `status` | VARCHAR(20) | 状态:`pending`, `done`, `canceled` | -| `completed_at` | TIMESTAMPTZ | 完成时间 | -| `created_by` | UUID | 创建者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 待办 ID | +| `owner_id` | UUID | NOT NULL, FK → profiles.id | 所有者 ID | +| `title` | VARCHAR(255) | NOT NULL | 标题 | +| `description` | VARCHAR(1000) | NULLABLE | 描述 | +| `due_at` | TIMESTAMPTZ | NULLABLE | 截止时间 | +| `priority` | INTEGER | NOT NULL, CHECK, DEFAULT 3 | 优先级(1-4,1=重要且紧急) | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`pending`, `done`, `canceled` | +| `completed_at` | TIMESTAMPTZ | NULLABLE | 完成时间 | +| `created_by` | UUID | NULLABLE | 创建者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | **约束:** `priority BETWEEN 1 AND 4` @@ -321,15 +346,15 @@ 待办与日程来源关联。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `todo_id` | UUID | 待办 ID | -| `schedule_item_id` | UUID | 日程事项 ID | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 关联 ID | +| `todo_id` | UUID | NOT NULL, FK → todos.id ON DELETE CASCADE | 待办 ID | +| `schedule_item_id` | UUID | NOT NULL, FK → schedule_items.id ON DELETE CASCADE | 日程事项 ID | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | -**约束:** `(todo_id, schedule_item_id)` 唯一 +**约束:** `UNIQUE(todo_id, schedule_item_id)` --- @@ -337,75 +362,77 @@ 自动化定时任务。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `owner_id` | UUID | 所有者 ID | -| `title` | VARCHAR(255) | 任务标题 | -| `prompt` | TEXT | AI 执行 prompt | -| `schedule_type` | VARCHAR(20) | 调度类型:`daily`, `weekly` | -| `run_at` | TIMESTAMPTZ | 首次运行时间 | -| `next_run_at` | TIMESTAMPTZ | 下次运行时间 | -| `timezone` | VARCHAR(50) | 时区 | -| `last_run_at` | TIMESTAMPTZ | 最近运行时间 | -| `status` | VARCHAR(20) | 状态:`active`, `disabled` | -| `created_by` | UUID | 创建者 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 任务 ID | +| `owner_id` | UUID | NOT NULL, FK → profiles.id | 所有者 ID | +| `title` | VARCHAR(255) | NOT NULL | 任务标题 | +| `prompt` | TEXT | NOT NULL | AI 执行 prompt | +| `schedule_type` | VARCHAR(20) | NOT NULL, CHECK | 调度类型:`daily`, `weekly` | +| `run_at` | TIMESTAMPTZ | NOT NULL | 首次运行时间 | +| `next_run_at` | TIMESTAMPTZ | NULLABLE | 下次运行时间 | +| `timezone` | VARCHAR(50) | NOT NULL, DEFAULT 'UTC' | 时区 | +| `last_run_at` | TIMESTAMPTZ | NULLABLE | 最近运行时间 | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`active`, `disabled` | +| `created_by` | UUID | NULLABLE | 创建者 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**约束:** `(id, owner_id)` 唯一 +**约束:** `UNIQUE(id, owner_id)` --- -### sessions +### agent_chat_sessions Agent 对话会话。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `user_id` | UUID | 用户 ID | -| `session_type` | VARCHAR(20) | 会话类型:`chat`, `automation` | -| `job_id` | UUID | 自动化任务 ID(automation 时必填) | -| `title` | VARCHAR(255) | 会话标题 | -| `status` | VARCHAR(20) | 状态:`pending`, `running`, `completed`, `failed` | -| `last_activity_at` | TIMESTAMPTZ | 最后活跃时间 | -| `message_count` | INTEGER | 消息计数,默认 0 | -| `total_tokens` | INTEGER | 总 token 数,默认 0 | -| `total_cost` | NUMERIC(12,6) | 总费用,默认 0 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 会话 ID | +| `user_id` | UUID | NOT NULL, FK → profiles.id | 用户 ID | +| `session_type` | VARCHAR(20) | NOT NULL, CHECK | 会话类型:`chat`, `automation` | +| `job_id` | UUID | NULLABLE, FK → automation_jobs.id ON DELETE RESTRICT | 自动化任务 ID(automation 时必填) | +| `title` | VARCHAR(255) | NULLABLE | 会话标题 | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`pending`, `running`, `completed`, `failed` | +| `last_activity_at` | TIMESTAMPTZ | NULLABLE | 最后活跃时间 | +| `message_count` | INTEGER | NOT NULL, DEFAULT 0 | 消息计数 | +| `total_tokens` | INTEGER | NOT NULL, DEFAULT 0 | 总 token 数 | +| `total_cost` | NUMERIC(12,6) | NOT NULL, DEFAULT 0 | 总费用 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**约束:** `session_type='chat' → job_id IS NULL`, `session_type='automation' → job_id IS NOT NULL` +**约束:** +- `session_type='chat' → job_id IS NULL` +- `session_type='automation' → job_id IS NOT NULL` --- -### messages +### agent_chat_messages 会话消息记录。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `session_id` | UUID | 会话 ID | -| `seq` | INTEGER | 消息序号 | -| `role` | VARCHAR(20) | 角色:`user`, `assistant`, `system`, `tool` | -| `content` | TEXT | 消息内容 | -| `model_code` | VARCHAR(50) | 模型标识 | -| `tool_name` | VARCHAR(100) | 工具名称 | -| `input_tokens` | INTEGER | 输入 token 数,默认 0 | -| `output_tokens` | INTEGER | 输出 token 数,默认 0 | -| `cost` | NUMERIC(12,6) | 费用,默认 0 | -| `currency` | VARCHAR(3) | 货币,默认 USD | -| `latency_ms` | INTEGER | 延迟(毫秒) | -| `metadata` | JSONB | 扩展字段 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 消息 ID | +| `session_id` | UUID | NOT NULL, FK → agent_chat_sessions.id | 会话 ID | +| `seq` | INTEGER | NOT NULL | 消息序号 | +| `role` | VARCHAR(20) | NOT NULL, CHECK | 角色:`user`, `assistant`, `system`, `tool` | +| `content` | TEXT | NOT NULL | 消息内容 | +| `model_code` | VARCHAR(50) | NULLABLE | 模型标识 | +| `tool_name` | VARCHAR(100) | NULLABLE | 工具名称 | +| `input_tokens` | INTEGER | NOT NULL, DEFAULT 0 | 输入 token 数 | +| `output_tokens` | INTEGER | NOT NULL, DEFAULT 0 | 输出 token 数 | +| `cost` | NUMERIC(12,6) | NOT NULL, DEFAULT 0 | 费用 | +| `currency` | VARCHAR(3) | NOT NULL, DEFAULT 'USD' | 货币 | +| `latency_ms` | INTEGER | NULLABLE | 延迟(毫秒) | +| `metadata` | JSONB | NOT NULL, DEFAULT '{}' | 扩展字段 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | -**约束:** `(session_id, seq)` 唯一 +**约束:** `UNIQUE(session_id, seq)` --- @@ -413,17 +440,15 @@ Agent 对话会话。 LLM 工厂配置。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `name` | VARCHAR(50) | 工厂名称 | -| `request_url` | VARCHAR(255) | API 请求 URL | -| `avatar` | TEXT | 头像 URL | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | - -**约束:** `name` 唯一 +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 工厂 ID | +| `name` | VARCHAR(50) | UNIQUE, NOT NULL | 工厂名称 | +| `request_url` | VARCHAR(255) | NOT NULL | API 请求 URL | +| `avatar` | TEXT | NULLABLE | 头像 URL | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | --- @@ -431,31 +456,34 @@ LLM 工厂配置。 LLM 模型实例。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `factory_id` | UUID | 工厂 ID | -| `model_code` | VARCHAR(50) | 模型标识 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | -| `deleted_at` | TIMESTAMPTZ | 软删时间 | - -**约束:** `model_code` 唯一 +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 模型 ID | +| `factory_id` | UUID | NOT NULL, FK → llm_factory.id ON DELETE RESTRICT | 工厂 ID | +| `model_code` | VARCHAR(50) | UNIQUE, NOT NULL | 模型标识 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | +| `deleted_at` | TIMESTAMPTZ | NULLABLE | 软删时间 | --- -### user_agent_catalog +### system_agents -Agent 类型目录。 +系统级 Agent 配置(原 user_agent_catalog)。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `agent_type` | VARCHAR(20) | PK,Agent 类型 | -| `llm_id` | UUID | 关联的 LLM 模型 | -| `status` | VARCHAR(20) | 状态:`active`, `paused`, `migrating` | -| `config` | JSONB | Agent 配置参数 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `agent_type` | VARCHAR(20) | PK, CHECK | Agent 类型 | +| `llm_id` | UUID | NOT NULL, FK → llms.id ON DELETE RESTRICT | 关联的 LLM 模型 | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`active`, `paused`, `migrating` | +| `config` | JSONB | NOT NULL, DEFAULT '{}' | Agent 配置参数 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | + +**agent_type 枚举值:** +- `INTENT_RECOGNITION` - 意图识别 +- `TASK_EXECUTION` - 任务执行 +- `RESULT_REPORTING` - 结果报告 --- @@ -463,33 +491,37 @@ Agent 类型目录。 邀请码。 -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | UUID | PK | -| `code` | VARCHAR(8) | 邀请码(8 位大写字母数字) | -| `owner_id` | UUID | 拥有者 ID | -| `status` | VARCHAR(20) | 状态:`active`, `disabled`, `expired` | -| `used_count` | INTEGER | 已使用次数,默认 0 | -| `max_uses` | INTEGER | 最大使用次数 | -| `expires_at` | TIMESTAMPTZ | 过期时间 | -| `reward_config` | JSONB | 奖励配置 | -| `created_at` | TIMESTAMPTZ | 创建时间 | -| `updated_at` | TIMESTAMPTZ | 更新时间 | +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| `id` | UUID | PK | 邀请码 ID | +| `code` | VARCHAR(8) | UNIQUE, NOT NULL, CHECK | 邀请码(8 位大写字母数字) | +| `owner_id` | UUID | NOT NULL, FK → profiles.id | 拥有者 ID | +| `status` | VARCHAR(20) | NOT NULL, CHECK | 状态:`active`, `disabled`, `expired` | +| `used_count` | INTEGER | NOT NULL, DEFAULT 0, CHECK | 已使用次数 | +| `max_uses` | INTEGER | NULLABLE | 最大使用次数 | +| `expires_at` | TIMESTAMPTZ | NULLABLE | 过期时间 | +| `reward_config` | JSONB | NULLABLE | 奖励配置 | +| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 创建时间 | +| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 更新时间 | -**约束:** `code` 唯一,`code` 符合 `[ABCDEFGHJKMNPQRSTUVWXYZ23456789]{8}`,`used_count >= 0` +**约束:** +- `code` 符合 `[ABCDEFGHJKMNPQRSTUVWXYZ23456789]{8}` +- `used_count >= 0` --- ## 外键删除策略 -| 外键 | 删除策略 | -|------|----------| -| `sessions.job_id` | RESTRICT | -| `todo_sources.todo_id` | CASCADE | -| `todo_sources.schedule_item_id` | CASCADE | -| `inbox_messages.friendship_id` | CASCADE | -| `inbox_messages.schedule_item_id` | CASCADE | -| `inbox_messages.group_id` | CASCADE | +| 外键 | 删除策略 | 说明 | +|------|----------|------| +| `agent_chat_sessions.job_id` | RESTRICT | 禁止删除正在使用的自动化任务 | +| `todo_sources.todo_id` | CASCADE | 删除待办时级联删除关联 | +| `todo_sources.schedule_item_id` | CASCADE | 删除日程时级联删除关联 | +| `inbox_messages.friendship_id` | CASCADE | 删除好友关系时级联删除消息 | +| `inbox_messages.schedule_item_id` | CASCADE | 删除日程时级联删除消息 | +| `inbox_messages.group_id` | CASCADE | 删除群组时级联删除消息 | +| `llms.factory_id` | RESTRICT | 禁止删除正在使用的工厂配置 | +| `system_agents.llm_id` | RESTRICT | 禁止删除正在使用的 LLM 模型 | --- @@ -499,3 +531,15 @@ Agent 类型目录。 - `anon`: 全部 DENY - `authenticated`: 全部 DENY - `service_role`: 由后端服务连接,不依赖 RLS + +**例外:** 迁移表 `alembic_version` 不暴露给任何角色。 + +--- + +## Change Log + +| 日期 | 变更 | +|------|------| +| 2026-03-06 | 删除 `user_agents` 表,重命名 `user_agent_catalog` → `system_agents`,更新 `agent_chat_sessions` / `agent_chat_messages` 表名,删除 `memories.agent_id` 字段 | +| 2026-02-28 | 新增 `invite_codes` 表、`profiles.referred_by` 字段 | +| 2026-02-26 | 初始版本,基于数据模型重设计 | diff --git a/docs/runtime/runtime-frontend.md b/docs/runtime/runtime-frontend.md index 769d2d4..406731f 100644 --- a/docs/runtime/runtime-frontend.md +++ b/docs/runtime/runtime-frontend.md @@ -1,11 +1,21 @@ -# Frontend Runtime Runbook +# Frontend Runtime -**Date:** 2026-02-27 -**Status:** Active +**Date:** 2026-03-06 +**Status:** Active **Audience:** 前端开发 --- +## 技术栈 + +- **Framework:** Flutter (Dart) +- **Routing:** go_router +- **State Management:** BLoC + Cubit +- **API Client:** Dio + Retrofit +- **Mock Mode:** 支持 `--dart-define=MOCK_API=true` + +--- + ## 开发环境 ### Mock 模式 @@ -35,6 +45,156 @@ Mock 模式下,启动 App 时会自动使用测试账号登录并跳转到首 --- +## 路由结构 + +### 认证路由(无需登录) + +| 路由 | 页面 | 说明 | +|------|------|------| +| `/` | LoginScreen | 登录页(默认首页) | +| `/register` | RegisterScreen | 注册页 | +| `/register/verification` | RegisterVerificationScreen | 注册验证码页 | +| `/reset-password` | ResetPasswordScreen | 重置密码页 | + +### 受保护路由(需要登录) + +| 路由 | 页面 | 说明 | +|------|------|------| +| `/home` | HomeScreen | 首页(AI 助手) | +| `/contacts` | ContactsScreen | 通讯录 | +| `/contacts/add` | AddContactScreen | 添加联系人 | +| `/calendar/month` | CalendarMonthScreen | 月视图 | +| `/calendar/dayweek` | CalendarDayweekScreen | 日/周视图 | +| `/calendar/events/:id` | CalendarEventDetailScreen | 日程详情 | +| `/todo` | TodoQuadrantsScreen | 待办四象限 | +| `/messages/invites` | MessageInviteListScreen | 消息邀请列表 | +| `/messages/invites/:id` | MessageInviteDetailScreen | 消息邀请详情 | +| `/settings` | SettingsScreen | 设置首页 | +| `/settings/features` | FeaturesScreen | 功能开关 | +| `/settings/memory` | MemoryScreen | 记忆管理 | +| `/settings/account` | AccountScreen | 账号设置 | + +--- + +## 功能模块 + +### Auth(认证) + +**路径:** `apps/lib/features/auth/` + +| 文件 | 说明 | +|------|------| +| `presentation/bloc/auth_bloc.dart` | 认证状态管理 | +| `presentation/cubits/` | 登录/注册/重置密码 Cubit | +| `ui/screens/` | 认证相关页面 | +| `data/repositories/auth_repository.dart` | 认证 API 调用 | + +**流程:** +1. 注册: `/register` → 输入邮箱/用户名/密码 → `/register/verification` → 输入验证码 → `/home` +2. 登录: `/` → 输入邮箱/密码 → `/home` +3. 重置密码: `/reset-password` → 输入邮箱 → 收到邮件 → 输入验证码+新密码 → `/` + +--- + +### Home(首页/AI 助手) + +**路径:** `apps/lib/features/home/` + +| 文件 | 说明 | +|------|------| +| `ui/screens/home_screen.dart` | 首页(AI 助手入口) | +| `ui/screens/home_sheet.dart` | 首页底部弹出面板 | + +**功能:** +- AI 助手对话入口 +- 快速访问常用功能 + +--- + +### Calendar(日历) + +**路径:** `apps/lib/features/calendar/` + +| 文件 | 说明 | +|------|------| +| `ui/screens/calendar_month_screen.dart` | 月视图 | +| `ui/screens/calendar_dayweek_screen.dart` | 日/周视图 | +| `ui/screens/calendar_event_detail_screen.dart` | 日程详情 | +| `ui/calendar_time_utils.dart` | 时间工具函数 | + +**功能:** +- 月/日/周三视图切换 +- 日程创建/编辑/删除 +- 日程分享 + +--- + +### Todo(待办) + +**路径:** `apps/lib/features/todo/` + +| 文件 | 说明 | +|------|------| +| `ui/screens/todo_quadrants_screen.dart` | 四象限视图 | +| `ui/screens/todo_detail_screen.dart` | 待办详情 | + +**功能:** +- 四象限管理(重要/紧急矩阵) +- 待办创建/编辑/完成/删除 + +--- + +### Contacts(通讯录) + +**路径:** `apps/lib/features/contacts/` + +| 文件 | 说明 | +|------|------| +| `ui/screens/contacts_screen.dart` | 通讯录列表 | +| `ui/screens/add_contact_screen.dart` | 添加联系人 | + +**功能:** +- 好友列表 +- 搜索用户 +- 添加好友 + +--- + +### Messages(消息) + +**路径:** `apps/lib/features/messages/` + +| 文件 | 说明 | +|------|------| +| `ui/screens/message_invite_list_screen.dart` | 邀请消息列表 | +| `ui/screens/message_invite_detail_screen.dart` | 邀请详情 | + +**功能:** +- 日程邀请通知 +- 好友请求通知 +- 群组邀请通知 + +--- + +### Settings(设置) + +**路径:** `apps/lib/features/settings/` + +| 文件 | 说明 | +|------|------| +| `ui/screens/settings_screen.dart` | 设置首页 | +| `ui/screens/features_screen.dart` | 功能开关 | +| `ui/screens/memory_screen.dart` | 记忆管理 | +| `ui/screens/account_screen.dart` | 账号设置 | + +**功能:** +- 个人资料编辑 +- 记忆管理(用户/工作记忆) +- 功能开关 +- 账号安全设置 + +--- + ## 打包构建 ### Debug Build @@ -100,4 +260,5 @@ flutter run -d emulator-5554 | 日期 | 变更 | |------|------| +| 2026-03-06 | 完善路由结构、功能模块说明,补充技术栈信息 | | 2026-02-27 | 新增 Frontend Runbook,支持 --dart-define=MOCK_API=true 切换 Mock 模式 |