feat: complete TASK-WP2-02 project autosave

This commit is contained in:
suyx
2026-08-02 18:28:07 +08:00
parent 4d38530361
commit da6fa25e60
17 changed files with 2268 additions and 35 deletions
+623 -1
View File
@@ -787,6 +787,407 @@
}
]
},
"CanvasBackgroundAdjustments": {
"additionalProperties": false,
"properties": {
"brightness": {
"maximum": 100,
"minimum": -100,
"type": "number"
},
"contrast": {
"maximum": 100,
"minimum": -100,
"type": "number"
},
"crop": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"height": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"width": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"x": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"y": {
"maximum": 1,
"minimum": 0,
"type": "number"
}
},
"required": [
"height",
"width",
"x",
"y"
],
"type": "object"
},
{
"type": "null"
}
]
},
"filter": {
"maxLength": 64,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
"fit": {
"anyOf": [
{
"enum": [
"fill"
],
"type": "string"
},
{
"enum": [
"fit"
],
"type": "string"
},
{
"enum": [
"crop"
],
"type": "string"
}
]
},
"saturation": {
"maximum": 100,
"minimum": -100,
"type": "number"
},
"sharpness": {
"maximum": 100,
"minimum": 0,
"type": "number"
},
"temperature": {
"maximum": 100,
"minimum": -100,
"type": "number"
}
},
"required": [
"brightness",
"contrast",
"crop",
"filter",
"fit",
"saturation",
"sharpness",
"temperature"
],
"type": "object"
},
"CanvasElement": {
"additionalProperties": false,
"properties": {
"colors": {
"items": {
"pattern": "^#[0-9A-Fa-f]{6}$",
"type": "string"
},
"maxItems": 5,
"minItems": 5,
"type": "array"
},
"content": {
"maxLength": 4000,
"type": "string"
},
"coordinates": {
"additionalProperties": false,
"properties": {
"latitude": {
"maximum": 90,
"minimum": -90,
"type": "number"
},
"longitude": {
"maximum": 180,
"minimum": -180,
"type": "number"
}
},
"required": [
"latitude",
"longitude"
],
"type": "object"
},
"created_at": {
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
"type": "string"
},
"dynamic_fields": {
"additionalProperties": {
"anyOf": [
{
"maxLength": 4000,
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
]
},
"type": "object"
},
"element_id": {
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
"type": "string"
},
"font_override": {
"maxLength": 120,
"pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$",
"type": "string"
},
"font_size": {
"maximum": 512,
"minimum": 1,
"type": "number"
},
"formatted_value": {
"maxLength": 4000,
"type": "string"
},
"opacity": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"position": {
"additionalProperties": false,
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
}
},
"required": [
"x",
"y"
],
"type": "object"
},
"resource_version": {
"maxLength": 120,
"pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$",
"type": "string"
},
"rotation": {
"maximum": 360,
"minimum": -360,
"type": "number"
},
"scale": {
"additionalProperties": false,
"properties": {
"x": {
"maximum": 100,
"minimum": 0.01,
"type": "number"
},
"y": {
"maximum": 100,
"minimum": 0.01,
"type": "number"
}
},
"required": [
"x",
"y"
],
"type": "object"
},
"style_id": {
"maxLength": 120,
"pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$",
"type": "string"
},
"style_parameters": {
"additionalProperties": {
"anyOf": [
{
"maxLength": 4000,
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
]
},
"type": "object"
},
"template_or_asset_id": {
"maxLength": 120,
"pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$",
"type": "string"
},
"type": {
"anyOf": [
{
"enum": [
"text_template"
],
"type": "string"
},
{
"enum": [
"static_sticker"
],
"type": "string"
},
{
"enum": [
"color_card"
],
"type": "string"
},
{
"enum": [
"dynamic_sticker"
],
"type": "string"
}
]
},
"z_index": {
"maximum": 49,
"minimum": 0,
"type": "integer"
}
},
"required": [
"created_at",
"element_id",
"opacity",
"position",
"resource_version",
"rotation",
"scale",
"template_or_asset_id",
"type",
"z_index"
],
"type": "object"
},
"CanvasState": {
"additionalProperties": false,
"properties": {
"background": {
"additionalProperties": false,
"properties": {
"adjustments": {
"$ref": "#/components/schemas/CanvasBackgroundAdjustments"
},
"asset_id": {
"anyOf": [
{
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"adjustments",
"asset_id"
],
"type": "object"
},
"elements": {
"items": {
"$ref": "#/components/schemas/CanvasElement"
},
"maxItems": 50,
"type": "array"
},
"pixel_height": {
"minimum": 1,
"type": "integer"
},
"pixel_width": {
"minimum": 1,
"type": "integer"
},
"ratio": {
"anyOf": [
{
"enum": [
"3:4"
],
"type": "string"
},
{
"enum": [
"1:1"
],
"type": "string"
},
{
"enum": [
"4:3"
],
"type": "string"
},
{
"enum": [
"9:16"
],
"type": "string"
}
]
},
"schema_version": {
"enum": [
1
],
"type": "number"
}
},
"required": [
"background",
"elements",
"pixel_height",
"pixel_width",
"ratio",
"schema_version"
],
"type": "object"
},
"CorrelationId": {
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
"type": "string"
@@ -1677,6 +2078,9 @@
"ProjectDetailResponse": {
"additionalProperties": false,
"properties": {
"canvas_state": {
"$ref": "#/components/schemas/CanvasState"
},
"created_at": {
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
"type": "string"
@@ -1750,6 +2154,12 @@
"ratio": {
"$ref": "#/components/schemas/ProjectRatio"
},
"save_status": {
"enum": [
"saved"
],
"type": "string"
},
"state_version": {
"minimum": 1,
"type": "integer"
@@ -1778,12 +2188,32 @@
"status",
"successful_image_count",
"updated_at",
"canvas_state",
"created_at",
"draft_prompt",
"generations",
"images",
"pixel_height",
"pixel_width"
"pixel_width",
"save_status"
],
"type": "object"
},
"ProjectEditableState": {
"additionalProperties": false,
"properties": {
"canvas_state": {
"$ref": "#/components/schemas/CanvasState"
},
"name": {
"maxLength": 80,
"minLength": 1,
"type": "string"
}
},
"required": [
"canvas_state",
"name"
],
"type": "object"
},
@@ -1944,6 +2374,72 @@
],
"type": "object"
},
"ProjectStateConflictResponse": {
"additionalProperties": false,
"properties": {
"latest_state_version": {
"minimum": 1,
"type": "integer"
},
"save_status": {
"enum": [
"conflicted"
],
"type": "string"
}
},
"required": [
"latest_state_version",
"save_status"
],
"type": "object"
},
"ProjectStateSaveHeaders": {
"additionalProperties": true,
"properties": {
"idempotency-key": {
"maxLength": 200,
"minLength": 32,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
"if-match": {
"pattern": "^[1-9][0-9]*$",
"type": "string"
},
"x-csrf-token": {
"maxLength": 512,
"minLength": 32,
"type": "string"
}
},
"required": [
"idempotency-key",
"if-match",
"x-csrf-token"
],
"type": "object"
},
"ProjectStateSaveResponse": {
"additionalProperties": false,
"properties": {
"save_status": {
"enum": [
"saved"
],
"type": "string"
},
"state_version": {
"minimum": 2,
"type": "integer"
}
},
"required": [
"save_status",
"state_version"
],
"type": "object"
},
"ProjectSummary": {
"additionalProperties": false,
"properties": {
@@ -4628,6 +5124,132 @@
]
}
},
"/api/v1/projects/{projectId}/state": {
"put": {
"operationId": "saveProjectState",
"parameters": [
{
"in": "path",
"name": "projectId",
"required": true,
"schema": {
"$ref": "#/components/schemas/ProjectId"
}
},
{
"in": "header",
"name": "idempotency-key",
"required": true,
"schema": {
"maxLength": 200,
"minLength": 32,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
}
},
{
"in": "header",
"name": "if-match",
"required": true,
"schema": {
"pattern": "^[1-9][0-9]*$",
"type": "string"
}
},
{
"in": "header",
"name": "x-csrf-token",
"required": true,
"schema": {
"maxLength": 512,
"minLength": 32,
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProjectEditableState"
}
}
},
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProjectStateSaveResponse"
}
}
},
"description": "Default Response"
},
"400": {
"description": "Default Response"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
},
"description": "Default Response"
},
"403": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
},
"description": "Default Response"
},
"404": {
"description": "Default Response"
},
"409": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
},
"description": "Default Response"
},
"412": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProjectStateConflictResponse"
}
}
},
"description": "Default Response"
},
"503": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
},
"description": "Default Response"
}
},
"tags": [
"Projects"
]
}
},
"/api/v1/projects/failed-empty/trash": {
"post": {
"operationId": "trashFailedEmptyProjects",