npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

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-commander

Nomeaçã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

  1. Workers:

    • Pasta: workers
    • Arquivo: task.worker.ts
  2. Controllers:

    • Pasta: controllers
    • Arquivo: user.controller.ts
  3. Services:

    • Pasta: services
    • Arquivo: auth.service.ts
  4. Models:

    • Pasta: models
    • Arquivo: user.model.ts

Benefícios do Padrão de Nomeação Contextual

  1. Clareza:
    • Facilita a compreensão imediata da responsabilidade de um arquivo.
  2. Organização:
    • Mantém uma estrutura de projeto organizada e coerente.
  3. Manutenção:
    • Simplifica a navegação e manutenção do código, especialmente em projetos grandes.
  4. 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:

  1. Nomeação Descritiva:

    • Use nomes descritivos para as funções e responsabilidades dos arquivos.
  2. Prefixos ou Sufixos:

    • Adicione prefixos ou sufixos que descrevam o contexto, como .worker, .controller, .service, etc.
  3. 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.ts

Documentaçã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-validator para 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.
  • Integrar validação com a rota:

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"
);