- Config: try ENV_FILE, .env, ../.env for loading; trim trailing slash from BaseURL - Log BASE_URL at server startup for verification - .env.example: document BASE_URL - Tasks, projects, tags, migrations and related API/handlers Made-with: Cursor
230 lines
10 KiB
JSON
230 lines
10 KiB
JSON
{
|
|
"paths": {
|
|
"/projects": {
|
|
"get": {
|
|
"tags": ["Projects"],
|
|
"summary": "List projects",
|
|
"description": "Returns the authenticated user's projects (owned and shared). Requires `tasks:read` scope.",
|
|
"operationId": "listProjects",
|
|
"parameters": [
|
|
{ "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } },
|
|
{ "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "Pagination cursor" }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "List of projects",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["items", "page"],
|
|
"properties": {
|
|
"items": { "type": "array", "items": { "$ref": "#/components/schemas/Project" } },
|
|
"page": { "$ref": "#/components/schemas/PageInfo" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": ["Projects"],
|
|
"summary": "Create a project",
|
|
"description": "Creates a new project for the authenticated user. Requires `tasks:write` scope.",
|
|
"operationId": "createProject",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["name"],
|
|
"properties": {
|
|
"name": { "type": "string", "minLength": 1, "maxLength": 100 },
|
|
"color": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "example": "#3B82F6" },
|
|
"deadline": { "type": "string", "format": "date-time" },
|
|
"sort_order": { "type": "integer" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Project created",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["project"],
|
|
"properties": {
|
|
"project": { "$ref": "#/components/schemas/Project" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
}
|
|
},
|
|
"/projects/{id}": {
|
|
"get": {
|
|
"tags": ["Projects"],
|
|
"summary": "Get a project",
|
|
"description": "Returns a single project by ID. User must be owner or member. Requires `tasks:read` scope.",
|
|
"operationId": "getProject",
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Project details",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["project"],
|
|
"properties": {
|
|
"project": { "$ref": "#/components/schemas/Project" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"404": { "description": "Project not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": ["Projects"],
|
|
"summary": "Update a project",
|
|
"description": "Updates a project. Requires `tasks:write` scope and owner/editor role.",
|
|
"operationId": "updateProject",
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "minLength": 1, "maxLength": 100 },
|
|
"color": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
|
|
"deadline": { "type": "string", "format": "date-time", "nullable": true },
|
|
"sort_order": { "type": "integer" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Project updated",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["project"],
|
|
"properties": {
|
|
"project": { "$ref": "#/components/schemas/Project" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"404": { "description": "Project not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": ["Projects"],
|
|
"summary": "Delete a project",
|
|
"description": "Deletes a project. Requires `tasks:write` scope and owner role.",
|
|
"operationId": "deleteProject",
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Project deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } },
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"404": { "description": "Project not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
}
|
|
},
|
|
"/projects/{id}/share": {
|
|
"post": {
|
|
"tags": ["Projects"],
|
|
"summary": "Share project",
|
|
"description": "Shares a project with a user by email. Requires `tasks:write` scope and owner/editor role.",
|
|
"operationId": "shareProject",
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["email", "role"],
|
|
"properties": {
|
|
"email": { "type": "string", "format": "email" },
|
|
"role": { "type": "string", "enum": ["editor", "viewer"] }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Project shared", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } },
|
|
"400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"404": { "description": "Project not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
}
|
|
},
|
|
"/projects/{id}/members": {
|
|
"get": {
|
|
"tags": ["Projects"],
|
|
"summary": "List project members",
|
|
"description": "Returns members of a project. Requires `tasks:read` scope.",
|
|
"operationId": "listProjectMembers",
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "List of project members",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["items"],
|
|
"properties": {
|
|
"items": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectMember" } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
|
|
"404": { "description": "Project not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|