{ "openapi": "3.0.3", "info": { "description": "Visione OpenAPI contract maintained manually and merged with Drogon route extraction.", "title": "Visione API", "version": "0.1.0" }, "servers": [ { "url": "http://localhost:5555" } ], "paths": { "/api/v1/admin/areas": { "get": { "description": "Lists configured municipal areas.", "operationId": "AdminController.listAreas", "parameters": [], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AreaListResponse" } } }, "description": "Area list." }, "401": { "$ref": "#/components/responses/Unauthorized" } }, "security": [ { "bearerAuth": [] } ], "summary": "List areas", "tags": [ "Admin" ] }, "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/categories": { "get": { "description": "Lists active report categories.", "operationId": "AdminController.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": [ "Admin" ] }, "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/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": { "get": { "description": "Lists intervention teams.", "operationId": "AdminController.listTeams", "parameters": [], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamListResponse" } } }, "description": "Team list." }, "401": { "$ref": "#/components/responses/Unauthorized" } }, "security": [ { "bearerAuth": [] } ], "summary": "List teams", "tags": [ "Admin" ] }, "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/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 MailHog 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" ] } }, "/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/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/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}/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}/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}/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 the current 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" ] } } }, "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": { "active": { "type": "boolean" }, "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" }, "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" }, "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" }, "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" }, "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" }, "OkResponse": { "additionalProperties": false, "properties": { "ok": { "type": "boolean" } }, "required": [ "ok" ], "type": "object" }, "OpenApiDocument": { "additionalProperties": true, "description": "Generated OpenAPI 3 document.", "type": "object" }, "OtpRequestResponse": { "additionalProperties": false, "properties": { "delivery": { "example": "mailhog", "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" }, "ok": { "type": "boolean" }, "reports_by_area": { "items": { "additionalProperties": true, "properties": { "area": { "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" } }, "required": [ "ok", "reports_by_status", "reports_by_area", "avg_resolution_hours" ], "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" }, "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" }, "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" }, "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" } } } }