006 — Anonymous-first identity (chat = onboarding, no signup)
Status: Aceita (2026-06-03)
Contexto
Section titled “Contexto”O cenário 008 estabeleceu AgentChat como Domain Service stateless. O 012 enriqueceu o contract com resourceId/threadId opacos — sem dizer de onde o resourceId vem. ADR 004 (memory architecture) referiu resourceId como “couple/Household” mas também deixou aberto se ele exige auth backend, signup form, ou outro mecanismo.
Insight do Gabriel (2026-06-03, conversa de produto): “Boa desse tipo de sistema que não tem cadastro, né? A gente fala com o agente e isso já resolve.” Combinado com o CEO doc — K-factor 1.5 viral + couples-first + bootstrap — fricção zero de entrada vira proposta de valor competitiva, não detalhe de UX. Honeydue (concorrente direto, em maintenance) ainda exige signup. Mobills/Organizze pedem conta. Janela aberta.
Decidir agora evita que 016 (onboarding) e 017 (referral) sejam modelados com signup screen por inércia. Também ancora resourceId (já planejado em 012/004) numa fonte concreta — sem auth backend.
Decisão
Section titled “Decisão”Adotar anonymous-first identity model. Chat É o onboarding. Sem signup tradicional, sem email obrigatório, sem password.
resourceId = UUID anônimo client-side
Section titled “resourceId = UUID anônimo client-side”- Gerado no primeiro hit do device (cookie + localStorage, dupla-persistência).
- Não é PII. UUID v4 random — não derivado de nada do user.
- Persistido device-side. Backend recebe via header/payload mas não emite nem valida contra auth.
Household.idmapeia 1:1 comresourceIdquando o Household é criado pelo agent (via write tool — cenário 013). Caller (composition root) faz o mapping; agent continua sem conhecerHousehold(gotcha “resourceId opaco no contract, mapping fica no caller”).
Onboarding = primeira conversa
Section titled “Onboarding = primeira conversa”- Device sem cookie → cookie criado on-the-fly →
resourceIdnovo. - Primeira
AgentChat.ask({messages, resourceId, threadId})chega com working memory vazia (ADR 004). - Agent extrai facts (nomes, renda, metas) via tool-calls naturais durante a conversa —
updateWorkingMemory(012) + write tools (013) populam o domínio progressivamente. - Sem signup screen. Sem email opcional na primeira interação.
Convidar parceiro = link assinado
Section titled “Convidar parceiro = link assinado”inviteToken= string assinada (HMAC-SHA256 + secret server-side) carregando{resourceId, expiresAt, mode}.- TTL 7 dias.
mode: single-use(default) invalida ao consumir;mode: multi-usedecisão futura (owner choice) — não decidido nesta ADR. - URL:
mel.finance/join?token=<inviteToken>. - Parceiro abre link → device dele recebe o MESMO
resourceId(transferido via token) → ambos veem mesmo state. Cookie/localStorage do parceiro persiste daí em diante. - Tech detail diferido: HMAC algo concreto, schema de rotação de secret, formato exato do payload (JWT vs string compacta) ficam pra spec/cenário 017. ADR cristaliza só a forma: link assinado, TTL, opacidade do token pro user.
Upgrade opcional pra account-bound (futuro)
Section titled “Upgrade opcional pra account-bound (futuro)”- Casal escolhe ligar email/passkey →
resourceIdcontinua válido, agora também acessível via login em outro device. - Working memory + history + aggregates persistidos sob o mesmo
resourceId— sem perda de estado no upgrade. - Trigger UX (quando agent oferece upgrade): milestone “1 mês ativo”, pedido explícito de export, ou tentativa de acesso em segundo device sem token.
Consequências
Section titled “Consequências”Implicações por cenário
Section titled “Implicações por cenário”- 008 / 012 / 013 —
resourceId/threadIdcontinuam opacos no contract (já decidido). Esta ADR confirma a fonte: cookie/localStorage UUID, sem auth backend. Nenhum scenario existente precisa amendment imediato — contract já era opaco por design. - 016 (onboarding casal — planejado) — vira “chat-as-onboarding”. Primeira mensagem cria
resourceId; agente pergunta nomes/contexto via conversa natural. SEM signup screen. SEM email obrigatório. Revisar quando escrever o cenário. - 016 (referral attribution) —
ShareTokenmechanism vira primary growth path. Parceiro/amigo via link gera attribution log (sem mecânica de fila). Em couple flow, parceiro vira device-bound do mesmoresourceIdvia group chat; amigo cria novoHousehold. Distinção fica no router de wa-001. - 018 (freemium gating — planejado) — Plan VO ligado a
resourceId, não a User. Free tier por device/cookie. Paid: escalar pra multi-device (login obrigatório) ou desbloquear features premium.
Privacidade / LGPD
Section titled “Privacidade / LGPD”- Sem PII default. Cookie é UUID anônimo — não rastreável a pessoa sem opt-in explícito.
- LGPD-friendly: base legal “legítimo interesse” enquanto anonymous; “consentimento” quando user opta por upgrade (email/passkey + dados pessoais).
- Working memory armazena nomes/renda que o casal escolheu contar pro agente — fact-extraction LLM-driven (ADR 004), não scraping silencioso.
Positivas
Section titled “Positivas”- Fricção zero de entrada — alinha com K-factor viral do CEO doc.
- LGPD-friendly por default — adia consent UX pra upgrade real.
resourceIdganha fonte concreta (cookie/localStorage) sem auth backend novo.- Compatível com ADR 004: memory layer já recebe
resourceIdopaco; nada muda noAgentChatcontract. - Diferenciação competitiva real — Honeydue/Mobills/Organizze todos exigem signup.
Negativas / Trade-offs
Section titled “Negativas / Trade-offs”- Sem recover-if-lose-device no nível anonymous. Casal limpa cookie / troca celular sem ter feito upgrade → state perdido (working memory + history + aggregates). Mitigação: agent oferece export por email quando user pede ou em milestone (“1 mês ativo”). UX explica antecipadamente.
- Cross-device sync requer upgrade. Segundo device do mesmo user precisa login (após upgrade) OU re-invite via link. Aceito: anonymous-first é entrada, não estado final.
- Anti-abuse mais frágil. Cookie reset = device “novo”, contornaria rate limits do free tier. Mitigação: rate limit por IP + device fingerprint suave (não draconian — não fingerprint exato). Aceito porque fricção 0 ganha de 100% anti-abuse pra MVP.
inviteTokené attack surface novo. HMAC + TTL + single-use default mitigam; rotação de secret e revogação ficam pra 017.
Alternativas consideradas
Section titled “Alternativas consideradas”- Email/password tradicional — fricção alta (form + verificação + recuperação). Conflita com viralidade do CEO doc. Rejeitado.
- Magic link only (email → link de login) — melhor que password mas ainda exige email logo de cara. Vira “auth-light”, não “anonymous-first”. Rejeitado pra MVP; reservado como caminho de upgrade.
- Passkey/WebAuthn primary — UX moderno mas ainda requer registration step (criar passkey, salvar no device). Não passa pelo “abre o app e fala”. Reservado como caminho de upgrade premium.
- Email opcional pós-conversa — adoptado como caminho de upgrade, não como entry point. User libera quando quiser export/multi-device.
- Server-side anonymous session (sem cookie) — exigiria token de sessão server-side, gerenciamento de expiration, refresh. Cookie/localStorage local é mais simples e alinha com local-first do stack (ADR 001).
Referências
Section titled “Referências”- ADR 001 — stack de infraestrutura (local-first, SQLite, sem backend auth pesado).
- ADR 004 — memory architecture (
resourceIdopaco no contract; memory ligada aresourceId, não a User). - Cenário 008 —
AgentChatstateless contract. - Cenário 012 —
resourceId/threadIdopacos, memory via DI. - Cenário 013 — write tools persistem state ligado ao
resourceId(via repositórios injetados). - Cenário 005 —
Household+Member(Household.id mapeia 1:1 comresourceId). docs/CEO.md— K-factor 1.5 viral, couples-first, janela aberta vs Honeydue/Mobills.- Insight Gabriel (2026-06-03): “não tem cadastro, fala com agente e resolve.”