{"openapi":"3.1.0","info":{"title":"Tá Resolvido — API","version":"1.0.0","summary":"Zeladoria urbana e ouvidoria digital para prefeituras","description":"API REST da plataforma **Tá Resolvido** (CM3 Soluções Tecnológicas) para integração com sistemas municipais: protocolo, SEI, BI, portais de transparência, chatbots e o próprio aplicativo do cidadão.\n\n### Autenticação\nObtenha um JWT em `POST /auth/login` e envie em `Authorization: Bearer <token>`. O painel web usa o mesmo token no cookie `tr_token`.\n\n### Multi-município (tenant)\nToda rota marcada com `X-Municipio` precisa saber a cidade: header `X-Municipio: <slug>`, query `?municipio=<slug>` ou o subdomínio `<slug>.taresolvido.app.br`. Dados de um município nunca aparecem nas respostas de outro.\n\n### Paginação e erros\nListas paginam por `page`/`perPage` (ou `pagina`) e trazem `total`. Erros vêm sempre como `{ \"erro\": \"mensagem\", \"detalhes\": ... }` — 400 corpo inválido, 401 sem login, 403 sem permissão, 404 não encontrado, 409 conflito (ex.: transição de status inválida), 422 dados inválidos (com erros por campo), 429 limite de requisições.","contact":{"name":"CM3 Soluções Tecnológicas","email":"contato@taresolvido.app.br","url":"https://taresolvido.app.br"},"license":{"name":"Uso conforme contrato com a prefeitura","identifier":"LicenseRef-Contrato"},"x-slogan":"Sua cidade melhor, todo dia."},"servers":[{"url":"https://coari.taresolvido.app.br/api/v1","description":"Esta instalação"},{"url":"https://{municipio}.taresolvido.app.br/api/v1","description":"Produção — edição do município (o subdomínio define o tenant)","variables":{"municipio":{"default":"manaus","description":"slug do município"}}},{"url":"https://taresolvido.app.br/api/v1","description":"Produção — domínio raiz (informe `X-Municipio`)"},{"url":"http://localhost:3000/api/v1","description":"Desenvolvimento local"}],"tags":[{"name":"Autenticação","description":"Cadastro, login e sessão. O JWT vai em `Authorization: Bearer <token>`."},{"name":"Municípios","description":"Catálogo público das cidades atendidas e sua configuração (categorias, órgãos, bairros)."},{"name":"Ocorrências","description":"Zeladoria urbana e manifestações de ouvidoria (Lei 13.460/2017): registro, acompanhamento, apoio, avaliação e gestão."},{"name":"Uploads","description":"Envio de fotos direto ao bucket (S3/MinIO) com URL assinada."},{"name":"Dispositivos","description":"Tokens de notificação push (Expo)."},{"name":"Dashboard","description":"Indicadores executivos para prefeito e gestores."},{"name":"Administração","description":"Cadastros e configuração pelo administrador municipal (ADMIN): órgãos, categorias, bairros, usuários, município, auditoria e exportação integral."},{"name":"Relatórios","description":"PDF/CSV gerenciais, relatório executivo mensal e relatório anual de ouvidoria (Lei 13.460/2017)."},{"name":"Dados abertos","description":"Portal de transparência: dados anonimizados em formato aberto."},{"name":"WhatsApp","description":"Webhook da Meta Cloud API para abertura de ocorrências por WhatsApp."},{"name":"Alertas","description":"Tarefa agendada de alertas de SLA e de repercussão ao gestor executivo (push)."},{"name":"Site","description":"Formulários do site institucional."},{"name":"Infraestrutura","description":"Rotas de uso interno da operação (proxy e certificados), não destinadas a integração."},{"name":"Documentação","description":"Este documento."}],"security":[{"bearerAuth":[]}],"paths":{"/auth/registro":{"post":{"operationId":"postAuthRegistro","tags":["Autenticação"],"summary":"Cadastro do cidadão","description":"Cria a conta (e-mail ou telefone + senha) e envia um código de 6 dígitos pelo canal informado. A conta só entra depois de `POST /auth/verificar`.\n\nAcesso público (sem token).","parameters":[],"responses":{"201":{"description":"Código enviado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verificacao"}}}},"409":{"description":"Já existe conta com este e-mail ou telefone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":3,"maxLength":120},"email":{"type":"string","format":"email"},"telefone":{"type":"string","pattern":"^\\d{10,11}$"},"senha":{"type":"string","minLength":6,"maxLength":72}},"required":["nome","senha"]}}}},"security":[],"x-acesso":"publica"}},"/auth/verificar":{"post":{"operationId":"postAuthVerificar","tags":["Autenticação"],"summary":"Confirmar o código do cadastro","description":"Marca o contato como verificado e devolve a sessão (mesmo formato do login), gravando também o cookie do painel.\n\nAcesso público (sem token).","parameters":[],"responses":{"200":{"description":"Sessão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Sessao"}}}},"400":{"description":"Código inválido, expirado ou com tentativas esgotadas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destino":{"type":"string","minLength":5,"maxLength":160},"codigo":{"type":"string","maxLength":6,"minLength":6},"senha":{"type":"string","minLength":6,"maxLength":72},"nome":{"type":"string","minLength":3,"maxLength":120}},"required":["destino","codigo"]}}}},"security":[],"x-acesso":"publica"}},"/auth/reenviar":{"post":{"operationId":"postAuthReenviar","tags":["Autenticação"],"summary":"Reenviar o código do cadastro","description":"Intervalo mínimo de 60 s entre envios para o mesmo contato (429 com `detalhes.aguardeSegundos`).\n\nAcesso público (sem token).","parameters":[],"responses":{"200":{"description":"Código reenviado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verificacao"}}}},"404":{"description":"Conta não encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Contato já confirmado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Muitas requisições","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destino":{"type":"string","minLength":5,"maxLength":160}},"required":["destino"]}}}},"security":[],"x-acesso":"publica"}},"/auth/login":{"post":{"operationId":"postAuthLogin","tags":["Autenticação"],"summary":"Login (e-mail ou telefone + senha)","description":"Devolve o JWT para o header `Authorization: Bearer` e grava o cookie `tr_token` do painel web. Conta com verificação em duas etapas ativa recebe `{exige2fa, tokenParcial}` e conclui em `POST /auth/2fa`. Conta ainda não confirmada recebe 403 com `detalhes.verificacaoPendente` (o código é reenviado).\n\nAcesso público (sem token).","parameters":[],"responses":{"200":{"description":"Sessão, ou pedido da segunda etapa","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Sessao"},{"$ref":"#/components/schemas/Sessao2fa"}]}}}},"401":{"description":"Login ou senha incorretos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Conta desativada ou contato não confirmado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"login":{"type":"string","minLength":3},"senha":{"type":"string","minLength":1}},"required":["login","senha"]}}}},"security":[],"x-acesso":"publica"}},"/auth/2fa":{"post":{"operationId":"postAuth2fa","tags":["Autenticação"],"summary":"Segunda etapa do login (TOTP ou código de recuperação)","description":"Troca o `tokenParcial` do login pelo token definitivo. `metodo` indica se foi usado o autenticador (`totp`) ou um código de recuperação (`recuperacao`, com `codigosRecuperacaoRestantes`).\n\nAcesso público (sem token).","parameters":[],"responses":{"200":{"description":"Sessão","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Sessao"},{"type":"object","properties":{"metodo":{"type":"string","enum":["totp","recuperacao"]},"codigosRecuperacaoRestantes":{"type":"integer"}}}]}}}},"401":{"description":"Código inválido ou etapa expirada (`detalhes.tokenParcialExpirado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conta sem 2FA ativa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tokenParcial":{"type":"string","minLength":20},"codigo":{"type":"string","pattern":"^(\\d{6}|[A-Z0-9]{8})$"}},"required":["tokenParcial","codigo"]}}}},"security":[],"x-acesso":"publica"}},"/auth/me":{"get":{"operationId":"getAuthMe","tags":["Autenticação"],"summary":"Usuário autenticado","description":"Exige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"Usuário e papéis por município","content":{"application/json":{"schema":{"type":"object","properties":{"usuario":{"$ref":"#/components/schemas/Usuario"}}}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"},"delete":{"operationId":"deleteAuthMe","tags":["Autenticação"],"summary":"Sair (painel web)","description":"Apaga o cookie de sessão do painel. O token Bearer do app basta ser descartado.\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"Sessão encerrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/auth/senha":{"post":{"operationId":"postAuthSenha","tags":["Autenticação"],"summary":"Trocar a senha","description":"Senha atual + nova senha. Contas criadas pelo gov.br (sem senha) definem a primeira senha sem informar a atual. Auditado (SENHA_ALTERADA) para gestores.\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"Senha alterada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Senha atual incorreta","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"senhaAtual":{"type":"string","maxLength":72},"novaSenha":{"type":"string","minLength":8,"maxLength":72}},"required":["novaSenha"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/auth/totp/gerar":{"post":{"operationId":"postAuthTotpGerar","tags":["Autenticação"],"summary":"Gerar o segredo TOTP (QR code)","description":"Cria o segredo para o aplicativo autenticador. Só passa a valer após `POST /auth/totp/ativar` com um código correto.\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"QR code e segredo manual","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Totp"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"2FA já ativa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/auth/totp/ativar":{"post":{"operationId":"postAuthTotpAtivar","tags":["Autenticação"],"summary":"Ativar a verificação em duas etapas","description":"Confere o primeiro código do autenticador e devolve 8 códigos de recuperação (mostrados uma única vez).\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"2FA ativada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TotpAtivado"}}}},"400":{"description":"Código incorreto ou segredo não gerado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"2FA já ativa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"codigo":{"type":"string","maxLength":6,"minLength":6}},"required":["codigo"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/auth/totp/desativar":{"post":{"operationId":"postAuthTotpDesativar","tags":["Autenticação"],"summary":"Desativar a verificação em duas etapas","description":"Exige a senha e um código válido (autenticador ou recuperação).\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"2FA desativada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Senha ou código inválidos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"2FA não está ativa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"senha":{"type":"string","minLength":1},"codigo":{"type":"string","pattern":"^(\\d{6}|[A-Z0-9]{8})$"}},"required":["senha","codigo"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/auth/govbr/iniciar":{"get":{"operationId":"getAuthGovbrIniciar","tags":["Autenticação"],"summary":"Iniciar login com gov.br (OpenID Connect)","description":"Gera state/nonce/PKCE em cookie assinado e redireciona ao gov.br. Com `GOVBR_AMBIENTE=simulado` exibe uma página de simulação. `retorno` define para onde o usuário volta (app por deep link, painel ou web).\n\nAcesso público (sem token).","parameters":[{"name":"retorno","in":"query","required":false,"schema":{"type":"string","enum":["app","painel","web"],"default":"painel"}},{"name":"m","in":"query","required":false,"schema":{"type":"string","maxLength":60}},{"name":"destino","in":"query","required":false,"schema":{"type":"string","maxLength":300}},{"name":"voltar","in":"query","required":false,"schema":{"type":"string","maxLength":200,"pattern":"^\\/[^\\s]*$"}}],"responses":{"200":{"description":"Página de simulação (ambiente simulado)","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"302":{"description":"Redirecionamento ao gov.br"},"503":{"description":"gov.br não configurado neste ambiente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/auth/govbr/callback":{"get":{"operationId":"getAuthGovbrCallback","tags":["Autenticação"],"summary":"Retorno do gov.br","description":"Troca o `code` pelos tokens, valida o `id_token`, vincula (por CPF/e-mail) ou cria a conta e redireciona ao destino com `token` (ou `tokenParcial` quando a conta tem 2FA).\n\nAcesso público (sem token).","parameters":[{"name":"code","in":"query","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string"}},{"name":"error","in":"query","schema":{"type":"string"}}],"responses":{"302":{"description":"Redirecionamento ao destino (app, painel ou web) com o token"}},"security":[],"x-acesso":"publica"}},"/auth/social/{provedor}/iniciar":{"get":{"operationId":"getAuthSocialProvedorIniciar","tags":["Autenticação"],"summary":"Iniciar login social (Google, Apple ou Facebook)","description":"Gera state/nonce/PKCE (S256 no Google e na Apple) em cookie httpOnly assinado por provedor (`tr_social_<provedor>`, 10 min) e redireciona ao provedor. Sem credenciais, e apenas FORA de um ambiente público (`NODE_ENV=production` ou `AUTH_BASE_URL` https), exibe a tela de simulação de demonstração; em ambiente público responde 503 a menos que `AUTH_SOCIAL_SIMULADO=1`. `retorno` define o destino: `app` (deep link `taresolvido://social`), `painel` (cookie `tr_token`) ou `web` (exige `url` com uma origem da lista permitida). Limite de 20 pedidos por minuto por IP. Com o provedor configurado, um pedido chegando por outro host é redirecionado uma vez para o mesmo caminho em `AUTH_BASE_URL` (`base=1`), porque o cookie de estado é host-only.\n\nAcesso público (sem token).","parameters":[{"name":"provedor","in":"path","required":true,"schema":{"type":"string","enum":["google","apple","facebook"]},"description":"Provedor de identidade"},{"name":"retorno","in":"query","required":false,"schema":{"type":"string","enum":["app","painel","web"],"default":"app"}},{"name":"url","in":"query","required":false,"schema":{"type":"string","maxLength":300}},{"name":"m","in":"query","required":false,"schema":{"type":"string","maxLength":60}},{"name":"destino","in":"query","required":false,"schema":{"type":"string","maxLength":300}},{"name":"voltar","in":"query","required":false,"schema":{"type":"string","maxLength":200,"pattern":"^\\/[^\\s]*$"}},{"name":"base","in":"query","required":false,"schema":{"type":"string","maxLength":4}}],"responses":{"302":{"description":"Redirecionamento ao provedor, à tela de simulação ou ao host canônico"},"400":{"description":"Origem de retorno (`url`) fora da lista permitida, ou parâmetros inválidos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Provedor desconhecido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Muitas tentativas a partir do mesmo IP","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"503":{"description":"Provedor não configurado neste ambiente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/auth/social/{provedor}/callback":{"get":{"operationId":"getAuthSocialProvedorCallback","tags":["Autenticação"],"summary":"Retorno do provedor social","description":"Confere o cookie assinado e o `state` (tempo constante), troca o `code` pelo perfil (validando o `id_token` e o `nonce` no Google e na Apple), aplica a política de vínculo e redireciona ao destino com `token` (ou `tokenParcial` quando a conta tem 2FA, ou `erro` + `motivo`). No modo simulado o `code` é um JWS assinado com o `JWT_SECRET` e amarrado ao `state` daquele fluxo. Limite de 10 pedidos por minuto por IP.\n\nAcesso público (sem token).","parameters":[{"name":"provedor","in":"path","required":true,"schema":{"type":"string","enum":["google","apple","facebook"]}},{"name":"code","in":"query","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string"}},{"name":"error","in":"query","schema":{"type":"string"}}],"responses":{"302":{"description":"Redirecionamento ao destino (app, painel ou web)"},"400":{"description":"Página de erro (cookie de estado ausente ou vencido)","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Provedor desconhecido","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"429":{"description":"Muitas tentativas a partir do mesmo IP","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}}},"security":[],"x-acesso":"publica"},"post":{"operationId":"postAuthSocialProvedorCallback","tags":["Autenticação"],"summary":"Retorno do provedor social (form_post da Apple)","description":"A Apple devolve o callback por POST `application/x-www-form-urlencoded` (`response_mode=form_post`), com `code`, `state` e — só na primeira autorização — o campo `user`, de onde é aproveitado apenas o NOME (o campo não é assinado; o e-mail sai da claim do `id_token`). Mesmo tratamento do GET.\n\nAcesso público (sem token).","parameters":[{"name":"provedor","in":"path","required":true,"schema":{"type":"string","enum":["google","apple","facebook"]}}],"responses":{"302":{"description":"Redirecionamento ao destino (app, painel ou web)"},"400":{"description":"Página de erro (cookie de estado ausente ou vencido)","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"429":{"description":"Muitas tentativas a partir do mesmo IP","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}}},"security":[],"x-acesso":"publica"}},"/auth/social/{provedor}/simular":{"get":{"operationId":"getAuthSocialProvedorSimular","tags":["Autenticação"],"summary":"Tela de simulação do provedor (demonstração)","description":"Só existe quando o provedor não tem credenciais e o ambiente não é público. Formulário com nome, e-mail e “e-mail verificado pelo provedor” (ausente no Facebook, que nunca confirma e-mail) que segue para o mesmo callback, com a mesma auditoria. Limite da simulação: nunca entra nem vincula conta que já existe — só cria conta nova e reentra nela. Limite de 10 pedidos por minuto por IP.\n\nAcesso público (sem token).","parameters":[{"name":"provedor","in":"path","required":true,"schema":{"type":"string","enum":["google","apple","facebook"]}},{"name":"state","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Formulário de simulação","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Sessão da simulação expirada","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Provedor configurado de verdade, ou simulação indisponível neste ambiente","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"429":{"description":"Muitas tentativas a partir do mesmo IP","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}}},"security":[],"x-acesso":"publica"},"post":{"operationId":"postAuthSocialProvedorSimular","tags":["Autenticação"],"summary":"Enviar a simulação","description":"Valida os campos e redireciona (303) ao callback com um `code` assinado (JWS HS256, amarrado ao `state`, 10 min) que carrega o perfil simulado.\n\nAcesso público (sem token).","parameters":[{"name":"provedor","in":"path","required":true,"schema":{"type":"string","enum":["google","apple","facebook"]}}],"responses":{"200":{"description":"Formulário com erro de validação","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"303":{"description":"Redirecionamento ao callback"},"400":{"description":"Sessão da simulação expirada","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"429":{"description":"Muitas tentativas a partir do mesmo IP","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}}},"security":[],"x-acesso":"publica"}},"/auth/identidades":{"get":{"operationId":"getAuthIdentidades","tags":["Autenticação"],"summary":"Contas externas vinculadas","description":"Lista as identidades sociais da conta logada (provedor, e-mail informado, quando vinculou, último login) com `formasDeEntrar`, `temSenha`, `govbrVinculado` e os provedores disponíveis no servidor. Usada pela tela de Segurança da conta.\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"Identidades da conta","content":{"application/json":{"schema":{"type":"object","properties":{"identidades":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"provedor":{"type":"string"},"chave":{"type":"string"},"nome":{"type":"string"},"email":{"type":"string"},"emailRelay":{"type":"boolean"},"vinculadaEm":{"type":"string"},"ultimoLoginEm":{"type":"string"},"podeRemover":{"type":"boolean"}}}},"formasDeEntrar":{"type":"integer"},"temSenha":{"type":"boolean"},"govbrVinculado":{"type":"boolean"},"disponiveis":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"},"delete":{"operationId":"deleteAuthIdentidades","tags":["Autenticação"],"summary":"Desvincular uma conta externa","description":"Remove a identidade por `id` ou por `provedor`. Exige que sobre pelo menos uma forma de entrar (senha, gov.br ou outra identidade): senão devolve 409 com `detalhes.formasDeEntrar`. Se a conta tiver mais de uma identidade do mesmo provedor, `provedor` é ambíguo e a resposta é 409 com `detalhes.vinculos` pedindo o `id`. Auditado (SOCIAL_VINCULO_REMOVIDO).\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[{"name":"id","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"provedor","in":"query","required":false,"schema":{"type":"string","enum":["google","apple","facebook"]}}],"responses":{"200":{"description":"Vínculo removido","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"removido":{"type":"object","properties":{"id":{"type":"string"},"provedor":{"type":"string"},"nome":{"type":"string"}}},"formasDeEntrar":{"type":"integer"}}}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Vínculo não encontrado nesta conta","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"É a única forma de entrar na conta, ou `provedor` ambíguo (informe o `id`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/municipios":{"get":{"operationId":"getMunicipios","tags":["Municípios"],"summary":"Municípios ativos","description":"Tela “escolha sua cidade” do app: identidade visual e centro do mapa de cada município.\n\nAcesso público (sem token).","parameters":[],"responses":{"200":{"description":"Lista","content":{"application/json":{"schema":{"type":"object","properties":{"municipios":{"type":"array","items":{"$ref":"#/components/schemas/MunicipioResumo"}}}}}}}},"security":[],"x-acesso":"publica"}},"/municipios/{slug}":{"get":{"operationId":"getMunicipiosSlug","tags":["Municípios"],"summary":"Detalhe do município","description":"Categorias ativas (com SLA e órgão responsável), órgãos e bairros — carregado uma vez pelo app.\n\nAcesso público (sem token).","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Ex.: `manaus`"}],"responses":{"200":{"description":"Município","content":{"application/json":{"schema":{"type":"object","properties":{"municipio":{"$ref":"#/components/schemas/MunicipioDetalhe"}}}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/ocorrencias":{"get":{"operationId":"getOcorrencias","tags":["Ocorrências"],"summary":"Listar ocorrências (mapa, fila do painel e tarefas de campo)","description":"Público (mapa da cidade). Ocorrências anônimas não expõem o autor. Com `lat`/`lng` filtra por proximidade (PostGIS). Filtros da fila: `prazo`, `atribuidas=1` (tarefas do usuário logado — app de campo), `doMeuOrgao=1`, `semResponsavel=1`, `ordem`, `busca`. Paginação por `page`/`perPage` (ou `pagina`); respostas de lista trazem `total`.\n\nAcesso público (sem token).","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgaoId","in":"query","required":false,"schema":{"type":"string"}},{"name":"categoriaId","in":"query","required":false,"schema":{"type":"string"}},{"name":"minhas","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"lat","in":"query","required":false,"schema":{"type":"number"}},{"name":"lng","in":"query","required":false,"schema":{"type":"number"}},{"name":"raioM","in":"query","required":false,"schema":{"type":"number","minimum":50,"maximum":20000}},{"name":"page","in":"query","required":false,"schema":{"type":"number","minimum":1,"default":1}},{"name":"perPage","in":"query","required":false,"schema":{"type":"number","minimum":1,"maximum":100,"default":20}},{"name":"bairroId","in":"query","required":false,"schema":{"type":"string"}},{"name":"responsavelId","in":"query","required":false,"schema":{"type":"string"}},{"name":"prazo","in":"query","required":false,"schema":{"type":"string","enum":["vencido","48h","no_prazo","sem_prazo"]}},{"name":"atribuidas","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"doMeuOrgao","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"semResponsavel","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"ordem","in":"query","required":false,"schema":{"type":"string","enum":["prazo","recentes","apoios"]}},{"name":"busca","in":"query","required":false,"schema":{"type":"string","maxLength":80}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Página de ocorrências","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListaOcorrencias"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"`minhas=1` / `atribuidas=1` exigem login","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos ou conta sem órgão (`doMeuOrgao`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"},"post":{"operationId":"postOcorrencias","tags":["Ocorrências"],"summary":"Registrar ocorrência ou manifestação","description":"Gera o protocolo, calcula o prazo pelo SLA da categoria e encaminha automaticamente ao órgão responsável (manifestações de ouvidoria vão à OUVIDORIA). Fotos: envie antes via `/uploads/presign` e informe `{chave, url}`.\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"201":{"description":"Ocorrência criada","content":{"application/json":{"schema":{"type":"object","properties":{"ocorrencia":{"$ref":"#/components/schemas/Ocorrencia"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos ou categoria de outro município","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tipo":{"type":"string","enum":["OCORRENCIA","RECLAMACAO","SUGESTAO","ELOGIO","DENUNCIA","SOLICITACAO_INFORMACAO"],"default":"OCORRENCIA"},"categoriaId":{"type":"string"},"descricao":{"type":"string","minLength":10,"maxLength":2000},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"endereco":{"type":"string","maxLength":300},"bairroId":{"type":"string"},"anonima":{"type":"boolean","default":false},"fotos":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"url":{"type":"string","format":"uri"}},"required":["chave","url"]},"maxItems":5,"default":[]}},"required":["descricao"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/ocorrencias/{id}":{"get":{"operationId":"getOcorrenciasId","tags":["Ocorrências"],"summary":"Detalhe com linha do tempo","description":"Aceita o id ou o número do protocolo. Gestores veem também as notas internas.\n\nAcesso público (sem token).","parameters":[{"name":"id","in":"path","required":true,"description":"Id da ocorrência ou número do protocolo","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Ocorrência","content":{"application/json":{"schema":{"type":"object","properties":{"ocorrencia":{"$ref":"#/components/schemas/OcorrenciaDetalhe"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/ocorrencias/{id}/apoiar":{"post":{"operationId":"postOcorrenciasIdApoiar","tags":["Ocorrências"],"summary":"Apoiar / retirar apoio","description":"Alterna o apoio do usuário (evita duplicidade de solicitações).\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[{"name":"id","in":"path","required":true,"description":"Id da ocorrência","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Estado do apoio","content":{"application/json":{"schema":{"type":"object","properties":{"apoiei":{"type":"boolean"},"apoiosCount":{"type":"integer"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/ocorrencias/{id}/avaliar":{"post":{"operationId":"postOcorrenciasIdAvaliar","tags":["Ocorrências"],"summary":"Avaliar o atendimento (1 a 5)","description":"Só o autor, após RESOLVIDA ou INDEFERIDA. Pode ser refeita (upsert).\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[{"name":"id","in":"path","required":true,"description":"Id da ocorrência","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Avaliação","content":{"application/json":{"schema":{"type":"object","properties":{"avaliacao":{"type":"object","properties":{"id":{"type":"string"},"nota":{"type":"integer"},"comentario":{"type":["string","null"]},"criadoEm":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Só o autor avalia","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Ainda não concluída","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nota":{"type":"integer","minimum":1,"maximum":5},"comentario":{"type":"string","maxLength":500}},"required":["nota"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/ocorrencias/{id}/status":{"patch":{"operationId":"patchOcorrenciasIdStatus","tags":["Ocorrências"],"summary":"Atualizar status / encaminhar / atribuir / responder / concluir","description":"Gestão (OPERADOR, CAMPO, GESTOR, OUVIDOR, ADMIN). Transições válidas em `TRANSICOES` de @taresolvido/shared; inválida → 409. Gera evento na linha do tempo e push ao cidadão quando público. `DUPLICADA` exige `duplicadaDeId` (mescla os apoios na original e devolve `mesclagem`); `fotosDepois` registra a conclusão pela equipe de campo (papel CAMPO só atua no próprio órgão: assumir, iniciar, concluir com foto “Depois” ou devolver).\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"id","in":"path","required":true,"description":"Id da ocorrência","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Ocorrência atualizada","content":{"application/json":{"schema":{"type":"object","properties":{"ocorrencia":{"$ref":"#/components/schemas/Ocorrencia"},"mesclagem":{"$ref":"#/components/schemas/Mesclagem"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Transição de status não permitida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"mensagem":{"type":"string","maxLength":2000},"publico":{"type":"boolean","default":true},"orgaoId":{"type":"string"},"responsavelId":{"type":"string"},"duplicadaDeId":{"type":"string"},"fotosDepois":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"url":{"type":"string","format":"uri"}},"required":["chave","url"]},"maxItems":5}},"required":["status"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/ocorrencias/{id}/semelhantes":{"get":{"operationId":"getOcorrenciasIdSemelhantes","tags":["Ocorrências"],"summary":"Candidatas a duplicata","description":"Mesma categoria, a até `raioM` metros (PostGIS), abertas e registradas nos últimos `dias`. Aceita id ou protocolo. Usado na mesclagem de duplicadas.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"id","in":"path","required":true,"description":"Id da ocorrência ou número do protocolo","schema":{"type":"string"}},{"name":"raioM","in":"query","required":false,"schema":{"type":"number","minimum":50,"maximum":2000,"default":150}},{"name":"dias","in":"query","required":false,"schema":{"type":"number","minimum":1,"maximum":365,"default":60}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Candidatas","content":{"application/json":{"schema":{"type":"object","properties":{"raioM":{"type":"number"},"dias":{"type":"integer"},"itens":{"type":"array","items":{"$ref":"#/components/schemas/Semelhante"}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/uploads/presign":{"post":{"operationId":"postUploadsPresign","tags":["Uploads"],"summary":"URL assinada para enviar imagem","description":"Fluxo: `POST /uploads/presign` → `PUT` do arquivo em `uploadUrl` (Content-Type igual ao informado) → usar `{chave, url}` em `/ocorrencias`, em `fotosDepois` ou em `brasaoUrl` do município. `finalidade` (ANTES, DEPOIS, BRASAO) organiza a chave no bucket.\n\nExige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"URL assinada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Presign"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp"]},"tamanho":{"type":"number","maximum":10485760},"finalidade":{"type":"string","enum":["ANTES","DEPOIS","BRASAO"]}},"required":["contentType"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/dispositivos":{"post":{"operationId":"postDispositivos","tags":["Dispositivos"],"summary":"Registrar token de push (Expo)","description":"Exige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"Registrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pushToken":{"type":"string","description":"ExponentPushToken[...]"},"plataforma":{"type":"string","enum":["ios","android","web"]}},"required":["pushToken","plataforma"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"},"delete":{"operationId":"deleteDispositivos","tags":["Dispositivos"],"summary":"Remover token de push","description":"Exige `Authorization: Bearer <token>` de qualquer usuário.","parameters":[],"responses":{"200":{"description":"Removido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pushToken":{"type":"string"}},"required":["pushToken"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"usuario"}},"/dashboard/resumo":{"get":{"operationId":"getDashboardResumo","tags":["Dashboard"],"summary":"Indicadores executivos","description":"Dashboard do prefeito (app e painel): abertas, resolvidas, atrasadas, tempo médio, ranking de órgãos (score 0–100), série diária, satisfação, alertas de SLA. Papéis: PREFEITO, GESTOR, OUVIDOR, OPERADOR, ADMIN.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"dias","in":"query","schema":{"type":"string","enum":["7","30","90"],"default":"30"},"description":"Período em dias"},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Resumo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResumoDashboard"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/dashboard/mapa":{"get":{"operationId":"getDashboardMapa","tags":["Dashboard"],"summary":"Mapa operacional e onde melhorar","description":"Alfinetes do mapa (até 2.000, mais recentes primeiro), agregados e satisfação por bairro e o diagnóstico \"onde melhorar\": os 5 piores bairros, órgãos e categorias com índice 0–100 (quanto maior, mais urgente: 45% insatisfação + 35% abertas fora do prazo, suavizado por atrasadas/(abertas+2) e só com 3+ abertas, + 20% volume relativo ao total de abertas do recorte) e o motivo em pt-BR. O recorte é o mesmo do /dashboard/resumo — carteira aberta + resolvidas no período + registradas no período —, e a satisfação conta as avaliações criadas no período. Ocorrência de zeladoria sem coordenada cai no centroide do bairro (`precisao: \"BAIRRO\"`); sem bairro com centroide, entra só em `semLocalizacao`. Manifestação de ouvidoria é sigilosa: vem sem título, endereço, prazo, nota e apoios, e sempre no centroide do bairro (nunca no GPS). Nenhuma ocorrência expõe autor ou descrição. Papéis: OPERADOR, GESTOR, OUVIDOR, PREFEITO, ADMIN.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"dias","in":"query","schema":{"type":"string","enum":["7","30","90","365"],"default":"90"},"description":"Período em dias (governa resolvidas, registradas e satisfação; as abertas são a carteira atual)"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Status separados por vírgula (ex.: RECEBIDA,EM_EXECUCAO)"},{"name":"orgaoId","in":"query","schema":{"type":"string"},"description":"Id do órgão no município (inexistente => 422)"},{"name":"categoriaId","in":"query","schema":{"type":"string"},"description":"Id da categoria no município (inexistente => 422)"},{"name":"bairroId","in":"query","schema":{"type":"string"},"description":"Id do bairro no município (inexistente => 422)"},{"name":"tipo","in":"query","schema":{"type":"string","enum":["OCORRENCIA","RECLAMACAO","SUGESTAO","ELOGIO","DENUNCIA","SOLICITACAO_INFORMACAO"]}},{"name":"apenasAbertas","in":"query","schema":{"type":"string"},"description":"1|true|sim ou 0|false|nao"},{"name":"comAvaliacao","in":"query","schema":{"type":"string"},"description":"1|true|sim ou 0|false|nao"},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Mapa e diagnóstico","content":{"application/json":{"schema":{"type":"object","properties":{"periodoDias":{"type":"integer","enum":[7,30,90,365]},"geradoEm":{"type":"string","format":"date-time"},"centro":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"},"zoom":{"type":"integer"}},"description":"Centro e zoom do cadastro do município"},"filtros":{"type":"object","description":"Eco dos filtros aplicados"},"ocorrencias":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"protocolo":{"type":"string"},"tipo":{"type":"string","enum":["OCORRENCIA","RECLAMACAO","SUGESTAO","ELOGIO","DENUNCIA","SOLICITACAO_INFORMACAO"]},"titulo":{"type":["string","null"]},"categoria":{"type":["string","null"]},"area":{"type":["string","null"]},"orgaoSigla":{"type":["string","null"]},"bairro":{"type":["string","null"]},"endereco":{"type":["string","null"]},"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"prioridade":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"},"precisao":{"type":"string","enum":["GPS","BAIRRO"]},"criadoEm":{"type":"string","format":"date-time"},"prazoEm":{"type":["string","null"],"format":"date-time"},"resolvidaEm":{"type":["string","null"],"format":"date-time"},"atrasada":{"type":"boolean"},"apoiosCount":{"type":"integer"},"nota":{"type":["integer","null"]}},"description":"Manifestação de ouvidoria (tipo != OCORRENCIA) vem com titulo, endereco, prazoEm, resolvidaEm e nota nulos, apoiosCount 0, atrasada false e precisao BAIRRO"}},"bairros":{"type":"array","items":{"type":"object","properties":{"bairroId":{"type":"string"},"bairro":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"},"total":{"type":"integer"},"abertas":{"type":"integer"},"atrasadas":{"type":"integer"},"resolvidas":{"type":"integer"},"satisfacaoMedia":{"type":["number","null"]},"avaliacoes":{"type":"integer"},"satisfacaoConfiavel":{"type":"boolean"},"dentroDoPrazoPct":{"type":["number","null"]},"tempoMedioHoras":{"type":["number","null"]}},"description":"Centroide das ocorrências de zeladoria do bairro; bairro sem coordenada conhecida não entra na lista"}},"ondeMelhorar":{"type":"object","properties":{"bairros":{"type":"array","items":{"type":"object"}},"orgaos":{"type":"array","items":{"type":"object"}},"categorias":{"type":"array","items":{"type":"object"}},"abertasNoRecorte":{"type":"integer"}},"description":"5 piores de cada dimensão (mínimo de 3 ocorrências no recorte), com indice 0–100, motivo e satisfacaoConfiavel; abertasNoRecorte é o denominador do volume (neutralizado quando a dimensão tem uma única linha elegível)"},"semLocalizacao":{"type":"integer"},"totalNoPeriodo":{"type":"integer"},"truncado":{"type":"boolean"},"limiteOcorrencias":{"type":"integer"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/contato":{"post":{"operationId":"postContato","tags":["Site"],"summary":"Solicitar demonstração (lead comercial)","description":"Formulário do site institucional. Sem autenticação; limite de 5 envios por IP a cada 10 minutos.\n\nAcesso público (sem token).","parameters":[],"responses":{"201":{"description":"Recebido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Muitas requisições","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":3,"maxLength":120},"cargo":{"type":"string","maxLength":80},"municipio":{"type":"string","minLength":2,"maxLength":120},"uf":{"type":"string","enum":["AC","AL","AP","AM","BA","CE","DF","ES","GO","MA","MT","MS","MG","PA","PB","PR","PE","PI","RJ","RN","RS","RO","RR","SC","SP","SE","TO"]},"email":{"type":"string","format":"email","maxLength":160},"telefone":{"type":"string","pattern":"^\\d{10,11}$"},"mensagem":{"type":"string","maxLength":2000}},"required":["nome","municipio","uf","email"]}}}},"security":[],"x-acesso":"publica"}},"/admin/orgaos":{"get":{"operationId":"getAdminOrgaos","tags":["Administração"],"summary":"Listar órgãos","description":"Exige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Órgãos com contagens","content":{"application/json":{"schema":{"type":"object","properties":{"orgaos":{"type":"array","items":{"$ref":"#/components/schemas/Orgao"}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"post":{"operationId":"postAdminOrgaos","tags":["Administração"],"summary":"Criar órgão","description":"Exige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"orgao":{"$ref":"#/components/schemas/Orgao"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Sigla já cadastrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":3,"maxLength":120},"sigla":{"type":"string","minLength":2,"maxLength":20,"pattern":"^[A-Z0-9][A-Z0-9_-]*$"},"email":{"type":["string","null"],"format":"email","maxLength":160},"telefone":{"type":["string","null"],"pattern":"^[\\d\\s()+-]{8,20}$"},"ativo":{"type":"boolean","default":true}},"required":["nome","sigla"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/orgaos/{id}":{"patch":{"operationId":"patchAdminOrgaosId","tags":["Administração"],"summary":"Editar órgão","description":"Nome, sigla, contato e `ativo`. `reatribuirCategoriasPara` (id de outro órgão ativo) move todas as categorias que apontam para este órgão — recomendado ao desativar, porque o encaminhamento automático segue `categoria.orgaoId`. A resposta traz `categoriasReatribuidas` quando houve reatribuição.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do órgão","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Atualizado","content":{"application/json":{"schema":{"type":"object","properties":{"orgao":{"$ref":"#/components/schemas/Orgao"},"categoriasReatribuidas":{"type":["object","null"],"properties":{"para":{"type":"object","properties":{"id":{"type":"string"},"sigla":{"type":"string"}}},"total":{"type":"integer"}}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conflito de estado ou de unicidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":3,"maxLength":120},"sigla":{"type":"string","minLength":2,"maxLength":20,"pattern":"^[A-Z0-9][A-Z0-9_-]*$"},"email":{"type":["string","null"],"format":"email","maxLength":160},"telefone":{"type":["string","null"],"pattern":"^[\\d\\s()+-]{8,20}$"},"ativo":{"type":"boolean","default":true},"reatribuirCategoriasPara":{"type":"string","minLength":1}}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"delete":{"operationId":"deleteAdminOrgaosId","tags":["Administração"],"summary":"Excluir órgão","description":"Só sem ocorrências, categorias e usuários vinculados — caso contrário 409 (desative-o).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do órgão","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Excluído","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Órgão com vínculos: desative em vez de excluir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/categorias":{"get":{"operationId":"getAdminCategorias","tags":["Administração"],"summary":"Listar categorias (inclui inativas)","description":"Cada categoria carrega o órgão responsável (regra de encaminhamento automático) e o SLA em horas.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Catálogo","content":{"application/json":{"schema":{"type":"object","properties":{"categorias":{"type":"array","items":{"$ref":"#/components/schemas/Categoria"}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"post":{"operationId":"postAdminCategorias","tags":["Administração"],"summary":"Criar categoria","description":"Nome único no município (sem distinguir maiúsculas).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"201":{"description":"Criada","content":{"application/json":{"schema":{"type":"object","properties":{"categoria":{"$ref":"#/components/schemas/Categoria"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Categoria já cadastrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"area":{"type":"string","minLength":2,"maxLength":80},"nome":{"type":"string","minLength":2,"maxLength":120},"orgaoId":{"type":["string","null"],"minLength":1},"slaHoras":{"type":"integer","minimum":1,"maximum":8760,"default":240},"icone":{"type":"string","enum":["alert-circle","warning","car","car-sport","bus","bicycle","train","walk","trail-sign","stop-circle","water","water-outline","funnel","rainy","boat","earth","thunderstorm","umbrella","trash","trash-bin","cube","leaf","flower","paw","fish","bug","flame","skull","nuclear","bulb","flash","flash-off","battery-charging","wifi","call","school","medkit","medical","bandage","pulse","football","basketball","barbell","library","book","construct","hammer","build","home","business","storefront","restaurant","cafe","bed","people","person","megaphone","shield","shield-checkmark","information-circle","help-circle","heart","map","location","pin","globe","planet","sunny","cloud","camera","image","musical-notes","volume-high","thermometer","speedometer","key","lock-closed","eye","layers","grid","color-palette","brush","cut","ellipsis-horizontal"],"default":"alert-circle"},"ordem":{"type":"integer","minimum":0,"maximum":9999,"default":0},"ativa":{"type":"boolean","default":true}},"required":["area","nome"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/categorias/{id}":{"patch":{"operationId":"patchAdminCategoriasId","tags":["Administração"],"summary":"Editar categoria","description":"Mudar `orgaoId` altera o encaminhamento das próximas ocorrências; `slaHoras` o prazo padrão; `ativa=false` some do app. Renomear para um nome já usado no município responde 409.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do categoria","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Atualizada","content":{"application/json":{"schema":{"type":"object","properties":{"categoria":{"$ref":"#/components/schemas/Categoria"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Categoria já cadastrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"area":{"type":"string","minLength":2,"maxLength":80},"nome":{"type":"string","minLength":2,"maxLength":120},"orgaoId":{"type":["string","null"],"minLength":1},"slaHoras":{"type":"integer","minimum":1,"maximum":8760,"default":240},"icone":{"type":"string","enum":["alert-circle","warning","car","car-sport","bus","bicycle","train","walk","trail-sign","stop-circle","water","water-outline","funnel","rainy","boat","earth","thunderstorm","umbrella","trash","trash-bin","cube","leaf","flower","paw","fish","bug","flame","skull","nuclear","bulb","flash","flash-off","battery-charging","wifi","call","school","medkit","medical","bandage","pulse","football","basketball","barbell","library","book","construct","hammer","build","home","business","storefront","restaurant","cafe","bed","people","person","megaphone","shield","shield-checkmark","information-circle","help-circle","heart","map","location","pin","globe","planet","sunny","cloud","camera","image","musical-notes","volume-high","thermometer","speedometer","key","lock-closed","eye","layers","grid","color-palette","brush","cut","ellipsis-horizontal"],"default":"alert-circle"},"ordem":{"type":"integer","minimum":0,"maximum":9999,"default":0},"ativa":{"type":"boolean","default":true}}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"delete":{"operationId":"deleteAdminCategoriasId","tags":["Administração"],"summary":"Excluir categoria","description":"Só sem ocorrências — caso contrário 409 (desative-a).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do categoria","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Excluída","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conflito de estado ou de unicidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/categorias/restaurar":{"post":{"operationId":"postAdminCategoriasRestaurar","tags":["Administração"],"summary":"Restaurar catálogo padrão","description":"Cria as categorias padrão do produto que ainda não existem no município (sem duplicar), ligadas ao órgão padrão quando ele existir.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Resultado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestauracaoCatalogo"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"criarOrgaos":{"type":"boolean","default":false}}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/bairros":{"get":{"operationId":"getAdminBairros","tags":["Administração"],"summary":"Listar bairros","description":"Exige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Bairros","content":{"application/json":{"schema":{"type":"object","properties":{"bairros":{"type":"array","items":{"$ref":"#/components/schemas/Bairro"}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"post":{"operationId":"postAdminBairros","tags":["Administração"],"summary":"Criar bairro","description":"Nome único no município, sem distinguir maiúsculas (`Centro` e `CENTRO` são o mesmo bairro).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"bairro":{"$ref":"#/components/schemas/Bairro"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Bairro já cadastrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":2,"maxLength":100},"zona":{"type":["string","null"],"maxLength":40}},"required":["nome"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/bairros/{id}":{"patch":{"operationId":"patchAdminBairrosId","tags":["Administração"],"summary":"Editar bairro","description":"Exige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do bairro","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Atualizado","content":{"application/json":{"schema":{"type":"object","properties":{"bairro":{"$ref":"#/components/schemas/Bairro"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conflito de estado ou de unicidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":2,"maxLength":100},"zona":{"type":["string","null"],"maxLength":40}}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"delete":{"operationId":"deleteAdminBairrosId","tags":["Administração"],"summary":"Remover bairro","description":"Só sem ocorrências (409 caso contrário).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do bairro","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Removido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conflito de estado ou de unicidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/membros":{"get":{"operationId":"getAdminMembros","tags":["Administração"],"summary":"Listar usuários do município","description":"Exige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Membros","content":{"application/json":{"schema":{"type":"object","properties":{"membros":{"type":"array","items":{"$ref":"#/components/schemas/Membro"}}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"post":{"operationId":"postAdminMembros","tags":["Administração"],"summary":"Criar servidor (usuário + papel)","description":"E-mail novo: cria a conta (usuário e papel na mesma transação) com senha temporária devolvida uma única vez. E-mail de conta que já pertence ao município: só concede o papel. E-mail de conta de outra edição: 409 `{detalhes: {contaExistente: true}}` sem revelar nada da conta — repita com `vincularExistente: true` para conceder o papel (nome, senha e 2FA atuais são mantidos). GESTOR e CAMPO exigem órgão.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembroCriado"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conta de outra edição sem confirmação (`contaExistente`) / já tem este papel / conta desativada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":3,"maxLength":120},"email":{"type":"string","format":"email","maxLength":160},"papel":{"type":"string","enum":["OPERADOR","CAMPO","GESTOR","OUVIDOR","PREFEITO","ADMIN"]},"orgaoId":{"type":["string","null"],"minLength":1},"vincularExistente":{"type":"boolean","default":false}},"required":["nome","email","papel"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/membros/{id}":{"patch":{"operationId":"patchAdminMembrosId","tags":["Administração"],"summary":"Alterar papel ou órgão","description":"Não permite alterar o próprio acesso, papéis SUPERADMIN nem rebaixar o último ADMIN.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do membro","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Atualizado","content":{"application/json":{"schema":{"type":"object","properties":{"membro":{"$ref":"#/components/schemas/Membro"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conflito de estado ou de unicidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"papel":{"type":"string","enum":["OPERADOR","CAMPO","GESTOR","OUVIDOR","PREFEITO","ADMIN"]},"orgaoId":{"type":["string","null"],"minLength":1}}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"delete":{"operationId":"deleteAdminMembrosId","tags":["Administração"],"summary":"Retirar acesso do usuário","description":"Remove o papel no município (a conta continua). Não remove o próprio acesso nem o último ADMIN.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"id","in":"path","required":true,"description":"Id do membro","schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Removido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Conflito de estado ou de unicidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/municipio":{"get":{"operationId":"getAdminMunicipio","tags":["Administração"],"summary":"Configuração do município","description":"Exige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Município","content":{"application/json":{"schema":{"type":"object","properties":{"municipio":{"$ref":"#/components/schemas/MunicipioAdmin"},"podeAlterarAtivoESlug":{"type":"boolean"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"},"patch":{"operationId":"patchAdminMunicipio","tags":["Administração"],"summary":"Editar configuração","description":"Nome, UF, população, cores, brasão, centro do mapa/zoom, WhatsApp, 2FA obrigatória e limiar de apoios. `brasaoUrl` precisa ser a URL devolvida por `POST /uploads/presign` (finalidade BRASAO) — só `http(s)://` no armazenamento da plataforma. `ativo` e `slug` só pelo SUPERADMIN (CM3).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Atualizado","content":{"application/json":{"schema":{"type":"object","properties":{"municipio":{"$ref":"#/components/schemas/MunicipioAdmin"},"podeAlterarAtivoESlug":{"type":"boolean"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Campo restrito à CM3","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Slug em uso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":2,"maxLength":120},"uf":{"type":"string","enum":["AC","AL","AP","AM","BA","CE","DF","ES","GO","MA","MT","MS","MG","PA","PB","PR","PE","PI","RJ","RN","RS","RO","RR","SC","SP","SE","TO"]},"populacao":{"type":["integer","null"],"minimum":0,"maximum":50000000},"corPrimaria":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"corSecundaria":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"brasaoUrl":{"type":["string","null"],"maxLength":500,"pattern":"^https?:\\/\\/[^\\s<>\"'`]+$"},"centroLat":{"type":"number","minimum":-90,"maximum":90},"centroLng":{"type":"number","minimum":-180,"maximum":180},"zoomInicial":{"type":"integer","minimum":3,"maximum":20},"whatsappNumero":{"type":["string","null"],"pattern":"^\\+\\d{10,15}$"},"exigir2fa":{"type":"boolean"},"limiarApoiosAlerta":{"type":"integer","minimum":1,"maximum":100000},"ativo":{"type":"boolean"},"slug":{"type":"string","pattern":"^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$"}}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/auditoria":{"get":{"operationId":"getAdminAuditoria","tags":["Administração"],"summary":"Consultar auditoria (log de ações)","description":"Filtros por usuário, ação, entidade, período e id/protocolo; 50 por página. `de`/`ate` no formato `AAAA-MM-DD` são dias civis no fuso do painel (`FUSO_HORARIO`, padrão America/Manaus), inclusivos; datas inexistentes respondem 422. `formato=csv` devolve o mesmo filtro em CSV (UTF-8 com BOM, `;`), limitado a 50 000 linhas.\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"usuarioId","in":"query","required":false,"schema":{"type":"string"}},{"name":"usuario","in":"query","required":false,"schema":{"type":"string","maxLength":120}},{"name":"acao","in":"query","required":false,"schema":{"type":"string","maxLength":60}},{"name":"entidade","in":"query","required":false,"schema":{"type":"string","maxLength":60}},{"name":"entidadeId","in":"query","required":false,"schema":{"type":"string","maxLength":80}},{"name":"de","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T.*)?$"}},{"name":"ate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T.*)?$"}},{"name":"pagina","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"formato","in":"query","required":false,"schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Página do log (JSON) ou arquivo CSV","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListaAuditoria"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/exportacao":{"get":{"operationId":"getAdminExportacao","tags":["Administração"],"summary":"Inventário da exportação integral","description":"Contagem por tabela e URLs dos arquivos disponíveis (JSON completo e CSVs).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Inventário","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventarioExportacao"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/admin/exportacao/{arquivo}":{"get":{"operationId":"getAdminExportacaoArquivo","tags":["Administração"],"summary":"Baixar exportação (JSON completo ou CSV por tabela)","description":"Streaming. `completo.json` traz município, órgãos, categorias, bairros, membros (sem senhas), ocorrências (fotos, eventos, apoios, avaliações) e auditoria. CSVs: `ocorrencias.csv`, `eventos.csv`, `avaliacoes.csv`, `orgaos.csv`, `categorias.csv`, `bairros.csv`, `membros.csv`, `auditoria.csv` — UTF-8 com BOM, separador `;`. Cada download é auditado (EXPORTACAO).\n\nExige token de ADMIN do município (ou SUPERADMIN da CM3).","parameters":[{"name":"arquivo","in":"path","required":true,"schema":{"type":"string","pattern":"^(completo\\.json|[a-z]+\\.csv)$","enum":["completo.json","ocorrencias.csv","eventos.csv","avaliacoes.csv","orgaos.csv","categorias.csv","bairros.csv","membros.csv","auditoria.csv"]},"description":"Nome do arquivo"},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo (`Content-Disposition: attachment`)","content":{"application/json":{"schema":{"type":"string","format":"binary"}},"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"admin"}},"/openapi.json":{"get":{"operationId":"getOpenapiJson","tags":["Documentação"],"summary":"Este documento (OpenAPI 3.1)","description":"Acesso público (sem token).","parameters":[],"responses":{"200":{"description":"Documento OpenAPI","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[],"x-acesso":"publica"}},"/relatorios/ocorrencias.csv":{"get":{"operationId":"getRelatoriosOcorrenciasCsv","tags":["Relatórios"],"summary":"Relatório de ocorrências em CSV","description":"Mesmos filtros da fila do painel (período, órgão, categoria, bairro, status, tipo). UTF-8 com BOM e separador `;` (Excel pt-BR). Gestor de órgão recebe só o próprio órgão. Auditado (RELATORIO).\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"de","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"ate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"orgaoId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"categoriaId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"bairroId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"tipo","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo CSV","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/ocorrencias.pdf":{"get":{"operationId":"getRelatoriosOcorrenciasPdf","tags":["Relatórios"],"summary":"Relatório de ocorrências em PDF","description":"PDF paisagem com cabeçalho da marca e do município, resumo (totais, tempo médio, % no prazo, satisfação) e tabela paginada. Auditado.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"de","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"ate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"orgaoId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"categoriaId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"bairroId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"tipo","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/ocorrencias.json":{"get":{"operationId":"getRelatoriosOcorrenciasJson","tags":["Relatórios"],"summary":"Prévia do relatório de ocorrências","description":"Totais do filtro (sem as linhas) — usada pela página /painel/relatorios antes de gerar o arquivo.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"de","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"ate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"orgaoId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"categoriaId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"bairroId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"tipo","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Prévia","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviaRelatorio"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/mensal.pdf":{"get":{"operationId":"getRelatoriosMensalPdf","tags":["Relatórios"],"summary":"Relatório executivo mensal (PDF)","description":"2–3 páginas para o prefeito: mês × mês anterior, ranking de órgãos, categorias, bairros e satisfação. Auditado.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"mes","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/mensal.json":{"get":{"operationId":"getRelatoriosMensalJson","tags":["Relatórios"],"summary":"Relatório executivo mensal (dados)","description":"Mesmos números do PDF em JSON (prévia no painel e integrações de BI).\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"mes","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Relatório mensal","content":{"application/json":{"schema":{"type":"object","description":"`RelatorioMensal` de @taresolvido/shared: municipio, mes, mesAnterior, atual, anterior, orgaos, categorias, bairros, satisfacao"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/ouvidoria-anual.pdf":{"get":{"operationId":"getRelatoriosOuvidoriaAnualPdf","tags":["Relatórios"],"summary":"Relatório anual de gestão da ouvidoria (PDF)","description":"Lei 13.460/2017, art. 14, § 2º: manifestações recebidas por tipo, motivos recorrentes, providências, prazo legal de 30 dias, anonimato e satisfação. Auditado.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"ano","in":"query","required":false,"schema":{"type":"integer","minimum":2020,"maximum":2100}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/ouvidoria-anual.csv":{"get":{"operationId":"getRelatoriosOuvidoriaAnualCsv","tags":["Relatórios"],"summary":"Anexo CSV do relatório anual de ouvidoria","description":"Uma linha por manifestação, sem texto nem autoria. Auditado.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"ano","in":"query","required":false,"schema":{"type":"integer","minimum":2020,"maximum":2100}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo CSV","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/relatorios/ouvidoria-anual.json":{"get":{"operationId":"getRelatoriosOuvidoriaAnualJson","tags":["Relatórios"],"summary":"Relatório anual de ouvidoria (dados)","description":"Números e textos do relatório anual (cache de 10 min).\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"ano","in":"query","required":false,"schema":{"type":"integer","minimum":2020,"maximum":2100}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Relatório anual","content":{"application/json":{"schema":{"type":"object","description":"`RelatorioAnualOuvidoria` de @taresolvido/shared"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/dados-abertos/ocorrencias.csv":{"get":{"operationId":"getDadosAbertosOcorrenciasCsv","tags":["Dados abertos"],"summary":"Dados abertos: ocorrências (CSV)","description":"Portal de transparência: ocorrências sem dados pessoais (sem autor; descrição só de zeladoria; lat/lng com 4 casas). Público, cache de 5 min, licença CC BY 4.0.\n\nAcesso público (sem token).","parameters":[{"name":"ano","in":"query","required":false,"schema":{"type":"integer","minimum":2020,"maximum":2100}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Arquivo CSV","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/dados-abertos/ocorrencias.json":{"get":{"operationId":"getDadosAbertosOcorrenciasJson","tags":["Dados abertos"],"summary":"Dados abertos: ocorrências (JSON)","description":"Mesmo conteúdo do CSV em JSON.\n\nAcesso público (sem token).","parameters":[{"name":"ano","in":"query","required":false,"schema":{"type":"integer","minimum":2020,"maximum":2100}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Lista","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DadosAbertos"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/dados-abertos/indicadores.json":{"get":{"operationId":"getDadosAbertosIndicadoresJson","tags":["Dados abertos"],"summary":"Dados abertos: indicadores do município","description":"Totais, por órgão/categoria/bairro, série mensal de 12 meses, tempo médio, % no prazo e satisfação. Público, cache de 5 min; alimenta a página /transparencia.\n\nAcesso público (sem token).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Indicadores","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndicadoresAbertos"}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/whatsapp/webhook":{"get":{"operationId":"getWhatsappWebhook","tags":["WhatsApp"],"summary":"Verificação do webhook (Meta)","description":"A Meta chama com `hub.mode=subscribe`, `hub.verify_token` (= WHATSAPP_VERIFY_TOKEN) e `hub.challenge`; a resposta é o challenge em texto. Sem parâmetros, devolve `{ok, canal}` (diagnóstico).\n\nChamado pelo provedor externo; validado por token/assinatura próprios.","parameters":[{"name":"hub.mode","in":"query","schema":{"type":"string"}},{"name":"hub.verify_token","in":"query","schema":{"type":"string"}},{"name":"hub.challenge","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge (texto) ou diagnóstico (JSON)","content":{"text/plain":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"type":"string","format":"binary"}}}},"403":{"description":"Token de verificação inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"webhook"},"post":{"operationId":"postWhatsappWebhook","tags":["WhatsApp"],"summary":"Mensagens recebidas (Meta Cloud API)","description":"Atendimento automatizado: conversa guiada (categoria, descrição, localização, foto) que abre a ocorrência com `origem=WHATSAPP`, consulta protocolo, ouvidoria e encaminha à central. Assinatura `X-Hub-Signature-256` validada com WHATSAPP_APP_SECRET; responde 200 imediatamente e processa em segundo plano (idempotente por id de mensagem).\n\nChamado pelo provedor externo; validado por token/assinatura próprios.","parameters":[],"responses":{"200":{"description":"Recebido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"Corpo inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Assinatura inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"whatsapp_business_account"},"entry":{"type":"array","items":{"type":"object"}}}}}}},"security":[],"x-acesso":"webhook"}},"/whatsapp/conversas":{"get":{"operationId":"getWhatsappConversas","tags":["WhatsApp"],"summary":"Conversas do município","description":"Etapa, última mensagem e transcrição curta de cada conversa; `etapa=ATENDENTE` lista as que aguardam um atendente humano. Papéis do painel.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"etapa","in":"query","required":false,"schema":{"type":"string","enum":["INICIO","CATEGORIA","DESCRICAO","LOCALIZACAO","BAIRRO","FOTO","NOME","CONFIRMACAO","OUVIDORIA_TIPO","OUVIDORIA_ANONIMA","OUVIDORIA_DESCRICAO","ATENDENTE"]}},{"name":"limite","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":100}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Conversas","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"aguardandoAtendente":{"type":"integer"},"itens":{"type":"array","items":{"$ref":"#/components/schemas/ConversaWhatsapp"}},"canal":{"type":"object"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/whatsapp/conversas/{telefone}":{"patch":{"operationId":"patchWhatsappConversasTelefone","tags":["WhatsApp"],"summary":"Encerrar o atendimento humano","description":"Devolve a conversa ao menu automático, opcionalmente enviando uma mensagem ao cidadão.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"telefone","in":"path","required":true,"schema":{"type":"string"},"description":"Só dígitos, com DDI (ex.: 5592999990000)"},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Conversa atualizada","content":{"application/json":{"schema":{"type":"object","properties":{"conversa":{"$ref":"#/components/schemas/ConversaWhatsapp"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não encontrado (ou pertence a outro município)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"acao":{"const":"encerrar"},"mensagem":{"type":"string","maxLength":1000}},"required":["acao"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"},"delete":{"operationId":"deleteWhatsappConversasTelefone","tags":["WhatsApp"],"summary":"Apagar a conversa","description":"Usado pelo simulador para recomeçar do zero (a conta do cidadão não é apagada). Auditado.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"name":"telefone","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Apagada","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"apagada":{"type":"boolean"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/whatsapp/simular":{"post":{"operationId":"postWhatsappSimular","tags":["WhatsApp"],"summary":"Simular uma mensagem do cidadão","description":"O simulador do painel roda o motor completo (banco, protocolo, fotos no bucket) em modo simulado — nunca chama a Meta. Papéis do painel.\n\nExige token de um usuário com papel de gestão no município (OPERADOR, CAMPO, GESTOR, OUVIDOR, PREFEITO, ADMIN).","parameters":[{"$ref":"#/components/parameters/MunicipioHeader"}],"responses":{"200":{"description":"Respostas do bot e estado da conversa","content":{"application/json":{"schema":{"type":"object","properties":{"respostas":{"type":"array","items":{"type":"object"}},"conversa":{"type":"object"},"canal":{"type":"object"}}}}}},"400":{"description":"Município não informado (header `X-Municipio`, `?municipio=` ou subdomínio)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Sem permissão para esta ação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"422":{"description":"Dados inválidos — `detalhes` traz os erros por campo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"telefone":{"type":"string","minLength":10,"maxLength":15},"tipo":{"type":"string","enum":["texto","localizacao","imagem","interativo"]},"texto":{"type":"string","maxLength":4096},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"fotoUrl":{"type":"string","maxLength":200000},"idBotao":{"type":"string","maxLength":256}},"required":["telefone","tipo"]}}}},"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"x-acesso":"gestor"}},"/tls/permitir":{"get":{"operationId":"getTlsPermitir","tags":["Infraestrutura"],"summary":"Autorizar certificado de um domínio (uso interno do proxy)","description":"Chamada pelo Caddy antes de emitir certificado para um host que não está no Caddyfile (`on_demand_tls { ask }`): responde 200 quando o rótulo é um host fixo da plataforma (raiz, www, app, fotos, minio, api, painel) ou o slug de um município **ativo**; 403 caso contrário. É o que faz `<cidade>.taresolvido.app.br` passar a funcionar em HTTPS assim que a cidade é cadastrada no painel, sem editar configuração do proxy. Sem esta recusa, qualquer host apontado ao nosso IP faria o proxy pedir certificados até bater o limite do Let's Encrypt.\n\nAcesso público (sem token).","parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string"},"description":"Host que o proxy quer certificar"}],"responses":{"200":{"description":"Emissão autorizada","content":{"application/json":{"schema":{"type":"object","properties":{"permitido":{"type":"boolean"},"municipio":{"type":"string"},"motivo":{"type":"string"}}}}}},"400":{"description":"Domínio não informado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Fora da plataforma, subdomínio de segundo nível, município inexistente ou inativo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[],"x-acesso":"publica"}},"/tarefas/alertas":{"post":{"operationId":"postTarefasAlertas","tags":["Alertas"],"summary":"Processar alertas de SLA e repercussão","description":"Tarefa agendada (cron do host, serviço `agendador` do docker compose ou Vercel Cron): avalia SLA estourado, vencimento em 48 h e ocorrências com apoios acima de `limiarApoiosAlerta`, enviando push aos gestores sem repetir (`AlertaEnviado`). `?municipio=<slug>` restringe a um município; sem ele, processa todos os ativos. Sem CRON_SECRET configurado a rota responde 503.\n\nExige `Authorization: Bearer <CRON_SECRET>` (agendador).","parameters":[{"name":"municipio","in":"query","schema":{"type":"string"},"description":"Slug do município (opcional)"}],"responses":{"200":{"description":"Resumo do processamento","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultadoAlertas"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Segredo do agendador inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"503":{"description":"CRON_SECRET não configurado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"cronSecret":[]}],"x-acesso":"cron"},"get":{"operationId":"getTarefasAlertas","tags":["Alertas"],"summary":"Processar alertas (GET, para agendadores que só fazem GET)","description":"Idêntico ao POST.\n\nExige `Authorization: Bearer <CRON_SECRET>` (agendador).","parameters":[{"name":"municipio","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Resumo do processamento","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultadoAlertas"}}}},"401":{"description":"Não autenticado (token ausente ou inválido)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Segredo do agendador inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"503":{"description":"CRON_SECRET não configurado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}},"security":[{"cronSecret":[]}],"x-acesso":"cron"}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Token obtido em `POST /auth/login` ou `POST /auth/registro`."},"cookieAuth":{"type":"apiKey","in":"cookie","name":"tr_token","description":"Cookie de sessão do painel web (mesmo JWT)."},"cronSecret":{"type":"http","scheme":"bearer","description":"`CRON_SECRET` do ambiente, para rotinas agendadas."}},"parameters":{"MunicipioHeader":{"name":"X-Municipio","in":"header","required":false,"schema":{"type":"string","examples":["manaus"]},"description":"Slug do município (tenant). Alternativas: `?municipio=<slug>` ou o subdomínio `<slug>.taresolvido.app.br`. Obrigatório quando nenhuma das três formas está presente."}},"schemas":{"Erro":{"type":"object","properties":{"erro":{"type":"string","description":"Mensagem legível em pt-BR"},"detalhes":{"description":"Erros por campo (422) ou dados extras"}},"required":["erro"],"description":"Formato padrão de erro da API"},"MembroUsuario":{"type":"object","properties":{"municipioId":{"type":"string"},"papel":{"type":"string","enum":["CIDADAO","OPERADOR","CAMPO","GESTOR","OUVIDOR","PREFEITO","ADMIN","SUPERADMIN"]},"orgao":{"type":["object","null"],"properties":{"id":{"type":"string"},"sigla":{"type":"string"},"nome":{"type":"string"}}}}},"Usuario":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"email":{"type":["string","null"]},"telefone":{"type":["string","null"]},"avatarUrl":{"type":["string","null"]},"membros":{"type":"array","items":{"$ref":"#/components/schemas/MembroUsuario"}},"emailVerificadoEm":{"type":["string","null"],"format":"date-time"},"telefoneVerificadoEm":{"type":["string","null"],"format":"date-time"},"totpAtivoEm":{"type":["string","null"],"format":"date-time","description":"Quando a verificação em duas etapas foi ativada"},"govbrVinculado":{"type":"boolean"},"temSenha":{"type":"boolean"}},"required":["id","nome","membros"]},"Sessao":{"type":"object","properties":{"token":{"type":"string","description":"JWT (Bearer) válido por 30 dias"},"usuario":{"$ref":"#/components/schemas/Usuario"},"exige2faPendente":{"type":"boolean","description":"true quando algum município exige 2FA e a conta ainda não a ativou (o painel redireciona para /painel/seguranca)"}},"required":["token","usuario"]},"Sessao2fa":{"type":"object","properties":{"exige2fa":{"type":"boolean","const":true},"tokenParcial":{"type":"string","description":"Válido por 5 minutos; só serve para `POST /auth/2fa`"},"metodo":{"type":"string","enum":["totp"]}},"required":["exige2fa","tokenParcial"],"description":"Conta com verificação em duas etapas: falta o código do autenticador"},"Verificacao":{"type":"object","properties":{"verificacao":{"type":"object","properties":{"canal":{"type":"string","enum":["EMAIL","SMS"]},"destino":{"type":"string","description":"Contato mascarado, ex.: jo***@gmail.com"},"expiraEm":{"type":"string","format":"date-time"}}},"codigoDev":{"type":"string","description":"Só fora de produção com provedor simulado (SMTP/SMS não configurados)"}},"required":["verificacao"]},"Totp":{"type":"object","properties":{"otpauthUrl":{"type":"string"},"qrCodeDataUrl":{"type":"string","description":"PNG em data URL para exibir o QR code"},"segredoManual":{"type":"string"},"cifrado":{"type":"boolean"}}},"TotpAtivado":{"type":"object","properties":{"totpAtivoEm":{"type":"string","format":"date-time"},"codigosRecuperacao":{"type":"array","items":{"type":"string"},"description":"8 códigos de uso único, mostrados uma única vez"}}},"Semelhante":{"type":"object","properties":{"id":{"type":"string"},"protocolo":{"type":"string"},"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"resumo":{"type":"string"},"distanciaM":{"type":["number","null"]},"apoiosCount":{"type":"integer"},"fotoUrl":{"type":["string","null"]}}},"Mesclagem":{"type":["object","null"],"properties":{"originalId":{"type":"string"},"originalProtocolo":{"type":"string"},"apoiosSomados":{"type":"integer"},"apoiosOriginal":{"type":"integer"}}},"ConversaWhatsapp":{"type":"object","properties":{"id":{"type":"string"},"telefone":{"type":"string"},"telefoneFormatado":{"type":"string"},"nome":{"type":["string","null"]},"etapa":{"type":"string","enum":["INICIO","CATEGORIA","DESCRICAO","LOCALIZACAO","BAIRRO","FOTO","NOME","CONFIRMACAO","OUVIDORIA_TIPO","OUVIDORIA_ANONIMA","OUVIDORIA_DESCRICAO","ATENDENTE"]},"etapaLabel":{"type":"string"},"aguardandoAtendente":{"type":"boolean"},"ultimaMensagem":{"type":["string","null"]},"ultimaMensagemEm":{"type":"string","format":"date-time"},"transcricao":{"type":"array","items":{"type":"object","properties":{"de":{"type":"string","enum":["cidadao","bot"]},"texto":{"type":"string"},"em":{"type":"string","format":"date-time"}}}}}},"LinhaDadosAbertos":{"type":"object","properties":{"protocolo":{"type":"string"},"tipo":{"type":"string"},"categoria":{"type":["string","null"]},"area":{"type":["string","null"]},"orgao":{"type":["string","null"]},"bairro":{"type":["string","null"]},"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"prioridade":{"type":"string"},"descricao":{"type":["string","null"],"description":"Só para ocorrências de zeladoria; manifestações de ouvidoria não expõem o texto"},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"criadoEm":{"type":"string","format":"date-time"},"prazoEm":{"type":["string","null"],"format":"date-time"},"resolvidaEm":{"type":["string","null"],"format":"date-time"},"apoios":{"type":"integer"},"avaliacao":{"type":["integer","null"]}},"required":["protocolo","tipo","status","criadoEm"]},"DadosAbertos":{"type":"object","properties":{"municipio":{"type":"object","properties":{"slug":{"type":"string"},"nome":{"type":"string"},"uf":{"type":"string"}}},"ano":{"type":["integer","null"]},"total":{"type":"integer"},"geradoEm":{"type":"string","format":"date-time"},"licenca":{"type":"string","const":"CC BY 4.0"},"itens":{"type":"array","items":{"$ref":"#/components/schemas/LinhaDadosAbertos"}}}},"IndicadoresAbertos":{"type":"object","properties":{"municipio":{"type":"object","properties":{"slug":{"type":"string"},"nome":{"type":"string"},"uf":{"type":"string"}}},"geradoEm":{"type":"string","format":"date-time"},"licenca":{"type":"string"},"totais":{"type":"object","properties":{"registradas":{"type":"integer"},"abertas":{"type":"integer"},"resolvidas":{"type":"integer"},"indeferidas":{"type":"integer"},"atrasadas":{"type":"integer"}}},"tempoMedioHoras":{"type":["number","null"]},"dentroDoPrazoPct":{"type":["number","null"]},"satisfacao":{"type":"object","properties":{"media":{"type":["number","null"]},"total":{"type":"integer"}}},"porStatus":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"total":{"type":"integer"}}}},"porOrgao":{"type":"array","items":{"type":"object","properties":{"sigla":{"type":["string","null"]},"nome":{"type":["string","null"]},"total":{"type":"integer"},"abertas":{"type":"integer"},"resolvidas":{"type":"integer"}}}},"porCategoria":{"type":"array","items":{"type":"object","properties":{"categoria":{"type":["string","null"]},"area":{"type":["string","null"]},"total":{"type":"integer"},"abertas":{"type":"integer"}}}},"porBairro":{"type":"array","items":{"type":"object","properties":{"bairro":{"type":["string","null"]},"total":{"type":"integer"},"abertas":{"type":"integer"}}}},"porMes":{"type":"array","items":{"type":"object","properties":{"mes":{"type":"string","description":"AAAA-MM"},"novas":{"type":"integer"},"resolvidas":{"type":"integer"}}}}}},"PreviaRelatorio":{"type":"object","properties":{"municipio":{"type":"string"},"filtros":{"type":"object"},"descricao":{"type":"array","items":{"type":"string"}},"total":{"type":"integer"},"resumo":{"type":"object","properties":{"total":{"type":"integer"},"abertas":{"type":"integer"},"resolvidas":{"type":"integer"},"tempoMedioHoras":{"type":["number","null"]},"dentroDoPrazoPct":{"type":["number","null"]},"satisfacaoMedia":{"type":["number","null"]},"avaliacoes":{"type":"integer"},"apoios":{"type":"integer"}}},"limites":{"type":"object","properties":{"pdf":{"type":"integer"},"csv":{"type":"integer"}}}}},"ResultadoAlertas":{"type":"object","properties":{"ok":{"type":"boolean"},"executadoEm":{"type":"string","format":"date-time"},"duracaoMs":{"type":"integer"},"municipios":{"type":"integer"},"avaliadas":{"type":"integer"},"enviados":{"type":"object","properties":{"SLA_ESTOURADO":{"type":"integer"},"SLA_VENCE_48H":{"type":"integer"},"MUITOS_APOIOS":{"type":"integer"}}},"notificacoes":{"type":"integer"}}},"MunicipioResumo":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nome":{"type":"string"},"uf":{"type":"string"},"corPrimaria":{"type":"string"},"corSecundaria":{"type":"string"},"brasaoUrl":{"type":["string","null"]},"centroLat":{"type":"number"},"centroLng":{"type":"number"},"zoomInicial":{"type":"integer"}},"required":["id","slug","nome","uf"]},"MunicipioDetalhe":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nome":{"type":"string"},"uf":{"type":"string"},"corPrimaria":{"type":"string"},"corSecundaria":{"type":"string"},"brasaoUrl":{"type":["string","null"]},"centroLat":{"type":"number"},"centroLng":{"type":"number"},"zoomInicial":{"type":"integer"},"orgaos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sigla":{"type":"string"},"nome":{"type":"string"}}}},"categorias":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"area":{"type":"string"},"nome":{"type":"string"},"icone":{"type":"string"},"slaHoras":{"type":"integer"},"orgaoId":{"type":["string","null"]}}}},"bairros":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"zona":{"type":["string","null"]}}}}}},"Foto":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"tipo":{"type":"string","enum":["ANTES","DEPOIS","ANEXO"]},"criadoEm":{"type":"string","format":"date-time"}}},"Evento":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string","enum":["CRIACAO","MUDANCA_STATUS","ENCAMINHAMENTO","ATRIBUICAO","COMENTARIO_PUBLICO","COMENTARIO_INTERNO","FOTO_CONCLUSAO","MESCLAGEM"]},"deStatus":{"type":["string","null"],"enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"paraStatus":{"type":["string","null"],"enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"mensagem":{"type":["string","null"]},"publico":{"type":"boolean","description":"false = nota interna (só gestores veem)"},"criadoEm":{"type":"string","format":"date-time"},"autor":{"type":["object","null"],"properties":{"id":{"type":"string"},"nome":{"type":"string"}}}}},"Ocorrencia":{"type":"object","properties":{"id":{"type":"string"},"protocolo":{"type":"string","description":"`<PREFIXO>-<ANO>-<000000>`, ex.: MAO-2026-000123"},"tipo":{"type":"string","enum":["OCORRENCIA","RECLAMACAO","SUGESTAO","ELOGIO","DENUNCIA","SOLICITACAO_INFORMACAO"]},"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"prioridade":{"type":"string","enum":["BAIXA","NORMAL","ALTA","URGENTE"]},"titulo":{"type":["string","null"]},"descricao":{"type":"string"},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"endereco":{"type":["string","null"]},"anonima":{"type":"boolean"},"apoiosCount":{"type":"integer"},"prazoEm":{"type":["string","null"],"format":"date-time"},"resolvidaEm":{"type":["string","null"],"format":"date-time"},"respostaFinal":{"type":["string","null"]},"criadoEm":{"type":"string","format":"date-time"},"atualizadoEm":{"type":"string","format":"date-time"},"categoria":{"type":["object","null"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"area":{"type":"string"},"icone":{"type":"string"},"slaHoras":{"type":"integer"}}},"orgao":{"type":["object","null"],"properties":{"id":{"type":"string"},"sigla":{"type":"string"},"nome":{"type":"string"}}},"bairro":{"type":["object","null"],"properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"autor":{"type":["object","null"],"properties":{"id":{"type":"string"},"nome":{"type":"string"}},"description":"null quando anônima (exceto para o próprio autor e gestores)"},"responsavel":{"type":["object","null"],"properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"fotos":{"type":"array","items":{"$ref":"#/components/schemas/Foto"}},"avaliacao":{"type":["object","null"],"properties":{"nota":{"type":"integer"},"comentario":{"type":["string","null"]}}}},"required":["id","protocolo","tipo","status","descricao","criadoEm"]},"OcorrenciaDetalhe":{"allOf":[{"$ref":"#/components/schemas/Ocorrencia"},{"type":"object","properties":{"eventos":{"type":"array","items":{"$ref":"#/components/schemas/Evento"}},"souAutor":{"type":"boolean"},"apoiei":{"type":"boolean"}}}]},"ListaOcorrencias":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"perPage":{"type":"integer"},"itens":{"type":"array","items":{"$ref":"#/components/schemas/Ocorrencia"}}},"required":["total","page","perPage","itens"]},"Presign":{"type":"object","properties":{"chave":{"type":"string"},"uploadUrl":{"type":"string","description":"PUT direto no bucket (expira em 10 min)"},"url":{"type":"string","description":"URL pública da foto após o envio"},"expiraEm":{"type":"integer"}}},"ResumoDashboard":{"type":"object","properties":{"periodoDias":{"type":"integer","enum":[7,30,90]},"geradoEm":{"type":"string","format":"date-time"},"filtros":{"type":"object","properties":{"categoriaId":{"type":["string","null"]},"bairroId":{"type":["string","null"]}},"description":"Filtros do mapa de calor aplicados (eco da query)"},"indicadores":{"type":"object","properties":{"abertas":{"type":"integer"},"atrasadas":{"type":"integer"},"novasPeriodo":{"type":"integer"},"resolvidasPeriodo":{"type":"integer"},"tempoMedioHoras":{"type":["number","null"]},"taxaResolucao":{"type":["number","null"]},"satisfacaoMedia":{"type":["number","null"]},"avaliacoes":{"type":"integer"},"dentroDoPrazoPct":{"type":["number","null"]},"apoiosPeriodo":{"type":"integer"},"vencemEm48h":{"type":"integer"}}},"porStatus":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"total":{"type":"integer"}}}},"porOrgao":{"type":"array","items":{"type":"object","properties":{"orgaoId":{"type":["string","null"]},"sigla":{"type":["string","null"]},"nome":{"type":["string","null"]},"abertas":{"type":"integer"},"resolvidas":{"type":"integer"},"atrasadas":{"type":"integer"},"horasMedias":{"type":["number","null"]},"satisfacaoMedia":{"type":["number","null"]},"score":{"type":"number","description":"0–100: 50% prazo + 30% sem atraso + 20% satisfação"}}}},"porCategoria":{"type":"array","items":{"type":"object","properties":{"categoriaId":{"type":["string","null"]},"categoria":{"type":["string","null"]},"area":{"type":["string","null"]},"total":{"type":"integer"},"abertas":{"type":"integer"}}}},"porBairro":{"type":"array","items":{"type":"object","properties":{"bairroId":{"type":["string","null"]},"bairro":{"type":["string","null"]},"total":{"type":"integer"},"abertas":{"type":"integer"}}}},"serie":{"type":"array","items":{"type":"object","properties":{"dia":{"type":"string","description":"AAAA-MM-DD"},"novas":{"type":"integer"},"resolvidas":{"type":"integer"}}}},"alertasSla":{"type":"object","properties":{"atrasadas":{"type":"integer"},"vencemEm48h":{"type":"integer"},"itens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"protocolo":{"type":"string"},"prazoEm":{"type":"string","format":"date-time"},"horasAtraso":{"type":"number"},"status":{"type":"string"}}}}}},"satisfacao":{"type":"object","properties":{"media":{"type":["number","null"]},"total":{"type":"integer"},"distribuicao":{"type":"array","items":{"type":"object","properties":{"nota":{"type":"integer"},"total":{"type":"integer"}}}},"comentariosRecentes":{"type":"array","items":{"type":"object","properties":{"nota":{"type":"integer"},"comentario":{"type":"string"},"protocolo":{"type":"string"},"criadoEm":{"type":"string","format":"date-time"}}}}}},"maisApoiadas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"protocolo":{"type":"string"},"categoria":{"type":["string","null"]},"bairro":{"type":["string","null"]},"apoiosCount":{"type":"integer"},"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]}}}},"pontos":{"type":"array","items":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"},"status":{"type":"string","enum":["RECEBIDA","EM_ANALISE","ENCAMINHADA","EM_EXECUCAO","RESOLVIDA","INDEFERIDA","DUPLICADA"]},"categoriaId":{"type":["string","null"]},"peso":{"type":"number"}}},"description":"Pontos do mapa de calor"},"comparativoMensal":{"type":"object","description":"Mês em curso × mês anterior com variações em %"},"historico":{"type":"array","items":{"type":"object"},"description":"12 meses civis (novas, resolvidas, % no prazo)"},"calorPorBairro":{"type":"array","items":{"type":"object","properties":{"bairroId":{"type":["string","null"]},"bairro":{"type":["string","null"]},"total":{"type":"integer"},"abertas":{"type":"integer"},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]}}}},"calorPorCategoria":{"type":"array","items":{"type":"object","properties":{"categoriaId":{"type":["string","null"]},"categoria":{"type":["string","null"]},"total":{"type":"integer"}}}}},"required":["periodoDias","indicadores"]},"Orgao":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"sigla":{"type":"string"},"email":{"type":["string","null"]},"telefone":{"type":["string","null"]},"ativo":{"type":"boolean"},"_count":{"type":"object","properties":{"categorias":{"type":"integer"},"ocorrencias":{"type":"integer"},"membros":{"type":"integer"}}}},"required":["id","nome","sigla","ativo"]},"Categoria":{"type":"object","properties":{"id":{"type":"string"},"area":{"type":"string"},"nome":{"type":"string"},"icone":{"type":"string"},"slaHoras":{"type":"integer","description":"Prazo padrão (SLA) em horas"},"ordem":{"type":"integer"},"ativa":{"type":"boolean"},"orgaoId":{"type":["string","null"],"description":"Órgão responsável — regra de encaminhamento automático"},"orgao":{"type":["object","null"],"properties":{"id":{"type":"string"},"sigla":{"type":"string"},"nome":{"type":"string"}}},"_count":{"type":"object","properties":{"ocorrencias":{"type":"integer"}}}},"required":["id","area","nome","slaHoras","ativa"]},"Bairro":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"zona":{"type":["string","null"]},"_count":{"type":"object","properties":{"ocorrencias":{"type":"integer"}}}},"required":["id","nome"]},"Membro":{"type":"object","properties":{"id":{"type":"string"},"papel":{"type":"string","enum":["CIDADAO","OPERADOR","CAMPO","GESTOR","OUVIDOR","PREFEITO","ADMIN","SUPERADMIN"]},"orgaoId":{"type":["string","null"]},"criadoEm":{"type":"string","format":"date-time"},"usuario":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"email":{"type":["string","null"]},"telefone":{"type":["string","null"]},"ativo":{"type":"boolean"},"doisFatores":{"type":"boolean"},"criadoEm":{"type":"string","format":"date-time"}}},"orgao":{"type":["object","null"],"properties":{"id":{"type":"string"},"sigla":{"type":"string"},"nome":{"type":"string"}}}},"required":["id","papel","usuario"]},"MembroCriado":{"type":"object","properties":{"membro":{"$ref":"#/components/schemas/Membro"},"usuarioExistente":{"type":"boolean","description":"true quando o e-mail já tinha conta (a senha não muda)"},"vinculoExterno":{"type":"boolean","description":"true quando a conta existia em outra edição e foi vinculada com `vincularExistente: true` (o telefone não é devolvido nesse caso)"},"senhaTemporaria":{"type":["string","null"],"description":"Devolvida uma única vez, só para usuário novo. Deve ser trocada em /painel/seguranca."}},"required":["membro","usuarioExistente","vinculoExterno"]},"MunicipioAdmin":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nome":{"type":"string"},"uf":{"type":"string"},"ibgeCodigo":{"type":["string","null"]},"populacao":{"type":["integer","null"]},"corPrimaria":{"type":"string"},"corSecundaria":{"type":"string"},"brasaoUrl":{"type":["string","null"]},"whatsappNumero":{"type":["string","null"]},"whatsappPhoneNumberId":{"type":["string","null"]},"exigir2fa":{"type":"boolean"},"limiarApoiosAlerta":{"type":"integer"},"centroLat":{"type":"number"},"centroLng":{"type":"number"},"zoomInicial":{"type":"integer"},"ativo":{"type":"boolean"},"criadoEm":{"type":"string","format":"date-time"},"atualizadoEm":{"type":"string","format":"date-time"}},"required":["id","slug","nome","uf"]},"Auditoria":{"type":"object","properties":{"id":{"type":"string"},"acao":{"type":"string","description":"Ex.: OCORRENCIA_STATUS, CATEGORIA_EDITAR, MEMBRO_REMOVER, EXPORTACAO"},"entidade":{"type":"string"},"entidadeId":{"type":["string","null"]},"detalhes":{"description":"JSON livre — normalmente `{antes, depois}`"},"ip":{"type":["string","null"]},"criadoEm":{"type":"string","format":"date-time"},"usuario":{"type":["object","null"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"email":{"type":["string","null"]}}}},"required":["id","acao","entidade","criadoEm"]},"ListaAuditoria":{"type":"object","properties":{"total":{"type":"integer"},"pagina":{"type":"integer"},"porPagina":{"type":"integer"},"totalPaginas":{"type":"integer"},"itens":{"type":"array","items":{"$ref":"#/components/schemas/Auditoria"}},"acoes":{"type":"array","items":{"type":"string"},"description":"Ações distintas já registradas (para filtros)"},"entidades":{"type":"array","items":{"type":"string"}}}},"InventarioExportacao":{"type":"object","properties":{"municipio":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nome":{"type":"string"}}},"versao":{"type":"integer"},"contagens":{"type":"object","properties":{"ocorrencias":{"type":"integer"},"eventos":{"type":"integer"},"avaliacoes":{"type":"integer"},"orgaos":{"type":"integer"},"categorias":{"type":"integer"},"bairros":{"type":"integer"},"membros":{"type":"integer"},"auditoria":{"type":"integer"}}},"arquivos":{"type":"array","items":{"type":"object","properties":{"arquivo":{"type":"string"},"formato":{"type":"string","enum":["json","csv"]},"tabela":{"type":["string","null"]},"nome":{"type":"string"},"descricao":{"type":"string"},"registros":{"type":"integer"},"url":{"type":"string"}}}}}},"RestauracaoCatalogo":{"type":"object","properties":{"criadas":{"type":"integer"},"nomes":{"type":"array","items":{"type":"string"}},"semOrgao":{"type":"array","items":{"type":"string"},"description":"Categorias criadas sem órgão (a sigla padrão não existe no município)"},"orgaosCriados":{"type":"array","items":{"type":"string"}},"totalPadrao":{"type":"integer"}}},"Ok":{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"]}}}}