{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/flowral-app/json-schema/flowral-app-report-schema.json",
  "title": "Report",
  "description": "The delivery health of a flow: what is done, what is left, what is holding it up, and who is carrying it.",
  "x-generated": "2026-11-08",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/flowral-app-openapi.json#/components/schemas/Report",
  "type": "object",
  "properties": {
    "flowId": {
      "type": "string"
    },
    "flowName": {
      "type": "string"
    },
    "completion": {
      "type": "number",
      "description": "0–1."
    },
    "tasksTotal": {
      "type": "integer"
    },
    "tasksDone": {
      "type": "integer"
    },
    "tasksReady": {
      "type": "integer"
    },
    "tasksBlocked": {
      "type": "integer"
    },
    "hoursEstimated": {
      "type": [
        "number",
        "null"
      ]
    },
    "hoursRemaining": {
      "type": [
        "number",
        "null"
      ]
    },
    "unestimatedTasks": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Task ids with no estimate — the reason a projection is soft."
    },
    "orphanedTasks": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Tasks nothing depends on and that depend on nothing."
    },
    "workload": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "memberId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "openTasks": {
            "type": "integer"
          },
          "hoursRemaining": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      }
    },
    "topBlockers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "taskId": {
            "type": "string"
          },
          "taskName": {
            "type": "string"
          },
          "blocking": {
            "type": "integer"
          }
        }
      }
    }
  },
  "required": [
    "flowId",
    "completion",
    "tasksTotal"
  ]
}