# 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`,非空表示软删除 删除普通清单时,其未删除任务原子移动到系统收集箱。系统收集箱不可重命名或删除。 ## 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`:新增文件夹/清单软删除列、历史标签表及游标/回收站索引 - `0008_remove_calendar_subscriptions.py`:移除日历订阅表 - `0009_remove_tags.py`:移除历史标签表及任务标签关联表 ## 后续阶段预留 - task_reminders - task_recurrence_templates - task_recurrence_exceptions - habits / habit_logs / habit_reminders - attachments - audit_logs