{
  "openapi": "3.1.0",
  "info": {
    "title": "40dayarrow REST API",
    "version": "1.4.0",
    "description": "REST API на 40dayarrow – приложение за задачи, Pomodoro таймер и 40-дневен challenge. Всички endpoints изискват активна потребителска сесия (Google Login). За AI-интеграция виж Diaktor MCP на https://40dayarrow.com/mcp.",
    "contact": {
      "name": "Diaktor",
      "email": "hello@diaktor.com",
      "url": "https://40dayarrow.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://40dayarrow.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://40dayarrow.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Sync",
      "description": "Синхронизация на задачи и Pomodoro"
    },
    {
      "name": "Tasks",
      "description": "Управление на задачи"
    },
    {
      "name": "Pomodoro",
      "description": "Pomodoro цикли"
    },
    {
      "name": "Stats",
      "description": "Статистики и streak"
    },
    {
      "name": "User",
      "description": "Потребителска информация"
    }
  ],
  "paths": {
    "/api/v1/sync": {
      "get": {
        "tags": ["Sync"],
        "summary": "Синхронизация на задачи и Pomodoro",
        "description": "Връща всички задачи и Pomodoro цикли от последните 90 дни (по подразбиране). Използва се при стартиране на приложението за пълно презареждане на локалното състояние.",
        "operationId": "sync",
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "description": "Начална дата във формат YYYY-MM-DD. По подразбиране: преди 90 дни.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-06-18"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Успешна синхронизация",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tasks": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Task" }
                    },
                    "pomos": {
                      "type": "object",
                      "description": "Map от дата → брой Pomodoro цикли",
                      "additionalProperties": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "example": {
                        "2026-09-15": 4,
                        "2026-09-16": 2
                      }
                    },
                    "server_time": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "api_version": {
                      "type": "integer",
                      "example": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/add_task": {
      "post": {
        "tags": ["Tasks"],
        "summary": "Добавя нова задача",
        "description": "Добавя задача. Ако ID вече съществува, обновява я (upsert). ID се генерира от клиента.",
        "operationId": "addTask",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "text", "date"],
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^[a-z0-9]{6,50}$",
                    "description": "Уникален ID на задачата (клиентски генериран)",
                    "example": "abc123xyz"
                  },
                  "date": {
                    "type": "string",
                    "format": "date",
                    "example": "2026-09-16"
                  },
                  "time": {
                    "type": "string",
                    "pattern": "^\\d{2}:\\d{2}$",
                    "nullable": true,
                    "example": "14:00"
                  },
                  "text": {
                    "type": "string",
                    "maxLength": 500,
                    "example": "Урок по астрология"
                  },
                  "type": {
                    "type": "string",
                    "enum": ["R", "O"],
                    "default": "R",
                    "description": "R = работна, O = обща"
                  },
                  "priority": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3,
                    "default": 2
                  },
                  "planned": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 24,
                    "default": 0,
                    "description": "Планирани часове"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Задачата е добавена",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "example": true },
                    "id": { "type": "string", "example": "abc123xyz" }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/update_task": {
      "post": {
        "tags": ["Tasks"],
        "summary": "Обновява задача",
        "description": "Обновява статус, реални часове или бележка. Опционално подаване на client_updated_at за защита срещу конфликти (409 ако задачата е променена другаде, 404 ако е изтрита).",
        "operationId": "updateTask",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id"],
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^[a-z0-9]{6,50}$"
                  },
                  "status": {
                    "type": "string",
                    "enum": ["pending", "done", "partial", "missed"]
                  },
                  "actual": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 24
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "client_updated_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Кога клиентът последно е виждал задачата (за optimistic locking)",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Задачата е обновена",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "example": true },
                    "updated_at": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Задачата е изтрита на друго устройство",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string", "example": "deleted" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Конфликт – задачата е променена на друго устройство",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string", "example": "conflict" },
                    "message": { "type": "string" },
                    "current": { "$ref": "#/components/schemas/Task" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/delete_task": {
      "post": {
        "tags": ["Tasks"],
        "summary": "Изтрива задача",
        "description": "Изтрива задача по ID. Само POST (405 ако е GET).",
        "operationId": "deleteTask",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id"],
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^[a-z0-9]{6,50}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Задачата е изтрита",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "example": true },
                    "deleted": { "type": "integer", "example": 1 }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "405": {
            "description": "Method Not Allowed – използвай POST"
          }
        }
      }
    },
    "/api/v1/add_pomo": {
      "post": {
        "tags": ["Pomodoro"],
        "summary": "Отбелязва Pomodoro цикъл",
        "description": "Увеличава брояча на Pomodoro за днес. Влияе на streak-а. Само POST.",
        "operationId": "addPomo",
        "responses": {
          "200": {
            "description": "Pomodoro е отбелязан",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "example": true },
                    "count": {
                      "type": "integer",
                      "description": "Брой Pomodoro за днес след увеличението",
                      "example": 3
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "405": {
            "description": "Method Not Allowed – използвай POST"
          }
        }
      }
    },
    "/api/v1/stats": {
      "get": {
        "tags": ["Stats"],
        "summary": "Статистики за период",
        "description": "Връща статистики за задачи и Pomodoro. Включва streak (дни с поне 1 Pomodoro).",
        "operationId": "getStats",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Период в дни (1-365). По подразбиране: 30.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Статистики",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "daily": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": { "type": "string", "format": "date" },
                          "total": { "type": "integer" },
                          "done": { "type": "integer" },
                          "missed": { "type": "integer" },
                          "partial": { "type": "integer" },
                          "actual_hours": { "type": "number" },
                          "planned_hours": { "type": "number" }
                        }
                      }
                    },
                    "byType": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": { "type": "string", "enum": ["R", "O"] },
                          "hours": { "type": "number" },
                          "count": { "type": "integer" }
                        }
                      }
                    },
                    "pomoTotal": { "type": "integer" },
                    "streak": { "type": "integer" },
                    "challenge_day": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 40,
                      "description": "min(streak, 40) – за UI брояча"
                    },
                    "api_version": { "type": "integer" }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "tags": ["User"],
        "summary": "Текущ потребител",
        "description": "Връща информация за логнатия потребител. Използва се за проверка дали сесията е активна.",
        "operationId": "me",
        "responses": {
          "200": {
            "description": "Информация за потребителя",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "integer", "example": 1 },
                    "email": {
                      "type": "string",
                      "format": "email",
                      "example": "user@example.com"
                    },
                    "name": { "type": "string", "example": "Иван Иванов" },
                    "picture": {
                      "type": "string",
                      "format": "uri",
                      "example": "https://lh3.googleusercontent.com/..."
                    },
                    "api_version": { "type": "integer", "example": 1 }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "arrow40_session",
        "description": "Сесийна бисквитка, получена след Google Login на /auth.php"
      }
    },
    "schemas": {
      "Task": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "example": "abc123xyz" },
          "user_id": { "type": "integer", "example": 1 },
          "date": { "type": "string", "format": "date", "example": "2026-09-16" },
          "time": {
            "type": "string",
            "nullable": true,
            "example": "14:00"
          },
          "text": {
            "type": "string",
            "maxLength": 500,
            "example": "Урок по астрология"
          },
          "type": {
            "type": "string",
            "enum": ["R", "O"],
            "description": "R = работна, O = обща"
          },
          "priority": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3
          },
          "planned": {
            "type": "number",
            "description": "Планирани часове"
          },
          "actual": {
            "type": "number",
            "description": "Реални часове"
          },
          "status": {
            "type": "string",
            "enum": ["pending", "done", "partial", "missed"]
          },
          "note": {
            "type": "string",
            "nullable": true,
            "maxLength": 1000
          },
          "moved_count": {
            "type": "integer",
            "description": "Колко пъти е преместена"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "message": { "type": "string" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Не е логнат",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": "Unauthorized" }
          }
        }
      },
      "BadRequest": {
        "description": "Невалидни данни",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": "Invalid date format" }
          }
        }
      }
    }
  },
  "security": [
    { "sessionCookie": [] }
  ],
  "externalDocs": {
    "description": "Diaktor MCP сървър за AI-интеграция",
    "url": "https://40dayarrow.com/mcp"
  }
}