Files
nexus/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md
2026-04-23 19:25:35 +08:00

262 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
`DATA_MODEL.md` 的核心目标是:**让 AI 在触碰任何数据相关代码时,都能理解业务语义,而不只是看到一堆字段名。**
---
### 必须包含的内容
#### 1. 领域概览Domain Overview
用业务语言(不是技术语言)描述核心概念和它们的关系。这是 AI 理解"为什么"的基础。
md
```md
## Domain Overview
This is a **multi-tenant** project management tool.
Core concepts:
- **Workspace**: The top-level container, maps to a paying customer (company)
- **Project**: Lives inside a Workspace, has a lifecycle (draft → active → archived)
- **Task**: The atomic unit of work, always belongs to a Project
- **Member**: A User's role within a specific Workspace (not global)
Key business rules:
- A User can belong to multiple Workspaces with different roles
- Deleting a Project soft-deletes all its Tasks (never hard delete)
- Only Workspace `owner` or `admin` can invite new Members
```
---
#### 2. 实体关系图Entity Relationship
用文字或 ASCII 图表达清楚关系,不要依赖读者去脑补。
md
```md
## Entity Relationships
Workspace (1) ──── (N) Project
Workspace (1) ──── (N) Member
Member (N) ──── (1) User ← same User, different roles per Workspace
Project (1) ──── (N) Task
Task (N) ──── (1) Member ← assignee
Task (1) ──── (N) Comment
Task (N) ──── (N) Tag ← via task_tags join table
```
---
#### 3. 完整 Schema 定义Schema Definition
每个表都需要:字段 + 类型 + 约束 + **业务注释**。注释是给 AI 的关键上下文。
md
```md
## Schema
### workspaces
| Column | Type | Constraints | Notes |
|--------------|-------------|-------------------|--------------------------------|
| id | uuid | PK, default gen | |
| slug | text | UNIQUE, NOT NULL | URL identifier, immutable after creation |
| name | text | NOT NULL | |
| plan | text | NOT NULL | enum: 'free' | 'pro' | 'enterprise' |
| created_at | timestamptz | NOT NULL, default now() | |
| deleted_at | timestamptz | nullable | soft delete, filter WHERE deleted_at IS NULL |
### members
| Column | Type | Constraints | Notes |
|--------------|-------------|-------------------|--------------------------------|
| id | uuid | PK | |
| workspace_id | uuid | FK → workspaces.id, CASCADE DELETE | |
| user_id | uuid | FK → users.id | |
| role | text | NOT NULL | enum: 'owner' \| 'admin' \| 'member' \| 'viewer' |
| invited_by | uuid | FK → members.id, nullable | null = founding owner |
| joined_at | timestamptz | nullable | null = invitation pending |
-- UNIQUE(workspace_id, user_id) — one membership per workspace per user
```
---
#### 4. 枚举与常量Enums & Constants
把所有枚举值集中在一处AI 就不会自己发明状态值。
md
```md
## Enums & Constants
### Task Status (ordered, represents workflow progression)
pending → in_progress → in_review → done → cancelled
Rules:
- Only forward transitions are allowed (no reopening cancelled tasks)
- `done` and `cancelled` are terminal states
- Changing status logs an entry in task_activity
### Member Role Permissions
| Action | owner | admin | member | viewer |
|---------------------|-------|-------|--------|--------|
| Invite members | ✅ | ✅ | ❌ | ❌ |
| Delete project | ✅ | ❌ | ❌ | ❌ |
| Create tasks | ✅ | ✅ | ✅ | ❌ |
| Comment on tasks | ✅ | ✅ | ✅ | ✅ |
```
---
#### 5. 索引策略Indexes
告诉 AI 哪些查询是热路径,避免它写出全表扫描的代码。
md
```md
## Indexes
-- tasks is the most queried table, optimize for these patterns:
CREATE INDEX idx_tasks_project_status ON tasks(project_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_tasks_assignee ON tasks(assignee_id) WHERE deleted_at IS NULL;
CREATE INDEX idx_members_user ON members(user_id); -- "get all workspaces for a user"
-- Avoid: never query tasks without a project_id filter
-- Avoid: never do SELECT * on tasks, always select specific columns
```
---
#### 6. 软删除约定Soft Delete Convention
如果使用软删除,必须明确说明规则,否则 AI 会写出漏掉过滤条件的查询。
md
```md
## Soft Delete Convention
Tables with soft delete: workspaces, projects, tasks
Rules:
- ALL queries MUST include `WHERE deleted_at IS NULL` unless explicitly retrieving deleted records
- Use `deletedAt: new Date()` to soft delete, never use DELETE SQL
- Cascading: deleting a Project sets deleted_at on all its Tasks in the same transaction
- Deleted records are purged by a cron job after 30 days (hard delete)
⚠️ AI Note: Never generate a query on these tables without the soft delete filter.
```
---
#### 7. 多租户隔离规则Multi-tenancy Rules
这是安全的核心,必须让 AI 理解每次查询都要带租户过滤。
md
```md
## Multi-tenancy & Data Isolation
This is a **workspace-scoped** multi-tenant system.
Rules:
- EVERY query involving projects, tasks, members MUST be scoped by workspace_id
- Never query tasks directly by id alone — always join through project → workspace
- The workspace_id must come from the authenticated session, never from user input
- Row Level Security (RLS) is enabled on Supabase for all tenant tables
Correct pattern:
SELECT * FROM tasks
JOIN projects ON tasks.project_id = projects.id
WHERE projects.workspace_id = :workspaceId ← always present
AND tasks.id = :taskId
Wrong pattern (security hole):
SELECT * FROM tasks WHERE id = :taskId ← missing tenant scope
```
---
#### 8. 核心查询模式Common Query Patterns
把最常用的查询写出来AI 会直接复用,而不是重新发明。
md
````md
## Common Query Patterns
### Get tasks for a project (with assignee info)
```sql
SELECT t.*, m.user_id, u.name as assignee_name
FROM tasks t
LEFT JOIN members m ON t.assignee_id = m.id
LEFT JOIN users u ON m.user_id = u.id
WHERE t.project_id = :projectId
AND t.deleted_at IS NULL
ORDER BY t.created_at DESC;
```
### Check if user has permission in workspace
```sql
SELECT role FROM members
WHERE workspace_id = :workspaceId
AND user_id = :userId
AND joined_at IS NOT NULL; -- pending invitations don't count
```
````
---
#### 9. 明确禁止的操作Forbidden Operations
md
```md
## Forbidden Operations
- ❌ Never hard DELETE on workspaces, projects, or tasks — use soft delete
- ❌ Never UPDATE a task's status by skipping intermediate states
- ❌ Never expose internal UUIDs in URLs — use slugs for workspaces/projects
- ❌ Never store user PII (email, name) in tasks or comments — always join from users table
- ❌ Never write a migration that drops a column without a deprecation period
```
---
#### 10. 数据迁移约定Migration Convention
md
```md
## Migration Convention
- Migration tool: Drizzle Kit
- File naming: `0001_create_workspaces.ts`, sequential, never rename
- Every migration must be reversible (include `down` function)
- Never edit a migration that has been merged to main
- Backfill scripts go in /scripts, not in migrations
```
---
### 内容优先级总结
|优先级|内容|为什么关键|
|---|---|---|
|🔴 必须|领域概览 + 业务规则|AI 需要理解"为什么"才能做正确取舍|
|🔴 必须|完整 Schema + 字段注释|防止字段命名歧义和类型错误|
|🔴 必须|软删除 + 多租户规则|安全漏洞和数据污染的高发区|
|🟡 重要|枚举常量 + 状态机|防止 AI 自己发明状态值|
|🟡 重要|常用查询模式|复用 > 重新发明|
|🟢 加分|索引策略|引导 AI 写出性能友好的查询|
|🟢 加分|迁移约定|保持 schema 演进的可控性|
---
**核心原则**`DATA_MODEL.md` 写的不是给数据库看的 DDL而是给 AI 看的**业务契约**。每一个"显而易见"的业务规则,在 AI 眼里都是需要被明确告知的约束。没写的,它都会自己猜。