Formato de Arquivo Seed

Nesta página

Arquivos seed são documentos JSON que inicializam sites EmDash. Eles definem coleções, campos, taxonomias, menus, redirecionamentos, áreas de widgets, configurações do site e conteúdo de exemplo opcional.

Estrutura Raiz

Um arquivo seed tem a seguinte estrutura de nível superior:

{
	"$schema": "https://emdashcms.com/seed.schema.json",
	"version": "1",
	"meta": {},
	"settings": {},
	"collections": [],
	"taxonomies": [],
	"bylines": [],
	"menus": [],
	"redirects": [],
	"widgetAreas": [],
	"sections": [],
	"content": {}
}
CampoTipoObrigatórioDescrição
$schemastringNãoURL do esquema JSON para validação do editor
version"1"SimVersão do formato seed
metaobjectNãoMetadados sobre o seed
settingsobjectNãoConfigurações do site
collectionsarrayNãoDefinições de coleções
taxonomiesarrayNãoDefinições de taxonomias
bylinesarrayNãoDefinições de perfis de byline
menusarrayNãoMenus de navegação
redirectsarrayNãoRegras de redirecionamento
widgetAreasarrayNãoDefinições de áreas de widgets
sectionsarrayNãoBlocos de conteúdo reutilizáveis
contentobjectNãoEntradas de conteúdo de exemplo

Meta

O objeto meta contém metadados descritivos opcionais sobre o seed:

{
	"meta": {
		"name": "Blog Starter",
		"description": "A simple blog with posts, pages, and categories",
		"author": "EmDash"
	}
}

Settings

O objeto settings contém valores de configuração de todo o site:

{
	"settings": {
		"title": "My Site",
		"tagline": "A modern CMS",
		"postsPerPage": 10,
		"dateFormat": "MMMM d, yyyy"
	}
}

As configurações são aplicadas à tabela options com o prefixo site:. O Assistente de Configuração pré-preencherá title e tagline do arquivo seed (se fornecido), permitindo aos usuários substituí-los durante a configuração inicial.

Collections

Cada definição de coleção cria um tipo de conteúdo no banco de dados:

{
	"collections": [
		{
			"slug": "posts",
			"label": "Posts",
			"labelSingular": "Post",
			"description": "Blog posts",
			"icon": "file-text",
			"supports": ["drafts", "revisions"],
			"fields": [
				{
					"slug": "title",
					"label": "Title",
					"type": "string",
					"required": true
				},
				{
					"slug": "content",
					"label": "Content",
					"type": "portableText"
				},
				{
					"slug": "featured_image",
					"label": "Featured Image",
					"type": "image"
				}
			]
		}
	]
}

Propriedades de Collection

PropriedadeTipoObrigatórioDescrição
slugstringSimIdentificador seguro para URL (minúsculas, underscores)
labelstringSimNome de exibição no plural
labelSingularstringNãoNome de exibição no singular
descriptionstringNãoDescrição da interface administrativa
iconstringNãoNome do ícone Lucide
supportsarrayNãoRecursos: "drafts", "revisions"
fieldsarraySimDefinições de campos

Propriedades de Field

PropriedadeTipoObrigatórioDescrição
slugstringSimNome da coluna (minúsculas, underscores)
labelstringSimNome de exibição
typestringSimTipo de campo
requiredbooleanNãoValidação: campo deve ter um valor
uniquebooleanNãoValidação: valor deve ser único
defaultValueanyNãoValor padrão para novas entradas
validationobjectNãoRegras de validação adicionais
widgetstringNãoSubstituição de widget da interface administrativa
optionsobjectNãoConfiguração específica do widget

Tipos de Field

TipoDescriçãoArmazenado como
stringTexto curtoTEXT
textTexto longo (textarea)TEXT
numberValor numéricoREAL
integerNúmero inteiroINTEGER
booleanVerdadeiro/falsoINTEGER
dateValor de dataTEXT (ISO 8601)
datetimeData e horaTEXT (ISO 8601)
emailEndereço de e-mailTEXT
urlURLTEXT
slugString segura para URLTEXT
portableTextConteúdo rich textJSON
imageReferência de imagemJSON
fileReferência de arquivoJSON
jsonJSON arbitrárioJSON
referenceReferência a outra entradaTEXT

Taxonomies

Taxonomias são sistemas de classificação para conteúdo:

{
	"taxonomies": [
		{
			"name": "category",
			"label": "Categories",
			"labelSingular": "Category",
			"hierarchical": true,
			"collections": ["posts"],
			"terms": [
				{ "slug": "news", "label": "News" },
				{ "slug": "tutorials", "label": "Tutorials" },
				{
					"slug": "advanced",
					"label": "Advanced Tutorials",
					"parent": "tutorials"
				}
			]
		},
		{
			"name": "tag",
			"label": "Tags",
			"labelSingular": "Tag",
			"hierarchical": false,
			"collections": ["posts"]
		}
	]
}

Propriedades de Taxonomy

PropriedadeTipoObrigatórioDescrição
namestringSimIdentificador único
labelstringSimNome de exibição no plural
labelSingularstringNãoNome de exibição no singular
hierarchicalbooleanSimPermitir termos aninhados (categorias) ou planos (tags)
collectionsarraySimColeções às quais esta taxonomia se aplica
termsarrayNãoTermos predefinidos

Propriedades de Term

PropriedadeTipoObrigatórioDescrição
slugstringSimIdentificador seguro para URL
labelstringSimNome de exibição
descriptionstringNãoDescrição do termo
parentstringNãoSlug do termo pai (apenas hierárquico)

O array menus define menus de navegação editáveis pelo administrador:

{
	"menus": [
		{
			"name": "primary",
			"label": "Primary Navigation",
			"items": [
				{ "type": "custom", "label": "Home", "url": "/" },
				{ "type": "page", "ref": "about" },
				{ "type": "custom", "label": "Blog", "url": "/posts" },
				{
					"type": "custom",
					"label": "External",
					"url": "https://example.com",
					"target": "_blank"
				}
			]
		}
	]
}

Tipos de Menu Item

TipoDescriçãoCampos obrigatórios
customURL personalizadourl
pageLink para uma entrada de páginaref
postLink para uma entrada de postref
taxonomyLink para um arquivo de taxonomiaref, collection
collectionLink para um arquivo de coleçãocollection

Propriedades de Menu Item

PropriedadeTipoDescrição
typestringTipo de item (veja acima)
labelstringTexto de exibição (gerado automaticamente para refs de página/post)
urlstringURL personalizado (para tipo custom)
refstringID de conteúdo no seed (para tipos page/post)
collectionstringSlug de coleção
targetstring"_blank" para nova janela
titleAttrstringAtributo title HTML
cssClassesstringClasses CSS personalizadas
childrenarrayItens de menu aninhados

Bylines

Perfis de byline são separados da propriedade (author_id). Defina identidades de byline reutilizáveis uma vez, depois referencie-as de entradas de conteúdo.

{
	"bylines": [
		{
			"id": "editorial",
			"slug": "emdash-editorial",
			"displayName": "EmDash Editorial"
		},
		{
			"id": "guest",
			"slug": "guest-contributor",
			"displayName": "Guest Contributor",
			"isGuest": true
		}
	]
}
PropriedadeTipoObrigatórioDescrição
idstringSimID local do seed usado por content[].bylines
slugstringSimSlug de byline seguro para URL
displayNamestringSimNome mostrado em modelos e APIs
biostringNãoBiografia de perfil opcional
websiteUrlstringNãoURL do site opcional
isGuestbooleanNãoMarca byline como perfil de convidado

Redirects

O array redirects define regras de redirecionamento que preservam URLs legados após migração:

{
	"redirects": [
		{ "source": "/old-about", "destination": "/about" },
		{ "source": "/legacy-feed", "destination": "/rss.xml", "type": 308 },
		{
			"source": "/category/news",
			"destination": "/categories/news",
			"groupName": "migration"
		}
	]
}

Propriedades de Redirect

PropriedadeTipoObrigatórioDescrição
sourcestringSimCaminho de origem (deve começar com /)
destinationstringSimCaminho de destino (deve começar com /)
typenumberNãoStatus HTTP: 301, 302, 307 ou 308
enabledbooleanNãoSe o redirecionamento está ativo (padrão: true)
groupNamestringNãoRótulo de agrupamento opcional para filtragem/pesquisa do admin

Widget Areas

O array widgetAreas define regiões de conteúdo configuráveis:

{
	"widgetAreas": [
		{
			"name": "sidebar",
			"label": "Main Sidebar",
			"description": "Appears on blog posts and pages",
			"widgets": [
				{
					"type": "component",
					"title": "Recent Posts",
					"componentId": "core:recent-posts",
					"props": { "count": 5 }
				},
				{
					"type": "menu",
					"title": "Quick Links",
					"menuName": "footer"
				},
				{
					"type": "content",
					"title": "About",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "Welcome to our site!" }]
						}
					]
				}
			]
		}
	]
}

Tipos de Widget

TipoDescriçãoCampos obrigatórios
contentConteúdo rich textcontent (Portable Text)
menuRenderiza um menumenuName
componentComponente registradocomponentId

Componentes Integrados

ID do componenteDescrição
core:recent-postsLista de posts recentes
core:categoriesLista de categorias
core:tagsNuvem de tags
core:searchFormulário de pesquisa
core:archivesArquivos mensais

Sections

Sections são blocos de conteúdo reutilizáveis que editores inserem em campos Portable Text via o comando de barra /section:

{
	"sections": [
		{
			"slug": "hero-centered",
			"title": "Centered Hero",
			"description": "Full-width hero with centered heading and CTA button",
			"keywords": ["hero", "banner", "header", "landing"],
			"content": [
				{
					"_type": "block",
					"style": "h1",
					"children": [{ "_type": "span", "text": "Welcome to Our Site" }]
				},
				{
					"_type": "block",
					"children": [
						{ "_type": "span", "text": "Your compelling tagline goes here." }
					]
				}
			]
		}
	]
}

Propriedades de Section

PropriedadeTipoObrigatórioDescrição
slugstringSimIdentificador seguro para URL
titlestringSimNome de exibição mostrado no seletor de sections
descriptionstringNãoExplica quando usar esta section
keywordsarrayNãoTermos de pesquisa para encontrar a section
contentarraySimBlocos Portable Text
sourcestringNão"theme" (padrão para seeds) ou "import"

Sections de arquivos seed são marcadas com source: "theme" e não podem ser excluídas da interface administrativa. Editores podem criar suas próprias sections (source: "user") e inserir qualquer tipo de section ao editar conteúdo.

Content

O objeto content contém entradas de conteúdo de exemplo organizadas por coleção:

{
	"content": {
		"posts": [
			{
				"id": "hello-world",
				"slug": "hello-world",
				"status": "published",
				"bylines": [
					{ "byline": "editorial" },
					{ "byline": "guest", "roleLabel": "Guest essay" }
				],
				"data": {
					"title": "Hello World",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "Welcome!" }]
						}
					],
					"excerpt": "Your first post."
				},
				"taxonomies": {
					"category": ["news"],
					"tag": ["welcome", "first-post"]
				}
			}
		],
		"pages": [
			{
				"id": "about",
				"slug": "about",
				"status": "published",
				"data": {
					"title": "About Us",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "About page content." }]
						}
					]
				}
			}
		]
	}
}

Propriedades de Content Entry

PropriedadeTipoObrigatórioDescrição
idstringSimID local do seed para referências
slugstringSimSlug de URL
statusstringNão"published" ou "draft" (padrão: "published")
dataobjectSimValores de campos
bylinesarrayNãoCréditos de byline ordenados (byline, opcional roleLabel)
taxonomiesobjectNãoAtribuições de termos por nome de taxonomia

Content References

Referencie outras entradas de conteúdo usando o prefixo $ref::

{
	"data": {
		"related_posts": ["$ref:another-post", "$ref:third-post"]
	}
}

O prefixo $ref: resolve IDs do seed para IDs do banco de dados durante o seeding.

Media References

Incluir imagens de URLs:

{
	"data": {
		"featured_image": {
			"$media": {
				"url": "https://images.unsplash.com/photo-xxx",
				"alt": "Description of the image",
				"filename": "hero.jpg",
				"caption": "Photo by Someone"
			}
		}
	}
}

Incluir imagens locais de .emdash/media/:

{
	"data": {
		"featured_image": {
			"$media": {
				"file": "hero.jpg",
				"alt": "Description of the image"
			}
		}
	}
}

Propriedades de Media

PropriedadeTipoObrigatórioDescrição
urlstringSim*URL remoto para download
filestringSim*Nome de arquivo local em .emdash/media/
altstringNãoTexto alternativo para acessibilidade
filenamestringNãoSubstituir nome de arquivo
captionstringNãoLegenda da mídia

*Ou url ou file é obrigatório, não ambos.

Applying Seeds Programmatically

Use a API de seed para ferramentas CLI ou scripts:

import { applySeed, validateSeed } from "emdash/seed";
import seedData from "./.emdash/seed.json";

// Valide primeiro
const validation = validateSeed(seedData);
if (!validation.valid) {
	console.error(validation.errors);
	process.exit(1);
}

// Aplique o seed
const result = await applySeed(db, seedData, {
	includeContent: true,
	onConflict: "skip",
	storage: myStorage,
	baseUrl: "http://localhost:4321",
});

console.log(result);
// {
//   collections: { created: 2, skipped: 0 },
//   fields: { created: 8, skipped: 0 },
//   taxonomies: { created: 2, terms: 5 },
//   bylines: { created: 2, skipped: 0 },
//   menus: { created: 1, items: 4 },
//   redirects: { created: 3, skipped: 0 },
//   widgetAreas: { created: 1, widgets: 3 },
//   settings: { applied: 3 },
//   content: { created: 3, skipped: 0 },
//   media: { created: 2, skipped: 0 }
// }

Opções de Apply

OpçãoTipoPadrãoDescrição
includeContentbooleanfalseCriar entradas de conteúdo de exemplo
onConflictstring"skip""skip", "update" ou "error"
mediaBasePathstringCaminho base para arquivos de mídia locais
storageStorageAdaptador de armazenamento para uploads de mídia
baseUrlstringURL base para URLs de mídia

Idempotency

O seeding é seguro para executar várias vezes. Comportamento de conflito por tipo de entidade:

EntidadeComportamento
CollectionPular se slug existir
FieldPular se collection + slug existir
Definição de taxonomiaPular se nome existir
Termo de taxonomiaPular se nome + slug existir
Perfil de bylinePular se slug existir
MenuPular se nome existir
Itens de menuSubstituir todos (menu é recriado)
RedirecionamentoPular se origem existir
Área de widgetPular se nome existir
WidgetsSubstituir todos (área é recriada)
SectionPular se slug existir
ConfiguraçõesAtualizar (configurações são destinadas a mudar)
ConteúdoPular se slug existir na coleção

Validation

Arquivos seed são validados antes da aplicação:

import { validateSeed } from "emdash/seed";

const { valid, errors, warnings } = validateSeed(seedData);

if (!valid) {
	errors.forEach((e) => console.error(e));
}

warnings.forEach((w) => console.warn(w));

A validação verifica que:

  • Campos obrigatórios estão presentes
  • Slugs são válidos para seu tipo (slugs de collection e field permitem letras minúsculas, dígitos e underscores; outros slugs também permitem hífens)
  • Tipos de campo são válidos
  • Referências apontam para conteúdo existente
  • Pais de termos hierárquicos existem
  • Caminhos de redirecionamento são URLs locais seguros
  • Origens de redirecionamento são únicos
  • Não há slugs duplicados dentro de coleções

CLI Commands

O arquivo seed em .emdash/seed.json, package.json#emdash.seed ou seed/seed.json é embutido na compilação e aplicado na primeira solicitação quando o banco de dados está vazio. Para exportar o esquema de um site existente (e opcionalmente seu conteúdo) como um arquivo seed:

# `mkdir -p` porque .emdash/ pode ainda não existir em um projeto novo
mkdir -p .emdash

# Exportar o esquema atual como um arquivo seed
npx emdash export-seed > .emdash/seed.json

# Exportar com conteúdo
npx emdash export-seed --with-content > .emdash/seed.json

Next Steps