@bstage-sdk/core 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +18 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +17 -1
- package/docs/AI_TOOLKIT.md +96 -0
- package/docs/BUILD_SYSTEM.md +35 -0
- package/docs/DEV_SERVER.md +56 -1
- package/docs/GETTING_STARTED.md +31 -7
- package/docs/INIT.md +76 -19
- package/docs/LIQUID.md +122 -0
- package/docs/MIGRATION.md +159 -1
- package/docs/README.md +4 -0
- package/docs/SLOT_CATALOG_V2.md +12 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
PlatformBridge: () => PlatformBridge,
|
|
31
31
|
SLOT_CATALOG: () => SLOT_CATALOG,
|
|
32
32
|
SLOT_CATALOG_V2: () => SLOT_CATALOG_V2,
|
|
33
|
+
VERSION: () => VERSION,
|
|
33
34
|
__resetElementRegistry__: () => __resetElementRegistry__,
|
|
34
35
|
announceElementName: () => announceElementName,
|
|
35
36
|
configureBstageI18n: () => configureBstageI18n,
|
|
@@ -172,6 +173,9 @@ var HttpTimeoutError = class extends Error {
|
|
|
172
173
|
}
|
|
173
174
|
};
|
|
174
175
|
|
|
176
|
+
// src/version.ts
|
|
177
|
+
var VERSION = "0.5.0";
|
|
178
|
+
|
|
175
179
|
// src/client/BstageClient.ts
|
|
176
180
|
function resolveBaseUrl() {
|
|
177
181
|
if (typeof globalThis.location !== "undefined") {
|
|
@@ -228,7 +232,9 @@ var BstageClient = class {
|
|
|
228
232
|
"X-BSTAGE-APP-ID": config.appId,
|
|
229
233
|
// 값이 없으면(UI 전용 템플릿의 빈 .env) 헤더 자체를 빼서 "undefined" 문자열이 실리지 않게 한다.
|
|
230
234
|
...appKey !== void 0 ? { "X-BSTAGE-APP-KEY": appKey } : {},
|
|
231
|
-
"X-BSTAGE-TENANT-ID": config.tenantId
|
|
235
|
+
"X-BSTAGE-TENANT-ID": config.tenantId,
|
|
236
|
+
// 어느 SDK(core) 버전이 호출하는지 게이트웨이 로그에서 볼 수 있게. 값은 버전 문자열만(패키지 이름 없음).
|
|
237
|
+
"x-bmf-sdk-version": VERSION
|
|
232
238
|
}
|
|
233
239
|
});
|
|
234
240
|
}
|
|
@@ -614,6 +620,16 @@ var SLOT_CATALOG_V2 = {
|
|
|
614
620
|
ticket: { type: "DigitalTicket", required: true }
|
|
615
621
|
}
|
|
616
622
|
},
|
|
623
|
+
// 어드민 — 콘텐츠 목록 PageTitleContainer 아래
|
|
624
|
+
"admin.contents-list.list:before": {
|
|
625
|
+
description: "\uCF58\uD150\uCE20 \uBAA9\uB85D \u2014 \uBAA9\uB85D \uC704",
|
|
626
|
+
context: {}
|
|
627
|
+
},
|
|
628
|
+
// 어드민 — 커뮤니티 보드 목록 PageTitleContainer 아래
|
|
629
|
+
"admin.community-board-list.list:before": {
|
|
630
|
+
description: "\uCEE4\uBBA4\uB2C8\uD2F0 \uBCF4\uB4DC \uBAA9\uB85D \u2014 \uBAA9\uB85D \uC704",
|
|
631
|
+
context: {}
|
|
632
|
+
},
|
|
617
633
|
// 유저 — 콘텐츠 홈 (결정-018에 1차 명시. curation은 신설, contents-section은 옛 contents.home.contents.before/after 이전)
|
|
618
634
|
"user.contents-home.curation:after": {
|
|
619
635
|
description: "\uCF58\uD150\uCE20 \uD648 \u2014 \uD050\uB808\uC774\uC158 \uC139\uC158 \uC544\uB798",
|
|
@@ -893,6 +909,7 @@ function __resetElementRegistry__() {
|
|
|
893
909
|
PlatformBridge,
|
|
894
910
|
SLOT_CATALOG,
|
|
895
911
|
SLOT_CATALOG_V2,
|
|
912
|
+
VERSION,
|
|
896
913
|
__resetElementRegistry__,
|
|
897
914
|
announceElementName,
|
|
898
915
|
configureBstageI18n,
|
package/dist/index.d.cts
CHANGED
|
@@ -771,6 +771,14 @@ declare const SLOT_CATALOG_V2: {
|
|
|
771
771
|
};
|
|
772
772
|
};
|
|
773
773
|
};
|
|
774
|
+
readonly 'admin.contents-list.list:before': {
|
|
775
|
+
readonly description: "콘텐츠 목록 — 목록 위";
|
|
776
|
+
readonly context: {};
|
|
777
|
+
};
|
|
778
|
+
readonly 'admin.community-board-list.list:before': {
|
|
779
|
+
readonly description: "커뮤니티 보드 목록 — 목록 위";
|
|
780
|
+
readonly context: {};
|
|
781
|
+
};
|
|
774
782
|
readonly 'user.contents-home.curation:after': {
|
|
775
783
|
readonly description: "콘텐츠 홈 — 큐레이션 섹션 아래";
|
|
776
784
|
readonly context: {};
|
|
@@ -1136,4 +1144,10 @@ declare function lookupElementName(url: string): string | undefined;
|
|
|
1136
1144
|
*/
|
|
1137
1145
|
declare function __resetElementRegistry__(): void;
|
|
1138
1146
|
|
|
1139
|
-
|
|
1147
|
+
/**
|
|
1148
|
+
* 번들에 심긴 core 버전. `BstageClient`가 모든 요청에 `x-bmf-sdk-version` 헤더로 실어
|
|
1149
|
+
* 게이트웨이 로그에서 어느 SDK 버전이 쓰이는지 볼 수 있게 한다.
|
|
1150
|
+
*/
|
|
1151
|
+
declare const VERSION: string;
|
|
1152
|
+
|
|
1153
|
+
export { ADMIN_EVENT_CATALOG, type AdminConnectPayload, type AdminDomainEventMap, type AdminDomainEventType, type BoardInfo, type BoardPostInfo, type BodyRequestOptions, BstageClient, type BstageConfig, type BstageI18nConfig, type Content, type ContentsSectionInfo, type CustomSlots, type CustomSlotsV2, DEFAULT_LANGUAGE, type DigitalTicket, type FetchFunction, type FrameworkAdapter, HttpClient, type HttpClientConfig, HttpError, type HttpMethod, type HttpResponse, HttpTimeoutError, LANGUAGES, type LanguageCode, type LocaleTarget, type PathParams, PlatformBridge, type PlatformEventHandler, type PlatformEventMap, type PlatformEventType, type Product, type QueryRequestOptions, type RequestConfig, type RequestInterceptor, type RequestOptions, type ResponseInterceptor, type RichTextToken, SLOT_CATALOG, SLOT_CATALOG_V2, type SlotCatalogEntryV2, type SlotContextMap, type SlotContextOf, type SlotContextOverrides, type SlotContextPayload, type SlotIdV2, type TemplateEventMap, type TemplateEventType, type TemplateOptions, type TemplateSlot, type TicketCreateAfterPayload, type TranslateParams, type TranslationDict, type TranslationKey, type TranslationKeyRegistry, type TranslationPhase, VERSION, __resetElementRegistry__, announceElementName, configureBstageI18n, createWebComponent, dirNameToSlotId, fetchTranslations, getAdminEventsByDomain, getSlotsByTarget, getSlotsByTargetV2, interpolateTranslation, isSlotIdV2, lookupElementName, normalizeLanguage, observeLocale, parseRichText, pickTranslation, readLocale, resolveTranslationChain, slotIdToDirName };
|
package/dist/index.d.ts
CHANGED
|
@@ -771,6 +771,14 @@ declare const SLOT_CATALOG_V2: {
|
|
|
771
771
|
};
|
|
772
772
|
};
|
|
773
773
|
};
|
|
774
|
+
readonly 'admin.contents-list.list:before': {
|
|
775
|
+
readonly description: "콘텐츠 목록 — 목록 위";
|
|
776
|
+
readonly context: {};
|
|
777
|
+
};
|
|
778
|
+
readonly 'admin.community-board-list.list:before': {
|
|
779
|
+
readonly description: "커뮤니티 보드 목록 — 목록 위";
|
|
780
|
+
readonly context: {};
|
|
781
|
+
};
|
|
774
782
|
readonly 'user.contents-home.curation:after': {
|
|
775
783
|
readonly description: "콘텐츠 홈 — 큐레이션 섹션 아래";
|
|
776
784
|
readonly context: {};
|
|
@@ -1136,4 +1144,10 @@ declare function lookupElementName(url: string): string | undefined;
|
|
|
1136
1144
|
*/
|
|
1137
1145
|
declare function __resetElementRegistry__(): void;
|
|
1138
1146
|
|
|
1139
|
-
|
|
1147
|
+
/**
|
|
1148
|
+
* 번들에 심긴 core 버전. `BstageClient`가 모든 요청에 `x-bmf-sdk-version` 헤더로 실어
|
|
1149
|
+
* 게이트웨이 로그에서 어느 SDK 버전이 쓰이는지 볼 수 있게 한다.
|
|
1150
|
+
*/
|
|
1151
|
+
declare const VERSION: string;
|
|
1152
|
+
|
|
1153
|
+
export { ADMIN_EVENT_CATALOG, type AdminConnectPayload, type AdminDomainEventMap, type AdminDomainEventType, type BoardInfo, type BoardPostInfo, type BodyRequestOptions, BstageClient, type BstageConfig, type BstageI18nConfig, type Content, type ContentsSectionInfo, type CustomSlots, type CustomSlotsV2, DEFAULT_LANGUAGE, type DigitalTicket, type FetchFunction, type FrameworkAdapter, HttpClient, type HttpClientConfig, HttpError, type HttpMethod, type HttpResponse, HttpTimeoutError, LANGUAGES, type LanguageCode, type LocaleTarget, type PathParams, PlatformBridge, type PlatformEventHandler, type PlatformEventMap, type PlatformEventType, type Product, type QueryRequestOptions, type RequestConfig, type RequestInterceptor, type RequestOptions, type ResponseInterceptor, type RichTextToken, SLOT_CATALOG, SLOT_CATALOG_V2, type SlotCatalogEntryV2, type SlotContextMap, type SlotContextOf, type SlotContextOverrides, type SlotContextPayload, type SlotIdV2, type TemplateEventMap, type TemplateEventType, type TemplateOptions, type TemplateSlot, type TicketCreateAfterPayload, type TranslateParams, type TranslationDict, type TranslationKey, type TranslationKeyRegistry, type TranslationPhase, VERSION, __resetElementRegistry__, announceElementName, configureBstageI18n, createWebComponent, dirNameToSlotId, fetchTranslations, getAdminEventsByDomain, getSlotsByTarget, getSlotsByTargetV2, interpolateTranslation, isSlotIdV2, lookupElementName, normalizeLanguage, observeLocale, parseRichText, pickTranslation, readLocale, resolveTranslationChain, slotIdToDirName };
|
package/dist/index.js
CHANGED
|
@@ -118,6 +118,9 @@ var HttpTimeoutError = class extends Error {
|
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
+
// src/version.ts
|
|
122
|
+
var VERSION = "0.5.0";
|
|
123
|
+
|
|
121
124
|
// src/client/BstageClient.ts
|
|
122
125
|
function resolveBaseUrl() {
|
|
123
126
|
if (typeof globalThis.location !== "undefined") {
|
|
@@ -174,7 +177,9 @@ var BstageClient = class {
|
|
|
174
177
|
"X-BSTAGE-APP-ID": config.appId,
|
|
175
178
|
// 값이 없으면(UI 전용 템플릿의 빈 .env) 헤더 자체를 빼서 "undefined" 문자열이 실리지 않게 한다.
|
|
176
179
|
...appKey !== void 0 ? { "X-BSTAGE-APP-KEY": appKey } : {},
|
|
177
|
-
"X-BSTAGE-TENANT-ID": config.tenantId
|
|
180
|
+
"X-BSTAGE-TENANT-ID": config.tenantId,
|
|
181
|
+
// 어느 SDK(core) 버전이 호출하는지 게이트웨이 로그에서 볼 수 있게. 값은 버전 문자열만(패키지 이름 없음).
|
|
182
|
+
"x-bmf-sdk-version": VERSION
|
|
178
183
|
}
|
|
179
184
|
});
|
|
180
185
|
}
|
|
@@ -560,6 +565,16 @@ var SLOT_CATALOG_V2 = {
|
|
|
560
565
|
ticket: { type: "DigitalTicket", required: true }
|
|
561
566
|
}
|
|
562
567
|
},
|
|
568
|
+
// 어드민 — 콘텐츠 목록 PageTitleContainer 아래
|
|
569
|
+
"admin.contents-list.list:before": {
|
|
570
|
+
description: "\uCF58\uD150\uCE20 \uBAA9\uB85D \u2014 \uBAA9\uB85D \uC704",
|
|
571
|
+
context: {}
|
|
572
|
+
},
|
|
573
|
+
// 어드민 — 커뮤니티 보드 목록 PageTitleContainer 아래
|
|
574
|
+
"admin.community-board-list.list:before": {
|
|
575
|
+
description: "\uCEE4\uBBA4\uB2C8\uD2F0 \uBCF4\uB4DC \uBAA9\uB85D \u2014 \uBAA9\uB85D \uC704",
|
|
576
|
+
context: {}
|
|
577
|
+
},
|
|
563
578
|
// 유저 — 콘텐츠 홈 (결정-018에 1차 명시. curation은 신설, contents-section은 옛 contents.home.contents.before/after 이전)
|
|
564
579
|
"user.contents-home.curation:after": {
|
|
565
580
|
description: "\uCF58\uD150\uCE20 \uD648 \u2014 \uD050\uB808\uC774\uC158 \uC139\uC158 \uC544\uB798",
|
|
@@ -838,6 +853,7 @@ export {
|
|
|
838
853
|
PlatformBridge,
|
|
839
854
|
SLOT_CATALOG,
|
|
840
855
|
SLOT_CATALOG_V2,
|
|
856
|
+
VERSION,
|
|
841
857
|
__resetElementRegistry__,
|
|
842
858
|
announceElementName,
|
|
843
859
|
configureBstageI18n,
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# AI 툴킷
|
|
2
|
+
|
|
3
|
+
에이전트(Claude Code·Codex·Cursor 등)가 이 SDK로 일할 때 읽는 자산을 SDK가 소유하고 배포합니다.
|
|
4
|
+
|
|
5
|
+
## 1. 무엇인가
|
|
6
|
+
|
|
7
|
+
템플릿 프로젝트에서 에이전트에게 일을 시키려면 에이전트가 "이 SDK가 무엇이고 무엇을 하면 안 되는지"를
|
|
8
|
+
알아야 합니다. 그 지식을 프로젝트마다 손으로 적어 두면 SDK가 올라갈 때마다 낡습니다. AI 툴킷은 그
|
|
9
|
+
지식을 **SDK 쪽 자산**으로 두고, `bstage ai` 명령이 프로젝트에 설치·동기화합니다.
|
|
10
|
+
|
|
11
|
+
**MCP 서버가 아닙니다.** 프로세스도 네트워크 연결도 없습니다. 파일을 몇 개 쓰는 것이 전부이며,
|
|
12
|
+
에이전트는 그 파일을 평소처럼 읽습니다.
|
|
13
|
+
|
|
14
|
+
## 2. 설치되는 파일
|
|
15
|
+
|
|
16
|
+
| 파일 | 무엇인가 | 갱신 규칙 |
|
|
17
|
+
| --------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
18
|
+
| `AGENTS.md` | 프로젝트 규칙·SDK 사용 규약. 관리 영역 마커로 감싼 부분만 SDK 것 | 관리 영역만 덮어씁니다. 마커 바깥 자유 영역은 보존합니다 |
|
|
19
|
+
| `CLAUDE.md` | `AGENTS.md`를 가리키는 한 줄 포인터 | **없을 때만** 만듭니다. 있으면 내용과 무관하게 손대지 않습니다 |
|
|
20
|
+
| `.claude/skills/<이름>/SKILL.md` | 작업별 절차서. 아래 kind별 세트 | SDK 소유입니다. 스탬프 버전이 다르면 통째로 다시 씁니다 |
|
|
21
|
+
| `.husky/pre-commit`·`check-secrets.mjs` | 커밋 전 시크릿 가드 | 가드 스크립트는 덮어쓰고, 기존 훅이 있으면 실행 줄만 덧붙입니다 |
|
|
22
|
+
|
|
23
|
+
스킬 세트는 프로젝트 종류(kind)로 갈립니다.
|
|
24
|
+
|
|
25
|
+
| kind | 설치되는 스킬 |
|
|
26
|
+
| -------- | ---------------------------------------------------------------------------- |
|
|
27
|
+
| `sdk` | `bstage-template` · `bstage-migrate` · `bstage-onboarding` · `bstage-deploy` |
|
|
28
|
+
| `liquid` | `bstage-liquid` · `bstage-migrate` · `bstage-onboarding` · `bstage-deploy` |
|
|
29
|
+
|
|
30
|
+
kind는 레포의 **파일 구조**로 판정합니다. `public/{user|admin}/{이름}/template.liquid`가 하나 이상이면
|
|
31
|
+
liquid, liquid 파일이 없고 `src/pages|slots/**/template.tsx`가 있거나 SDK 패키지를 의존하면 sdk입니다.
|
|
32
|
+
템플릿 파일이 **양쪽 다** 있으면 `mixed`이고, 포털이 빌드하지 못하므로 명령이 종료 코드 2로 멈춥니다.
|
|
33
|
+
의존성만으로는 mixed가 되지 않습니다 — liquid 파일이 있으면 `@bstage-sdk/cli`를 의존해도
|
|
34
|
+
liquid입니다(liquid 스캐폴드도 저작 도구로 CLI를 씁니다).
|
|
35
|
+
|
|
36
|
+
## 3. 어느 도구가 무엇을 읽나
|
|
37
|
+
|
|
38
|
+
- **`AGENTS.md`** — Codex·Cursor·Copilot 등 대부분의 코딩 에이전트가 공통으로 읽는 관례 파일입니다.
|
|
39
|
+
- **`.claude/skills/`** — Claude Code가 자동으로 인식합니다.
|
|
40
|
+
|
|
41
|
+
다른 도구 전용 규칙 파일(예: `.cursor/rules`)이 필요하면, 내용을 복제하지 말고 `AGENTS.md`를 가리키는
|
|
42
|
+
한 줄짜리 파일을 직접 두세요. 복제본은 SDK가 갱신하지 않으므로 반드시 낡습니다.
|
|
43
|
+
|
|
44
|
+
## 4. 명령
|
|
45
|
+
|
|
46
|
+
| 명령 | 하는 일 |
|
|
47
|
+
| ------------------- | --------------------------------------------------------------------------- |
|
|
48
|
+
| `bstage ai install` | 없는 파일은 만들고 낡은 파일은 갱신 + pre-commit 시크릿 가드 설치 |
|
|
49
|
+
| `bstage ai update` | **이미 있는** 파일만 갱신. 없는 파일은 만들지 않고 가드도 건드리지 않습니다 |
|
|
50
|
+
| `bstage ai doctor` | 상태만 진단(파일 수정 없음). `--json` 지원 |
|
|
51
|
+
|
|
52
|
+
- 새 프로젝트는 `bstage init`이 이미 설치해 둡니다 — `install`을 다시 돌릴 필요가 없습니다.
|
|
53
|
+
- SDK를 올린 뒤에는 `update`를 돌립니다. "최신화"를 부른 사람이 새 파일이 생기는 것을 기대하지 않기
|
|
54
|
+
때문에 `update`는 생성을 하지 않습니다. 없는 파일이 있으면 `install`로 안내합니다.
|
|
55
|
+
- 셋 다 `--dir <경로>`(기본 `.claude/skills`)와 `--kind sdk|liquid`를 받습니다. `--kind`는 자동 판정이
|
|
56
|
+
실패할 때의 보조 수단이며, 판정 결과와 어긋나면 덮어쓰지 않고 멈춥니다.
|
|
57
|
+
- `bstage skills install`은 `bstage ai install`의 **deprecated 별칭**입니다. 경고를 출력하고 같은 일을
|
|
58
|
+
하며 다음 릴리즈에서 제거됩니다.
|
|
59
|
+
- `bstage doctor`는 진단에 더해 **SDK 소유 스킬만** 자동 동기화합니다. `package.json`과 `.husky`는
|
|
60
|
+
건드리지 않으므로, pre-commit 시크릿 가드는 `bstage ai install`로 설치하세요.
|
|
61
|
+
|
|
62
|
+
`doctor`의 종료 코드는 전부 최신이면 0, 하나라도 어긋나면 2입니다. 상태 값은 `ok` · `stale` · `missing` ·
|
|
63
|
+
`extra`이며, **`extra`(지금 kind에 속하지 않는 SDK 스킬이 남아 있음)는 경고일 뿐 종료 코드에 영향을 주지
|
|
64
|
+
않습니다.** 설치가 남의 파일을 지우지 않는 것이 설계라, 실패로 치면 사람이 손으로 지울 때까지 CI가 계속
|
|
65
|
+
빨간불이 되기 때문입니다.
|
|
66
|
+
|
|
67
|
+
## 5. 처음 시작하는 법
|
|
68
|
+
|
|
69
|
+
프로젝트가 아직 없다면 에이전트에게 이렇게 말하는 것으로 충분합니다.
|
|
70
|
+
|
|
71
|
+
> 이 프로젝트를 처음 만드는데, 포털에 올리는 것까지 도와줘.
|
|
72
|
+
|
|
73
|
+
`bstage-onboarding` 스킬이 받아서 진행합니다.
|
|
74
|
+
|
|
75
|
+
1. 결정 세 가지(유저·어드민 / React·liquid / 배포 환경)를 한 번에 묻고 나머지 확인은 에이전트가 합니다.
|
|
76
|
+
2. 프로젝트 생성 → 로컬 실행 → 커밋·push → 포털 화면에서 레포 연결·첫 빌드·페이지(배치) 만들기 →
|
|
77
|
+
`bstage login`·`bstage link` → 첫 배포(`bstage deploy`) 순서로 단계마다 **성공 판정 기준을 먼저 말하고**
|
|
78
|
+
확인합니다.
|
|
79
|
+
3. 되돌리기 어려운 일(원격 push·배포·게시 전환)은 실행 전에 보여 주고 확인을 받습니다.
|
|
80
|
+
|
|
81
|
+
배치(어느 페이지·어느 자리에 템플릿을 켤지)를 만들거나 지우는 일은 **포털 화면에서만** 합니다. CLI도
|
|
82
|
+
에이전트도 하지 않습니다.
|
|
83
|
+
|
|
84
|
+
## 6. 갱신 규칙
|
|
85
|
+
|
|
86
|
+
- **스킬 파일은 SDK 소유입니다.** 손으로 고쳐도 다음 갱신에 덮어쓰입니다. 프로젝트 고유 규칙은
|
|
87
|
+
`AGENTS.md` 자유 영역에 적으세요.
|
|
88
|
+
- **`AGENTS.md`는 관리 영역만 덮습니다.** 마커(`BSTAGE:MANAGED:START`~`END`) 바깥은 그대로 둡니다.
|
|
89
|
+
관리 영역 안의 프로젝트 정체성(스페이스·프로젝트명)은 기존 파일 값을 우선합니다.
|
|
90
|
+
- **마커가 없는 레거시 `AGENTS.md`는 자동으로 건드리지 않습니다.** 어디까지가 SDK 것인지 알 수 없어
|
|
91
|
+
덮어쓰면 사용자 내용을 잃기 때문입니다. `bstage-migrate` 스킬이 실제 파일을 읽고 reconcile합니다.
|
|
92
|
+
- `CLAUDE.md`는 포인터일 뿐이고 그 뒤는 사용자 것이므로, 있으면 내용 불문 손대지 않습니다.
|
|
93
|
+
|
|
94
|
+
## 7. 예정
|
|
95
|
+
|
|
96
|
+
포털 측 MCP 서버가 생기면 `bstage ai install`이 그 클라이언트 설정도 함께 놓을 자리입니다.
|
package/docs/BUILD_SYSTEM.md
CHANGED
|
@@ -149,9 +149,44 @@ dist/
|
|
|
149
149
|
|
|
150
150
|
---
|
|
151
151
|
|
|
152
|
+
## 5. liquid 레포
|
|
153
|
+
|
|
154
|
+
`public/{user|admin}/{이름}/template.liquid` 로 만드는 레포는 **빌드 단계가 없습니다.** 서버(플랫폼)가 liquid를 렌더하므로 번들링할 것이 없고, 포털이 push된 커밋의 파일을 그대로 패키징합니다.
|
|
155
|
+
|
|
156
|
+
### `bstage build`는 검증만 합니다
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
bstage build # 산출물 없음 — 문법·규약 검증만
|
|
160
|
+
bstage build --json # { "kind": "liquid", "issues": [...] } 한 덩어리
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
종료코드는 오류가 하나라도 있으면 `2`, 없으면 `0`입니다. `dist/`는 만들어지지 않습니다.
|
|
164
|
+
|
|
165
|
+
| 수준 | 검사 |
|
|
166
|
+
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
167
|
+
| error | `template.liquid` 문법 오류(줄 번호 표시) · `data.json` JSON 파싱 실패 · 폴더 이름 규칙(`^[a-z][a-z0-9-]*$`) 위반 · sdk 템플릿과 혼재 · liquid 템플릿 0개 |
|
|
168
|
+
| warn | `public/{user\|admin}/{이름}/` 밖이거나 깊이가 다른 `template.liquid`(포털이 무시) · `layout.json` 존재(포털이 지움) · 폴더에 `template.liquid`가 아닌 이름만 있음 |
|
|
169
|
+
|
|
170
|
+
같은 검사를 `bstage doctor`도 "liquid 검증" 절에서 보여 줍니다(`--json`의 `liquid.issues`).
|
|
171
|
+
|
|
172
|
+
### 포털의 패키징 규약
|
|
173
|
+
|
|
174
|
+
- `public/user/` · `public/admin/` 아래 **한 단계** 폴더만 템플릿으로 인정합니다 — `public/user/events/summer/template.liquid` 는 무시됩니다.
|
|
175
|
+
- 그 폴더를 통째로 복사한 뒤 `data.json` · `layout.json` 을 지웁니다. 두 파일은 로컬 프리뷰와 관리도구의 것이라 배포에 나가지 않습니다 — 배포에 필요한 값을 거기 두지 마세요.
|
|
176
|
+
- 그 밖의 위치에 있는 `template.liquid` 는 무시합니다.
|
|
177
|
+
- sdk(`src/pages` · `src/slots` 의 `template.tsx`)와 섞인 레포는 지원하지 않습니다. `bstage build` · `bstage deploy` 가 포털에 가기 전에 막습니다.
|
|
178
|
+
- 배치는 페이지(PAGE)만 가능합니다. 위젯(SLOT) 자리에 liquid 산출물을 붙이면 포털이 400을 냅니다 — `bstage deploy` 가 빌드를 만들기 전에 사전조건 오류로 끊습니다.
|
|
179
|
+
|
|
180
|
+
로컬에서 화면을 보려면 `bstage dev`를 씁니다(같은 폴더의 `data.json`으로 렌더). 자세한 내용은 [DEV_SERVER.md](./DEV_SERVER.md)를 참고하세요.
|
|
181
|
+
|
|
182
|
+
liquid 레포를 만드는 것부터 배포까지의 전체 흐름은 [LIQUID.md](./LIQUID.md)에 정리돼 있습니다.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
152
186
|
## 관련 문서
|
|
153
187
|
|
|
154
188
|
- [GETTING_STARTED.md](./GETTING_STARTED.md) — 빠른 시작 가이드 (빌드 및 배포 포함)
|
|
155
189
|
- [SDK_ARCHITECTURE.md](./SDK_ARCHITECTURE.md) — 단일 번들 출력 설계 원칙
|
|
156
190
|
- [DEV_SERVER.md](./DEV_SERVER.md) — 로컬 개발 서버 (빌드 없이 개발)
|
|
157
191
|
- [API_REFERENCE.md](./API_REFERENCE.md) — Host 패키지의 loadTemplate 시그니처
|
|
192
|
+
- [LIQUID.md](./LIQUID.md) — liquid 템플릿 레포 가이드 (5절의 검증·패키징 규약 포함)
|
package/docs/DEV_SERVER.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
**왜 프록시가 필요한가:** b.stage gateway는 인증 토큰을 httpOnly 쿠키로 관리합니다. 프로덕션에서는 동일 도메인이므로 쿠키가 자동 첨부되지만, localhost에서는 도메인이 달라 쿠키가 전달되지 않습니다. 인증 프록시가 이 문제를 해결합니다.
|
|
8
8
|
|
|
9
|
+
> **liquid 템플릿 레포는 다릅니다.** `public/{user|admin}/{이름}/template.liquid`로 만든 레포에서는 같은 명령이 Vite·인증 프록시 없이 liquidjs 프리뷰를 띄웁니다 — [7절](#7-liquid-프리뷰-liquid-레포) 참조. 1~6절은 React(SDK) 레포 이야기입니다.
|
|
10
|
+
|
|
9
11
|
---
|
|
10
12
|
|
|
11
13
|
## 2. 아키텍처
|
|
@@ -314,7 +316,7 @@ packages/cli/src/
|
|
|
314
316
|
index.ts ← CLI 명령어 등록 (build, dev, init)
|
|
315
317
|
commands/
|
|
316
318
|
build.ts ← 빌드 명령어
|
|
317
|
-
dev.ts ← Vite 서버
|
|
319
|
+
dev.ts ← 레포 종류 판정 후 Vite 서버 또는 liquid 프리뷰 기동
|
|
318
320
|
init.ts ← 프로젝트 스캐폴딩
|
|
319
321
|
dev/
|
|
320
322
|
devVitePlugin.ts ← Vite 플러그인 (프록시, 쿠키, 로그인, URL 치환, 토큰 리프레시, ESM resolve)
|
|
@@ -323,8 +325,60 @@ packages/cli/src/
|
|
|
323
325
|
preset.ts ← Vite 빌드 설정 프리셋 + bstageDevPlugin export
|
|
324
326
|
metaPlugin.ts ← 빌드 시 createTemplate 메타데이터 추출
|
|
325
327
|
registerPlugin.ts ← 빌드/dev 시 WC 등록 코드 자동 주입
|
|
328
|
+
liquid/ ← liquid 레포 프리뷰 (7절). Vite·프록시 없음
|
|
329
|
+
server.ts ← node:http 서버 + 정적 파일 + 파일 감시(SSE 새로고침)
|
|
330
|
+
routes.ts ← 경로 → 화면 판정 (순수 함수)
|
|
331
|
+
render.ts ← liquidjs 엔진 + data.json 렌더
|
|
332
|
+
templates.ts ← 템플릿 목록 (규약 밖 파일 표시 포함)
|
|
333
|
+
pages.ts ← 목록·오류 페이지 HTML + content-type 표
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 7. liquid 프리뷰 (liquid 레포)
|
|
339
|
+
|
|
340
|
+
`public/{user|admin}/{이름}/template.liquid`로 만든 **liquid 템플릿 레포**에서는 `bstage dev`가 Vite 대신 Node `http` + [liquidjs](https://liquidjs.com/) 기반 프리뷰 서버를 띄웁니다. 레포 종류 판정은 포털 빌더와 같은 규칙(파일 구조)으로 하며, 따로 옵션을 주지 않아도 자동으로 갈립니다.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
bstage dev # liquid 레포면 프리뷰, React(SDK) 레포면 기존 Vite 서버
|
|
344
|
+
bstage dev -p 5180 # 포트 지정
|
|
326
345
|
```
|
|
327
346
|
|
|
347
|
+
### 무엇을 하나
|
|
348
|
+
|
|
349
|
+
| 경로 | 내용 |
|
|
350
|
+
| ------------------- | ------------------------------------------------------------------------------ |
|
|
351
|
+
| `/` | user·admin 목록으로 가는 첫 화면 |
|
|
352
|
+
| `/user` · `/admin` | 그 surface의 템플릿 목록 |
|
|
353
|
+
| `/{surface}/{이름}` | `template.liquid`를 같은 폴더의 `data.json`으로 렌더한 결과 |
|
|
354
|
+
| 그 밖의 경로 | `public/` 아래에 실제로 있는 파일이면 그대로 제공 (확장자로 content-type 결정) |
|
|
355
|
+
|
|
356
|
+
- **데이터는 `data.json`에서** 옵니다. 파일이 없으면 빈 컨텍스트로 렌더되므로, 값이 비어도 화면이 깨지지 않게 `{{ title | default: '...' }}`처럼 기본값을 두는 편이 좋습니다.
|
|
357
|
+
- 플랫폼과 같은 이름의 **`parse_json` 필터**가 등록돼 있습니다 — `{% assign parsed = payload | parse_json %}`.
|
|
358
|
+
- **자동 새로고침**: `public/` 아래 파일이 바뀌면 열려 있는 화면이 스스로 다시 로드됩니다. 재귀 파일 감시를 지원하지 않는 환경에서는 안내 한 줄을 남기고 감시 없이 동작합니다(직접 새로고침하면 됩니다).
|
|
359
|
+
|
|
360
|
+
### 무엇을 안 하나
|
|
361
|
+
|
|
362
|
+
- **인증 프록시도 API 프록시도 없습니다.** 1~4절의 `/__auth__/*`·`/gw/*` 흐름은 liquid 프리뷰에 존재하지 않습니다.
|
|
363
|
+
- **`--phase`를 쓰지 않습니다.** 옵션을 줘도 안내 한 줄과 함께 무시합니다.
|
|
364
|
+
- **실데이터가 아닙니다.** 실제 값은 플랫폼이 서버에서 넣습니다. `data.json`은 로컬 미리보기용 샘플이며 배포에는 나가지 않습니다.
|
|
365
|
+
- 번들링·HMR·React가 없습니다. 파일을 고치고 화면이 다시 로드되는 것이 전부입니다.
|
|
366
|
+
|
|
367
|
+
### 렌더가 실패하면 — 오류 페이지
|
|
368
|
+
|
|
369
|
+
`data.json`이 깨졌거나 템플릿 문법이 틀리면 브라우저 기본 오류 화면 대신 **파일 경로·줄 번호·메시지를 담은 진단 페이지**가 뜹니다. 상태코드는 500이 아니라 200입니다 — 이 화면이 주 진단 수단이라 가려지면 안 되기 때문입니다. 파일을 고치면 자동 새로고침으로 곧바로 복구됩니다.
|
|
370
|
+
|
|
371
|
+
### 규약 밖 파일 경고
|
|
372
|
+
|
|
373
|
+
포털 빌더는 `public/{user|admin}/{이름}/template.liquid`, **정확히 이 깊이만** 인정합니다. 목록 화면은 규약을 벗어난 `template.liquid`도 함께 보여 주되 "포털이 무시합니다"라고 표시합니다. 프리뷰에서는 보이는데 배포하면 안 나오는 상황을 배포 전에 알아차리기 위한 것입니다.
|
|
374
|
+
|
|
375
|
+
- `public/user/events/summer/template.liquid` — 한 단계 더 깊어 무시됩니다(프리뷰는 렌더해 줍니다).
|
|
376
|
+
- `public/shared/hero/template.liquid` — user·admin 밖이라 무시됩니다(경로만 경고로 표시).
|
|
377
|
+
|
|
378
|
+
### 한 레포에 섞여 있으면
|
|
379
|
+
|
|
380
|
+
liquid 템플릿과 React 템플릿(`src/**/template.tsx`)이 함께 있으면 포털 빌더가 빌드하지 못합니다. `bstage dev`는 이 경우 서버를 띄우지 않고 종료코드 **2**로 안내합니다.
|
|
381
|
+
|
|
328
382
|
---
|
|
329
383
|
|
|
330
384
|
## 관련 문서
|
|
@@ -333,3 +387,4 @@ packages/cli/src/
|
|
|
333
387
|
- [SDK_ARCHITECTURE.md](./SDK_ARCHITECTURE.md) — BstageClient의 base URL 결정과 fetch 주입 설계
|
|
334
388
|
- [BUILD_SYSTEM.md](./BUILD_SYSTEM.md) — 프로덕션 빌드 파이프라인
|
|
335
389
|
- [INIT.md](./INIT.md) — `bstage init`이 생성하는 vite.config.ts와 .env 설정
|
|
390
|
+
- [LIQUID.md](./LIQUID.md) — liquid 템플릿 레포 가이드 (프리뷰 포함 전체 흐름)
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -23,6 +23,23 @@ b.stage 3rd-party 템플릿은 **Web Component** 기반으로 동작합니다. S
|
|
|
23
23
|
|
|
24
24
|
설계 원리와 내부 동작은 [SDK_ARCHITECTURE.md](./SDK_ARCHITECTURE.md)를 참고하세요.
|
|
25
25
|
|
|
26
|
+
### 두 가지 커스텀 방식
|
|
27
|
+
|
|
28
|
+
| 방식 | 무엇을 쓰나 |
|
|
29
|
+
| -------- | ---------------------------------------------------------------------------------- |
|
|
30
|
+
| `sdk` | React 컴포넌트를 Web Component로 빌드해 페이지·위젯 자리에 올립니다 (이 문서 전체) |
|
|
31
|
+
| `liquid` | 플랫폼이 서버에서 데이터를 넣어 렌더하는 템플릿을 페이지 자리에만 올립니다 |
|
|
32
|
+
|
|
33
|
+
이 문서는 `sdk` 방식을 기준으로 씁니다. liquid 방식은 [LIQUID.md](./LIQUID.md)에 따로 정리돼 있습니다. 한 레포에 두 방식을 섞으면 포털 빌더가 패키징하지 못합니다.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## AI와 함께 시작하기
|
|
38
|
+
|
|
39
|
+
이 문서를 직접 따라가는 대신 코딩 에이전트에게 맡길 수 있습니다. SDK가 에이전트용 자산을 함께 배포하기 때문입니다 — 프로젝트 규칙과 SDK 사용 규약을 담은 `AGENTS.md`, 작업별 절차서인 `.claude/skills/*/SKILL.md`(온보딩·템플릿 작성·마이그레이션·배포), 그리고 커밋 전에 시크릿을 걸러 내는 pre-commit 가드입니다. `bstage init`이 새 프로젝트에 이미 깔아 두고, 기존 프로젝트는 `npx @bstage-sdk/cli@latest ai install`로 설치합니다. SDK를 올린 뒤에는 `bstage ai update`로 최신화하고, 상태만 보려면 `bstage ai doctor`를 씁니다.
|
|
40
|
+
|
|
41
|
+
프로젝트가 아직 없다면 에이전트에게 "이 프로젝트를 처음 만드는데, 포털에 올리는 것까지 도와줘"라고 하면 온보딩 스킬이 생성부터 첫 배포까지 단계별로 안내합니다. 이미 프로젝트가 있다면 "이 슬롯에 들어갈 위젯을 만들어 줘"처럼 목적만 말해도 됩니다 — 에이전트가 `AGENTS.md`와 설치된 문서를 읽고 규약에 맞춰 작성합니다. 무엇이 설치되고 어떻게 갱신되는지는 [AI_TOOLKIT.md](./AI_TOOLKIT.md)를 참고하세요.
|
|
42
|
+
|
|
26
43
|
---
|
|
27
44
|
|
|
28
45
|
## 1. 프로젝트 생성
|
|
@@ -50,6 +67,8 @@ API 키는 나중에 설정해도 됩니다. "API 키가 있으신가요?" 질
|
|
|
50
67
|
> npx @bstage-sdk/cli@latest init --yes --space bmf --phase dev
|
|
51
68
|
> ```
|
|
52
69
|
|
|
70
|
+
React 대신 liquid 템플릿으로 만들려면 `--kind liquid`를 붙입니다(대화형에서는 "어떤 방식으로 만들까요?" 질문). 생성되는 구조와 규약, 로컬 미리보기·검증·배포는 [LIQUID.md](./LIQUID.md)를 참고하세요.
|
|
71
|
+
|
|
53
72
|
---
|
|
54
73
|
|
|
55
74
|
## 2. 로컬 개발 서버 실행
|
|
@@ -270,6 +289,8 @@ export const client = new BstageClient({
|
|
|
270
289
|
- 로컬 개발에서는 **dev 서버**가 `.env`의 `VITE_BSTAGE_PHASE`(→ `vite.config.ts`의 `bstageDevPlugin`)를 보고 해당 phase 게이트웨이로 프록시합니다. 이 phase는 **dev 서버 설정**이지 `BstageClient`의 옵션이 아닙니다.
|
|
271
290
|
- 특정 게이트웨이를 직접 지정하려면 `baseUrl` 옵션을 사용합니다(예: 플랫폼 임베드가 아닌 standalone 앱).
|
|
272
291
|
|
|
292
|
+
`BstageClient`는 위 인증 헤더와 함께 모든 요청에 `x-bmf-sdk-version` 헤더(템플릿을 빌드할 때 설치돼 있던 core 버전)를 자동으로 붙입니다. 별도 설정은 없고, 게이트웨이 쪽에서 어느 SDK 버전이 쓰이는지 볼 때 사용됩니다.
|
|
293
|
+
|
|
273
294
|
### 6.2 로그인
|
|
274
295
|
|
|
275
296
|
인증이 필요한 API를 호출하려면 먼저 로그인합니다.
|
|
@@ -612,6 +633,8 @@ CI에서는 `BSTAGE_TOKEN`·`BSTAGE_PORTAL_URL`(또는 `VITE_BSTAGE_PHASE`)·`BS
|
|
|
612
633
|
|
|
613
634
|
로컬에서 산출물을 확인하고 싶으면 `npx bstage build`를 실행합니다. 페이지는 `dist/{경로}/template.js`, 위젯은 `dist/{슬롯 id}/template.js`로 나옵니다.
|
|
614
635
|
|
|
636
|
+
배포 절차를 에이전트에게 맡기려면 `bstage-deploy` 스킬을 쓰세요([AI_TOOLKIT.md](./AI_TOOLKIT.md)).
|
|
637
|
+
|
|
615
638
|
### 9.1 인증 값은 빌드 시점에 번들로 들어갑니다
|
|
616
639
|
|
|
617
640
|
`.env`의 `VITE_BSTAGE_*` 값은 **빌드할 때 번들 안에 문자열로 박힙니다.** 배포한 뒤에 `.env`를 고쳐도 반영되지 않습니다. 값을 바꿨으면 반드시 다시 빌드해야 합니다.
|
|
@@ -629,14 +652,14 @@ CI에서는 `BSTAGE_TOKEN`·`BSTAGE_PORTAL_URL`(또는 `VITE_BSTAGE_PHASE`)·`BS
|
|
|
629
652
|
|
|
630
653
|
아래 항목은 **SDK가 감지할 수 없습니다.** 키 형식(`bsa_`/`bsp_`)은 ID·시크릿 구분일 뿐 어느 환경에서 발급했는지를 담지 않습니다. 나머지는 BE·콘솔 설정이라 코드에 흔적이 없습니다. 리얼 배포 후 아래 에러를 만나면 이 표로 되짚으세요.
|
|
631
654
|
|
|
632
|
-
| 증상 | 원인 | 조치
|
|
633
|
-
| ----------------------- | ---------------------------------------- |
|
|
655
|
+
| 증상 | 원인 | 조치 | 소관 |
|
|
656
|
+
| ----------------------- | ---------------------------------------- | -------------------------------------------- | ------------ |
|
|
634
657
|
| `401 Unauthorized` | 다른 환경(QA 등)의 키로 배포 / 키 미발급 | 배포할 환경에서 발급한 appId·appKey인지 확인 | 파트너 콘솔 |
|
|
635
|
-
| `403 Forbidden` | Space ID가 프로젝트에 미등록 | BE에 Space ID 등록 요청
|
|
636
|
-
| `400 MISSING_ORIGIN` | 키의 Allowed Origins에 배포 도메인 없음 | 배포 도메인을 키 설정에 추가 요청
|
|
637
|
-
| 템플릿이 화면에 안 뜸 | 콘솔 "커스텀 템플릿 사용" 토글이 꺼짐 | 콘솔에서 토글 확인
|
|
638
|
-
| 배포 자체가 안 됨 | 데브포털 접근·리얼 배포 권한 없음 | 권한 요청
|
|
639
|
-
| 임베드(iframe)가 차단됨 | CSP `frame-ancestors`에 도메인 없음 | 도메인 추가 요청
|
|
658
|
+
| `403 Forbidden` | Space ID가 프로젝트에 미등록 | BE에 Space ID 등록 요청 | BE |
|
|
659
|
+
| `400 MISSING_ORIGIN` | 키의 Allowed Origins에 배포 도메인 없음 | 배포 도메인을 키 설정에 추가 요청 | BE (키 설정) |
|
|
660
|
+
| 템플릿이 화면에 안 뜸 | 콘솔 "커스텀 템플릿 사용" 토글이 꺼짐 | 콘솔에서 토글 확인 | 콘솔 |
|
|
661
|
+
| 배포 자체가 안 됨 | 데브포털 접근·리얼 배포 권한 없음 | 권한 요청 | DevOps |
|
|
662
|
+
| 임베드(iframe)가 차단됨 | CSP `frame-ancestors`에 도메인 없음 | 도메인 추가 요청 | BE·보안 |
|
|
640
663
|
|
|
641
664
|
**QA에서 됐다고 리얼에서 되지 않습니다.** 위 항목은 전부 환경마다 따로 설정됩니다. 하나씩 막힐 때마다 요청·대기가 반복되면 며칠이 걸립니다. 처음 리얼로 나갈 때는 위 표의 BE·콘솔 항목을 **한 번에 모아서** 요청하세요.
|
|
642
665
|
|
|
@@ -674,5 +697,6 @@ CI에서는 `BSTAGE_TOKEN`·`BSTAGE_PORTAL_URL`(또는 `VITE_BSTAGE_PHASE`)·`BS
|
|
|
674
697
|
- [DEV_SERVER.md](./DEV_SERVER.md) — 로컬 개발 서버의 인증 프록시 동작 방식
|
|
675
698
|
- [BUILD_SYSTEM.md](./BUILD_SYSTEM.md) — 빌드 파이프라인과 산출물 구조
|
|
676
699
|
- [INIT.md](./INIT.md) — `bstage init` 커맨드 상세
|
|
700
|
+
- [LIQUID.md](./LIQUID.md) — liquid 템플릿 레포 가이드(생성·미리보기·검증·배포)
|
|
677
701
|
- [SLOT_SYSTEM.md](./SLOT_SYSTEM.md) — Extension Slot 시스템
|
|
678
702
|
- [SLOT_CATALOG.md](./SLOT_CATALOG.md) — 슬롯 목록, 이벤트 인터페이스, resourceId 의미
|
package/docs/INIT.md
CHANGED
|
@@ -23,15 +23,17 @@ Node.js v20 이상과 npm(또는 pnpm)만 있으면 됩니다. SDK 패키지는
|
|
|
23
23
|
|
|
24
24
|
`@clack/prompts` 기반의 인터랙티브 UI를 제공합니다.
|
|
25
25
|
|
|
26
|
-
| 순서 | 질문
|
|
27
|
-
| ---- |
|
|
28
|
-
| 1 |
|
|
29
|
-
| 2 |
|
|
30
|
-
| 3 |
|
|
31
|
-
| 4 |
|
|
32
|
-
| 5 |
|
|
33
|
-
| 6 |
|
|
34
|
-
| 7 |
|
|
26
|
+
| 순서 | 질문 | 필수 | 비고 |
|
|
27
|
+
| ---- | -------------------------- | :--: | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| 1 | 첫 템플릿의 플랫폼(target) | O | `user` / `admin` — 아래 [§4.1](#41-첫-템플릿의-target---target) |
|
|
29
|
+
| 2 | 방식(kind) | O | `sdk`(React 컴포넌트) / `liquid`(liquid 템플릿) — 아래 [§4.2](#42-liquid-프로젝트---kind-liquid) |
|
|
30
|
+
| 3 | 템플릿을 적용할 Space ID | O | 레포명 `{space}-custom-templates-{phase}`, BstageClient의 `tenantId`로 사용 |
|
|
31
|
+
| 4 | 배포 환경(Phase) | O | `dev` / `qa` / `real` / `sandbox` — 레포명에 포함되며 `.env`의 `VITE_BSTAGE_PHASE`로 주입 |
|
|
32
|
+
| 5 | 첫 번째 템플릿 이름 | O | sdk는 `src/pages/{name}/template.tsx`(Custom Element 스펙상 하이픈 필수), liquid는 `public/{target}/{name}/template.liquid`(소문자·숫자·하이픈 한 단어) |
|
|
33
|
+
| 6 | 패키지 매니저 | O | `npm` 또는 `pnpm` |
|
|
34
|
+
| 7 | API 키 설정 여부 | - | sdk에서만 질문합니다 — "없어도 시작할 수 있어요" |
|
|
35
|
+
| 8 | APP-ID | - | API 키가 있는 경우만 |
|
|
36
|
+
| 9 | APP KEY | - | API 키가 있는 경우만 |
|
|
35
37
|
|
|
36
38
|
### 레포명 결정 로직
|
|
37
39
|
|
|
@@ -45,24 +47,33 @@ npx @bstage-sdk/cli@latest init --yes --space bmf --phase dev
|
|
|
45
47
|
|
|
46
48
|
`--yes` 플래그를 사용하면 프롬프트 없이 실행됩니다. `--space`는 필수입니다.
|
|
47
49
|
|
|
48
|
-
| 옵션 | 기본값
|
|
49
|
-
| ------------ |
|
|
50
|
-
| `--space` | (필수)
|
|
51
|
-
| `--target` | `user`
|
|
52
|
-
| `--
|
|
53
|
-
| `--
|
|
54
|
-
| `--
|
|
50
|
+
| 옵션 | 기본값 |
|
|
51
|
+
| ------------ | ------------------------------------ |
|
|
52
|
+
| `--space` | (필수) |
|
|
53
|
+
| `--target` | `user` |
|
|
54
|
+
| `--kind` | `sdk` |
|
|
55
|
+
| `--phase` | `sandbox` |
|
|
56
|
+
| `--template` | sdk `{space}-hello` / liquid `hello` |
|
|
57
|
+
| `--pm` | `npm` |
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
liquid 프로젝트를 만들려면 `--kind liquid`를 붙입니다.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx @bstage-sdk/cli@latest init --yes --kind liquid --space demo --target user
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`--target`은 **첫 템플릿**이 유저용인지 어드민용인지만 정합니다(대화형에서는 첫 질문). 자세한 내용은 아래 [§4.1](#41-첫-템플릿의-target---target)을 참고하세요. `--kind`는 프로젝트 전체를 가릅니다 — [§4.2](#42-liquid-프로젝트---kind-liquid)를 참고하세요.
|
|
57
66
|
|
|
58
67
|
---
|
|
59
68
|
|
|
60
69
|
## 4. 생성되는 파일 구조
|
|
61
70
|
|
|
71
|
+
`--kind sdk`(기본)일 때의 구조입니다. liquid 프로젝트는 [§4.2](#42-liquid-프로젝트---kind-liquid)를 참고하세요.
|
|
72
|
+
|
|
62
73
|
```
|
|
63
74
|
{space}-custom-templates-{phase}/
|
|
64
|
-
├── CLAUDE.md #
|
|
65
|
-
├── AGENTS.md
|
|
75
|
+
├── CLAUDE.md # AGENTS.md를 가리키는 포인터 (파일이 없을 때만 생성)
|
|
76
|
+
├── AGENTS.md # 프로젝트 규칙·SDK 규약 (관리 영역은 bstage ai가 갱신)
|
|
66
77
|
├── README.md
|
|
67
78
|
├── package.json
|
|
68
79
|
├── tsconfig.json
|
|
@@ -74,6 +85,12 @@ npx @bstage-sdk/cli@latest init --yes --space bmf --phase dev
|
|
|
74
85
|
├── index.html
|
|
75
86
|
├── .gitignore
|
|
76
87
|
├── eslint.config.js
|
|
88
|
+
├── .claude/
|
|
89
|
+
│ └── skills/ # 에이전트용 스킬 (SDK 소유 — bstage ai가 갱신)
|
|
90
|
+
│ ├── bstage-onboarding/SKILL.md # 처음부터 첫 배포까지 안내
|
|
91
|
+
│ ├── bstage-template/SKILL.md # 템플릿 작성 가이드
|
|
92
|
+
│ ├── bstage-deploy/SKILL.md # 배포·롤백·게시
|
|
93
|
+
│ └── bstage-migrate/SKILL.md # SDK 버전업 마이그레이션
|
|
77
94
|
└── src/
|
|
78
95
|
├── main.tsx # App 마운트만
|
|
79
96
|
├── App.tsx # import.meta.glob 기반 라우팅 + picker UI
|
|
@@ -90,6 +107,8 @@ npx @bstage-sdk/cli@latest init --yes --space bmf --phase dev
|
|
|
90
107
|
|
|
91
108
|
> init은 `.github/workflows/` 파일을 생성하지 않습니다. CI 워크플로우 구성은 관리도구의 책임입니다.
|
|
92
109
|
|
|
110
|
+
`AGENTS.md`·`CLAUDE.md`·`.claude/skills/`는 init이 한 번 깔고, 이후에는 `bstage ai install|update|doctor`가 관리합니다. 자세한 내용은 [AI_TOOLKIT.md](./AI_TOOLKIT.md)를 참고하세요.
|
|
111
|
+
|
|
93
112
|
---
|
|
94
113
|
|
|
95
114
|
## 4.1 첫 템플릿의 target (`--target`)
|
|
@@ -106,6 +125,43 @@ npx @bstage-sdk/cli@latest init --yes --space my-space --phase dev --target admi
|
|
|
106
125
|
|
|
107
126
|
---
|
|
108
127
|
|
|
128
|
+
## 4.2 liquid 프로젝트 (`--kind liquid`)
|
|
129
|
+
|
|
130
|
+
`--kind liquid`는 React 대신 **liquid 템플릿**을 작성하는 프로젝트를 만듭니다. 템플릿을 번들링하지 않고 플랫폼이 서버에서 데이터를 넣어 렌더하므로, 스캐폴드에 Vite·TypeScript·ESLint·`.env`가 들어가지 않습니다. 의존성은 저작 도구인 `@bstage-sdk/cli` 하나뿐입니다.
|
|
131
|
+
|
|
132
|
+
작성·미리보기·검증·배포까지의 전체 흐름은 [LIQUID.md](./LIQUID.md)에 있습니다. 이 절은 init이 만드는 파일만 다룹니다.
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
{space}-custom-templates-{phase}/
|
|
136
|
+
├── CLAUDE.md # AGENTS.md를 가리키는 포인터
|
|
137
|
+
├── AGENTS.md # liquid 규약 (관리 영역은 bstage ai가 갱신)
|
|
138
|
+
├── README.md
|
|
139
|
+
├── package.json # bstage.kind = "liquid", 의존성은 cli 하나
|
|
140
|
+
├── .gitignore
|
|
141
|
+
├── .husky/
|
|
142
|
+
│ ├── pre-commit # 시크릿 가드
|
|
143
|
+
│ └── check-secrets.mjs
|
|
144
|
+
├── .claude/
|
|
145
|
+
│ └── skills/ # 에이전트용 스킬 (SDK 소유 — bstage ai가 갱신)
|
|
146
|
+
│ ├── bstage-onboarding/SKILL.md
|
|
147
|
+
│ ├── bstage-liquid/SKILL.md # liquid 작성 가이드
|
|
148
|
+
│ ├── bstage-deploy/SKILL.md
|
|
149
|
+
│ └── bstage-migrate/SKILL.md
|
|
150
|
+
└── public/
|
|
151
|
+
└── {user|admin}/
|
|
152
|
+
└── {name}/
|
|
153
|
+
├── template.liquid # 템플릿 본문 (파일명 고정)
|
|
154
|
+
└── data.json # 로컬 미리보기용 샘플 (배포에는 나가지 않음)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- **경로 깊이가 규약입니다** — `public/{user|admin}/{name}/template.liquid` 자리에 있는 파일만 인식됩니다. 깊이가 다르거나 `user`/`admin` 밖에 있으면 **조용히 무시됩니다**(빌드는 성공하는데 화면에 나오지 않습니다).
|
|
158
|
+
- `{name}`은 소문자로 시작하고 소문자·숫자·하이픈만 쓰는 **한 단어**입니다(`hello`, `landing-v1`). 폴더 하나가 페이지 하나입니다.
|
|
159
|
+
- `data.json`은 로컬 미리보기용 샘플일 뿐이고 배포 패키징에서 제외됩니다. 배포에 필요한 설정을 여기에 담지 마세요.
|
|
160
|
+
- 한 레포에 liquid와 React 템플릿(`src/**/template.tsx`)을 **섞지 마세요** — 빌드되지 않습니다.
|
|
161
|
+
- liquid 템플릿은 **페이지 배치만** 가능합니다(슬롯 위젯은 sdk 방식만 지원).
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
109
165
|
## 5. Phase 관리
|
|
110
166
|
|
|
111
167
|
init에서 선택한 Phase 값이 두 위치에 기록됩니다:
|
|
@@ -165,3 +221,4 @@ init 완료 시 다음이 자동으로 실행됩니다:
|
|
|
165
221
|
- [GETTING_STARTED.md](./GETTING_STARTED.md) — 빠른 시작 가이드
|
|
166
222
|
- [DEV_SERVER.md](./DEV_SERVER.md) — 생성된 프로젝트의 로컬 개발 서버 동작 방식
|
|
167
223
|
- [BUILD_SYSTEM.md](./BUILD_SYSTEM.md) — 빌드 파이프라인과 산출물 경로 규칙
|
|
224
|
+
- [LIQUID.md](./LIQUID.md) — liquid 템플릿 레포 가이드 (`--kind liquid`로 만든 프로젝트)
|
package/docs/LIQUID.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# liquid 템플릿 가이드
|
|
2
|
+
|
|
3
|
+
`.liquid` 템플릿으로 b.stage 페이지를 만드는 방법입니다. React(sdk) 방식은 [GETTING_STARTED.md](./GETTING_STARTED.md)를 참고하세요.
|
|
4
|
+
|
|
5
|
+
## 1. liquid 방식이란
|
|
6
|
+
|
|
7
|
+
플랫폼(서버)이 데이터를 넣어 렌더하는 [liquidjs](https://liquidjs.com/) 템플릿입니다. 브라우저에서 번들을 실행하지 않으므로 **빌드 산출물이 없습니다** — 포털이 push된 커밋의 템플릿 파일을 그대로 패키징합니다.
|
|
8
|
+
|
|
9
|
+
| 항목 | sdk | liquid |
|
|
10
|
+
| ----------- | ------------------------------------------- | ----------------------------------------- |
|
|
11
|
+
| 작성 대상 | React 컴포넌트 (`template.tsx`) | `.liquid` 템플릿 (`template.liquid`) |
|
|
12
|
+
| 렌더 시점 | 브라우저 (Web Component) | 서버 (플랫폼이 데이터를 넣어 렌더) |
|
|
13
|
+
| 배치 가능 | 페이지(PAGE) · 위젯(SLOT) | 페이지(PAGE)만 |
|
|
14
|
+
| 로컬 산출물 | `dist/{경로}/template.js` | 없음 (검증만) |
|
|
15
|
+
| 의존성 | core · react · design + Vite · 타입스크립트 | 저작 도구 `@bstage-sdk/cli` 하나 |
|
|
16
|
+
|
|
17
|
+
- **페이지 단위로만** 배치합니다. 슬롯(위젯) 자리에는 쓸 수 없습니다 — `bstage deploy`가 위젯 배치를 발견하면 빌드를 만들기 전에 사전조건 오류(종료 코드 2)로 끊습니다.
|
|
18
|
+
- **한 레포에 sdk와 섞지 않습니다.** `src/**/template.tsx`와 liquid 템플릿이 함께 있으면 포털 빌더가 패키징하지 못합니다.
|
|
19
|
+
|
|
20
|
+
## 2. 시작
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @bstage-sdk/cli@latest init --kind liquid
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
대화형에서는 첫 질문("어떤 방식으로 만들까요?")에서 `liquid`를 고릅니다. 비인터랙티브는 `--yes --kind liquid --space demo --target user` 형태입니다. 생성되는 파일 목록은 [INIT.md §4.2](./INIT.md#42-liquid-프로젝트---kind-liquid)에 있습니다.
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
public/
|
|
30
|
+
└── user/ # 또는 admin — 첫 템플릿의 target
|
|
31
|
+
└── hello/
|
|
32
|
+
├── template.liquid # 템플릿 본문 (파일명 고정)
|
|
33
|
+
└── data.json # 로컬 미리보기용 샘플 값 (배포에 나가지 않음)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **이름 규칙**: 소문자로 시작하고 소문자·숫자·하이픈만 씁니다(`^[a-z][a-z0-9-]*$`). CDN 경로 세그먼트가 되므로 대문자를 쓰면 대소문자를 구분하지 않는 파일시스템에서 로컬과 배포가 갈립니다.
|
|
37
|
+
- **한 세그먼트**여야 합니다. `public/user/events/summer/`처럼 한 단계 더 깊으면 포털이 조용히 무시합니다.
|
|
38
|
+
- `data.json`은 로컬 전용입니다. 실제 값은 플랫폼이 서버에서 넣습니다. **키 이름은 플랫폼 계약을 따라야 합니다** — 유저 화면 최상위는 `lounges`·`stories`·`contentSections`·`latestContents`·`shopCategories` 다섯 개입니다. 다른 이름을 쓰면 프리뷰에서만 그려지고 배포하면 빕니다. 각 항목의 필드는 계약이 아니라 모양을 보기 위한 예시이므로 실제 렌더 결과로 확인하세요. 어드민 화면이 받는 값은 확인되지 않았습니다.
|
|
39
|
+
- 스캐폴드는 Vite·TypeScript·ESLint·`.env`를 만들지 않습니다. 번들링도 타입 검사도 하지 않기 때문입니다.
|
|
40
|
+
|
|
41
|
+
## 3. 로컬 미리보기 — `bstage dev`
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm run dev # = bstage dev
|
|
45
|
+
bstage dev -p 3000 # 포트 지정 (기본 5173)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
레포 종류는 파일 구조로 자동 판정하므로 옵션을 따로 주지 않습니다. liquid 레포면 Vite 대신 Node `http` + liquidjs 프리뷰가 뜨고, 항상 루프백(`127.0.0.1`)에만 바인딩합니다.
|
|
49
|
+
|
|
50
|
+
| 경로 | 화면 |
|
|
51
|
+
| ------------------- | -------------------------------------------- |
|
|
52
|
+
| `/` | user · admin 템플릿 개수와 규약 밖 파일 목록 |
|
|
53
|
+
| `/user` | user 템플릿 목록 |
|
|
54
|
+
| `/admin` | admin 템플릿 목록 |
|
|
55
|
+
| `/{surface}/{이름}` | 같은 폴더의 `data.json`으로 렌더한 결과 |
|
|
56
|
+
| 그 밖의 경로 | `public/` 아래 정적 파일 (없으면 404) |
|
|
57
|
+
|
|
58
|
+
- 파일을 고치면 **자동으로 새로고침**됩니다(프리뷰가 넣는 SSE 스크립트 — 배포물과 무관합니다).
|
|
59
|
+
- 렌더가 실패하면 파일·줄 번호·메시지를 보여 주는 **오류 페이지**가 200으로 뜹니다. 고치는 즉시 리로드로 복구됩니다.
|
|
60
|
+
- 규약을 벗어난 `template.liquid`도 목록에 보여 주되 "포털이 무시합니다"라고 표시합니다.
|
|
61
|
+
|
|
62
|
+
**프리뷰에 없는 것**: 인증 프록시 · API 프록시 · phase · 실데이터. `--phase`를 줘도 무시한다는 안내만 출력합니다. 상세는 [DEV_SERVER.md §7](./DEV_SERVER.md#7-liquid-프리뷰-liquid-레포)을 참고하세요.
|
|
63
|
+
|
|
64
|
+
## 4. 검증 — `bstage build` · `bstage doctor`
|
|
65
|
+
|
|
66
|
+
liquid 레포에는 빌드 단계가 없으므로 `bstage build`는 **검증만** 합니다. 오류가 하나라도 있으면 종료 코드 2입니다.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm run build # = bstage build
|
|
70
|
+
bstage build --json # { "kind": "liquid", "issues": [...] } 한 덩어리
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| 등급 | 검사 |
|
|
74
|
+
| ----- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
75
|
+
| error | `template.liquid` 문법 오류(줄 번호 표시) · `data.json` JSON 파싱 실패 · 폴더 이름 규칙 위반 · sdk 템플릿과 혼재 · liquid 템플릿 0개 |
|
|
76
|
+
| warn | 규약 밖 위치의 `template.liquid`(포털이 무시) · `layout.json` 존재(포털이 지움) · 폴더에 `template.liquid`가 아닌 파일만 있음 |
|
|
77
|
+
|
|
78
|
+
같은 결과를 `bstage doctor`가 "liquid 검증" 절에서 보여 줍니다(`--json`에서는 `liquid.issues`). doctor의 liquid 표는 sdk와 다릅니다 — 기대 파일은 템플릿 루트(`public/user` 또는 `public/admin`)와 `AGENTS.md`, 기대 스크립트는 `dev`·`build`이고, 권장 의존성 절은 나오지 않습니다. 버전 표도 `@bstage-sdk/cli` 한 줄뿐입니다.
|
|
79
|
+
|
|
80
|
+
## 5. 배포
|
|
81
|
+
|
|
82
|
+
포털이 push된 커밋의 `public/{user|admin}/{이름}/`을 **그대로 패키징합니다**(`data.json`·`layout.json`은 제외 — 배치는 관리도구가 소유합니다). 로컬 산출물은 올라가지 않으므로 커밋·push가 먼저입니다.
|
|
83
|
+
|
|
84
|
+
1. **첫 배포는 포털 화면에서** 합니다 — 레포 연결 → 빌드 → 페이지 배치 생성.
|
|
85
|
+
2. 이후에는 터미널에서 `bstage deploy`(빌드 → 라이브 적용) · `bstage rollback`(이전 성공 빌드로 되돌리기) · `bstage publish on|off`(게시 토글)를 씁니다. 로그인·링크·종료 코드 등 공통 절차는 sdk와 같습니다 — [GETTING_STARTED.md §9](./GETTING_STARTED.md#9-배포)를 참고하세요.
|
|
86
|
+
|
|
87
|
+
> liquid 레포에는 `.env`가 없어 `bstage login`·`bstage link`가 phase를 읽을 곳이 없습니다. sandbox가 아닌 포털이면 두 명령 모두에 `--phase <phase>`를 주세요(생략하면 sandbox). 3. `bstage list`는 최근 빌드의 산출물 종류(`sdk`·`liquid`) 열을 함께 보여 줍니다. 옛 빌드에는 이 값이 없어 `-`로 나옵니다.
|
|
88
|
+
|
|
89
|
+
## 6. 이미지·영상 넣기
|
|
90
|
+
|
|
91
|
+
**포털 화면의 스테이지 > 미디어에 올리고, 받은 URL을 템플릿에 절대 주소로 넣습니다.** 이미지와 영상만 올릴 수 있고, 허용 형식·용량 한도는 업로드할 때 화면이 알려 줍니다.
|
|
92
|
+
|
|
93
|
+
레포에 파일을 두고 상대 경로로 참조하면 **배포 후 깨집니다.** 포털은 템플릿 폴더를 그대로 복사하지만, 렌더된 HTML이 스페이스 도메인 페이지 안으로 들어가므로 상대 경로는 그 도메인 기준으로 풀리고 산출물이 놓인 주소를 가리키지 않습니다.
|
|
94
|
+
|
|
95
|
+
로컬 프리뷰는 이 점에서 배포와 **반대로** 동작합니다. 프리뷰는 템플릿 폴더의 파일을 함께 서빙하므로 상대 경로 이미지가 잘 보입니다. 프리뷰에서 보였다는 것을 배포에서도 되리라는 근거로 삼지 마세요.
|
|
96
|
+
|
|
97
|
+
## 7. liquidjs 문법 요점
|
|
98
|
+
|
|
99
|
+
```liquid
|
|
100
|
+
{{ lounges.first.name }} 변수 출력 (없는 값은 빈 문자열)
|
|
101
|
+
{{ lounges.first.name | default: '라운지' }} 기본값
|
|
102
|
+
{{ section.title | upcase }} · {{ latestContents | size }} 필터
|
|
103
|
+
{% if contentSections.size > 0 %} ... {% else %} ... {% endif %}
|
|
104
|
+
{% for section in contentSections %}{{ section.title }}{% endfor %}
|
|
105
|
+
{% assign count = latestContents | size %}
|
|
106
|
+
{% comment %} 렌더되지 않는 주석 {% endcomment %}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- 없는 값은 오류가 아니라 **빈 문자열**로 렌더됩니다(플랫폼과 같은 설정). 화면이 비어 보이면 값 이름을 먼저 의심하세요.
|
|
110
|
+
- **`{% render %}`·`{% include %}`(파셜)는 배포에서 동작하지 않습니다.** 배포 뷰어의 엔진은 레포의 파일을 찾지 못해 그 자리를 빈 문자열로 렌더합니다. 로컬 프리뷰(탐색 루트 `public/`)에서만 동작하므로, 프리뷰에서 보였다는 것이 근거가 되지 않습니다. 템플릿은 `template.liquid` **한 파일**에 담고, `bstage build`는 파셜 태그를 경고로 짚어 줍니다.
|
|
111
|
+
- 전체 문법은 [liquidjs 공식 문서](https://liquidjs.com/)를 참고하세요.
|
|
112
|
+
|
|
113
|
+
## 8. 함정
|
|
114
|
+
|
|
115
|
+
- **sdk와 섞지 않습니다.** 섞이면 `bstage dev`·`build`·`deploy`가 종료 코드 2로 멈추고 포털 빌드도 실패합니다.
|
|
116
|
+
- **깊이가 규약입니다.** `public/{user|admin}/{이름}/template.liquid`, 정확히 이 자리만 인정됩니다. 어긋나면 빌드는 성공하는데 화면에 나오지 않습니다.
|
|
117
|
+
- **페이지(PAGE) 배치만** 됩니다. 위젯 자리에 붙이면 포털이 400을 냅니다.
|
|
118
|
+
- **`data.json`·`layout.json`은 로컬 전용입니다.** 포털이 패키징에서 지우므로 배포에 필요한 값을 여기에 담지 마세요.
|
|
119
|
+
- **파일명은 `template.liquid` 고정입니다.** `index.html`처럼 다른 이름이면 포털이 그 폴더를 템플릿으로 보지 않습니다.
|
|
120
|
+
- **파셜(`{% render %}`·`{% include %}`)을 쓰지 않습니다.** 배포에서 빈 문자열이 됩니다 — 7절을 참고하세요.
|
|
121
|
+
- **에셋을 레포에 두고 상대 경로로 참조하지 않습니다.** 배포 후 깨집니다 — 6절을 참고하세요. 로컬 프리뷰에서는 보이므로 프리뷰 결과가 근거가 되지 않습니다.
|
|
122
|
+
- **플랫폼이 넣는 값의 이름을 지어내지 않습니다.** 유저 화면 최상위는 `lounges`·`stories`·`contentSections`·`latestContents`·`shopCategories` 다섯 개뿐이고, 그 밖의 이름은 빈 문자열이 됩니다(어드민 화면이 받는 값은 확인되지 않았습니다). `data.json` 샘플도 같은 이름을 써야 프리뷰가 배포와 같은 모양이 됩니다.
|
package/docs/MIGRATION.md
CHANGED
|
@@ -50,13 +50,171 @@
|
|
|
50
50
|
> **정렬**: 릴리즈 **시점 최신이 위**. 패키지가 독립 버전이라 헤더 숫자만으로는 시간순 정렬이 되지 않으므로 릴리즈 순서를 기준으로 한다.
|
|
51
51
|
|
|
52
52
|
---
|
|
53
|
+
## → cli 0.5.0
|
|
54
|
+
|
|
55
|
+
### liquid 에셋은 포털 미디어에 올린다 — 레포 상대 경로는 배포 후 깨진다 — `판단` · `필수`
|
|
56
|
+
|
|
57
|
+
**영향**
|
|
58
|
+
|
|
59
|
+
- liquid 템플릿 레포 전부. 이미지·영상을 레포에 두고 상대 경로(`images/logo.png`·`/user/home/images/logo.png`)로 참조하는 템플릿이 해당한다.
|
|
60
|
+
- 감지: 배포한 화면에서 이미지가 뜨지 않는다(요청이 404). **로컬 프리뷰에서는 정상으로 보이므로 프리뷰로는 감지되지 않는다.**
|
|
61
|
+
|
|
62
|
+
**변경 내용**
|
|
63
|
+
|
|
64
|
+
포털은 템플릿 폴더를 그대로 복사하지만, 렌더된 HTML이 스페이스 도메인 페이지 안으로 들어간다. 그래서 상대 경로는 그 도메인 기준으로 풀리고 산출물이 놓인 주소를 가리키지 않는다. 옛 가이드에 있던 "`public`에 두고 상대 경로로 참조" 안내는 신규 포털에서 맞지 않는다.
|
|
65
|
+
|
|
66
|
+
지금 방법은 포털 화면의 스테이지 > 미디어에 파일을 올리고, 받은 URL을 템플릿에 절대 주소로 넣는 것이다. 이미지와 영상만 올릴 수 있고, 허용 형식·용량 한도는 업로드할 때 화면이 알려 준다.
|
|
67
|
+
|
|
68
|
+
`bstage ai install`·`update`가 놓는 `AGENTS.md`·`bstage-liquid` 스킬도 같은 내용으로 바뀌었다(관리 영역 v12).
|
|
69
|
+
|
|
70
|
+
**적용**
|
|
71
|
+
|
|
72
|
+
1. (판단) 템플릿에서 상대 경로로 참조하는 에셋을 찾는다.
|
|
73
|
+
2. (판단) 해당 파일을 포털 미디어에 올리고 받은 URL로 참조를 바꾼다.
|
|
74
|
+
3. (자동) `npx @bstage-sdk/cli@latest ai update`로 스킬·`AGENTS.md`를 최신 안내로 갱신한다.
|
|
75
|
+
|
|
76
|
+
### liquid `data.json` 샘플 키를 플랫폼 계약에 맞춘다 — `판단` · `선택`
|
|
77
|
+
|
|
78
|
+
**영향**
|
|
79
|
+
|
|
80
|
+
- liquid 템플릿 레포. `data.json`이 `title`·`heading`·`description` 같은 임의 이름을 쓰고 있으면 해당한다.
|
|
81
|
+
- 감지: 로컬 프리뷰에서는 값이 그려지는데 배포하면 그 자리가 빈다.
|
|
82
|
+
|
|
83
|
+
**변경 내용**
|
|
84
|
+
|
|
85
|
+
플랫폼이 유저 화면 템플릿에 넣는 최상위 값은 `lounges` · `stories` · `contentSections` · `latestContents` · `shopCategories` 다섯 개다. 그 밖의 이름은 빈 문자열이 된다. 스캐폴드가 만드는 `data.json`과 첫 `template.liquid`가 이 이름을 쓰도록 바뀌었다. 각 항목의 필드는 계약이 아니라 모양을 보기 위한 예시이므로 실제 렌더 결과로 확인한다. 어드민 화면이 받는 값은 확인되지 않았다.
|
|
86
|
+
|
|
87
|
+
**적용**
|
|
88
|
+
|
|
89
|
+
1. (판단) `data.json`의 최상위 키를 위 다섯 개 중 쓰는 것으로 바꾸고, 템플릿의 변수 이름도 함께 맞춘다.
|
|
90
|
+
2. (자동) 새로 만드는 프로젝트는 `bstage init --kind liquid`가 이미 맞춰 준다.
|
|
91
|
+
|
|
92
|
+
### `bstage docs`가 문서를 못 찾으면 종료 코드 2 — `자동` · `선택`
|
|
93
|
+
|
|
94
|
+
**영향**
|
|
95
|
+
|
|
96
|
+
- `bstage docs`의 종료 코드를 확인하는 스크립트·CI. SDK 의존이 없는 레포(예: `.liquid` 파일만 둔 레포)에서 이 경로를 탄다.
|
|
97
|
+
|
|
98
|
+
**변경 내용**
|
|
99
|
+
|
|
100
|
+
예전에는 "문서를 찾을 수 없습니다"를 출력하고도 0으로 끝나서, 종료 코드로 갈래를 잡는 호출자가 문서를 읽은 것으로 착각했다. 이제 2로 끝나고, liquid 레포에서는 `bstage-liquid` 스킬을 보라는 안내가 함께 나온다.
|
|
101
|
+
|
|
102
|
+
**적용**
|
|
103
|
+
|
|
104
|
+
1. (자동) 문서 유무를 그냥 확인만 하던 자리라면 종료 코드 2를 허용하도록 고친다.
|
|
105
|
+
|
|
106
|
+
### `bstage skills install` → `bstage ai install` — `자동` · `선택`
|
|
107
|
+
|
|
108
|
+
**영향**
|
|
109
|
+
|
|
110
|
+
- 스크립트·문서·CI에 `bstage skills install`을 적어 둔 프로젝트. 명령 자체는 아직 동작하므로 당장 깨지지는 않는다.
|
|
111
|
+
- 감지: 레포에서 `skills install` 문자열을 찾는다. 실행하면 `bstage ai install`로 바뀌었다는 경고가 뜬다.
|
|
112
|
+
|
|
113
|
+
**변경 내용**
|
|
114
|
+
|
|
115
|
+
스킬만이 아니라 `AGENTS.md`·`CLAUDE.md`·pre-commit 시크릿 가드까지 다루게 되어 이름이 맞지 않게 됐다. `bstage ai install`(설치·갱신) · `bstage ai update`(있는 파일만 갱신) · `bstage ai doctor`(진단, `--json`, 종료코드 0·2)로 나뉘었고, `bstage skills install`은 deprecated 별칭으로 남아 경고 후 `ai install`을 그대로 수행한다. 별칭은 **다음 릴리즈에서 제거된다.** 설치되는 콘텐츠는 새 패키지 `@bstage-sdk/ai-toolkit`이 들고 있고, cli가 그 패키지를 의존하므로 따로 설치할 필요는 없다.
|
|
116
|
+
|
|
117
|
+
이 명령들은 **프로젝트 종류(`sdk`·`liquid`)를 판정해 그 종류의 자산만 설치한다.** 판정은 레포의 파일 구조로 한다(포털 빌더와 같은 규칙). 템플릿 파일이 아직 없어 판정이 안 되는 레포에서는 종료 코드 2로 끝나므로 `bstage ai install --kind sdk` 또는 `--kind liquid`로 지정한다. 두 종류가 한 레포에 섞여 있으면 포털이 빌드하지 못하므로 역시 종료 코드 2로 멈춘다.
|
|
118
|
+
|
|
119
|
+
자세한 내용은 `AI_TOOLKIT.md`를 참고한다.
|
|
120
|
+
|
|
121
|
+
**적용**
|
|
122
|
+
|
|
123
|
+
1. (자동) 스크립트·문서의 `bstage skills install`을 `bstage ai install`로 바꾼다.
|
|
124
|
+
2. (자동) CI에서 최신 여부만 확인하려면 `bstage ai doctor --json`을 쓴다 — 전부 최신이면 0, 하나라도 어긋나면 2로 끝난다.
|
|
125
|
+
3. (판단) 판정이 실패하는 빈 레포에서만 `--kind`를 붙인다. 판정 결과와 다른 값을 주면 덮어쓰지 않고 멈추므로, 어긋나면 옵션을 빼고 다시 실행한다.
|
|
126
|
+
|
|
127
|
+
### AGENTS.md 관리 영역 갱신 · 스킬 2종 추가(`bstage-onboarding`·`bstage-deploy`) — `자동` · `선택`
|
|
128
|
+
|
|
129
|
+
**영향**
|
|
130
|
+
|
|
131
|
+
- `bstage init`으로 만든 모든 프로젝트. 관리 영역이 낡았거나 새 스킬이 없으면 해당한다.
|
|
132
|
+
- 감지: `bstage ai doctor`가 해당 항목을 `stale`·`missing`으로 보고한다(`bstage doctor`의 에이전트 스킬 절에도 나온다).
|
|
133
|
+
|
|
134
|
+
**변경 내용**
|
|
135
|
+
|
|
136
|
+
- `AGENTS.md`의 SDK 관리 영역에 배포 절이 추가되고, 프로젝트 종류(`sdk`·`liquid`)에 따라 본문이 갈린다. 마커 바깥 자유 영역은 그대로 보존된다.
|
|
137
|
+
- 스킬이 둘 늘었다. `bstage-onboarding`(빈손에서 첫 배포까지 안내) · `bstage-deploy`(배포·롤백·게시). 기존 `bstage-template`·`bstage-migrate`는 그대로다.
|
|
138
|
+
- 스캐폴드 `package.json`에 `bstage.kind`가 기록된다. **기존 프로젝트는 없어도 동작한다** — 종류 판정은 파일 구조로 하고 이 값은 읽지 않는다. 추가는 선택이다.
|
|
139
|
+
- `bstage doctor --json`에 `skillsSkipped` 필드가 생겼다(두 종류가 섞여 스킬 검사를 건너뛴 경우 `true`). 기존 필드는 그대로이므로 비파괴적 추가다.
|
|
140
|
+
|
|
141
|
+
**적용**
|
|
142
|
+
|
|
143
|
+
1. (자동) `npx @bstage-sdk/cli@latest ai install` — 없는 스킬을 만들고 관리 영역을 갱신한다. 이미 있는 것만 최신화하려면 `ai update`.
|
|
144
|
+
2. (판단) `AGENTS.md`에 관리 영역 마커가 없는 레거시 파일이면 자동 갱신 대상이 아니다. 명령이 레거시로 표시하고 건드리지 않으므로 `bstage-migrate` 스킬로 기존 내용과 reconcile한다.
|
|
145
|
+
3. (자동) 다른 종류의 스킬이 남아 있으면 `extra`로 보고되지만 지우지 않는다. 필요 없으면 직접 삭제한다 — 종료 코드에는 영향이 없다.
|
|
146
|
+
|
|
147
|
+
### liquid 템플릿 레포 지원 — `자동` · `선택`
|
|
148
|
+
|
|
149
|
+
**영향**
|
|
150
|
+
|
|
151
|
+
- liquid 템플릿(`public/{user|admin}/{이름}/template.liquid`)으로 포털에 배포하는 레포. 기존 SDK 프로젝트에는 영향이 없다.
|
|
152
|
+
- 감지: 레포에 위 경로의 `template.liquid`가 있으면 cli가 liquid 레포로 판정한다.
|
|
153
|
+
|
|
154
|
+
**변경 내용**
|
|
155
|
+
|
|
156
|
+
- `bstage init --kind liquid`가 liquid 레포를 스캐폴드한다. React·Vite 없이 cli 하나만 의존한다.
|
|
157
|
+
- `bstage dev`가 liquid 레포에서는 liquidjs 로컬 프리뷰를 띄운다(템플릿 목록·데이터 렌더·정적 파일·자동 리로드). 루프백에만 바인딩하고 템플릿 디렉터리 밖을 가리키는 경로는 차단한다. 인증 프록시는 없다.
|
|
158
|
+
- `bstage build`는 liquid 레포에서 **검증만** 한다(파스 오류·규약 밖 파일·폴더명·데이터 파일). 오류면 종료 코드 2. 포털이 파일을 그대로 패키징하므로 빌드 산출물은 만들지 않는다.
|
|
159
|
+
- `bstage doctor`에 liquid 진단 절이 생겼고, 배포 명령(`deploy`·`list`·`rollback`·`publish`)은 종류와 무관하게 같은 방식으로 동작한다.
|
|
160
|
+
|
|
161
|
+
**적용**
|
|
162
|
+
|
|
163
|
+
1. (자동) 기존 liquid 레포에서 `npx @bstage-sdk/cli@latest ai install`을 실행하면 liquid용 스킬과 `AGENTS.md`가 놓인다.
|
|
164
|
+
2. (자동) 로컬 확인은 `bstage dev`, 배포 전 검증은 `bstage build`.
|
|
165
|
+
3. (판단) SDK 템플릿과 liquid 템플릿을 한 레포에 섞지 않는다 — 포털 빌더가 빌드하지 못하고 cli도 종료 코드 2로 멈춘다.
|
|
166
|
+
|
|
167
|
+
자세한 내용은 `LIQUID.md`를 참고한다.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### liquid 파셜(`{% render %}`·`{% include %}`)은 배포에서 동작하지 않는다 — `판단` · `필수`
|
|
172
|
+
|
|
173
|
+
**영향**
|
|
174
|
+
|
|
175
|
+
- liquid 템플릿 레포 중 템플릿을 파셜로 쪼갠 곳. 옛 문서가 "탐색 루트는 `public/`"이라고만 적어 프리뷰에서 되는 것을 배포에서도 되는 것으로 읽게 했다.
|
|
176
|
+
- 감지: `bstage build`가 파셜 태그를 경고로 짚는다. 배포 화면에서는 그 자리가 비어 보인다.
|
|
177
|
+
|
|
178
|
+
**변경 내용**
|
|
179
|
+
|
|
180
|
+
배포 뷰어의 엔진은 레포의 파일을 찾지 못해 파셜 자리를 빈 문자열로 렌더한다. 문서·`bstage-liquid` 스킬·`AGENTS.md` 관리 영역이 그렇게 안내한다.
|
|
181
|
+
|
|
182
|
+
**적용**
|
|
183
|
+
|
|
184
|
+
1. (판단) 파셜 내용을 `template.liquid`에 인라인으로 옮긴다.
|
|
185
|
+
2. (자동) `npx @bstage-sdk/cli@latest ai update`로 스킬·`AGENTS.md`를 갱신한다.
|
|
186
|
+
|
|
187
|
+
### pre-commit 시크릿 가드 보강 — `자동` · `선택`
|
|
188
|
+
|
|
189
|
+
가드(`.husky/check-secrets.mjs`)가 포털 CLI 토큰 형태를 잡고, 크기 때문에 읽지 못한 파일을 검사 없이 통과시키던 것을 막으며(읽지 못하면 차단), NUL 바이트가 든 파일도 훑고, `.env.{phase}`의 SECRET·TOKEN·PASSWORD 계열 키에 실제 값이 있으면 차단한다. 알림에 값의 앞부분을 드러내지 않는다(길이만). `.env.example` 계열은 값 검사에서 빠지지만 키·토큰 검사는 그대로 받는다. `npx @bstage-sdk/cli@latest ai install`이 갱신한다.
|
|
190
|
+
|
|
191
|
+
### pre-commit 가드 줄이 정본 자리·정본 형태로 재배치된다 — `자동` · `선택`
|
|
192
|
+
|
|
193
|
+
가드 줄은 **shebang 다음 첫 줄에 `node .husky/check-secrets.mjs || exit 1`** 형태일 때만 그대로 둔다. 기존 훅의 가드 줄이 함수 본문·조건 블록 안에 있거나, 상태를 전파하지 않거나, `exit` 뒤에 있으면 `bstage ai install`·`update`가 그 줄을 지우고 정본 자리에 다시 넣는다(훅의 나머지 내용은 보존). 셸 제어 흐름을 정규식으로 판정할 수 없어 "애매하면 다시 넣는" 쪽으로 정했다.
|
|
194
|
+
|
|
195
|
+
### SDK 소유 파일 쓰기가 링크를 따라가지 않는다 — `자동` · `선택`
|
|
196
|
+
|
|
197
|
+
`ai install`·`update`가 파일을 쓸 때 대상과 경로 중간 디렉터리를 realpath로 검사하고, 여는 순간 심볼릭 링크를 거부하며, 하드 링크가 걸렸거나 일반 파일이 아니면(디렉터리·FIFO) 손대지 않는다. 레포에 커밋된 링크로 프로젝트 밖 파일이 바뀌는 경로를 막는다. 기존 파일의 느슨한 권한도 함께 바로잡는다.
|
|
198
|
+
|
|
199
|
+
### 손수정한 스킬은 `.bak`으로 남긴다 — `자동` · `선택`
|
|
200
|
+
|
|
201
|
+
`bstage ai install`·`update`가 손으로 고친 `SKILL.md`를 SDK 본문으로 되돌릴 때 기존 본문을 `SKILL.md.bak`에 남긴다. 프로젝트 고유 규칙은 `AGENTS.md` 자유 영역에 옮긴 뒤 `.bak`은 지운다.
|
|
202
|
+
|
|
203
|
+
### `bstage build`가 빌드할 것을 못 찾으면 종료 코드 2 — `자동` · `선택`
|
|
204
|
+
|
|
205
|
+
`src/pages`·`src/slots`에 `template.tsx`가 없거나 `.liquid`가 전부 규약 밖 자리에 있을 때 1로 끝나던 것을 2(사전조건 미충족)로 바꿨다 — liquid 검증 실패·`deploy` 사전점검과 같은 부류다. 종료 코드로 갈래를 잡는 스크립트만 영향받는다. `bstage dev`도 규약 밖 `.liquid`를 시작 전에 경고한다.
|
|
206
|
+
|
|
207
|
+
### 프로젝트에 고정된 옛 CLI로 실행하면 하향임을 알린다 — `판단` · `선택`
|
|
208
|
+
|
|
209
|
+
옛 `bstage`로 `doctor`·`ai install`을 돌리면 새 CLI가 놓은 스킬·가드를 "구버전/수정됨"으로만 표시하고 옛 본문으로 덮었다. 이제 설치본의 버전이 더 높으면 **하향**임을 분명히 알리고 최신 CLI로 다시 실행하라고 안내한다. 덮어쓰기 자체는 막지 않는다 — 파일 안의 버전 표기는 누구나 적을 수 있어, 그것으로 덮어쓰기를 막으면 높은 버전을 자칭한 임의 본문이 가드·스킬 자리에 영구히 남는다. 진단·갱신은 항상 `npx @bstage-sdk/cli@latest`로 실행한다.
|
|
210
|
+
|
|
53
211
|
## → core 0.3.0 · cli 0.3.0
|
|
54
212
|
|
|
55
213
|
### 앱 키 이름 정리(`appSecret` → `appKey`, `VITE_BSTAGE_APP_SECRET` → `VITE_BSTAGE_APP_KEY`) — `판단` · `선택`
|
|
56
214
|
|
|
57
215
|
**영향**
|
|
58
216
|
|
|
59
|
-
- **기존 프로젝트가 반드시 할 일은 없다.** `appSecret`·`VITE_BSTAGE_APP_SECRET`은 deprecated 별칭으로 그대로 동작한다.
|
|
217
|
+
- **기존 프로젝트가 반드시 할 일은 없다.** `appSecret`·`VITE_BSTAGE_APP_SECRET`은 deprecated 별칭으로 그대로 동작한다. **별칭 제거는 0.4.0에서 이뤄지지 않았고 다음 버전으로 연기됐다** — 제거 시점은 이 문서에 다시 공지한다. 그래도 새 코드는 `appKey`를 쓰는 것을 권장한다.
|
|
60
218
|
- 감지: `src/shared/client.ts`에 `appSecret:`이 있거나, `.env`·`.env.example`에 `VITE_BSTAGE_APP_SECRET`이 있는 경우.
|
|
61
219
|
|
|
62
220
|
**변경 내용**
|
package/docs/README.md
CHANGED
|
@@ -12,7 +12,9 @@ b.stage 서드파티 템플릿 SDK의 기술 문서입니다. React 컴포넌트
|
|
|
12
12
|
| [BUILD_SYSTEM.md](./BUILD_SYSTEM.md) | 빌드 파이프라인, Vite 설정, 산출물 경로 규칙 | 빌드 산출물을 이해하고 싶은 개발자 |
|
|
13
13
|
| [DEV_SERVER.md](./DEV_SERVER.md) | 로컬 개발 서버의 인증 프록시와 요청 흐름 | 로컬 개발 환경을 이해하고 싶은 개발자 |
|
|
14
14
|
| [INIT.md](./INIT.md) | `bstage init` 명령어의 프롬프트, 생성 파일, 옵션 | init 동작을 상세히 알고 싶은 개발자 |
|
|
15
|
+
| [LIQUID.md](./LIQUID.md) | liquid 템플릿 레포 가이드 — 생성·미리보기·검증·배포와 규약 | React 대신 liquid 템플릿으로 페이지를 만드는 개발자 |
|
|
15
16
|
| [I18N.md](./I18N.md) | 다국어 훅(useLocale/useMessages/useBstageTranslations) + `bstage i18n pull` codegen | 템플릿에 다국어를 적용하려는 개발자 |
|
|
17
|
+
| [AI_TOOLKIT.md](./AI_TOOLKIT.md) | 에이전트용 스킬·AGENTS.md와 `bstage ai install/update/doctor` | 코딩 에이전트와 함께 작업하려는 개발자 |
|
|
16
18
|
| [MIGRATION.md](./MIGRATION.md) | 버전 사이 소비자 마이그레이션 가이드 | 오래된 프로젝트를 최신 SDK로 올리려는 개발자 |
|
|
17
19
|
| [SLOT_PROTOCOL.md](./SLOT_PROTOCOL.md) | **슬롯 시스템 v1**(현행). 3-part 키·context 단방향·위젯 독립 | 슬롯 템플릿을 개발하거나 플랫폼 통합을 이해하고 싶은 개발자 |
|
|
18
20
|
| [SLOT_SYSTEM.md](./SLOT_SYSTEM.md) | 옛 슬롯 시스템 아키텍처 (공존 기간 참조용) | 레거시 슬롯을 이해해야 하는 개발자 |
|
|
@@ -23,3 +25,5 @@ b.stage 서드파티 템플릿 SDK의 기술 문서입니다. React 컴포넌트
|
|
|
23
25
|
1. **처음 시작한다면** — [GETTING_STARTED.md](./GETTING_STARTED.md)를 따라 프로젝트를 생성하고 로컬에서 실행해 보세요.
|
|
24
26
|
2. **SDK가 어떻게 동작하는지 궁금하다면** — [SDK_ARCHITECTURE.md](./SDK_ARCHITECTURE.md)에서 설계 원칙과 핵심 개념을 확인하세요.
|
|
25
27
|
3. **API를 찾고 싶다면** — [API_REFERENCE.md](./API_REFERENCE.md)에서 각 패키지의 public API를 확인하세요.
|
|
28
|
+
4. **코딩 에이전트와 함께 작업한다면** — [AI_TOOLKIT.md](./AI_TOOLKIT.md)에서 어떤 자산이 깔리고 무엇이 그것을 읽는지 확인하세요.
|
|
29
|
+
5. **liquid 템플릿으로 만든다면** — [LIQUID.md](./LIQUID.md)가 생성부터 배포까지의 흐름과 규약을 다룹니다.
|
package/docs/SLOT_CATALOG_V2.md
CHANGED
|
@@ -220,6 +220,18 @@ export default createTemplate(ContentBadge, {
|
|
|
220
220
|
| ---------------------------------------- | ------------------------------ | ----------------------- |
|
|
221
221
|
| `admin.digital-ticket-detail.form:after` | 디지털 티켓 상세 본문(폼) 아래 | `ticket: DigitalTicket` |
|
|
222
222
|
|
|
223
|
+
### 콘텐츠 목록 — `/contents/media/list`
|
|
224
|
+
|
|
225
|
+
| 슬롯 키 | 위치 | context |
|
|
226
|
+
| --------------------------------- | -------------- | ------- |
|
|
227
|
+
| `admin.contents-list.list:before` | 콘텐츠 목록 위 | — |
|
|
228
|
+
|
|
229
|
+
### 커뮤니티 보드 목록 — `/my-stage/community-home`
|
|
230
|
+
|
|
231
|
+
| 슬롯 키 | 위치 | context |
|
|
232
|
+
| ---------------------------------------- | --------------------- | ------- |
|
|
233
|
+
| `admin.community-board-list.list:before` | 커뮤니티 보드 목록 위 | — |
|
|
234
|
+
|
|
223
235
|
> 도식은 어드민 플랫폼 화면 실측이 필요해 아직 넣지 않았다(후속 보강). 키·context 계약은 위 표가 SSOT(`SLOT_CATALOG_V2`)와 일치한다.
|
|
224
236
|
|
|
225
237
|
---
|