Initial project import

This commit is contained in:
Tiago
2026-09-29 12:12:31 -03:00
commit c435bb5e23
120 changed files with 5371 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
# Prompt 06 — Painel Cliente (escritório): condomínios, contatos, espaços comuns, assembleias, documentos
## Contexto
Prompts 01–05 concluídos: autenticação completa, painel master funcionando, empresas sendo provisionadas com tenant próprio. **Leia `10-tracker-progresso.md` antes de começar.**
Este prompt implementa o CRUD principal do menu **Cliente → Cadastro Condomínio**, que é o coração do sistema: condomínios, contatos (síndico/subsíndico/conselheiro), vínculo de funcionários, espaços comuns, assembleias e documentos.
Todos os endpoints deste prompt exigem `exigirFuncionario` (Prompt 04) e operam sobre o `db_empresa_<slug>` do `empresa_id` do token (usar `TenantDataSourceProvider` do Prompt 03).
## Objetivo
CRUD completo de `condominios`, `contatos` + `contato_condominio`, `funcionario_condominio`, `espacos_comuns`, `assembleias`, `documentos` (upload de arquivo).
## Especificação
### 1. Condomínios
```
POST /api/condominios body: {"nome", "cnpj", "endereco"}
GET /api/condominios lista todos do tenant
GET /api/condominios/{id}
→ resposta agregada: dados do condomínio + síndico atual (via ContatoCondominioDao) +
contagem de assembleias futuras + contagem de avisos ativos (isso é o "checklist"
que o funcionário usa como referência rápida)
PUT /api/condominios/{id}
```
### 2. Contatos (síndico/subsíndico/conselheiro)
```
POST /api/contatos body: {"nome", "telefone", "email"}
→ cria a pessoa (sem vínculo ainda)
POST /api/condominios/{id}/contatos/vincular
body: {"contato_id" (ou dados de um contato novo pra criar+vincular numa chamada só),
"tipo": "sindico"|"subsindico"|"conselheiro",
"data_inicio_mandato", "data_fim_mandato"}
→ grava em contato_condominio; se marcar tipo=sindico e já existir outro síndico ativo
pro mesmo condomínio, perguntar/forçar: por padrão, encerrar automaticamente o mandato
anterior (status='inativo', data_fim_mandato=hoje) e ativar o novo — deixar isso
documentado no código como decisão de negócio
GET /api/condominios/{id}/contatos lista todos os vínculos ativos daquele condomínio
DELETE /api/condominios/{id}/contatos/{contatoId}?tipo=... (desvincula — não apaga o contato,
só remove o vínculo daquele condomínio/tipo específico; um contato pode continuar
vinculado a outros condomínios)
```
### 3. Funcionários vinculados a condomínios
```
POST /api/condominios/{id}/funcionarios-vinculados
body: {"funcionario_id"} (funcionario precisa existir em db_master, mesma empresa)
GET /api/condominios/{id}/funcionarios-vinculados
DELETE /api/condominios/{id}/funcionarios-vinculados/{funcionarioId}
```
### 4. Espaços comuns
```
POST /api/condominios/{id}/espacos-comuns
body: {"nome", "descricao", "valor_utilizacao_centavos", "indice_correcao"}
GET /api/condominios/{id}/espacos-comuns
PUT /api/condominios/{id}/espacos-comuns/{espacoId}
→ se o valor mudar, atualizar data_ultimo_reajuste=hoje automaticamente
```
### 5. Assembleias
```
POST /api/condominios/{id}/assembleias
body: {"tipo", "data_hora", "local", "pauta"}
GET /api/condominios/{id}/assembleias (ordenar por data_hora desc)
PUT /api/condominios/{id}/assembleias/{id} (inclui mudar status: agendada/realizada/cancelada)
```
### 6. Documentos (upload)
```
POST /api/condominios/{id}/documentos multipart/form-data: arquivo + tipo
→ salvar o arquivo em um diretório local montado como volume Docker (ex: /app/uploads/
<empresa_slug>/<condominio_id>/<uuid>-<nome_original>), gravar caminho_armazenamento
com esse path relativo
→ validar extensão (permitir: pdf, jpg, jpeg, png, docx) e tamanho máximo (ex: 10MB)
GET /api/condominios/{id}/documentos
GET /api/documentos/{id}/download → serve o arquivo (Content-Disposition: attachment)
```
Adicionar o volume de uploads no `docker-compose.yml` do Prompt 01 (`./uploads:/app/uploads`).
### 7. Auditoria
Toda operação de `POST`/`PUT`/`DELETE` deste prompt deve gravar uma linha em `log_auditoria` (tabela_afetada, registro_id, ação, dados_anteriores/dados_novos em JSON, funcionario_id do token).
## Critérios de aceite
- [ ] Criar um condomínio, vincular um síndico e um subsíndico, e chamar `GET /api/condominios/{id}` mostra o síndico atual corretamente.
- [ ] Vincular um segundo síndico ao mesmo condomínio encerra automaticamente o mandato do primeiro (`status='inativo'`).
- [ ] O mesmo `contato` pode ser vinculado como síndico em dois condomínios diferentes simultaneamente.
- [ ] Upload de um PDF funciona; upload de um `.exe` é rejeitado com erro claro; upload de 15MB é rejeitado.
- [ ] `log_auditoria` recebe uma linha para cada operação de escrita feita neste prompt (testar com pelo menos 3 operações diferentes).
- [ ] Todos os endpoints só retornam/alteram dados do `empresa_id` do token — tentar acessar `/api/condominios/{id}` de outra empresa retorna 404 (não 403 — não revelar que o ID existe em outro tenant).
## Ao concluir
Atualizar `10-tracker-progresso.md`: Prompt 06 concluído, data, resumo. Confirmar Prompts 01–05 seguem marcados.