{
  "openapi": "3.1.0",
  "info": {
    "title": "生活工作台 AI 操作 API",
    "version": "3.1.0",
    "description": "通过 Supabase PostgREST 对生活工作台当前启用的五张业务表执行查询、新增和修改。删除必须由用户明确指定记录。日记存放在 habits 表，任务、待办与行程存放在 schedule 表。日记和行程图片二进制由 Supabase Storage 管理，本合同只保存并保留已上传对象的元数据。"
  },
  "servers": [
    {
      "url": "https://raaxisgewmzcxdpuhosj.supabase.co/rest/v1",
      "description": "生活工作台 Supabase REST"
    }
  ],
  "security": [
    {
      "SupabasePublishableKey": []
    }
  ],
  "paths": {
    "/finance": {
      "get": {
        "operationId": "listFinanceRecords",
        "summary": "查询收入、支出、预算和工作设置",
        "parameters": [
          { "$ref": "#/components/parameters/Select" },
          { "$ref": "#/components/parameters/Order" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/IdFilter" },
          { "$ref": "#/components/parameters/DateFilter" },
          { "$ref": "#/components/parameters/RecordTypeFilter" }
        ],
        "responses": { "200": { "$ref": "#/components/responses/FinanceRows" } }
      },
      "post": {
        "operationId": "createFinanceRecord",
        "summary": "新增收入、支出、预算或工作设置",
        "parameters": [{ "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FinanceWrite" } } } },
        "responses": { "201": { "$ref": "#/components/responses/FinanceRows" } }
      },
      "patch": {
        "operationId": "updateFinanceRecord",
        "summary": "按 UUID 修改一条财务记录",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FinancePatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/FinanceRows" } }
      },
      "delete": {
        "operationId": "deleteFinanceRecord",
        "summary": "按 UUID 删除一条财务记录",
        "description": "只有用户明确要求删除该具体记录时才能调用。",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "responses": { "200": { "$ref": "#/components/responses/FinanceRows" } }
      }
    },
    "/habits": {
      "get": {
        "operationId": "listHabitAndJournalRecords",
        "summary": "查询习惯、打卡、目标、目标记录和日记",
        "parameters": [
          { "$ref": "#/components/parameters/Select" },
          { "$ref": "#/components/parameters/Order" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/IdFilter" },
          { "$ref": "#/components/parameters/DateFilter" },
          { "$ref": "#/components/parameters/DataTypeFilter" }
        ],
        "responses": { "200": { "$ref": "#/components/responses/HabitRows" } }
      },
      "post": {
        "operationId": "createHabitOrJournalRecord",
        "summary": "新增习惯、打卡、目标、目标记录或日记",
        "description": "写日记时 data_type=日记，habit_name=标题，method=心情，note 使用 journal:v2: 后接含 content 与 images 的 JSON；没有图片时 images=[]。",
        "parameters": [{ "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HabitWrite" } } } },
        "responses": { "201": { "$ref": "#/components/responses/HabitRows" } }
      },
      "patch": {
        "operationId": "updateHabitOrJournalRecord",
        "summary": "按 UUID 修改习惯、目标或日记",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HabitPatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/HabitRows" } }
      },
      "delete": {
        "operationId": "deleteHabitOrJournalRecord",
        "summary": "按 UUID 删除习惯、目标或日记",
        "description": "只有用户明确要求删除该具体记录时才能调用。",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "responses": { "200": { "$ref": "#/components/responses/HabitRows" } }
      }
    },
    "/fitness": {
      "get": {
        "operationId": "listFitnessRecords",
        "summary": "查询健康记录及兼容保留的旧体测、目标、周计划和热量记录",
        "parameters": [
          { "$ref": "#/components/parameters/Select" },
          { "$ref": "#/components/parameters/Order" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/IdFilter" },
          { "$ref": "#/components/parameters/DateFilter" },
          { "$ref": "#/components/parameters/DataTypeFilter" }
        ],
        "responses": { "200": { "$ref": "#/components/responses/FitnessRows" } }
      },
      "post": {
        "operationId": "createFitnessRecord",
        "summary": "新增健康记录",
        "description": "当前页面不再提供目标或运动独立模块；旧体测、目标、周计划和热量记录只为历史兼容保留。新增健康记录前按 data_type=eq.健康记录 且 date=eq.YYYY-MM-DD 查询同日记录；意图不清时询问一次。健康可选数字未知时写 null，不得写 0。写入使用 Prefer: return=representation，返回数组必须恰好一条并包含真实 UUID；随后按 UUID 再查询一次核验关键字段。",
        "parameters": [{ "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FitnessWrite" } } } },
        "responses": { "201": { "$ref": "#/components/responses/FitnessRows" } }
      },
      "patch": {
        "operationId": "updateFitnessRecord",
        "summary": "按 UUID 修改健康或兼容历史记录",
        "description": "用户要求更新今天健康状态时，先查询同日健康记录取得真实 UUID 后 PATCH。写入返回数组必须恰好一条并包含 UUID，随后按 UUID 再查询一次核验关键字段。健康 plan JSON 修改前应读取并合并未改变字段。",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FitnessPatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/FitnessRows" } }
      },
      "delete": {
        "operationId": "deleteFitnessRecord",
        "summary": "按 UUID 删除健康或兼容历史记录",
        "description": "只有用户明确要求删除该具体记录时才能调用。",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "responses": { "200": { "$ref": "#/components/responses/FitnessRows" } }
      }
    },
    "/schedule": {
      "get": {
        "operationId": "listScheduleRecords",
        "summary": "查询任务、待办和行程",
        "parameters": [
          { "$ref": "#/components/parameters/Select" },
          { "$ref": "#/components/parameters/Order" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/IdFilter" },
          { "$ref": "#/components/parameters/DateFilter" }
        ],
        "responses": { "200": { "$ref": "#/components/responses/ScheduleRows" } }
      },
      "post": {
        "operationId": "createScheduleRecord",
        "summary": "新增任务、待办或行程",
        "description": "普通任务使用 category=每日任务、待办事项等，note 使用 task:v2: JSON 保存 startDate、startTime、endDate、endTime、noDeadline 和 note。跨天任务的物理 date 列保存开始日期，缺少开始日期时保存截止日期；无截止且无日期时可为 null。行程固定使用 category=行程，并按 ScheduleWrite.note 的约定保存车次、路线、时长和座位信息。行程展示按 date、start_time 升序，缺少出发时间的同日记录排在有时间记录之后。",
        "parameters": [{ "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScheduleWrite" } } } },
        "responses": { "201": { "$ref": "#/components/responses/ScheduleRows" } }
      },
      "patch": {
        "operationId": "updateScheduleRecord",
        "summary": "按 UUID 修改任务、待办或行程",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SchedulePatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/ScheduleRows" } }
      },
      "delete": {
        "operationId": "deleteScheduleRecord",
        "summary": "按 UUID 删除任务、待办或行程",
        "description": "只有用户明确要求删除该具体记录时才能调用。",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "responses": { "200": { "$ref": "#/components/responses/ScheduleRows" } }
      }
    },
    "/media": {
      "get": {
        "operationId": "listMediaRecords",
        "summary": "查询书影音收藏",
        "parameters": [
          { "$ref": "#/components/parameters/Select" },
          { "$ref": "#/components/parameters/Order" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/IdFilter" },
          { "$ref": "#/components/parameters/FinishDateFilter" }
        ],
        "responses": { "200": { "$ref": "#/components/responses/MediaRows" } }
      },
      "post": {
        "operationId": "createMediaRecord",
        "summary": "新增书影音收藏",
        "parameters": [{ "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MediaWrite" } } } },
        "responses": { "201": { "$ref": "#/components/responses/MediaRows" } }
      },
      "patch": {
        "operationId": "updateMediaRecord",
        "summary": "按 UUID 修改书影音收藏",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MediaPatch" } } } },
        "responses": { "200": { "$ref": "#/components/responses/MediaRows" } }
      },
      "delete": {
        "operationId": "deleteMediaRecord",
        "summary": "按 UUID 删除书影音收藏",
        "description": "只有用户明确要求删除该具体记录时才能调用。",
        "parameters": [{ "$ref": "#/components/parameters/RequiredIdFilter" }, { "$ref": "#/components/parameters/Prefer" }],
        "responses": { "200": { "$ref": "#/components/responses/MediaRows" } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "SupabasePublishableKey": {
        "type": "apiKey",
        "in": "header",
        "name": "apikey",
        "description": "使用生活工作台网页现有的 Supabase 公开 publishable key。不要使用 service_role。"
      }
    },
    "parameters": {
      "Select": { "name": "select", "in": "query", "schema": { "type": "string", "default": "*" }, "description": "PostgREST 字段列表。" },
      "Order": { "name": "order", "in": "query", "schema": { "type": "string", "default": "created_at.desc" }, "description": "PostgREST 排序表达式。" },
      "Limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 } },
      "Offset": { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
      "IdFilter": { "name": "id", "in": "query", "required": false, "schema": { "type": "string", "example": "eq.00000000-0000-0000-0000-000000000000" }, "description": "可选 UUID 精确过滤，格式 eq.<uuid>。" },
      "RequiredIdFilter": { "name": "id", "in": "query", "required": true, "schema": { "type": "string", "example": "eq.00000000-0000-0000-0000-000000000000" }, "description": "必须按 UUID 精确定位，格式 eq.<uuid>。" },
      "DateFilter": { "name": "date", "in": "query", "required": false, "schema": { "type": "string", "example": "eq.2026-08-13" }, "description": "PostgREST 日期过滤，如 eq.2026-08-13、gte.2026-08-01。" },
      "FinishDateFilter": { "name": "finish_date", "in": "query", "required": false, "schema": { "type": "string", "example": "gte.2026-01-01" } },
      "RecordTypeFilter": { "name": "record_type", "in": "query", "required": false, "schema": { "type": "string", "example": "eq.支出" } },
      "DataTypeFilter": { "name": "data_type", "in": "query", "required": false, "schema": { "type": "string", "example": "eq.日记" } },
      "Prefer": { "name": "Prefer", "in": "header", "required": false, "schema": { "type": "string", "default": "return=representation" }, "description": "写入后返回实际记录，用于核验 UUID 和最终字段。" }
    },
    "responses": {
      "FinanceRows": { "description": "财务记录数组", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FinanceRow" } } } } },
      "HabitRows": { "description": "习惯、目标或日记记录数组", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/HabitRow" } } } } },
      "FitnessRows": { "description": "运动或健康记录数组", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FitnessRow" } } } } },
      "ScheduleRows": { "description": "任务、待办或行程记录数组", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ScheduleRow" } } } } },
      "MediaRows": { "description": "书影音记录数组", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/MediaRow" } } } } }
    },
    "schemas": {
      "RecordMeta": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "FinanceWrite": {
        "type": "object",
        "description": "网页手动表单字段均可选；record_type 和 date 可由当前选定日期及系统默认值补齐，未知数字必须为 null。",
        "properties": {
          "record_type": { "type": "string", "enum": ["收入", "支出", "预算"] },
          "name": { "type": "string" },
          "category": { "type": "string", "default": "" },
          "amount": { "type": ["number", "null"], "minimum": 0 },
          "date": { "type": "string", "format": "date" },
          "account": { "type": "string", "default": "" },
          "note": { "type": "string", "default": "" }
        }
      },
      "FinancePatch": { "type": "object", "minProperties": 1, "additionalProperties": true, "description": "只提供需要修改的 finance 字段。" },
      "FinanceRow": { "allOf": [{ "$ref": "#/components/schemas/RecordMeta" }, { "$ref": "#/components/schemas/FinanceWrite" }] },
      "HabitWrite": {
        "type": "object",
        "description": "网页手动表单字段均可选；data_type、method 和 date 可由系统补齐。旧目标和目标记录继续可查询，但页面不再提供目标模块或新增入口。",
        "properties": {
          "data_type": { "type": "string", "enum": ["习惯", "打卡", "目标", "目标记录", "日记"] },
          "habit_name": { "type": "string", "description": "习惯名、目标名或日记标题。" },
          "method": { "type": "string", "default": "勾选", "description": "日记使用心情文字。" },
          "date": { "type": "string", "format": "date" },
          "target": { "type": ["number", "null"] },
          "value": { "type": ["number", "null"] },
          "unit": { "type": "string", "default": "" },
          "color": { "type": "string", "default": "#4d3045" },
          "note": { "type": "string", "default": "", "description": "日记使用 journal:v2: 后接 JSON，字段为 content、images；images 每项为 path、name、type、size。修改时必须保留未被用户明确移除的图片。打卡/目标记录可存关联前缀。" }
        }
      },
      "HabitPatch": { "type": "object", "minProperties": 1, "additionalProperties": true, "description": "只提供需要修改的 habits 字段。" },
      "HabitRow": { "allOf": [{ "$ref": "#/components/schemas/RecordMeta" }, { "$ref": "#/components/schemas/HabitWrite" }] },
      "FitnessWrite": {
        "type": "object",
        "description": "当前页面新增记录统一使用 data_type=健康记录；体测、目标、周计划和热量枚举仅用于兼容历史数据。网页健康字段均可选，未知数字必须为 null。",
        "properties": {
          "data_type": { "type": "string", "enum": ["体测", "目标", "周计划", "热量", "健康记录"] },
          "title": { "type": "string", "default": "" },
          "date": { "type": "string", "format": "date" },
          "weight": { "type": ["number", "null"], "description": "健康记录体重；未知时为 null。旧 data_type=体测 的有效非零体重继续进入健康趋势。" },
          "body_fat": { "type": ["number", "null"], "description": "体脂率；未知时为 null。" },
          "height": { "type": ["number", "null"] },
          "target_weight": { "type": ["number", "null"] },
          "target_calories": { "type": ["number", "null"] },
          "intake": { "type": ["number", "null"] },
          "burn": { "type": ["number", "null"] },
          "weekday": { "type": "string", "default": "" },
          "plan": { "type": "string", "default": "", "description": "兼容旧周计划文字；健康记录时为 sleepDuration、sleepAt、wakeAt、sleepQuality、weight、bodyFat、restingHeartRate、temperatureStatus、temperatureValue、bodyStatus、medication、note 的单行 JSON。所有字段选填：sleepDuration 可为 null，非 null 时 0–24；sleepQuality 可为 null，非 null 时必须是 0–100 整数；weight、bodyFat、restingHeartRate 未知时为 null；temperatureStatus 可为空字符串、正常或异常；temperatureValue 仅异常时可为 34–45 数值，否则为 null。即使状态异常且具体体温未知，也允许 temperatureValue=null。plan.note 与顶层 note 双写；读取旧记录时 plan.note 缺失才回退顶层 note。不得用 0 或正常代替未知。" },
          "status": { "type": "string", "default": "", "description": "健康记录时镜像体温状态，可为空字符串、正常或异常；旧运动计划状态仅作历史兼容。" },
          "note": { "type": "string", "default": "", "description": "健康记录时必须与 plan JSON 内的 note 写入相同文本，作为兼容镜像。" }
        }
      },
      "FitnessPatch": { "type": "object", "minProperties": 1, "additionalProperties": true, "description": "只提供需要修改的 fitness 字段。" },
      "FitnessRow": { "allOf": [{ "$ref": "#/components/schemas/RecordMeta" }, { "$ref": "#/components/schemas/FitnessWrite" }] },
      "ScheduleWrite": {
        "type": "object",
        "description": "网页任务和行程字段均可选。普通任务用 task:v2: JSON 扩展跨天和无截止语义；旧纯文本 note 与旧 date 记录继续兼容。",
        "properties": {
          "title": { "type": "string" },
          "date": { "type": ["string", "null"], "format": "date", "description": "行程为出发日期；普通任务为开始日期，缺少开始日期时为截止日期，无截止且无日期时为 null。" },
          "start_time": { "type": "string", "default": "" },
          "end_time": { "type": "string", "default": "" },
          "priority": { "type": "string", "enum": ["高", "中", "低"], "default": "中" },
          "status": { "type": "string", "enum": ["待处理", "进行中", "已完成"], "default": "待处理" },
          "category": { "type": "string", "default": "待办事项", "description": "普通记录可用每日任务、待办事项、工作、生活或其他；行程固定为 行程。" },
          "note": { "type": "string", "default": "", "description": "普通任务保存 task:v2: 后接 JSON，字段为 startDate、startTime、endDate、endTime、noDeadline、note；noDeadline=true 时日期时间可全部为空，未完成前持续显示且不判逾期。行程保存 trip:v1: 后接 JSON，字段为 mode、number、from、to、duration、seat、note、images；images 每项为 path、name、type、size，修改时必须保留未被用户明确移除的图片。" }
        }
      },
      "SchedulePatch": { "type": "object", "minProperties": 1, "additionalProperties": true, "description": "只提供需要修改的 schedule 字段。" },
      "ScheduleRow": { "allOf": [{ "$ref": "#/components/schemas/RecordMeta" }, { "$ref": "#/components/schemas/ScheduleWrite" }] },
      "MediaWrite": {
        "type": "object",
        "description": "网页收藏表单字段均可选；finish_date 有值时记录会出现在对应选定日期总览。",
        "properties": {
          "name": { "type": "string" },
          "type": { "type": "string", "enum": ["书", "电影", "剧集", "播客", "音乐", "游戏"], "default": "书" },
          "status": { "type": "string", "enum": ["想看", "在看", "已完成", "搁置"], "default": "想看" },
          "rating": { "type": ["integer", "null"], "minimum": 0, "maximum": 5 },
          "year": { "type": ["integer", "null"] },
          "finish_date": { "type": ["string", "null"], "format": "date" },
          "cover_url": { "type": "string", "default": "" },
          "review": { "type": "string", "default": "" },
          "tags": { "type": "string", "default": "" }
        }
      },
      "MediaPatch": { "type": "object", "minProperties": 1, "additionalProperties": true, "description": "只提供需要修改的 media 字段。" },
      "MediaRow": { "allOf": [{ "$ref": "#/components/schemas/RecordMeta" }, { "$ref": "#/components/schemas/MediaWrite" }] }
    }
  }
}
