{
  "markdown": "# Lunar\n\nTemplate white-label de documentação para desenvolvedores, construído com Astro e Starlight. Luna é uma ferramenta completa de engenharia de documentação. Indicando onde sua documentação falha e a mantendo sempre atualizada.\n\nO portal separa três tipos de conteúdo:\n\n- **Guias:** instruções orientadas a tarefas e fluxos de integração.\n- **Referência de API:** contratos técnicos, autenticação e erros.\n- **Changelog:** alterações relevantes para integrações existentes.\n\nTodas as páginas oferecem o menu **Compartilhar com IA**: ele copia o título, URL e conteúdo da página. A lista de clientes e seus destinos pode ser configurada em `src/config/portal.ts`.\n\nA barra lateral traz **Fale com o chatbot**, aberto: você escreve a dúvida em linguagem natural e recebe uma resposta com as fontes. Sem chave de provedor no ambiente — que é o padrão — ele devolve os trechos das páginas e um resumo extrativo, sem redigir nada. Com `ANTHROPIC_API_KEY`, o mesmo pipeline redige a resposta a partir desses trechos, atravessando os guardrails descritos em *Assistente de documentação*. Um bloco de conteúdo reutilizável aparece com o link da página que o inclui, porque bloco não tem página própria.\n\n## Idiomas\n\nPortuguês (Brasil) é o idioma nativo, sem prefixo de URL. As traduções completas ficam disponíveis em `/en/` e `/es/`, com o seletor de idioma nativo do Starlight. Para manter a associação entre idiomas, crie páginas com o mesmo caminho relativo em `src/content/docs/`, `src/content/docs/en/` e `src/content/docs/es/`.\n\n## Personalização\n\nEdite `src/config/portal.ts` para definir a empresa, o título do portal, a descrição, a URL base da API e o e-mail de suporte. As cores ficam em `src/styles/custom.css`.\n\n## Estrutura de conteúdo\n\n```text\nsrc/content/docs/\n├── api-reference/  # Contratos e convenções da API\n├── changelog/      # Alterações por versão ou data\n├── guides/         # Tutoriais e tarefas de integração\n└── index.mdx       # Página inicial\n```\n\nArquivos Markdown e MDX dentro de `src/content/docs/` são publicados automaticamente pelo Starlight. A navegação das três áreas é gerada a partir desses diretórios.\n\n## Comandos\n\n| Comando | Ação |\n| --- | --- |\n| `npm install` | Instala as dependências. |\n| `npm run dev` | Inicia o ambiente de desenvolvimento. |\n| `npm run build` | Gera a versão de produção em `dist/`. |\n| `npm run preview` | Visualiza localmente a versão de produção. |\n| `npm run check` | Typecheck de `.astro`, `.ts` e `.tsx` (`astro check`). |\n| `npm test` | Roda os testes (Vitest). |\n| `npm run docs:lint` | Analisa a documentação e calcula o Quality Score. |\n| `npm run docs:test` | Testes de documentação: links, âncoras, referências e exemplos de API. |\n| `npm run docs:health` | Observabilidade: dimensões, SLOs, orçamento, histórico e regressões. |\n| `npm run twin` | Digital Twin: cobertura, não documentados, obsoletos, impacto. |\n| `npm run contract` | Contract Testing: o exemplo representa o contrato de verdade? |\n| `npm run gaps` | Gap Mining: o que as pessoas procuram e não encontram. |\n| `npm run agent` | Agentes de documentação: pesquisa, rascunho, validação. |\n| `npm run history` | Time Machine: timeline, snapshot, comparação e restore. |\n| `npm run docs:code` | Vínculo com o código: impacto, cobertura, órfãos e entidades sem documentação. |\n| `npm run governance` | Governança: donos, revisões pendentes, aprovações e auditoria. |\n| `npm run analytics` | Observabilidade de leitura: busca, jornadas, abandono e lacunas comportamentais. |\n| `npm run ai:eval` | Avaliação do assistente: conjuntos de perguntas, métricas verificáveis e regressão. |\n| `npm run graph` | Knowledge Graph: consulta, impacto e frescor. |\n| `npm run org` | Organização: repositórios, produtos, saúde agregada e busca global. |\n| `npm run heal` | Self-healing: detectar, diagnosticar, propor e validar correções. |\n| `npm run sdk` | SDK: gerar, verificar e comparar o cliente TypeScript da API. |\n| `npm run overlay` | Overlays: validar, prever, aplicar, comparar e rastrear proveniência. |\n| `npm run changelog` | Changelog mensal a partir dos commits, com filtro de ruído e links de endpoint. |\n| `npm run api` | API Views: listar, construir as especificações efetivas e verificar. |\n| `npm run docs:asyncapi` | Gera páginas de referência a partir de especificações AsyncAPI. |\n| `npm run user:create` | Cria um usuário do portal (ver *Usuários e controle de acesso*). |\n| `npm run db:*` | Supabase local: `db:start`, `db:stop`, `db:reset`, `db:migrate`, `db:types`, `db:test`, `db:prune` (ver [docs/banco-de-dados.md](docs/banco-de-dados.md)). |\n\n> **Comece pelo [Manual completo](src/content/docs/guides/manual.mdx)** (publicado em `/guides/manual/`): recursos do portal e do editor, atalhos de teclado, fluxos de trabalho e casos de uso, com diagramas.\n\n## Arquitetura e decisões\n\n- **[docs/arquitetura.md](docs/arquitetura.md)** — o portal nos níveis do\n  [modelo C4](https://c4model.com/): contexto, contêineres, componentes e dois\n  diagramas dinâmicos (o portão de pull request e o ciclo de self-healing).\n- **[docs/banco-de-dados.md](docs/banco-de-dados.md)** — a camada de\n  persistência em nuvem: o que vive no Git e o que vive no Supabase, o modelo de\n  dados, as políticas de RLS e o ambiente local.\n- **[docs/adr/](docs/adr/)** — 22 Architectural Decision Records. Cada uma\n  registra uma decisão, o que ela custou, o que foi descartado e — quando a\n  decisão nasceu de um defeito observado — o defeito.\n\nA distinção entre os dois vale saber: a arquitetura descreve como o sistema é\nhoje e muda quando ele muda; uma ADR descreve por que ele ficou assim e não muda\nnunca. Quando a decisão é revista, a ADR antiga é marcada como substituída e uma\nnova é escrita.\n\n## Recursos\n\nCada recurso tem um guia próprio no portal publicado. As seções abaixo dão o\nresumo e o link.\n\nPara ver todos operando ao mesmo tempo sobre um produto fictício, veja a\n**[vitrine de recursos](src/content/docs/exemplos/index.mdx)** (publicada em `/exemplos/`).\n\n```mermaid\nflowchart LR\n    A[\"<b>Escrever</b><br/>editor · reuso · glossário<br/>audiências · versões\"]\n    B[\"<b>Verificar</b><br/>linter · testes · contratos<br/>Digital Twin · proveniência\"]\n    C[\"<b>Revisar</b><br/>impacto · saúde · governança<br/>vínculo com o código\"]\n    D[\"<b>Publicar</b><br/>site · SDK · llms.txt<br/>MCP · API Explorer\"]\n    E[\"<b>Observar</b><br/>leitura · lacunas<br/>avaliação de IA\"]\n\n    A --> B --> C --> D --> E\n    E -. \"a lacuna medida vira tarefa de escrita\" .-> A\n\n    classDef s fill:#438dd5,stroke:#2e6295,color:#fff\n    class A,B,C,D,E s\n```\n\nA seta de volta é a tese: o portal não termina em publicar. O que os leitores não\nencontram vira item de backlog priorizado, e o ciclo recomeça.\n\n### Autoria\n\n_Escrever, revisar e reaproveitar conteúdo._\n\n#### Editor de documentação\n\nUm editor Markdown/MDX completo em `/editor`, com Monaco, preview em tempo real, reuso de conteúdo, grafo de dependências bidirecional, paleta de comandos e consciência de Git. Ele lê e grava os arquivos de `src/content/docs` diretamente — não há banco de dados no meio.\nDetalhes em **[Editor de documentação](/guides/editor/)**.\n\n#### Linter e Quality Score\n\nUm revisor editorial automatizado que aponta problemas com id estável e calcula uma nota de 0 a 10 por dimensão. O style guide fica versionado em Git, e a nota não é `10 − nº de erros`: cada dimensão é pontuada isoladamente e o dano é normalizado por tamanho.\nDetalhes em **[Linter e Quality Score](/guides/linter-e-quality-score/)**.\n\n#### Navegação\n\nSidebar por diretório, breadcrumbs, paginação, índice da página e navegação por tags — tudo derivado da estrutura de arquivos, sem um índice paralelo para manter sincronizado.\nDetalhes em **[Navegação](/guides/navegacao/)**.\n\n#### Documentação adaptativa\n\nA mesma página serve a quem programa, a quem atende cliente e a quem opera, sem duplicar arquivo. Nada é escondido: o conteúdo de outra audiência fica recolhido num `<details>` com rótulo, alcançável por teclado e pelo Ctrl+F. Quem lê escolhe o perfil; nada é inferido por comportamento.\nDetalhes em **[Documentação adaptativa](/guides/documentacao-adaptativa/)**.\n\n#### Busca\n\nBusca local com Pagefind por padrão, Algolia DocSearch opcional, e a busca \"warp drive\" que cai direto no melhor resultado.\nDetalhes em **[Busca](/guides/busca/)**.\n\n#### Versionamento da documentação\n\nVersões da documentação com seletor, aviso de versão antiga e congelamento. A versão é um diretório de conteúdo, não um branch — o que permite ler duas versões lado a lado.\nDetalhes em **[Versionamento da documentação](/guides/versionamento/)**.\n\n#### Glossário\n\nUm arquivo Markdown por termo em `src/content/glossary/`, versionado pelo Git. Um termo cadastrado é destacado nas páginas, listado em `/glossary` e **usado pelo linter** para avaliar consistência de terminologia — o glossário é a fonte, e o linter é consumidor dela.\nDetalhes em **[Mantenha o glossário](/guides/glossario/)**. Arquitetura em [docs/glossario.md](docs/glossario.md).\n\n#### Testes de documentação\n\nO linter pergunta \"isto está bem escrito?\". A suíte pergunta \"isto **funciona**?\" — um link para página inexistente passa em qualquer regra de estilo, e um exemplo que não bate mais com o schema está impecavelmente redigido.\nVerifica links, âncoras, Content Graph e exemplos de API, em três perfis do mais barato ao mais caro. A execução de snippets fica desligada por padrão: rodar código vindo de arquivo de conteúdo é execução arbitrária.\n\n```bash\nnpm run docs:test\n```\n\nDetalhes em **[Testes de documentação](/guides/testes-de-documentacao/)**.\n\n#### Contratos de documentação\n\nA suíte pergunta _\"este exemplo funciona?\"_. Esta camada pergunta _\"ele representa o **contrato** de verdade?\"_. O caso que as separa: a API exige `amount` e `currency`, a documentação mostra só `amount` — o exemplo roda, e está incompleto.\n\nA comparação corre nos **dois sentidos**, e o segundo é o que quase nenhuma ferramenta faz: campo que o exemplo mostra e o contrato não tem. É assim que documentação envelhece sem quebrar nenhum teste.\nDetalhes em **[Contratos de documentação](/guides/contratos-de-documentacao/)**.\n\n#### Análise de impacto\n\nO Content Graph responde \"quem usa o quê\" — informação. O Impact Engine responde \"se eu mudar isso, o que preciso revisar?\" — decisão. Aparece no editor e no corpo do pull request.\nA razão de o motor existir é a dependência **indireta**: A inclui B, que inclui o bloco que você está editando, e não há aresta entre os dois. A contagem de um salto respondia \"nenhuma página afetada\" com convicção e errada.\nDetalhes em **[Análise de impacto](/guides/analise-de-impacto/)**.\n\n#### Confiança e proveniência\n\nUma página pode dizer \"chaves expiram em 90 dias\" sem que exista registro de onde isso veio, quem confirmou e quando. A proveniência é declarada no próprio conteúdo e versionada no Git.\n**O limite do selo vem antes da funcionalidade.** \"Verificado\" quer dizer que a evidência citada existe e confere — o endpoint está na especificação, o arquivo e a linha estão no código. **Não** quer dizer que a frase é verdadeira.\nDetalhes em **[Confiança e proveniência](/guides/confianca-e-proveniencia/)**.\n\n#### Observabilidade e SLOs\n\nDez dimensões, SLOs, orçamento de erro e regressão entre medições — a pergunta de segunda-feira, que nenhuma das outras camadas responde: **a documentação está saudável, e o que fazemos primeiro?**\nEla não mede nada de novo; consulta as camadas que já medem. E a idade sozinha não determina obsolescência: o que empurra uma página para vermelho é evidência de divergência, não o calendário.\nDetalhes em **[Observabilidade e SLOs](/guides/observabilidade/)**.\n\n#### Avaliação de IA\n\nMede o assistente contra conjuntos de perguntas versionados em `evals/`. A camada separa **verificável** de **inferido** e só mede o primeiro: citação aponta para página que existe, página esperada foi citada, termo exigido apareceu. Por isso a métrica se chama \"termos presentes\", não \"correção\" — uma resposta pode conter todas as palavras e estar errada.\nEm `npm run ai:eval` e em Settings → AI Evaluation.\nDetalhes em **[Avaliação de IA](/guides/avaliacao-de-ia/)**.\n\n### Qualidade e verificação\n\n_Descobrir o que está errado antes de quem lê descobrir._\n\n### O produto como fonte\n\n_A especificação e o código dirigindo a documentação, os testes e o SDK._\n\n```mermaid\nflowchart TB\n    spec[\"<b>OpenAPI</b><br/>src/schemas/\"]\n    parse[\"<b>parseOpenApi → ApiModel</b><br/><i>a única leitura da especificação</i>\"]\n\n    exp[\"API Explorer\"]\n    con[\"Contratos\"]\n    twin[\"Digital Twin\"]\n    imp[\"Análise de impacto\"]\n    sdk[\"SDK\"]\n\n    spec --> parse\n    parse --> exp\n    parse --> con\n    parse --> twin\n    parse --> imp\n    parse --> sdk\n\n    classDef f fill:#1168bd,stroke:#0b4884,color:#fff\n    classDef n fill:#f0ad4e,stroke:#a8791f,color:#000\n    classDef c fill:#85bbf0,stroke:#5d82a8,color:#000\n    class spec f\n    class parse n\n    class exp,con,twin,imp,sdk c\n```\n\nNenhum consumidor abre YAML. Quando um deles precisa de algo que o `ApiModel` não\ncarrega, o modelo ganha o campo — cinco leituras da mesma especificação divergem\nna primeira vez que alguém corrige um caso de borda em uma delas.\nO porquê está em [ADR-0004](docs/adr/0004-uma-leitura-do-openapi.md).\n\n#### Digital Twin\n\nO Content Graph responde sobre a documentação. O Twin sobe um nível e responde sobre o **produto**: o que está documentado, o que a documentação descreve e não existe mais, e o que quebra se um endpoint mudar.\nO grafo de código é **exato**, não heurístico — a Astro mapeia arquivo para rota de forma determinística, então `src/pages/api/auth/me.ts` que exporta `GET` implementa `GET /api/auth/me`. Implementação sem documentação é dívida certa; documentação sem implementação é *potencialmente* obsoleta, porque a página pode descrever comportamento histórico.\nDetalhes em **[Digital Twin](/guides/digital-twin/)**.\n\n#### Vínculo com o código\n\nUma página declara, no frontmatter, quais entidades do produto ela documenta:\n\n```yaml\ndocumentation:\n  bindings:\n    - type: api\n      id: POST /api/payments\n```\n\nA CI cobra a partir daí: entidade pública alterada sem página vinculada bloqueia o merge. Menção em texto não conta — só o vínculo declarado e resolvido contra o Digital Twin. E ele vive na documentação, nunca no código: o produto não deve depender de Markdown.\n\nEm `npm run docs:code` e em Settings → Code Loop.\nDetalhes em **[Vínculo com o código](/guides/vinculo-com-o-codigo/)**.\n\n#### Knowledge Graph\n\nEstende o Digital Twin com time, release, lacuna e contrato — **não** é um segundo grafo: duas estruturas com as mesmas entidades divergiriam na primeira semana.\nNem toda aresta propaga impacto. Se um endpoint muda, as páginas que o documentam são afetadas; a especificação que o define não é. Quando uma camada não carrega, o grafo é montado sem ela e declara a degradação, porque um grafo sem a governança responde \"ninguém é dono disto\" com a mesma confiança de um completo.\nEm `npm run graph` e em Settings → Knowledge Graph.\nDetalhes em **[Knowledge Graph](/guides/knowledge-graph/)**.\n\n#### SDK\n\nGera um cliente TypeScript a partir da **mesma** especificação que já move a documentação, os contratos e o Digital Twin — sem segundo parser, segundo engine de contrato nem segundo engine de impacto.\nOnde a especificação não diz o tipo, o código gerado diz `unknown`: um SDK que finge saber faz o compilador aprovar uma chamada errada. O diff deriva do contrato, não da comparação textual dos arquivos gerados.\nEm `npm run sdk` e no portão de revisão de PR.\nDetalhes em **[SDK](/guides/sdk/)**.\n\n#### Changelog automático\n\nTodo dia 1º uma automação lê os commits do mês anterior e abre um **pull request** com a página daquele mês. Ela não publica: o texto vem de mensagens escritas para desenvolvedores, e o changelog é o que um cliente lê para decidir se precisa mexer no código dele.\n\nO filtro é a maior parte do valor — de 97 commits num mês, quase todos são manutenção. Mudança incompatível entra sempre, mesmo com tipo de manutenção. Endpoint citado só vira link se existir na especificação.\n\nEm `npm run changelog`.\n\nDetalhes em **[Changelog automático](/guides/changelog-automatico/)**.\n\n#### Overlays e API Views\n\nA mesma OpenAPI origina `base`, `public` e `partner` sem duplicar uma linha de contrato. Um **overlay** descreve a transformação — remova este endpoint, reescreva aquela descrição — em vez de ser uma segunda cópia da especificação, que diverge no primeiro erro corrigido só de um lado.\n\nO motor entra **antes** do `parseOpenApi`, então a especificação efetiva alimenta documentação, contratos, SDK e Explorer como qualquer OpenAPI. E alvo que deixou de casar bloqueia a CI: é o defeito próprio desta camada — a ação que roda com sucesso e não faz efeito, deixando publicado um endpoint que deveria ter sumido.\n\nEm `npm run overlay` e `npm run api`.\n\nDetalhes em **[Overlays e API Views](/guides/overlays-e-api-views/)**.\n\n#### API Explorer\n\nUm console de requisições embutido, derivado da mesma especificação OpenAPI que move os contratos, o Digital Twin e o SDK. Nenhum endpoint é redigido de novo para ele.\nDetalhes em **[API Explorer](/guides/api-explorer/)**.\n\n#### Referência de API a partir de especificação\n\nPáginas de referência geradas a partir de OpenAPI e AsyncAPI. O portal exige que a especificação se declare — um arquivo AsyncAPI aceito em silêncio por um gerador de OpenAPI produz uma página que parece certa e está errada.\nDetalhes em **[Referência de API a partir de especificação](/guides/referencia-de-api/)**.\n\n### Operação\n\n_Quem é dono do quê, o que os leitores fazem e onde estão os buracos._\n\n#### Governança\n\nCada página declara dono, revisor e intervalo de revisão no frontmatter; o `governance.yml` preenche o resto por regra de caminho, e a regra mais específica vence.\n\"Revisada\" é o que alguém declarou, nunca a data do último commit — corrigir uma vírgula não reinicia o relógio de uma página que ninguém leu. E vencida (foi revisada, o intervalo passou) é contada à parte de nunca revisada (entrou no regime, nunca teve revisão): somar as duas acusaria a equipe de atraso no primeiro dia de qualquer regime.\nEm `npm run governance` e em Settings → Governance.\nDetalhes em **[Governança](/guides/governanca/)**.\n\n#### Observabilidade de leitura\n\nMede se a documentação **resolve o problema de quem chegou**, não se ela está tecnicamente correta — e as duas notas ficam lado a lado, nunca somadas.\nNada identifica uma pessoa: sem IP, sem id de usuário, sem cookie, sem user-agent. O que existe é uma sessão efêmera do navegador que some quando a aba fecha. Do Not Track, Global Privacy Control e a escolha do leitor desligam a coleta; o texto das buscas é desligado por padrão; uma linha só aparece com 3+ sessões distintas.\nOs nomes das métricas carregam os seus limites: \"clique em resultado\", não \"taxa de sucesso\" — clicar é o mais longe que a instrumentação enxerga.\n\nAgentes de IA são contados à parte, no servidor: eles não executam JavaScript, então a medição acontece nas próprias rotas de `llms.txt` e do Markdown bruto — e não pelo referrer, que veria a pessoa clicando num link do ChatGPT e não o agente lendo o índice.\nEm `npm run analytics` e em Settings → Observability.\nDetalhes em **[Observabilidade de leitura](/guides/observabilidade-de-leitura/)**.\n\n#### Lacunas de documentação\n\nSaber que uma página teve dez mil acessos não diz o que falta. Esta camada pergunta **que informação as pessoas procuram e não encontram**, cruzando busca, assistente, MCP, feedback, contratos e o Digital Twin num backlog priorizado.\n**Publicar não é resolver.** `start` registra o sinal de hoje como linha de base; depois de publicar, `resolve` compara — e recusa se o sinal não caiu. Não se exige queda a zero: a pergunta continua sendo feita mesmo quando a resposta existe.\nDetalhes em **[Lacunas de documentação](/guides/lacunas-de-documentacao/)**.\n\n#### Feedback de página\n\nUm widget de utilidade no rodapé de cada página. Ele guarda o voto e o caminho, e nada sobre quem votou.\nDetalhes em **[Feedback de página](/guides/feedback/)**.\n\n#### Organização e múltiplos repositórios\n\nRegistra repositórios, produtos e times em `organization.yml` e agrega o que dá para agregar sem mentir.\nO portal **não busca repositório da rede**: registrado por `url`, ele é listado e não lido — clonar e ler conteúdo arbitrário a cada coleta é decisão de quem opera. A profundidade da leitura é declarada por repositório, e o que não foi medido fica fora da média: contá-lo como zero faria registrar um repositório baixar a nota da organização.\nEm `npm run org` e em Settings → Organization.\nDetalhes em **[Organização e múltiplos repositórios](/guides/organizacao/)**.\n\n### Automação\n\n_O que o portal faz sozinho — e onde ele para para pedir aprovação._\n\n#### Agentes de documentação\n\nCinco agentes especializados usam as ferramentas que o portal já tem — Twin, Content Graph, glossário, linter, testes, contratos — e produzem mudanças **verificáveis**. Quatro dos cinco funcionam sem provedor nenhum.\nOs guardrails são **código, não instrução de prompt**: allowlist de ferramentas, escrita restrita a um workspace isolado, e nada publicado sem aprovação humana. O guardrail de descarte nasceu de um defeito real — a primeira execução substituiu uma página inteira por um esqueleto, e passou por revisão, testes e auditoria, porque esqueleto bem formado é Markdown válido.\nDetalhes em **[Agentes de documentação](/guides/agentes-de-documentacao/)**.\n\n#### Self-healing\n\nDetectar → diagnosticar → propor → validar → revisar → PR. Nunca `detectar → corrigir`.\nNada é escrito fora do workspace isolado dos agentes, nada é publicado sem aprovação humana, e nenhum nível de autonomia faz merge. O diagnóstico recusa sem fonte autoritativa; quando fontes autoritativas discordam, o ciclo declara conflito e para, em vez de escolher uma — documentação errada com ar de certeza é pior que a lacuna.\nValidação que não roda vale \"não verificado\", nunca \"aprovado\".\nEm `npm run heal` e em Settings → Self-Healing.\nDetalhes em **[Self-healing](/guides/self-healing/)**.\n\n#### Time Machine\n\nComo esta página evoluiu, como o portal estava em maio, o que mudou de **comportamento** entre dois pontos, e o que aquele commit afetou.\nO Git continua sendo a fonte: cada consulta reconstrói do repositório, e nada aqui escreve, faz checkout ou muda de branch. O que não dá para reconstruir vem ausente, não estimado — o Health Score de uma data passada não é recalculado, porque ele dependia das ferramentas daquela época.\nDetalhes em **[Time Machine](/guides/time-machine/)**.\n\n#### Assistente de documentação\n\nUm chatbot que responde a partir da documentação e cita as fontes. Sem chave de provedor ele devolve trechos e um resumo extrativo, sem redigir nada; com chave, o mesmo pipeline redige a resposta atravessando os guardrails.\nDetalhes em **[Assistente de documentação](/guides/assistente/)**.\n\n#### Documentação legível por máquina\n\n`llms.txt`, Markdown bruto em cada página e metadados estruturados — para que um agente leia a documentação sem raspar HTML.\nDetalhes em **[Documentação legível por máquina](/guides/documentacao-legivel-por-maquina/)**.\n\n#### Consulta pelo terminal (MCP)\n\nUm servidor MCP e uma CLI que expõem a documentação para agentes e para o terminal, com os mesmos filtros de público e versão do portal.\nDetalhes em **[Consulta pelo terminal (MCP)](/guides/mcp/)**.\n\n### Plataforma\n\n_Acesso, fluxo de trabalho e publicação._\n\n#### Usuários e controle de acesso\n\nTrês papéis — viewer, editor e admin. A leitura é pública; editar e administrar exigem entrar. A autorização é por capacidade, aplicada num único middleware, e os dados de usuário ficam fora do Git.\nDetalhes em **[Usuários e controle de acesso](/guides/usuarios-e-acesso/)**.\n\n#### Workflow de Git\n\nBranch, diff, portão de qualidade e preparação de pull request a partir do editor — com o corpo do PR montado a partir do que os motores de análise já sabem.\nDetalhes em **[Workflow de Git](/guides/workflow-de-git/)**.\n\n#### Publicação no GitHub Pages\n\nPublicação automatizada no GitHub Pages, com o caminho base tratado e a distinção entre o site estático e o modo servidor.\nDetalhes em **[Publicação no GitHub Pages](/guides/publicacao-no-github-pages/)**.\n\n#### Atualizações recentes\n\nUma lista do que mudou recentemente, derivada do Git — não uma lista mantida à mão que alguém esquece de atualizar.\nDetalhes em **[Atualizações recentes](/guides/atualizacoes-recentes/)**.\n\n#### Plugins da comunidade\n\nOs plugins da comunidade Starlight em uso, com o que cada um resolve e por que foi escolhido\nem vez das alternativas.\nGuia: **[Plugins da comunidade](/guides/plugins/)**. Notas de avaliação: [docs/plugins.md](docs/plugins.md).\n\n## Build e preview de produção\n\nO projeto usa `@astrojs/node` com `output: 'server'`, porque as rotas do editor precisam de execução sob demanda para ler e gravar arquivos no filesystem.\n\n```bash\nnpm run build\nnpm run preview\n```\n\nTambém é possível iniciar diretamente o servidor standalone gerado:\n\n```bash\nnode ./dist/server/entry.mjs\n```\n\n## Docker\n\nHá um `Dockerfile` de dois estágios (build + runtime) que empacota o portal como imagem Node 22 Alpine. O container roda como usuário não-root (`node`) e espera um volume persistente em `/app/data`, onde ficam usuários, sessões e auditoria.\n\n**Construir e rodar:**\n\n```bash\ndocker build -t lunar-limb .\ndocker run -d --name lunar-limb \\\n  -p 4321:4321 \\\n  --env-file .env \\\n  -v lunar-limb-data:/app/data \\\n  --restart unless-stopped \\\n  lunar-limb\n```\n\nO portal fica em `http://localhost:4321`.\n\n**Variáveis de ambiente:** o container lê as mesmas variáveis do `.env` (veja [`.env.sample`](.env.sample)) — `AUTH_SECRET`, `PORTAL_ADMIN_EMAIL`, `PORTAL_ADMIN_PASSWORD`, `SITE_URL`, `PORTAL_DATA_DIR` etc. Com `--env-file .env`, basta preencher o arquivo local.\n\n**Volume de dados:** `data/` é o único estado persistente. Remover o volume (`docker volume rm lunar-limb-data`) apaga usuários e sessões e faz o portal semear um novo admin no primeiro request.\n\n**Perda de senha do admin:** como `users.json` guarda só o hash, a senha não é recuperável. Apague o volume e reinicie com `PORTAL_ADMIN_EMAIL`/`PORTAL_ADMIN_PASSWORD` definidas, ou crie outro admin por `npm run user:create`.\n\n> O seed do admin (`PORTAL_ADMIN_EMAIL`/`PORTAL_ADMIN_PASSWORD`) só roda quando não existe nenhum usuário. Depois que `users.json` é criado, mudar essas variáveis não tem efeito.\n\n## Dependências\n\nO projeto utiliza React, `@astrojs/react`, `@astrojs/node`, Monaco, `remark-mdx` e `js-yaml`. A Fase 5 adiciona `monaco-vim` como única dependência de runtime nova; as de desenvolvimento (`vitest`, `typescript`, `@astrojs/check`) vieram na Fase 4. Rode `npm install` sempre que o `package.json` mudar.\n\n> `astro check` depende de uma API programática que o compilador nativo do TypeScript 7 ainda não expõe, por isso o projeto fixa `typescript@^6` em devDependencies.\n\n## Limitações conhecidas\n\nO que o portal não faz hoje, e por quê, em **[docs/limitacoes.md](docs/limitacoes.md)**.\n\n## Clean install\n\nSe o `node_modules`/lockfile ficarem inconsistentes com o `package.json` (por exemplo depois de puxar uma versão nova do editor):\n\n```powershell\nRemove-Item -Recurse -Force node_modules -ErrorAction SilentlyContinue\nRemove-Item -Force package-lock.json -ErrorAction SilentlyContinue\nnpm install\nnpm run build\nnpm run dev\n```\n",
  "bytes": 27425,
  "sha": "10436fe1e2b246b4495f5c684e9d9fb4c60630134e3e9b54ca8925231537fd3d",
  "repo_slug": "andre-sato/lunar-limb",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_andre_sato_lunar_limb_okf_index_md_1fd3667b/readme"
}