콘텐츠 모델은 사이트가 저장하는 컬렉션과 필드의 집합입니다. 관리 패널이나 CLI에서 정의하고, 필요할 때 변경하며, 선택적으로 TypeScript 타입을 생성할 수 있습니다. 이 페이지에서는 사용 방법을 다룹니다.
컬렉션과 필드
컬렉션은 콘텐츠 유형입니다(게시물, 제품, 저자). 각 컬렉션에는 정의한 필드가 있습니다(제목, 본문, 가격). 모든 항목에는 EmDash가 관리하는 시스템 필드도 있습니다.
Content Types의 관리 패널에서 시각적으로 컬렉션과 필드를 생성하고 편집하거나 CLI를 사용할 수 있습니다. 변경 사항은 즉시 적용되며 개발자가 아닌 사람도 수행할 수 있습니다.
시스템 필드
정의한 필드 외에도 모든 항목에는 다음 필드가 항상 존재합니다:
| 필드 | 목적 |
|---|---|
id | 안정적인 고유 식별자 |
slug | URL 안전 식별자, 로케일별로 고유 |
status | draft, published 또는 scheduled |
author_id | 항목을 생성한 사용자 |
created_at / updated_at / published_at | 타임스탬프 |
deleted_at | 소프트 삭제 시 설정됨, 행은 유지됨 |
version | 저장할 때마다 증가 |
항목 삭제는 소프트 삭제입니다: 복원할 수 있습니다.
언제든지 모델 변경
관리 패널이나 CLI를 통해 라이브 컬렉션의 필드를 언제든지 추가, 이름 변경, 제거 또는 유형 변경할 수 있습니다. 기존 콘텐츠는 보존됩니다.
TypeScript 타입
타입 생성은 선택 사항이지만 권장됩니다. 현재 모델에서 타입을 생성합니다:
npx emdash types
이렇게 하면 컬렉션당 인터페이스와 타입이 지정된 쿼리 오버로드가 포함된 .emdash/types.ts가 작성되므로 getEmDashCollection("posts")는 완전히 타입이 지정된 항목을 반환합니다:
export interface Post {
title: string;
content: PortableTextBlock[];
excerpt?: string;
}
declare module "emdash" {
export function getEmDashCollection(
type: "posts",
): Promise<{ entries: ContentEntry<Post>[]; error?: Error }>;
}
모델 변경 후 명령을 다시 실행하여 타입을 동기화하세요.
워크플로
두 워크플로 모두 동일한 모델을 변경합니다.
개발자가 아닌 사용자는 관리 패널을 사용합니다:
- 관리 패널에서 Content Types를 엽니다.
- Add Collection을 클릭합니다.
- 시각적 빌더로 필드를 정의합니다.
- 콘텐츠 생성을 시작합니다.
개발자는 CLI를 사용하여 타입을 생성하고 환경 간에 모델을 이동할 수 있습니다:
npx emdash types # TypeScript 타입 생성
npx emdash export-seed > seed.json # 모델을 시드 파일로 내보내기
시드 파일
시드 파일은 컬렉션, 분류체계, 메뉴에 대한 JSON 설명입니다. 템플릿에는 하나가 포함되어 있으며, 버전 관리나 다른 환경 설정을 위해 자체적으로 내보낼 수 있습니다.
{
"version": "1",
"collections": [
{
"slug": "posts",
"label": "Blog Posts",
"labelSingular": "Post",
"supports": ["drafts", "revisions", "preview"],
"fields": [
{ "slug": "title", "type": "string", "required": true },
{ "slug": "content", "type": "portableText" }
]
}
],
"taxonomies": [{ "name": "category", "label": "Categories", "hierarchical": true }],
"menus": [{ "name": "primary", "label": "Primary Navigation" }]
}
시드 적용은 멱등성이므로 다시 실행해도 안전합니다:
import { applySeed, validateSeed } from "emdash/seed";
import seedData from "./.emdash/seed.json";
const { valid, errors } = validateSeed(seedData);
await applySeed(db, seedData, { includeContent: true, onConflict: "skip" });
전체 스키마는 시드 파일 형식을 참조하세요.