Entidades e relacionamentos · Pessoas
Diagrama
Carregando diagrama…
Ver código Mermaid
erDiagram
PERSON ||--o{ PERSON_PHONE : "phones"
PERSON ||--o{ PERSON_EMAIL : "emails"
PERSON ||--o{ PERSON_ADDRESS : "addresses"
PERSON ||--o{ PERSON_ID_DOCUMENT : "documents"
PERSON ||--o{ PERSON_DOCUMENT_CHECKLIST_ITEM : "checklist (4 kinds)"
PERSON }o--o| PERSON : "referredBy (indicacao)"
PERSON ||--o{ PERSON_RELATIONSHIP : "personA"
PERSON ||--o{ PERSON_RELATIONSHIP : "personB"
USER |o--o| PERSON : "Conta da Pessoa (users.personId)"
USER ||--o{ PERSON : "author"
PERSON ||--o{ PORTFOLIO_CLIENT : "Cliente da Carteira (vigencia)"
PERSON ||--o{ STAFF_MEMBER : "Vinculo Profissional"
PERSON ||--o{ ASSOCIATIVE_PARTICIPATION : "Associado"
PERSON ||--o{ CASE : "clientPersonId"
PERSON ||--o{ CASE_PARTY : "personId"
PERSON ||--o{ CONSULTATION : "clientPersonId"
PERSON ||--o{ SERVICE_RECORD : "personId"
PERSON ||--o{ PERSON_BANK_ACCOUNT : "bankAccounts"
PERSON }o--o{ REPRESENTED_PARTY : "person_represented_parties (EXTERNAL_LAWYER)"
PERSON |o--o| PORTFOLIO : "ownerPersonId (PARTNER)"
PERSON |o--o| ORG_UNIT : "org_units.personId (vinculo legado)"
PERSON }o--o| ORG_UNIT : "serviceUnitId (unidade de atendimento)"
PERSON }o--o| DOCUMENT : "avatarDocumentId (foto)"
PERSON ||--o{ PERSON_RELATIONSHIP_RECORD : "registros de relacionamento"
PERSON ||--o{ PERSON_CREDENTIAL : "credenciais de servico"
PERSON ||--o{ PERSON_SERVICE_NOTE : "notas de atendimento"
PERSON_RELATIONSHIP_RECORD }o--o| CASE : "caseId (expectativa)"
Modelo físico
O modelo é físico (TypeORM sobre PostgreSQL). A inscrição na OAB pertence à Pessoa, não a Documento de Identificação. A Pessoa concentra a identidade civil, a inscrição na OAB, os papéis, a originação e a indicação; contatos, endereços, documentos de identificação e contas bancárias são filhos embutidos, substituídos em lista inteira a cada PATCH. Telefones e endereços acompanham a Pessoa em toda leitura; e-mails, documentos e contas bancárias saem apenas na leitura individual e nas respostas de escrita. Os Representados de um advogado externo ficam em catálogo próprio, ligado à Pessoa por uma tabela de junção.
Pessoa (people)
| Atributo | Tipo | Obrigatório | Regra |
|---|---|---|---|
id | UUID, chave primária | Gerado | — |
personType | enum FISICA ou JURIDICA | Não | Decide o tamanho do CPF/CNPJ. |
name | varchar(255) | Condicional | name ou companyName é obrigatório. |
companyName | varchar(255) | Condicional | name ou companyName é obrigatório. |
cpfCnpj | varchar(14), único | Não | Somente dígitos; regra R9. |
hasNoCpfCnpj | boolean, padrão false | — | Incompatível com cpfCnpj presente. |
noCpfCnpjReason | varchar(120) | Não | Justificativa da ausência de documento. |
identifier | varchar(40) | Não | Identificador livre. |
identityStatus | enum confirmado ou pendente, padrão confirmado | — | A importação marca pendente. |
possibleDuplicateOf | UUID[] | — | Candidatas a duplicata para o fluxo de fusão; apenas marcação. |
nucleos | text[], índice GIN | — | Siglas em maiúsculas; precisam existir no catálogo de núcleos. |
roles | enum[] PersonRole, índice GIN | — | O valor legado HEADQUARTERS_UNIT permanece legível. |
originUoSigla | varchar(40), indexado | Se CLIENT | Formato ^[A-Z0-9][A-Z0-9-]{1,39}$; diferente de LSA. |
originDate | date | Não | Data civil YYYY-MM-DD. |
originationType | enum, sete valores | Não | DECLARED_MANUAL derivado quando a sigla chega sem tipo. |
originCity | varchar(120), indexado | Não | Cidade de captação. |
serviceUnitId | UUID, indexado | Não | Unidade de atendimento habitual: escritório físico onde a pessoa costuma ser atendida, informado no cadastro. FK → org_units (SET NULL); precisa ser uma unidade cadastrada. |
avatarDocumentId | UUID, FK → documents (SET NULL) | Não | Foto da Pessoa, vinculada a um Documento existente. |
referredByPersonId | UUID, FK → people (RESTRICT), indexado | Não | Precisa existir e ser diferente da própria pessoa. |
referralType | enum, cinco valores | Não | Exige referredByPersonId. |
referralChannel | enum, seis valores, indexado | Não | — |
birthDate | date | Não | Data civil YYYY-MM-DD. |
gender | enum MALE, FEMALE ou OTHER | Não | — |
generalNotes | text | Não | Até 20000 caracteres na entrada. |
oabNumber | varchar(20) | Condicional | Aparado; pessoa física ou jurídica (sociedade de advogados), com a aceitação em pessoa jurídica pendente de nead-hub-api#84 (RN-PESSOAS-046); exigido do Advogado externo; sempre com oabUf; entra em searchText. Definida como única por advogado; o índice (oabUf, oabNumber) vigente ainda não é único. |
oabUf | char(2) | Condicional | ^[A-Z]{2}$ após maiúsculas; sempre com oabNumber. |
isClient, isOpposingParty | boolean | — | Derivados dos processos; apenas a importação os preenche. |
authorUserId | UUID, FK → users (SET NULL), indexado | — | Ator do cadastro; base do alcance. |
searchText, nameSortKey, birthDayKey | Derivados | — | Fora do contrato. |
projurisPersonCode (único), legacyId (único) | Linhagem | — | Fora do contrato. |
createdAt, updatedAt | timestamptz | — | — |
Vocabulários: roles permite novas atribuições de USER, ASSOCIATE, CLIENT, PARTNER, SERVICE_PROVIDER, EXTERNAL_LAWYER, EXPERT, JUDGE e PUBLIC_SERVANT. HEADQUARTERS_UNIT permanece legível em registros antigos. originationType aceita DECLARED_PARTNER, INFERRED_TERRITORY, INFERRED_HISTORY, INFERRED_CURRENT_UNIT, PENDING_REVIEW, NO_SIGNAL e DECLARED_MANUAL. referralType aceita PARTNER, SCOUT, CLIENT, ASSOCIATE e INTERNAL. referralChannel aceita WHATSAPP, INSTAGRAM, PHONE_CALL, IN_PERSON, WEBSITE e OTHER.
Filhos embutidos
Relação 1:N com a Pessoa, ON DELETE CASCADE e substituição em lista inteira no PATCH. Telefone e Endereço têm carregamento imediato; E-mail, Documento de Identificação e Conta Bancária são carregados apenas na leitura individual.
| Entidade | Tabela | Atributos | Obrigatório |
|---|---|---|---|
| Telefone | person_phones | phoneType, number (30, como informado), numberDigits (coluna gerada pelo banco com só os dígitos de number, indexada por trigram para a busca; fora do contrato), isPrimary, ownership (SELF, FAMILY, WORK, THIRD_PARTY), contactChannel (CALL_ONLY, MESSAGE_ONLY, BOTH) | number |
person_emails | emailType, email (255, formato de e-mail), isPrimary | email | |
| Endereço | person_addresses | addressType, zipCode, street, number, complement, district, city, state (4), isPrimary, referencePoints (até 5 × 120) | Nenhum |
| Documento de Identificação | person_documents | documentType (60), number (60), issuingAuthority (120), issueDate (date) | Nenhum |
| Conta Bancária | person_bank_accounts | bankCode (char 3, ^\d{3}$, COMPE), bankName (120), branchNumber (10, só dígitos), branchDigit (2), accountNumber (20, só dígitos), accountDigit (2), accountType (CHECKING, SAVINGS, PAYMENT, SALARY, BENEFIT), operation (20, operação bancária), notes (text, até 2000 na entrada), pixKeyType (CPF_CNPJ, EMAIL, PHONE, RANDOM), pixKey (140), holderName (255), isPrimary (padrão false) | bankCode, branchNumber, accountNumber, accountType |
Em Telefone, E-mail e Endereço não há unicidade de item principal (mais de um isPrimary pode coexistir) nem unicidade de número. documentType é texto livre (por exemplo, RG), não um enum. Na Conta Bancária, no máximo uma isPrimary por lista; pixKeyType e pixKey vêm juntos ou não vêm; holderName identifica o titular quando a conta não é da própria pessoa.
Relacionamento entre Pessoas (person_relationships)
| Atributo | Tipo | Regra |
|---|---|---|
id | UUID, chave primária | Mesmo id pelas duas pontas. |
personAId, personBId | UUID, FK → people (CASCADE) | Restrição A ≠ B. |
relationType | enum, treze tipos canônicos | Único por (personAId, personBId, relationType). |
note | varchar(255) | Observação livre. |
authorUserId | UUID, anulável | Autor do registro. |
createdAt | timestamptz | — |
A forma canônica define qual ponta ocupa A. Em laços dirigidos, A guarda o ascendente: PARENT, GRANDPARENT, UNCLE_AUNT, PARENT_IN_LAW, LEGAL_GUARDIAN, ADOPTIVE_PARENT, TUTOR e CURATOR. Em laços simétricos, A guarda o menor UUID: SPOUSE, SIBLING, COUSIN, SIBLING_IN_LAW e FRIEND. Os oito tipos de leitura (CHILD, GRANDCHILD, NEPHEW_NIECE, CHILD_IN_LAW, WARD, ADOPTED_CHILD, TUTELAGE_WARD, CURATORSHIP_WARD) são aceitos na entrada e apresentados na saída do ponto de vista da âncora, mas não são gravados. Uma tabela de exclusões impede laços contraditórios entre a mesma dupla (por exemplo, "mãe" e "neta"), respondendo 409.
Registro de relacionamento (person_relationship_records)
Registro tipado do relacionamento do escritório com a Pessoa. Uma única coleção guarda os quatro tipos apresentados no card Relacionamento da ficha.
| Atributo | Tipo | Obrigatório | Regra |
|---|---|---|---|
id | UUID, chave primária | Gerado | Identifica o registro. |
personId | UUID, FK → people (CASCADE) | Sim | Pessoa a que o registro pertence; vem do caminho. |
type | enum relationship_record_type: EXPECTATION, PREFERENCE, AFFINITY ou ATTENTION | Sim | Expectativa, Preferência, Afinidade ou Atenção. |
content | text | Sim | Texto do registro; até 2000 caracteres e aparado na entrada. |
preferenceCategory | enum relationship_preference_category: SERVICE_CHANNEL, COMMUNICATION_FORM, SERVICE_HOURS ou OTHER, anulável | Não | Categoria da preferência: canal de atendimento, forma de comunicação, horário de atendimento ou outros. Só em PREFERENCE. |
attentionKind | enum relationship_attention_kind: DOCUMENTS, EXPERT_EXAM, HEARING, FEES, CALL_IN ou APPOINTMENT, anulável | Em ATTENTION | Tipo da etiqueta de Atenção. Só em ATTENTION. |
caseId | UUID anulável, FK → cases (SET NULL) | Não | Processo em que a pessoa é cliente. Só em EXPECTATION. |
detail | text, anulável | Não | Até 5000 caracteres, aparado. Relato completo em AFFINITY; processo, data, local ou outra informação em ATTENTION. |
authorUserId | UUID, FK → users (SET NULL) | Gerado | Usuário que criou o registro. |
createdAt | timestamptz(3) | Gerado | Data do registro; com id, ordena a coleção do mais recente ao mais antigo. |
updatedAt | timestamptz(3) | Gerado | Data da última alteração. |
Criação, alteração e exclusão gravam entradas no histórico da Pessoa (person-relationship-record.created, person-relationship-record.updated e person-relationship-record.deleted), com o registro como ficou ou, na exclusão, como estava. Os campos preferenceCategory, attentionKind, caseId e detail estão em implementação na API.
Nota de atendimento (person_service_notes)
Registro simplificado de atendimento feito na Ficha da Pessoa: o que foi tratado, a forma, quem iniciou, a finalidade e a satisfação. Não é um Registro de Atendimento (service_records): usa os mesmos vocabulários de modo, canal, direção e finalidade, sem unidade, núcleo, assuntos nem ciclo de vida. Em implementação na API.
| Atributo | Tipo | Obrigatório | Regra |
|---|---|---|---|
id | UUID, chave primária | Gerado | Identifica a nota. |
personId | UUID, FK → people (CASCADE) | Sim | Pessoa atendida; vem do caminho. |
content | text | Sim | O que foi tratado: texto ou HTML do editor da ficha, com menções; até 20.000 caracteres e aparado na entrada. |
mode | enum service_mode: PRESENCIAL ou REMOTO, anulável | Sim, na criação | Forma do atendimento; null só em nota registrada antes do campo. |
channel | enum service_channel: WHATSAPP, TELEFONE, VIDEOCONFERENCIA, EMAIL ou REDE_SOCIAL, anulável | Com REMOTO | Canal remoto; obrigatório quando mode é REMOTO e ausente quando é PRESENCIAL. |
direction | enum service_record_direction: INBOUND (Recebido) ou OUTBOUND (Realizado), anulável | Sim, na criação | Quem iniciou o atendimento; null só em nota registrada antes do campo. |
purpose | enum service_record_subject_purpose: AVULSO, ENTREVISTA_INAUGURAL, ACOMPANHAMENTO, SOLICITACAO, ORIENTACAO ou FINANCEIRO, anulável | Não | Finalidade, um único valor; null quando não informada. |
satisfaction | enum service_note_satisfaction: SATISFEITO, INDIFERENTE, INSATISFEITO, CRITICO ou SEM_RESPOSTA, anulável | Não | Satisfação da pessoa; null quando não informada. |
authorUserId | UUID anulável, FK → users (SET NULL) | Gerado | Usuário que registrou. |
createdAt | timestamptz(3) | Gerado | Data do atendimento: o instante do registro. |
O registro grava person-service-note.created no histórico da Pessoa. Notas registradas antes da forma e de quem iniciou continuam legíveis, com mode, channel, direction e purpose nulos; não há preenchimento retroativo.
Texto gerado (generated_texts)
Último texto gerado de um registro da Ficha da Pessoa e a impressão dos dados de origem que ele reflete (RN-PESSOAS-068). Serve ao Resumo do Relacionamento, à Sugestão de atendimento do processo e à Explicação da movimentação. A tabela fica fora do contrato: a leitura sai por text, generatedAt e upToDate. Em implementação na API.
| Atributo | Tipo | Obrigatório | Regra |
|---|---|---|---|
id | UUID, chave primária | Gerado | Identifica a linha. |
kind | enum generated_text_kind: RELATIONSHIP_SUMMARY, CASE_SERVICE_SUGGESTION ou MOVEMENT_EXPLANATION | Sim | Tipo de texto. |
subjectId | UUID | Sim | Recurso de que o texto trata: a Pessoa, o Processo ou a Movimentação, conforme kind; sem chave estrangeira. Único com kind. |
text | text, anulável | Não | Último texto gerado; null antes da primeira geração. |
sourceFingerprint | char(64), anulável | Não | Impressão SHA-256 dos dados que o texto reflete, gerado ou confirmado pelo Jev. |
sourceSnapshot | text, anulável | Não | Dados de origem dessa impressão, comparados pelo Jev com os novos. |
generatedAt | timestamptz(3), anulável | Não | Data da última geração. |
attemptedFingerprint, attemptedAt | char(64) e timestamptz(3), anuláveis | Não | Reserva da última avaliação iniciada: limita cada mudança a uma avaliação por intervalo de nova tentativa. |
createdAt, updatedAt | timestamptz(3) | Gerado | Trilha temporal. |
Credencial de serviço (person_credentials)
Acesso da Pessoa a um serviço externo. A senha é gravada cifrada e só sai em claro pela leitura própria da senha, registrada no histórico da Pessoa.
| Atributo | Tipo | Obrigatório | Regra |
|---|---|---|---|
id | UUID, chave primária | Gerado | Identifica a credencial. |
personId | UUID, FK → people (RESTRICT), indexado | Sim | Pessoa dona da credencial; vem do caminho. |
service | varchar(60) | Sim | Serviço externo a que a credencial dá acesso. |
login | varchar(255) | Sim | Login no serviço. |
url | varchar(2048) | Não | Endereço de acesso ao serviço; aceita apenas http ou https com protocolo explícito. Em implementação na API. |
secretCiphertext | text | Sim | Senha cifrada; fora do contrato. |
authorUserId | UUID, anulável | Gerado | Usuário que registrou a credencial. |
createdAt, updatedAt | timestamptz(3) | Gerado | Trilha temporal. |
Representado (represented_parties) e Representação (person_represented_parties)
Catálogo institucional, em módulo próprio, sem escopo por núcleo.
| Atributo | Tipo | Regra |
|---|---|---|
id | UUID, chave primária | — |
name | varchar(255), aparado, indexado | — |
kind | enum RepresentedPartyKind | COMPANY, PUBLIC_BODY, NONPROFIT, UNION, COOPERATIVE, CONDOMINIUM, INDIVIDUAL, OTHER. |
authorUserId | UUID, FK → users (SET NULL) | Autor do registro. |
createdAt, updatedAt | timestamptz | — |
A unicidade é por (lower(name), kind), em índice de expressão criado por migração. A tabela de junção person_represented_parties (person_id CASCADE, represented_party_id RESTRICT) liga a Pessoa EXTERNAL_LAWYER aos seus Representados; a Pessoa é o lado dono da relação, e a lista de ids enviada substitui o conjunto inteiro.
Checklist de documentos (person_document_checklist_items)
Uma linha por (personId, kind), única. kind pertence a procuracao, identidade_cpf, comprovante_residencia ou contrato_honorarios; status pertence a pendente ou confirmado; authorUserId registra o autor da última mudança. Um item sem linha é apresentado como pendente (item virtual na leitura).
Relações e cardinalidades
| Relação | Cardinalidade | Obrigatória | Integridade |
|---|---|---|---|
| Pessoa → Telefone, E-mail, Endereço, Documento, Conta Bancária | 1:N | Não | CASCADE |
| Pessoa → Pessoa (indicação) | N:1 | Não | RESTRICT; não pode ser a própria pessoa |
| Pessoa ↔ Pessoa (relacionamento) | N:N por aresta | — | CASCADE; sem autorrelação; sem duplicata por dupla e tipo |
| Pessoa → Checklist | 1:4 (virtual) | — | CASCADE |
Pessoa (EXTERNAL_LAWYER) ↔ Representado | N:N por junção | Não | Junção CASCADE no lado da Pessoa; Representado RESTRICT (409 ao apagar Representado vinculado) |
Pessoa (PARTNER) → Carteira própria | 1:0..1 | Sim enquanto PARTNER | RESTRICT; ownerPersonId com índice único parcial |
| Pessoa → Unidade de Negócio | 1:0..1 | Não | org_units.personId; vínculo legado legível, sem criação pelo cadastro de Pessoa |
Pessoa (ASSOCIATE) → Associação (participação) | 1:N | Não | Nasce no cadastro conjunto ou em /v1/associations |
| Usuário → Pessoa (Conta da Pessoa) | 1:1, users.personId anulável | Sim no modelo | RESTRICT; somente pessoa física (restrição no banco) |
| Pessoa → Cliente da Carteira | 1:N no tempo, no máximo 1 vigente | Se CLIENT | RESTRICT; exclusão por intervalo de datas |
| Pessoa → Vínculo Profissional | 1:N no tempo, no máximo 1 ativo | Não | RESTRICT |
| Pessoa → Participação Associativa | 1:N | Não | RESTRICT |
| Pessoa → Processo (cliente), Entrevista, Atendimento, Solicitação, Dossiê | 1:N | Não | RESTRICT |
| Pessoa → Parte de Processo, Atividade, Compromisso, Outbox | 1:N | Não | SET NULL |
| Pessoa → Núcleo | N:N por sigla (nucleos) | Não | Sem FK; existência validada no serviço |
| Pessoa → Usuário autor | N:1 | — | SET NULL |
| Pessoa → Unidade de atendimento habitual | N:0..1 | Não | serviceUnitId, FK com SET NULL |
| Pessoa → Documento (foto) | N:0..1 | Não | avatarDocumentId, FK com SET NULL |
| Pessoa → Registro de relacionamento | 1:N | Não | CASCADE |
| Registro de relacionamento → Processo | N:0..1 | Não | caseId, FK com SET NULL; só em EXPECTATION |
| Pessoa → Nota de atendimento | 1:N | Não | CASCADE |
| Pessoa → Credencial de serviço | 1:N | Não | RESTRICT |
Colunas de outros domínios que apontam para a Pessoa
portfolios.ownerPersonId: UUID anulável, FK →people(RESTRICT), índice único parcial onde não nulo; restriçãoCHECKgarante exatamente um dono entre unidade, associação e pessoa. Cada dono — Unidade de Negócio, Associação ou Pessoa Parceira — tem a sua própria Carteira.org_units.personId: UUID anulável, Pessoa jurídica que representa a unidade; o horário de funcionamento fica na versão da unidade, em faixas deMONDAYaSUNDAY, no formatoHH:mm, com fuso implícitoAmerica/Recife(OpeningHoursEntryDto).users.passwordHash: anulável; restriçãoCHECKgarante um único provedor de credencial por conta (hash local ouappwriteSubject, nunca ambos).
A criação de um vínculo profissional trava a Pessoa durante a transação. Dossiê, anexos, espelhos Projuris e tickets DigiSac usam rotas sob /v1/people/{personId}/..., com controladores próprios dos domínios responsáveis.
Ciclo de vida
A Pessoa é criada e editada indefinidamente. Não há exclusão: não existe rota para isso, e as chaves estrangeiras RESTRICT de quadro de pessoal, processos, entrevistas, atendimentos, solicitações, clientes de carteira, associações, dossiê, usuários e indicação impediriam a remoção. Não há inativação: não existe campo de estado de vida. identityStatus: pendente sinaliza revisão de duplicata importada; a fusão de duplicatas não está implementada, apenas a marcação possibleDuplicateOf.
Os registros de relacionamento são criados, alterados e excluídos; cada operação fica registrada no histórico da Pessoa. Unidade de atendimento habitual, foto, operação, observações bancárias, tipo BENEFIT e URL de credencial são opcionais e não têm preenchimento retroativo. Esses campos e a tabela person_relationship_records estão em implementação na API.
Os vínculos com outros domínios têm ciclo próprio, como a vigência do Cliente da Carteira e do vínculo profissional. Perder o papel PARTNER apaga a Carteira própria somente se ela está vazia e sem histórico; caso contrário, a API responde 422 e a pessoa continua parceira. Perder o papel EXTERNAL_LAWYER exige representedPartyIds: [] antes ou junto (422). Apagar um Representado vinculado responde 409.