profound-logoProfound CMS
โŒ˜K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Hybrid

Collection of Pages with Components๊ตฌ์„ฑ ์š”์†Œ ์œ ํ˜•Setup server sent events (SSE) content refetch์–ด๋“œ๋ฏผ ํŒจ๋„ ํ”„๋ก์‹œ ์„ค์ •ํ…œํ”Œ๋ฆฟ ๋นŒ๋”์—์„œ ์Šคํฌ๋ฆฝํŒ…Project Scaffolding๋ฏธ๋””์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Headless

Quick startjson๊ณผ Claude ์ฝ”๋“œ์ปดํฌ๋„ŒํŠธ Zod ๊ฐ€์ ธ์˜ค๊ธฐ

REST API

REST API ๊ฐœ์š”get์›น์‚ฌ์ดํŠธ๋ฅผ CMS API์— ์—ฐ๊ฒฐํ•˜๊ธฐget๊ฒฝ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐget๋ผ์šฐํŠธ ๊ฐ€์ ธ์˜ค๊ธฐget๋ธ”๋ก ๊ฐ€์ ธ์˜ค๊ธฐgetCEL ์บ์‹œ๊ฐ€ ํฌํ•จ๋œ ๋ธ”๋ก ๊ฐ€์ ธ์˜ค๊ธฐget๋ธ”๋ก ์ƒ์„ฑ ๊ฐ€์ ธ์˜ค๊ธฐget์ปดํฌ๋„ŒํŠธ ๊ฐ€์ ธ์˜ค๊ธฐgetGET /components/{name}get๋ฐ์ดํ„ฐ์…‹ ์Šคํ‚ค๋งˆ ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐgetGET /content-changes (SSE)patchPATCH /dataset/{schema_name}post๊ฒŒ์‹œ๋ฌผ ๋ฒˆ์—ญpatch๋ฒˆ์—ญ ํŒจ์น˜get์‚ฌ์šฉ๋Ÿ‰ ๊ฐ€์ ธ์˜ค๊ธฐpostPOST /csvpatchPATCH /csv
All Systems Operational
Powered Byprofound-logo
Theme

ํ…œํ”Œ๋ฆฟ ๋นŒ๋”์—์„œ ์Šคํฌ๋ฆฝํŒ…

CMS์—์„œ CEL ํ‘œํ˜„์‹์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์‹ค์šฉ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค.

CMS์—์„œ CEL ํ‘œํ˜„์‹์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์‹ค์šฉ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค.


CEL ๋™์ž‘ ๋ฐฉ์‹

CEL(Common Expression Language)์€ CMS์— ๋‚ด์žฅ๋œ ๊ฐ€๋ฒผ์šด ์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ๋ฌธ์„œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , URL ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ณ , ์ฆ‰์„์—์„œ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ๋™์  ํ‘œํ˜„์‹์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CEL ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ์ผ์–ด๋‚˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์Šคํฌ๋ฆฝํŠธ                 ์—”์ง„                          ๊ฒฐ๊ณผ
    |                              |                              |
    v                              v                              v
documents.get("article", "intro") --> ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค --> { headline: "Welcome", body: "..." }
         .headline                --> ํ•„๋“œ๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค         --> "Welcome"

CEL์„ ์ฝ๊ธฐ ์ „์šฉ ์ฟผ๋ฆฌ ์–ธ์–ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์„ธ์š”. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์–ด๋–ค ๊ฒƒ๋„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์™€ ๊ณ„์‚ฐ๋œ ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— CMS ์–ด๋””์—์„œ๋“  ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๊ตฌ์„ฑ ์š”์†Œ

๋ชจ๋“  CEL ํ‘œํ˜„์‹์€ ์„ธ ๊ฐ€์ง€ ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด์„ค๋ช…์˜ˆ์‹œ
documentsCMS์—์„œ ์–ด๋–ค ๋ฌธ์„œ๋“  ๊ฐ€์ ธ์˜ค๊ธฐdocuments.get("country", "us")
metaํ˜„์žฌ ์š”์ฒญ์— ๋Œ€ํ•œ ์ •๋ณด(๋กœ์ผ€์ผ, URL ๋งค๊ฐœ๋ณ€์ˆ˜)meta.locale, meta.params.slug
schemaํ˜„์žฌ ๋ฌธ์„œ์˜ ํ•„๋“œ ์ •์˜schema.fields

doc๋ฅผ ์‚ฌ์šฉํ•œ ์ž๊ธฐ ์ฐธ์กฐ

๋ฌธ์„œ ํŽธ์ง‘๊ธฐ ์•ˆ์—์„œ CEL ํ‘œํ˜„์‹์„ ์ž‘์„ฑํ•  ๋•Œ๋Š” doc ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด ํ˜„์žฌ ๋ฌธ์„œ์˜ ํ•„๋“œ ๊ฐ’์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ณ„์‚ฐ ํ•„๋“œ์™€ ํ•„๋“œ ๊ฐ„ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

// ํ˜„์žฌ ๋ฌธ์„œ์˜ price ํ•„๋“œ์— ์ ‘๊ทผ
doc.price

// ํ˜„์žฌ ๋ฌธ์„œ ํ•„๋“œ๋กœ ํ•ฉ๊ณ„ ๊ณ„์‚ฐ
doc.price * doc.quantity

// ํ˜„์žฌ ๋ฌธ์„œ ์ƒํƒœ์— ๋”ฐ๋ฅธ ์กฐ๊ฑด ์ฒ˜๋ฆฌ
doc.status == "published" ? doc.title : "Draft: " + doc.title

doc ๊ฐ์ฒด์—๋Š” ํŽธ์ง‘ ์ค‘์ธ ๋ฌธ์„œ์˜ ๋ชจ๋“  ํ•„๋“œ ๊ฐ’์ด ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๊ณ„์‚ฐ ํ•„๋“œ(์˜ˆ: doc.price * doc.quantity)
  • ๋ฌธ์„œ ์ƒํƒœ์— ๋”ฐ๋ฅธ ์กฐ๊ฑด๋ถ€ ํ‘œ์‹œ ๋กœ์ง
  • ๊ฒ€์ฆ ์Šคํƒ€์ผ ํ‘œํ˜„์‹

๋ฌธ์„œ ๊ฐ€์ ธ์˜ค๊ธฐ

CEL์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์€ CMS ์–ด๋””์—์„œ๋“  ๋ฌธ์„œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

๋‹จ์ผ ๋ฌธ์„œ ๊ฐ€์ ธ์˜ค๊ธฐ

๊ตฌ๋ฌธ: documents.get(schemaName, identifier)

"welcome-post" ์‹๋ณ„์ž๋กœ ์ €์žฅ๋œ article ๋ฌธ์„œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// CMS์— ์ €์žฅ๋œ ํ˜•ํƒœ: article / welcome-post
{
  "headline": "Welcome to Our Platform",
  "author": "Sarah Chen",
  "body": "We're excited to announce...",
  "tags": ["announcement", "news"]
}

์ „์ฒด ๋ฌธ์„œ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด:

documents.get("article", "welcome-post")

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ:

{
  "headline": "Welcome to Our Platform",
  "author": "Sarah Chen",
  "body": "We're excited to announce...",
  "tags": ["announcement", "news"]
}

ํ—ค๋“œ๋ผ์ธ๋งŒ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด:

documents.get("article", "welcome-post").headline

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ: "Welcome to Our Platform"

์ž‘์„ฑ์ž๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด:

documents.get("article", "welcome-post").author

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ: "Sarah Chen"


URL ๋งค๊ฐœ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ

ํŽ˜์ด์ง€์— /articles/[slug] ๊ฐ™์€ ๋™์  ๋ผ์šฐํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด meta.params๋ฅผ ์‚ฌ์šฉํ•ด URL ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ณ  ์˜ฌ๋ฐ”๋ฅธ ๋ฌธ์„œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ /articles/welcome-post ์— ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ:

documents.get("article", meta.params.slug).headline

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ: "Welcome to Our Platform"

์ด ๋ฐฉ์‹์œผ๋กœ ๋™์  ํŽ˜์ด์ง€๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ CEL ์Šคํฌ๋ฆฝํŠธ๊ฐ€ URL์— ์–ด๋–ค ์Šฌ๋Ÿฌ๊ทธ๊ฐ€ ์žˆ๋“  ๋ชจ๋“  ๊ธฐ์‚ฌ์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.


์—ฌ๋Ÿฌ ๋ฌธ์„œ ๊ฐ€์ ธ์˜ค๊ธฐ

๊ตฌ๋ฌธ: documents.find(schemaName) ๋˜๋Š” documents.find(schemaName, filter)

// ๋ชจ๋“  ๊ตญ๊ฐ€ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.find("country")

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ:

[
  { "code": "us", "name": "United States", "flag": "US" },
  { "code": "sa", "name": "Saudi Arabia", "flag": "SA" },
  { "code": "gb", "name": "United Kingdom", "flag": "GB" }
]
// ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๊ตญ๊ฐ€ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.find("country", { "where": { "code": "us" } })

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ:

[
  { "code": "us", "name": "United States", "flag": "US" }
]

๋ฒˆ์—ญ

CEL์€ ์ž๋™ ๋กœ์ผ€์ผ ๊ธฐ๋ฐ˜ ๋ฒˆ์—ญ๊ณผ ๋ช…์‹œ์  ๋ฒˆ์—ญ ์กฐํšŒ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฒˆ์—ญ๋œ ๋ฌธ์„œ ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

meta.locale์„ ํ†ตํ•œ ์ž๋™ ๋ฒˆ์—ญ

meta.locale์ด ์„ค์ •๋˜์–ด ์žˆ์œผ๋ฉด(์˜ˆ: ๋ผ์šฐํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋˜๋Š” ์‚ฌ์šฉ์ž ์„ ํ˜ธ) documents.get()์ด ์ž๋™์œผ๋กœ ๋ฒˆ์—ญ๋œ ์ฝ˜ํ…์ธ ๋ฅผ ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

// meta.locale์ด "fr"์ด๋ฉด ๊ธฐ๋ณธ ๋ฌธ์„œ์— ํ”„๋ž‘์Šค์–ด ๋ฒˆ์—ญ์„ ๋ณ‘ํ•ฉํ•˜์—ฌ ๋ฐ˜ํ™˜
documents.get("greeting", "welcome").headline

๋™์ž‘ ๋ฐฉ์‹:

  1. ๊ธฐ๋ณธ ๋ฌธ์„œ ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  2. meta.locale์ด "en" ๋˜๋Š” "en-US"๊ฐ€ ์•„๋‹ˆ๋ฉด translations ํ…Œ์ด๋ธ”์—์„œ ๋ฒˆ์—ญ์„ ์ฐพ์Šต๋‹ˆ๋‹ค.
  3. ๋ฒˆ์—ญ๋œ ํ•„๋“œ๋ฅผ ๊ธฐ๋ณธ ์ฝ˜ํ…์ธ  ์œ„์— ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค: { ...baseContent, ...translatedContent }

์ฆ‰, ๋ฒˆ์—ญ๋œ ํ•„๋“œ๋Š” ๊ธฐ๋ณธ ํ•„๋“œ๋ฅผ ๋ฎ์–ด์“ฐ๊ณ , ๋ฒˆ์—ญ๋˜์ง€ ์•Š์€ ํ•„๋“œ๋Š” ๊ธฐ๋ณธ ๋ฌธ์„œ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

documents.translated()๋กœ ๋ช…์‹œ์  ๋ฒˆ์—ญ ๊ฐ€์ ธ์˜ค๊ธฐ

ํ˜„์žฌ ๋กœ์ผ€์ผ๊ณผ ๊ด€๊ณ„์—†์ด ํŠน์ • ๋ฒˆ์—ญ์„ ๊ฐ€์ ธ์™€์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ: documents.translated(schemaName, identifier, locale)

// ํ•ญ์ƒ ์ŠคํŽ˜์ธ์–ด ๋ฒˆ์—ญ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.translated("greeting", "welcome", "es").headline

// URL ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฒˆ์—ญ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.translated("product", meta.params.id, meta.params.lang).description

// ๋ฒˆ์—ญ ๋น„๊ตํ•˜๊ธฐ
documents.translated("article", "intro", "en").title + " / " + documents.translated("article", "intro", "fr").title

๋ฒˆ์—ญ ์˜ˆ์‹œ

๋‹ค์Œ์€ ๋ฒˆ์—ญ์ด ํฌํ•จ๋œ ์ธ์‚ฌ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค.

// ๊ธฐ๋ณธ ๋ฌธ์„œ: greeting / welcome
{ "headline": "Welcome", "subheadline": "Welcome to our platform" }

// ๋ฒˆ์—ญ(์–ธ์–ด: "fr")
{ "headline": "Bienvenue", "subheadline": "Bienvenue sur notre plateforme" }

// ๋ฒˆ์—ญ(์–ธ์–ด: "es")
{ "headline": "Bienvenido", "subheadline": "Bienvenido a nuestra plataforma" }

CEL ์Šคํฌ๋ฆฝํŠธ:

// meta.locale = "fr"์ผ ๋•Œ
documents.get("greeting", "welcome").headline
// ๋ฐ˜ํ™˜: "Bienvenue"

// ๋ช…์‹œ์  ์ŠคํŽ˜์ธ์–ด ๋ฒˆ์—ญ
documents.translated("greeting", "welcome", "es").headline
// ๋ฐ˜ํ™˜: "Bienvenido"

// ๋ˆ„๋ฝ๋œ ๋ฒˆ์—ญ์— ๋Œ€ํ•œ ํด๋ฐฑ ํŒจํ„ด
documents.translated("greeting", "welcome", meta.params.lang) != null
  ? documents.translated("greeting", "welcome", meta.params.lang).headline
  : documents.get("greeting", "welcome").headline

์‹ค์ œ ํ™œ์šฉ ์˜ˆ์‹œ

์˜ˆ์‹œ 1: ๋‹ค๋ฅธ ๋ฌธ์„œ์—์„œ ํžˆ์–ด๋กœ ๋ธ”๋ก ์ œ๋ชฉ ๊ฐ€์ ธ์˜ค๊ธฐ

article ๋ฌธ์„œ์—์„œ ํ—ค๋“œ๋ผ์ธ์„ ๊ฐ€์ ธ์™€ ํ‘œ์‹œํ•ด์•ผ ํ•˜๋Š” hero-block์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์‚ฌ ๋ฌธ์„œ(์‹๋ณ„์ž: "homepage-hero"):

{
  "headline": "Build Faster, Ship Smarter",
  "subheadline": "The modern CMS for developers"
}

ํžˆ์–ด๋กœ ๋ธ”๋ก์˜ ์ œ๋ชฉ ํ•„๋“œ์— ์‚ฌ์šฉํ•˜๋Š” CEL ์Šคํฌ๋ฆฝํŠธ:

documents.get("article", "homepage-hero").headline

๊ฒฐ๊ณผ: ํžˆ์–ด๋กœ์—๋Š” "Build Faster, Ship Smarter"๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.


์˜ˆ์‹œ 2: ์ฝ”๋“œ๋กœ ๊ตญ๊ฐ€ ์ด๋ฆ„ ํ‘œ์‹œํ•˜๊ธฐ

/countries/[code] ํŽ˜์ด์ง€์—์„œ ์ „์ฒด ๊ตญ๊ฐ€ ์ด๋ฆ„์„ ํ‘œ์‹œํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ตญ๊ฐ€ ๋ฌธ์„œ:

// country / us
{ "code": "us", "name": "United States", "flag": "US", "languages": ["en", "es"] }

// country / sa
{ "code": "sa", "name": "Saudi Arabia", "flag": "SA", "languages": ["ar", "en"] }

CEL ์Šคํฌ๋ฆฝํŠธ:

documents.get("country", meta.params.code).name

์‚ฌ์šฉ์ž๊ฐ€ /countries/us ๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด:

  • meta.params.code = "us"
  • ๊ฒฐ๊ณผ: "United States"

์‚ฌ์šฉ์ž๊ฐ€ /countries/sa ๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด:

  • meta.params.code = "sa"
  • ๊ฒฐ๊ณผ: "Saudi Arabia"

์˜ˆ์‹œ 3: ๋กœ์ผ€์ผ์— ๋”ฐ๋ฅธ ์กฐ๊ฑด๋ถ€ ์ฝ˜ํ…์ธ 

์‚ฌ์šฉ์ž ๋กœ์ผ€์ผ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํ—ค๋“œ๋ผ์ธ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

meta.locale == "ar-SA" ? "Welcome, everyone" : "Welcome"

๋กœ์ผ€์ผ์ด "ar-SA" ๋ผ๋ฉด: "Welcome, everyone" ๋ฐ˜ํ™˜ ๊ทธ ์™ธ ๋กœ์ผ€์ผ์ด๋ผ๋ฉด: "Welcome" ๋ฐ˜ํ™˜


์˜ˆ์‹œ 4: ๋ฌธ์„œ ์ฒด์ธ์„ ํ†ตํ•œ ์กฐํšŒ

article ๋ฌธ์„œ์— countryCode ํ•„๋“œ๊ฐ€ ์žˆ๊ณ , ๊ตญ๊ฐ€์˜ ์ „์ฒด ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์‚ฌ ๋ฌธ์„œ:

{ "headline": "News from the US", "countryCode": "us" }

CEL ์Šคํฌ๋ฆฝํŠธ:

documents.get("country", documents.get("article", "us-news").countryCode).name

์‹คํ–‰ ๊ณผ์ •:

  1. documents.get("article", "us-news")๋Š” { "headline": "News from the US", "countryCode": "us" }๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. .countryCode๋กœ "us"๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
  3. documents.get("country", "us")๋Š” { "code": "us", "name": "United States", ... }๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  4. .name์œผ๋กœ "United States"๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ: "United States"


์˜ˆ์‹œ 5: ํด๋ฐฑ ๊ฐ’ ์‚ฌ์šฉํ•˜๊ธฐ

๋ฌธ์„œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋ฉด ํด๋ฐฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

documents.get("article", meta.params.slug) != null
  ? documents.get("article", meta.params.slug).headline
  : "Article Not Found"

๋˜๋Š” ํŠน์ • ํ•„๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

documents.get("article", "intro").author != null
  ? documents.get("article", "intro").author
  : "Unknown Author"

์˜ˆ์‹œ 6: ๋ชฉ๋ก ๋‹ค๋ฃจ๊ธฐ

๊ธฐ์‚ฌ์— ํƒœ๊ทธ๊ฐ€ ์žˆ๊ณ  ํŠน์ • ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด:

"featured" in documents.get("article", "welcome-post").tags

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ: ๊ธฐ์‚ฌ์— "featured" ํƒœ๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด true

์ฒซ ๋ฒˆ์งธ ํƒœ๊ทธ ๊ฐ€์ ธ์˜ค๊ธฐ:

documents.get("article", "welcome-post").tags[0]

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ: "announcement"(์ฒซ ๋ฒˆ์งธ ํƒœ๊ทธ)

ํƒœ๊ทธ ๊ฐœ์ˆ˜ ์„ธ๊ธฐ:

size(documents.get("article", "welcome-post").tags)

๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ: 2(ํƒœ๊ทธ ๊ฐœ์ˆ˜)


ํŒŒ๋ผ๋ฉ”ํŠธ๋ฆญ ๋ผ์šฐํŠธ์™€ meta.params

ํŒŒ๋ผ๋ฉ”ํŠธ๋ฆญ ๋ผ์šฐํŠธ๋Š” ๋™์ ์ด๊ณ  ํ˜„์ง€ํ™”๋œ ํŽ˜์ด์ง€๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. /{lang}/landingPage ๊ฐ™์€ ๋ผ์šฐํŠธ ํŒจํ„ด์„ ์ •์˜ํ•˜๋ฉด CMS๊ฐ€ URL์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”์ถœํ•ด meta.params๋ฅผ ํ†ตํ•ด ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ผ์šฐํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋™์ž‘ ๋ฐฉ์‹

๋ผ์šฐํŠธ ํŒจํ„ด ์ •์˜: ๋ผ์šฐํŠธ๋Š” ๋™์  ๊ตฌ๊ฐ„์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด :paramName ๋˜๋Š” {paramName} ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํŒจํ„ด์˜ˆ์‹œ URL์ถ”์ถœ๋œ ๋งค๊ฐœ๋ณ€์ˆ˜
/:lang/landingPage/ko/landingPage{ lang: "ko" }
/{country}/{lang}/products/us/en/products{ country: "us", lang: "en" }
/articles/:slug/articles/welcome-post{ slug: "welcome-post" }

๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ”์ธ๋”ฉ: ๊ฐ ๋ผ์šฐํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๊ฒ€์ฆ์„ ์œ„ํ•ด ๋ฌธ์„œ ์Šคํ‚ค๋งˆ์— ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{
  "pattern": "/{lang}/landingPage",
  "param_bindings": {
    "lang": "language"
  }
}

์ด ๋ฐ”์ธ๋”ฉ์€ CMS์— ๋‹ค์Œ์„ ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค.

  1. URL์—์„œ lang ๊ตฌ๊ฐ„์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
  2. language ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•ด ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค(content.code๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์„œ ์ฐพ๊ธฐ).
  3. ๊ฒ€์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด ์ „์ฒด ๋ฌธ์„œ๋ฅผ resolved params์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ: ์–ธ์–ด ๊ธฐ๋ฐ˜ ๋žœ๋”ฉ ํŽ˜์ด์ง€

๋ผ์šฐํŠธ ๊ตฌ์„ฑ:

  • ๊ฒฝ๋กœ: /{lang}/landingPage
  • ํŒจํ„ด: /{lang}/landingPage
  • ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ”์ธ๋”ฉ: { "lang": "language" }

์ธ์‚ฌ ๋ฌธ์„œ:

// greeting / ko
{ "code": "ko", "headline": "Welcome", "subheadline": "Welcome to our platform", "ctaText": "Get Started", "ctaUrl": "/ko/get-started" }

// greeting / en
{ "code": "en", "headline": "Welcome", "subheadline": "Welcome to our platform", "ctaText": "Get Started", "ctaUrl": "/en/get-started" }

// greeting / ja
{ "code": "ja", "headline": "Welcome", "subheadline": "Welcome to our platform", "ctaText": "Start", "ctaUrl": "/ja/get-started" }

๋กœ์ปฌ๋ผ์ด์ฆˆ๋œ ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” CEL ์Šคํฌ๋ฆฝํŠธ:

documents.get("greeting", meta.params.lang).headline

ํ•ด์„ ๋ฐฉ์‹:

URLmeta.params.lang๊ฒฐ๊ณผ
/ko/landingPage"ko""Welcome"
/en/landingPage"en""Welcome"
/ja/landingPage"ja""Welcome"

๊ณ ๊ธ‰ ํŒจํ„ด: ๊ตญ๊ฐ€ + ์–ธ์–ด ๋ผ์šฐํŠธ

/{country}/{lang}/products ๊ฐ™์€ ๋ผ์šฐํŠธ๋ฅผ ์œ„ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

๋ผ์šฐํŠธ ๊ตฌ์„ฑ:

{
  "pattern": "/{country}/{lang}/products",
  "param_bindings": {
    "country": "country",
    "lang": "language"
  }
}

CEL ์Šคํฌ๋ฆฝํŠธ:

// ๊ตญ๊ฐ€ ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.get("country", meta.params.country).name

// ๊ตญ๊ฐ€์— ๋”ฐ๋ผ ํ˜„์ง€ํ™”๋œ ์ƒํ’ˆ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ
documents.find("product", { "where": { "country": meta.params.country } })

// ๊ฒฐํ•ฉ: ์‚ฌ์šฉ์ž์˜ ์–ธ์–ด๋กœ ๊ตญ๊ฐ€๋ณ„ ์ธ์‚ฌ๋ง ํ‘œ์‹œ
documents.get("greeting", meta.params.lang).headline + " from " + documents.get("country", meta.params.country).name

๊ฒ€์ฆ ๊ณ„์ธต ๊ตฌ์กฐ: CMS๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ณ„์ธต์ ์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. /{country}/{lang} ๋ผ์šฐํŠธ์˜ ๊ฒฝ์šฐ:

  1. country ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ country ์Šคํ‚ค๋งˆ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  2. lang ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ language ์Šคํ‚ค๋งˆ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  3. ํ•„์š”ํ•˜๋‹ค๋ฉด lang์ด country.languages[] ๋ฐฐ์—ด์— ์žˆ๋Š”์ง€๊นŒ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(๊ณ„์ธต์  ๊ฒ€์ฆ).

meta.segments - ์›์‹œ URL ๊ฒฝ๋กœ ์ ‘๊ทผ

meta.segments๋Š” URL ๊ฒฝ๋กœ๋ฅผ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•˜์—ฌ ์ด๋ฆ„ ์žˆ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์œ„์น˜ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋™์ž‘ ๋ฐฉ์‹:

URL ๊ฒฝ๋กœmeta.segments
/articles/tech/ai-news["articles", "tech", "ai-news"]
/ko/landingPage["ko", "landingPage"]
/us/en/products/featured["us", "en", "products", "featured"]
/[]

meta.segments์™€ meta.params ์‚ฌ์šฉ ์‹œ์  ๋น„๊ต

์‚ฌ์šฉ ์‚ฌ๋ก€์ตœ์ ์˜ ์ ‘๊ทผ ๋ฐฉ์‹
๋ผ์šฐํŠธ ํŒจํ„ด์—์„œ ์ถ”์ถœํ•œ ์ด๋ฆ„ ์žˆ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜meta.params.lang
์œ„์น˜ ๊ธฐ๋ฐ˜ ์ ‘๊ทผmeta.segments[0]
๊ฒฝ๋กœ ๊นŠ์ด ํ™•์ธsize(meta.segments)
ํŠน์ • ๊ตฌ๊ฐ„ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ"admin" in meta.segments

meta.segments ์˜ˆ์‹œ

// ์ฒซ ๋ฒˆ์งธ ๊ตฌ๊ฐ„ ๊ฐ€์ ธ์˜ค๊ธฐ(์ฃผ๋กœ ์–ธ์–ด ์ฝ”๋“œ)
meta.segments[0]

// ๊ฒฝ๋กœ ๊นŠ์ด ํ™•์ธ
size(meta.segments) > 2 ? "deep" : "shallow"

// ๊ด€๋ฆฌ์ž ์˜์—ญ์ธ์ง€ ํ™•์ธ
"admin" in meta.segments ? "admin mode" : "public mode"

// ํด๋ฐฑ: ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ฐ”์ธ๋”ฉ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๊ตฌ๊ฐ„ ์‚ฌ์šฉ
has(meta.params.lang) ? meta.params.lang : meta.segments[0]

meta ๊ฐ์ฒด ์ „์ฒด ์ฐธ์กฐ

meta ๊ฐ์ฒด์—๋Š” ํ˜„์žฌ ์š”์ฒญ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ปจํ…์ŠคํŠธ๊ฐ€ ๋‹ด๊ฒจ ์žˆ์Šต๋‹ˆ๋‹ค.

์†์„ฑํƒ€์ž…์„ค๋ช…
meta.localestringํ˜„์žฌ ๋กœ์ผ€์ผ ์ฝ”๋“œ(์˜ˆ: "en-US", "ko-KR", "ar-SA")
meta.paramsRecord<string, string>URL ํŒจํ„ด์—์„œ ์ถ”์ถœํ•œ ๋ผ์šฐํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜
meta.segmentsstring[]URL ๊ฒฝ๋กœ๋ฅผ ๋ถ„ํ• ํ•œ ๋ฐฐ์—ด
meta.docId`string \null`ํ˜„์žฌ ๋ฌธ์„œ UUID(์ƒˆ ๋ฌธ์„œ์ผ ๋•Œ๋Š” null)
meta.titlestringํ˜„์žฌ ๋ฌธ์„œ ์ œ๋ชฉ

meta.locale

๋กœ์ผ€์ผ ์ฝ”๋“œ๋Š” BCP 47 ํ˜•์‹(์–ธ์–ด-์ง€์—ญ)์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

// ๋กœ์ผ€์ผ์„ ํ™•์ธํ•ด RTL ์–ธ์–ด์ธ์ง€ ํŒŒ์•…
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"

// ์–ธ์–ด ๋ถ€๋ถ„๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ
meta.locale.split("-")[0]  // ์ง€์›๋˜์ง€ ์•Š์Œ - ๋Œ€์‹  meta.params.lang ์‚ฌ์šฉ

meta.params

๋ผ์šฐํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํ•ญ์ƒ ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค. CMS๋Š” ํ‰๊ฐ€ ์ „์— ๋ฐ”์ธ๋”ฉ๋œ ์Šคํ‚ค๋งˆ๋กœ ์ด๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

// ์ด๋ฆ„ ์žˆ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ ‘๊ทผ
meta.params.lang           // "ko"
meta.params.country        // "us"
meta.params.slug           // "welcome-post"

// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
has(meta.params.category)  // true/false

// ๋ฌธ์„œ ์กฐํšŒ์— ์‚ฌ์šฉ
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)

meta.segments

์›์‹œ URL ๊ตฌ๊ฐ„์€ ๋ฐฐ์—ด๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

// ์ธ๋ฑ์Šค๋กœ ์ ‘๊ทผ(0๋ถ€ํ„ฐ ์‹œ์ž‘)
meta.segments[0]           // ์ฒซ ๋ฒˆ์งธ ๊ตฌ๊ฐ„
meta.segments[1]           // ๋‘ ๋ฒˆ์งธ ๊ตฌ๊ฐ„

// ๊ธธ์ด ํ™•์ธ
size(meta.segments)        // ๊ตฌ๊ฐ„ ์ˆ˜

// ํฌํ•จ ์—ฌ๋ถ€ ํ™•์ธ
"products" in meta.segments  // ๊ฒฝ๋กœ์— "products"๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”๊ฐ€?

meta.docId

ํ˜„์žฌ ๋ฌธ์„œ์˜ UUID๋กœ, ์ž๊ธฐ ์ฐธ์กฐ ์Šคํฌ๋ฆฝํŠธ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

// ๊ธฐ์กด ๋ฌธ์„œ๋ฅผ ํŽธ์ง‘ ์ค‘์ผ ๋•Œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
meta.docId != null ? "editing" : "creating new"

// ์กฐ๊ฑด๋ถ€ ๋กœ์ง์— ์‚ฌ์šฉ
meta.docId != null ? documents.get("article", meta.docId).status : "draft"

meta.title

ํ˜„์žฌ ๋ฌธ์„œ์˜ ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.

// ํ‘œ์‹œ์šฉ
"Editing: " + meta.title

// ์ œ๋ชฉ ๊ธฐ๋ฐ˜ ์กฐ๊ฑด๋ถ€ ์ฒ˜๋ฆฌ
meta.title.contains("Draft") ? "work in progress" : "published"

documents.ref() - ์ฒด์ด๋‹๋œ ์กฐํšŒ

์Šคํ‚ค๋งˆ๋Š” ๊ณ ์ •๋˜์–ด ์žˆ๊ณ  ์‹๋ณ„์ž๋งŒ ๋™์ ์ธ ๊ฒฝ์šฐ ๋” ๊น”๋”ํ•œ ๊ตฌ๋ฌธ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

// ์ „ํ†ต์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹
documents.get("airports", meta.params.code).name

// ref() ์‚ฌ์šฉ - ์Šคํ‚ค๋งˆ๋Š” ๋ถ„๋ฆฌํ•˜๊ณ  ์‹๋ณ„์ž๋งŒ ๋™์ ์œผ๋กœ
documents.ref("airports").get(meta.params.code).name

๋‘ ๋ฐฉ์‹ ๋ชจ๋‘ ๋™์ผํ•˜์ง€๋งŒ, ref()๋Š” ๋™์ ์ธ ๋ถ€๋ถ„์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.


๋น ๋ฅธ ์ฐธ์กฐ

๋ฌธ์„œ ๊ฐ€์ ธ์˜ค๊ธฐ

documents.get("schema", "identifier")       // ๋ฌธ์„œ ํ•˜๋‚˜ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.get("schema", "id").fieldName     // ํŠน์ • ํ•„๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.find("schema")                    // ๋ชจ๋“  ๋ฌธ์„œ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.find("schema", { "where": {...}}) // ํ•„ํ„ฐ ์ฟผ๋ฆฌ
documents.ref("schema").get(identifier)     // ์ฒด์ด๋‹ ์กฐํšŒ
documents.translated("schema", "id", "fr")  // ๋ช…์‹œ์  ๋กœ์ผ€์ผ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ

์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜

meta.locale          // "en-US", "ar-SA" ๋“ฑ
meta.params.xyz      // "xyz"๋ผ๋Š” ์ด๋ฆ„์˜ URL ๋งค๊ฐœ๋ณ€์ˆ˜
meta.segments        // URL ๊ฒฝ๋กœ ๋ฐฐ์—ด: ["articles", "intro"]
meta.segments[0]     // ์ฒซ ๋ฒˆ์งธ ๊ฒฝ๋กœ ๊ตฌ๊ฐ„
meta.docId           // ํ˜„์žฌ ๋ฌธ์„œ ID(๋˜๋Š” null)
meta.title           // ํ˜„์žฌ ๋ฌธ์„œ ์ œ๋ชฉ
doc.fieldName        // ํŽธ์ง‘๊ธฐ ์ปจํ…์ŠคํŠธ์—์„œ ํ˜„์žฌ ๋ฌธ์„œ ํ•„๋“œ ๊ฐ’

์—ฐ์‚ฐ์ž

// ๋น„๊ต
==  !=  <  <=  >  >=

// ๋…ผ๋ฆฌ
&&  ||  !

// ์‚ผํ•ญ ์—ฐ์‚ฐ์ž(์กฐ๊ฑด๋ถ€)
condition ? valueIfTrue : valueIfFalse

// ๋ฉค๋ฒ„์‹ญ
"value" in listOrMap

์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜

size(list)                    // ํ•ญ๋ชฉ ์ˆ˜
size(string)                  // ๋ฌธ์ž์—ด ๊ธธ์ด
"text".startsWith("te")       // true
"text".endsWith("xt")         // true
"text".contains("ex")         // true
has(object.property)          // ์†์„ฑ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ
hasProperty(obj, "key")       // ๊ฐ์ฒด์— ํ‚ค๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ(๋Œ€์ฒด ๊ตฌ๋ฌธ)

์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์˜ ์˜ค๋ฅ˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋ฅ˜์˜๋ฏธ
SYNTAX_ERROR์Šคํฌ๋ฆฝํŠธ์— ์˜คํƒ€๊ฐ€ ์žˆ์Œ(๋”ฐ์˜ดํ‘œ ๋ˆ„๋ฝ, ์ž˜๋ชป๋œ ์—ฐ์‚ฐ์ž ๋“ฑ)
TYPE_ERRORํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ํƒ€์ž…์„ ํ˜ผํ•ฉํ•จ
RUNTIME_ERROR์Šคํฌ๋ฆฝํŠธ๋Š” ์‹คํ–‰๋˜์—ˆ์ง€๋งŒ ๋ฌธ์ œ ๋ฐœ์ƒ(์ •์˜๋˜์ง€ ์•Š์€ ๋ณ€์ˆ˜ ๋“ฑ)
FETCH_LIMIT_EXCEEDED๋„ˆ๋ฌด ๋งŽ์€ ๋ฌธ์„œ๋ฅผ ๊ฐ€์ ธ์˜ด(์ตœ๋Œ€ 50๊ฐœ)
TIMEOUT์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ์‹œ๊ฐ„์ด ๋„ˆ๋ฌด ๊น€(์ตœ๋Œ€ 5์ดˆ)
AST_DEPTH_EXCEEDEDํ‘œํ˜„์‹์ด ๋„ˆ๋ฌด ๊นŠ๊ฒŒ ์ค‘์ฒฉ๋จ(์ตœ๋Œ€ ๊นŠ์ด: 50)
SCRIPT_TOO_LONG์Šคํฌ๋ฆฝํŠธ ๊ธ€์ž ์ˆ˜๊ฐ€ 5000์ž๋ฅผ ์ดˆ๊ณผํ•จ

ํ™•์žฅ์„ฑ ๋ฐ ํ–ฅํ›„ ๊ธฐ๋Šฅ

CEL ์—”์ง„์€ ํ™•์žฅ์„ฑ์„ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์˜ˆ์ •๋œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

๊ณ„ํš: MCP ์„œ๋ฒ„ ํ†ตํ•ฉ

// ํ–ฅํ›„: MCP๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€ ์„œ๋น„์Šค ํ˜ธ์ถœ
mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)

๊ณ„ํš: AI ๊ธฐ๋Šฅ

// ํ–ฅํ›„: AI ๊ธฐ๋ฐ˜ ์ฝ˜ํ…์ธ  ์ƒ์„ฑ
ai.summarize(documents.get("article", meta.params.id).body, 100)
ai.translate(meta.params.text, meta.params.targetLang)
ai.classify(meta.params.input, ["positive", "negative", "neutral"])

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ ๋“ฑ๋ก๋œ ํ•จ์ˆ˜ ์‹œ์Šคํ…œ์„ ํ†ตํ•ด ์ถ”๊ฐ€๋˜๋ฉฐ, ๊ธฐ์กด ์Šคํฌ๋ฆฝํŠธ์™€์˜ ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.


ํŒ

  1. ์ž๋™ ์™„์„ฑ ์‚ฌ์šฉ - documents. ๋˜๋Š” meta.๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ํŽธ์ง‘๊ธฐ๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์„ ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.
  2. ๊ฐ„๋‹จํ•˜๊ฒŒ ์‹œ์ž‘ - ๋จผ์ € documents.get("schema", "id")๋กœ ํ…Œ์ŠคํŠธํ•œ ํ›„ .fieldName์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
  3. null ํ™•์ธ - ๋ฌธ์„œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด != null ? ... : ...์œผ๋กœ ํด๋ฐฑ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
  4. ๊ณผ๋„ํ•œ ์กฐํšŒ ํ”ผํ•˜๊ธฐ - ๊ฐ documents.get() ๋˜๋Š” documents.find() ํ˜ธ์ถœ์€ 50ํšŒ ์ œํ•œ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  5. meta.segments๋ณด๋‹ค meta.params ์„ ํ˜ธ - ์ด๋ฆ„ ์žˆ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๊ฒ€์ฆ๋˜๋ฏ€๋กœ ๋” ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.
  6. ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜์—๋Š” has() ์‚ฌ์šฉ - ์ ‘๊ทผ ์ „์— has(meta.params.category)๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
  7. ๋™์  ์‹๋ณ„์ž์—๋Š” documents.ref() ์‚ฌ์šฉ - ์Šคํ‚ค๋งˆ๋Š” ๊ณ ์ •์ด๊ณ  ์‹๋ณ„์ž๋งŒ ๋™์ ์ผ ๋•Œ ๋” ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.
  8. self-reference์—๋Š” doc.fieldName ํ™œ์šฉ - ๊ณ„์‚ฐ ํ‘œํ˜„์‹์—์„œ ํ˜„์žฌ ๋ฌธ์„œ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

๋ฌธ์„œ ๊ฐ„ ์ฐธ์กฐ

์ด ์„น์…˜์—์„œ๋Š” ๋ฌธ์„œ ๊ฐ„ ์—ฐ๊ฒฐ๊ณผ ๊ด€๊ณ„ํ˜• ์ฝ˜ํ…์ธ  ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๊ณ ๊ธ‰ ํŒจํ„ด์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ฐธ์กฐ ํŒจํ„ด

๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ˜•ํƒœ๋Š” ํ•œ ๋ฌธ์„œ๊ฐ€ ๋‹ค๋ฅธ ๋ฌธ์„œ๋ฅผ ์‹๋ณ„์ž๋กœ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// ๊ธฐ์‚ฌ์— ์ €์žฅ๋œ author ID๋กœ ์ž‘์„ฑ์ž ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.get("author", documents.get("article", "intro").authorId).name

documents.ref()๋ฅผ ์‚ฌ์šฉํ•œ ์ฒด์ด๋‹ ์กฐํšŒ

์‹๋ณ„์ž๊ฐ€ ๋™์ ์ผ ๋•Œ ๋” ๊น”๋”ํ•œ ๊ตฌ๋ฌธ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

// ์ „ํ†ต์  ์ ‘๊ทผ
documents.get("country", documents.get("airport", meta.params.code).countryCode).name

// ref() ์‚ฌ์šฉ - ์Šคํ‚ค๋งˆ๋Š” ๊ณ ์ •, ์‹๋ณ„์ž๋Š” ๋™์ 
documents.ref("country").get(documents.get("airport", meta.params.code).countryCode).name

๋‹ค๋‹จ๊ณ„ ์ฐธ์กฐ ์ฒด์ธ

์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ์ฒด์ธ์„ ๊ตฌ์„ฑํ•ด ๊นŠ์€ ๊ด€๊ณ„๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค.

// ๊ณตํ•ญ โ†’ ๊ตญ๊ฐ€ โ†’ ์ง€์—ญ โ†’ ๋Œ€๋ฅ™
documents.get("continent",
  documents.get("region",
    documents.get("country",
      documents.get("airport", meta.params.code).countryCode
    ).regionCode
  ).continentCode
).name

๋ฒˆ์—ญ๊ณผ ๊ฒฐํ•ฉ๋œ ์ฐธ์กฐ

๋ฌธ์„œ ์ฐธ์กฐ๋ฅผ ๋ฒˆ์—ญ๊ณผ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๊ณตํ•ญ์˜ ๊ตญ๊ฐ€ ์ด๋ฆ„์„ ํ˜„์ง€ํ™”ํ•ด์„œ ๊ฐ€์ ธ์˜ค๊ธฐ
documents.translated("country",
  documents.get("airport", meta.params.code).countryCode,
  meta.params.lang
).name

์‚ฌ์šฉ ์‚ฌ๋ก€๋ณ„ ์ฐธ์กฐ ํŒจํ„ด

ํŒจํ„ด 1: ์™ธ๋ž˜ ํ‚ค ์กฐํšŒ

๋ฌธ์„œ์— ๋‹ค๋ฅธ ๋ฌธ์„œ์˜ ID๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

// article / tech-news
{ "title": "Tech Update", "authorId": "author-123", "categoryId": "cat-tech" }
// ์ž‘์„ฑ์ž ์ด๋ฆ„ ํ™•์ธ
documents.get("author", documents.get("article", meta.params.slug).authorId).name

// ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ํด๋ฐฑ๊ณผ ํ•จ๊ป˜ ํ™•์ธ
documents.get("article", meta.params.slug).categoryId != null
  ? documents.get("category", documents.get("article", meta.params.slug).categoryId).name
  : "Uncategorized"

ํŒจํ„ด 2: ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ์ฐธ์กฐ

๋ฌธ์„œ๊ฐ€ UUID ๋Œ€์‹  ์˜๋ฏธ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

// airport / JFK
{ "code": "JFK", "name": "John F. Kennedy International", "countryCode": "us" }

// country / us
{ "code": "us", "name": "United States", "currencyCode": "usd" }

// currency / usd
{ "code": "usd", "symbol": "$", "name": "US Dollar" }
// ๊ณตํ•ญ โ†’ ๊ตญ๊ฐ€ โ†’ ํ†ตํ™” ์ฒด์ธ
documents.get("currency",
  documents.get("country",
    documents.get("airport", meta.params.code).countryCode
  ).currencyCode
).symbol
// JFK์˜ ๊ฒฝ์šฐ: "$" ๋ฐ˜ํ™˜

ํŒจํ„ด 3: doc ์ปจํ…์ŠคํŠธ๋ฅผ ํ™œ์šฉํ•œ ์ž๊ธฐ ์ฐธ์กฐ

ํ˜„์žฌ ๋ฌธ์„œ์˜ ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค๋ฅธ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ณ„์‚ฐ ํ•„๋“œ์— doc์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

// ์ƒํ’ˆ ๋ฌธ์„œ์—์„œ ๊ด€๋ จ ์นดํ…Œ๊ณ ๋ฆฌ ์„ธ๋ถ€ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
documents.get("category", doc.categoryId).description

// ์ƒํ’ˆ์˜ ์›์‚ฐ์ง€ ๊ตญ๊ฐ€์— ๋”ฐ๋ผ ๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ
documents.get("shipping-rates", doc.originCountry).baseRate * doc.weight

ํŒจํ„ด 4: ์–‘๋ฐฉํ–ฅ ์ฐธ์กฐ

๋ฌธ์„œ๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•  ๋•Œ๋Š” ์กฐํšŒ ์ œํ•œ์— ์ฃผ์˜ํ•˜์„ธ์š”.

// ๊ธฐ์‚ฌ ์ž‘์„ฑ์ž๋ฅผ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ, ๊ทธ ์ž‘์„ฑ์ž์˜ ๋‹ค๋ฅธ ๊ธฐ์‚ฌ ๊ฐ€์ ธ์˜ค๊ธฐ(์กฐํšŒ ํšŸ์ˆ˜ ์ฃผ์˜)
documents.find("article", { "where": { "authorId": documents.get("article", meta.params.slug).authorId } })

ํŒจํ„ด 5: ๋‹คํ˜•์„ฑ ์ฐธ์กฐ

ํ•˜๋‚˜์˜ ํ•„๋“œ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ์Šคํ‚ค๋งˆ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

// content-block / hero-1
{ "type": "hero", "sourceType": "article", "sourceId": "welcome-post" }

// content-block / hero-2
{ "type": "hero", "sourceType": "product", "sourceId": "featured-item" }
// sourceType์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์Šคํ‚ค๋งˆ ์กฐํšŒ
documents.get("content-block", "hero-1").sourceType == "article"
  ? documents.get("article", documents.get("content-block", "hero-1").sourceId).headline
  : documents.get("product", documents.get("content-block", "hero-1").sourceId).name

์˜์กด์„ฑ ์ถ”์ 

๋ชจ๋“  documents.get(), documents.find(), documents.ref().get() ํ˜ธ์ถœ์€ ์บ์‹œ ๋ฌดํšจํ™”๋ฅผ ์œ„ํ•ด ์ถ”์ ๋ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐ๋œ ๋ฌธ์„œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด CMS๋Š” ์–ด๋–ค CEL ํ‘œํ˜„์‹์„ ๋‹ค์‹œ ํ‰๊ฐ€ํ•ด์•ผ ํ• ์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ถ”์ ๋˜๋Š” ์˜์กด์„ฑ:

  • get: schema:identifier - ํŠน์ • ๋ฌธ์„œ ์˜์กด์„ฑ
  • ref: schema:identifier - ์ฒด์ด๋‹ ๊ตฌ๋ฌธ์„ ํ†ตํ•œ get๊ณผ ๋™์ผ
  • query: schema:* - ์Šคํ‚ค๋งˆ ์ˆ˜์ค€ ์˜์กด์„ฑ(ํ•ด๋‹น ์Šคํ‚ค๋งˆ์˜ ๋ชจ๋“  ๋ฌธ์„œ)

์ฐธ์กฐ ๋ชจ๋ฒ” ์‚ฌ๋ก€

  1. ์ฒด์ธ ๊นŠ์ด๋ฅผ ์ตœ์†Œํ™” - ๋‹จ๊ณ„๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์ง€์—ฐ ์‹œ๊ฐ„๊ณผ ์กฐํšŒ ํšŸ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ค‘๊ฐ„ ๊ฒฐ๊ณผ ์บ์‹œ - ๋™์ผํ•œ ์ค‘์ฒฉ ๊ฐ’์„ ๋‘ ๋ฒˆ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ถ€๋ชจ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์กฐํšŒํ•˜์„ธ์š”.
  3. null ๊ฒ€์‚ฌ ์‚ฌ์šฉ - ๋ฌธ์„œ๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ์ฐธ์กฐ๊ฐ€ ๋Š์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  4. UUID๋ณด๋‹ค ์ฝ”๋“œ ์‚ฌ์šฉ ์„ ํ˜ธ - ์ฝ”๋“œ๋Š” ํ‘œํ˜„์‹์—์„œ ์ฝ๊ธฐ ์‰ฝ๊ณ  ํ™˜๊ฒฝ ๊ฐ„์— ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.
  5. ์กฐํšŒ ์ œํ•œ ์ฃผ์˜ - ๋ณต์žกํ•œ ์ฐธ์กฐ ์ฒด์ธ์€ 50ํšŒ ์ œํ•œ์— ๋น ๋ฅด๊ฒŒ ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
// ๋‚˜์œ ์˜ˆ: ๋™์ผํ•œ ๋ฌธ์„œ๋ฅผ ๋‘ ๋ฒˆ ์กฐํšŒ
documents.get("author", documents.get("article", "intro").authorId).name + " - " +
documents.get("author", documents.get("article", "intro").authorId).bio

// ๋” ๋‚˜์€ ์˜ˆ: ํ•œ ๋ฒˆ๋งŒ ์กฐ๊ฑด ํ™•์ธ
documents.get("article", "intro").authorId != null
  ? documents.get("author", documents.get("article", "intro").authorId).name
  : "Unknown Author"

๋ถ€๋ก A: ํŒŒ๋ผ๋ฉ”ํŠธ๋ฆญ ๋ผ์šฐํŠธ ์ „์ฒด ์˜ˆ์ œ

์ด ์›Œํฌ์Šค๋ฃจ์—์„œ๋Š” /{lang}/landingPage๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋‹ค๊ตญ์–ด ๋žœ๋”ฉ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

1๋‹จ๊ณ„: ์ธ์‚ฌ ๋ฌธ์„œ ์Šคํ‚ค๋งˆ ์ƒ์„ฑ

CMS ๊ด€๋ฆฌ์ž์—์„œ greeting์ด๋ผ๋Š” ์ปค์Šคํ…€ ์Šคํ‚ค๋งˆ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

{
  "name": "greeting",
  "fields": [
    { "name": "code", "type": "string", "required": true },
    { "name": "headline", "type": "string", "required": true },
    { "name": "subheadline", "type": "string" },
    { "name": "ctaText", "type": "string" },
    { "name": "ctaUrl", "type": "string" }
  ]
}

2๋‹จ๊ณ„: ์ธ์‚ฌ ๋ฌธ์„œ ์ƒ์„ฑ

์–ธ์–ด๋ณ„๋กœ ๋ฌธ์„œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œ: greeting/ko

{
  "code": "ko",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Get Started",
  "ctaUrl": "/ko/get-started"
}

๋ฌธ์„œ: greeting/en

{
  "code": "en",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Get Started",
  "ctaUrl": "/en/get-started"
}

๋ฌธ์„œ: greeting/ja

{
  "code": "ja",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Start",
  "ctaUrl": "/ja/get-started"
}

3๋‹จ๊ณ„: ํŽ˜์ด์ง€ ์ƒ์„ฑ

๋‹ค์Œ ๊ตฌ์„ฑ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • ๊ฒฝ๋กœ/ํŒจํ„ด: /{lang}/landingPage
  • ์ƒํƒœ: ๋ผ์ด๋ธŒ
  • ๋™์  ๊ตฌ๊ฐ„ ๋งคํ•‘: lang์„ language ์ปดํฌ๋„ŒํŠธ์— ๋งคํ•‘
  {
    "lang": "language"
  }

4๋‹จ๊ณ„: CEL ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํฌํ•จ๋œ ๋ธ”๋ก ์ถ”๊ฐ€

๋ผ์šฐํŠธ์— ํžˆ์–ด๋กœ ๋ธ”๋ก์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ฐ ํ•„๋“œ์— ๋‹ค์Œ CEL ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

ํ—ค๋“œ๋ผ์ธ ํ•„๋“œ:

documents.get("greeting", meta.params.lang).headline

์„œ๋ธŒํ—ค๋“œ๋ผ์ธ ํ•„๋“œ:

documents.get("greeting", meta.params.lang).subheadline

CTA ํ…์ŠคํŠธ ํ•„๋“œ:

documents.get("greeting", meta.params.lang).ctaText

CTA URL ํ•„๋“œ:

documents.get("greeting", meta.params.lang).ctaUrl

5๋‹จ๊ณ„: Next.js์—์„œ ์‚ฌ์šฉ

์บ์น˜์˜ฌ ๋ผ์šฐํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ParametricRoutePage๋Š” ํŽ˜์ด์ง€๋ฅผ ํ•ด์„ํ•˜๊ณ  URL์—์„œ meta.params๋ฅผ ์ถ”์ถœํ•˜๋ฉฐ, ์„œ๋ฒ„ ์ธก์—์„œ CEL ๋ฐ”์ธ๋”ฉ์„ ํ‰๊ฐ€ํ•œ ๋’ค ๊ฐ ๋ธ”๋ก์„ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. meta ์ปจํ…์ŠคํŠธ๋ฅผ ์ง์ ‘ ๊ตฌ์„ฑํ•˜๊ฑฐ๋‚˜ ๋กœ์šฐ ๋ ˆ๋ฒจ ํด๋ผ์ด์–ธํŠธ๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

// app/[...slug]/page.tsx
import ParametricRoutePage from 'cms-renderer/lib/renderer';
import { registry } from '@/lib/registry';
import { cmsConfig } from '@/lib/cms-config';

export const dynamic = 'force-static';

interface PageProps {
  params: Promise<{ slug: string[] }>;
}

export default async function Page({ params }: PageProps) {
  const { slug } = await params;

  return (
    <ParametricRoutePage
      registry={registry}
      apiKey={cmsConfig.apiKey}
      websiteId={cmsConfig.websiteId}
      cmsUrl={cmsConfig.cmsUrl}
      params={Promise.resolve({ slug })}
    />
  );
}

6๋‹จ๊ณ„: ๋ผ์šฐํŠธ ํ…Œ์ŠคํŠธ

๋‹ค์Œ URL์„ ๋ฐฉ๋ฌธํ•ด ํ˜„์ง€ํ™”๋œ ์ฝ˜ํ…์ธ ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

URL์˜ˆ์ƒ ํ—ค๋“œ๋ผ์ธ
/ko/landingPageํ™˜์˜
/en/landingPageWelcome
/ja/landingPageใ„ใ‚‰ใฃใ—ใ‚ƒใ„ใพใ›

ํ•ด์„ ๊ณผ์ •

์‚ฌ์šฉ์ž๊ฐ€ /ko/landingPage๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด:

  1. ๋ผ์šฐํŠธ ๋งค์นญ: CMS๊ฐ€ /{lang}/landingPage ํŒจํ„ด์„ ๋งค์นญํ•ฉ๋‹ˆ๋‹ค.
  2. ๋งค๊ฐœ๋ณ€์ˆ˜ ์ถ”์ถœ: meta.params.lang = "ko"
  3. ๊ฒ€์ฆ: CMS๊ฐ€ language ์Šคํ‚ค๋งˆ์—์„œ "ko"๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  4. CEL ํ‰๊ฐ€: documents.get("greeting", meta.params.lang) ๊ฐ™์€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํ•œ๊ตญ์–ด ์ฝ˜ํ…์ธ ๋กœ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  5. ์‘๋‹ต: ํ˜„์ง€ํ™”๋œ ๋ธ”๋ก์ด ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

๋ถ€๋ก B: ๊ธฐ์ˆ  ์ฐธ์กฐ

CelMeta ์ธํ„ฐํŽ˜์ด์Šค(TypeScript)

interface CelMeta {
  /** Current locale code (e.g., 'en-US') */
  locale: string;
  /** Route parameters extracted from URL */
  params: Record<string, string>;
  /** URL path segments */
  segments: string[];
  /** Current document ID (if editing existing document) */
  docId: string | null;
  /** Current document title */
  title: string;
}

๋งค๊ฐœ๋ณ€์ˆ˜ ์ถ”์ถœ ์•Œ๊ณ ๋ฆฌ์ฆ˜

extractParams ํ•จ์ˆ˜๋Š” URL ๊ฒฝ๋กœ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ํŒจํ„ด: /{country}/{lang}/products
๊ฒฝ๋กœ:    /us/en/products

์•Œ๊ณ ๋ฆฌ์ฆ˜:
1. ๋‘˜ ๋‹ค ์ •๊ทœํ™”(ํ›„ํ–‰ ์Šฌ๋ž˜์‹œ ์ œ๊ฑฐ)
2. ๊ตฌ๊ฐ„์œผ๋กœ ๋ถ„ํ• : ["us", "en", "products"]์™€ ["{country}", "{lang}", "products"]
3. ๊ตฌ๊ฐ„ ๊ฐœ์ˆ˜๊ฐ€ ์ผ์น˜ํ•ด์•ผ ํ•จ
4. ๊ฐ ๊ตฌ๊ฐ„ ์Œ์— ๋Œ€ํ•ด:
   - ํŒจํ„ด์ด : ๋˜๋Š” {}๋กœ ์‹œ์ž‘ํ•˜๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ถ”์ถœ
   - ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ •ํ™•ํžˆ ์ผ์น˜ํ•ด์•ผ ํ•จ
5. ๋ฐ˜ํ™˜: { country: "us", lang: "en" }

์ง€์›๋˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ”์ธ๋”ฉ ํ˜•์‹

// ๊ฐ„๋‹จํ•œ ๋ฐ”์ธ๋”ฉ("code" ํ•„๋“œ๋กœ ์กฐํšŒ)
{ "lang": "language" }

// ์„ธ๋ถ€ ๋ฐ”์ธ๋”ฉ(๋งž์ถค ์Šฌ๋Ÿฌ๊ทธ ํ•„๋“œ)
{
  "lang": {
    "schemaName": "language",
    "slugField": "code"
  },
  "slug": {
    "schemaName": "article",
    "slugField": "slug"
  }
}

๋ฌธ์„œ ์กฐํšŒ ์šฐ์„ ์ˆœ์œ„

documents.get(schema, identifier)๋กœ ๊ฐ€์ ธ์˜ฌ ๋•Œ์˜ ์šฐ์„ ์ˆœ์œ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. UUID ์ผ์น˜: ์‹๋ณ„์ž๊ฐ€ ์œ ํšจํ•œ UUID์ด๋ฉด id๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  2. code ํ•„๋“œ: content.code ํ•„๋“œ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  3. slug ํ•„๋“œ: content.slug ํ•„๋“œ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  4. title ์ผ์น˜: title ํ•„๋“œ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์–ด๋–ค ๊ณ ์œ  ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•˜๋“  ์œ ์—ฐํ•˜๊ฒŒ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Continue Reading
Previousโ€น์–ด๋“œ๋ฏผ ํŒจ๋„ ํ”„๋ก์‹œ ์„ค์ •NextProject Scaffoldingโ€บ