{
    "openapi": "3.0.3",
    "info": {
        "title": "VDS Pro API",
        "version": "1.0.0",
        "description": "Public REST API for the VDS Pro Unity SDK and integration partners. All endpoints require a Bearer token issued by Cognito (or a server-signed JWT for Steam users) in the `Authorization` header.",
        "contact": {
            "name": "VDS Pro Support",
            "email": "support@vdspro.net",
            "url": "https://www.vdspro.net/support"
        },
        "license": {
            "name": "Proprietary"
        }
    },
    "servers": [
        { "url": "https://www.vdspro.net/api/v1", "description": "Production" }
    ],
    "security": [
        { "BearerAuth": [] }
    ],
    "tags": [
        { "name": "health", "description": "Lightweight liveness probe for SDK clients" },
        { "name": "session", "description": "Concurrent-session lifecycle for the simulator" },
        { "name": "saves", "description": "Cloud-saved game state" },
        { "name": "capabilities", "description": "Per-user feature flags resolved from subscription / org" },
        { "name": "courseAssignments", "description": "Instructor-assigned course sequences and learner progress" },
        { "name": "progress", "description": "Module progress and aggregate stats" },
        { "name": "delegatedProgress", "description": "Organisation teaching-staff supervised learner progress" },
        { "name": "assessments", "description": "Instructor-assigned assessments" },
        { "name": "certificates", "description": "Pass certificates issued on assessment completion" },
        { "name": "link", "description": "Account linking (Steam, etc.)" }
    ],
    "components": {
        "securitySchemes": {
            "BearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT"
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "properties": {
                    "error": { "type": "string", "description": "Stable machine-readable error code" }
                },
                "required": ["error"]
            },
            "ProgressEvent": {
                "type": "object",
                "properties": {
                    "moduleId": { "type": "string" },
                    "score": { "type": "integer" },
                    "maxScore": { "type": "integer" },
                    "passed": { "type": "boolean" },
                    "completionPercent": { "type": "integer", "minimum": 0, "maximum": 100 },
                    "duration": { "type": "integer", "description": "Seconds" },
                    "metadata": { "type": "object", "additionalProperties": true },
                    "createdAt": { "type": "string", "format": "date-time" }
                },
                "required": ["moduleId", "score", "createdAt"]
            },
            "ProgressEvidence": {
                "type": "object",
                "description": "Optional Unity lesson evidence stored under metadata.unityEvidence for reports and exports.",
                "properties": {
                    "eventType": {
                        "type": "string",
                        "enum": ["module_attempt", "lesson_started", "lesson_completed", "scenario_checkpoint", "hazard_event", "instructor_note", "custom"]
                    },
                    "sessionId": { "type": "string" },
                    "lessonId": { "type": "string" },
                    "lessonName": { "type": "string" },
                    "scenarioId": { "type": "string" },
                    "scenarioName": { "type": "string" },
                    "occurredAt": { "type": "string", "format": "date-time" },
                    "focusAreas": { "type": "array", "items": { "type": "string" } },
                    "conditions": { "type": "array", "items": { "type": "string" } },
                    "metrics": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "key": { "type": "string" },
                                "value": { "oneOf": [{ "type": "number" }, { "type": "string" }] },
                                "unit": { "type": "string" }
                            }
                        }
                    },
                    "incidents": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "type": { "type": "string" },
                                "severity": { "type": "string" },
                                "count": { "type": "integer" },
                                "notes": { "type": "string" }
                            }
                        }
                    },
                    "scoreBreakdown": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "skill": { "type": "string" },
                                "score": { "type": "integer" },
                                "maxScore": { "type": "integer" },
                                "passed": { "type": "boolean" },
                                "notes": { "type": "string" }
                            }
                        }
                    },
                    "instructorNotes": { "type": "string" },
                    "learnerNotes": { "type": "string" },
                    "nextSteps": { "type": "array", "items": { "type": "string" } }
                }
            },
            "Capability": {
                "type": "object",
                "properties": {
                    "userId": { "type": "string" },
                    "email": { "type": "string", "format": "email" },
                    "productSubscriptions": {
                        "type": "object",
                        "additionalProperties": { "$ref": "#/components/schemas/ProductSubscriptionCapability" }
                    },
                    "orgAccess": {
                        "type": "array",
                        "items": { "$ref": "#/components/schemas/OrganisationCapability" }
                    },
                    "subscriptionStatus": { "type": "string", "enum": ["none", "trial", "active", "included", "paused", "expired", "cancelled", "steam"] },
                    "trialDaysLeft": { "type": "integer" },
                    "isTrialActive": { "type": "boolean" },
                    "isIncludedLicenseActive": { "type": "boolean" },
                    "includedLicenseDaysLeft": { "type": "integer" },
                    "includedLicenseEndsAt": { "type": "string", "format": "date-time", "nullable": true },
                    "canAccessPro": { "type": "boolean" },
                    "canAccessProduct": { "type": "boolean" },
                    "targetProduct": { "type": "string", "example": "vdspro" },
                    "activeSessions": { "type": "integer" },
                    "purchases": { "type": "array", "items": { "type": "string" } }
                }
            },
            "ProductSubscriptionCapability": {
                "type": "object",
                "properties": {
                    "status": { "type": "string", "enum": ["trial", "active", "included", "paused", "expired", "cancelled", "steam"] },
                    "trialDaysLeft": { "type": "integer" },
                    "isActive": { "type": "boolean" },
                    "isTrialActive": { "type": "boolean" },
                    "isIncludedLicenseActive": { "type": "boolean" },
                    "includedLicenseDaysLeft": { "type": "integer" },
                    "includedLicenseEndsAt": { "type": "string", "format": "date-time", "nullable": true },
                    "canAccess": { "type": "boolean" }
                }
            },
            "OrganisationCapability": {
                "type": "object",
                "properties": {
                    "orgId": { "type": "string" },
                    "name": { "type": "string" },
                    "role": { "type": "string" },
                    "plan": { "type": "string", "enum": ["personal", "education", "enterprise"] },
                    "products": { "type": "array", "items": { "type": "string" } },
                    "stationSeatCount": { "type": "integer" },
                    "namedUserLimit": { "type": "integer", "nullable": true },
                    "accessStatus": { "type": "string", "enum": ["trial", "active", "included", "expired", "cancelled"] },
                    "trialEndsAt": { "type": "string", "format": "date-time", "nullable": true },
                    "includedLicenseEndsAt": { "type": "string", "format": "date-time", "nullable": true },
                    "includedLicenseDaysLeft": { "type": "integer" },
                    "isIncludedLicenseActive": { "type": "boolean" }
                }
            },
            "CourseModuleState": {
                "type": "object",
                "properties": {
                    "moduleId": { "type": "string" },
                    "name": { "type": "string" },
                    "description": { "type": "string" },
                    "position": { "type": "integer", "minimum": 0 },
                    "state": { "type": "string", "enum": ["locked", "unlocked", "in-progress", "completed"] },
                    "passed": { "type": "boolean" },
                    "bestScore": { "type": "integer" },
                    "maxScore": { "type": "integer" },
                    "attempts": { "type": "integer", "minimum": 0 },
                    "lastAttempt": { "type": "string", "format": "date-time", "nullable": true }
                },
                "required": ["moduleId", "name", "position", "state", "passed", "bestScore", "maxScore", "attempts"]
            },
            "CourseAssignment": {
                "type": "object",
                "properties": {
                    "assignmentId": { "type": "string", "format": "uuid" },
                    "courseId": { "type": "string" },
                    "courseName": { "type": "string" },
                    "orgId": { "type": "string", "nullable": true },
                    "productId": { "type": "string" },
                    "status": { "type": "string", "enum": ["active"] },
                    "assignedBy": { "type": "string", "nullable": true },
                    "assignedAt": { "type": "string", "format": "date-time" },
                    "completedAt": { "type": "string", "format": "date-time", "nullable": true },
                    "dueAt": { "type": "string", "format": "date-time", "nullable": true },
                    "instructions": { "type": "string", "nullable": true },
                    "completedModules": { "type": "integer", "minimum": 0 },
                    "totalModules": { "type": "integer", "minimum": 0 },
                    "progressPercent": { "type": "integer", "minimum": 0, "maximum": 100 },
                    "modules": {
                        "type": "array",
                        "items": { "$ref": "#/components/schemas/CourseModuleState" }
                    }
                },
                "required": ["assignmentId", "courseId", "courseName", "productId", "status", "assignedAt", "completedModules", "totalModules", "progressPercent", "modules"]
            },
            "CourseAssignmentsResponse": {
                "type": "object",
                "properties": {
                    "assignments": {
                        "type": "array",
                        "items": { "$ref": "#/components/schemas/CourseAssignment" }
                    }
                },
                "required": ["assignments"]
            },
            "ProgressModuleSummary": {
                "type": "object",
                "properties": {
                    "moduleId": { "type": "string" },
                    "name": { "type": "string" },
                    "description": { "type": "string" },
                    "order": { "type": "integer" },
                    "bestScore": { "type": "integer" },
                    "maxScore": { "type": "integer" },
                    "passed": { "type": "boolean" },
                    "completionPercent": { "type": "integer", "minimum": 0, "maximum": 100 },
                    "totalDuration": { "type": "integer", "minimum": 0, "description": "Seconds across all attempts" },
                    "attempts": { "type": "integer", "minimum": 0 },
                    "lastAttempt": { "type": "string", "format": "date-time", "nullable": true }
                },
                "required": ["moduleId", "name", "description", "order", "bestScore", "maxScore", "passed", "completionPercent", "totalDuration", "attempts", "lastAttempt"]
            },
            "ProgressSummary": {
                "type": "object",
                "properties": {
                    "productId": { "type": "string" },
                    "modules": {
                        "type": "array",
                        "items": { "$ref": "#/components/schemas/ProgressModuleSummary" }
                    },
                    "completedModules": { "type": "integer", "minimum": 0 },
                    "totalModules": { "type": "integer", "minimum": 0 },
                    "overallPercent": { "type": "integer", "minimum": 0, "maximum": 100 },
                    "totalDuration": { "type": "integer", "minimum": 0, "description": "Seconds across all product attempts" },
                    "totalAttempts": { "type": "integer", "minimum": 0 }
                },
                "required": ["productId", "modules", "completedModules", "totalModules", "overallPercent", "totalDuration", "totalAttempts"]
            },
            "EligibleLearner": {
                "type": "object",
                "properties": {
                    "userId": { "type": "string" },
                    "name": { "type": "string", "nullable": true },
                    "email": { "type": "string", "format": "email", "nullable": true }
                },
                "required": ["userId", "name", "email"]
            },
            "LearnersResponse": {
                "type": "object",
                "properties": {
                    "learners": {
                        "type": "array",
                        "items": { "$ref": "#/components/schemas/EligibleLearner" }
                    }
                },
                "required": ["learners"]
            },
            "DelegatedProgressAuditMetadata": {
                "type": "object",
                "description": "Server-controlled attribution for a supervised simulator attempt.",
                "properties": {
                    "operatorUserId": { "type": "string", "readOnly": true },
                    "operatorRole": { "type": "string", "enum": ["instructor", "manager", "admin"], "readOnly": true },
                    "orgId": { "type": "string", "readOnly": true },
                    "learnerUserId": { "type": "string", "readOnly": true },
                    "recordedAt": { "type": "string", "format": "date-time", "readOnly": true }
                },
                "required": ["operatorUserId", "operatorRole", "orgId", "learnerUserId", "recordedAt"]
            },
            "DelegatedProgressEntry": {
                "type": "object",
                "properties": {
                    "PK": { "type": "string", "description": "Selected learner user ID", "readOnly": true },
                    "SK": { "type": "string", "readOnly": true },
                    "productId": { "type": "string", "minLength": 1 },
                    "moduleId": { "type": "string", "minLength": 1 },
                    "score": { "type": "integer", "minimum": 0, "description": "Must not exceed maxScore." },
                    "maxScore": { "type": "integer", "minimum": 1 },
                    "passed": { "type": "boolean" },
                    "completionPercent": { "type": "integer", "minimum": 0, "maximum": 100 },
                    "duration": { "type": "integer", "minimum": 0, "description": "Seconds" },
                    "metadata": {
                        "type": "object",
                        "properties": {
                            "delegatedProgress": { "$ref": "#/components/schemas/DelegatedProgressAuditMetadata" }
                        },
                        "additionalProperties": true
                    },
                    "orgId": { "type": "string", "readOnly": true },
                    "recordedByUserId": { "type": "string", "description": "Authenticated organisation staff member who recorded the attempt", "readOnly": true },
                    "recordingMode": { "type": "string", "enum": ["supervised"], "readOnly": true },
                    "supervisorRole": { "type": "string", "enum": ["instructor", "manager", "admin"], "readOnly": true },
                    "createdAt": { "type": "string", "format": "date-time", "readOnly": true }
                },
                "required": ["PK", "SK", "productId", "moduleId", "score", "maxScore", "passed", "completionPercent", "duration", "metadata", "orgId", "recordedByUserId", "recordingMode", "supervisorRole", "createdAt"]
            },
            "DelegatedProgressRecordResponse": {
                "type": "object",
                "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "entry": { "$ref": "#/components/schemas/DelegatedProgressEntry" },
                    "learnerId": { "type": "string", "readOnly": true },
                    "orgId": { "type": "string", "readOnly": true },
                    "recordedBy": { "type": "string", "description": "Authenticated organisation staff user ID", "readOnly": true }
                },
                "required": ["success", "entry", "learnerId", "orgId", "recordedBy"]
            },
            "Assessment": {
                "type": "object",
                "properties": {
                    "assessmentId": { "type": "string" },
                    "templateId": { "type": "string" },
                    "templateName": { "type": "string" },
                    "userId": { "type": "string" },
                    "orgId": { "type": "string", "nullable": true },
                    "status": { "type": "string", "enum": ["assigned", "in-progress", "submitted", "reviewed", "passed", "failed"] },
                    "attemptNumber": { "type": "integer" },
                    "percentScore": { "type": "integer" },
                    "passed": { "type": "boolean" },
                    "createdAt": { "type": "string", "format": "date-time" }
                }
            }
        }
    },
    "paths": {
        "/health": {
            "get": {
                "tags": ["health"],
                "summary": "Liveness probe",
                "description": "Returns 200 with a small JSON body. Public; does not require a Bearer token.",
                "security": [],
                "responses": {
                    "200": {
                        "description": "API is up",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "status": { "type": "string", "example": "ok" },
                                        "api": { "type": "string", "example": "v1" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/session/start": {
            "post": {
                "tags": ["session"],
                "summary": "Acquire a concurrent-session slot",
                "description": "Reserves a seat in the org's concurrency limit (or the user's personal subscription) for the duration of the simulator run. Returns 429 if no seats are available.",
                "responses": {
                    "200": { "description": "Session acquired" },
                    "401": { "description": "Missing or invalid bearer token" },
                    "429": { "description": "Concurrency limit reached" }
                }
            }
        },
        "/session/heartbeat": {
            "post": {
                "tags": ["session"],
                "summary": "Keep the session alive",
                "description": "Must be called every ~60 seconds. Sessions without a recent heartbeat are reclaimed to free seats.",
                "responses": {
                    "200": { "description": "Heartbeat acknowledged" },
                    "401": { "description": "Missing or invalid bearer token" }
                }
            }
        },
        "/session/end": {
            "post": {
                "tags": ["session"],
                "summary": "Release the session slot",
                "responses": {
                    "200": { "description": "Session released" }
                }
            }
        },
        "/saves": {
            "post": {
                "tags": ["saves"],
                "summary": "Upload a cloud save",
                "responses": {
                    "200": { "description": "Save accepted" }
                }
            }
        },
        "/saves/{productId}": {
            "get": {
                "tags": ["saves"],
                "summary": "Fetch the latest save for a product",
                "parameters": [
                    { "name": "productId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": { "description": "Save payload" },
                    "404": { "description": "No save exists" }
                }
            }
        },
        "/saves/{productId}/list": {
            "get": {
                "tags": ["saves"],
                "summary": "List all saved slots for a product",
                "parameters": [
                    { "name": "productId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": { "description": "Array of save metadata" }
                }
            }
        },
        "/saves/{productId}/{slot}": {
            "delete": {
                "tags": ["saves"],
                "summary": "Delete a save slot",
                "parameters": [
                    { "name": "productId", "in": "path", "required": true, "schema": { "type": "string" } },
                    { "name": "slot", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": { "description": "Save deleted" }
                }
            }
        },
        "/capabilities": {
            "get": {
                "tags": ["capabilities"],
                "summary": "Resolve the user's feature capabilities",
                "description": "Returns product subscriptions, trials, simulator-purchase licences, organisation station access, and purchased content packs. The simulator client should call this on launch to gate paid features.",
                "responses": {
                    "200": {
                        "description": "Capabilities resolved",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/Capability" }
                            }
                        }
                    }
                }
            }
        },
        "/course-assignments": {
            "get": {
                "tags": ["courseAssignments"],
                "summary": "List the caller's active course assignments",
                "description": "Returns active course assignments enriched with organisation-scoped module progress. Assignments from inactive organisations, inactive memberships, or organisations without access to the assigned product are omitted.",
                "parameters": [
                    {
                        "name": "productId",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Optionally return assignments for one product only."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Active assignments available to the caller",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/CourseAssignmentsResponse" }
                            }
                        }
                    },
                    "401": { "description": "Missing or invalid bearer token" }
                }
            }
        },
        "/organisations/{orgId}/learners": {
            "get": {
                "tags": ["delegatedProgress"],
                "summary": "List learners eligible for supervised simulator use",
                "description": "Requires a user Bearer token for an active instructor, manager, or admin in the active organisation. API keys are rejected. Only active `student` members are returned, and the organisation must be entitled to the requested product.",
                "parameters": [
                    { "name": "orgId", "in": "path", "required": true, "schema": { "type": "string" } },
                    {
                        "name": "productId",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "default": "vdspro" },
                        "description": "Product the simulator will use. Defaults to `vdspro` and is checked against organisation entitlement."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Active eligible learners",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/LearnersResponse" }
                            }
                        }
                    },
                    "401": { "description": "Missing or invalid bearer token" },
                    "403": { "description": "Not active organisation teaching staff, API key used, or product unavailable" }
                }
            }
        },
        "/organisations/{orgId}/learners/{learnerId}/progress/{productId}": {
            "get": {
                "tags": ["delegatedProgress"],
                "summary": "Get one learner's organisation-scoped product progress",
                "description": "Requires an active organisation instructor, manager, or admin and an active student in the same path organisation. Progress attempts from other organisations or personal use are excluded.",
                "parameters": [
                    { "name": "orgId", "in": "path", "required": true, "schema": { "type": "string" } },
                    { "name": "learnerId", "in": "path", "required": true, "schema": { "type": "string" } },
                    { "name": "productId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": {
                        "description": "Organisation-scoped product summary",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/ProgressSummary" }
                            }
                        }
                    },
                    "401": { "description": "Missing or invalid bearer token" },
                    "403": { "description": "Delegated access denied or product unavailable" },
                    "404": { "description": "Learner is not an active student in this organisation" }
                }
            }
        },
        "/organisations/{orgId}/learners/{learnerId}/course-assignments": {
            "get": {
                "tags": ["delegatedProgress", "courseAssignments"],
                "summary": "List one learner's active assignments in an organisation",
                "description": "Returns only active assignments owned by the selected learner in the path organisation and enriched with that learner's organisation-scoped module progress.",
                "parameters": [
                    { "name": "orgId", "in": "path", "required": true, "schema": { "type": "string" } },
                    { "name": "learnerId", "in": "path", "required": true, "schema": { "type": "string" } },
                    {
                        "name": "productId",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Optionally return assignments for one entitled product only."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Active assignments for the selected learner",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/CourseAssignmentsResponse" }
                            }
                        }
                    },
                    "401": { "description": "Missing or invalid bearer token" },
                    "403": { "description": "Delegated access denied or product unavailable" },
                    "404": { "description": "Learner is not an active student in this organisation" }
                }
            }
        },
        "/organisations/{orgId}/learners/{learnerId}/progress": {
            "post": {
                "tags": ["delegatedProgress"],
                "summary": "Record supervised progress for one selected learner",
                "description": "Records an attempt for the active student named in the path while preserving the authenticated staff member as the operator. Organisation, learner, operator, recording-mode, and supervisor-role fields are derived by the server; any top-level client override of those identities is rejected.",
                "parameters": [
                    { "name": "orgId", "in": "path", "required": true, "schema": { "type": "string" } },
                    { "name": "learnerId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["productId", "moduleId"],
                                "properties": {
                                    "productId": { "type": "string", "minLength": 1, "description": "Trimmed by the server and must contain non-whitespace characters.", "example": "vdspro" },
                                    "moduleId": { "type": "string", "minLength": 1, "description": "Trimmed by the server and must contain non-whitespace characters.", "example": "roundabouts" },
                                    "score": { "type": "integer", "minimum": 0, "description": "Must not exceed maxScore (or 100 when maxScore is omitted).", "example": 82 },
                                    "maxScore": { "type": "integer", "minimum": 1, "example": 100 },
                                    "passed": { "type": "boolean", "example": true },
                                    "completionPercent": { "type": "integer", "minimum": 0, "maximum": 100, "example": 100 },
                                    "duration": { "type": "integer", "minimum": 0, "description": "Seconds", "example": 900 },
                                    "metadata": { "type": "object", "additionalProperties": true },
                                    "evidence": { "$ref": "#/components/schemas/ProgressEvidence" }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Attempt recorded for the selected learner with immutable supervised attribution",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/DelegatedProgressRecordResponse" }
                            }
                        }
                    },
                    "400": { "description": "Missing/invalid progress values or a client identity override was supplied" },
                    "401": { "description": "Missing or invalid bearer token" },
                    "403": { "description": "Delegated access denied or product unavailable" },
                    "404": { "description": "Learner is not an active student in this organisation" }
                }
            }
        },
        "/progress": {
            "post": {
                "tags": ["progress"],
                "summary": "Record a module attempt",
                "description": "Records progress from Unity. Include `evidence` when the simulator has lesson-level data for reports, CSV exports, instructor review, or compliance records.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["productId", "moduleId"],
                                "properties": {
                                    "productId": { "type": "string", "example": "vdspro" },
                                    "orgId": { "type": "string", "description": "Organisation whose assignment and progress should be updated. Strongly recommended for organisation learners." },
                                    "moduleId": { "type": "string", "example": "roundabouts" },
                                    "score": { "type": "integer", "example": 62 },
                                    "maxScore": { "type": "integer", "example": 100 },
                                    "passed": { "type": "boolean", "example": false },
                                    "completionPercent": { "type": "integer", "minimum": 0, "maximum": 100, "example": 80 },
                                    "duration": { "type": "integer", "description": "Seconds", "example": 1200 },
                                    "metadata": { "type": "object", "additionalProperties": true },
                                    "evidence": { "$ref": "#/components/schemas/ProgressEvidence" }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": { "description": "Recorded" }
                }
            },
            "get": {
                "tags": ["progress"],
                "summary": "Aggregate progress across all products",
                "responses": {
                    "200": { "description": "Per-product summaries" }
                }
            }
        },
        "/progress/{productId}": {
            "get": {
                "tags": ["progress"],
                "summary": "Get the caller's per-product progress summary",
                "parameters": [
                    { "name": "productId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": {
                        "description": "Aggregate module progress summary",
                        "content": {
                            "application/json": {
                                "schema": { "$ref": "#/components/schemas/ProgressSummary" }
                            }
                        }
                    }
                }
            }
        },
        "/assessments": {
            "get": {
                "tags": ["assessments"],
                "summary": "List assessments assigned to the user",
                "responses": {
                    "200": {
                        "description": "Array of assessments",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": { "$ref": "#/components/schemas/Assessment" }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/assessments/{assessmentId}": {
            "get": {
                "tags": ["assessments"],
                "summary": "Get one assessment",
                "parameters": [
                    { "name": "assessmentId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": { "description": "Assessment detail" },
                    "404": { "description": "Assessment not found or not assigned to caller" }
                }
            }
        },
        "/assessments/{assessmentId}/start": {
            "post": {
                "tags": ["assessments"],
                "summary": "Mark assessment as in-progress",
                "parameters": [
                    { "name": "assessmentId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": { "description": "Started" }
                }
            }
        },
        "/assessments/{assessmentId}/submit": {
            "post": {
                "tags": ["assessments"],
                "summary": "Submit assessment scores",
                "parameters": [
                    { "name": "assessmentId", "in": "path", "required": true, "schema": { "type": "string" } }
                ],
                "responses": {
                    "200": { "description": "Submitted; awaiting instructor review" }
                }
            }
        },
        "/certificates": {
            "get": {
                "tags": ["certificates"],
                "summary": "List the user's pass certificates",
                "responses": {
                    "200": { "description": "Array of certificate refs" }
                }
            }
        }
    }
}
