# dodo 数据模型 所有业务实体使用 UUIDv7 主键并按 `user_id` 隔离。生产使用 PostgreSQL,测试使用 SQLite;模型保持两者兼容。 ## app_state - `key` 主键 - `created_at` ## users - `id` - `username` 唯一 - `password_hash` - `timezone` - `created_at` ## sessions - `id` - `token_hash` 唯一 - `user_id` → users,级联删除 - `expires_at` - `created_at` ## folders - `id` - `user_id` → users - `name` - `position` - `created_at` - `deleted_at`,非空表示软删除 删除文件夹不会删除清单;清单的 `folder_id` 被置空。 ## task_lists - `id` - `user_id` → users - `folder_id` → folders,可空 - `name` - `is_inbox`,每个用户初始化时创建一个受保护的系统收集箱 - `position` - `created_at` - `deleted_at`,非空表示软删除 删除普通清单时,其未删除任务原子移动到系统收集箱。系统收集箱不可重命名或删除。 ## tags - `id` - `user_id` → users - `name`,同一用户内唯一 - `color` - `created_at` 标签是用户级全局实体,不隶属于清单。 ## task_tags - `task_id` → tasks - `tag_id` → tags - `(task_id, tag_id)` 联合主键 ## tasks - `id` - `user_id` → users - `list_id` → task_lists - `parent_id` → tasks,可空;仅允许一层子任务且必须与父任务同清单 - `title` - `description` - `priority`(0–3) - `completed` - `due_at`,可空 - `version`,乐观锁版本;单任务更新用 `id + user_id + version` 原子比较更新 - `position` - `created_at` - `updated_at` - `deleted_at`,非空表示进入回收站 顶层任务软删除、恢复或永久删除时同步处理直接子任务。列表与回收站使用 `(created_at, id)` 作为稳定游标排序键。 ## 迁移 - `0001_initial.py`:已部署的初始模式,不修改 - `0002_task_management.py`:新增文件夹/清单软删除列、标签表、任务标签关联表及游标/回收站索引 ## 后续阶段预留 - task_reminders - task_recurrence_templates - task_recurrence_exceptions - habits / habit_logs / habit_reminders - attachments - audit_logs