SuperdindaDocs

Como escrever docs

O guia de autoria deste site - frontmatter, diagramas, tabelas de tipo, gráficos, árvores de arquivo, passos, código e os outros componentes do MDX, cada um em uso.

EstávelDono: João#docs#mdx#fumadocs

Toda página é um .mdx em apps/docs/content/docs/<raiz>/. Os componentes desta página funcionam em qualquer .mdx sem import: estão no mapa de src/components/mdx.tsx. Os plugins de remark e rehype ficam em source.config.ts.

Frontmatter

Além de title e description, toda página aceita três campos opcionais. O build valida o frontmatter (src/lib/frontmatter.ts): um status com erro de digitação para o build e aponta o arquivo.

content/docs/framework/minha-pagina.mdx
---
title: Minha página
description: Uma frase que diz o que a página resolve.
owner: João
status: review
tags: [sse, pareamento]
---

Prop

Type

owner, status e tags aparecem numa linha embaixo da descrição, como no topo desta página.

Onde fica cada coisa

Um bloco de código com a linguagem files vira uma árvore (plugin remarkMdxFiles). Pastas terminam em /:

source.config.ts
rate-limits.json
reconnect.json
meta.json
writing-docs.mdx
mdx.tsx
chart.tsx
mermaid.tsx
frontmatter.ts
source.ts

A mesma árvore em JSX, quando precisa abrir uma pasta ou trocar um ícone:

<Files>
  <Folder name="content" defaultOpen>
    <Folder name="docs" defaultOpen>
      <File name="meta.json" />
      <File name="index.mdx" />
    </Folder>
  </Folder>
  <File name="source.config.ts" />
</Files>
meta.json
index.mdx
source.config.ts

Uma página nova entra no menu pelo meta.json da pasta (pages). Sem isso, ela vai pro fim da lista.

Diagramas

Escreva um bloco mermaid. O plugin remarkMdxMermaid o transforma em <Mermaid chart="…" />, que desenha no navegador com as cores dos tokens e acompanha o tema claro e escuro. No servidor e sem JavaScript, aparece o código do diagrama.

Fluxo

flowchart LR
  A["Mudança de estado"] --> B[("Tabela events")]
  B --> C["XADD events:account:id"]
  C --> D["SSE pro app"]

Sequência

sequenceDiagram
  participant App as app
  participant API as api
  App->>API: POST /accounts/{uid}/events/ticket
  API-->>App: 201 { ticket, url }
  App->>API: GET url (EventSource, em até 60 s)
  API-->>App: event: event
  API-->>App: event: ping (a cada 5 s sem dados)

Estados

Use stateDiagram-v2. O diagrama completo do pareamento está em Pareamento.

stateDiagram-v2
  direction LR
  [*] --> open
  open --> resolved: resolver
  open --> dismissed: não é risco
  resolved --> open: reabrir em até 7 dias
  dismissed --> open: reabrir em até 7 dias

Entidades e relações

Um erDiagram com as tabelas de alerta da migração 0044_risk_alerts:

erDiagram
  seats ||--o{ risk_alerts : "tem"
  risk_alerts |o--o{ risk_findings : "agrupa (alert_id)"
  risk_alerts ||--o{ risk_alert_events : "histórico"
  risk_alerts |o--o| risk_alerts : "previous_alert_id"
  risk_alerts {
    uuid uid
    text kind
    text severity
    text group_key
    text status
    timestamptz superseded_at
  }
  risk_alert_events {
    text type
    bigint member_user_id
    jsonb detail
    timestamptz at
  }

Os diagramas reais dos guias: estados em Pareamento, o ciclo do alerta em Alertas e o caminho de um evento em Webhooks e eventos.

Tabelas de tipo

Direto do TypeScript

<AutoTypeTable> lê o tipo exportado do arquivo na hora do build (fumadocs-typescript), com os comentários de documentação. O path é relativo a apps/docs.

<AutoTypeTable
  path="../../backend/src/domains/protection/dtos/protection.dto.ts"
  name="ProtectionState"
/>

Prop

Type

Pra mostrar só parte de um tipo grande (props que estendem um elemento HTML, por exemplo), passe um type no mesmo contexto do arquivo:

<AutoTypeTable
  path="../../packages/ui/src/feedback/badge.tsx"
  name="BadgeLook"
  type="Pick<BadgeProps, 'tone' | 'size' | 'icon' | 'render'>"
/>

Prop

Type

Tipos que dependem do kysely

O docs não instala as dependências do backend. Um DTO que usa PairingRow["status"] (um Selectable do kysely) sai como Selectable<object>. Prefira os DTOs que usam os tipos do domínio direto (EventDto, PublicPairingDto, ProtectionState). As páginas de componente do design system já trazem as props geradas.

Escrita à mão

<TypeTable> quando o tipo não existe em TypeScript, como o frontmatter acima ou o corpo de um webhook:

<TypeTable
  type={{
    status: {
      type: '"draft" | "review" | "stable" | "deprecated"',
      description: "Vira um selo embaixo da descrição.",
    },
  }}
/>

Gráficos

<Chart> desenha linha (line), barra (bar) ou área (area) do mesmo jeito que os gráficos do backoffice: SVG na largura real, grade discreta, legenda a partir de duas séries, tooltip ao passar o mouse e uma tabela com os dados pra leitores de tela. As cores das séries são --docs-chart-1 a --docs-chart-5 (theme.css).

Nunca invente número

Um gráfico aqui mostra configuração ou dado real, com a fonte na legenda (caption). Sem fonte, sem gráfico.

Dados de um JSON

Importe o arquivo no topo da página e espalhe as props. Os JSONs ficam em content/data/ (fora de content/docs/, onde todo .json é lido como meta.json).

content/docs/framework/rate-limits.mdx
import rateLimits from "../../data/rate-limits.json";

<Chart {...rateLimits} />
Pedidos permitidos por janela de 1 hora
  • Por identificador (e-mail ou link)
  • Por IP
Pedidos permitidos por janela de 1 hora
regraPor identificador (e-mail ou link)Por IP
Pedir código520
Evidência1030
Recusar ou parar1030

Padrões de backend/src/config/env.ts: RATE_OTP_REQUEST_PER_EMAIL/_PER_IP, RATE_EVIDENCE_PER_LINK/_PER_IP, RATE_CONSENT_WRITE_PER_LINK/_PER_IP.

Reconexão depois de uma queda
  • Espera antes da tentativa
  • Tempo desde a queda
Reconexão depois de uma queda
tentativaEspera antes da tentativaTempo desde a queda
1ª tentativa0,5 min0,5 min
2ª tentativa2 min2,5 min
3ª tentativa10 min12,5 min

RECONNECT_DELAYS_MS em backend/src/domains/channels/use-cases/apply-provider-state.ts: 30 s, 2 min e 10 min. Se a 3ª também falhar, o pareamento vai pra disconnected.

Reconexão depois de uma queda
  • Espera antes da tentativa
  • Tempo desde a queda
Reconexão depois de uma queda
tentativaEspera antes da tentativaTempo desde a queda
1ª tentativa0,5 min0,5 min
2ª tentativa2 min2,5 min
3ª tentativa10 min12,5 min

RECONNECT_DELAYS_MS em backend/src/domains/channels/use-cases/apply-provider-state.ts: 30 s, 2 min e 10 min. Se a 3ª também falhar, o pareamento vai pra disconnected.

Dados na própria página

<Chart
  type="bar"
  title="Janela de análise ao vivo: o que fecha a janela"
  caption="ANALYSIS_QUIET_SECONDS e ANALYSIS_MAX_WINDOW_SECONDS em backend/src/config/env.ts."
  x="regra"
  unit=" min"
  series={[{ key: "minutos", label: "Minutos" }]}
  data={[
    { regra: "Conversa quieta", minutos: 2 },
    { regra: "Idade máxima", minutos: 15 },
  ]}
/>
Janela de análise ao vivo: o que fecha a janela
Janela de análise ao vivo: o que fecha a janela
regraMinutos
Conversa quieta2 min
Idade máxima15 min

ANALYSIS_QUIET_SECONDS (120 s) e ANALYSIS_MAX_WINDOW_SECONDS (900 s) em backend/src/config/env.ts. A janela também fecha com 60 mensagens (ANALYSIS_MAX_WINDOW_MESSAGES).

Prop

Type

Código

Blocos de código têm título, abas, destaque de linha e números de linha (Shiki, pelo rehypeCode).

minha-rota.ts (exemplo)
await rateLimit(`minha-rota:link:${hashToken(token)}`, {
  limit: 10,
  windowSeconds: 600, 
});
await rateLimit(`minha-rota:ip:${clientIp(c)}`, {
  limit: 30, 
  limit: 60, 
  windowSeconds: 600,
});
No blocoEfeito
```ts title="arquivo.ts"título em cima do bloco
```ts lineNumbersnúmeros de linha (lineNumbers=4 começa no 4)
// [!code highlight]destaca a linha
// [!code ++], // [!code --]linha adicionada ou removida
// [!code word:rateLimit]destaca a palavra no bloco
// [!code focus]foca a linha e apaga o resto
```ts tab="Nome"blocos seguidos com tab viram abas

Blocos seguidos com tab viram um grupo de abas:

200 OK
{
  "success": true,
  "data": { "ticket": "eyJ…", "url": "/accounts/…/events?ticket=eyJ…" }
}

Código inline também ganha cor: termine o trecho com {:ts} (ou outra linguagem) dentro dos acentos graves, como em rateLimit(key, { limit: 10 }).

Passos

Títulos com [step] viram passos (plugin remarkSteps):

Crie o arquivo

content/docs/<raiz>/minha-pagina.mdx, com title e description.

Ponha no menu

Adicione "minha-pagina" em pages no meta.json da pasta.

Rode o CI

bun run ci em apps/docs: prettier, eslint, typecheck e build. O build valida o frontmatter e renderiza cada página.

Ou, sem mexer nos títulos, <Steps> e <Step>:

Escreva a página.

Confira em localhost:3300, nos dois temas.

Outros componentes

Callout

Informação

O padrão (type="info").

Sucesso

type="success".

Atenção

type="warn": um "Em aberto" no fim de cada guia.

Ideia

type="idea".

Um aviso de largura total dentro da página (<Banner>):

Esta seção ainda segue a API antiga.

Accordion

Cards

Imagem com zoom

Toda imagem em Markdown abre ampliada ao clicar. Caminhos relativos viram import (o build sabe o tamanho):

![Lockup da Superdinda](../../../../platform/public/brand/lockup-violet.png)

Lockup da Superdinda

Índice no corpo

<InlineTOC items={toc} /> mostra os títulos da página, como no começo desta. toc já existe em todo .mdx.

Fontes

  • apps/docs/source.config.ts, src/lib/source.ts, src/lib/frontmatter.ts
  • apps/docs/src/components/mdx.tsx, src/components/mdx/mermaid.tsx, src/components/mdx/chart.tsx, src/components/page-meta.tsx
  • apps/backoffice/src/components/charts/* (o desenho que o <Chart> segue)
  • Fumadocs: Mermaid, Markdown, Collections, Macro API, Global options, Auto Type Table

On this page