Arquitetura
O slash-kit tem três partes de código que você pode ler e estender: o painel (panel/), a interface que todo projeto
copia (ui/) e os módulos (modules/). O CLI (cli/) cria os projetos a partir dos templates (templates/). Esta página
descreve o painel, que é onde os módulos entram. A linha entre as pastas está em
Fronteiras e projeto gerado.
Só o template blog copia o painel e os módulos para src/. Os outros templates copiam ui/ e mais nada do painel
(cli/commands/create.ts:240-245).
Mapa das pastas
Seção intitulada “Mapa das pastas”| Pasta | O que tem | Onde vai no projeto |
|---|---|---|
ui/ | Componentes, temas, seções e o documento do site | src/ui/, em todo projeto, sem testes nem galerias |
panel/ | Núcleo, portas, adaptadores, host, contrato, coleções, telas e servidor | src/panel/, só no blog |
modules/ | O catálogo e os módulos oficiais, um por pasta | src/modules/<id>/, só os instalados |
templates/ | Camadas de cada template: files/ e manifest.ts | Não é copiada; as camadas são aplicadas por cima da base |
cli/ | Os comandos do slash | Não vai para o projeto |
Diagrama
Seção intitulada “Diagrama”As setas vão de quem usa para quem é usado. O núcleo usa as portas; cada adaptador implementa uma ou mais portas; os módulos entram pelo contrato, que o host lê. Toque na imagem para abrir o SVG em tamanho cheio.
O desenho mostra as dependências principais, não uma pilha estrita. O núcleo também usa o host, as coleções, o servidor
e a sessão (panel/core/records.ts:1-4, panel/core/services.ts:2-6, panel/core/auth.ts:2), e o host usa o núcleo
(panel/host/services.ts:2). A única regra de importação garantida por teste aqui é panel/ não importar modules/
(architecture.test.ts:159-166).
Núcleo e portas
Seção intitulada “Núcleo e portas”O núcleo (panel/core/) tem as regras do painel: sessão e usuários, configurações, backups, publicação e mídia. Ele não
importa adaptador nenhum. Para banco, arquivos, e-mail e build, ele usa as portas, que são as interfaces de panel/ports/.
A interface Ports junta as que o núcleo usa: store, storeBackup, sessions, passwords, audit, media, mailer,
clock, scheduler, publisher e contentSource (panel/ports/index.ts:51).
Quem monta as portas é a raiz de produção. A função launch (panel/production/root.ts:110) abre o banco pela
DATABASE_URL, prepara as tabelas e liga as portas SQL (sqlPorts, root.ts:129). A mesma raiz importa os adaptadores
(root.ts:3-11) e o servidor (root.ts:20).
Adaptadores
Seção intitulada “Adaptadores”| Adaptador | Pasta | Papel |
|---|---|---|
| Memória | panel/adapters/memory/ | Testes. Na produção, a auditoria do arranque (root.ts:125) e o relógio do sistema (root.ts:5, :119). |
| SQL | panel/adapters/sql/ | Banco de produção. A URL escolhe o driver pelo esquema; hoje só sqlite (panel/adapters/sql/open.ts:7-9). O padrão de openDatabase() é sqlite://storage/db.sqlite (open.ts:5); na produção, o caminho sai da pasta do projeto (panel/production/env.ts:94). |
| Publicação | panel/adapters/publisher-ssg.ts | Roda o build do slash-ssg (ver Publicação). |
| Mídia | panel/adapters/media-disk.ts | Arquivos em disco. |
panel/adapters/mailer-*.ts | Resend, com RESEND_API_KEY e MAIL_FROM. Na produção as duas são obrigatórias: sem elas o painel não sobe (panel/production/env.ts:82; panel/adapters/mailer-env.ts:22-27). O console vale só no desenvolvimento (mailer-env.ts:11). | |
| Senhas | panel/adapters/passwords-bun.ts | Hash argon2id pelo Bun.password (passwords-bun.ts:3). |
| Agendador | panel/adapters/scheduler-interval.ts | Tarefas em intervalo, com setInterval (scheduler-interval.ts:36). |
Em panel/adapters/sql/, o código é escrito uma vez sobre o SQL do Bun (sqlite.ts:4). O que muda entre bancos fica
na interface Dialect (panel/adapters/sql/dialect.ts:15-21).
Módulos, host e contrato
Seção intitulada “Módulos, host e contrato”Um módulo é um objeto ModuleDef criado por defineModule (panel/contract/module.ts:322). Os campos do ModuleDef (panel/contract/module.ts:216-247) são id, version, core, title, description, requires, permissions, permissionLabels, activityLabels, menuGroups, menu, collections, screens, api, jobs, settings, extend, hooks, site e migrations.
requires ordena os módulos: cada um entra depois das dependências (panel/host/order.ts:9). Os campos de rótulo dão o texto que o painel mostra: title e permissionLabels vão para a matriz de permissões (panel/host/host.ts:43-46; permissionLabels em module.ts:228-229); activityLabels vai para a atividade da Visão geral (module.ts:230-234); menuGroups acrescenta grupos ao menu, além dos do núcleo (module.ts:236).
createHost (panel/host/host.ts:84) junta os módulos: ordena pelas dependências (panel/host/order.ts:9), monta o menu e
as permissões e recusa colisões de coleção, rota, endereço do menu e grupo entre módulos e com o núcleo
(panel/host/registry.ts:76).
Ganchos
Seção intitulada “Ganchos”Um gancho reage a uma ação de escrita. O nome segue o padrão <algo>.before<Algo> ou <algo>.after<Algo>
(panel/contract/module.ts:106).
- Um gancho
beforepode recusar a ação com uma mensagem. A primeira recusa para a cadeia e a mensagem vai ao usuário. Se o gancho falha, ou a mensagem vem vazia, a ação para comHOOK_FAILED(panel/host/hooks.ts:5, 14-16). - Um gancho
afterroda sempre. Um erro nele não para os outros (panel/host/hooks.ts:14-16). - O erro vai para a auditoria como
hook.error, com o alvo<modulo>:<gancho>(panel/host/hooks.ts:41-43).
Extensões
Seção intitulada “Extensões”extend.fields acrescenta campos à coleção de outro módulo. O formulário mostra os campos da coleção, depois os de
extend.fields e por último os dos painéis laterais (panel/host/extensions.ts:26).
Coleções
Seção intitulada “Coleções”collections declara uma coleção: lista, formulário e ações. O motor de coleções (createMountCollections,
panel/collections/routes.ts:125) gera as rotas. A lista fica em /painel/c/<chave>. A edição fica em
/painel/c/<chave>/<id>, a menos que o manifesto defina editHref (panel/host/registry.ts:30-35; panel/host/extensions.ts:33).
Telas e rotas
Seção intitulada “Telas e rotas”- Telas do núcleo estão na lista
CORE_SCREENS(panel/screens/registry.ts:23). - Telas de módulo ficam em
/painel/<modulo>/<tela>(panel/host/registry.ts:24-27) e são montadas pormountScreens(panel/app/modules.ts:59, chamada empanel/app.ts:267). - API de módulo fica em
/api/<modulo>/…quando é pública e em/painel/api/<modulo>/…quando exige login (panel/app/modules.ts:89-91). - Roteador. Uma rota sem correspondência responde 404 (
panel/server/router.ts:4-6). Um método que não existe nessa rota responde 405 com os métodos aceitos (panel/server/router.ts:102).
Publicação
Seção intitulada “Publicação”Quando um conteúdo muda, publishOnWrite pede uma publicação (panel/core/publish-on-write.ts:68). O pedido vira um
job na fila, guardada no banco (PUBLISH_JOBS, panel/ports/publisher.ts:33). O ssgPublisher
(panel/adapters/publisher-ssg.ts:126) faz quatro passos, registrados no log do job:
- Copia o projeto para
storage/build(publisher-ssg.ts:213). - Grava o snapshot do conteúdo (
publisher-ssg.ts:216). - Roda
bun run buildnessa cópia (publisher-ssg.ts:221). - Troca
dist/pelo resultado do build (publisher-ssg.ts:232).
O build recebe só as variáveis da lista BUILD_ENV_ALLOWED (publisher-ssg.ts:31). Segredos do painel, como
DATABASE_URL, não chegam a ele.
Onde continuar
Seção intitulada “Onde continuar”- Fronteiras e projeto gerado: quem pode importar quem, e o que o
createcopia. - Portas e Contrato: as assinaturas, uma por uma.
- Tutorial: definir o módulo: um módulo do zero, passo a passo.