diff --git a/AGENTS.md b/AGENTS.md index 1730b7d6..fc7d98de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -502,11 +502,18 @@ Icon 은 `` 글리프라 박스 크기가 곧 `font-size` 다. `w-N h-N` 은 | 신규 확장을 문서 없이 스캐폴딩 | `php artisan ext:docgen --scope={type}:{id} --init` 으로 골격을 함께 만든다 — 없으면 21번째 확장부터 다시 문서 없이 태어난다 | | 확장 문서를 활성 디렉토리에서 작성 | `_bundled` 에서만 작성하고 update 커맨드로 반영 (문서만이면 빌드 불필요) | | 확장이 훅을 추가할 때 코어 문서를 고침 | 훅 집계는 그 확장의 `docs/extension-points.md` 소유 — 코어에는 총계와 링크만 | +| 레이아웃에 `data_source` 를 추가하고 `editor-spec.json` 의 `sampleData` 를 그대로 둠 | 같은 ID 로 프리뷰 샘플 추가 — 없으면 **편집기 캔버스에서만** 그 영역이 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다 | +| 컴포넌트를 추가하고 팔레트에만 등록 | 템플릿 스펙은 `componentPalette.entries` · `componentPalette.groups` · `nesting` · `componentCapabilities` **넷 다** — 하나만 빠지면 편집기에서 절반만 동작하고, 어느 단계가 빠졌는지는 증상으로만 구분된다 | +| 모듈·플러그인 스펙에 `componentPalette` 선언 | 컴포넌트는 템플릿 소유 — 모듈·플러그인 스펙은 도메인 데이터(`sampleData`·`states`)만 담는다. 같은 자리를 두고 다투면 어느 쪽이 이기는지가 병합 순서에 좌우된다 | +| 공용 ID(`settings`·`roles`·`me`)를 확장마다 각자 선언 | 템플릿 스펙 한 곳 — 사본이 갈라져도 오류가 나지 않는다 | +| 편집기 스펙을 고치고 update 커맨드 생략 | 서빙은 **활성 디렉토리만** 읽는다(`_bundled` 폴백 없음) — 파일은 고쳤는데 편집기에 직전 내용이 그대로 보인다 | 이 결함군은 오류를 남기지 않는다. 문서가 코드와 어긋난 채로 계속 읽히는 것이 유일한 증상이며, 훅 이름이 어긋나면 그 확장을 잡으려던 쪽이 **잡히지 않는 훅을 구독**하게 된다(예외도 경고도 없이 리스너가 호출되지 않을 뿐이다). mermaid 문법 오류는 GitHub 렌더 시점에만 드러난다. 구조 검사가 잡을 수 있는 것은 선언된 다이어그램 종류·빈 본문·괄호 균형까지이므로, 새 형식은 실제 렌더를 눈으로 확인한다. +`docs/editor-spec.md` 는 세 유형 공통이다 — 편집기 스펙을 두지 않는 확장에도 문서를 둔다. 미보유가 정상일 수 있고("이 확장은 공용 ID 만 쓴다") 그 정상 여부를 적을 자리가 없으면 다음 사람이 부재를 누락으로 오해하거나 필요한 시점을 놓친다. 그 문서의 "샘플 데이터와 페이지 상태" 절은 그 확장 레이아웃의 `data_source` 중 프리뷰 샘플이 붙지 않는 것을 실측해 나열한다 — 이 결함은 편집기 캔버스에서만 빈 화면으로 나타나므로 그 목록이 유일한 통로다. + > 상세: [extension-documentation.md](docs/extension/extension-documentation.md) > 정적 검사가 확장 표면 변경 시 문서 미동반과 미채움 마커 잔존을 검출한다. 생성기의 비파괴 계약(블록 밖 손실 0 · 재실행 멱등 · 미존재 키 미주입)과 필수 문서·섹션·블록 목록은 테스트가 잠근다. diff --git a/CHANGELOG.md b/CHANGELOG.md index 247db960..4b1c73a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,11 +24,15 @@ - 사이트가 쓰는 외부 라이브러리의 알려진 취약점을 한 번에 점검하는 명령이 추가되었습니다. `php artisan security:audit-dependencies` 로 코어와 설치된 모든 확장을 함께 확인할 수 있고, 개발 대시보드에서도 실행할 수 있습니다. 점검 도구가 원리상 볼 수 없는 동봉 라이브러리는 버전 목록으로 함께 표시해 운영자가 직접 확인할 수 있게 했습니다. (#126 @jiwonpapa 님께서 제보해주셨습니다.) - 확장(모듈·플러그인·템플릿)이 개발자 문서를 갖추기 위한 체계가 마련되었습니다. 확장마다 `AGENTS.md`(확장을 고치는 사람용 — 설계 의도·확장점·수정 시 동반 의무·금지 패턴)와 `README.md`(도입 검토·운영자용 — 기능·설치·사용 방법·트러블슈팅), `docs/` 상세 문서를 두는 형식을 정의했으며, **동봉된 확장 20개 전부에 문서가 채워졌습니다.** 새 확장을 만들면 스캐폴딩 단계에서 이 문서 골격이 함께 생성됩니다. - 확장 문서에서 코드로 확인되는 부분(발행·구독 훅, 라우트, 권한, 메뉴, 설정 항목, 모델과 테이블, 레이아웃, 액션 핸들러, 테스트 실행 경로, 다른 확장과의 의존 관계)을 `php artisan ext:docgen` 이 자동으로 채우고 유지합니다. 사람이 쓴 서술은 손대지 않고 자동 생성 표만 교체하며, `php artisan ext:docgen --check` 로 문서가 코드와 어긋났는지 확인할 수 있습니다. 개발 대시보드에서도 실행할 수 있습니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목이 추가되었습니다. 그 확장이 레이아웃 편집기에 무엇을 선언했는지(추가 가능한 화면 요소, 스타일 조절 항목, 미리보기용 샘플 데이터, 화면 상태)와 화면 요소·데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담으며, 편집기 스펙을 두지 않은 확장에는 그것이 정상인지 아닌지를 적습니다. +- 확장 문서 검사가 「설명 자리를 비워 둔 상태」도 미작성으로 셉니다. 종전에는 채워 넣으라는 표시만 지우고 내용을 쓰지 않으면 검사를 통과해, 빈 문서가 완비된 것으로 집계되었습니다. +- 확장의 화면에 데이터를 붙였는데 레이아웃 편집기 미리보기에서 그 자리가 비는 경우를 문서가 실측해 알려 줍니다. 이 어긋남은 실제 화면이 정상 동작해 아무 오류도 남지 않으므로 종전에는 편집기를 열어 보기 전까지 드러나지 않았습니다. ### Changed - 템플릿 컴포넌트 정의·다국어·라우트 응답에 조건부 캐시(ETag)가 적용되어, 변경이 없으면 본문 전송 없이 캐시를 재사용합니다. (#122 @glitter-gim 님께서 건의해주셨습니다.) - 레이아웃 편집기를 여는 중 네트워크가 잠시 끊겨도 자동으로 다시 시도합니다. 끝내 실패하면 내부 파일 경로 대신 다음에 무엇을 하면 되는지를 안내합니다. +- 확장 문서에서 제품을 가리키는 이름이 「그누보드7」로 통일되었습니다. 종전에는 같은 문서 안에서도 약칭과 정식 명칭이 섞여, 확장만 내려받은 사람에게 별개 제품처럼 보였습니다. - 번들 템플릿의 컴포넌트·핸들러·레이아웃 상세 문서와 확장이 사용하는 활동 로그 항목 목록이 각 확장의 문서로 옮겨졌습니다. 확장이 기능을 늘릴 때 코어 문서를 함께 고쳐야 하던 의존이 사라졌으며, 코어 문서에는 총계와 각 확장 문서로의 링크만 남습니다. ### Fixed diff --git a/app/Console/Commands/Extension/ExtDocgenCommand.php b/app/Console/Commands/Extension/ExtDocgenCommand.php index d5119b6d..34667562 100644 --- a/app/Console/Commands/Extension/ExtDocgenCommand.php +++ b/app/Console/Commands/Extension/ExtDocgenCommand.php @@ -2,14 +2,9 @@ namespace App\Console\Commands\Extension; -use App\Support\ExtensionDoc\DataModelCollector; -use App\Support\ExtensionDoc\DeclarativeSurfaceCollector; -use App\Support\ExtensionDoc\DependencyGraphCollector; +use App\Support\ExtensionDoc\ExtensionDocContext; use App\Support\ExtensionDoc\ExtensionDocScaffolder; use App\Support\ExtensionDoc\ExtensionInventory; -use App\Support\ExtensionDoc\FrontendInventory; -use App\Support\ExtensionDoc\HookInventory; -use App\Support\ExtensionDoc\TestPathCollector; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; use InvalidArgumentException; @@ -49,23 +44,13 @@ class ExtDocgenCommand extends Command * 커맨드를 실행합니다. * * @param ExtensionInventory $inventory 번들 확장 인벤토리 - * @param DeclarativeSurfaceCollector $surface 선언형 표면 수집기 - * @param HookInventory $hooks 훅 인벤토리 - * @param DataModelCollector $data 데이터 모델 수집기 - * @param FrontendInventory $frontend 프론트 인벤토리 - * @param TestPathCollector $tests 테스트 경로 수집기 - * @param DependencyGraphCollector $deps 의존 관계 수집기 + * @param ExtensionDocContext $context 수집 컨텍스트 조립기 * @param ExtensionDocScaffolder $scaffolder 문서 스캐폴더 * @return int 종료 코드 */ public function handle( ExtensionInventory $inventory, - DeclarativeSurfaceCollector $surface, - HookInventory $hooks, - DataModelCollector $data, - FrontendInventory $frontend, - TestPathCollector $tests, - DependencyGraphCollector $deps, + ExtensionDocContext $context, ExtensionDocScaffolder $scaffolder ): int { $scope = (string) $this->option('scope'); @@ -134,19 +119,7 @@ class ExtDocgenCommand extends Command $results = []; foreach ($records as $record) { - // 선언형 표면을 먼저 모은다 — 발행 훅의 1차 출처가 그 안의 `getHooks()` 선언이다. - $collectedSurface = $surface->collect($record); - $declaredHooks = $collectedSurface['values']['getHooks'] ?? []; - - $ctx = [ - 'record' => $record, - 'surface' => $collectedSurface, - 'hooks' => $hooks->collect($record, is_array($declaredHooks) ? $declaredHooks : []), - 'data' => $data->collect($record), - 'frontend' => $frontend->collect($record), - 'tests' => $tests->collect($record), - 'deps' => $deps->collect($record), - ]; + $ctx = $context->build($record); $results[] = $this->processExtension($ctx, $scaffolder); } @@ -229,6 +202,18 @@ class ExtDocgenCommand extends Command } } + // 마커를 지우기만 하고 서술을 안 쓴 자리도 미채움이다. 이 축이 없으면 + // "TODO 를 삭제한 문서" 가 "채운 문서" 와 같은 모양으로 통과한다. + $emptyIntents = ExtensionDocScaffolder::emptyIntentBlocks($content); + + if ($emptyIntents > 0) { + $result['unfilled'][] = [ + 'doc' => $doc, + 'marker' => ExtensionDocScaffolder::EMPTY_INTENT_LABEL, + 'count' => $emptyIntents, + ]; + } + $docBodies = []; foreach (ExtensionDocScaffolder::blocksFor($doc) as $key) { if (array_key_exists($key, $bodies)) { diff --git a/app/Support/ExtensionDoc/EditorSpecCollector.php b/app/Support/ExtensionDoc/EditorSpecCollector.php new file mode 100644 index 00000000..0a31bbeb --- /dev/null +++ b/app/Support/ExtensionDoc/EditorSpecCollector.php @@ -0,0 +1,566 @@ + false`). 미보유는 정상 상태일 수 있고, 문서는 그 + * 정상 여부를 서술할 자리를 가져야 합니다. + * + * 합본은 런타임 서빙과 같은 경로(`EditorSpecAssembler`)를 씁니다. 수집기가 별도 병합 + * 규칙을 갖게 되면 문서가 말하는 스펙과 편집기가 읽는 스펙이 갈라집니다. + */ +class EditorSpecCollector +{ + /** + * 블록별 **항목이 실제로 담긴 자리**. + * + * 블록 최상위 키를 그대로 세면 안 됩니다 — 블록들은 자기 항목을 `entries` / `groups` / + * `byDataSourceId` 같은 하위 자리에 담고, 최상위에는 `comment` 같은 메타 키를 함께 + * 둡니다. 최상위를 세면 팔레트 79개가 3(comment·groups·entries)으로 집계되는데, 그 + * 숫자는 오류 없이 문서에 실려 "이 확장은 팔레트 항목이 3개" 라는 사실 주장이 됩니다. + * + * 값이 빈 배열인 블록은 최상위(메타 키 제외)가 곧 항목입니다. + * + * 선언 순서가 곧 문서 표의 행 순서입니다. + * + * @var array> 블록 키 → 항목이 담긴 하위 키 목록 + */ + private const ITEM_PATHS = [ + 'componentPalette' => ['entries', 'groups'], + 'controls' => [], + 'componentCapabilities' => [], + 'nesting' => ['draggable', 'containers'], + 'sampleData' => ['byDataSourceId', 'byEndpointPattern'], + 'sampleGlobal' => [], + 'states' => ['groups'], + 'stateLabels' => [], + 'actionRecipes' => [], + 'conditionRecipes' => ['operators'], + 'computedRecipes' => [], + 'errorRecipes' => [], + 'loadingComponents' => [], + 'actionChipCandidates' => [], + ]; + + /** + * 항목이 아니라 설명인 키 — 개수에서 제외한다. + * + * **접두 규칙으로 넓히지 않는다.** `_` 로 시작하는 키를 일괄 배제하면 실제 항목까지 + * 삼킨다 — `sampleGlobal._local` 이 그 예이고, 그렇게 빠진 항목은 오류 없이 문서에 + * "1개 적은 수" 로 실린다. 설명 키는 실측으로 확인된 것만 이름으로 열거한다. + * + * @var array 설명 키 목록 + */ + private const META_KEYS = ['comment', '$comment', '$schema', '_propControlsComment']; + + /** + * @var array|null 번들 템플릿이 커버하는 샘플 ID (프로세스 단위 메모) + */ + private static ?array $fallbackSampleIds = null; + + /** + * 확장의 편집기 스펙 표면을 수집합니다. + * + * @param array $record ExtensionInventory 레코드 + * @param array $layoutRelFiles 이 확장의 레이아웃 파일(확장 루트 기준 상대 경로) + * @return array 편집기 스펙 인벤토리 + */ + public function collect(array $record, array $layoutRelFiles = []): array + { + $manifestPath = $record['path'].DIRECTORY_SEPARATOR.'editor-spec.json'; + + if (! is_file($manifestPath)) { + return $this->absent($record, $layoutRelFiles); + } + + $spec = EditorSpecAssembler::assemble($manifestPath); + + if ($spec === null) { + // manifest 가 있는데 디코드에 실패한 상태다. "스펙 없음" 과 구분해 보고한다 — + // 뭉뚱그리면 깨진 JSON 이 "이 확장은 편집기 스펙을 두지 않는다" 로 읽힌다. + return $this->absent($record, $layoutRelFiles, malformed: true); + } + + $includes = $this->includeMap($manifestPath); + + return [ + 'present' => true, + 'malformed' => false, + 'manifest' => $record['relPath'].'/editor-spec.json', + 'split' => $includes !== [], + 'includes' => $includes, + 'version' => $this->stringOrNull($spec['version'] ?? null), + 'description' => $this->stringOrNull($spec['description'] ?? null), + 'styleSystem' => $this->stringOrNull($spec['styleSystem'] ?? null), + 'darkMode' => $this->stringOrNull(($spec['darkMode']['strategy'] ?? null)), + 'blocks' => $this->blockSummaries($spec, $includes), + 'paletteGroups' => $this->paletteGroups($spec['componentPalette'] ?? null), + 'sampleDataIds' => $this->idsAt($spec['sampleData'] ?? null, 'byDataSourceId'), + 'sampleEndpointPatterns' => $this->idsAt($spec['sampleData'] ?? null, 'byEndpointPattern'), + 'stateScopes' => $this->idsAt($spec['states'] ?? null, 'groups'), + 'uncovered' => $this->uncoveredDataSources($record, $layoutRelFiles, $spec), + 'declaredPaths' => [ + 'sampleData.byDataSourceId' => $this->hasPath($spec['sampleData'] ?? null, 'byDataSourceId'), + 'sampleData.byEndpointPattern' => $this->hasPath($spec['sampleData'] ?? null, 'byEndpointPattern'), + 'states.groups' => $this->hasPath($spec['states'] ?? null, 'groups'), + ], + ]; + } + + /** + * 스펙 미보유(또는 손상) 상태의 산출물을 만듭니다. + * + * @param array $record 확장 레코드 + * @param array $layoutRelFiles 레이아웃 파일 목록 + * @param bool $malformed manifest 는 있으나 디코드에 실패했는지 여부 + * @return array 인벤토리 + */ + private function absent(array $record, array $layoutRelFiles, bool $malformed = false): array + { + return [ + 'present' => false, + 'malformed' => $malformed, + 'manifest' => null, + 'split' => false, + 'includes' => [], + 'version' => null, + 'description' => null, + 'styleSystem' => null, + 'darkMode' => null, + 'blocks' => [], + 'paletteGroups' => [], + 'sampleDataIds' => [], + 'sampleEndpointPatterns' => [], + 'stateScopes' => [], + 'uncovered' => $this->uncoveredDataSources($record, $layoutRelFiles, []), + 'declaredPaths' => [], + ]; + } + + /** + * manifest 의 `$include` 맵을 원본 그대로 읽습니다. + * + * 합본 결과에는 `$include` 가 남지 않으므로(assemble 이 벗겨낸다) 분할 여부와 블록 + * 파일 경로는 manifest 를 다시 읽어야 알 수 있습니다. + * + * @param string $manifestPath manifest 절대 경로 + * @return array 블록 키 → 상대 경로 + */ + private function includeMap(string $manifestPath): array + { + $decoded = json_decode((string) file_get_contents($manifestPath), true); + + if (! is_array($decoded) || ! is_array($decoded['$include'] ?? null)) { + return []; + } + + $map = []; + + foreach ($decoded['$include'] as $key => $relative) { + if (is_string($key) && is_string($relative) && $relative !== '') { + $map[$key] = $relative; + } + } + + return $map; + } + + /** + * 블록별 요약(항목 수·출처)을 만듭니다. + * + * 항목이 여러 하위 자리에 나뉜 블록(`nesting`, `sampleData`)은 자리마다 한 행을 + * 냅니다. 합산하면 "끌 수 있는 컴포넌트 84 + 담을 수 있는 컨테이너 19 = 103" 처럼 + * 뜻이 없는 수가 되고, 그 수는 표에서 사실처럼 읽힙니다. + * + * @param array $spec 합본 spec + * @param array $includes 블록 키 → 분할 파일 상대 경로 + * @return array 블록 요약 + */ + private function blockSummaries(array $spec, array $includes): array + { + $summaries = []; + + foreach (self::ITEM_PATHS as $key => $paths) { + if (! array_key_exists($key, $spec)) { + continue; + } + + $source = $includes[$key] ?? 'editor-spec.json (인라인)'; + $block = $spec[$key]; + + if ($paths === []) { + $summaries[] = [ + 'key' => $key, + 'count' => $this->countItems($block), + 'source' => $source, + ]; + + continue; + } + + // 선언된 하위 자리 중 **실제로 있는 것만** 행으로 낸다. 없는 자리를 0 으로 + // 내보내면 "선언했는데 비었다" 와 "그 형태를 쓰지 않는다" 가 같은 모양이 된다. + foreach ($paths as $path) { + if (! is_array($block) || ! array_key_exists($path, $block)) { + continue; + } + + $summaries[] = [ + 'key' => $key.'.'.$path, + 'count' => $this->countItems($block[$path]), + 'source' => $source, + ]; + } + } + + return $summaries; + } + + /** + * 값의 항목 수를 셉니다. 맵이면 메타 키를 뺀 나머지, 리스트면 길이입니다. + * + * @param mixed $value 블록 또는 하위 자리의 값 + * @return int|null 항목 수 (개수 개념이 없으면 null) + */ + private function countItems(mixed $value): ?int + { + if (! is_array($value)) { + return null; + } + + if (array_is_list($value)) { + return count($value); + } + + return count($this->withoutMeta($value)); + } + + /** + * 맵에서 메타 키를 제거합니다. + * + * @param array $map 대상 맵 + * @return array 메타 키를 뺀 맵 + */ + private function withoutMeta(array $map): array + { + return array_filter( + $map, + static fn ($k): bool => ! in_array((string) $k, self::META_KEYS, true), + ARRAY_FILTER_USE_KEY, + ); + } + + /** + * 팔레트 그룹별 컴포넌트 수를 셉니다. + * + * 팔레트는 `{ groups: [{ label, kind, components[] }], entries: { … } }` 형태입니다. + * `groups` 가 편집기 좌측 목록의 묶음이고, 각 묶음이 담는 컴포넌트 이름이 `components` + * 입니다. + * + * @param mixed $palette componentPalette 블록 + * @return array 그룹 요약 + */ + private function paletteGroups(mixed $palette): array + { + if (! is_array($palette) || ! is_array($palette['groups'] ?? null)) { + return []; + } + + $out = []; + + foreach ($palette['groups'] as $group) { + if (! is_array($group)) { + continue; + } + + $out[] = [ + 'group' => $this->resolveLabel($this->stringOrNull($group['label'] ?? null) ?? '(이름 없음)'), + 'kind' => $this->stringOrNull($group['kind'] ?? null) ?? '-', + 'count' => is_array($group['components'] ?? null) ? count($group['components']) : 0, + ]; + } + + return $out; + } + + /** + * 블록의 하위 자리에서 항목 ID 목록을 뽑습니다. + * + * 맵이면 키가 ID 이고, 리스트면 각 항목의 `id`(없으면 `scope.match`)가 ID 입니다. + * 페이지 상태는 리스트 + `scope` 형태라 키가 없습니다. + * + * @param mixed $block 블록 값 + * @param string $path 항목이 담긴 하위 키 + * @return array ID 목록 + */ + private function idsAt(mixed $block, string $path): array + { + if (! is_array($block) || ! is_array($block[$path] ?? null)) { + return []; + } + + $items = $block[$path]; + + if (! array_is_list($items)) { + return array_values(array_map( + static fn ($k): string => (string) $k, + array_keys($this->withoutMeta($items)), + )); + } + + $ids = []; + + foreach ($items as $item) { + if (! is_array($item)) { + continue; + } + + $id = $this->stringOrNull($item['id'] ?? null) + ?? $this->stringOrNull($item['scope']['match'] ?? null) + ?? $this->stringOrNull($item['label'] ?? null); + + if ($id !== null) { + $ids[] = $id; + } + } + + return $ids; + } + + /** + * 이 확장 레이아웃의 `data_source` 중 **프리뷰 샘플이 붙지 않는 것**을 찾습니다. + * + * 편집기 캔버스는 실제 API 를 부르지 않고 `sampleData` 로 화면을 그립니다. 그래서 + * 레이아웃에 `data_source` 를 추가하고 샘플을 붙이지 않으면 그 영역만 편집기에서 + * 빈 화면이 되는데, 실제 화면은 정상 동작하므로 어긋남이 드러나지 않습니다. 오류도 + * 경고도 남지 않아 문서의 이 목록이 유일한 통로입니다. + * + * 커버 판정에는 확장 자신의 스펙뿐 아니라 **번들 템플릿의 스펙**도 넣습니다 — + * `settings` 처럼 여러 확장이 함께 쓰는 공용 ID 는 템플릿 스펙이 대신 채우도록 설계된 + * 것이라, 그것까지 미커버로 세면 목록이 잡음으로 가득 차 정작 볼 것이 묻힙니다. + * + * 번들 템플릿은 출하 기본값입니다. 운영자가 다른 템플릿을 쓰면 커버 집합이 달라질 수 + * 있으므로, 이 목록은 "반드시 빈다" 가 아니라 "기본 구성에서 빈다" 로 읽습니다. + * + * @param array $record 확장 레코드 + * @param array $layoutRelFiles 레이아웃 파일(확장 루트 기준 상대 경로) + * @param array $spec 이 확장의 합본 spec (없으면 빈 배열) + * @return array 샘플이 없는 data_source ID 목록 + */ + private function uncoveredDataSources(array $record, array $layoutRelFiles, array $spec): array + { + if ($layoutRelFiles === []) { + return []; + } + + $covered = array_flip(array_merge($this->sampleIdsOf($spec), $this->fallbackSampleIds())); + $uncovered = []; + + foreach ($layoutRelFiles as $rel) { + $abs = $record['path'].DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $rel); + $layout = $this->decodeJson($abs); + + if ($layout === null) { + continue; + } + + foreach ($this->layoutDataSourceIds($layout) as $id) { + if (! isset($covered[$id])) { + $uncovered[$id] = true; + } + } + } + + $ids = array_keys($uncovered); + sort($ids); + + return $ids; + } + + /** + * spec 의 `sampleData.byDataSourceId` 키 목록을 뽑습니다. + * + * @param array $spec 합본 spec + * @return array ID 목록 + */ + private function sampleIdsOf(array $spec): array + { + return $this->idsAt($spec['sampleData'] ?? null, 'byDataSourceId'); + } + + /** + * 번들 템플릿 스펙이 채우는 샘플 ID 집합을 돌려줍니다. + * + * 결과를 프로세스 단위로 기억합니다. 확장 20개를 도는 동안 매번 다시 합본하면 템플릿 + * 스펙(팔레트·컨트롤·역량을 담아 수만 줄에 이른다)을 스무 번 메모리에 올리게 되고, + * 메모리 한도가 낮은 실행 환경(테스트 프로세스)에서는 그대로 OOM 이 됩니다. 남기는 + * 것은 스펙 전체가 아니라 **ID 문자열 목록**이라 유지 비용도 작습니다. + * + * @return array 번들 템플릿이 커버하는 data_source ID 목록 + */ + private function fallbackSampleIds(): array + { + if (self::$fallbackSampleIds !== null) { + return self::$fallbackSampleIds; + } + + $glob = glob(base_path('templates'.DIRECTORY_SEPARATOR.'_bundled'.DIRECTORY_SEPARATOR.'*'.DIRECTORY_SEPARATOR.'editor-spec.json')); + $ids = []; + + foreach ($glob === false ? [] : $glob as $manifest) { + $assembled = EditorSpecAssembler::assemble($manifest); + + if (is_array($assembled)) { + $ids = array_merge($ids, $this->sampleIdsOf($assembled)); + } + + // 합본 결과를 즉시 놓아준다 — 다음 manifest 를 읽기 전에 회수되게 한다. + unset($assembled); + } + + return self::$fallbackSampleIds = array_values(array_unique($ids)); + } + + /** + * 레이아웃 JSON 트리에서 `data_sources[].id` 를 전부 긁습니다. + * + * `data_sources` 는 최상위뿐 아니라 컴포넌트 노드에도 붙을 수 있어 트리 전체를 봅니다. + * + * @param array $node 레이아웃 노드 + * @return array data_source ID 목록 + */ + private function layoutDataSourceIds(array $node): array + { + $ids = []; + + if (is_array($node['data_sources'] ?? null)) { + foreach ($node['data_sources'] as $ds) { + $id = is_array($ds) ? $this->stringOrNull($ds['id'] ?? null) : null; + + if ($id !== null) { + $ids[] = $id; + } + } + } + + foreach ($node as $value) { + if (is_array($value)) { + $ids = array_merge($ids, $this->layoutDataSourceIds($value)); + } + } + + return $ids; + } + + /** + * `$t:` 접두 다국어 키를 코어 한국어 문자열로 풉니다. + * + * 편집기 스펙의 라벨은 화면에 그대로 나오지 않고 프론트 i18n 을 거칩니다. 문서에 키 + * 원문(`$t:layout_editor.palette.group.design`)을 그대로 실으면 읽는 쪽이 그 묶음이 + * 무엇인지 알 수 없습니다. + * + * Laravel 의 `__()` 로는 풀리지 않습니다 — 이 키들은 PHP lang 파일이 아니라 프론트 + * 다국어 JSON(`lang/ko.json` + `$partial` 분할)에 있고, JSON 번역기는 문자열 전체를 + * 키로 쓰기 때문입니다. 그래서 `$partial` 한 홉을 직접 따라갑니다. + * + * 풀리지 않으면 **원문을 그대로 둡니다.** 없는 번역을 지어내는 것보다 키가 드러나는 + * 편이 어디를 고쳐야 하는지 알려 주고, 이 해석이 어긋나도 문서가 틀린 사실을 주장하는 + * 대신 키만 남습니다. + * + * @param string $label 라벨 원문 + * @return string 해석된 라벨 (실패 시 원문) + */ + private function resolveLabel(string $label): string + { + if (! str_starts_with($label, '$t:')) { + return $label; + } + + $root = base_path('lang'); + $node = $this->langRoot($root); + + if ($node === null) { + return $label; + } + + foreach (explode('.', substr($label, 3)) as $segment) { + if (is_array($node) && isset($node['$partial']) && is_string($node['$partial'])) { + $node = $this->decodeJson($root.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $node['$partial'])); + } + + if (! is_array($node) || ! array_key_exists($segment, $node)) { + return $label; + } + + $node = $node[$segment]; + } + + return is_string($node) && $node !== '' ? $node : $label; + } + + /** + * 코어 프론트 다국어 루트(`lang/ko.json`)를 읽습니다. + * + * @param string $root `lang` 디렉토리 절대 경로 + * @return array|null 디코드 결과 + */ + private function langRoot(string $root): ?array + { + return $this->decodeJson($root.DIRECTORY_SEPARATOR.'ko.json'); + } + + /** + * JSON 파일을 배열로 읽습니다. + * + * @param string $path 절대 경로 + * @return array|null 디코드 결과 (실패 시 null) + */ + private function decodeJson(string $path): ?array + { + if (! is_file($path)) { + return null; + } + + $decoded = json_decode((string) file_get_contents($path), true); + + return is_array($decoded) ? $decoded : null; + } + + /** + * 블록이 그 하위 자리를 **선언했는지** 봅니다. + * + * 선언하고 비운 것(`0`)과 아예 선언하지 않은 것은 다릅니다 — 전자는 채울 자리가 + * 있다는 뜻이고 후자는 그 형태를 쓰지 않는다는 뜻입니다. 뭉뚱그려 `0` 으로 적으면 + * 읽는 쪽이 "채워야 할 자리를 비워 뒀다" 로 오해합니다. + * + * @param mixed $block 블록 값 + * @param string $path 하위 키 + * @return bool 선언 여부 + */ + private function hasPath(mixed $block, string $path): bool + { + return is_array($block) && array_key_exists($path, $block); + } + + /** + * 비어 있지 않은 문자열만 통과시킵니다. + * + * @param mixed $value 후보 값 + * @return string|null 문자열 또는 null + */ + private function stringOrNull(mixed $value): ?string + { + return is_string($value) && $value !== '' ? $value : null; + } +} diff --git a/app/Support/ExtensionDoc/ExtensionDocContext.php b/app/Support/ExtensionDoc/ExtensionDocContext.php new file mode 100644 index 00000000..8fc6ec11 --- /dev/null +++ b/app/Support/ExtensionDoc/ExtensionDocContext.php @@ -0,0 +1,72 @@ + $record ExtensionInventory 레코드 + * @return array 수집 컨텍스트 + */ + public function build(array $record): array + { + // 선언형 표면을 먼저 모은다 — 발행 훅의 1차 출처가 그 안의 `getHooks()` 선언이다. + $surface = $this->surface->collect($record); + $declaredHooks = $surface['values']['getHooks'] ?? []; + + // 편집기 스펙 수집기는 레이아웃 목록을 받아 "프리뷰 샘플이 없는 data_source" 를 + // 판정한다. 레이아웃 경로 규약(모듈·플러그인 `resources/layouts/` ↔ 템플릿 + // `layouts/`)은 FrontendInventory 가 단독으로 소유하므로, 그 결과를 넘겨 분기가 + // 두 곳에 생기지 않게 한다. + $frontend = $this->frontend->collect($record); + $layoutRelFiles = array_map( + static fn (array $layout): string => $layout['relFile'], + $frontend['layouts'], + ); + + return [ + 'record' => $record, + 'surface' => $surface, + 'hooks' => $this->hooks->collect($record, is_array($declaredHooks) ? $declaredHooks : []), + 'data' => $this->data->collect($record), + 'frontend' => $frontend, + 'tests' => $this->tests->collect($record), + 'deps' => $this->deps->collect($record), + 'editorSpec' => $this->editorSpec->collect($record, $layoutRelFiles), + ]; + } +} diff --git a/app/Support/ExtensionDoc/ExtensionDocScaffolder.php b/app/Support/ExtensionDoc/ExtensionDocScaffolder.php index 31d30972..717cc98b 100644 --- a/app/Support/ExtensionDoc/ExtensionDocScaffolder.php +++ b/app/Support/ExtensionDoc/ExtensionDocScaffolder.php @@ -21,6 +21,11 @@ class ExtensionDocScaffolder */ public const GEN_PREFIX = '(.*?)/s', $content, $m) === false) { + return 0; + } + + $empty = 0; + + foreach ($m[1] as $body) { + if (trim($body) === '') { + $empty++; + } + } + + return $empty; + } + /** * 자동 생성 블록을 마커로 감쌉니다. * @@ -565,6 +617,11 @@ class ExtensionDocScaffolder 'assets' => $this->renderAssets($ctx), 'components' => $this->renderComponents($ctx), 'layout-map' => $this->renderLayoutMap($ctx), + 'editor-spec-summary' => $this->renderEditorSpecSummary($ctx), + 'editor-spec-blocks' => $this->renderEditorSpecBlocks($ctx), + 'editor-spec-palette' => $this->renderEditorSpecPalette($ctx), + 'editor-spec-samples' => $this->renderEditorSpecSamples($ctx), + 'editor-spec-obligations' => $this->renderEditorSpecObligations($ctx), default => $this->none('알 수 없는 블록 키: '.$key), }; } @@ -593,7 +650,7 @@ class ExtensionDocScaffolder $core = $ctx['deps']['coreVersion'] ?? null; if ($core !== null) { - $badges[] = $this->badge('G7', $core, '1F883D'); + $badges[] = $this->badge('그누보드7', $core, '1F883D'); } $license = $manifest['license'] ?? null; @@ -639,7 +696,7 @@ class ExtensionDocScaffolder private function renderRequirements(array $ctx): string { $rows = []; - $rows[] = ['G7 코어', $this->code($ctx['deps']['coreVersion'] ?? '(제약 없음)')]; + $rows[] = ['그누보드7 코어', $this->code($ctx['deps']['coreVersion'] ?? '(제약 없음)')]; $rows[] = ['PHP', $this->code($this->composerPhp($ctx) ?? '^8.2')]; foreach ($ctx['deps']['requires'] as $dep) { @@ -826,6 +883,7 @@ class ExtensionDocScaffolder 'docs/components.md' => '템플릿이 제공하는 컴포넌트', 'docs/layouts.md' => '레이아웃 목록과 라우트 매핑', 'docs/handlers.md' => '템플릿 전용 핸들러와 부트스트랩', + 'docs/editor-spec.md' => '레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터', default => '-', }; } @@ -2252,7 +2310,7 @@ class ExtensionDocScaffolder $lines = []; $lines[] = '# '.$name; $lines[] = ''; - $lines[] = "**G7 {$label} · {$record['id']}**"; + $lines[] = "**그누보드7 {$label} · {$record['id']}**"; $lines[] = $this->escape($description); $lines[] = ''; $lines[] = self::wrap('badges', $this->renderBlock('badges', $ctx)); @@ -2455,10 +2513,284 @@ class ExtensionDocScaffolder 'docs/components.md' => '컴포넌트', 'docs/layouts.md' => '레이아웃', 'docs/handlers.md' => '핸들러', + 'docs/editor-spec.md' => '레이아웃 편집기 스펙', default => basename($doc, '.md'), }; } + // ----------------------------------------------------------------------- + // 편집기 스펙 블록 렌더러 + // ----------------------------------------------------------------------- + + /** + * 편집기 스펙 보유 여부와 형태를 렌더합니다. + * + * 미보유는 결함이 아니라 정상일 수 있으므로 "없음" 을 사실로 적고 사람 서술에 넘깁니다. + * 다만 manifest 가 있는데 읽지 못한 경우(malformed)는 구분해 적습니다 — 뭉뚱그리면 + * 깨진 JSON 이 "이 확장은 편집기 스펙을 두지 않는다" 로 굳습니다. + * + * @param array $ctx 수집 컨텍스트 + * @return string 마크다운 + */ + private function renderEditorSpecSummary(array $ctx): string + { + $spec = $ctx['editorSpec'] ?? null; + + if (! is_array($spec)) { + return $this->none('편집기 스펙을 수집하지 못했습니다.'); + } + + if (($spec['malformed'] ?? false) === true) { + return $this->none('`editor-spec.json` 이 존재하지만 JSON 으로 읽지 못했습니다 — 편집기가 이 확장의 선언을 무시하고 있습니다.'); + } + + if (($spec['present'] ?? false) !== true) { + return $this->none('이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다.'); + } + + $rows = []; + $rows[] = ['manifest', $this->code((string) $spec['manifest'])]; + $rows[] = ['형태', $spec['split'] === true + ? '분할 — manifest + `editor-spec/*.json` '.count($spec['includes']).'개 블록' + : '단일 파일 (인라인)']; + $rows[] = ['스펙 버전', $this->code((string) ($spec['version'] ?? ''))]; + $rows[] = ['스타일 시스템', $this->code((string) ($spec['styleSystem'] ?? ''))]; + $rows[] = ['다크 모드 전략', $this->code((string) ($spec['darkMode'] ?? ''))]; + + $table = $this->table(['항목', '값'], $rows); + + $description = $spec['description'] ?? null; + + if (is_string($description) && $description !== '') { + return $table."\n\n> ".$this->escape($description); + } + + return $table; + } + + /** + * 스펙이 선언한 블록별 항목 수를 렌더합니다. + * + * @param array $ctx 수집 컨텍스트 + * @return string 마크다운 + */ + private function renderEditorSpecBlocks(array $ctx): string + { + $spec = $ctx['editorSpec'] ?? null; + + if (! is_array($spec) || ($spec['present'] ?? false) !== true) { + return $this->none('선언된 편집기 스펙 블록이 없습니다.'); + } + + $rows = []; + + foreach ($spec['blocks'] as $block) { + $rows[] = [ + $this->code($block['key']), + $this->editorSpecBlockRole($block['key']), + $block['count'] === null ? '-' : (string) $block['count'], + $this->code($block['source']), + ]; + } + + return $this->table(['블록', '역할', '항목 수', '출처'], $rows); + } + + /** + * 편집기 스펙 블록의 역할을 한 줄로 설명합니다. + * + * 블록 키는 코어가 정한 어휘이므로 확장마다 다시 설명할 필요가 없고, 반대로 설명이 + * 없으면 확장 문서만 읽는 쪽이 키 이름만으로 의미를 추측하게 됩니다. + * + * @param string $key 블록 키 + * @return string 역할 설명 + */ + private function editorSpecBlockRole(string $key): string + { + return match ($key) { + 'componentPalette', 'componentPalette.entries' => '편집기 "요소 추가" 팔레트에 나타나는 항목', + 'componentPalette.groups' => '팔레트 좌측 목록의 묶음', + 'nesting.draggable' => '캔버스에서 끌어 옮길 수 있는 컴포넌트', + 'nesting.containers' => '자식을 담을 수 있는 컴포넌트와 그 허용 규칙', + 'sampleData.byDataSourceId' => '레이아웃 `data_sources` ID 로 붙는 프리뷰 응답', + 'sampleData.byEndpointPattern' => '엔드포인트 패턴으로 붙는 프리뷰 응답', + 'states.groups' => '상태 변종을 적용할 범위(라우트·베이스 레이아웃)', + 'conditionRecipes.operators' => '조건 표현식에 쓸 수 있는 연산자', + 'controls' => '재사용 스타일 컨트롤 정의', + 'componentCapabilities' => '컴포넌트별 편집 역량(어떤 속성을 편집기가 다루는가)', + 'nesting' => '어떤 컴포넌트 안에 무엇을 넣을 수 있는가', + 'sampleData' => '캔버스 프리뷰용 샘플 응답', + 'sampleGlobal' => '`_global.*` 프리뷰 baseline 시드', + 'states' => '페이지 상태 변종(빈 목록·오류 등)', + 'stateLabels' => '상태값 친화 명칭 카탈로그', + 'actionRecipes' => '친화 명칭 → 액션 JSON 레시피', + 'conditionRecipes' => '친화 조건 → `if` 표현식 레시피', + 'computedRecipes' => '계산값 레시피', + 'errorRecipes' => '오류 처리 레시피', + 'loadingComponents' => '로딩 표시 컴포넌트 후보', + 'actionChipCandidates' => '동작 데이터 칩 컨텍스트 후보', + default => '-', + }; + } + + /** + * ID 목록을 표 한 칸에 담을 수 있게 줄입니다. + * + * 70개를 한 줄로 늘어놓으면 표가 읽히지 않고, 그렇다고 개수만 남기면 어떤 ID 인지 + * 확인할 길이 사라집니다. 앞쪽을 보이고 나머지는 수로 줄입니다. + * + * @param array $ids ID 목록 + * @param int $limit 나열할 최대 개수 + * @return string 마크다운 셀 내용 + */ + private function idListCell(array $ids, int $limit = 12): string + { + if ($ids === []) { + return '-'; + } + + $shown = array_slice($ids, 0, $limit); + $cell = implode(' · ', array_map(fn (string $id): string => $this->code($id), $shown)); + + $rest = count($ids) - count($shown); + + return $rest > 0 ? $cell." … 외 {$rest}개" : $cell; + } + + /** + * 팔레트 그룹별 항목 수를 렌더합니다. + * + * @param array $ctx 수집 컨텍스트 + * @return string 마크다운 + */ + private function renderEditorSpecPalette(array $ctx): string + { + $spec = $ctx['editorSpec'] ?? null; + + if (! is_array($spec) || ($spec['present'] ?? false) !== true) { + return $this->none('이 확장은 편집기 팔레트에 항목을 추가하지 않습니다.'); + } + + $rows = []; + + foreach ($spec['paletteGroups'] as $group) { + $rows[] = [ + $this->escape($group['group']), + $this->code($group['kind']), + (string) $group['count'], + ]; + } + + if ($rows === []) { + return $this->none('이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다.'); + } + + return $this->table(['그룹', '종류', '컴포넌트 수'], $rows); + } + + /** + * 샘플 데이터 ID 와 페이지 상태 변종을 렌더합니다. + * + * 이 두 축은 편집기 캔버스가 실제 API 없이 화면을 그릴 때 쓰는 값입니다. 레이아웃의 + * `data_sources` ID 와 어긋나면 편집기 프리뷰만 빈 화면이 되는데, 실제 화면은 정상이라 + * 어긋남이 드러나지 않습니다. + * + * @param array $ctx 수집 컨텍스트 + * @return string 마크다운 + */ + private function renderEditorSpecSamples(array $ctx): string + { + $spec = $ctx['editorSpec'] ?? null; + + if (! is_array($spec)) { + return $this->none('편집기 스펙을 수집하지 못했습니다.'); + } + + // 스펙이 없어도 **미커버 목록은 낸다.** 스펙이 없는 확장이야말로 프리뷰가 비는 + // 자리를 가질 가능성이 크고, 여기서 조기 반환하면 정작 필요한 확장에서 그 목록이 + // 통째로 사라진다 — 그런데 결과는 "빈 자리가 없다" 와 구분되지 않는다. + $sections = []; + + if (($spec['present'] ?? false) === true) { + // 세 자리를 한 행으로 합치지 않는다 — `data_sources` ID 로 붙는 샘플과 엔드포인트 + // 패턴으로 붙는 샘플은 어긋났을 때 고칠 자리가 다르고, 페이지 상태는 ID 가 아니라 + // 적용 범위(라우트/베이스 레이아웃)로 식별된다. + $rows = []; + + foreach ([ + ['sampleData.byDataSourceId', $spec['sampleDataIds']], + ['sampleData.byEndpointPattern', $spec['sampleEndpointPatterns']], + ['states.groups', $spec['stateScopes']], + ] as [$label, $ids]) { + $declared = ($spec['declaredPaths'][$label] ?? false) === true; + + $rows[] = [ + $this->code($label), + $this->editorSpecBlockRole($label), + $declared ? (string) count($ids) : '미선언', + $declared ? $this->idListCell($ids) : '-', + ]; + } + + $sections[] = $this->table(['자리', '역할', '개수', 'ID'], $rows); + } else { + $sections[] = $this->none('이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다.'); + } + + $uncovered = $spec['uncovered'] ?? []; + + if ($uncovered === []) { + $sections[] = $this->none('이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버).'); + } else { + $sections[] = '**프리뷰 샘플이 없는 `data_source` '.count($uncovered).'개** — 편집기 캔버스에서 이 자리만 빈 화면이 됩니다. 실제 화면은 정상이라 오류도 경고도 남지 않습니다.' + ."\n\n".$this->idListCell($uncovered, 20); + } + + return implode("\n\n", $sections); + } + + /** + * 편집기 스펙을 함께 고쳐야 하는 변경과 그 절차를 렌더합니다. + * + * 이 표가 없으면 확장에 화면 요소를 추가해도 편집기 팔레트에 나타나지 않는 상태가 + * 오류도 경고도 없이 남습니다 — 편집기는 선언되지 않은 컴포넌트를 "없는 것" 으로 + * 다룰 뿐 실패를 보고하지 않습니다. + * + * @param array $ctx 수집 컨텍스트 + * @return string 마크다운 + */ + private function renderEditorSpecObligations(array $ctx): string + { + $record = $ctx['record']; + $spec = $ctx['editorSpec'] ?? null; + $hasSpec = is_array($spec) && ($spec['present'] ?? false) === true; + + $update = "php artisan {$record['type']}:update {$record['id']} --force"; + + $rows = [ + ['컴포넌트를 새로 만들었다', '`componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정'], + ['레이아웃에 `data_sources` 를 추가했다', '`sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면)'], + ['`_global.*` 을 새로 읽는다', '`sampleGlobal` 에 baseline 값 추가'], + ['빈 목록·오류 같은 화면 변종을 추가했다', '`states` 에 변종 추가 · `stateLabels` 에 친화 명칭'], + ['새 액션·조건 패턴을 도입했다', '`actionRecipes` / `conditionRecipes` 에 친화 명칭 등록'], + ]; + + $table = $this->table(['이런 변경을 했다면', '편집기 스펙에서 함께 할 일'], $rows); + + if (! $hasSpec) { + // 스펙이 없는 확장에도 이 표를 남긴다. 지금은 해당 없음이지만, 위 사건 중 하나가 + // 일어나는 순간 스펙을 **신설**해야 한다는 것이 이 문서가 전할 내용이다. + return $this->none('이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다.') + ."\n\n".$table; + } + + // `_bundled` 편집분은 update 커맨드로 활성 디렉토리에 반영된 뒤에만 편집기에 보인다 + // (`EditorSpecAssembler` 는 활성 디렉토리만 합본한다 — `_bundled` 폴백이 없다). + return $table."\n\n" + .'편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다:' + ."\n\n```bash\n".$update."\n```"; + } + // ----------------------------------------------------------------------- // 마크다운 유틸 // ----------------------------------------------------------------------- diff --git a/docs/extension/editor-spec.md b/docs/extension/editor-spec.md index aef85104..b875f3c2 100644 --- a/docs/extension/editor-spec.md +++ b/docs/extension/editor-spec.md @@ -10,6 +10,7 @@ 3. 분할 형식: manifest(editor-spec.json) + `$include` 맵 → editor-spec/{block}.json. 서버가 합본해 단일 spec 으로 서빙 4. 서빙은 활성 디렉토리만 기준 (_bundled 폴백 없음). _bundled 작업분은 {type}:update 로 활성 반영 후 런타임 노출 5. 친화 라벨은 $t: 다국어 키, comment 는 작성자 메모(엔진 무시), 알려진 필드 외 자유 필드는 보존만 +6. 확장별 선언 실측·동반 의무는 그 확장의 docs/editor-spec.md 가 소유 (ext:docgen 이 유지) ``` ## 개요 @@ -60,6 +61,71 @@ editor-spec.json 이 커지면(코어 admin 템플릿은 단일 파일 18,000줄 런타임 서빙은 **활성 디렉토리(`templates/{id}/...`)만** 읽는다. `_bundled` 폴백은 없다. `_bundled` 에서 작업한 분할본은 `{type}:update {id} --force` 로 활성 디렉토리에 반영된 뒤에만 편집기에 나타난다. JSON 만 바뀐 경우 빌드는 불필요하고 update 만 실행한다. +## 확장 개발자의 작업 순서 + +아래 규칙들은 블록 하나하나의 **문법**을 말한다. 실제로 확장을 고칠 때 필요한 것은 그 +앞의 판단이다 — 무엇을 손대야 하고, 무엇을 빠뜨리면 어떤 증상이 나는가. + +### 어느 확장의 스펙에 넣는가 + +컴포넌트를 만드는 것은 템플릿의 일이고, 모듈·플러그인은 템플릿이 제공하는 컴포넌트를 +쓰기만 한다. 그래서 두 부류가 담는 것이 다르다. + +| 선언할 것 | 자리 | +|---|---| +| `componentPalette` · `controls` · `componentCapabilities` · `nesting` | **템플릿** 스펙 | +| `sampleData` · `sampleGlobal` · `states` · `*Recipes` | 그 데이터를 소유한 **모듈·플러그인** 스펙 | +| 여러 확장이 함께 쓰는 공용 ID(`settings` · `roles` · `me` 등) | **템플릿** 스펙 | + +공용 ID 를 확장마다 각자 선언하면 같은 ID 의 샘플이 여러 곳에 생기고, 그것들이 갈라져도 +오류가 나지 않는다 — 어느 것이 쓰이는지가 병합 순서에 좌우된다. + +모듈·플러그인이 `componentPalette` 를 선언하면 템플릿 선언과 같은 자리를 두고 다투게 +되므로 두지 않는다. 팔레트에 얹고 싶은 것이 있다면 그것은 활성 템플릿의 스펙으로 간다. + +### 무엇을 빠뜨렸는지는 증상으로 가른다 + +편집기는 선언되지 않은 것을 **없는 것**으로 다룰 뿐 실패를 보고하지 않는다. 그래서 +빠뜨린 자리를 알려 주는 것은 오류 메시지가 아니라 증상이다. + +| 증상 | 빠뜨린 자리 | +|---|---| +| 컴포넌트가 팔레트 목록에 아예 없다 | `componentPalette.entries` | +| 팔레트에 등록했는데 목록에 안 보인다 | `componentPalette.groups` 의 어느 묶음에도 없다 | +| 팔레트에서 끌어 놓을 수 없다 | `nesting.draggable` | +| 놓을 자리가 없다(컨테이너가 거부한다) | `nesting.containers` | +| 놓았는데 속성 패널이 비어 있다 | `componentCapabilities` | +| 속성 패널에 특정 항목만 없다 | `controls` | +| 캔버스의 한 영역만 빈 화면이다 | `sampleData.byDataSourceId`(또는 `byEndpointPattern`) | +| 값이 `undefined` 라 영역 전체가 사라진다 | `sampleGlobal` | +| 특정 상태(빈 목록·오류·모달 열림)를 볼 수 없다 | `states` | + +캔버스는 실제 API 를 부르지 않고 `sampleData` 로 그린다. 그래서 레이아웃에 +`data_source` 를 추가하고 샘플을 붙이지 않으면 **편집기에서만** 그 자리가 비고 실제 +화면은 정상 동작한다 — 오류도 경고도 서버 로그도 남지 않는다. + +캔버스는 또한 정적 시뮬레이션이라 클릭·응답으로 만들어지는 상태를 스스로 만들지 못한다. +모바일 드로어(햄버거 클릭), 쿠키 동의 배너(동의 전 방문자), 본인인증 창(428 응답)처럼 +**어떤 사건 뒤에만 나타나는 화면**은 `states` 로 그 상태를 주입해 두지 않으면 편집 +자체가 불가능하다. + +### 반영 절차 + +편집기 스펙은 JSON 이므로 빌드가 필요 없다. 다만 서빙은 **활성 디렉토리만** 읽고 +`_bundled` 폴백이 없으므로, `_bundled` 에서 고친 뒤 update 커맨드를 돌리지 않으면 +편집기에는 직전 내용이 그대로 보인다. 파일은 고쳤는데 화면이 안 바뀌었다면 거의 이 경우다. + +```bash +php artisan {module|plugin|template}:update {id} --force +``` + +### 확장별 실측은 그 확장이 소유한다 + +어느 확장이 무엇을 얼마나 선언했는지, 그 확장에서 프리뷰 샘플이 붙지 않는 `data_source` +가 무엇인지는 **그 확장의 `docs/editor-spec.md`** 가 답한다. `php artisan ext:docgen` 이 +그 실측 부분을 유지하므로 스펙을 고친 뒤 재실행한다. 코어 문서(이 문서)에는 블록 문법과 +공통 판단 기준만 둔다. + ## 블록별 작성 규칙 ### componentPalette — 요소 추가 팔레트 @@ -240,4 +306,6 @@ export function registerSirsoftAdminBasicEditorWidgets(): void { - 타입 SSoT: `resources/js/core/template-engine/layout-editor/spec/specTypes.ts` - 로더(fetch + 병합): `resources/js/core/template-engine/layout-editor/spec/editorSpecLoader.ts` - 서버 합본 헬퍼: `app/Extension/Helpers/EditorSpecAssembler.php` +- 확장별 실측 문서 생성: `php artisan ext:docgen` — 각 확장 `docs/editor-spec.md` +- 확장 문서 규정: [extension-documentation.md](extension-documentation.md) - 서빙: `app/Http/Controllers/Api/Public/PublicTemplateController.php`, `app/Http/Controllers/Api/Admin/AdminTemplateAssetController.php`, `app/Services/ModuleService.php`, `app/Services/PluginService.php` diff --git a/docs/extension/extension-documentation.md b/docs/extension/extension-documentation.md index 7b116eec..eaa64d87 100644 --- a/docs/extension/extension-documentation.md +++ b/docs/extension/extension-documentation.md @@ -54,11 +54,14 @@ ├─ components.md 제공 컴포넌트 [템플릿] ├─ layouts.md 레이아웃 목록 · 라우트 매핑 [템플릿] ├─ handlers.md 템플릿 전용 핸들러 · 부트스트랩 [템플릿] + ├─ editor-spec.md 레이아웃 편집기 선언 · 프리뷰 샘플 커버리지 └─ api/ API 레퍼런스 (별도 체계) ``` 템플릿은 API·모델·훅 축이 사실상 비므로 골격이 다르다. `ext:docgen` 이 manifest 유형을 보고 골격을 고르므로 유형을 직접 지정할 필요가 없다. +`docs/editor-spec.md` 만은 **세 유형 공통**이다. 편집기 스펙(`editor-spec.json`)을 두지 않는 확장에도 문서를 두는 것은, 미보유가 정상일 수 있고 그 정상 여부를 적을 자리가 필요하기 때문이다 — "이 확장은 왜 스펙이 없어도 되는가 / 언제 필요해지는가" 가 어디에도 없으면 다음 사람이 그 부재를 누락으로 오해하거나 반대로 필요한 시점을 놓친다. + 이 문서들은 `{ext}/` 안에 있으므로 **릴리즈 페이로드에 실리는 공개 배포물**이다. 확장 저장소를 받은 사람이 그대로 읽는다. ## 3. 역할 경계와 SSoT @@ -93,6 +96,7 @@ | `docs/components.md` (템플릿) | `제공 컴포넌트` | | `docs/layouts.md` (템플릿) | `레이아웃 목록` · `라우트 매핑` | | `docs/handlers.md` (템플릿) | `템플릿 전용 핸들러` · `부트스트랩` | +| `docs/editor-spec.md` | `선언 요약` · `선언 블록` · `컴포넌트 팔레트` · `샘플 데이터와 페이지 상태` · `수정 시 동반 의무` | 목록의 SSoT 는 생성기이므로, 직접 옮겨 적기보다 `ext:docgen --init` 이 만든 골격에서 시작하는 편이 어긋나지 않는다. diff --git a/modules/_bundled/gnuboard7-hello_module/AGENTS.md b/modules/_bundled/gnuboard7-hello_module/AGENTS.md index 497ddbdb..28b13e5a 100644 --- a/modules/_bundled/gnuboard7-hello_module/AGENTS.md +++ b/modules/_bundled/gnuboard7-hello_module/AGENTS.md @@ -71,7 +71,7 @@ Listener · Layout · Test · 다국어(백엔드 PHP + 프론트 JSON)가 각 1 `Memo` 모델. 저장 직후 `gnuboard7-hello_module.memo.created` 액션 훅을 발행하고, `LogMemoCreatedListener` 가 그것을 받아 로그를 남깁니다. -이 한 흐름에 G7 모듈의 규약이 전부 들어 있습니다: +이 한 흐름에 그누보드7 모듈의 규약이 전부 들어 있습니다: - 검증은 Service 가 아니라 **FormRequest** 에 둔다 - Service 는 구체 Repository 가 아니라 **인터페이스**를 주입받는다 @@ -129,6 +129,7 @@ Listener · Layout · Test · 다국어(백엔드 PHP + 프론트 JSON)가 각 1 - [ ] 규약(FormRequest 검증 · Repository 인터페이스 주입 · 훅으로 부가작업 분리)이 흐트러지지 않았는지 확인 — 이 코드는 본보기로 읽힌다 - [ ] `docs/extension/sample-extensions.md` 의 계층 표와 어긋나지 않는지 확인 (파일을 추가·삭제했다면 그 표도 갱신) - [ ] 발행 훅 이름을 바꾸면 `gnuboard7-hello_plugin` 의 구독이 조용히 끊긴다 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어 `memoData` · `memos` 가 편집기 캔버스에서 빈 화면으로 보인다. `data_source` 를 더 늘리면 그 자리도 같은 상태가 된다 ## 6. 금지 패턴 @@ -176,6 +177,7 @@ php vendor/bin/phpunit modules/_bundled/gnuboard7-hello_module/tests --filter='< | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/gnuboard7-hello_module/CHANGELOG.md b/modules/_bundled/gnuboard7-hello_module/CHANGELOG.md index 5968ab21..684f86df 100644 --- a/modules/_bundled/gnuboard7-hello_module/CHANGELOG.md +++ b/modules/_bundled/gnuboard7-hello_module/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [0.1.1] - 2026-08-10 diff --git a/modules/_bundled/gnuboard7-hello_module/README.md b/modules/_bundled/gnuboard7-hello_module/README.md index a6838cbd..950102b9 100644 --- a/modules/_bundled/gnuboard7-hello_module/README.md +++ b/modules/_bundled/gnuboard7-hello_module/README.md @@ -1,13 +1,13 @@ # Hello 모듈 -**G7 모듈 · gnuboard7-hello_module** +**그누보드7 모듈 · gnuboard7-hello_module** 학습용 최소 샘플 모듈 (Memo CRUD)

version 0.1.2 type 모듈 - G7 >=7.0.0 + 그누보드7 >=7.0.0 license MIT

@@ -70,7 +70,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.0` | +| 그누보드7 코어 | `>=7.0.0` | | PHP | `^8.2` | @@ -151,6 +151,7 @@ php artisan module:activate gnuboard7-hello_module | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/gnuboard7-hello_module/docs/README.md b/modules/_bundled/gnuboard7-hello_module/docs/README.md index e69da05f..9f2a0337 100644 --- a/modules/_bundled/gnuboard7-hello_module/docs/README.md +++ b/modules/_bundled/gnuboard7-hello_module/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/modules/_bundled/gnuboard7-hello_module/docs/architecture.md b/modules/_bundled/gnuboard7-hello_module/docs/architecture.md index 121919fb..f8fa045c 100644 --- a/modules/_bundled/gnuboard7-hello_module/docs/architecture.md +++ b/modules/_bundled/gnuboard7-hello_module/docs/architecture.md @@ -43,7 +43,7 @@ Listeners/LogMemoCreatedListener memo.created 구독 — 부가 작업은 resources/layouts/ admin 2 + user 1 ``` -이 지도가 곧 **G7 모듈의 규약**입니다 — 검증은 FormRequest, 데이터 접근은 Repository +이 지도가 곧 **그누보드7 모듈의 규약**입니다 — 검증은 FormRequest, 데이터 접근은 Repository 인터페이스, 부가 작업은 훅 리스너, 응답 형태는 Resource. 샘플이 잘못된 본을 보이면 그것을 따라 한 모듈이 전부 같은 형태가 되므로, 이 네 경계는 편의를 위해서도 흐트러뜨리지 않습니다. diff --git a/modules/_bundled/gnuboard7-hello_module/docs/editor-spec.md b/modules/_bundled/gnuboard7-hello_module/docs/editor-spec.md new file mode 100644 index 00000000..f3ba70a7 --- /dev/null +++ b/modules/_bundled/gnuboard7-hello_module/docs/editor-spec.md @@ -0,0 +1,86 @@ +# Hello 모듈 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +학습용 샘플 모듈이라 편집기 스펙을 일부러 두지 않았습니다. 이 모듈의 목적은 모듈의 +최소 구조(라우트 → 컨트롤러 → 서비스 → 저장소)를 보여 주는 것이고, 편집기 스펙은 그 +구조와 무관한 별개 축입니다. + +다만 아래 "샘플 데이터와 페이지 상태" 절이 보여 주듯, 이 모듈에는 프리뷰가 비는 자리가 +실제로 있습니다. 스펙이 없어도 되는 상태와 스펙이 필요한데 없는 상태는 다릅니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없으므로 표가 비어 있습니다. 이것은 "편집기가 이 모듈을 다루지 않는다" +가 아니라 "이 모듈이 편집기에 아무것도 알려 주지 않는다" 는 뜻입니다 — 편집기는 여전히 +이 모듈의 레이아웃을 열 수 있고, 다만 데이터가 붙지 않은 채로 엽니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +**프리뷰 샘플이 없는 `data_source` 2개** — 편집기 캔버스에서 이 자리만 빈 화면이 됩니다. 실제 화면은 정상이라 오류도 경고도 남지 않습니다. + +`memoData` · `memos` + + + +`memoData` · `memos` 두 ID 가 미커버입니다. 메모 목록과 폼이 편집기 캔버스에서 빈 +채로 보인다는 뜻입니다. + +샘플 모듈이므로 이 상태를 그대로 두는 것도 선택입니다 — 다만 그것은 "편집기 스펙이 +없으면 어떤 화면이 되는가" 를 보여 주는 교보재로서 의도적으로 남긴 것이지, 문제가 +없다는 뜻이 아닙니다. 스펙을 하나 만들어 보는 것이 이 모듈로 할 수 있는 좋은 연습입니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +편집기 스펙을 신설해야 하는 시점은 하나입니다 — **이 확장이 소유한 레이아웃에 +이 확장만 쓰는 `data_source` 가 생겼을 때**. 그 순간부터 편집기 캔버스의 그 영역은 +빈 화면이 되고, 실제 화면은 정상 동작하므로 오류도 경고도 남지 않습니다. + +신설 절차는 확장 루트에 `editor-spec.json` 을 만들고 `sampleData.byDataSourceId` 에 +그 ID 를 넣는 것으로 시작합니다. 팔레트·컨트롤은 템플릿의 일이므로 넣지 않습니다. +파일을 만든 뒤 update 커맨드로 활성 디렉토리에 반영해야 편집기가 읽습니다 — +`_bundled` 폴백이 없습니다. + diff --git a/modules/_bundled/sirsoft-board/AGENTS.md b/modules/_bundled/sirsoft-board/AGENTS.md index d8989f2a..8e3c4d71 100644 --- a/modules/_bundled/sirsoft-board/AGENTS.md +++ b/modules/_bundled/sirsoft-board/AGENTS.md @@ -136,6 +136,7 @@ CRUD 흐름 자체를 **자기 도메인으로 대체**하는 가장 무거운 - [ ] 비밀글이 관여하는 새 조회 경로(댓글·첨부·검색 결과 등)를 추가할 때 `SecretContentGate` 재적용 (KVE-2026-1914 — 부모에서 한 번 판정하고 끝나지 않는다) - [ ] `boards`/`board_posts`/`board_comments` 의 count 컬럼(`posts_count`/`comments_count`/`replies_count`/`attachments_count`)은 훅 리스너(`*CountSyncListener`)가 갱신 — Service 에서 직접 증감 금지 - [ ] 게시판 삭제 시 `getDynamicPermissionIdentifiers()`/`getDynamicRoleIdentifiers()`/`getDynamicMenuSlugs()` 가 최신 상태를 반영하도록 동일 트랜잭션에서 정리 (module.php `uninstall()` 의 `chunkById` 패턴 참고 — OFFSET 순회로 삭제 금지) +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan module:update sirsoft-board --force` ## 6. 금지 패턴 @@ -186,6 +187,7 @@ npx playwright test modules/_bundled/sirsoft-board/tests/Playwright/specs/<대 | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/sirsoft-board/CHANGELOG.md b/modules/_bundled/sirsoft-board/CHANGELOG.md index dac74732..516582cb 100644 --- a/modules/_bundled/sirsoft-board/CHANGELOG.md +++ b/modules/_bundled/sirsoft-board/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.1.0] - 2026-08-24 diff --git a/modules/_bundled/sirsoft-board/README.md b/modules/_bundled/sirsoft-board/README.md index a1854129..2221fc8d 100644 --- a/modules/_bundled/sirsoft-board/README.md +++ b/modules/_bundled/sirsoft-board/README.md @@ -1,13 +1,13 @@ # 게시판 -**G7 모듈 · sirsoft-board** +**그누보드7 모듈 · sirsoft-board** 게시판 관리를 위한 모듈

version 1.1.1 type 모듈 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -69,7 +69,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | @@ -147,6 +147,7 @@ _별도의 관리자 설정 항목이 없습니다._ | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/sirsoft-board/docs/README.md b/modules/_bundled/sirsoft-board/docs/README.md index f09ee1fe..37c0db83 100644 --- a/modules/_bundled/sirsoft-board/docs/README.md +++ b/modules/_bundled/sirsoft-board/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/modules/_bundled/sirsoft-board/docs/editor-spec.md b/modules/_bundled/sirsoft-board/docs/editor-spec.md new file mode 100644 index 00000000..424d2ea0 --- /dev/null +++ b/modules/_bundled/sirsoft-board/docs/editor-spec.md @@ -0,0 +1,123 @@ +# 게시판 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `modules/_bundled/sirsoft-board/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> 레이아웃 편집기 스펙 — 게시판 모듈 도메인 sampleData/sampleGlobal/states. 실제 admin 레이아웃 data_source ID 전수 스캔 기반 도메인 ID(posts/post/reports/report_detail/reporters_list/boards/boards_list/board_types/form_data/form_meta/settings) + 사용자 게시판 페이지 byEndpointPattern. 공용 인프라(roles/availableChannels/identityProviders/boardIdentity*/boardNotificationDefinitions)는 admin 템플릿 스펙(roles/availableChannels/identityProviders)·코어 프리셋 폴백이 커버. + + + +단일 파일로 둔 것은 분량 때문입니다. 게시판 스펙은 도메인 데이터 4블록뿐이라 분할할 +이유가 없습니다 — 분할은 템플릿 스펙처럼 한 파일이 만 줄 단위로 커질 때의 장치입니다. + +`스타일 시스템`·`다크 모드 전략` 이 비어 있는 것도 의도입니다. 그 둘은 화면을 **그리는** +쪽의 결정이라 템플릿 스펙이 소유합니다. 게시판이 여기에 값을 넣으면 어떤 템플릿을 깔든 +게시판이 스타일 체계를 강제하는 셈이 됩니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 23 | `editor-spec.json (인라인)` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 4 | `editor-spec.json (인라인)` | +| `sampleGlobal` | `_global.*` 프리뷰 baseline 시드 | 1 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 8 | `editor-spec.json (인라인)` | + + + +이 네 블록은 "편집기가 게시판 화면을 실제 API 없이 그리려면 무엇이 필요한가" 에서 +그대로 나옵니다. `byDataSourceId` 23종은 admin 레이아웃의 `data_source` ID 를 전수 +스캔해 맞춘 것이고, `byEndpointPattern` 4종은 사용자 게시판 페이지처럼 ID 가 아니라 +호출 주소로 붙는 자리를 덮습니다. + +여기에 없는 것이 무엇인지가 더 중요합니다 — `roles`·`availableChannels`· +`identityProviders` 같은 공용 인프라 ID 는 게시판이 쓰지만 게시판이 선언하지 않습니다. +그것들은 admin 템플릿 스펙과 코어 프리셋이 채웁니다. 여기에 같이 넣으면 같은 ID 의 +샘플이 두 곳에 생기고, 둘이 갈라져도 아무 오류가 나지 않습니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 23 | `posts` · `post` · `reports` · `report_detail` · `reporters_list` · `boards` · `boards_list` · `board_types` · `form_data` · `form_meta` · `settings` · `availableChannels` … 외 11개 | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 4 | `/api/modules/sirsoft-board/boards/*/posts*` · `/api/modules/sirsoft-board/boards/popular*` · `/api/modules/sirsoft-board/me/*` · `/api/modules/sirsoft-board/users/*/posts*` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 8 | `/board/:slug/:id` · `/board/:slug` · `/boards` · `/board/:slug/write` · `*/admin/boards/:slug/edit` · `*/admin/board/:slug/:id/edit` · `*/admin/boards/settings` · `*/admin/board/:slug/post/:id` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +`states.groups` 8종은 게시판 화면 중 **상태에 따라 다르게 보이는 것**만 골랐습니다. +비밀글 잠금(`/board/:slug/:id`), 목록의 빈 상태(`/board/:slug`), 작성 폼 등입니다. 상태 +변종이 없는 화면은 기본 샘플 하나로 충분하므로 등록하지 않습니다. + +게시판 레이아웃에 `data_source` 를 새로 붙일 때는 그 ID 가 공용 인프라인지 게시판 +도메인인지 먼저 가릅니다. 도메인이면 이 스펙의 `byDataSourceId` 에, 공용이면 템플릿 +스펙에 갑니다. 잘못 판단해도 편집기 화면만 비므로 실행 중에는 드러나지 않습니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan module:update sirsoft-board --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +게시판은 관리자 화면과 사용자 화면을 모두 갖습니다. 관리자 쪽 `data_source` 는 +`byDataSourceId` 로 붙지만 사용자 게시판 페이지는 템플릿이 렌더하므로 ID 가 아니라 +`byEndpointPattern` 으로 붙습니다 — 사용자 화면을 건드렸는데 관리자 쪽 자리만 고치면 +그 화면은 편집기에서 계속 빈 채로 남습니다. + diff --git a/modules/_bundled/sirsoft-ecommerce/AGENTS.md b/modules/_bundled/sirsoft-ecommerce/AGENTS.md index 6e8c4d32..1a7cab89 100644 --- a/modules/_bundled/sirsoft-ecommerce/AGENTS.md +++ b/modules/_bundled/sirsoft-ecommerce/AGENTS.md @@ -172,6 +172,7 @@ CRUD 를 바꾸고 싶으면 이 4종 중 하나를 잡으면 되고, 이 모듈 - [ ] 목록 응답에 하위 컬렉션(옵션·이미지)을 실을 때 화면이 실제로 그리는 것만 — Repository 의 `relations:` 와 Resource 의 `whenLoaded` 를 함께 본다 - [ ] 결제수단·PG 관련 선언을 바꾸면 기설치본 `order_settings.json` 을 정정하는 업그레이드 스텝 동반 (자기 접두사만, 멱등) - [ ] 새 관리자 화면을 추가하면 그 화면의 권한(`getPermissions()`)·메뉴(`getAdminMenus()`)·라우트 이름이 서로 가리키는 대상이 일치하는지 확인 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan module:update sirsoft-ecommerce --force` ## 6. 금지 패턴 @@ -227,6 +228,7 @@ npx playwright test modules/_bundled/sirsoft-ecommerce/tests/Playwright/specs/< | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/sirsoft-ecommerce/CHANGELOG.md b/modules/_bundled/sirsoft-ecommerce/CHANGELOG.md index acbd5764..c8bace6e 100644 --- a/modules/_bundled/sirsoft-ecommerce/CHANGELOG.md +++ b/modules/_bundled/sirsoft-ecommerce/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ### Fixed diff --git a/modules/_bundled/sirsoft-ecommerce/README.md b/modules/_bundled/sirsoft-ecommerce/README.md index cf8f7bc4..abc31368 100644 --- a/modules/_bundled/sirsoft-ecommerce/README.md +++ b/modules/_bundled/sirsoft-ecommerce/README.md @@ -1,13 +1,13 @@ # 이커머스 -**G7 모듈 · sirsoft-ecommerce** +**그누보드7 모듈 · sirsoft-ecommerce** 그누보드7 이커머스 모듈 - 상품, 주문, 결제 관리

version 1.2.1 type 모듈 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -96,7 +96,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | @@ -198,6 +198,7 @@ _별도의 관리자 설정 항목이 없습니다._ | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/sirsoft-ecommerce/docs/README.md b/modules/_bundled/sirsoft-ecommerce/docs/README.md index 29a22065..4394904c 100644 --- a/modules/_bundled/sirsoft-ecommerce/docs/README.md +++ b/modules/_bundled/sirsoft-ecommerce/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/modules/_bundled/sirsoft-ecommerce/docs/editor-spec.md b/modules/_bundled/sirsoft-ecommerce/docs/editor-spec.md new file mode 100644 index 00000000..9d1da38b --- /dev/null +++ b/modules/_bundled/sirsoft-ecommerce/docs/editor-spec.md @@ -0,0 +1,125 @@ +# 이커머스 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `modules/_bundled/sirsoft-ecommerce/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> 레이아웃 편집기 스펙 — 이커머스 모듈 도메인 sampleData/sampleGlobal/states. admin 레이아웃 data_source ID 전수 스캔 기반 도메인 ID 28종(상품·주문·브랜드·쿠폰·배송정책·정산·설정 등) byDataSourceId + 사용자 페이지(템플릿 렌더) byEndpointPattern. 공용 인프라(roles/availableChannels/identityProviders/ecommerceIdentity*/ecommerceNotificationDefinitions)는 admin 템플릿 스펙·코어 프리셋 폴백이 커버. + + + +이커머스는 저장소에서 가장 큰 모듈이지만 편집기 스펙은 여전히 단일 파일입니다. 스펙 +분량을 키우는 것은 팔레트·컨트롤·컴포넌트 역량인데 그 셋은 템플릿이 소유하기 때문입니다. +모듈 쪽에 남는 것은 도메인 데이터라 라우트 239개·레이아웃 206개 규모에도 한 파일에 +들어갑니다. + +이 사실이 곧 설계 원칙입니다 — 확장이 커진다고 편집기 스펙이 따라 커지지 않습니다. +커진다면 그 확장이 템플릿의 일을 하고 있다는 신호입니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 51 | `editor-spec.json (인라인)` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 7 | `editor-spec.json (인라인)` | +| `sampleGlobal` | `_global.*` 프리뷰 baseline 시드 | 12 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 17 | `editor-spec.json (인라인)` | +| `actionRecipes` | 친화 명칭 → 액션 JSON 레시피 | 1 | `editor-spec.json (인라인)` | +| `actionChipCandidates` | 동작 데이터 칩 컨텍스트 후보 | 1 | `editor-spec.json (인라인)` | + + + +`actionRecipes` 와 `actionChipCandidates` 를 각 1건씩 둔 것이 다른 모듈과 다른 +지점입니다. 이커머스에는 운영자가 편집기에서 직접 조립하기 어려운 동작(장바구니·주문 +흐름에 얽힌 것)이 있어, 친화 명칭으로 미리 만들어 둔 레시피가 필요합니다. + +나머지 네 블록은 게시판과 같은 원리입니다 — admin 레이아웃 `data_source` ID 51종을 +전수로 덮고, 사용자 페이지 7종은 호출 주소로 덮습니다. `sampleGlobal` 12종은 통화·로케일 +같은 값이 `_global` 에 없으면 상품 카드가 통째로 깨지기 때문에 baseline 으로 박아 +둔 것입니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 51 | `transactions` · `products` · `product` · `categories` · `orders` · `order` · `reviews` · `brands` · `carriers` · `active_carriers` · `coupons` · `coupon` … 외 39개 | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 7 | `/api/modules/sirsoft-ecommerce/products*` · `/api/modules/sirsoft-ecommerce/cart*` · `/api/modules/sirsoft-ecommerce/checkout*` · `/api/modules/sirsoft-ecommerce/wishlist*` · `/api/modules/sirsoft-ecommerce/user/orders*` · `/api/modules/sirsoft-ecommerce/user/addresses*` · `/api/modules/sirsoft-ecommerce/user/inquiries*` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 17 | `/*?/products/:product_code` · `/*?/products` · `/*?/cart` · `/*?/checkout` · `/*?/orders/:id/complete` · `/*?/reorder/:id` · `*/admin/ecommerce/products/:itemCode/edit` · `*/admin/ecommerce/promotion-coupons/:id/edit` · `*/admin/ecommerce/shipping-policies/:id/edit` · `*/admin/ecommerce/settings` · `*/admin/ecommerce/mileage-deposit-settings` · `/*?/guest/orders` … 외 5개 | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +`states.groups` 17종은 이커머스에서 상태가 실제로 화면을 가르는 자리입니다 — 품절 +상품, 빈 장바구니, 비회원 주문 조회, 재주문 등입니다. 상태를 늘리는 기준은 "그 상태에서 +운영자가 화면을 따로 손봐야 하는가" 입니다. 값만 다르고 구조가 같은 경우는 변종을 +만들지 않습니다. + +`sampleGlobal` 에 통화 관련 값을 둘 때는 특정 통화를 정답으로 박지 않도록 주의합니다. +기본 통화는 설정이 정하므로, 샘플이 특정 통화를 전제하면 편집기 프리뷰만 그 통화로 +고정되어 다른 통화 상점의 운영자에게 잘못된 화면을 보여 줍니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan module:update sirsoft-ecommerce --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +이커머스는 `sampleGlobal` 이 12종으로 가장 많습니다. 레이아웃이 `_global.*` 을 새로 +읽기 시작했는데 baseline 을 안 넣으면 그 값이 `undefined` 가 되어, 표현식이 통째로 +falsy 로 떨어지며 **영역 전체가 사라집니다.** 값 하나가 비는 것보다 알아채기 어렵습니다. + diff --git a/modules/_bundled/sirsoft-ecommerce/tests/Playwright/README.md b/modules/_bundled/sirsoft-ecommerce/tests/Playwright/README.md index 6eadf69f..8849c6d4 100644 --- a/modules/_bundled/sirsoft-ecommerce/tests/Playwright/README.md +++ b/modules/_bundled/sirsoft-ecommerce/tests/Playwright/README.md @@ -23,7 +23,7 @@ modules/_bundled/sirsoft-ecommerce/ ## 데이터 생성 위치 분리 (CRITICAL) E2E spec 이 "특정 유저 + 특정 역할 + 특정 도메인 상황" 에서 동작하려면 백엔드 데이터 생성 코드가 -필요하다. **그 코드는 데이터를 소유한 영역에 위치해야 한다** — 기존 G7 의 Seeder/Factory 분리 원칙과 동일. +필요하다. **그 코드는 데이터를 소유한 영역에 위치해야 한다** — 기존 그누보드7 의 Seeder/Factory 분리 원칙과 동일. | 데이터 종류 | 위치 | |---|---| diff --git a/modules/_bundled/sirsoft-page/AGENTS.md b/modules/_bundled/sirsoft-page/AGENTS.md index 1656e861..23ad7e76 100644 --- a/modules/_bundled/sirsoft-page/AGENTS.md +++ b/modules/_bundled/sirsoft-page/AGENTS.md @@ -149,6 +149,7 @@ - [ ] 코어 검색·SEO·ckeditor5 의 훅 이름이 바뀌면 이 모듈의 구독 5종이 조용히 끊기므로 함께 확인 - [ ] 첨부 제한(`attachment.*`)은 `config/settings/defaults.json` 이 SSoT — 서비스에서 리터럴로 재클램프하지 않는다 - [ ] 활동 로그 항목을 추가하면 코어 `lang/{ko,en}/activity_log.php` 의 action 라벨·description 과 번들 ja 팩까지 동반 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan module:update sirsoft-page --force` ## 6. 금지 패턴 @@ -202,6 +203,7 @@ npx playwright test modules/_bundled/sirsoft-page/tests/Playwright/specs/<대상 | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/sirsoft-page/CHANGELOG.md b/modules/_bundled/sirsoft-page/CHANGELOG.md index e751d789..a2e8aa9d 100644 --- a/modules/_bundled/sirsoft-page/CHANGELOG.md +++ b/modules/_bundled/sirsoft-page/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.1.0] - 2026-08-24 diff --git a/modules/_bundled/sirsoft-page/README.md b/modules/_bundled/sirsoft-page/README.md index 32d9185a..5ba30c6e 100644 --- a/modules/_bundled/sirsoft-page/README.md +++ b/modules/_bundled/sirsoft-page/README.md @@ -1,13 +1,13 @@ # 페이지 -**G7 모듈 · sirsoft-page** +**그누보드7 모듈 · sirsoft-page** 정적 페이지(정보/정책/안내) 관리 모듈

version 1.1.1 type 모듈 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -73,7 +73,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | @@ -156,6 +156,7 @@ _별도의 관리자 설정 항목이 없습니다._ | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/modules/_bundled/sirsoft-page/docs/README.md b/modules/_bundled/sirsoft-page/docs/README.md index 91d30ce2..a5ac3747 100644 --- a/modules/_bundled/sirsoft-page/docs/README.md +++ b/modules/_bundled/sirsoft-page/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/modules/_bundled/sirsoft-page/docs/editor-spec.md b/modules/_bundled/sirsoft-page/docs/editor-spec.md new file mode 100644 index 00000000..c7639e8d --- /dev/null +++ b/modules/_bundled/sirsoft-page/docs/editor-spec.md @@ -0,0 +1,115 @@ +# 페이지 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `modules/_bundled/sirsoft-page/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> 레이아웃 편집기 스펙 — 페이지 모듈 도메인 sampleData/states. 실제 admin 레이아웃 data_source ID 4종 전수(pages/page/pageData/versions) + 사용자 페이지(/p/:slug, 약관/개인정보) byEndpointPattern. sampleGlobal 은 페이지 도메인이 _global keyspace 를 두지 않아 미작성('필요 시' 조건부 — 정당). + + + +페이지 모듈의 스펙은 세 블록뿐입니다. 화면이 "목록 · 편집 · 공개 보기" 로 단순하고, +운영자가 편집기에서 손대는 대상이 페이지 **내용**이 아니라 그것을 감싸는 레이아웃이기 +때문입니다. + +`sampleGlobal` 을 두지 않은 것은 누락이 아닙니다 — 페이지 도메인은 `_global` 키를 +자기 것으로 쓰지 않습니다. 필요 없는 블록을 빈 값으로라도 선언해 두면 다음 사람이 그 +빈 값을 채워야 할 자리로 오해합니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 6 | `editor-spec.json (인라인)` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 3 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 3 | `editor-spec.json (인라인)` | + + + +`byDataSourceId` 6종 중 `termsContent`·`privacyContent` 는 다른 넷과 성격이 다릅니다. +약관·개인정보 페이지는 슬러그가 고정된 특수 페이지라 편집기에서 그 자리에 무엇이 들어갈지 +미리 보여 줘야 합니다. `byEndpointPattern` 3종도 같은 이유로 이 둘을 따로 덮습니다. + +`states.groups` 3종은 공개 페이지와 관리자 편집·상세를 하나씩 맡습니다. 페이지는 상태 +변종이 적은 도메인이라 이 수가 늘어난다면 화면이 복잡해지고 있다는 신호입니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 6 | `pages` · `page` · `pageData` · `versions` · `termsContent` · `privacyContent` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 3 | `/api/modules/sirsoft-page/pages/terms` · `/api/modules/sirsoft-page/pages/privacy` · `/api/modules/sirsoft-page/pages/*` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 3 | `/page/:slug` · `*/admin/pages/:id/edit` · `*/admin/pages/:id` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +페이지 모듈에서 주의할 것은 `/p/:slug` 처럼 **슬러그가 열려 있는 라우트**입니다. +편집기는 특정 슬러그 하나를 골라 프리뷰를 그리므로, 그 샘플이 실제 운영 페이지 중 +가장 단순한 것을 닮아 있으면 복잡한 페이지에서 레이아웃이 깨지는 것을 편집기에서 +미리 볼 수 없습니다. + +샘플을 고를 때는 가장 짧은 페이지가 아니라 **가장 많은 요소를 가진 페이지**를 기준으로 +삼습니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan module:update sirsoft-page --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + diff --git a/plugins/_bundled/gnuboard7-hello_plugin/AGENTS.md b/plugins/_bundled/gnuboard7-hello_plugin/AGENTS.md index 64040dd5..0ba92ccd 100644 --- a/plugins/_bundled/gnuboard7-hello_plugin/AGENTS.md +++ b/plugins/_bundled/gnuboard7-hello_plugin/AGENTS.md @@ -125,6 +125,7 @@ Filter 구독에는 `'type' => 'filter'` 선언이 반드시 필요합니다. - [ ] 구독 대상 모듈의 훅 이름이 바뀌면 이 플러그인이 조용히 아무 일도 하지 않게 된다 - [ ] `docs/extension/sample-extensions.md` 의 계층 표와 어긋나지 않는지 확인 (파일을 추가·삭제했다면 그 표도 갱신) - [ ] 플러그인은 완전한 페이지 레이아웃을 등록할 수 없다 — 설정 화면과 `layout_extensions` 만 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어도 되는 상태(공용 ID 만 사용)다. 이 확장만 쓰는 `data_source` 를 새로 붙이는 순간 `editor-spec.json` 신설이 필요해진다 ## 6. 금지 패턴 @@ -173,5 +174,6 @@ php vendor/bin/phpunit plugins/_bundled/gnuboard7-hello_plugin/tests --filter='< | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/gnuboard7-hello_plugin/CHANGELOG.md b/plugins/_bundled/gnuboard7-hello_plugin/CHANGELOG.md index 16b97f97..a4e228fb 100644 --- a/plugins/_bundled/gnuboard7-hello_plugin/CHANGELOG.md +++ b/plugins/_bundled/gnuboard7-hello_plugin/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [0.1.1] - 2026-08-17 diff --git a/plugins/_bundled/gnuboard7-hello_plugin/README.md b/plugins/_bundled/gnuboard7-hello_plugin/README.md index 3549c536..6add9dcc 100644 --- a/plugins/_bundled/gnuboard7-hello_plugin/README.md +++ b/plugins/_bundled/gnuboard7-hello_plugin/README.md @@ -1,13 +1,13 @@ # Hello 플러그인 -**G7 플러그인 · gnuboard7-hello_plugin** +**그누보드7 플러그인 · gnuboard7-hello_plugin** 학습용 최소 샘플 플러그인 (Hello 모듈 훅 소비)

version 0.1.2 type 플러그인 - G7 >=7.0.0 + 그누보드7 >=7.0.0 license MIT requires gnuboard7-hello_module

@@ -72,7 +72,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.0` | +| 그누보드7 코어 | `>=7.0.0` | | PHP | `^8.2` | | 의존 모듈 | `gnuboard7-hello_module` `>=0.1.0` | @@ -158,6 +158,7 @@ php artisan plugin:activate gnuboard7-hello_plugin | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/gnuboard7-hello_plugin/docs/README.md b/plugins/_bundled/gnuboard7-hello_plugin/docs/README.md index d9e3948a..db5cadab 100644 --- a/plugins/_bundled/gnuboard7-hello_plugin/docs/README.md +++ b/plugins/_bundled/gnuboard7-hello_plugin/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/gnuboard7-hello_plugin/docs/editor-spec.md b/plugins/_bundled/gnuboard7-hello_plugin/docs/editor-spec.md new file mode 100644 index 00000000..019c28aa --- /dev/null +++ b/plugins/_bundled/gnuboard7-hello_plugin/docs/editor-spec.md @@ -0,0 +1,82 @@ +# Hello 플러그인 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +학습용 샘플 플러그인이라 편집기 스펙을 두지 않았고, 지금 상태에서는 **둘 필요도 +없습니다.** 이 플러그인이 소유한 화면은 설정 화면 하나이고 그 화면이 읽는 `settings` 는 +여러 확장이 공유하는 공용 ID 라 admin 템플릿 스펙이 이미 채웁니다. + +이것이 "스펙 없음" 의 정상 형태입니다 — 아래 미커버 목록이 비어 있다는 사실이 그 +근거입니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 공용 ID 만 쓰는 확장은 자기 스펙을 갖지 않는 것이 규율에 +맞습니다 — 같은 ID 의 샘플을 확장마다 두면 어느 것이 쓰이는지가 합본 순서에 좌우되고, +둘이 갈라져도 오류가 나지 않습니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +미커버가 없습니다. 이 플러그인의 레이아웃이 쓰는 `data_source` 는 전부 번들 템플릿 +스펙이 채우므로, 편집기에서 설정 화면을 열면 값이 채워진 상태로 보입니다. + +스펙을 갖지 않은 확장이 이 상태여야 정상입니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +편집기 스펙을 신설해야 하는 시점은 하나입니다 — **이 확장이 소유한 레이아웃에 +이 확장만 쓰는 `data_source` 가 생겼을 때**. 그 순간부터 편집기 캔버스의 그 영역은 +빈 화면이 되고, 실제 화면은 정상 동작하므로 오류도 경고도 남지 않습니다. + +신설 절차는 확장 루트에 `editor-spec.json` 을 만들고 `sampleData.byDataSourceId` 에 +그 ID 를 넣는 것으로 시작합니다. 팔레트·컨트롤은 템플릿의 일이므로 넣지 않습니다. +파일을 만든 뒤 update 커맨드로 활성 디렉토리에 반영해야 편집기가 읽습니다 — +`_bundled` 폴백이 없습니다. + diff --git a/plugins/_bundled/sirsoft-ckeditor5/AGENTS.md b/plugins/_bundled/sirsoft-ckeditor5/AGENTS.md index 19c7d81c..5e4c0a73 100644 --- a/plugins/_bundled/sirsoft-ckeditor5/AGENTS.md +++ b/plugins/_bundled/sirsoft-ckeditor5/AGENTS.md @@ -148,6 +148,7 @@ - [ ] 정리 커맨드의 판정 로직을 고쳤다면 fail-open 가드(`hasPotentiallyMissingSources()`)가 여전히 앞에 있는지 확인 — 이 가드가 빠지면 이미지가 조용히 지워진다 - [ ] 편집기 폴백 경로를 고쳤다면 저장 계약(`{name}_mode`)과 재시도 시 내용 승계가 유지되는지 확인 - [ ] 프론트엔드를 고쳤다면 Playwright 위지윅 spec 을 함께 갱신·실행한다 (단위 테스트만으로는 편집기 장착 회귀가 드러나지 않는다) +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어 `ckeditor5Uploads` 가 편집기 캔버스에서 빈 화면으로 보인다. `data_source` 를 더 늘리면 그 자리도 같은 상태가 된다 ## 6. 금지 패턴 @@ -202,6 +203,7 @@ npx playwright test plugins/_bundled/sirsoft-ckeditor5/tests/Playwright/specs/< | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-ckeditor5/CHANGELOG.md b/plugins/_bundled/sirsoft-ckeditor5/CHANGELOG.md index a9099d40..86a50993 100644 --- a/plugins/_bundled/sirsoft-ckeditor5/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-ckeditor5/CHANGELOG.md @@ -11,6 +11,8 @@ - CKEditor 5 본체·스타일·번역 파일을 플러그인에 함께 담았습니다. 이제 외부 CDN 에 연결하지 않고 사이트 자신의 서버에서 불러오므로, 폐쇄망이나 외부 접속이 제한된 환경에서도 에디터가 동작합니다. - 에디터를 불러오지 못한 경우 안내와 함께 임시 입력창으로 자동 전환됩니다. 작성한 내용은 그대로 저장되고, 이미 저장된 글을 수정할 때는 기존 본문이 임시 입력창에 그대로 실립니다. [다시 시도] 로 편집기를 되살리면 입력해 둔 내용이 그대로 이어집니다. - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ### Fixed diff --git a/plugins/_bundled/sirsoft-ckeditor5/README.md b/plugins/_bundled/sirsoft-ckeditor5/README.md index 16ecf934..7f02da6f 100644 --- a/plugins/_bundled/sirsoft-ckeditor5/README.md +++ b/plugins/_bundled/sirsoft-ckeditor5/README.md @@ -1,13 +1,13 @@ # CKEditor 5 WYSIWYG 에디터 -**G7 플러그인 · sirsoft-ckeditor5** +**그누보드7 플러그인 · sirsoft-ckeditor5** CKEditor 5를 이용한 WYSIWYG 에디터 플러그인입니다. 플러그인 설치만으로 기존 HtmlEditor가 교체됩니다.

version 1.0.3 type 플러그인 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -84,7 +84,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | @@ -178,6 +178,7 @@ php artisan plugin:update sirsoft-ckeditor5 --force | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-ckeditor5/docs/README.md b/plugins/_bundled/sirsoft-ckeditor5/docs/README.md index 91fae51f..a64e0dc5 100644 --- a/plugins/_bundled/sirsoft-ckeditor5/docs/README.md +++ b/plugins/_bundled/sirsoft-ckeditor5/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-ckeditor5/docs/editor-spec.md b/plugins/_bundled/sirsoft-ckeditor5/docs/editor-spec.md new file mode 100644 index 00000000..097a5cce --- /dev/null +++ b/plugins/_bundled/sirsoft-ckeditor5/docs/editor-spec.md @@ -0,0 +1,85 @@ +# CKEditor 5 WYSIWYG 에디터 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +위지윅 에디터 플러그인이지만 편집기 스펙은 두지 않았습니다. 이 플러그인이 다루는 것은 +**본문 작성기**이고, 레이아웃 편집기가 다루는 것은 그 작성기를 **배치하는 화면**이라 +서로 다른 층이기 때문입니다. + +에디터 자체의 팔레트(툴바 구성)는 이 플러그인의 설정 화면에서 정하지, 레이아웃 편집기 +스펙과는 무관합니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 다만 이 플러그인은 설정 화면 외에 **업로드 관리 화면**을 하나 +더 갖고 있고, 그 화면은 자기 도메인 데이터를 읽습니다 — 아래 미커버 목록에 그 결과가 +드러납니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +**프리뷰 샘플이 없는 `data_source` 1개** — 편집기 캔버스에서 이 자리만 빈 화면이 됩니다. 실제 화면은 정상이라 오류도 경고도 남지 않습니다. + +`ckeditor5Uploads` + + + +`ckeditor5Uploads` 가 미커버입니다. 업로드 관리 화면의 목록 영역이 편집기 캔버스에서 +빈 채로 보입니다. + +설정 화면 쪽 `settings` 는 공용 ID 라 템플릿 스펙이 채우므로 문제가 없습니다. 즉 이 +플러그인은 **화면 둘 중 하나만** 편집기에서 온전히 보이는 상태입니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +편집기 스펙을 신설해야 하는 시점은 하나입니다 — **이 확장이 소유한 레이아웃에 +이 확장만 쓰는 `data_source` 가 생겼을 때**. 그 순간부터 편집기 캔버스의 그 영역은 +빈 화면이 되고, 실제 화면은 정상 동작하므로 오류도 경고도 남지 않습니다. + +신설 절차는 확장 루트에 `editor-spec.json` 을 만들고 `sampleData.byDataSourceId` 에 +그 ID 를 넣는 것으로 시작합니다. 팔레트·컨트롤은 템플릿의 일이므로 넣지 않습니다. +파일을 만든 뒤 update 커맨드로 활성 디렉토리에 반영해야 편집기가 읽습니다 — +`_bundled` 폴백이 없습니다. + diff --git a/plugins/_bundled/sirsoft-daum_postcode/AGENTS.md b/plugins/_bundled/sirsoft-daum_postcode/AGENTS.md index 8ca6bc07..f5bdcd40 100644 --- a/plugins/_bundled/sirsoft-daum_postcode/AGENTS.md +++ b/plugins/_bundled/sirsoft-daum_postcode/AGENTS.md @@ -126,6 +126,7 @@ Daum SDK 를 로드 → 컨테이너 `onMount` 에서 `sirsoft-daum_postcode.set - [ ] `dist/` 는 커밋되는 배포 산출물 — TS 를 고쳤으면 `--production` 재빌드 후 커밋 (`sourceMappingURL` 잔존 금지) - [ ] 조각이 붙는 확장점(`address_search_slot`)을 여는 화면이 그 자리를 없애면 오류 없이 사라진다 — 대상 확장 업그레이드 후 노출 확인 - [ ] 프론트엔드를 고쳤다면 Playwright spec 을 함께 갱신·실행한다 (단위 테스트만으로는 장착 회귀가 드러나지 않는다) +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어도 되는 상태(공용 ID 만 사용)다. 이 확장만 쓰는 `data_source` 를 새로 붙이는 순간 `editor-spec.json` 신설이 필요해진다 ## 6. 금지 패턴 @@ -171,5 +172,6 @@ cd plugins/_bundled/sirsoft-daum_postcode && powershell -Command "npm run test:r | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-daum_postcode/CHANGELOG.md b/plugins/_bundled/sirsoft-daum_postcode/CHANGELOG.md index b729fc91..41bcfbb1 100644 --- a/plugins/_bundled/sirsoft-daum_postcode/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-daum_postcode/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ### Fixed diff --git a/plugins/_bundled/sirsoft-daum_postcode/README.md b/plugins/_bundled/sirsoft-daum_postcode/README.md index 0ec6f033..aafabed0 100644 --- a/plugins/_bundled/sirsoft-daum_postcode/README.md +++ b/plugins/_bundled/sirsoft-daum_postcode/README.md @@ -1,13 +1,13 @@ # Daum 우편번호 -**G7 플러그인 · sirsoft-daum_postcode** +**그누보드7 플러그인 · sirsoft-daum_postcode** Daum 우편번호 서비스를 통한 주소 검색 기능을 제공하는 플러그인입니다. API 키 없이 무료로 사용할 수 있습니다.

version 1.0.3 type 플러그인 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -72,7 +72,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 외부 스크립트 호스트 | `t1.daumcdn.net` | @@ -158,6 +158,7 @@ php artisan plugin:update sirsoft-daum_postcode --force | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-daum_postcode/docs/README.md b/plugins/_bundled/sirsoft-daum_postcode/docs/README.md index 27ea9047..11e6bc92 100644 --- a/plugins/_bundled/sirsoft-daum_postcode/docs/README.md +++ b/plugins/_bundled/sirsoft-daum_postcode/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-daum_postcode/docs/editor-spec.md b/plugins/_bundled/sirsoft-daum_postcode/docs/editor-spec.md new file mode 100644 index 00000000..6dfd1633 --- /dev/null +++ b/plugins/_bundled/sirsoft-daum_postcode/docs/editor-spec.md @@ -0,0 +1,79 @@ +# Daum 우편번호 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +주소 검색 플러그인은 자기 화면을 거의 갖지 않습니다. 주소 검색 창은 외부 서비스가 +띄우는 것이고, 이 플러그인이 소유한 화면은 그 창의 모양·크기를 정하는 설정 하나입니다. +그래서 편집기 스펙을 두지 않으며, 지금 상태에서는 둘 필요도 없습니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 설정 화면이 읽는 `settings` 는 공용 ID 라 admin 템플릿 스펙이 +채웁니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +미커버가 없습니다. 이 플러그인의 레이아웃이 쓰는 `data_source` 는 전부 번들 템플릿 +스펙이 채우므로 편집기에서 설정 화면이 온전히 보입니다. + +주소 검색 창 자체는 외부 스크립트가 띄우므로 편집기 캔버스에는 나타나지 않습니다. +그것은 스펙으로 해결할 수 있는 종류가 아닙니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +편집기 스펙을 신설해야 하는 시점은 하나입니다 — **이 확장이 소유한 레이아웃에 +이 확장만 쓰는 `data_source` 가 생겼을 때**. 그 순간부터 편집기 캔버스의 그 영역은 +빈 화면이 되고, 실제 화면은 정상 동작하므로 오류도 경고도 남지 않습니다. + +신설 절차는 확장 루트에 `editor-spec.json` 을 만들고 `sampleData.byDataSourceId` 에 +그 ID 를 넣는 것으로 시작합니다. 팔레트·컨트롤은 템플릿의 일이므로 넣지 않습니다. +파일을 만든 뒤 update 커맨드로 활성 디렉토리에 반영해야 편집기가 읽습니다 — +`_bundled` 폴백이 없습니다. + diff --git a/plugins/_bundled/sirsoft-gdpr/AGENTS.md b/plugins/_bundled/sirsoft-gdpr/AGENTS.md index 84ba34ca..3446949b 100644 --- a/plugins/_bundled/sirsoft-gdpr/AGENTS.md +++ b/plugins/_bundled/sirsoft-gdpr/AGENTS.md @@ -129,6 +129,7 @@ necessary 4종(`XSRF-TOKEN`/세션/`laravel_maintenance`/`gdpr_session`)을 제 - [ ] `gdpr_user_consent_histories` 는 append-only — UPDATE/DELETE 로 기존 행을 고치지 않는다 (완전삭제 시 익명화 UPDATE 예외는 `GdprUserDeleteListener` 단일 지점에서만 수행) - [ ] 새 자동 차단 카테고리(기능/분석/마케팅 외)를 추가하면 배너 UI·`blocked_domains` 스키마·차단 스크립트 3곳 동기화 - [ ] `CookieConsentMiddleware` 의 strictly-necessary allowlist(4종)를 확장할 때는 ePrivacy Art.5(3) 면제 항목인지 먼저 검토 — 임의로 늘리면 동의 전 차단 원칙이 무력화된다 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-gdpr --force` ## 6. 금지 패턴 @@ -179,6 +180,7 @@ npx playwright test plugins/_bundled/sirsoft-gdpr/tests/Playwright/specs/<대상 | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md b/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md index 27bdf8e3..256ada28 100644 --- a/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ### Fixed diff --git a/plugins/_bundled/sirsoft-gdpr/README.md b/plugins/_bundled/sirsoft-gdpr/README.md index bf22c348..8a5ecde2 100644 --- a/plugins/_bundled/sirsoft-gdpr/README.md +++ b/plugins/_bundled/sirsoft-gdpr/README.md @@ -1,13 +1,13 @@ # GDPR -**G7 플러그인 · sirsoft-gdpr** +**그누보드7 플러그인 · sirsoft-gdpr** GDPR·개인정보보호법 대응 쿠키 동의 배너와 동의 이력 관리를 제공하는 플러그인

version 1.0.4 type 플러그인 - G7 >=7.0.6 + 그누보드7 >=7.0.6 license MIT

@@ -69,7 +69,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.6` | +| 그누보드7 코어 | `>=7.0.6` | | PHP | `^8.2` | @@ -185,6 +185,7 @@ Google Analytics, Facebook Pixel, Kakao Pixel 등)가 시드되어 있고 운영 | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-gdpr/docs/README.md b/plugins/_bundled/sirsoft-gdpr/docs/README.md index b2f5a3a6..3ce257b0 100644 --- a/plugins/_bundled/sirsoft-gdpr/docs/README.md +++ b/plugins/_bundled/sirsoft-gdpr/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-gdpr/docs/editor-spec.md b/plugins/_bundled/sirsoft-gdpr/docs/editor-spec.md new file mode 100644 index 00000000..f9baf038 --- /dev/null +++ b/plugins/_bundled/sirsoft-gdpr/docs/editor-spec.md @@ -0,0 +1,112 @@ +# GDPR (일반 데이터 보호 규정) — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-gdpr/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> GDPR 플러그인 레이아웃 편집기 샘플 데이터 (쿠키 동의 설정 / 동의 이력 / 개인정보 정책 버전). + + + +GDPR 플러그인은 관리자 설정·동의 이력 화면과 **사용자 화면에 얹히는 쿠키 배너**를 +함께 갖습니다. 스펙이 두 블록만으로 끝나는 것은 이 플러그인이 컴포넌트를 만들지 않고 +템플릿 컴포넌트로 배너를 조립하기 때문입니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 9 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 2 | `editor-spec.json (인라인)` | + + + +`byDataSourceId` 9종이 설정·정책 버전·동의 이력 세 갈래를 덮습니다. `gdprPublicSettings` +와 `gdprSettings` 가 따로 있는 것이 이 스펙의 핵심입니다 — 공개 응답과 관리자 응답은 +같은 저장값에서 나오지만 **내보내는 항목이 다릅니다.** 샘플을 하나로 합치면 편집기에서 +사용자 배너를 편집할 때 관리자만 볼 수 있는 항목까지 보이게 됩니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 9 | `gdprSettings` · `gdprPolicyVersionCurrent` · `gdprPolicyVersionHistory` · `gdprPolicyVersionSnapshot` · `gdprConsentLog` · `gdprPublicSettings` · `gdprMyConsent` · `gdprMeConsents` · `gdprMyConsents` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 2 | `*/admin/plugins/sirsoft-gdpr/consent-log` · `_user_base` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +`states.groups` 가 `_user_base` 를 범위로 갖는 것이 이 플러그인의 특징입니다. 쿠키 +배너는 특정 라우트가 아니라 **모든 사용자 화면의 베이스 레이아웃**에 얹히므로, 편집기가 +배너를 보여 주려면 베이스 레이아웃에 상태를 주입해야 합니다. + +배너는 동의 전에만 보입니다. 편집기 캔버스는 정적 시뮬레이션이라 "아직 동의하지 않은 +방문자" 상태를 만들어 주지 않으면 배너가 화면에 나타나지 않아 **편집 자체가 불가능**합니다. +`_user_base` 상태 변종이 그 역할입니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-gdpr --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +동의 항목을 추가·제거할 때는 `gdprPublicSettings` 와 `gdprSettings` 샘플을 **함께** +고칩니다. 한쪽만 고치면 편집기에서 관리자 화면과 사용자 배너가 서로 다른 항목 목록을 +보여 주는데, 어느 쪽이 맞는지 화면만 봐서는 알 수 없습니다. + diff --git a/plugins/_bundled/sirsoft-marketing/AGENTS.md b/plugins/_bundled/sirsoft-marketing/AGENTS.md index a2b06761..843d293a 100644 --- a/plugins/_bundled/sirsoft-marketing/AGENTS.md +++ b/plugins/_bundled/sirsoft-marketing/AGENTS.md @@ -143,6 +143,7 @@ - [ ] 레이아웃 조각 5개는 대상 화면의 슬롯이 사라지면 오류 없이 빠진다 — 템플릿·코어 회원 화면 업그레이드 후 노출 확인 - [ ] 약관 페이지 slug 설정은 `sirsoft-page` 모듈의 페이지를 가리킨다 (manifest 의존 `>=1.0.0`) - [ ] 동의 항목을 늘릴 때는 설정만 바꾼다 — 마이그레이션이 필요해졌다면 EAV 구조를 벗어난 설계라는 신호 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-marketing --force` ## 6. 금지 패턴 @@ -193,6 +194,7 @@ cd plugins/_bundled/sirsoft-marketing && powershell -Command "npm run test:run - | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-marketing/CHANGELOG.md b/plugins/_bundled/sirsoft-marketing/CHANGELOG.md index e7f30711..f40accfd 100644 --- a/plugins/_bundled/sirsoft-marketing/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-marketing/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.3] - 2026-08-22 diff --git a/plugins/_bundled/sirsoft-marketing/README.md b/plugins/_bundled/sirsoft-marketing/README.md index 0b07b414..8e1f9146 100644 --- a/plugins/_bundled/sirsoft-marketing/README.md +++ b/plugins/_bundled/sirsoft-marketing/README.md @@ -1,13 +1,13 @@ # 마케팅 동의 -**G7 플러그인 · sirsoft-marketing** +**그누보드7 플러그인 · sirsoft-marketing** 이메일 구독, 마케팅 동의, 제3자 제공 동의 등을 관리하는 플러그인

version 1.0.4 type 플러그인 - G7 >=7.0.0 + 그누보드7 >=7.0.0 license MIT requires sirsoft-page

@@ -78,7 +78,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.0` | +| 그누보드7 코어 | `>=7.0.0` | | PHP | `^8.2` | | 의존 모듈 | `sirsoft-page` `>=1.0.0` | @@ -174,6 +174,7 @@ php artisan plugin:update sirsoft-marketing --force | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-marketing/docs/README.md b/plugins/_bundled/sirsoft-marketing/docs/README.md index 0d42c1cb..e6016401 100644 --- a/plugins/_bundled/sirsoft-marketing/docs/README.md +++ b/plugins/_bundled/sirsoft-marketing/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-marketing/docs/editor-spec.md b/plugins/_bundled/sirsoft-marketing/docs/editor-spec.md new file mode 100644 index 00000000..d369502d --- /dev/null +++ b/plugins/_bundled/sirsoft-marketing/docs/editor-spec.md @@ -0,0 +1,111 @@ +# 마케팅 동의 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-marketing/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> 마케팅 동의 플러그인 레이아웃 편집기 샘플 데이터. + + + +마케팅 동의 플러그인의 스펙은 `sampleData` 한 블록, ID 하나가 전부입니다. 이 플러그인이 +소유한 화면이 설정 화면 하나뿐이고 그 화면이 읽는 도메인 데이터가 `marketing_settings` +하나이기 때문입니다. + +스펙이 작다는 것이 곧 부실을 뜻하지는 않습니다. 필요한 만큼만 선언하는 것이 규율이고, +쓰지 않는 블록을 빈 값으로 채워 두면 다음 사람이 그것을 채워야 할 자리로 오해합니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `editor-spec.json (인라인)` | + + + +`states.groups` 를 두지 않은 것은 이 플러그인의 설정 화면에 **상태 변종이 없기** +때문입니다. 값이 있든 없든 같은 폼이 그려지므로, 상태를 나눠도 편집기에서 보이는 화면이 +달라지지 않습니다. + +동의 항목이 여러 개로 늘거나 항목별로 화면이 갈라지는 날이 오면 그때 `states` 를 +신설합니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `marketing_settings` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 미선언 | - | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +마케팅 동의는 회원가입 폼·마이페이지 등 **다른 확장이 소유한 화면**에도 얹힙니다. +그 자리들은 레이아웃 확장 조각으로 주입되므로 이 스펙이 아니라 그 화면을 소유한 쪽의 +샘플로 그려집니다 — 여기 `sampleData` 가 하나뿐인 이유입니다. + +이 플러그인이 주입한 조각이 편집기에서 비어 보인다면 고칠 자리는 여기가 아니라 +그 화면을 소유한 확장의 스펙입니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-marketing --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + diff --git a/plugins/_bundled/sirsoft-message_bizppurio/AGENTS.md b/plugins/_bundled/sirsoft-message_bizppurio/AGENTS.md index be2ccaf0..ecad0822 100644 --- a/plugins/_bundled/sirsoft-message_bizppurio/AGENTS.md +++ b/plugins/_bundled/sirsoft-message_bizppurio/AGENTS.md @@ -160,6 +160,7 @@ HookManager::addAction( - [ ] 레이아웃 조각 7개는 대상 화면(알림 설정·알림 템플릿 편집·발송 이력)의 자리가 사라지면 오류 없이 빠진다 — 코어·게시판·이커머스 업그레이드 후 노출 확인 - [ ] 크리덴셜 설정을 추가한다면 `frontend_schema` 에 `expose: false` + `sensitive: true` 를 함께 선언 - [ ] `dist/` 는 커밋되는 배포 산출물 — TS 를 고쳤으면 `--production` 재빌드 후 커밋 (`sourceMappingURL` 잔존 금지) +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어 `bizppurioCategories` · `bizppurioProfiles` · `bizppurio_templates_list` · `report_url` · `templates_readiness` 가 편집기 캔버스에서 빈 화면으로 보인다. `data_source` 를 더 늘리면 그 자리도 같은 상태가 된다 ## 6. 금지 패턴 @@ -216,6 +217,7 @@ npx playwright test plugins/_bundled/sirsoft-message_bizppurio/tests/Playwright/ | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-message_bizppurio/CHANGELOG.md b/plugins/_bundled/sirsoft-message_bizppurio/CHANGELOG.md index 36830d35..b9e811ba 100644 --- a/plugins/_bundled/sirsoft-message_bizppurio/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-message_bizppurio/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.0] - 2026-08-24 diff --git a/plugins/_bundled/sirsoft-message_bizppurio/README.md b/plugins/_bundled/sirsoft-message_bizppurio/README.md index 2cd06828..c7ad2ffa 100644 --- a/plugins/_bundled/sirsoft-message_bizppurio/README.md +++ b/plugins/_bundled/sirsoft-message_bizppurio/README.md @@ -1,13 +1,13 @@ # 비즈뿌리오 메시지 발송 -**G7 플러그인 · sirsoft-message_bizppurio** +**그누보드7 플러그인 · sirsoft-message_bizppurio** 비즈뿌리오 연동 SMS/LMS·카카오 알림톡 발송 플러그인입니다. 코어 알림 시스템 채널로 문자·알림톡을 발송하고 발송 결과를 webhook 으로 수신합니다.

version 1.0.1 type 플러그인 - G7 >=7.0.6 + 그누보드7 >=7.0.6 license MIT

@@ -23,7 +23,7 @@ 비즈뿌리오(Bizppurio)를 연동해 **문자(SMS/LMS)와 카카오 알림톡**을 발송하는 플러그인입니다. -G7 코어 알림 시스템에 문자·알림톡 채널을 추가하므로, 회원가입·주문 완료처럼 코어와 모듈이 +그누보드7 코어 알림 시스템에 문자·알림톡 채널을 추가하므로, 회원가입·주문 완료처럼 코어와 모듈이 이미 발화하는 알림을 문자와 알림톡으로도 자동 발송할 수 있습니다. 알림을 새로 만들 필요 없이 **기존 알림의 채널만 켜면** 됩니다. @@ -98,7 +98,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.6` | +| 그누보드7 코어 | `>=7.0.6` | | PHP | `^8.2` | @@ -259,6 +259,7 @@ https://your-domain.com/api/plugins/sirsoft-message_bizppurio/webhook | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-message_bizppurio/docs/README.md b/plugins/_bundled/sirsoft-message_bizppurio/docs/README.md index 5b54335b..297a8e10 100644 --- a/plugins/_bundled/sirsoft-message_bizppurio/docs/README.md +++ b/plugins/_bundled/sirsoft-message_bizppurio/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-message_bizppurio/docs/api/webhook.md b/plugins/_bundled/sirsoft-message_bizppurio/docs/api/webhook.md index 2e390b3d..d903b631 100644 --- a/plugins/_bundled/sirsoft-message_bizppurio/docs/api/webhook.md +++ b/plugins/_bundled/sirsoft-message_bizppurio/docs/api/webhook.md @@ -33,7 +33,7 @@ | PHONE | body | string | 아니오 | max 20 | 수신 전화번호 | | MEDIA | body | string | 아니오 | max 10 | 실제 발송된 매체 유형(대체발송 시 요청 유형과 다를 수 있음) | | RESULT | body | string | 예 | max 10 | 발송 결과 코드 — ResultCodeResolver 가 성공/실패와 사유로 해석 | -| REFKEY | body | string | 예 | max 32 | 발송 시 G7 이 부여한 참조 키 — 이 값으로 bizppurio_dispatches 행을 찾는다 | +| REFKEY | body | string | 예 | max 32 | 발송 시 그누보드7 이 부여한 참조 키 — 이 값으로 bizppurio_dispatches 행을 찾는다 | | TELRES | body | string | 아니오 | max 10 | 대체발송(문자) 결과 코드 | | KAORES | body | string | 아니오 | max 10 | 알림톡 발송 결과 코드 | diff --git a/plugins/_bundled/sirsoft-message_bizppurio/docs/editor-spec.md b/plugins/_bundled/sirsoft-message_bizppurio/docs/editor-spec.md new file mode 100644 index 00000000..7fbd5ce8 --- /dev/null +++ b/plugins/_bundled/sirsoft-message_bizppurio/docs/editor-spec.md @@ -0,0 +1,83 @@ +# 비즈뿌리오 메시지 발송 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +문자·알림톡 채널 플러그인은 라우트 21개에 관리자 화면도 여럿 갖지만 편집기 스펙이 +없습니다. 이것은 설계가 아니라 **아직 만들지 않은 상태**입니다 — 아래 미커버 목록이 그 +결과를 보여 줍니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 이 플러그인의 관리자 화면은 연동 설정·알림톡 템플릿 관리 등 +여러 갈래이고 각각이 자기 도메인 데이터를 읽으므로, 공용 ID 만으로는 덮이지 않습니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +**프리뷰 샘플이 없는 `data_source` 5개** — 편집기 캔버스에서 이 자리만 빈 화면이 됩니다. 실제 화면은 정상이라 오류도 경고도 남지 않습니다. + +`bizppurioCategories` · `bizppurioProfiles` · `bizppurio_templates_list` · `report_url` · `templates_readiness` + + + +미커버가 5종으로 저장소에서 가장 많습니다 — `bizppurioCategories` · +`bizppurioProfiles` · `bizppurio_templates_list` · `report_url` · `templates_readiness`. + +알림톡 템플릿 관리 화면 전체가 편집기 캔버스에서 빈 채로 보인다는 뜻입니다. 이 플러그인의 +관리자 화면을 편집기로 손보려는 운영자는 지금 목록도 상태도 볼 수 없습니다. + +연동 설정 쪽 `settings` 만 공용 ID 라 템플릿 스펙이 채웁니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +편집기 스펙을 신설해야 하는 시점은 하나입니다 — **이 확장이 소유한 레이아웃에 +이 확장만 쓰는 `data_source` 가 생겼을 때**. 그 순간부터 편집기 캔버스의 그 영역은 +빈 화면이 되고, 실제 화면은 정상 동작하므로 오류도 경고도 남지 않습니다. + +신설 절차는 확장 루트에 `editor-spec.json` 을 만들고 `sampleData.byDataSourceId` 에 +그 ID 를 넣는 것으로 시작합니다. 팔레트·컨트롤은 템플릿의 일이므로 넣지 않습니다. +파일을 만든 뒤 update 커맨드로 활성 디렉토리에 반영해야 편집기가 읽습니다 — +`_bundled` 폴백이 없습니다. + diff --git a/plugins/_bundled/sirsoft-pay_kginicis/AGENTS.md b/plugins/_bundled/sirsoft-pay_kginicis/AGENTS.md index 994314bd..d4987b49 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/AGENTS.md +++ b/plugins/_bundled/sirsoft-pay_kginicis/AGENTS.md @@ -120,6 +120,7 @@ CBT 인증 URL 로 폼 POST → KG 이니시스가 `sid` 를 콜백으로 전달 - [ ] 승인/취소 흐름을 고칠 때 `before_*`/`after_*` 훅 순서와 우선순위(`PaymentRefundListener` < `CancelActivityLogListener`)를 유지 — 로그가 실제 처리보다 먼저 실행되면 안 된다 - [ ] IP 화이트리스트(`InicisNotifyIpWhitelist`) 대상 라우트를 추가/변경하면 미들웨어 부착 대상(targets)도 함께 갱신 - [ ] 새 결제수단·통화를 추가하면 그 결제수단의 콜백 URL을 관리자 설정 안내(README "콜백/통보 URL 등록")에도 반영 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-pay_kginicis --force` ## 6. 금지 패턴 @@ -168,6 +169,7 @@ cd plugins/_bundled/sirsoft-pay_kginicis && powershell -Command "npm run test:ru | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md b/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md index 49242449..9abf5077 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.1.2] - 2026-08-22 diff --git a/plugins/_bundled/sirsoft-pay_kginicis/README.md b/plugins/_bundled/sirsoft-pay_kginicis/README.md index fd4db78a..43ce9204 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/README.md +++ b/plugins/_bundled/sirsoft-pay_kginicis/README.md @@ -1,13 +1,13 @@ # KG 이니시스 -**G7 플러그인 · sirsoft-pay_kginicis** +**그누보드7 플러그인 · sirsoft-pay_kginicis** KG 이니시스 표준결제를 sirsoft-ecommerce 에 연결하는 결제 플러그인

version 1.1.3 type 플러그인 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT requires sirsoft-ecommerce

@@ -22,7 +22,7 @@ KG 이니시스 표준결제를 sirsoft-ecommerce 에 연결하는 결제 플러 ## 소개 -KG 이니시스 표준결제를 G7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. PC 결제는 +KG 이니시스 표준결제를 그누보드7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. PC 결제는 `INIStdPay.js` 표준결제창을, 모바일 결제는 모바일 표준결제창으로 이동한 뒤 서버 승인 API로 최종 승인하는 흐름을 씁니다. 일본 엔(JPY) 결제는 별도의 KG 이니시스 CBT(JPPG) 흐름을 씁니다. @@ -85,7 +85,7 @@ CBT 결제창으로 진입하며, 설정이 부족하면 한국 표준결제로 | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 의존 모듈 | `sirsoft-ecommerce` `>=1.1.0` | @@ -250,6 +250,7 @@ IP와 `devcbt.inicis.com` 443 연결 상태를 먼저 확인합니다. | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-pay_kginicis/docs/README.md b/plugins/_bundled/sirsoft-pay_kginicis/docs/README.md index 6f32a869..4d4ba29b 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/docs/README.md +++ b/plugins/_bundled/sirsoft-pay_kginicis/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-pay_kginicis/docs/editor-spec.md b/plugins/_bundled/sirsoft-pay_kginicis/docs/editor-spec.md new file mode 100644 index 00000000..9d59063c --- /dev/null +++ b/plugins/_bundled/sirsoft-pay_kginicis/docs/editor-spec.md @@ -0,0 +1,117 @@ +# KG 이니시스 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-pay_kginicis/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> KG이니시스 결제 플러그인 레이아웃 편집기 샘플 데이터 (가상계좌 입금통보 URL). + + + +KG이니시스 결제 플러그인이 소유한 화면은 관리자 설정 하나뿐입니다. 결제 자체는 PG 결제창에서 +일어나고 그 창은 이 확장이 그리는 화면이 아니므로, 편집기가 다룰 표면이 설정 화면으로 +좁혀집니다. + +`스타일 시스템`·`다크 모드 전략` 이 비어 있는 것은 정상입니다 — 화면을 그리는 규칙은 +템플릿이 정하고, 결제 플러그인은 그 위에 자기 설정 항목만 얹습니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 1 | `editor-spec.json (인라인)` | + + + +선언한 것은 `vbank_info` 하나, 그리고 설정 화면의 상태 변종 하나입니다. 다른 설정 항목 +(`settings` 등)은 여러 확장이 공유하는 공용 ID 라 admin 템플릿 스펙이 채웁니다 — +여기에 다시 선언하면 같은 ID 의 샘플이 두 곳에 생기고, 둘이 갈라져도 오류가 나지 +않습니다. + +가상계좌 안내(`vbank_info`)를 굳이 넣은 것은 그 영역이 **결제 수단에 따라 나타났다 +사라지는** 자리라, 샘플이 없으면 편집기에서 그 영역 자체를 볼 수 없기 때문입니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `vbank_info` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 1 | `*/admin/plugins/sirsoft-pay_kginicis/settings` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +상태 변종의 범위가 `*/admin/plugins/sirsoft-pay_kginicis/settings` 하나인 것은 이 플러그인이 자기 +설정 화면만 소유하기 때문입니다. 주문·결제 화면은 `sirsoft-ecommerce` 가 소유하므로 +그 화면의 프리뷰는 이커머스 스펙이 그립니다. + +결제 흐름을 편집기에서 확인하려던 것이라면 이 문서가 아니라 이커머스 모듈의 편집기 스펙 +문서를 봅니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-pay_kginicis --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +이 플러그인의 결제 수단이 이커머스 관리자 화면에 어떻게 보이는지는 편집기 스펙이 아니라 +결제수단 카탈로그 선언(`needs_pg`·`pg_provider`·`pg_locked`)이 정합니다. 배지가 이상하게 +보인다면 스펙이 아니라 그 선언을 봅니다. + diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/AGENTS.md b/plugins/_bundled/sirsoft-pay_nhnkcp/AGENTS.md index 4d88e782..beeb9dd9 100644 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/AGENTS.md +++ b/plugins/_bundled/sirsoft-pay_nhnkcp/AGENTS.md @@ -124,6 +124,7 @@ OS 판별 후 `executeCliWindows()`/`executeCliLinux()` 로 분기 → CLI 인 - [ ] 승인/취소 흐름을 고칠 때 `before_*`/`after_*` 훅 순서와 우선순위(`PaymentRefundListener` < `CancelActivityLogListener`)를 유지 — 로그가 실제 처리보다 먼저 실행되면 안 된다 - [ ] IP 화이트리스트(`RestrictKcpIp`) 대상 라우트를 추가/변경하면 미들웨어 부착 대상(targets)도 함께 갱신 - [ ] 새 결제수단·통화를 추가하면 그 결제수단의 콜백 URL을 관리자 설정 안내(README "콜백 및 통보 URL")에도 반영 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-pay_nhnkcp --force` ## 6. 금지 패턴 @@ -172,6 +173,7 @@ cd plugins/_bundled/sirsoft-pay_nhnkcp && powershell -Command "npm run test:run | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md b/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md index ea0caec9..ca9a86be 100644 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-pay_nhnkcp/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.3] - 2026-08-22 diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/README.md b/plugins/_bundled/sirsoft-pay_nhnkcp/README.md index 85ceb13c..179b5272 100644 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/README.md +++ b/plugins/_bundled/sirsoft-pay_nhnkcp/README.md @@ -1,13 +1,13 @@ # NHN KCP -**G7 플러그인 · sirsoft-pay_nhnkcp** +**그누보드7 플러그인 · sirsoft-pay_nhnkcp** NHN KCP Standard Pay 결제를 sirsoft-ecommerce 에 연결하는 결제 플러그인

version 1.0.4 type 플러그인 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT requires sirsoft-ecommerce

@@ -22,7 +22,7 @@ NHN KCP Standard Pay 결제를 sirsoft-ecommerce 에 연결하는 결제 플러 ## 소개 -NHN KCP Standard Pay 결제를 G7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. PC +NHN KCP Standard Pay 결제를 그누보드7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. PC 결제는 `payplus_web.jsp` 결제창 + 서버의 KCP CLI 승인 모듈을, 모바일 결제는 SmartPhone Pay SOAP 승인키 발급 + 모바일 결제창을 씁니다. @@ -83,7 +83,7 @@ PC 결제 승인은 `NhnKcpApiService`가 OS 를 판별해 `pp_cli`/`pp_cli_x64` | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 의존 모듈 | `sirsoft-ecommerce` `>=1.1.0` | @@ -254,6 +254,7 @@ php artisan plugin:update sirsoft-pay_nhnkcp --force | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/docs/README.md b/plugins/_bundled/sirsoft-pay_nhnkcp/docs/README.md index d5b170b7..d682a3ed 100644 --- a/plugins/_bundled/sirsoft-pay_nhnkcp/docs/README.md +++ b/plugins/_bundled/sirsoft-pay_nhnkcp/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-pay_nhnkcp/docs/editor-spec.md b/plugins/_bundled/sirsoft-pay_nhnkcp/docs/editor-spec.md new file mode 100644 index 00000000..849addbe --- /dev/null +++ b/plugins/_bundled/sirsoft-pay_nhnkcp/docs/editor-spec.md @@ -0,0 +1,117 @@ +# NHN KCP — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-pay_nhnkcp/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> NHN KCP 결제 플러그인 레이아웃 편집기 샘플 데이터 (가상계좌 입금통보 URL / 연동 상태 점검). + + + +NHN KCP 결제 플러그인이 소유한 화면은 관리자 설정 하나뿐입니다. 결제 자체는 PG 결제창에서 +일어나고 그 창은 이 확장이 그리는 화면이 아니므로, 편집기가 다룰 표면이 설정 화면으로 +좁혀집니다. + +`스타일 시스템`·`다크 모드 전략` 이 비어 있는 것은 정상입니다 — 화면을 그리는 규칙은 +템플릿이 정하고, 결제 플러그인은 그 위에 자기 설정 항목만 얹습니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 2 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 1 | `editor-spec.json (인라인)` | + + + +선언한 것은 `vbank_info` 와 연동 점검용 `health` 둘, 그리고 설정 화면의 상태 변종 하나입니다. 다른 설정 항목 +(`settings` 등)은 여러 확장이 공유하는 공용 ID 라 admin 템플릿 스펙이 채웁니다 — +여기에 다시 선언하면 같은 ID 의 샘플이 두 곳에 생기고, 둘이 갈라져도 오류가 나지 +않습니다. + +가상계좌 안내(`vbank_info`)를 굳이 넣은 것은 그 영역이 **결제 수단에 따라 나타났다 +사라지는** 자리라, 샘플이 없으면 편집기에서 그 영역 자체를 볼 수 없기 때문입니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 2 | `vbank_info` · `health` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 1 | `*/admin/plugins/sirsoft-pay_nhnkcp/settings` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +상태 변종의 범위가 `*/admin/plugins/sirsoft-pay_nhnkcp/settings` 하나인 것은 이 플러그인이 자기 +설정 화면만 소유하기 때문입니다. 주문·결제 화면은 `sirsoft-ecommerce` 가 소유하므로 +그 화면의 프리뷰는 이커머스 스펙이 그립니다. + +결제 흐름을 편집기에서 확인하려던 것이라면 이 문서가 아니라 이커머스 모듈의 편집기 스펙 +문서를 봅니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-pay_nhnkcp --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +이 플러그인의 결제 수단이 이커머스 관리자 화면에 어떻게 보이는지는 편집기 스펙이 아니라 +결제수단 카탈로그 선언(`needs_pg`·`pg_provider`·`pg_locked`)이 정합니다. 배지가 이상하게 +보인다면 스펙이 아니라 그 선언을 봅니다. + diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/AGENTS.md b/plugins/_bundled/sirsoft-pay_nicepayments/AGENTS.md index db6c03fd..e2db3de2 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/AGENTS.md +++ b/plugins/_bundled/sirsoft-pay_nicepayments/AGENTS.md @@ -117,6 +117,7 @@ API 와 동기화하는 역할만 합니다. 등록은 훅 기반입니다 - [ ] 인증 실패(1단계)와 승인 실패(2단계)의 사용자 안내 방식(silent redirect vs `?error=`)을 구분 유지 — §1 "의도적으로 하지 않는 것" 참고 - [ ] IP 화이트리스트(`VbankNotifyIpWhitelist`) 대상 라우트를 추가/변경하면 미들웨어 부착 대상(targets)도 함께 갱신 - [ ] 새 간편결제 수단을 추가하면 그 결제수단의 계약 상태를 관리자 안내에도 반영 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-pay_nicepayments --force` ## 6. 금지 패턴 @@ -164,6 +165,7 @@ cd plugins/_bundled/sirsoft-pay_nicepayments && powershell -Command "npm run tes | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md b/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md index 44192624..995ce18a 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-pay_nicepayments/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.2] - 2026-08-19 diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/README.md b/plugins/_bundled/sirsoft-pay_nicepayments/README.md index 4b72791c..ee14a231 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/README.md +++ b/plugins/_bundled/sirsoft-pay_nicepayments/README.md @@ -1,13 +1,13 @@ # NicePayments -**G7 플러그인 · sirsoft-pay_nicepayments** +**그누보드7 플러그인 · sirsoft-pay_nicepayments** 나이스페이먼츠 결제를 sirsoft-ecommerce 에 연결하는 결제 플러그인

version 1.0.3 type 플러그인 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT requires sirsoft-ecommerce

@@ -22,7 +22,7 @@ ## 소개 -나이스페이먼츠(NicePayments) 표준결제를 G7 `sirsoft-ecommerce` 모듈에 연결하는 결제 +나이스페이먼츠(NicePayments) 표준결제를 그누보드7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. 결제 승인은 **인증→승인 2단계**로 나뉩니다 — 결제창(`goPay` iframe 팝업/모바일 폼)이 먼저 인증 결과를 서버로 보내고, 서버가 그 결과를 받아 별도 승인 API를 호출해야 최종 완료됩니다. @@ -76,7 +76,7 @@ URL로 결과를 POST 하면 결제 완료 처리됩니다. | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 의존 모듈 | `sirsoft-ecommerce` `>=1.1.0` | @@ -212,6 +212,7 @@ https://your-domain.com/plugins/sirsoft-pay_nicepayments/payment/vbank-notify | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/docs/README.md b/plugins/_bundled/sirsoft-pay_nicepayments/docs/README.md index a89e9caf..1a5b6da2 100644 --- a/plugins/_bundled/sirsoft-pay_nicepayments/docs/README.md +++ b/plugins/_bundled/sirsoft-pay_nicepayments/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-pay_nicepayments/docs/editor-spec.md b/plugins/_bundled/sirsoft-pay_nicepayments/docs/editor-spec.md new file mode 100644 index 00000000..e54db583 --- /dev/null +++ b/plugins/_bundled/sirsoft-pay_nicepayments/docs/editor-spec.md @@ -0,0 +1,117 @@ +# 나이스페이먼츠 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-pay_nicepayments/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> 나이스페이먼츠 결제 플러그인 레이아웃 편집기 샘플 데이터 (가상계좌 입금통보 URL). + + + +나이스페이먼츠 결제 플러그인이 소유한 화면은 관리자 설정 하나뿐입니다. 결제 자체는 PG 결제창에서 +일어나고 그 창은 이 확장이 그리는 화면이 아니므로, 편집기가 다룰 표면이 설정 화면으로 +좁혀집니다. + +`스타일 시스템`·`다크 모드 전략` 이 비어 있는 것은 정상입니다 — 화면을 그리는 규칙은 +템플릿이 정하고, 결제 플러그인은 그 위에 자기 설정 항목만 얹습니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 1 | `editor-spec.json (인라인)` | + + + +선언한 것은 `vbank_info` 하나, 그리고 설정 화면의 상태 변종 하나입니다. 다른 설정 항목 +(`settings` 등)은 여러 확장이 공유하는 공용 ID 라 admin 템플릿 스펙이 채웁니다 — +여기에 다시 선언하면 같은 ID 의 샘플이 두 곳에 생기고, 둘이 갈라져도 오류가 나지 +않습니다. + +가상계좌 안내(`vbank_info`)를 굳이 넣은 것은 그 영역이 **결제 수단에 따라 나타났다 +사라지는** 자리라, 샘플이 없으면 편집기에서 그 영역 자체를 볼 수 없기 때문입니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `vbank_info` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 1 | `*/admin/plugins/sirsoft-pay_nicepayments/settings` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +상태 변종의 범위가 `*/admin/plugins/sirsoft-pay_nicepayments/settings` 하나인 것은 이 플러그인이 자기 +설정 화면만 소유하기 때문입니다. 주문·결제 화면은 `sirsoft-ecommerce` 가 소유하므로 +그 화면의 프리뷰는 이커머스 스펙이 그립니다. + +결제 흐름을 편집기에서 확인하려던 것이라면 이 문서가 아니라 이커머스 모듈의 편집기 스펙 +문서를 봅니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-pay_nicepayments --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +이 플러그인의 결제 수단이 이커머스 관리자 화면에 어떻게 보이는지는 편집기 스펙이 아니라 +결제수단 카탈로그 선언(`needs_pg`·`pg_provider`·`pg_locked`)이 정합니다. 배지가 이상하게 +보인다면 스펙이 아니라 그 선언을 봅니다. + diff --git a/plugins/_bundled/sirsoft-tosspayments/AGENTS.md b/plugins/_bundled/sirsoft-tosspayments/AGENTS.md index 3ee72510..b3b9eb9f 100644 --- a/plugins/_bundled/sirsoft-tosspayments/AGENTS.md +++ b/plugins/_bundled/sirsoft-tosspayments/AGENTS.md @@ -126,6 +126,7 @@ - [ ] 가상계좌 웹훅의 secret 대조(`webhook_secret_verify`)를 기본값 `true` 이외로 바꾸지 않는다 — 끄면 토스 노티 위조를 막을 수단이 사라진다 - [ ] `order_sheet_mode` 관련 로직을 고칠 때 `RegisterPgProviderListener`(enabled_methods)와 `RegisterTossPaymentMethodsListener`(builtin 결제수단 주입) 양쪽을 함께 갱신 — 한쪽만 고치면 설정과 노출 목록이 어긋난다 - [ ] `ValidateTossSettingsListener`에 새 범위 검증을 추가하면 `core.plugin_settings.before_save` 의 `sync: true`를 유지 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어도 되는 상태(공용 ID 만 사용)다. 이 확장만 쓰는 `data_source` 를 새로 붙이는 순간 `editor-spec.json` 신설이 필요해진다 ## 6. 금지 패턴 @@ -173,6 +174,7 @@ cd plugins/_bundled/sirsoft-tosspayments && powershell -Command "npm run test:ru | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-tosspayments/CHANGELOG.md b/plugins/_bundled/sirsoft-tosspayments/CHANGELOG.md index 492d50ed..e648579a 100644 --- a/plugins/_bundled/sirsoft-tosspayments/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-tosspayments/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.2] - 2026-08-19 diff --git a/plugins/_bundled/sirsoft-tosspayments/README.md b/plugins/_bundled/sirsoft-tosspayments/README.md index bca51140..c3bc959f 100644 --- a/plugins/_bundled/sirsoft-tosspayments/README.md +++ b/plugins/_bundled/sirsoft-tosspayments/README.md @@ -1,13 +1,13 @@ # 토스페이먼츠 -**G7 플러그인 · sirsoft-tosspayments** +**그누보드7 플러그인 · sirsoft-tosspayments** 토스페이먼츠 결제 게이트웨이 (통합결제창 연동)

version 1.0.3 type 플러그인 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT requires sirsoft-ecommerce

@@ -22,7 +22,7 @@ ## 소개 -토스페이먼츠 통합결제창 결제를 G7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. +토스페이먼츠 통합결제창 결제를 그누보드7 `sirsoft-ecommerce` 모듈에 연결하는 결제 플러그인입니다. 승인은 브라우저 리다이렉트 기반입니다 — 결제창(SDK)이 결제를 처리한 뒤 브라우저를 콜백 URL로 돌려보내고, 서버가 그 파라미터로 승인 확인 API를 호출합니다. @@ -72,7 +72,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 의존 모듈 | `sirsoft-ecommerce` `>=1.1.0` | @@ -188,6 +188,7 @@ https://your-domain.com/plugins/sirsoft-tosspayments/webhook/deposit | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-tosspayments/docs/README.md b/plugins/_bundled/sirsoft-tosspayments/docs/README.md index a724a00d..708c7737 100644 --- a/plugins/_bundled/sirsoft-tosspayments/docs/README.md +++ b/plugins/_bundled/sirsoft-tosspayments/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-tosspayments/docs/api/payment.md b/plugins/_bundled/sirsoft-tosspayments/docs/api/payment.md index dc5a9ca2..8dbdea9d 100644 --- a/plugins/_bundled/sirsoft-tosspayments/docs/api/payment.md +++ b/plugins/_bundled/sirsoft-tosspayments/docs/api/payment.md @@ -86,7 +86,7 @@ Location: /shop/checkout?error=PAY_PROCESS_CANCELED&orderId=20260711-000001 | 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 | | --- | --- | --- | --- | --- | --- | | paymentKey | query | string | 예 | — | 토스가 발급한 결제 키. Confirm API 호출에 사용한다. | -| orderId | query | string | 예 | — | 주문번호 (G7 `orders.order_number`). SDK 호출 시 넘긴 값이 그대로 돌아온다. | +| orderId | query | string | 예 | — | 주문번호 (그누보드7 `orders.order_number`). SDK 호출 시 넘긴 값이 그대로 돌아온다. | | amount | query | integer | 예 | min 1 | 결제 금액. 주문의 결제요청 금액과 대조하며, 불일치 시 결제를 승인하지 않는다. | **요청 예시** diff --git a/plugins/_bundled/sirsoft-tosspayments/docs/api/webhook.md b/plugins/_bundled/sirsoft-tosspayments/docs/api/webhook.md index dc539b60..6b315991 100644 --- a/plugins/_bundled/sirsoft-tosspayments/docs/api/webhook.md +++ b/plugins/_bundled/sirsoft-tosspayments/docs/api/webhook.md @@ -27,7 +27,7 @@ | 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 | | --- | --- | --- | --- | --- | --- | -| orderId | body | string | 예 | max 100 | 주문번호 (G7 `orders.order_number`). 이 값으로 주문·결제 레코드를 조회한다. | +| orderId | body | string | 예 | max 100 | 주문번호 (그누보드7 `orders.order_number`). 이 값으로 주문·결제 레코드를 조회한다. | | status | body | string | 예 | `DONE`, `CANCELED` | 입금 결과. `DONE`=입금완료 → 결제완료 처리, `CANCELED`=입금취소 → 결제실패 처리. | | secret | body | string | 아니오 | max 255 | 결제 승인 응답에서 발급받아 `payment_meta.toss_secret` 에 저장해 둔 값. 위조 방지 대조에 사용. | | transactionKey | body | string | 아니오 | max 255 | 토스 거래 키. 결제완료 처리 시 `transaction_id` 로 기록한다 (없으면 기존 값 유지). | @@ -111,7 +111,7 @@ OK | eventType | body | string | 아니오 | max 64 | 토스 이벤트 종류 (예: `PAYMENT_STATUS_CHANGED`). | | createdAt | body | string | 아니오 | max 64 | 토스가 이벤트를 생성한 시각. | | data | body | array | 예 | — | 결제 정보 객체. `data.orderId`(주문번호)와 `data.status`(토스 결제상태)를 읽어 로컬 상태와 대조한다. | -| data.orderId | body | string | 예 | max 100 | 주문번호 (G7 `orders.order_number`). 이 값으로 주문·결제 레코드를 조회해 로컬 결제상태를 확인한다. | +| data.orderId | body | string | 예 | max 100 | 주문번호 (그누보드7 `orders.order_number`). 이 값으로 주문·결제 레코드를 조회해 로컬 결제상태를 확인한다. | | data.status | body | string | 예 | max 40 | 토스 측 결제상태 (예: `DONE`, `CANCELED`, `WAITING_FOR_DEPOSIT`). 로컬 `payments.payment_status` 와 함께 로그에 기록해 불일치를 추적한다. | | data.paymentKey | body | string | 아니오 | max 255 | 토스 결제 키. 수신만 하며 이 엔드포인트에서 상태 전이에 사용하지 않는다. | diff --git a/plugins/_bundled/sirsoft-tosspayments/docs/editor-spec.md b/plugins/_bundled/sirsoft-tosspayments/docs/editor-spec.md new file mode 100644 index 00000000..7bfa9b9b --- /dev/null +++ b/plugins/_bundled/sirsoft-tosspayments/docs/editor-spec.md @@ -0,0 +1,83 @@ +# 토스페이먼츠 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +토스페이먼츠 결제 플러그인은 다른 결제 3종과 달리 편집기 스펙을 두지 않았습니다. +그럼에도 미커버가 없는 것은 이 플러그인의 설정 화면이 공용 ID 만 읽기 때문입니다 — +다른 결제 플러그인이 선언한 `vbank_info` 에 해당하는 영역을 이 플러그인은 설정 화면에서 +같은 방식으로 다루지 않습니다. + +즉 지금은 스펙 없이도 편집기에서 화면이 온전히 보입니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 형제 결제 플러그인(`sirsoft-pay_kginicis` 등)은 스펙을 갖고 +있으므로, 이 플러그인에 가상계좌 안내 같은 도메인 영역을 추가할 때는 그쪽 스펙을 선례로 +봅니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +미커버가 없습니다. 설정 화면이 읽는 `settings` 는 공용 ID 라 admin 템플릿 스펙이 +채우므로, 편집기에서 설정 화면이 값이 채워진 상태로 보입니다. + +결제 흐름 화면(주문·결제·완료)은 `sirsoft-ecommerce` 가 소유하므로 그 프리뷰는 이커머스 +스펙이 그립니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +편집기 스펙을 신설해야 하는 시점은 하나입니다 — **이 확장이 소유한 레이아웃에 +이 확장만 쓰는 `data_source` 가 생겼을 때**. 그 순간부터 편집기 캔버스의 그 영역은 +빈 화면이 되고, 실제 화면은 정상 동작하므로 오류도 경고도 남지 않습니다. + +신설 절차는 확장 루트에 `editor-spec.json` 을 만들고 `sampleData.byDataSourceId` 에 +그 ID 를 넣는 것으로 시작합니다. 팔레트·컨트롤은 템플릿의 일이므로 넣지 않습니다. +파일을 만든 뒤 update 커맨드로 활성 디렉토리에 반영해야 편집기가 읽습니다 — +`_bundled` 폴백이 없습니다. + diff --git a/plugins/_bundled/sirsoft-verification_kginicis/AGENTS.md b/plugins/_bundled/sirsoft-verification_kginicis/AGENTS.md index e2740e79..73ae0ca9 100644 --- a/plugins/_bundled/sirsoft-verification_kginicis/AGENTS.md +++ b/plugins/_bundled/sirsoft-verification_kginicis/AGENTS.md @@ -134,6 +134,7 @@ Cache 에 stash(`inicis:pending_record:{key}`) → 회원가입 완료 → `core - [ ] PII 컬럼(이름·생년월일·성별·CI/DI 등)을 다루는 코드 변경 시 GDPR 삭제/탈퇴 정리 리스너(`CleanInicisRecordOnUserDelete`/`CleanInicisRecordOnUserWithdraw`)가 여전히 그 컬럼을 정리하는지 확인 - [ ] 팝업 기반 인증 흐름(`startAuth`)을 고칠 때 `window.open`을 사용자 클릭 컨텍스트 밖으로 옮기지 않는다 — Chrome popup blocker 회피가 깨진다 - [ ] `duplicate_field`/`duplicate_block_enabled` 로직을 고치면 `InicisDuplicateField` Enum 과 `AssertNoDuplicateInicisIdentity`를 함께 갱신 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-verification_kginicis --force` ## 6. 금지 패턴 @@ -182,6 +183,7 @@ cd plugins/_bundled/sirsoft-verification_kginicis && powershell -Command "npm ru | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-verification_kginicis/CHANGELOG.md b/plugins/_bundled/sirsoft-verification_kginicis/CHANGELOG.md index e632cf9e..cab377a0 100644 --- a/plugins/_bundled/sirsoft-verification_kginicis/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-verification_kginicis/CHANGELOG.md @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.4] - 2026-08-22 diff --git a/plugins/_bundled/sirsoft-verification_kginicis/README.md b/plugins/_bundled/sirsoft-verification_kginicis/README.md index d4e2e735..f179c7f9 100644 --- a/plugins/_bundled/sirsoft-verification_kginicis/README.md +++ b/plugins/_bundled/sirsoft-verification_kginicis/README.md @@ -1,13 +1,13 @@ # KG이니시스 본인인증 -**G7 플러그인 · sirsoft-verification_kginicis** -KG이니시스 통합인증의 본인확인(reqSvcCd=03)을 G7 코어 IDV 인프라에 Provider 로 등록하는 플러그인 +**그누보드7 플러그인 · sirsoft-verification_kginicis** +KG이니시스 통합인증의 본인확인(reqSvcCd=03)을 그누보드7 코어 IDV 인프라에 Provider 로 등록하는 플러그인

version 1.0.5 type 플러그인 - G7 >=7.0.8 + 그누보드7 >=7.0.8 license MIT

@@ -21,7 +21,7 @@ KG이니시스 통합인증의 본인확인(reqSvcCd=03)을 G7 코어 IDV 인프 ## 소개 -KG이니시스 본인확인(휴대폰 인증, reqSvcCd=03)을 G7 코어의 본인인증(IDV) 체계에 연결하는 +KG이니시스 본인확인(휴대폰 인증, reqSvcCd=03)을 그누보드7 코어의 본인인증(IDV) 체계에 연결하는 플러그인입니다. 코어가 정의한 표준 인터페이스를 구현해, 회원가입·비밀번호 찾기·민감작업 등 코어가 IDV 를 요구하는 모든 지점에서 이메일 인증 대신 이니시스 팝업이 동작하게 합니다. @@ -70,7 +70,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.8` | +| 그누보드7 코어 | `>=7.0.8` | | PHP | `^8.2` | @@ -158,6 +158,7 @@ provider 를 쓸지 선택합니다. | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-verification_kginicis/docs/README.md b/plugins/_bundled/sirsoft-verification_kginicis/docs/README.md index 0cc88202..b6a592a5 100644 --- a/plugins/_bundled/sirsoft-verification_kginicis/docs/README.md +++ b/plugins/_bundled/sirsoft-verification_kginicis/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-verification_kginicis/docs/editor-spec.md b/plugins/_bundled/sirsoft-verification_kginicis/docs/editor-spec.md new file mode 100644 index 00000000..4c62d987 --- /dev/null +++ b/plugins/_bundled/sirsoft-verification_kginicis/docs/editor-spec.md @@ -0,0 +1,113 @@ +# KG이니시스 본인인증 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-verification_kginicis/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> KG이니시스 본인인증 플러그인 레이아웃 편집기 샘플 데이터. + + + +KG이니시스 통합인증 Provider 플러그인은 코어 IDV 인프라에 자기 Provider 를 등록하는 것이 본체이고, +화면은 관리자 설정과 **사용자 화면에 뜨는 인증 창**입니다. 그래서 스펙이 담는 것도 그 +두 자리뿐입니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 2 | `editor-spec.json (인라인)` | + + + +`byDataSourceId` 는 `inicisRecord` 하나입니다 — 인증 결과 레코드를 화면에 보여 주는 자리입니다. +인증 정책·목적·메시지는 코어 IDV 가 소유하고 admin 템플릿 스펙이 그 샘플을 채우므로 +여기서 다시 선언하지 않습니다. + +`states.groups` 가 2종인 것이 이 플러그인의 특징입니다. 인증은 **여러 화면에 걸쳐 +나타나는 기능**이라 설정 화면 하나로 끝나지 않습니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `inicisRecord` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 2 | `*/admin/plugins/sirsoft-verification_kginicis/settings` · `_user_base` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +상태 범위는 `*/admin/plugins/sirsoft-verification_kginicis/settings` 와 `_user_base` 입니다. `_user_base` 가 들어 있는 것이 핵심입니다 — 본인인증 +요구는 특정 라우트가 아니라 **어느 화면에서든 428 응답으로 발생**할 수 있고, 그때 뜨는 +인증 창은 베이스 레이아웃 위에 얹힙니다. + +편집기 캔버스는 실제 428 응답을 받지 않으므로, 그 상태를 변종으로 주입해 두지 않으면 +인증 창이 화면에 나타나지 않아 **편집할 방법이 없습니다.** + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-verification_kginicis --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +인증 창의 모양을 바꿨다면 이 스펙만으로는 끝나지 않습니다. 인증 창을 여는 주체는 +템플릿 부트스트랩이 등록한 launcher 이므로, launcher 가 여는 화면과 여기 상태 변종이 +가리키는 화면이 같은지 함께 확인합니다. + diff --git a/plugins/_bundled/sirsoft-verification_nhnkcp/AGENTS.md b/plugins/_bundled/sirsoft-verification_nhnkcp/AGENTS.md index f909084f..a638c7cd 100644 --- a/plugins/_bundled/sirsoft-verification_nhnkcp/AGENTS.md +++ b/plugins/_bundled/sirsoft-verification_nhnkcp/AGENTS.md @@ -132,6 +132,7 @@ FormRequest 검증과 Service 저장이 서로 다른 파이프라인 단계이 - [ ] 데스크톱/모바일 분기(`isMobileEnvironment()`)를 고칠 때 양쪽 복귀 경로(팝업 종료 감지 / `redirectStash` 복원)를 함께 테스트 - [ ] `duplicate_field`/`duplicate_block_enabled` 로직을 고치면 `KcpDuplicateField` Enum 과 `AssertNoDuplicateKcpIdentity`를 함께 갱신 - [ ] `normalizeLiveSiteCd()`/`addLiveModeRules()`를 고칠 때 두 훅(`filter_save_data`/`update_validation_rules`)의 실행 순서(검증 먼저, 정규화는 저장 시점)를 유지 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec.json` 을 함께 갱신 — 샘플이 없는 `data_source` 는 편집기 캔버스에서만 빈 화면이 되고 실제 화면은 정상이라 오류도 경고도 남지 않는다. 반영은 `php artisan plugin:update sirsoft-verification_nhnkcp --force` ## 6. 금지 패턴 @@ -184,6 +185,7 @@ npx playwright test plugins/_bundled/sirsoft-verification_nhnkcp/tests/Playwrigh | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-verification_nhnkcp/CHANGELOG.md b/plugins/_bundled/sirsoft-verification_nhnkcp/CHANGELOG.md index 71fcf931..dbe7af2f 100644 --- a/plugins/_bundled/sirsoft-verification_nhnkcp/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-verification_nhnkcp/CHANGELOG.md @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [1.0.1] - 2026-08-19 diff --git a/plugins/_bundled/sirsoft-verification_nhnkcp/README.md b/plugins/_bundled/sirsoft-verification_nhnkcp/README.md index 2f42090d..2bc488e5 100644 --- a/plugins/_bundled/sirsoft-verification_nhnkcp/README.md +++ b/plugins/_bundled/sirsoft-verification_nhnkcp/README.md @@ -1,13 +1,13 @@ # NHN KCP 휴대폰 본인확인 -**G7 플러그인 · sirsoft-verification_nhnkcp** -NHN KCP 휴대폰 본인확인(V2 REST)을 G7 코어 IDV 인프라에 Provider 로 등록하는 플러그인 +**그누보드7 플러그인 · sirsoft-verification_nhnkcp** +NHN KCP 휴대폰 본인확인(V2 REST)을 그누보드7 코어 IDV 인프라에 Provider 로 등록하는 플러그인

version 1.0.2 type 플러그인 - G7 >=7.0.6 + 그누보드7 >=7.0.6 license MIT

@@ -21,7 +21,7 @@ NHN KCP 휴대폰 본인확인(V2 REST)을 G7 코어 IDV 인프라에 Provider ## 소개 -NHN KCP 휴대폰 본인확인을 G7 코어의 본인인증(IDV) 체계에 연결하는 플러그인입니다. +NHN KCP 휴대폰 본인확인을 그누보드7 코어의 본인인증(IDV) 체계에 연결하는 플러그인입니다. `sirsoft-verification_kginicis`와 같은 부류(코어 표준 인터페이스 구현)지만 다른 벤더이며, 운영자는 둘 중 하나 또는 둘 다 설치해 사용할 수 있습니다. @@ -73,7 +73,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.6` | +| 그누보드7 코어 | `>=7.0.6` | | PHP | `^8.2` | @@ -161,6 +161,7 @@ php artisan plugin:update sirsoft-verification_nhnkcp --force | [docs/data-model.md](docs/data-model.md) | 모델·소유 테이블·마이그레이션·Enum | ✅ | | [docs/settings.md](docs/settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | ✅ | | [docs/frontend.md](docs/frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [docs/api/](docs/api/README.md) | API 레퍼런스 (엔드포인트별 파라미터·응답 필드) | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/plugins/_bundled/sirsoft-verification_nhnkcp/docs/README.md b/plugins/_bundled/sirsoft-verification_nhnkcp/docs/README.md index a9c0e86d..86888b4f 100644 --- a/plugins/_bundled/sirsoft-verification_nhnkcp/docs/README.md +++ b/plugins/_bundled/sirsoft-verification_nhnkcp/docs/README.md @@ -16,6 +16,7 @@ | [data-model.md](data-model.md) | 모델·소유 테이블·마이그레이션·Enum | | [settings.md](settings.md) | 설정 스키마·권한·메뉴·라우트·의존 관계 | | [frontend.md](frontend.md) | 레이아웃·액션 핸들러·전역 진입점·에셋 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [api/](api/README.md) | API 레퍼런스 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/plugins/_bundled/sirsoft-verification_nhnkcp/docs/editor-spec.md b/plugins/_bundled/sirsoft-verification_nhnkcp/docs/editor-spec.md new file mode 100644 index 00000000..d6852227 --- /dev/null +++ b/plugins/_bundled/sirsoft-verification_nhnkcp/docs/editor-spec.md @@ -0,0 +1,113 @@ +# NHN KCP 휴대폰 본인확인 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `plugins/_bundled/sirsoft-verification_nhnkcp/editor-spec.json` | +| 형태 | 단일 파일 (인라인) | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | - | +| 다크 모드 전략 | - | + +> NHN KCP 휴대폰 본인확인 플러그인 레이아웃 편집기 샘플 데이터. + + + +NHN KCP 휴대폰 본인확인 Provider 플러그인은 코어 IDV 인프라에 자기 Provider 를 등록하는 것이 본체이고, +화면은 관리자 설정과 **사용자 화면에 뜨는 인증 창**입니다. 그래서 스펙이 담는 것도 그 +두 자리뿐입니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `editor-spec.json (인라인)` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 3 | `editor-spec.json (인라인)` | + + + +`byDataSourceId` 는 `nhnkcpRecord` 하나입니다 — 인증 결과 레코드를 화면에 보여 주는 자리입니다. +인증 정책·목적·메시지는 코어 IDV 가 소유하고 admin 템플릿 스펙이 그 샘플을 채우므로 +여기서 다시 선언하지 않습니다. + +`states.groups` 가 3종인 것이 이 플러그인의 특징입니다. 인증은 **여러 화면에 걸쳐 +나타나는 기능**이라 설정 화면 하나로 끝나지 않습니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 `componentPalette` 를 선언하지 않습니다 — 편집기 팔레트에 추가되는 항목이 없습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일입니다. 모듈·플러그인은 레이아웃 JSON 에서 템플릿이 +제공하는 컴포넌트를 **쓰기만** 하므로, 편집기 팔레트에 새로 얹을 것이 없습니다. 그래서 이 +확장의 스펙은 `componentPalette`·`controls`·`componentCapabilities`·`nesting` 을 비우고 +**도메인 데이터**(`sampleData`·`states`)만 담습니다. + +팔레트에 무언가를 추가하고 싶다면 그것은 이 확장이 아니라 활성 템플릿 +(`sirsoft-admin_basic` / `sirsoft-basic`)의 스펙에 가야 합니다. 여기에 팔레트를 선언하면 +템플릿 선언과 같은 자리를 두고 다투게 되고, 어느 쪽이 이기는지가 합본 순서에 좌우됩니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 1 | `nhnkcpRecord` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 3 | `*/mypage/profile` · `*/admin/plugins/sirsoft-verification_nhnkcp/settings` · `_user_base` | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +상태 범위는 `*/mypage/profile` · `*/admin/plugins/sirsoft-verification_nhnkcp/settings` · `_user_base` 입니다. `_user_base` 가 들어 있는 것이 핵심입니다 — 본인인증 +요구는 특정 라우트가 아니라 **어느 화면에서든 428 응답으로 발생**할 수 있고, 그때 뜨는 +인증 창은 베이스 레이아웃 위에 얹힙니다. + +편집기 캔버스는 실제 428 응답을 받지 않으므로, 그 상태를 변종으로 주입해 두지 않으면 +인증 창이 화면에 나타나지 않아 **편집할 방법이 없습니다.** + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan plugin:update sirsoft-verification_nhnkcp --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +인증 창의 모양을 바꿨다면 이 스펙만으로는 끝나지 않습니다. 인증 창을 여는 주체는 +템플릿 부트스트랩이 등록한 launcher 이므로, launcher 가 여는 화면과 여기 상태 변종이 +가리키는 화면이 같은지 함께 확인합니다. + diff --git a/templates/_bundled/gnuboard7-hello_admin_template/AGENTS.md b/templates/_bundled/gnuboard7-hello_admin_template/AGENTS.md index f1c7bb69..7417390b 100644 --- a/templates/_bundled/gnuboard7-hello_admin_template/AGENTS.md +++ b/templates/_bundled/gnuboard7-hello_admin_template/AGENTS.md @@ -116,6 +116,7 @@ SSoT 는 코어 `config/template.php` 의 `required_admin_components` 입니다. - [ ] TSX 를 고쳤다면 `template:build --production` 후 `dist/` 동반 커밋 (`sourceMappingURL` 잔존 금지) - [ ] `docs/extension/sample-extensions.md` 의 계층 표와 어긋나지 않는지 확인 - [ ] 레이아웃 렌더링 테스트(`__tests__/layouts/*.test.tsx`)는 이 템플릿 디렉토리에 둔다 — 코어 디렉토리에 두지 않는다 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어도 되는 상태(공용 ID 만 사용)다. 이 확장만 쓰는 `data_source` 를 새로 붙이는 순간 `editor-spec.json` 신설이 필요해진다 ## 6. 금지 패턴 @@ -161,5 +162,6 @@ cd templates/_bundled/gnuboard7-hello_admin_template && powershell -Command "npm | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/gnuboard7-hello_admin_template/CHANGELOG.md b/templates/_bundled/gnuboard7-hello_admin_template/CHANGELOG.md index 6f524ce7..3f28fd64 100644 --- a/templates/_bundled/gnuboard7-hello_admin_template/CHANGELOG.md +++ b/templates/_bundled/gnuboard7-hello_admin_template/CHANGELOG.md @@ -10,6 +10,8 @@ - 아이콘(Font Awesome)을 템플릿에 함께 담아 외부 CDN 없이 동작합니다. - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [0.1.0] - 2026-07-01 diff --git a/templates/_bundled/gnuboard7-hello_admin_template/README.md b/templates/_bundled/gnuboard7-hello_admin_template/README.md index dbc76e8e..dd1b4370 100644 --- a/templates/_bundled/gnuboard7-hello_admin_template/README.md +++ b/templates/_bundled/gnuboard7-hello_admin_template/README.md @@ -1,13 +1,13 @@ # Hello Admin Template -**G7 템플릿 · gnuboard7-hello_admin_template** +**그누보드7 템플릿 · gnuboard7-hello_admin_template** 그누보드7 학습용 최소 Admin 템플릿 스켈레톤

version 0.1.1 type 템플릿 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -72,7 +72,7 @@ flowchart TD | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | @@ -156,6 +156,7 @@ php artisan template:activate gnuboard7-hello_admin_template | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/gnuboard7-hello_admin_template/docs/README.md b/templates/_bundled/gnuboard7-hello_admin_template/docs/README.md index aa58a292..3e09d714 100644 --- a/templates/_bundled/gnuboard7-hello_admin_template/docs/README.md +++ b/templates/_bundled/gnuboard7-hello_admin_template/docs/README.md @@ -15,6 +15,7 @@ | [components.md](components.md) | 템플릿이 제공하는 컴포넌트 | | [layouts.md](layouts.md) | 레이아웃 목록과 라우트 매핑 | | [handlers.md](handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/templates/_bundled/gnuboard7-hello_admin_template/docs/editor-spec.md b/templates/_bundled/gnuboard7-hello_admin_template/docs/editor-spec.md new file mode 100644 index 00000000..fb188458 --- /dev/null +++ b/templates/_bundled/gnuboard7-hello_admin_template/docs/editor-spec.md @@ -0,0 +1,85 @@ +# Hello Admin Template — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +학습용 관리자 템플릿이라 편집기 스펙을 두지 않았습니다. 이 템플릿의 목적은 관리자 +템플릿의 최소 구조(레이아웃·라우트·베이스 레이아웃)를 보여 주는 것이고, 편집기 스펙은 +그 위에 얹히는 별개 축입니다. + +실제 관리자 템플릿이 스펙으로 무엇을 선언하는지는 `sirsoft-admin_basic` 의 같은 문서를 +봅니다 — 팔레트 79 · 컨트롤 303 · 역량 86 이 그 규모입니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 팔레트·컨트롤·역량·중첩을 선언하지 않았으므로 이 템플릿을 +활성화한 상태에서는 편집기가 다룰 컴포넌트 어휘가 없습니다. + +이것이 "템플릿이 편집기 스펙을 갖는다" 는 규율의 의미입니다 — 스펙은 편집기의 부가 +기능이 아니라 **편집기가 그 템플릿에서 동작하기 위한 어휘 자체**입니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +미커버가 없습니다. 이 템플릿의 레이아웃에는 `data_source` 자체가 없기 때문입니다 — +정적 화면만으로 구성된 학습용 골격이라 붙일 데이터가 없습니다. + +미커버 0 이 곧 "편집기에서 온전히 보인다" 를 뜻하지는 않습니다. 여기서는 그릴 데이터가 +애초에 없다는 뜻입니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +이 템플릿을 실제 사용 템플릿으로 발전시킨다면 편집기 스펙 신설이 **가장 먼저** 필요한 +작업 중 하나입니다. 템플릿의 스펙은 모듈·플러그인과 달리 도메인 데이터가 아니라 +**컴포넌트 어휘**(팔레트·컨트롤·역량·중첩)를 담기 때문입니다. + +신설 순서는 `componentPalette` → `nesting` → `componentCapabilities` → `controls` +입니다. 앞의 둘이 없으면 편집기에서 컴포넌트를 놓을 수조차 없고, 뒤의 둘은 놓은 다음에 +속성을 바꾸기 위한 것입니다. `sirsoft-admin_basic/editor-spec/` 의 13개 블록 파일이 +완성된 형태의 선례입니다. + diff --git a/templates/_bundled/gnuboard7-hello_user_template/AGENTS.md b/templates/_bundled/gnuboard7-hello_user_template/AGENTS.md index e2189880..0f80b452 100644 --- a/templates/_bundled/gnuboard7-hello_user_template/AGENTS.md +++ b/templates/_bundled/gnuboard7-hello_user_template/AGENTS.md @@ -23,7 +23,7 @@ **홈 화면이 이 샘플의 핵심**입니다. `data_sources` 로 학습용 모듈의 메모 API (`/api/modules/gnuboard7-hello_module/memos`)를 호출해 목록을 그립니다 — 모듈이 데이터를, -템플릿이 화면을 담당하는 G7 의 기본 경계를 가장 짧게 보여주는 예시입니다. 실제 게시판·이커머스 +템플릿이 화면을 담당하는 그누보드7 의 기본 경계를 가장 짧게 보여주는 예시입니다. 실제 게시판·이커머스 모듈도 방문자 화면을 갖지 않고 같은 방식으로 템플릿에 맡깁니다. `manifest.hidden = true` 라 관리자 UI 의 템플릿 목록에 나타나지 않습니다. artisan CLI 로는 @@ -117,6 +117,7 @@ User 템플릿은 자기가 그리고 싶은 화면에 필요한 API 를 `data_s - [ ] `manifest.hidden = true` 를 유지 (복제본에서만 제거) - [ ] TSX 를 고쳤다면 `template:build --production` 후 `dist/` 동반 커밋 (`sourceMappingURL` 잔존 금지) - [ ] 레이아웃 렌더링 테스트(`__tests__/layouts/*.test.tsx`)는 이 템플릿 디렉토리에 둔다 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 를 확인 — 이 확장은 편집기 스펙이 없어 `memos` 가 편집기 캔버스에서 빈 화면으로 보인다. `data_source` 를 더 늘리면 그 자리도 같은 상태가 된다 ## 6. 금지 패턴 @@ -163,5 +164,6 @@ cd templates/_bundled/gnuboard7-hello_user_template && powershell -Command "npm | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/gnuboard7-hello_user_template/CHANGELOG.md b/templates/_bundled/gnuboard7-hello_user_template/CHANGELOG.md index 967eecf8..920ee9b9 100644 --- a/templates/_bundled/gnuboard7-hello_user_template/CHANGELOG.md +++ b/templates/_bundled/gnuboard7-hello_user_template/CHANGELOG.md @@ -10,6 +10,8 @@ - 아이콘(Font Awesome)을 템플릿에 함께 담아 외부 CDN 없이 동작합니다. - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ## [0.1.0] - 2026-07-01 diff --git a/templates/_bundled/gnuboard7-hello_user_template/README.md b/templates/_bundled/gnuboard7-hello_user_template/README.md index ed78a42b..ab5cd7b3 100644 --- a/templates/_bundled/gnuboard7-hello_user_template/README.md +++ b/templates/_bundled/gnuboard7-hello_user_template/README.md @@ -1,13 +1,13 @@ # Hello 사용자 템플릿 -**G7 템플릿 · gnuboard7-hello_user_template** +**그누보드7 템플릿 · gnuboard7-hello_user_template** 학습용 최소 샘플 사용자 템플릿 (Basic 8개 컴포넌트)

version 0.1.1 type 템플릿 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT requires gnuboard7-hello_module

@@ -80,7 +80,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 의존 모듈 | `gnuboard7-hello_module` `>=0.1.0` | @@ -167,6 +167,7 @@ php artisan template:activate gnuboard7-hello_user_template | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/gnuboard7-hello_user_template/docs/README.md b/templates/_bundled/gnuboard7-hello_user_template/docs/README.md index 8c280451..3b5ea646 100644 --- a/templates/_bundled/gnuboard7-hello_user_template/docs/README.md +++ b/templates/_bundled/gnuboard7-hello_user_template/docs/README.md @@ -15,6 +15,7 @@ | [components.md](components.md) | 템플릿이 제공하는 컴포넌트 | | [layouts.md](layouts.md) | 레이아웃 목록과 라우트 매핑 | | [handlers.md](handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/templates/_bundled/gnuboard7-hello_user_template/docs/editor-spec.md b/templates/_bundled/gnuboard7-hello_user_template/docs/editor-spec.md new file mode 100644 index 00000000..524c9d3a --- /dev/null +++ b/templates/_bundled/gnuboard7-hello_user_template/docs/editor-spec.md @@ -0,0 +1,80 @@ +# Hello 사용자 템플릿 — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +_이 확장은 편집기 스펙(`editor-spec.json`)을 두지 않습니다. 편집기는 코어 기본 팔레트와 활성 템플릿의 스펙만으로 이 확장의 화면을 다룹니다._ + + + +학습용 사용자 템플릿이라 편집기 스펙을 두지 않았습니다. 실제 사용자 템플릿이 무엇을 +선언하는지는 `sirsoft-basic` 의 같은 문서를 봅니다 — 팔레트 45 · 상태 범위 17 이 그 +규모입니다. + + +## 선언 블록 + + +_선언된 편집기 스펙 블록이 없습니다._ + + + +선언한 블록이 없습니다. 팔레트·중첩을 선언하지 않았으므로 이 템플릿을 활성화한 상태에서는 +편집기가 놓을 수 있는 컴포넌트가 없습니다. + + +## 컴포넌트 팔레트 + + +_이 확장은 편집기 팔레트에 항목을 추가하지 않습니다._ + + + +컴포넌트를 만드는 것은 템플릿의 일이므로, 이 확장이 팔레트에 얹을 것은 원래 없습니다. +편집기 팔레트는 활성 템플릿의 스펙이 정합니다 — 이 확장에 편집기 스펙이 생기더라도 +`componentPalette` 는 여전히 비어 있을 것입니다. + + +## 샘플 데이터와 페이지 상태 + + +_이 확장은 편집기 스펙을 두지 않아 선언된 샘플 데이터·페이지 상태가 없습니다._ + +**프리뷰 샘플이 없는 `data_source` 1개** — 편집기 캔버스에서 이 자리만 빈 화면이 됩니다. 실제 화면은 정상이라 오류도 경고도 남지 않습니다. + +`memos` + + + +`memos` 가 미커버입니다. 이 템플릿은 `gnuboard7-hello_module` 의 메모 목록을 화면에 +그리는데, 그 데이터의 프리뷰 샘플을 어느 쪽도 선언하지 않았기 때문입니다. + +이 한 건이 모듈과 템플릿의 역할 분담을 그대로 보여 줍니다 — 데이터를 주는 것은 모듈이고 +그리는 것은 템플릿이라, 샘플을 어느 쪽에 둘지 판단이 필요합니다. `memos` 를 이 템플릿만 +쓴다면 템플릿 스펙에, 여러 템플릿이 쓴다면 모듈 스펙에 둡니다. + + +## 수정 시 동반 의무 + + +_이 확장은 아직 편집기 스펙을 두지 않습니다. 아래 변경이 생기면 `editor-spec.json` 을 신설합니다._ + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + + + +이 템플릿을 실제 사용 템플릿으로 발전시킨다면 편집기 스펙 신설이 필요합니다. 템플릿 +스펙은 **컴포넌트 어휘**(팔레트·중첩·역량·컨트롤)를 담고, 거기에 이 템플릿이 그리는 +화면의 `sampleData` 를 더합니다. + +신설 순서는 `componentPalette` → `nesting` → `componentCapabilities` → `controls` +입니다. `sirsoft-basic/editor-spec/` 의 13개 블록 파일이 완성된 형태의 선례입니다. + diff --git a/templates/_bundled/sirsoft-admin_basic/AGENTS.md b/templates/_bundled/sirsoft-admin_basic/AGENTS.md index 27548884..b3596452 100644 --- a/templates/_bundled/sirsoft-admin_basic/AGENTS.md +++ b/templates/_bundled/sirsoft-admin_basic/AGENTS.md @@ -15,7 +15,7 @@ ## 1. 이 확장은 무엇인가 -G7 이 기본 제공하는 유일한 admin 타입 템플릿입니다 — 코어 관리자 화면(대시보드·사용자·역할· +그누보드7 이 기본 제공하는 유일한 admin 타입 템플릿입니다 — 코어 관리자 화면(대시보드·사용자·역할· 설정·확장 관리 등)뿐 아니라 **모든 번들 모듈/플러그인의 관리자 레이아웃**(`resources/layouts/ admin/`)이 이 템플릿의 베이스(`_admin_base`)를 extends 하고 이 템플릿의 컴포넌트로 그려집니다. 그래서 이 템플릿의 공개 계약(필수 컴포넌트 35개, `_admin_base` 슬롯 구조)을 깨면 코어가 @@ -102,6 +102,7 @@ admin/`)이 이 템플릿의 베이스(`_admin_base`)를 extends 하고 이 템 - [ ] 필수 컴포넌트(35개) 의 Props 시그니처를 깨는 변경은 전체 번들 확장 관리자 화면에 영향 — 변경 전 `src/components/{basic,composite}/` 의 실사용처를 넓게 확인 - [ ] `_admin_base.json` 슬롯 구조(`content` 슬롯 등) 변경 시 그 슬롯에 의존하는 모든 화면(145개 레이아웃 대다수) 영향 검토 - [ ] AdminSidebar 의 `MenuItem`/`AdminSidebarProps` 인터페이스 확장 시 이 문서의 §docs/components.md "AdminSidebar 상세" 동기화 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec/` 블록을 함께 갱신 — 컴포넌트는 팔레트·역량·중첩 **넷 다** 손대야 편집기에서 온전히 동작하고, 하나만 빠지면 절반만 동작한다. 반영은 `php artisan template:update sirsoft-admin_basic --force` (편집기는 활성 디렉토리만 읽는다) ## 6. 금지 패턴 @@ -146,5 +147,6 @@ npx playwright test templates/_bundled/sirsoft-admin_basic/tests/Playwright/spec | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/sirsoft-admin_basic/CHANGELOG.md b/templates/_bundled/sirsoft-admin_basic/CHANGELOG.md index 2ade5f23..aef6171f 100644 --- a/templates/_bundled/sirsoft-admin_basic/CHANGELOG.md +++ b/templates/_bundled/sirsoft-admin_basic/CHANGELOG.md @@ -14,6 +14,8 @@ - 확장(템플릿·모듈·플러그인)을 제거할 때 `custom/` 에 넣어 둔 파일의 사본이 보관되며, 제거 창이 그 보관 경로를 보여 줍니다. 보관된 파일이 없으면 창은 종전대로 곧바로 닫힙니다. - 환경설정 > 고급 에 리버스 프록시 진단이 추가되었습니다. 사이트가 받고 있는 프록시 정보, HTTPS 인식 여부, 방문자 IP 로 인식된 값과 직전 호출 IP 를 나란히 보여 줍니다. 읽기 전용이며 값은 `.env` 에서만 변경합니다. - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ### Changed diff --git a/templates/_bundled/sirsoft-admin_basic/README.md b/templates/_bundled/sirsoft-admin_basic/README.md index 669ff4fb..4432afd4 100644 --- a/templates/_bundled/sirsoft-admin_basic/README.md +++ b/templates/_bundled/sirsoft-admin_basic/README.md @@ -1,13 +1,13 @@ # Admin Basic -**G7 템플릿 · sirsoft-admin_basic** +**그누보드7 템플릿 · sirsoft-admin_basic** 그누보드7 기본 관리자 템플릿

version 1.0.8 type 템플릿 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT

@@ -21,7 +21,7 @@ ## 소개 -G7 이 기본 제공하는 관리자(admin) 템플릿입니다. 코어 관리자 화면뿐 아니라 설치된 모든 +그누보드7 이 기본 제공하는 관리자(admin) 템플릿입니다. 코어 관리자 화면뿐 아니라 설치된 모든 모듈/플러그인의 관리자 화면이 이 템플릿의 컴포넌트와 베이스 레이아웃을 그대로 사용합니다 — 확장을 설치하면 그 확장의 관리자 UI 도 자동으로 이 템플릿의 디자인(사이드바·헤더·색상·다크 모드)을 따릅니다. @@ -68,7 +68,7 @@ flowchart TD | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | @@ -157,6 +157,7 @@ formal 의존성이 양쪽 다 "없음"인 것은 이 템플릿이 코어만으 | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/sirsoft-admin_basic/docs/README.md b/templates/_bundled/sirsoft-admin_basic/docs/README.md index 91fef5af..96fc6f73 100644 --- a/templates/_bundled/sirsoft-admin_basic/docs/README.md +++ b/templates/_bundled/sirsoft-admin_basic/docs/README.md @@ -15,6 +15,7 @@ | [components.md](components.md) | 템플릿이 제공하는 컴포넌트 | | [layouts.md](layouts.md) | 레이아웃 목록과 라우트 매핑 | | [handlers.md](handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/templates/_bundled/sirsoft-admin_basic/docs/editor-spec.md b/templates/_bundled/sirsoft-admin_basic/docs/editor-spec.md new file mode 100644 index 00000000..313ff302 --- /dev/null +++ b/templates/_bundled/sirsoft-admin_basic/docs/editor-spec.md @@ -0,0 +1,151 @@ +# Admin Basic — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `templates/_bundled/sirsoft-admin_basic/editor-spec.json` | +| 형태 | 분할 — manifest + `editor-spec/*.json` 13개 블록 | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | `tailwind` | +| 다크 모드 전략 | `ancestor-class` | + +> 레이아웃 편집기 스펙 — Phase 3 (nesting + componentPalette 블록). controls/componentCapabilities/actionRecipes 등은 Phase 4/5 에서 추가. + + + +이 스펙만 **분할**되어 있는 데는 이유가 있습니다. 팔레트·컨트롤·컴포넌트 역량을 한 파일에 +두면 만 줄을 넘겨 사람이 열어 보기 어려워지고, 블록 하나를 고칠 때마다 파일 전체가 diff 에 +잡힙니다. `$include` 는 그 분할을 런타임에 되돌리는 장치이므로 서빙 형태는 단일 파일과 +같습니다. + +`다크 모드 전략: ancestor-class` 는 Tailwind 규약(`조상 .dark`)을 그대로 따른다는 뜻입니다. +편집기 프리뷰는 페이지 전체가 아니라 캔버스 안만 다크로 바꿔야 하므로, 코어 CSS 서빙이 +`.dark` 셀렉터를 프리뷰 전용 마커로 치환해 내보냅니다 — 사용자 페이지 CSS 는 건드리지 +않습니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `componentPalette.entries` | 편집기 "요소 추가" 팔레트에 나타나는 항목 | 79 | `editor-spec/componentPalette.json` | +| `componentPalette.groups` | 팔레트 좌측 목록의 묶음 | 2 | `editor-spec/componentPalette.json` | +| `controls` | 재사용 스타일 컨트롤 정의 | 303 | `editor-spec/controls.json` | +| `componentCapabilities` | 컴포넌트별 편집 역량(어떤 속성을 편집기가 다루는가) | 86 | `editor-spec/componentCapabilities.json` | +| `nesting.draggable` | 캔버스에서 끌어 옮길 수 있는 컴포넌트 | 84 | `editor-spec/nesting.json` | +| `nesting.containers` | 자식을 담을 수 있는 컴포넌트와 그 허용 규칙 | 19 | `editor-spec/nesting.json` | +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 70 | `editor-spec/sampleData.json` | +| `sampleGlobal` | `_global.*` 프리뷰 baseline 시드 | 5 | `editor-spec/sampleGlobal.json` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 10 | `editor-spec/states.json` | +| `stateLabels` | 상태값 친화 명칭 카탈로그 | 8 | `editor-spec/stateLabels.json` | +| `actionRecipes` | 친화 명칭 → 액션 JSON 레시피 | 14 | `editor-spec/actionRecipes.json` | +| `conditionRecipes.operators` | 조건 표현식에 쓸 수 있는 연산자 | 35 | `editor-spec/conditionRecipes.json` | +| `computedRecipes` | 계산값 레시피 | 4 | `editor-spec/computedRecipes.json` | +| `errorRecipes` | 오류 처리 레시피 | 7 | `editor-spec/errorRecipes.json` | +| `loadingComponents` | 로딩 표시 컴포넌트 후보 | 2 | `editor-spec/loadingComponents.json` | + + + +블록 15행이 이 템플릿이 편집기에 제공하는 전부입니다. 수가 큰 셋(`controls` 303, +`componentCapabilities` 86, `nesting.draggable` 84)이 곧 "편집기로 무엇을 조작할 수 +있는가" 의 상한입니다 — 여기 없는 속성은 편집기 속성 패널에 나타나지 않습니다. + +컴포넌트를 새로 만들었는데 편집기에서 속성을 못 바꾸겠다면 `componentCapabilities` 에 +그 컴포넌트가 없는 것입니다. 팔레트에 아예 안 보인다면 `componentPalette.entries` 입니다. +둘은 다른 자리라 한쪽만 고치면 증상이 절반만 사라집니다. + + +## 컴포넌트 팔레트 + + +| 그룹 | 종류 | 컴포넌트 수 | +|---|---|---| +| 디자인 요소 | `design` | 62 | +| DB 요소 | `data` | 17 | + + + +그룹을 `디자인 요소`(62)와 `DB 요소`(17) 둘로만 나눈 것은 운영자가 편집기에서 하는 +판단이 그 둘로 갈리기 때문입니다 — "모양을 만드는 것" 과 "데이터를 붙이는 것". + +그룹을 늘리면 팔레트가 잘 정리된 것처럼 보이지만, 운영자는 찾으려는 컴포넌트가 어느 +묶음에 있는지 매번 추측하게 됩니다. 컴포넌트를 추가할 때는 새 그룹을 만들기 전에 기존 +두 그룹 중 어디에 속하는지 먼저 판단합니다. + +팔레트에 **무엇이 보이는가**를 정하는 것은 `groups` 입니다. `entries` 는 그 컴포넌트의 +친화 라벨과 신규 노드 골격(`defaultNode`)을 줄 뿐이라, `entries` 에만 있고 어느 묶음에도 +없는 컴포넌트는 팔레트에 나타나지 않습니다. 반대로 `groups` 에만 있고 `entries` 가 없는 +것은 정상이며, 라벨이 컴포넌트 정의의 설명으로 폴백됩니다. + +지금은 두 수가 우연히 같지만(entries 79 · 그룹 합계 62+17=79), 같아야 한다는 규칙은 없습니다. 컴포넌트를 +추가했는데 팔레트에 안 보인다면 먼저 `groups` 를 봅니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 70 | `sitemap_status` · `sitemap_progress_ws` · `locales` · `me` · `installed_modules` · `active_plugins` · `users` · `roles` · `availableChannels` · `identityProviders` · `identityPurposes` · `identityPolicies` … 외 58개 | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 미선언 | - | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 10 | `_admin_base` · `*/admin/users` · `*/admin/users/:id/edit` · `*/admin/settings` · `*/admin/reset-password` · `*/admin/roles/:id/edit` · `*/admin/identity/challenge` · `*/admin/templates/:type` · `*/admin/login` · `*/admin/forgot-password` | + +**프리뷰 샘플이 없는 `data_source` 1개** — 편집기 캔버스에서 이 자리만 빈 화면이 됩니다. 실제 화면은 정상이라 오류도 경고도 남지 않습니다. + +`trustedProxy` + + + +`byDataSourceId` 70종은 코어 관리자 화면 전체를 덮습니다. 이 템플릿의 샘플이 코어뿐 +아니라 **여러 확장의 공용 ID**(`settings`·`roles`·`me` 등)까지 담는 것은 설계입니다 — +확장마다 같은 ID 의 샘플을 각자 두면 어느 것이 쓰이는지가 합본 순서에 좌우됩니다. + +`states.groups` 10종에 `_admin_base` 가 들어 있는 것은 모바일 드로어 때문입니다. +드로어는 햄버거를 눌러야 열리는데 편집기 캔버스에는 클릭이 없으므로, 열린 상태를 주입하지 +않으면 드로어 **안쪽을 편집할 수 없습니다.** + +미커버로 잡힌 `trustedProxy` 는 신뢰 프록시 진단 영역입니다. 이 영역은 서버 구성에 따라 +내용이 달라지는 읽기 전용 진단이라 편집기에서 손댈 것이 없지만, 샘플이 없으면 그 자리가 +빈 채로 보여 운영자가 레이아웃이 깨진 것으로 오해할 수 있습니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan template:update sirsoft-admin_basic --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +이 템플릿은 팔레트·역량·중첩을 모두 소유하므로 컴포넌트를 하나 추가할 때 손댈 자리가 +가장 많습니다. `componentPalette.entries` 에 넣고, `componentPalette.groups` 중 하나에 +이름을 넣고, `componentCapabilities` 에 편집 가능한 속성을 선언하고, `nesting` 에 +어디에 담길 수 있는지를 적습니다. 넷 중 하나라도 빠지면 그 컴포넌트는 편집기에서 +**절반만 동작**하고, 어느 단계가 빠졌는지는 증상으로 구분됩니다 (위 "선언 블록" 절 참조). + diff --git a/templates/_bundled/sirsoft-basic/AGENTS.md b/templates/_bundled/sirsoft-basic/AGENTS.md index 1d098560..24709d18 100644 --- a/templates/_bundled/sirsoft-basic/AGENTS.md +++ b/templates/_bundled/sirsoft-basic/AGENTS.md @@ -134,6 +134,7 @@ API 까지만 소유하고, 그 API 를 소비해 실제로 그리는 것은 이 - [ ] `extensions/sirsoft-daum_postcode/` 오버라이드는 원본이 바뀌어도 따라가지 않는다 — 그 플러그인 업그레이드 후 확인 - [ ] TSX/TS 를 고쳤다면 `template:build --production` 후 `dist/` 동반 커밋 (`sourceMappingURL` 잔존 금지) - [ ] 프론트엔드 변경은 Playwright spec 동반 — 단위 테스트만으로는 화면 회귀가 드러나지 않는다 +- [ ] 레이아웃·컴포넌트·`data_source` 를 건드렸다면 [`docs/editor-spec.md`](docs/editor-spec.md) 의 동반 의무 표를 따라 `editor-spec/` 블록을 함께 갱신 — 컴포넌트는 팔레트·역량·중첩 **넷 다** 손대야 편집기에서 온전히 동작하고, 하나만 빠지면 절반만 동작한다. 반영은 `php artisan template:update sirsoft-basic --force` (편집기는 활성 디렉토리만 읽는다) ## 6. 금지 패턴 @@ -183,5 +184,6 @@ npx playwright test templates/_bundled/sirsoft-basic/tests/Playwright/specs/<대 | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/sirsoft-basic/CHANGELOG.md b/templates/_bundled/sirsoft-basic/CHANGELOG.md index 12b3443e..0a6364b2 100644 --- a/templates/_bundled/sirsoft-basic/CHANGELOG.md +++ b/templates/_bundled/sirsoft-basic/CHANGELOG.md @@ -12,6 +12,8 @@ - 이미지 업로드 시 쓰는 압축 라이브러리도 함께 담아, 업로드할 때마다 외부로 나가던 요청이 없어졌습니다. - 검색엔진 크롤러가 보는 페이지도 같은 아이콘 파일을 사이트 자신의 주소에서 불러옵니다. - 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다. +- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다. +- 문서의 제품 표기를 「그누보드7」로 통일했습니다. ### Fixed diff --git a/templates/_bundled/sirsoft-basic/README.md b/templates/_bundled/sirsoft-basic/README.md index 8bdffc19..bdffe7de 100644 --- a/templates/_bundled/sirsoft-basic/README.md +++ b/templates/_bundled/sirsoft-basic/README.md @@ -1,13 +1,13 @@ # Basic -**G7 템플릿 · sirsoft-basic** +**그누보드7 템플릿 · sirsoft-basic** 그누보드7 기본 사용자 템플릿

version 1.1.3 type 템플릿 - G7 >=7.0.10 + 그누보드7 >=7.0.10 license MIT requires sirsoft-board requires sirsoft-ecommerce @@ -87,7 +87,7 @@ flowchart LR | 항목 | 값 | |---|---| -| G7 코어 | `>=7.0.10` | +| 그누보드7 코어 | `>=7.0.10` | | PHP | `^8.2` | | 의존 모듈 | `sirsoft-board` `>=1.0.0` | | 의존 모듈 | `sirsoft-ecommerce` `>=1.1.0` | @@ -182,6 +182,7 @@ php artisan template:update sirsoft-basic --force | [docs/components.md](docs/components.md) | 템플릿이 제공하는 컴포넌트 | ✅ | | [docs/layouts.md](docs/layouts.md) | 레이아웃 목록과 라우트 매핑 | ✅ | | [docs/handlers.md](docs/handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | ✅ | +| [docs/editor-spec.md](docs/editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | ✅ | | [CHANGELOG.md](CHANGELOG.md) | 변경 이력 | ✅ | diff --git a/templates/_bundled/sirsoft-basic/docs/README.md b/templates/_bundled/sirsoft-basic/docs/README.md index 04344852..576e3ac2 100644 --- a/templates/_bundled/sirsoft-basic/docs/README.md +++ b/templates/_bundled/sirsoft-basic/docs/README.md @@ -15,6 +15,7 @@ | [components.md](components.md) | 템플릿이 제공하는 컴포넌트 | | [layouts.md](layouts.md) | 레이아웃 목록과 라우트 매핑 | | [handlers.md](handlers.md) | 템플릿 전용 핸들러와 부트스트랩 | +| [editor-spec.md](editor-spec.md) | 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 | | [../AGENTS.md](../AGENTS.md) | 에이전트·확장개발자 진입점 | | [../README.md](../README.md) | 사람(도입검토자·운영자) 진입점 | diff --git a/templates/_bundled/sirsoft-basic/docs/editor-spec.md b/templates/_bundled/sirsoft-basic/docs/editor-spec.md new file mode 100644 index 00000000..9ad22964 --- /dev/null +++ b/templates/_bundled/sirsoft-basic/docs/editor-spec.md @@ -0,0 +1,139 @@ +# Basic — 레이아웃 편집기 스펙 + +> 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 · 진입점: [AGENTS.md](../AGENTS.md) + +## 선언 요약 + + +| 항목 | 값 | +|---|---| +| manifest | `templates/_bundled/sirsoft-basic/editor-spec.json` | +| 형태 | 분할 — manifest + `editor-spec/*.json` 13개 블록 | +| 스펙 버전 | `1.0.0` | +| 스타일 시스템 | `tailwind` | +| 다크 모드 전략 | `ancestor-class` | + +> 레이아웃 편집기 스펙 — Phase 3 (nesting + componentPalette 블록). controls/componentCapabilities/actionRecipes 등은 Phase 4/5 에서 추가. + + + +사용자 템플릿의 스펙도 관리자 템플릿과 같은 분할 형태입니다. 두 템플릿이 형태를 공유하는 +것은 의도입니다 — 편집기는 어느 템플릿이 활성이든 같은 방식으로 스펙을 읽어야 하고, +템플릿마다 형태가 다르면 편집기가 템플릿별 분기를 갖게 됩니다. + +`다크 모드 전략: ancestor-class` 역시 같습니다. 프리뷰 격리 규칙을 두 템플릿이 공유하므로 +편집기 캔버스의 다크 표현이 템플릿에 따라 달라지지 않습니다. + + +## 선언 블록 + + +| 블록 | 역할 | 항목 수 | 출처 | +|---|---|---|---| +| `componentPalette.entries` | 편집기 "요소 추가" 팔레트에 나타나는 항목 | 45 | `editor-spec/componentPalette.json` | +| `componentPalette.groups` | 팔레트 좌측 목록의 묶음 | 2 | `editor-spec/componentPalette.json` | +| `controls` | 재사용 스타일 컨트롤 정의 | 173 | `editor-spec/controls.json` | +| `componentCapabilities` | 컴포넌트별 편집 역량(어떤 속성을 편집기가 다루는가) | 51 | `editor-spec/componentCapabilities.json` | +| `nesting.draggable` | 캔버스에서 끌어 옮길 수 있는 컴포넌트 | 45 | `editor-spec/nesting.json` | +| `nesting.containers` | 자식을 담을 수 있는 컴포넌트와 그 허용 규칙 | 14 | `editor-spec/nesting.json` | +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 59 | `editor-spec/sampleData.json` | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 1 | `editor-spec/sampleData.json` | +| `sampleGlobal` | `_global.*` 프리뷰 baseline 시드 | 6 | `editor-spec/sampleGlobal.json` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 17 | `editor-spec/states.json` | +| `stateLabels` | 상태값 친화 명칭 카탈로그 | 7 | `editor-spec/stateLabels.json` | +| `actionRecipes` | 친화 명칭 → 액션 JSON 레시피 | 20 | `editor-spec/actionRecipes.json` | +| `conditionRecipes.operators` | 조건 표현식에 쓸 수 있는 연산자 | 37 | `editor-spec/conditionRecipes.json` | +| `computedRecipes` | 계산값 레시피 | 4 | `editor-spec/computedRecipes.json` | +| `errorRecipes` | 오류 처리 레시피 | 7 | `editor-spec/errorRecipes.json` | +| `loadingComponents` | 로딩 표시 컴포넌트 후보 | 2 | `editor-spec/loadingComponents.json` | + + + +블록 16행 중 팔레트가 관리자 템플릿보다 작습니다(45 대 79). 사용자 화면은 관리자 화면보다 +쓰는 컴포넌트가 좁기 때문이고, 이 차이가 곧 두 템플릿이 별개로 존재하는 이유입니다 — +사용자 편집기에 관리자 전용 컴포넌트를 늘어놓으면 운영자가 쓸 수 없는 것을 고르게 됩니다. + +컴포넌트를 추가할 때 "관리자에도 있으니 여기도" 라는 판단은 하지 않습니다. 그 컴포넌트가 +사용자 화면에서 실제로 쓰이는지가 기준입니다. + + +## 컴포넌트 팔레트 + + +| 그룹 | 종류 | 컴포넌트 수 | +|---|---|---| +| 디자인 요소 | `design` | 36 | +| DB 요소 | `data` | 9 | + + + +그룹은 관리자 템플릿과 같은 둘(`디자인 요소` 36 · `DB 요소` 9)입니다. 그룹 체계를 +공유하는 것은 운영자가 두 편집기를 오갈 때 같은 자리에서 같은 종류를 찾게 하기 +위해서입니다. + +팔레트에 **무엇이 보이는가**를 정하는 것은 `groups` 입니다. `entries` 는 그 컴포넌트의 +친화 라벨과 신규 노드 골격(`defaultNode`)을 줄 뿐이라, `entries` 에만 있고 어느 묶음에도 +없는 컴포넌트는 팔레트에 나타나지 않습니다. 반대로 `groups` 에만 있고 `entries` 가 없는 +것은 정상이며, 라벨이 컴포넌트 정의의 설명으로 폴백됩니다. + +지금은 두 수가 우연히 같지만(entries 45 · 그룹 합계 36+9=45), 같아야 한다는 규칙은 없습니다. 컴포넌트를 +추가했는데 팔레트에 안 보인다면 먼저 `groups` 를 봅니다. + + +## 샘플 데이터와 페이지 상태 + + +| 자리 | 역할 | 개수 | ID | +|---|---|---|---| +| `sampleData.byDataSourceId` | 레이아웃 `data_sources` ID 로 붙는 프리뷰 응답 | 59 | `mileage_balance` · `mileage_history` · `user` · `userNotifications` · `searchResults` · `profile` · `userProfile` · `addresses` · `userAddresses` · `boardList` · `boards` · `home_boards` … 외 47개 | +| `sampleData.byEndpointPattern` | 엔드포인트 패턴으로 붙는 프리뷰 응답 | 1 | `/api/modules/sirsoft-page/pages/*` | +| `states.groups` | 상태 변종을 적용할 범위(라우트·베이스 레이아웃) | 17 | `/login` · `/search` · `/mypage/notifications` · `/mypage/profile/edit` · `/forgot-password` · `/reset-password` · `/identity/challenge` · `/mypage/change-password` · `/mypage/wishlist` · `/mypage/addresses` · `/users/:userId` · `/users/:userId/posts` … 외 5개 | + +_이 확장 레이아웃의 `data_source` 는 전부 프리뷰 샘플이 붙습니다 (이 확장 또는 번들 템플릿 스펙이 커버)._ + + + +`byDataSourceId` 59종이 사용자 화면 전반을 덮고, `byEndpointPattern` 1종이 +`sirsoft-page` 의 공개 페이지를 덮습니다. 다른 확장 소유 경로를 이 템플릿이 덮는 것은 +그 화면을 **렌더하는 쪽이 템플릿**이기 때문입니다 — 페이지 모듈은 데이터를 주고, 그리는 +것은 템플릿입니다. + +`states.groups` 17종은 로그인·검색·마이페이지처럼 로그인 여부와 데이터 유무로 화면이 +갈리는 자리입니다. 사용자 화면은 "비어 있는 상태" 가 관리자 화면보다 흔하므로, 새 화면을 +만들 때는 데이터가 있는 경우보다 **없는 경우**를 먼저 상태로 등록합니다. + + +## 수정 시 동반 의무 + + +| 이런 변경을 했다면 | 편집기 스펙에서 함께 할 일 | +|---|---| +| 컴포넌트를 새로 만들었다 | `componentPalette` 에 항목 추가 · `componentCapabilities` 에 편집 역량 선언 · `nesting` 에 담길 자리 규정 | +| 레이아웃에 `data_sources` 를 추가했다 | `sampleData` 에 같은 ID 로 프리뷰 응답 추가 (없으면 편집기 캔버스만 빈 화면) | +| `_global.*` 을 새로 읽는다 | `sampleGlobal` 에 baseline 값 추가 | +| 빈 목록·오류 같은 화면 변종을 추가했다 | `states` 에 변종 추가 · `stateLabels` 에 친화 명칭 | +| 새 액션·조건 패턴을 도입했다 | `actionRecipes` / `conditionRecipes` 에 친화 명칭 등록 | + +편집기 스펙은 JSON 이므로 빌드가 필요 없습니다. 다만 편집기 서빙은 **활성 디렉토리만** 읽으므로(`_bundled` 폴백 없음) 편집 후 반드시 반영합니다: + +```bash +php artisan template:update sirsoft-basic --force +``` + + + +위 표는 "무엇을 함께 고치는가" 만 말합니다. 실제로 놓치는 자리는 **반영 절차**입니다 — +편집기가 읽는 것은 활성 디렉토리이고 `_bundled` 폴백이 없으므로, `_bundled` 에서 스펙을 +고치고 update 커맨드를 돌리지 않으면 편집기에는 **직전 내용이 그대로 보입니다.** 파일은 +고쳤는데 화면이 안 바뀌었다면 거의 이 경우입니다. + +또 하나는 검증 시점입니다. 편집기 스펙은 스키마 검증을 통과해도 "레이아웃이 실제로 쓰는 +ID 와 맞는가" 는 확인해 주지 않습니다. 그 어긋남은 편집기 캔버스에서만 빈 화면으로 +나타나고 실제 화면은 정상이므로, 위 "샘플 데이터와 페이지 상태" 절의 미커버 목록이 유일한 +통로입니다. + +사용자 화면은 모듈이 데이터를 주고 템플릿이 그립니다. 그래서 모듈 레이아웃에 +`data_source` 가 늘었을 때 고칠 자리가 모듈 스펙일 수도, 이 템플릿 스펙일 수도 있습니다. +기준은 그 ID 가 그 모듈만 쓰는가(모듈 스펙), 여러 확장이 함께 쓰는가(템플릿 스펙) +입니다. + diff --git a/tests/Feature/Documentation/ExtensionDocContractTest.php b/tests/Feature/Documentation/ExtensionDocContractTest.php index f448314f..ee6e095b 100644 --- a/tests/Feature/Documentation/ExtensionDocContractTest.php +++ b/tests/Feature/Documentation/ExtensionDocContractTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature\Documentation; use App\Support\ExtensionDoc\DataModelCollector; use App\Support\ExtensionDoc\DeclarativeSurfaceCollector; use App\Support\ExtensionDoc\DependencyGraphCollector; +use App\Support\ExtensionDoc\ExtensionDocContext; use App\Support\ExtensionDoc\ExtensionDocScaffolder; use App\Support\ExtensionDoc\ExtensionInventory; use App\Support\ExtensionDoc\FrontendInventory; @@ -426,6 +427,43 @@ class ExtensionDocContractTest extends TestCase } } + /** + * 빈 서술 축이 PHP 와 검사 스크립트 양쪽에 존재하고 같은 판정을 내려야 합니다. + * + * 미채움은 두 축입니다 — `TODO:` 마커 잔량과, 마커를 지우고 서술을 쓰지 않은 빈 + * `@intent` 블록. 후자가 한쪽에만 있으면 그 도구만 통과시키는데, 결과가 "다 채웠다" + * 와 구분되지 않아 비어 있는 문서가 완비로 집계됩니다. + */ + public function test_empty_intent_axis_agrees_across_tooling(): void + { + $filled = " +서술이 있다. +"; + $empty = " + +"; + + $this->assertSame(0, ExtensionDocScaffolder::emptyIntentBlocks($filled)); + $this->assertSame(1, ExtensionDocScaffolder::emptyIntentBlocks($empty)); + $this->assertSame(2, ExtensionDocScaffolder::emptyIntentBlocks($empty." +".$empty)); + $this->assertSame(1, ExtensionDocScaffolder::emptyIntentBlocks($filled." +".$empty)); + + $script = (string) file_get_contents(base_path('.claude/scripts/check-extension-docs.cjs')); + + $this->assertStringContainsString( + 'countEmptyIntentBlocks', + $script, + 'check-extension-docs.cjs 에 빈 서술 축이 없습니다 — PHP 만 세면 하네스가 통과시킵니다.', + ); + $this->assertStringContainsString( + "id: 'emptyIntent'", + $script, + 'check-extension-docs.cjs 의 빈 서술 축 식별자가 없습니다.', + ); + } + /** * 모든 번들 확장에서 수집기와 렌더러가 예외 없이 동작해야 합니다. * @@ -760,7 +798,10 @@ class ExtensionDocContractTest extends TestCase $module = ExtensionDocScaffolder::documentsForType(ExtensionInventory::TYPE_MODULE); $template = ExtensionDocScaffolder::documentsForType(ExtensionInventory::TYPE_TEMPLATE); - foreach (['AGENTS.md', 'README.md', 'docs/README.md', 'docs/architecture.md'] as $shared) { + // `docs/editor-spec.md` 는 세 유형 공통이다. 편집기 스펙을 두지 않는 확장에도 문서를 + // 두는 것은 "왜 없어도 되는가 / 언제 필요해지는가" 를 적을 자리가 필요하기 때문이며, + // 그 자리가 사라지면 미보유가 누락으로 오해되거나 필요한 시점을 놓친다. + foreach (['AGENTS.md', 'README.md', 'docs/README.md', 'docs/architecture.md', 'docs/editor-spec.md'] as $shared) { $this->assertContains($shared, $module); $this->assertContains($shared, $template); } @@ -1295,20 +1336,9 @@ class ExtensionDocContractTest extends TestCase */ private function contextFor(array $record, ExtensionInventory $inventory): array { - // 커맨드와 **같은 방식**으로 조립해야 한다. 발행 훅의 1차 출처가 선언형 표면의 - // `getHooks()` 이므로, 그것을 넘기지 않으면 여기서 만든 블록이 커맨드가 쓰는 블록과 - // 달라진다 — 문서가 생기는 순간 드리프트 검사가 없는 드리프트를 보고하게 된다. - $surface = (new DeclarativeSurfaceCollector)->collect($record); - $declaredHooks = $surface['values']['getHooks'] ?? []; - - return [ - 'record' => $record, - 'surface' => $surface, - 'hooks' => (new HookInventory)->collect($record, is_array($declaredHooks) ? $declaredHooks : []), - 'data' => (new DataModelCollector)->collect($record), - 'frontend' => (new FrontendInventory)->collect($record), - 'tests' => (new TestPathCollector)->collect($record), - 'deps' => (new DependencyGraphCollector($inventory))->collect($record), - ]; + // 커맨드와 **같은 조립기**를 쓴다. 여기서 배열을 손으로 다시 엮으면 수집 축이 하나 + // 늘 때 한쪽만 갱신되어, 테스트가 만든 블록에 그 축이 빠진 채 파일과 달라진다 — + // 결과는 "생성기를 다시 돌려라" 인데 아무리 돌려도 사라지지 않는 드리프트다. + return app(ExtensionDocContext::class)->build($record); } }