Publicar é um ato, não uma coluna
published_at é um momento e não uma flag: a lista é ordenada por ele, e o badge de
não lidos compara a chegada de um contato contra ele. Publicar tem endpoint próprio
porque é o passo que entra num documento cacheável e anuncia
changelog_post.published para os seus webhooks — e um
formulário enviado duas vezes não pode anunciar um release duas vezes. O UPDATE leva
published_at IS NULL, então essa idempotência é do banco e não de uma checagem que
alguém lembrou de escrever.
Editar um post publicado é uma edição; muda o documento e não anuncia nada. Os fatos
do rascunho ficam dentro do prédio: um post não publicado é um anúncio que você
ainda não fez.
O documento público
segment_id aqui exigiria um identificador que quem chama fornece —
e um documento que responde “aqui está o post para este endereço de e-mail” é um
oráculo de quem está em qual segmento, respondível por
qualquer um com uma página e uma lista de endereços. Pertencer a um segmento é a sua
própria análise sobre os seus usuários; um documento cacheável não pode ser sondado
atrás disso.
Então só um post mirado em ninguém em particular chega a este documento. Um post
direcionado é alcançável exclusivamente por uma sessão de contato.
body_markdown é markdown como foi escrito. Renderizar é da página que desenha —
a API nunca te devolve HTML, e você nunca deve entregar texto de banco a um
renderizador de markup que confia nele.
O feed do próprio contato
@userkit/nextjs — é o mesmo componente, e em
modo proxy a leitura e o recibo de leitura são
encaminhados pelos handlers, com a sessão num cookie httpOnly da sua própria origem.
O <WhatsNew /> mais abaixo e o useChangelogFeed atravessam pela mesma porta.
Esta é a superfície que carrega os posts direcionados, e ela fica atrás do portão
de contato verificado exatamente pela razão que faz o documento público abrir mão do
direcionamento. Uma sessão não verificada mas identificada é uma afirmação que
qualquer um que saiba um external_id pode fazer de um navegador, e a resposta deste
endpoint difere por pertencimento a segmento. Sem o portão, seria o mesmo oráculo
alcançado pela outra porta: “esse external_id vê o post do beta enterprise” é “essa
pessoa está no segmento do beta enterprise”.
Sessões anônimas passam pelo portão, como passam em todo lugar — a linha foi criada
pela mesma chamada que a está segurando, então não há ninguém para personificar. O
que elas veem são os posts não direcionados, com estado de leitura.
O badge conta a partir da chegada
since é quando este contato chegou, e nada publicado antes disso conta. Um badge
que abre em 47 no primeiro dia de alguém é um badge que a pessoa dispensa uma vez e
nunca mais olha. O número ser pequeno o bastante para agir é a única coisa que faz
dele um badge em vez de decoração.
Marcar um post como lido é idempotente — ler duas vezes é ler uma — e um post que esta
pessoa nunca viu responde 404 em vez de deixar um badge ser limpo por uuid.
O permalink
Exportações virando exporta-es é
um endereço que ninguém lê — e é único por ambiente, pela mesma razão de todo
environment_id aqui: um ensaio no test não pode tomar o endereço que o gêmeo live ia
usar.
Trocar o título não move a página. Essa é a promessa inteira de um permalink: os
links já enviados continuam apontando para o post, e nada os reenvia. Mover o endereço
é mandar slug no PATCH, de propósito, e custa o endereço antigo.
Um rascunho e um post direcionado respondem 404 aqui, com a mesma frase de um slug
que não existe. Distinguir os três responderia “existe um post não publicado neste
endereço” para qualquer um que adivinhe uma manchete — e numa superfície pública o
palpite é de graça. Um post mirado num segmento guarda o slug: ampliá-lo para todo
mundo depois liga aquele endereço em vez de inventar um.
O prefixo para montar essas URLs é changelog_url, em GET /v1/config/{publishable_key}
— resolvido por nós, porque só este lado sabe se o domínio próprio do inquilino foi
verificado. Na lista do contato, cada post carrega slug e public: só ofereça o
link quando public for true, ou você está oferecendo um 404.
”Enquanto você esteve fora”
/v1/contact/changelog/unread
primeiro e, num zero, acaba ali: a lista não é pedida, nenhum diálogo é montado, e quem
está em dia recebe a própria página de volta intacta. Um modal que cumprimenta alguém
com “nada de novo” é um modal que a pessoa aprende a fechar antes de ler, e quem paga
essa conta é o próximo anúncio de verdade.
O conjunto que ele mostra é o do próprio contador, repetido do lado do cliente: não
lido e publicado depois de since. A lista responde com tudo o que aquele contato
pode ver, inclusive o que é anterior a ele; o contador conta a partir da chegada. Ou os
dois números descrevem o mesmo conjunto, ou um deles está mentindo — e o que dá para
conferir é o que está na tela. Quem chegou hoje tem conjunto vazio por construção.
Ser mostrado é o que marca esses posts como lidos, senão o mesmo diálogo volta
amanhã com os mesmos posts. Os recibos são escritos depois que o diálogo está na tela,
um por post desenhado, e um recibo que falha custa uma reaparição — não um post.
E “mostrado” quer dizer na tela mesmo: o centro da página comporta um diálogo por
vez — um termo pendente vem antes deste, uma pesquisa vem depois —, e enquanto este
espera a vez nada é marcado como lido. Ele aparece assim que o de cima sair, ou na
próxima visita. A ordem está em Pesquisas, com a página que
explica a fila.
Diferente do badge, o corpo aqui é renderizado como markdown, pelo mesmo renderer
da central de ajuda: ele constrói elementos e nunca HTML, então a prosa que chega pela
rede não tem onde injetar. Uma nota de release lida num diálogo é prosa que alguém
escreveu para ser lida; a linha de preview do badge não tinha o que ganhar com títulos
e listas, e esta tem.
A segunda audiência: quem pediu
Um post pode ser mirado num segmento, ou nos votantes de um post de feedback:O que sai do prédio
changelog_post.published é entregável como webhook. O payload leva o título e o
momento e nunca a audiência — segment_id é o único campo que o documento público
recusa, e um webhook entregando isso seria o mesmo vazamento por outra porta.
Editar e excluir um post não são entregues.
Permissões
engagement:manage — owner e admin por padrão, compartilhada com checklists e
pesquisas, porque operar o que seus usuários veem dentro do seu produto é um ato e não
três.