# Documentacao do Backend - Finance App

Este documento descreve o backend PHP localizado em `back/`. Ele foi escrito para uma pessoa conseguir consumir e manter a API com base no codigo atual e no schema real do banco `financeiro`.

## Visao geral

O backend e uma API PHP simples, sem framework full-stack. O ponto de entrada e `back/index.php`, que configura CORS, responde `OPTIONS`, define `Content-Type: application/json; charset=utf-8` e executa as rotas em `App\Routers\Routers`.

Dependencias principais:

- `bramus/router` 1.6.1: roteamento HTTP.
- `vlucas/phpdotenv` 5.6.3: leitura do arquivo `.env`.
- `firebase/php-jwt` 6.11.1: criacao e validacao de JWT.
- PDO MySQL/MariaDB: acesso ao banco.

Arquivos importantes:

- `back/index.php`: bootstrap HTTP.
- `back/App/Routers/Routers.php`: lista de rotas publicadas.
- `back/App/Middlewares/AuthMiddleware.php`: validacao JWT, mas atualmente nao esta conectado as rotas.
- `back/App/Controllers/ControllerBase.php`: includes, validacoes e contrato comum dos controllers.
- `back/App/Models/BaseModel.php`: filtros dinamicos, relacoes por FK, DataTable e metadados de tabela.
- `back/App/Models/QueryBuilder.php`: builder SQL usado em buscas especificas e resumos.

## Base URL

No frontend atual, a base configurada e:

```text
https://apifinance.supertheus.site
```

Em ambiente local com Devilbox/Apache, use a URL configurada no virtual host local. Todas as rotas abaixo sao relativas a base da API.

## Autenticacao

Existe login e existe middleware JWT, mas no roteador atual os `before()` de autenticacao estao comentados. Isso significa que, no codigo atual, as rotas `/root` e `/private` nao exigem token automaticamente.

Login:

```http
POST /login
Content-Type: application/json
```

```json
{
  "email": "usuario@email.com",
  "senha": "123456"
}
```

Resposta de sucesso:

```json
{
  "id": "1",
  "nome": "Usuario",
  "email": "usuario@email.com",
  "token": "jwt..."
}
```

Se o middleware for religado no futuro, envie:

```http
Authorization: Bearer <token>
Content-Type: application/json
```

Observacao importante: os controllers nao injetam `id_usuario` automaticamente a partir do token. Hoje, os payloads de criacao/listagem normalmente precisam informar `id_usuario` quando a tabela exige esse campo.

## Rotas publicadas

Publicas:

| Metodo | Rota | Controller | Observacao |
|---|---|---|---|
| GET | `/` | inline | Retorna `Home` |
| POST | `/` | inline | Retorna `Home` |
| POST | `/login` | `UsuariosController::login` | Autentica por email/senha |
| GET | `/payments-forms` | `FormasPagamentosController::find` | Lista formas de pagamento |

Root:

| Metodo | Rota |
|---|---|
| POST | `/root/usuarios/buscar` |
| POST | `/root/usuarios/criar` |
| POST | `/root/usuarios/listar` |
| PUT | `/root/usuarios/atualizar/{id}` |

Private:

| Recurso | Rotas |
|---|---|
| categorias | `POST /private/categorias/buscar`, `POST /private/categorias/criar`, `POST /private/categorias/listar`, `PUT /private/categorias/atualizar/{id}` |
| cards | `POST /private/cards/criar`, `POST /private/cards/listar`, `PUT /private/cards/atualizar/{id}` |
| tarefas | `POST /private/tarefas/criar`, `POST /private/tarefas/listar`, `PUT /private/tarefas/atualizar/{id}` |
| contas | `POST /private/contas/buscar`, `POST /private/contas/criar`, `POST /private/contas/listar`, `PUT /private/contas/atualizar/{id}` |
| contas-bancarias | `POST /private/contas-bancarias/buscar`, `POST /private/contas-bancarias/criar`, `POST /private/contas-bancarias/listar`, `PUT /private/contas-bancarias/atualizar/{id}` |
| resumos | `POST /private/resumos/geral`, `POST /private/resumos/anual` |
| notas | `POST /private/notas/criar`, `POST /private/notas/listar`, `PUT /private/notas/atualizar/{id}` |

Nao ha rotas `DELETE` publicadas, embora as models tenham metodo `delete()` fisico.

## Padrao de resposta

Listagens retornam:

```json
{
  "total": 10,
  "data": []
}
```

Criacao e atualizacao retornam o registro salvo.

Erros em controllers comuns retornam status `500` com:

```json
{
  "message": "descricao do erro"
}
```

Login invalido retorna `401`:

```json
{
  "message": "Unauthorized"
}
```

## Schema do banco

Banco analisado: `financeiro`.

Tabelas com rotas ou models:

| Tabela | Linhas no banco | Descricao |
|---|---:|---|
| `usuarios` | 2 | Usuarios do sistema |
| `categorias` | 12 | Categorias financeiras por usuario |
| `contas` | 182 | Contas a pagar/receber |
| `contas_bancarias` | 1 | Contas bancarias/carteiras |
| `formas_pagamentos` | 5 | Formas de pagamento |
| `kanban_cards` | 4 | Colunas/cards do kanban |
| `tarefas` | 3 | Tarefas vinculadas a cards |
| `notas` | 1 | Notas por usuario |

Tabelas existentes no banco, mas sem controller/model/rota no backend atual:

- `lista_compra`
- `lista_compras_itens`

### Usuarios

Tabela `usuarios`:

| Campo | Tipo | Obrigatorio | Default | Observacao |
|---|---|---|---|---|
| `id` | int | sim | auto | PK |
| `nome` | varchar(100) | sim | - | |
| `email` | varchar(100) | sim | - | unico |
| `senha` | varchar(200) | sim | `''` | salva com `password_hash` quando enviada |
| `deletado` | char(1) | nao | `N` | filtro automatico em listagem |
| `dthr_registro` | timestamp | nao | current timestamp | |
| `dthr_atualizacao` | timestamp | nao | current timestamp | on update |

### Categorias

Tabela `categorias`:

| Campo | Tipo | Obrigatorio | Default | Observacao |
|---|---|---|---|---|
| `id` | int | sim | auto | PK |
| `id_usuario` | int | sim | - | FK `usuarios.id` |
| `descricao` | varchar(255) | sim | - | |
| `deletado` | char(1) | nao | `N` | |
| `dthr_criacao` | timestamp | nao | current timestamp | |
| `dthr_registro` | timestamp | nao | current timestamp | on update |

### Contas

Tabela `contas`:

| Campo | Tipo | Obrigatorio | Default | Observacao |
|---|---|---|---|---|
| `id` | int | sim | auto | PK |
| `id_usuario` | int | sim | - | FK `usuarios.id` |
| `id_forma_pagamento` | int | nao | null | FK `formas_pagamentos.id` |
| `id_conta_bancaria` | int | nao | null | FK `contas_bancarias.id` |
| `id_categoria` | int | nao | null | FK `categorias.id` |
| `token_unico` | varchar(100) | sim | `''` | gerado no controller ao criar |
| `titulo` | varchar(100) | sim | - | |
| `descricao` | text | nao | null | |
| `valor` | decimal(15,2) | sim | - | |
| `valor_pago` | decimal(15,2) | nao | null | exigido ao pagar |
| `tipo` | char(1) | sim | - | `D` despesa, `R` receita |
| `status` | char(2) | sim | `PN` | no banco atual aparecem `PE` e `PA` |
| `vencimento` | date | sim | - | |
| `parcelas` | int | nao | null | usado na criacao parcelada |
| `num_parcela` | int | nao | null | numero da parcela/ocorrencia gerada |
| `conta_agrupada` | char(1) | nao | `N` | |
| `id_conta_resultante` | int | nao | null | criado em pagamento parcial |
| `id_original` | int | nao | null | referencia da conta resultante |
| `frequencia` | int | nao | null | usado na criacao recorrente |
| `valor_total_parcelas` | decimal(15,2) | nao | null | total original ao parcelar |
| `modo_pagamento` | char(1) | nao | null | tipo aberto no schema/frontend |
| `data_pagamento` | date | nao | null | preenchida ao pagar |
| `deletado` | char(1) | nao | `N` | |
| `dthr_registro` | timestamp | nao | current timestamp | |
| `dthr_atualizacao` | timestamp | nao | current timestamp | on update |

### Contas bancarias

Tabela `contas_bancarias`:

| Campo | Tipo | Obrigatorio | Default |
|---|---|---|---|
| `id` | int | sim | auto |
| `id_usuario` | int | sim | - |
| `descricao` | varchar(100) | sim | - |
| `observacoes` | text | sim | - |
| `saldo` | double(15,2) | sim | `0.00` |
| `principal` | char(1) | sim | `N` |
| `deletado` | char(1) | sim | `N` |
| `dthr_registro` | timestamp | sim | current timestamp |
| `dthr_atualizacao` | timestamp | sim | current timestamp |

### Formas de pagamento

Tabela `formas_pagamentos`:

| id | descricao | tipo |
|---:|---|---|
| 1 | DINHEIRO | `V` |
| 2 | CARTAO DE DEBITO | `V` |
| 3 | CARTAO DE CREDITO | `C` |
| 4 | PIX | `V` |
| 6 | DEBITO EM CONTA | `V` |

No banco, `tipo` possui valores `V` e `C`. A API nao define no codigo o significado formal desses valores.

### Kanban cards e tarefas

`kanban_cards`:

| Campo | Tipo | Obrigatorio | Observacao |
|---|---|---|---|
| `id` | int | sim | PK |
| `id_usuario` | int | sim | FK `usuarios.id` |
| `titulo` | varchar(100) | sim | |
| `ordem` | int | sim | |
| `deletado` | char(1) | nao | default `N` |
| `dthr_registro` | datetime | nao | |
| `dthr_atualizacao` | datetime | nao | |

`tarefas`:

| Campo | Tipo | Obrigatorio | Observacao |
|---|---|---|---|
| `id` | int | sim | PK |
| `id_usuario` | int | sim | FK `usuarios.id` |
| `id_card` | int | sim | FK `kanban_cards.id` |
| `titulo` | varchar(100) | sim | |
| `descricao` | longtext | nao | |
| `deletado` | char(1) | nao | default `N` |
| `dthr_registro` | datetime | nao | |
| `dthr_atualizacao` | datetime | nao | |

### Notas

Tabela `notas`:

| Campo | Tipo | Obrigatorio | Default |
|---|---|---|---|
| `id` | int | sim | auto |
| `id_usuario` | int | sim | - |
| `titulo` | varchar(255) | sim | `''` |
| `texto` | longtext | sim | - |
| `arquivado` | char(1) | nao | `N` |
| `deletado` | char(1) | nao | `N` |
| `dthr_registro` | timestamp | nao | current timestamp |
| `dthr_atualizacao` | timestamp | nao | current timestamp |

## Listagem com filtros

Todas as rotas `listar` chamam `find()` do controller. O controller adiciona automaticamente `deletado = "N"` ao filtro.

Payload base:

```json
{
  "filter": {},
  "limit": 20,
  "offset": 0,
  "order": {
    "cols": ["id"],
    "direction": "DESC"
  },
  "includes": {}
}
```

`limit`, `offset`, `order` e `includes` sao opcionais.

### Igualdade simples

```http
POST /private/contas/listar
Content-Type: application/json
```

```json
{
  "filter": {
    "id_usuario": 1,
    "status": "PE",
    "tipo": "D"
  }
}
```

### Paginacao

```json
{
  "filter": {
    "id_usuario": 1
  },
  "limit": 10,
  "offset": 20
}
```

### Ordenacao

```json
{
  "filter": {
    "id_usuario": 1
  },
  "order": {
    "cols": ["vencimento", "id"],
    "direction": "ASC"
  }
}
```

A direcao aceita apenas `ASC` ou `DESC`; qualquer outro valor vira `ASC`.

### LIKE

```json
{
  "filter": {
    "titulo": {
      "LIKE": "aluguel"
    }
  }
}
```

O backend adiciona `%` automaticamente, gerando busca aproximada.

### Operadores

```json
{
  "filter": {
    "valor": {
      "OPERATOR": ">=",
      "VALUE": 100
    }
  }
}
```

Outros exemplos:

```json
{
  "filter": {
    "vencimento": {
      "OPERATOR": "<",
      "VALUE": "2026-07-01"
    }
  }
}
```

Use operadores SQL validos e controlados: `=`, `<>`, `>`, `>=`, `<`, `<=`.

### BETWEEN

```json
{
  "filter": {
    "vencimento": {
      "BETWEEN": ["2026-07-01", "2026-07-31"]
    }
  }
}
```

### IN

```json
{
  "filter": {
    "status": {
      "IN": ["PE", "PA"]
    }
  }
}
```

### NOT IN

```json
{
  "filter": {
    "id_categoria": {
      "NOT IN": [3, 4]
    }
  }
}
```

### IS NULL

```json
{
  "filter": {
    "data_pagamento": {
      "IS NULL": true
    }
  }
}
```

### IS NOT NULL

```json
{
  "filter": {
    "id_conta_bancaria": {
      "IS NOT NULL": true
    }
  }
}
```

### OR entre campos

```json
{
  "filter": {
    "id_usuario": 1,
    "OR": {
      "titulo": {
        "LIKE": "internet"
      },
      "descricao": {
        "LIKE": "fibra"
      }
    }
  }
}
```

### AND/OR aninhado

```json
{
  "filter": {
    "id_usuario": 1,
    "OR": {
      "status": "PE",
      "AND": {
        "tipo": "D",
        "valor": {
          "OPERATOR": ">=",
          "VALUE": 500
        }
      }
    }
  }
}
```

### OR no mesmo campo

```json
{
  "filter": {
    "tipo": {
      "OR": ["D", "R"]
    }
  }
}
```

### Consulta completa de contas

```json
{
  "filter": {
    "id_usuario": 1,
    "tipo": "D",
    "status": {
      "IN": ["PE", "PA"]
    },
    "vencimento": {
      "BETWEEN": ["2026-07-01", "2026-07-31"]
    },
    "OR": {
      "titulo": {
        "LIKE": "cartao"
      },
      "descricao": {
        "LIKE": "compra"
      }
    }
  },
  "limit": 25,
  "offset": 0,
  "order": {
    "cols": ["vencimento", "titulo"],
    "direction": "ASC"
  }
}
```

## Includes

`includes` carrega relacoes configuradas em `relationConfig`. Existem dois tipos:

- Relacao manual: exemplo `kanban_cards -> tarefas`.
- Relacao por FK detectada no banco: exemplo `contas.id_categoria -> categorias.id`.

Formato:

```json
{
  "filter": {
    "id_usuario": 1
  },
  "includes": {
    "usuarios": true
  }
}
```

Includes aceitam:

```json
{
  "includes": {
    "tarefas": {
      "filter": {},
      "limit": 10,
      "offset": 0,
      "order": {
        "cols": ["id"],
        "direction": "DESC"
      },
      "includes": {}
    }
  }
}
```

Profundidade maxima: 5 niveis.

Relacoes que funcionam no runtime atual:

| Entidade | Include | Tipo de retorno | Observacao |
|---|---|---|---|
| `categorias` | `usuarios` | array | FK `id_usuario` |
| `contas` | `usuarios` | array | FK `id_usuario` |
| `contas` | `contas_bancarias` | array | FK `id_conta_bancaria` |
| `contas` | `categorias` | array | FK `id_categoria` |
| `contas_bancarias` | `usuarios` | array | FK `id_usuario` |
| `kanban_cards` | `tarefas` | array | relacao manual `id_card` |
| `kanban_cards` | `usuarios` | array | FK `id_usuario` |
| `tarefas` | `usuarios` | array | FK `id_usuario` |
| `tarefas` | `kanban_cards` | array | FK `id_card` |
| `notas` | `usuarios` | array | FK `id_usuario` |

Atencao: `contas.id_forma_pagamento` existe no banco, mas o include de `formas_pagamentos` nao fica disponivel no codigo atual porque o mapa interno de `BaseModel` usa nome singular incorreto (`formas_pagamento`) enquanto a tabela real e `formas_pagamentos`.

Exemplo: listar contas com categoria e conta bancaria:

```json
{
  "filter": {
    "id_usuario": 1
  },
  "includes": {
    "categorias": true,
    "contas_bancarias": true,
    "usuarios": true
  }
}
```

Exemplo: listar cards com tarefas:

```json
{
  "filter": {
    "id_usuario": 1
  },
  "includes": {
    "tarefas": {
      "filter": {
        "deletado": "N"
      },
      "order": {
        "cols": ["id"],
        "direction": "ASC"
      }
    }
  }
}
```

## Criacao e atualizacao padrao

Na criacao, o controller valida obrigatorios com base no schema real da tabela. Campos `id` e timestamps sao ignorados.

Na atualizacao, somente os campos enviados e existentes na tabela sao alterados.

Exemplo de criar categoria:

```http
POST /private/categorias/criar
Content-Type: application/json
```

```json
{
  "id_usuario": 1,
  "descricao": "Moradia"
}
```

Exemplo de atualizar categoria:

```http
PUT /private/categorias/atualizar/10
Content-Type: application/json
```

```json
{
  "descricao": "Casa e moradia"
}
```

Exclusao logica:

Nao ha rota `DELETE`. Para ocultar um registro das listagens, atualize `deletado` para `S`:

```json
{
  "deletado": "S"
}
```

## Usuarios

Criar usuario:

```http
POST /root/usuarios/criar
Content-Type: application/json
```

```json
{
  "nome": "Maria Silva",
  "email": "maria@example.com",
  "senha": "123456"
}
```

A senha e salva com bcrypt.

Listar usuarios:

```http
POST /root/usuarios/listar
Content-Type: application/json
```

```json
{
  "filter": {
    "nome": {
      "LIKE": "Maria"
    }
  },
  "order": {
    "cols": ["nome"],
    "direction": "ASC"
  }
}
```

Atualizar senha:

```http
PUT /root/usuarios/atualizar/1
Content-Type: application/json
```

```json
{
  "senha": "nova-senha"
}
```

A rota `POST /root/usuarios/buscar` esta publicada, mas nao deve ser usada no estado atual. O metodo de busca le `$_REQUEST['id_conta']` e filtra por `usuarios.id_conta`, coluna que nao existe na tabela `usuarios` do banco analisado. Use `/root/usuarios/listar` com `filter` e `LIKE`.

## Categorias

Criar:

```json
{
  "id_usuario": 1,
  "descricao": "Alimentacao"
}
```

Listar:

```json
{
  "filter": {
    "id_usuario": 1,
    "descricao": {
      "LIKE": "Alim"
    }
  },
  "order": {
    "cols": ["descricao"],
    "direction": "ASC"
  }
}
```

Buscar:

```http
POST /private/categorias/buscar
```

```json
{
  "searchTerm": "maria",
  "limit": 10,
  "offset": 0
}
```

Atencao: no codigo atual, o metodo `search()` de `CategoriasModel` esta copiado para pesquisar a tabela `usuarios`, nao `categorias`. Para buscar categorias por descricao, prefira `/private/categorias/listar` com `LIKE`.

## Contas bancarias

Criar:

```http
POST /private/contas-bancarias/criar
Content-Type: application/json
```

```json
{
  "id_usuario": 1,
  "descricao": "Carteira principal",
  "observacoes": "Conta usada para pagamentos do dia a dia",
  "saldo": 1500.00,
  "principal": "S"
}
```

Listar:

```json
{
  "filter": {
    "id_usuario": 1,
    "principal": "S"
  }
}
```

Atualizar saldo manualmente:

```http
PUT /private/contas-bancarias/atualizar/1
Content-Type: application/json
```

```json
{
  "saldo": 1750.00
}
```

Atencao: `/private/contas-bancarias/buscar` tambem usa busca copiada sobre `usuarios` e depende de `id_conta`. Para consultar contas bancarias, prefira `/listar` com filtros.

## Formas de pagamento

Listar:

```http
GET /payments-forms
```

Resposta:

```json
{
  "total": 5,
  "data": [
    {
      "id": "1",
      "descricao": "DINHEIRO",
      "tipo": "V",
      "deletado": "N"
    }
  ]
}
```

Nao existem rotas publicadas para criar, editar ou deletar formas de pagamento.

## Contas

Contas sao o principal fluxo de negocio. Elas representam despesas (`tipo = "D"`) e receitas (`tipo = "R"`), com status pendente (`PE`) ou pago (`PA`) nos dados atuais.

### Criar conta simples

```http
POST /private/contas/criar
Content-Type: application/json
```

```json
{
  "id_usuario": 1,
  "id_categoria": 2,
  "titulo": "Aluguel",
  "descricao": "Aluguel de julho",
  "valor": 1200.00,
  "tipo": "D",
  "status": "PE",
  "vencimento": "2026-07-10"
}
```

O controller sempre gera `token_unico` antes de inserir. Se voce enviar `token_unico`, ele sera sobrescrito.

### Criar conta com frequencia

Use `frequencia` quando voce quer repetir a mesma conta por varios meses, mantendo o mesmo valor.

```json
{
  "id_usuario": 1,
  "id_categoria": 2,
  "titulo": "Assinatura",
  "descricao": "Assinatura mensal",
  "valor": 59.90,
  "tipo": "D",
  "status": "PE",
  "vencimento": "2026-07-05",
  "frequencia": 6
}
```

Com `frequencia = 6`, o backend cria 6 contas:

| num_parcela | vencimento |
|---:|---|
| 1 | 2026-07-05 |
| 2 | 2026-08-05 |
| 3 | 2026-09-05 |
| 4 | 2026-10-05 |
| 5 | 2026-11-05 |
| 6 | 2026-12-05 |

Resposta:

```json
{
  "id": "10",
  "id_usuario": "1",
  "titulo": "Assinatura",
  "valor": "59.90",
  "num_parcela": "1",
  "contas_geradas": []
}
```

`contas_geradas` contem todas as contas criadas. O objeto principal da resposta e a primeira conta gerada.

### Criar conta parcelada

Use `parcelas` quando um valor total precisa ser dividido em partes mensais iguais.

```json
{
  "id_usuario": 1,
  "id_categoria": 3,
  "titulo": "Notebook",
  "descricao": "Compra parcelada",
  "valor": 3000.00,
  "tipo": "D",
  "status": "PE",
  "vencimento": "2026-07-15",
  "parcelas": 3
}
```

O backend gera:

| num_parcela | vencimento | valor | valor_total_parcelas |
|---:|---|---:|---:|
| 1 | 2026-07-15 | 1000.00 | 3000.00 |
| 2 | 2026-08-15 | 1000.00 | 3000.00 |
| 3 | 2026-09-15 | 1000.00 | 3000.00 |

Regra importante: se `frequencia` e `parcelas` forem enviados juntos, `frequencia` ganha prioridade porque o controller testa `frequencia` primeiro. Nao envie os dois no mesmo payload.

### Listar contas por periodo

```json
{
  "filter": {
    "id_usuario": 1,
    "vencimento": {
      "BETWEEN": ["2026-07-01", "2026-07-31"]
    }
  },
  "order": {
    "cols": ["vencimento"],
    "direction": "ASC"
  }
}
```

### Listar contas a pagar pendentes

```json
{
  "filter": {
    "id_usuario": 1,
    "tipo": "D",
    "status": "PE"
  }
}
```

### Listar receitas pagas

```json
{
  "filter": {
    "id_usuario": 1,
    "tipo": "R",
    "status": "PA"
  }
}
```

### Marcar conta como paga

```http
PUT /private/contas/atualizar/123
Content-Type: application/json
```

```json
{
  "status": "PA",
  "valor_pago": 1200.00,
  "id_forma_pagamento": 1,
  "data_pagamento": "2026-07-10",
  "id_conta_bancaria": 1
}
```

Regras aplicadas quando o status muda para `PA`:

- `valor_pago` e obrigatorio.
- `valor_pago` deve ser maior que zero.
- `id_forma_pagamento` e obrigatorio.
- Se `data_pagamento` nao for enviada, o backend usa a data atual do servidor.
- Se `id_conta_bancaria` for enviado, o saldo da conta bancaria e atualizado.
- Para despesa (`tipo = "D"`), o saldo e reduzido por `valor_pago`.
- Para receita (`tipo = "R"`), o saldo e aumentado por `valor_pago`.

### Pagamento parcial

Se `valor_pago` for menor que o valor original da conta, o backend cria automaticamente uma nova conta pendente com o restante.

Exemplo: conta original de `1000.00`, pagamento de `400.00`:

```json
{
  "status": "PA",
  "valor_pago": 400.00,
  "id_forma_pagamento": 1,
  "id_conta_bancaria": 1
}
```

Efeito:

- A conta original vira `PA`.
- Uma nova conta e criada com `valor = 600.00`.
- A nova conta recebe `status = "PE"`.
- A nova conta recebe `id_original` apontando para a conta original.
- A conta original recebe `id_conta_resultante` apontando para a nova conta.
- O vencimento da conta resultante e `+1 month` a partir da data do pagamento/processamento.

### Cancelar ou reabrir pagamento

Nao existe regra especifica para reverter saldo bancario quando uma conta ja paga volta para `PE`. O update generico permite alterar `status`, mas a regra de saldo so roda quando o status muda para `PA`.

## Cards e tarefas

Criar card:

```http
POST /private/cards/criar
Content-Type: application/json
```

```json
{
  "id_usuario": 1,
  "titulo": "A fazer",
  "ordem": 1
}
```

Criar card com tarefas no mesmo payload:

```json
{
  "id_usuario": 1,
  "titulo": "A fazer",
  "ordem": 1,
  "tarefas": [
    {
      "id_usuario": 1,
      "titulo": "Conferir contas do mes",
      "descricao": "Validar despesas pendentes"
    }
  ]
}
```

O `id_card` das tarefas e injetado automaticamente apos criar o card.

Listar cards com tarefas:

```json
{
  "filter": {
    "id_usuario": 1
  },
  "includes": {
    "tarefas": true
  },
  "order": {
    "cols": ["ordem"],
    "direction": "ASC"
  }
}
```

Criar tarefa avulsa:

```http
POST /private/tarefas/criar
Content-Type: application/json
```

```json
{
  "id_usuario": 1,
  "id_card": 1,
  "titulo": "Pagar fornecedor",
  "descricao": "Vence hoje"
}
```

## Notas

Criar:

```http
POST /private/notas/criar
Content-Type: application/json
```

```json
{
  "id_usuario": 1,
  "titulo": "Ideias",
  "texto": "Anotar melhorias do dashboard",
  "arquivado": "N"
}
```

Listar:

```json
{
  "filter": {
    "id_usuario": 1,
    "arquivado": "N"
  },
  "order": {
    "cols": ["dthr_registro"],
    "direction": "DESC"
  }
}
```

Arquivar:

```http
PUT /private/notas/atualizar/1
Content-Type: application/json
```

```json
{
  "arquivado": "S"
}
```

## Resumos

### Resumo geral

```http
POST /private/resumos/geral
Content-Type: application/json
```

```json
{
  "inicio": "2026-07-01",
  "fim": "2026-07-31",
  "usuario": 1
}
```

Resposta:

```json
{
  "totalPagar": 1000,
  "totalFaltaPagar": 700,
  "totalPago": 300,
  "totalReceber": 2000,
  "totalFaltaReceber": 500,
  "totalRecebido": 1500,
  "quantidadeFaltaPagar": 2,
  "quantidadePaga": 1,
  "quantidadeTotalPagar": 3,
  "quantidadeFaltaReceber": 1,
  "quantidadeRecebida": 4,
  "quantidadeTotalReceber": 5,
  "saldo": 1000
}
```

O resumo usa `contas.vencimento` entre `inicio 00:00:00` e `fim 23:59:59`, filtra `deletado = "N"` e soma por `tipo`/`status`.

### Resumo anual

```http
POST /private/resumos/anual
Content-Type: application/json
```

```json
{
  "ano": 2026,
  "usuario": 1
}
```

Resposta:

```json
[
  {
    "mes": "janeiro",
    "totalPagar": 0,
    "totalReceber": 0,
    "saldo": 0
  }
]
```

Sempre retorna 12 itens, um por mes.

## DataTable

`BaseModel::dataTable()` e os controllers possuem `searchDataTable()`, mas nenhuma rota `/tabela` esta publicada em `Routers.php`. Portanto, essa funcionalidade existe no codigo, mas nao esta acessivel pela API atual.

Se uma rota for adicionada no futuro, o payload esperado e o padrao DataTables:

```json
{
  "draw": 1,
  "start": 0,
  "length": 10,
  "search": {
    "value": "texto"
  },
  "order": [
    {
      "column": 0,
      "dir": "asc"
    }
  ],
  "columns": [
    {
      "data": "titulo",
      "name": "titulo",
      "searchable": true,
      "orderable": true,
      "search": {
        "value": ""
      }
    }
  ]
}
```

## Pontos de atencao

- As rotas `/private` nao estao protegidas no roteador atual.
- `id_usuario` deve ser enviado nos payloads que precisam desse campo.
- `date_ranger` e lido pelos controllers, mas as models atuais ignoram esse argumento.
- Os campos de filtro e ordenacao entram na montagem SQL. Nao passe nomes de colunas vindos de input nao confiavel.
- O operador de `OPERATOR` tambem entra diretamente no SQL. Use somente operadores conhecidos.
- Todas as rotas `/buscar` publicadas devem ser tratadas como nao confiaveis no estado atual: elas usam `$_REQUEST['id_conta']` e/ou consultam `usuarios.id_conta`, campo inexistente no schema analisado. Prefira `/listar` com filtros.
- Include de forma de pagamento em contas nao funciona no mapa atual por diferenca de nome singular/plural.
- `delete()` nas models faz exclusao fisica, mas nao ha rota publicada para ele.
- `formatData()` de algumas models foi copiado de usuarios e pode nao representar corretamente recursos sem `nome`, `email` e `status`. Como nenhuma rota DataTable esta publicada, isso nao afeta o uso normal.
