Parte IV — Copa, chão e cuidado
09 · A copa: o site
A copa é o que se vê de longe. No Baobáxia ela é o site em SvelteKit, com lentes que olham os mesmos saberes de jeitos diferentes — cada lente com um símbolo adinkra.
| Lente | Símbolo | Rota |
|---|---|---|
| Acervo | /[lang]/busca, /[lang]/saber/[id] | |
| Blog | /[lang]/blog | |
| Mapa | /[lang]/mapa | |
| Agenda | /[lang]/agenda | |
| Linha do tempo | /[lang]/timeline | |
| Mocambolas | /[lang]/mocambolas | |
| Territórios | /[lang]/territorios |
Arquivos para ler
svelte.config.js,vite.config.ts— adapter-node, PWA.src/hooks.server.ts+src/lib/server/api.ts— o token por requisição no lado do SvelteKit que roda na mucua (AsyncLocalStorage) e o cache curto das listas.src/lib/api/client.ts— o cliente da API (≈ 1200 linhas),fetchComEspera.src/routes/[lang]/+layout.server.tse+layout.svelte— o que toda página carrega.src/lib/stores/—auth,permissoes,tocador,galaxias,filtros.src/routes/[lang]/saber/[id]/+page.svelte— a página mais completa.src/lib/components/RaizHistoria.svelte,Tocador.svelte,TeiaConstelacao.svelte,BaobaVivo.svelte— as visões com mais desenho.src/lib/i18n/— pt-BR, en-US, es-ES, it-IT e aw-AW (A'uwẽ).
Estrutura
flowchart TB
subgraph Navegador
PG["+page.svelte"]
ST["stores<br/>auth · permissoes · tocador"]
CL["ApiClient<br/>token do localStorage"]
end
subgraph Node["SvelteKit na mucua (adapter-node, :3000)"]
HK["hooks.server.ts<br/>lê cookie auth_token"]
ALS["AsyncLocalStorage<br/>{token, versão}"]
LD["+page.server.ts / +layout.server.ts<br/>load()"]
SAC["ServerApiClient<br/>cache 30 s das listas"]
end
API[("API /api/v3<br/>127.0.0.1:8000")]
PG --> ST --> CL -->|"/api/v3 via nginx"| API
HK --> ALS --> LD --> SAC -->|"SSR direto"| API
Por que AsyncLocalStorage
O cliente da API é um singleton no processo Node. Se o token fosse um campo dele, a requisição da pessoa A poderia usar o token da pessoa B no meio de um await. Cada requisição roda num contexto próprio (authContext.run), e o ServerApiClient só lê o token desse contexto. O cache das listas usa o hash do token na chave: um visitante nunca recebe o que foi buscado para o admin.
Permissões no front
O front nunca decide permissão: lê os booleanos de GET /auth/me/permissoes, calculados pelo mesmo motor que o backend aplica. Eles servem para esconder botões; o 403 continua sendo a verdade.
Raízes: listas, histórias e livros
A lente Raízes (/[lang]/raizes) mostra as coleções, e cada formato tem o seu jeito de ser visto: a lista, a história (uma raiz que desce pela página) e o livro. Um livro é uma coleção com formato: livro (data.livro guarda subtítulo, autoria, introdução, capa). Os capítulos são os membros, na ordem; o campo parte de cada membro agrupa o sumário. src/lib/livros/livro.ts monta o livro a partir do GET /colecoes/{uuid}; /raizes/[id] mostra a capa com o sumário e /raizes/[id]/[n] é a leitura de um capítulo. Os diagramas Mermaid são desenhados pela action lib/actions/mermaid.ts, com a biblioteca empacotada no build (funciona sem internet). Título, corpo, partes e introdução podem vir em vários idiomas ({pt: …, en: …, es: …}): o site mostra o idioma da URL e cai no português quando falta a tradução — este curso é assim.
Os capítulos moram no livro: a listagem do Acervo e a home não os mostram (SaberService.search com application="acervo" e sem texto deixa de fora os membros de coleções formato: livro). Numa busca por texto eles aparecem; ?capitulos=true traz sempre.
Galáxia em zip
Em Galáxias, quem administra a mucua pode exportar uma galáxia como .zip (história git + anexos; services/galaxia_zip.py) e importar um zip para instalar a galáxia sem rede — o mesmo caminho de instalar por URL, só que a origem é o arquivo.
O tocador e as histórias
stores/tocador.svelte.ts mantém uma fila de faixas (áudio/vídeo) que atravessa as páginas. Uma história (coleção no formato historia) guarda, por arquivo (uuid::arquivo em historia.itens), os trechos a tocar (cortes: [{de, ate}]), título e texto próprios. RaizHistoria.svelte desenha a história como uma raiz que desce pela página.
Segurança na copa
- Markdown de saber é renderizado por
lib/util/markdown.ts: escapa HTML e, desde a 3.3, só aceita linkshttp(s),mailto,xmpp,tel,geoou relativos (hrefSeguro). Qualquerhrefvindo de dado deve passar por ali. - O token vive no
localStoragee num cookie lido pelo SSR — qualquer XSS rouba sessão. Ver o módulo 11.
Práticas
- Rode
npm run dev, abra a página de um saber com a aba de rede aberta. Quais chamadas saem do navegador e quais vieram prontas do SSR? - Acrescente uma palavra nova nos cinco arquivos de
src/lib/i18n/locales/e use-a num componente com$_('…'). - Em
markdown.ts, escreva um teste (pode ser comnode --experimental-strip-types) que garanta que[x](javascript:alert(1))não vira link. npm run checkmostra ~55 erros de tipo antigos. Escolha um arquivo e zere os erros dele.
Para conversar
- O que significa ter a interface do acervo numa língua indígena, além de traduzir palavras? (Datas, números, ordem das coisas, quem decide os termos.)
