{"openapi":"3.0.0","paths":{"/auth/login":{"post":{"operationId":"AuthController_loginRoute","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponseDto"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Invalid credentials"},"429":{"description":"Rate limit exceeded — try again later"}},"summary":"Authenticate and obtain a JWT access token","tags":["auth"]}},"/auth/register":{"post":{"operationId":"AuthController_registerRoute","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDto"}}}},"responses":{"201":{"description":"User registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterResponseDto"}}}},"400":{"description":"Invalid request body"},"409":{"description":"Email already registered"},"429":{"description":"Rate limit exceeded — try again later"}},"summary":"Register a new user account (auto-login returns JWT)","tags":["auth"]}},"/auth/me":{"get":{"operationId":"AuthController_me","parameters":[],"responses":{"200":{"description":"Authenticated user info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponseDto"}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"Get the authenticated user profile","tags":["auth"]}},"/grants/at-scope":{"get":{"operationId":"GrantsController_listAtScope","parameters":[{"name":"scopeType","required":true,"in":"query","description":"platform | organization | emergency | group","schema":{"type":"string"}},{"name":"scopeId","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GrantListItemDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Not authorized to administer this scope"}},"security":[{"bearer":[]}],"summary":"List the grants made AT a scope (scoped administrator)","tags":["grants"]}},"/grants":{"get":{"operationId":"GrantsController_list","parameters":[{"name":"principalId","required":true,"in":"query","description":"User or service-account id","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GrantListItemDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"}},"security":[{"bearer":[]}],"summary":"List the grants held by a principal (admin)","tags":["grants"]},"post":{"operationId":"GrantsController_grant","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantRoleDto"}}}},"responses":{"201":{"description":"Role granted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Not authorized to grant, or privilege escalation"}},"security":[{"bearer":[]}],"summary":"Grant a role to a principal in a scope (delegated, attenuated)","tags":["grants"]}},"/grants/{id}":{"delete":{"operationId":"GrantsController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Grant revoked"},"401":{"description":"Missing or invalid token"},"403":{"description":"Not authorized to revoke"}},"security":[{"bearer":[]}],"summary":"Revoke a grant","tags":["grants"]}},"/service-accounts":{"get":{"operationId":"ApiKeysController_listServiceAccounts","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAccountListItemDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"}},"security":[{"bearer":[]}],"summary":"List all service accounts (platform admin)","tags":["service-accounts"]},"post":{"operationId":"ApiKeysController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceAccountDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccountResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"apikey:create required"}},"security":[{"bearer":[]}],"summary":"Create a service account (machine principal)","tags":["service-accounts"]}},"/organizations/{organizationId}/service-accounts":{"get":{"operationId":"ApiKeysController_listOrgServiceAccounts","parameters":[{"name":"organizationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAccountListItemDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"apikey:create required in the org"}},"security":[{"bearer":[]}],"summary":"List a single organization’s service accounts (org admin)","tags":["service-accounts"]}},"/service-accounts/{serviceAccountId}/api-keys":{"get":{"operationId":"ApiKeysController_listApiKeys","parameters":[{"name":"serviceAccountId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyListItemDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"apikey:create required in scope"}},"security":[{"bearer":[]}],"summary":"List a service account’s keys — metadata only (scoped admin)","tags":["service-accounts"]},"post":{"operationId":"ApiKeysController_issue","parameters":[{"name":"serviceAccountId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueApiKeyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssuedApiKeyResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"apikey:create required"}},"security":[{"bearer":[]}],"summary":"Issue an API key for a service account (secret shown once)","tags":["service-accounts"]}},"/api-keys/{keyId}":{"delete":{"operationId":"ApiKeysController_revoke","parameters":[{"name":"keyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Key revoked"},"401":{"description":"Missing or invalid token"},"403":{"description":"apikey:revoke required"}},"security":[{"bearer":[]}],"summary":"Revoke an API key","tags":["service-accounts"]}},"/service-accounts/me":{"get":{"operationId":"ServiceAccountIntrospectionController_me","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccountIdentityDto"}}}},"401":{"description":"Missing, malformed, invalid or revoked API key"}},"security":[{"api-key":[]}],"summary":"Introspect the calling service account (authenticated by X-API-Key)","tags":["service-accounts"]}},"/roles":{"get":{"operationId":"RolesController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RoleDto"}}}}}},"security":[{"bearer":[]}],"summary":"List the fixed role catalog","tags":["roles"]}},"/users/lookup":{"get":{"operationId":"UsersController_lookup","parameters":[{"name":"email","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLookupDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Not authorized to look up users"},"404":{"description":"No user with that email"}},"security":[{"bearer":[]}],"summary":"Resolve an email to a principal id (admin only)","tags":["users"]}},"/notifications/mine":{"get":{"operationId":"NotificationsController_getMyNotifications","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMyNotificationsResponseDto"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Get my in-app notifications","tags":["notifications"]}},"/notifications/{id}/read":{"post":{"operationId":"NotificationsController_markRead","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Unauthorized"},"403":{"description":"Not the owner of this notification"},"404":{"description":"Notification not found"}},"security":[{"bearer":[]}],"summary":"Mark a notification as read (owner only)","tags":["notifications"]}},"/notifications/read-all":{"post":{"operationId":"NotificationsController_markAllRead","parameters":[],"responses":{"204":{"description":""},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Mark all my notifications as read","tags":["notifications"]}},"/emergencies/{emergencyId}/resources":{"post":{"operationId":"ResourcesController_create","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterResourceDto"}}}},"responses":{"201":{"description":"Resource registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterResourceResponseDto"}}}},"400":{"description":"Invalid request body or UUID"},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"Register a resource for an emergency (requires authentication)","tags":["resources"]}},"/resources/{resourceId}/verify":{"post":{"operationId":"ResourcesController_verifyResource","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResourceDto"}}}},"responses":{"204":{"description":"Resource verified"},"400":{"description":"Invalid verification level or UUID"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Resource not found"}},"security":[{"bearer":[]}],"summary":"Verify a resource (coordinator of the resource's emergency only)","tags":["resources"]}},"/resources/{resourceId}/publish":{"post":{"operationId":"ResourcesController_publishResource","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Resource published"},"400":{"description":"Invalid UUID"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Resource not found"},"409":{"description":"Resource not verified yet"}},"security":[{"bearer":[]}],"summary":"Publish a resource (verifier or coordinator of the resource's emergency)","tags":["resources"]}},"/resources/{resourceId}":{"patch":{"operationId":"ResourcesController_editResourceFields","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditResourceDto"}}}},"responses":{"204":{"description":"Resource edited"},"400":{"description":"Missing reason or resource is discarded"},"401":{"description":"Missing or invalid token"},"403":{"description":"Validator/coordinator role required"},"404":{"description":"Resource not found"}},"security":[{"bearer":[]}],"summary":"Edit a resource during verification (validator/coordinator). Requires a reason; recorded in the audit trail.","tags":["resources"]}},"/resources/{resourceId}/discard":{"post":{"operationId":"ResourcesController_discardResourceAction","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscardResourceDto"}}}},"responses":{"204":{"description":"Resource discarded"},"400":{"description":"Missing reason or resource is not pending verification"},"401":{"description":"Missing or invalid token"},"403":{"description":"Validator/coordinator role required"},"404":{"description":"Resource not found"}},"security":[{"bearer":[]}],"summary":"Discard a resource during verification (validator/coordinator). Requires a reason; recorded in the audit trail.","tags":["resources"]}},"/resources/{resourceId}/status":{"post":{"operationId":"ResourcesController_updateResourceStatus","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateResourcePublicStatusDto"}}}},"responses":{"204":{"description":"Status updated"},"400":{"description":"Invalid status transition or UUID"},"401":{"description":"Missing or invalid token"},"403":{"description":"Not authorized to update this resource status"},"404":{"description":"Resource not found"}},"security":[{"bearer":[]}],"summary":"Update the operational public status of a resource (owner or coordinator)","tags":["resources"]}},"/emergencies/{emergencyId}/resources/mine":{"get":{"operationId":"ResourcesController_listMyResources","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of own resources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResourceViewDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List resources owned by the authenticated user in an emergency","tags":["resources"]}},"/resources/{resourceId}/validity-reports":{"post":{"operationId":"ResourcesController_submitValidityReport","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportResourceValidityDto"}}}},"responses":{"201":{"description":"Report recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportResourceValidityResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"The owner cannot report their own resource"},"404":{"description":"Resource not found"},"409":{"description":"Resource is not publicly visible"}},"security":[{"bearer":[]}],"summary":"Report a resource as closed / nonexistent / moved / outdated (any authenticated user)","tags":["resources"]},"get":{"operationId":"ResourcesController_listValidityReports","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Validity reports for the resource","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ValidityReportDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"}},"security":[{"bearer":[]}],"summary":"List the citizen validity reports of a resource (coordinator)","tags":["resources"]}},"/resources/{resourceId}/dispute/resolve":{"post":{"operationId":"ResourcesController_resolveDisputeAction","parameters":[{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveResourceDisputeDto"}}}},"responses":{"204":{"description":"Dispute resolved"},"400":{"description":"Missing reason or invalid resolution"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Resource not found"},"409":{"description":"Resource is not disputed"}},"security":[{"bearer":[]}],"summary":"Resolve a disputed resource (coordinator): confirm closure, mark invalid or dismiss. Requires a reason; recorded in the audit trail.","tags":["resources"]}},"/emergencies/{emergencyId}/coordination/queue":{"get":{"operationId":"CoordinationController_list","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"default":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (max 100)","schema":{"default":50,"example":50,"type":"number"}},{"name":"type","required":false,"in":"query","description":"Filter the queue by resource type","schema":{"example":"collection_point","type":"string","enum":["collection_point","delivery_point","collection_and_delivery","warehouse","transport","supplier","venue"]}},{"name":"q","required":false,"in":"query","description":"Full-text search string matched against name, address, and city (case-insensitive, max 100 chars)","schema":{"example":"cruz roja","type":"string"}}],"responses":{"200":{"description":"Paged list of resources pending verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagedResourcesDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required for this emergency"},"404":{"description":"Emergency not found"}},"security":[{"bearer":[]}],"summary":"Get the verification queue for an emergency (paginated + searchable)","tags":["resources"]}},"/emergencies/{emergencyId}/coordination/disputed":{"get":{"operationId":"CoordinationController_disputedQueue","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Disputed resources for the emergency","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DisputedResourceDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required for this emergency"}},"security":[{"bearer":[]}],"summary":"List resources flagged as disputed by citizens, with a reason breakdown","tags":["resources"]}},"/emergencies/{emergencyId}/public/resources":{"get":{"operationId":"PublicController_list","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"default":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (max 100)","schema":{"default":50,"example":50,"type":"number"}},{"name":"category","required":false,"in":"query","description":"Filter by category slug","schema":{"example":"water","type":"string"}},{"name":"country","required":false,"in":"query","description":"Filter by ISO 3166-1 alpha-2 country code","schema":{"example":"VE","type":"string"}},{"name":"q","required":false,"in":"query","description":"Full-text search string matched against name, address, and city (case-insensitive, max 100 chars)","schema":{"example":"caritas","type":"string"}}],"responses":{"200":{"description":"Paged list of published resources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagedResourcesDto"}}}}},"summary":"List published resources for an emergency (paginated + filterable)","tags":["public"]}},"/emergencies/{emergencyId}/public/resources/nearby":{"get":{"operationId":"PublicController_nearby","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"lat","required":true,"in":"query","description":"Latitude between -90 and 90","schema":{"example":10.4806,"type":"number"}},{"name":"lng","required":true,"in":"query","description":"Longitude between -180 and 180","schema":{"example":-66.9036,"type":"number"}},{"name":"radius","required":true,"in":"query","description":"Search radius in meters (max 100000)","schema":{"example":5000,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Max results (default 50, max 100)","schema":{"example":50,"type":"number"}}],"responses":{"200":{"description":"Resources within radius ordered by distance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NearbyResourcesResponseDto"}}}}},"summary":"Find visible resources near a GPS point, ordered by distance","tags":["public"]}},"/emergencies/{emergencyId}/public/resources/in-bounds":{"get":{"operationId":"PublicController_inBounds","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"minLat","required":true,"in":"query","description":"South latitude bound (-90 to 90)","schema":{"example":10.3,"type":"number"}},{"name":"minLng","required":true,"in":"query","description":"West longitude bound (-180 to 180)","schema":{"example":-67.2,"type":"number"}},{"name":"maxLat","required":true,"in":"query","description":"North latitude bound (-90 to 90)","schema":{"example":10.7,"type":"number"}},{"name":"maxLng","required":true,"in":"query","description":"East longitude bound (-180 to 180)","schema":{"example":-66.6,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Max results (default 500, max 1000)","schema":{"example":500,"type":"number"}}],"responses":{"200":{"description":"Resources within the bounding box","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InBoundsResourcesDto"}}}}},"summary":"Find visible resources within a geographic bounding box","tags":["public"]}},"/emergencies/{emergencyId}/public/resources/facets":{"get":{"operationId":"PublicController_facets","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Facets for filtering visible resources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceFacetsDto"}}}}},"summary":"Get facets (counts by category and country) for visible resources","tags":["public"]}},"/emergencies/{emergencyId}/public/resources/{resourceId}":{"get":{"operationId":"PublicController_getOne","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"resourceId","required":true,"in":"path","description":"Resource UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"The published resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceDetailViewDto"}}}},"404":{"description":"Resource not found or not public"}},"summary":"Get a single published resource by id","tags":["public"]}},"/recipient-types":{"get":{"operationId":"RecipientTypesController_list","parameters":[],"responses":{"200":{"description":"Recipient types ordered by sort","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecipientTypeDto"}}}}}},"summary":"List the recipient-type taxonomy for final recipients (extensible)","tags":["public"]}},"/templates":{"post":{"operationId":"TemplatesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateDto"}}}},"responses":{"201":{"description":"Template created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateResponseDto"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"}},"security":[{"bearer":[]}],"summary":"Create an emergency template (admin only)","tags":["templates"]},"get":{"operationId":"TemplatesController_list","parameters":[],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TemplateViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"}},"security":[{"bearer":[]}],"summary":"List all emergency templates (admin only)","tags":["templates"]}},"/templates/{id}":{"delete":{"operationId":"TemplatesController_delete","parameters":[{"name":"id","required":true,"in":"path","description":"Template UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Template deleted"},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"},"404":{"description":"Template not found"}},"security":[{"bearer":[]}],"summary":"Delete an emergency template (admin only)","tags":["templates"]}},"/emergencies":{"post":{"operationId":"EmergenciesController_createEmergency","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmergencyDto"}}}},"responses":{"201":{"description":"Emergency created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmergencyResponseDto"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid token"},"403":{"description":"emergency:create required"},"409":{"description":"Slug already exists"}},"security":[{"bearer":[]}],"summary":"Create an emergency (emergency:create)","tags":["emergencies"]},"get":{"operationId":"EmergenciesController_list","parameters":[],"responses":{"200":{"description":"List of active emergencies","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmergencyViewDto"}}}}}},"summary":"List active emergencies","tags":["emergencies"]}},"/emergencies/mine":{"get":{"operationId":"EmergenciesController_listMine","parameters":[],"responses":{"200":{"description":"Emergencies the principal holds a grant in — including paused/closed — each with the role ids held at that scope","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyEmergencyViewDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List the emergencies the authenticated principal is granted into (any status)","tags":["emergencies"]}},"/emergencies/by-slug/{slug}":{"get":{"operationId":"EmergenciesController_getBySlugRoute","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Emergency found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmergencyViewDto"}}}},"404":{"description":"Emergency not found"}},"summary":"Get emergency by slug","tags":["emergencies"]}},"/emergencies/from-template":{"post":{"operationId":"EmergenciesController_createFromTemplateRoute","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmergencyFromTemplateDto"}}}},"responses":{"201":{"description":"Emergency created from template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmergencyResponseDto"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid token"},"403":{"description":"emergency:create required"},"404":{"description":"Template not found"},"409":{"description":"Slug already exists"}},"security":[{"bearer":[]}],"summary":"Create an emergency from a template (emergency:create)","tags":["emergencies"]}},"/emergencies/{emergencyId}/pause":{"post":{"operationId":"EmergenciesController_pauseEmergency","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Emergency paused"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Emergency not found"},"409":{"description":"Invalid transition (emergency is not active)"}},"security":[{"bearer":[]}],"summary":"Pause an active emergency (coordinator only)","tags":["emergencies"]}},"/emergencies/{emergencyId}/resume":{"post":{"operationId":"EmergenciesController_resumeEmergency","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Emergency resumed"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Emergency not found"},"409":{"description":"Invalid transition (emergency is not paused)"}},"security":[{"bearer":[]}],"summary":"Resume a paused emergency (coordinator only)","tags":["emergencies"]}},"/emergencies/{emergencyId}/announcement":{"put":{"operationId":"EmergenciesController_publishEmergencyAnnouncement","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishAnnouncementDto"}}}},"responses":{"204":{"description":"Announcement published"},"400":{"description":"Invalid body"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Emergency not found"}},"security":[{"bearer":[]}],"summary":"Publish official announcement for an emergency (coordinator only)","tags":["emergencies"]}},"/emergencies/{emergencyId}/needs":{"post":{"operationId":"NeedsController_create","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNeedDto"}}}},"responses":{"201":{"description":"Need created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNeedResponseDto"}}}},"400":{"description":"Invalid request body or UUID"},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"Create a need for an emergency (authenticated requester)","tags":["needs"]}},"/emergencies/{emergencyId}/public/needs":{"get":{"operationId":"NeedsController_listPublic","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"category","required":false,"in":"query","description":"Filter by item category (needs with at least one item of this category)","schema":{"enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"type":"string"}},{"name":"priority","required":false,"in":"query","description":"Filter by need priority","schema":{"enum":["low","medium","high","urgent"],"type":"string"}},{"name":"resourceId","required":false,"in":"query","description":"Filter to needs linked to this resource / final recipient","schema":{"format":"uuid","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size for pagination (1-100). Omit to return all.","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","description":"Number of items to skip (pagination). Defaults to 0.","schema":{"type":"string"}}],"responses":{"200":{"description":"List of validated needs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NeedViewDto"}}}}}},"summary":"List validated needs for an emergency (public)","tags":["needs"]}},"/emergencies/{emergencyId}/public/needs/nearby":{"get":{"operationId":"NeedsController_listNearby","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"lat","required":true,"in":"query","description":"Latitude between -90 and 90","schema":{"example":10.4806,"type":"number"}},{"name":"lng","required":true,"in":"query","description":"Longitude between -180 and 180","schema":{"example":-66.9036,"type":"number"}},{"name":"radius","required":true,"in":"query","description":"Search radius in meters (max 100000)","schema":{"example":5000,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Max results (default 50, max 100)","schema":{"example":50,"type":"number"}}],"responses":{"200":{"description":"Validated needs within radius ordered by distance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NearbyNeedsResponseDto"}}}}},"summary":"List validated needs near a GPS point, ordered by distance (public, #57)","tags":["needs"]}},"/emergencies/{emergencyId}/public/needs/in-bounds":{"get":{"operationId":"NeedsController_needsInBounds","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"minLat","required":true,"in":"query","description":"South latitude bound (-90 to 90)","schema":{"example":10.3,"type":"number"}},{"name":"minLng","required":true,"in":"query","description":"West longitude bound (-180 to 180)","schema":{"example":-67.2,"type":"number"}},{"name":"maxLat","required":true,"in":"query","description":"North latitude bound (-90 to 90)","schema":{"example":10.7,"type":"number"}},{"name":"maxLng","required":true,"in":"query","description":"East longitude bound (-180 to 180)","schema":{"example":-66.6,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Max results (default 500, max 1000)","schema":{"example":500,"type":"number"}}],"responses":{"200":{"description":"Validated needs within the bounding box","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InBoundsNeedsDto"}}}}},"summary":"List validated needs within a geographic bounding box (public)","tags":["needs"]}},"/emergencies/{emergencyId}/needs/queue":{"get":{"operationId":"NeedsController_listQueue","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"category","required":false,"in":"query","description":"Filter by item category (needs with at least one item of this category)","schema":{"enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"type":"string"}},{"name":"priority","required":false,"in":"query","description":"Filter by need priority","schema":{"enum":["low","medium","high","urgent"],"type":"string"}}],"responses":{"200":{"description":"List of pending needs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NeedViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required for this emergency"}},"security":[{"bearer":[]}],"summary":"Get pending needs queue for an emergency (coordinator only)","tags":["needs"]}},"/needs/{needId}/validate":{"post":{"operationId":"NeedsController_validate","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Need validated"},"400":{"description":"Need is not in pending status"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Validate a need (coordinator of the need's emergency only)","tags":["needs"]}},"/needs/{needId}":{"patch":{"operationId":"NeedsController_edit","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditNeedDto"}}}},"responses":{"204":{"description":"Need edited"},"400":{"description":"Missing reason or need is in a terminal status"},"401":{"description":"Missing or invalid token"},"403":{"description":"Validator/coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Edit a need during validation (validator/coordinator). Requires a reason; recorded in the audit trail.","tags":["needs"]}},"/needs/{needId}/discard":{"post":{"operationId":"NeedsController_discard","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscardNeedDto"}}}},"responses":{"204":{"description":"Need discarded (rejected)"},"400":{"description":"Missing reason or need is not in pending status"},"401":{"description":"Missing or invalid token"},"403":{"description":"Validator/coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Discard a need during validation (validator/coordinator). Requires a reason; recorded in the audit trail.","tags":["needs"]}},"/needs/{needId}/assign-manager":{"post":{"operationId":"NeedsController_assignManager","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignNeedManagerDto"}}}},"responses":{"204":{"description":"Manager assigned"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Assign a managing organization to a need (coordinator of the need's emergency only)","tags":["needs"]}},"/needs/{needId}/renew":{"post":{"operationId":"NeedsController_renew","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Need renewed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedViewDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Renew a need (reset expiresAt to now+48h) — coordinator only","tags":["needs"]}},"/emergencies/{emergencyId}/needs/expired":{"get":{"operationId":"NeedsController_listExpired","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of expired validated needs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NeedViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"}},"security":[{"bearer":[]}],"summary":"List expired needs for an emergency (coordinator only)","tags":["needs"]}},"/needs/{needId}/volunteer-suggestions":{"get":{"operationId":"NeedsController_getVolunteerSuggestions","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of suggestions (default 20)","schema":{"type":"number"}}],"responses":{"200":{"description":"List of suggested volunteers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VolunteerSuggestionDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Suggest available volunteers for a personnel need (coordinator only)","tags":["needs"]}},"/needs/{needId}/create-task":{"post":{"description":"Creates one Task linked to the need and optionally assigns volunteers. Reuses existing CreateTask / AssignVolunteerToTask logic.","operationId":"NeedsController_createTask","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskFromNeedDto"}}}},"responses":{"201":{"description":"Task created and volunteers assigned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedTaskFromNeedDto"}}}},"400":{"description":"Invalid body"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Create a task from a personnel need (coordinator only)","tags":["needs"]}},"/organizations":{"post":{"operationId":"OrganizationsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationDto"}}}},"responses":{"201":{"description":"Organization created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationResponseDto"}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"Create a new organization (authenticated users)","tags":["organizations"]},"get":{"operationId":"OrganizationsController_list","parameters":[],"responses":{"200":{"description":"All organizations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationViewDto"}}}}}},"summary":"List all organizations (public)","tags":["organizations"]}},"/organizations/mine":{"get":{"operationId":"OrganizationsController_mine","parameters":[],"responses":{"200":{"description":"User organizations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationViewDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List organizations the authenticated user belongs to","tags":["organizations"]}},"/organizations/{id}/members":{"get":{"operationId":"OrganizationsController_listMembers","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Organization members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationMemberDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Not a member of this organization"}},"security":[{"bearer":[]}],"summary":"List members of an organization (must be a member)","tags":["organizations"]},"post":{"operationId":"OrganizationsController_addMember","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemberDto"}}}},"responses":{"201":{"description":"Member added"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the owner can add members"},"404":{"description":"User not found by email"},"409":{"description":"User is already a member"}},"security":[{"bearer":[]}],"summary":"Add a member to an organization (owner only)","tags":["organizations"]}},"/organizations/{id}/members/{userId}":{"delete":{"operationId":"OrganizationsController_removeMember","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Member removed"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the owner can remove members"},"404":{"description":"Member not found"}},"security":[{"bearer":[]}],"summary":"Remove a member from an organization (owner only)","tags":["organizations"]}},"/accreditations":{"post":{"operationId":"AccreditationsController_grantAccreditation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantAccreditationDto"}}}},"responses":{"201":{"description":"Accreditation granted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccreditationResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"}},"security":[{"bearer":[]}],"summary":"Grant accreditation to an organization (accreditation:grant)","tags":["accreditations"]},"get":{"operationId":"AccreditationsController_listAccreditations","parameters":[{"name":"organizationId","required":false,"in":"query","description":"Filter by organization UUID","schema":{"type":"string"}},{"name":"emergencyId","required":false,"in":"query","description":"Filter by emergency UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of accreditations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AccreditationViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"}},"security":[{"bearer":[]}],"summary":"List accreditations (accreditation:grant)","tags":["accreditations"]}},"/accreditations/{id}":{"delete":{"operationId":"AccreditationsController_revokeAccreditation","parameters":[{"name":"id","required":true,"in":"path","description":"Accreditation UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Accreditation revoked"},"401":{"description":"Missing or invalid token"},"403":{"description":"Admin access required"},"404":{"description":"Accreditation not found"}},"security":[{"bearer":[]}],"summary":"Revoke an accreditation (accreditation:revoke)","tags":["accreditations"]}},"/geocode":{"get":{"operationId":"GeocodingController_search","parameters":[{"name":"q","required":true,"in":"query","description":"Address or place name to search","schema":{"example":"Madrid"}}],"responses":{"200":{"description":"Geocoding results (empty array when query is shorter than 3 characters)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GeocodeResultDto"}}}}}},"summary":"Geocode a free-text address query (Nominatim / OpenStreetMap)","tags":["geocoding"]}},"/emergencies/{emergencyId}/metrics":{"get":{"operationId":"MetricsController_metrics","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Emergency metrics summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmergencyMetricsDto"}}}}},"summary":"Get aggregated metrics for an emergency (public)","tags":["metrics"]}},"/emergencies/{emergencyId}/offers":{"post":{"operationId":"OffersController_submit","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitOfferDto"}}}},"responses":{"201":{"description":"Offer created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitOfferResponseDto"}}}},"400":{"description":"Invalid request body or UUID"},"401":{"description":"Missing or invalid token"},"409":{"description":"Emergency is not accepting intake (paused/closed)"}},"security":[{"bearer":[]}],"summary":"Submit a donation offer for an emergency (authenticated donor)","tags":["offers"]}},"/emergencies/{emergencyId}/offers/queue":{"get":{"operationId":"OffersController_listQueue","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of open offers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OfferViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"}},"security":[{"bearer":[]}],"summary":"Get open offers queue for an emergency (coordinator only)","tags":["offers"]}},"/emergencies/{emergencyId}/offers/mine":{"get":{"operationId":"OffersController_listMine","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"My offers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OfferViewDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List my offers for an emergency (authenticated donor)","tags":["offers"]}},"/needs/{needId}/offers":{"get":{"operationId":"OffersController_listForNeed","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Offers matched to the need","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OfferViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"List matched offers for a need (coordinator only)","tags":["offers"]}},"/needs/{needId}/offer-suggestions":{"get":{"operationId":"OffersController_suggestForNeed","parameters":[{"name":"needId","required":true,"in":"path","description":"Need UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Suggested offers sorted by proximity","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OfferViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Need not found"}},"security":[{"bearer":[]}],"summary":"Suggest open offers for a need (coordinator only), sorted by proximity","tags":["offers"]}},"/offers/{offerId}/match":{"post":{"operationId":"OffersController_match","parameters":[{"name":"offerId","required":true,"in":"path","description":"Offer UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchOfferDto"}}}},"responses":{"204":{"description":"Offer matched to need"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Offer or need not found"},"409":{"description":"Offer is not in Open status"}},"security":[{"bearer":[]}],"summary":"Match an offer to a need (coordinator of the offer's emergency only)","tags":["offers"]}},"/offers/{offerId}":{"patch":{"operationId":"OffersController_edit","parameters":[{"name":"offerId","required":true,"in":"path","description":"Offer UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditOfferDto"}}}},"responses":{"204":{"description":"Offer edited"},"400":{"description":"Missing reason or offer is in a terminal status"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Offer not found"}},"security":[{"bearer":[]}],"summary":"Edit a donation offer (coordinator). Requires a reason; recorded in the audit trail.","tags":["offers"]}},"/offers/{offerId}/discard":{"post":{"operationId":"OffersController_discard","parameters":[{"name":"offerId","required":true,"in":"path","description":"Offer UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscardOfferDto"}}}},"responses":{"204":{"description":"Offer discarded (cancelled)"},"400":{"description":"Missing reason or offer cannot be discarded in its status"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Offer not found"}},"security":[{"bearer":[]}],"summary":"Discard a donation offer (coordinator). Requires a reason; recorded in the audit trail.","tags":["offers"]}},"/offers/{offerId}/fulfill":{"post":{"operationId":"OffersController_fulfill","parameters":[{"name":"offerId","required":true,"in":"path","description":"Offer UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Offer fulfilled"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Offer not found"},"409":{"description":"Offer is not in Matched status"}},"security":[{"bearer":[]}],"summary":"Mark an offer as fulfilled (coordinator of the offer's emergency only)","tags":["offers"]}},"/offers/{offerId}/cancel":{"post":{"operationId":"OffersController_cancel","parameters":[{"name":"offerId","required":true,"in":"path","description":"Offer UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Offer cancelled"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the offer owner or a coordinator can cancel"},"404":{"description":"Offer not found"},"409":{"description":"Offer cannot be cancelled in its current status"}},"security":[{"bearer":[]}],"summary":"Cancel an offer (owner or coordinator)","tags":["offers"]}},"/emergencies/{emergencyId}/donation-intakes":{"post":{"operationId":"DonationIntakesController_create","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDonationIntakeDto"}}}},"responses":{"201":{"description":"Intake created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDonationIntakeResponseDto"}}}},"400":{"description":"Invalid request body"},"409":{"description":"Emergency is not accepting intake (paused/closed)"},"422":{"description":"Invalid collection point"},"429":{"description":"Rate limit exceeded"}},"summary":"Pre-register a donation at a collection point (public)","tags":["donation-intakes"]}},"/emergencies/{emergencyId}/donation-intakes/lookup-contact":{"post":{"operationId":"DonationIntakesController_lookupContact","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupDonorByContactDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupDonorByContactResponseDto"}}}},"400":{"description":"Invalid request body"},"429":{"description":"Rate limit exceeded"}},"summary":"Recognize a returning donor by phone or email (public)","tags":["donation-intakes"]}},"/donation-intakes/{intakeId}":{"patch":{"operationId":"DonationIntakesController_update","parameters":[{"name":"intakeId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDonationIntakeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DonationIntakeViewDto"}}}},"400":{"description":"Invalid request body"},"403":{"description":"Contact or code mismatch"},"404":{"description":"Intake not found"},"409":{"description":"Intake already processed"},"429":{"description":"Rate limit exceeded"}},"summary":"Update a pending intake (public, requires code + contact)","tags":["donation-intakes"]},"get":{"operationId":"DonationIntakesController_getById","parameters":[{"name":"intakeId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DonationIntakeViewDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing intake:read"},"404":{"description":"Intake not found"}},"security":[{"bearer":[]}],"summary":"Get full intake detail with lines","tags":["donation-intakes"]}},"/emergencies/{emergencyId}/donation-intakes/search":{"get":{"operationId":"DonationIntakesController_search","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"q","required":true,"in":"query","description":"Phone, email, code or name","schema":{"example":"ACO-7F3K","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DonationIntakeSearchHitDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing intake:read"}},"security":[{"bearer":[]}],"summary":"Search intakes by phone, email, code or name","tags":["donation-intakes"]}},"/resources/{resourceId}/donation-intakes/pending":{"get":{"operationId":"DonationIntakesController_listPending","parameters":[{"name":"resourceId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DonationIntakeSearchHitDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing intake:read"},"404":{"description":"Resource not found"}},"security":[{"bearer":[]}],"summary":"List pending intakes for a collection point","tags":["donation-intakes"]}},"/donation-intakes/{intakeId}/receive":{"post":{"operationId":"DonationIntakesController_receive","parameters":[{"name":"intakeId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceiveDonationIntakeDto"}}}},"responses":{"204":{"description":"Intake marked as received"},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing intake:receive"},"404":{"description":"Intake not found"},"409":{"description":"Intake already processed"}},"security":[{"bearer":[]}],"summary":"Confirm physical reception of a pending intake","tags":["donation-intakes"]}},"/donation-intakes/{intakeId}/reject":{"post":{"operationId":"DonationIntakesController_reject","parameters":[{"name":"intakeId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectDonationIntakeDto"}}}},"responses":{"204":{"description":"Intake marked as rejected"},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing intake:receive"},"404":{"description":"Intake not found"},"409":{"description":"Intake already processed"}},"security":[{"bearer":[]}],"summary":"Reject a pending intake at reception","tags":["donation-intakes"]}},"/donation-intakes/{intakeId}/incomplete":{"post":{"operationId":"DonationIntakesController_markIncomplete","parameters":[{"name":"intakeId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkDonationIntakeIncompleteDto"}}}},"responses":{"204":{"description":"Intake marked as incomplete"},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing intake:receive"},"404":{"description":"Intake not found"},"409":{"description":"Intake already processed"}},"security":[{"bearer":[]}],"summary":"Mark a pending intake as incomplete (material mismatch)","tags":["donation-intakes"]}},"/logistics/capacities":{"post":{"operationId":"LogisticsController_publish","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishCapacityDto"}}}},"responses":{"201":{"description":"Capacity published","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishCapacityResponseDto"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing capacity:publish permission"},"409":{"description":"Emergency is not accepting intake (paused/closed)"}},"security":[{"bearer":[]}],"summary":"Publish a transport-capacity offer (authenticated, citizen-grade)","tags":["logistics"]}},"/logistics/capacities/{id}/withdraw":{"post":{"operationId":"LogisticsController_withdraw","parameters":[{"name":"id","required":true,"in":"path","description":"Capacity UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Capacity withdrawn"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the provider or a coordinator can withdraw"},"404":{"description":"Capacity not found"},"409":{"description":"Capacity cannot be withdrawn in its current status"}},"security":[{"bearer":[]}],"summary":"Withdraw a transport-capacity offer (provider or coordinator)","tags":["logistics"]}},"/emergencies/{emergencyId}/logistics/capacities":{"get":{"operationId":"LogisticsController_list","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"mode","required":false,"in":"query","description":"Filter by mode","schema":{"type":"string","enum":["road","sea","air"]}},{"name":"status","required":false,"in":"query","description":"Filter by status","schema":{"type":"string","enum":["available","reserved","withdrawn"]}},{"name":"availableFrom","required":false,"in":"query","description":"Keep capacities available at/after this instant (ISO-8601)","schema":{"example":"2026-07-05T00:00:00.000Z","type":"string"}},{"name":"availableTo","required":false,"in":"query","description":"Keep capacities available at/before this instant (ISO-8601)","schema":{"example":"2026-07-10T00:00:00.000Z","type":"string"}}],"responses":{"200":{"description":"Capacities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CapacityViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing capacity:read permission"}},"security":[{"bearer":[]}],"summary":"List transport capacities for an emergency (coordinator/verifier)","tags":["logistics"]}},"/logistics/shipments":{"post":{"operationId":"ShipmentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShipmentDto"}}}},"responses":{"201":{"description":"Shipment created (planned)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShipmentResponseDto"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid token"},"403":{"description":"Not a coordinator of the emergency"},"409":{"description":"Emergency is not accepting intake (paused/closed)"}},"security":[{"bearer":[]}],"summary":"Create a shipment / expedición (coordinator)","tags":["logistics"]}},"/logistics/shipments/{id}/assign-capacity":{"post":{"operationId":"ShipmentController_assignCapacity","parameters":[{"name":"id","required":true,"in":"path","description":"Shipment UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignCapacityToShipmentDto"}}}},"responses":{"204":{"description":"Capacity assigned"},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid token"},"403":{"description":"Not a coordinator of the shipment emergency"},"404":{"description":"Shipment not found"},"409":{"description":"Shipment is not in planned status"}},"security":[{"bearer":[]}],"summary":"Assign a transport capacity (and optional carrier) (coordinator)","tags":["logistics"]}},"/logistics/shipments/{id}/in-transit":{"post":{"operationId":"ShipmentController_markInTransit","parameters":[{"name":"id","required":true,"in":"path","description":"Shipment UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Shipment marked in transit"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the assigned carrier or a coordinator can act"},"404":{"description":"Shipment not found"},"409":{"description":"Shipment is not in assigned status"}},"security":[{"bearer":[]}],"summary":"Mark a shipment in transit (assigned carrier or coordinator)","tags":["logistics"]}},"/logistics/shipments/{id}/deliver":{"post":{"operationId":"ShipmentController_deliver","parameters":[{"name":"id","required":true,"in":"path","description":"Shipment UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Shipment delivered"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the assigned carrier or a coordinator can act"},"404":{"description":"Shipment not found"},"409":{"description":"Shipment is not in transit"}},"security":[{"bearer":[]}],"summary":"Confirm a shipment delivery (assigned carrier or coordinator)","tags":["logistics"]}},"/logistics/shipments/{id}/cancel":{"post":{"operationId":"ShipmentController_cancel","parameters":[{"name":"id","required":true,"in":"path","description":"Shipment UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Shipment cancelled"},"401":{"description":"Missing or invalid token"},"403":{"description":"Not a coordinator of the shipment emergency"},"404":{"description":"Shipment not found"},"409":{"description":"Shipment cannot be cancelled in its current status"}},"security":[{"bearer":[]}],"summary":"Cancel a shipment (coordinator)","tags":["logistics"]}},"/logistics/shipments/mine":{"get":{"operationId":"ShipmentController_listMine","parameters":[{"name":"emergencyId","required":false,"in":"query","description":"Optional emergency scope; omit to list across emergencies","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"My shipments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ShipmentViewDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List my shipments as a carrier (\"mis expediciones\")","tags":["logistics"]}},"/emergencies/{emergencyId}/logistics/shipments":{"get":{"operationId":"ShipmentController_list","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status","schema":{"type":"string","enum":["planned","assigned","in_transit","delivered","failed","cancelled"]}}],"responses":{"200":{"description":"Shipments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ShipmentViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Missing shipment:read permission"}},"security":[{"bearer":[]}],"summary":"List shipments for an emergency (coordinator/verifier)","tags":["logistics"]}},"/logistics/shipments/{id}/capacity-suggestions":{"get":{"operationId":"ShipmentController_capacitySuggestions","parameters":[{"name":"id","required":true,"in":"path","description":"Shipment UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Compatible capacities ranked by proximity/coverage fit","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CapacityViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Not a coordinator of the shipment emergency"},"404":{"description":"Shipment not found"}},"security":[{"bearer":[]}],"summary":"Suggest compatible transport capacities for a shipment, ranked (coordinator)","tags":["logistics"]}},"/emergencies/{emergencyId}/volunteers":{"post":{"operationId":"VolunteersController_registerVolunteer","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterVolunteerDto"}}}},"responses":{"201":{"description":"Volunteer registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterVolunteerResponseDto"}}}},"400":{"description":"Invalid request body or UUID"},"401":{"description":"Missing or invalid token"},"409":{"description":"Emergency not accepting volunteers (paused/closed)"}},"security":[{"bearer":[]}],"summary":"Register as a volunteer for an emergency (requires authentication)","tags":["volunteers"]},"get":{"operationId":"VolunteersController_getRosterForEmergency","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"skill","required":false,"in":"query","schema":{"enum":["driving","medical","logistics","cooking","languages","admin","general"],"type":"string"}},{"name":"availability","required":false,"in":"query","schema":{"enum":["immediate","this_week","flexible"],"type":"string"}},{"name":"vehicle","required":false,"in":"query","schema":{"enum":["none","car","van","truck"],"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["available","assigned","inactive"],"type":"string"}}],"responses":{"200":{"description":"List of volunteers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VolunteerViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"}},"security":[{"bearer":[]}],"summary":"Get volunteer roster for an emergency (coordinator only)","tags":["volunteers"]}},"/volunteers/{volunteerId}/status":{"post":{"operationId":"VolunteersController_updateVolunteerStatus","parameters":[{"name":"volunteerId","required":true,"in":"path","description":"Volunteer UUID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVolunteerStatusDto"}}}},"responses":{"204":{"description":"Status updated"},"400":{"description":"Invalid status or UUID"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Volunteer not found"}},"security":[{"bearer":[]}],"summary":"Update volunteer status (coordinator of the volunteer's emergency only)","tags":["volunteers"]}},"/emergencies/{emergencyId}/volunteers/me":{"get":{"operationId":"VolunteersController_fetchMyProfile","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"My volunteer profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolunteerViewDto"}}}},"401":{"description":"Missing or invalid token"},"404":{"description":"Not registered as volunteer in this emergency"}},"security":[{"bearer":[]}],"summary":"Get my volunteer profile for an emergency","tags":["volunteers"]}},"/emergencies/{emergencyId}/tasks":{"post":{"operationId":"TasksController_createTask","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskDto"}}}},"responses":{"201":{"description":"Task created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskResponseDto"}}}},"400":{"description":"Invalid body or UUID"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"}},"security":[{"bearer":[]}],"summary":"Create a task for an emergency (coordinator only)","tags":["tasks"]},"get":{"operationId":"TasksController_getTasks","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["open","in_progress","completed","cancelled"],"type":"string"}}],"responses":{"200":{"description":"Task list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskViewDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"}},"security":[{"bearer":[]}],"summary":"List tasks for an emergency (coordinator only)","tags":["tasks"]}},"/emergencies/{emergencyId}/tasks/mine":{"get":{"operationId":"TasksController_getMyTasks","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Tasks assigned to me","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyTaskViewDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"Get tasks assigned to the authenticated volunteer","tags":["tasks"]}},"/tasks/{taskId}/assign":{"post":{"operationId":"TasksController_assignVolunteer","parameters":[{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignVolunteerDto"}}}},"responses":{"204":{"description":"Volunteer assigned"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Task or volunteer not found"},"422":{"description":"Volunteer already assigned, wrong emergency, or task closed"}},"security":[{"bearer":[]}],"summary":"Assign a volunteer to a task (coordinator only)","tags":["tasks"]}},"/tasks/{taskId}/unassign":{"post":{"operationId":"TasksController_unassignVolunteer","parameters":[{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignVolunteerDto"}}}},"responses":{"204":{"description":"Volunteer unassigned"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Task not found"},"422":{"description":"Volunteer not assigned"}},"security":[{"bearer":[]}],"summary":"Unassign a volunteer from a task (coordinator only)","tags":["tasks"]}},"/tasks/{taskId}/check-in":{"post":{"operationId":"TasksController_checkIn","parameters":[{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignVolunteerDto"}}}},"responses":{"204":{"description":"Checked in"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the assigned volunteer or a coordinator"},"404":{"description":"Task not found"},"422":{"description":"Not assigned or already checked in"}},"security":[{"bearer":[]}],"summary":"Check in a volunteer to a task (volunteer themselves or coordinator)","tags":["tasks"]}},"/tasks/{taskId}/check-out":{"post":{"operationId":"TasksController_checkOut","parameters":[{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignVolunteerDto"}}}},"responses":{"204":{"description":"Checked out"},"401":{"description":"Missing or invalid token"},"403":{"description":"Only the assigned volunteer or a coordinator"},"404":{"description":"Task not found"},"422":{"description":"Not checked in"}},"security":[{"bearer":[]}],"summary":"Check out a volunteer from a task (volunteer themselves or coordinator)","tags":["tasks"]}},"/tasks/{taskId}/complete":{"post":{"operationId":"TasksController_completeTask","parameters":[{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Task completed"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Task not found"},"422":{"description":"Task already cancelled"}},"security":[{"bearer":[]}],"summary":"Mark a task as completed (coordinator only)","tags":["tasks"]}},"/tasks/{taskId}/cancel":{"post":{"operationId":"TasksController_cancelTask","parameters":[{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Task cancelled"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Task not found"},"422":{"description":"Task already completed"}},"security":[{"bearer":[]}],"summary":"Cancel a task (coordinator only)","tags":["tasks"]}},"/files":{"post":{"operationId":"FilesController_upload","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"File stored successfully","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"url":{"type":"string"}}}}}}},"security":[{"bearer":[]}],"summary":"Upload an image file (max 5 MB)","tags":["files"]}},"/files/{key}":{"get":{"operationId":"FilesController_serve","parameters":[{"name":"key","required":true,"in":"path","description":"Storage key returned by POST /files","schema":{"type":"string"}}],"responses":{"200":{"description":"File content streamed"}},"summary":"Download a stored file by key","tags":["files"]}},"/emergencies/{emergencyId}/reports":{"post":{"operationId":"ReportsController_submit","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitReportDto"}}}},"responses":{"201":{"description":"Report submitted"}},"security":[{"bearer":[]}],"summary":"Submit a field report","tags":["reports"]},"get":{"operationId":"ReportsController_getQueue","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["open","reviewed","closed"]}},{"name":"priority","required":false,"in":"query","schema":{"type":"string","enum":["low","medium","high","urgent"]}},{"name":"resourceId","required":false,"in":"query","description":"Filter by resource ID","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by type","schema":{"type":"string","enum":["incident","stock","status","other"]}}],"responses":{"200":{"description":"List of reports"}},"security":[{"bearer":[]}],"summary":"Get coordination queue of reports","tags":["reports"]}},"/reports/{reportId}/review":{"post":{"operationId":"ReportsController_review","parameters":[{"name":"reportId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Report marked as reviewed"}},"security":[{"bearer":[]}],"summary":"Mark a report as reviewed","tags":["reports"]}},"/reports/{reportId}":{"patch":{"operationId":"ReportsController_edit","parameters":[{"name":"reportId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditReportDto"}}}},"responses":{"204":{"description":"Report edited"},"400":{"description":"Missing reason or report is closed"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Report not found"}},"security":[{"bearer":[]}],"summary":"Editar un reporte durante el triaje (coordinador). Requiere un motivo; se registra en la trazabilidad.","tags":["reports"]}},"/reports/{reportId}/discard":{"post":{"operationId":"ReportsController_discard","parameters":[{"name":"reportId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscardReportDto"}}}},"responses":{"204":{"description":"Report discarded (closed)"},"400":{"description":"Missing reason or report already closed"},"401":{"description":"Missing or invalid token"},"403":{"description":"Coordinator role required"},"404":{"description":"Report not found"}},"security":[{"bearer":[]}],"summary":"Descartar un reporte durante el triaje (coordinador). Requiere un motivo; se registra en la trazabilidad.","tags":["reports"]}},"/emergencies/{emergencyId}/reports/mine":{"get":{"operationId":"ReportsController_mine","parameters":[{"name":"emergencyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"List of my reports"}},"security":[{"bearer":[]}],"summary":"Get my field reports for an emergency","tags":["reports"]}},"/audit":{"get":{"operationId":"AuditController_list","parameters":[{"name":"emergencyId","required":false,"in":"query","description":"Filter by emergency ID","schema":{"type":"string"}},{"name":"actorUserId","required":false,"in":"query","description":"Filter by actor user ID","schema":{"type":"string"}},{"name":"entityType","required":false,"in":"query","description":"Filter by entity type (e.g. resource, need)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max results to return (default 100, max 500)","schema":{"default":100,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination (default 0)","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditListResponseDto"}}}},"401":{"description":"Unauthorized"},"403":{"description":"audit:read required"}},"security":[{"bearer":[]}],"summary":"List audit log entries (audit:read)","tags":["audit"]}},"/emergencies/{emergencyId}/audit":{"get":{"operationId":"EmergencyAuditController_list","parameters":[{"name":"emergencyId","required":true,"in":"path","description":"Emergency UUID","schema":{"format":"uuid","type":"string"}},{"name":"actorUserId","required":false,"in":"query","description":"Filter by actor user ID","schema":{"type":"string"}},{"name":"entityType","required":false,"in":"query","description":"Filter by entity type (e.g. resource, need)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max results to return (default 100, max 500)","schema":{"default":100,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination (default 0)","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditListResponseDto"}}}},"401":{"description":"Unauthorized"},"403":{"description":"audit:read required (coordinator of this emergency)"}},"security":[{"bearer":[]}],"summary":"Activity trail for an emergency — coordinators of the emergency only","tags":["audit"]}},"/groups/mine":{"get":{"operationId":"GroupsController_mine","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyGroupResponseDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List the groups I belong to (any status)","tags":["groups"]}},"/groups":{"get":{"operationId":"GroupsController_list","parameters":[{"name":"ownerKind","required":true,"in":"query","schema":{"type":"string","enum":["organization","emergency"]}},{"name":"ownerId","required":true,"in":"query","description":"Id of the owning org/emergency","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GroupResponseDto"}}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"List groups under an org/emergency (all if you can read; else public)","tags":["groups"]},"post":{"operationId":"GroupsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"group:create required in the owner scope"}},"security":[{"bearer":[]}],"summary":"Create a group (creator becomes its first manager)","tags":["groups"]}},"/groups/{groupId}":{"get":{"operationId":"GroupsController_getOne","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponseDto"}}}},"401":{"description":"Missing or invalid token"}},"security":[{"bearer":[]}],"summary":"Get a group’s basic info","tags":["groups"]}},"/groups/{groupId}/join":{"post":{"operationId":"GroupsController_join","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Join request registered"},"401":{"description":"Missing or invalid token"},"403":{"description":"Group is private"}},"security":[{"bearer":[]}],"summary":"Request to join a public group (awaits approval)","tags":["groups"]}},"/groups/{groupId}/members":{"get":{"operationId":"GroupsController_members","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GroupMemberResponseDto"}}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"group:read required"}},"security":[{"bearer":[]}],"summary":"List a group’s members","tags":["groups"]},"post":{"operationId":"GroupsController_addMember","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemberByEmailDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupMemberResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"group:manage_members required"}},"security":[{"bearer":[]}],"summary":"Add a member by email (manager only)","tags":["groups"]}},"/groups/{groupId}/members/{userId}/approve":{"post":{"operationId":"GroupsController_approve","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Member approved"},"401":{"description":"Missing or invalid token"},"403":{"description":"group:manage_members required"}},"security":[{"bearer":[]}],"summary":"Approve a pending member (manager only)","tags":["groups"]}},"/groups/{groupId}/managers":{"post":{"operationId":"GroupsController_assignManager","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignManagerDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResponseDto"}}}},"401":{"description":"Missing or invalid token"},"403":{"description":"role:grant required, or privilege escalation"}},"security":[{"bearer":[]}],"summary":"Appoint a member as co-manager (delegated, attenuated)","tags":["groups"]}},"/categories":{"get":{"operationId":"CategoriesController_list","parameters":[],"responses":{"200":{"description":"The category taxonomy","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryDto"}}}}}},"summary":"List the shared category taxonomy (slug + labels + hierarchy)","tags":["categories"]}}},"info":{"title":"ResponseGrid API","description":"API for humanitarian emergency resource coordination","version":"0.1","contact":{}},"tags":[{"name":"resources","description":""}],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"},"api-key":{"type":"apiKey","in":"header","name":"X-API-Key"}},"schemas":{"LoginDto":{"type":"object","properties":{"email":{"type":"string","example":"admin@reliefhub.org"},"password":{"type":"string","example":"admin1234","minLength":6}},"required":["email","password"]},"LoginResponseDto":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT access token"}},"required":["accessToken"]},"RegisterDto":{"type":"object","properties":{"email":{"type":"string","example":"user@reliefhub.org"},"password":{"type":"string","example":"password123","minLength":8},"name":{"type":"string","example":"Jane Doe"}},"required":["email","password","name"]},"RegisterResponseDto":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT access token (auto-login after registration)"}},"required":["accessToken"]},"MeGrantDto":{"type":"object","properties":{"roleId":{"type":"string","description":"Role id from the catalog","example":"org_admin"},"scopeType":{"type":"string","enum":["platform","organization","emergency","group","entity"]},"scopeId":{"type":"string","nullable":true,"description":"Scope id (null for platform)"},"expiresAt":{"type":"string","nullable":true,"description":"ISO expiry, or null"}},"required":["roleId","scopeType","scopeId","expiresAt"]},"MeResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"User UUID"},"email":{"type":"string","example":"user@example.com"},"name":{"type":"string","example":"Jane Doe"},"isAdmin":{"type":"boolean"},"grants":{"description":"The effective role grants (role @ scope) for this user","type":"array","items":{"$ref":"#/components/schemas/MeGrantDto"}}},"required":["id","email","name","isAdmin","grants"]},"GrantListItemDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"principalId":{"type":"string","format":"uuid"},"principalType":{"type":"string","enum":["user","service_account"]},"roleId":{"type":"string"},"scopeType":{"type":"string"},"scopeId":{"type":"string","nullable":true},"grantedByPrincipalId":{"type":"string","nullable":true},"grantedAt":{"type":"string"},"expiresAt":{"type":"string","nullable":true},"principalName":{"type":"string","nullable":true,"description":"Display name of the principal (when resolvable)"},"principalEmail":{"type":"string","nullable":true,"description":"Email of the principal (users only)"}},"required":["id","principalId","principalType","roleId","scopeType","scopeId","grantedByPrincipalId","grantedAt","expiresAt","principalName","principalEmail"]},"GrantRoleDto":{"type":"object","properties":{"principalId":{"type":"string","format":"uuid","description":"Principal receiving the role"},"roleId":{"type":"string","description":"Role id from the fixed catalog (e.g. emergency_coordinator)"},"scopeType":{"type":"string","enum":["platform","organization","emergency","group","entity"],"description":"Scope the role applies to"},"scopeId":{"type":"string","description":"Scope id (required for every scope except platform)"},"scopeEntityType":{"type":"string","description":"Entity type (required for entity scope)"},"expiresAt":{"type":"string","description":"ISO 8601 expiry — for temporary / break-glass grants"}},"required":["principalId","roleId","scopeType"]},"GrantResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"ServiceAccountListItemDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"ownerOrganizationId":{"type":"object","format":"uuid","nullable":true},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string"}},"required":["id","name","ownerOrganizationId","createdByUserId","createdAt"]},"ApiKeyListItemDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"prefix":{"type":"string","description":"Non-secret lookup prefix"},"active":{"type":"boolean"},"expiresAt":{"type":"string","nullable":true},"lastUsedAt":{"type":"string","nullable":true},"revokedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","prefix","active","expiresAt","lastUsedAt","revokedAt","createdAt"]},"CreateServiceAccountDto":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable name for the service account"},"ownerOrganizationId":{"type":"string","format":"uuid","description":"Owning organization; omit for a platform-level account"}},"required":["name"]},"ServiceAccountResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"IssueApiKeyDto":{"type":"object","properties":{"expiresAt":{"type":"string","description":"ISO 8601 expiry for the key"}}},"IssuedApiKeyResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"apiKey":{"type":"string","description":"The full secret key — shown once; store it now"},"prefix":{"type":"string"}},"required":["id","apiKey","prefix"]},"IntrospectedGrantDto":{"type":"object","properties":{"roleId":{"type":"string"},"scopeType":{"type":"string"},"scopeId":{"type":"object","nullable":true}},"required":["roleId","scopeType","scopeId"]},"ServiceAccountIdentityDto":{"type":"object","properties":{"principalId":{"type":"string","format":"uuid"},"principalType":{"type":"string","enum":["service_account"]},"grants":{"type":"array","items":{"$ref":"#/components/schemas/IntrospectedGrantDto"}}},"required":["principalId","principalType","grants"]},"RoleDto":{"type":"object","properties":{"id":{"type":"string"},"description":{"type":"string"},"defaultScopeType":{"type":"string"},"permissions":{"type":"array","items":{"type":"string"}}},"required":["id","description","defaultScopeType","permissions"]},"UserLookupDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"name":{"type":"string"}},"required":["id","email","name"]},"NotificationDto":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"emergencyId":{"type":"string","nullable":true},"type":{"type":"string","enum":["resource_verified","offer_matched","task_assigned"]},"message":{"type":"string"},"link":{"type":"string","nullable":true},"read":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"}},"required":["id","userId","emergencyId","type","message","link","read","createdAt"]},"GetMyNotificationsResponseDto":{"type":"object","properties":{"notifications":{"type":"array","items":{"$ref":"#/components/schemas/NotificationDto"}},"unreadCount":{"type":"number"}},"required":["notifications","unreadCount"]},"LocationDto":{"type":"object","properties":{"address":{"type":"string","example":"Calle Mayor 1, Valencia"},"latitude":{"type":"number","example":39.4699,"description":"Latitude between -90 and 90"},"longitude":{"type":"number","example":-0.3763,"description":"Longitude between -180 and 180"}},"required":["address","latitude","longitude"]},"SupplyLineDto":{"type":"object","properties":{"name":{"type":"string","example":"Water bottles","description":"Name of the supply"},"quantity":{"type":"number","example":100,"description":"Quantity (positive integer)"},"unit":{"type":"string","example":"liters","description":"Unit of measurement (optional)"},"category":{"type":"string","enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"example":"water"},"presentation":{"type":"string","example":"ampolla","description":"Presentation / route of administration: ampolla, EV (intravenoso), inhalador, pastilla, jarabe… Optional, free-form (#61)."}},"required":["name","quantity","category"]},"RegisterResourceDto":{"type":"object","properties":{"type":{"type":"string","enum":["collection_point","delivery_point","collection_and_delivery","warehouse","transport","supplier","venue"],"example":"collection_point"},"stage":{"type":"string","enum":["origin","intermediate","destination"],"example":"origin","description":"Stage of the resource in the emergency supply chain"},"name":{"type":"string","example":"Cruz Roja Madrid","minLength":2},"description":{"type":"string","example":"Centro de acopio principal"},"location":{"description":"Physical location of the resource","allOf":[{"$ref":"#/components/schemas/LocationDto"}]},"ownerOrganizationId":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6","description":"Organization offering this resource (optional)"},"contact":{"type":"string","example":"+58 212 555 0000","description":"Contact info for this resource point"},"schedule":{"type":"string","example":"Lun-Vie 08-18","description":"Operating schedule"},"manager":{"type":"string","example":"Juan Pérez","description":"Responsible manager name"},"accepts":{"example":["water","food"],"description":"Category slugs this resource accepts","type":"array","items":{"type":"string"}},"country":{"type":"string","example":"VE","description":"ISO 3166-1 alpha-2 country code"},"city":{"type":"string","example":"Caracas","description":"City name"},"isFinalRecipient":{"type":"boolean","example":true,"description":"Mark this resource as a final recipient of aid (requires the destination stage)"},"recipientType":{"type":"string","example":"hospital","description":"Recipient type slug (see the emergency recipient-type taxonomy)"},"items":{"description":"Declared inventory: the supply lines this place holds for delivery (optional)","type":"array","items":{"$ref":"#/components/schemas/SupplyLineDto"}}},"required":["type","stage","name","location"]},"RegisterResourceResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"required":["id"]},"VerifyResourceDto":{"type":"object","properties":{}},"EditResourceDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo de la edición (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Se corrige el nombre y se completa el horario"},"name":{"type":"string","description":"Nuevo nombre (omitir para no cambiarlo)","minLength":2},"description":{"type":"string","description":"Nueva descripción. Cadena vacía la borra. Omitir para no cambiarla.","nullable":true},"contact":{"type":"string","description":"Nuevo contacto. Cadena vacía lo borra. Omitir para no cambiarlo.","nullable":true},"schedule":{"type":"string","description":"Nuevo horario. Cadena vacía lo borra. Omitir para no cambiarlo.","nullable":true}},"required":["reason"]},"DiscardResourceDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo del descarte (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Punto duplicado / fuera del ámbito de la emergencia"}},"required":["reason"]},"UpdateResourcePublicStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["active","saturated","paused","closed"],"example":"saturated","description":"Target operational status. Hidden is not allowed; use close() to deactivate."}},"required":["status"]},"LocationViewDto":{"type":"object","properties":{"address":{"type":"string","example":"Calle Mayor 1, Valencia"},"latitude":{"type":"number","example":39.4699},"longitude":{"type":"number","example":-0.3763}},"required":["address","latitude","longitude"]},"ResourceViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"type":{"type":"string","enum":["collection_point","delivery_point","collection_and_delivery","warehouse","transport","supplier","venue"],"example":"collection_point"},"stage":{"type":"string","enum":["origin","intermediate","destination"],"example":"origin"},"name":{"type":"string","example":"Cruz Roja Madrid"},"description":{"type":"string","example":"Centro de acopio principal","nullable":true},"location":{"$ref":"#/components/schemas/LocationViewDto"},"verificationLevel":{"type":"string","enum":["unverified","verified","official","rejected"],"example":"verified"},"publicStatus":{"type":"string","enum":["hidden","active","saturated","paused","closed"],"example":"active"},"ownerOrganizationId":{"type":"string","format":"uuid","nullable":true},"accepts":{"example":["water","food"],"type":"array","items":{"type":"string"}},"contact":{"type":"string","example":"+58 212 555 0000","nullable":true},"schedule":{"type":"string","example":"Lun-Vie 08-18","nullable":true},"manager":{"type":"string","example":"Juan Pérez","nullable":true},"sourceName":{"type":"string","example":"acopiove.org","nullable":true},"externalUpdatedAt":{"type":"string","example":"2026-06-27T00:00:00.000Z","description":"ISO 8601 date string","nullable":true},"country":{"type":"string","example":"Venezuela","description":"Country string as stored by the ingestion source (e.g. full Spanish name \"Venezuela\"). NOT guaranteed to be an ISO 3166-1 alpha-2 code — value depends on the source `pais` field.","nullable":true},"city":{"type":"string","example":"Caracas","nullable":true},"isFinalRecipient":{"type":"boolean","example":false,"description":"Whether this resource is a final recipient of aid"},"recipientType":{"type":"string","example":"hospital","nullable":true,"description":"Recipient type slug (see the emergency recipient-type taxonomy)"},"disputed":{"type":"boolean","example":false,"description":"Whether enough citizens have reported this point as invalid; it stays visible with an \"in review\" warning until a coordinator resolves it."},"disputedAt":{"type":"string","example":"2026-06-28T12:00:00.000Z","nullable":true,"description":"When the point was flagged as disputed (ISO 8601), or null"}},"required":["id","type","stage","name","description","location","verificationLevel","publicStatus","ownerOrganizationId","accepts","contact","schedule","manager","sourceName","externalUpdatedAt","country","city","isFinalRecipient","recipientType","disputed","disputedAt"]},"ReportResourceValidityDto":{"type":"object","properties":{"reason":{"type":"string","enum":["closed","nonexistent","moved","outdated"],"example":"closed","description":"Motivo: cerrado / ya no existe / se ha mudado / datos desactualizados"},"note":{"type":"string","description":"Detalle opcional aportado por el ciudadano","maxLength":1000},"photoUrls":{"description":"URLs de fotos de evidencia (subidas vía /files)","type":"array","items":{"type":"string"}}},"required":["reason"]},"ReportResourceValidityResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"disputed":{"type":"boolean","example":false,"description":"Whether this report pushed the resource over the threshold to disputed"}},"required":["id","disputed"]},"ResolveResourceDisputeDto":{"type":"object","properties":{"resolution":{"type":"string","enum":["confirm_closed","mark_invalid","dismiss"],"example":"confirm_closed","description":"confirm_closed = cerrar (reversible) · mark_invalid = marcar inválido (rejected, para \"ya no existe\") · dismiss = descartar (sigue activo)"},"reason":{"type":"string","description":"Motivo de la resolución (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Confirmado por teléfono con el responsable: el punto cerró."}},"required":["resolution","reason"]},"ValidityReportDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"resourceId":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"reporterUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","enum":["closed","nonexistent","moved","outdated"],"example":"closed"},"note":{"type":"string","nullable":true},"photoUrls":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["open","accepted","dismissed"],"example":"open"},"createdAt":{"type":"string","format":"date-time"},"resolvedByUserId":{"type":"string","format":"uuid","nullable":true},"resolvedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","resourceId","emergencyId","reporterUserId","reason","note","photoUrls","status","createdAt","resolvedByUserId","resolvedAt"]},"PagedResourcesDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ResourceViewDto"}},"total":{"type":"number","example":123},"page":{"type":"number","example":1},"limit":{"type":"number","example":50}},"required":["items","total","page","limit"]},"DisputedResourceDto":{"type":"object","properties":{"resource":{"$ref":"#/components/schemas/ResourceViewDto"},"distinctReporters":{"type":"number","example":3,"description":"Distinct citizens with an open report on this resource"},"byReason":{"type":"object","additionalProperties":{"type":"number"},"example":{"closed":2,"moved":1},"description":"Open-report counts keyed by reason"},"lastReportedAt":{"type":"string","format":"date-time","nullable":true}},"required":["resource","distinctReporters","byReason","lastReportedAt"]},"NearbyResourceViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"type":{"type":"string","enum":["collection_point","delivery_point","collection_and_delivery","warehouse","transport","supplier","venue"],"example":"collection_point"},"stage":{"type":"string","enum":["origin","intermediate","destination"],"example":"origin"},"name":{"type":"string","example":"Cruz Roja Madrid"},"description":{"type":"string","example":"Centro de acopio principal","nullable":true},"location":{"$ref":"#/components/schemas/LocationViewDto"},"verificationLevel":{"type":"string","enum":["unverified","verified","official","rejected"],"example":"verified"},"publicStatus":{"type":"string","enum":["hidden","active","saturated","paused","closed"],"example":"active"},"ownerOrganizationId":{"type":"string","format":"uuid","nullable":true},"accepts":{"example":["water","food"],"type":"array","items":{"type":"string"}},"contact":{"type":"string","example":"+58 212 555 0000","nullable":true},"schedule":{"type":"string","example":"Lun-Vie 08-18","nullable":true},"manager":{"type":"string","example":"Juan Pérez","nullable":true},"sourceName":{"type":"string","example":"acopiove.org","nullable":true},"externalUpdatedAt":{"type":"string","example":"2026-06-27T00:00:00.000Z","description":"ISO 8601 date string","nullable":true},"country":{"type":"string","example":"Venezuela","description":"Country string as stored by the ingestion source (e.g. full Spanish name \"Venezuela\"). NOT guaranteed to be an ISO 3166-1 alpha-2 code — value depends on the source `pais` field.","nullable":true},"city":{"type":"string","example":"Caracas","nullable":true},"isFinalRecipient":{"type":"boolean","example":false,"description":"Whether this resource is a final recipient of aid"},"recipientType":{"type":"string","example":"hospital","nullable":true,"description":"Recipient type slug (see the emergency recipient-type taxonomy)"},"disputed":{"type":"boolean","example":false,"description":"Whether enough citizens have reported this point as invalid; it stays visible with an \"in review\" warning until a coordinator resolves it."},"disputedAt":{"type":"string","example":"2026-06-28T12:00:00.000Z","nullable":true,"description":"When the point was flagged as disputed (ISO 8601), or null"},"distanceMeters":{"type":"number","example":1234,"description":"Distance from query point in meters (rounded)"}},"required":["id","type","stage","name","description","location","verificationLevel","publicStatus","ownerOrganizationId","accepts","contact","schedule","manager","sourceName","externalUpdatedAt","country","city","isFinalRecipient","recipientType","disputed","disputedAt","distanceMeters"]},"NearbyResourcesResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NearbyResourceViewDto"}}},"required":["items"]},"InBoundsResourcesDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ResourceViewDto"}}},"required":["items"]},"ResourceFacetsDto":{"type":"object","properties":{"byCategory":{"type":"object","example":{"water":5,"food":3}},"byCountry":{"type":"object","example":{"Venezuela":3,"Colombia":2},"description":"Counts keyed by the stored `country` string. Values mirror the ingestion source `pais` field (full Spanish names, NOT ISO 3166-1 alpha-2 codes)."},"total":{"type":"number","example":8}},"required":["byCategory","byCountry","total"]},"ResourceDetailViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"type":{"type":"string","enum":["collection_point","delivery_point","collection_and_delivery","warehouse","transport","supplier","venue"],"example":"collection_point"},"stage":{"type":"string","enum":["origin","intermediate","destination"],"example":"origin"},"name":{"type":"string","example":"Cruz Roja Madrid"},"description":{"type":"string","example":"Centro de acopio principal","nullable":true},"location":{"$ref":"#/components/schemas/LocationViewDto"},"verificationLevel":{"type":"string","enum":["unverified","verified","official","rejected"],"example":"verified"},"publicStatus":{"type":"string","enum":["hidden","active","saturated","paused","closed"],"example":"active"},"ownerOrganizationId":{"type":"string","format":"uuid","nullable":true},"accepts":{"example":["water","food"],"type":"array","items":{"type":"string"}},"contact":{"type":"string","example":"+58 212 555 0000","nullable":true},"schedule":{"type":"string","example":"Lun-Vie 08-18","nullable":true},"manager":{"type":"string","example":"Juan Pérez","nullable":true},"sourceName":{"type":"string","example":"acopiove.org","nullable":true},"externalUpdatedAt":{"type":"string","example":"2026-06-27T00:00:00.000Z","description":"ISO 8601 date string","nullable":true},"country":{"type":"string","example":"Venezuela","description":"Country string as stored by the ingestion source (e.g. full Spanish name \"Venezuela\"). NOT guaranteed to be an ISO 3166-1 alpha-2 code — value depends on the source `pais` field.","nullable":true},"city":{"type":"string","example":"Caracas","nullable":true},"isFinalRecipient":{"type":"boolean","example":false,"description":"Whether this resource is a final recipient of aid"},"recipientType":{"type":"string","example":"hospital","nullable":true,"description":"Recipient type slug (see the emergency recipient-type taxonomy)"},"disputed":{"type":"boolean","example":false,"description":"Whether enough citizens have reported this point as invalid; it stays visible with an \"in review\" warning until a coordinator resolves it."},"disputedAt":{"type":"string","example":"2026-06-28T12:00:00.000Z","nullable":true,"description":"When the point was flagged as disputed (ISO 8601), or null"},"inventoryCategories":{"example":["water","hygiene"],"description":"Distinct categories of material this place has declared","type":"array","items":{"type":"string"}}},"required":["id","type","stage","name","description","location","verificationLevel","publicStatus","ownerOrganizationId","accepts","contact","schedule","manager","sourceName","externalUpdatedAt","country","city","isFinalRecipient","recipientType","disputed","disputedAt","inventoryCategories"]},"RecipientTypeDto":{"type":"object","properties":{"slug":{"type":"string","example":"hospital"},"labelEs":{"type":"string","example":"Hospital"},"labelEn":{"type":"string","example":"Hospital"},"sort":{"type":"number","example":10}},"required":["slug","labelEs","labelEn","sort"]},"CreateTemplateDto":{"type":"object","properties":{"name":{"type":"string","example":"Terremoto básico","minLength":2},"description":{"type":"string","example":"Template para emergencias sísmicas de nivel moderado"},"dontBringList":{"example":["mascotas","joyas","vehículos grandes"],"description":"Items that volunteers should NOT bring","type":"array","items":{"type":"string"}},"defaultAnnouncement":{"type":"string","example":"No se aceptan mascotas en el centro de acopio.","nullable":true}},"required":["name","description","dontBringList"]},"CreateTemplateResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"}},"required":["id"]},"TemplateViewDto":{"type":"object","properties":{"id":{"type":"string","example":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"},"name":{"type":"string","example":"Terremoto básico"},"description":{"type":"string","example":"Template para emergencias sísmicas"},"dontBringList":{"example":["mascotas","joyas"],"type":"array","items":{"type":"string"}},"defaultAnnouncement":{"type":"string","example":"No se aceptan mascotas.","nullable":true},"createdAt":{"type":"string","example":"2026-06-27T10:00:00.000Z"}},"required":["id","name","description","dontBringList","defaultAnnouncement","createdAt"]},"CreateEmergencyDto":{"type":"object","properties":{"name":{"type":"string","example":"Emergencia sísmica — Venezuela","minLength":2},"slug":{"type":"string","example":"venezuela","description":"URL-safe slug (lowercase letters, digits, hyphens). Auto-generated from name if omitted.","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"country":{"type":"string","example":"VE","minLength":2,"description":"ISO 3166-1 alpha-2 country code"}},"required":["name","country"]},"CreateEmergencyResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"11111111-1111-4111-8111-111111111111"},"slug":{"type":"string","example":"venezuela"}},"required":["id","slug"]},"EmergencyViewDto":{"type":"object","properties":{"id":{"type":"string","example":"11111111-1111-4111-8111-111111111111"},"name":{"type":"string","example":"Emergencia sísmica — Venezuela"},"slug":{"type":"string","example":"venezuela"},"country":{"type":"string","example":"VE"},"status":{"type":"string","example":"active","enum":["active","paused","closed"]},"announcement":{"type":"string","example":"El puente de acceso norte está cortado.","nullable":true},"dontBringList":{"example":["mascotas","joyas","vehículos grandes"],"description":"Items volunteers should NOT bring to the emergency","type":"array","items":{"type":"string"}},"updatedAt":{"type":"string","example":"2026-06-25T10:00:00.000Z"}},"required":["id","name","slug","country","status","announcement","dontBringList","updatedAt"]},"MyEmergencyViewDto":{"type":"object","properties":{"id":{"type":"string","example":"11111111-1111-4111-8111-111111111111"},"name":{"type":"string","example":"Emergencia sísmica — Venezuela"},"slug":{"type":"string","example":"venezuela"},"country":{"type":"string","example":"VE"},"status":{"type":"string","example":"active","enum":["active","paused","closed"]},"announcement":{"type":"string","example":"El puente de acceso norte está cortado.","nullable":true},"dontBringList":{"example":["mascotas","joyas","vehículos grandes"],"description":"Items volunteers should NOT bring to the emergency","type":"array","items":{"type":"string"}},"updatedAt":{"type":"string","example":"2026-06-25T10:00:00.000Z"},"roleIds":{"example":["emergency_verifier","emergency_coordinator"],"description":"Role ids the principal holds at this emergency scope","type":"array","items":{"type":"string"}}},"required":["id","name","slug","country","status","announcement","dontBringList","updatedAt","roleIds"]},"CreateEmergencyFromTemplateDto":{"type":"object","properties":{"templateId":{"type":"string","example":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"},"name":{"type":"string","example":"Terremoto Valencia 2026","minLength":2},"slug":{"type":"string","example":"terremoto-valencia-2026","description":"URL-safe slug (lowercase letters, digits, hyphens)","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"country":{"type":"string","example":"ES","minLength":2}},"required":["templateId","name","slug","country"]},"PublishAnnouncementDto":{"type":"object","properties":{"message":{"type":"string","example":"Se suspenden las operaciones de rescate hasta nuevo aviso."}},"required":["message"]},"NeedLocationDto":{"type":"object","properties":{"address":{"type":"string","example":"123 Main Street, Caracas, Venezuela"},"latitude":{"type":"number","example":10.4806,"description":"Latitude (-90 to 90)"},"longitude":{"type":"number","example":-66.9036,"description":"Longitude (-180 to 180)"}},"required":["address","latitude","longitude"]},"CreateNeedDto":{"type":"object","properties":{"title":{"type":"string","example":"Alimentos para 50 familias","minLength":2},"description":{"type":"string","example":"Descripción detallada de la necesidad"},"location":{"$ref":"#/components/schemas/NeedLocationDto"},"priority":{"type":"string","enum":["low","medium","high","urgent"],"example":"high"},"requesterOrganizationId":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6","description":"Organization on whose behalf the request is made (optional)"},"items":{"description":"List of items needed (minimum 1)","minItems":1,"type":"array","items":{"$ref":"#/components/schemas/SupplyLineDto"}},"requiredSkill":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"],"example":"medical","description":"Required volunteer skill for personnel needs","nullable":true},"skillSpecialty":{"type":"string","example":"Médico urgencias pediátricas","description":"Free-text specialty detail (coordinator-only, not exposed publicly)","nullable":true},"requestedCount":{"type":"number","example":3,"description":"How many personnel are needed (>= 1)","nullable":true},"resourceId":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6","description":"Link this need to a resource / final recipient (#60). Optional.","nullable":true}},"required":["title","location","priority","items"]},"CreateNeedResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"required":["id"]},"NeedLocationResponseDto":{"type":"object","properties":{"address":{"type":"string","example":"123 Main Street, Caracas"},"latitude":{"type":"number","example":10.4806},"longitude":{"type":"number","example":-66.9036}},"required":["address","latitude","longitude"]},"SupplyLineResponseDto":{"type":"object","properties":{"name":{"type":"string","example":"Water bottles"},"quantity":{"type":"number","example":100},"unit":{"type":"string","example":"liters","nullable":true},"category":{"type":"string","enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"example":"water"},"presentation":{"type":"string","example":"ampolla","nullable":true,"description":"Presentation / route of administration (ampolla, EV, inhalador…) — #61."}},"required":["name","quantity","category"]},"NeedViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"emergencyId":{"type":"string","format":"uuid","example":"11111111-1111-4111-8111-111111111111"},"title":{"type":"string","example":"Alimentos para 50 familias"},"description":{"type":"string","example":"Descripción detallada","nullable":true},"location":{"$ref":"#/components/schemas/NeedLocationResponseDto"},"locationSensitivity":{"type":"string","enum":["public","approximate"],"example":"approximate","description":"When \"approximate\", the coordinates in location are jittered for privacy. Coordinators always receive exact coordinates regardless of this value."},"priority":{"type":"string","enum":["low","medium","high","urgent"],"example":"high"},"requesterOrganizationId":{"type":"string","format":"uuid","nullable":true},"managingOrganizationId":{"type":"string","format":"uuid","nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/SupplyLineResponseDto"}},"status":{"type":"string","enum":["pending","validated","rejected","fulfilled"],"example":"pending"},"createdAt":{"type":"string","example":"2024-01-01T00:00:00.000Z"},"expiresAt":{"type":"string","example":"2024-01-03T00:00:00.000Z","nullable":true,"description":"Timestamp when the need expires (48 h after validation). Null for legacy needs."},"lastVerifiedAt":{"type":"string","example":"2024-01-01T12:00:00.000Z","nullable":true,"description":"Timestamp when the need was last verified by a coordinator."},"requiredSkill":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"],"nullable":true,"description":"Required volunteer skill (personnel needs only)"},"requestedCount":{"type":"number","example":3,"nullable":true,"description":"Number of personnel needed"},"resourceId":{"type":"string","format":"uuid","nullable":true,"description":"Linked resource / final recipient id (#60), or null if standalone."}},"required":["id","emergencyId","title","location","locationSensitivity","priority","items","status","createdAt"]},"NearbyNeedViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"emergencyId":{"type":"string","format":"uuid","example":"11111111-1111-4111-8111-111111111111"},"title":{"type":"string","example":"Alimentos para 50 familias"},"description":{"type":"string","example":"Descripción detallada","nullable":true},"location":{"$ref":"#/components/schemas/NeedLocationResponseDto"},"locationSensitivity":{"type":"string","enum":["public","approximate"],"example":"approximate","description":"When \"approximate\", the coordinates in location are jittered for privacy. Coordinators always receive exact coordinates regardless of this value."},"priority":{"type":"string","enum":["low","medium","high","urgent"],"example":"high"},"requesterOrganizationId":{"type":"string","format":"uuid","nullable":true},"managingOrganizationId":{"type":"string","format":"uuid","nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/SupplyLineResponseDto"}},"status":{"type":"string","enum":["pending","validated","rejected","fulfilled"],"example":"pending"},"createdAt":{"type":"string","example":"2024-01-01T00:00:00.000Z"},"expiresAt":{"type":"string","example":"2024-01-03T00:00:00.000Z","nullable":true,"description":"Timestamp when the need expires (48 h after validation). Null for legacy needs."},"lastVerifiedAt":{"type":"string","example":"2024-01-01T12:00:00.000Z","nullable":true,"description":"Timestamp when the need was last verified by a coordinator."},"requiredSkill":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"],"nullable":true,"description":"Required volunteer skill (personnel needs only)"},"requestedCount":{"type":"number","example":3,"nullable":true,"description":"Number of personnel needed"},"resourceId":{"type":"string","format":"uuid","nullable":true,"description":"Linked resource / final recipient id (#60), or null if standalone."},"distanceMeters":{"type":"number","example":1850,"description":"Distance in meters from the queried location to the (public) need location."}},"required":["id","emergencyId","title","location","locationSensitivity","priority","items","status","createdAt","distanceMeters"]},"NearbyNeedsResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NearbyNeedViewDto"}}},"required":["items"]},"InBoundsNeedsDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NeedViewDto"}}},"required":["items"]},"EditNeedDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo de la edición (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Se corrige la prioridad y se completa la descripción"},"title":{"type":"string","description":"Nuevo título (omitir para no cambiarlo)","minLength":2},"description":{"type":"string","description":"Nueva descripción. Cadena vacía la borra. Omitir para no cambiarla.","nullable":true},"priority":{"type":"string","enum":["low","medium","high","urgent"],"description":"Nueva prioridad"}},"required":["reason"]},"DiscardNeedDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo del descarte (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Petición duplicada; ya validada en otra entrada"}},"required":["reason"]},"AssignNeedManagerDto":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6","description":"ID of the organization that will manage this need"}},"required":["organizationId"]},"VolunteerSuggestionDto":{"type":"object","properties":{"volunteerId":{"type":"string","format":"uuid","description":"Volunteer record ID"},"userId":{"type":"string","format":"uuid","description":"User account ID"},"name":{"type":"string","example":"Ana García"},"skills":{"description":"All volunteer skills","type":"array","items":{"type":"string"}},"hasVehicle":{"type":"boolean","description":"Whether the volunteer has any vehicle"},"availability":{"type":"string","description":"Volunteer availability level"}},"required":["volunteerId","userId","name","skills","hasVehicle","availability"]},"CreateTaskFromNeedDto":{"type":"object","properties":{"volunteerIds":{"description":"IDs of volunteers to assign to the task (optional)","type":"array","items":{"type":"string","format":"uuid"}},"dueDate":{"type":"string","example":"2025-12-31","description":"ISO date string for task due date (optional, informational)","nullable":true}}},"CreatedTaskFromNeedDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":"string"},"requiredSkill":{"type":"string","nullable":true,"enum":["driving","medical","logistics","cooking","languages","admin","general"]},"linkedNeedId":{"type":"string","nullable":true,"format":"uuid"},"status":{"type":"string"},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"assignments":{"type":"array","items":{"type":"object","properties":{"volunteerId":{"type":"string","format":"uuid"},"assignedAt":{"type":"string","format":"date-time"},"checkedInAt":{"type":"string","format":"date-time","nullable":true},"checkedOutAt":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string"}}}}},"required":["id","emergencyId","title","description","status","createdByUserId","createdAt","updatedAt","assignments"]},"CreateOrganizationDto":{"type":"object","properties":{"name":{"type":"string","example":"Red Cross Spain"},"type":{"type":"string","enum":["ngo","company","public_admin","association","transport_operator","other"],"example":"ngo"},"taxId":{"type":"string","example":"ES-12345678"},"contactEmail":{"type":"string","example":"contact@org.example"}},"required":["name","type"]},"CreateOrganizationResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"New organization UUID"}},"required":["id"]},"OrganizationViewDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["ngo","company","public_admin","association","transport_operator","other"]},"verificationLevel":{"type":"string"}},"required":["id","name","type","verificationLevel"]},"OrganizationMemberDto":{"type":"object","properties":{"userId":{"type":"string","description":"User UUID"},"email":{"type":"string","example":"member@example.com"},"name":{"type":"string","example":"Jane Doe"},"role":{"type":"string","enum":["owner","member"],"example":"member"}},"required":["userId","email","name","role"]},"AddMemberDto":{"type":"object","properties":{"email":{"type":"string","example":"member@example.com"}},"required":["email"]},"GrantAccreditationDto":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"Organization to accredit"},"scope":{"description":"Scope: \"global\" or { emergencyId: \"<uuid>\" }","oneOf":[{"type":"string","enum":["global"]},{"type":"object","properties":{"emergencyId":{"type":"string","format":"uuid"}},"required":["emergencyId"]}]},"evidence":{"type":"string","description":"Free-text evidence / justification"}},"required":["organizationId","scope"]},"AccreditationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"AccreditationViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"scope":{"type":"object"},"grantedByUserId":{"type":"string","format":"uuid"},"grantedAt":{"type":"string","description":"ISO 8601 timestamp"},"evidence":{"type":"object","nullable":true}},"required":["id","organizationId","scope","grantedByUserId","grantedAt"]},"GeocodeResultDto":{"type":"object","properties":{"address":{"type":"string","example":"Madrid, Community of Madrid, Spain"},"latitude":{"type":"number","example":40.4165,"description":"Decimal degrees latitude"},"longitude":{"type":"number","example":-3.70256,"description":"Decimal degrees longitude"}},"required":["address","latitude","longitude"]},"NeedsMetricsDto":{"type":"object","properties":{"total":{"type":"number","description":"Total needs registered for this emergency","example":10},"open":{"type":"number","description":"Open needs: pending + validated","example":7},"closed":{"type":"number","description":"Closed needs: fulfilled","example":2}},"required":["total","open","closed"]},"ResourcesMetricsDto":{"type":"object","properties":{"total":{"type":"number","description":"Total resources registered for this emergency","example":5},"active":{"type":"number","description":"Active logistic points (publicStatus = Active)","example":3},"pending":{"type":"number","description":"Resources pending publication (publicStatus = Hidden)","example":2}},"required":["total","active","pending"]},"EmergencyMetricsDto":{"type":"object","properties":{"needs":{"$ref":"#/components/schemas/NeedsMetricsDto"},"resources":{"$ref":"#/components/schemas/ResourcesMetricsDto"}},"required":["needs","resources"]},"OfferLocationDto":{"type":"object","properties":{"address":{"type":"string","example":"123 Main Street, Caracas, Venezuela"},"latitude":{"type":"number","example":10.4806,"description":"Latitude (-90 to 90)"},"longitude":{"type":"number","example":-66.9036,"description":"Longitude (-180 to 180)"}},"required":["address","latitude","longitude"]},"SubmitOfferDto":{"type":"object","properties":{"category":{"type":"string","enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"example":"food"},"description":{"type":"string","example":"Rice bags 25kg","description":"Description of the item being offered"},"quantity":{"type":"number","example":50,"description":"Quantity offered (positive integer)"},"unit":{"type":"string","example":"bags","description":"Unit of measurement"},"location":{"$ref":"#/components/schemas/OfferLocationDto"},"targetNeedId":{"type":"string","format":"uuid","description":"Target need this offer is directed at (optional)"},"donorOrganizationId":{"type":"string","format":"uuid","description":"Organization on whose behalf the offer is made (optional)"},"notes":{"type":"string","example":"Available for pickup Mon-Fri","description":"Additional notes (optional)"}},"required":["category","description","quantity","location"]},"SubmitOfferResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"required":["id"]},"OfferLocationResponseDto":{"type":"object","properties":{"address":{"type":"string","example":"123 Main Street, Caracas"},"latitude":{"type":"number","example":10.4806},"longitude":{"type":"number","example":-66.9036}},"required":["address","latitude","longitude"]},"OfferViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"donorUserId":{"type":"string","format":"uuid"},"donorOrganizationId":{"type":"string","format":"uuid","nullable":true},"category":{"type":"string","enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"example":"food"},"description":{"type":"string","example":"Rice bags 25kg"},"quantity":{"type":"number","example":50},"unit":{"type":"string","example":"bags","nullable":true},"location":{"$ref":"#/components/schemas/OfferLocationResponseDto"},"targetNeedId":{"type":"string","format":"uuid","nullable":true},"matchedNeedId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","enum":["open","matched","fulfilled","cancelled"],"example":"open"},"notes":{"type":"string","example":"Available Mon-Fri","nullable":true},"createdAt":{"type":"string","example":"2024-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2024-01-01T00:00:00.000Z"}},"required":["id","emergencyId","donorUserId","category","description","quantity","location","status","createdAt","updatedAt"]},"MatchOfferDto":{"type":"object","properties":{"needId":{"type":"string","format":"uuid","description":"The need to match this offer against"}},"required":["needId"]},"EditOfferDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo de la edición (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Se corrige la cantidad y se completa la descripción"},"description":{"type":"string","description":"Nueva descripción (omitir para no cambiarla)","minLength":2},"quantity":{"type":"number","example":20,"description":"Nueva cantidad (entero positivo). Omitir para no cambiarla."},"unit":{"type":"string","description":"Nueva unidad. Cadena vacía la borra. Omitir para no cambiarla.","nullable":true},"notes":{"type":"string","description":"Nuevas notas. Cadena vacía las borra. Omitir para no cambiarlas.","nullable":true}},"required":["reason"]},"DiscardOfferDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo del descarte (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Oferta duplicada; ya gestionada en otra entrada"}},"required":["reason"]},"CreateDonationIntakeDto":{"type":"object","properties":{"targetResourceId":{"type":"string","format":"uuid","description":"Target collection point"},"donorName":{"type":"string","example":"María López"},"donorPhone":{"type":"object","example":"+52 55 1234 5678","nullable":true},"donorEmail":{"type":"object","example":"maria@example.com","nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/SupplyLineDto"}}},"required":["targetResourceId","donorName","items"]},"CreateDonationIntakeResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"intakeCode":{"type":"string","example":"ACO-7F3K"},"status":{"type":"string","enum":["pending","received","rejected","incomplete"],"example":"pending"}},"required":["id","intakeCode","status"]},"LookupDonorByContactDto":{"type":"object","properties":{"donorPhone":{"type":"object","example":"+52 55 1234 5678","nullable":true},"donorEmail":{"type":"object","example":"maria@example.com","nullable":true}}},"PendingIntakeSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"intakeCode":{"type":"string","example":"ACO-7F3K"},"targetResourceId":{"type":"string","format":"uuid"},"itemCount":{"type":"number","example":2},"createdAt":{"type":"string","format":"date-time"}},"required":["id","intakeCode","targetResourceId","itemCount","createdAt"]},"LookupDonorByContactResponseDto":{"type":"object","properties":{"donorName":{"type":"string","example":"María López","nullable":true},"pendingIntakes":{"type":"array","items":{"$ref":"#/components/schemas/PendingIntakeSummaryDto"}}},"required":["pendingIntakes"]},"UpdateDonationIntakeDto":{"type":"object","properties":{"intakeCode":{"type":"string","example":"ACO-7F3K"},"donorName":{"type":"string","example":"María López"},"donorPhone":{"type":"object","example":"+52 55 1234 5678","nullable":true},"donorEmail":{"type":"object","example":"maria@example.com","nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/SupplyLineDto"}}},"required":["intakeCode","donorName","items"]},"IntakeLineViewDto":{"type":"object","properties":{"name":{"type":"string","example":"Water bottles"},"quantity":{"type":"number","example":100},"unit":{"type":"string","example":"liters","nullable":true},"category":{"type":"string","enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"example":"water"},"presentation":{"type":"string","example":"ampolla","nullable":true,"description":"Presentation / route of administration (ampolla, EV, inhalador…) — #61."},"id":{"type":"string","format":"uuid"},"sortOrder":{"type":"number"}},"required":["name","quantity","category","id","sortOrder"]},"DonationIntakeViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"targetResourceId":{"type":"string","format":"uuid"},"intakeCode":{"type":"string","example":"ACO-7F3K"},"status":{"type":"string","enum":["pending","received","rejected","incomplete"]},"donorName":{"type":"string"},"donorPhone":{"type":"string","nullable":true},"donorEmail":{"type":"string","nullable":true},"donorUserId":{"type":"string","format":"uuid","nullable":true},"lines":{"type":"array","items":{"$ref":"#/components/schemas/IntakeLineViewDto"}},"volunteerNotes":{"type":"string","nullable":true},"evidenceFileKey":{"type":"string","nullable":true},"receivedAt":{"type":"string","format":"date-time","nullable":true},"receivedByUserId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","emergencyId","targetResourceId","intakeCode","status","donorName","lines","createdAt","updatedAt"]},"DonationIntakeSearchHitDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"intakeCode":{"type":"string","example":"ACO-7F3K"},"donorName":{"type":"string"},"donorPhone":{"type":"string","nullable":true},"donorEmail":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","received","rejected","incomplete"]},"targetResourceId":{"type":"string","format":"uuid"},"itemCount":{"type":"number"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","intakeCode","donorName","status","targetResourceId","itemCount","createdAt"]},"ReceiveDonationIntakeDto":{"type":"object","properties":{"volunteerNotes":{"type":"string","nullable":true},"evidenceFileKey":{"type":"string","description":"File key from POST /files","nullable":true}}},"RejectDonationIntakeDto":{"type":"object","properties":{"volunteerNotes":{"type":"string","nullable":true}}},"MarkDonationIntakeIncompleteDto":{"type":"object","properties":{"volunteerNotes":{"type":"string","nullable":true}}},"PublishCapacityProviderDto":{"type":"object","properties":{"type":{"type":"string","enum":["volunteer","organization"],"example":"volunteer"},"id":{"type":"string","format":"uuid","description":"Volunteer or organization id (polymorphic, no FK)"}},"required":["type","id"]},"CapacityAmountDto":{"type":"object","properties":{"weightKg":{"type":"number","example":1500,"description":"Carrying weight in kilograms (positive)","nullable":true},"volumeM3":{"type":"number","example":12,"description":"Carrying volume in cubic metres (positive)","nullable":true}}},"CoverageDto":{"type":"object","properties":{"kind":{"type":"string","enum":["corridor","area"],"example":"corridor"},"originResourceId":{"type":"string","format":"uuid","description":"Corridor: origin collection point (resource) id"},"destinationResourceId":{"type":"string","format":"uuid","description":"Corridor: destination collection point (resource) id"},"originLat":{"type":"number","example":10.4806,"description":"Corridor: origin lat"},"originLng":{"type":"number","example":-66.9036,"description":"Corridor: origin lng"},"destinationLat":{"type":"number","example":10.6,"description":"Corridor: destination lat"},"destinationLng":{"type":"number","example":-67,"description":"Corridor: destination lng"},"area":{"type":"string","example":"Estado Vargas","description":"Area: free-text served area (required when kind=area)"}},"required":["kind"]},"CapacityWindowDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-07-01T00:00:00.000Z","description":"Availability start (ISO-8601)"},"to":{"type":"string","example":"2026-07-31T00:00:00.000Z","description":"Availability end (ISO-8601)"}}},"PublishCapacityDto":{"type":"object","properties":{"emergencyId":{"type":"string","format":"uuid","description":"Emergency this capacity serves"},"provider":{"$ref":"#/components/schemas/PublishCapacityProviderDto"},"mode":{"type":"string","enum":["road","sea","air"],"example":"road"},"capacity":{"description":"At least one of weightKg / volumeM3 is required","allOf":[{"$ref":"#/components/schemas/CapacityAmountDto"}]},"coverage":{"$ref":"#/components/schemas/CoverageDto"},"window":{"$ref":"#/components/schemas/CapacityWindowDto"},"constraints":{"example":["refrigerated","hazmat"],"description":"Free-form constraints","type":"array","items":{"type":"string"}},"notes":{"type":"string","example":"Salida diaria a las 08:00","description":"Additional notes"}},"required":["emergencyId","provider","mode","capacity","coverage"]},"PublishCapacityResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"required":["id"]},"CapacityAmountResponseDto":{"type":"object","properties":{"weightKg":{"type":"number","example":1500,"nullable":true},"volumeM3":{"type":"number","example":12,"nullable":true}}},"CoverageResponseDto":{"type":"object","properties":{"kind":{"type":"string","enum":["corridor","area"],"example":"corridor"},"originResourceId":{"type":"string","format":"uuid","nullable":true},"destinationResourceId":{"type":"string","format":"uuid","nullable":true},"originLat":{"type":"number","example":10.4806,"nullable":true},"originLng":{"type":"number","example":-66.9036,"nullable":true},"destinationLat":{"type":"number","example":10.6,"nullable":true},"destinationLng":{"type":"number","example":-67,"nullable":true},"area":{"type":"string","example":"Estado Vargas"}},"required":["kind"]},"CapacityWindowResponseDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-07-01T00:00:00.000Z","nullable":true},"to":{"type":"string","example":"2026-07-31T00:00:00.000Z","nullable":true}}},"CapacityViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"providerType":{"type":"string","enum":["volunteer","organization"],"example":"volunteer"},"providerId":{"type":"string","format":"uuid"},"mode":{"type":"string","enum":["road","sea","air"],"example":"road"},"capacity":{"$ref":"#/components/schemas/CapacityAmountResponseDto"},"coverage":{"$ref":"#/components/schemas/CoverageResponseDto"},"window":{"$ref":"#/components/schemas/CapacityWindowResponseDto"},"constraints":{"example":["refrigerated"],"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["available","reserved","withdrawn"],"example":"available"},"notes":{"type":"string","example":"Salida diaria a las 08:00","nullable":true},"createdAt":{"type":"string","example":"2026-07-01T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-07-01T00:00:00.000Z"}},"required":["id","emergencyId","providerType","providerId","mode","capacity","coverage","window","constraints","status","createdAt","updatedAt"]},"ShipmentItemDto":{"type":"object","properties":{"description":{"type":"string","example":"5 cajas de agua","description":"What moves"},"quantity":{"type":"number","example":5,"description":"How much (positive). Optional — cargo is often loose.","nullable":true},"unit":{"type":"string","example":"cajas","nullable":true},"category":{"type":"string","enum":["food","water","hygiene","clothing","medical","shelter","tools","other","medicines","medical_equipment","medical_supplies","medical_personnel"],"example":"food","description":"Shared category taxonomy (optional — cargo may be loose)"}},"required":["description"]},"CreateShipmentDto":{"type":"object","properties":{"emergencyId":{"type":"string","format":"uuid","description":"Emergency this shipment serves"},"originResourceId":{"type":"string","format":"uuid","description":"Origin resource node (collection point) id"},"destinationResourceId":{"type":"string","format":"uuid","description":"Destination resource node id"},"items":{"description":"Cargo manifest lines (at least one)","type":"array","items":{"$ref":"#/components/schemas/ShipmentItemDto"}},"manifest":{"type":"string","example":"Carga frágil, manipular con cuidado","description":"Free-text cargo manifest note"}},"required":["emergencyId","originResourceId","destinationResourceId","items"]},"CreateShipmentResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"required":["id"]},"AssignShipmentCarrierDto":{"type":"object","properties":{"type":{"type":"string","enum":["volunteer","organization"],"example":"volunteer"},"id":{"type":"string","format":"uuid","description":"Volunteer or organization id (polymorphic, no FK)"}},"required":["type","id"]},"AssignCapacityToShipmentDto":{"type":"object","properties":{"assignedCapacityId":{"type":"string","format":"uuid","description":"TransportCapacity (#105) to earmark for this shipment"},"carrier":{"description":"Optional carrier. Omit for an internal inventory transfer (no carrier).","allOf":[{"$ref":"#/components/schemas/AssignShipmentCarrierDto"}]}},"required":["assignedCapacityId"]},"ShipmentItemResponseDto":{"type":"object","properties":{"description":{"type":"string","example":"5 cajas de agua"},"quantity":{"type":"number","example":5,"nullable":true},"unit":{"type":"string","example":"cajas","nullable":true},"category":{"type":"string","example":"alimentacion","nullable":true}},"required":["description"]},"ShipmentViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"originResourceId":{"type":"string","format":"uuid"},"destinationResourceId":{"type":"string","format":"uuid"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ShipmentItemResponseDto"}},"assignedCapacityId":{"type":"string","format":"uuid","nullable":true},"carrierType":{"type":"string","enum":["volunteer","organization"],"nullable":true,"example":"volunteer"},"carrierId":{"type":"string","format":"uuid","nullable":true},"manifest":{"type":"string","example":"Carga frágil","nullable":true},"status":{"type":"string","enum":["planned","assigned","in_transit","delivered","failed","cancelled"],"example":"planned"},"createdAt":{"type":"string","example":"2026-07-01T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-07-01T00:00:00.000Z"}},"required":["id","emergencyId","originResourceId","destinationResourceId","items","status","createdAt","updatedAt"]},"RegisterVolunteerDto":{"type":"object","properties":{"name":{"type":"string","example":"Ana García","minLength":2},"contact":{"type":"string","example":"ana@example.com"},"municipality":{"type":"string","example":"Valencia"},"skills":{"type":"array","example":["medical","driving"],"items":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"]}},"availability":{"type":"string","enum":["immediate","this_week","flexible"],"example":"immediate"},"vehicle":{"type":"string","enum":["none","car","van","truck"],"example":"car"},"consentAccepted":{"type":"boolean","example":true,"description":"Must be true to register as a volunteer"}},"required":["name","contact","municipality","skills","availability","vehicle","consentAccepted"]},"RegisterVolunteerResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"VolunteerViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"contact":{"type":"string"},"municipality":{"type":"string"},"skills":{"type":"array","items":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"]}},"availability":{"type":"string","enum":["immediate","this_week","flexible"]},"vehicle":{"type":"string","enum":["none","car","van","truck"]},"status":{"type":"string","enum":["available","assigned","inactive"]},"consentAccepted":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","emergencyId","userId","name","contact","municipality","skills","availability","vehicle","status","consentAccepted","createdAt","updatedAt"]},"UpdateVolunteerStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["available","assigned","inactive"],"example":"assigned"}},"required":["status"]},"CreateTaskDto":{"type":"object","properties":{"title":{"type":"string","example":"Deliver supplies to zone 3"},"description":{"type":"string","example":"Transport 200 water bottles to the distribution point"},"location":{"$ref":"#/components/schemas/LocationDto"},"requiredSkill":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"]}},"required":["title","description"]},"CreateTaskResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"TaskLocationDto":{"type":"object","properties":{"address":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"}},"required":["address","latitude","longitude"]},"TaskAssignmentViewDto":{"type":"object","properties":{"volunteerId":{"type":"string","format":"uuid"},"volunteerName":{"type":"string","nullable":true},"assignedAt":{"format":"date-time","type":"string"},"checkedInAt":{"type":"string","nullable":true,"format":"date-time"},"checkedOutAt":{"type":"string","nullable":true,"format":"date-time"},"status":{"type":"string","enum":["assigned","checked_in","checked_out"]}},"required":["volunteerId","assignedAt","status"]},"TaskViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":"string"},"location":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/TaskLocationDto"}]},"requiredSkill":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"],"nullable":true},"status":{"type":"string","enum":["open","in_progress","completed","cancelled"]},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"assignments":{"type":"array","items":{"$ref":"#/components/schemas/TaskAssignmentViewDto"}}},"required":["id","emergencyId","title","description","status","createdByUserId","createdAt","updatedAt","assignments"]},"MyTaskViewDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emergencyId":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":"string"},"location":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/TaskLocationDto"}]},"requiredSkill":{"type":"string","enum":["driving","medical","logistics","cooking","languages","admin","general"],"nullable":true},"status":{"type":"string","enum":["open","in_progress","completed","cancelled"]},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"assignments":{"type":"array","items":{"$ref":"#/components/schemas/TaskAssignmentViewDto"}},"myAssignmentStatus":{"type":"string","enum":["assigned","checked_in","checked_out"]}},"required":["id","emergencyId","title","description","status","createdByUserId","createdAt","updatedAt","assignments","myAssignmentStatus"]},"AssignVolunteerDto":{"type":"object","properties":{"volunteerId":{"type":"string","format":"uuid"}},"required":["volunteerId"]},"SubmitReportDto":{"type":"object","properties":{"type":{"type":"string","enum":["incident","stock","status","other"]},"note":{"type":"string","example":"Road blocked near bridge"},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"photoUrls":{"description":"URLs from POST /files (e.g. /files/key.png)","type":"array","items":{"type":"string"}},"resourceId":{"type":"string","description":"Resource ID this report refers to"},"location":{"$ref":"#/components/schemas/LocationDto"}},"required":["type","note","priority"]},"EditReportDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo de la edición (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Se corrige la prioridad y se completa la nota"},"note":{"type":"string","description":"Nueva nota (omitir para no cambiarla)","minLength":2},"priority":{"type":"string","enum":["low","medium","high","urgent"],"description":"Nueva prioridad"}},"required":["reason"]},"DiscardReportDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo del descarte (obligatorio, para trazabilidad)","minLength":3,"maxLength":1000,"example":"Reporte duplicado; ya registrado en otra entrada"}},"required":["reason"]},"AuditChangeDto":{"type":"object","properties":{"field":{"type":"string","description":"Name of the field that changed"},"before":{"type":"object","description":"Value before the change (any JSON type)","nullable":true},"after":{"type":"object","description":"Value after the change (any JSON type)","nullable":true}},"required":["field"]},"AuditEntryDto":{"type":"object","properties":{"id":{"type":"string"},"actorUserId":{"type":"string","nullable":true},"actorName":{"type":"string","nullable":true,"description":"Actor display name captured at write time"},"action":{"type":"string"},"entityType":{"type":"string","nullable":true},"entityId":{"type":"string","nullable":true},"emergencyId":{"type":"string","nullable":true},"method":{"type":"string"},"path":{"type":"string"},"statusCode":{"type":"number"},"reason":{"type":"string","nullable":true,"description":"Mandatory reason for edit/discard actions"},"changes":{"nullable":true,"description":"Before/after field changes for edit actions","type":"array","items":{"$ref":"#/components/schemas/AuditChangeDto"}},"targetStatus":{"type":"string","nullable":true,"description":"State the entity transitioned to (e.g. rejected)"},"createdAt":{"format":"date-time","type":"string"}},"required":["id","action","method","path","statusCode","createdAt"]},"AuditListResponseDto":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/AuditEntryDto"}},"total":{"type":"number"}},"required":["entries","total"]},"MyGroupResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"ownerKind":{"type":"string","enum":["organization","emergency"]},"ownerId":{"type":"string","format":"uuid"},"parentGroupId":{"type":"object","format":"uuid","nullable":true},"createdAt":{"type":"string"},"membershipStatus":{"type":"string","enum":["pending","approved"]}},"required":["id","name","visibility","ownerKind","ownerId","parentGroupId","createdAt","membershipStatus"]},"GroupResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"ownerKind":{"type":"string","enum":["organization","emergency"]},"ownerId":{"type":"string","format":"uuid"},"parentGroupId":{"type":"object","format":"uuid","nullable":true},"createdAt":{"type":"string"}},"required":["id","name","visibility","ownerKind","ownerId","parentGroupId","createdAt"]},"CreateGroupDto":{"type":"object","properties":{"name":{"type":"string","description":"Group/cuadrilla name"},"visibility":{"type":"string","enum":["public","private"]},"ownerKind":{"type":"string","enum":["organization","emergency"],"description":"Whether the group hangs off an organization or an emergency"},"ownerId":{"type":"string","format":"uuid","description":"Id of the owning org/emergency"},"parentGroupId":{"type":"string","format":"uuid","description":"Parent group (nesting)"}},"required":["name","visibility","ownerKind","ownerId"]},"IdResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"GroupMemberResponseDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","approved"]},"addedByUserId":{"type":"object","format":"uuid","nullable":true}},"required":["userId","status","addedByUserId"]},"AddMemberByEmailDto":{"type":"object","properties":{"email":{"type":"string","description":"Email of the user to add (must already exist)"}},"required":["email"]},"AssignManagerDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","description":"Member to appoint as manager"}},"required":["userId"]},"CategoryDto":{"type":"object","properties":{"slug":{"type":"string","example":"medicines"},"labelEs":{"type":"string","example":"Medicamentos"},"labelEn":{"type":"string","example":"Medicines"},"parentSlug":{"type":"string","example":"medical","nullable":true,"description":"Parent category slug, or null for a top-level category"},"vertical":{"type":"string","example":"general"},"sort":{"type":"number","example":41,"description":"Display sort order"}},"required":["slug","labelEs","labelEn","parentSlug","vertical","sort"]}}}}