← Back to site

PPRT (Point Perfect)

1. O que é

Uma ferramenta de "ler depois" para quem salva artigos e nunca volta neles. Em vez de uma caixa de entrada de links não lidos ordenados por recência, a tela inicial é um digest ranqueado de Tópicos — aglomerados sintetizados por IA das coisas que você salvou que são sobre o mesmo assunto, cada um com uma síntese curta do que você aprenderia lendo todos juntos. (README.md, docs/PPRT_PRD.md §1)

2. Por que eu construí

Dito diretamente na própria spec do produto: ferramentas read-later existentes (Instapaper, Readwise Reader, Karakeep) são organizadas em torno do item salvo como objeto principal, então você acumula uma pilha que pretendia ler e na maioria das vezes não lê. A aposta do PPRT é que inverter o objeto principal — de "item" para "tópico sintetizado" — produz algo a que as pessoas realmente voltam. O produto começou como um exercício de validação construído por uma pessoa e agora está no ar, em validação com aproximadamente 35 usuários.

3. O que faz

Baseado no relato de construído-vs-não-construído do próprio README e corroborado no código:

Explicitamente não construído, por decisão (não por descuido — veja docs/ROADMAP.md): integração de billing/Stripe, um teto de gasto diário total entre todos os usuários, member-gets-member e os pontos de entrada Safari/iOS.

4. Como é construído

Extraído diretamente dos arquivos package.json e wrangler.toml, não assumido:

5. Decisões notáveis

O agrupamento tinha que ser complete-linkage, e o repo guarda a evidência da falha. Duas abordagens mais simples foram tentadas em um lote real de 40 itens e ambas colapsaram a biblioteca em um único aglomerado gigante: uma representação por centroide derivou para sinal genérico compartilhado (um centroide de 3 itens marcou 0.59 de similaridade contra um artigo totalmente não relacionado), e o encadeamento single-linkage mesclou transitivamente itens não relacionados através de um vizinho compartilhado (≈19% de todos os pares no lote excederam o limite de 0.55 — densidade de arestas suficiente para colapsar tudo). O comentário do código é direto: "Não reverta isso. Falhou duas vezes em dados reais." Uma troca específica e medida, não uma escolha de livro-texto de agrupamento.

Toda chamada de LLM é forçada por uma função, e o modelo é dado, não código. server/src/llm/index.js é o único ponto de entrada para seis tipos de tarefa (summarize, embed, consolidate, classify, tag, format-title); qual modelo cuida de cada um é lido de uma tabela D1 model_config no momento da chamada, então trocar um modelo é uma chamada de API de admin, nunca um redeploy. Isso é aplicado como exigência dura na spec do produto, não como convenção — e é a primeira regra listada no guia de contribuição do próprio repo.

O gating freemium foi entregue como dois eixos independentes, não uma coluna, especificamente para proteger uma promessa feita aos primeiros usuários. Desde 2026-08-20, os primeiros usuários reais são promovidos a premium manualmente no Backstage com a promessa explícita de que nunca pagarão, inclusive após o lançamento comercial. Um único campo tier não consegue distinguir um fundador comped de um assinante pagante assim que ambos existem — então o schema divide tier (o que uma conta pode fazer) de subscription_status (se há dinheiro envolvido), e o caminho de código que concede premium no Backstage deliberadamente nunca toca o subscription status, para que uma edição manual não possa acidentalmente tornar a contagem de assinantes não confiável.

O portão de convite é um toggle, não uma reescrita, quando chega a hora de abrir. O registro foi apenas por convite durante a maior parte da construção; abri-lo (depois que Consolidate/Bulk Import foram gated server-side por tier para que o custo fosse limitado de outra forma) foi uma única leitura de variável de ambiente em um lugar, honrada pelas três rotas que tocam a criação de conta, com os convites ainda totalmente funcionais por baixo — não obrigatórios, mas ainda consultados, ainda atribuídos, ainda gastáveis — então o portão pode ser fechado de novo sem perda de dados.

6. Construído com Claude Code

Isso é diretamente atribuível do histórico do git, não inferido. O repo tem 413 commits de 2026-05-09 a 2026-08-22 (~3,5 meses), efetivamente autoral solo (399 commits sob um nome, 14 sob uma identidade de teste placeholder do scaffolding inicial). 311 desses 413 commits — cerca de 75% — carregam um trailer Co-Authored-By: Claude (188 Opus 5, 119 Sonnet 5, 4 Fable 5), o que significa que as próprias mensagens de commit registram o Claude Code como contribuinte em três de cada quatro commits ao longo da vida do projeto, cobrindo toda a gama: a migração inicial para a Cloudflare, o algoritmo de agrupamento e suas duas tentativas de falha documentadas, o sistema freemium/tier, a integração do CMS e correções de incidentes de produção em andamento.

A própria spec do produto nomeia a ferramenta diretamente: o cabeçalho de docs/PPRT_PRD.md afirma "Prototyping target: Claude Code (Fable 5) for scaffolding and implementation." — isso não foi retrofitado para uma narrativa de portfólio; está embutido nos documentos de trabalho do projeto desde o início.

O que é distintivo no workflow, visível no próprio repo: comentários em prosa extensos por todo o codebase que registram por que uma decisão foi tomada e qual alternativa foi tentada e rejeitada, um arquivo docs/HISTORY.md mantido explicitamente como uma trilha de auditoria de decisões revertidas, e um arquivo guia CLAUDE.md cujo propósito declarado é rotear um colaborador de IA para o documento certo antes de começar — ou seja, o projeto foi estruturado, enquanto era construído, para ser legível a um agente de IA retomando contexto a frio em uma nova sessão. Não fica claro no repo: a divisão precisa de "quais linhas Eduardo digitou vs. Claude digitou" dentro de qualquer commit individual — o trailer de co-autoria marca colaboração, não percentual de autoria.

7. Estado atual

Ao vivo e funcionando hoje: salvar via extensão/bookmarklet/web, ingestão e sumarização, o Dream Job (agrupamento, subtópicos, mesclagem, auto-split), o digest de Tópicos, exportação em dois formatos, Tópicos da Comunidade, avaliações de síntese, correções manuais de tópicos, login magic-link e Google, importação em lote, Backstage e o CMS apoiado em Git para todo o texto editável.

Marcos do GitHub (verificados ao vivo): "Friends and Family" — 13/13 issues fechadas, 0 abertas. "Public Launch" — 10 fechadas, 8 abertas (itens abertos incluem submissão do add-on Firefox, notificações por email no encerramento da conta e medição de custo por usuário).

Deliberadamente não construído: billing/integração Stripe e planos pagos (o freemium existe estruturalmente — um campo tier que toda rota já verifica — mas nada é cobrado hoje), um teto de gasto diário entre usuários, referrals member-gets-member, Safari/iOS.

Números de uso: não estão claros no repo. Nenhuma integração de analytics (PostHog, GA, Mixpanel, Plausible etc.) foi encontrada em nenhum lugar do codebase. As métricas de sucesso do próprio produto são explicitamente qualitativas e manuais — "um testador descreve uma síntese de Tópico como algo que ele não teria montado sozinho? Teste isso diretamente perguntando." O custo de LLM por chamada é registrado (~US$0.0106/item salvo), mas relatar uso agregado/contagem de usuários é um problema aberto e não construído. O registro está aberto a qualquer um hoje, mas o repo não contém registro de quantas pessoas se inscreveram.

8. Resumo em uma linha

Um app read-later construído por uma pessoa, hospedado na Cloudflare, que usa IA para transformar seus links salvos em tópicos sintetizados em vez de uma pilha de não lidos — construído na mão com Claude Code ao longo de 400+ commits, três quartos deles co-autorados por IA.