@simplysm/sd-claude 14.0.88 → 14.0.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/claude/references/sd-simplysm14/README.md +16 -17
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +39 -43
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +174 -80
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -50
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +60 -26
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +109 -37
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +61 -44
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +39 -31
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +73 -85
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -39
  11. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -30
  12. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +71 -67
  13. package/claude/references/sd-simplysm14/apis/angular/sheet.md +82 -72
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +35 -36
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +38 -30
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +45 -50
  18. package/claude/references/sd-simplysm14/apis/core-browser/README.md +42 -55
  19. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +62 -0
  20. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +39 -38
  21. package/claude/references/sd-simplysm14/apis/core-common/README.md +95 -103
  22. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +59 -54
  23. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +86 -0
  24. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +57 -66
  25. package/claude/references/sd-simplysm14/apis/core-common/errors.md +86 -0
  26. package/claude/references/sd-simplysm14/apis/core-common/obj.md +60 -42
  27. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
  28. package/claude/references/sd-simplysm14/apis/core-node/README.md +10 -8
  29. package/claude/references/sd-simplysm14/apis/core-node/consola.md +29 -32
  30. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +34 -22
  31. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +29 -25
  32. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +40 -53
  33. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +22 -29
  34. package/claude/references/sd-simplysm14/apis/core-node/worker.md +31 -31
  35. package/claude/references/sd-simplysm14/apis/excel/README.md +26 -26
  36. package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
  37. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
  38. package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
  39. package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
  40. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
  41. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
  42. package/claude/references/sd-simplysm14/apis/lint/README.md +27 -21
  43. package/claude/references/sd-simplysm14/apis/lint/rules.md +89 -49
  44. package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -62
  45. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +149 -67
  46. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +111 -99
  47. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +115 -72
  48. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +134 -92
  49. package/claude/references/sd-simplysm14/apis/orm-common/types.md +67 -52
  50. package/claude/references/sd-simplysm14/apis/orm-node/README.md +63 -26
  51. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +51 -40
  52. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +10 -12
  53. package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +92 -45
  54. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +226 -108
  55. package/claude/references/sd-simplysm14/apis/service-client/README.md +90 -88
  56. package/claude/references/sd-simplysm14/apis/service-client/orm.md +37 -29
  57. package/claude/references/sd-simplysm14/apis/service-client/transport.md +45 -20
  58. package/claude/references/sd-simplysm14/apis/service-common/README.md +89 -40
  59. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
  60. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
  61. package/claude/references/sd-simplysm14/apis/service-server/README.md +70 -66
  62. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +47 -47
  63. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +71 -34
  64. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +31 -32
  65. package/claude/references/sd-simplysm14/apis/storage/README.md +34 -28
  66. package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
  67. package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
  68. package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
  69. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
  70. package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
  71. package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
  72. package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
  73. package/claude/rules/sd-design-rules.md +10 -0
  74. package/claude/skills/sd-docs/SKILL.md +58 -46
  75. package/claude/skills/sd-docs/references/{doc-rules.md → subagent-prompt.md} +103 -103
  76. package/claude/skills/sd-impl/SKILL.md +1 -1
  77. package/claude/skills/sd-spec/SKILL.md +858 -858
  78. package/claude/skills/sd-spec/references/example-spec.md +26 -36
  79. package/package.json +1 -1
  80. package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -47
  81. package/claude/references/sd-simplysm14/apis/orm-common/query-builder.md +0 -29
  82. package/claude/skills/sd-demo/evals/fixtures/inventory-list/.specs/inventory/spec.md +0 -99
  83. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/package.json +0 -12
  84. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/index.ts +0 -3
  85. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inbound/inbound.list.ts +0 -150
  86. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inventory/inventory-master.list.ts +0 -143
  87. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/outbound/outbound.list.ts +0 -150
  88. package/claude/skills/sd-demo/evals/fixtures/inventory-list/pnpm-workspace.yaml +0 -2
  89. package/claude/skills/sd-demo/evals/fixtures/inventory-list/sd.config.ts +0 -12
  90. package/claude/skills/sd-demo/evals/golden.jsonl +0 -1
  91. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/package.json +0 -8
  92. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/src/.gitkeep +0 -0
  93. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tests/.gitkeep +0 -0
  94. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tsconfig.json +0 -10
  95. package/claude/skills/sd-dev/evals/golden.jsonl +0 -1
  96. package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +0 -7
  97. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +0 -5
  98. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +0 -3
  99. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +0 -6
  100. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +0 -1
  101. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +0 -5
  102. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +0 -8
  103. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +0 -7
  104. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +0 -3
  105. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +0 -5
  106. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +0 -3
  107. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +0 -6
  108. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +0 -1
  109. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +0 -5
  110. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +0 -8
  111. package/claude/skills/sd-docs/evals/golden.jsonl +0 -2
  112. package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +0 -101
  113. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +0 -101
  114. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/packages/app/src/screens/box-register/box-register.view.ts +0 -46
  115. package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +0 -89
  116. package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +0 -101
  117. package/claude/skills/sd-impl/evals/golden.jsonl +0 -4
  118. package/claude/skills/sd-manual/evals/fixtures/new-manual/src/notification.ts +0 -25
  119. package/claude/skills/sd-manual/evals/fixtures/update-manual/.claude/references/sd-simplysm14/manuals/notification.md +0 -14
  120. package/claude/skills/sd-manual/evals/fixtures/update-manual/src/notification.ts +0 -37
  121. package/claude/skills/sd-manual/evals/golden.jsonl +0 -2
  122. package/claude/skills/sd-review/evals/fixtures/code-review/src/foo.ts +0 -7
  123. package/claude/skills/sd-review/evals/fixtures/doc-review/docs/foo.md +0 -4
  124. package/claude/skills/sd-review/evals/golden.jsonl +0 -2
  125. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +0 -14
  126. package/claude/skills/sd-skill/evals/fixtures/new-skill/.gitkeep +0 -0
  127. package/claude/skills/sd-skill/evals/golden.jsonl +0 -2
  128. package/claude/skills/sd-spec/evals/fixtures/case-a-split//355/232/214/354/235/230/353/241/235.md +0 -20
  129. package/claude/skills/sd-spec/evals/fixtures/case-b-detail/.specs/260513120000_warehouse/spec.md +0 -95
  130. package/claude/skills/sd-spec/evals/golden.jsonl +0 -2
  131. package/claude/skills/sd-unpack/evals/fixtures/eml-with-text-attachment/meeting.eml +0 -21
  132. package/claude/skills/sd-unpack/evals/fixtures/simple-eml/meeting.eml +0 -10
  133. package/claude/skills/sd-unpack/evals/golden.jsonl +0 -2
  134. package/claude/skills/sd-use/evals/fixtures/empty/.gitkeep +0 -0
  135. package/claude/skills/sd-use/evals/golden.jsonl +0 -6
@@ -1,44 +1,78 @@
1
- # @simplysm/angular — 호스트 디렉티브·동작 셋업
1
+ # @simplysm/angular — 디렉티브·signal setup 헬퍼
2
2
 
3
- 엘리먼트에 부착하는 동작 디렉티브와, 컴포넌트 생성자에서 호출해 호스트 엘리먼트에 동작을 주입하는 `setup*` 함수, 타입 안전 템플릿 디렉티브. 다른 컴포넌트들이 ripple/검증/리사이즈 감지 등에 내부적으로 사용하며 단독으로도 쓸 수 있음.
3
+ DOM 관찰(리사이즈/교차)·캡처 이벤트·커맨드 단축키·ripple·노출 애니메이션·invalid 표시·타입드 템플릿을 호스트 엘리먼트에 붙이는 군. `setup*` 헬퍼는 컴포넌트 `constructor` 안에서 호출(`inject(ElementRef)` 의존), `Sd*` 디렉티브는 헬퍼를 attribute 래핑한 것.
4
4
 
5
- ## 이벤트 옵저버 디렉티브
5
+ ## SdResizeDirective (`[sdResize]`)
6
6
 
7
- - `[sdResize]` (`SdResizeDirective`) `ResizeObserver` 크기 변화 감지. `sdResize = output<SdResizeEvent>()`. `SdResizeEvent = { heightChanged; widthChanged; target: HTMLElement; contentRect: DOMRectReadOnly }`. requestAnimationFrame 디바운스.
8
- - `[sdIntersection]` (`SdIntersectionDirective`) — `IntersectionObserver` 로 가시성 감지. `sdIntersection = output<SdIntersectionEvent>()`. `SdIntersectionEvent = { entry: IntersectionObserverEntry }`.
7
+ `ResizeObserver` requestAnimationFrame 으로 디바운스해 크기 변화를 emit.
9
8
 
10
- ## SdEvents
9
+ - `sdResize: output<SdResizeEvent>` — 크기 변화 시 발화.
10
+ - `SdResizeEvent = { heightChanged: boolean; widthChanged: boolean; target: HTMLElement; contentRect: DOMRectReadOnly }` — 어떤 축이 바뀌었는지·대상·새 사각형. `heightChanged`/`widthChanged` 로 필요한 축만 처리.
11
+ - 사용: `<div (sdResize)="onResize($event)">`. `sd-sheet`·`sd-collapse`·`sd-echarts` 등이 hostDirective 로 사용.
11
12
 
12
- `SdEvents` 디렉티브 — capture/passive/once 옵션 이벤트를 output 으로 노출(Angular 기본 바인딩이 지원 않는 리스너 옵션용). 셀렉터에 해당하는 속성을 호스트에 쓰면 동작. 예: `(click.capture)`, `(scroll.passive)`, `(wheel.capture.passive)`, `(touchstart.passive)`, `(transitionend.once)` 등. 각 output 은 대응 DOM 이벤트 타입(MouseEvent/WheelEvent/TouchEvent 등) emit.
13
+ ## SdIntersectionDirective (`[sdIntersection]`)
13
14
 
14
- `SdOptionEventPlugin` `provideSdAngular` 등록하는 `EventManagerPlugin`. `.capture`/`.passive`/`.once` 접미사 이벤트 바인딩을 실제 리스너 옵션으로 변환. 직접 사용 불필요.
15
+ `IntersectionObserver` 뷰포트 진입/이탈 emit.
15
16
 
16
- ## SdCommandDirective
17
+ - `sdIntersection: output<SdIntersectionEvent>` — 교차 변화 시 발화.
18
+ - `SdIntersectionEvent = { entry: IntersectionObserverEntry }` — `entry.isIntersecting` 으로 진입 판단. 무한 스크롤·지연 로드에 사용.
17
19
 
18
- `[sdRefreshCommand],[sdSaveCommand],[sdInsertCommand]` 전역 단축키를 명령 이벤트로 변환(최상위 모달 컨텍스트에서만 발동).
20
+ ## SdEvents (옵션부 이벤트)
19
21
 
20
- - `sdRefreshCommand = output<KeyboardEvent>()` Ctrl+Alt+L.
21
- - `sdSaveCommand = output<KeyboardEvent>()` — Ctrl+S.
22
- - `sdInsertCommand = output<KeyboardEvent>()` — Ctrl+Insert.
22
+ Angular 기본 바인딩이 못 거는 capture/passive/once 이벤트를 output 으로 노출하는 디렉티브. selector 에 든 attribute 중 쓰는 것만 바인딩하면 됨(전부 listen 하지 않음). `SdOptionEventPlugin`(provideSdAngular 등록) 이 실제 옵션 처리.
23
23
 
24
- CRUD 컨테이너가 `sdSaveCommand` 저장에 연결.
24
+ - 클릭/마우스: `click.capture`, `click.once`, `click.capture.once`, `mousedown.capture`, `mouseup.capture`, `mouseover.capture`, `mouseout.capture` — `output<MouseEvent>`.
25
+ - 키보드: `keydown.capture`, `keyup.capture` — `output<KeyboardEvent>`.
26
+ - 포커스: `focus.capture`, `blur.capture` — `output<FocusEvent>`(버블 안 되므로 capture 필수).
27
+ - 폼: `invalid.capture` — `output<Event>`.
28
+ - 스크롤/휠: `scroll.capture`, `scroll.passive`, `scroll.capture.passive`, `wheel.passive`, `wheel.capture.passive` — passive 로 스크롤 성능 확보.
29
+ - 터치: `touchstart.passive`(+capture), `touchmove.passive`(+capture), `touchend.passive` — `output<TouchEvent>`.
30
+ - 드래그: `dragover.capture`, `dragenter.capture`, `dragleave.capture`, `drop.capture` — `output<DragEvent>`.
31
+ - 애니메이션: `transitionend.once`, `animationend.once` — 1회만.
32
+ - `.capture` = 캡처 단계 수신, `.passive` = preventDefault 불가(스크롤 블로킹 방지), `.once` = 1회 후 자동 해제.
33
+ - 사용: `<div (scroll.passive)="onScroll()">`, `<div (keydown.capture)="onKeydown($event)">`.
25
34
 
26
- ## ripple / show-effect / invalid 디렉티브·셋업
35
+ ## SdCommandDirective (`[sdRefreshCommand],[sdSaveCommand],[sdInsertCommand]`)
27
36
 
28
- 부착형 디렉티브와 동치 셋업 함수 쌍.
37
+ 문서 레벨 Ctrl 단축키를 명령 output 으로. 최상위 열린 모달 안에서만 동작(다른 컨텍스트로 새지 않게 가드).
29
38
 
30
- - `[sdRipple]` (`SdRipple`)클릭 ripple 효과. `sdRipple = input.required(booleanAttribute)`(활성 여부). `setupRipple(enableFn?: () => boolean)` 는 컴포넌트 생성자에서 호스트에 ripple 주입(버튼/체크박스가 사용).
31
- - `[sdShowEffect]` (`SdShowEffect`)스크롤 진입 시 페이드/슬라이드 인. `sdShowEffect = input.required(booleanAttribute)`(활성), `sdShowEffectType: "l2r"|"t2b"`(슬라이드 방향, 기본 `"t2b"`). `setupRevealOnShow(optFn?)` 가 동치 셋업.
32
- - `[sdInvalid]` (`SdInvalid`)임의 엘리먼트에 폼 검증 메시지 부착. `sdInvalid = input.required<string>()`(메시지, 빈 문자열이면 유효). `setupInvalid(getInvalidMessage: () => string)` 가 동치 셋업(숨김 input + `setCustomValidity` 로 네이티브 검증 연동, `<sd-form>` 제출 시 표시). 모든 `required` 컨트롤이 내부 사용.
39
+ - `sdRefreshCommand: output<KeyboardEvent>`Ctrl+Alt+L.
40
+ - `sdSaveCommand: output<KeyboardEvent>`Ctrl+S.
41
+ - `sdInsertCommand: output<KeyboardEvent>`Ctrl+Insert.
42
+ - 매칭 시 preventDefault + stopPropagation. `sd-crud-list`/`sd-crud-detail` 가 `sdSaveCommand` 를 hostDirective 로 받아 저장 트리거.
33
43
 
34
- ## setupModelHook
44
+ ## SdRipple (`[sdRipple]`) / setupRipple
35
45
 
36
- `setupModelHook<T, S extends WritableSignal<T>>(model: S, canFn: Signal<(item: T) => boolean | Promise<boolean>>): void` — `model` 의 set/update 를 가로채 `canFn` 통과 시에만 값 적용. 체크박스/스위치/공유선택리스트의 `canChangeFn` 구현.
46
+ 클릭 지점에서 퍼지는 물결 효과.
37
47
 
38
- - `model` — 가로챌 WritableSignal.
39
- - `canFn` — 변경 허용 판정 시그널. `false` 반환 시 무시, `true` 즉시 set, Promise resolve `false` 아닐 때 set(에러는 ErrorHandler 위임).
48
+ - `SdRipple.sdRipple: input.required(booleanAttribute)` — true 일 때만 ripple 동작(disabled 토글). `<sd-button [sdRipple]="!disabled()">`.
49
+ - `setupRipple(enableFn?: () => boolean): void` — constructor 에서 호출하는 헬퍼. `enableFn` 이 false 반환 시 해당 클릭은 ripple 생략. 커스텀 컴포넌트 내부에서 직접 ripple 부여 시.
40
50
 
41
- ## 타입 안전 템플릿 디렉티브
51
+ ## SdShowEffect (`[sdShowEffect]`) / setupRevealOnShow
42
52
 
43
- - `ng-template[typed]` (`SdTypedTemplate<T>`) `typed = input.required<T>()` 로 템플릿 컨텍스트 타입을 명시(재귀 메뉴 등 `let-x` 타입 추론용). 값은 타입 토큰일 뿐.
44
- - `ng-template[itemOf]` (`SdItemOfTemplate<TItem>`) — `itemOf = input.required<TItem[]>()` 로 항목 반복 템플릿의 컨텍스트 타입 제공. select/calendar/공유선택이 항목 슬롯에 사용. 컨텍스트 `SdItemOfTemplateContext<TItem> = { $implicit; item; index; depth }`.
53
+ 뷰포트 진입 페이드+슬라이드로 나타나는 효과.
54
+
55
+ - `SdShowEffect.sdShowEffect: input.required(booleanAttribute)` — true 면 효과 적용, false 면 효과 없이 즉시 표시.
56
+ - `SdShowEffect.sdShowEffectType: "l2r" | "t2b"` — 등장 방향. `"t2b"`(기본) = 위에서 아래로, `"l2r"` = 왼쪽에서 오른쪽으로.
57
+ - `setupRevealOnShow(optFn?: () => { type?: "l2r"|"t2b"; enabled?: boolean }): void` — constructor 헬퍼. `enabled` false 면 트랜지션 없이 노출.
58
+
59
+ ## SdInvalid (`[sdInvalid]`) / setupInvalid
60
+
61
+ 폼 검증 실패를 좌상단 빨간 점 + 네이티브 form 검증으로 표시. 숨은 input 에 `setCustomValidity` 를 걸어 form submit 시 차단.
62
+
63
+ - `SdInvalid.sdInvalid: input.required<string>` — 빈 문자열이면 유효, 비어있지 않으면 그 메시지로 invalid 표시.
64
+ - `setupInvalid(getInvalidMessage: () => string): void` — constructor 헬퍼. 반환 문자열이 비면 valid, 아니면 invalid. 모든 입력 컨트롤(`sd-textfield`/`sd-select`/`sd-modal-select-button` 등)이 내부에서 이걸로 required/형식 검증을 구현. 커스텀 입력 컴포넌트 작성 시 동일 패턴.
65
+
66
+ ## SdTypedTemplate (`ng-template[typed]`)
67
+
68
+ `<ng-template>` 컨텍스트에 타입을 주는 디렉티브(런타임 동작 없음, 타입 가드만).
69
+
70
+ - `typed: input.required<T>` — 컨텍스트 타입 토큰. `let-x` 변수에 `T` 타입이 추론됨. 사이드바/탑바 메뉴 재귀 템플릿이 사용.
71
+
72
+ ## SdItemOfTemplate (`ng-template[itemOf]`)
73
+
74
+ 항목 반복 템플릿에 항목 타입을 주는 디렉티브.
75
+
76
+ - `itemOf: input.required<TItem[]>` — 항목 배열(타입 추론용 더미, 실제 반복은 부모가 수행).
77
+ - 컨텍스트: `SdItemOfTemplateContext<TItem> = { $implicit; item; index: number; depth: number }`. `let-item="item"` / `let-index="index"` / `let-depth="depth"`.
78
+ - 사용: `sd-shared-data-select`·`sd-calendar` 의 항목 템플릿. `<ng-template [itemOf]="items()" let-item="item">{{ item.name }}</ng-template>`.
@@ -1,55 +1,127 @@
1
- # @simplysm/angular — 부가 기능(테마·주소·에디터·시각화·칸반·프리셋)
1
+ # @simplysm/angular — 기능 컴포넌트 (칸반·권한표·상태프리셋·테마선택·주소검색·에디터·시각화)
2
2
 
3
- 화면에 부분적으로 끼워 쓰는 독립 기능 컴포넌트·프로바이더. 테마(다크/폰트), 주소검색 모달, TipTap 리치에디터, 시각화(라벨/노트/진행률/달력/바코드/차트), 칸반 보드, 상태 프리셋.
3
+ 군에 들지 않는 도메인성/표시용 컴포넌트 모음. 특정 화면 기능을 붙일 개별로 읽힘.
4
4
 
5
- ## SdThemeProvider / SdThemeSelector
5
+ ## 칸반 (드래그 보드)
6
6
 
7
- - `SdThemeProvider` — 루트 테마 프로바이더. `dark: WritableSignal<boolean>`(다크모드, body 클래스 토글), `fontSize: WritableSignal<number>`(루트 폰트크기 px), `fontSizePresets: readonly number[]`(`[12,14,16,20,24,28]`), `increaseFontSize()`/`decreaseFontSize()`(프리셋 단계 이동). `provideSdAngular` 가 localStorage 영속화 연결.
8
- - `<sd-theme-selector>` — 드롭다운 UI. 폰트크기 ±버튼·다크모드 스위치로 프로바이더 조작. input 없음.
7
+ ### SdKanbanBoard<L, T> (`sd-kanban-board`)
9
8
 
10
- ## SdAddressSearchModal
9
+ 레인(`L`)·카드(`T`) 드래그 보드의 루트. 드래그 종료 시 drop 정보 emit.
11
10
 
12
- `<sd-address-search-modal>` 다음(카카오) 우편번호 검색 모달. `SdModalContentDef<Address>` 구현(`SdModalProvider.showAsync` type 으로 사용). 스크립트 동적 로드 후 임베드, 선택 시 결과 emit.
11
+ - `selectedValues: model<T[]>` Shift+클릭으로 선택된 카드 값들.
12
+ - `drop: output<SdKanbanBoardDropInfo<L, T>>` — 카드 drop 시 발화.
13
+ - `SdKanbanBoardDropInfo<L, T> = { sourceKanbanValue?: T; targetLaneValue?: L; targetKanbanValue?: T }` — 옮긴 카드·대상 레인·대상 카드(앞에 끼움).
14
+ - `SdKanbanDragRef`/`SdKanbanDropTarget` — 내부 드래그/드롭 인터페이스.
13
15
 
14
- - `close = output<Address>()` — 선택 결과. `Address = { postNumber?; address?; buildingName? }`(결측 보존).
15
- - input 없음. 스크립트 로드 실패 시 에러 메시지 표시.
16
+ ### SdKanbanLane<L, T> (`sd-kanban-lane`)
16
17
 
17
- ## SdTiptapEditor
18
+ 레인(컬럼). 카드들을 담고 drop 대상이 됨.
18
19
 
19
- `<sd-tiptap-editor>` — TipTap 기반 리치텍스트 에디터(HTML 값, 툴바: 제목·굵게·기울임·밑줄·취소선·색상·리스트 등).
20
+ - `value: input<L>` — 레인 (drop `targetLaneValue`).
21
+ - `busy: boolean` — 레인 busy 오버레이.
22
+ - `useCollapse: boolean` — 접기 토글 표시. `collapse: model<boolean>` — 접힘 상태.
23
+ - 슬롯: `#titleTpl`(제목), `#toolTpl`(도구). 전체선택 체크박스는 선택 가능 카드가 있을 때.
20
24
 
21
- - `value = model<string>()` — HTML 콘텐츠. 빈 내용이면 `undefined`(결측 보존).
22
- - `disabled`/`readonly` — 비활성/읽기전용(편집 불가, 툴바 숨김).
23
- - `required` — 필수 검증(폼 연동).
24
- - `placeholder` — 빈 상태 안내(미지정 확장 시 적용).
25
- - `validatorFn?: (value) => string | undefined` — 커스텀 검증 메시지.
26
- - `extensions?: AnyExtension[]` — TipTap 확장 직접 지정(미지정 시 기본 확장 + placeholder).
27
- - `editor: WritableSignal<Editor | undefined>` — 내부 TipTap 인스턴스(@internal, 고급/테스트용).
25
+ ### SdKanban<L, T> (`sd-kanban`)
28
26
 
29
- ## 시각화 컴포넌트
27
+ 카드. 드래그 소스 + 선택 대상.
30
28
 
31
- - `<sd-label>` — 인라인 라벨/배지. `theme`(공통 8색), `color?`(임의 배경색), `clickable`(호버 효과·커서).
32
- - `<sd-note>`강조 박스. `theme`(공통 8색), `size`(`"sm"|"lg"`), `inset`.
33
- - `<sd-progress>` — 진행률 막대. `value = input.required<number>()`(0~1, 퍼센트 표시·막대폭), `theme = input.required<...>()`(공통 8색), `size`, `inset`.
34
- - `<sd-calendar>` — 월 달력에 항목 배치. 제네릭 `<T>`. `items = input.required<T[]>()`, `getItemDateFn = input.required<(item, index) => DateOnly>()`(항목 날짜), `yearMonth = input(...)`(표시 월, 기본 이번달 1일), `weekStartDay = input(0)`(주 시작 요일), `minDaysInFirstWeek = input(1)`. 셀 항목은 `<ng-template [itemOf]>`.
35
- - `<sd-barcode>` — 바코드/QR SVG 렌더(bwip-js). `type = input.required<BarcodeType>()`(바코드 종류, `"qrcode"`/`"code128"`/`"ean13"` 등 다수 리터럴 유니온), `value = input<string>()`(인코딩 텍스트, 빈값이면 미표시).
36
- - `<sd-echarts>` — ECharts 차트. `option = input.required<EChartsOption>()`(차트 옵션), `notMerge = input(false)`(setOption 병합 여부), `loading = input(false)`(로딩 스피너). 리사이즈 자동 반영.
29
+ - `value: input<T>` — 카드 값.
30
+ - `draggable: boolean` true 드래그 가능.
31
+ - `selectable: boolean` true Shift+클릭 선택 가능.
32
+ - `contentClass: string` 카드 본문 클래스.
33
+ - 사용: `<sd-kanban-board (drop)="onDrop($event)"><sd-kanban-lane [value]="lane"><sd-kanban [value]="card" [draggable]="true">...</sd-kanban></sd-kanban-lane></sd-kanban-board>`.
37
34
 
38
- ## SdKanbanBoard / SdKanbanLane / SdKanban
35
+ ## SdPermissionTable<TModule> (`sd-permission-table`)
39
36
 
40
- 드래그 가능한 칸반 보드. 보드 > 레인 > 카드 계층.
37
+ 권한 트리를 표로 표시·편집(use/edit 체크박스). `SdAppStructureProvider.getPermissionsByStructure(...)` 결과를 입력.
41
38
 
42
- - `<sd-kanban-board>` — 보드 컨테이너. 제네릭 `<L, T>`. `selectedValues = model<T[]>([])`(선택된 카드 값), `drop = output<SdKanbanBoardDropInfo<L, T>>()`(드롭 `{ sourceKanbanValue?; targetLaneValue?; targetKanbanValue? }`).
43
- - `<sd-kanban-lane>` — 레인(열). 제네릭 `<L, T>`. `value = input<L>()`(레인 값), `busy`(로딩), `useCollapse`(접기 버튼), `collapse = model(false)`. `#titleTpl`/`#toolTpl` 슬롯. 선택 가능 카드 있으면 전체선택 체크박스.
44
- - `<sd-kanban>` — 카드. 제네릭 `<L, T>`. `value = input<T>()`(카드 값), `selectable`(Shift클릭 선택), `draggable`(드래그 이동), `contentClass`.
39
+ - `value: model<Record<string, boolean>>` `<코드>.<use|edit>` 부여 여부 맵.
40
+ - `items: SdPermission<TModule>[]` 권한 트리(routing-appstructure.md `SdPermission`).
41
+ - `disabled: boolean` 편집 비활성(조회).
45
42
 
46
- 타입: `SdKanbanBoardDropInfo<L,T>`, `SdKanbanDragRef<L,T>`(`value()`/`heightOnDrag()`), `SdKanbanDropTarget<L,T>`(`targetLaneValue()`/`targetKanbanValue?()`).
43
+ ## SdStatePreset<TState> (`sd-state-preset`)
47
44
 
48
- ## SdStatePreset
45
+ 화면 검색/필터 상태를 이름붙은 프리셋으로 저장·복원(즐겨찾기). 프리셋은 `injectSdSystemConfigResource` 로 영속.
49
46
 
50
- `<sd-state-preset>` — 화면 상태(필터 등)를 명명 프리셋으로 저장·복원(시스템설정 영속화). 제네릭 `<TState>`.
47
+ - `key: input.required<string>` — 프리셋 저장 키.
48
+ - `state: model.required<TState>` — 현재 상태(프리셋 적용 시 이 모델에 set). 저장은 현재 state 를 스냅샷.
49
+ - `size: "sm"|"lg"` — 버튼 크기.
50
+ - `SdStatePresetDef<TState> = { name: string; state: TState }` — 저장된 프리셋 1개.
51
+ - 별(추가)·저장·삭제 동작은 내장(이름 prompt/덮어쓰기 confirm 모달 사용).
51
52
 
52
- - `key = input.required<string>()` 프리셋 저장 키(태그명과 결합).
53
- - `state = model.required<TState>()` — 현재 상태(저장/적용 대상). 프리셋 클릭 시 이 값으로 복원.
54
- - `size = input<"sm"|"lg">()` — 크기.
55
- - ⭐버튼=현재 상태 새 프리셋 저장, 각 프리셋=클릭 적용/저장/삭제. `SdStatePresetDef<TState> = { name: string; state: TState }`.
53
+ ## SdThemeProvider 관련SdThemeSelector (`sd-theme-selector`)
54
+
55
+ 글자 크기 증감 + 다크모드 스위치를 담은 드롭다운 UI. 내부에서 `SdThemeProvider`(infra.md) 조작.
56
+
57
+ - (입력 없음) 탑바 등에 `<sd-theme-selector />` 로 배치. 글자 크기는 `fontSizePresets` 단계, 다크는 `dark` 토글.
58
+
59
+ ## SdAddressSearchModal (`sd-address-search-modal`)
60
+
61
+ 다음(카카오) 우편번호 검색 모달(`SdModalContentDef<Address>`). 외부 스크립트를 동적 로드해 임베드.
62
+
63
+ - `close: output<Address>` — 선택한 주소 emit.
64
+ - `initialized: Signal<boolean>` — 스크립트 로드 완료 여부.
65
+ - `Address = { postNumber?: string; address?: string; buildingName?: string }` — 결과(각 필드 결측 가능).
66
+ - 사용: `const addr = await this._sdModal.showAsync({ type: SdAddressSearchModal, title: "주소 검색", inputs: {} }); if (!addr) return;`.
67
+
68
+ ## SdTiptapEditor (`sd-tiptap-editor`)
69
+
70
+ Tiptap 기반 리치 텍스트(HTML) 에디터. 툴바 내장.
71
+
72
+ - `value: model<string>` — HTML 문자열.
73
+ - `disabled: boolean` — 비활성. `readonly: boolean` — 읽기 전용.
74
+ - `required: boolean` — 빈 값이면 invalid. `validatorFn: (value) => string | undefined` — 커스텀 검증.
75
+ - `placeholder: string` — 빈 에디터 안내.
76
+ - `extensions: AnyExtension[]` — 추가 Tiptap 확장.
77
+
78
+ ## 시각화·표시 컴포넌트 (features/visual)
79
+
80
+ ### SdLabel (`sd-label`)
81
+
82
+ 배지/태그. `<ng-content>` 본문.
83
+
84
+ - `theme: "primary"|"secondary"|"info"|"success"|"warning"|"danger"|"gray"|"blue-gray"` — 배경 색(미지정=회색 darker). 상태 표시에 의미별 색.
85
+ - `color: string` — 임의 배경색 직접 지정(theme 대신).
86
+ - `clickable: boolean` — true 면 포인터 커서 + hover 효과.
87
+
88
+ ### SdNote (`sd-note`)
89
+
90
+ 안내 박스(연한 배경). `<ng-content>` 본문.
91
+
92
+ - `theme: "primary"|...|"blue-gray"` — 박스 색(미지정=회색 lightest).
93
+ - `size: "sm"|"lg"` — 패딩.
94
+ - `inset: boolean` — 테두리 제거.
95
+
96
+ ### SdProgress (`sd-progress`)
97
+
98
+ 가로 진행 바 + 퍼센트 텍스트.
99
+
100
+ - `value: input.required<number>` — 진행값(0~1, percent 파이프로 표시).
101
+ - `theme: input.required<...>` — 바 색(필수).
102
+ - `size: "sm"|"lg"` / `inset: boolean` — 크기/테두리.
103
+
104
+ ### SdCalendar<T> (`sd-calendar`)
105
+
106
+ 월 달력 그리드에 항목을 날짜별로 배치. 항목 템플릿으로 셀 내용 렌더.
107
+
108
+ - `items: input.required<T[]>` — 표시할 항목들.
109
+ - `getItemDateFn: input.required<(item, index) => DateOnly>` — 항목의 날짜 추출.
110
+ - `yearMonth: input<DateOnly>` — 표시 연월(기본 이번 달 1일).
111
+ - `weekStartDay: number` — 주 시작 요일(0=일, 기본 0). `minDaysInFirstWeek: number` — 첫 주 최소 일수(기본 1).
112
+ - 항목 템플릿: `<ng-template [itemOf]="items()" let-item="item">`(필수).
113
+
114
+ ### SdBarcode (`sd-barcode`)
115
+
116
+ 바코드/QR 등을 SVG 로 렌더(bwip-js).
117
+
118
+ - `type: input.required<BarcodeType>` — 바코드 종류. `BarcodeType` 은 `"code128"|"qrcode"|"ean13"|"datamatrix"|...`(bwip-js 의 100+ 심볼로지 리터럴 유니온). 대표: `"code128"`(범용 1D), `"qrcode"`(QR), `"ean13"`/`"upca"`(상품), `"datamatrix"`(소형 2D).
119
+ - `value: string` — 인코딩할 데이터(빈 값이면 미렌더).
120
+
121
+ ### SdEcharts (`sd-echarts`)
122
+
123
+ ECharts 차트(SVG 렌더). 리사이즈 자동 대응.
124
+
125
+ - `option: input.required<echarts.EChartsOption>` — 차트 옵션. 변경 시 재설정.
126
+ - `notMerge: boolean` — true 면 옵션 병합 없이 교체(기본 false=병합).
127
+ - `loading: boolean` — true 면 로딩 인디케이터.
@@ -1,74 +1,91 @@
1
- # @simplysm/angular — 설정·로깅·서비스 인프라
1
+ # @simplysm/angular — 부트스트랩·전역 프로바이더
2
2
 
3
- 부트스트랩과 함께 읽히는 인프라 묶음. `provideSdAngular()` 로 전역 프로바이더를 등록하고, 클라이언트명·테마영속화·시스템로그·로컬스토리지·시스템설정·서비스 클라이언트 연결·전역 에러 처리를 담당.
3
+ 시작 1회 배선하는 `provideSdAngular` 와, `providedIn: "root"` 어디서든 inject 하는 전역 프로바이더(테마·로컬스토리지·시스템설정·시스템로그·서비스클라이언트·설정값)를 모은 군. 화면이 아니라 부트스트랩(`provideAppInitializer`)·앱 코드에서 같이 읽힌다.
4
4
 
5
5
  ## provideSdAngular
6
6
 
7
- `provideSdAngular(opt: { clientName: string }): EnvironmentProviders` — 앱 부트스트랩 시 `providers` 에 넣는 핵심 프로바이더 묶음.
8
-
9
- - `opt.clientName` — 클라이언트 식별명. `SdAngularConfigProvider.clientName` 에 주입되어 로컬스토리지 키 prefix·서비스 클라이언트 생성에 사용. 앱마다 고유해야 함.
10
-
11
- 등록 내용(본문 기준): 이미지 경고 비활성화, ng-icon 기본 설정, 다크모드/폰트크기 localStorage 영속화 effect, `window` 의 `error`/`unhandledrejection` → ErrorHandler 위임, `SdOptionEventPlugin`(이벤트 옵션 플러그인), `SdGlobalErrorHandlerPlugin`(ErrorHandler), zoneless 변경감지, Service Worker 업데이트 폴링(지수 백오프, 발견 시 confirm 후 reload), 라우터 내비게이션 중 `SdBusyProvider.globalBusyCount` 증감.
12
-
13
- ```typescript
14
- bootstrapApplication(AppComponent, {
15
- providers: [provideRouter(routes), provideSdAngular({ clientName: "my-app" })],
16
- });
7
+ ```ts
8
+ function provideSdAngular(opt: { clientName: string }): EnvironmentProviders
17
9
  ```
18
10
 
19
- ## setupBgTheme
11
+ `ApplicationConfig.providers` 에 1개 넣으면 simplysm 클라이언트 동작 전체가 배선됨. 내부 처리:
20
12
 
21
- `setupBgTheme(options?: { theme?: ..., lightness?: "lightest" | "lighter" }): void` 컴포넌트 활성 동안 `document.body` `--background-color` 테마 색으로 지정(effect, cleanup복원). 컴포넌트 생성자/필드에서 호출.
13
+ - `clientName` 클라이언트의 식별 이름. `SdAngularConfigProvider.clientName` 으로 보관되어 로컬스토리지 prefix, 서비스 클라이언트 이름, 시스템 로그 `clientName` 등에 사용. `provideSdAngular({ clientName: CLIENT_NAME })` 형태로 전달하며, 시스템 로그 배선 같은 값을 씀(`client-system-log.md`).
14
+ - ng-icons 전역 설정(strokeWidth 1.5, size 1.33em), `IMAGE_CONFIG`(이미지 경고 비활성), `provideZonelessChangeDetection()`.
15
+ - 테마(dark/fontSize) 를 `SdLocalStorageProvider` 와 양방향 동기화(저장값 복원 + 변경 시 저장).
16
+ - `window` 의 `unhandledrejection`/`error` 를 `ErrorHandler` 로 위임 + `ErrorHandler` 를 `SdGlobalErrorHandlerPlugin` 으로 교체(미처리 에러를 전체화면 표시 + 시스템로그 적재).
17
+ - `EVENT_MANAGER_PLUGINS` 에 `SdOptionEventPlugin`(capture/passive/once 이벤트 옵션 지원) 추가.
18
+ - service-worker(`SwUpdate`) 가 있으면 5분 주기(실패 시 지수 백오프, 최대 1시간)로 업데이트 확인 후 사용자 confirm → reload.
19
+ - 라우터가 있으면 네비게이션 시작/종료에 `SdBusyProvider.globalBusyCount` 를 ±1 → 전역 busy 표시.
22
20
 
23
- - `options.theme` `"primary"|"secondary"|"info"|"success"|"warning"|"danger"|"gray"|"blue-gray"`. 배경 테마 색. 미지정 변수 비움(`""`).
24
- - `options.lightness` — `"lightest"|"lighter"`. 밝기 단계. 기본 `"lightest"`.
21
+ 사용: `bootstrapApplication(AppRoot, { providers: [provideSdAngular({ clientName: CLIENT_NAME }), provideRouter(...), ...] })`.
25
22
 
26
23
  ## SdAngularConfigProvider
27
24
 
28
- `class SdAngularConfigProvider { clientName!: string }` — `provideSdAngular` 가 설정하는 클라이언트명 보관 루트 프로바이더. 다른 프로바이더가 inject prefix 사용.
25
+ - `clientName: string` — `provideSdAngular` 가 주입하는 클라이언트 이름. 다른 provider prefix/식별자로 참조. 보통 직접 set 하지 않음.
29
26
 
30
- - `clientName` — 클라이언트 식별명. 직접 set 하지 말고 `provideSdAngular({clientName})` 로 주입됨.
27
+ ## SdThemeProvider
31
28
 
32
- ## SdSystemLogProvider
29
+ 다크모드·기본 글자크기 전역 상태. `provideSdAngular` 가 로컬스토리지 동기화를 자동 배선하므로 화면에서는 토글만 호출.
33
30
 
34
- `class SdSystemLogProvider` — 시스템 로그 기록 루트 프로바이더. 콘솔 로깅 + 선택적 외부 전송.
31
+ - `dark: WritableSignal<boolean>` 다크모드 on/off. true `<body>` `sd-theme-dark` 클래스 토글. 테마 전환 UI 에서 set.
32
+ - `fontSize: WritableSignal<number>` — 루트 폰트 크기(px). 변경 시 `<html>` 의 `font-size` 적용(전체 rem 기준 스케일).
33
+ - `fontSizePresets: readonly number[]` — `[12,14,16,20,24,28]`. 증감 단계 후보.
34
+ - `increaseFontSize(): void` / `decreaseFontSize(): void` — presets 안에서 한 단계 위/아래로 이동. 경계면 무변경.
35
+ - 사용: 테마 선택 UI 는 `sd-theme-selector`(features.md) 가 이 provider 를 래핑. 직접 다크 토글은 `inject(SdThemeProvider).dark.update(v => !v)`.
35
36
 
36
- - `writeFn?: (severity, ...data) => Promise<void> | void` — 외부 로그 싱크. 지정 시 `writeAsync` 가 콘솔 출력 후 이 함수도 호출. 미지정이면 콘솔만.
37
- - `writeAsync(severity: "error"|"warn"|"log", ...data): Promise<void>` — 로그 기록. `severity` 로 로거 메서드 선택 후 `writeFn` 있으면 await(실패 시 내부 로깅만, throw 안 함).
37
+ ## SdLocalStorageProvider<T>
38
38
 
39
- ## SdLocalStorageProvider
39
+ `localStorage` 를 `<clientName>.<key>` 네임스페이스로 JSON 직렬화해 읽고 씀. 제네릭 `T` 로 키→값 타입 매핑.
40
40
 
41
- `class SdLocalStorageProvider<T>` `clientName.{key}` prefix localStorage JSON 저장하는 타입드 래퍼.
41
+ - `set<K extends keyof T & string>(key: K, value: T[K]): void` — `JSON.stringify` 저장.
42
+ - `get<K extends keyof T & string>(key: K): T[K] | undefined` — 파싱해 반환. 미존재·파싱실패 시 `undefined`(결측 보존).
43
+ - `remove(key: keyof T & string): void` — 삭제.
44
+ - 사용: `inject<SdLocalStorageProvider<{ "last-tab": string }>>(SdLocalStorageProvider)`.
42
45
 
43
- - `set<K>(key, value)` — `JSON.stringify` 후 저장. `key` 는 `T` 의 키.
44
- - `get<K>(key): T[K] | undefined` — 파싱 반환. 없거나 파싱 실패 시 `undefined`(결측 보존).
45
- - `remove(key)` — 항목 제거.
46
+ ## SdSystemConfigProvider<T>
46
47
 
47
- ## SdSystemConfigProvider
48
+ 화면별 설정(시트 컬럼 구성, 모달 위치 등) 영속화. 외부 저장 함수(`fn`) 가 꽂혀 있으면 그쪽, 없으면 `SdLocalStorageProvider` 로 폴백.
48
49
 
49
- `class SdSystemConfigProvider<T>`시스템 설정 저장소. 외부 `fn` 있으면 서버, 없으면 localStorage 폴백.
50
+ - `fn?: { set(key, data): Promise<void>|void; get(key): PromiseLike<unknown> }` 서버 외부 저장소 연동 훅. 부트스트랩에서 할당하면 모든 설정이 외부로 영속. 미할당이면 로컬스토리지만 사용.
51
+ - `setAsync<K>(key: K, data: T[K] | undefined): Promise<void>` — `fn` 있으면 위임, 없으면 로컬스토리지에 저장(데이터 `null` 이면 remove).
52
+ - `getAsync(key): Promise<unknown>` — `fn` 있으면 위임, 없으면 로컬스토리지 get.
53
+ - 직접 호출보다 `injectSdSystemConfigResource` (아래) 로 컴포넌트별 자동 키 분리·resource 화해 쓰는 게 표준.
50
54
 
51
- - `fn?: { set(key, data): ...; get(key): PromiseLike<unknown> }` — 외부 저장 핸들러. 지정 시 서버 영속, 미지정 시 `SdLocalStorageProvider` 사용.
52
- - `setAsync<K>(key, data: T[K] | undefined)` — 저장. `fn` 있으면 위임, 없고 `data==null` 이면 remove, 아니면 localStorage set.
53
- - `getAsync(key)` — 조회. `fn` 있으면 위임, 없으면 localStorage get.
55
+ ## injectSdSystemConfigResource<T>
54
56
 
55
- ## injectSdSystemConfigResource
57
+ ```ts
58
+ function injectSdSystemConfigResource<T>(options: { key: Signal<string | undefined> }): {
59
+ value: Signal<T | undefined>;
60
+ isLoading: Signal<boolean>;
61
+ status: Signal<...>;
62
+ hasValue(): boolean;
63
+ reload(): void;
64
+ set(value: T | undefined): void;
65
+ update(fn: (prev: T | undefined) => T | undefined): void;
66
+ }
67
+ ```
56
68
 
57
- `injectSdSystemConfigResource<T>(options: { key: Signal<string | undefined> })` 호스트 엘리먼트 태그명 + `key`시스템 설정을 읽고 쓰는 Angular `resource` 래퍼. 시트/상태프리셋이 컬럼·프리셋 영속화에 사용.
69
+ `SdSystemConfigProvider` 위에 Angular `resource` 얹은 컴포넌트 스코프 헬퍼. 실제 저장 키는 `<호스트엘리먼트태그>.<key>`자동 분리되어 같은 컴포넌트 종류끼리 설정을 공유.
58
70
 
59
- - `options.key` — 설정 키 시그널. `undefined` 면 로드 함(결측). 실제 키는 `{태그명}.{key}`.
60
- - 반환: `{ value, isLoading, status, hasValue(), reload(), set(value), update(fn) }` — `set` 즉시 resource 갱신 + 마이크로태스크로 `setAsync` 영속화(실패 시 ErrorHandler 위임).
71
+ - `options.key: Signal<string | undefined>` — 설정 키 signal. `undefined` 면 로드/저장 스킵. 컴포넌트의 `key` 입력을 그대로 넘김.
72
+ - `set` — 메모리 즉시 반영 microtask `setAsync` 영속(실패 시 ErrorHandler 로 전파, silent skip 아님).
73
+ - `sd-sheet` 가 컬럼 설정을 이걸로 보관(sheet.md 참조).
61
74
 
62
- ## SdServiceClientFactoryProvider
75
+ ## SdSystemLogProvider
63
76
 
64
- `class SdServiceClientFactoryProvider` 키별 `ServiceClient` 연결 풀. 요청/응답 진행률을 토스트 progress 표시.
77
+ 프레임워크가 잡은 에러/경고를 콘솔 + (배선 시) 외부 저장소로 적재. 자세한 배선·자동 적재 지점은 `client-system-log.md` 참조.
65
78
 
66
- - `connectAsync(key, options?: Partial<ServiceConnectionOptions>)` `key` 클라이언트 연결. 호스트/포트/ssl `location` 기본값 + `options` 머지. 이미 연결/이미 끊긴 키면 throw.
67
- - `closeAsync(key)`연결 종료 풀에서 제거(미연결 키면 throw).
68
- - `get(key): ServiceClient` 연결된 클라이언트 반환. 미연결/끊긴 키면 throw.
79
+ - `writeFn?: (severity: "error"|"warn"|"log", ...data: any[]) => Promise<void>|void` 외부 적재 함수. 부트스트랩에서 1회 할당(예: DB insert). 미할당 콘솔만.
80
+ - `writeAsync(severity: "error"|"warn"|"log", ...data: any[]): Promise<void>` 항상 콘솔(`createLogger("angular:system-log")`)로 먼저 찍고, `writeFn` 있으면 추가 적재. `writeFn` 호출은 try/catch 로 감싸 실패해도 throw 하지 않음(로그 싱크 실패가 본 동작을 막지 않게 한 의도된 설계).
81
+ - `severity` 값 차이: `"error"` = 문제 발생, `"warn"` = 인지 필요, `"log"` = 일반. `SdGlobalErrorHandlerPlugin`·`SdToastProvider.try/danger` 가 자동으로 `"error"` 적재.
82
+ - 직접 적재: `await this._sdSystemLog.writeAsync("error", "결제 승인 실패", err.stack)`.
69
83
 
70
- ## SdGlobalErrorHandlerPlugin
84
+ ## SdServiceClientFactoryProvider
71
85
 
72
- `class SdGlobalErrorHandlerPlugin implements ErrorHandler` `provideSdAngular` `ErrorHandler` 등록하는 전역 에러 핸들러.
86
+ `@simplysm/service-client` `ServiceClient` key 별로 생성·보관·종료. 요청/응답 진행률을 자동으로 토스트 progress 로 표시.
73
87
 
74
- - `handleError(event)``PromiseRejectionEvent`/`ErrorEvent`/`Error`/기타를 분기해 메시지 구성 시스템 로그 기록 + 파괴 전체화면 에러 오버레이 표시(클릭 시 reload). 최초 1회만 오버레이 노출. 직접 호출보다 Angular 자동 호출.
88
+ - `connectAsync(key: string, options?: Partial<ServiceConnectionOptions>): Promise<void>` key 클라이언트 연결. host/port/ssl 미지정 현재 `location` 기준 기본값. 이미 연결됐거나 닫힌 key throw. 연결 `request-progress`/`response-progress` 받아 `SdToastProvider.info(..., true)` progress 갱신.
89
+ - `closeAsync(key: string): Promise<void>` — 연결 종료 + 해당 key 를 닫힘 처리(재연결 불가). 미연결 key 면 throw.
90
+ - `get(key: string): ServiceClient` — 연결된 클라이언트 반환. 미연결/닫힘이면 throw(silent 반환 안 함).
91
+ - 앱은 보통 `AppServiceProvider` 가 이걸 래핑(`client-service.md`). 화면에서 직접 inject 하기보다 앱 provider 경유.
@@ -1,55 +1,63 @@
1
- # @simplysm/angular — 레이아웃(사이드바·탑바)
1
+ # @simplysm/angular — 레이아웃(사이드바·탑바)
2
2
 
3
- 화면 셸을 구성하는 사이드바/탑바 컨테이너·메뉴·사용자 메뉴. 사이드바는 모바일에서 백드롭+슬라이드, 탑바는 사이드바 토글 버튼을 자동 제공. 메뉴 입력은 `SdMenu[]`(라우팅·앱구조 참조)이며 `sdRouterLink`/선택표시가 내장됨.
3
+ 셸의 좌측 사이드바·상단바와 안의 메뉴/사용자 메뉴 컴포넌트 군. 루트 레이아웃(`app.root` 등)에서 구성. 메뉴 항목 타입(`SdMenu`)·라우터 링크는 routing-appstructure.md 것을 사용.
4
4
 
5
- ## SdSidebarContainer
5
+ ## 사이드바
6
6
 
7
- `<sd-sidebar-container>` — 사이드바 + 본문 레이아웃 컨테이너. 본문에 좌측 패딩(`--sidebar-width`)을 주고, 모바일에서는 백드롭 표시. 라우터 내비게이션 시작 시 자동으로 사이드바를 닫음(`toggle` 신호 보유). input 없음.
7
+ ### SdSidebarContainer (`sd-sidebar-container`)
8
8
 
9
- ## SdSidebar
9
+ 사이드바 + 본문을 감싸는 컨테이너. 데스크톱은 사이드바 폭만큼 좌패딩, 모바일은 오버레이. 라우팅 시작 시 자동으로 토글을 닫음(모바일 메뉴 닫힘).
10
10
 
11
- `<sd-sidebar>` — 실제 사이드바 패널. 부모 `SdSidebarContainer.toggle` 따라 슬라이드 표시/숨김. 콘텐츠는 투영. input 없음.
11
+ - `toggle: WritableSignal<boolean>` — 사이드바 접힘(데스크톱) / 닫힘(모바일) 상태. `sd-topbar` 햄버거가 이걸 토글. 배경(backdrop) 클릭으로도 토글.
12
+ - 자식으로 `<sd-sidebar>` 와 본문을 둠.
12
13
 
13
- ## SdSidebarMenu
14
+ ### SdSidebar (`sd-sidebar`)
14
15
 
15
- `<sd-sidebar-menu>` 사이드바 메뉴 트리.
16
+ 실제 사이드바 패널. 부모 `SdSidebarContainer.toggle` 에 따라 슬라이드 인/아웃.
16
17
 
17
- - `menus = input<SdMenu[]>([])` 메뉴 트리. `SdAppStructureProvider.usableMenus()` 결과를 주로 넣음.
18
- - `layout: "accordion"|"flat"` — 루트 메뉴 레이아웃. 미지정 시 메뉴 3개 이하면 flat, 초과면 accordion 자동.
19
- - `getMenuIsSelectedFn?: (menu) => boolean` — 선택 판정 커스텀(미지정 시 현재 페이지코드와 codeChain 비교).
18
+ - (입력 없음) 부모 컨테이너의 toggle computed 반영. 내부에 `<sd-sidebar-user>`·`<sd-sidebar-menu>` 등을 배치.
20
19
 
21
- 메뉴 항목은 `sdRouterLink` 로 `/home/{codeChain}` 이동, `url` 있으면 새 탭, 자식 있으면 하위 트리.
20
+ ### SdSidebarMenu (`sd-sidebar-menu`)
22
21
 
23
- ## SdSidebarUser
22
+ 메뉴 트리를 리스트로 렌더(중첩, 라우터 링크/외부 URL).
24
23
 
25
- `<sd-sidebar-user>` 사이드바 상단 사용자 영역 + 접이식 메뉴.
24
+ - `menus: SdMenu[]` 표시할 메뉴 트리(보통 `SdAppStructureProvider.usableMenus()`).
25
+ - `layout: "accordion"|"flat"` — 루트 레벨 레이아웃. 미지정 시 메뉴 3개 이하면 `"flat"`, 초과면 `"accordion"` 자동 선택.
26
+ - `getMenuIsSelectedFn: (menu: SdMenu) => boolean` — 선택 판정 커스텀(미지정 시 현재 페이지 코드 비교).
27
+ - 동작: leaf 메뉴는 `getMenuRouterLinkOption` 으로 라우팅, `url` 메뉴는 새 창.
26
28
 
27
- - `userMenu = input<SdSidebarUserMenu>()``{ title: string; menus: { title; onClick }[] }`. title 클릭 시 메뉴 펼침, 각 항목 클릭 시 `onClick` 실행.
28
- - 콘텐츠 투영부에 사용자 정보 표시.
29
+ ### SdSidebarUser (`sd-sidebar-user`)
29
30
 
30
- ## SdTopbarContainer
31
+ 사이드바 상단 사용자 영역 + 접이식 사용자 메뉴.
31
32
 
32
- `<sd-topbar-container>`탑바 + 본문 세로 레이아웃 컨테이너. input 없음. `<sd-topbar>` 본문을 자식으로 둠.
33
+ - `userMenu: SdSidebarUserMenu` `{ title: string; menus: { title: string; onClick: () => void }[] }`. `title` 클릭 시 메뉴 펼침, 각 메뉴 클릭 시 `onClick`. 로그아웃/설정 등.
34
+ - `<ng-content>` 로 사용자 이름/아바타 영역 배치.
33
35
 
34
- ## SdTopbar
36
+ ## 탑바
35
37
 
36
- `<sd-topbar>` — 상단 바. 사이드바 컨테이너가 있으면 좌측에 메뉴 토글 버튼 자동 표시.
38
+ ### SdTopbarContainer (`sd-topbar-container`)
37
39
 
38
- - `sidebarContainer = input<SdSidebarContainer>()` 토글 대상 사이드바. 미지정 inject 된 부모 `SdSidebarContainer` 사용. 하나라도 있으면 토글 버튼 노출.
39
- - 콘텐츠(제목·액션)는 투영.
40
+ 상단바 + 본문 세로 스택 컨테이너(상단 고정 + 본문 fill). `sd-base-container` page 모드에서 내부적으로 사용.
40
41
 
41
- ## SdTopbarMenu
42
+ ### SdTopbar (`sd-topbar`)
42
43
 
43
- `<sd-topbar-menu>` 탑바 가로 메뉴(각 루트 메뉴가 드롭다운).
44
+ 상단바 본문. 사이드바가 있으면 좌측에 햄버거 토글 버튼 자동 표시.
44
45
 
45
- - `menus = input<SdMenu[]>([])` 메뉴 트리.
46
- - `getMenuIsSelectedFn?: (menu) => boolean`선택 판정 커스텀.
46
+ - `sidebarContainer: SdSidebarContainer` — 토글 대상 사이드바 컨테이너(미지정 시 inject 로 자동 탐색). 없으면 햄버거 미표시.
47
+ - `hasSidebar: Signal<boolean>`사이드바 존재 여부(햄버거 표시 기준).
48
+ - `<ng-content>` 로 제목·메뉴·사용자 영역 배치.
47
49
 
48
- 리프 메뉴 클릭 시 드롭다운 닫힘, `url` 있으면 새 탭.
50
+ ### SdTopbarMenu (`sd-topbar-menu`)
49
51
 
50
- ## SdTopbarUser
52
+ 상단바 가로 메뉴(드롭다운 펼침).
51
53
 
52
- `<sd-topbar-user>`탑바 우측 사용자 드롭다운 메뉴.
54
+ - `menus: SdMenu[]` 표시할 메뉴 트리. 각 루트 메뉴가 드롭다운 버튼이 되고 children 을 팝업 리스트로.
55
+ - `getMenuIsSelectedFn: (menu: SdMenu) => boolean` — 선택 판정 커스텀.
56
+ - leaf 클릭 시 라우팅 + 드롭다운 닫힘, `url` 메뉴는 새 창.
53
57
 
54
- - `menus = input.required<SdTopbarUserMenu[]>()``{ title: string; onClick: () => void }[]`. 항목 클릭 시 `onClick` 실행 후 드롭다운 닫힘.
55
- - 트리거 라벨(사용자명 등)은 콘텐츠 투영.
58
+ ### SdTopbarUser (`sd-topbar-user`)
59
+
60
+ 상단바 우측 사용자 드롭다운 메뉴.
61
+
62
+ - `menus: input.required<SdTopbarUserMenu[]>` — `SdTopbarUserMenu = { title: string; onClick: () => void }`. 각 항목 클릭 시 `onClick` 실행 후 드롭다운 닫힘.
63
+ - `<ng-content>` 로 트리거 버튼 라벨(사용자 이름) 배치.