mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 23:53:05 +00:00
Contact.phone deixa de ser único em enforcement (nunca houve constraint DB): - remove o hook enforceUniqueContactPhone e os asserts assertContactPhone* (conflicts/ambiguity) — os 5 fluxos de escrita de pessoa salvam com número compartilhado; rename contactPhoneInvariant.ts -> contactPhoneLocks.ts (locks passam a significar serialização, não unicidade) - findOrCreateContactByPhone: 0 fichas cria, 1 reusa (dedupe C6/C99), 2+ cria ficha nova (a identidade da pessoa em criação é a ficha nova) - convite autofill/login: ficha ancorada pode compartilhar o phone; o lado conta permanece fail-closed (username DB-unique; check de 2+ contas) - import CSV: preview sinaliza telefone_compartilhado (resolução manual); confirm/bulk abortam fail-closed se um phone ganhar 2+ fichas (race) - fix de achado de execução: supporter_import_batch.actor_id NOT NULL com FK ON DELETE set null derrubava o delete de campaignUser com batch órfão (23502) — CampaignUser.beforeDelete limpa batches + fixture cleanup descobre/deleta batches dos accounts owned
25 lines
1 KiB
TypeScript
25 lines
1 KiB
TypeScript
import 'server-only'
|
|
|
|
import type { Payload, PayloadRequest } from 'payload'
|
|
|
|
import type { PayloadTransactionRequest } from '@/utilities/payloadTransaction'
|
|
import { acquireTextAdvisoryLocks } from '@/utilities/postgresTransactionLocks'
|
|
|
|
type ContactPhonePayload = Pick<Payload, 'db'>
|
|
type ContactPhoneRequest = PayloadTransactionRequest | PayloadRequest
|
|
|
|
/**
|
|
* Advisory locks keyed by phone (C111 — the phone is a contact channel, not a
|
|
* unique person identity, so these serialize read-modify-write flows that
|
|
* look contacts up by phone: find-or-create, CSV import, invite redemption,
|
|
* LGPD tombstone). They no longer guard uniqueness — they prevent two
|
|
* concurrent flows from racing the same phone key.
|
|
*/
|
|
export const contactPhoneLockKeys = (phones: string[]): string[] =>
|
|
[...new Set(phones)].sort().map((phone) => `contact-phone:${phone}`)
|
|
|
|
export const acquireContactPhoneLocks = (
|
|
payload: ContactPhonePayload,
|
|
req: ContactPhoneRequest,
|
|
phones: string[],
|
|
): Promise<void> => acquireTextAdvisoryLocks(payload, req, contactPhoneLockKeys(phones))
|