Telemetria opt-in para os projetos open source da ETUS.
⚠️ Não confundir com OpenTelemetry (CNCF). Este projeto é sobre coletar métricas agregadas de adoção dos OSS da ETUS — não sobre tracing/logs/métricas internas de aplicações.
Cada instância self-hosted de um OSS da ETUS (ex: etus-foo, etus-bar) pode embutir
o SDK @etus/telemetry-sdk. Se o operador da instância der opt-in explícito, o SDK
envia heartbeats diários anônimos com informações agregadas sobre o uso da instância:
versão, SO, features ativas, etc. — nunca dados dos usuários finais daquela instância.
Modelo de referência: o telemetry.umami.is do Umami e o phone-home opt-in do Plausible CE.
- Opt-in explícito. Telemetria desligada por padrão. Operador habilita ativamente.
- Whitelist estrita. Só campos listados em
docs/02-event-schema.mdsão coletados. - Sem PII, sem conteúdo de aplicação. Coletamos sobre a instância, não sobre quem a usa.
- Buckets em vez de números exatos. Reduz risco de re-identificação.
- IDs hashed+seeded. Não correlacionáveis entre produtos diferentes.
- Política pública versionada. Schema = contrato com a comunidade.
Toda a infra roda em Cloudflare (ADR-0002):
| Componente | Cloudflare |
|---|---|
| Ingestor HTTP + Persistor + Aggregator | Workers (3 entry points num único worker) |
| Buffer entre aceite e escrita | Queues |
| Storage transacional | D1 (SQLite) |
| Stats públicos + backups | R2 |
| Dashboard interno + site público | Pages |
SDK em TypeScript, framework do Worker é Hono + zod.
| Componente | URL |
|---|---|
| Ingestor + API pública (Worker) | https://otw.etus.dev |
| Site público (Pages) | https://telemetry.etus.dev |
| Dashboard interno (Pages, atrás de Cloudflare Access) | https://telemetry-dashboard.etus.dev |
| SDK no npm | @etus/telemetry-sdk |
Deploy é via GitHub Actions: cada push em main que toca worker/dashboard/site dispara o workflow correspondente. Bump em packages/sdk/package.json publica nova versão no npm automaticamente.
| Doc | Conteúdo |
|---|---|
docs/01-research.md |
Pesquisa de telemetria em OSS de referência |
docs/02-event-schema.md |
Schema dos eventos coletados (MVP) |
docs/03-architecture.md |
Stack Cloudflare, monorepo, fluxo end-to-end |
docs/04-privacy-policy.md |
Política pública PT-BR + EN (v1.0.0) |
docs/05-integration-guide.md |
Guia interno para times de produto integrarem o SDK |
docs/06-public-api.md |
API pública de estatísticas (estilo Homebrew) |
docs/adr/ |
Architecture Decision Records (0001 fundação, 0002 stack Cloudflare, 0003 usage inteiros, 0004 usage mapa dinâmico, 0005 registro de produtos) |
packages/
schema/ Tipos canônicos do payload (zod)
sdk/ @etus/telemetry-sdk — embarcado nas instâncias
worker/ Cloudflare Worker: ingestor + persistor + aggregator
dashboard/ Painel interno (Next.js em Pages)
site/ Site público (privacy + stats viewer, Pages)
shared/ Utils (hashing, buckets, env detection)
docs/ Documentação + ADRs
Monorepo gerenciado com pnpm workspaces + Turborepo.
pnpm install
pnpm turbo run typecheck # valida tipos em todos os packages (com cache)
pnpm wrangler d1 create etus-telemetry # primeira vez — colar o database_id em packages/worker/wrangler.toml
pnpm --filter @etus/telemetry-worker db:migrate:local
pnpm --filter @etus/telemetry-worker devScripts úteis:
| Comando | O que faz |
|---|---|
pnpm turbo run build |
Build de todos os packages, respeitando dependências |
pnpm turbo run typecheck |
tsc --noEmit em todos os packages com typecheck |
pnpm turbo run test |
Testes em todos os packages |
pnpm turbo run dev |
Dev paralelo (Worker + dashboard + site quando existirem) |
pnpm clean |
Remove dists, .turbo, node_modules |
pnpm dev:reset |
Mata dev servers órfãos (next-server/workerd/miniflare) e limpa .next corrompido |
Sem Docker. D1 e Queues rodam locais via Miniflare.
Erros tipo
ENOENT .next/server/app/page.jsouChunkLoadError? São cache stale do Next + processos órfãos de dev servers anteriores. Rodepnpm dev:resete suba de novo. Causa:next devdeixa processos filhos (next-server) órfãos quando o wrapper é morto; múltiplos escrevendo no mesmo.nextcorrompem o build.
Só o SDK é publicado (worker/dashboard/site são deployados na Cloudflare). A publicação é automática via GitHub Actions no push pra main — workflow .github/workflows/publish-sdk.yml.
Guarda de versão: o workflow só publica se a versão em packages/sdk/package.json ainda não existe no npm. Então o fluxo de release é:
- Bump da versão em
packages/sdk/package.json(ex:0.1.0→0.1.1) - PR + merge na
main - O Action builda, roda typecheck+test, e publica
@etus/telemetry-sdk@<nova-versão>
Push na main sem bump → builda e testa, mas pula o publish (versão já existe). Sem republicação acidental.
Setup único (uma vez): criar um Automation token no npm (npmjs.com → Access Tokens → Generate → Automation) e adicioná-lo como secret do repositório em Settings → Secrets and variables → Actions → New repository secret, com nome NPM_TOKEN.
Publicação manual local (alternativa): pnpm publish:sdk.
Após o MVP, produtos novos passam por uma quarentena de aprovação: o primeiro heartbeat de um product_name desconhecido cria automaticamente uma linha pending em products. Eventos são aceitos e persistidos, mas não publicados em R2 até que um admin (atrás do Cloudflare Access) aprove pelo dashboard em /registry. Estados: pending, approved, disabled, rejected (tombstone — devolve 202 e descarta). Há também purge por produto e por instância (DSR LGPD/GDPR) que apaga events/instances/rollup_daily/R2 e grava em audit_log. Ver docs/adr/0005-product-registry.md.
✅ MVP no ar. SDK publicado, infra deployada nos domínios acima, deploy contínuo via GitHub Actions, registro de produtos (ADR-0005) implementado e em uso.