Lar/Documentos/Métricas personalizadas
Contrato de métricas personalizadas
Métricas personalizadas permitem que o próprio serviço da sua extensão empurre quaisquer números importantes para isso (conversões, receita, integridade de back-end, funis) no mesmo painel que já rastreia instalações e a integridade da Chrome Web Store. O contrato é orientada por metadados e de superfície dupla: cada métrica declara onde e como aparece tanto no painel quanto no status Telegram, então o painel permanece um renderizador genérico sem código específico do produto.
1. Como funciona (superfície dupla)
Seu serviço expõe um ponto de extremidade de métricas. Ext Ops Panel é o cliente: é puxa esse ponto final (nunca o inverso) e renderiza o resposta. A resposta aciona duas superfícies ao mesmo tempo:
- Guias do painel na extensão Visualização de detalhes: guias, seções e tipos de renderização por métrica.
- Telegram status: linhas lógicas compostas pelas mesmas métricas, filtradas e formatadas por métrica.
O painel mescla suas métricas com as métricas básicas primárias (instala/desinstala/reinstala/feedback/Chrome Web Store/saúde), que moram no reservado base guia e linha Telegram.
2. O endpoint e a autenticação
O painel chama seu endpoint com GET e espera a v2 carga útil como a resposta 200. Dois modos de puxar compartilham a mesma forma:
- Sob demanda: acionado quando um usuário abre Detalhe. Taxa limitada a no máximo 1 solicitação por minuto por origem, em todos os planos, incluindo Grátis.
- Monitoramento: em um agendamento (somente Teste/Pago), compõe o status Telegram e alertas de borda.
A autenticação é um dos nenhum, portador ou api_key_header. Os segredos são armazenados criptografados em repouso no back-end do painel e nunca são entregues para a extensão do painel. Se um pull falhar, o painel se degradará normalmente (último instantâneo ou oculto) sem quebrar as métricas básicas.
3. Estrutura de carga útil
A carga útil de nível superior carrega o layout (guias, seções, Telegram linhas) e a matriz de métricas.
| Campo | Tipo | Notas |
|---|---|---|
schema_version | corda | Obrigatório. Deve ser "2.0". |
generated_at | string (data-hora) | Quando a carga útil foi composta (detecção de atualização/inatividade). |
tabs | Guia[] | Guias do painel. Consulte a seção 4. |
sections | Seção[] | Grupos de métricas dentro de uma aba (tab, id, title, order). |
telegram | TelegramMeta | Modelo header + lines[]. Consulte a seção 7. |
metrics | Métrica[] | As próprias métricas. Consulte as seções 5 e 6. |
4. Guias e ícones de guias
Uma guia é { id, title, order, icon? }. O reservado
base aba é do próprio painel
(icon="layout-dashboard"); seu serviço adiciona o resto. Quando muitos
as guias estão abertas, a guia ativa mostra o ícone + título e as outras são recolhidas para o
apenas ícone (o título permanece na dica de ferramenta e no rótulo aria).
O valor icon é uma de duas coisas:
- UM Nome do ícone Lucide em kebab-case ASCII (corresponde
^[a-z][a-z0-9-]*$), por ex.trending-up. Um bem formado, mas o nome não suportado é degradado para o ícone padrão (square) para que a barra nunca quebre. - UM emoji único, por ex. 💰 ou 🚀, renderizado como texto.
O painel envia um subconjunto selecionado de 37 nomes Lucide (mantidos enxutos para o pacote MV3):
- painel de layout
- atividade
- medidor
- camadas
- plugue
- cifrão
- nota
- carteira
- Cartão de crédito
- recibo
- gráfico de barras-3
- gráfico de linhas
- gráfico de pizza
- tendência
- tendência de queda
- Usuários
- usuário
- triângulo de alerta
- sino
- relógio
- git-branch
- pacote
- caixa
- banco de dados
- servidor
- CPU
- zap
- globo
- quebra-cabeça
- funil
- filtro
- quadrado
- círculo
- hash
- por cento
- marcação
- bandeira
5. Métrica: valor + dois blocos de posicionamento
Uma métrica carrega um valor digitado mais dois blocos independentes:
dashboard (onde e como na extensão) e
telegram (onde e como na mensagem). Pode ser omitido ou
oculto por meio de show:false, portanto, uma métrica pode residir em apenas uma superfície.
| Campo | Notas |
|---|---|
id | ID de métrica estável, exclusivo na carga útil. |
kind | Tipo de dados (seção 5.1). Seleciona quais campos de valor se aplicam. |
label | Rótulo humano canônico. |
value e campos de tipo | Os campos de carga útil dependem de kind (seção 5.1). |
severity | Um de ok, info, warn, crit (mapeia para cores/emoji). |
shareable | Booleano opcional, padrão true. Quando false a métrica é somente do proprietário: em um projeto compartilhado somente leitura, ela é removida do lado do servidor e nunca atinge um observador/visão pública (use para métricas financeiras). Governa o acesso, não a colocação. |
dashboard | { show, tab, section, order, name, render, options } (seção 5.2). |
telegram | { show, line, pos, format, sep, when } (seções 6 e 8). |
5.1. Tipos (tipo de dados + carga útil)
Os tipos são um conjunto aberto: um tipo desconhecido é ignorado pelo renderizador (compatível com versões futuras).
| tipo | Campos de carga útil | Exemplo de uso |
|---|---|---|
number | value (+ opcional delta, unit) | contagens de instalação/feedback |
delta | value, delta (renderiza 1200 (+72)) | total (+hoje) |
percent | value (0 a 100) | taxa de sucesso do motor |
duration | seconds ou minutes | p50/p95/média, frescor |
bytes | bytes ou kb | tamanho de saída (~522 KB) |
rating | value, count | 5,0★ (1) |
money | value, currency, opcional delta | MRR, gastar |
status | state + severity | semáforo de saúde |
series | points:[{date,count}], multi series:[{name,points}] opcional | instalações diárias, usuários ativos |
intraday | series:[{name,intraday:[{minute,value}]}], opcional step_min (padrão 15), tz | hoje em intervalos de 15 minutos |
hour_histogram | { weekdays:[...], start, end, tz } | conversões por hora |
funnel | steps:[{key,label,value}] | preços para finalizar a compra |
breakdown | items:[{label,value,unit?,sub?/money?}] | submarinos por plano, por motor, por superfície |
list | items:[{text,count?,severity?}] | erros recentes |
text | value (sequência) | texto livre |
5.2. Renderizar (como mostrar no painel)
dashboard.render escolhe o visual (geralmente corresponde a kind,
mas pode diferir, por ex. mostre um percent como um badge). Também
um conjunto aberto.
| renderizar | Olhar | Opções (dashboard.options) |
|---|---|---|
kpi | Cartão: nome + valor grande + delta | tone |
badge | Pílula de status/pictograma por gravidade | – |
chart | Gráfico de linhas (mês/duração, média contínua de 7, foco) | series, defaultMode |
intraday | Hoje por intervalos (96 por UTC dia): barras empilhadas ou linhas suavizadas, eixo de tempo HH:MM, leitura instantânea entre séries | mode (bars | lines, padrão lines) |
hour_histogram | Barras horárias, agrupadas Dias da semana / Fim de semana / Por dia da semana | series |
funnel | Etapas com conversão entre eles | – |
breakdown | Barras categóricas horizontais com valor + parcela do total | items |
table | Tabela (por exemplo, feedback) | columns |
text | Parágrafo/inline | – |
status | Estado do semáforo por gravidade | – |
list | Lista de itens com contagem/gravidade opcional | – |
intraday versus chart. O chart
eixo é diário (points[].date = YYYY-MM-DD) e seu
A visualização mensal divide os últimos 30 pontos, portanto, os 96 intervalos de hoje não cabem nela.
intraday é o gráfico Today primário exposto como um tipo de contrato: o
mesma convenção onde minute conta minutos a partir do início do dia UTC
(0, 15,…, 1425), mas as séries e os dados são declarados pela fonte. Enviar apenas
baldes não vazios, o painel densifica o resto.
Um intervalo vazio é null, não 0. Por um
média (por exemplo, tempo médio de conversão), um zero seria uma mentira, então a linha pausas
em vez de cair no chão. Um intervalo ausente e value: null são
equivalente: a linha quebra, nenhuma barra é desenhada e a leitura instantânea mostra um traço.
6. O painel é dono da paleta
As cores do gráfico e da série são atribuídas pelo painel da marca
tokens, não pela fonte. options.series[] carrega apenas identidade
({key,label,order}); um campo color na carga útil é
consultivo e ignorado. Mapa de chaves semânticas para tokens fixos
(paid para acentuar, free para neutro silenciado,
failed/error ao perigo,
ready/success para sucesso); outras chaves levam o
paleta de marca categórica posicionalmente. O contraste permanece pelo menos 4,5:1 em ambos
temas. Isso protege a marca de hexadecimal externo arbitrário.
7. Modelos Telegram
telegram.header é o cabeçalho da mensagem;
telegram.lines[] são linhas lógicas
({ id, order, prefix, when }). O compositor reúne todas as métricas
com um determinado telegram.line, filtra por when, classifica por
pos, renderiza cada um por meio de seu modelo format e une
eles com sep de cada métrica. A linha prefix é impressa
primeiro. Tudo é texto simples.
| Espaço reservado | Saída |
|---|---|
{value} | Por tipo (número 1,200; porcentagem 99%) |
{value:k} | 1.2k / 3.0M (compacto) |
{delta:+} | +72 / -3 |
{value:pct} | 99% |
{seconds:dur} | 28s / 5m 47s |
{minutes:age} | 45m / 2h 30m / never |
{bytes:size} | ~522KB / 1.4MB |
{value}★ ({count}) | 5.0★ (1) |
{sev} | Emoji de gravidade: 🟢 ok, 🟡 avisar, 🔴 crítico, ⚪ inativo |
{trend} | ↗ / ↘ (±5pp vs 7d) |
8. Condições de visibilidade (quando)
when controla se um campo de métrica (ou uma linha Telegram inteira)
mostra. Valores:
| quando | Mostra o campo |
|---|---|
always | Sempre (padrão). |
nonzero | Somente quando o valor não for 0/vazio. |
severity>=warn | Somente quando a gravidade é avisada ou crítica. |
changed | Somente quando mudou desde o instantâneo anterior. |
Valores desconhecidos de when se comportam como always (compatível com versões futuras).
9. Exemplo de carga útil
{
"schema_version": "2.0",
"generated_at": "2026-07-02T23:17:30Z",
"tabs": [
{ "id": "conv", "title": "Conversions", "order": 1, "icon": "trending-up" }
],
"sections": [
{ "tab": "conv", "id": "by_hour", "title": "By hour", "order": 0 }
],
"telegram": {
"header": "{name} • {cws.users} • {cws.rating}★ ({cws.rating_count})",
"lines": [
{ "id": "base", "order": 0 },
{ "id": "conv", "order": 1, "prefix": "{sev} Conv " }
]
},
"metrics": [
{
"id": "conv_today",
"kind": "number",
"label": "Conversions today",
"value": 254,
"severity": "ok",
"shareable": true,
"dashboard": {
"show": true,
"tab": "conv", "section": "by_hour", "order": 10,
"name": "Today", "render": "kpi", "options": {}
},
"telegram": {
"show": true,
"line": "conv", "pos": 20,
"format": "today {value}", "sep": " • ", "when": "always"
}
}
]
}10. O contrato legível por máquina
A descrição formal e importável deste endpoint é o arquivo OpenAPI 3.1. Ele carrega a mesma versão do contrato (2.0.0) e é o único canônico artefato de máquina, compartilhado entre idiomas.