{
  "openapi": "3.0.3",
  "info": {
    "title": "小台·待办 AI 助手 API",
    "version": "1.1.2",
    "description": "使用 Authorization: Bearer <token> 认证。除健康检查外，成功响应为 {code:0,message:'ok',data:...}，失败响应为 {code:HTTP状态码,message:'...'}。readonly Key 仅允许 GET；写请求返回 403。日期为 YYYY-MM-DD，时间为 ISO 8601。覆盖式导入和批量清空不开放；永久删除回收站内容前必须向用户明确确认。"
  },
  "servers": [{ "url": "https://sundancekid.cn" }],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    { "name": "system" },
    { "name": "tasks" },
    { "name": "week" },
    { "name": "habits" },
    { "name": "memos" },
    { "name": "trash" }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "token" }
    },
    "parameters": {
      "id": {
        "name": "id", "in": "path", "required": true,
        "schema": { "type": "integer", "minimum": 1 }
      },
      "trashType": {
        "name": "type", "in": "path", "required": true,
        "schema": { "type": "string", "enum": ["tasks", "habits", "memos"] }
      },
      "weekKey": {
        "name": "key", "in": "query", "required": false,
        "schema": { "type": "string", "pattern": "^\\d{4}-W\\d{2}$", "example": "2026-W42" }
      }
    },
    "schemas": {
      "Success": {
        "type": "object",
        "required": ["code", "message", "data"],
        "properties": {
          "code": { "type": "integer", "example": 0 },
          "message": { "type": "string", "example": "ok" },
          "data": { "type": "object", "additionalProperties": true }
        }
      },
      "Error": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": { "type": "integer", "example": 422 },
          "message": { "type": "string", "example": "参数错误" }
        }
      },
      "Task": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string" },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] },
          "due_date": { "type": "string", "format": "date", "nullable": true },
          "notes": { "type": "string" },
          "status": { "type": "string", "enum": ["open", "done"] },
          "goal_id": { "type": "integer", "nullable": true },
          "carry_count": { "type": "integer" },
          "repeat_interval": { "type": "integer", "minimum": 0, "maximum": 3650 },
          "repeat_source_id": { "type": "integer", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "done_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "TaskCreate": {
        "type": "object",
        "required": ["title"],
        "properties": {
          "title": { "type": "string", "maxLength": 200 },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"], "default": "其他" },
          "due_date": { "type": "string", "format": "date", "nullable": true },
          "notes": { "type": "string" },
          "goal_id": { "type": "integer", "nullable": true },
          "repeat_interval": { "type": "integer", "minimum": 0, "maximum": 3650, "default": 0, "description": "每 N 天重复；大于 0 时必须有 due_date" }
        }
      },
      "TaskPatch": {
        "type": "object",
        "properties": {
          "title": { "type": "string", "maxLength": 200 },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] },
          "due_date": { "type": "string", "format": "date", "nullable": true },
          "notes": { "type": "string" },
          "goal_id": { "type": "integer", "nullable": true },
          "repeat_interval": { "type": "integer", "minimum": 0, "maximum": 3650 }
        }
      },
      "Goal": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string" },
          "category": { "type": "string" },
          "status": { "type": "string", "enum": ["active", "done", "dropped", "carried"] },
          "done": { "type": "integer" },
          "total": { "type": "integer" }
        }
      },
      "GoalCreate": {
        "type": "object",
        "required": ["title"],
        "properties": {
          "weekKey": { "type": "string", "example": "2026-W42" },
          "title": { "type": "string" },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] }
        }
      },
      "GoalPatch": {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] },
          "status": { "type": "string", "enum": ["active", "done", "dropped", "carried"] }
        }
      },
      "WeekReview": {
        "type": "object",
        "properties": {
          "weekKey": { "type": "string", "example": "2026-W42" },
          "wins": { "type": "string" },
          "blockers": { "type": "string" },
          "adjustments": { "type": "string" },
          "createdAt": { "type": "string", "format": "date-time", "nullable": true },
          "updatedAt": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "Habit": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "category": { "type": "string" },
          "freqType": { "type": "string", "enum": ["daily", "weekly"] },
          "freqTarget": { "type": "integer", "minimum": 1, "maximum": 7 },
          "note": { "type": "string" },
          "createdAt": { "type": "string", "format": "date-time" },
          "stats": { "type": "object", "additionalProperties": true }
        }
      },
      "HabitInput": {
        "type": "object",
        "required": ["name", "freqType"],
        "properties": {
          "name": { "type": "string" },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] },
          "freqType": { "type": "string", "enum": ["daily", "weekly"] },
          "freqTarget": { "type": "integer", "minimum": 1, "maximum": 7 },
          "note": { "type": "string" }
        }
      },
      "Memo": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string" },
          "content": { "type": "string" },
          "category": { "type": "string" },
          "recite": { "type": "boolean" },
          "reviewCount": { "type": "integer" },
          "lastReviewedAt": { "type": "string", "format": "date-time", "nullable": true },
          "nextReviewDate": { "type": "string", "format": "date", "nullable": true },
          "familiarity": { "type": "integer", "minimum": 0, "maximum": 4 },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "MemoInput": {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "content": { "type": "string" },
          "category": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] },
          "recite": { "type": "boolean" }
        },
        "description": "title 和 content 至少一项非空"
      }
    },
    "responses": {
      "Success": {
        "description": "成功，具体业务对象位于 data 内",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Success" } } }
      },
      "DefaultError": {
        "description": "失败。401 未认证，403 只读 Key 写入，404 不存在，422 参数错误，503 API 未配置",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  },
  "paths": {
    "/api/health": {
      "get": {
        "tags": ["system"], "summary": "健康检查，无需认证", "security": [],
        "responses": {
          "200": {
            "description": "服务正常",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "ok" } } } } }
          }
        }
      }
    },
    "/api/tasks": {
      "get": {
        "tags": ["tasks"], "summary": "任务列表与组合筛选",
        "parameters": [
          { "name": "scope", "in": "query", "schema": { "type": "string", "enum": ["today", "week", "all"], "default": "today" } },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["open", "done", "all"], "default": "open" } },
          { "name": "category", "in": "query", "schema": { "type": "string", "enum": ["工作", "生活", "学习", "其他"] } },
          { "name": "q", "in": "query", "description": "搜索标题和备注", "schema": { "type": "string" } },
          { "name": "due", "in": "query", "schema": { "type": "string", "enum": ["all", "overdue", "today", "nodate"], "default": "all" } },
          { "name": "goal_id", "in": "query", "schema": { "type": "integer", "minimum": 1 } }
        ],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "post": {
        "tags": ["tasks"], "summary": "新建任务",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskCreate" } } } },
        "responses": { "201": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/tasks/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "patch": {
        "tags": ["tasks"], "summary": "局部更新任务",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskPatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "delete": {
        "tags": ["tasks"], "summary": "软删任务到回收站",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/tasks/{id}/done": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "post": {
        "tags": ["tasks"], "summary": "幂等完成任务；重复任务自动生成下一次",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/tasks/{id}/reopen": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "post": {
        "tags": ["tasks"], "summary": "幂等重开任务",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/week": {
      "get": {
        "tags": ["week"], "summary": "周计划详情",
        "parameters": [{ "$ref": "#/components/parameters/weekKey" }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/week/goals": {
      "post": {
        "tags": ["week"], "summary": "新建周目标",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GoalCreate" } } } },
        "responses": { "201": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/week/goals/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "put": {
        "tags": ["week"], "summary": "修改周目标",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GoalPatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "delete": {
        "tags": ["week"], "summary": "删除周目标，任务保留并解除关联",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/week/rollover": {
      "post": {
        "tags": ["week"], "summary": "将指定周未完成任务顺延到下周",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "weekKey": { "type": "string", "example": "2026-W42" } } } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/week/rollover/auto": {
      "post": {
        "tags": ["week"], "summary": "将历史未完成周自动顺延到本周",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/weeks": {
      "get": {
        "tags": ["week"], "summary": "历史周及完成率",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/week/review": {
      "get": {
        "tags": ["week"], "summary": "读取周复盘",
        "parameters": [{ "$ref": "#/components/parameters/weekKey" }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "put": {
        "tags": ["week"], "summary": "保存周复盘",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WeekReview" } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/habits": {
      "get": {
        "tags": ["habits"], "summary": "习惯列表及统计",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "post": {
        "tags": ["habits"], "summary": "新建习惯",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HabitInput" } } } },
        "responses": { "201": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/habits/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "put": {
        "tags": ["habits"], "summary": "修改习惯",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HabitInput" } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "delete": {
        "tags": ["habits"], "summary": "软删习惯，保留打卡到回收站",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/habits/{id}/checkin": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "post": {
        "tags": ["habits"], "summary": "打卡或补卡",
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "date": { "type": "string", "format": "date" } } } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/habits/{id}/uncheckin": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "post": {
        "tags": ["habits"], "summary": "取消打卡",
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "date": { "type": "string", "format": "date" } } } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/memos": {
      "get": {
        "tags": ["memos"], "summary": "备忘列表",
        "parameters": [
          { "name": "recite", "in": "query", "description": "传 1 只看背诵", "schema": { "type": "string", "enum": ["1"] } },
          { "name": "due", "in": "query", "description": "传 1 只看到期复习", "schema": { "type": "string", "enum": ["1"] } }
        ],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "post": {
        "tags": ["memos"], "summary": "新建备忘",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemoInput" } } } },
        "responses": { "201": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/memos/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "put": {
        "tags": ["memos"], "summary": "修改备忘或背诵标记",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemoInput" } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      },
      "delete": {
        "tags": ["memos"], "summary": "软删备忘到回收站",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/memos/{id}/review": {
      "parameters": [{ "$ref": "#/components/parameters/id" }],
      "post": {
        "tags": ["memos"], "summary": "记录背诵复习",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object", "required": ["familiarity"], "properties": { "familiarity": { "type": "integer", "enum": [1, 2, 3, 4], "description": "分别安排 1/3/7/15 天后复习" } } } } }
        },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/trash": {
      "get": {
        "tags": ["trash"], "summary": "回收站列表",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/trash/{type}/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/trashType" }, { "$ref": "#/components/parameters/id" }],
      "delete": {
        "tags": ["trash"], "summary": "永久删除单条回收站内容",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    },
    "/api/trash/{type}/{id}/restore": {
      "parameters": [{ "$ref": "#/components/parameters/trashType" }, { "$ref": "#/components/parameters/id" }],
      "post": {
        "tags": ["trash"], "summary": "恢复单条回收站内容",
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "default": { "$ref": "#/components/responses/DefaultError" } }
      }
    }
  }
}
