{"openapi":"3.0.0","paths":{"/api/users":{"post":{"operationId":"UserController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRo"}}}},"409":{"description":"Username already exists"}},"security":[{"bearer":[]}],"summary":"Create a new user","tags":["Users"]},"get":{"operationId":"UserController_findAll","parameters":[],"responses":{"200":{"description":"List of all users","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserRo"}}}}}},"security":[{"bearer":[]}],"summary":"Get all users","tags":["Users"]}},"/api/users/{id}":{"get":{"operationId":"UserController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"User found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRo"}}}},"404":{"description":"User not found"}},"security":[{"bearer":[]}],"summary":"Get a user by ID","tags":["Users"]},"patch":{"operationId":"UserController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRo"}}}},"404":{"description":"User not found"},"409":{"description":"Username already exists"}},"security":[{"bearer":[]}],"summary":"Update a user","tags":["Users"]},"delete":{"operationId":"UserController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"User deleted successfully"},"404":{"description":"User not found"}},"security":[{"bearer":[]}],"summary":"Delete a user","tags":["Users"]}},"/api/auth/login":{"post":{"operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRo"}}}},"401":{"description":"Invalid credentials"}},"summary":"Login with username and password","tags":["Auth"]}},"/api/auth/signup":{"post":{"operationId":"AuthController_signup","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupDto"}}}},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRo"}}}},"409":{"description":"Email already exists"}},"summary":"Register a new user","tags":["Auth"]}},"/api/auth/profile":{"get":{"operationId":"AuthController_getProfile","parameters":[],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileRo"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Get current user profile","tags":["Auth"]}},"/api/auth/forget-password":{"post":{"operationId":"AuthController_forgetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgetPasswordDto"}}}},"responses":{"200":{"description":"Password reset email sent (if email exists)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgetPasswordRo"}}}}},"summary":"Request password reset","tags":["Auth"]}},"/api/auth/reset-password":{"post":{"operationId":"AuthController_resetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRo"}}}},"400":{"description":"Invalid or expired token"}},"summary":"Reset password with token","tags":["Auth"]}},"/api/employees":{"post":{"operationId":"EmployeeController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmployeeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeDetailRo"}}}},"409":{"description":"Email already exists"}},"security":[{"bearer":[]}],"summary":"Create a new employee","tags":["Employees"]},"get":{"operationId":"EmployeeController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search by name or email","schema":{"type":"string"}},{"name":"course","required":false,"in":"query","description":"Filter by course name","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by training status","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Sort field","schema":{"default":"createdAt","type":"string","enum":["name","email","createdAt","updatedAt"]}},{"name":"sortOrder","required":false,"in":"query","description":"Sort direction","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"minimum":1,"maximum":100,"default":10,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmployeesRo"}}}}},"security":[{"bearer":[]}],"summary":"List employees with pagination and filtering","tags":["Employees"]}},"/api/employees/stats":{"get":{"operationId":"EmployeeController_getStats","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgramStatsRo"}}}}},"security":[{"bearer":[]}],"summary":"Get program-wide statistics","tags":["Employees"]}},"/api/employees/reports/{course}":{"get":{"operationId":"EmployeeController_getCourseReport","parameters":[{"name":"course","required":true,"in":"path","schema":{"example":"Self Assessment","type":"string"}},{"name":"search","required":false,"in":"query","description":"Search by name or email","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by training status","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Sort field","schema":{"default":"createdAt","type":"string","enum":["name","email","createdAt","updatedAt"]}},{"name":"sortOrder","required":false,"in":"query","description":"Sort direction","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"minimum":1,"maximum":100,"default":10,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedCourseReportRo"}}}}},"security":[{"bearer":[]}],"summary":"Get report data for a specific course","tags":["Employees"]}},"/api/employees/reports/{course}/body-aggregation":{"get":{"operationId":"EmployeeController_getBodyAggregation","parameters":[{"name":"course","required":true,"in":"path","schema":{"example":"Self Assessment","type":"string"}},{"name":"dataPath","required":false,"in":"query","description":"Dot-notated path within courseData","schema":{"example":"bodyPartsDiscomfort","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscomfortSummaryRo"}}}}},"security":[{"bearer":[]}],"summary":"Get aggregated body part data for a course","tags":["Employees"]}},"/api/employees/reports/{course}/chart-aggregation":{"get":{"operationId":"EmployeeController_getChartAggregation","parameters":[{"name":"course","required":true,"in":"path","schema":{"example":"Self Assessment","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChartAggregationRo"}}}}},"security":[{"bearer":[]}],"summary":"Get aggregated chart data (result, issues, actions, equipment)","tags":["Employees"]}},"/api/employees/{id}":{"get":{"operationId":"EmployeeController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeDetailRo"}}}},"404":{"description":"Employee not found"}},"security":[{"bearer":[]}],"summary":"Get employee detail by ID","tags":["Employees"]},"patch":{"operationId":"EmployeeController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmployeeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeDetailRo"}}}},"404":{"description":"Employee not found"}},"security":[{"bearer":[]}],"summary":"Update employee","tags":["Employees"]},"delete":{"operationId":"EmployeeController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Employee deleted"},"404":{"description":"Employee not found"}},"security":[{"bearer":[]}],"summary":"Delete employee","tags":["Employees"]}},"/api/employees/{id}/follow-up-status":{"patch":{"operationId":"EmployeeController_updateFollowUpStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeDetailRo"}}}}},"security":[{"bearer":[]}],"summary":"Update follow-up status of an employee","tags":["Employees"]}},"/api/employees/{id}/trainings":{"post":{"operationId":"EmployeeController_addTraining","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTrainingDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingRo"}}}}},"security":[{"bearer":[]}],"summary":"Add a training to an employee","tags":["Employees"]}},"/api/employees/{id}/trainings/{trainingId}":{"patch":{"operationId":"EmployeeController_updateTraining","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"trainingId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTrainingDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingRo"}}}}},"security":[{"bearer":[]}],"summary":"Update a training","tags":["Employees"]},"delete":{"operationId":"EmployeeController_removeTraining","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"trainingId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Training removed"}},"security":[{"bearer":[]}],"summary":"Remove a training","tags":["Employees"]}},"/api/employees/{id}/attachments":{"post":{"operationId":"EmployeeController_uploadAttachment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"File to attach (max 10 MB)","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"label":{"type":"string","description":"Optional label"}},"required":["file"]}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentRo"}}}},"404":{"description":"Employee not found"}},"security":[{"bearer":[]}],"summary":"Upload a file attachment to an employee","tags":["Employees"]},"get":{"operationId":"EmployeeController_listAttachments","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentWithUrlRo"}}}}}},"security":[{"bearer":[]}],"summary":"List all attachments for an employee (with download URLs)","tags":["Employees"]}},"/api/employees/{id}/attachments/bulk":{"post":{"operationId":"EmployeeController_uploadAttachmentsBulk","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Files to attach (max 10 MB each)","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"}}},"required":["files"]}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentRo"}}}}}},"security":[{"bearer":[]}],"summary":"Upload multiple file attachments (max 10 files)","tags":["Employees"]}},"/api/employees/{id}/attachments/{attachmentId}":{"get":{"operationId":"EmployeeController_getAttachment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"attachmentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentWithUrlRo"}}}},"404":{"description":"Employee or attachment not found"}},"security":[{"bearer":[]}],"summary":"Get a single attachment with a pre-signed download URL","tags":["Employees"]},"delete":{"operationId":"EmployeeController_removeAttachment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"attachmentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Attachment deleted"},"404":{"description":"Employee or attachment not found"}},"security":[{"bearer":[]}],"summary":"Delete an attachment from employee and S3","tags":["Employees"]}},"/api/employees/{id}/notes":{"get":{"operationId":"EmployeeController_listNotes","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteRo"}}}}},"404":{"description":"Employee not found"}},"security":[{"bearer":[]}],"summary":"List all notes for an employee (newest first)","tags":["Employees"]},"post":{"operationId":"EmployeeController_addNote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteRo"}}}},"404":{"description":"Employee not found"}},"security":[{"bearer":[]}],"summary":"Add a note to an employee","tags":["Employees"]}},"/api/employees/{id}/notes/{noteId}":{"patch":{"operationId":"EmployeeController_updateNote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"noteId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNoteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteRo"}}}},"404":{"description":"Employee or note not found"}},"security":[{"bearer":[]}],"summary":"Update a note","tags":["Employees"]},"delete":{"operationId":"EmployeeController_removeNote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"noteId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Note deleted"},"404":{"description":"Employee or note not found"}},"security":[{"bearer":[]}],"summary":"Delete a note from an employee","tags":["Employees"]}},"/api/employees/lms/receive":{"post":{"operationId":"EmployeeController_receiveLmsData","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LmsPayloadDto"}}}},"responses":{"200":{"description":"Data received successfully"},"400":{"description":"Bad request / course not enabled"},"401":{"description":"Invalid or inactive API key"}},"security":[{"bearer":[]}],"summary":"Receive training data from LMS / Storyline","tags":["Employees"]}},"/api/organizations":{"post":{"operationId":"OrganizationController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDetailRo"}}}},"409":{"description":"Abbreviation already exists"}},"security":[{"bearer":[]}],"summary":"Create a new organization","tags":["Organizations"]},"get":{"operationId":"OrganizationController_findAll","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationListItemRo"}}}}}},"security":[{"bearer":[]}],"summary":"List all organizations","tags":["Organizations"]}},"/api/organizations/{id}":{"get":{"operationId":"OrganizationController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDetailRo"}}}},"404":{"description":"Organization not found"}},"security":[{"bearer":[]}],"summary":"Get organization detail by ID","tags":["Organizations"]},"patch":{"operationId":"OrganizationController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDetailRo"}}}},"404":{"description":"Organization not found"}},"security":[{"bearer":[]}],"summary":"Update organization","tags":["Organizations"]},"delete":{"operationId":"OrganizationController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Organization deleted"},"404":{"description":"Organization not found"}},"security":[{"bearer":[]}],"summary":"Delete organization","tags":["Organizations"]}},"/api/organizations/{id}/regenerate-api-key":{"post":{"operationId":"OrganizationController_regenerateApiKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDetailRo"}}}}},"security":[{"bearer":[]}],"summary":"Regenerate API key for organization","tags":["Organizations"]}},"/api/organizations/{id}/users":{"get":{"operationId":"OrganizationController_getUsers","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserRo"}}}}}},"security":[{"bearer":[]}],"summary":"List users of an organization","tags":["Organizations"]},"post":{"operationId":"OrganizationController_addUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddOrgUserDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRo"}}}},"409":{"description":"Email or username already exists"}},"security":[{"bearer":[]}],"summary":"Add a user to organization","tags":["Organizations"]}},"/api/organizations/{id}/users/{userId}":{"patch":{"operationId":"OrganizationController_updateUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrgUserDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRo"}}}}},"security":[{"bearer":[]}],"summary":"Update an organization user","tags":["Organizations"]},"delete":{"operationId":"OrganizationController_removeUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"User removed"}},"security":[{"bearer":[]}],"summary":"Remove an organization user","tags":["Organizations"]}},"/api/organizations/{id}/sync-ewihub-super-admin":{"post":{"description":"Super-admin endpoint. Logs in to ewihub.com with admin credentials creates a temporary org user, scrapes every employee profile, upserts the data, and removes the temp user. No org-user credentials required.","operationId":"OrganizationController_syncFromEwihubSuperAdmin","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResultRo"}}}},"400":{"description":"Admin credentials not configured or org not found"},"401":{"description":"EWI Hub admin credentials invalid"},"404":{"description":"Organization not found"}},"security":[{"bearer":[]}],"summary":"Sync employee data from ewihub.com (admin-based)","tags":["Organizations"]}},"/api/organizations/{id}/sync-ewihub":{"post":{"description":"Logs in to ewihub.com with the supplied organization-user credentials, scrapes every employee profile, and upserts the data. Existing employees (matched by email) are updated; new ones are created.","operationId":"OrganizationController_syncFromEwihub","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncEwihubDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResultRo"}}}},"401":{"description":"EWI Hub credentials invalid"},"404":{"description":"Organization not found"}},"security":[{"bearer":[]}],"summary":"Sync employee data from ewihub.com","tags":["Organizations"]}},"/api/organizations/seed":{"post":{"operationId":"OrganizationController_seedFromFile","parameters":[],"requestBody":{"required":true,"description":"JSON file containing an array of organization seed objects","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedResultRo"}}}},"400":{"description":"Invalid JSON or missing file"}},"security":[{"bearer":[]}],"summary":"Seed organizations from a JSON file upload","tags":["Organizations"]}}},"info":{"title":"Image Generation API","description":"API for image generation service with user management","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"CreateUserDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"},"email":{"type":"string","description":"Email address","example":"john.doe@example.com"},"username":{"type":"string","description":"Username","example":"john_doe","minLength":3},"password":{"type":"string","description":"Password","example":"password123","minLength":6},"role":{"type":"string","description":"User role","enum":["superAdmin","orgUser"],"default":"orgUser"},"organization":{"type":"string","description":"Organization ID (required for orgUser role)","example":"507f1f77bcf86cd799439011"}},"required":["firstName","lastName","email","username","password"]},"UserRo":{"type":"object","properties":{"id":{"type":"string","description":"User ID","example":"507f1f77bcf86cd799439011"},"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"},"email":{"type":"string","description":"Email address","example":"john.doe@example.com"},"username":{"type":"string","description":"Username","example":"john_doe"},"role":{"type":"string","description":"User role","enum":["superAdmin","orgUser"],"example":"orgUser"},"organization":{"type":"string","description":"Organization ID","example":"507f1f77bcf86cd799439011"},"createdAt":{"format":"date-time","type":"string","description":"User creation timestamp","example":"2024-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","description":"User update timestamp","example":"2024-01-01T00:00:00.000Z"}},"required":["id","firstName","lastName","email","username","role","createdAt","updatedAt"]},"UpdateUserDto":{"type":"object","properties":{"username":{"type":"string","description":"Username","example":"john_doe","minLength":3},"password":{"type":"string","description":"Password","example":"password123","minLength":6},"role":{"type":"string","description":"User role","enum":["superAdmin","orgUser"]},"organization":{"type":"string","description":"Organization ID","example":"507f1f77bcf86cd799439011"}}},"LoginDto":{"type":"object","properties":{"username":{"type":"string","description":"Username","example":"john_doe"},"password":{"type":"string","description":"Password","example":"password123"}},"required":["username","password"]},"LoginRo":{"type":"object","properties":{"access_token":{"type":"string","description":"JWT access token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}},"required":["access_token"]},"SignupDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"},"email":{"type":"string","description":"Email address","example":"john.doe@example.com"},"username":{"type":"string","description":"Username","example":"john_doe","minLength":3},"password":{"type":"string","description":"Password (min 8 chars, must include letter and number)","example":"Password123","minLength":8}},"required":["firstName","lastName","email","username","password"]},"SignupRo":{"type":"object","properties":{"id":{"type":"string","description":"User ID","example":"507f1f77bcf86cd799439011"},"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"},"email":{"type":"string","description":"Email address","example":"john.doe@example.com"},"username":{"type":"string","description":"Username","example":"john_doe"},"createdAt":{"format":"date-time","type":"string","description":"User creation timestamp","example":"2024-01-01T00:00:00.000Z"}},"required":["id","firstName","lastName","email","username","createdAt"]},"ProfileRo":{"type":"object","properties":{"id":{"type":"string","description":"User ID","example":"507f1f77bcf86cd799439011"},"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"},"email":{"type":"string","description":"Email address","example":"john.doe@example.com"},"username":{"type":"string","description":"Username","example":"john_doe"},"role":{"type":"string","description":"User role","example":"orgUser"},"organization":{"type":"string","description":"Organization ID","example":"507f1f77bcf86cd799439011"},"createdAt":{"format":"date-time","type":"string","description":"User creation timestamp","example":"2024-01-01T00:00:00.000Z"},"updatedAt":{"format":"date-time","type":"string","description":"User update timestamp","example":"2024-01-01T00:00:00.000Z"}},"required":["id","firstName","lastName","email","username","role","createdAt","updatedAt"]},"ForgetPasswordDto":{"type":"object","properties":{"email":{"type":"string","description":"User email address","example":"john@example.com"}},"required":["email"]},"ForgetPasswordRo":{"type":"object","properties":{"message":{"type":"string","description":"Success message","example":"If the email exists, a password reset link has been sent"},"resetToken":{"type":"string","description":"Reset token (only returned in development mode for testing)","example":"abc123..."}},"required":["message"]},"ResetPasswordDto":{"type":"object","properties":{"token":{"type":"string","description":"Password reset token received via email"},"newPassword":{"type":"string","description":"New password","example":"newPassword123"}},"required":["token","newPassword"]},"ResetPasswordRo":{"type":"object","properties":{"message":{"type":"string","description":"Success message","example":"Password has been reset successfully"}},"required":["message"]},"CreateEmployeeDto":{"type":"object","properties":{"name":{"type":"string","description":"Employee full name","example":"John Doe"},"email":{"type":"string","description":"Employee email","example":"john.doe@company.com"},"oldProfileUrl":{"type":"string","description":"Legacy profile URL","example":"/employees/123/john-doe"},"followUpStatus":{"type":"string","description":"Follow-up status","example":"Not Assigned"}},"required":["name","email"]},"DemographicRo":{"type":"object","properties":{"age":{"type":"string"},"heightRaw":{"type":"string"},"heightInches":{"type":"number"},"handedness":{"type":"string"},"wearsBifocals":{"type":"boolean"},"visualIssue":{"type":"string"},"computerTime":{"type":"string"},"dualMonitors":{"type":"boolean"},"usesLaptop":{"type":"boolean"},"sitToStand":{"type":"string"},"chairAdjustable":{"type":"boolean"}}},"DiscomfortRo":{"type":"object","properties":{"area":{"type":"string"},"severity":{"type":"number"}},"required":["area"]},"IssuesRo":{"type":"object","properties":{"recommendations":{"type":"array","items":{"type":"string"}},"actionItems":{"type":"array","items":{"type":"string"}},"suggestions":{"type":"array","items":{"type":"string"}},"result":{"type":"string"},"raw":{"type":"string"},"other":{"type":"array","items":{"type":"string"}}}},"BodyPartDiscomfortRo":{"type":"object","properties":{"bodyPart":{"type":"string","enum":["upperBack","midBack","lowerBack","buttocks","head","neck","eyes","leftShoulder","rightShoulder","leftUpperArm","rightUpperArm","leftElbow","rightElbow","leftLowerArm","rightLowerArm","leftWrist","rightWrist","leftHand","rightHand","leftThigh","rightThigh","leftKnee","rightKnee","leftLowerLeg","rightLowerLeg","leftFootOrAnkle","rightFootOrAnkle"],"description":"Body part key","example":"rightKnee"},"severity":{"type":"number","description":"Non-zero severity level","example":2}},"required":["bodyPart","severity"]},"SelfAssessmentCourseDataRo":{"type":"object","properties":{"demographic":{"$ref":"#/components/schemas/DemographicRo"},"discomforts":{"type":"array","items":{"$ref":"#/components/schemas/DiscomfortRo"}},"actions":{"type":"array","items":{"type":"string"}},"equipment":{"type":"array","items":{"type":"string"}},"issues":{"$ref":"#/components/schemas/IssuesRo"},"result":{"type":"string"},"bodyPartsDiscomfort":{"description":"Body parts with non-zero severity","type":"array","items":{"$ref":"#/components/schemas/BodyPartDiscomfortRo"}}}},"OfficeErgonomicsCourseDataRo":{"type":"object","properties":{}},"TrainingRo":{"type":"object","properties":{"id":{"type":"string","description":"Training ID"},"course":{"type":"string","description":"Course name"},"status":{"type":"string","description":"Training status"},"startedDate":{"type":"string","description":"Start date"},"completedDate":{"type":"string","description":"Completion date"},"courseData":{"description":"Course-specific data","oneOf":[{"$ref":"#/components/schemas/SelfAssessmentCourseDataRo"},{"$ref":"#/components/schemas/OfficeErgonomicsCourseDataRo"}]}},"required":["id","course","status"]},"AttachmentRo":{"type":"object","properties":{"id":{"type":"string","description":"Attachment ID"},"key":{"type":"string","description":"S3 object key"},"originalName":{"type":"string","description":"Original file name","example":"report.pdf"},"mimeType":{"type":"string","description":"MIME type","example":"application/pdf"},"size":{"type":"number","description":"File size in bytes","example":204800},"label":{"type":"string","description":"User-provided label"},"uploadedBy":{"type":"string","description":"User ID of uploader"},"createdAt":{"type":"string","description":"Upload timestamp"}},"required":["id","key","originalName","mimeType","size","createdAt"]},"NoteRo":{"type":"object","properties":{"id":{"type":"string","description":"Note ID"},"content":{"type":"string","description":"Note content (Markdown)"},"createdBy":{"type":"string","description":"User ID of the author"},"createdByName":{"type":"string","description":"Display name of the author"},"createdAt":{"type":"string","description":"Creation timestamp"},"updatedAt":{"type":"string","description":"Last update timestamp"}},"required":["id","content","createdAt","updatedAt"]},"EmployeeDetailRo":{"type":"object","properties":{"id":{"type":"string","description":"Employee ID"},"name":{"type":"string","description":"Employee full name"},"email":{"type":"string","description":"Employee email"},"oldProfileUrl":{"type":"string","description":"Legacy profile URL"},"organization":{"type":"string","description":"Organization ID"},"department":{"type":"string","description":"Department name"},"followUpStatus":{"type":"string","description":"Follow-up status"},"trainings":{"description":"All trainings","type":"array","items":{"$ref":"#/components/schemas/TrainingRo"}},"attachments":{"description":"File attachments","type":"array","items":{"$ref":"#/components/schemas/AttachmentRo"}},"notes":{"description":"Manager/admin notes (Markdown)","type":"array","items":{"$ref":"#/components/schemas/NoteRo"}},"createdAt":{"type":"string","description":"Creation timestamp"},"updatedAt":{"type":"string","description":"Update timestamp"}},"required":["id","name","email","trainings","attachments","notes","createdAt","updatedAt"]},"TrainingStatusRo":{"type":"object","properties":{"course":{"type":"string","description":"Course name"},"status":{"type":"string","description":"Training status"}},"required":["course","status"]},"EmployeeListItemRo":{"type":"object","properties":{"id":{"type":"string","description":"Employee ID"},"name":{"type":"string","description":"Employee full name"},"email":{"type":"string","description":"Employee email"},"oldProfileUrl":{"type":"string","description":"Legacy profile URL"},"followUpStatus":{"type":"string","description":"Follow-up status"},"trainingStatuses":{"description":"Status per course","type":"array","items":{"$ref":"#/components/schemas/TrainingStatusRo"}}},"required":["id","name","email","trainingStatuses"]},"PaginationMetaRo":{"type":"object","properties":{"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}},"required":["total","page","limit","totalPages"]},"PaginatedEmployeesRo":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmployeeListItemRo"}},"meta":{"$ref":"#/components/schemas/PaginationMetaRo"}},"required":["data","meta"]},"CourseStatsRo":{"type":"object","properties":{"course":{"type":"string"},"enrolled":{"type":"number"},"completed":{"type":"number"},"inProgress":{"type":"number"},"statusBreakdown":{"type":"object","description":"Status breakdown"}},"required":["course","enrolled","completed","inProgress","statusBreakdown"]},"ProgramStatsRo":{"type":"object","properties":{"totalEmployees":{"type":"number"},"courses":{"type":"array","items":{"$ref":"#/components/schemas/CourseStatsRo"}},"completionRate":{"type":"number"}},"required":["totalEmployees","courses","completionRate"]},"CourseReportRowRo":{"type":"object","properties":{"employeeId":{"type":"string","description":"Employee ID"},"name":{"type":"string","description":"Employee name"},"email":{"type":"string","description":"Employee email"},"oldProfileUrl":{"type":"string","description":"Legacy profile URL"},"course":{"type":"string","description":"Course name"},"status":{"type":"string","description":"Training status"},"startedDate":{"type":"string","description":"Start date"},"completedDate":{"type":"string","description":"Completion date"},"result":{"type":"string","description":"Course-specific result extracted from courseData"},"followUpStatus":{"type":"string","description":"Employee Follow-up status"},"trainingId":{"type":"string","description":"Training ID"}},"required":["employeeId","name","email","course","status"]},"PaginatedCourseReportRo":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CourseReportRowRo"}},"meta":{"$ref":"#/components/schemas/PaginationMetaRo"}},"required":["data","meta"]},"BodyPartAggregationRo":{"type":"object","properties":{"key":{"type":"string","description":"Body part key"},"count":{"type":"number","description":"Number of reports"},"totalSeverity":{"type":"number","description":"Sum of severity values"},"avgSeverity":{"type":"number","description":"Average severity"}},"required":["key","count","totalSeverity","avgSeverity"]},"DiscomfortSummaryRo":{"type":"object","properties":{"countData":{"type":"object","description":"Count per body part"},"avgData":{"type":"object","description":"Average severity per body part"},"details":{"description":"Detailed aggregation per body part","type":"array","items":{"$ref":"#/components/schemas/BodyPartAggregationRo"}}},"required":["countData","avgData","details"]},"ChartAggregationRo":{"type":"object","properties":{"result":{"type":"object","description":"Aggregated result counts","example":{"Pass":408,"Action Needed":314,"Assessment":500}},"issues":{"type":"object","description":"Aggregated issue counts across all completed trainings"},"actions":{"type":"object","description":"Aggregated action item counts across all completed trainings"},"equipment":{"type":"object","description":"Aggregated equipment need counts across all completed trainings"}},"required":["result","issues","actions","equipment"]},"UpdateEmployeeDto":{"type":"object","properties":{"name":{"type":"string","description":"Employee full name"},"email":{"type":"string","description":"Employee email"},"oldProfileUrl":{"type":"string","description":"Legacy profile URL"},"followUpStatus":{"type":"string","description":"Follow-up status"}}},"DemographicDto":{"type":"object","properties":{"age":{"type":"string","example":"25-34"},"heightRaw":{"type":"string","example":"5'10\""},"heightInches":{"type":"number","example":70},"handedness":{"type":"string","example":"right"},"wearsBifocals":{"type":"boolean","example":false},"visualIssue":{"type":"string","example":"none"},"computerTime":{"type":"string","example":"6-8 hours"},"dualMonitors":{"type":"boolean","example":false},"usesLaptop":{"type":"boolean","example":false},"sitToStand":{"type":"string","example":"sit only"},"chairAdjustable":{"type":"boolean","example":true}}},"DiscomfortDto":{"type":"object","properties":{"area":{"type":"string","example":"lower_back"},"severity":{"type":"number","example":3}},"required":["area"]},"IssuesDto":{"type":"object","properties":{"recommendations":{"type":"array","items":{"type":"string"}},"actionItems":{"type":"array","items":{"type":"string"}},"suggestions":{"type":"array","items":{"type":"string"}},"result":{"type":"string","example":"pass"},"raw":{"type":"string"},"other":{"type":"array","items":{"type":"string"}}}},"BodyPartDiscomfortDto":{"type":"object","properties":{"bodyPart":{"type":"string","enum":["upperBack","midBack","lowerBack","buttocks","head","neck","eyes","leftShoulder","rightShoulder","leftUpperArm","rightUpperArm","leftElbow","rightElbow","leftLowerArm","rightLowerArm","leftWrist","rightWrist","leftHand","rightHand","leftThigh","rightThigh","leftKnee","rightKnee","leftLowerLeg","rightLowerLeg","leftFootOrAnkle","rightFootOrAnkle"],"example":"rightKnee","description":"Body part key"},"severity":{"type":"number","example":2,"description":"Non-zero severity level"}},"required":["bodyPart","severity"]},"SelfAssessmentCourseDataDto":{"type":"object","properties":{"demographic":{"$ref":"#/components/schemas/DemographicDto"},"discomforts":{"type":"array","items":{"$ref":"#/components/schemas/DiscomfortDto"}},"actions":{"type":"array","items":{"type":"string"}},"equipment":{"type":"array","items":{"type":"string"}},"issues":{"$ref":"#/components/schemas/IssuesDto"},"result":{"type":"string","example":"pass"},"bodyPartsDiscomfort":{"description":"Body parts with non-zero severity","type":"array","items":{"$ref":"#/components/schemas/BodyPartDiscomfortDto"}}}},"OfficeErgonomicsCourseDataDto":{"type":"object","properties":{}},"AddTrainingDto":{"type":"object","properties":{"course":{"type":"string","description":"Course name","example":"Self Assessment"},"status":{"type":"string","description":"Training status","example":"pass"},"startedDate":{"type":"string","description":"Training start date","example":"1/15/2024"},"completedDate":{"type":"string","description":"Training completion date","example":"1/20/2024"},"courseData":{"description":"Course-specific data payload","oneOf":[{"$ref":"#/components/schemas/SelfAssessmentCourseDataDto"},{"$ref":"#/components/schemas/OfficeErgonomicsCourseDataDto"}]}},"required":["course","status"]},"UpdateTrainingDto":{"type":"object","properties":{"status":{"type":"string","description":"Training status"},"startedDate":{"type":"string","description":"Training start date"},"completedDate":{"type":"string","description":"Training completion date"},"courseData":{"description":"Course-specific data payload","oneOf":[{"$ref":"#/components/schemas/SelfAssessmentCourseDataDto"},{"$ref":"#/components/schemas/OfficeErgonomicsCourseDataDto"}]}}},"AttachmentWithUrlRo":{"type":"object","properties":{"id":{"type":"string","description":"Attachment ID"},"key":{"type":"string","description":"S3 object key"},"originalName":{"type":"string","description":"Original file name","example":"report.pdf"},"mimeType":{"type":"string","description":"MIME type","example":"application/pdf"},"size":{"type":"number","description":"File size in bytes","example":204800},"label":{"type":"string","description":"User-provided label"},"uploadedBy":{"type":"string","description":"User ID of uploader"},"createdAt":{"type":"string","description":"Upload timestamp"},"url":{"type":"string","description":"Pre-signed download URL (temporary)"}},"required":["id","key","originalName","mimeType","size","createdAt","url"]},"CreateNoteDto":{"type":"object","properties":{"content":{"type":"string","description":"Note content in Markdown format","example":"## Follow-up\n\n- Called employee about **ergonomic chair**"}},"required":["content"]},"UpdateNoteDto":{"type":"object","properties":{"content":{"type":"string","description":"Updated note content in Markdown format","example":"## Follow-up\n\nResolved — chair delivered."}},"required":["content"]},"LmsPayloadDto":{"type":"object","properties":{"id":{"type":"string","description":"Learner identifier","example":"john@company.com"},"email":{"type":"string","description":"Learner email","example":"john@company.com"},"name":{"type":"string","description":"Learner full name","example":"John Doe"},"department":{"type":"string","description":"Department","example":"Default"},"course":{"type":"string","description":"Course slug","example":"self-assessment"},"status":{"type":"string","description":"Training status","example":"started","enum":["started","finished"]},"apiKey":{"type":"string","description":"Organization API key"},"data":{"type":"object","description":"Course-specific data payload (null for started, object for finished)","example":null}},"required":["email","name","department","course","status","apiKey"]},"CreateOrganizationDto":{"type":"object","properties":{"name":{"type":"string","description":"Organization full name","example":"EWI Works"},"abbreviation":{"type":"string","description":"Abbreviated name","example":"EWI"},"notes":{"type":"string","description":"Optional notes","example":"Contact info..."},"logo":{"type":"string","description":"Logo URL or base64","example":"/uploads/logo.png"},"courses":{"description":"Enabled courses","example":["Self Assessment","Office Ergonomics"],"type":"array","items":{"type":"string"}},"enableDepartments":{"type":"boolean","description":"Enable department tracking","default":false},"active":{"type":"boolean","description":"Whether organization is active","default":true},"enableFollowUpStatus":{"type":"boolean","description":"Enable follow-up status tracking for Self Assessment","default":false},"followUpStatuses":{"description":"Custom follow-up status options","example":["Not Assigned","Assigned","Case Closed"],"type":"array","items":{"type":"string"}}},"required":["name","abbreviation"]},"OrganizationDetailRo":{"type":"object","properties":{"id":{"type":"string","description":"Organization ID"},"name":{"type":"string","description":"Organization name"},"abbreviation":{"type":"string","description":"Abbreviated name"},"notes":{"type":"string","description":"Notes"},"logo":{"type":"string","description":"Logo URL"},"apiKey":{"type":"string","description":"API Key"},"courses":{"description":"Enabled courses","type":"array","items":{"type":"string"}},"enableDepartments":{"type":"boolean","description":"Enable departments"},"active":{"type":"boolean","description":"Is active"},"users":{"description":"Organization users","type":"array","items":{"$ref":"#/components/schemas/UserRo"}},"departments":{"description":"Departments","type":"array","items":{"type":"string"}},"enableFollowUpStatus":{"type":"boolean","description":"Enable follow-up status"},"followUpStatuses":{"description":"Follow-up status options","type":"array","items":{"type":"string"}},"createdAt":{"type":"string","description":"Creation timestamp"},"updatedAt":{"type":"string","description":"Update timestamp"}},"required":["id","name","abbreviation","apiKey","courses","enableDepartments","active","users","departments","enableFollowUpStatus","followUpStatuses","createdAt","updatedAt"]},"OrganizationListItemRo":{"type":"object","properties":{"id":{"type":"string","description":"Organization ID"},"name":{"type":"string","description":"Organization name"},"abbreviation":{"type":"string","description":"Abbreviated name"},"logo":{"type":"string","description":"Logo URL"},"apiKey":{"type":"string","description":"API Key"},"courses":{"description":"Enabled courses","type":"array","items":{"type":"string"}},"enableDepartments":{"type":"boolean","description":"Enable departments"},"active":{"type":"boolean","description":"Is active"},"enableFollowUpStatus":{"type":"boolean","description":"Enable follow-up status"},"followUpStatuses":{"description":"Follow-up status options","type":"array","items":{"type":"string"}}},"required":["id","name","abbreviation","apiKey","courses","enableDepartments","active","enableFollowUpStatus","followUpStatuses"]},"UpdateOrganizationDto":{"type":"object","properties":{"name":{"type":"string","description":"Organization full name"},"abbreviation":{"type":"string","description":"Abbreviated name"},"notes":{"type":"string","description":"Optional notes"},"logo":{"type":"string","description":"Logo URL or base64"},"courses":{"description":"Enabled courses","type":"array","items":{"type":"string"}},"enableDepartments":{"type":"boolean","description":"Enable department tracking"},"active":{"type":"boolean","description":"Whether organization is active"},"enableFollowUpStatus":{"type":"boolean","description":"Enable follow-up status tracking for Self Assessment"},"followUpStatuses":{"description":"Custom follow-up status options","type":"array","items":{"type":"string"}}}},"AddOrgUserDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"},"email":{"type":"string","description":"User email","example":"user@ewi.com"},"username":{"type":"string","description":"Username","example":"john_doe","minLength":3},"password":{"type":"string","description":"User password","example":"password123","minLength":6}},"required":["firstName","lastName","email","username","password"]},"UpdateOrgUserDto":{"type":"object","properties":{"username":{"type":"string","description":"Username"},"password":{"type":"string","description":"User password"}}},"SyncResultRo":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the sync completed","example":true},"message":{"type":"string","description":"Human-readable summary","example":"Synced 42 employees from ewihub.com"},"totalScraped":{"type":"number","description":"Number of profiles scraped","example":42},"created":{"type":"number","description":"New employees created","example":10},"updated":{"type":"number","description":"Existing employees updated","example":32},"errors":{"description":"Per-employee errors (non-fatal)","type":"array","items":{"type":"string"}}},"required":["success","message","totalScraped","created","updated","errors"]},"SyncEwihubDto":{"type":"object","properties":{"email":{"type":"string","description":"EWI Hub login email (organization user credential)","example":"admin@company.com"},"password":{"type":"string","description":"EWI Hub login password","example":"password123"}},"required":["email","password"]},"SeedResultRo":{"type":"object","properties":{"organizationsCreated":{"type":"number","description":"Number of organizations created","example":3},"usersCreated":{"type":"number","description":"Number of users created","example":8},"errors":{"description":"Non-fatal errors encountered","type":"array","items":{"type":"string"}}},"required":["organizationsCreated","usersCreated","errors"]}}}}