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

8.3 KiB
Raw Blame History

DATA_MODEL.md 的核心目标是:让 AI 在触碰任何数据相关代码时,都能理解业务语义,而不只是看到一堆字段名。


必须包含的内容

1. 领域概览Domain Overview

用业务语言(不是技术语言)描述核心概念和它们的关系。这是 AI 理解"为什么"的基础。

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

## 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

## 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

## 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

## 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

## 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

## 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

## 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

## 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

## 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 眼里都是需要被明确告知的约束。没写的,它都会自己猜。