Compartilhar anotações sem conflito de mesclagem

Product

Os espaços de trabalho do Notez tinham exatamente uma pessoa. A partir da v0.3.0, podem ter várias: convide alguém por e-mail e vocês passam a compartilhar as notas, as tags, os quadros e o chat de IA sobre tudo isso.

A parte interessante é o que eu deixei de fora.

O recurso que todo mundo pede primeiro

"Duas pessoas podem editar a mesma nota ao mesmo tempo?"

No sentido do Google Docs — dois cursores num parágrafo, caracteres se intercalando enquanto são digitados —, não. É um problema difícil de verdade, e resolvê-lo direito exige CRDTs ou transformações operacionais, uma conexão persistente por documento aberto e reescrever o jeito como uma nota é armazenada: não mais um documento, e sim um fluxo de operações que você reproduz.

É um bom recurso. Também é quase um produto inteiro por si só, e teria atrasado o compartilhamento em meses para atender a um caso que, num app de anotações, é raro. As pessoas não costumam escrever o mesmo parágrafo ao mesmo tempo. Escrevem notas diferentes, ou a mesma nota em momentos diferentes.

Então fiz o compartilhamento pensando no que acontece de fato e, no caso raro, preferi a segurança à fluidez.

O que acontece de fato

Três coisas, em ordem de importância.

Você quer saber se há mais alguém ali. Se um colega estiver com a mesma nota aberta, o avatar dele aparece ao lado do status de salvamento. O avatar se atualiza a cada poucos segundos e some cerca de um minuto depois que o colega fecha a nota.

É de propósito um indicador de presença, e não de digitação. Responde a "tem mais alguém aqui agora?" — a pergunta que faz você esperar ou seguir em frente. É um hash no Redis por nota, com TTL de 60 segundos, e um polling; nada de WebSocket, nada de fan-out de assinaturas. O recurso inteiro tem algumas dezenas de linhas, e se o Redis ficar indisponível por um momento, a nota continua abrindo e salvando.

Você quer saber quem mudou alguma coisa. O status de salvamento agora mostra Editado por Sam · há 4 minutos quando o último salvamento não foi seu, e volta a ser um simples horário quando foi. Junto com os 30 dias de histórico de versões que toda nota já guarda, dá para responder "como isto estava antes de o Sam mexer?".

A autoria acabou sendo o que as pessoas mais queriam da colaboração, e ela custa duas colunas.

Você não quer perder trabalho. Esta é a que importa.

Recusar o salvamento

A falha do compartilhamento ingênuo é silenciosa e total: você abre uma nota, edita por dez minutos, salva, e a sua versão substitui a que o seu colega salvou oito minutos antes. Nenhum erro. O trabalho dele simplesmente some, e nenhum dos dois descobre até alguém notar um parágrafo faltando na semana seguinte.

Agora o Notez dá a cada nota um número de versão. Quando o seu editor carrega uma nota, ele guarda a versão que viu, e cada salvamento leva esse número de volta. O update roda assim:

SQL
UPDATE "Note" SET ... WHERE id = $1 AND "contentVersion" = $2

Se alguém salvou nesse meio-tempo, a versão não bate mais, a cláusula WHERE encontra zero linhas e a gravação não acontece. Você vê um aviso com o nome de quem alterou a nota e um botão Recarregar.

O detalhe importante é que a proteção fica na cláusula WHERE, e não num if antes dela. Verificar e depois gravar deixa uma janela entre a verificação e a gravação — pequena, mas dois salvamentos chegando no mesmo instante é justamente quando a proteção precisa segurar. Com a versão como parte da condição do update, quem decide é o banco de dados, de forma atômica, e quem grava em segundo lugar perde.

Perder é o resultado correto. A alternativa a recusar um salvamento é adivinhar como combinar duas versões de um parágrafo, e um palpite errado é pior que um erro honesto, porque um palpite errado parece ter funcionado.

O que deixei de fora, de propósito

  • Sem permissões por nota. O acesso é por espaço de trabalho. Todo mundo que foi convidado lê tudo o que há nele, inclusive a lixeira. ACLs por nota significam uma verificação de permissão em cada caminho de leitura, uma interface para gerenciá-las e um suporte cheio de gente que não entende por que uma nota está invisível. Se você precisa de uma fronteira, crie um segundo espaço de trabalho — eles são gratuitos e totalmente isolados.

  • Sem comentários. Uma conversa de comentários é uma pequena rede social. Agora não.

  • Sem cursores ao vivo. Veja acima.

  • Sem cobrança por usuário. Os membros não precisam de plano próprio. As vagas vêm do plano do proprietário: 3 no Grátis, 10 no Pro, 25 no Ultra, e tudo o que o espaço de trabalho armazena conta na cota do proprietário.

Onde fica a fronteira

O compartilhamento é por espaço de trabalho, e os espaços de trabalho já eram a fronteira de isolamento no Notez — o chat de IA só vê o espaço atual, e uma chave MCP fica presa a um único espaço. Essa propriedade continua valendo com o compartilhamento: convide um colega para Trabalho e ele não recebe nada de Pessoal, nem na busca, nem pela IA, nem por uma chave.

Isso é garantido no servidor, a cada requisição, e é o motivo de eu ter escolhido o espaço de trabalho como unidade de compartilhamento em vez de inventar uma nova.

Se você vinha guardando tudo num único espaço de trabalho e agora quer compartilhar parte dele, mova primeiro essas notas para um espaço de trabalho só delas e depois convide.


Detalhes em Compartilhar um espaço de trabalho com outras pessoas. Tudo o que saiu nessa versão: v0.3.0.

Continue lendo