intimacao-api
v1.0.1
Published
```bash # Instale as dependências $ npm install
Readme
Api de Intimação
Rodando a API no ambiente de desenvolvimento
# Instale as dependências
$ npm install
# Gere uma cópia do arquivo ".env.example" como ".env.local"
$ cp ./.env.example ./.env.local
# Inicie os contêineres dos serviços
$ docker-compose up app
# Use a API na porta 2024
$ curl http://localhost:2024/api/status
# O serviço do mongodb exporta a porta 27018 para a sua máquina, você pode acessar o banco para debugar em qualquer client a partir da URI a seguir
$ mongodb://root:[email protected]:27018/intima-db-dev?directConnection=true
# O serviço do redis exporta a porta 6380 para a sua máquina, você pode acessar o banco para debugar em qualquer client a partir das informações no docker-compose.yml
# O docker-compose também dispobiliza o redis-commander, basta iniciá-lo e acessar a porta 8082 no browser para ter acesso ao banco do redis em uma interface gráfica
$ docker-compose up redis-commanderNomeação de Arquivos e Estrutura de Pastas
Este projeto adota um padrão de nomeação contextual para arquivos, visando melhorar a clareza e a organização do código. Este padrão facilita a identificação da função de um arquivo apenas pelo seu nome, o que é especialmente útil em grandes projetos com múltiplos arquivos de nomes similares, mas que pertencem a diferentes contextos ou têm diferentes responsabilidades.
Exemplos de Nomeação Contextual
Workers:
- Pasta:
workers - Arquivo:
task.worker.ts
- Pasta:
Controllers:
- Pasta:
controllers - Arquivo:
user.controller.ts
- Pasta:
Services:
- Pasta:
services - Arquivo:
auth.service.ts
- Pasta:
Models:
- Pasta:
models - Arquivo:
user.model.ts
- Pasta:
Benefícios do Padrão de Nomeação Contextual
- Clareza:
- Facilita a compreensão imediata da responsabilidade de um arquivo.
- Organização:
- Mantém uma estrutura de projeto organizada e coerente.
- Manutenção:
- Simplifica a navegação e manutenção do código, especialmente em projetos grandes.
- Consistência:
- Promove a consistência na nomeação dos arquivos, tornando o projeto mais legível e previsível.
Implementação do Padrão
Para implementar este padrão, siga as diretrizes abaixo:
Nomeação Descritiva:
- Use nomes descritivos para as funções e responsabilidades dos arquivos.
Prefixos ou Sufixos:
- Adicione prefixos ou sufixos que descrevam o contexto, como
.worker,.controller,.service, etc.
- Adicione prefixos ou sufixos que descrevam o contexto, como
Estrutura de Pastas:
- Organize os arquivos em pastas que correspondam aos seus contextos ou responsabilidades.
Exemplo de Estrutura de Projeto
src/
workers/
task.worker.ts
notification.worker.ts
controllers/
user.controller.ts
auth.controller.ts
services/
auth.service.ts
user.service.ts
models/
user.model.ts
post.model.tsDocumentação de rotas
Estamos utilizando o RapiDoc como ferramenta para apresentar a documenação da API, ela permite interagir com APIs definidas em formato OpenAPI.
Também estamos utilizando o swagger-jsdocs, é uma biblioteca que permite gerar documentação Swagger (OpenAPI) diretamente dos comentários JSDoc em seu código JavaScript ou TypeScript.
Como documentar rotas usando Swagger-jsdoc
Para documentar suas rotas usando Swagger-jsdoc, adicione os comentários diretamente acima das rotas. Aqui está um exemplo de como documentar a rota para criar um novo usuário:
/**
* @openapi
* /api/user:
* post:
* summary: Create a new user
* tags: [User]
* parameters:
* - in: header
* name: authorization
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* username:
* type: string
* format: email
* description: User's email
* password:
* type: string
* description: User's password
* minLength: 8
* maxLength: 24
* responses:
* '201':
* description: User created successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* _id:
* type: string
* description: User's ID
* username:
* type: string
* description: User's email
* __v:
* type: number
* description: Version key
* '400':
* description: Bad request
*/
router.post("/", bodyValidationMiddleware(CreateUserRequestDto), createUser);Como usar class-validator para validações de entrada e saída
Para garantir que as entradas e saídas da API estejam validadas corretamente, use o class-validator. Abaixo está um exemplo de como definir DTOs de request e response:
Request DTO
import { IsEmail, IsNotEmpty, Length } from "class-validator";
export class CreateUserRequestDto {
@IsEmail()
@IsNotEmpty()
username: string;
@IsNotEmpty()
@Length(8, 24)
password: string;
}Response DTO
export class CreateUserResponseDto {
_id: string;
username: string;
__v: number;
constructor(data: Partial<CreateUserResponseDto>) {
Object.assign(this, data);
}
}Passos para Implementação
Documentar a rota:
- Adicione os comentários do Swagger-jsdoc diretamente acima das rotas.
- Defina os parâmetros, corpo da requisição e respostas conforme o exemplo fornecido.
Definir DTOs:
- Utilize
class-validatorpara criar classes que representem os DTOs de request e response. - Adicione as anotações de validação (
@IsEmail,@IsNotEmpty,@Length, etc.) para garantir que os dados estejam corretos antes de processá-los.
- Utilize
Integrar validação com a rota:
- Utilize um middleware de validação para aplicar as validações definidas nos DTOs ao processar a requisição.
- Alguns middlewares disponíveis
Estrutura das Coleções
Users Collection
Descrição: Armazena as informações dos usuários que acessam o sistema.
Exemplo de Documento:
{
"_id": ObjectId("60d21b467d8f7e5e4c8c6ef0"),
"username": "alice",
"password": "hashedpassword"
}
Campos:
_id: Identificador único do usuário.
username: Nome de usuário para login.
password: Senha do usuário, armazenada de forma segura (hasheada)Intimations Collection
Descrição: Armazena as intimações criadas, incluindo o histórico de status que contém messageId para rastreamento.
Exemplo de Documento:
{
"_id": ObjectId("60d21b867d8f7e5e4c8c6ef4"),
"tituloId": ObjectId("60d21b567d8f7e5e4c8c6ef1"),
"usuarioId": ObjectId("60d21b467d8f7e5e4c8c6ef0"),
"dataCriacao": ISODate("2024-05-21T10:00:00Z"),
"status": "Pendente",
"historicoStatus": [
{
"status": "Pendente",
"dataMudanca": ISODate("2024-05-21T10:00:00Z"),
"comentario": "Intimação criada e pendente de envio",
"canal": "Sistema"
},
{
"status": "Enviado",
"dataMudanca": ISODate("2024-05-21T10:30:00Z"),
"comentario": "Intimação enviada por e-mail",
"canal": "Email",
"messageId": "messageIdEmail"
},
{
"status": "Enviado",
"dataMudanca": ISODate("2024-05-21T10:30:00Z"),
"comentario": "Intimação enviada por SMS",
"canal": "SMS",
"messageId": "messageIdSMS"
},
{
"status": "Recebido",
"dataMudanca": ISODate("2024-05-21T11:00:00Z"),
"comentario": "Confirmação de recebimento pelo destinatário via E-mail",
"canal": "Email",
"messageId": "messageIdEmail",
"mensagemStatus": "Recebido"
}
]
}
Campos:
_id: Identificador único da intimação.
tituloId: Referência ao título associado à intimação.
usuarioId: Referência ao usuário que criou a intimação.
dataCriacao: Data de criação da intimação.
status: Status atual da intimação.
historicoStatus: Array de objetos contendo o histórico de status da intimação.Subdocumento historicoStatus:
status: Status da intimação (e.g., Pendente, Enviado, Recebido).
dataMudanca: Data da mudança de status.
comentario: Comentário sobre a mudança de status.
canal: Canal pelo qual a intimação foi enviada (e.g., Email, SMS).
messageId: Identificador da mensagem enviada pelo canal.
mensagemStatus: Status da mensagem enviada pelo canal.Presenters Collection
Descrição: Armazena as informações dos apresentantes.
Exemplo de Documento:
{
"_id": ObjectId("60d21b667d8f7e5e4c8c6ef2"),
"tipo_apresentante": "Empresa",
"nome": "Empresa ABC",
"documento": "12345678000199",
"endereco": {
"rua": "Rua A, 100",
"complemento": "Sala 101",
"bairro": "Centro",
"cep": "01000-000",
"cidade": "São Paulo",
"uf": "SP"
}
}
Campos:
_id: Identificador único do apresentante.
tipo_apresentante: Tipo do apresentante (e.g., Empresa, Pessoa Física).
nome: Nome do apresentante.
documento: Documento do apresentante (e.g., CNPJ, CPF).
endereco: Objeto contendo o endereço do apresentante.Subdocumento endereco:
rua: Nome da rua.
complemento: Complemento do endereço.
bairro: Bairro.
cep: Código postal.
cidade: Cidade.
uf: Unidade federativa (estado).Debtors Collection
Descrição: Armazena as informações dos sacados (devedores), incluindo múltiplos endereços e contatos.
Exemplo de Documento:
{
"_id": ObjectId("60d21b767d8f7e5e4c8c6ef3"),
"nome": "Carlos Almeida",
"tipo_documento": "CPF",
"documento": "98765432100",
"enderecos": [
{
"endereco": "Rua das Flores, 500",
"complemento": "Apto 101",
"bairro": "Jardim das Rosas",
"cep": "12345-678",
"cidade": "São Paulo",
"uf": "SP",
"prioridade": 1,
"confirmado": false,
"data_confirmacao": null,
"comentario": null
}
],
"contatos": [
{
"tipo_contato": "Telefone",
"valor": "11987654321",
"prioridade": 1,
"confirmado": false,
"data_confirmacao": null,
"comentario": null
},
{
"tipo_contato": "WhatsApp",
"valor": "11987654321",
"prioridade": 1,
"confirmado": false,
"data_confirmacao": null,
"comentario": null
}
]
}
Campos:
_id: Identificador único do sacado.
nome: Nome do sacado.
tipo_documento: Tipo de documento (e.g., CPF, CNPJ).
documento: Número do documento.
enderecos: Array de objetos contendo os endereços do sacado.
contatos: Array de objetos contendo os contatos do sacado.Subdocumento enderecos:
endereco: Endereço.
complemento: Complemento do endereço.
bairro: Bairro.
cep: Código postal.
cidade: Cidade.
uf: Unidade federativa (estado).
prioridade: Prioridade do endereço.
confirmado: Indica se o endereço foi confirmado.
data_confirmacao: Data da confirmação do endereço.
comentario: Comentário sobre o endereço.Subdocumento contatos:
tipo_contato: Tipo de contato (e.g., Telefone, WhatsApp).
valor: Valor do contato (e.g., número de telefone).
prioridade: Prioridade do contato.
confirmado: Indica se o contato foi confirmado.
data_confirmacao: Data da confirmação do contato.
comentario: Comentário sobre o contato.Titles Collection
Descrição: Armazena as informações dos títulos, relacionando cedentes, sacadores, apresentantes e sacados.
Exemplo de Documento:
{
"_id": ObjectId("60d21b567d8f7e5e4c8c6ef1"),
"apresentante_id": ObjectId("60d21b667d8f7e5e4c8c6ef2"),
"sacador": {
"nome": "Empresa XYZ",
"documento": "98765432000188",
"endereco": {
"rua": "Rua B, 200",
"complemento": "Sala 202",
"bairro": "Bela Vista",
"cep": "02000-000",
"cidade": "São Paulo",
"uf": "SP"
}
},
"cedente": {
"nome": "Empresa PQR",
"documento": "11223344000155",
"endereco": {
"rua": "Rua C, 300",
"complemento": "Sala 303",
"bairro": "Moema",
"cep": "03000-000",
"cidade": "São Paulo",
"uf": "SP"
}
},
"sacado_id": ObjectId("60d21b767d8f7e5e4c8c6ef3"),
"valor_protesto": 5000.00,
"valor_total": 5000.00,
"valor_titulo": 5000.00,
"praca_protesto": "São Paulo",
"finalidade_protesto": "Cobrança",
"numero_titulo": "NP123456",
"tipo_aceite": "Eletrônico",
"especie_titulo": "Nota Promissória",
"codigo_motivo_protesto": "01",
"data_emissao": ISODate("2024-05-01T00:00:00Z"),
"tipo_endosso": "Não endossado",
"data_vencimento": ISODate("2024-06-01T00:00:00Z")
}
Campos:
_id: Identificador único do título.
apresentante_id: Referência ao apresentante associado ao título.
sacador: Objeto contendo as informações do sacador.
cedente: Objeto contendo as informações do cedente (se houver).
sacado_id: Referência ao sacado (devedor) associado ao título.
valor_protesto: Valor de protesto do título.
valor_total: Valor total do título.
valor_titulo: Valor do título.
praca_protesto: Praça de protesto do título.
finalidade_protesto: Finalidade do protesto.
numero_titulo: Número do título.
tipo_aceite: Tipo de aceite do título.
especie_titulo: Espécie do título.
codigo_motivo_protesto: Código do motivo do protesto.
data_emissao: Data de emissão do título.
tipo_endosso: Tipo de endosso do título.
data_vencimento: Data de vencimento do título.Subdocumento sacador:
nome: Nome do sacador.
documento: Documento do sacador (e.g., CNPJ, CPF).
endereco: Objeto contendo o endereço do sacador.Subdocumento cedente:
nome: Nome do cedente.
documento: Documento do cedente (e.g., CNPJ, CPF).
endereco: Objeto contendo o endereço do cedente.Subdocumento endereco:
rua: Nome da rua.
complemento: Complemento do endereço.
bairro: Bairro.
cep: Código postal.
cidade: Cidade.
uf: Unidade federativa (estado).Lists Colletion
{
"_id": ObjectId("60d21b967d8f7e5e4c8c6ef5"),
"name": "Lista de Títulos",
"userId": ObjectId("60d21b467d8f7e5e4c8c6ef0"),
"titles": [
ObjectId("60d21b567d8f7e5e4c8c6ef1")
]
}
Fluxo de Dados
Criação de Usuário
Um administrador cria o usuário Alice:
{
"username": "alice",
"password": "hashedpassword"
}Criação do Título
Alice registra um novo título de dívida:
{
"apresentante_id": ObjectId("60d21b667d8f7e5e4c8c6ef2"),
"sacador": {
"nome": "Empresa XYZ",
"documento": "98765432000188",
"endereco": {
"rua": "Rua B, 200",
"complemento": "Sala 202",
"bairro": "Bela Vista",
"cep": "02000-000",
"cidade": "São Paulo",
"uf": "SP"
}
},
"cedente": {
"nome": "Empresa PQR",
"documento": "11223344000155",
"endereco": {
"rua": "Rua C, 300",
"complemento": "Sala 303",
"bairro": "Moema",
"cep": "03000-000",
"cidade": "São Paulo",
"uf": "SP"
}
},
"sacado_id": ObjectId("60d21b767d8f7e5e4c8c6ef3"),
"valor_protesto": 5000.00,
"valor_total": 5000.00,
"valor_titulo": 5000.00,
"praca_protesto": "São Paulo",
"finalidade_protesto": "Cobrança",
"numero_titulo": "NP123456",
"tipo_aceite": "Eletrônico",
"especie_titulo": "Nota Promissória",
"codigo_motivo_protesto": "01",
"data_emissao": ISODate("2024-05-01T00:00:00Z"),
"tipo_endosso": "Não endossado",
"data_vencimento": ISODate("2024-06-01T00:00:00Z")
}
Registro de Contatos
Alice registra os possíveis contatos de João:
{
"nome": "Carlos Almeida",
"tipo_documento": "CPF",
"documento": "98765432100",
"enderecos": [
{
"endereco": "Rua das Flores, 500",
"complemento": "Apto 101",
"bairro": "Jardim das Rosas",
"cep": "12345-678",
"cidade": "São Paulo",
"uf": "SP",
"prioridade": 1,
"confirmado": false,
"data_confirmacao": null,
"comentario": null
}
],
"contatos": [
{
"tipo_contato": "Telefone",
"valor": "11987654321",
"prioridade": 1,
"confirmado": false,
"data_confirmacao": null,
"comentario": null
},
{
"tipo_contato": "WhatsApp",
"valor": "11987654321",
"prioridade": 1,
"confirmado": false,
"data_confirmacao": null,
"comentario": null
}
]
}Criação da Intimação
Alice cria uma intimação para João:
{
"tituloId": ObjectId("60d21b567d8f7e5e4c8c6ef1"),
"usuarioId": ObjectId("60d21b467d8f7e5e4c8c6ef0"),
"dataCriacao": ISODate("2024-05-21T10:00:00Z"),
"status": "Pendente",
"historicoStatus": [
{
"status": "Pendente",
"dataMudanca": ISODate("2024-05-21T10:00:00Z"),
"comentario": "Intimação criada e pendente de envio",
"canal": "Sistema"
}
]
}
Envio da Intimação
A intimação é enviada por e-mail e SMS:
{
"$push": {
"historicoStatus": [
{
"status": "Enviado",
"dataMudanca": ISODate("2024-05-21T10:30:00Z"),
"comentario": "Intimação enviada por e-mail",
"canal": "Email",
"messageId": "messageIdEmail"
},
{
"status": "Enviado",
"dataMudanca": ISODate("2024-05-21T10:30:00Z"),
"comentario": "Intimação enviada por SMS",
"canal": "SMS",
"messageId": "messageIdSMS"
}
]
},
"$set": {
"status": "Enviado"
}
}Confirmação de Recebimento
João confirma o recebimento por e-mail:
{
"$push": {
"historicoStatus": {
"status": "Recebido",
"dataMudanca": ISODate("2024-05-21T11:00:00Z"),
"comentario": "Confirmação de recebimento pelo destinatário via E-mail",
"canal": "Email",
"messageId": "messageIdEmail",
"mensagemStatus": "Recebido"
}
},
"$set": {
"status": "Recebido"
}
}
Atualização Automática via Webhook
Quando um webhook é recebido, ele contém um messageId que deve ser usado para identificar e atualizar a intimação correspondente.
Webhook Recebido:
{
"messageId": "messageIdEmail",
"status": "Recebido"
}Atualização da Intimação:
const updateIntimationStatus = async (messageId, status, comentario) => {
await Intimation.updateOne(
{ "historicoStatus.messageId": messageId },
{
$push: {
"historicoStatus.$.mensagemStatus": status,
"historicoStatus.$.comentario": comentario,
"historicoStatus.$.dataMudanca": new Date(),
},
$set: {
status: status,
},
}
);
};
// Exemplo de chamada da função
updateIntimationStatus(
"messageIdEmail",
"Recebido",
"Confirmação de recebimento pelo destinatário via E-mail"
);