{ "components": { "responses": { "BadRequest": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }, "description": "Invalid request or business validation failure." }, "Forbidden": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }, "description": "Authenticated user cannot perform this action." }, "NotFound": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }, "description": "Requested resource was not found." }, "Unauthorized": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }, "description": "Missing or invalid bearer token." } }, "schemas": { "AdminUser": { "additionalProperties": true, "properties": { "banned": { "type": "boolean" }, "email": { "format": "email", "type": "string" }, "first_name": { "type": "string" }, "fiscal_code": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "last_name": { "type": "string" }, "must_change_password": { "type": "boolean" }, "phone": { "type": "string" }, "points": { "type": "integer" }, "roles": { "description": "Comma-separated role names from SQL GROUP_CONCAT.", "type": "string" } }, "type": "object" }, "Area": { "additionalProperties": true, "properties": { "boundary_geojson": { "$ref": "#/components/schemas/GeoJsonObject" }, "description": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "name": { "type": "string" } }, "type": "object" }, "AreaListResponse": { "additionalProperties": false, "properties": { "areas": { "items": { "$ref": "#/components/schemas/Area" }, "type": "array" }, "ok": { "type": "boolean" } }, "required": [ "ok", "areas" ], "type": "object" }, "AssignTeamRequest": { "additionalProperties": false, "properties": { "team_id": { "format": "int64", "type": "integer" } }, "required": [ "team_id" ], "type": "object" }, "AssignmentLinkResponse": { "additionalProperties": false, "properties": { "expires_at": { "type": "string" }, "ok": { "type": "boolean" }, "url": { "type": "string" } }, "required": [ "ok", "url", "expires_at" ], "type": "object" }, "Category": { "additionalProperties": true, "properties": { "active": { "type": "boolean" }, "description": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "name": { "type": "string" } }, "type": "object" }, "CategoryListResponse": { "additionalProperties": false, "properties": { "categories": { "items": { "$ref": "#/components/schemas/Category" }, "type": "array" }, "ok": { "type": "boolean" } }, "required": [ "ok", "categories" ], "type": "object" }, "ChangePasswordRequest": { "additionalProperties": false, "properties": { "current_password": { "format": "password", "type": "string" }, "new_password": { "format": "password", "minLength": 10, "type": "string" } }, "required": [ "current_password", "new_password" ], "type": "object" }, "CreateAreaRequest": { "additionalProperties": false, "properties": { "boundary_geojson": { "$ref": "#/components/schemas/GeoJsonObject" }, "description": { "type": "string" }, "name": { "type": "string" } }, "required": [ "name", "boundary_geojson" ], "type": "object" }, "CreateCategoryRequest": { "additionalProperties": false, "properties": { "description": { "type": "string" }, "name": { "type": "string" } }, "required": [ "name" ], "type": "object" }, "CreateReportRequest": { "additionalProperties": false, "properties": { "address": { "type": "string" }, "category_id": { "format": "int64", "type": "integer" }, "description": { "type": "string" }, "latitude": { "format": "double", "type": "number" }, "longitude": { "format": "double", "type": "number" }, "media": { "items": { "format": "uri-reference", "type": "string" }, "type": "array" } }, "required": [ "category_id", "latitude", "longitude", "address", "description" ], "type": "object" }, "CreateReportResponse": { "additionalProperties": false, "properties": { "area_id": { "format": "int64", "type": "integer" }, "ok": { "type": "boolean" }, "report_id": { "format": "int64", "type": "integer" } }, "required": [ "ok", "report_id" ], "type": "object" }, "CreateTeamRequest": { "additionalProperties": false, "properties": { "area_id": { "format": "int64", "type": "integer" }, "description": { "type": "string" }, "name": { "type": "string" }, "team_category_id": { "format": "int64", "type": "integer" } }, "required": [ "team_category_id", "name" ], "type": "object" }, "CurrentUser": { "additionalProperties": false, "properties": { "email": { "format": "email", "type": "string" }, "first_name": { "type": "string" }, "fiscal_code": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "last_name": { "type": "string" }, "must_change_password": { "type": "boolean" }, "permissions": { "items": { "type": "string" }, "type": "array" }, "phone": { "type": "string" }, "points": { "type": "integer" }, "role": { "type": "string" }, "roles": { "items": { "type": "string" }, "type": "array" } }, "required": [ "id", "first_name", "last_name", "email", "fiscal_code", "points", "must_change_password", "role", "roles", "permissions" ], "type": "object" }, "CurrentUserResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "user": { "$ref": "#/components/schemas/CurrentUser" } }, "required": [ "ok", "user" ], "type": "object" }, "EditUserRequest": { "additionalProperties": false, "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, "phone": { "type": "string" } }, "type": "object" }, "EmailRequest": { "additionalProperties": false, "properties": { "email": { "format": "email", "type": "string" } }, "required": [ "email" ], "type": "object" }, "ErrorResponse": { "additionalProperties": false, "properties": { "error": { "type": "string" }, "fields": { "items": { "type": "string" }, "type": "array" }, "message": { "type": "string" } }, "required": [ "error" ], "type": "object" }, "FeedbackRequest": { "additionalProperties": false, "properties": { "comment": { "type": "string" }, "rating": { "maximum": 5, "minimum": 1, "type": "integer" } }, "required": [ "rating" ], "type": "object" }, "FlagRequest": { "additionalProperties": false, "properties": { "details": { "type": "string" }, "reason": { "maxLength": 120, "type": "string" } }, "required": [ "reason" ], "type": "object" }, "FlagResponse": { "additionalProperties": false, "properties": { "flag_id": { "format": "int64", "type": "integer" }, "ok": { "type": "boolean" } }, "required": [ "ok", "flag_id" ], "type": "object" }, "GeoJsonObject": { "additionalProperties": true, "description": "GeoJSON polygon or multipolygon boundary.", "type": "object" }, "HealthResponse": { "additionalProperties": false, "properties": { "service": { "example": "visione-backend", "type": "string" }, "status": { "example": "ok", "type": "string" } }, "required": [ "status", "service" ], "type": "object" }, "InterventionSummaryResponse": { "additionalProperties": false, "properties": { "latest_messages": { "items": { "$ref": "#/components/schemas/Message" }, "type": "array" }, "media": { "items": { "$ref": "#/components/schemas/Media" }, "type": "array" }, "ok": { "type": "boolean" }, "summary": { "$ref": "#/components/schemas/Report" } }, "required": [ "ok", "summary", "media", "latest_messages" ], "type": "object" }, "Media": { "additionalProperties": true, "properties": { "content_type": { "type": "string" }, "created_at": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "media_kind": { "enum": [ "IMAGE", "VIDEO" ], "type": "string" }, "original_filename": { "type": "string" }, "report_id": { "format": "int64", "type": "integer" }, "size_bytes": { "format": "int64", "type": "integer" }, "url": { "type": "string" } }, "type": "object" }, "MediaUploadRequest": { "additionalProperties": false, "properties": { "files": { "items": { "format": "binary", "type": "string" }, "maxItems": 5, "type": "array" } }, "required": [ "files" ], "type": "object" }, "MediaUploadResponse": { "additionalProperties": false, "properties": { "media": { "items": { "$ref": "#/components/schemas/Media" }, "type": "array" }, "ok": { "type": "boolean" } }, "required": [ "ok", "media" ], "type": "object" }, "Message": { "additionalProperties": true, "properties": { "body": { "type": "string" }, "created_at": { "type": "string" }, "first_name": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "last_name": { "type": "string" }, "report_id": { "format": "int64", "type": "integer" }, "user_id": { "format": "int64", "type": "integer" } }, "type": "object" }, "MessageListResponse": { "additionalProperties": false, "properties": { "messages": { "items": { "$ref": "#/components/schemas/Message" }, "type": "array" }, "ok": { "type": "boolean" } }, "required": [ "ok", "messages" ], "type": "object" }, "MessageRequest": { "additionalProperties": false, "properties": { "body": { "type": "string" } }, "required": [ "body" ], "type": "object" }, "ModerationFlag": { "additionalProperties": true, "properties": { "content_type": { "enum": [ "REPORT", "MESSAGE" ], "type": "string" }, "created_at": { "type": "string" }, "created_by_email": { "type": "string" }, "created_by_user_id": { "format": "int64", "type": "integer" }, "details": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "message_id": { "format": "int64", "nullable": true, "type": "integer" }, "reason": { "type": "string" }, "report_id": { "format": "int64", "type": "integer" }, "resolution_note": { "nullable": true, "type": "string" }, "resolved_at": { "nullable": true, "type": "string" }, "resolved_by_email": { "nullable": true, "type": "string" }, "resolved_by_user_id": { "format": "int64", "nullable": true, "type": "integer" }, "status": { "enum": [ "OPEN", "RESOLVED", "DISMISSED" ], "type": "string" } }, "type": "object" }, "ModerationListResponse": { "additionalProperties": false, "properties": { "flags": { "items": { "$ref": "#/components/schemas/ModerationFlag" }, "type": "array" }, "ok": { "type": "boolean" }, "page": { "type": "integer" }, "per_page": { "type": "integer" } }, "required": [ "ok", "page", "per_page", "flags" ], "type": "object" }, "Notification": { "additionalProperties": true, "properties": { "body": { "type": "string" }, "created_at": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "read_at": { "nullable": true, "type": "string" }, "report_id": { "format": "int64", "nullable": true, "type": "integer" }, "title": { "type": "string" }, "type": { "type": "string" } }, "type": "object" }, "NotificationListResponse": { "additionalProperties": false, "properties": { "notifications": { "items": { "$ref": "#/components/schemas/Notification" }, "type": "array" }, "ok": { "type": "boolean" }, "page": { "type": "integer" }, "per_page": { "type": "integer" } }, "required": [ "ok", "page", "per_page", "notifications" ], "type": "object" }, "OkResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" } }, "required": [ "ok" ], "type": "object" }, "OpenApiDocument": { "additionalProperties": true, "description": "Generated OpenAPI 3 document.", "type": "object" }, "OpenDataReport": { "additionalProperties": true, "properties": { "area_id": { "format": "int64", "nullable": true, "type": "integer" }, "area_name": { "nullable": true, "type": "string" }, "category_id": { "format": "int64", "type": "integer" }, "category_name": { "type": "string" }, "created_at": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "latitude": { "type": "number" }, "longitude": { "type": "number" }, "status": { "$ref": "#/components/schemas/ReportStatus" }, "updated_at": { "type": "string" } }, "type": "object" }, "OpenDataReportListResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "page": { "type": "integer" }, "per_page": { "type": "integer" }, "reports": { "items": { "$ref": "#/components/schemas/OpenDataReport" }, "type": "array" } }, "required": [ "ok", "page", "per_page", "reports" ], "type": "object" }, "OtpRequestResponse": { "additionalProperties": false, "properties": { "delivery": { "example": "mailpit", "type": "string" }, "expires_in_minutes": { "type": "integer" }, "ok": { "type": "boolean" } }, "required": [ "ok", "delivery", "expires_in_minutes" ], "type": "object" }, "OverviewStatsResponse": { "additionalProperties": false, "properties": { "avg_resolution_hours": { "items": { "additionalProperties": true, "properties": { "value": { "type": "number" } }, "type": "object" }, "type": "array" }, "avg_resolution_hours_by_area": { "items": { "additionalProperties": true, "properties": { "area": { "type": "string" }, "value": { "type": "number" } }, "type": "object" }, "type": "array" }, "avg_resolution_hours_by_category": { "items": { "additionalProperties": true, "properties": { "category": { "type": "string" }, "value": { "type": "number" } }, "type": "object" }, "type": "array" }, "monthly_reports": { "items": { "additionalProperties": true, "properties": { "month": { "type": "string" }, "total": { "type": "integer" } }, "type": "object" }, "type": "array" }, "ok": { "type": "boolean" }, "reports_by_area": { "items": { "additionalProperties": true, "properties": { "area": { "type": "string" }, "total": { "type": "integer" } }, "type": "object" }, "type": "array" }, "reports_by_category": { "items": { "additionalProperties": true, "properties": { "category": { "type": "string" }, "total": { "type": "integer" } }, "type": "object" }, "type": "array" }, "reports_by_status": { "items": { "additionalProperties": true, "properties": { "status": { "$ref": "#/components/schemas/ReportStatus" }, "total": { "type": "integer" } }, "type": "object" }, "type": "array" }, "assignments_by_team": { "items": { "additionalProperties": true, "properties": { "team": { "type": "string" }, "total": { "type": "integer" } }, "type": "object" }, "type": "array" }, "resolved_reports_by_team": { "items": { "additionalProperties": true, "properties": { "team": { "type": "string" }, "total": { "type": "integer" } }, "type": "object" }, "type": "array" } }, "required": [ "ok", "reports_by_status", "reports_by_area", "avg_resolution_hours", "reports_by_category", "assignments_by_team", "resolved_reports_by_team", "monthly_reports", "avg_resolution_hours_by_category", "avg_resolution_hours_by_area" ], "type": "object" }, "PagedReportListResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "page": { "type": "integer" }, "per_page": { "type": "integer" }, "reports": { "items": { "$ref": "#/components/schemas/Report" }, "type": "array" } }, "required": [ "ok", "page", "per_page", "reports" ], "type": "object" }, "PasswordLoginRequest": { "additionalProperties": false, "properties": { "email": { "format": "email", "type": "string" }, "password": { "format": "password", "type": "string" } }, "required": [ "email", "password" ], "type": "object" }, "ReadyResponse": { "additionalProperties": false, "properties": { "dependencies": { "additionalProperties": false, "properties": { "mysql": { "type": "boolean" } }, "required": [ "mysql" ], "type": "object" }, "errors": { "additionalProperties": false, "properties": { "mysql": { "type": "string" } }, "type": "object" }, "status": { "enum": [ "ready", "not_ready" ], "type": "string" } }, "required": [ "status", "dependencies" ], "type": "object" }, "RegisterCitizenRequest": { "additionalProperties": false, "properties": { "birth_date": { "format": "date", "type": "string" }, "birth_place": { "type": "string" }, "email": { "format": "email", "type": "string" }, "first_name": { "type": "string" }, "fiscal_code": { "maxLength": 16, "minLength": 16, "type": "string" }, "last_name": { "type": "string" }, "password": { "format": "password", "minLength": 10, "type": "string" }, "phone": { "type": "string" } }, "required": [ "first_name", "last_name", "email", "password", "fiscal_code" ], "type": "object" }, "RegisterCitizenResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "user_id": { "format": "int64", "type": "integer" } }, "required": [ "ok", "user_id" ], "type": "object" }, "Report": { "additionalProperties": true, "properties": { "address": { "type": "string" }, "area_id": { "format": "int64", "type": "integer" }, "area_name": { "type": "string" }, "assigned_operator_id": { "format": "int64", "type": "integer" }, "category_id": { "format": "int64", "type": "integer" }, "category_name": { "type": "string" }, "created_at": { "type": "string" }, "description": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "latitude": { "type": "number" }, "longitude": { "type": "number" }, "status": { "$ref": "#/components/schemas/ReportStatus" }, "updated_at": { "type": "string" }, "user_id": { "format": "int64", "type": "integer" } }, "required": [ "id", "category_id", "latitude", "longitude", "address", "description", "status" ], "type": "object" }, "ReportDetailResponse": { "additionalProperties": false, "properties": { "history": { "items": { "$ref": "#/components/schemas/StatusHistoryItem" }, "type": "array" }, "media": { "items": { "$ref": "#/components/schemas/Media" }, "type": "array" }, "ok": { "type": "boolean" }, "report": { "$ref": "#/components/schemas/Report" } }, "required": [ "ok", "report", "history", "media" ], "type": "object" }, "ReportListResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "reports": { "items": { "$ref": "#/components/schemas/Report" }, "type": "array" } }, "required": [ "ok", "reports" ], "type": "object" }, "ReportStatus": { "enum": [ "OPEN", "UNDER_REVIEW", "ASSIGNED", "IN_PROGRESS", "RESOLVED", "REJECTED", "CLOSED" ], "type": "string" }, "RewardEvent": { "additionalProperties": true, "properties": { "created_at": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "points": { "type": "integer" }, "reason": { "type": "string" }, "report_id": { "format": "int64", "type": "integer" } }, "type": "object" }, "RewardsResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "page": { "type": "integer" }, "per_page": { "type": "integer" }, "points": { "type": "integer" }, "reward_events": { "items": { "$ref": "#/components/schemas/RewardEvent" }, "type": "array" } }, "required": [ "ok", "points", "page", "per_page", "reward_events" ], "type": "object" }, "StatusHistoryItem": { "additionalProperties": true, "properties": { "changed_by_user_id": { "format": "int64", "type": "integer" }, "created_at": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "new_status": { "$ref": "#/components/schemas/ReportStatus" }, "note": { "type": "string" }, "old_status": { "$ref": "#/components/schemas/ReportStatus" }, "report_id": { "format": "int64", "type": "integer" } }, "type": "object" }, "Team": { "additionalProperties": true, "properties": { "active": { "type": "boolean" }, "area_id": { "format": "int64", "type": "integer" }, "area_name": { "type": "string" }, "category_name": { "type": "string" }, "description": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "name": { "type": "string" }, "team_category_id": { "format": "int64", "type": "integer" } }, "type": "object" }, "TeamListResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "teams": { "items": { "$ref": "#/components/schemas/Team" }, "type": "array" } }, "required": [ "ok", "teams" ], "type": "object" }, "TeamSuggestionListResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "suggestions": { "items": { "additionalProperties": true, "type": "object" }, "type": "array" } }, "required": [ "ok", "suggestions" ], "type": "object" }, "TokenResponse": { "additionalProperties": false, "properties": { "expires_in_hours": { "type": "integer" }, "ok": { "type": "boolean" }, "token": { "type": "string" }, "token_type": { "example": "Bearer", "type": "string" } }, "required": [ "ok", "token", "token_type", "expires_in_hours" ], "type": "object" }, "UpdateModerationRequest": { "additionalProperties": false, "properties": { "reject_report": { "type": "boolean" }, "resolution_note": { "type": "string" }, "status": { "enum": [ "RESOLVED", "DISMISSED" ], "type": "string" } }, "required": [ "status" ], "type": "object" }, "UpdateStatusRequest": { "additionalProperties": false, "properties": { "note": { "type": "string" }, "status": { "$ref": "#/components/schemas/ReportStatus" } }, "required": [ "status" ], "type": "object" }, "UpdateUserBanRequest": { "additionalProperties": false, "properties": { "banned": { "type": "boolean" } }, "required": [ "banned" ], "type": "object" }, "UpdateUserRolesRequest": { "additionalProperties": false, "properties": { "roles": { "items": { "type": "string" }, "type": "array" } }, "required": [ "roles" ], "type": "object" }, "UserListResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" }, "users": { "items": { "$ref": "#/components/schemas/AdminUser" }, "type": "array" } }, "required": [ "ok", "users" ], "type": "object" }, "VerifyOtpRequest": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "email": { "format": "email", "type": "string" } }, "required": [ "email", "code" ], "type": "object" } }, "securitySchemes": { "bearerAuth": { "scheme": "bearer", "type": "http" } } }, "info": { "description": "Visione OpenAPI contract maintained manually and merged with Drogon route extraction.", "title": "Visione API", "version": "0.1.0" }, "openapi": "3.0.3", "paths": { "/api/v1/admin/areas": { "post": { "description": "Creates a municipal area with GeoJSON boundary.", "operationId": "AdminController.createArea", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAreaRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Created area result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Create area", "tags": [ "Admin" ] } }, "/api/v1/admin/areas/{id}": { "delete": { "description": "Deletes an existing municipal area and clears linked report/team area references.", "operationId": "AdminController.deleteArea", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Deleted area result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Delete area", "tags": [ "Admin" ] }, "patch": { "description": "Updates an existing municipal area.", "operationId": "AdminController.updateArea", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAreaRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Updated area result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Update area", "tags": [ "Admin" ] } }, "/api/v1/admin/categories": { "post": { "description": "Creates a report category.", "operationId": "AdminController.createCategory", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCategoryRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Created category result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Create category", "tags": [ "Admin" ] } }, "/api/v1/admin/categories/{id}": { "delete": { "description": "Soft-deletes an existing report category by setting active to false.", "operationId": "AdminController.deleteCategory", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Deleted category result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Delete category", "tags": [ "Admin" ] }, "patch": { "description": "Updates an existing report category.", "operationId": "AdminController.updateCategory", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCategoryRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Updated category result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Update category", "tags": [ "Admin" ] } }, "/api/v1/admin/moderation": { "get": { "description": "Lists moderation flags for admin/operator review.", "operationId": "AdminController.listModeration", "parameters": [ { "in": "query", "name": "status", "required": false, "schema": { "enum": [ "OPEN", "RESOLVED", "DISMISSED" ], "type": "string" } }, { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModerationListResponse" } } }, "description": "Paged moderation flags." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List moderation flags", "tags": [ "Moderation" ] } }, "/api/v1/admin/moderation/{id}": { "patch": { "description": "Resolves or dismisses a moderation flag. Optionally rejects the related report.", "operationId": "AdminController.updateModeration", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateModerationRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Moderation update result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Update moderation flag", "tags": [ "Moderation" ] } }, "/api/v1/admin/stats/overview": { "get": { "description": "Returns report statistics for administration dashboards.", "operationId": "AdminController.overviewStats", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OverviewStatsResponse" } } }, "description": "Aggregated report statistics." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Overview stats", "tags": [ "Admin" ] } }, "/api/v1/admin/teams": { "post": { "description": "Creates an intervention team.", "operationId": "AdminController.createTeam", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTeamRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Created team result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Create team", "tags": [ "Admin" ] } }, "/api/v1/admin/teams/{id}": { "delete": { "description": "Soft-deletes an existing intervention team by setting active to false.", "operationId": "AdminController.deleteTeam", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Deleted team result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Delete team", "tags": [ "Admin" ] }, "patch": { "description": "Updates an existing intervention team.", "operationId": "AdminController.updateTeam", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTeamRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Updated team result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Update team", "tags": [ "Admin" ] } }, "/api/v1/areas": { "get": { "description": "Lists municipal areas.", "operationId": "PublicController.listAreas", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AreaListResponse" } } }, "description": "Area list." } }, "summary": "List areas", "tags": [ "Public" ] } }, "/api/v1/admin/users": { "get": { "description": "Lists platform users with role information.", "operationId": "AdminController.listUsers", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserListResponse" } } }, "description": "User list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List users", "tags": [ "Admin" ] } }, "/api/v1/admin/users/{id}/ban": { "patch": { "description": "Updates a user's banned flag.", "operationId": "AdminController.updateUserBan", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateUserBanRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Ban update result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Ban or unban user", "tags": [ "Admin" ] } }, "/api/v1/admin/users/{id}/roles": { "patch": { "description": "Replaces the roles assigned to a user.", "operationId": "AdminController.updateUserRoles", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateUserRolesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Role update result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Update user roles", "tags": [ "Admin" ] } }, "/api/v1/auth/change-password": { "post": { "description": "Changes the authenticated user's password.", "operationId": "AuthController.changePassword", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangePasswordRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Password change result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Change password", "tags": [ "Auth" ] } }, "/api/v1/auth/login/password": { "post": { "description": "Password-based login fallback for local development.", "operationId": "AuthController.loginWithPassword", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasswordLoginRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenResponse" } } }, "description": "Bearer token when credentials are valid." }, "400": { "$ref": "#/components/responses/BadRequest" } }, "summary": "Password login", "tags": [ "Auth" ] } }, "/api/v1/auth/otp/request": { "post": { "description": "Sends a one-time code by email through Mailpit locally.", "operationId": "AuthController.requestOtp", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OtpRequestResponse" } } }, "description": "OTP challenge result." }, "400": { "$ref": "#/components/responses/BadRequest" } }, "summary": "Request OTP", "tags": [ "Auth" ] } }, "/api/v1/auth/otp/verify": { "post": { "description": "Verifies an email OTP and creates an API token.", "operationId": "AuthController.verifyOtp", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VerifyOtpRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenResponse" } } }, "description": "Bearer token when verification succeeds." }, "400": { "$ref": "#/components/responses/BadRequest" } }, "summary": "Verify OTP", "tags": [ "Auth" ] } }, "/api/v1/auth/register": { "post": { "description": "Creates a citizen account with personal data and password.", "operationId": "AuthController.registerCitizen", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterCitizenRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterCitizenResponse" } } }, "description": "Registration result." }, "400": { "$ref": "#/components/responses/BadRequest" } }, "summary": "Register citizen", "tags": [ "Auth" ] } }, "/api/v1/docs": { "get": { "description": "Serves a local Swagger UI page backed by openapi.json.", "operationId": "ApiController.docs", "parameters": [ ], "responses": { "200": { "content": { "text/html": { "schema": { "type": "string" } } }, "description": "HTML documentation page." } }, "summary": "Swagger UI", "tags": [ "Technical" ] } }, "/api/v1/health": { "get": { "description": "Returns process health without checking dependencies.", "operationId": "ApiController.health", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } }, "description": "Service health status." } }, "summary": "Health check", "tags": [ "Technical" ] } }, "/api/v1/me": { "get": { "description": "Returns the authenticated user's profile and permissions.", "operationId": "AuthController.me", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CurrentUserResponse" } } }, "description": "Authenticated user context." }, "401": { "$ref": "#/components/responses/Unauthorized" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Current user", "tags": [ "Auth" ] }, "patch": { "description": "Updates fields of the authenticated user's profile.", "operationId": "AuthController.editUser", "parameters": [ ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EditUserRequest" } } } }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "User profile updated successfully." }, "400": { "description": "Invalid parameter type or structural error." }, "401": { "$ref": "#/components/responses/Unauthorized" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Edit current user profile", "tags": [ "Auth" ] } }, "/api/v1/me/rewards": { "get": { "description": "Returns current points and reward events for the authenticated user.", "operationId": "UserController.rewards", "parameters": [ { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RewardsResponse" } } }, "description": "Reward ledger." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Reward ledger", "tags": [ "User" ] } }, "/api/v1/notifications": { "get": { "description": "Lists notifications for the authenticated user.", "operationId": "UserController.listNotifications", "parameters": [ { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationListResponse" } } }, "description": "Paged notification list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List notifications", "tags": [ "User" ] } }, "/api/v1/notifications/{id}/read": { "patch": { "description": "Marks a notification as read for the authenticated user.", "operationId": "UserController.markNotificationRead", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Notification update result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Mark notification read", "tags": [ "User" ] } }, "/api/v1/notifications/read-all": { "patch": { "description": "Marks all notifications as read for the authenticated user.", "operationId": "UserController.markAllNotificationsRead", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Notification update result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Mark all notifications read", "tags": [ "User" ] } }, "/api/v1/open-data/reports": { "get": { "description": "Returns anonymized resolved/closed report data for public reuse.", "operationId": "PublicController.openDataReports", "parameters": [ { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenDataReportListResponse" } } }, "description": "Paged open-data report list." } }, "summary": "Open data reports", "tags": [ "Public" ] } }, "/api/v1/openapi.json": { "get": { "description": "Returns the generated OpenAPI JSON document.", "operationId": "ApiController.openApi", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenApiDocument" } } }, "description": "OpenAPI 3 JSON document." }, "404": { "$ref": "#/components/responses/NotFound" } }, "summary": "OpenAPI document", "tags": [ "Technical" ] } }, "/api/v1/interventions/{id}": { "get": { "description": "Returns public intervention summary for external intervention teams.", "operationId": "PublicController.interventionSummary", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InterventionSummaryResponse" } } }, "description": "Public intervention summary." }, "404": { "$ref": "#/components/responses/NotFound" } }, "summary": "Public intervention summary", "tags": [ "Public" ] } }, "/api/v1/operator/reports/assigned": { "get": { "description": "Lists reports assigned to the authenticated operator.", "operationId": "ReportController.assignedReports", "parameters": [ { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PagedReportListResponse" } } }, "description": "Paged assigned report list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Assigned reports", "tags": [ "Reports" ] } }, "/api/v1/operator/reports/open": { "get": { "description": "Lists open reports not yet taken by an operator.", "operationId": "ReportController.openReports", "parameters": [ { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PagedReportListResponse" } } }, "description": "Paged open report list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Open unassigned reports", "tags": [ "Reports" ] } }, "/api/v1/operator/reports/others": { "get": { "description": "Lists reports assigned to another operator.", "operationId": "ReportController.otherOperatorReports", "parameters": [ { "in": "query", "name": "page", "required": false, "schema": { "type": "integer" } }, { "in": "query", "name": "per_page", "required": false, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PagedReportListResponse" } } }, "description": "Paged report list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Other operator reports", "tags": [ "Reports" ] } }, "/api/v1/operator/teams": { "get": { "description": "Lists active intervention teams for operators and admins.", "operationId": "ReportController.listTeams", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamListResponse" } } }, "description": "Team list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List teams", "tags": [ "Reports" ] } }, "/api/v1/ready": { "get": { "description": "Checks whether MySQL is reachable.", "operationId": "ApiController.ready", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadyResponse" } } }, "description": "Dependency readiness status." }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadyResponse" } } }, "description": "Dependency readiness failure." } }, "summary": "Readiness check", "tags": [ "Technical" ] } }, "/api/v1/reports": { "get": { "description": "Lists reports visible to the authenticated user.", "operationId": "ReportController.list", "parameters": [ { "in": "query", "name": "area_id", "required": false, "schema": { "format": "int64", "type": "integer" } }, { "in": "query", "name": "category_id", "required": false, "schema": { "format": "int64", "type": "integer" } }, { "in": "query", "name": "status", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportListResponse" } } }, "description": "Report list." }, "401": { "$ref": "#/components/responses/Unauthorized" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List reports", "tags": [ "Reports" ] }, "post": { "description": "Creates a citizen urban issue report.", "operationId": "ReportController.create", "parameters": [ ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReportRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReportResponse" } } }, "description": "Created report id and inferred area." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Create report", "tags": [ "Reports" ] } }, "/api/v1/report-categories": { "get": { "description": "Lists active report categories for authenticated users.", "operationId": "ReportController.listCategories", "parameters": [ ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CategoryListResponse" } } }, "description": "Report category list." }, "401": { "$ref": "#/components/responses/Unauthorized" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List categories", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}": { "get": { "description": "Returns report detail, status history and media.", "operationId": "ReportController.detail", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportDetailResponse" } } }, "description": "Report detail." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Report detail", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/intervention-link": { "delete": { "description": "Revokes current public intervention link for assigned team.", "operationId": "ReportController.revokeInterventionLink", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Link revocation result." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Revoke intervention link", "tags": [ "Reports" ] }, "post": { "description": "Creates or rotates public intervention link for external intervention team.", "operationId": "ReportController.createInterventionLink", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignmentLinkResponse" } } }, "description": "Generated public link." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "409": { "$ref": "#/components/responses/Conflict" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Create intervention link", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/assignments": { "post": { "description": "Assigns an intervention team to a report.", "operationId": "ReportController.assignTeam", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignTeamRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Assignment result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Assign team", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/feedback": { "post": { "description": "Adds citizen feedback after report resolution.", "operationId": "ReportController.addFeedback", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FeedbackRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Feedback result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Add feedback", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/flags": { "post": { "description": "Creates a moderation flag for a report by assigned operator only.", "operationId": "ReportController.flagReport", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlagRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlagResponse" } } }, "description": "Created moderation flag." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Flag report", "tags": [ "Moderation" ] } }, "/api/v1/reports/{id}/intervention-summary": { "get": { "description": "Returns operator-facing report data, media and the latest messages for intervention planning.", "operationId": "ReportController.interventionSummary", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InterventionSummaryResponse" } } }, "description": "Intervention summary." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Intervention summary", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/team-suggestions": { "get": { "description": "Suggests compatible teams for report category and area.", "operationId": "ReportController.teamSuggestions", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamSuggestionListResponse" } } }, "description": "Suggested teams." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Team suggestions", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/media": { "post": { "description": "Uploads report images or videos as multipart files.", "operationId": "ReportController.uploadMedia", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/MediaUploadRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MediaUploadResponse" } } }, "description": "Uploaded media list." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Upload media", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/messages": { "get": { "description": "Lists messages for a report conversation.", "operationId": "ReportController.listMessages", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageListResponse" } } }, "description": "Message list." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "List messages", "tags": [ "Reports" ] }, "post": { "description": "Adds a citizen/operator message to a report.", "operationId": "ReportController.addMessage", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Message creation result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Add message", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/messages/{message_id}/flags": { "post": { "description": "Creates a moderation flag for a report message by assigned operator only.", "operationId": "ReportController.flagMessage", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } }, { "in": "path", "name": "message_id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlagRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlagResponse" } } }, "description": "Created moderation flag." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Flag message", "tags": [ "Moderation" ] } }, "/api/v1/reports/{id}/status": { "patch": { "description": "Updates a report status following allowed transitions.", "operationId": "ReportController.updateStatus", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateStatusRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Status update result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Update report status", "tags": [ "Reports" ] } }, "/api/v1/reports/{id}/take": { "post": { "description": "Assigns an open report to current non-admin operator.", "operationId": "ReportController.takeReport", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }, "description": "Take report result." }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" } }, "security": [ { "bearerAuth": [ ] } ], "summary": "Take report", "tags": [ "Reports" ] } } }, "servers": [ { "url": "http://localhost:5555" } ] }