์ค์ตํ ์๋ด์: Profound CMS์์ ๊ตญ์ ํ๋ ๊ณตํญ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ตฌ์ถํ์ธ์ โ 35๊ฐ ์ธ์ด๋ก ๋ชจ๋ ๊ณตํญ ํ์ด์ง๋ฅผ ๋ ๋๋งํ๋ ํ๋์ ๋งค๊ฐ๋ณ์ ๋ผ์ฐํธ.
Profound CMS์์ ์ค์ ๊ตญ์ ํ๋ ๊ณตํญ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ตฌ์ถํ์ธ์: ํ๋์ URL ํจํด์ผ๋ก 35๊ฐ ์ธ์ด๋ก ๋ชจ๋ ๊ณตํญ ํ์ด์ง๋ฅผ ๋ ๋๋งํฉ๋๋ค. Next.js ์ฝ๋๋ฅผ ์์ฑํ๊ณ CMS ๊ตฌ์กฐ๋ฅผ ์ง์ ๊ตฌ์ฑํ์ธ์; Claude Code(Profound MCP๋ฅผ ํตํด)๊ฐ ์ธ ๊ฐ์ง ์์ ์ ์ฒ๋ฆฌํฉ๋๋ค โ ๊ณตํญ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ , ๋์์ธ ์์คํ ์ ์ฐ๊ฒฐํ๋ฉฐ, ๋ค ๊ฐ์ React ์ปดํฌ๋ํธ๋ฅผ ์์ฑํฉ๋๋ค. ์ธ ํํธ: Setup, Build, Production.
์ ์ฒด ๋น๋์ค ์ํฌ์ค๋ฃจ ๋ณด๊ธฐ.
/{language}/{airport_code}.cms-renderer์ ์ํด ๋ ๋๋ง๋ฉ๋๋ค.curl -fsSL https://bun.sh/install | bashgh)์ GitHub์ ์ฐ๊ฒฐ๋ Vercel ๊ณ์ .language ๊ฐ์ ์์คํ
์ปดํฌ๋ํธ๋ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณต๋ฉ๋๋ค.cms-renderer SDK๋ฅผ ํตํด ๋ชจ๋ ๊ฒ์ ๋ ๋๋งํฉ๋๋ค.์ต์ข ์ํ: CMS์ ~50๊ฐ์ ๊ณตํญ์ด ์๊ณ , ์ฑ์ด ์ด๋ฅผ ์ฝ๋๋ก ์ฐ๊ฒฐ๋๋ฉฐ, ๋์์ธ ์์คํ ์ด ๊ตฌ์ฑ๋ฉ๋๋ค.
Profound(WorkOS ์ธ์ฆ)์ ๊ฐ์
ํ๊ณ airports๋ผ๋ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ญ๋๋ค. ๋ ๊ฐ์ง๋ฅผ ๋ณต์ฌํ์ธ์: website ID(๊ด๋ฆฌ์ URL์ UUID)์ Deployments โ Create API key์์ ๋ฐ๊ธ๋ฐ์ ์ฝ๊ธฐ ์ ์ฉ API ํค. ์ฑ์ ์ฝ๊ธฐ๋ง ํ๋ฏ๋ก ์ฝ๊ธฐ ํค๋ง ํ์ํฉ๋๋ค.
bunx create-profound-next airports
cd airports
์๊ฒฉ ์ฆ๋ช
์ .env.local์ ์ถ๊ฐํ์ธ์:
PROFOUND_API_KEY=<your read key>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<your website id>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net
bun dev๋ฅผ ์คํํ๊ณ localhost:3000์ ์ด์ด ์ฐ๊ฒฐ์ ํ์ธํฉ๋๋ค.
airport ์ปดํฌ๋ํธ ์์ฑ๊ด๋ฆฌ์์์ Components โ Create new component๋ก ์ด๋ํด ์ด๋ฆ์ airport๋ก ์ง์ ํฉ๋๋ค. ์ฌ์ฏ ๊ฐ ํ๋๋ฅผ ์ถ๊ฐํ์ธ์: code, name, city, country(Text)์ latitude, longitude(Number). code๋ฅผ Route Slug ํ๋๋ก ํ์ํ๊ณ ์ํ๋ฅผ Active๋ก ์ค์ ํฉ๋๋ค. ๋ชจ๋ ํ๋๋ ์ ํ ์ฌํญ์ผ๋ก ๋๊ณ , UI Element ํ๊ทธ๋ ์ถ๊ฐํ์ง ๋ง์ธ์.
airport ์ปดํฌ๋ํธ โ ์ฌ์ฏ ๊ฐ์ ํ๋์ Route Slug๋ก ์ค์ ๋ code ํ๋.
bun run generate-schemas
์ด ๋ช
๋ น์ airportSchema(Zod)์ Airport(type)๋ฅผ generated/cms-schemas.ts์ ์์ฑํ๋ฉฐ ์๊ฒฉ ์ฆ๋ช
๋ ํ์ธํฉ๋๋ค.
MCP๋ฅผ ์ฐ๊ฒฐํ๊ณ ์ธ์ฆํ์ธ์:
claude mcp add --transport http Profound http://107.21.107.99:8081/mcp
์๋ฒ๋ OAuth(WorkOS)๋ก ์ธ์ฆํฉ๋๋ค. Claude Code์์ /mcp๋ฅผ ์คํํ๊ณ Profound๋ฅผ ์ ํํ ๋ค ๋ธ๋ผ์ฐ์ ์์ ๋ก๊ทธ์ธ์ ์๋ฃํ์ธ์ โ Profound ๋๊ตฌ๋ฅผ ์ฒ์ ํธ์ถํ๋ฉด Claude Code๊ฐ ์๋์ผ๋ก ํ๋กฌํํธ๋ฅผ ๋์๋๋ค. /mcp์ Profound๊ฐ connected๋ก ํ์๋๋ฉด Claude์๊ฒ ๋ค์๊ณผ ๊ฐ์ด ์์ฒญํ์ธ์:
์ค์ ๊ณตํญ 50๊ณณ์ ์์ฑํ์ธ์ โ ์ฌ๋ฐ๋ฅธ IATA ์ฝ๋, ์ด๋ฆ, ๋์, ๊ตญ๊ฐ, ์ขํ๋ฅผ ํฌํจํฉ๋๋ค. ์ด๋ฅผ
dataํด๋์ JSON์ผ๋ก ์ ์ฅํ๊ณ , ์ฐ๋ฆฌ airport ์ปดํฌ๋ํธ์ ๋ํด ๊ฒ์ฆํ ๋ค, Profound MCP๋ฅผ ํตํด ๋ณ๋ ฌ๋ก ๊ฒ์๋ ๋ฌธ์๋ก ๊ฐ๊ฐ ์์ฑํ์ธ์.
airport โ Variants๋ฅผ ์ด์ด ~50๊ฐ์ ๊ฒ์๋ ๊ณตํญ์ ํ์ธํฉ๋๋ค. ์ฑ์ API ํค๋ก ์ฝ๊ณ , MCP๋ ์์ฒด WorkOS ์ธ์ ์ผ๋ก ๊ธฐ๋กํฉ๋๋ค.
์ฝ 50๊ฐ์ ๊ณตํญ์ด ๊ฒ์๋ Variant๋ก ์๋๋์์ต๋๋ค.
์ค์บํด๋๋ ์คํ์ผ์ด ์์ต๋๋ค. ํ๋ก์ ํธ ๋ฃจํธ์ DESIGN.md(Tailwind v4 @theme ๋ธ๋ก๊ณผ ํ ํฐ)๋ฅผ ๋์ธ์ โ ์ง์ ์์ฑํ๊ฑฐ๋ refero.design์์ ๋ค์ด๋ก๋ํด๋ ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ Claude์๊ฒ ์์ฒญํ์ธ์:
DESIGN.md๋ฅผ ์ฝ๊ณ Tailwind v4๋ฅผ ์ค์ ํ ๋ค ํ ๋ง์ ํฐํธ๋ฅผ ์ฐ๊ฒฐํ์ธ์. ํฐํธ๋ ๋ฐํ์ Google import๊ฐ ์๋๋ผ
next/font๋ฅผ ์ฌ์ฉํ์ธ์. ์คํ์ผ๋ง๋ง โ ํ์ด์ง๋ ์ปดํฌ๋ํธ๋ ์์ง ๋ง๋ค์ง ๋ง์ธ์.
src/app/globals.css์ @import "tailwindcss";์ @theme ๋ธ๋ก์ด ํฌํจ๋์ด ์๋์ง, localhost:3000์์ ํ ํฐ์ด ํ์๋๋์ง ํ์ธํ์ธ์.
๋ ๋๋ง ๋ ์ด์ด๋ฅผ ๊ตฌ์ถํฉ๋๋ค: UI ์์, React ์ปดํฌ๋ํธ, ๋ผ์ฐํธ, CEL ๋ฐ์ธ๋ฉ, ๋ฒ์ญ์ ์ค์ ํฉ๋๋ค.
๊ด๋ฆฌ์์์ Create new component๋ฅผ ๋ค ๋ฒ ์คํํฉ๋๋ค(Route Slug ์์). ๊ฐ ์ปดํฌ๋ํธ๋ง๋ค ํ๋๋ฅผ Text๋ก ์ถ๊ฐํ๊ณ (๋ช
์๋ ๊ฒฝ์ฐ ์ ์ธ), ์ํ๋ฅผ Active๋ก ์ค์ ํ ๋ค Settings โ Tags์์ UI Element ํ๊ทธ๋ฅผ ์ถ๊ฐํ์ธ์:
nav โ brandheadline โ title, subtitlebody โ code, city, country, latitude(Number), longitude(Number)footer โ textbody.latitude์ body.longitude๋ ๊ณตํญ ์ปดํฌ๋ํธ์ ์ผ์นํ๋๋ก ๋ฐ๋์ Number์ฌ์ผ ํฉ๋๋ค.
๊ฐ UI ์์๋ ์์ฒด ์ปดํฌ๋ํธ์
๋๋ค โ ์ฌ๊ธฐ์๋ body๊ฐ Active๋ก ์ค์ ๋๊ณ UI Element ํ๊ทธ๊ฐ ์ถ๊ฐ๋์ด ์์ต๋๋ค.
๋ชจ๋ UI ์์๊ฐ airport ์ปดํฌ๋ํธ์ ํจ๊ป ๋์ด๋์ด ์์ต๋๋ค.
bun run generate-schemas
Claude์๊ฒ ๋ค์๊ณผ ๊ฐ์ด ์์ฒญํ์ธ์:
components/์ nav, headline, body, footer๋ผ๋ ๋ค ๊ฐ์ React ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ์ธ์. ๊ฐ ์ปดํฌ๋ํธ๋ ์์ฑ๋ ํ์T๋ฅผ ์ฌ์ฉํ๋BlockComponentProps<T>ํ์ ์ ๋จ์ผcontentprop์ ๋ฐ์content์์ ํ๋๋ฅผ ์ฝ์ด์ผ ํฉ๋๋ค. ๋ค ์ปดํฌ๋ํธ๋ฅผ catch-all ๋ผ์ฐํธ์ ๋ ์ง์คํธ๋ฆฌ์ ์ปดํฌ๋ํธ ์ด๋ฆ์ผ๋ก ๋ฑ๋กํ์ธ์. ๋์์ธ ์์คํ ์ผ๋ก ์คํ์ผ๋งํ๋, ์ฐ๋ฆฌ๋ง์ ์ปดํฌ๋ํธ๋ก ๊ตฌํํ๊ณ ์์ค ์ฌ์ดํธ ๋ ์ด์์์ ๋ณต์ฌํ์ง ๋ง์ธ์. Nav: ์ผ์ชฝ์ ๋ธ๋๋. Headline:code ยท city, country์๋ธํ์ดํ์ ๊ฐ์ง ๊ณตํญ ์ด๋ฆ. Body: ์ฝ๋, ๋์, ๊ตญ๊ฐ, ์ขํ๊ฐ ํฌํจ๋ ์์ธ ํจ๋. Footer: ๊ณ ์ ๋ ํ ์ค ํ ์คํธ. ๋ ์ด์์๊ณผ ์คํ์ผ๋ง๋ง ์ฒ๋ฆฌํ์ธ์.
Claude๋ ๋ค ๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๊ณ src/app/[...slug]/page.tsx์ ๋ ์ง์คํธ๋ฆฌ์ ์ฑ์๋๋ค:
const registry = { nav: Nav, headline: Headline, body: Body, footer: Footer };
๊ท์น ๋ ๊ฐ์ง: ๊ฐ ์ปดํฌ๋ํธ๋ ํ๋๋ฅผ content์์ ์ฝ์ด์ผ ํ๋ฉฐ(๊ฐ๋ณ prop ๊ธ์ง), ๋ ์ง์คํธ๋ฆฌ ํค๋ CMS ์ปดํฌ๋ํธ ์ด๋ฆ๊ณผ ์ ํํ ์ผ์นํด์ผ ํฉ๋๋ค โ ์ผ์นํ์ง ์์ผ๋ฉด ๋ ๋๋ง๋์ง ์์ต๋๋ค.
๊ด๋ฆฌ์์์ Pages โ Create page๋ก ์ด๋ํด ํจํด์ /{airport_code}๋ก ์ค์ ํฉ๋๋ค. Dynamic Segment Mappings์์ airport_code๋ฅผ airport ์ปดํฌ๋ํธ์ slug ํ๋ code์ ๋งคํํฉ๋๋ค. ์ ์ฅํ๋ฉด Page Builder๋ก ์ด๋ํฉ๋๋ค. /JFK๊ฐ ํด์๋๋์ง ํ์ธํ์ธ์.
Custom ํญ์์ UI ์์๋ฅผ ํ์ด์ง์ ์ถ๊ฐํฉ๋๋ค.
JFK ๋ฐ์ธ๋ฉ์ Page Builder์ ๋ค ๊ฐ์ UI ์์๊ฐ ์ถ๊ฐ๋ ์ํ์ ๋๋ค.
JFK ๋ฐ์ธ๋ฉ์ ์ ํํ๊ณ Add UI Element โ Custom ํญ โ nav, headline, body, footer ์์๋ก ์ถ๊ฐํ์ธ์. Profound๋ ์ด ๊ตฌ์ฑ์ ๋ชจ๋ ๊ณตํญ ๋ฐ์ธ๋ฉ์ผ๋ก ์ ํํฉ๋๋ค.
๊ฐ ํ๋๋ฅผ ์ฑ์๋๋ค. ์ ์ ๊ฐ(nav ๋ธ๋๋, footer ํ
์คํธ)์ ์ง์ ์
๋ ฅํ์ธ์. ๋์ ๊ฐ์ ๋์ ์ผ๋ก ์ ํํ ๋ค CEL์ ์์ฑํ์ธ์. ๊ณต์ ์กฐํ๋ documents.get("airport", meta.params.airport_code)์
๋๋ค.
| ํ๋ | CEL ๊ฐ |
|---|---|
headline.title | documents.get("airport", meta.params.airport_code).name |
headline.subtitle | documents.get("airport", meta.params.airport_code).code + " ยท " + documents.get("airport", meta.params.airport_code).city + ", " + documents.get("airport", meta.params.airport_code).country |
body.code / body.city / body.country | documents.get("airport", meta.params.airport_code).<field> |
body.latitude / body.longitude | documents.get("airport", meta.params.airport_code).latitude ๋ฐ .longitude |
nav.brand, footer.text | ์ ์ ๋ฌธ์์ด |
ํ์ด์ง๋ฅผ Publish(์ฐ์ธก ์๋จ)ํ์ธ์.
localhost:3000/JFK๋ฅผ ์ฐ ๋ค์ /SFO, /LAX๋ ์ด์ด๋ณด์ธ์ โ ๋์ผํ ํ
ํ๋ฆฟ์ ๋ค๋ฅธ ๊ณตํญ์ด ์ ์ฉ๋ฉ๋๋ค.
์์ฑ๋ ํ์ด์ง๊ฐ JFK ๋ฐ์ดํฐ๋ฅผ ์์ด๋ก ๋ ๋๋งํฉ๋๋ค.
๋จผ์ ์ปดํฌ๋ํธ๋ฅผ ๋ฒ์ญํ์ธ์. ๊ด๋ฆฌ์์์ ๊ฐ ์ปดํฌ๋ํธ(ํ์๋ก UI ์์์ผ ํ์๋ ์์)๋ฅผ ์ด๊ณ Translate โ Submit์ ํด๋ฆญํ์ธ์. Profound๋ ํ ๋ฒ์ 35๊ฐ ์ธ์ด๋ก ์ฝํ ์ธ ๋ฅผ ๋ฒ์ญํ๋ฉฐ, ์ ์ ํ๋ ๊ฐ๋ ํฌํจ๋ฉ๋๋ค. ๋ผ์ฐํธ๋ฅผ ์์ ํ๊ฑฐ๋ CEL์ ๊ฑด๋๋ฆฌ๊ธฐ ์ ์ ์ด ์์ ์ ์ํํ์ธ์.
Translate โ Submit์ ํ ๋ฒ์ 35๊ฐ ์ธ์ด๋ก ์ปดํฌ๋ํธ๋ฅผ ์ ์กํฉ๋๋ค.
์ธ์ด ์ฐจ์์ ์ถ๊ฐํ์ธ์. Pages์์ ํจํด์ /{language}/{airport_code}๋ก ๋ณ๊ฒฝํฉ๋๋ค. language์ ๋ํ Dynamic Segment Mapping์ ์ถ๊ฐํ๊ณ ๋ด์ฅ language ์์คํ
์ปดํฌ๋ํธ์ slug ํ๋๋ฅผ code๋ก ์ค์ ํ์ธ์. ์ ์ฅ ํ /en/JFK๊ฐ ํด์๋๋์ง ํ์ธํฉ๋๋ค.
{language} ์ธ๊ทธ๋จผํธ๋ฅผ ๋ผ์ฐํธ์ ์ถ๊ฐํ๋ ๋ชจ์ต์
๋๋ค.
๋ชจ๋ ๋ฒ์ญ ๊ฐ๋ฅํ ํ๋๋ฅผ ๋ฒ์ญ๋ fetch๋ก ์ฐ๊ฒฐํ์ธ์. ํ์ด์ง๋ฅผ ๊ตญ์ ํํ๋ ค๋ฉด ์ธ์ด์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ๋ชจ๋ ํ๋๋ฅผ documents.get(...)์์ documents.translated("airport", meta.params.airport_code, meta.params.language)๋ก ์ ํํด์ผ ํฉ๋๋ค:
| ํ๋ | ๋ฒ์ญ๋ CEL |
|---|---|
headline.title | documents.translated("airport", meta.params.airport_code, meta.params.language).name |
headline.subtitle | documents.get("airport", meta.params.airport_code).code + " ยท " + documents.translated("airport", meta.params.airport_code, meta.params.language).city + ", " + documents.translated("airport", meta.params.airport_code, meta.params.language).country |
body.city / body.country | documents.translated("airport", meta.params.airport_code, meta.params.language).city ๋ฐ .country |
IATA code์ ์ขํ๋ ์ธ์ด์ ์๊ด์์ด ๋์ผํ๋ฏ๋ก documents.get์ ๊ทธ๋๋ก ์ฌ์ฉํฉ๋๋ค. nav.brand์ footer.text๋ ์ด๋ฏธ 1๋จ๊ณ์์ ๋ฒ์ญ๋์์ต๋๋ค.
์ธ ๊ฐ์ง๊ฐ ๋ชจ๋ ์๋ฃ๋๋ฉด /fr/SFO, /de/SFO ๋ฑ ๋ชจ๋ ์ธ์ด๊ฐ ์์ ํ ๋ฒ์ญ๋์ด ํ์๋ฉ๋๋ค.
GitHub์ ํธ์ํ์ธ์:
git init
git add -A
git commit -m "Airport directory"
gh repo create airports --public --source=. --push
Vercel์ ๊ฐ์ ธ์ค๊ธฐ: Add New โ Project โ airports ์ ์ฅ์๋ฅผ ๊ฐ์ ธ์ต๋๋ค. ํ๊ฒฝ ๋ณ์๋ฅผ ์ถ๊ฐํ์ธ์ โ PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, ํ์ํ๋ฉด NEXT_PUBLIC_BUNNY_CDN_URL โ ๊ทธ๋ค์ Deploy๋ฅผ ํด๋ฆญํฉ๋๋ค. /en/JFK์ /fr/SFO๋ฅผ ๋ฐฉ๋ฌธํ์ธ์. ์ดํ git push๋ง๋ค ์๋ ๋ฐฐํฌ๋ฉ๋๋ค.
๋ ๊ธฐ๋ฅ ๋ชจ๋ ์ค์บํด๋์ ํฌํจ๋์ด ์์ต๋๋ค.
layout.tsx์ <Refresher>๋ ๊ด๋ฆฌ์๊ฐ ํธ์ง ํ ์ ์ฅํ ๋, ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ค์ธ ํ์ด์ง๋ฅผ ์ฌ๋ฐฐํฌ ์์ด ์
๋ฐ์ดํธํฉ๋๋ค.?edit_mode=true๋ฅผ ์ถ๊ฐํ์ธ์(์: โฆ/en/JFK?edit_mode=true). ๊ทธ๋ฌ๋ฉด ํธ์ง ์ค๋ฒ๋ ์ด๊ฐ ํ์๋ฉ๋๋ค. ์ผ๋ฐ ๋ฐฉ๋ฌธ์๋ ๊นจ๋ํ ํ์ด์ง๋ฅผ ๊ทธ๋๋ก ๋ณด๊ฒ ๋ฉ๋๋ค.?edit_mode=true๋ ๋ผ์ด๋ธ ํ์ด์ง ์์ ํธ์ง๊ธฐ๋ฅผ ์ค๋ฒ๋ ์ดํฉ๋๋ค.
50๊ฐ์ ๊ณตํญ, 35๊ฐ ์ธ์ด, ์ค์๊ฐ โ ํ ๋ฒ ์ค๊ณํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ฑ์ ๋ฃ์ต๋๋ค: ํ๋์ ๋ผ์ฐํธ, ๋ค ๊ฐ์ React ์ปดํฌ๋ํธ, ๋ช ๊ฐ์ CEL ๋ฐ์ธ๋ฉ. CMS๊ฐ ์ฝํ ์ธ ๋ฅผ ๋ณด๊ดํ๊ณ , ์ฌ๋ฌ๋ถ์ ์ฝ๋๊ฐ ์ด๋ฅผ ๋ ๋๋งํ๋ฉฐ, CEL์ด ๋์ ์ฐ๊ฒฐํฉ๋๋ค.