Entidades e relacionamentos · Pessoas

Diagrama

Pessoa e seus vínculos

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)

AtributoTipoObrigatórioRegra
idUUID, chave primáriaGerado—
personTypeenum FISICA ou JURIDICANãoDecide o tamanho do CPF/CNPJ.
namevarchar(255)Condicionalname ou companyName é obrigatório.
companyNamevarchar(255)Condicionalname ou companyName é obrigatório.
cpfCnpjvarchar(14), únicoNãoSomente dígitos; regra R9.
hasNoCpfCnpjboolean, padrão false—Incompatível com cpfCnpj presente.
noCpfCnpjReasonvarchar(120)NãoJustificativa da ausência de documento.
identifiervarchar(40)NãoIdentificador livre.
identityStatusenum confirmado ou pendente, padrão confirmado—A importação marca pendente.
possibleDuplicateOfUUID[]—Candidatas a duplicata para o fluxo de fusão; apenas marcação.
nucleostext[], índice GIN—Siglas em maiúsculas; precisam existir no catálogo de núcleos.
rolesenum[] PersonRole, índice GIN—O valor legado HEADQUARTERS_UNIT permanece legível.
originUoSiglavarchar(40), indexadoSe CLIENTFormato ^[A-Z0-9][A-Z0-9-]{1,39}$; diferente de LSA.
originDatedateNãoData civil YYYY-MM-DD.
originationTypeenum, sete valoresNãoDECLARED_MANUAL derivado quando a sigla chega sem tipo.
originCityvarchar(120), indexadoNãoCidade de captação.
serviceUnitIdUUID, indexadoNãoUnidade 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.
avatarDocumentIdUUID, FK → documents (SET NULL)NãoFoto da Pessoa, vinculada a um Documento existente.
referredByPersonIdUUID, FK → people (RESTRICT), indexadoNãoPrecisa existir e ser diferente da própria pessoa.
referralTypeenum, cinco valoresNãoExige referredByPersonId.
referralChannelenum, seis valores, indexadoNão—
birthDatedateNãoData civil YYYY-MM-DD.
genderenum MALE, FEMALE ou OTHERNão—
generalNotestextNãoAté 20000 caracteres na entrada.
oabNumbervarchar(20)CondicionalAparado; 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.
oabUfchar(2)Condicional^[A-Z]{2}$ após maiúsculas; sempre com oabNumber.
isClient, isOpposingPartyboolean—Derivados dos processos; apenas a importação os preenche.
authorUserIdUUID, FK → users (SET NULL), indexado—Ator do cadastro; base do alcance.
searchText, nameSortKey, birthDayKeyDerivados—Fora do contrato.
projurisPersonCode (único), legacyId (único)Linhagem—Fora do contrato.
createdAt, updatedAttimestamptz——

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.

EntidadeTabelaAtributosObrigatório
Telefoneperson_phonesphoneType, 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
E-mailperson_emailsemailType, email (255, formato de e-mail), isPrimaryemail
Endereçoperson_addressesaddressType, zipCode, street, number, complement, district, city, state (4), isPrimary, referencePoints (até 5 × 120)Nenhum
Documento de Identificaçãoperson_documentsdocumentType (60), number (60), issuingAuthority (120), issueDate (date)Nenhum
Conta Bancáriaperson_bank_accountsbankCode (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)

AtributoTipoRegra
idUUID, chave primáriaMesmo id pelas duas pontas.
personAId, personBIdUUID, FK → people (CASCADE)Restrição A ≠ B.
relationTypeenum, treze tipos canônicosÚnico por (personAId, personBId, relationType).
notevarchar(255)Observação livre.
authorUserIdUUID, anulávelAutor do registro.
createdAttimestamptz—

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.

AtributoTipoObrigatórioRegra
idUUID, chave primáriaGeradoIdentifica o registro.
personIdUUID, FK → people (CASCADE)SimPessoa a que o registro pertence; vem do caminho.
typeenum relationship_record_type: EXPECTATION, PREFERENCE, AFFINITY ou ATTENTIONSimExpectativa, Preferência, Afinidade ou Atenção.
contenttextSimTexto do registro; até 2000 caracteres e aparado na entrada.
preferenceCategoryenum relationship_preference_category: SERVICE_CHANNEL, COMMUNICATION_FORM, SERVICE_HOURS ou OTHER, anulávelNãoCategoria da preferência: canal de atendimento, forma de comunicação, horário de atendimento ou outros. Só em PREFERENCE.
attentionKindenum relationship_attention_kind: DOCUMENTS, EXPERT_EXAM, HEARING, FEES, CALL_IN ou APPOINTMENT, anulávelEm ATTENTIONTipo da etiqueta de Atenção. Só em ATTENTION.
caseIdUUID anulável, FK → cases (SET NULL)NãoProcesso em que a pessoa é cliente. Só em EXPECTATION.
detailtext, anulávelNãoAté 5000 caracteres, aparado. Relato completo em AFFINITY; processo, data, local ou outra informação em ATTENTION.
authorUserIdUUID, FK → users (SET NULL)GeradoUsuário que criou o registro.
createdAttimestamptz(3)GeradoData do registro; com id, ordena a coleção do mais recente ao mais antigo.
updatedAttimestamptz(3)GeradoData 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.

AtributoTipoObrigatórioRegra
idUUID, chave primáriaGeradoIdentifica a nota.
personIdUUID, FK → people (CASCADE)SimPessoa atendida; vem do caminho.
contenttextSimO que foi tratado: texto ou HTML do editor da ficha, com menções; até 20.000 caracteres e aparado na entrada.
modeenum service_mode: PRESENCIAL ou REMOTO, anulávelSim, na criaçãoForma do atendimento; null só em nota registrada antes do campo.
channelenum service_channel: WHATSAPP, TELEFONE, VIDEOCONFERENCIA, EMAIL ou REDE_SOCIAL, anulávelCom REMOTOCanal remoto; obrigatório quando mode é REMOTO e ausente quando é PRESENCIAL.
directionenum service_record_direction: INBOUND (Recebido) ou OUTBOUND (Realizado), anulávelSim, na criaçãoQuem iniciou o atendimento; null só em nota registrada antes do campo.
purposeenum service_record_subject_purpose: AVULSO, ENTREVISTA_INAUGURAL, ACOMPANHAMENTO, SOLICITACAO, ORIENTACAO ou FINANCEIRO, anulávelNãoFinalidade, um único valor; null quando não informada.
satisfactionenum service_note_satisfaction: SATISFEITO, INDIFERENTE, INSATISFEITO, CRITICO ou SEM_RESPOSTA, anulávelNãoSatisfação da pessoa; null quando não informada.
authorUserIdUUID anulável, FK → users (SET NULL)GeradoUsuário que registrou.
createdAttimestamptz(3)GeradoData 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.

AtributoTipoObrigatórioRegra
idUUID, chave primáriaGeradoIdentifica a linha.
kindenum generated_text_kind: RELATIONSHIP_SUMMARY, CASE_SERVICE_SUGGESTION ou MOVEMENT_EXPLANATIONSimTipo de texto.
subjectIdUUIDSimRecurso de que o texto trata: a Pessoa, o Processo ou a Movimentação, conforme kind; sem chave estrangeira. Único com kind.
texttext, anulávelNãoÚltimo texto gerado; null antes da primeira geração.
sourceFingerprintchar(64), anulávelNãoImpressão SHA-256 dos dados que o texto reflete, gerado ou confirmado pelo Jev.
sourceSnapshottext, anulávelNãoDados de origem dessa impressão, comparados pelo Jev com os novos.
generatedAttimestamptz(3), anulávelNãoData da última geração.
attemptedFingerprint, attemptedAtchar(64) e timestamptz(3), anuláveisNãoReserva da última avaliação iniciada: limita cada mudança a uma avaliação por intervalo de nova tentativa.
createdAt, updatedAttimestamptz(3)GeradoTrilha 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.

AtributoTipoObrigatórioRegra
idUUID, chave primáriaGeradoIdentifica a credencial.
personIdUUID, FK → people (RESTRICT), indexadoSimPessoa dona da credencial; vem do caminho.
servicevarchar(60)SimServiço externo a que a credencial dá acesso.
loginvarchar(255)SimLogin no serviço.
urlvarchar(2048)NãoEndereço de acesso ao serviço; aceita apenas http ou https com protocolo explícito. Em implementação na API.
secretCiphertexttextSimSenha cifrada; fora do contrato.
authorUserIdUUID, anulávelGeradoUsuário que registrou a credencial.
createdAt, updatedAttimestamptz(3)GeradoTrilha temporal.

Representado (represented_parties) e Representação (person_represented_parties)

Catálogo institucional, em módulo próprio, sem escopo por núcleo.

AtributoTipoRegra
idUUID, chave primária—
namevarchar(255), aparado, indexado—
kindenum RepresentedPartyKindCOMPANY, PUBLIC_BODY, NONPROFIT, UNION, COOPERATIVE, CONDOMINIUM, INDIVIDUAL, OTHER.
authorUserIdUUID, FK → users (SET NULL)Autor do registro.
createdAt, updatedAttimestamptz—

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çãoCardinalidadeObrigatóriaIntegridade
Pessoa → Telefone, E-mail, Endereço, Documento, Conta Bancária1:NNãoCASCADE
Pessoa → Pessoa (indicação)N:1NãoRESTRICT; 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 → Checklist1:4 (virtual)—CASCADE
Pessoa (EXTERNAL_LAWYER) ↔ RepresentadoN:N por junçãoNãoJunção CASCADE no lado da Pessoa; Representado RESTRICT (409 ao apagar Representado vinculado)
Pessoa (PARTNER) → Carteira própria1:0..1Sim enquanto PARTNERRESTRICT; ownerPersonId com índice único parcial
Pessoa → Unidade de Negócio1:0..1Nãoorg_units.personId; vínculo legado legível, sem criação pelo cadastro de Pessoa
Pessoa (ASSOCIATE) → Associação (participação)1:NNãoNasce no cadastro conjunto ou em /v1/associations
Usuário → Pessoa (Conta da Pessoa)1:1, users.personId anulávelSim no modeloRESTRICT; somente pessoa física (restrição no banco)
Pessoa → Cliente da Carteira1:N no tempo, no máximo 1 vigenteSe CLIENTRESTRICT; exclusão por intervalo de datas
Pessoa → Vínculo Profissional1:N no tempo, no máximo 1 ativoNãoRESTRICT
Pessoa → Participação Associativa1:NNãoRESTRICT
Pessoa → Processo (cliente), Entrevista, Atendimento, Solicitação, Dossiê1:NNãoRESTRICT
Pessoa → Parte de Processo, Atividade, Compromisso, Outbox1:NNãoSET NULL
Pessoa → NúcleoN:N por sigla (nucleos)NãoSem FK; existência validada no serviço
Pessoa → Usuário autorN:1—SET NULL
Pessoa → Unidade de atendimento habitualN:0..1NãoserviceUnitId, FK com SET NULL
Pessoa → Documento (foto)N:0..1NãoavatarDocumentId, FK com SET NULL
Pessoa → Registro de relacionamento1:NNãoCASCADE
Registro de relacionamento → ProcessoN:0..1NãocaseId, FK com SET NULL; só em EXPECTATION
Pessoa → Nota de atendimento1:NNãoCASCADE
Pessoa → Credencial de serviço1:NNãoRESTRICT

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ção CHECK garante 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 de MONDAY a SUNDAY, no formato HH:mm, com fuso implícito America/Recife (OpeningHoursEntryDto).
  • users.passwordHash: anulável; restrição CHECK garante um único provedor de credencial por conta (hash local ou appwriteSubject, 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.

Camadas do domínio