@hed-hog/contact
v0.0.350
Published
O módulo `@hed-hog/contact` gerencia informações relacionadas a contatos, documentos, pessoas e seus tipos, além das relações entre pessoas. Ele oferece funcionalidades completas de CRUD para tipos de contato, tipos de documento, pessoas e suas relações,
Readme
@hed-hog/contact
1. Visão geral do módulo
O módulo @hed-hog/contact gerencia informações relacionadas a contatos, documentos, pessoas e seus tipos, além das relações entre pessoas. Ele oferece funcionalidades completas de CRUD para tipos de contato, tipos de documento, pessoas e suas relações, com suporte a internacionalização (locales), paginação e controle de acesso baseado em roles.
2. Escopo e responsabilidades
- Gerenciar tipos de contato (
contact_type). - Gerenciar tipos de documento (
document_type). - Gerenciar pessoas (
person), incluindo contatos, documentos, endereços e metadados. - Gerenciar tipos de relação entre pessoas (
person_relation_type), que são fixos e imutáveis via API. - Validar regras específicas de negócio, como unicidade de contatos primários e restrições para registro de empresas.
- Suportar autenticação e autorização baseada em roles (
admin,admin-contact). - Suportar internacionalização para mensagens e dados localizados.
- Integrar com serviços de paginação, banco de dados Prisma e envio de emails.
3. Endpoints
Person Contact Type (/person-contact-type)
| Método | Path | Autenticação | Descrição |
|--------|------------------------|-------------------------------------|----------------------------------|
| GET | /person-contact-type | Autenticado (roles: admin, admin-contact) | Lista tipos de contato com paginação e locale. |
| GET | /person-contact-type/:id | Autenticado (roles: admin, admin-contact) | Obtém tipo de contato por ID com locale. |
| POST | /person-contact-type | Autenticado (roles: admin, admin-contact) | Cria um novo tipo de contato. |
| PATCH | /person-contact-type/:id | Autenticado (roles: admin, admin-contact) | Atualiza um tipo de contato existente. |
| DELETE | /person-contact-type | Autenticado (roles: admin, admin-contact) | Exclui tipos de contato por IDs. |
Parâmetros e corpo:
CreateDTOpara criação:code(string): código do tipo de contato.locale(objeto): nomes localizados, ex:{ "pt": { "name": "Telefone" }, "en": { "name": "Phone" } }.
UpdateDTOpara atualização: campos parciais deCreateDTO,localeopcional.
Resposta:
- Listagem paginada ou objeto do tipo criado/atualizado.
- Erros:
- 400 Bad Request: dados inválidos,
localevazio, IDs para exclusão não informados. - 404 Not Found: tipo de contato não encontrado.
- 400 Bad Request: dados inválidos,
Person Document Type (/person-document-type)
| Método | Path | Autenticação | Descrição |
|--------|------------------------|-------------------------------------|----------------------------------|
| GET | /person-document-type | Autenticado (roles: admin, admin-contact) | Lista tipos de documento com paginação e locale. |
| GET | /person-document-type/:id | Autenticado (roles: admin, admin-contact) | Obtém tipo de documento por ID com locale. |
| POST | /person-document-type | Autenticado (roles: admin, admin-contact) | Cria um novo tipo de documento. |
| PATCH | /person-document-type/:id | Autenticado (roles: admin, admin-contact) | Atualiza um tipo de documento existente. |
| DELETE | /person-document-type | Autenticado (roles: admin, admin-contact) | Exclui tipos de documento por IDs. |
Parâmetros e corpo:
CreateDTOpara criação:code(string): código do tipo de documento.country_code(string): código do país.is_unique(boolean): indica se o documento é único.locale(objeto): nomes localizados.
UpdateDTOpara atualização: campos parciais deCreateDTO,localeopcional.
Resposta:
- Listagem paginada ou objeto do tipo criado/atualizado.
- Erros:
- 400 Bad Request: dados inválidos,
localevazio, IDs para exclusão não informados. - 404 Not Found: tipo de documento não encontrado.
- 400 Bad Request: dados inválidos,
Person (/person)
| Método | Path | Autenticação | Descrição |
|--------|------------------------|-------------------------------------|----------------------------------|
| GET | /person | Autenticado (roles: admin, admin-contact) | Lista pessoas com filtros e paginação. |
| GET | /person/stats | Autenticado (roles: admin, admin-contact) | Estatísticas de pessoas. |
| GET | /person/dashboard | Autenticado (roles: admin, admin-contact) | Dashboard de pessoas com filtros. |
| GET | /person/reports | Autenticado (roles: admin, admin-contact) | Relatórios de pessoas por período. |
| GET | /person/owner-options| Autenticado (roles: admin, admin-contact) | Lista usuários possíveis para atribuição como responsáveis. |
| GET | /person/duplicates | Autenticado (roles: admin, admin-contact) | Verifica duplicatas de pessoa por email, telefone ou documento. |
| GET | /person/accounts | Autenticado (roles: admin, admin-contact) | Lista contas (empresas) com filtros e paginação. |
| GET | /person/accounts/stats | Autenticado (roles: admin, admin-contact) | Estatísticas de contas. |
| POST | /person/accounts | Autenticado (roles: admin, admin-contact) | Cria uma nova conta (empresa). |
| PATCH | /person/accounts/:id | Autenticado (roles: admin, admin-contact) | Atualiza uma conta existente. |
| DELETE | /person/accounts | Autenticado (roles: admin, admin-contact) | Exclui contas por IDs. |
| GET | /person/followups | Autenticado (roles: admin, admin-contact) | Lista followups com filtros e paginação. |
| GET | /person/followups/stats | Autenticado (roles: admin, admin-contact) | Estatísticas de followups. |
| GET | /person/activities | Autenticado (roles: admin, admin-contact) | Lista atividades com filtros e paginação. |
| GET | /person/activities/stats | Autenticado (roles: admin, admin-contact) | Estatísticas de atividades. |
| GET | /person/activities/:id | Autenticado (roles: admin, admin-contact) | Obtém atividade por ID. |
| POST | /person/activities/:id/complete | Autenticado (roles: admin, admin-contact) | Marca atividade como concluída. |
| GET | /person/avatar/:id | Pública | Abre avatar público pelo ID do arquivo. |
| GET | /person/:id | Autenticado (roles: admin, admin-contact) | Obtém pessoa por ID com detalhes. |
| POST | /person | Autenticado (roles: admin, admin-contact) | Cria uma nova pessoa. |
| PATCH | /person/:id | Autenticado (roles: admin, admin-contact) | Atualiza pessoa existente. |
| DELETE | /person | Autenticado (roles: admin, admin-contact) | Exclui pessoas por IDs. |
| POST | /person/merge | Autenticado (roles: admin, admin-contact) | Mescla duas pessoas (estratégia 'contact_only'). |
| GET | /person/:id/interaction | Autenticado (roles: admin, admin-contact) | Lista interações da pessoa. |
| POST | /person/:id/interaction | Autenticado (roles: admin, admin-contact) | Cria interação para pessoa. |
| POST | /person/:id/followup | Autenticado (roles: admin, admin-contact) | Agenda followup para pessoa. |
| POST | /person/:id/lifecycle-stage | Autenticado (roles: admin, admin-contact) | Atualiza estágio do ciclo de vida da pessoa. |
| POST | /person/import/preview | Autenticado (roles: admin, admin-contact) | Pré-visualiza importação CSV de pessoas. |
| POST | /person/import | Autenticado (roles: admin, admin-contact) | Importa pessoas via CSV com mapeamento. |
Parâmetros e corpo:
CreateDTOpara criação de pessoa:name(string): nome da pessoa.type(enum: individual, company): tipo da pessoa.status(enum: active, inactive): status da pessoa.- Campos opcionais:
avatar_id,birth_date,gender,job_title,trade_name,foundation_date,legal_nature,notes,employer_company_id,owner_user_id,source,lifecycle_stage,next_action_at,score,deal_value,tags.
UpdateAllPersonDTOpara atualização:- Inclui todos os campos do
CreateDTO. - Arrays para
contacts,addresses,documentscom seus respectivos campos e validações. - Campos opcionais
branch_ids(array de números) eheadquarter_id(número opcional para empresa). - Validação para garantir apenas um contato, endereço ou documento primário por tipo.
- Inclui todos os campos do
MergePersonDTOpara mesclagem:source_person_id(number): ID da pessoa origem.target_person_id(number): ID da pessoa destino.strategy: atualmente suportado apenas'contact_only'.
CreateInteractionDTOpara criação de interação:type(enum: call, email, whatsapp, meeting, note).notes(string, opcional).
CreateFollowupDTOpara criação de followup:next_action_at(string, data ISO).notes(string, opcional).
UpdateLifecycleStageDTOpara atualização do estágio do ciclo de vida:lifecycle_stage(enum: new, contacted, qualified, proposal, negotiation, customer, lost).
Importação CSV:
- Arquivo CSV enviado via multipart/form-data.
mapping(string JSON): mapeamento de colunas para campos.company_id(string numérico opcional): ID da empresa para associação.
Resposta:
- Listagem paginada, objeto da pessoa criada/atualizada, estatísticas, dashboards ou relatórios conforme endpoint.
- Pré-visualização e resultado da importação CSV.
- Erros:
- 400 Bad Request: dados inválidos, mais de um primário por tipo, referência inválida, registro de empresa desabilitado, IDs para exclusão não informados, tentativa de criar/atualizar tipos de relação.
- 404 Not Found: pessoa, avatar, atividade ou entidade relacionada não encontrada.
Person Relation Type (/person-relation-type)
| Método | Path | Autenticação | Descrição |
|--------|------------------------|-------------------------------------|----------------------------------|
| GET | /person-relation-type | Autenticado (roles: admin, admin-contact) | Lista tipos fixos de relação entre pessoas. |
| GET | /person-relation-type/:id | Autenticado (roles: admin, admin-contact) | Obtém tipo de relação por ID. |
| POST | /person-relation-type | Autenticado (roles: admin, admin-contact) | Não suportado (tipos fixos). |
| PATCH | /person-relation-type/:id | Autenticado (roles: admin, admin-contact) | Não suportado (tipos fixos). |
| DELETE | /person-relation-type | Autenticado (roles: admin, admin-contact) | Não suportado (tipos fixos). |
Observação: Tipos de relação são fixos e não podem ser criados, atualizados ou deletados via API. Tentativas resultam em erro 400.
4. Regras de autenticação e autorização
- A maioria dos endpoints requer autenticação via JWT.
- Acesso restrito a usuários com roles
adminouadmin-contact. - O endpoint de avatar (
/person/avatar/:id) é público. - Tentativas de criar, atualizar ou deletar tipos de relação entre pessoas resultam em erro 400, pois são fixos.
5. Estruturas de request/response
CreateDTO (Person Contact Type)
{
"code": "string",
"locale": {
"pt": { "name": "string" },
"en": { "name": "string" }
}
}UpdateDTO (Person Contact Type)
Campos parciais de CreateDTO, locale opcional.
CreateDTO (Person Document Type)
{
"code": "string",
"country_code": "string",
"is_unique": true,
"locale": {
"pt": { "name": "string" },
"en": { "name": "string" }
}
}UpdateDTO (Person Document Type)
Campos parciais de CreateDTO, locale opcional.
CreateDTO (Person)
{
"name": "string",
"type": "individual | company",
"status": "active | inactive",
"avatar_id": "number | null",
"birth_date": "string (date) | null",
"gender": "male | female | other | null",
"job_title": "string | null",
"trade_name": "string | null",
"foundation_date": "string (date) | null",
"legal_nature": "string | null",
"notes": "string | null",
"employer_company_id": "number | null",
"owner_user_id": "number | null",
"source": "referral | website | social | inbound | outbound | other | null",
"lifecycle_stage": "new | contacted | qualified | proposal | negotiation | customer | lost | null",
"next_action_at": "string (date) | null",
"score": "number | null",
"deal_value": "number | null",
"tags": ["string", "..."] | null
}UpdateAllPersonDTO (Person)
Inclui todos os campos do CreateDTO e:
contacts: array de objetos com:id?(number)value(string)is_primary(boolean)contact_type_id(number)
addresses: array de objetos com:id?(number)line1(string)line2?(string)city(string)state(string)country_code?(string)postal_code?(string)is_primary(boolean)address_type(enum: residencial, comercial, etc. conforme AddressTypeEnum)
documents: array de objetos com:id?(number)value(string)document_type_id(number)
branch_ids?: array de números (IDs de filiais)headquarter_id?: número opcional (ID da matriz)
MergePersonDTO
{
"source_person_id": 1,
"target_person_id": 2,
"strategy": "contact_only"
}CreateInteractionDTO
{
"type": "call | email | whatsapp | meeting | note",
"notes": "string | null"
}CreateFollowupDTO
{
"next_action_at": "string (date ISO)",
"notes": "string | null"
}UpdateLifecycleStageDTO
{
"lifecycle_stage": "new | contacted | qualified | proposal | negotiation | customer | lost"
}Import CSV (Person)
- Arquivo CSV enviado via multipart/form-data.
- Campos no corpo:
mapping(string JSON): mapeamento de colunas para campos.company_id(string numérico opcional): ID da empresa para associação.
6. Erros comuns
400 Bad Request
- Falta de campos obrigatórios (ex:
localevazio). - Tentativa de criar/atualizar tipos de relação (não suportado).
- Mais de um contato, endereço ou documento primário do mesmo tipo.
- Tentativa de registrar empresa quando registro está desabilitado.
- Referência inválida para empresa ou endereço.
- IDs para exclusão não informados.
- Arquivo CSV ausente ou mapeamento JSON inválido na importação.
- Falta de campos obrigatórios (ex:
404 Not Found
- Entidade não encontrada por ID (pessoa, tipo de contato, tipo de documento, avatar, atividade).
- Pessoa do tipo empresa não encontrada quando registro está desabilitado.
7. Banco de dados (tabelas YAML)
contact
- Finalidade: Armazena contatos associados a pessoas.
- Colunas:
id(PK)person_id(FK paraperson.id)contact_type_id(FK paracontact_type.id)value(string)is_primary(boolean, default: false)created_at,updated_at
- Índices:
- Único em
(person_id, contact_type_id, is_primary)ondeis_primary = true.
- Único em
contact_type
- Finalidade: Define tipos de contato.
- Colunas:
id(PK)name(locale_varchar, com traduções pt/en)code(string)created_at,updated_at
document
- Finalidade: Armazena documentos associados a pessoas.
- Colunas:
id(PK)person_id(FK paraperson.id)document_type_id(FK paradocument_type.id)value(string)created_at,updated_at
document_type
- Finalidade: Define tipos de documento.
- Colunas:
id(PK)name(locale_varchar, pt/en)code(string)country_code(string)is_unique(boolean)created_at,updated_at
person
- Finalidade: Armazena pessoas (indivíduos e empresas).
- Colunas:
id(PK)name(string)type(enum: individual, company)status(enum: active, inactive)avatar_id(FK parafile.id, nullable, onDelete SET NULL)created_at,updated_at
person_address
- Finalidade: Associação entre pessoas e endereços.
- Colunas:
id(PK)person_id(FK paraperson.id)address_id(FK paraaddress.id)created_at,updated_at
- Índices:
- Único em
address_id.
- Único em
person_company
- Finalidade: Dados específicos para pessoas do tipo empresa.
- Colunas:
id(PK, FK paraperson.id)trade_name(string, nullable)foundation_date(date, nullable)legal_nature(string, nullable)headquarter_id(FK paraperson_company.id, nullable, onDelete SET NULL, onUpdate CASCADE)created_at,updated_at
- Índices:
- Em
headquarter_id
- Em
person_individual
- Finalidade: Dados específicos para pessoas do tipo indivíduo.
- Colunas:
id(PK, FK paraperson.id)birth_date(date, nullable)gender(enum: male, female, other, nullable)job_title(string, nullable)created_at,updated_at
person_individual_relation
- Finalidade: Relações entre pessoas do tipo indivíduo.
- Colunas:
id(PK)person_individual_id(FK paraperson_individual.id, onDelete CASCADE, onUpdate CASCADE)related_person_individual_id(FK paraperson_individual.id, onDelete CASCADE, onUpdate CASCADE)relation_type(enum: parent, child, spouse, sibling, guardian, dependent, partner, responsible, emergency_contact, other)created_at,updated_at
- Índices:
- Em
person_individual_id,related_person_individual_id,relation_type - Único em
(person_individual_id, related_person_individual_id, relation_type)
- Em
person_metadata
- Finalidade: Metadados arbitrários associados a pessoas.
- Colunas:
id(PK)person_id(FK paraperson.id)key(string)value(json)created_at,updated_at
8. Regras de negócio relevantes
- Tipos de relação entre pessoas são fixos e não podem ser alterados via API.
- Apenas um contato, endereço ou documento pode ser marcado como primário por tipo para uma pessoa.
- Registro de pessoas do tipo empresa pode ser desabilitado via configuração
contact-allow-company-registration. - Ao criar ou atualizar pessoa, validações garantem integridade das relações e dados.
- Exclusão de pessoas remove em cascata contatos, documentos, endereços, relações e metadados associados.
- Avatar público pode ser acessado via endpoint público, com cache control configurado.
- Ao criar pessoa sem usuário, é enviado email com link para criação de conta, com token JWT válido por 1 dia.
- Metadados como
noteseemployer_company_idsão armazenados separadamente e sincronizados. - Empresas não podem ser vinculadas como sua própria matriz (headquarter).
- Apenas empresas podem ser vinculadas como matriz ou filial.
- Validações específicas impedem inconsistências nas relações de empresas e indivíduos.
- Atualização de pessoa sincroniza contatos, endereços e documentos, criando, atualizando ou removendo conforme necessário.
- Pesquisa de pessoas suporta filtros por nome, tipo, status, e busca por dados normalizados em contatos, documentos e endereços.
- Mesclagem de pessoas suporta estratégia
contact_onlypara unir contatos sem duplicar pessoas. - Atividades e followups são gerenciados com tipos, status e prioridades específicas.
- Estágios do ciclo de vida da pessoa são atualizáveis via API.
- Importação CSV permite mapear colunas para campos do modelo, associando opcionalmente a uma empresa.
9. Guia rápido de uso (exemplos)
Criar tipo de contato
POST /person-contact-type
Authorization: Bearer <token>
Content-Type: application/json
{
"code": "phone",
"locale": {
"pt": { "name": "Telefone" },
"en": { "name": "Phone" }
}
}Atualizar tipo de documento
PATCH /person-document-type/3
Authorization: Bearer <token>
Content-Type: application/json
{
"is_unique": true,
"locale": {
"pt": { "name": "CPF" },
"en": { "name": "CPF" }
}
}Listar pessoas com filtro e paginação
GET /person?search=joao&type=individual&status=active&page=1&pageSize=20
Authorization: Bearer <token>Criar pessoa
POST /person
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "João Silva",
"type": "individual",
"status": "active",
"birth_date": "1980-05-10",
"gender": "male",
"contacts": [
{
"value": "[email protected]",
"is_primary": true,
"contact_type_id": 1
}
],
"addresses": [
{
"line1": "Rua A, 123",
"city": "São Paulo",
"state": "SP",
"country_code": "BRA",
"postal_code": "01000-000",
"is_primary": true,
"address_type": "residential"
}
],
"documents": [
{
"value": "123.456.789-00",
"document_type_id": 1
}
]
}Atualizar pessoa
PATCH /person/10
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "João da Silva",
"status": "active",
"contacts": [
{
"id": 5,
"value": "[email protected]",
"is_primary": true,
"contact_type_id": 1
}
]
}Excluir pessoas
DELETE /person
Authorization: Bearer <token>
Content-Type: application/json
{
"ids": [10, 11, 12]
}Mesclar pessoas (estratégia contact_only)
POST /person/merge
Authorization: Bearer <token>
Content-Type: application/json
{
"source_person_id": 15,
"target_person_id": 10,
"strategy": "contact_only"
}Criar interação para pessoa
POST /person/10/interaction
Authorization: Bearer <token>
Content-Type: application/json
{
"type": "call",
"notes": "Ligação para confirmar reunião"
}Agendar followup para pessoa
POST /person/10/followup
Authorization: Bearer <token>
Content-Type: application/json
{
"next_action_at": "2024-07-01T10:00:00Z",
"notes": "Enviar proposta"
}Atualizar estágio do ciclo de vida da pessoa
POST /person/10/lifecycle-stage
Authorization: Bearer <token>
Content-Type: application/json
{
"lifecycle_stage": "customer"
}Pré-visualizar importação CSV de pessoas
POST /person/import/preview
Authorization: Bearer <token>
Content-Type: multipart/form-data
Content-Disposition: form-data; name="file"; filename="pessoas.csv"
Content-Type: text/csv
<arquivo CSV>Importar pessoas via CSV
POST /person/import
Authorization: Bearer <token>
Content-Type: multipart/form-data
--boundary
Content-Disposition: form-data; name="file"; filename="pessoas.csv"
Content-Type: text/csv
<arquivo CSV>
--boundary
Content-Disposition: form-data; name="mapping"
{"Nome":"name","Email":"email","Telefone":"phone", ...}
--boundary
Content-Disposition: form-data; name="company_id"
123
--boundary--Este README documenta as funcionalidades principais do módulo @hed-hog/contact com base no código e definições atuais. Para detalhes adicionais, consulte o código fonte e as definições de DTOs.
