@simplysm/sd-claude 14.0.50 → 14.0.52

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 (318) hide show
  1. package/claude/references/sd-frontend-design.md +10 -9
  2. package/claude/references/sd-simplysm-v14/angular/README.md +497 -0
  3. package/claude/references/sd-simplysm-v14/angular/bootstrap/provide-sd-angular.md +37 -0
  4. package/claude/references/sd-simplysm-v14/angular/bootstrap/sd-angular-config-provider.md +16 -0
  5. package/claude/references/sd-simplysm-v14/angular/directives/sd-command-directive.md +27 -0
  6. package/claude/references/sd-simplysm-v14/angular/directives/sd-events.md +25 -0
  7. package/claude/references/sd-simplysm-v14/angular/directives/sd-intersection-directive.md +36 -0
  8. package/claude/references/sd-simplysm-v14/angular/directives/sd-invalid.md +24 -0
  9. package/claude/references/sd-simplysm-v14/angular/directives/sd-resize-directive.md +42 -0
  10. package/claude/references/sd-simplysm-v14/angular/directives/sd-ripple.md +23 -0
  11. package/claude/references/sd-simplysm-v14/angular/directives/sd-router-link.md +38 -0
  12. package/claude/references/sd-simplysm-v14/angular/directives/sd-show-effect.md +18 -0
  13. package/claude/references/sd-simplysm-v14/angular/directives/sd-typed-template.md +69 -0
  14. package/claude/references/sd-simplysm-v14/angular/features/sd-address-search-modal.md +50 -0
  15. package/claude/references/sd-simplysm-v14/angular/features/sd-permission-table.md +20 -0
  16. package/claude/references/sd-simplysm-v14/angular/features/sd-shared-data-components.md +158 -0
  17. package/claude/references/sd-simplysm-v14/angular/features/sd-tiptap-editor.md +26 -0
  18. package/claude/references/sd-simplysm-v14/angular/pipes/format-pipe.md +41 -0
  19. package/claude/references/sd-simplysm-v14/angular/plugins/sd-global-error-handler.md +23 -0
  20. package/claude/references/sd-simplysm-v14/angular/plugins/sd-option-event-plugin.md +34 -0
  21. package/claude/references/sd-simplysm-v14/angular/provider-types/sd-menu.md +65 -0
  22. package/claude/references/sd-simplysm-v14/angular/provider-types/sd-modal-content-def.md +148 -0
  23. package/claude/references/sd-simplysm-v14/angular/provider-types/sd-toast-content-def.md +73 -0
  24. package/claude/references/sd-simplysm-v14/angular/provider-types/shared-data-base.md +59 -0
  25. package/claude/references/sd-simplysm-v14/angular/providers/sd-activated-modal-provider.md +34 -0
  26. package/claude/references/sd-simplysm-v14/angular/providers/sd-app-structure-provider.md +81 -0
  27. package/claude/references/sd-simplysm-v14/angular/providers/sd-busy-provider.md +18 -0
  28. package/claude/references/sd-simplysm-v14/angular/providers/sd-file-dialog-provider.md +40 -0
  29. package/claude/references/sd-simplysm-v14/angular/providers/sd-local-storage-provider.md +20 -0
  30. package/claude/references/sd-simplysm-v14/angular/providers/sd-modal-provider.md +67 -0
  31. package/claude/references/sd-simplysm-v14/angular/providers/sd-navigate-window-provider.md +18 -0
  32. package/claude/references/sd-simplysm-v14/angular/providers/sd-print-provider.md +25 -0
  33. package/claude/references/sd-simplysm-v14/angular/providers/sd-service-client-factory-provider.md +43 -0
  34. package/claude/references/sd-simplysm-v14/angular/providers/sd-shared-data-provider.md +64 -0
  35. package/claude/references/sd-simplysm-v14/angular/providers/sd-system-config-provider.md +46 -0
  36. package/claude/references/sd-simplysm-v14/angular/providers/sd-system-log-provider.md +18 -0
  37. package/claude/references/sd-simplysm-v14/angular/providers/sd-theme-provider.md +38 -0
  38. package/claude/references/sd-simplysm-v14/angular/providers/sd-toast-provider.md +65 -0
  39. package/claude/references/sd-simplysm-v14/angular/recipes/_common-rules.md +336 -0
  40. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-a-edit-save.md +191 -0
  41. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-b-delete-restore.md +103 -0
  42. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-c-modal-view.md +198 -0
  43. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-d-control-view.md +109 -0
  44. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-e-auxiliary.md +87 -0
  45. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail/extension-f-complex-detail.md +202 -0
  46. package/claude/references/sd-simplysm-v14/angular/recipes/crud-detail.md +280 -0
  47. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-a-inline-edit.md +386 -0
  48. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-b-selection.md +215 -0
  49. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-c-inline-delete.md +64 -0
  50. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-d-select-modal.md +193 -0
  51. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-e-readonly-modal.md +140 -0
  52. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-f-modal-edit.md +123 -0
  53. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list/extension-g-excel.md +145 -0
  54. package/claude/references/sd-simplysm-v14/angular/recipes/crud-list.md +377 -0
  55. package/claude/references/sd-simplysm-v14/angular/recipes/data-select-button.md +368 -0
  56. package/claude/references/sd-simplysm-v14/angular/recipes/page-modal-container.md +238 -0
  57. package/claude/references/sd-simplysm-v14/angular/styling/classes.md +149 -0
  58. package/claude/references/sd-simplysm-v14/angular/styling/mixins.md +100 -0
  59. package/claude/references/sd-simplysm-v14/angular/styling/themes.md +35 -0
  60. package/claude/references/sd-simplysm-v14/angular/styling/variables.md +147 -0
  61. package/claude/references/sd-simplysm-v14/angular/type-utilities/directive-input-signals.md +232 -0
  62. package/claude/references/sd-simplysm-v14/angular/ui-data/sd-list.md +37 -0
  63. package/claude/references/sd-simplysm-v14/angular/ui-data/sd-sheet.md +212 -0
  64. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-additional-button.md +26 -0
  65. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-anchor.md +31 -0
  66. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-button.md +103 -0
  67. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-checkbox-group.md +39 -0
  68. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-checkbox.md +81 -0
  69. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-date-range-picker.md +27 -0
  70. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-form.md +89 -0
  71. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-modal-select-button.md +54 -0
  72. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-numpad.md +26 -0
  73. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-range.md +26 -0
  74. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-select.md +68 -0
  75. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-shared-data-select.md +52 -0
  76. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-state-preset.md +37 -0
  77. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-switch.md +27 -0
  78. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-textarea.md +33 -0
  79. package/claude/references/sd-simplysm-v14/angular/ui-form/sd-textfield.md +145 -0
  80. package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-dock-container.md +64 -0
  81. package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-dock.md +37 -0
  82. package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-gap.md +26 -0
  83. package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-kanban-board.md +96 -0
  84. package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-kanban-lane.md +34 -0
  85. package/claude/references/sd-simplysm-v14/angular/ui-layout/sd-kanban.md +29 -0
  86. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-collapse.md +35 -0
  87. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-pagination.md +26 -0
  88. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-sidebar-container.md +49 -0
  89. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-sidebar-menu.md +22 -0
  90. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-sidebar-user.md +43 -0
  91. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-tab.md +51 -0
  92. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar-container.md +97 -0
  93. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar-menu.md +23 -0
  94. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar-user.md +38 -0
  95. package/claude/references/sd-simplysm-v14/angular/ui-navigation/sd-topbar.md +30 -0
  96. package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-busy-container.md +69 -0
  97. package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-confirm-modal.md +30 -0
  98. package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-dropdown.md +40 -0
  99. package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-modal.md +34 -0
  100. package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-prompt-modal.md +30 -0
  101. package/claude/references/sd-simplysm-v14/angular/ui-overlay/sd-toast.md +35 -0
  102. package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-barcode.md +36 -0
  103. package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-calendar.md +34 -0
  104. package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-echarts.md +32 -0
  105. package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-label.md +24 -0
  106. package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-note.md +23 -0
  107. package/claude/references/sd-simplysm-v14/angular/ui-visual/sd-progress.md +23 -0
  108. package/claude/references/sd-simplysm-v14/angular/utils/inject-routing-signals.md +161 -0
  109. package/claude/references/sd-simplysm-v14/angular/utils/inject-sd-system-config-resource.md +35 -0
  110. package/claude/references/sd-simplysm-v14/angular/utils/mark.md +43 -0
  111. package/claude/references/sd-simplysm-v14/angular/utils/selection-managers.md +96 -0
  112. package/claude/references/sd-simplysm-v14/angular/utils/set-safe-style.md +19 -0
  113. package/claude/references/sd-simplysm-v14/angular/utils/setup-functions.md +93 -0
  114. package/claude/references/sd-simplysm-v14/capacitor-plugin-auto-update/README.md +38 -0
  115. package/claude/references/sd-simplysm-v14/capacitor-plugin-auto-update/apk-installer/apk-installer.md +115 -0
  116. package/claude/references/sd-simplysm-v14/capacitor-plugin-auto-update/auto-update/auto-update.md +113 -0
  117. package/claude/references/sd-simplysm-v14/capacitor-plugin-file-system/README.md +197 -0
  118. package/claude/references/sd-simplysm-v14/capacitor-plugin-intent/README.md +235 -0
  119. package/claude/references/sd-simplysm-v14/capacitor-plugin-usb-storage/README.md +251 -0
  120. package/claude/references/sd-simplysm-v14/core-browser/README.md +52 -0
  121. package/claude/references/sd-simplysm-v14/core-browser/extensions/copy-paste.md +59 -0
  122. package/claude/references/sd-simplysm-v14/core-browser/extensions/element-prototype-extensions.md +137 -0
  123. package/claude/references/sd-simplysm-v14/core-browser/extensions/get-bounds.md +84 -0
  124. package/claude/references/sd-simplysm-v14/core-browser/utils/download-blob.md +59 -0
  125. package/claude/references/sd-simplysm-v14/core-browser/utils/fetch-url-bytes.md +91 -0
  126. package/claude/references/sd-simplysm-v14/core-browser/utils/indexed-db-store.md +131 -0
  127. package/claude/references/sd-simplysm-v14/core-browser/utils/indexed-db-virtual-fs.md +121 -0
  128. package/claude/references/sd-simplysm-v14/core-browser/utils/open-file-dialog.md +60 -0
  129. package/claude/references/sd-simplysm-v14/core-common/README.md +179 -0
  130. package/claude/references/sd-simplysm-v14/core-common/errors/argument-error.md +26 -0
  131. package/claude/references/sd-simplysm-v14/core-common/errors/not-implemented-error.md +33 -0
  132. package/claude/references/sd-simplysm-v14/core-common/errors/sd-error.md +38 -0
  133. package/claude/references/sd-simplysm-v14/core-common/errors/timeout-error.md +36 -0
  134. package/claude/references/sd-simplysm-v14/core-common/extensions/array.md +125 -0
  135. package/claude/references/sd-simplysm-v14/core-common/extensions/map.md +43 -0
  136. package/claude/references/sd-simplysm-v14/core-common/extensions/set.md +35 -0
  137. package/claude/references/sd-simplysm-v14/core-common/features/debounce-queue.md +48 -0
  138. package/claude/references/sd-simplysm-v14/core-common/features/event-emitter.md +52 -0
  139. package/claude/references/sd-simplysm-v14/core-common/features/serial-queue.md +44 -0
  140. package/claude/references/sd-simplysm-v14/core-common/type-utils/common-types.md +100 -0
  141. package/claude/references/sd-simplysm-v14/core-common/type-utils/env.md +42 -0
  142. package/claude/references/sd-simplysm-v14/core-common/types/date-only.md +86 -0
  143. package/claude/references/sd-simplysm-v14/core-common/types/date-time.md +106 -0
  144. package/claude/references/sd-simplysm-v14/core-common/types/lazy-gc-map.md +59 -0
  145. package/claude/references/sd-simplysm-v14/core-common/types/time.md +62 -0
  146. package/claude/references/sd-simplysm-v14/core-common/types/uuid.md +41 -0
  147. package/claude/references/sd-simplysm-v14/core-common/utils/bytes.md +36 -0
  148. package/claude/references/sd-simplysm-v14/core-common/utils/dt.md +60 -0
  149. package/claude/references/sd-simplysm-v14/core-common/utils/err.md +26 -0
  150. package/claude/references/sd-simplysm-v14/core-common/utils/json.md +58 -0
  151. package/claude/references/sd-simplysm-v14/core-common/utils/num.md +56 -0
  152. package/claude/references/sd-simplysm-v14/core-common/utils/obj.md +107 -0
  153. package/claude/references/sd-simplysm-v14/core-common/utils/path.md +30 -0
  154. package/claude/references/sd-simplysm-v14/core-common/utils/primitive.md +28 -0
  155. package/claude/references/sd-simplysm-v14/core-common/utils/str.md +63 -0
  156. package/claude/references/sd-simplysm-v14/core-common/utils/template-strings.md +49 -0
  157. package/claude/references/sd-simplysm-v14/core-common/utils/transfer.md +35 -0
  158. package/claude/references/sd-simplysm-v14/core-common/utils/wait.md +35 -0
  159. package/claude/references/sd-simplysm-v14/core-common/utils/xml.md +49 -0
  160. package/claude/references/sd-simplysm-v14/core-common/utils/zip-archive.md +77 -0
  161. package/claude/references/sd-simplysm-v14/core-node/README.md +59 -0
  162. package/claude/references/sd-simplysm-v14/core-node/features/fs-watcher.md +110 -0
  163. package/claude/references/sd-simplysm-v14/core-node/logging/create-file-reporter.md +78 -0
  164. package/claude/references/sd-simplysm-v14/core-node/logging/pretty-reporter.md +38 -0
  165. package/claude/references/sd-simplysm-v14/core-node/logging/setup-consola.md +77 -0
  166. package/claude/references/sd-simplysm-v14/core-node/utils/cpx.md +128 -0
  167. package/claude/references/sd-simplysm-v14/core-node/utils/fsx.md +168 -0
  168. package/claude/references/sd-simplysm-v14/core-node/utils/pathx.md +73 -0
  169. package/claude/references/sd-simplysm-v14/core-node/worker/create-worker.md +85 -0
  170. package/claude/references/sd-simplysm-v14/core-node/worker/worker.md +160 -0
  171. package/claude/references/sd-simplysm-v14/excel/README.md +66 -0
  172. package/claude/references/sd-simplysm-v14/excel/core-classes/excel-cell.md +79 -0
  173. package/claude/references/sd-simplysm-v14/excel/core-classes/excel-col.md +36 -0
  174. package/claude/references/sd-simplysm-v14/excel/core-classes/excel-row.md +34 -0
  175. package/claude/references/sd-simplysm-v14/excel/core-classes/excel-workbook.md +93 -0
  176. package/claude/references/sd-simplysm-v14/excel/core-classes/excel-worksheet.md +147 -0
  177. package/claude/references/sd-simplysm-v14/excel/types/excel-address-point.md +33 -0
  178. package/claude/references/sd-simplysm-v14/excel/types/excel-style-options.md +57 -0
  179. package/claude/references/sd-simplysm-v14/excel/types/excel-value-type.md +28 -0
  180. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-content-type-data.md +23 -0
  181. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-drawing-data.md +29 -0
  182. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-relationship-data.md +39 -0
  183. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-shared-string-data.md +42 -0
  184. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-style-data.md +97 -0
  185. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-workbook-data.md +22 -0
  186. package/claude/references/sd-simplysm-v14/excel/types/excel-xml-worksheet-data.md +68 -0
  187. package/claude/references/sd-simplysm-v14/excel/types/excel-xml.md +15 -0
  188. package/claude/references/sd-simplysm-v14/excel/utilities/excel-utils.md +101 -0
  189. package/claude/references/sd-simplysm-v14/excel/wrapper/excel-wrapper.md +108 -0
  190. package/claude/references/sd-simplysm-v14/lint/README.md +183 -0
  191. package/claude/references/sd-simplysm-v14/orm-common/README.md +156 -0
  192. package/claude/references/sd-simplysm-v14/orm-common/core/db-context.md +208 -0
  193. package/claude/references/sd-simplysm-v14/orm-common/core/db-transaction-error.md +64 -0
  194. package/claude/references/sd-simplysm-v14/orm-common/expression/expr-unit.md +62 -0
  195. package/claude/references/sd-simplysm-v14/orm-common/expression/expr.md +198 -0
  196. package/claude/references/sd-simplysm-v14/orm-common/models/migration.md +37 -0
  197. package/claude/references/sd-simplysm-v14/orm-common/query-builder/create-query-builder.md +80 -0
  198. package/claude/references/sd-simplysm-v14/orm-common/queryable-executable/executable.md +54 -0
  199. package/claude/references/sd-simplysm-v14/orm-common/queryable-executable/parse-search-query.md +75 -0
  200. package/claude/references/sd-simplysm-v14/orm-common/queryable-executable/queryable.md +238 -0
  201. package/claude/references/sd-simplysm-v14/orm-common/schema-builders/column-builder.md +63 -0
  202. package/claude/references/sd-simplysm-v14/orm-common/schema-builders/foreign-key-builder.md +137 -0
  203. package/claude/references/sd-simplysm-v14/orm-common/schema-builders/index-builder.md +54 -0
  204. package/claude/references/sd-simplysm-v14/orm-common/schema-builders/procedure.md +67 -0
  205. package/claude/references/sd-simplysm-v14/orm-common/schema-builders/table.md +95 -0
  206. package/claude/references/sd-simplysm-v14/orm-common/schema-builders/view.md +71 -0
  207. package/claude/references/sd-simplysm-v14/orm-common/types/data-type.md +146 -0
  208. package/claude/references/sd-simplysm-v14/orm-common/types/dialect.md +151 -0
  209. package/claude/references/sd-simplysm-v14/orm-common/types/expr.md +175 -0
  210. package/claude/references/sd-simplysm-v14/orm-common/types/parse-query-result.md +58 -0
  211. package/claude/references/sd-simplysm-v14/orm-common/types/query-def.md +224 -0
  212. package/claude/references/sd-simplysm-v14/orm-node/README.md +65 -0
  213. package/claude/references/sd-simplysm-v14/orm-node/connections/mssql-db-conn.md +85 -0
  214. package/claude/references/sd-simplysm-v14/orm-node/connections/mysql-db-conn.md +83 -0
  215. package/claude/references/sd-simplysm-v14/orm-node/connections/postgresql-db-conn.md +86 -0
  216. package/claude/references/sd-simplysm-v14/orm-node/core/create-db-conn.md +62 -0
  217. package/claude/references/sd-simplysm-v14/orm-node/core/create-orm.md +107 -0
  218. package/claude/references/sd-simplysm-v14/orm-node/core/node-db-context-executor.md +50 -0
  219. package/claude/references/sd-simplysm-v14/orm-node/types/db-conn-config.md +91 -0
  220. package/claude/references/sd-simplysm-v14/orm-node/types/db-conn-constants.md +33 -0
  221. package/claude/references/sd-simplysm-v14/orm-node/types/db-conn.md +60 -0
  222. package/claude/references/sd-simplysm-v14/orm-node/types/get-dialect-from-config.md +17 -0
  223. package/{README.md → claude/references/sd-simplysm-v14/sd-claude/README.md} +85 -84
  224. package/{docs → claude/references/sd-simplysm-v14/sd-claude}/assets.md +2 -2
  225. package/{docs → claude/references/sd-simplysm-v14/sd-claude}/hooks.md +15 -1
  226. package/claude/references/sd-simplysm-v14/sd-cli/README.md +138 -0
  227. package/claude/references/sd-simplysm-v14/sd-cli/angular-vite-plugin/sd-angular-plugin.md +60 -0
  228. package/claude/references/sd-simplysm-v14/sd-cli/config/build-target.md +31 -0
  229. package/claude/references/sd-simplysm-v14/sd-cli/config/npm-config.md +27 -0
  230. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-browser-support-config.md +19 -0
  231. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-build-package-config.md +21 -0
  232. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-capacitor-config.md +109 -0
  233. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-client-package-config.md +33 -0
  234. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-config.md +78 -0
  235. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-electron-config.md +27 -0
  236. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-package-config.md +18 -0
  237. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-post-publish-script-config.md +19 -0
  238. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-publish-config.md +72 -0
  239. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-pwa-config.md +41 -0
  240. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-scripts-package-config.md +19 -0
  241. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-server-package-config.md +32 -0
  242. package/claude/references/sd-simplysm-v14/sd-cli/config/sd-watch-hook-config.md +19 -0
  243. package/claude/references/sd-simplysm-v14/sd-cli/ts-compiler/sd-ts-compiler.md +158 -0
  244. package/claude/references/sd-simplysm-v14/service-client/README.md +74 -0
  245. package/claude/references/sd-simplysm-v14/service-client/features/event-client.md +93 -0
  246. package/claude/references/sd-simplysm-v14/service-client/features/file-client.md +63 -0
  247. package/claude/references/sd-simplysm-v14/service-client/features/orm-client-connector.md +89 -0
  248. package/claude/references/sd-simplysm-v14/service-client/features/orm-client-db-context-executor.md +31 -0
  249. package/claude/references/sd-simplysm-v14/service-client/main/service-client.md +206 -0
  250. package/claude/references/sd-simplysm-v14/service-client/protocol/client-protocol-wrapper.md +64 -0
  251. package/claude/references/sd-simplysm-v14/service-client/transport/service-transport.md +68 -0
  252. package/claude/references/sd-simplysm-v14/service-client/transport/socket-provider.md +100 -0
  253. package/claude/references/sd-simplysm-v14/service-client/types/blob-input.md +7 -0
  254. package/claude/references/sd-simplysm-v14/service-client/types/browser-worker.md +47 -0
  255. package/claude/references/sd-simplysm-v14/service-client/types/file-collection.md +21 -0
  256. package/claude/references/sd-simplysm-v14/service-client/types/service-connection-options.md +22 -0
  257. package/claude/references/sd-simplysm-v14/service-client/types/service-progress.md +39 -0
  258. package/claude/references/sd-simplysm-v14/service-common/README.md +161 -0
  259. package/claude/references/sd-simplysm-v14/service-common/app-structure/app-structure-item.md +107 -0
  260. package/claude/references/sd-simplysm-v14/service-common/app-structure/get-flat-permissions.md +57 -0
  261. package/claude/references/sd-simplysm-v14/service-common/app-structure/is-usable-modules-chain.md +23 -0
  262. package/claude/references/sd-simplysm-v14/service-common/app-structure/is-usable-modules.md +42 -0
  263. package/claude/references/sd-simplysm-v14/service-common/events/define-event.md +68 -0
  264. package/claude/references/sd-simplysm-v14/service-common/protocol/create-service-protocol.md +93 -0
  265. package/claude/references/sd-simplysm-v14/service-common/protocol/protocol-config.md +21 -0
  266. package/claude/references/sd-simplysm-v14/service-common/protocol/service-add-event-listener-message.md +23 -0
  267. package/claude/references/sd-simplysm-v14/service-common/protocol/service-auth-message.md +17 -0
  268. package/claude/references/sd-simplysm-v14/service-common/protocol/service-emit-event-message.md +21 -0
  269. package/claude/references/sd-simplysm-v14/service-common/protocol/service-error-message.md +29 -0
  270. package/claude/references/sd-simplysm-v14/service-common/protocol/service-event-message.md +21 -0
  271. package/claude/references/sd-simplysm-v14/service-common/protocol/service-get-event-listener-infos-message.md +19 -0
  272. package/claude/references/sd-simplysm-v14/service-common/protocol/service-message.md +52 -0
  273. package/claude/references/sd-simplysm-v14/service-common/protocol/service-progress-message.md +21 -0
  274. package/claude/references/sd-simplysm-v14/service-common/protocol/service-remove-event-listener-message.md +19 -0
  275. package/claude/references/sd-simplysm-v14/service-common/protocol/service-request-message.md +17 -0
  276. package/claude/references/sd-simplysm-v14/service-common/protocol/service-response-message.md +17 -0
  277. package/claude/references/sd-simplysm-v14/service-common/service-types/app-structure-service.md +15 -0
  278. package/claude/references/sd-simplysm-v14/service-common/service-types/auto-update-service.md +20 -0
  279. package/claude/references/sd-simplysm-v14/service-common/service-types/orm-service.md +61 -0
  280. package/claude/references/sd-simplysm-v14/service-common/types/service-upload-result.md +19 -0
  281. package/claude/references/sd-simplysm-v14/service-server/README.md +162 -0
  282. package/claude/references/sd-simplysm-v14/service-server/auth/auth-token-payload.md +18 -0
  283. package/claude/references/sd-simplysm-v14/service-server/auth/sign-jwt.md +30 -0
  284. package/claude/references/sd-simplysm-v14/service-server/auth/verify-jwt.md +35 -0
  285. package/claude/references/sd-simplysm-v14/service-server/core/auth.md +64 -0
  286. package/claude/references/sd-simplysm-v14/service-server/core/define-service.md +81 -0
  287. package/claude/references/sd-simplysm-v14/service-server/core/execute-service-method.md +43 -0
  288. package/claude/references/sd-simplysm-v14/service-server/core/service-context.md +79 -0
  289. package/claude/references/sd-simplysm-v14/service-server/legacy/handle-v1-connection.md +25 -0
  290. package/claude/references/sd-simplysm-v14/service-server/main/create-service-server.md +32 -0
  291. package/claude/references/sd-simplysm-v14/service-server/main/service-server.md +113 -0
  292. package/claude/references/sd-simplysm-v14/service-server/protocol/server-protocol-wrapper.md +35 -0
  293. package/claude/references/sd-simplysm-v14/service-server/services/app-structure-service.md +59 -0
  294. package/claude/references/sd-simplysm-v14/service-server/services/auto-update-service.md +34 -0
  295. package/claude/references/sd-simplysm-v14/service-server/services/orm-service.md +43 -0
  296. package/claude/references/sd-simplysm-v14/service-server/transport-http/handle-http-request.md +33 -0
  297. package/claude/references/sd-simplysm-v14/service-server/transport-http/handle-static-file.md +29 -0
  298. package/claude/references/sd-simplysm-v14/service-server/transport-http/handle-upload.md +33 -0
  299. package/claude/references/sd-simplysm-v14/service-server/transport-socket/service-socket.md +64 -0
  300. package/claude/references/sd-simplysm-v14/service-server/transport-socket/websocket-handler.md +57 -0
  301. package/claude/references/sd-simplysm-v14/service-server/types/service-server-options.md +36 -0
  302. package/claude/references/sd-simplysm-v14/service-server/utils/get-config.md +29 -0
  303. package/claude/references/sd-simplysm-v14/storage/README.md +99 -0
  304. package/claude/references/sd-simplysm-v14/storage/clients/ftp-storage-client.md +99 -0
  305. package/claude/references/sd-simplysm-v14/storage/clients/sftp-storage-client.md +108 -0
  306. package/claude/references/sd-simplysm-v14/storage/factory/storage-factory.md +114 -0
  307. package/claude/references/sd-simplysm-v14/storage/types/file-info.md +32 -0
  308. package/claude/references/sd-simplysm-v14/storage/types/storage-client.md +55 -0
  309. package/claude/references/sd-simplysm-v14/storage/types/storage-conn-config.md +34 -0
  310. package/claude/rules/sd-claude-rules.md +8 -8
  311. package/claude/rules/sd-simplysm-v14.md +33 -0
  312. package/claude/skills/sd-claude-docs/SKILL.md +41 -24
  313. package/claude/skills/sd-claude-docs/references/package-docs.md +240 -116
  314. package/claude/skills/sd-inner-debug/SKILL.md +1 -1
  315. package/claude/skills/sd-inner-review/SKILL.md +4 -2
  316. package/package.json +2 -3
  317. /package/{docs → claude/references/sd-simplysm-v14/sd-claude}/cli.md +0 -0
  318. /package/{docs → claude/references/sd-simplysm-v14/sd-claude}/scripts.md +0 -0
@@ -0,0 +1,193 @@
1
+ ← [CRUD 리스트 레시피 진입점](../crud-list.md)
2
+
3
+ # 확장 D: 선택 모달 전환
4
+
5
+ > **선행:** [확장 A: inline 편집/저장](./extension-a-inline-edit.md) + [확장 B: 선택 기능](./extension-b-selection.md)
6
+
7
+ 같은 리스트 화면이 **다른 화면에서 항목을 골라주는 "선택 모달"로도 재사용**되도록 한다. 라우트로 진입하면 page 뷰(CRUD 리스트), `SdModalProvider.showAsync()`로 열리면 modal 뷰(selectMode에 따라 single/multi)로 자동 전환되며, 선택 결과를 `close.emit`으로 돌려준다.
8
+
9
+ ## When to use / When NOT to use
10
+
11
+ - ✅ 같은 리스트를 라우트 페이지와 "선택 모달" 두 용도로 겸용
12
+ - ✅ 항목을 골라 호출 측에 `SelectModalOutputResult<T>`로 돌려주는 selector 화면
13
+ - ✅ multi 선택에서 페이지 이동 후에도 선택을 누적 유지해야 하는 경우
14
+ - ❌ 부모 레코드의 자식 목록·이력을 **읽기 전용으로** 표시(닫기는 SdModal 기본 "X") → [확장 E](./extension-e-readonly-modal.md)
15
+ - ❌ 리스트 **자체는 page** 이고 행 클릭 시 **편집 모달**만 띄우는 경우 → [확장 F](./extension-f-modal-edit.md). 확장 A(inline 편집)와 상호 배타
16
+ - ❌ 리스트가 아닌 단일 값 셀렉트 버튼 → [`data-select-button.md`](../data-select-button.md)
17
+
18
+ ## 전제조건
19
+
20
+ - 선행: 확장 A(inline 편집/저장) + 확장 B(선택 기능). 본 확장의 코드는 A의 `canEdit` / `_checkIgnoreChanges` 와 B의 `selectedItems` / `isDeleted` / `getItemCellStyleFn` / `selectMode="multi"` 를 그대로 재사용한다
21
+ - 횡단 규칙: [`_common-rules.md`](../_common-rules.md) — 특히 [`injectViewTypeSignal()` 호출 시점](../_common-rules.md#injectviewtypesignal은-생성자-또는-필드-이니셜라이저에서만-호출한다), [signal 필드 초기값에서 다른 signal 읽기 금지](../_common-rules.md#signal-필드-초기값에서-다른-signal을-읽지-않는다)
22
+ - 호출 측: `SdModalProvider.showAsync(CustomerList, { inputs: { selectMode: "multi", selectedItemKeys: [...] } })` 형태로 연다
23
+
24
+ ## 이 확장이 도입하는 요소
25
+
26
+ | 영역 | 추가 |
27
+ |------|------|
28
+ | imports | `input`, `output` (`@angular/core`), `type SdSelectModal`, `type SelectModalOutputResult` (`@simplysm/angular`) |
29
+ | 계약 | `implements SdSelectModal<ICustomer>` + `selectMode` input + `selectedItemKeys` input + `close` output |
30
+ | 생성자 effect | modal 뷰일 때 `selectedItemKeys` → `selectedItems` 복원 (items 로드 후) |
31
+ | `setupCanDeactivate` | modal 뷰에서 변경사항 체크 스킵 |
32
+ | 메서드 | `onSelectedItemsChange` — modal + single 모드일 때 선택 즉시 자동 닫기 |
33
+ | 메서드 | `onModalConfirmClick`, `onModalCancelClick` |
34
+ | 파생 | `canEdit = computed(() => perms().includes("edit") && viewType() === "page")` — modal에서는 inline 편집 자동 비활성화 |
35
+ | 템플릿 | `<sd-sheet>`에 `[selectMode]` 조건부 바인딩 + `[autoSelect]` single 모드 클릭 자동선택 + modal 전용 하단 dock (확인/선택 해제) |
36
+
37
+ ## 코드 (확장 A + B 위에 얹는 diff)
38
+
39
+ > **아래 코드 블록은 diff 조각이다.** 독립 실행 가능한 완성 클래스가 아니며, 선행 확장(A+B) 위에 번호 순서대로 삽입·교체할 지점을 나타낸다. 그대로 컴파일되지 않는다.
40
+
41
+ ```typescript
42
+ // 1) imports 추가
43
+ import { input, output } from "@angular/core";
44
+ import { type SdSelectModal, type SelectModalOutputResult } from "@simplysm/angular";
45
+
46
+ // 2) 클래스에 SdSelectModal<ICustomer> 계약 구현
47
+ export class CustomerList implements SdSelectModal<ICustomer> {
48
+ // ... 기존 확장 A + B 멤버 ...
49
+
50
+ //== SdSelectModal<ICustomer> 계약 ==
51
+ selectMode = input<"single" | "multi" | undefined>();
52
+ selectedItemKeys = input<(number | undefined)[]>([]);
53
+ close = output<SelectModalOutputResult<ICustomer> | undefined>();
54
+
55
+ //== 파생 재정의 — modal 뷰에서는 inline 편집 자동 비활성화 ==
56
+ // canEdit을 viewType=="page" 조건으로 묶어, modal 뷰에서는 편집 셀·저장·등록 버튼이 자동으로 숨겨진다
57
+ canEdit = computed(() => this.perms().includes("edit") && this.viewType() === "page");
58
+
59
+ constructor() {
60
+ // ... 기존 초기 effect (필터/페이지/정렬 재조회) ...
61
+
62
+ // modal 뷰: selectedItemKeys → selectedItems 복원 (items 로드 후)
63
+ effect(() => {
64
+ if (this.viewType() !== "modal") return;
65
+
66
+ const keys = this.selectedItemKeys();
67
+ if (keys.length === 0) return;
68
+
69
+ const currItems = this.items();
70
+ if (currItems.length === 0) return;
71
+
72
+ untracked(() => {
73
+ const sel = currItems.filter((it) => keys.includes(this.trackByFn(it)));
74
+ if (sel.length > 0) this.selectedItems.set(sel);
75
+ });
76
+ });
77
+
78
+ // modal 뷰는 라우트 이탈 개념이 없으므로 변경사항 체크 스킵
79
+ setupCanDeactivate(() => this.viewType() === "modal" || this._checkIgnoreChanges());
80
+ }
81
+
82
+ // 3) 메서드 추가
83
+
84
+ // modal + single 모드: 선택 즉시 자동 닫기
85
+ onSelectedItemsChange(): void {
86
+ if (this.viewType() !== "modal") return;
87
+ if (this.selectMode() !== "single") return;
88
+
89
+ const sel = this.selectedItems();
90
+ if (sel.length !== 1) return;
91
+
92
+ const selKey = this.trackByFn(sel[0]);
93
+ if (this.selectedItemKeys().includes(selKey)) return;
94
+
95
+ this.close.emit({
96
+ selectedItemKeys: sel.map((it) => this.trackByFn(it)).filterExists(),
97
+ selectedItems: sel,
98
+ });
99
+ }
100
+
101
+ onModalConfirmClick(): void {
102
+ const sel = this.selectedItems();
103
+ this.close.emit({
104
+ // id=undefined 신규 행 제거 — index fallback 금지(아래 Anti-patterns 참조)
105
+ selectedItemKeys: sel.map((it) => this.trackByFn(it)).filterExists(),
106
+ selectedItems: sel,
107
+ });
108
+ }
109
+
110
+ onModalCancelClick(): void {
111
+ this.selectedItems.set([]);
112
+
113
+ // single 모드에서만 즉시 close (multi는 "확인" 버튼 필요 — 아래 Anti-patterns 참조)
114
+ if (this.selectMode() === "single") {
115
+ this.close.emit({ selectedItemKeys: [], selectedItems: [] });
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ ```html
122
+ <!-- 4) template — <sd-sheet>에 selectMode + autoSelect 추가, selectedItemsChange 이벤트, 시트 뒤에 modal 하단 dock 배치 -->
123
+ <sd-sheet
124
+ ...(기존)
125
+ [selectMode]="selectMode() ?? 'multi'"
126
+ [autoSelect]="viewType() === 'modal' && selectMode() === 'single' ? 'click' : undefined"
127
+ [(selectedItems)]="selectedItems"
128
+ (selectedItemsChange)="onSelectedItemsChange()"
129
+ >
130
+ <!-- 컬럼들 동일 -->
131
+ </sd-sheet>
132
+
133
+ <!-- modal 하단 확인 바 -->
134
+ @if (viewType() === "modal") {
135
+ <sd-dock
136
+ [position]="'bottom'"
137
+ class="p-sm-default flex-row main-align-end gap-sm bdt bdt-theme-gray-lightest"
138
+ >
139
+ <sd-button [size]="'sm'" [theme]="'danger'"
140
+ (click)="onModalCancelClick()"
141
+ [disabled]="selectedItems().length < 1">
142
+ 선택 해제
143
+ </sd-button>
144
+ @if (selectMode() === "multi") {
145
+ <sd-button [size]="'sm'" [theme]="'primary'" (click)="onModalConfirmClick()">
146
+ 확인({{ selectedItems().length }})
147
+ </sd-button>
148
+ }
149
+ </sd-dock>
150
+ }
151
+ ```
152
+
153
+ ## 포인트
154
+
155
+ - **`canEdit`에 `viewType() === "page"` 조건 추가.** modal 뷰에서 자동으로 inline 편집 셀이 읽기 전용이 되고, 상단 "저장" 버튼과 inline 도구 dock(등록/선택 삭제·복구)이 숨겨진다. 선택 모달은 편집 목적이 아니다.
156
+ - **`[autoSelect]="'click'"` — modal + single 모드 전용.** 클릭 한 번으로 행이 즉시 선택되도록 한다. multi 모드에서는 `undefined`(기본 동작)로 두어 체크박스 누적 선택이 유지된다.
157
+ - **`(selectedItemsChange)` 이벤트에서 single 자동 닫기.** modal + single 모드일 때 행 하나가 선택되면 `close.emit`으로 결과를 즉시 반환한다. 이미 선택된 key와 동일한 행을 클릭하면 무시하여 중복 닫기를 방지한다.
158
+ ## 🚫 Anti-patterns
159
+
160
+ ### multi 모드에서 "선택 해제"가 close까지 호출
161
+
162
+ ```typescript
163
+ // ✅ single에서만 즉시 close. multi는 set([])만 수행 후 "확인" 버튼으로 최종 emit
164
+ onModalCancelClick(): void {
165
+ this.selectedItems.set([]);
166
+ if (this.selectMode() === "single") {
167
+ this.close.emit({ selectedItemKeys: [], selectedItems: [] });
168
+ }
169
+ }
170
+ ```
171
+
172
+ **근거**: multi에서 "선택 해제" = "취소 + 닫기"가 되면 사용자가 다시 선택을 시작하려고 모달을 재오픈해야 한다. multi는 여러 행을 점진적으로 누적하는 UX이므로 닫는 트리거는 "확인" 버튼에만 둔다.
173
+
174
+ ### `selectedItemKeys` 반환에 index fallback
175
+
176
+ ```typescript
177
+ // ✅ undefined를 제거하여 확정된 key만 전달
178
+ this.close.emit({
179
+ selectedItemKeys: sel.map((it) => this.trackByFn(it)).filterExists(),
180
+ selectedItems: sel,
181
+ });
182
+ ```
183
+
184
+ **근거**: `SelectModalOutputResult<T>.selectedItemKeys`는 호출 측이 DB 식별자로 사용한다(`packages/angular/src/core/select-modal-output-result.ts:4`). 신규 행 index를 섞으면 호출 측의 "이미 저장된 id" 집합과 충돌한다.
185
+
186
+ ## 관련 Entry
187
+
188
+ - 진입점: [crud-list.md](../crud-list.md)
189
+ - 선행: [확장 A: inline 편집/저장](./extension-a-inline-edit.md) — `canEdit` / `_checkIgnoreChanges` 제공
190
+ - 선행: [확장 B: 선택 기능](./extension-b-selection.md) — `selectedItems` / multi 선택 / `getItemCellStyleFn` 제공
191
+ - 대안: [확장 E: 조회 전용 modal](./extension-e-readonly-modal.md) — 부모 레코드의 자식 목록·이력을 input으로 받아 읽기 전용 표시. `SdSelectModal<T>` 계약을 부착하지 않는다
192
+ - 대안: [확장 F: 모달 편집 모드](./extension-f-modal-edit.md) — page 상에서 행 클릭 시 편집 모달. inline 편집(확장 A)과 상호 배타
193
+ - 계약 타입: `SdSelectModal<T>` (`packages/angular/src/controls/button/sd-modal-select-button.ts:30`), `SelectModalOutputResult<T>` (`packages/angular/src/core/select-modal-output-result.ts:4`)
@@ -0,0 +1,140 @@
1
+ ← [CRUD 리스트 레시피 진입점](../crud-list.md)
2
+
3
+ # 확장 E: 조회 전용 modal
4
+
5
+ > **선행:** 없음 (최소 뼈대 §3에 직접 얹음 — 확장 A/B/D 미사용)
6
+
7
+ 호출자(상세 화면 등)가 부모 레코드 식별자를 input으로 전달하면, 이 modal은 해당 부모의 자식 목록·이력만 필터링해 읽기 전용으로 표시한다. 닫기는 SdModal 기본 "X" 버튼이며, 선택·확정·저장·이탈 방지는 전부 불필요하다.
8
+
9
+ - ✅ 부모 레코드의 자식 목록·이력만 필터링해 읽기 전용으로 표시할 때
10
+ - ❌ 항목을 골라 호출자에게 돌려줘야 할 때 → [확장 D: 선택 모달](./extension-d-select-modal.md)
11
+ - ❌ 부모 레코드에 대한 inline 편집·삭제가 필요할 때 → [확장 A](./extension-a-inline-edit.md)(+B) 또는 [확장 F: 모달 편집](./extension-f-modal-edit.md)
12
+
13
+ 호출 예:
14
+
15
+ ```typescript
16
+ await this._sdModal.showAsync({
17
+ title: "고객 주문 이력",
18
+ type: CustomerOrderHistoryModal,
19
+ inputs: { customerId: 123 },
20
+ });
21
+ ```
22
+
23
+ **이 확장이 도입하는 요소:**
24
+
25
+ - **imports:** `input`(`@angular/core`), `expr`(`@simplysm/orm-common`) 추가
26
+ - **input:** 부모 식별자(예: `customerId = input.required<number>()`)
27
+ - **초기 effect 의존성:** 부모 식별자 input 추가
28
+ - **`_search` 변경:** where절에 부모 식별자 하드 필터(`expr.eq(...)`), 기존 `filter.searchText` 조건과 AND
29
+ - **부착하지 않는 요소:** `implements SdSelectModal<T>` 계약, `selectedItems` / 하단 확인 바 / `canEdit` / `diffs` / `setupCanDeactivate` / `<sd-form #formCtrl>` 래퍼
30
+
31
+ ```typescript
32
+ // 1) imports 추가 — @angular/core의 {input}
33
+ import { input } from "@angular/core";
34
+
35
+ // 2) 클래스 선언 — implements 없음. SdSelectModal<T> 계약 3종 부착 안 함
36
+ export class CustomerOrderHistoryModal {
37
+ // ...DI, perms, 상태는 최소 뼈대와 동일
38
+
39
+ // 3) 부모 식별자 input (필수) — 맥락에 맞는 이름(customerId / orderId / companyId 등)
40
+ customerId = input.required<number>();
41
+
42
+ // 4) 초기 effect 의존성에 input 추가
43
+ constructor() {
44
+ effect(() => {
45
+ if (!this.perms().includes("use")) {
46
+ this.initialized.set(true);
47
+ return;
48
+ }
49
+
50
+ this.lastFilter();
51
+ this.page();
52
+ this.sortingDefs();
53
+ this.customerId(); // ← input 의존성 추가
54
+
55
+ void untracked(async () => {
56
+ this.busyCount.update((v) => v + 1);
57
+ await this._sdToast.try(async () => { await this._refresh(); });
58
+ this.busyCount.update((v) => v - 1);
59
+ this.initialized.set(true);
60
+ });
61
+ });
62
+ }
63
+
64
+ // 5) _search — where절에 부모 식별자 하드 필터. filter.searchText 등 기존 조건과 AND
65
+ private async _search(usePagination: boolean): Promise<{ items: ICustomerOrder[]; pageLength: number }> {
66
+ const filter = this.lastFilter();
67
+ const sortingDefs = this.sortingDefs();
68
+ const page = this.page();
69
+ const customerId = this.customerId(); // ← input 값
70
+
71
+ return this._appOrm.connectAsync(async (db) => {
72
+ let qr1 = db.customerOrder()
73
+ .where((item) => [expr.eq(item.customerId, customerId)]);
74
+
75
+ if (!str.isNullOrEmpty(filter.searchText)) {
76
+ qr1 = qr1.search((item) => [item.name], filter.searchText);
77
+ }
78
+ // 나머지는 최소 뼈대 _search와 동일 (paging/sorting/select/limit)
79
+ // ...
80
+ });
81
+ }
82
+ }
83
+
84
+ // 6) template — modal 전용 레이아웃. <sd-sheet>에 selectMode / selectedItems 미사용.
85
+ // 시트 셀은 순수 표시({{ item.name }}). 하단 "선택 해제 / 확인" 바, 상단 inline 도구 dock 부재.
86
+ `
87
+ <sd-topbar-container>
88
+ <sd-dock-container>
89
+ <sd-dock class="p-default">
90
+ <sd-form (formSubmit)="onFilterSubmit()">
91
+ <!-- 필터 (최소 뼈대와 동일) -->
92
+ </sd-form>
93
+ </sd-dock>
94
+
95
+ <sd-sheet
96
+ [key]="'customer-order-history-sheet'"
97
+ [items]="items()"
98
+ [(currentPage)]="page"
99
+ [totalPageCount]="pageLength()"
100
+ [(sorts)]="sortingDefs"
101
+ [trackByFn]="trackByFn"
102
+ >
103
+ <sd-sheet-column [key]="'name'" [header]="'이름'">
104
+ <ng-template [cell]="items()" let-item="item">
105
+ <div class="p-xs-sm">{{ item.name }}</div>
106
+ </ng-template>
107
+ </sd-sheet-column>
108
+ <!-- 필요한 조회 컬럼만 -->
109
+ </sd-sheet>
110
+ </sd-dock-container>
111
+ </sd-topbar-container>
112
+ `
113
+ ```
114
+
115
+ **포인트:**
116
+
117
+ - **부모 식별자는 호출자가 `inputs`으로 전달한다.** 값이 반드시 주어져야 하면 `input.required<T>()`, 없으면 전체 조회로 fallback하는 설계면 `input<T | undefined>()`. 어느 쪽이든 `_search`의 `where` 절과 초기 effect 의존성에 반드시 포함시킨다.
118
+ - **닫기 = SdModal 기본 "X".** `close` output이 없으므로 `SdModalProvider.showAsync`의 리턴값도 사용하지 않는다. 호출 측은 `await showAsync(...)` 결과를 버리거나 `void`로 처리한다.
119
+ - **시트는 읽기 전용.** `[cell]` 템플릿에 `<sd-textfield>` 대신 `{{ item.name }}` 같은 순수 표시만 쓰고, `let-edit="edit"` / `[readonly]="!edit"` / `(valueChange)="mark(items)"`는 제거한다. `canEdit` / `diffs` / `_itemsSnapshot` / `setupCanDeactivate`도 함께 제거한다.
120
+ - **`viewType()` 분기는 쓰지 않아도 된다.** 조회 전용 modal은 보통 modal 전용으로 라우트 없이 등록된다. page/modal 양쪽을 모두 지원해야 할 때만 `viewType()`으로 topbar 영역을 분기하고, 시트·필터는 공통으로 둔다.
121
+ - **input 반영 패턴은 공통 규칙을 따른다.** → [공통 규칙: input 변경을 effect 내부에서 filter·lastFilter·page에 반영한다](../_common-rules.md#input-변경을-effect-내부에서-filterlastfilterpage에-반영한다) · [공통 규칙: input 의존 데이터 로딩에 `void this._initAsync()`를 사용하지 않는다](../_common-rules.md#input-의존-데이터-로딩에-void-this_initasync를-사용하지-않는다)
122
+
123
+ ## 🚫 흔한 실수
124
+
125
+ ### signal 필드 초기값에서 부모 식별자 input 읽기
126
+
127
+ ```typescript
128
+ // ✅ 기본값은 고정, 부모 식별자는 _search 호출부에서 input을 직접 읽는다
129
+ filter = signal<IFilter>({});
130
+ // _search 내부:
131
+ const customerId = this.customerId();
132
+ qr1 = qr1.where((item) => [expr.eq(item.customerId, customerId)]);
133
+ ```
134
+
135
+ **근거**: 필드 이니셜라이저는 부모로부터 input 값이 전달되기 전에 실행되므로 항상 기본값만 반환한다. → [공통 규칙: signal 필드 초기값에서 다른 signal을 읽지 않는다](../_common-rules.md#signal-필드-초기값에서-다른-signal을-읽지-않는다)
136
+
137
+ ## Cross-reference
138
+
139
+ - 진입점: [crud-list.md](../crud-list.md)
140
+ - 관련: [확장 D: 선택 모달 전환](./extension-d-select-modal.md) (계약이 다른 modal 변형) · [확장 F: 모달 편집 모드](./extension-f-modal-edit.md) (부모 레코드 편집 modal)
@@ -0,0 +1,123 @@
1
+ ← [CRUD 리스트 레시피 진입점](../crud-list.md)
2
+
3
+ # 확장 F: 모달 편집 모드
4
+
5
+ > **선행:** 없음 (최소 뼈대 §3에 직접 얹음 — [확장 A: inline 편집/저장](./extension-a-inline-edit.md)와 **상호 배타**)
6
+
7
+ 시트 셀 직접 수정(inline 편집) + 일괄 저장 대신, **행 클릭 시 편집 모달을 띄워 한 행씩 편집**하는 모드. 확장 A(inline 편집)와 **상호 배타**이므로 확장 A가 덧씌우는 파이프라인(`diffs` / `_itemsSnapshot` / `onSubmit` / `setupCanDeactivate` / `hostDirectives.sdSaveCommand` / `<sd-form #formCtrl>` 래퍼)을 이 확장에서는 부착하지 않는다. 대신 [`SdModalProvider.showAsync`](../../providers/sd-modal-provider.md)로 편집 모달을 호출하고, 모달 close 후 `_refresh()`로 리스트를 재조회한다.
8
+
9
+ **이 확장이 도입하는 요소:**
10
+
11
+ - **imports:** `SdAnchor`, `SdModalProvider`, `tablerEdit`
12
+ - **DI:** `SdModalProvider`
13
+ - **클래스 필드:** `tablerEdit` 아이콘 템플릿 참조
14
+ - **메서드:** `onCreateItemButtonClick`, `onEditItemButtonClick`, `_editItem`
15
+ - **템플릿:** 이름 컬럼 셀을 `<sd-anchor>` + 편집 아이콘으로 교체한다. inline 편집용 `<sd-textfield let-edit="edit">`는 사용하지 않는다. 등록 버튼은 `_editItem()` 직접 호출로 전환한다
16
+ - **제거 대상(확장 A가 이미 적용되어 있는 경우):** `hostDirectives.sdSaveCommand` / `host (sdSaveCommand)` / `onSaveButtonClick` / `onSubmit` / `diffs` / `_itemsSnapshot` / `_checkIgnoreChanges` / `_upsertItem` / `getIsItemChanged` / `onRemoveNewItemButtonClick` / `setupCanDeactivate` / `<sd-form #formCtrl (formSubmit)="onSubmit()">` 래퍼
17
+
18
+ > 상세: [`SdModalProvider.showAsync` 편집 모달 호출](../../providers/sd-modal-provider.md#편집-모달-호출) · [`<sd-anchor>`](../../ui-form/sd-anchor.md)
19
+
20
+ > **아래 코드 블록은 diff 조각이다.** 독립 실행 가능한 완성 클래스가 아니며, 최소 뼈대 위에 번호 순서대로 삽입할 지점을 나타낸다. 그대로 컴파일되지 않는다.
21
+
22
+ ```typescript
23
+ // 1) imports 추가
24
+ import { SdAnchor, SdModalProvider } from "@simplysm/angular";
25
+ import { tablerEdit } from "@ng-icons/tabler-icons";
26
+ // 앱별 편집 모달 컴포넌트 (crud-detail.md 레시피로 작성):
27
+ import { CustomerEditModal } from "./CustomerEditModal";
28
+
29
+ // 2) DI 추가
30
+ private readonly _sdModal = inject(SdModalProvider);
31
+
32
+ // 3) 클래스 필드 추가 — 편집 버튼 아이콘
33
+ protected readonly tablerEdit = tablerEdit;
34
+
35
+ // 4) template — 이름 컬럼 셀을 <sd-anchor> + 편집 아이콘으로 교체한다.
36
+ // inline 편집용 <sd-textfield> / let-edit 바인딩은 쓰지 않는다.
37
+ `
38
+ <sd-sheet-column [key]="'name'" [header]="'이름'">
39
+ <ng-template [cell]="items()" let-item="item">
40
+ <sd-anchor (click)="onEditItemButtonClick(item, $event)" class="flex-row">
41
+ <div class="p-xs-sm">
42
+ <ng-icon [svg]="tablerEdit" />
43
+ </div>
44
+ <div class="flex-fill p-xs-sm">{{ item.name }}</div>
45
+ </sd-anchor>
46
+ </ng-template>
47
+ </sd-sheet-column>
48
+ `
49
+
50
+ // 5) inline 편집용 도구 dock의 "등록" 버튼은 _editItem() 호출로 바꾼다.
51
+ // "선택 삭제/복구"를 남기려면 bulk API로 전환한다(아래 포인트 참조).
52
+ // template:
53
+ `<sd-button ... (click)="onCreateItemButtonClick()">등록</sd-button>`
54
+
55
+ // 6) 메서드 교체
56
+ protected async onCreateItemButtonClick(): Promise<void> {
57
+ await this._editItem();
58
+ }
59
+
60
+ protected async onEditItemButtonClick(item: ICustomer, event: MouseEvent): Promise<void> {
61
+ event.preventDefault();
62
+ event.stopPropagation();
63
+ await this._editItem(item);
64
+ }
65
+
66
+ private async _editItem(item?: ICustomer): Promise<void> {
67
+ const r = await this._sdModal.showAsync({
68
+ title: item == null ? "고객 등록" : "고객 수정",
69
+ type: CustomerEditModal,
70
+ inputs: { itemId: item?.id },
71
+ });
72
+ if (r != null) await this._refresh();
73
+ }
74
+
75
+ // 7) 제거 대상 (확장 A가 이미 적용되어 있는 경우 — 위 "제거 대상" 불릿 참조):
76
+ // - @Component hostDirectives의 sdSaveCommand / host의 (sdSaveCommand)
77
+ // - onSaveButtonClick / onSubmit / onAddItemButtonClick
78
+ // - diffs computed / _itemsSnapshot / _checkIgnoreChanges / _upsertItem
79
+ // - getIsItemChanged / onRemoveNewItemButtonClick
80
+ // - setupCanDeactivate(...) 호출 (이탈 방지는 편집 모달 쪽 책임)
81
+ // - <sd-form #formCtrl (formSubmit)="onSubmit()"> 래퍼 → <sd-sheet>를 main 영역에 직접 배치
82
+ ```
83
+
84
+ **포인트:**
85
+
86
+ - **모달 편집 모드에는 inline diff 개념이 없다.** 개별 item 변경은 `CustomerEditModal`(상세 폼) 내부에서 즉시 upsert하고 결과를 `close.emit(true)` 같은 신호로 반환한다. 리스트는 모달 close 후 `_refresh()`로 재조회한다.
87
+ - **`CustomerEditModal`은 [`crud-detail.md`](../crud-detail.md) 레시피로 별도 작성한다.** modal 뷰 분기를 그대로 활용한다.
88
+ - **시트 `[cell]` 템플릿에 `let-edit="edit"` / `[readonly]="!edit"` 바인딩은 불필요** — inline 편집이 아니며 읽기 전용 표시만 한다.
89
+ - **"선택 삭제/복구"를 남길 경우 (확장 B와 병용):** `onToggleDeleteItemsButtonClick(del)` 내부를 diff 방식 대신 **bulk API 호출 + `_refresh()`** 로 구현한다. 확장 F는 `diffs` 파이프라인이 없어 확장 B 원본의 diff 경로가 동작하지 않기 때문이다.
90
+ - **`itemId: item?.id`**: `item`이 undefined이면 "등록", id가 있으면 "수정"으로 위임한다. `CustomerEditModal` 내부에서 id 유무로 분기한다.
91
+
92
+ **🚫 흔한 실수**
93
+
94
+ > 공통 규칙(`mark` 오용, `setupCanDeactivate` 호출 위치, 시트 셀 `[inset]`/`[size]` 등)은 [레시피 공통 규칙](../_common-rules.md)을 참조한다. 이 섹션은 **모달 편집 모드 고유 실수**만 다룬다.
95
+
96
+ ### 확장 A의 inline 편집 파이프라인과 동시 적용
97
+
98
+ ```typescript
99
+ // ✅ 두 경로 중 하나만 선택한다. 확장 F를 선택하면 확장 A가 덧씌웠던 파이프라인은 전부 제거한다.
100
+ @Component({
101
+ // hostDirectives / sdSaveCommand 불필요 — 모달 편집 모드는 inline 저장이 없다
102
+ template: `
103
+ <!-- <sd-form #formCtrl (formSubmit)="onSubmit()"> 래퍼 없음 -->
104
+ <sd-sheet ...>
105
+ <sd-sheet-column [key]="'name'">
106
+ <ng-template [cell]="items()" let-item="item">
107
+ <sd-anchor (click)="onEditItemButtonClick(item, $event)">
108
+ <ng-icon [svg]="tablerEdit" /> {{ item.name }}
109
+ </sd-anchor>
110
+ </ng-template>
111
+ </sd-sheet-column>
112
+ </sd-sheet>
113
+ `,
114
+ })
115
+ ```
116
+
117
+ **근거**: Ctrl+S가 어느 폼을 submit할지 모호해지고, `setupCanDeactivate`가 편집 모달 open 중에 이중 발동하며, 동일 행 편집 경로(inline vs 모달)가 둘 다 활성화되어 UX가 깨진다. "편집 모드"는 하나만 선택한다.
118
+
119
+ ## Cross-reference
120
+
121
+ - 진입점: [crud-list.md](../crud-list.md)
122
+ - 관련: [확장 A: inline 편집/저장](./extension-a-inline-edit.md) (이 확장과 상호 배타)
123
+ - 공통 규칙: [_common-rules.md](../_common-rules.md)
@@ -0,0 +1,145 @@
1
+ ← [CRUD 리스트 레시피 진입점](../crud-list.md)
2
+
3
+ # 확장 G: 엑셀 업로드/다운로드
4
+
5
+ > **선행:** [확장 A: inline 편집/저장](./extension-a-inline-edit.md) (`_upsertItem` / `_search` / 감사 로그 재사용)
6
+
7
+ `SdFileDialogProvider`로 파일 선택, `ExcelWrapper`(@simplysm/excel) + `zod` 스키마로 읽기/쓰기를 수행한다. 다운로드는 확장 A의 `_search(false)`로 페이지네이션 없이 전체를 조회한 뒤 `@simplysm/core-browser`의 `downloadBlob`으로 내려받는다. 업로드된 각 행은 확장 A의 `_upsertItem`을 재사용해 중복 검사·감사 로그를 일관된 경로로 적용한다.
8
+
9
+ **이 확장이 도입하는 요소:**
10
+
11
+ - **imports:** `SdFileDialogProvider`, `DateTime`, `downloadBlob`(@simplysm/core-browser), `ExcelWrapper`(@simplysm/excel), `z`(zod), `tablerFileExcel`, `tablerUpload`
12
+ - **DI:** `SdFileDialogProvider`
13
+ - **필드:** `tablerFileExcel` / `tablerUpload` 아이콘, `_excelWrapper` (zod 스키마로 컬럼 정의)
14
+ - **메서드:** `onUploadExcelButtonClick`, `onDownloadExcelButtonClick`
15
+ - **템플릿:** 확장 A가 도입한 inline 도구 dock 뒤쪽에 엑셀 업로드/다운로드 버튼 2개 추가
16
+
17
+ > **아래 코드 블록은 diff 조각이다.** 독립 실행 가능한 완성 클래스가 아니며, 선행 확장(A) 위에 번호 순서대로 삽입할 지점을 나타낸다. 그대로 컴파일되지 않는다.
18
+
19
+ ```typescript
20
+ // 1) imports 추가
21
+ import { tablerFileExcel, tablerUpload } from "@ng-icons/tabler-icons";
22
+ import { SdFileDialogProvider } from "@simplysm/angular";
23
+ import { DateTime } from "@simplysm/core-common";
24
+ import { downloadBlob } from "@simplysm/core-browser";
25
+ import { ExcelWrapper } from "@simplysm/excel";
26
+ import { z } from "zod";
27
+
28
+ // 2) DI 추가
29
+ private readonly _sdFileDialog = inject(SdFileDialogProvider);
30
+
31
+ // 3) 클래스 필드 — 아이콘 + ExcelWrapper (zod 스키마로 컬럼 정의)
32
+ protected readonly tablerFileExcel = tablerFileExcel;
33
+ protected readonly tablerUpload = tablerUpload;
34
+
35
+ private readonly _excelWrapper = new ExcelWrapper(
36
+ z.object({
37
+ id: z.number().optional().describe("ID"),
38
+ name: z.string().describe("이름"),
39
+ phone: z.string().optional().describe("전화번호"),
40
+ categoryId: z.number().optional().describe("카테고리.ID"),
41
+ // isDeleted는 확장 B 적용 시(DB Table에 isDeleted 컬럼이 있는 경우)에만 추가:
42
+ // isDeleted: z.boolean().describe("삭제"),
43
+ lastModifiedAt: z.custom<DateTime>().optional().describe("최종수정일시"),
44
+ lastModifiedBy: z.string().optional().describe("최종수정자"),
45
+ }),
46
+ );
47
+
48
+ // 4) template — 확장 A가 도입한 inline 도구 dock 뒤쪽에 엑셀 버튼 2개 추가.
49
+ // 확장 B가 함께 적용되면 동일 dock 안에 "등록 → 선택 삭제 → 선택 복구 → 엑셀 업로드 → 엑셀 다운로드" 순으로 배치한다.
50
+ `
51
+ <!-- 확장 A가 도입한 도구 dock (canEdit && page 가드) -->
52
+ @if (canEdit() && viewType() === "page") {
53
+ <sd-dock class="flex-row gap-sm p-xs-default">
54
+ <sd-button [size]="'sm'" [theme]="'link-primary'" (click)="onAddItemButtonClick()">
55
+ <ng-icon [svg]="tablerCirclePlus" /> 등록
56
+ </sd-button>
57
+ <!-- 확장 B 적용 시: 선택 삭제 / 선택 복구 버튼이 여기에 위치 -->
58
+
59
+ <!-- ↓ 확장 G가 추가 -->
60
+ <sd-button [size]="'sm'" [theme]="'link-success'" (click)="onUploadExcelButtonClick()">
61
+ <ng-icon [svg]="tablerUpload" /> 엑셀 업로드
62
+ </sd-button>
63
+ <sd-button [size]="'sm'" [theme]="'link-success'" (click)="onDownloadExcelButtonClick()">
64
+ <ng-icon [svg]="tablerFileExcel" /> 엑셀 다운로드
65
+ </sd-button>
66
+ </sd-dock>
67
+ }
68
+ `
69
+
70
+ // 5) 메서드 추가
71
+ async onUploadExcelButtonClick(): Promise<void> {
72
+ const file = await this._sdFileDialog.showAsync(false, ".xlsx");
73
+ if (file == null) return;
74
+ if (Array.isArray(file)) return;
75
+
76
+ this.busyCount.update((v) => v + 1);
77
+ await this._sdToast.try(async () => {
78
+ const excelItems = await this._excelWrapper.read(file);
79
+ const changedIds: number[] = [];
80
+ await this._appOrm.connectAsync(async (db) => {
81
+ for (const raw of excelItems) {
82
+ changedIds.push(await this._upsertItem(db, raw, "엑셀업로드"));
83
+ }
84
+ });
85
+ await this._appSharedData.emitAsync(this.SHARED_DATA_KEY, changedIds);
86
+
87
+ this._sdToast.success("업로드되었습니다.");
88
+
89
+ await this._refresh();
90
+ });
91
+ this.busyCount.update((v) => v - 1);
92
+ }
93
+
94
+ async onDownloadExcelButtonClick(): Promise<void> {
95
+ if (this.busyCount() > 0) return;
96
+
97
+ this.busyCount.update((v) => v + 1);
98
+ await this._sdToast.try(async () => {
99
+ // 전체 조회 (페이지네이션 없이) — 확장 A의 _search를 그대로 재사용
100
+ const r = await this._search(false);
101
+ const wb = await this._excelWrapper.write(this.viewTitle(), r.items);
102
+ try {
103
+ downloadBlob(
104
+ await wb.toBlob(),
105
+ `${this.viewTitle()}_${new DateTime().toFormatString("yyMMdd")}.xlsx`,
106
+ );
107
+ } finally {
108
+ await wb.close();
109
+ }
110
+ });
111
+ this.busyCount.update((v) => v - 1);
112
+ }
113
+ ```
114
+
115
+ **포인트:**
116
+
117
+ - **다운로드는 `_search(false)`로 전체를 쿼리한다.** 페이지당 50건 제한이 걸리면 현재 페이지만 다운로드되므로 `usePagination: false`를 명시한다.
118
+ - **업로드는 `_excelWrapper.read(file)` → `_upsertItem` 루프로 수행한다.** 확장 A의 중복 검사·감사 로그가 동일하게 적용되며, `logType: "엑셀업로드"`로 감사 로그를 구분한다. 상세 Usage는 [`SdFileDialogProvider.showAsync`](../../providers/sd-file-dialog-provider.md#usage) 참조.
119
+ - **엑셀의 텍스트 컬럼을 FK id로 변환해야 하면** DB 재조회 대신 `useSharedSignal(...)`로 이미 로드된 공유 데이터를 `toMapValues`로 변환하여 재사용한다.
120
+
121
+ **🚫 흔한 실수**
122
+
123
+ > 공통 규칙(`mark` 오용, `setupCanDeactivate` 호출 위치, 시트 셀 `[inset]/[size]`, 공유 데이터 `wait()` 호출 위치 등)은 [레시피 공통 규칙](../_common-rules.md)을 참조한다. 이 섹션은 **엑셀 업로드/다운로드 고유 실수**만 다룬다.
124
+
125
+ ### 필수 필드를 `z.string().optional()`로 선언
126
+
127
+ ```typescript
128
+ // ✅ 필수 필드는 .optional() 없이 선언 — 빈 셀 행은 ExcelWrapper가 safeParse 단계에서 차단
129
+ new ExcelWrapper(
130
+ z.object({
131
+ id: z.number().optional().describe("ID"),
132
+ name: z.string().describe("이름"), // ← 필수
133
+ phone: z.string().optional().describe("전화번호"),
134
+ categoryId: z.number().optional().describe("카테고리.ID"),
135
+ }),
136
+ );
137
+ ```
138
+
139
+ **근거**: `ExcelWrapper.read`는 각 행을 `_schema.safeParse(record)`로 검증하고 실패 시 에러를 던진다(`packages/excel/src/excel-wrapper.ts:77`). zod 스키마가 업로드 유효성의 유일한 방어선이므로, 필수 필드에 `.optional()`을 달면 검증 자체를 통과해 잘못된 값이 `_upsertItem`까지 내려간다. `isDeleted` 컬럼이 있는 테이블에서는 [공통 규칙: 삭제 방식](../_common-rules.md#삭제-방식은-db-스키마에-따라-결정한다)에 따라 `isDeleted: z.boolean().describe("삭제")` 필드를 추가한다(확장 B 병용).
140
+
141
+ ## Cross-reference
142
+
143
+ - 진입점: [crud-list.md](../crud-list.md)
144
+ - 선행: [확장 A: inline 편집/저장](./extension-a-inline-edit.md) (`_upsertItem`/`_search`/감사 로그 재사용)
145
+ - 병용 가능: [확장 B: 선택 기능 + 선택 삭제/복구](./extension-b-selection.md) (`isDeleted` 컬럼이 있는 테이블 — zod 스키마에 `isDeleted` 필드 추가)