developer #3
@ -2,3 +2,5 @@ VITE_KEYCLOAK_URL=
|
||||
VITE_KEYCLOAK_REALM=
|
||||
VITE_KEYCLOAK_CLIENT_ID=
|
||||
VITE_API_URL=
|
||||
# Ativar mock: copie esta linha para .env.development.local e defina como true
|
||||
VITE_USE_MOCK=false
|
||||
|
||||
699
docs/api-backend.md
Normal file
699
docs/api-backend.md
Normal file
@ -0,0 +1,699 @@
|
||||
# API Backend — portal-modumfiscal-web
|
||||
|
||||
Documentação dos endpoints que o portal consome. Base URL: `https://sistema.modumfiscal.com.br/api/v1`.
|
||||
|
||||
**Envelope padrão de resposta (sucesso):**
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-05-18T10:00:00Z",
|
||||
"statusCode": 200,
|
||||
"responseType": "SUCCESS",
|
||||
"message": "OK",
|
||||
"data": { }
|
||||
}
|
||||
```
|
||||
|
||||
**Envelope de erro:**
|
||||
```json
|
||||
{
|
||||
"statusCode": 422,
|
||||
"message": "Unprocessable Entity",
|
||||
"internalCode": "119",
|
||||
"description": "Registro não foi encontrado."
|
||||
}
|
||||
```
|
||||
|
||||
Respostas binárias (PDF) retornam `Content-Type: application/pdf` direto — sem envelope.
|
||||
|
||||
---
|
||||
|
||||
## Módulo Público — sem autenticação
|
||||
|
||||
Headers obrigatórios em toda requisição:
|
||||
- `X-Municipio: <id_municipio>`
|
||||
- `X-Dominio: <subdominio>`
|
||||
|
||||
---
|
||||
|
||||
### Prefeitura (bootstrap)
|
||||
|
||||
#### `GET /publico/prefeitura/{dominio}`
|
||||
|
||||
Retorna a configuração visual e institucional da prefeitura.
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"idMunicipio": 1,
|
||||
"nomePrefeitura": "Prefeitura Municipal de Tutóia",
|
||||
"nomeMunicipio": "Tutóia",
|
||||
"uf": "MA",
|
||||
"template": "tutoia",
|
||||
"pathLogo": "/logos/tutoia.png",
|
||||
"pathBackground": "/backgrounds/tutoia.jpeg",
|
||||
"corPrimaria": "#F59E0B",
|
||||
"cnpj": "12.345.678/0001-90",
|
||||
"site": "https://tutoia.ma.gov.br",
|
||||
"email": "atendimento@tutoia.ma.gov.br",
|
||||
"telefone": "(98) 3478-1234"
|
||||
}
|
||||
```
|
||||
|
||||
> `pathLogo` e `pathBackground` são paths relativos — o frontend resolve para URL absoluta via `resolverUrl()`.
|
||||
|
||||
---
|
||||
|
||||
### Certidão Pública
|
||||
|
||||
#### `GET /publico/certidao/consultar`
|
||||
|
||||
Consulta a situação fiscal do contribuinte.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `documento` | string | sim | CPF (11 dígitos) ou CNPJ (14 dígitos) sem formatação |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"situacao": "NEGATIVA",
|
||||
"nomeContribuinte": "João da Silva Santos"
|
||||
}
|
||||
```
|
||||
|
||||
`situacao` possíveis: `NEGATIVA` · `POSITIVA` · `POSITIVA_EFEITOS_NEGATIVA`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /publico/certidao/emitir`
|
||||
|
||||
Emite a certidão em PDF.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `documento` | string | sim | CPF/CNPJ sem formatação |
|
||||
| `tipoCertidao` | string | sim | `NEGATIVA` · `POSITIVA` · `POSITIVA_EFEITOS_NEGATIVA` |
|
||||
|
||||
**Response:** `application/pdf` (binário direto, sem envelope)
|
||||
|
||||
---
|
||||
|
||||
### IPTU Público
|
||||
|
||||
#### `GET /publico/iptu/consultar`
|
||||
|
||||
Retorna todos os imóveis e débitos de IPTU do contribuinte ou de uma inscrição específica.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `documento` | string | condicional | CPF/CNPJ sem formatação (informar `documento` **ou** `inscricao`) |
|
||||
| `inscricao` | string | condicional | Inscrição imobiliária (ex: `0001.001.0001.001`) |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"inscricaoImobiliaria": "0001.001.0001.001",
|
||||
"enderecoCompleto": "Rua das Flores, 100 — Centro",
|
||||
"debitos": [
|
||||
{
|
||||
"id": "d1",
|
||||
"descricao": "IPTU 2025 — Cota 4/10",
|
||||
"vencimento": "30/04/2025",
|
||||
"valor": 125.90,
|
||||
"valorAtualizado": 138.49,
|
||||
"status": "VENCIDO"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`status` possíveis: `VENCIDO` · `A_VENCER` · `PAGO` · `PARCELADO`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /publico/iptu/carne`
|
||||
|
||||
Emite o carnê completo de IPTU em PDF.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `inscricao` | string | sim | Inscrição imobiliária |
|
||||
|
||||
**Response:** `application/pdf`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /publico/iptu/boleto`
|
||||
|
||||
Emite o boleto avulso de uma parcela.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `idDebito` | string | sim | ID do débito retornado por `/consultar` |
|
||||
|
||||
**Response:** `application/pdf`
|
||||
|
||||
---
|
||||
|
||||
### Primeiro Acesso
|
||||
|
||||
Fluxo de 4 etapas para o contribuinte criar senha de acesso ao portal.
|
||||
|
||||
#### `GET /publico/primeiro-acesso/verificar`
|
||||
|
||||
Valida se o documento tem cadastro e retorna os canais disponíveis para envio do código.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório |
|
||||
|---|---|---|
|
||||
| `documento` | string | sim |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"nome": "Maria Aparecida Santos",
|
||||
"canais": [
|
||||
{ "tipo": "EMAIL", "valor": "ma***@gmail.com" },
|
||||
{ "tipo": "WHATSAPP", "valor": "(98) *****-8901" },
|
||||
{ "tipo": "SMS", "valor": "(98) *****-8901" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`tipo` possíveis: `EMAIL` · `WHATSAPP` · `SMS`
|
||||
|
||||
---
|
||||
|
||||
#### `POST /publico/primeiro-acesso/codigo`
|
||||
|
||||
Envia o código de 6 dígitos para o canal escolhido.
|
||||
|
||||
**Request body:**
|
||||
```json
|
||||
{
|
||||
"documento": "12345678900",
|
||||
"canal": "EMAIL"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{ "enviado": true }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `POST /publico/primeiro-acesso/validar`
|
||||
|
||||
Valida o código digitado e retorna um token temporário para definição de senha.
|
||||
|
||||
**Request body:**
|
||||
```json
|
||||
{
|
||||
"documento": "12345678900",
|
||||
"codigo": "123456"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{ "token": "eyJhb..." }
|
||||
```
|
||||
|
||||
Erros: `422` se código inválido ou expirado.
|
||||
|
||||
---
|
||||
|
||||
#### `POST /publico/primeiro-acesso/senha`
|
||||
|
||||
Define a nova senha usando o token temporário.
|
||||
|
||||
**Request body:**
|
||||
```json
|
||||
{
|
||||
"token": "eyJhb...",
|
||||
"senha": "MinhaS3nha!"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{ "sucesso": true }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Credenciamento
|
||||
|
||||
Fluxo para novo contribuinte solicitar cadastro no sistema.
|
||||
|
||||
#### `GET /publico/credenciamento/verificar`
|
||||
|
||||
Verifica se o documento já tem cadastro ou pode ser credenciado.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório |
|
||||
|---|---|---|
|
||||
| `documento` | string | sim |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{ "situacao": "APTO" }
|
||||
```
|
||||
|
||||
`situacao` possíveis:
|
||||
- `APTO` — pode prosseguir com o credenciamento
|
||||
- `JA_CREDENCIADO` — já tem acesso ao sistema
|
||||
- `BLOQUEADO` — documento bloqueado (contatar prefeitura)
|
||||
|
||||
---
|
||||
|
||||
#### `GET /publico/cep/{cep}`
|
||||
|
||||
Busca endereço por CEP para auto-preenchimento no formulário de credenciamento.
|
||||
|
||||
**Path param:** `cep` — 8 dígitos sem hífen
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"logradouro": "Rua das Acácias",
|
||||
"bairro": "Centro",
|
||||
"localidade": "Tutóia",
|
||||
"uf": "MA"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `POST /publico/credenciamento/solicitar`
|
||||
|
||||
Envia a solicitação de credenciamento para análise da prefeitura.
|
||||
|
||||
**Request body (Pessoa Física):**
|
||||
```json
|
||||
{
|
||||
"documento": "12345678900",
|
||||
"tipoPessoa": "FISICA",
|
||||
"nomeCompleto": "João da Silva Santos",
|
||||
"dataNascimento": "1990-05-15",
|
||||
"email": "joao@email.com",
|
||||
"emailConfirmacao": "joao@email.com",
|
||||
"telefone": "98991234567",
|
||||
"whatsapp": true,
|
||||
"endereco": {
|
||||
"cep": "65900000",
|
||||
"logradouro": "Rua das Flores",
|
||||
"numero": "100",
|
||||
"complemento": "Apto 201",
|
||||
"bairro": "Centro",
|
||||
"cidade": "Tutóia",
|
||||
"uf": "MA"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Request body adicional (Pessoa Jurídica):**
|
||||
```json
|
||||
{
|
||||
"tipoPessoa": "JURIDICA",
|
||||
"razaoSocial": "Empresa LTDA",
|
||||
"nomeFantasia": "Empresa",
|
||||
"inscricaoEstadual": "12345678",
|
||||
"representanteLegal": {
|
||||
"nomeCompleto": "João da Silva",
|
||||
"cpf": "12345678900",
|
||||
"cargo": "Diretor"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{ "protocolo": "CRED-2025-00123" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Módulo Portal — requer autenticação
|
||||
|
||||
Header obrigatório além dos de tenant:
|
||||
- `Authorization: Bearer <jwt_keycloak>`
|
||||
|
||||
---
|
||||
|
||||
### Painel
|
||||
|
||||
#### `GET /contribuinte/painel/resumo`
|
||||
|
||||
Dados do card de resumo do dashboard.
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"totalDebitos": 1250.90,
|
||||
"certidoesAtivas": 2,
|
||||
"alvarasAndamento": 2,
|
||||
"ultimoPagamento": 430.00,
|
||||
"debitosVencidos": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /contribuinte/painel/atividades`
|
||||
|
||||
Lista das últimas atividades do contribuinte.
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"tipo": "PAGAMENTO",
|
||||
"descricao": "IPTU 2025 — Parcela 3/10 paga",
|
||||
"data": "15/05/2025"
|
||||
},
|
||||
{
|
||||
"tipo": "CERTIDAO",
|
||||
"descricao": "Certidão Negativa emitida",
|
||||
"data": "10/05/2025"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`tipo` possíveis: `PAGAMENTO` · `CERTIDAO` · `DEBITO` · `ALVARA` · `CADASTRO`
|
||||
|
||||
---
|
||||
|
||||
### Débitos
|
||||
|
||||
#### `GET /contribuinte/debitos`
|
||||
|
||||
Lista os débitos do contribuinte com filtros opcionais.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `tipo` | string | não | `IPTU` · `ISS` · `TAXA` · `MULTA` |
|
||||
| `status` | string | não | `VENCIDO` · `A_VENCER` · `PARCELADO` |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"id": "deb1",
|
||||
"descricao": "IPTU 2025 — Cota 4/10",
|
||||
"tipo": "IPTU",
|
||||
"referencia": "ABR/2025",
|
||||
"vencimento": "30/04/2025",
|
||||
"valor": 125.90,
|
||||
"valorAtualizado": 138.49,
|
||||
"status": "VENCIDO"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`valorAtualizado` inclui juros e multa (pode ser igual a `valor` se em dia).
|
||||
|
||||
---
|
||||
|
||||
#### `GET /contribuinte/debitos/{id}/guia`
|
||||
|
||||
Emite a guia de pagamento (boleto/DAM) de um débito específico em PDF.
|
||||
|
||||
**Path param:** `id` — ID do débito
|
||||
|
||||
**Response:** `application/pdf`
|
||||
|
||||
---
|
||||
|
||||
### Certidões
|
||||
|
||||
#### `GET /contribuinte/certidoes`
|
||||
|
||||
Lista todas as certidões emitidas pelo contribuinte.
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"id": "cert1",
|
||||
"tipo": "Certidão Negativa de Débitos",
|
||||
"numero": "CN-2025-00481",
|
||||
"dataEmissao": "10/05/2025",
|
||||
"dataValidade": "07/11/2025",
|
||||
"status": "ATIVA"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`status` possíveis: `ATIVA` · `VENCIDA` · `CANCELADA`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /contribuinte/certidoes/{id}/pdf`
|
||||
|
||||
Reemite uma certidão em PDF.
|
||||
|
||||
**Path param:** `id` — ID da certidão
|
||||
|
||||
**Response:** `application/pdf`
|
||||
|
||||
> Retorna `422` se a certidão estiver com status `CANCELADA`.
|
||||
|
||||
---
|
||||
|
||||
### Alvarás
|
||||
|
||||
#### `GET /contribuinte/alvaras`
|
||||
|
||||
Lista os processos de alvará do contribuinte.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `status` | string | não | Filtro por status do processo |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"id": "alv1",
|
||||
"tipo": "Alvará de Funcionamento — Comércio Varejista",
|
||||
"numeroProcesso": "ALV-2025-00342",
|
||||
"status": "EM_ANALISE",
|
||||
"ultimaAtualizacao": "14/05/2025",
|
||||
"etapas": [
|
||||
{ "nome": "Protocolo", "concluida": true, "atual": false },
|
||||
{ "nome": "Análise", "concluida": false, "atual": true },
|
||||
{ "nome": "Vistoria", "concluida": false, "atual": false },
|
||||
{ "nome": "Emissão", "concluida": false, "atual": false }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`status` possíveis: `EM_ANALISE` · `AGUARDANDO_DOCUMENTOS` · `DEFERIDO` · `INDEFERIDO` · `CANCELADO`
|
||||
|
||||
---
|
||||
|
||||
### Pagamentos
|
||||
|
||||
#### `GET /contribuinte/pagamentos`
|
||||
|
||||
Histórico de pagamentos do contribuinte, filtrável por ano.
|
||||
|
||||
**Query params:**
|
||||
| Param | Tipo | Obrigatório | Descrição |
|
||||
|---|---|---|---|
|
||||
| `ano` | integer | não | Ano de referência (padrão: ano atual) |
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"id": "pag1",
|
||||
"descricao": "IPTU 2025 — Cota 3/10",
|
||||
"referencia": "MAR/2025",
|
||||
"dataPagamento": "28/03/2025",
|
||||
"formaPagamento": "PIX",
|
||||
"valor": 125.90
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`formaPagamento` possíveis: `BOLETO` · `PIX` · `CARTAO` · `TRANSFERENCIA` · `ESPECIE`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /contribuinte/pagamentos/{id}/comprovante`
|
||||
|
||||
Baixa o comprovante de um pagamento em PDF.
|
||||
|
||||
**Path param:** `id` — ID do pagamento
|
||||
|
||||
**Response:** `application/pdf`
|
||||
|
||||
---
|
||||
|
||||
### Dados Cadastrais
|
||||
|
||||
#### `GET /contribuinte/dados`
|
||||
|
||||
Retorna os dados cadastrais completos do contribuinte autenticado.
|
||||
|
||||
**Response `data` (Pessoa Física):**
|
||||
```json
|
||||
{
|
||||
"tipoPessoa": "FISICA",
|
||||
"documento": "123.456.789-00",
|
||||
"nomeCompleto": "João da Silva Santos",
|
||||
"dataNascimento": "15/06/1975",
|
||||
"email": "joao.santos@email.com",
|
||||
"telefone": "(98) 99123-4567",
|
||||
"whatsapp": true,
|
||||
"endereco": {
|
||||
"cep": "65900-000",
|
||||
"logradouro": "Rua das Flores",
|
||||
"numero": "100",
|
||||
"complemento": "Apto 201",
|
||||
"bairro": "Centro",
|
||||
"cidade": "Tutóia",
|
||||
"uf": "MA"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Campos adicionais (Pessoa Jurídica):**
|
||||
```json
|
||||
{
|
||||
"tipoPessoa": "JURIDICA",
|
||||
"documento": "12.345.678/0001-90",
|
||||
"razaoSocial": "Empresa LTDA",
|
||||
"nomeFantasia": "Empresa",
|
||||
"inscricaoEstadual": "12345678"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `PUT /contribuinte/dados/contato`
|
||||
|
||||
Atualiza os dados de contato editáveis (email, telefone, WhatsApp).
|
||||
|
||||
**Request body:**
|
||||
```json
|
||||
{
|
||||
"email": "novo@email.com",
|
||||
"telefone": "98991234567",
|
||||
"whatsapp": true
|
||||
}
|
||||
```
|
||||
|
||||
`telefone` deve ser enviado **sem formatação** (apenas dígitos).
|
||||
|
||||
**Response `data`:**
|
||||
```json
|
||||
{ "atualizado": true }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Avisos (pendente no backend)
|
||||
|
||||
#### `GET /publico/avisos/{dominio}`
|
||||
|
||||
Retorna os avisos/banners exibidos no carousel da Home.
|
||||
|
||||
> **Status:** endpoint ainda não implementado no backend. O frontend usa dados estáticos hardcoded em `HomeView.vue`.
|
||||
|
||||
**Response `data` esperada:**
|
||||
```json
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"id": "av1",
|
||||
"titulo": "IPTU 2025 — Prazo final",
|
||||
"descricao": "Últimas parcelas com desconto até 30 de junho.",
|
||||
"tipo": "ALERTA",
|
||||
"ativo": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`tipo` sugeridos: `INFO` · `ALERTA` · `URGENTE`
|
||||
|
||||
---
|
||||
|
||||
## Fluxo de Autenticação
|
||||
|
||||
O portal usa **Keycloak PKCE** — nenhuma credencial trafega pelo frontend.
|
||||
|
||||
```
|
||||
1. Usuário informa CPF/CNPJ na Home
|
||||
2. LoginView monta — exibe doc mascarado + campo senha
|
||||
3. entrar() → redireciona para Keycloak (PKCE code challenge)
|
||||
4. Keycloak autentica e redireciona de volta com ?code=
|
||||
5. authService troca code por access_token + refresh_token
|
||||
6. authStore.setSession(token, userInfo) persiste sessão
|
||||
7. router.push({ name: 'painel' })
|
||||
```
|
||||
|
||||
**Realm:** `modumfiscal-dev`
|
||||
**Client ID:** `portal-modumfiscal-web`
|
||||
**Grant type:** `authorization_code` com PKCE (S256)
|
||||
**Token endpoint:** `https://keycloakprod.modumfiscal.com.br/realms/modumfiscal-dev/protocol/openid-connect/token`
|
||||
|
||||
O `preferred_username` do JWT é o CPF/CNPJ sem formatação — usado como identificador do contribuinte nas chamadas ao backend.
|
||||
|
||||
---
|
||||
|
||||
## Status de Implementação dos Endpoints
|
||||
|
||||
| Endpoint | Frontend pronto | Backend pronto | Mock |
|
||||
|---|---|---|---|
|
||||
| `GET /publico/prefeitura/{dominio}` | ✓ | ✓ | — |
|
||||
| `GET /publico/certidao/consultar` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/certidao/emitir` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/iptu/consultar` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/iptu/carne` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/iptu/boleto` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/primeiro-acesso/verificar` | ✓ | pendente | ✓ |
|
||||
| `POST /publico/primeiro-acesso/codigo` | ✓ | pendente | ✓ |
|
||||
| `POST /publico/primeiro-acesso/validar` | ✓ | pendente | ✓ |
|
||||
| `POST /publico/primeiro-acesso/senha` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/credenciamento/verificar` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/cep/{cep}` | ✓ | pendente | ✓ |
|
||||
| `POST /publico/credenciamento/solicitar` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/painel/resumo` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/painel/atividades` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/debitos` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/debitos/{id}/guia` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/certidoes` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/certidoes/{id}/pdf` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/alvaras` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/pagamentos` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/pagamentos/{id}/comprovante` | ✓ | pendente | ✓ |
|
||||
| `GET /contribuinte/dados` | ✓ | pendente | ✓ |
|
||||
| `PUT /contribuinte/dados/contato` | ✓ | pendente | ✓ |
|
||||
| `GET /publico/avisos/{dominio}` | parcial | pendente | — |
|
||||
@ -21,7 +21,12 @@ async function startApp() {
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
app.use(pinia)
|
||||
|
||||
if (import.meta.env.VITE_USE_MOCK === 'true') {
|
||||
const { setupMocks } = await import('@/mocks/mockInterceptor')
|
||||
setupMocks(pinia)
|
||||
} else {
|
||||
await bootstrapPrefeitura(pinia)
|
||||
}
|
||||
|
||||
app.use(router)
|
||||
app.use(PrimeVue, primeVueConfig)
|
||||
|
||||
281
src/mocks/mockInterceptor.js
Normal file
281
src/mocks/mockInterceptor.js
Normal file
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Mock interceptor para desenvolvimento sem backend.
|
||||
* Ativado via VITE_USE_MOCK=true em .env.development.local
|
||||
*
|
||||
* Técnica: injeta config.adapter em cada request que bate em uma rota mockada.
|
||||
* O adapter retorna dados falsos diretamente, sem fazer chamada HTTP.
|
||||
* Simula latência aleatória de 400–800ms para comportamento realista.
|
||||
*/
|
||||
|
||||
import apiClient, { apiClientPublico } from '@/config/apiClient'
|
||||
import { useAuthStore } from '@/stores/authStore'
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
function envelope(data) {
|
||||
return {
|
||||
timestamp: new Date().toISOString(),
|
||||
statusCode: 200,
|
||||
responseType: 'SUCCESS',
|
||||
message: 'OK',
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
// PDF mínimo válido — suficiente para o browser abrir/baixar
|
||||
const FAKE_PDF = '%PDF-1.4\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj\n3 0 obj<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]>>endobj\nxref\n0 4\n0000000000 65535 f\n0000000009 00000 n\n0000000068 00000 n\n0000000125 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxref\n240\n%%EOF'
|
||||
const fakePdf = () => new Blob([FAKE_PDF], { type: 'application/pdf' })
|
||||
|
||||
// ─── Rotas mockadas ───────────────────────────────────────────────────────────
|
||||
|
||||
const routes = [
|
||||
|
||||
// ── Certidão pública ──────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/publico\/certidao\/consultar/.test(url) && m === 'get',
|
||||
data: envelope({ situacao: 'NEGATIVA', nomeContribuinte: 'João da Silva Santos' }),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/publico\/certidao\/emitir/.test(url) && m === 'get',
|
||||
blob: true,
|
||||
},
|
||||
|
||||
// ── IPTU público ──────────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/publico\/iptu\/consultar/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
content: [
|
||||
{
|
||||
inscricaoImobiliaria: '0001.001.0001.001',
|
||||
enderecoCompleto: 'Rua das Flores, 100 — Centro',
|
||||
debitos: [
|
||||
{ id: 'd1', descricao: 'IPTU 2025 — Cota 4/10', vencimento: '30/04/2025', valor: 125.90, valorAtualizado: 138.49, status: 'VENCIDO' },
|
||||
{ id: 'd2', descricao: 'IPTU 2025 — Cota 5/10', vencimento: '31/05/2025', valor: 125.90, valorAtualizado: 125.90, status: 'A_VENCER' },
|
||||
],
|
||||
},
|
||||
{
|
||||
inscricaoImobiliaria: '0001.001.0002.001',
|
||||
enderecoCompleto: 'Av. Principal, 250 — Bairro Novo',
|
||||
debitos: [],
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{ test: (url, m) => /\/publico\/iptu\/carne/.test(url) && m === 'get', blob: true },
|
||||
{ test: (url, m) => /\/publico\/iptu\/boleto/.test(url) && m === 'get', blob: true },
|
||||
|
||||
// ── Primeiro Acesso ───────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/publico\/primeiro-acesso\/verificar/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
nome: 'Maria Aparecida Santos',
|
||||
canais: [
|
||||
{ tipo: 'EMAIL', valor: 'ma***@gmail.com' },
|
||||
{ tipo: 'WHATSAPP', valor: '(98) *****-8901' },
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/publico\/primeiro-acesso\/codigo/.test(url) && m === 'post',
|
||||
data: envelope({ enviado: true }),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/publico\/primeiro-acesso\/validar/.test(url) && m === 'post',
|
||||
data: envelope({ token: 'mock-reset-token-abc123' }),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/publico\/primeiro-acesso\/senha/.test(url) && m === 'post',
|
||||
data: envelope({ sucesso: true }),
|
||||
},
|
||||
|
||||
// ── Credenciamento ────────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/publico\/credenciamento\/verificar/.test(url) && m === 'get',
|
||||
data: envelope({ situacao: 'APTO' }),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/publico\/cep\//.test(url) && m === 'get',
|
||||
data: envelope({ logradouro: 'Rua das Acácias', bairro: 'Centro', localidade: 'Tutóia', uf: 'MA' }),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/publico\/credenciamento\/solicitar/.test(url) && m === 'post',
|
||||
data: envelope({ protocolo: 'CRED-2025-00123' }),
|
||||
},
|
||||
|
||||
// ── Portal — Painel ───────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/painel\/resumo/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
totalDebitos: 1250.90,
|
||||
certidoesAtivas: 2,
|
||||
alvarasAndamento: 2,
|
||||
ultimoPagamento: 430.00,
|
||||
debitosVencidos: 1,
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/painel\/atividades/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
content: [
|
||||
{ tipo: 'PAGAMENTO', descricao: 'IPTU 2025 — Parcela 3/10 paga', data: '15/05/2025' },
|
||||
{ tipo: 'CERTIDAO', descricao: 'Certidão Negativa emitida', data: '10/05/2025' },
|
||||
{ tipo: 'DEBITO', descricao: 'ISS 1º Trimestre 2025 lançado', data: '01/04/2025' },
|
||||
{ tipo: 'ALVARA', descricao: 'Alvará de Funcionamento — documento solicitado', data: '28/03/2025' },
|
||||
],
|
||||
}),
|
||||
},
|
||||
|
||||
// ── Portal — Débitos ──────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/debitos$/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
content: [
|
||||
{ id: 'deb1', descricao: 'IPTU 2025 — Cota 4/10', tipo: 'IPTU', referencia: 'ABR/2025', vencimento: '30/04/2025', valor: 125.90, valorAtualizado: 138.49, status: 'VENCIDO' },
|
||||
{ id: 'deb2', descricao: 'IPTU 2025 — Cota 5/10', tipo: 'IPTU', referencia: 'MAI/2025', vencimento: '31/05/2025', valor: 125.90, valorAtualizado: 125.90, status: 'A_VENCER' },
|
||||
{ id: 'deb3', descricao: 'ISS — 1º Trimestre 2025', tipo: 'ISS', referencia: '1T/2025', vencimento: '28/02/2025', valor: 520.00, valorAtualizado: 572.00, status: 'VENCIDO' },
|
||||
{ id: 'deb4', descricao: 'Taxa de Licença 2025', tipo: 'TAXA', referencia: '2025', vencimento: '30/06/2025', valor: 180.00, valorAtualizado: 180.00, status: 'A_VENCER' },
|
||||
{ id: 'deb5', descricao: 'IPTU 2024 — Parcelamento', tipo: 'IPTU', referencia: '2024', vencimento: '15/06/2025', valor: 307.10, valorAtualizado: 307.10, status: 'PARCELADO' },
|
||||
],
|
||||
}),
|
||||
},
|
||||
{ test: (url, m) => /\/contribuinte\/debitos\/.+\/guia/.test(url) && m === 'get', blob: true },
|
||||
|
||||
// ── Portal — Certidões ────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/certidoes$/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
content: [
|
||||
{ id: 'cert1', tipo: 'Certidão Negativa de Débitos', numero: 'CN-2025-00481', dataEmissao: '10/05/2025', dataValidade: '07/11/2025', status: 'ATIVA' },
|
||||
{ id: 'cert2', tipo: 'Positiva com Efeitos de Negativa', numero: 'CPN-2025-00219', dataEmissao: '03/03/2025', dataValidade: '29/08/2025', status: 'ATIVA' },
|
||||
{ id: 'cert3', tipo: 'Certidão Negativa de Débitos', numero: 'CN-2024-01102', dataEmissao: '15/10/2024', dataValidade: '13/04/2025', status: 'VENCIDA' },
|
||||
],
|
||||
}),
|
||||
},
|
||||
{ test: (url, m) => /\/contribuinte\/certidoes\/.+\/pdf/.test(url) && m === 'get', blob: true },
|
||||
|
||||
// ── Portal — Alvarás ──────────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/alvaras/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
content: [
|
||||
{
|
||||
id: 'alv1', tipo: 'Alvará de Funcionamento — Comércio Varejista',
|
||||
numeroProcesso: 'ALV-2025-00342', status: 'EM_ANALISE', ultimaAtualizacao: '14/05/2025',
|
||||
etapas: [
|
||||
{ nome: 'Protocolo', concluida: true, atual: false },
|
||||
{ nome: 'Análise', concluida: false, atual: true },
|
||||
{ nome: 'Vistoria', concluida: false, atual: false },
|
||||
{ nome: 'Emissão', concluida: false, atual: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'alv2', tipo: 'Alvará de Construção — Reforma Residencial',
|
||||
numeroProcesso: 'ALV-2024-00891', status: 'AGUARDANDO_DOCUMENTOS', ultimaAtualizacao: '02/04/2025',
|
||||
etapas: [
|
||||
{ nome: 'Protocolo', concluida: true, atual: false },
|
||||
{ nome: 'Docs', concluida: false, atual: true },
|
||||
{ nome: 'Análise', concluida: false, atual: false },
|
||||
{ nome: 'Emissão', concluida: false, atual: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'alv3', tipo: 'Alvará de Funcionamento — Bares e Restaurantes',
|
||||
numeroProcesso: 'ALV-2023-00114', status: 'DEFERIDO', ultimaAtualizacao: '10/01/2024',
|
||||
etapas: [
|
||||
{ nome: 'Protocolo', concluida: true, atual: false },
|
||||
{ nome: 'Análise', concluida: true, atual: false },
|
||||
{ nome: 'Vistoria', concluida: true, atual: false },
|
||||
{ nome: 'Emissão', concluida: true, atual: false },
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
|
||||
// ── Portal — Pagamentos ───────────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/pagamentos/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
content: [
|
||||
{ id: 'pag1', descricao: 'IPTU 2025 — Cota 3/10', referencia: 'MAR/2025', dataPagamento: '28/03/2025', formaPagamento: 'PIX', valor: 125.90 },
|
||||
{ id: 'pag2', descricao: 'IPTU 2025 — Cota 2/10', referencia: 'FEV/2025', dataPagamento: '27/02/2025', formaPagamento: 'BOLETO', valor: 125.90 },
|
||||
{ id: 'pag3', descricao: 'ISS — 4º Trimestre 2024', referencia: '4T/2024', dataPagamento: '15/01/2025', formaPagamento: 'BOLETO', valor: 480.00 },
|
||||
{ id: 'pag4', descricao: 'Taxa Coleta Lixo 2024', referencia: '2024', dataPagamento: '10/12/2024', formaPagamento: 'CARTAO', valor: 98.50 },
|
||||
{ id: 'pag5', descricao: 'IPTU 2025 — Cota 1/10', referencia: 'JAN/2025', dataPagamento: '30/01/2025', formaPagamento: 'TRANSFERENCIA', valor: 125.90 },
|
||||
],
|
||||
}),
|
||||
},
|
||||
{ test: (url, m) => /\/contribuinte\/pagamentos\/.+\/comprovante/.test(url) && m === 'get', blob: true },
|
||||
|
||||
// ── Portal — Dados Cadastrais ─────────────────────────────────────────
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/dados$/.test(url) && m === 'get',
|
||||
data: envelope({
|
||||
tipoPessoa: 'FISICA',
|
||||
documento: '123.456.789-00',
|
||||
nomeCompleto: 'João da Silva Santos',
|
||||
dataNascimento: '15/06/1975',
|
||||
email: 'joao.santos@email.com',
|
||||
telefone: '(98) 99123-4567',
|
||||
whatsapp: true,
|
||||
endereco: {
|
||||
cep: '65900-000',
|
||||
logradouro: 'Rua das Flores',
|
||||
numero: '100',
|
||||
complemento: 'Apto 201',
|
||||
bairro: 'Centro',
|
||||
cidade: 'Tutóia',
|
||||
uf: 'MA',
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: (url, m) => /\/contribuinte\/dados\/contato/.test(url) && m === 'put',
|
||||
data: envelope({ atualizado: true }),
|
||||
},
|
||||
]
|
||||
|
||||
// ─── Engine ───────────────────────────────────────────────────────────────────
|
||||
|
||||
function buildAdapter(route) {
|
||||
return (config) => {
|
||||
const ms = 400 + Math.random() * 400
|
||||
return new Promise((resolve) =>
|
||||
setTimeout(() => resolve({
|
||||
data: route.blob ? fakePdf() : route.data,
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
headers: { 'content-type': route.blob ? 'application/pdf' : 'application/json' },
|
||||
config,
|
||||
request: {},
|
||||
}), ms),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function applyInterceptor(client) {
|
||||
client.interceptors.request.use((config) => {
|
||||
const url = config.url ?? ''
|
||||
const method = (config.method ?? 'get').toLowerCase()
|
||||
const route = routes.find((r) => r.test(url, method))
|
||||
if (route) config.adapter = buildAdapter(route)
|
||||
return config
|
||||
})
|
||||
}
|
||||
|
||||
// ─── Entry point ─────────────────────────────────────────────────────────────
|
||||
|
||||
export function setupMocks(pinia) {
|
||||
// Sessão fake para acessar rotas autenticadas do /portal/*
|
||||
const auth = useAuthStore(pinia)
|
||||
auth.setSession('mock-dev-token', {
|
||||
name: 'João da Silva',
|
||||
preferred_username: '12345678900',
|
||||
email: 'joao@mock.dev',
|
||||
})
|
||||
|
||||
applyInterceptor(apiClientPublico)
|
||||
applyInterceptor(apiClient)
|
||||
|
||||
console.info('[mock] Interceptor ativo — todas as chamadas à API estão sendo mockadas.')
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user