@simplysm/sd-claude 14.0.65 → 14.0.66

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 (227) hide show
  1. package/claude/references/sd-requirement-source-handling.md +64 -0
  2. package/claude/references/sd-simplysm14/README.md +44 -40
  3. package/claude/references/sd-simplysm14/apis/angular/README.md +95 -0
  4. package/claude/references/sd-simplysm14/apis/angular/app-structure.md +49 -0
  5. package/claude/references/sd-simplysm14/apis/angular/buttons.md +42 -0
  6. package/claude/references/sd-simplysm14/apis/angular/crud.md +35 -0
  7. package/claude/references/sd-simplysm14/apis/angular/forms.md +63 -0
  8. package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +80 -0
  9. package/claude/references/sd-simplysm14/apis/angular/kanban.md +33 -0
  10. package/claude/references/sd-simplysm14/apis/angular/layout.md +41 -0
  11. package/claude/references/sd-simplysm14/apis/angular/modal.md +63 -0
  12. package/claude/references/sd-simplysm14/apis/angular/routing.md +45 -0
  13. package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +35 -0
  14. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +50 -0
  15. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +42 -0
  16. package/claude/references/sd-simplysm14/apis/angular/sheet.md +52 -0
  17. package/claude/references/sd-simplysm14/apis/angular/toast.md +46 -0
  18. package/claude/references/sd-simplysm14/apis/angular/visual.md +41 -0
  19. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +76 -0
  20. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +83 -0
  21. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +80 -0
  22. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +39 -0
  23. package/claude/references/sd-simplysm14/apis/core-browser/README.md +112 -0
  24. package/claude/references/sd-simplysm14/apis/core-common/README.md +53 -0
  25. package/claude/references/sd-simplysm14/apis/core-common/extensions.md +123 -0
  26. package/claude/references/sd-simplysm14/apis/core-common/features.md +46 -0
  27. package/claude/references/sd-simplysm14/apis/core-common/types.md +114 -0
  28. package/claude/references/sd-simplysm14/apis/core-common/utils.md +158 -0
  29. package/claude/references/sd-simplysm14/apis/core-node/README.md +12 -0
  30. package/claude/references/sd-simplysm14/apis/core-node/consola.md +64 -0
  31. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +52 -0
  32. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +53 -0
  33. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +81 -0
  34. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +55 -0
  35. package/claude/references/sd-simplysm14/apis/core-node/worker.md +111 -0
  36. package/claude/references/sd-simplysm14/apis/excel/README.md +81 -0
  37. package/claude/references/sd-simplysm14/apis/lint/README.md +80 -0
  38. package/claude/references/sd-simplysm14/apis/orm-common/README.md +33 -0
  39. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +77 -0
  40. package/claude/references/sd-simplysm14/apis/orm-common/executable.md +20 -0
  41. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +92 -0
  42. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +98 -0
  43. package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +128 -0
  44. package/claude/references/sd-simplysm14/apis/orm-node/README.md +59 -0
  45. package/claude/references/sd-simplysm14/apis/sd-claude/README.md +9 -0
  46. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +50 -0
  47. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +155 -0
  48. package/claude/references/sd-simplysm14/apis/service-client/README.md +92 -0
  49. package/claude/references/sd-simplysm14/apis/service-common/README.md +29 -0
  50. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +63 -0
  51. package/claude/references/sd-simplysm14/apis/service-common/messages.md +56 -0
  52. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +64 -0
  53. package/claude/references/sd-simplysm14/apis/service-common/service-types.md +43 -0
  54. package/claude/references/sd-simplysm14/apis/service-server/README.md +20 -0
  55. package/claude/references/sd-simplysm14/apis/service-server/auth.md +31 -0
  56. package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +47 -0
  57. package/claude/references/sd-simplysm14/apis/service-server/define-service.md +71 -0
  58. package/claude/references/sd-simplysm14/apis/service-server/internals.md +41 -0
  59. package/claude/references/sd-simplysm14/apis/service-server/server.md +66 -0
  60. package/claude/references/sd-simplysm14/apis/storage/README.md +69 -0
  61. package/claude/references/sd-simplysm14/{client-component.md → manuals/client-component.md} +133 -128
  62. package/claude/references/sd-simplysm14/manuals/client-crud.md +102 -0
  63. package/claude/references/sd-simplysm14/manuals/client-demo.md +128 -0
  64. package/claude/references/sd-simplysm14/manuals/client-rules.md +7 -0
  65. package/claude/references/sd-simplysm14/{client-setup.md → manuals/client-setup.md} +2 -2
  66. package/claude/references/sd-simplysm14/{client-tab.md → manuals/client-tab.md} +13 -11
  67. package/claude/references/sd-simplysm14/{orm-union.md → manuals/orm-union.md} +1 -1
  68. package/claude/references/sd-simplysm14/manuals/orm.md +75 -0
  69. package/claude/rules/sd-base-rules.md +172 -79
  70. package/claude/sd-check-bash.py +5 -0
  71. package/claude/sd-statusline.py +7 -12
  72. package/claude/skills/sd-commit/SKILL.md +7 -3
  73. package/claude/skills/sd-demo/SKILL.md +81 -62
  74. package/claude/skills/sd-demo/evals/fixtures/empty/.specs/260513120000_warehouse/spec.md +45 -0
  75. package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/.specs/260513120000_warehouse/spec.md +42 -0
  76. package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
  77. package/claude/skills/sd-demo/evals/fixtures/with-master-screen/.specs/260513120000_warehouse/spec.md +45 -0
  78. package/claude/skills/sd-demo/evals/fixtures/with-master-screen/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
  79. package/claude/skills/sd-demo/evals/fixtures/with-modal/.specs/260513120000_warehouse/spec.md +75 -0
  80. package/claude/skills/sd-demo/evals/fixtures/with-modal/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
  81. package/claude/skills/sd-demo/evals/fixtures/with-screens/.specs/260513120000_warehouse/spec.md +45 -0
  82. package/claude/skills/sd-demo/evals/fixtures/with-screens/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
  83. package/claude/skills/sd-demo/evals/golden.jsonl +5 -3
  84. package/claude/skills/sd-dev/SKILL.md +33 -63
  85. package/claude/skills/sd-dev/evals/fixtures/case-add/package.json +13 -0
  86. package/claude/skills/sd-dev/evals/fixtures/case-add/src/index.ts +10 -0
  87. package/claude/skills/sd-dev/evals/fixtures/case-add/tests/index.test.ts +11 -0
  88. package/claude/skills/sd-dev/evals/fixtures/case-add/tsconfig.json +12 -0
  89. package/claude/skills/sd-dev/evals/fixtures/case-bug/package.json +13 -0
  90. package/claude/skills/sd-dev/evals/fixtures/case-bug/src/index.ts +10 -0
  91. package/claude/skills/sd-dev/evals/fixtures/case-bug/tests/index.test.ts +11 -0
  92. package/claude/skills/sd-dev/evals/fixtures/case-bug/tsconfig.json +12 -0
  93. package/claude/skills/sd-dev/evals/fixtures/case-modify/package.json +13 -0
  94. package/claude/skills/sd-dev/evals/fixtures/case-modify/src/index.ts +10 -0
  95. package/claude/skills/sd-dev/evals/fixtures/case-modify/tests/index.test.ts +11 -0
  96. package/claude/skills/sd-dev/evals/fixtures/case-modify/tsconfig.json +12 -0
  97. package/claude/skills/sd-dev/evals/golden.jsonl +3 -3
  98. package/claude/skills/sd-docs/SKILL.md +53 -0
  99. package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +7 -0
  100. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +5 -0
  101. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +3 -0
  102. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +6 -0
  103. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +1 -0
  104. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +5 -0
  105. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +8 -0
  106. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +7 -0
  107. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +3 -0
  108. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +5 -0
  109. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +3 -0
  110. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +6 -0
  111. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +1 -0
  112. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +5 -0
  113. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +8 -0
  114. package/claude/skills/sd-docs/evals/golden.jsonl +2 -0
  115. package/claude/skills/sd-docs/references/subagent-prompt.md +100 -0
  116. package/claude/skills/sd-impl/SKILL.md +125 -46
  117. package/claude/skills/sd-impl/evals/fixtures/case-new/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +101 -0
  118. package/claude/skills/sd-impl/evals/fixtures/case-update/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +101 -0
  119. package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/250/353/215/270.txt +1 -0
  120. package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.txt +1 -0
  121. package/claude/skills/sd-impl/evals/golden.jsonl +2 -3
  122. package/claude/skills/sd-skill/SKILL.md +3 -3
  123. package/claude/skills/sd-skill/evals/golden.jsonl +0 -1
  124. package/claude/skills/sd-skill/references/eval-authoring.md +15 -0
  125. package/claude/skills/sd-skill/references/eval-run.md +1 -1
  126. package/claude/skills/sd-skill/references/skill-authoring.md +8 -5
  127. package/claude/skills/sd-skill/scripts/run_eval.py +39 -60
  128. package/claude/skills/sd-spec/SKILL.md +163 -105
  129. package/claude/skills/sd-spec/references/example-spec.md +585 -0
  130. package/claude/skills/sd-spec/references/spec-authoring.md +287 -0
  131. package/claude/skills/sd-spec/references/spec-md-template.md +15 -93
  132. package/claude/skills/sd-unpack/SKILL.md +7 -1
  133. package/claude/skills/sd-unpack/scripts/handlers/_common.py +10 -0
  134. package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +5 -13
  135. package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +3 -12
  136. package/claude/skills/sd-unpack/scripts/handlers/office_com.py +23 -37
  137. package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +1 -4
  138. package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +4 -13
  139. package/claude/skills/sd-unpack/scripts/unpack.py +4 -4
  140. package/claude/skills/sd-use/SKILL.md +1 -0
  141. package/claude/skills/sd-wip/SKILL.md +38 -0
  142. package/claude/skills/sd-wip/evals/fixtures/with-artifact/projects/acct/_wip.md +3 -0
  143. package/claude/skills/sd-wip/evals/fixtures/with-artifact/projects/acct/spec.md +15 -0
  144. package/claude/skills/sd-wip/evals/fixtures/with-existing-wip/.wips/260101120000_acct.md +6 -0
  145. package/claude/skills/sd-wip/evals/fixtures/with-existing-wip-for-compact/.wips/260101120000_acct.md +14 -0
  146. package/claude/skills/sd-wip/evals/golden.jsonl +4 -0
  147. package/claude/skills/sd-wip/references/compact.md +79 -0
  148. package/package.json +1 -1
  149. package/claude/references/sd-simplysm14/orm.md +0 -11
  150. package/claude/skills/sd-demo/evals/fixtures/basic-single-req/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -27
  151. package/claude/skills/sd-demo/evals/fixtures/basic-single-req/.specs/260503143025/overview.md +0 -12
  152. package/claude/skills/sd-demo/evals/fixtures/basic-single-req/src/components/Button.tsx +0 -12
  153. package/claude/skills/sd-demo/evals/fixtures/basic-single-req/src/components/Input.tsx +0 -27
  154. package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/355/231/224/353/251/264/spec.md +0 -25
  155. package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/.specs/260503143025/overview.md +0 -12
  156. package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/src/components/Input.tsx +0 -25
  157. package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/src/pages/.gitkeep +0 -0
  158. package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/REQ-001-RTP/354/236/205/353/240/245/355/231/224/353/251/264/spec.md +0 -19
  159. package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/REQ-002-RTP/354/266/234/353/240/245/355/231/224/353/251/264/spec.md +0 -20
  160. package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/overview.md +0 -16
  161. package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/components/Button.tsx +0 -6
  162. package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/components/Input.tsx +0 -15
  163. package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/pages/.gitkeep +0 -0
  164. package/claude/skills/sd-demo/references/demo-md-template.md +0 -92
  165. package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260301_/352/263/240/352/260/235/354/202/254_/354/236/205/352/263/240/354/232/224/354/262/255.eml +0 -5
  166. package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260305_/352/263/240/352/260/235/354/202/254_/354/266/234/352/263/240/354/232/224/354/262/255.eml +0 -6
  167. package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260310_/352/263/240/352/260/235/354/202/254_/352/266/214/355/225/234.eml +0 -6
  168. package/claude/skills/sd-dev/evals/fixtures/single-req-auto-chain/src/lib/.gitkeep +0 -0
  169. package/claude/skills/sd-dev/evals/fixtures/start-from-plan/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
  170. package/claude/skills/sd-dev/evals/fixtures/start-from-plan/src/lib/.gitkeep +0 -0
  171. package/claude/skills/sd-impl/evals/fixtures/basic-single-r/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/plan.md +0 -28
  172. package/claude/skills/sd-impl/evals/fixtures/basic-single-r/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -14
  173. package/claude/skills/sd-impl/evals/fixtures/basic-single-r/src/components/Input.tsx +0 -6
  174. package/claude/skills/sd-impl/evals/fixtures/basic-single-r/src/pages/.gitkeep +0 -0
  175. package/claude/skills/sd-impl/evals/fixtures/multi-r/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/plan.md +0 -40
  176. package/claude/skills/sd-impl/evals/fixtures/multi-r/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/spec.md +0 -13
  177. package/claude/skills/sd-impl/evals/fixtures/multi-r/src/components/Input.tsx +0 -25
  178. package/claude/skills/sd-impl/evals/fixtures/multi-r/src/pages/.gitkeep +0 -0
  179. package/claude/skills/sd-impl/evals/fixtures/with-test-file/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/plan.md +0 -26
  180. package/claude/skills/sd-impl/evals/fixtures/with-test-file/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
  181. package/claude/skills/sd-impl/evals/fixtures/with-test-file/src/lib/.gitkeep +0 -0
  182. package/claude/skills/sd-impl/references/impl-md-template.md +0 -87
  183. package/claude/skills/sd-impl/references/modes-and-failure.md +0 -65
  184. package/claude/skills/sd-plan/SKILL.md +0 -130
  185. package/claude/skills/sd-plan/evals/fixtures/already-implemented/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/spec.md +0 -14
  186. package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/api/user.ts +0 -13
  187. package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/components/Input.tsx +0 -15
  188. package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/pages/UserList.tsx +0 -29
  189. package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -17
  190. package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/src/components/Input.tsx +0 -6
  191. package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/src/pages/.gitkeep +0 -0
  192. package/claude/skills/sd-plan/evals/fixtures/demo-built/.specs/260503143025/DEMO-001-/352/261/260/353/236/230/354/262/230/demo.md +0 -26
  193. package/claude/skills/sd-plan/evals/fixtures/demo-built/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/355/231/224/353/251/264/spec.md +0 -15
  194. package/claude/skills/sd-plan/evals/fixtures/demo-built/src/components/Input.tsx +0 -25
  195. package/claude/skills/sd-plan/evals/fixtures/demo-built/src/data/mock-customer.ts +0 -16
  196. package/claude/skills/sd-plan/evals/fixtures/demo-built/src/pages/CustomerList.tsx +0 -25
  197. package/claude/skills/sd-plan/evals/golden.jsonl +0 -3
  198. package/claude/skills/sd-plan/references/plan-md-template.md +0 -138
  199. package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260122_/352/263/240/352/260/235/354/202/254_/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/260/234/354/204/240/354/232/224/354/262/255.eml +0 -20
  200. package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260205_/352/263/240/352/260/235/354/202/254_/354/266/234/352/263/240/355/231/224/353/251/264/352/264/200/353/240/250.eml +0 -17
  201. package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260301_/352/263/240/352/260/235/354/202/254_/352/266/214/355/225/234/354/262/264/352/263/204.eml +0 -18
  202. package/claude/skills/sd-spec/evals/fixtures/conflict-detection/.docs/20260317_/352/263/240/352/260/235/354/202/254_/352/270/264/352/270/211/354/262/230/353/246/254/353/260/251/354/271/250.eml +0 -17
  203. package/claude/skills/sd-spec/evals/fixtures/conflict-detection/.docs//355/232/214/354/235/230/353/214/200/353/263/270_20260320.txt +0 -13
  204. package/claude/skills/sd-spec/evals/fixtures/direct-simple/.gitkeep +0 -0
  205. package/claude/skills/sd-spec/evals/fixtures/spec-md-input/.specs/260101120000/REQ-001-test/spec.md +0 -19
  206. package/claude/skills/sd-spec/evals/fixtures/spec-md-input/.specs/260101120000/overview.md +0 -18
  207. package/claude/skills/sd-spec/evals/golden.jsonl +0 -4
  208. package/claude/skills/sd-spec/references/overview-md-template.md +0 -89
  209. package/claude/skills/sd-spec/references/raw-input-handling.md +0 -96
  210. package/claude/skills/sd-verify/SKILL.md +0 -96
  211. package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/impl.md +0 -20
  212. package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/plan.md +0 -14
  213. package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
  214. package/claude/skills/sd-verify/evals/fixtures/all-satisfied/src/lib/discount.test.ts +0 -11
  215. package/claude/skills/sd-verify/evals/fixtures/all-satisfied/src/lib/discount.ts +0 -7
  216. package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/impl.md +0 -21
  217. package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/plan.md +0 -21
  218. package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/spec.md +0 -12
  219. package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/src/pages/UserList.tsx +0 -19
  220. package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/impl.md +0 -19
  221. package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/plan.md +0 -14
  222. package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/spec.md +0 -12
  223. package/claude/skills/sd-verify/evals/fixtures/tdd-only/src/lib/validate-amount.test.ts +0 -10
  224. package/claude/skills/sd-verify/evals/fixtures/tdd-only/src/lib/validate-amount.ts +0 -7
  225. package/claude/skills/sd-verify/evals/golden.jsonl +0 -3
  226. package/claude/skills/sd-verify/references/verify-md-template.md +0 -99
  227. /package/claude/skills/{sd-demo/evals/fixtures/basic-single-req/src/pages → sd-wip/evals/fixtures/empty}/.gitkeep +0 -0
@@ -0,0 +1,155 @@
1
+ # @simplysm/sd-cli — sd-config
2
+
3
+ `sd.config.ts` 작성용 타입 모음. 진실 근거: `packages/sd-cli/src/sd-config.types.ts`.
4
+
5
+ ## 진입 타입
6
+
7
+ ```typescript
8
+ import type { SdConfig, SdConfigFn, SdConfigParams } from "@simplysm/sd-cli";
9
+
10
+ const config: SdConfigFn = (params) => ({
11
+ packages: {
12
+ "core-common": { target: "neutral" },
13
+ "core-node": { target: "node" },
14
+ },
15
+ });
16
+ export default config;
17
+ ```
18
+
19
+ - `SdConfigFn = (params: SdConfigParams) => SdConfig | Promise<SdConfig>`
20
+ - `SdConfigParams = { cwd: string; dev: boolean; opt: string[] }` — `opt` 는 CLI `-o` 플래그.
21
+ - `SdConfig = { packages: Record<string, SdPackageConfig | undefined>; replaceDeps?: Record<string, string>; postPublish?: SdPostPublishScriptConfig[] }`
22
+ - `packages` 키 = `packages/` 하위 디렉토리명.
23
+ - `replaceDeps`: node_modules 의 패키지를 로컬 소스로 심링크 교체. 예: `{ "@simplysm/*": "../simplysm/packages/*" }` (key 의 `*` 가 value 의 `*` 로 치환).
24
+
25
+ ## 패키지 설정
26
+
27
+ `SdPackageConfig = SdBuildPackageConfig | SdClientPackageConfig | SdServerPackageConfig | SdScriptsPackageConfig`.
28
+
29
+ ### SdBuildPackageConfig (라이브러리: node/browser/neutral)
30
+
31
+ ```typescript
32
+ {
33
+ target: "node" | "browser" | "neutral"; // BuildTarget
34
+ publish?: SdPublishConfig;
35
+ copySrc?: string[]; // src/ 기준 glob → dist/ 로 복사
36
+ watch?: SdWatchHookConfig; // watch 모드 훅
37
+ }
38
+ ```
39
+
40
+ ### SdClientPackageConfig (Frontend 앱)
41
+
42
+ ```typescript
43
+ {
44
+ target: "client";
45
+ server: string | number; // 연결 서버 패키지명, 또는 포트
46
+ env?: Record<string, string>; // esbuild define 으로 process.env 치환
47
+ publish?: SdPublishConfig;
48
+ capacitor?: SdCapacitorConfig;
49
+ electron?: SdElectronConfig;
50
+ configs?: Record<string, unknown>; // 런타임 설정 → dist/.config.json
51
+ exclude?: string[]; // Capacitor/Electron package.json 에 추가
52
+ browserSupport?: SdBrowserSupportConfig;
53
+ pwa?: false | SdPwaConfig; // 미지정 시 기본값으로 활성
54
+ }
55
+ ```
56
+
57
+ ### SdServerPackageConfig (Fastify 서버)
58
+
59
+ ```typescript
60
+ {
61
+ target: "server";
62
+ env?: Record<string, string>; // esbuild banner 로 process.env.KEY 상수 치환
63
+ publish?: SdPublishConfig;
64
+ configs?: Record<string, unknown>; // 런타임 설정 → dist/.config.json
65
+ externals?: string[]; // esbuild external (binding.gyp 자동 감지에 추가)
66
+ pm2?: { name?: string; ignoreWatchPaths?: string[] }; // 지정 시 dist/pm2.config.cjs 생성
67
+ packageManager?: "volta" | "mise"; // mise.toml / volta 설정 생성에 영향
68
+ }
69
+ ```
70
+
71
+ ### SdScriptsPackageConfig (유틸·임의 명령 실행)
72
+
73
+ ```typescript
74
+ {
75
+ target: "scripts";
76
+ publish?: SdPublishConfig;
77
+ watch?: SdWatchHookConfig; // 미지정이면 watch/typecheck 에서 제외
78
+ }
79
+ ```
80
+
81
+ `SdWatchHookConfig`: `{ target: string[]; cmd: string; args?: string[] }`. `target` 은 패키지 디렉토리 기준 glob. 매칭 변경 시 `cmd args` 실행.
82
+
83
+ ## 배포 설정
84
+
85
+ `SdPublishConfig`:
86
+ - `{ type: "npm" }` — npm 레지스트리.
87
+ - `{ type: "local-directory"; path: string }` — 로컬 복사. `path` 에 `%VER%`, `%PROJECT%` 치환.
88
+ - `{ type: "ftp" | "ftps" | "sftp"; host; port?; path?; user?; password? }`.
89
+
90
+ `postPublish` 항목 `SdPostPublishScriptConfig`: `{ type: "script"; cmd: string; args: string[] }`. `args` 의 `%VER%`, `%PROJECT%` 치환.
91
+
92
+ ## 클라이언트 부속 옵션
93
+
94
+ ### SdCapacitorConfig
95
+
96
+ ```typescript
97
+ {
98
+ appId: string; // 예 "com.example.app"
99
+ appName: string;
100
+ plugins?: Record<string, Record<string, unknown> | true>;
101
+ icon?: string; // 패키지 기준 상대 경로
102
+ debug?: boolean;
103
+ platform?: { android?: SdCapacitorAndroidConfig };
104
+ }
105
+ ```
106
+
107
+ `SdCapacitorAndroidConfig`: `config`(AndroidManifest application 속성), `bundle`(true=AAB, false=APK), `intentFilters`, `sign: SdCapacitorSignConfig`, `sdkVersion`, `permissions: SdCapacitorPermission[]`.
108
+
109
+ - `SdCapacitorSignConfig`: `keystore, storePassword, alias, password, keystoreType?` (기본 `"jks"`).
110
+ - `SdCapacitorPermission`: `{ name; maxSdkVersion?; ignore? }`.
111
+ - `SdCapacitorIntentFilter`: `{ action?; category? }`.
112
+
113
+ ### SdElectronConfig
114
+
115
+ ```typescript
116
+ {
117
+ appId: string;
118
+ portable?: boolean; // true=포터블 exe, 미지정/false=NSIS 설치본
119
+ installerIcon?: string; // .ico, 패키지 기준 상대 경로
120
+ reinstallDependencies?: string[]; // 네이티브 모듈 등
121
+ postInstallScript?: string;
122
+ nsisOptions?: Record<string, unknown>;
123
+ env?: Record<string, string>; // electron-main.ts 의 process.env
124
+ }
125
+ ```
126
+
127
+ ### SdPwaConfig
128
+
129
+ ```typescript
130
+ {
131
+ manifest?: {
132
+ name?; short_name?;
133
+ display?: "standalone" | "fullscreen" | "minimal-ui" | "browser";
134
+ theme_color?; background_color?;
135
+ icons?: Array<{ src: string; sizes: string; type?: string }>;
136
+ };
137
+ }
138
+ ```
139
+
140
+ `pwa: false` 로 비활성. 미지정 시 기본값으로 활성.
141
+
142
+ ### SdBrowserSupportConfig
143
+
144
+ ```typescript
145
+ {
146
+ browserslist?: string | string[]; // 예 "last 2 Chrome versions"
147
+ postCss?: { plugins: [string, (object | string)?][] };
148
+ legacyModule?: boolean; // 코드 분할 비활성 + import.meta 치환
149
+ }
150
+ ```
151
+
152
+ ## 부수 타입
153
+
154
+ - `BuildTarget = "node" | "browser" | "neutral"` — `SdBuildPackageConfig.target`.
155
+ - `NpmConfig` — `package.json` 구조 헬퍼 (`name`, `version`, `dependencies`, `devDependencies`, `peerDependencies`, `volta?`).
@@ -0,0 +1,92 @@
1
+ # @simplysm/service-client
2
+
3
+ `@simplysm/service-server` 와 WebSocket 으로 통신하는 클라이언트. RPC 호출·이벤트 구독·파일 업/다운로드·원격 ORM 실행을 단일 `ServiceClient` 에서 제공한다 (Node/브라우저 공용).
4
+
5
+ ## 사용 트리거 인덱스
6
+ - **createServiceClient / ServiceConnectionOptions** — 클라이언트 인스턴스 생성·서버 접속/종료할 때.
7
+ - **getService / send / ServiceProxy** — 서버 서비스 메서드를 타입 안전 RPC 로 호출할 때.
8
+ - **auth** — 서버 인증 토큰을 등록하고 재연결 시 자동 재인증되게 할 때.
9
+ - **getEvent / addListener / removeListener / emitEvent** — 서버 사이드 이벤트 구독 또는 다른 클라이언트로 이벤트 발행할 때.
10
+ - **uploadFile / downloadFileBuffer** — 서버에 파일을 올리거나 정적 경로에서 바이트로 받을 때.
11
+ - **createOrmClientConnector / OrmConnectOptions** — 서버의 ORM 서비스를 통해 DbContext 트랜잭션을 원격 실행할 때.
12
+ - **ServiceClient 이벤트 (`state`, `request-progress`, `response-progress`, `server-progress`)** — 연결 상태와 전송/응답/서버 진행률을 구독할 때.
13
+
14
+ ## 연결/생성
15
+ ```ts
16
+ createServiceClient(name: string, options: ServiceConnectionOptions): ServiceClient
17
+ interface ServiceConnectionOptions { port: number; host: string; ssl?: boolean; maxReconnectCount?: number; }
18
+ client.connect(): Promise<void>
19
+ client.close(): Promise<void>
20
+ client.connected: boolean
21
+ client.hostUrl: string // `${ssl?https:http}://host:port`
22
+ ```
23
+ - WebSocket URL 은 `${ws|wss}://host:port/ws` 로 고정.
24
+ - `maxReconnectCount` 기본 10, `0` 이면 재연결 비활성.
25
+ - 5s ping / 30s 무응답 시 강제 재연결, 재연결 성공 시 인증 토큰과 이벤트 리스너가 자동 복구됨.
26
+
27
+ ## RPC 호출
28
+ ```ts
29
+ client.getService<TService>(serviceName): ServiceProxy<TService>
30
+ client.send(serviceName, methodName, params, progress?): Promise<unknown>
31
+ type ServiceProxy<T> = { [K in keyof T]: T[K] extends (...a:infer P)=>infer R ? (...a:P)=>Promise<Awaited<R>> : never }
32
+ interface ServiceProgress { request?(s); response?(s); server?(s); }
33
+ interface ServiceProgressState { uuid: string; totalSize: number; completedSize: number; }
34
+ ```
35
+ - `getService` 는 Proxy 라 임의 메서드명 호출 가능. 타입은 `TService` 로만 보장됨.
36
+ - 메시지 이름은 `"<serviceName>.<methodName>"` 으로 전송.
37
+ - 30KB 초과 또는 `Uint8Array`/큰 배열 페이로드는 Worker 에서 인코딩/디코딩.
38
+
39
+ ## 인증
40
+ ```ts
41
+ client.auth(token: string): Promise<void>
42
+ ```
43
+ - 서버에 `auth` 메시지를 보내고 토큰을 내부 저장. 재연결 시 자동으로 같은 토큰으로 재인증.
44
+ - `uploadFile` 은 인증 토큰이 없으면 에러를 던짐.
45
+
46
+ ## 이벤트 (서버 push)
47
+ ```ts
48
+ client.getEvent<TEventDef>(eventName): ClientEventProxy<TEventDef>
49
+ client.addListener<TEventDef>(eventName, info, cb): Promise<string> // key 반환
50
+ client.removeListener(key): Promise<void>
51
+ client.emitEvent<TEventDef>(eventName, infoSelector, data): Promise<void>
52
+ interface ClientEventProxy<T> { addListener(info, cb): Promise<string>; removeListener(key): Promise<void>; emit(infoSelector, data): Promise<void>; }
53
+ ```
54
+ - `addListener` 는 연결 상태에서만 가능. 로컬 맵에도 보관해 재연결 시 자동 재구독.
55
+ - `emitEvent` 는 서버에 `evt:gets` 로 후보를 받아 `infoSelector` 통과분에만 `evt:emit` 호출.
56
+ - 핸들러 내부 에러는 로깅만 되고 다른 핸들러 호출은 계속됨.
57
+
58
+ ## 파일 업/다운로드
59
+ ```ts
60
+ client.uploadFile(files: File[] | FileCollection | { name: string; data: BlobInput }[]): Promise<ServiceUploadResult[]>
61
+ client.downloadFileBuffer(relPath: string): Promise<Uint8Array>
62
+ type BlobInput = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | string
63
+ interface FileCollection { length; item(i); [i]; [Symbol.iterator]() } // 브라우저 FileList 호환
64
+ ```
65
+ - 업로드: `POST {hostUrl}/upload` (multipart). 헤더 `x-sd-client-name`, `Authorization: Bearer <token>`. 인증 필수.
66
+ - 다운로드: `GET {hostUrl}/{relPath}` 의 응답 본문을 `Uint8Array` 로 반환.
67
+ - 브라우저 전용 `File`/`FileList` 대신 `BlobInput`/`FileCollection` 으로 Node 환경도 지원.
68
+
69
+ ## ORM 클라이언트
70
+ ```ts
71
+ createOrmClientConnector(client: ServiceClient): OrmClientConnector
72
+ interface OrmConnectOptions<T extends DbContext> {
73
+ DbClass: new (executor, { database, schema? }) => T;
74
+ connOpt: DbConnOptions & { configName: string };
75
+ dbContextOpt?: { database: string; schema: string };
76
+ }
77
+ connector.connect(config, async db => ...) // 트랜잭션 래핑
78
+ connector.connectWithoutTransaction(config, async db => ...)
79
+ ```
80
+ - 서버의 `"Orm"` 서비스에 RPC 를 걸어 `getInfo` → `connect` → `executeDefs` 등을 실행.
81
+ - `dbContextOpt` 생략 시 서버가 알려준 `database`/`schema` 사용. 둘 다 비면 에러.
82
+ - 외래키 참조 위반 에러(`a parent row: a foreign key constraint` / `conflicted with the REFERENCE`)는 사용자 메시지로 변환되어 throw.
83
+
84
+ ## 상태/진행률 이벤트
85
+ ```ts
86
+ client.on("state", (s: "connected" | "closed" | "reconnecting") => ...)
87
+ client.on("request-progress", (s: ServiceProgressState) => ...) // 클라이언트 → 서버 전송 청크 진행
88
+ client.on("response-progress", (s: ServiceProgressState) => ...) // 서버 → 클라이언트 응답 청크 진행
89
+ client.on("server-progress", (s: ServiceProgressState) => ...) // 서버가 명시적으로 보내는 진행률
90
+ ```
91
+ - 단일 청크 메시지에는 progress 가 발행되지 않음(분할 메시지에서만).
92
+ - `send` 호출 시 전달한 `progress?: ServiceProgress` 콜백은 인스턴스 이벤트와 별도로 호출됨.
@@ -0,0 +1,29 @@
1
+ # @simplysm/service-common
2
+
3
+ 서버/클라이언트가 공유하는 서비스 프로토콜·메시지 타입·서비스 인터페이스·앱 구조 정의·이벤트 정의 유틸.
4
+
5
+ ## 사용 트리거 인덱스
6
+
7
+ - **`createServiceProtocol` / `ServiceProtocol` / `ServiceMessageDecodeResult` / `PROTOCOL_CONFIG`** — 서버/클라이언트 transport 의 바이너리 V2 프로토콜(헤더 28B + JSON, 3MB↑ 자동 청킹, 100MB 한계) 인/디코더 생성. 자세히: [protocol.md](./protocol.md)
8
+ - **메시지 타입 (`ServiceMessage` / `ServiceClientMessage` / `ServiceServerMessage` / `ServiceServerRawMessage` 및 9 종의 개별 메시지)** — 프로토콜 위에 실리는 메시지 식별·타입 가드·핸들러 분기. 자세히: [messages.md](./messages.md)
9
+ - **서비스 인터페이스 (`OrmService` / `AutoUpdateService` / `AppStructureService` / `DbConnOptions`)** — 서버 구현·클라이언트 호출 양쪽이 공유하는 빌트인 서비스의 시그니처. 자세히: [service-types.md](./service-types.md)
10
+ - **앱 구조 (`AppStructureItem` / `AppStructureGroupItem` / `AppStructureLeafItem` / `AppStructureSubPermission` / `FlatPermission` + `isUsableModules` / `isUsableModulesChain` / `getFlatPermissions`)** — 메뉴/권한 트리 정의와 모듈 기반 가용성 평가·평탄화. 자세히: [app-structure.md](./app-structure.md)
11
+ - **`defineEvent` / `ServiceEventDef`** — 서버 발신·클라이언트 구독에서 `info`/`data` 타입을 공유하기 위한 이벤트 정의.
12
+ - **`ServiceUploadResult`** — 파일 업로드 결과(저장 경로·원본명·바이트 크기).
13
+
14
+ ## defineEvent / ServiceEventDef
15
+
16
+ ```ts
17
+ function defineEvent<TInfo, TData>(eventName: string): ServiceEventDef<TInfo, TData>
18
+ interface ServiceEventDef<TInfo, TData> { eventName: string; readonly $info: TInfo; readonly $data: TData; }
19
+ ```
20
+
21
+ `$info`/`$data` 는 런타임 미사용, 타입 추출 전용 마커. 서버는 `defineEvent` 로 정의·export 하고, 클라이언트는 `import type` 으로 가져와 `addListener<typeof Evt>(...)` / `emitEvent<typeof Evt>(...)` 에 전달해 `info` 필터·`data` 페이로드를 정적으로 검증한다.
22
+
23
+ ## ServiceUploadResult
24
+
25
+ ```ts
26
+ interface ServiceUploadResult { path: string; filename: string; size: number; }
27
+ ```
28
+
29
+ 서버 업로드 핸들러가 클라이언트로 반환하는 결과. `path` 는 서버 내부 저장 경로다.
@@ -0,0 +1,63 @@
1
+ # @simplysm/service-common — app-structure
2
+
3
+ 메뉴/권한 트리 정의 타입과 모듈(라이선스/플랜 등) 기반 가용성 평가·평탄화 함수.
4
+
5
+ ## 타입
6
+
7
+ ```ts
8
+ type AppStructureItem<TModule = unknown> =
9
+ | AppStructureGroupItem<TModule>
10
+ | AppStructureLeafItem<TModule>;
11
+
12
+ interface AppStructureGroupItem<TModule> {
13
+ code: string; title: string;
14
+ modules?: TModule[]; requiredModules?: TModule[];
15
+ icon?: string;
16
+ children: AppStructureItem<TModule>[];
17
+ }
18
+
19
+ interface AppStructureLeafItem<TModule> {
20
+ code: string; title: string;
21
+ modules?: TModule[]; requiredModules?: TModule[];
22
+ perms?: ("use" | "edit")[];
23
+ subPerms?: AppStructureSubPermission<TModule>[];
24
+ icon?: string; url?: string;
25
+ isNotMenu?: boolean;
26
+ }
27
+
28
+ interface AppStructureSubPermission<TModule> {
29
+ code: string; title: string;
30
+ modules?: TModule[]; requiredModules?: TModule[];
31
+ perms: ("use" | "edit")[];
32
+ }
33
+
34
+ interface FlatPermission<TModule = unknown> {
35
+ titleChain: string[];
36
+ codeChain: string[]; // [...상위 code, perm] 또는 [...상위 code, subPerm.code, perm]
37
+ modulesChain: TModule[][];
38
+ }
39
+ ```
40
+
41
+ Group/Leaf 는 `children` 존재로 구분(`"children" in item`).
42
+
43
+ ## isUsableModules(modules, requiredModules, usableModules) → boolean
44
+
45
+ - `requiredModules` (AND): 모두 `usableModules` 에 포함되어야 함. 없거나 빈 배열이면 통과.
46
+ - `modules` (OR): 비었거나 그 중 하나라도 `usableModules` 에 있으면 통과.
47
+
48
+ ## isUsableModulesChain(modulesChain, requiredModulesChain, usableModules) → boolean
49
+
50
+ 체인 각 레벨에 대해 `modules` OR 와 `requiredModules` AND 모두 만족해야 통과. 트리 깊이별 누적 조건 평가용.
51
+
52
+ ## getFlatPermissions(items, usableModules) → FlatPermission[]
53
+
54
+ 트리를 BFS 로 순회하며 각 leaf 의 `perms` / `subPerms` 를 평탄화한다.
55
+
56
+ - 진행 중 노드 단위로 `isUsableModulesChain` 체크 — 실패 시 하위 폐기.
57
+ - `subPerms` 도 자체 `modules`/`requiredModules` 로 추가 필터.
58
+ - 결과 `codeChain` 마지막에 권한값(`"use"|"edit"`)이 붙는다.
59
+
60
+ ```ts
61
+ const perms = getFlatPermissions(items, ["BASIC", "PRO"]);
62
+ // [{ titleChain: ["주문","주문등록"], codeChain: ["order","register","use"], modulesChain: [["PRO"]] }, ...]
63
+ ```
@@ -0,0 +1,56 @@
1
+ # @simplysm/service-common — messages
2
+
3
+ `ServiceProtocol` 위에 실리는 메시지 식별자(`name`) 별 바디 스키마. 모든 인터페이스는 `name` discriminator 로 좁힌다.
4
+
5
+ ## 유니언
6
+
7
+ ```ts
8
+ type ServiceMessage =
9
+ | ServiceRequestMessage | ServiceAuthMessage
10
+ | ServiceProgressMessage | ServiceResponseMessage | ServiceErrorMessage
11
+ | ServiceAddEventListenerMessage | ServiceRemoveEventListenerMessage
12
+ | ServiceGetEventListenerInfosMessage
13
+ | ServiceEmitEventMessage | ServiceEventMessage;
14
+
15
+ type ServiceClientMessage = // 클라이언트 → 서버
16
+ | ServiceRequestMessage | ServiceAuthMessage
17
+ | ServiceAddEventListenerMessage | ServiceRemoveEventListenerMessage
18
+ | ServiceGetEventListenerInfosMessage | ServiceEmitEventMessage;
19
+
20
+ type ServiceServerMessage = // 서버 → 클라이언트 (디스패치 대상)
21
+ | ServiceResponseMessage | ServiceErrorMessage | ServiceEventMessage;
22
+
23
+ type ServiceServerRawMessage = // 서버 → 클라이언트 (progress 포함 전체)
24
+ | ServiceProgressMessage | ServiceServerMessage;
25
+ ```
26
+
27
+ ## 시스템
28
+
29
+ - `ServiceProgressMessage` — `name: "progress"`, `body: { totalSize, completedSize }`. 서버가 청크 수신 진행률 알림.
30
+ - `ServiceErrorMessage` — `name: "error"`, `body: { name, message, code, stack?, detail?, cause? }`. 처리 중 에러 알림.
31
+ - `ServiceAuthMessage` — `name: "auth"`, `body: string` (토큰). 클라이언트 인증.
32
+
33
+ ## 서비스 메서드
34
+
35
+ - `ServiceRequestMessage` — `` name: `${string}.${string}` `` (예: `"User.findOne"`), `body: unknown[]` (매개변수 배열).
36
+ - `ServiceResponseMessage` — `name: "response"`, `body?: unknown` (반환값).
37
+
38
+ ## 이벤트
39
+
40
+ - `ServiceAddEventListenerMessage` — `name: "evt:add"`, `body: { key, name, info }`. `key` 는 uuid (remove 키).
41
+ - `ServiceRemoveEventListenerMessage` — `name: "evt:remove"`, `body: { key }`.
42
+ - `ServiceGetEventListenerInfosMessage` — `name: "evt:gets"`, `body: { name }`. 동일 이벤트 구독자들의 `info` 목록 요청.
43
+ - `ServiceEmitEventMessage` — `name: "evt:emit"`, `body: { keys, data }`. 클라이언트 발생.
44
+ - `ServiceEventMessage` — `name: "evt:on"`, `body: { keys, data }`. 서버 알림.
45
+
46
+ ## 사용
47
+
48
+ ```ts
49
+ function dispatch(msg: ServiceServerMessage) {
50
+ switch (msg.name) {
51
+ case "response": return resolveCall(msg.body);
52
+ case "error": return rejectCall(msg.body);
53
+ case "evt:on": return notifyListeners(msg.body.keys, msg.body.data);
54
+ }
55
+ }
56
+ ```
@@ -0,0 +1,64 @@
1
+ # @simplysm/service-common — protocol
2
+
3
+ 서비스 transport(웹소켓 등) 위에 얹는 바이너리 메시지 프로토콜(V2). 메시지를 청크로 자르고/재조립하며, 청크 누적의 GC 까지 캡슐화한다.
4
+
5
+ ## PROTOCOL_CONFIG
6
+
7
+ ```ts
8
+ const PROTOCOL_CONFIG = {
9
+ MAX_TOTAL_SIZE: 100 * 1024 * 1024, // 100MB 한계 (인/디코딩 양쪽에서 검사)
10
+ SPLIT_MESSAGE_SIZE: 3 * 1024 * 1024, // 이 크기 초과 시 청크 분할
11
+ CHUNK_SIZE: 300 * 1024, // 청크 본문 크기
12
+ GC_INTERVAL: 10 * 1000, // 청크 누적기 GC 주기
13
+ EXPIRE_TIME: 60 * 1000, // 미완성 메시지 만료
14
+ } as const;
15
+ ```
16
+
17
+ `as const`. 임계값 조정 필요 시 이 상수를 참조한다.
18
+
19
+ ## ServiceProtocol
20
+
21
+ ```ts
22
+ interface ServiceProtocol {
23
+ encode(uuid: string, message: ServiceMessage): { chunks: Bytes[]; totalSize: number };
24
+ decode<T extends ServiceMessage>(bytes: Bytes): ServiceMessageDecodeResult<T>;
25
+ dispose(): void;
26
+ }
27
+ ```
28
+
29
+ - 청크 헤더 28B: UUID 16B + TotalSize 8B(uint64, 상위 4B 는 0) + Index 4B(uint32), Big Endian.
30
+ - 본문: `json.stringify([name, body?])` UTF-8.
31
+ - `dispose()` 는 내부 `LazyGcMap` 의 GC 타이머를 해제. 인스턴스 종료 시 반드시 호출.
32
+
33
+ ## ServiceMessageDecodeResult
34
+
35
+ ```ts
36
+ type ServiceMessageDecodeResult<T extends ServiceMessage> =
37
+ | { type: "complete"; uuid: string; message: T }
38
+ | { type: "progress"; uuid: string; totalSize: number; completedSize: number };
39
+ ```
40
+
41
+ - `complete`: 모든 청크 수신·재조립 완료. 메시지 디스패치 가능.
42
+ - `progress`: 청크 일부만 도착. 진행률 표시·`progress` 알림 송신에 사용.
43
+
44
+ ## createServiceProtocol()
45
+
46
+ `ServiceProtocol` 인스턴스를 생성한다. 서버·클라이언트 각자 1 개씩 보유하는 것이 일반적.
47
+
48
+ ```ts
49
+ const proto = createServiceProtocol();
50
+ const { chunks } = proto.encode(uuid, { name: "User.findOne", body: [{ id: 1 }] });
51
+ for (const c of chunks) socket.send(c);
52
+
53
+ const res = proto.decode<ServiceServerMessage>(receivedBytes);
54
+ if (res.type === "complete") handle(res.message);
55
+ ```
56
+
57
+ 예외:
58
+
59
+ - `MAX_TOTAL_SIZE` 초과: `ArgumentError("메시지 크기가 제한을 초과했습니다.")`.
60
+ - 헤더(<28B) 미달: `ArgumentError("버퍼 크기가 헤더 크기보다 작습니다.")`.
61
+ - 본문 JSON 파싱 실패: `ArgumentError("메시지 디코딩에 실패했습니다.", { uuid, cause })`.
62
+ - 무결성 위반(누적 크기 > totalSize): `ArgumentError("프로토콜 무결성 위반: ...")`.
63
+
64
+ 중복 청크는 인덱스가 이미 채워진 경우 무시(방어). 만료(`EXPIRE_TIME`) 시 누적 항목은 GC 가 폐기.
@@ -0,0 +1,43 @@
1
+ # @simplysm/service-common — service-types
2
+
3
+ 서버 구현·클라이언트 호출이 공유하는 빌트인 서비스 인터페이스. 서버는 인터페이스를 구현, 클라이언트는 동일 시그니처로 RPC 호출한다.
4
+
5
+ ## OrmService
6
+
7
+ ```ts
8
+ interface OrmService {
9
+ getInfo(opt: DbConnOptions & { configName: string }): Promise<{ dialect: Dialect; database?: string; schema?: string }>;
10
+ connect(opt: DbConnOptions & { configName: string }): Promise<number>; // connId
11
+ close(connId: number): Promise<void>;
12
+ beginTransaction(connId: number, isolationLevel?: IsolationLevel): Promise<void>;
13
+ commitTransaction(connId: number): Promise<void>;
14
+ rollbackTransaction(connId: number): Promise<void>;
15
+ executeParametrized(connId: number, query: string, params?: unknown[]): Promise<unknown[][]>;
16
+ executeDefs(connId: number, defs: QueryDef[], options?: (ResultMeta | undefined)[]): Promise<unknown[][]>;
17
+ bulkInsert(connId: number, tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]): Promise<void>;
18
+ }
19
+
20
+ type DbConnOptions = { configName?: string; config?: Record<string, unknown> };
21
+ ```
22
+
23
+ MySQL / MSSQL / PostgreSQL 공통 추상. `connId` 단위로 트랜잭션·세션 식별. `Dialect`·`IsolationLevel`·`QueryDef`·`ColumnMeta`·`ResultMeta` 는 `@simplysm/orm-common` 정의.
24
+
25
+ ## AutoUpdateService
26
+
27
+ ```ts
28
+ interface AutoUpdateService {
29
+ getLastVersion(platform: string): Promise<{ version: string; downloadPath: string } | undefined>;
30
+ }
31
+ ```
32
+
33
+ `platform` 예: `"win32" | "darwin" | "linux"`. 등록된 버전 없으면 `undefined`.
34
+
35
+ ## AppStructureService
36
+
37
+ ```ts
38
+ interface AppStructureService {
39
+ getItems(): Record<string, AppStructureItem[]>;
40
+ }
41
+ ```
42
+
43
+ 키는 클라이언트명, 값은 해당 클라이언트의 앱 구조 트리. `AppStructureItem` 은 [app-structure.md](./app-structure.md) 참조.
@@ -0,0 +1,20 @@
1
+ # @simplysm/service-server
2
+
3
+ Fastify 기반 서비스 서버. HTTP/WebSocket 양 전송 위에서 "서비스(`이름`+`메서드 맵`)" 단위로 RPC, JWT 인증, 정적 파일, 업로드, 이벤트 브로드캐스트, V1 레거시 호환을 제공한다.
4
+
5
+ ## 사용 트리거 인덱스
6
+
7
+ - **`ServiceServer` / `createServiceServer` / `ServiceServerOptions`** — 서버 인스턴스 생성·기동·종료·이벤트 브로드캐스트·JWT 발급. 자세히: [server.md](./server.md)
8
+ - **`defineService` / `auth` / `ServiceContext` / `ServiceMethods`** — 서비스 정의 및 메서드/팩토리 인증 래퍼, 컨텍스트 헬퍼. 자세히: [define-service.md](./define-service.md)
9
+ - **`AuthTokenPayload` / `signJwt` / `verifyJwt` / `decodeJwt`** — JWT 토큰 페이로드 타입 및 직접 서명/검증 유틸. 자세히: [auth.md](./auth.md)
10
+ - **빌트인 서비스 (`OrmService` / `AutoUpdateService` / `AppStructureService`)** — `services` 옵션에 그대로 등록해 ORM 프록시·자동 업데이트·앱 메뉴 트리 제공. 자세히: [builtin-services.md](./builtin-services.md)
11
+ - **전송/프로토콜/레거시 내부** (`handleHttpRequest`, `handleUpload`, `handleStaticFile`, `createWebSocketHandler`, `createServiceSocket`, `createServerProtocolWrapper`, `handleV1Connection` 등) — `ServiceServer.listen()` 이 자동 사용. 커스텀 Fastify 라우트 직조 시에만 직접 호출. 자세히: [internals.md](./internals.md)
12
+
13
+ ## `getConfig`
14
+
15
+ ```ts
16
+ import { getConfig } from "@simplysm/service-server";
17
+ const conf = await getConfig<{ orm: { default: DbConnConfig } }>(filePath);
18
+ ```
19
+
20
+ `<rootPath>/.config.json` 같은 JSON 설정 파일을 읽고 LazyGcMap 캐시 + `FsWatcher` 로 핫리로드한다. 보통은 `ctx.getConfig(section)` 으로 충분하며, 이 함수를 직접 호출할 일은 root/client 경로 외 설정 파일을 읽을 때만 있다.
@@ -0,0 +1,31 @@
1
+ # @simplysm/service-server — auth
2
+
3
+ JWT 페이로드 타입 및 서명/검증 유틸. 일반 시나리오에서는 `server.signAuthToken` / `server.verifyAuthToken` 이 동일 알고리즘으로 감싸므로 그쪽을 쓴다. 이 모듈을 직접 import 하는 경우는 토큰 발급/검증을 서버 인스턴스 없이 수행해야 할 때 (테스트, 별도 인증 서비스, 디코드 등).
4
+
5
+ ## `AuthTokenPayload<TAuthInfo>`
6
+
7
+ ```ts
8
+ interface AuthTokenPayload<TAuthInfo = unknown> extends jose.JWTPayload {
9
+ roles: string[]; // auth(["role"], fn) 검사 대상
10
+ data: TAuthInfo; // ctx.authInfo 로 노출
11
+ }
12
+ ```
13
+
14
+ ## `signJwt(jwtSecret, payload) → Promise<string>`
15
+
16
+ HS256, `iat` 자동, 만료 `12h` 고정. 토큰 수명을 바꿔야 하면 이 함수 대신 직접 `jose.SignJWT` 를 쓴다.
17
+
18
+ ## `verifyJwt<TAuthInfo>(jwtSecret, token) → Promise<AuthTokenPayload<TAuthInfo>>`
19
+
20
+ 검증 실패 시 `토큰이 만료되었습니다.` 또는 `유효하지 않은 토큰입니다.` 를 throw.
21
+
22
+ ## `decodeJwt<TAuthInfo>(token) → AuthTokenPayload<TAuthInfo>`
23
+
24
+ 서명 검증 없이 페이로드만 디코드. 클라이언트 측 만료 표시 등 비보안 용도에만.
25
+
26
+ ## 예제
27
+
28
+ ```ts
29
+ const token = await signJwt(secret, { roles: ["admin"], data: { userId: "U1" } });
30
+ const payload = await verifyJwt<{ userId: string }>(secret, token);
31
+ ```
@@ -0,0 +1,47 @@
1
+ # @simplysm/service-server — builtin-services
2
+
3
+ `ServiceServerOptions.services` 에 그대로 푸시해서 쓰는 사전 정의 서비스. 각각의 `*ServiceType` 은 클라이언트 측에서 `client.getService<*ServiceType>("<이름>")` 로 타입 공유한다.
4
+
5
+ ## `OrmService` / `OrmServiceType`
6
+
7
+ 이름 alias: `["Orm", "SdOrmService"]`. **WebSocket 전용** (HTTP 호출 시 throw — 트랜잭션을 소켓 라이프타임에 묶기 위함). `auth()` 로 감싸져 있어 로그인 필요.
8
+
9
+ 설정: `ctx.getConfig("orm")` 으로 `Record<string, DbConnConfig>` 를 읽고 `opt.configName` 으로 선택. 클라이언트가 `opt.config` 로 일부 필드 override 가능.
10
+
11
+ 메서드: `getInfo`, `connect → connId`, `close(connId)`, `beginTransaction(connId, isolation?)`, `commitTransaction`, `rollbackTransaction`, `executeParametrized(connId, sql, params?)`, `executeDefs(connId, defs, optionsMeta?)`, `bulkInsert(connId, table, colDefs, records)`. 소켓 close 시 그 소켓의 모든 연결을 자동 정리.
12
+
13
+ ## `AutoUpdateService` / `AutoUpdateServiceType`
14
+
15
+ 이름 alias: `["AutoUpdate", "SdAutoUpdateService"]`. 인증 없음.
16
+
17
+ `getLastVersion(platform)` — `<clientPath>/<platform>/updates/` 디렉토리에서 `android` 는 `.apk`, 그 외는 `.exe` 중 `semver.maxSatisfying("*")` 으로 최신을 골라 `{ version, downloadPath }` 반환. 없으면 `undefined`.
18
+
19
+ ## `AppStructureService(itemsMap) → ServiceDefinition` / `AppStructureServiceType`
20
+
21
+ 다른 두 서비스와 달리 **팩토리 호출 결과**를 등록한다. 이름 `"AppStructure"`, 인증 없음.
22
+
23
+ ```ts
24
+ import { AppStructureService } from "@simplysm/service-server";
25
+ import type { AppStructureItem } from "@simplysm/service-common";
26
+
27
+ const itemsMap: Record<string, AppStructureItem[]> = { admin: [...], shop: [...] };
28
+ services: [AppStructureService(itemsMap)];
29
+ ```
30
+
31
+ `getItems()` 한 메서드만 노출. 클라이언트 메뉴/라우트 트리 공급용.
32
+
33
+ ## 등록 예제
34
+
35
+ ```ts
36
+ import { createServiceServer, OrmService, AutoUpdateService, AppStructureService } from "@simplysm/service-server";
37
+
38
+ createServiceServer({
39
+ rootPath, port: 50080, auth: { jwtSecret },
40
+ services: [
41
+ OrmService,
42
+ AutoUpdateService,
43
+ AppStructureService(appItemsMap),
44
+ MyAppService,
45
+ ],
46
+ });
47
+ ```