@things-factory/headless-twin 10.0.18 โ†’ 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +10 -1
  2. package/dist-server/engine/canonical-ingest.js +110 -33
  3. package/dist-server/engine/canonical-ingest.js.map +1 -1
  4. package/dist-server/engine/event-time.d.ts +25 -0
  5. package/dist-server/engine/event-time.js +98 -0
  6. package/dist-server/engine/event-time.js.map +1 -0
  7. package/dist-server/engine/index.d.ts +2 -0
  8. package/dist-server/engine/index.js +23 -0
  9. package/dist-server/engine/index.js.map +1 -1
  10. package/dist-server/engine/ingest-dedupe.d.ts +18 -6
  11. package/dist-server/engine/ingest-dedupe.js +201 -15
  12. package/dist-server/engine/ingest-dedupe.js.map +1 -1
  13. package/dist-server/engine/ingest-health.d.ts +60 -1
  14. package/dist-server/engine/ingest-health.js +43 -8
  15. package/dist-server/engine/ingest-health.js.map +1 -1
  16. package/dist-server/engine/kpi-fold.d.ts +19 -0
  17. package/dist-server/engine/kpi-fold.js +4 -1
  18. package/dist-server/engine/kpi-fold.js.map +1 -1
  19. package/dist-server/engine/kpi-query.js +23 -3
  20. package/dist-server/engine/kpi-query.js.map +1 -1
  21. package/dist-server/engine/oee-accumulator.d.ts +35 -2
  22. package/dist-server/engine/oee-accumulator.js +56 -4
  23. package/dist-server/engine/oee-accumulator.js.map +1 -1
  24. package/dist-server/engine/twin-engine.d.ts +72 -3
  25. package/dist-server/engine/twin-engine.js +118 -5
  26. package/dist-server/engine/twin-engine.js.map +1 -1
  27. package/dist-server/index.js +21 -0
  28. package/dist-server/index.js.map +1 -1
  29. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.d.ts +5 -0
  30. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js +66 -0
  31. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +1 -0
  32. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.d.ts +5 -0
  33. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js +79 -0
  34. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +1 -0
  35. package/dist-server/migrations/index.js +5 -1
  36. package/dist-server/migrations/index.js.map +1 -1
  37. package/dist-server/routes.js +19 -16
  38. package/dist-server/routes.js.map +1 -1
  39. package/dist-server/service/actuation/actuation-advisor.d.ts +60 -0
  40. package/dist-server/service/actuation/actuation-advisor.js +53 -0
  41. package/dist-server/service/actuation/actuation-advisor.js.map +1 -0
  42. package/dist-server/service/actuation/actuation-outcome.d.ts +52 -0
  43. package/dist-server/service/actuation/actuation-outcome.js +34 -0
  44. package/dist-server/service/actuation/actuation-outcome.js.map +1 -0
  45. package/dist-server/service/actuation/actuation-rule-resolver.d.ts +19 -0
  46. package/dist-server/service/actuation/actuation-rule-resolver.js +161 -0
  47. package/dist-server/service/actuation/actuation-rule-resolver.js.map +1 -0
  48. package/dist-server/service/actuation/actuation-rule.d.ts +55 -0
  49. package/dist-server/service/actuation/actuation-rule.js +130 -0
  50. package/dist-server/service/actuation/actuation-rule.js.map +1 -0
  51. package/dist-server/service/actuation/approval-gateway.d.ts +20 -0
  52. package/dist-server/service/actuation/approval-gateway.js +14 -0
  53. package/dist-server/service/actuation/approval-gateway.js.map +1 -0
  54. package/dist-server/service/actuation/catch-up-effects.d.ts +16 -0
  55. package/dist-server/service/actuation/catch-up-effects.js +120 -0
  56. package/dist-server/service/actuation/catch-up-effects.js.map +1 -0
  57. package/dist-server/service/actuation/command-dispatcher.d.ts +230 -0
  58. package/dist-server/service/actuation/command-dispatcher.js +269 -0
  59. package/dist-server/service/actuation/command-dispatcher.js.map +1 -0
  60. package/dist-server/service/actuation/command-store.d.ts +11 -0
  61. package/dist-server/service/actuation/command-store.js +219 -0
  62. package/dist-server/service/actuation/command-store.js.map +1 -0
  63. package/dist-server/service/actuation/dispatch-after-approval.d.ts +11 -0
  64. package/dist-server/service/actuation/dispatch-after-approval.js +73 -0
  65. package/dist-server/service/actuation/dispatch-after-approval.js.map +1 -0
  66. package/dist-server/service/actuation/effect-match.d.ts +53 -0
  67. package/dist-server/service/actuation/effect-match.js +65 -0
  68. package/dist-server/service/actuation/effect-match.js.map +1 -0
  69. package/dist-server/service/actuation/index.d.ts +25 -0
  70. package/dist-server/service/actuation/index.js +30 -0
  71. package/dist-server/service/actuation/index.js.map +1 -0
  72. package/dist-server/service/actuation/retry-plan.d.ts +63 -0
  73. package/dist-server/service/actuation/retry-plan.js +99 -0
  74. package/dist-server/service/actuation/retry-plan.js.map +1 -0
  75. package/dist-server/service/actuation/rule-evaluate.d.ts +127 -0
  76. package/dist-server/service/actuation/rule-evaluate.js +205 -0
  77. package/dist-server/service/actuation/rule-evaluate.js.map +1 -0
  78. package/dist-server/service/actuation/rule-loop.d.ts +5 -0
  79. package/dist-server/service/actuation/rule-loop.js +156 -0
  80. package/dist-server/service/actuation/rule-loop.js.map +1 -0
  81. package/dist-server/service/actuation/rule-runner.d.ts +52 -0
  82. package/dist-server/service/actuation/rule-runner.js +135 -0
  83. package/dist-server/service/actuation/rule-runner.js.map +1 -0
  84. package/dist-server/service/actuation/rule-wiring.d.ts +24 -0
  85. package/dist-server/service/actuation/rule-wiring.js +80 -0
  86. package/dist-server/service/actuation/rule-wiring.js.map +1 -0
  87. package/dist-server/service/actuation/settle-effects.d.ts +21 -0
  88. package/dist-server/service/actuation/settle-effects.js +101 -0
  89. package/dist-server/service/actuation/settle-effects.js.map +1 -0
  90. package/dist-server/service/actuation/sweep-dispatch.d.ts +37 -0
  91. package/dist-server/service/actuation/sweep-dispatch.js +125 -0
  92. package/dist-server/service/actuation/sweep-dispatch.js.map +1 -0
  93. package/dist-server/service/actuation/twin-command-resolver.d.ts +120 -0
  94. package/dist-server/service/actuation/twin-command-resolver.js +406 -0
  95. package/dist-server/service/actuation/twin-command-resolver.js.map +1 -0
  96. package/dist-server/service/actuation/twin-command.d.ts +111 -0
  97. package/dist-server/service/actuation/twin-command.js +170 -0
  98. package/dist-server/service/actuation/twin-command.js.map +1 -0
  99. package/dist-server/service/actuation/twin-now.d.ts +41 -0
  100. package/dist-server/service/actuation/twin-now.js +65 -0
  101. package/dist-server/service/actuation/twin-now.js.map +1 -0
  102. package/dist-server/service/index.d.ts +5 -2
  103. package/dist-server/service/index.js +28 -17
  104. package/dist-server/service/index.js.map +1 -1
  105. package/dist-server/service/reference/actuation-routing.d.ts +60 -0
  106. package/dist-server/service/reference/actuation-routing.js +126 -0
  107. package/dist-server/service/reference/actuation-routing.js.map +1 -0
  108. package/dist-server/service/reference/actuation-target.d.ts +65 -0
  109. package/dist-server/service/reference/actuation-target.js +94 -0
  110. package/dist-server/service/reference/actuation-target.js.map +1 -0
  111. package/dist-server/service/reference/connection-portability-resolver.d.ts +29 -0
  112. package/dist-server/service/reference/connection-portability-resolver.js +181 -0
  113. package/dist-server/service/reference/connection-portability-resolver.js.map +1 -0
  114. package/dist-server/service/reference/connection-portability.d.ts +138 -0
  115. package/dist-server/service/reference/connection-portability.js +230 -0
  116. package/dist-server/service/reference/connection-portability.js.map +1 -0
  117. package/dist-server/service/reference/fill-cadence.d.ts +17 -0
  118. package/dist-server/service/reference/fill-cadence.js +31 -0
  119. package/dist-server/service/reference/fill-cadence.js.map +1 -0
  120. package/dist-server/service/reference/fill-dedupe.d.ts +16 -0
  121. package/dist-server/service/reference/fill-dedupe.js +63 -0
  122. package/dist-server/service/reference/fill-dedupe.js.map +1 -0
  123. package/dist-server/service/reference/fill-loop.d.ts +35 -0
  124. package/dist-server/service/reference/fill-loop.js +187 -0
  125. package/dist-server/service/reference/fill-loop.js.map +1 -0
  126. package/dist-server/service/reference/fill-span.d.ts +10 -0
  127. package/dist-server/service/reference/fill-span.js +37 -0
  128. package/dist-server/service/reference/fill-span.js.map +1 -0
  129. package/dist-server/service/reference/hook-contract.d.ts +149 -22
  130. package/dist-server/service/reference/hook-contract.js +236 -23
  131. package/dist-server/service/reference/hook-contract.js.map +1 -1
  132. package/dist-server/service/reference/hook-rejected.d.ts +25 -0
  133. package/dist-server/service/reference/hook-rejected.js +48 -0
  134. package/dist-server/service/reference/hook-rejected.js.map +1 -0
  135. package/dist-server/service/reference/hook-store.d.ts +3 -0
  136. package/dist-server/service/reference/hook-store.js +28 -0
  137. package/dist-server/service/reference/hook-store.js.map +1 -0
  138. package/dist-server/service/reference/index.d.ts +4 -1
  139. package/dist-server/service/reference/index.js +5 -1
  140. package/dist-server/service/reference/index.js.map +1 -1
  141. package/dist-server/service/reference/live-cadence.d.ts +68 -0
  142. package/dist-server/service/reference/live-cadence.js +44 -0
  143. package/dist-server/service/reference/live-cadence.js.map +1 -0
  144. package/dist-server/service/reference/live-feed-lease.d.ts +15 -0
  145. package/dist-server/service/reference/live-feed-lease.js +56 -0
  146. package/dist-server/service/reference/live-feed-lease.js.map +1 -0
  147. package/dist-server/service/reference/live-ingest.d.ts +21 -0
  148. package/dist-server/service/reference/live-ingest.js +66 -0
  149. package/dist-server/service/reference/live-ingest.js.map +1 -0
  150. package/dist-server/service/reference/reference-adapter.d.ts +355 -2
  151. package/dist-server/service/reference/reference-adapter.js +19 -1
  152. package/dist-server/service/reference/reference-adapter.js.map +1 -1
  153. package/dist-server/service/reference/reference-fill-run.d.ts +50 -0
  154. package/dist-server/service/reference/reference-fill-run.js +142 -0
  155. package/dist-server/service/reference/reference-fill-run.js.map +1 -0
  156. package/dist-server/service/reference/reference-fill.d.ts +90 -0
  157. package/dist-server/service/reference/reference-fill.js +141 -0
  158. package/dist-server/service/reference/reference-fill.js.map +1 -0
  159. package/dist-server/service/reference/reference-hook.d.ts +64 -6
  160. package/dist-server/service/reference/reference-hook.js +265 -27
  161. package/dist-server/service/reference/reference-hook.js.map +1 -1
  162. package/dist-server/service/reference/reference-link-groups.d.ts +10 -0
  163. package/dist-server/service/reference/reference-link-groups.js +15 -0
  164. package/dist-server/service/reference/reference-link-groups.js.map +1 -0
  165. package/dist-server/service/reference/reference-links.d.ts +14 -0
  166. package/dist-server/service/reference/reference-links.js +73 -0
  167. package/dist-server/service/reference/reference-links.js.map +1 -0
  168. package/dist-server/service/reference/reference-live.d.ts +1 -0
  169. package/dist-server/service/reference/reference-live.js +32 -6
  170. package/dist-server/service/reference/reference-live.js.map +1 -1
  171. package/dist-server/service/reference/reference-master.d.ts +56 -2
  172. package/dist-server/service/reference/reference-master.js +33 -3
  173. package/dist-server/service/reference/reference-master.js.map +1 -1
  174. package/dist-server/service/reference/reference-resolver.d.ts +27 -0
  175. package/dist-server/service/reference/reference-resolver.js +79 -1
  176. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  177. package/dist-server/service/twin-event/twin-event-keys.d.ts +31 -3
  178. package/dist-server/service/twin-event/twin-event-keys.js +36 -4
  179. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  180. package/dist-server/service/twin-event/twin-event.d.ts +1 -0
  181. package/dist-server/service/twin-event/twin-event.js +11 -2
  182. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  183. package/dist-server/service/twin-model/choose-recipe.d.ts +15 -0
  184. package/dist-server/service/twin-model/choose-recipe.js +33 -0
  185. package/dist-server/service/twin-model/choose-recipe.js.map +1 -0
  186. package/dist-server/service/twin-model/external-resolver.d.ts +76 -0
  187. package/dist-server/service/twin-model/external-resolver.js +109 -0
  188. package/dist-server/service/twin-model/external-resolver.js.map +1 -0
  189. package/dist-server/service/twin-model/project-structure.js +16 -3
  190. package/dist-server/service/twin-model/project-structure.js.map +1 -1
  191. package/dist-server/service/twin-model/twin-equipment.d.ts +17 -0
  192. package/dist-server/service/twin-model/twin-equipment.js +10 -0
  193. package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
  194. package/dist-server/service/twin-model/twin-lineage-query.js +75 -1
  195. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
  196. package/dist-server/service/twin-model/twin-model-item-query.js +94 -5
  197. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
  198. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
  199. package/dist-server/service/twin-space/twin-space.d.ts +29 -0
  200. package/dist-server/service/twin-space/twin-space.js +13 -0
  201. package/dist-server/service/twin-space/twin-space.js.map +1 -1
  202. package/dist-server/service/twin-subject/event-subjects.d.ts +3 -1
  203. package/dist-server/service/twin-subject/event-subjects.js +8 -1
  204. package/dist-server/service/twin-subject/event-subjects.js.map +1 -1
  205. package/dist-shared/entity-delta.js +1 -1
  206. package/dist-shared/entity-delta.js.map +1 -1
  207. package/package.json +7 -7
  208. package/server/engine/canonical-ingest.ts +119 -33
  209. package/server/engine/event-time.ts +96 -0
  210. package/server/engine/index.ts +20 -0
  211. package/server/engine/ingest-dedupe.ts +203 -27
  212. package/server/engine/ingest-health.ts +91 -6
  213. package/server/engine/kpi-fold.ts +24 -1
  214. package/server/engine/kpi-query.ts +23 -4
  215. package/server/engine/oee-accumulator.ts +80 -8
  216. package/server/engine/twin-engine.ts +119 -5
  217. package/server/index.ts +23 -0
  218. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +66 -0
  219. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +82 -0
  220. package/server/migrations/index.ts +5 -1
  221. package/server/routes.ts +19 -20
  222. package/server/service/actuation/actuation-advisor.ts +124 -0
  223. package/server/service/actuation/actuation-outcome.ts +97 -0
  224. package/server/service/actuation/actuation-rule-resolver.ts +147 -0
  225. package/server/service/actuation/actuation-rule.ts +139 -0
  226. package/server/service/actuation/approval-gateway.ts +44 -0
  227. package/server/service/actuation/catch-up-effects.ts +152 -0
  228. package/server/service/actuation/command-dispatcher.ts +511 -0
  229. package/server/service/actuation/command-store.ts +236 -0
  230. package/server/service/actuation/dispatch-after-approval.ts +71 -0
  231. package/server/service/actuation/effect-match.ts +124 -0
  232. package/server/service/actuation/index.ts +27 -0
  233. package/server/service/actuation/retry-plan.ts +145 -0
  234. package/server/service/actuation/rule-evaluate.ts +352 -0
  235. package/server/service/actuation/rule-loop.ts +160 -0
  236. package/server/service/actuation/rule-runner.ts +216 -0
  237. package/server/service/actuation/rule-wiring.ts +84 -0
  238. package/server/service/actuation/settle-effects.ts +115 -0
  239. package/server/service/actuation/sweep-dispatch.ts +179 -0
  240. package/server/service/actuation/twin-command-resolver.ts +387 -0
  241. package/server/service/actuation/twin-command.ts +232 -0
  242. package/server/service/actuation/twin-now.ts +97 -0
  243. package/server/service/index.ts +11 -0
  244. package/server/service/reference/actuation-routing.ts +165 -0
  245. package/server/service/reference/actuation-target.ts +163 -0
  246. package/server/service/reference/connection-portability-resolver.ts +171 -0
  247. package/server/service/reference/connection-portability.ts +285 -0
  248. package/server/service/reference/fill-cadence.ts +29 -0
  249. package/server/service/reference/fill-dedupe.ts +66 -0
  250. package/server/service/reference/fill-loop.ts +153 -0
  251. package/server/service/reference/fill-span.ts +31 -0
  252. package/server/service/reference/hook-contract.ts +280 -22
  253. package/server/service/reference/hook-rejected.ts +53 -0
  254. package/server/service/reference/hook-store.ts +28 -0
  255. package/server/service/reference/index.ts +5 -1
  256. package/server/service/reference/live-cadence.ts +129 -0
  257. package/server/service/reference/live-feed-lease.ts +56 -0
  258. package/server/service/reference/live-ingest.ts +94 -0
  259. package/server/service/reference/reference-adapter.ts +392 -5
  260. package/server/service/reference/reference-fill-run.ts +165 -0
  261. package/server/service/reference/reference-fill.ts +223 -0
  262. package/server/service/reference/reference-hook.ts +355 -32
  263. package/server/service/reference/reference-link-groups.ts +21 -0
  264. package/server/service/reference/reference-links.ts +77 -0
  265. package/server/service/reference/reference-live.ts +30 -5
  266. package/server/service/reference/reference-master.ts +90 -5
  267. package/server/service/reference/reference-resolver.ts +77 -2
  268. package/server/service/twin-event/twin-event-keys.ts +37 -4
  269. package/server/service/twin-event/twin-event.ts +18 -1
  270. package/server/service/twin-model/choose-recipe.ts +31 -0
  271. package/server/service/twin-model/external-resolver.ts +161 -0
  272. package/server/service/twin-model/project-structure.ts +16 -3
  273. package/server/service/twin-model/twin-equipment.ts +22 -0
  274. package/server/service/twin-model/twin-lineage-query.ts +82 -1
  275. package/server/service/twin-model/twin-model-item-query.ts +95 -4
  276. package/server/service/twin-model/twin-model-tree-query.ts +1 -1
  277. package/server/service/twin-space/twin-space.ts +39 -0
  278. package/server/service/twin-subject/event-subjects.ts +8 -1
  279. package/shared/entity-delta.ts +1 -1
  280. package/test/ack-shape-alignment.test.ts +97 -0
  281. package/test/actuation-approval-door.test.ts +421 -0
  282. package/test/actuation-dispatch.test.ts +209 -0
  283. package/test/actuation-effect.test.ts +162 -0
  284. package/test/actuation-outcome.test.ts +152 -0
  285. package/test/actuation-rule-runner.test.ts +281 -0
  286. package/test/actuation-rule.test.ts +266 -0
  287. package/test/actuation-seam.test.ts +249 -0
  288. package/test/actuation-settle.test.ts +164 -0
  289. package/test/actuation-target.test.ts +145 -0
  290. package/test/canonical-ingest-vocabularies.test.ts +49 -2
  291. package/test/capability-mapping.test.ts +1 -1
  292. package/test/choose-recipe.test.ts +117 -0
  293. package/test/command-store-writes-columns.test.ts +126 -0
  294. package/test/connection-portability-doors.test.ts +87 -0
  295. package/test/connector-capability-declaration.test.ts +54 -4
  296. package/test/declaration-reaches-model.test.ts +43 -0
  297. package/test/dedupe-transformation.test.ts +112 -0
  298. package/test/entity-delta.test.ts +1 -1
  299. package/test/event-subjects.test.ts +2 -1
  300. package/test/external-resolver.test.ts +171 -0
  301. package/test/fill-dedupe.test.ts +59 -0
  302. package/test/fill-loop.test.ts +35 -0
  303. package/test/first-envelope.test.ts +153 -0
  304. package/test/fold-shift-dst.test.ts +110 -0
  305. package/test/home-in-area.test.ts +90 -0
  306. package/test/hook-rejected-shape.test.ts +86 -0
  307. package/test/hook-response-sum.test.ts +193 -0
  308. package/test/hook-sequence.test.ts +333 -0
  309. package/test/ingest-dedupe.test.ts +56 -0
  310. package/test/ingest-expected-quiet.test.ts +111 -0
  311. package/test/ingest-idempotent.test.ts +79 -0
  312. package/test/ingest-reconcile-four-ways.test.ts +97 -0
  313. package/test/ingest-rules-header.test.ts +100 -0
  314. package/test/ingest-window-rolls-unobserved.test.ts +72 -0
  315. package/test/intake-mapping-parity.test.ts +175 -0
  316. package/test/live-cadence.test.ts +170 -0
  317. package/test/live-feed-lease.test.ts +63 -0
  318. package/test/live-mirror-parity.test.ts +1 -1
  319. package/test/oee-accumulator.test.ts +3 -3
  320. package/test/oee-site-calendar.test.ts +146 -0
  321. package/test/order-and-transaction-split.test.ts +107 -0
  322. package/test/reference-fill.test.ts +235 -0
  323. package/test/reference-hook.test.ts +114 -23
  324. package/test/reference-links.test.ts +56 -0
  325. package/test/retry-plan.test.ts +139 -0
  326. package/test/sweep-dispatch.test.ts +191 -0
  327. package/test/twin-event-keys.test.ts +20 -6
  328. package/test/twin-model-item-db.test.ts +6 -6
  329. package/test/twin-model-tree-db.test.ts +6 -6
  330. package/tsconfig.shared.tsbuildinfo +1 -1
  331. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"twin-event-keys.js","sourceRoot":"","sources":["../../../server/service/twin-event/twin-event-keys.ts"],"names":[],"mappings":"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","sourcesContent":["import { twinWarn } from '../../engine/log.js'\n/*\n * ์ €๋„ ๊ฒ€์ƒ‰ ํ‚ค ์ถ”์ถœ โ€” **์ˆœ์ˆ˜**. ์ธ์ œ์ŠคํŠธ๊ฐ€ ๊ธฐ๋กํ•  ๋•Œ ํ•œ ๋ฒˆ ๋ฝ‘์•„ ์ธ๋ฑ์Šค ๊ฐ€๋Šฅํ•œ ์‹ค์ปฌ๋Ÿผ์œผ๋กœ ์Šน๊ฒฉํ•œ๋‹ค.\n *\n * โ”€โ”€ ์™œ ์Šน๊ฒฉํ•˜๋Š”๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‚ฌ์šฉ์ž๊ฐ€ ์ €๋„์—์„œ ์‹ค์ œ๋กœ ์ฐพ๋Š” ๊ฒƒ์€ \"์ด ํŒ”๋ ˆํŠธ์˜ ์ด๋ ฅ\", \"์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜\", \"์ด ๋„ํฌ์—์„œ\n * ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜\" ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๊ฐ’๋“ค์€ ์ „๋ถ€ `payload`(simple-json = TEXT) **์•ˆ**์— ์žˆ์—ˆ๋‹ค.\n * things-factory ๋Š” 5๊ฐœ DB ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ด์„œ DB๋ณ„ JSON ์—ฐ์‚ฐ์ž๋ฅผ ์“ธ ์ˆ˜ ์—†๋‹ค โ€”\n * ์ฆ‰ ์Šน๊ฒฉ ์—†์ด๋Š” **์–ด๋–ค ๋ฐฉ๋ฒ•์œผ๋กœ๋„ ์„œ๋ฒ„์—์„œ ๊ทธ ์กฐ๊ฑด์œผ๋กœ ๊ฑฐ๋ฅผ ์ˆ˜ ์—†์—ˆ๋‹ค**. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›์•„์˜จ\n * ๋ช‡ ์ฒœ ๊ฑด ์•ˆ์—์„œ๋งŒ ์ฐพ๋Š” ์‹œ๋Љ์ด ์ตœ์„ ์ด์—ˆ๊ณ , ์ €๋„์ด ์ปค์งˆ์ˆ˜๋ก ๊ทธ ์‹œ๋Љ์€ ๊ฑฐ์ง“๋ง์— ๊ฐ€๊นŒ์›Œ์ง„๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ๊ฒ€์ƒ‰ ์ถ•์ด ๋˜๋Š” ๊ฐ’๋งŒ ๊ณจ๋ผ ์ปฌ๋Ÿผ์œผ๋กœ ๊บผ๋‚ธ๋‹ค. payload ๋Š” ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค(์ •๋ณธ์€ ์—ฌ์ „ํžˆ payload โ€”\n * ์ด๊ฑด ํŒŒ์ƒ ์ƒ‰์ธ์ด์ง€ ์ƒˆ๋กœ์šด ์ง„์‹ค์ด ์•„๋‹ˆ๋‹ค).\n *\n * โ”€โ”€ ์™œ ์—ฌ๊ธฐ(์ˆœ์ˆ˜ ๋ชจ๋“ˆ)์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ๋‘˜์ด๋‹ค(`persistBatch` ๋ผ์ด๋ธŒ ๋ฒŒํฌ ยท `persist` ์‹ฌ ๋‹จ๊ฑด). ๋‘ ๊ณณ์— ๊ฐ์ž ์ ์œผ๋ฉด\n * ๋ฐ˜๋“œ์‹œ ์–ด๊ธ‹๋‚˜๊ณ , ์–ด๊ธ‹๋‚œ ์ƒ‰์ธ์€ \"์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ์ด๋ฒคํŠธ\" ๋ฅผ ๋งŒ๋“ ๋‹ค โ€” ์ €๋„์—์„œ ๊ฐ€์žฅ ๋‚˜์œ ๊ฒฐํ•จ์ด๋‹ค.\n */\n\n/** ์Šน๊ฒฉ๋œ ๊ฒ€์ƒ‰ ํ‚ค โ€” ์ „๋ถ€ ์„ ํƒ์ . ๋ฝ‘ํžˆ์ง€ ์•Š์œผ๋ฉด **๋นˆ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ undefined**(๊ฒฐ์ธกโ‰ ๋นˆ๊ฐ’). */\nexport interface TwinEventKeys {\n action?: string\n bizStep?: string\n epc?: string\n orderId?: string\n locationId?: string\n moverId?: string\n}\n\n/*\n * ์ปฌ๋Ÿผ ๊ธธ์ด ์ƒํ•œ. GS1 ์‹๋ณ„์ž(EPC URNยทGDTIยทSGLN)๋Š” ๊ทœ๊ฒฉ์ƒ ์ด๋ณด๋‹ค ํ›จ์”ฌ ์งง๋‹ค.\n * ๋„˜์น˜๋Š” ๊ฐ’์ด ์˜ค๋ฉด **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ž๋ฅด์ง€ ์•Š๊ณ ** ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค โ€” ์ƒ‰์ธ์ด ์›๋ณธ๊ณผ ๋‹ค๋ฅด๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๊ฑฐ์ง“์ด ๋˜๋Š”๋ฐ,\n * ๊ทธ ์‚ฌ์‹ค์ด ์–ด๋””์—๋„ ์•ˆ ๋‚จ์œผ๋ฉด ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.\n */\nconst MAX_KEY = 255\n\nfunction clip(v: unknown, field: string): string | undefined {\n if (v === undefined || v === null) return undefined\n const s = String(v)\n if (!s) return undefined\n if (s.length <= MAX_KEY) return s\n twinWarn(\n `[twin-event-keys] ${field} exceeds ${MAX_KEY} chars and was clipped for indexing โ€” ` +\n `search on this value may be incomplete. payload keeps the full value. (${s.slice(0, 60)}โ€ฆ)`\n )\n return s.slice(0, MAX_KEY)\n}\n\n/** CBV bizStep URN ์˜ ๋๋งˆ๋””. ์—†์œผ๋ฉด ์ด๋ฒคํŠธ ํƒ€์ž…์—์„œ ์œ ์ถ”(`epcis.` ์ ‘๋‘ ์ œ๊ฑฐ). */\nexport function bizStepOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n const tail = String(d.bizStep ?? '').split(':').pop()\n return tail || String(envelope?.eventType ?? '').replace('epcis.', '') || undefined\n}\n\n/**\n * ํ’ˆ๋ชฉ ์‹๋ณ„์ž โ€” **์ „์ฒด ๊ฐ’**์„ ์ €์žฅํ•œ๋‹ค(๋๋งˆ๋””๋งŒ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค).\n *\n * ํ‘œ์‹œ์šฉ ์ถ•์•ฝ์€ ํ™”๋ฉด์ด ํ•˜๊ณ , ์ƒ‰์ธ์€ ์›๋ณธ์„ ๊ฐ–๋Š”๋‹ค. `search` ๋Š” ๋ถ€๋ถ„์ผ์น˜(contains)๋ผ\n * ์ „์ฒด๋ฅผ ์ €์žฅํ•ด ๋‘๋ฉด ๋๋งˆ๋””(\"402.2\")๋กœ๋„ URN ์ „์ฒด๋กœ๋„ ์ฐพํžŒ๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋๋งˆ๋””๋งŒ ์ €์žฅํ•˜๋ฉด\n * URN ์œผ๋กœ ์ฐพ๋Š” ๊ฒฝ๋กœ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.\n */\nexport function epcOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.epcList?.[0] ?? d.parentID ?? d.quantityList?.[0]?.epcClass ?? undefined\n}\n\n/**\n * ์˜ค๋” ์‹๋ณ„์ž โ€” ์šด์˜ ๋ธํƒ€์˜ `orderId` ์šฐ์„ , EPCIS ๋Š” `bizTransactionList`.\n *\n * โ”€โ”€ ์‹ค์ธก (2026-08-24) โ€” ์ด ์ปฌ๋Ÿผ์ด **์ „๋ถ€ ๋น„์–ด ์žˆ์—ˆ๋‹ค** โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์—ฌ๊ธฐ๊ฐ€ ์ฐพ๋˜ ์ด๋ฆ„์ด `d.order` ์˜€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ปค๋„์ด ๋‚ด๋Š” ์ด๋ฆ„์€ **`orderId`** ๋‹ค\n * (`OrderStatusDelta.orderId` ยท `TaskStatusDelta.orderId`). `d.order` ๋ฅผ ๋‚ด๋Š” ์ฝ”๋“œ๋Š” ์ปค๋„์— **ํ•œ ๊ณณ๋„\n * ์—†๋‹ค** โ€” ์ฃฝ์€ ๊ฐ€์ง€์˜€๋‹ค. ๊ทธ๋ž˜์„œ ์šด์˜ ๋ธํƒ€๋Š” ์ด ์ปฌ๋Ÿผ์„ ํ•œ ๋ฒˆ๋„ ์ฑ„์šฐ์ง€ ๋ชปํ–ˆ๋‹ค.\n *\n * order.status 29,403,565 ํ–‰ โ€” order_id ๋น„์–ด ์žˆ์Œ 29,403,565 (100%)\n * task.status 191,175 ํ–‰ โ€” ๋น„์–ด ์žˆ์Œ 191,175 (100%)\n *\n * ๊ทธ ๊ฒฐ๊ณผ ์ƒ‰์ธ `ix_twin_event_4` ๊ฐ€ **์ž๊ธฐ ์ฃผ์„์ด ์ ์–ด ๋‘” ์šฉ๋„**(ใ€Œ์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜ใ€)๋กœ ์“ธ ์ˆ˜\n * ์—†์—ˆ๋‹ค. ํ™”๋ฉด์€ ์˜ค๋”๋ฅผ ๋ˆŒ๋Ÿฌ๋„ ใ€Œ์—ฐ๊ฒฐ๋œ ์ด๋ฒคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹คใ€๋ฅผ ๋ƒˆ๊ณ , ๊ทธ ๋‹ต์€ ์งˆ์˜ ๊ฒฐ๊ณผ๋กœ๋Š” ์ •์งํ–ˆ๋‹ค โ€”\n * ์‹œ์ ์„ ์–ด๋””๋กœ ์˜ฎ๊ฒจ๋„ 0 ์ด์—ˆ๋‹ค.\n *\n * ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค: ์šด์˜ ๋ธํƒ€๊ฐ€ ๋จผ์ €๋‹ค. EPCIS ์˜ `bizTransactionList` ๋Š” **๊ฑฐ๋ž˜**(PO/SO)์ด๊ณ  ์˜ค๋”์™€\n * ๊ฐ™์€ ๊ฒƒ์ด ์•„๋‹ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์˜ค๋”๋ฅผ ์Šค์Šค๋กœ ๋งํ•˜๋Š” ์‚ฌ๊ฑด์€ ๊ทธ ๋ง์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค.\n *\n * **๊ณผ๊ฑฐ ํ–‰์€ ์ฑ„์›Œ์ง€์ง€ ์•Š๋Š”๋‹ค**(์‚ฌ์šฉ์ž ๊ฒฐ์ • 2026-08-24, `moverId` ๋•Œ์™€ ๊ฐ™์€ ๋ฐฉ์‹). ์•ž์œผ๋กœ ๋“ค์–ด์˜ค๋Š”\n * ์‚ฌ๊ฑด๋ถ€ํ„ฐ ์กฐํšŒ๋œ๋‹ค.\n */\nexport function orderOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.orderId ?? d.bizTransactionList?.[0]?.bizTransaction ?? undefined\n}\n\n/**\n * ์œ„์น˜ โ€” EPCIS ๋Š” ์ฝ์€ ์ง€์ (readPoint) ์šฐ์„ , ์—†์œผ๋ฉด ์—…๋ฌด ์œ„์น˜(bizLocation).\n * ์šด์˜ ๋ธํƒ€(๋ฌด๋ฒ„ ์ด๋™ ๋“ฑ)๋Š” ๊ทธ ๋‘˜์ด ์—†๊ณ  ํ‰๋ฒ”ํ•œ `location` ์„ ์“ด๋‹ค โ€” ๋น ๋œจ๋ฆฌ๋ฉด ์„ค๋น„๊ฐ€ ์–ด๋””์„œ\n * ๋ฌด์—‡์„ ํ–ˆ๋Š”์ง€๊ฐ€ ์œ„์น˜ ์ถ•์—์„œ ํ†ต์งธ๋กœ ์‚ฌ๋ผ์ง„๋‹ค.\n */\nexport function locationOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.readPoint?.id ?? d.bizLocation?.id ?? d.location ?? undefined\n}\n\n/**\n * ์„ค๋น„ยท๋ฌด๋ฒ„ โ€” ์šด์˜ ๋ธํƒ€(equipment.statusยทtask.status)๊ฐ€ ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ถ•.\n *\n * EPCIS ์–ดํœ˜๊ฐ€ ์•„๋‹ˆ๋ผ์„œ ๋‹ค๋ฅธ ์ถ• ์–ด๋””์—๋„ ์•ˆ ์žกํžŒ๋‹ค. ์ด๊ฒŒ ์—†์œผ๋ฉด \"์ด ์ง€๊ฒŒ์ฐจ๊ฐ€ ์˜ค๋Š˜ ๋ฌด์—‡์„ ํ–ˆ๋‚˜\" ๋ฅผ\n * ์„œ๋ฒ„์—์„œ ๋ฌผ์„ ๋ฐฉ๋ฒ•์ด ์—†์–ด, ํ™”๋ฉด์ด ์ €๋„์„ ํ†ต์งธ๋กœ ๋ฐ›์•„ ์ „์ˆ˜ ์กฐํšŒํ•˜๋Š” ์ˆ˜๋ฐ–์— ์—†๋‹ค.\n */\nexport function equipmentIdOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n /*\n * โ”€โ”€ ์‹ค์ธก (2026-08-24) โ€” ๋‘ ๊ฐˆ๋ž˜๋ฅผ ๋†“์น˜๊ณ  ์žˆ์—ˆ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์œ„ ์ฃผ์„์ด `task.status` ๋ฅผ ์ถœ์ฒ˜๋กœ **์ ์–ด ๋‘์—ˆ๋Š”๋ฐ** ์ด ํ•จ์ˆ˜๋Š” `d.moverId` ๋งŒ ๋ดค๋‹ค. ์ž‘์—…์ด ์ž์›์„\n * ๊ฐ€๋ฆฌํ‚ค๋Š” ์ด๋ฆ„์€ `resourceRef` ๋‹ค(`TaskStatusDelta.resourceRef`) โ€” ๊ทธ๋ž˜์„œ ์ž‘์—… 191,175 ํ–‰ ์ „๋ถ€\n * ์ด ์ปฌ๋Ÿผ์ด ๋น„์—ˆ๊ณ , ใ€Œ์ด ์ง€๊ฒŒ์ฐจ๊ฐ€ ์˜ค๋Š˜ ๋ฌด์—‡์„ ํ–ˆ๋‚˜ใ€์—์„œ **์ž‘์—…์ด ํ†ต์งธ๋กœ ๋น ์กŒ๋‹ค.**\n *\n * ๊ทธ๋ฆฌ๊ณ  ์—๋„ˆ์ง€ ์‚ฌ๊ฑด์€ `equipmentId` ๋ฅผ ์“ด๋‹ค(์–ดํœ˜๊ฐ€ `movers`โ†’`equipment` ๋กœ ๊ฐœ๋ช…๋œ ๋’ค์— ์ƒ๊ธด\n * ์ฑ„๋„์ด๋‹ค). ์‹ค์ธก `energy.equipment` 31,079 ํ–‰ ์ „๋ถ€ ๋น„์–ด ์žˆ์—ˆ๋‹ค โ€” ใ€Œ์ด ์„ค๋น„๊ฐ€ ์–ผ๋งˆ๋ฅผ ๋จน์—ˆ๋‚˜ใ€๋ฅผ\n * ์„ค๋น„ ์ถ•์œผ๋กœ ๋ฌผ์„ ์ˆ˜ ์—†์—ˆ๋‹ค.\n *\n * ์…‹์„ ํ•จ๊ป˜ ๋ณธ๋‹ค. ๊ฐœ๋ช… ์„ธ๋Œ€๊ฐ€ ์„ž์—ฌ ์žˆ๋Š” ๊ฒƒ์€ ์ €๋„์˜ ์„ฑ์งˆ์ด๊ณ , ์ฝ๋Š” ์ชฝ์ด ๊ทธ๊ฒƒ์„ ํก์ˆ˜ํ•œ๋‹ค.\n */\n return d.moverId ?? d.resourceRef ?? d.equipmentId ?? undefined\n}\n\n/**\n * EPCIS ํ–‰์œ„ โ€” `ADD`ยท`OBSERVE`ยท`DELETE`. ์„ธ ๊ฐ’์ด ์•„๋‹ˆ๋ฉด `undefined`(์›์ฒœ์˜ ์žก๊ฐ’์„ ์ƒ‰์ธ์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค).\n *\n * ์ด ํ‚ค๋Š” ๊ฒ€์ƒ‰ ์ถ•์ด ์•„๋‹ˆ๋ผ **ํŒ๋ณ„์‹**์ด๋‹ค: ๋˜ํ’€์–ด ์ฝ๋Š” ์Šค๋ƒ…์ƒท์€ ์›๋ฆฌ์ ์œผ๋กœ `DELETE` ๋ฅผ ๋ชป ๋‚ธ๋‹ค.\n * ๊ทธ๋ž˜์„œ ใ€Œ์ด ํŠธ์œˆ์ด ๋ฐ˜์ถœ์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๊ณ„์‚ฐํ–ˆ๋Š”๊ฐ€ใ€๊ฐ€ ์ง„์งœ delta ํ”ผ๋“œ์˜ ์ฆ๊ฑฐ์ธ๋ฐ, payload ์•ˆ์— ์žˆ๋Š”\n * ๋™์•ˆ์—๋Š” 5๊ฐœ ๋“œ๋ผ์ด๋ฒ„ ์–ด๋””์—์„œ๋„ ๊ทธ ์งˆ๋ฌธ์„ ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค. ์šด์˜ ๋ธํƒ€์—๋Š” ํ–‰์œ„๊ฐ€ ์—†๋‹ค โ€” ๋น„์šด๋‹ค.\n */\nexport function actionOf(envelope: any): string | undefined {\n const a = (envelope?.data ?? envelope ?? {}).action\n return a === 'ADD' || a === 'OBSERVE' || a === 'DELETE' ? a : undefined\n}\n\n/** ํ•œ ์ด๋ฒคํŠธ์—์„œ ์Šน๊ฒฉ ํ‚ค ์ „๋ถ€ โ€” ๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ์ด ํ•จ์ˆ˜ ํ•˜๋‚˜๋งŒ ๋ถ€๋ฅธ๋‹ค. */\nexport function twinEventKeys(envelope: any): TwinEventKeys {\n return {\n action: actionOf(envelope),\n bizStep: clip(bizStepOf(envelope), 'bizStep'),\n epc: clip(epcOf(envelope), 'epc'),\n orderId: clip(orderOf(envelope), 'orderId'),\n locationId: clip(locationOf(envelope), 'locationId'),\n moverId: clip(equipmentIdOf(envelope), 'moverId')\n }\n}\n"]}
1
+ {"version":3,"file":"twin-event-keys.js","sourceRoot":"","sources":["../../../server/service/twin-event/twin-event-keys.ts"],"names":[],"mappings":"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","sourcesContent":["import { twinWarn } from '../../engine/log.js'\n/*\n * ์ €๋„ ๊ฒ€์ƒ‰ ํ‚ค ์ถ”์ถœ โ€” **์ˆœ์ˆ˜**. ์ธ์ œ์ŠคํŠธ๊ฐ€ ๊ธฐ๋กํ•  ๋•Œ ํ•œ ๋ฒˆ ๋ฝ‘์•„ ์ธ๋ฑ์Šค ๊ฐ€๋Šฅํ•œ ์‹ค์ปฌ๋Ÿผ์œผ๋กœ ์Šน๊ฒฉํ•œ๋‹ค.\n *\n * โ”€โ”€ ์™œ ์Šน๊ฒฉํ•˜๋Š”๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‚ฌ์šฉ์ž๊ฐ€ ์ €๋„์—์„œ ์‹ค์ œ๋กœ ์ฐพ๋Š” ๊ฒƒ์€ \"์ด ํŒ”๋ ˆํŠธ์˜ ์ด๋ ฅ\", \"์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜\", \"์ด ๋„ํฌ์—์„œ\n * ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜\" ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๊ฐ’๋“ค์€ ์ „๋ถ€ `payload`(simple-json = TEXT) **์•ˆ**์— ์žˆ์—ˆ๋‹ค.\n * things-factory ๋Š” 5๊ฐœ DB ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ด์„œ DB๋ณ„ JSON ์—ฐ์‚ฐ์ž๋ฅผ ์“ธ ์ˆ˜ ์—†๋‹ค โ€”\n * ์ฆ‰ ์Šน๊ฒฉ ์—†์ด๋Š” **์–ด๋–ค ๋ฐฉ๋ฒ•์œผ๋กœ๋„ ์„œ๋ฒ„์—์„œ ๊ทธ ์กฐ๊ฑด์œผ๋กœ ๊ฑฐ๋ฅผ ์ˆ˜ ์—†์—ˆ๋‹ค**. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›์•„์˜จ\n * ๋ช‡ ์ฒœ ๊ฑด ์•ˆ์—์„œ๋งŒ ์ฐพ๋Š” ์‹œ๋Љ์ด ์ตœ์„ ์ด์—ˆ๊ณ , ์ €๋„์ด ์ปค์งˆ์ˆ˜๋ก ๊ทธ ์‹œ๋Љ์€ ๊ฑฐ์ง“๋ง์— ๊ฐ€๊นŒ์›Œ์ง„๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ๊ฒ€์ƒ‰ ์ถ•์ด ๋˜๋Š” ๊ฐ’๋งŒ ๊ณจ๋ผ ์ปฌ๋Ÿผ์œผ๋กœ ๊บผ๋‚ธ๋‹ค. payload ๋Š” ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค(์ •๋ณธ์€ ์—ฌ์ „ํžˆ payload โ€”\n * ์ด๊ฑด ํŒŒ์ƒ ์ƒ‰์ธ์ด์ง€ ์ƒˆ๋กœ์šด ์ง„์‹ค์ด ์•„๋‹ˆ๋‹ค).\n *\n * โ”€โ”€ ์™œ ์—ฌ๊ธฐ(์ˆœ์ˆ˜ ๋ชจ๋“ˆ)์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ๋‘˜์ด๋‹ค(`persistBatch` ๋ผ์ด๋ธŒ ๋ฒŒํฌ ยท `persist` ์‹ฌ ๋‹จ๊ฑด). ๋‘ ๊ณณ์— ๊ฐ์ž ์ ์œผ๋ฉด\n * ๋ฐ˜๋“œ์‹œ ์–ด๊ธ‹๋‚˜๊ณ , ์–ด๊ธ‹๋‚œ ์ƒ‰์ธ์€ \"์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ์ด๋ฒคํŠธ\" ๋ฅผ ๋งŒ๋“ ๋‹ค โ€” ์ €๋„์—์„œ ๊ฐ€์žฅ ๋‚˜์œ ๊ฒฐํ•จ์ด๋‹ค.\n */\n\n/** ์Šน๊ฒฉ๋œ ๊ฒ€์ƒ‰ ํ‚ค โ€” ์ „๋ถ€ ์„ ํƒ์ . ๋ฝ‘ํžˆ์ง€ ์•Š์œผ๋ฉด **๋นˆ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ undefined**(๊ฒฐ์ธกโ‰ ๋นˆ๊ฐ’). */\nexport interface TwinEventKeys {\n action?: string\n bizStep?: string\n epc?: string\n orderId?: string\n bizTransaction?: string\n locationId?: string\n moverId?: string\n}\n\n/*\n * ์ปฌ๋Ÿผ ๊ธธ์ด ์ƒํ•œ. GS1 ์‹๋ณ„์ž(EPC URNยทGDTIยทSGLN)๋Š” ๊ทœ๊ฒฉ์ƒ ์ด๋ณด๋‹ค ํ›จ์”ฌ ์งง๋‹ค.\n * ๋„˜์น˜๋Š” ๊ฐ’์ด ์˜ค๋ฉด **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ž๋ฅด์ง€ ์•Š๊ณ ** ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค โ€” ์ƒ‰์ธ์ด ์›๋ณธ๊ณผ ๋‹ค๋ฅด๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๊ฑฐ์ง“์ด ๋˜๋Š”๋ฐ,\n * ๊ทธ ์‚ฌ์‹ค์ด ์–ด๋””์—๋„ ์•ˆ ๋‚จ์œผ๋ฉด ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.\n */\nconst MAX_KEY = 255\n\nfunction clip(v: unknown, field: string): string | undefined {\n if (v === undefined || v === null) return undefined\n const s = String(v)\n if (!s) return undefined\n if (s.length <= MAX_KEY) return s\n twinWarn(\n `[twin-event-keys] ${field} exceeds ${MAX_KEY} chars and was clipped for indexing โ€” ` +\n `search on this value may be incomplete. payload keeps the full value. (${s.slice(0, 60)}โ€ฆ)`\n )\n return s.slice(0, MAX_KEY)\n}\n\n/** CBV bizStep URN ์˜ ๋๋งˆ๋””. ์—†์œผ๋ฉด ์ด๋ฒคํŠธ ํƒ€์ž…์—์„œ ์œ ์ถ”(`epcis.` ์ ‘๋‘ ์ œ๊ฑฐ). */\nexport function bizStepOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n const tail = String(d.bizStep ?? '').split(':').pop()\n return tail || String(envelope?.eventType ?? '').replace('epcis.', '') || undefined\n}\n\n/**\n * ํ’ˆ๋ชฉ ์‹๋ณ„์ž โ€” **์ „์ฒด ๊ฐ’**์„ ์ €์žฅํ•œ๋‹ค(๋๋งˆ๋””๋งŒ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค).\n *\n * ํ‘œ์‹œ์šฉ ์ถ•์•ฝ์€ ํ™”๋ฉด์ด ํ•˜๊ณ , ์ƒ‰์ธ์€ ์›๋ณธ์„ ๊ฐ–๋Š”๋‹ค. `search` ๋Š” ๋ถ€๋ถ„์ผ์น˜(contains)๋ผ\n * ์ „์ฒด๋ฅผ ์ €์žฅํ•ด ๋‘๋ฉด ๋๋งˆ๋””(\"402.2\")๋กœ๋„ URN ์ „์ฒด๋กœ๋„ ์ฐพํžŒ๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋๋งˆ๋””๋งŒ ์ €์žฅํ•˜๋ฉด\n * URN ์œผ๋กœ ์ฐพ๋Š” ๊ฒฝ๋กœ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.\n */\nexport function epcOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.epcList?.[0] ?? d.parentID ?? d.quantityList?.[0]?.epcClass ?? undefined\n}\n\n/**\n * ์˜ค๋” ์‹๋ณ„์ž โ€” ์šด์˜ ๋ธํƒ€์˜ `orderId` ์šฐ์„ , EPCIS ๋Š” `bizTransactionList`.\n *\n * โ”€โ”€ ์‹ค์ธก (2026-08-24) โ€” ์ด ์ปฌ๋Ÿผ์ด **์ „๋ถ€ ๋น„์–ด ์žˆ์—ˆ๋‹ค** โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์—ฌ๊ธฐ๊ฐ€ ์ฐพ๋˜ ์ด๋ฆ„์ด `d.order` ์˜€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ปค๋„์ด ๋‚ด๋Š” ์ด๋ฆ„์€ **`orderId`** ๋‹ค\n * (`OrderStatusDelta.orderId` ยท `TaskStatusDelta.orderId`). `d.order` ๋ฅผ ๋‚ด๋Š” ์ฝ”๋“œ๋Š” ์ปค๋„์— **ํ•œ ๊ณณ๋„\n * ์—†๋‹ค** โ€” ์ฃฝ์€ ๊ฐ€์ง€์˜€๋‹ค. ๊ทธ๋ž˜์„œ ์šด์˜ ๋ธํƒ€๋Š” ์ด ์ปฌ๋Ÿผ์„ ํ•œ ๋ฒˆ๋„ ์ฑ„์šฐ์ง€ ๋ชปํ–ˆ๋‹ค.\n *\n * order.status 29,403,565 ํ–‰ โ€” order_id ๋น„์–ด ์žˆ์Œ 29,403,565 (100%)\n * task.status 191,175 ํ–‰ โ€” ๋น„์–ด ์žˆ์Œ 191,175 (100%)\n *\n * ๊ทธ ๊ฒฐ๊ณผ ์ƒ‰์ธ `ix_twin_event_4` ๊ฐ€ **์ž๊ธฐ ์ฃผ์„์ด ์ ์–ด ๋‘” ์šฉ๋„**(ใ€Œ์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜ใ€)๋กœ ์“ธ ์ˆ˜\n * ์—†์—ˆ๋‹ค. ํ™”๋ฉด์€ ์˜ค๋”๋ฅผ ๋ˆŒ๋Ÿฌ๋„ ใ€Œ์—ฐ๊ฒฐ๋œ ์ด๋ฒคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹คใ€๋ฅผ ๋ƒˆ๊ณ , ๊ทธ ๋‹ต์€ ์งˆ์˜ ๊ฒฐ๊ณผ๋กœ๋Š” ์ •์งํ–ˆ๋‹ค โ€”\n * ์‹œ์ ์„ ์–ด๋””๋กœ ์˜ฎ๊ฒจ๋„ 0 ์ด์—ˆ๋‹ค.\n *\n * **๊ณผ๊ฑฐ ํ–‰์€ ์ฑ„์›Œ์ง€์ง€ ์•Š๋Š”๋‹ค**(์‚ฌ์šฉ์ž ๊ฒฐ์ • 2026-08-24, `moverId` ๋•Œ์™€ ๊ฐ™์€ ๋ฐฉ์‹). ์•ž์œผ๋กœ ๋“ค์–ด์˜ค๋Š”\n * ์‚ฌ๊ฑด๋ถ€ํ„ฐ ์กฐํšŒ๋œ๋‹ค.\n *\n * โ”€โ”€ ํ•œ ์นธ์— ๋‘ ๋‚ฑ๋ง์ด ๋“ค์–ด ์žˆ์—ˆ๋‹ค (2026-09-05 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์œ„ ์ฃผ์„์ด ์ด๋ฏธ ์•Œ๊ณ  ์žˆ์—ˆ๋‹ค โ€” ใ€ŒEPCIS ์˜ `bizTransactionList` ๋Š” **๊ฑฐ๋ž˜**(PO/SO)์ด๊ณ  ์˜ค๋”์™€ ๊ฐ™์€\n * ๊ฒƒ์ด ์•„๋‹ ์ˆ˜ ์žˆ๋‹คใ€. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋‘˜์„ **๊ฐ™์€ ์นธ์—** ๋„ฃ๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ ‡๊ฒŒ ๋๋‹ค.\n *\n * order.status order-1 ๋‚ด๋ถ€ ์˜ค๋” id\n * epcis.TransformationEvent urn:epc:id:gdti:9521321.403.1 GS1 ๊ฑฐ๋ž˜ ์‹๋ณ„์ž\n * epcis.TransactionEvent urn:epc:id:gdti:9521321.403.1\n *\n * ํ•œ ์˜ค๋”์˜ ์ด๋ ฅ์ด **์ƒ‰์ธ ์•ˆ์—์„œ ๋‘ ์ชฝ์œผ๋กœ ๊ฐˆ๋ผ์ง„๋‹ค.** ์–ด๋А ์ด๋ฆ„์œผ๋กœ ๋ฌผ์–ด๋„ ์ ˆ๋ฐ˜๋งŒ ๋‚˜์˜ค๊ณ ,\n * ์˜ค๋ฅ˜๋Š” ๋‚˜์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ธก: ์–ดํœ˜๊ฐ€ ์„ž์ธ ํ–‰ 10,004๊ฐœ.\n *\n * ์ด๊ฒƒ์ด ์‹ค์ œ๋กœ ๋ง‰์€ ๊ฒƒ โ€” ใ€Œ์ด ๊ฐœ์ฒด๋ฅผ ์–ด๋А ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“ค์—ˆ๋‚˜ใ€๋‹ค. ๋‹ต์€ ๊ธฐ๋ก๋˜์–ด ์žˆ๋‹ค(์˜ค๋” ์‚ฌ๊ฑด์ด\n * `recipeKey` ๋ฅผ ๋“ ๋‹ค, ์‹ค์ธก 328,021/328,021 = 100%). ๋ณ€ํ™˜ ์‚ฌ๊ฑด์€ ๊ทธ ์˜ค๋”๋ฅผ GDTI ๋กœ ๊ฐ€๋ฆฌํ‚ค๋Š”๋ฐ\n * ์˜ค๋” ์‚ฌ๊ฑด์€ `order-1` ๋กœ ์ ํ˜€ ์žˆ์–ด **์ƒ‰์ธ์œผ๋กœ ์ด์„ ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค.**\n *\n * ๊ทธ๋ž˜์„œ ์นธ์„ ๊ฐˆ๋ž๋‹ค(์‚ฌ์šฉ์ž ๊ฒฐ์ • 2026-09-05).\n *\n * orderId ๋‚ด๋ถ€ ์˜ค๋” id โ€” ์ฝ๊ธฐ ๋ชจ๋ธ์˜ ์ด์Œ์‡ \n * bizTransaction GS1 ๊ฑฐ๋ž˜ ์‹๋ณ„์ž โ€” ํ‘œ์ค€์ด ๋งํ•˜๋Š” ๊ทธ ๊ฑฐ๋ž˜\n *\n * ์˜ค๋” ์‚ฌ๊ฑด์€ **๋‘˜ ๋‹ค** ๋“ ๋‹ค(`order.status` ์˜ payload ์— `orderId` ์™€ `bizTransaction` ์ด ํ•จ๊ป˜\n * ์žˆ๋‹ค). ๊ทธ๋ž˜์„œ EPCIS ์‚ฌ๊ฑด์˜ ๊ฑฐ๋ž˜ ์‹๋ณ„์ž๋กœ ์˜ค๋”๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค โ€” ์ด ๋‘ ์นธ์ด ๊ทธ ๋‹ค๋ฆฌ๋‹ค.\n */\nexport function orderOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.orderId ?? undefined\n}\n\n/**\n * **๊ทธ ์‚ฌ๊ฑด์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฑฐ๋ž˜** โ€” EPCIS `bizTransactionList` ์˜ ์ฒซ ํ•ญ๋ชฉ, ๋˜๋Š” ์šด์˜ ๋ธํƒ€๊ฐ€ ์ง์ ‘ ๋“  ๊ฐ’.\n *\n * ์˜ค๋”๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ‘œ์ค€์ด ๋งํ•˜๋Š” ๊ฑฐ๋ž˜(PO/SO/์ƒ์‚ฐ์˜ค๋”)์ด๊ณ , ํ•œ ์˜ค๋”๊ฐ€ ์—ฌ๋Ÿฌ ๊ฑฐ๋ž˜์— ๊ฑธ๋ฆด ์ˆ˜๋„ ์žˆ๋‹ค.\n * ๊ทธ ๊ตฌ๋ณ„์„ ์ง€ํ‚ค๋ ค๊ณ  `orderId` ์™€ ๊ฐˆ๋ผ ๋‘์—ˆ๋‹ค โ€” ํ•ฉ์น˜๋ฉด ์œ„ ์ฃผ์„์˜ ๊ทธ ์ผ์ด ๋‹ค์‹œ ๋‚œ๋‹ค.\n */\nexport function bizTransactionOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.bizTransactionList?.[0]?.bizTransaction ?? d.bizTransaction ?? undefined\n}\n\n/**\n * ์œ„์น˜ โ€” EPCIS ๋Š” ์ฝ์€ ์ง€์ (readPoint) ์šฐ์„ , ์—†์œผ๋ฉด ์—…๋ฌด ์œ„์น˜(bizLocation).\n * ์šด์˜ ๋ธํƒ€(๋ฌด๋ฒ„ ์ด๋™ ๋“ฑ)๋Š” ๊ทธ ๋‘˜์ด ์—†๊ณ  ํ‰๋ฒ”ํ•œ `location` ์„ ์“ด๋‹ค โ€” ๋น ๋œจ๋ฆฌ๋ฉด ์„ค๋น„๊ฐ€ ์–ด๋””์„œ\n * ๋ฌด์—‡์„ ํ–ˆ๋Š”์ง€๊ฐ€ ์œ„์น˜ ์ถ•์—์„œ ํ†ต์งธ๋กœ ์‚ฌ๋ผ์ง„๋‹ค.\n */\nexport function locationOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n return d.readPoint?.id ?? d.bizLocation?.id ?? d.location ?? undefined\n}\n\n/**\n * ์„ค๋น„ยท๋ฌด๋ฒ„ โ€” ์šด์˜ ๋ธํƒ€(equipment.statusยทtask.status)๊ฐ€ ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ถ•.\n *\n * EPCIS ์–ดํœ˜๊ฐ€ ์•„๋‹ˆ๋ผ์„œ ๋‹ค๋ฅธ ์ถ• ์–ด๋””์—๋„ ์•ˆ ์žกํžŒ๋‹ค. ์ด๊ฒŒ ์—†์œผ๋ฉด \"์ด ์ง€๊ฒŒ์ฐจ๊ฐ€ ์˜ค๋Š˜ ๋ฌด์—‡์„ ํ–ˆ๋‚˜\" ๋ฅผ\n * ์„œ๋ฒ„์—์„œ ๋ฌผ์„ ๋ฐฉ๋ฒ•์ด ์—†์–ด, ํ™”๋ฉด์ด ์ €๋„์„ ํ†ต์งธ๋กœ ๋ฐ›์•„ ์ „์ˆ˜ ์กฐํšŒํ•˜๋Š” ์ˆ˜๋ฐ–์— ์—†๋‹ค.\n */\nexport function equipmentIdOf(envelope: any): string | undefined {\n const d = envelope?.data ?? envelope ?? {}\n /*\n * โ”€โ”€ ์‹ค์ธก (2026-08-24) โ€” ๋‘ ๊ฐˆ๋ž˜๋ฅผ ๋†“์น˜๊ณ  ์žˆ์—ˆ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์œ„ ์ฃผ์„์ด `task.status` ๋ฅผ ์ถœ์ฒ˜๋กœ **์ ์–ด ๋‘์—ˆ๋Š”๋ฐ** ์ด ํ•จ์ˆ˜๋Š” `d.moverId` ๋งŒ ๋ดค๋‹ค. ์ž‘์—…์ด ์ž์›์„\n * ๊ฐ€๋ฆฌํ‚ค๋Š” ์ด๋ฆ„์€ `resourceRef` ๋‹ค(`TaskStatusDelta.resourceRef`) โ€” ๊ทธ๋ž˜์„œ ์ž‘์—… 191,175 ํ–‰ ์ „๋ถ€\n * ์ด ์ปฌ๋Ÿผ์ด ๋น„์—ˆ๊ณ , ใ€Œ์ด ์ง€๊ฒŒ์ฐจ๊ฐ€ ์˜ค๋Š˜ ๋ฌด์—‡์„ ํ–ˆ๋‚˜ใ€์—์„œ **์ž‘์—…์ด ํ†ต์งธ๋กœ ๋น ์กŒ๋‹ค.**\n *\n * ๊ทธ๋ฆฌ๊ณ  ์—๋„ˆ์ง€ ์‚ฌ๊ฑด์€ `equipmentId` ๋ฅผ ์“ด๋‹ค(์–ดํœ˜๊ฐ€ `movers`โ†’`equipment` ๋กœ ๊ฐœ๋ช…๋œ ๋’ค์— ์ƒ๊ธด\n * ์ฑ„๋„์ด๋‹ค). ์‹ค์ธก `energy.equipment` 31,079 ํ–‰ ์ „๋ถ€ ๋น„์–ด ์žˆ์—ˆ๋‹ค โ€” ใ€Œ์ด ์„ค๋น„๊ฐ€ ์–ผ๋งˆ๋ฅผ ๋จน์—ˆ๋‚˜ใ€๋ฅผ\n * ์„ค๋น„ ์ถ•์œผ๋กœ ๋ฌผ์„ ์ˆ˜ ์—†์—ˆ๋‹ค.\n *\n * ์…‹์„ ํ•จ๊ป˜ ๋ณธ๋‹ค. ๊ฐœ๋ช… ์„ธ๋Œ€๊ฐ€ ์„ž์—ฌ ์žˆ๋Š” ๊ฒƒ์€ ์ €๋„์˜ ์„ฑ์งˆ์ด๊ณ , ์ฝ๋Š” ์ชฝ์ด ๊ทธ๊ฒƒ์„ ํก์ˆ˜ํ•œ๋‹ค.\n */\n return d.moverId ?? d.resourceRef ?? d.equipmentId ?? undefined\n}\n\n/**\n * EPCIS ํ–‰์œ„ โ€” `ADD`ยท`OBSERVE`ยท`DELETE`. ์„ธ ๊ฐ’์ด ์•„๋‹ˆ๋ฉด `undefined`(์›์ฒœ์˜ ์žก๊ฐ’์„ ์ƒ‰์ธ์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค).\n *\n * ์ด ํ‚ค๋Š” ๊ฒ€์ƒ‰ ์ถ•์ด ์•„๋‹ˆ๋ผ **ํŒ๋ณ„์‹**์ด๋‹ค: ๋˜ํ’€์–ด ์ฝ๋Š” ์Šค๋ƒ…์ƒท์€ ์›๋ฆฌ์ ์œผ๋กœ `DELETE` ๋ฅผ ๋ชป ๋‚ธ๋‹ค.\n * ๊ทธ๋ž˜์„œ ใ€Œ์ด ํŠธ์œˆ์ด ๋ฐ˜์ถœ์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๊ณ„์‚ฐํ–ˆ๋Š”๊ฐ€ใ€๊ฐ€ ์ง„์งœ delta ํ”ผ๋“œ์˜ ์ฆ๊ฑฐ์ธ๋ฐ, payload ์•ˆ์— ์žˆ๋Š”\n * ๋™์•ˆ์—๋Š” 5๊ฐœ ๋“œ๋ผ์ด๋ฒ„ ์–ด๋””์—์„œ๋„ ๊ทธ ์งˆ๋ฌธ์„ ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค. ์šด์˜ ๋ธํƒ€์—๋Š” ํ–‰์œ„๊ฐ€ ์—†๋‹ค โ€” ๋น„์šด๋‹ค.\n */\nexport function actionOf(envelope: any): string | undefined {\n const a = (envelope?.data ?? envelope ?? {}).action\n return a === 'ADD' || a === 'OBSERVE' || a === 'DELETE' ? a : undefined\n}\n\n/** ํ•œ ์ด๋ฒคํŠธ์—์„œ ์Šน๊ฒฉ ํ‚ค ์ „๋ถ€ โ€” ๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ์ด ํ•จ์ˆ˜ ํ•˜๋‚˜๋งŒ ๋ถ€๋ฅธ๋‹ค. */\nexport function twinEventKeys(envelope: any): TwinEventKeys {\n return {\n action: actionOf(envelope),\n bizStep: clip(bizStepOf(envelope), 'bizStep'),\n epc: clip(epcOf(envelope), 'epc'),\n orderId: clip(orderOf(envelope), 'orderId'),\n bizTransaction: clip(bizTransactionOf(envelope), 'bizTransaction'),\n locationId: clip(locationOf(envelope), 'locationId'),\n moverId: clip(equipmentIdOf(envelope), 'moverId')\n }\n}\n"]}
@@ -32,6 +32,7 @@ export declare class TwinEvent {
32
32
  bizStep?: string;
33
33
  epc?: string;
34
34
  orderId?: string;
35
+ bizTransaction?: string;
35
36
  locationId?: string;
36
37
  moverId?: string;
37
38
  payload?: any;
@@ -22,6 +22,7 @@ const shell_1 = require("@things-factory/shell");
22
22
  * ix_2 (domain, instanceId, eventType, revision) ํƒ€์ž… ํ•„ํ„ฐ + ์ •๋ ฌ ๋™์‹œ ์ถฉ์กฑ(์Šค์ผ€์ค„ ํ™”๋ฉด task/equipment)
23
23
  * ix_3 (domain, instanceId, epc) "์ด ๋ฌผ๊ฑด์˜ ์ด๋ ฅ" โ€” Entity360 ์˜ ๋ณธ์งˆ ์งˆ๋ฌธ
24
24
  * ix_4 (domain, instanceId, orderId) "์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜"
25
+ * ix_9 (domain, instanceId, bizTransaction) "์ด ๊ฑฐ๋ž˜์— ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜" โ€” EPCISโ†”์˜ค๋”์˜ ๋‹ค๋ฆฌ
25
26
  *
26
27
  * bizStepยทlocationIdยทmoverId ๋Š” ์ปฌ๋Ÿผ๋งŒ ๋‘๊ณ  ์ธ๋ฑ์Šค๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ํ•œ ํŠธ์œˆ ์•ˆ์—์„œ ์นด๋””๋„๋ฆฌํ‹ฐ๊ฐ€
27
28
  * ๋‚ฎ์•„(์—…๋ฌด๋‹จ๊ณ„ ๋ช‡ ๊ฐœ, ์œ„์น˜ ์ˆ˜๋ฐฑ, ์„ค๋น„ ์ˆ˜์‹ญ) (domain,instanceId) ๋กœ ์ด๋ฏธ ์ขํ˜€์ง„ ๋’ค์˜ ์ž”์—ฌ ํ•„ํ„ฐ๋กœ
@@ -121,9 +122,14 @@ tslib_1.__decorate([
121
122
  ], TwinEvent.prototype, "epc", void 0);
122
123
  tslib_1.__decorate([
123
124
  (0, typeorm_1.Column)({ length: 255, nullable: true }),
124
- (0, type_graphql_1.Field)({ nullable: true, description: 'Business transaction identifier (PO / SO), promoted from the payload for indexed lookup of one order history.' }),
125
+ (0, type_graphql_1.Field)({ nullable: true, description: 'Internal order identifier, promoted from the payload for indexed lookup of one order history.' }),
125
126
  tslib_1.__metadata("design:type", String)
126
127
  ], TwinEvent.prototype, "orderId", void 0);
128
+ tslib_1.__decorate([
129
+ (0, typeorm_1.Column)({ length: 255, nullable: true }),
130
+ (0, type_graphql_1.Field)({ nullable: true, description: 'Business transaction identifier (PO / SO / production order), promoted from the payload for indexed lookup of one transaction.' }),
131
+ tslib_1.__metadata("design:type", String)
132
+ ], TwinEvent.prototype, "bizTransaction", void 0);
127
133
  tslib_1.__decorate([
128
134
  (0, typeorm_1.Column)({ length: 255, nullable: true }),
129
135
  (0, type_graphql_1.Field)({ nullable: true, description: 'Location identifier (read point, business location, or the plain location an operational delta carries), promoted from the payload for indexed filtering.' }),
@@ -184,7 +190,10 @@ exports.TwinEvent = TwinEvent = tslib_1.__decorate([
184
190
  * ์ •๋ฆฌ๋Š” ํ•œ ์ฐฝ์— 2์ดˆ๋งŒ ์“ฐ๋„๋ก ์˜ˆ์‚ฐ์ด ๊ฑธ๋ ค ์žˆ์–ด์„œ, ๊ทธ 2์ดˆ๋ฅผ ์ฃผ์‚ฌ์— ๋‹ค ์“ฐ๊ณ  44๊ฑด๋งŒ ์ง€์šฐ๊ณ  ๋ฉˆ์ท„๋‹ค.
185
191
  */
186
192
  ,
187
- (0, typeorm_1.Index)('ix_twin_event_8', (e) => [e.domain, e.instanceId, e.createdAt], { unique: false }),
193
+ (0, typeorm_1.Index)('ix_twin_event_8', (e) => [e.domain, e.instanceId, e.createdAt], { unique: false })
194
+ /* ix_9 โ€” "์ด ๊ฑฐ๋ž˜์— ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜". EPCIS ์‚ฌ๊ฑด์—์„œ ์˜ค๋”๋กœ ๊ฑด๋„ˆ๊ฐ€๋Š” ๋‹ค๋ฆฌ(ยง`bizTransaction`). */
195
+ ,
196
+ (0, typeorm_1.Index)('ix_twin_event_9', (e) => [e.domain, e.instanceId, e.bizTransaction], { unique: false }),
188
197
  (0, type_graphql_1.ObjectType)({ description: 'Append-only twin event journal record (EPCIS event or operational delta).' })
189
198
  ], TwinEvent);
190
199
  //# sourceMappingURL=twin-event.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"twin-event.js","sourceRoot":"","sources":["../../../server/service/twin-event/twin-event.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\n/*\n * TwinEvent โ€” append-only ํŠธ์œˆ ์ด๋ฒคํŠธ ์ €๋„(EPCIS ์ด๋ฒคํŠธ + ์šด์˜ ๋ธํƒ€).\n * ์ปค๋„ EventJournal ์˜ ์˜์† ๋Œ€์‘ โ€” ์ƒํƒœ=์ด๋ฒคํŠธ์—ด์˜ ํ•จ์ˆ˜(์žฌ๋ถ€ํŒ… ์‹œ DBโ†’replay ์žฌ๊ตฌ์„ฑ).\n * append-only ์ด๋ฏ€๋กœ updater/deletedAt ์—†์Œ(์ด๋ ฅ CRUD ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ถˆ๋ณ€ ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ).\n * payload ๋Š” simple-json(๋ฉ€ํ‹ฐDB ์ด์‹ โ€” postgres/mysql/sqlite/mssql/oracle ๊ณตํ†ต, DB-specific JSON ํƒ€์ž… ๊ธˆ์ง€).\n * (CLAUDE.md: ๋ชจ๋“  @ObjectType/@Field ๋Š” ์˜๋ฌธ description ํ•„์ˆ˜.)\n */\n/*\n * โ”€โ”€ ์ธ๋ฑ์Šค ์„ค๊ณ„ (2026-07-31) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ‘œ๋Š” **์ธ์ œ์ŠคํŠธ ๊ฒฝ๋กœ์˜ ๋œจ๊ฑฐ์šด append-only ํ…Œ์ด๋ธ”**์ด๋‹ค. ์ธ๋ฑ์Šค ํ•˜๋‚˜ํ•˜๋‚˜๊ฐ€ ์“ฐ๊ธฐ ์ฆํญ์ด๋ฏ€๋กœ\n * \"์žˆ์œผ๋ฉด ์ข‹์„\" ์ธ๋ฑ์Šค๋ฅผ ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ œ ์งˆ์˜ ํŒจํ„ด์— ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ๋งŒ ๋‘”๋‹ค.\n *\n * ix_0 (domain, instanceId, revision) ์›์žฅ ๊ธฐ๋ณธ ์ •๋ ฌยท์ปค์„œ ํŽ˜์ด์ง•ยทreplay(ASC ์ฃผ์‚ฌ)\n * ix_1 (domain, instanceId, eventTime) ์‹œ๊ฐ ์ปค์„œ(untilTime)ยท์‹œ๊ฐ„์ฐฝ KPI โ€” ๊ฑฐ์˜ ๋ชจ๋“  ์กฐํšŒ๊ฐ€ ํƒ„๋‹ค\n * ix_2 (domain, instanceId, eventType, revision) ํƒ€์ž… ํ•„ํ„ฐ + ์ •๋ ฌ ๋™์‹œ ์ถฉ์กฑ(์Šค์ผ€์ค„ ํ™”๋ฉด task/equipment)\n * ix_3 (domain, instanceId, epc) \"์ด ๋ฌผ๊ฑด์˜ ์ด๋ ฅ\" โ€” Entity360 ์˜ ๋ณธ์งˆ ์งˆ๋ฌธ\n * ix_4 (domain, instanceId, orderId) \"์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜\"\n *\n * bizStepยทlocationIdยทmoverId ๋Š” ์ปฌ๋Ÿผ๋งŒ ๋‘๊ณ  ์ธ๋ฑ์Šค๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ํ•œ ํŠธ์œˆ ์•ˆ์—์„œ ์นด๋””๋„๋ฆฌํ‹ฐ๊ฐ€\n * ๋‚ฎ์•„(์—…๋ฌด๋‹จ๊ณ„ ๋ช‡ ๊ฐœ, ์œ„์น˜ ์ˆ˜๋ฐฑ, ์„ค๋น„ ์ˆ˜์‹ญ) (domain,instanceId) ๋กœ ์ด๋ฏธ ์ขํ˜€์ง„ ๋’ค์˜ ์ž”์—ฌ ํ•„ํ„ฐ๋กœ\n * ์ถฉ๋ถ„ํ•˜๊ณ , ๋œจ๊ฑฐ์šด ํ‘œ์— ์ธ๋ฑ์Šค๋ฅผ ๋” ์–น์„ ๊ฐ€์น˜๊ฐ€ ์—†๋‹ค. ์ €๋„ ํ•˜๋‚˜๊ฐ€ ์•„์ฃผ ์ปค์ ธ์„œ ์ด ์ถ•๋“ค์˜ ์กฐํšŒ๊ฐ€\n * ๋А๋ ค์ง€๋ฉด ๊ทธ๋•Œ ์ธก์ •์„ ๊ทผ๊ฑฐ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ผ์ด์ง€, ์ง€๋ ˆ ์–น์–ด ์“ฐ๊ธฐ๋ฅผ ๋ฌด๊ฒ๊ฒŒ ํ•  ์ผ์€ ์•„๋‹ˆ๋‹ค.\n */\n@Entity()\n@Index('ix_twin_event_0', (e: TwinEvent) => [e.domain, e.instanceId, e.revision], { unique: false })\n@Index('ix_twin_event_1', (e: TwinEvent) => [e.domain, e.instanceId, e.eventTime], { unique: false })\n@Index('ix_twin_event_2', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.revision], { unique: false })\n@Index('ix_twin_event_3', (e: TwinEvent) => [e.domain, e.instanceId, e.epc], { unique: false })\n@Index('ix_twin_event_4', (e: TwinEvent) => [e.domain, e.instanceId, e.orderId], { unique: false })\n/* ix_5 โ€” \"์ด ์ง€์‹œ๊ฐ€ ๋ฌด์—‡์„ ์ผ์œผ์ผฐ๋‚˜\". ๊ฐ์‚ฌ ๊ธฐ๋ก์˜ commandId ๋กœ ์ €๋„์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋Š” ์ถ•. */\n@Index('ix_twin_event_5', (e: TwinEvent) => [e.domain, e.correlationId], { unique: false })\n/* ix_6 โ€” \"๋ฐ˜์ถœ์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๊ณ„์‚ฐํ–ˆ๋‚˜\". ์—†์œผ๋ฉด ๊ทธ ์งˆ๋ฌธ์ด ์ธ์Šคํ„ด์Šค ์ €๋„ ์ „๋Ÿ‰ ์ฃผ์‚ฌ๊ฐ€ ๋œ๋‹ค. */\n@Index('ix_twin_event_6', (e: TwinEvent) => [e.domain, e.instanceId, e.action], { unique: false })\n/*\n * ix_7 โ€” **\"์ด ์ข…๋ฅ˜์˜ ์‚ฌ์‹ค์„ ์‹œ๊ฐ์ˆœ์œผ๋กœ\"** (2026-08-25 ์‹ค์ธก์œผ๋กœ ์ถ”๊ฐ€)\n *\n * ์ด ์ถ•์ด ์—†์–ด์„œ ๊ณต์ • ํƒ€์ž„๋ผ์ธ์ด 22์ดˆ์˜€๋‹ค. ์ข…๋ฅ˜๋กœ ๊ฑฐ๋ฅด๊ณ  ์‹œ๊ฐ์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ์กฐํšŒ๊ฐ€ ๊ฐˆ ๊ณณ์ด ์—†์—ˆ๋‹ค:\n *\n * ix_2 (โ€ฆ, eventType, revision) ์ข…๋ฅ˜๋Š” ๊ฑธ๋Ÿฌ์ง€๊ณ  ์ •๋ ฌ์ด **์ ํžŒ ์ˆœ์„œ**๋‹ค โ†’ 4์›” ์‚ฌ์‹ค์„ ์ตœ๊ทผ์œผ๋กœ ๊ทธ๋ ธ๋‹ค\n * ix_1 (โ€ฆ, eventTime) ์ •๋ ฌ์€ ๋งž๊ณ  **์ข…๋ฅ˜๋ฅผ ๋ชป ๊ฑฐ๋ฅธ๋‹ค** โ†’ ํ–‰๋งˆ๋‹ค ํ…Œ์ด๋ธ”์„ ์—ด์–ด ํ™•์ธํ•œ๋‹ค\n *\n * ๋’ค์ชฝ์œผ๋กœ ๊ฑธ์œผ๋ฉด ๊ทธ ํŠธ์œˆ์—์„œ ์ฐพ๋Š” ์ข…๋ฅ˜๊ฐ€ ๋ฉˆ์ถ˜ ์‹œ์ ๊นŒ์ง€์˜ ๋ชจ๋“  ํ–‰์„ ์ฝ๊ณ  ๋ฒ„๋ฆฐ๋‹ค. ์Šนํ™”ํ‘ธ๋“œ์—์„œ ์ž‘์—…\n * ์‚ฌ์‹ค์€ 8์›” 22์ผ์— ๋ฉˆ์ถฐ ์žˆ๊ณ  ๊ทธ ๋’ค๋กœ ๋ฆฌ๋น„์ „์ด 110๋งŒ ๋Š˜์—ˆ์œผ๋ฏ€๋กœ, 200๊ฑด์— ๋‹ฟ๊ธฐ๊นŒ์ง€ 110๋งŒ ํ–‰์„ ์—ด์—ˆ๋‹ค.\n *\n * ์œ„ ์ฃผ์„์ด ใ€Œ์ธก์ •์„ ๊ทผ๊ฑฐ๋กœ ์ถ”๊ฐ€ํ•  ์ผ์ด์ง€ ์ง€๋ ˆ ์–น์„ ์ผ์€ ์•„๋‹ˆ๋‹คใ€๋ผ๊ณ  ์ ์–ด ๋‘์—ˆ๋‹ค. ๊ทธ ์ธก์ •์ด ๋‚˜์™”๋‹ค.\n */\n@Index('ix_twin_event_7', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.eventTime], { unique: false })\n/*\n * ix_8 โ€” **\"์ด ํŠธ์œˆ์˜ ์˜ค๋ž˜๋œ ๊ธฐ๋ก\"** (2026-08-27 ์‹ค์ธก์œผ๋กœ ์ถ”๊ฐ€)\n *\n * ๋ณด๊ด€ ๊ธฐ๊ฐ„ ์ •๋ฆฌ๊ฐ€ `created_at` ์œผ๋กœ ์ž๋ฅด๋Š”๋ฐ(๋ณด๊ด€์€ ์ €์žฅ ๋‚˜์ด์˜ ๋ฌธ์ œ๋‹ค) ๊ทธ ์ถ•์— ์ธ๋ฑ์Šค๊ฐ€ ์—†์—ˆ๋‹ค.\n * ๊ทธ๋ž˜์„œ ์ •๋ฆฌ๊ฐ€ ๋งค ๋ฐฐ์น˜๋งˆ๋‹ค ๊ทธ ํŠธ์œˆ์˜ ์ €๋„์„ ์ „๋Ÿ‰ ์ฃผ์‚ฌํ–ˆ๋‹ค.\n *\n * hatio-mx2 ์˜ 7์ผ ๋ฐ– ํ–‰์„ ์„ธ๊ธฐ 208์ดˆ โ† 1,029๋งŒ ํ–‰์„ ์ „๋ถ€ ์ฝ๋Š”๋‹ค(7์ผ ๋ฐ–์€ 2,446๊ฑด๋ฟ์ด๋‹ค)\n * revision ์œผ๋กœ ํ•œ ํ–‰ ์งš๊ธฐ 0.004์ดˆ\n *\n * ์ •๋ฆฌ๋Š” ํ•œ ์ฐฝ์— 2์ดˆ๋งŒ ์“ฐ๋„๋ก ์˜ˆ์‚ฐ์ด ๊ฑธ๋ ค ์žˆ์–ด์„œ, ๊ทธ 2์ดˆ๋ฅผ ์ฃผ์‚ฌ์— ๋‹ค ์“ฐ๊ณ  44๊ฑด๋งŒ ์ง€์šฐ๊ณ  ๋ฉˆ์ท„๋‹ค.\n */\n@Index('ix_twin_event_8', (e: TwinEvent) => [e.domain, e.instanceId, e.createdAt], { unique: false })\n@ObjectType({ description: 'Append-only twin event journal record (EPCIS event or operational delta).' })\nexport class TwinEvent {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the event record.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinEvent) => e.domain)\n domainId?: string\n\n /*\n * ์ด ์‚ฌ์‹ค์„ ๋‚ธ ํŠธ์œˆ. **๋นŒ ์ˆ˜ ์—†๋‹ค** โ€” ์ €๋„ ํ–‰์„ ๋งŒ๋“œ๋Š” ๊ณณ์€ `journalRow` ํ•˜๋‚˜๋ฟ์ด๊ณ  ๊ฑฐ๊ธฐ์„œ\n * ํ•„์ˆ˜ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. nullable ๋กœ ๋‘๋ฉด ์ฝ๋Š” ์ชฝ์ด ๋งค๋ฒˆ `?? ''` ๋ฅผ ๋‹ฌ๊ฒŒ ๋˜๊ณ , ๊ทธ ๋ฐฉ์–ด๊ฐ€ ์‹ค์ œ๋กœ๋Š”\n * ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜๋А๋ผ \"๋นˆ ์ธ์Šคํ„ด์Šค์˜ ์ด๋ฒคํŠธ\" ๋ผ๋Š” ์—†๋Š” ๊ฐœ๋…์„ ์ฝ”๋“œ์— ๋‚จ๊ธด๋‹ค.\n */\n @Column()\n @Field({ description: 'Twin runtime instance id that emitted the event.' })\n instanceId: string\n\n /* ์ปค๋„ ๋ด‰ํˆฌ์˜ ํ•„์ˆ˜ ํ•„๋“œ(`CanonicalEnvelope.eventType`)๋ผ ๋นŒ ์ˆ˜ ์—†๋‹ค โ€” ๊ณ„์•ฝ์„ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด๋‹ค. */\n @Column()\n @Field({ description: 'Event type: epcis.* | task.status | equipment.status | order.status.' })\n eventType: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Monotonic state revision at which the event was emitted.' })\n revision?: number\n\n /**\n * ์ด ์‚ฌ์‹ค์ด **์–ด๋А ๊ณต์žฅ์—์„œ** ์ผ์–ด๋‚ฌ๋‚˜ โ€” `TwinStructure.rev`.\n *\n * ์ด๊ฒƒ์ด ์—†๋˜ ์‹œ์ ˆ์—๋Š” ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ €๋„์„ ํ†ต์งธ๋กœ ์ง€์šฐ๋Š” ๊ฒƒ์ด ์œ ์ผํ•œ ๊ธธ์ด์—ˆ๋‹ค(์•ˆ ์ง€์šฐ๋ฉด ์˜›\n * ์ด๋ฒคํŠธ๋ฅผ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ๊ณ„์‚ฐํ•ด ์ด๋ ฅ์ด ๊ฑฐ์ง“๋ง์„ ํ•œ๋‹ค). ์ด ํ•œ ์นธ์ด ์…‹์งธ ๊ธธ์„ ์—ฐ๋‹ค โ€” ์žฌ์ƒ์ด\n * ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ์ „ํ™˜ํ•œ ๋’ค ์ด์–ด์„œ ๊ณ„์‚ฐํ•œ๋‹ค.\n *\n * **๋น„์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค**: ์ปฌ๋Ÿผ์ด ์ƒ๊ธฐ๊ธฐ ์ „์— ์“ฐ์ธ ํ–‰์ด๋‹ค. ๊ทธ ํ–‰๋“ค์€ **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฆฌ๋น„์ „**์—\n * ์†ํ•œ๋‹ค(0 ์„ ์ฑ„์›Œ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค โ€” 0 ์€ \"๋ชจ๋ฆ„\" ์ด ์•„๋‹ˆ๋ผ ์œ ํšจํ•œ ๋ฒˆํ˜ธ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค).\n */\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Structure revision (TwinStructure.rev) in force when this event happened. Absent on rows written before structure revisions existed; those belong to the oldest revision.' })\n structureRev?: number\n\n /*\n * ์ด ์‚ฌ์‹ค์ด ์ผ์–ด๋‚œ ์‹œ๊ฐ(ํŠธ์œˆ์˜ ์‹œ๊ณ„). **๋‚ ์งœ ํƒ€์ž…์ด๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ฌธ์ž์—ด์ด์—ˆ๋‹ค. ์ฝ์„ ๋•Œ๋งˆ๋‹ค `Date.parse` ํ–ˆ๊ณ , ์ •๋ ฌ์€ UTC ISO ๋งŒ ๋“ค์–ด์˜จ๋‹ค๋Š” ์ „์ œ ์œ„์—์„œ\n * ์‚ฌ์ „์‹ ๋น„๊ต๊ฐ€ ์šฐ์—ฐํžˆ ๋งž์•˜๋‹ค โ€” `+09:00` ์˜คํ”„์…‹ ํ‘œ๊ธฐ๊ฐ€ ํ•˜๋‚˜ ์„ž์ด๋ฉด ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ˆœ์„œ๊ฐ€ ํ‹€๋ฆฐ๋‹ค.\n * ๊ทธ ์ „์ œ๋Š” ์ปฌ๋Ÿผ ์–ด๋””์—๋„ ์ ํ˜€ ์žˆ์ง€ ์•Š์•˜๋‹ค.\n *\n * **ํƒ€์ž… ์ด๋ฆ„์„ ์ ์ง€ ์•Š๋Š”๋‹ค** (2026-08-19 Postgres ๋ถ€ํŒ… ์‹คํŒจ๋กœ ๊ณ ์นจ).\n *\n * `datetime` ์„ ์ ์—ˆ๋”๋‹ˆ Postgres ๊ฐ€ ๋ถ€ํŒ… ์ค‘์— ๊ฑฐ์ ˆํ–ˆ๋‹ค(`DataTypeNotSupportedError`) โ€” ๊ทธ ์ด๋ฆ„์€\n * sqliteยทMySQL ์˜ ๊ฒƒ์ด๊ณ  Postgres ๋Š” `timestamp` ๋งŒ ์•ˆ๋‹ค. ๊ฑฐ๊พธ๋กœ `timestamp` ๋Š” sqlite ๊ฐ€ ๋ชจ๋ฅธ๋‹ค:\n * **๋‹ค์„ฏ ๋“œ๋ผ์ด๋ฒ„์— ๋‹ค ํ†ตํ•˜๋Š” ์ด๋ฆ„์ด ์•„์˜ˆ ์—†๋‹ค.**\n *\n * ๊ทธ๋ž˜์„œ ์ด๋ฆ„์„ ๊ณ ๋ฅด๋Š” ์ผ์„ TypeORM ์— ๋งก๊ธด๋‹ค. `emitDecoratorMetadata` ๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฏ€๋กœ ์ด ์†์„ฑ์˜\n * TS ํƒ€์ž…(`Date`)์—์„œ ๋“œ๋ผ์ด๋ฒ„๋ณ„ ํƒ€์ž…์„ ์Šค์Šค๋กœ ๊ณ ๋ฅธ๋‹ค(Postgres `timestamp` ยท sqliteยทMySQL `datetime`).\n * ์ด ๋ ˆํฌ์˜ ๋‹ค์ค‘ DB ๊ทœ์•ฝ์ด ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ๊ทธ๊ฒƒ์ด๋‹ค โ€” ๋“œ๋ผ์ด๋ฒ„ ๋ฐฉ์–ธ์„ ์ฝ”๋“œ์— ์ ์ง€ ์•Š๋Š”๋‹ค.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Time at which the fact happened on the twin clock.' })\n eventTime?: Date\n\n /*\n * โ”€โ”€ ์Šน๊ฒฉ๋œ ๊ฒ€์ƒ‰ ์ถ• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * payload ์•ˆ์— ์žˆ๋˜ ๊ฐ’์„ ์ธ์ œ์ŠคํŠธ ์‹œ์ ์— ๊บผ๋‚ด ์‹ค์ปฌ๋Ÿผ์œผ๋กœ ๋‘”๋‹ค(`twin-event-keys.ts` ๊ฐ€ ๋‹จ๋… ์†Œ์œ ).\n * payload ๊ฐ€ ์—ฌ์ „ํžˆ ์ •๋ณธ์ด๊ณ  ์ด๊ฒƒ๋“ค์€ **ํŒŒ์ƒ ์ƒ‰์ธ**์ด๋‹ค โ€” ์ƒˆ๋กœ์šด ์ง„์‹ค์ด ์•„๋‹ˆ๋ผ ์ฐพ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์žฅ์น˜.\n * simple-json(TEXT) ์•ˆ์˜ ๊ฐ’์€ 5๊ฐœ DB ๋“œ๋ผ์ด๋ฒ„ ๊ณตํ†ต์œผ๋กœ ๊ฑฐ๋ฅผ ๋ฐฉ๋ฒ•์ด ์—†์–ด์„œ(๋ฉ€ํ‹ฐDB ํ˜ธํ™˜ ๊ทœ์น™์ƒ\n * DB๋ณ„ JSON ์—ฐ์‚ฐ์ž ๊ธˆ์ง€) ์Šน๊ฒฉ ์™ธ์˜ ์„ ํƒ์ง€๊ฐ€ ์—†๋‹ค.\n * ๊ธธ์ด ์ƒํ•œ 255 ๋Š” GS1 ์‹๋ณ„์ž ๊ทœ๊ฒฉ ๋Œ€๋น„ ์ถฉ๋ถ„ํ•˜๋ฉฐ, ๋„˜์น˜๋Š” ๊ฐ’์€ ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ž˜๋ฆฌ์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค.\n *\n * โ”€โ”€ ์ถ•์„ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  ๋•Œ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ƒˆ ์Šน๊ฒฉ ์ปฌ๋Ÿผ์„ ๋งŒ๋“ค๋ฉด **์ด๋ฏธ ์Œ“์ธ ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค.** ๊ทธ ํ–‰๋“ค์€ ์ƒˆ ์ถ•์œผ๋กœ ๊ฒ€์ƒ‰๋˜์ง€ ์•Š๊ณ ,\n * ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” \"๊ณผ๊ฑฐ๊ฐ€ ์—†๋Š” ๊ฒƒ\" ์œผ๋กœ ๋ณด์ธ๋‹ค(์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋น ์ง„ ๋ฐ์ดํ„ฐ).\n *\n * ์˜ˆ์ „์—๋Š” ๊ธฐ๋™ ํ›…์ด ๋งค๋ฒˆ ํ…Œ์ด๋ธ”์„ ์‚ดํŽด ์ฑ„์› ๋‹ค. ๊ทธ๊ฑด ๋‘ ๊ฐ€์ง€๋กœ ํ‹€๋ ธ๋‹ค โ€” ์ €๋„์ด ์ปค์งˆ์ˆ˜๋ก ๋ถ€ํŒ…์ด\n * ๋А๋ ค์ง€๊ณ , \"bizStep ์ด ๋น„์—ˆ์œผ๋ฉด ์˜› ํ–‰\" ์ด๋ผ๋Š” ์ „์ œ๋ฅผ ์ฝ”๋“œ์— ๊ณ ์ •ํ•ด ๊ทธ ์ „์ œ๊ฐ€ ๊นจ์ง€๋Š” ์ˆœ๊ฐ„\n * (๊ฐ์‚ฌ ํ–‰์ฒ˜๋Ÿผ ์—…๋ฌด ๋‹จ๊ณ„๊ฐ€ ์—†๋Š” ํ–‰) ๋งค ๋ถ€ํŒ…๋งˆ๋‹ค ํ—›๋Œ์•˜๋‹ค. ๊ทธ๋ž˜์„œ ๊ฑท์–ด๋ƒˆ๋‹ค(git: backfill-keys.ts).\n *\n * ์ฑ„์šฐ๋Š” ์ผ์€ **๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•œ ๋ฒˆ**์ด ๋งž๋‹ค(`yarn migration`). ๊ทธ ์ปฌ๋Ÿผ์— ๋งž๋Š” ๊ฒƒ์„ ๊ทธ๋•Œ ์“ด๋‹ค โ€”\n * ๋ฒ”์šฉ ์Šค์บ๋„ˆ๋ฅผ ๋˜์‚ด๋ฆฌ์ง€ ๋ง ๊ฒƒ. ๊ฐœ๋ฐœ ๋ฐ์ดํƒ€๋ผ๋ฉด ๊ทธ๋ƒฅ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ๋„ ๋‹ต์ด๋‹ค.\n */\n /**\n * ์ด ์‚ฌ์‹ค์„ ์ผ์œผํ‚จ **์ง€์‹œ** โ€” ์ปค๋„์ด ์ปค๋งจ๋“œ์—์„œ ์ด์–ด ์ค€ ์ƒ๊ด€๊ฐ’(๊ธฐ๋ณธ์€ commandId).\n *\n * ์ด๊ฒƒ์ด ๊ฐ์‚ฌ ๊ธฐ๋ก(TwinAuditEvent.commandId)๊ณผ ์ €๋„์„ ์ž‡๋Š” ์œ ์ผํ•œ ๋‹ค๋ฆฌ๋‹ค. ์—†์œผ๋ฉด ์Šน์ธ ๊ธฐ๋ก์€\n * \"์‚ฌ๋žŒ์ด ํ—ˆ๋ฝํ–ˆ๋‹ค\" ๊นŒ์ง€์ด๊ณ , ๊ทธ ๋’ค ๊ณต์žฅ์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์›€์ง์˜€๋Š”์ง€์™€ ์ด์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.\n *\n * **๋Œ€๋ถ€๋ถ„์˜ ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค** โ€” ์ปค๋งจ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹œ๋ฎฌ ์‹œ๊ฐ„์ด ๋‚ณ์€ ์‚ฌ์‹ค์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๊ฒƒ์ด ์ •์ƒ์ด๊ณ ,\n * ๋น„์–ด ์žˆ๋‹ค๊ณ  \"๋œ ์ฑ„์›Œ์ง„ ์˜› ํ–‰\" ์œผ๋กœ ๋ณด๋ฉด ์•ˆ ๋œ๋‹ค(๊ฐ™์€ ์˜คํ•ด๋ฅผ bizStep ์—์„œ ์ด๋ฏธ ํ•œ ๋ฒˆ ํ–ˆ๋‹ค).\n */\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Id of the command that caused this fact (kernel correlation id; defaults to the commandId). Empty for facts that simulation time produced rather than a command.' })\n correlationId?: string\n\n /* ์˜› ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค โ€” ์Šน๊ฒฉ ์ „์— ๊ธฐ๋ก๋œ ๊ฒƒ์ด๋ผ **๋ชจ๋ฅธ๋‹ค**(0 ์ด๋‚˜ OBSERVE ๋กœ ์œ„์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n @Column({ length: 16, nullable: true })\n @Field({ nullable: true, description: 'EPCIS action (ADD / OBSERVE / DELETE), promoted from the payload. Empty for operational deltas, and for rows journaled before this column existed.' })\n action?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Business step (CBV bizStep tail), promoted from the payload for indexed filtering.' })\n bizStep?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Item identifier (EPC / EPC class / parent id), promoted from the payload for indexed lookup of one item history.' })\n epc?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Business transaction identifier (PO / SO), promoted from the payload for indexed lookup of one order history.' })\n orderId?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Location identifier (read point, business location, or the plain location an operational delta carries), promoted from the payload for indexed filtering.' })\n locationId?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Equipment identifier carried by operational deltas, promoted from the payload so one machine history can be asked for on the server. The column keeps the legacy name `moverId`: the journal is append-only history and mixing two names for the same fact across time is worse than an outdated name. Renaming belongs with event-schema versioning.' })\n moverId?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Raw canonical envelope (EPCIS event or operational delta) as JSON.' })\n payload?: any\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Wall-clock timestamp when the record was persisted.' })\n createdAt?: Date\n}\n"]}
1
+ {"version":3,"file":"twin-event.js","sourceRoot":"","sources":["../../../server/service/twin-event/twin-event.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\n/*\n * TwinEvent โ€” append-only ํŠธ์œˆ ์ด๋ฒคํŠธ ์ €๋„(EPCIS ์ด๋ฒคํŠธ + ์šด์˜ ๋ธํƒ€).\n * ์ปค๋„ EventJournal ์˜ ์˜์† ๋Œ€์‘ โ€” ์ƒํƒœ=์ด๋ฒคํŠธ์—ด์˜ ํ•จ์ˆ˜(์žฌ๋ถ€ํŒ… ์‹œ DBโ†’replay ์žฌ๊ตฌ์„ฑ).\n * append-only ์ด๋ฏ€๋กœ updater/deletedAt ์—†์Œ(์ด๋ ฅ CRUD ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ถˆ๋ณ€ ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ).\n * payload ๋Š” simple-json(๋ฉ€ํ‹ฐDB ์ด์‹ โ€” postgres/mysql/sqlite/mssql/oracle ๊ณตํ†ต, DB-specific JSON ํƒ€์ž… ๊ธˆ์ง€).\n * (CLAUDE.md: ๋ชจ๋“  @ObjectType/@Field ๋Š” ์˜๋ฌธ description ํ•„์ˆ˜.)\n */\n/*\n * โ”€โ”€ ์ธ๋ฑ์Šค ์„ค๊ณ„ (2026-07-31) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ‘œ๋Š” **์ธ์ œ์ŠคํŠธ ๊ฒฝ๋กœ์˜ ๋œจ๊ฑฐ์šด append-only ํ…Œ์ด๋ธ”**์ด๋‹ค. ์ธ๋ฑ์Šค ํ•˜๋‚˜ํ•˜๋‚˜๊ฐ€ ์“ฐ๊ธฐ ์ฆํญ์ด๋ฏ€๋กœ\n * \"์žˆ์œผ๋ฉด ์ข‹์„\" ์ธ๋ฑ์Šค๋ฅผ ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ œ ์งˆ์˜ ํŒจํ„ด์— ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ๋งŒ ๋‘”๋‹ค.\n *\n * ix_0 (domain, instanceId, revision) ์›์žฅ ๊ธฐ๋ณธ ์ •๋ ฌยท์ปค์„œ ํŽ˜์ด์ง•ยทreplay(ASC ์ฃผ์‚ฌ)\n * ix_1 (domain, instanceId, eventTime) ์‹œ๊ฐ ์ปค์„œ(untilTime)ยท์‹œ๊ฐ„์ฐฝ KPI โ€” ๊ฑฐ์˜ ๋ชจ๋“  ์กฐํšŒ๊ฐ€ ํƒ„๋‹ค\n * ix_2 (domain, instanceId, eventType, revision) ํƒ€์ž… ํ•„ํ„ฐ + ์ •๋ ฌ ๋™์‹œ ์ถฉ์กฑ(์Šค์ผ€์ค„ ํ™”๋ฉด task/equipment)\n * ix_3 (domain, instanceId, epc) \"์ด ๋ฌผ๊ฑด์˜ ์ด๋ ฅ\" โ€” Entity360 ์˜ ๋ณธ์งˆ ์งˆ๋ฌธ\n * ix_4 (domain, instanceId, orderId) \"์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜\"\n * ix_9 (domain, instanceId, bizTransaction) \"์ด ๊ฑฐ๋ž˜์— ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜\" โ€” EPCISโ†”์˜ค๋”์˜ ๋‹ค๋ฆฌ\n *\n * bizStepยทlocationIdยทmoverId ๋Š” ์ปฌ๋Ÿผ๋งŒ ๋‘๊ณ  ์ธ๋ฑ์Šค๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ํ•œ ํŠธ์œˆ ์•ˆ์—์„œ ์นด๋””๋„๋ฆฌํ‹ฐ๊ฐ€\n * ๋‚ฎ์•„(์—…๋ฌด๋‹จ๊ณ„ ๋ช‡ ๊ฐœ, ์œ„์น˜ ์ˆ˜๋ฐฑ, ์„ค๋น„ ์ˆ˜์‹ญ) (domain,instanceId) ๋กœ ์ด๋ฏธ ์ขํ˜€์ง„ ๋’ค์˜ ์ž”์—ฌ ํ•„ํ„ฐ๋กœ\n * ์ถฉ๋ถ„ํ•˜๊ณ , ๋œจ๊ฑฐ์šด ํ‘œ์— ์ธ๋ฑ์Šค๋ฅผ ๋” ์–น์„ ๊ฐ€์น˜๊ฐ€ ์—†๋‹ค. ์ €๋„ ํ•˜๋‚˜๊ฐ€ ์•„์ฃผ ์ปค์ ธ์„œ ์ด ์ถ•๋“ค์˜ ์กฐํšŒ๊ฐ€\n * ๋А๋ ค์ง€๋ฉด ๊ทธ๋•Œ ์ธก์ •์„ ๊ทผ๊ฑฐ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ผ์ด์ง€, ์ง€๋ ˆ ์–น์–ด ์“ฐ๊ธฐ๋ฅผ ๋ฌด๊ฒ๊ฒŒ ํ•  ์ผ์€ ์•„๋‹ˆ๋‹ค.\n */\n@Entity()\n@Index('ix_twin_event_0', (e: TwinEvent) => [e.domain, e.instanceId, e.revision], { unique: false })\n@Index('ix_twin_event_1', (e: TwinEvent) => [e.domain, e.instanceId, e.eventTime], { unique: false })\n@Index('ix_twin_event_2', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.revision], { unique: false })\n@Index('ix_twin_event_3', (e: TwinEvent) => [e.domain, e.instanceId, e.epc], { unique: false })\n@Index('ix_twin_event_4', (e: TwinEvent) => [e.domain, e.instanceId, e.orderId], { unique: false })\n/* ix_5 โ€” \"์ด ์ง€์‹œ๊ฐ€ ๋ฌด์—‡์„ ์ผ์œผ์ผฐ๋‚˜\". ๊ฐ์‚ฌ ๊ธฐ๋ก์˜ commandId ๋กœ ์ €๋„์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋Š” ์ถ•. */\n@Index('ix_twin_event_5', (e: TwinEvent) => [e.domain, e.correlationId], { unique: false })\n/* ix_6 โ€” \"๋ฐ˜์ถœ์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๊ณ„์‚ฐํ–ˆ๋‚˜\". ์—†์œผ๋ฉด ๊ทธ ์งˆ๋ฌธ์ด ์ธ์Šคํ„ด์Šค ์ €๋„ ์ „๋Ÿ‰ ์ฃผ์‚ฌ๊ฐ€ ๋œ๋‹ค. */\n@Index('ix_twin_event_6', (e: TwinEvent) => [e.domain, e.instanceId, e.action], { unique: false })\n/*\n * ix_7 โ€” **\"์ด ์ข…๋ฅ˜์˜ ์‚ฌ์‹ค์„ ์‹œ๊ฐ์ˆœ์œผ๋กœ\"** (2026-08-25 ์‹ค์ธก์œผ๋กœ ์ถ”๊ฐ€)\n *\n * ์ด ์ถ•์ด ์—†์–ด์„œ ๊ณต์ • ํƒ€์ž„๋ผ์ธ์ด 22์ดˆ์˜€๋‹ค. ์ข…๋ฅ˜๋กœ ๊ฑฐ๋ฅด๊ณ  ์‹œ๊ฐ์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ์กฐํšŒ๊ฐ€ ๊ฐˆ ๊ณณ์ด ์—†์—ˆ๋‹ค:\n *\n * ix_2 (โ€ฆ, eventType, revision) ์ข…๋ฅ˜๋Š” ๊ฑธ๋Ÿฌ์ง€๊ณ  ์ •๋ ฌ์ด **์ ํžŒ ์ˆœ์„œ**๋‹ค โ†’ 4์›” ์‚ฌ์‹ค์„ ์ตœ๊ทผ์œผ๋กœ ๊ทธ๋ ธ๋‹ค\n * ix_1 (โ€ฆ, eventTime) ์ •๋ ฌ์€ ๋งž๊ณ  **์ข…๋ฅ˜๋ฅผ ๋ชป ๊ฑฐ๋ฅธ๋‹ค** โ†’ ํ–‰๋งˆ๋‹ค ํ…Œ์ด๋ธ”์„ ์—ด์–ด ํ™•์ธํ•œ๋‹ค\n *\n * ๋’ค์ชฝ์œผ๋กœ ๊ฑธ์œผ๋ฉด ๊ทธ ํŠธ์œˆ์—์„œ ์ฐพ๋Š” ์ข…๋ฅ˜๊ฐ€ ๋ฉˆ์ถ˜ ์‹œ์ ๊นŒ์ง€์˜ ๋ชจ๋“  ํ–‰์„ ์ฝ๊ณ  ๋ฒ„๋ฆฐ๋‹ค. ์Šนํ™”ํ‘ธ๋“œ์—์„œ ์ž‘์—…\n * ์‚ฌ์‹ค์€ 8์›” 22์ผ์— ๋ฉˆ์ถฐ ์žˆ๊ณ  ๊ทธ ๋’ค๋กœ ๋ฆฌ๋น„์ „์ด 110๋งŒ ๋Š˜์—ˆ์œผ๋ฏ€๋กœ, 200๊ฑด์— ๋‹ฟ๊ธฐ๊นŒ์ง€ 110๋งŒ ํ–‰์„ ์—ด์—ˆ๋‹ค.\n *\n * ์œ„ ์ฃผ์„์ด ใ€Œ์ธก์ •์„ ๊ทผ๊ฑฐ๋กœ ์ถ”๊ฐ€ํ•  ์ผ์ด์ง€ ์ง€๋ ˆ ์–น์„ ์ผ์€ ์•„๋‹ˆ๋‹คใ€๋ผ๊ณ  ์ ์–ด ๋‘์—ˆ๋‹ค. ๊ทธ ์ธก์ •์ด ๋‚˜์™”๋‹ค.\n */\n@Index('ix_twin_event_7', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.eventTime], { unique: false })\n/*\n * ix_8 โ€” **\"์ด ํŠธ์œˆ์˜ ์˜ค๋ž˜๋œ ๊ธฐ๋ก\"** (2026-08-27 ์‹ค์ธก์œผ๋กœ ์ถ”๊ฐ€)\n *\n * ๋ณด๊ด€ ๊ธฐ๊ฐ„ ์ •๋ฆฌ๊ฐ€ `created_at` ์œผ๋กœ ์ž๋ฅด๋Š”๋ฐ(๋ณด๊ด€์€ ์ €์žฅ ๋‚˜์ด์˜ ๋ฌธ์ œ๋‹ค) ๊ทธ ์ถ•์— ์ธ๋ฑ์Šค๊ฐ€ ์—†์—ˆ๋‹ค.\n * ๊ทธ๋ž˜์„œ ์ •๋ฆฌ๊ฐ€ ๋งค ๋ฐฐ์น˜๋งˆ๋‹ค ๊ทธ ํŠธ์œˆ์˜ ์ €๋„์„ ์ „๋Ÿ‰ ์ฃผ์‚ฌํ–ˆ๋‹ค.\n *\n * hatio-mx2 ์˜ 7์ผ ๋ฐ– ํ–‰์„ ์„ธ๊ธฐ 208์ดˆ โ† 1,029๋งŒ ํ–‰์„ ์ „๋ถ€ ์ฝ๋Š”๋‹ค(7์ผ ๋ฐ–์€ 2,446๊ฑด๋ฟ์ด๋‹ค)\n * revision ์œผ๋กœ ํ•œ ํ–‰ ์งš๊ธฐ 0.004์ดˆ\n *\n * ์ •๋ฆฌ๋Š” ํ•œ ์ฐฝ์— 2์ดˆ๋งŒ ์“ฐ๋„๋ก ์˜ˆ์‚ฐ์ด ๊ฑธ๋ ค ์žˆ์–ด์„œ, ๊ทธ 2์ดˆ๋ฅผ ์ฃผ์‚ฌ์— ๋‹ค ์“ฐ๊ณ  44๊ฑด๋งŒ ์ง€์šฐ๊ณ  ๋ฉˆ์ท„๋‹ค.\n */\n@Index('ix_twin_event_8', (e: TwinEvent) => [e.domain, e.instanceId, e.createdAt], { unique: false })\n/* ix_9 โ€” \"์ด ๊ฑฐ๋ž˜์— ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜\". EPCIS ์‚ฌ๊ฑด์—์„œ ์˜ค๋”๋กœ ๊ฑด๋„ˆ๊ฐ€๋Š” ๋‹ค๋ฆฌ(ยง`bizTransaction`). */\n@Index('ix_twin_event_9', (e: TwinEvent) => [e.domain, e.instanceId, e.bizTransaction], { unique: false })\n@ObjectType({ description: 'Append-only twin event journal record (EPCIS event or operational delta).' })\nexport class TwinEvent {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the event record.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinEvent) => e.domain)\n domainId?: string\n\n /*\n * ์ด ์‚ฌ์‹ค์„ ๋‚ธ ํŠธ์œˆ. **๋นŒ ์ˆ˜ ์—†๋‹ค** โ€” ์ €๋„ ํ–‰์„ ๋งŒ๋“œ๋Š” ๊ณณ์€ `journalRow` ํ•˜๋‚˜๋ฟ์ด๊ณ  ๊ฑฐ๊ธฐ์„œ\n * ํ•„์ˆ˜ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. nullable ๋กœ ๋‘๋ฉด ์ฝ๋Š” ์ชฝ์ด ๋งค๋ฒˆ `?? ''` ๋ฅผ ๋‹ฌ๊ฒŒ ๋˜๊ณ , ๊ทธ ๋ฐฉ์–ด๊ฐ€ ์‹ค์ œ๋กœ๋Š”\n * ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜๋А๋ผ \"๋นˆ ์ธ์Šคํ„ด์Šค์˜ ์ด๋ฒคํŠธ\" ๋ผ๋Š” ์—†๋Š” ๊ฐœ๋…์„ ์ฝ”๋“œ์— ๋‚จ๊ธด๋‹ค.\n */\n @Column()\n @Field({ description: 'Twin runtime instance id that emitted the event.' })\n instanceId: string\n\n /* ์ปค๋„ ๋ด‰ํˆฌ์˜ ํ•„์ˆ˜ ํ•„๋“œ(`CanonicalEnvelope.eventType`)๋ผ ๋นŒ ์ˆ˜ ์—†๋‹ค โ€” ๊ณ„์•ฝ์„ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด๋‹ค. */\n @Column()\n @Field({ description: 'Event type: epcis.* | task.status | equipment.status | order.status.' })\n eventType: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Monotonic state revision at which the event was emitted.' })\n revision?: number\n\n /**\n * ์ด ์‚ฌ์‹ค์ด **์–ด๋А ๊ณต์žฅ์—์„œ** ์ผ์–ด๋‚ฌ๋‚˜ โ€” `TwinStructure.rev`.\n *\n * ์ด๊ฒƒ์ด ์—†๋˜ ์‹œ์ ˆ์—๋Š” ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ €๋„์„ ํ†ต์งธ๋กœ ์ง€์šฐ๋Š” ๊ฒƒ์ด ์œ ์ผํ•œ ๊ธธ์ด์—ˆ๋‹ค(์•ˆ ์ง€์šฐ๋ฉด ์˜›\n * ์ด๋ฒคํŠธ๋ฅผ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ๊ณ„์‚ฐํ•ด ์ด๋ ฅ์ด ๊ฑฐ์ง“๋ง์„ ํ•œ๋‹ค). ์ด ํ•œ ์นธ์ด ์…‹์งธ ๊ธธ์„ ์—ฐ๋‹ค โ€” ์žฌ์ƒ์ด\n * ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ์ „ํ™˜ํ•œ ๋’ค ์ด์–ด์„œ ๊ณ„์‚ฐํ•œ๋‹ค.\n *\n * **๋น„์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค**: ์ปฌ๋Ÿผ์ด ์ƒ๊ธฐ๊ธฐ ์ „์— ์“ฐ์ธ ํ–‰์ด๋‹ค. ๊ทธ ํ–‰๋“ค์€ **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฆฌ๋น„์ „**์—\n * ์†ํ•œ๋‹ค(0 ์„ ์ฑ„์›Œ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค โ€” 0 ์€ \"๋ชจ๋ฆ„\" ์ด ์•„๋‹ˆ๋ผ ์œ ํšจํ•œ ๋ฒˆํ˜ธ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค).\n */\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Structure revision (TwinStructure.rev) in force when this event happened. Absent on rows written before structure revisions existed; those belong to the oldest revision.' })\n structureRev?: number\n\n /*\n * ์ด ์‚ฌ์‹ค์ด ์ผ์–ด๋‚œ ์‹œ๊ฐ(ํŠธ์œˆ์˜ ์‹œ๊ณ„). **๋‚ ์งœ ํƒ€์ž…์ด๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ฌธ์ž์—ด์ด์—ˆ๋‹ค. ์ฝ์„ ๋•Œ๋งˆ๋‹ค `Date.parse` ํ–ˆ๊ณ , ์ •๋ ฌ์€ UTC ISO ๋งŒ ๋“ค์–ด์˜จ๋‹ค๋Š” ์ „์ œ ์œ„์—์„œ\n * ์‚ฌ์ „์‹ ๋น„๊ต๊ฐ€ ์šฐ์—ฐํžˆ ๋งž์•˜๋‹ค โ€” `+09:00` ์˜คํ”„์…‹ ํ‘œ๊ธฐ๊ฐ€ ํ•˜๋‚˜ ์„ž์ด๋ฉด ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ˆœ์„œ๊ฐ€ ํ‹€๋ฆฐ๋‹ค.\n * ๊ทธ ์ „์ œ๋Š” ์ปฌ๋Ÿผ ์–ด๋””์—๋„ ์ ํ˜€ ์žˆ์ง€ ์•Š์•˜๋‹ค.\n *\n * **ํƒ€์ž… ์ด๋ฆ„์„ ์ ์ง€ ์•Š๋Š”๋‹ค** (2026-08-19 Postgres ๋ถ€ํŒ… ์‹คํŒจ๋กœ ๊ณ ์นจ).\n *\n * `datetime` ์„ ์ ์—ˆ๋”๋‹ˆ Postgres ๊ฐ€ ๋ถ€ํŒ… ์ค‘์— ๊ฑฐ์ ˆํ–ˆ๋‹ค(`DataTypeNotSupportedError`) โ€” ๊ทธ ์ด๋ฆ„์€\n * sqliteยทMySQL ์˜ ๊ฒƒ์ด๊ณ  Postgres ๋Š” `timestamp` ๋งŒ ์•ˆ๋‹ค. ๊ฑฐ๊พธ๋กœ `timestamp` ๋Š” sqlite ๊ฐ€ ๋ชจ๋ฅธ๋‹ค:\n * **๋‹ค์„ฏ ๋“œ๋ผ์ด๋ฒ„์— ๋‹ค ํ†ตํ•˜๋Š” ์ด๋ฆ„์ด ์•„์˜ˆ ์—†๋‹ค.**\n *\n * ๊ทธ๋ž˜์„œ ์ด๋ฆ„์„ ๊ณ ๋ฅด๋Š” ์ผ์„ TypeORM ์— ๋งก๊ธด๋‹ค. `emitDecoratorMetadata` ๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฏ€๋กœ ์ด ์†์„ฑ์˜\n * TS ํƒ€์ž…(`Date`)์—์„œ ๋“œ๋ผ์ด๋ฒ„๋ณ„ ํƒ€์ž…์„ ์Šค์Šค๋กœ ๊ณ ๋ฅธ๋‹ค(Postgres `timestamp` ยท sqliteยทMySQL `datetime`).\n * ์ด ๋ ˆํฌ์˜ ๋‹ค์ค‘ DB ๊ทœ์•ฝ์ด ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ๊ทธ๊ฒƒ์ด๋‹ค โ€” ๋“œ๋ผ์ด๋ฒ„ ๋ฐฉ์–ธ์„ ์ฝ”๋“œ์— ์ ์ง€ ์•Š๋Š”๋‹ค.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Time at which the fact happened on the twin clock.' })\n eventTime?: Date\n\n /*\n * โ”€โ”€ ์Šน๊ฒฉ๋œ ๊ฒ€์ƒ‰ ์ถ• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * payload ์•ˆ์— ์žˆ๋˜ ๊ฐ’์„ ์ธ์ œ์ŠคํŠธ ์‹œ์ ์— ๊บผ๋‚ด ์‹ค์ปฌ๋Ÿผ์œผ๋กœ ๋‘”๋‹ค(`twin-event-keys.ts` ๊ฐ€ ๋‹จ๋… ์†Œ์œ ).\n * payload ๊ฐ€ ์—ฌ์ „ํžˆ ์ •๋ณธ์ด๊ณ  ์ด๊ฒƒ๋“ค์€ **ํŒŒ์ƒ ์ƒ‰์ธ**์ด๋‹ค โ€” ์ƒˆ๋กœ์šด ์ง„์‹ค์ด ์•„๋‹ˆ๋ผ ์ฐพ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์žฅ์น˜.\n * simple-json(TEXT) ์•ˆ์˜ ๊ฐ’์€ 5๊ฐœ DB ๋“œ๋ผ์ด๋ฒ„ ๊ณตํ†ต์œผ๋กœ ๊ฑฐ๋ฅผ ๋ฐฉ๋ฒ•์ด ์—†์–ด์„œ(๋ฉ€ํ‹ฐDB ํ˜ธํ™˜ ๊ทœ์น™์ƒ\n * DB๋ณ„ JSON ์—ฐ์‚ฐ์ž ๊ธˆ์ง€) ์Šน๊ฒฉ ์™ธ์˜ ์„ ํƒ์ง€๊ฐ€ ์—†๋‹ค.\n * ๊ธธ์ด ์ƒํ•œ 255 ๋Š” GS1 ์‹๋ณ„์ž ๊ทœ๊ฒฉ ๋Œ€๋น„ ์ถฉ๋ถ„ํ•˜๋ฉฐ, ๋„˜์น˜๋Š” ๊ฐ’์€ ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ž˜๋ฆฌ์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค.\n *\n * โ”€โ”€ ์ถ•์„ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  ๋•Œ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ƒˆ ์Šน๊ฒฉ ์ปฌ๋Ÿผ์„ ๋งŒ๋“ค๋ฉด **์ด๋ฏธ ์Œ“์ธ ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค.** ๊ทธ ํ–‰๋“ค์€ ์ƒˆ ์ถ•์œผ๋กœ ๊ฒ€์ƒ‰๋˜์ง€ ์•Š๊ณ ,\n * ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” \"๊ณผ๊ฑฐ๊ฐ€ ์—†๋Š” ๊ฒƒ\" ์œผ๋กœ ๋ณด์ธ๋‹ค(์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋น ์ง„ ๋ฐ์ดํ„ฐ).\n *\n * ์˜ˆ์ „์—๋Š” ๊ธฐ๋™ ํ›…์ด ๋งค๋ฒˆ ํ…Œ์ด๋ธ”์„ ์‚ดํŽด ์ฑ„์› ๋‹ค. ๊ทธ๊ฑด ๋‘ ๊ฐ€์ง€๋กœ ํ‹€๋ ธ๋‹ค โ€” ์ €๋„์ด ์ปค์งˆ์ˆ˜๋ก ๋ถ€ํŒ…์ด\n * ๋А๋ ค์ง€๊ณ , \"bizStep ์ด ๋น„์—ˆ์œผ๋ฉด ์˜› ํ–‰\" ์ด๋ผ๋Š” ์ „์ œ๋ฅผ ์ฝ”๋“œ์— ๊ณ ์ •ํ•ด ๊ทธ ์ „์ œ๊ฐ€ ๊นจ์ง€๋Š” ์ˆœ๊ฐ„\n * (๊ฐ์‚ฌ ํ–‰์ฒ˜๋Ÿผ ์—…๋ฌด ๋‹จ๊ณ„๊ฐ€ ์—†๋Š” ํ–‰) ๋งค ๋ถ€ํŒ…๋งˆ๋‹ค ํ—›๋Œ์•˜๋‹ค. ๊ทธ๋ž˜์„œ ๊ฑท์–ด๋ƒˆ๋‹ค(git: backfill-keys.ts).\n *\n * ์ฑ„์šฐ๋Š” ์ผ์€ **๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•œ ๋ฒˆ**์ด ๋งž๋‹ค(`yarn migration`). ๊ทธ ์ปฌ๋Ÿผ์— ๋งž๋Š” ๊ฒƒ์„ ๊ทธ๋•Œ ์“ด๋‹ค โ€”\n * ๋ฒ”์šฉ ์Šค์บ๋„ˆ๋ฅผ ๋˜์‚ด๋ฆฌ์ง€ ๋ง ๊ฒƒ. ๊ฐœ๋ฐœ ๋ฐ์ดํƒ€๋ผ๋ฉด ๊ทธ๋ƒฅ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ๋„ ๋‹ต์ด๋‹ค.\n */\n /**\n * ์ด ์‚ฌ์‹ค์„ ์ผ์œผํ‚จ **์ง€์‹œ** โ€” ์ปค๋„์ด ์ปค๋งจ๋“œ์—์„œ ์ด์–ด ์ค€ ์ƒ๊ด€๊ฐ’(๊ธฐ๋ณธ์€ commandId).\n *\n * ์ด๊ฒƒ์ด ๊ฐ์‚ฌ ๊ธฐ๋ก(TwinAuditEvent.commandId)๊ณผ ์ €๋„์„ ์ž‡๋Š” ์œ ์ผํ•œ ๋‹ค๋ฆฌ๋‹ค. ์—†์œผ๋ฉด ์Šน์ธ ๊ธฐ๋ก์€\n * \"์‚ฌ๋žŒ์ด ํ—ˆ๋ฝํ–ˆ๋‹ค\" ๊นŒ์ง€์ด๊ณ , ๊ทธ ๋’ค ๊ณต์žฅ์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์›€์ง์˜€๋Š”์ง€์™€ ์ด์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.\n *\n * **๋Œ€๋ถ€๋ถ„์˜ ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค** โ€” ์ปค๋งจ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹œ๋ฎฌ ์‹œ๊ฐ„์ด ๋‚ณ์€ ์‚ฌ์‹ค์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๊ฒƒ์ด ์ •์ƒ์ด๊ณ ,\n * ๋น„์–ด ์žˆ๋‹ค๊ณ  \"๋œ ์ฑ„์›Œ์ง„ ์˜› ํ–‰\" ์œผ๋กœ ๋ณด๋ฉด ์•ˆ ๋œ๋‹ค(๊ฐ™์€ ์˜คํ•ด๋ฅผ bizStep ์—์„œ ์ด๋ฏธ ํ•œ ๋ฒˆ ํ–ˆ๋‹ค).\n */\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Id of the command that caused this fact (kernel correlation id; defaults to the commandId). Empty for facts that simulation time produced rather than a command.' })\n correlationId?: string\n\n /* ์˜› ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค โ€” ์Šน๊ฒฉ ์ „์— ๊ธฐ๋ก๋œ ๊ฒƒ์ด๋ผ **๋ชจ๋ฅธ๋‹ค**(0 ์ด๋‚˜ OBSERVE ๋กœ ์œ„์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n @Column({ length: 16, nullable: true })\n @Field({ nullable: true, description: 'EPCIS action (ADD / OBSERVE / DELETE), promoted from the payload. Empty for operational deltas, and for rows journaled before this column existed.' })\n action?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Business step (CBV bizStep tail), promoted from the payload for indexed filtering.' })\n bizStep?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Item identifier (EPC / EPC class / parent id), promoted from the payload for indexed lookup of one item history.' })\n epc?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Internal order identifier, promoted from the payload for indexed lookup of one order history.' })\n orderId?: string\n\n /*\n * **๊ฑฐ๋ž˜ ์‹๋ณ„์ž๋Š” ์˜ค๋” ์‹๋ณ„์ž์™€ ๋‹ค๋ฅธ ๊ฒƒ์ด๋‹ค.**\n *\n * ์ „์—๋Š” ๋‘˜์ด ํ•œ ์นธ(`orderId`)์— ๋“ค์–ด๊ฐ”๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ์˜ค๋”์˜ ์ด๋ ฅ์ด ์ƒ‰์ธ ์•ˆ์—์„œ ๋‘ ์ชฝ์œผ๋กœ\n * ๊ฐˆ๋ผ์กŒ๋‹ค โ€” ์šด์˜ ๋ธํƒ€๋Š” `order-1`, EPCIS ์‚ฌ๊ฑด์€ `urn:epc:id:gdti:โ€ฆ` ๋กœ ์ ํ˜€ ์–ด๋А ์ด๋ฆ„์œผ๋กœ\n * ๋ฌผ์–ด๋„ ์ ˆ๋ฐ˜๋งŒ ๋‚˜์™”๋‹ค(์‹ค์ธก 2026-09-05: ์–ดํœ˜๊ฐ€ ์„ž์ธ ํ–‰ 10,004๊ฐœ, ์˜ค๋ฅ˜๋Š” ๋‚˜์ง€ ์•Š์Œ).\n *\n * ์˜ค๋” ์‚ฌ๊ฑด์€ ๋‘ ๊ฐ’์„ ๋‹ค ๋“ค๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์นธ์ด **EPCIS ์‚ฌ๊ฑด์—์„œ ์˜ค๋”๋กœ ๊ฑด๋„ˆ๊ฐ€๋Š” ๋‹ค๋ฆฌ**๊ฐ€\n * ๋œ๋‹ค โ€” ใ€Œ์ด ๊ฐœ์ฒด๋ฅผ ์–ด๋А ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“ค์—ˆ๋‚˜ใ€๊ฐ€ ๊ทธ ๋‹ค๋ฆฌ๋กœ ๋‹ตํ•ด์ง„๋‹ค.\n */\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Business transaction identifier (PO / SO / production order), promoted from the payload for indexed lookup of one transaction.' })\n bizTransaction?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Location identifier (read point, business location, or the plain location an operational delta carries), promoted from the payload for indexed filtering.' })\n locationId?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Equipment identifier carried by operational deltas, promoted from the payload so one machine history can be asked for on the server. The column keeps the legacy name `moverId`: the journal is append-only history and mixing two names for the same fact across time is worse than an outdated name. Renaming belongs with event-schema versioning.' })\n moverId?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Raw canonical envelope (EPCIS event or operational delta) as JSON.' })\n payload?: any\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Wall-clock timestamp when the record was persisted.' })\n createdAt?: Date\n}\n"]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ์ง์ž‘ํ•˜์ง€ ์•Š๋Š” ๊ทœ์น™.
3
+ *
4
+ * order ์˜ค๋”๊ฐ€ ๋งํ–ˆ๋‹ค. ํŒ์ด ๋‘˜์ด๋“  ์—ด์ด๋“  ๊ทธ๊ฒƒ์„ ์“ด๋‹ค
5
+ * only-candidate ์˜ค๋”๋Š” ๋ง ์•ˆ ํ–ˆ์ง€๋งŒ ํ›„๋ณด๊ฐ€ ํ•˜๋‚˜๋‹ค โ€” ๊ณ ๋ฅผ ๊ฒƒ์ด ์—†์œผ๋ฉด ์ง์ž‘์ด ์•„๋‹ˆ๋‹ค
6
+ * ambiguous ํ›„๋ณด๊ฐ€ ๋‘˜ ์ด์ƒ์ธ๋ฐ ๋งํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ์—†๋‹ค โ†’ **๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค**
7
+ * said-but-undeclared ์˜ค๋”๋Š” ๋งํ–ˆ๋Š”๋ฐ ๊ทธ ๋ ˆ์‹œํ”ผ๊ฐ€ ์„ ์–ธ์— ์—†๋‹ค โ€” ๋ชจ๋ฅด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์–ด๊ธ‹๋‚œ ๊ฒƒ์ด๋‹ค
8
+ *
9
+ * ๋งˆ์ง€๋ง‰ ๋‘˜์„ ๊ฐ€๋ฅด๋Š” ์ด์œ : ์‚ฌ๋žŒ์ด ํ•  ์ผ์ด ๋‹ค๋ฅด๋‹ค. ์–ด๊ธ‹๋‚จ์€ ์„ ์–ธ์ด๋‚˜ ์›๋ณธ์„ ๊ณ ์น  ์ผ์ด๊ณ ,
10
+ * ๋ชจํ˜ธํ•จ์€ ๊ทธ ๊ฐœ์ฒด๊ฐ€ ์–ด๋А ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ๊ธฐ๋ก์ด ์—†๋Š” ์ผ์ด๋‹ค.
11
+ */
12
+ export declare function chooseRecipe(recipes: any[], candidates: any[], saidRecipeKey: string | undefined): {
13
+ recipe?: any;
14
+ basis: 'order' | 'only-candidate' | 'ambiguous' | 'said-but-undeclared' | 'none';
15
+ };
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.chooseRecipe = chooseRecipe;
4
+ /*
5
+ * **์–ด๋А ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“ค์—ˆ๋‚˜** โ€” ํŒ์ •๋งŒ. ์ˆœ์ˆ˜ํ•˜๋‹ค.
6
+ *
7
+ * โ”€โ”€ ์™œ ๋”ฐ๋กœ ์žˆ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
8
+ * ๊ณ„๋ณด ์งˆ์˜๋Š” TypeORM ๊ณผ shell ์„ ๋Œ์–ด์˜จ๋‹ค. ๊ทœ์น™๋งŒ ์žฌ๋ ค๋Š” ์‹œํ—˜์ด ๊ทธ๊ฒƒ๊นŒ์ง€ ๋“ค๊ณ  ์˜ค๋ฉด ๋ฌด๊ฒ๊ณ , ์ด
9
+ * ์ €์žฅ์†Œ์—์„œ ๊ทธ ์ด์œ ๋กœ ์‹œํ—˜์ด ์•ˆ ์„œ๋Š” ์ผ์„ ๊ฒช์—ˆ๋‹ค. ํŒ๋‹จ๊ณผ ๋ฐฐ์„ ์„ ๋‚˜๋ˆˆ๋‹ค โ€” ์—ฌ๊ธฐ๋Š” ๊ฐ’๋งŒ ๋ณด๊ณ  ๋‹ตํ•œ๋‹ค.
10
+ */
11
+ /**
12
+ * ์ง์ž‘ํ•˜์ง€ ์•Š๋Š” ๊ทœ์น™.
13
+ *
14
+ * order ์˜ค๋”๊ฐ€ ๋งํ–ˆ๋‹ค. ํŒ์ด ๋‘˜์ด๋“  ์—ด์ด๋“  ๊ทธ๊ฒƒ์„ ์“ด๋‹ค
15
+ * only-candidate ์˜ค๋”๋Š” ๋ง ์•ˆ ํ–ˆ์ง€๋งŒ ํ›„๋ณด๊ฐ€ ํ•˜๋‚˜๋‹ค โ€” ๊ณ ๋ฅผ ๊ฒƒ์ด ์—†์œผ๋ฉด ์ง์ž‘์ด ์•„๋‹ˆ๋‹ค
16
+ * ambiguous ํ›„๋ณด๊ฐ€ ๋‘˜ ์ด์ƒ์ธ๋ฐ ๋งํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ์—†๋‹ค โ†’ **๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค**
17
+ * said-but-undeclared ์˜ค๋”๋Š” ๋งํ–ˆ๋Š”๋ฐ ๊ทธ ๋ ˆ์‹œํ”ผ๊ฐ€ ์„ ์–ธ์— ์—†๋‹ค โ€” ๋ชจ๋ฅด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์–ด๊ธ‹๋‚œ ๊ฒƒ์ด๋‹ค
18
+ *
19
+ * ๋งˆ์ง€๋ง‰ ๋‘˜์„ ๊ฐ€๋ฅด๋Š” ์ด์œ : ์‚ฌ๋žŒ์ด ํ•  ์ผ์ด ๋‹ค๋ฅด๋‹ค. ์–ด๊ธ‹๋‚จ์€ ์„ ์–ธ์ด๋‚˜ ์›๋ณธ์„ ๊ณ ์น  ์ผ์ด๊ณ ,
20
+ * ๋ชจํ˜ธํ•จ์€ ๊ทธ ๊ฐœ์ฒด๊ฐ€ ์–ด๋А ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ๊ธฐ๋ก์ด ์—†๋Š” ์ผ์ด๋‹ค.
21
+ */
22
+ function chooseRecipe(recipes, candidates, saidRecipeKey) {
23
+ if (saidRecipeKey) {
24
+ const said = recipes.find((r) => r?.key === saidRecipeKey);
25
+ return said ? { recipe: said, basis: 'order' } : { basis: 'said-but-undeclared' };
26
+ }
27
+ if (candidates.length === 1)
28
+ return { recipe: candidates[0], basis: 'only-candidate' };
29
+ if (candidates.length > 1)
30
+ return { basis: 'ambiguous' };
31
+ return { basis: 'none' };
32
+ }
33
+ //# sourceMappingURL=choose-recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choose-recipe.js","sourceRoot":"","sources":["../../../server/service/twin-model/choose-recipe.ts"],"names":[],"mappings":";;AAkBA,oCAYC;AA9BD;;;;;;GAMG;AACH;;;;;;;;;;GAUG;AACH,SAAgB,YAAY,CAC1B,OAAc,EACd,UAAiB,EACjB,aAAiC;IAEjC,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,aAAa,CAAC,CAAA;QAC/D,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAA;IACnF,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACtF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAA;IACxD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAC1B,CAAC","sourcesContent":["/*\n * **์–ด๋А ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“ค์—ˆ๋‚˜** โ€” ํŒ์ •๋งŒ. ์ˆœ์ˆ˜ํ•˜๋‹ค.\n *\n * โ”€โ”€ ์™œ ๋”ฐ๋กœ ์žˆ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ณ„๋ณด ์งˆ์˜๋Š” TypeORM ๊ณผ shell ์„ ๋Œ์–ด์˜จ๋‹ค. ๊ทœ์น™๋งŒ ์žฌ๋ ค๋Š” ์‹œํ—˜์ด ๊ทธ๊ฒƒ๊นŒ์ง€ ๋“ค๊ณ  ์˜ค๋ฉด ๋ฌด๊ฒ๊ณ , ์ด\n * ์ €์žฅ์†Œ์—์„œ ๊ทธ ์ด์œ ๋กœ ์‹œํ—˜์ด ์•ˆ ์„œ๋Š” ์ผ์„ ๊ฒช์—ˆ๋‹ค. ํŒ๋‹จ๊ณผ ๋ฐฐ์„ ์„ ๋‚˜๋ˆˆ๋‹ค โ€” ์—ฌ๊ธฐ๋Š” ๊ฐ’๋งŒ ๋ณด๊ณ  ๋‹ตํ•œ๋‹ค.\n */\n/**\n * ์ง์ž‘ํ•˜์ง€ ์•Š๋Š” ๊ทœ์น™.\n *\n * order ์˜ค๋”๊ฐ€ ๋งํ–ˆ๋‹ค. ํŒ์ด ๋‘˜์ด๋“  ์—ด์ด๋“  ๊ทธ๊ฒƒ์„ ์“ด๋‹ค\n * only-candidate ์˜ค๋”๋Š” ๋ง ์•ˆ ํ–ˆ์ง€๋งŒ ํ›„๋ณด๊ฐ€ ํ•˜๋‚˜๋‹ค โ€” ๊ณ ๋ฅผ ๊ฒƒ์ด ์—†์œผ๋ฉด ์ง์ž‘์ด ์•„๋‹ˆ๋‹ค\n * ambiguous ํ›„๋ณด๊ฐ€ ๋‘˜ ์ด์ƒ์ธ๋ฐ ๋งํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ์—†๋‹ค โ†’ **๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค**\n * said-but-undeclared ์˜ค๋”๋Š” ๋งํ–ˆ๋Š”๋ฐ ๊ทธ ๋ ˆ์‹œํ”ผ๊ฐ€ ์„ ์–ธ์— ์—†๋‹ค โ€” ๋ชจ๋ฅด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์–ด๊ธ‹๋‚œ ๊ฒƒ์ด๋‹ค\n *\n * ๋งˆ์ง€๋ง‰ ๋‘˜์„ ๊ฐ€๋ฅด๋Š” ์ด์œ : ์‚ฌ๋žŒ์ด ํ•  ์ผ์ด ๋‹ค๋ฅด๋‹ค. ์–ด๊ธ‹๋‚จ์€ ์„ ์–ธ์ด๋‚˜ ์›๋ณธ์„ ๊ณ ์น  ์ผ์ด๊ณ ,\n * ๋ชจํ˜ธํ•จ์€ ๊ทธ ๊ฐœ์ฒด๊ฐ€ ์–ด๋А ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ๊ธฐ๋ก์ด ์—†๋Š” ์ผ์ด๋‹ค.\n */\nexport function chooseRecipe(\n recipes: any[],\n candidates: any[],\n saidRecipeKey: string | undefined\n): { recipe?: any; basis: 'order' | 'only-candidate' | 'ambiguous' | 'said-but-undeclared' | 'none' } {\n if (saidRecipeKey) {\n const said = recipes.find((r: any) => r?.key === saidRecipeKey)\n return said ? { recipe: said, basis: 'order' } : { basis: 'said-but-undeclared' }\n }\n if (candidates.length === 1) return { recipe: candidates[0], basis: 'only-candidate' }\n if (candidates.length > 1) return { basis: 'ambiguous' }\n return { basis: 'none' }\n}\n"]}
@@ -0,0 +1,76 @@
1
+ /** ๋ฐ–์— ์‚ฌ๋Š” ๋Œ€์ƒ ํ•˜๋‚˜ โ€” ํ™”๋ฉด์ด ์ด๋ฆ„์„ ๋ณด์ด๊ณ  ๊ฐˆ ๊ณณ์„ ์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ. */
2
+ export interface ExternalRef {
3
+ id: string;
4
+ /** ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์ด๋ฆ„. ์—†์œผ๋ฉด ํ™”๋ฉด์ด id ๋ฅผ ๋ณด์ธ๋‹ค(์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค). */
5
+ name?: string;
6
+ /**
7
+ * ๊ทธ ์ œํ’ˆ์—์„œ ์ด๊ฒƒ์„ ์—ด ์ˆ˜ ์žˆ๋Š” ์ž๋ฆฌ โ€” ์—†์œผ๋ฉด ํ™”๋ฉด์ด ๋งํฌ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
8
+ *
9
+ * ๋ง‰๋‹ค๋ฅธ ๋งํฌ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ด ์นธ์˜ ์š”์ ์ด๋‹ค. ๋ˆŒ๋Ÿฌ์„œ ์•„๋ฌด ์ผ๋„ ์•ˆ ์ผ์–ด๋‚˜๋ฉด ์‚ฌ๋žŒ์€ ๊ทธ๊ฒƒ์„
10
+ * ๊ฒฐํ•จ์œผ๋กœ ์ฝ๋Š”๋‹ค.
11
+ */
12
+ href?: string;
13
+ /** ๊ทธ id ๊ฐ€ ์‹ค์ œ๋กœ ์žˆ๋‚˜ โ€” **์—†์œผ๋ฉด ์—†๋‹ค๊ณ  ๋งํ•œ๋‹ค.** ๋‹ต์—์„œ ๋นผ์ง€ ์•Š๋Š”๋‹ค. */
14
+ missing?: boolean;
15
+ }
16
+ /**
17
+ * ๋ฐ–์—์„œ ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค โ€” ๋“ค์–ด์˜ค๋Š” ๊ด€๊ณ„ ํ•œ ๋ฌถ์Œ.
18
+ *
19
+ * `tense` ๋ฅผ **์ œํ’ˆ์ด ์„ ์–ธํ•œ๋‹ค**(๊ณ„์•ฝ์˜ `RelationTense`). ์‹ค์ ยท์ƒํƒœ ๊ตฌ๊ฐ„์€ ์ง€๋‚œ ์ผ์ด๊ณ  ์ •๋น„ ๊ณ„ํšยท
20
+ * ์ง€์‹œ๋Š” ์•ž์˜ ์ผ์ด๋‹ค โ€” ใ€Œ๊ฑธ๋ฆฐ ๊ฒƒ์ด ์—ดใ€์ด ๋‘ ๋œป์ด ๋˜๋Š” ์ž๋ฆฌ์ด๋ฏ€๋กœ ๋ฌถ์Œ์ด ์Šค์Šค๋กœ ๋งํ•ด์•ผ ํ•œ๋‹ค.
21
+ */
22
+ export interface ExternalIncoming {
23
+ /** ๊ด€๊ณ„์˜ ์ด๋ฆ„(i18n ํ‚ค) โ€” ๊ณ„์•ฝ์˜ `via` ์™€ ๊ฐ™์€ ๊ทœ์น™. ์ œํ’ˆ์€ ์ž๊ธฐ ์ ‘๋‘๋ฅผ ์“ด๋‹ค. */
24
+ via: string;
25
+ /** ์–ด๋””์„œ ์˜ค๋‚˜ โ€” ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์ถ• ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ ๊ทธ ์ œํ’ˆ์˜ ์ถ• ํ‚ค๋‹ค. */
26
+ from: string;
27
+ /** ์–ธ์ œ์˜ ์ผ์ธ๊ฐ€. ์•ˆ ์ฃผ๋ฉด ใ€Œ์„ ์–ธ์ด ๋งํ•˜์ง€ ์•Š์•˜๋‹คใ€๋‹ค โ€” `standing` ์œผ๋กœ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. */
28
+ tense?: 'past' | 'future' | 'standing';
29
+ ids: string[];
30
+ /** ์ „์ฒด ์ˆ˜ โ€” `ids` ๊ฐ€ ์ž˜๋ ธ์–ด๋„ ๋ช‡์ธ์ง€ ๋งํ•œ๋‹ค. */
31
+ total: number;
32
+ }
33
+ /**
34
+ * ํ•œ external ๋Œ€์ƒ์„ ํ‘ธ๋Š” ์ œํ’ˆ ์ชฝ ๊ตฌํ˜„.
35
+ *
36
+ * ๋‘˜ ๋‹ค ์„ ํƒ์ด๋‹ค. ์ด๋ฆ„๋งŒ ๋Œ€ ์ค„ ์ˆ˜ ์žˆ๋Š” ์ œํ’ˆ๊ณผ ๋“ค์–ด์˜ค๋Š” ๊ด€๊ณ„๋งŒ ๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ œํ’ˆ์ด ๋‹ค ์žˆ๋‹ค โ€” ํ•˜๋‚˜๋งŒ
37
+ * ๊ฝ‚์•„๋„ ๊ทธ๋งŒํผ์€ ๋‹ตํ•ด์ง„๋‹ค.
38
+ */
39
+ export interface ExternalResolver {
40
+ /** ๊ณ„์•ฝ์˜ `target.entity` ์™€ **๊ฐ™์€ ๋‚ฑ๋ง**. ๋‹ค๋ฅด๋ฉด ์•„๋ฌด ๊ด€๊ณ„์—๋„ ์•ˆ ๋ถ™๋Š”๋‹ค. */
41
+ entity: string;
42
+ /** ์ด id ๋“ค์ด ๋ฌด์—‡์ธ๊ฐ€. */
43
+ resolve?(domainId: string, ids: readonly string[]): Promise<ExternalRef[]>;
44
+ /** ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค. */
45
+ incoming?(domainId: string, instanceId: string, axis: string, itemId: string): Promise<ExternalIncoming[]>;
46
+ }
47
+ /**
48
+ * ํ•ด์†Œ๊ธฐ๋ฅผ ๊ฝ‚๋Š”๋‹ค โ€” **๋ถ€ํŒ…์—์„œ ํ•œ ๋ฒˆ.**
49
+ *
50
+ * ๊ฐ™์€ `entity` ๋ฅผ ๋‘ ๋ฒˆ ๊ฝ‚์œผ๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์ด๊ธด๋‹ค. ๊ทธ๊ฒƒ์ด ๊ฐœ๋ฐœ ์ค‘ ์žฌ์ ์žฌ์˜ ์ •์ƒ ๋™์ž‘์ด๊ณ , ์šด์˜์—์„œ
51
+ * ์ผ์–ด๋‚˜๋ฉด ๋‘ ์ œํ’ˆ์ด ๊ฐ™์€ ๋Œ€์ƒ์„ ์ž๊ธฐ ๊ฒƒ์ด๋ผ ๋งํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ **๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค** โ€” ์กฐ์šฉํžˆ ๋ฎ์œผ๋ฉด
52
+ * ์–ด๋А ์ชฝ์ด ๋‹ตํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.
53
+ */
54
+ export declare function registerExternalResolver(r: ExternalResolver, warn?: (msg: string) => void): void;
55
+ /** ์ง€๊ธˆ ๊ฝ‚ํ˜€ ์žˆ๋Š” ๊ฒƒ๋“ค โ€” ใ€Œ๋ฌด์—‡์„ ํ’€ ์ˆ˜ ์žˆ๋‚˜ใ€๋ฅผ ๋ฐ–์—์„œ ์žด ์ˆ˜ ์žˆ๊ฒŒ. */
56
+ export declare function externalResolverEntities(): string[];
57
+ /** ์‹œํ—˜์ด ์žฌ๊ธฐ๋™์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ฒŒ. */
58
+ export declare function clearExternalResolvers(): void;
59
+ /**
60
+ * ๊ทธ id ๋“ค์„ ํ‘ผ๋‹ค โ€” **๋ชป ํ’€๋ฉด ๋ชป ํ‘ผ๋‹ค๊ณ  ๋งํ•œ๋‹ค.**
61
+ *
62
+ * ํ•ด์†Œ๊ธฐ๊ฐ€ ํ„ฐ์ ธ๋„ 360 ์ „์ฒด๋ฅผ ์ฃฝ์ด์ง€ ์•Š๋Š”๋‹ค. ํ•œ ๊ด€๊ณ„๊ฐ€ ๋‹ต์„ ๋ชป ํ•˜๋Š” ๊ฒƒ๊ณผ ํ™”๋ฉด์ด ์•ˆ ๋œจ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ
63
+ * ์‚ฌ๊ณ ์ด๊ณ , ๋’ค์—ฃ๊ฒƒ์ด ํ›จ์”ฌ ๋‚˜์˜๋‹ค.
64
+ */
65
+ export declare function resolveExternal(entity: string, domainId: string, ids: readonly string[], warn?: (msg: string) => void): Promise<{
66
+ refs?: ExternalRef[];
67
+ unresolved?: 'no-resolver' | 'failed';
68
+ }>;
69
+ /**
70
+ * ๋ฐ–์—์„œ ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค์„ ๋ชจ์€๋‹ค.
71
+ *
72
+ * ๊ฝ‚ํžŒ ๊ฒƒ์ด ์—†์œผ๋ฉด **๋นˆ ๋ฐฐ์—ด์ด์ง€ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋‹ค** โ€” ๋ฐ–์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด ์—†๋Š” ๋Œ€์ƒ์ด ์ •์ƒ์ด๋‹ค.
73
+ * ๋‹ค๋งŒ ใ€Œํ•ด์†Œ๊ธฐ๊ฐ€ ์—†์–ด์„œ ๋ชจ๋ฅธ๋‹คใ€์™€ ใ€Œ์—†๋‹คใ€๋Š” ๋‹ค๋ฅด๋ฏ€๋กœ, ๊ทธ ๊ตฌ๋ณ„์€ `externalResolverEntities()` ๋กœ
74
+ * ๋ฐ–์—์„œ ์žฐ๋‹ค.
75
+ */
76
+ export declare function externalIncoming(domainId: string, instanceId: string, axis: string, itemId: string, warn?: (msg: string) => void): Promise<ExternalIncoming[]>;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ /*
3
+ * **board ๋ฐ–์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ด€๊ณ„๋ฅผ ํ‘ธ๋Š” ์ž๋ฆฌ** โ€” ์„ ์–ธ์€ ์žˆ๊ณ  ์ฝ”๋“œ๊ฐ€ 0๊ณณ์ด๋˜ ์ด์Œ์ƒˆ.
4
+ *
5
+ * โ”€โ”€ ๋ฌด์—‡์ด ์žˆ์—ˆ๋‚˜ (2026-09-05 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
6
+ * ๊ณ„์•ฝ์ด `target: { kind: 'external', entity: โ€ฆ }` ๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ฃผ์„์— ใ€Œํ•ด์†Œ๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€ ํ•œ๋‹คใ€๊ณ 
7
+ * ์ ์–ด ๋‘์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ **`headless-twin/server` ์–ด๋””์—๋„ `kind === 'external'` ์„ ๋‹ค๋ฃจ๋Š” ์ฝ”๋“œ๊ฐ€
8
+ * ์—†์—ˆ๋‹ค**(0๊ณณ).
9
+ *
10
+ * `space.area` ๊ฐ€ ๋„๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ ์ด์œ ๋Š” ์ด์Œ์ƒˆ๊ฐ€ ์žˆ์–ด์„œ๊ฐ€ ์•„๋‹ˆ๋ผ **ํ˜ธ์ŠคํŠธ์—์„œ ๊ทธ๊ฒƒ์ด ํ‰๋ฒ”ํ•œ FK
11
+ * ๋ผ์„œ**๋‹ค. TypeORM ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ์—ฐํžˆ ๋‹ตํ•ด ์ค€ ๊ฒƒ์ด์ง€ ์„ ์–ธ์ด ๊ธธ์„ ๋‚ธ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.
12
+ *
13
+ * โ”€โ”€ ์™œ ์ง€๊ธˆ ์ฑ„์šฐ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
14
+ * ์•„์นจ์—๋Š” ใ€Œ์•„๋ฌด๋„ ์•ˆ ๋ง‰ํ˜”์œผ๋‹ˆ ๊ธ‰ํ•˜์ง€ ์•Š๋‹คใ€๋กœ ์ ์—ˆ๋‹ค. **๊ทธ ํŒ๋‹จ์ด ๊ทœ๋ชจ๋ฅผ ์ž‘๊ฒŒ ์žก์€ ๊ฒƒ์ด์—ˆ๋‹ค.**
15
+ *
16
+ * 360(ํ•œ ๋Œ€์ƒ์— ๊ฑธ๋ฆฐ ๊ฒƒ์„ ํ•œ์ž๋ฆฌ์—)์˜ ์†Œ๋น„์ฒ˜๋Š” ๋ฌดํ•œํžˆ ๋Š˜์–ด๋‚œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ฐ ์ œํ’ˆ์˜ ์ž๊ธฐ ์ €์žฅ์†Œ๊ฐ€
17
+ * ๊ด€๊ณ„์˜ ์›์ฒœ์ด ๋œ๋‹ค โ€” MES ์˜ ์‹ค์ ยท์ƒํƒœ ๊ตฌ๊ฐ„ยท์ •๋น„ ๊ณ„ํš์ด ๊ทธ๋ ‡๊ณ , ๋‹ค์Œ ์ œํ’ˆ๋„ ๊ทธ๋Ÿด ๊ฒƒ์ด๋‹ค.
18
+ *
19
+ * ๊ทธ๋•Œ **์„ ์–ธ์€ ใ€Œ๋ฐ–์„ ๊ฐ€๋ฆฌํ‚จ๋‹คใ€๊ณ  ๋งํ•˜๋Š”๋ฐ ํ‘ธ๋Š” ๊ธธ์ด ์—†์œผ๋ฉด ์ œํ’ˆ๋งˆ๋‹ค ์ž๊ธฐ ๊ธธ์„ ๋‚ธ๋‹ค.** ๊ทธ๊ฒƒ์ด
20
+ * ์ •ํ™•ํžˆ ใ€Œ๋ฌดํ•œํžˆ ๊ฐˆ๋ฆฐ๋‹คใ€๋‹ค. ์ด ํŒŒ์ผ์ด ๊ทธ ๊ฐˆ๋ฆผ์„ ๋ง‰๋Š”๋‹ค.
21
+ *
22
+ * โ”€โ”€ ์ปค๋„์€ ์–ด๋А ํ‘œ์ธ์ง€ ๋ชจ๋ฅธ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
23
+ * ๊ณ„์•ฝ์€ ใ€Œ์ด ์ถ•์ด ๋ฐ–์„ ๊ฐ€๋ฆฌํ‚จ๋‹คใ€๊นŒ์ง€๋งŒ ์•ˆ๋‹ค. **ใ€Œ์–ด๋А ํ‘œ์˜ ์–ด๋А ์นธใ€์€ ์ œํ’ˆ์ด ์•ˆ๋‹ค.** ๊ทธ๋ž˜์„œ ์ œํ’ˆ์ด
24
+ * ๋ถ€ํŒ…์—์„œ ํ•ด์†Œ๊ธฐ๋ฅผ ๊ฝ‚๋Š”๋‹ค โ€” ์žฅ๋ถ€ ๊ธฐ๋ก๊ธฐ(`installIngestWindowWriter`)์™€ ๊ฐ™์€ ๊ทœ์œจ์ด๋‹ค.
25
+ *
26
+ * ์ปค๋„์ด ํ‘œ ์ด๋ฆ„์„ ์•Œ๊ฒŒ ๋˜๋ฉด ํ•œ ์ œํ’ˆ์˜ ์ €์žฅ ๊ตฌ์กฐ์— ๋งค์ด๊ณ , ๋‹ค์Œ ์ œํ’ˆ์ด ๋‹ค๋ฅธ ํ‘œ๋ฅผ ์“ฐ๋ฉด ์ปค๋„์„ ๋˜
27
+ * ๊ณ ์ณ์•ผ ํ•œ๋‹ค.
28
+ *
29
+ * โ”€โ”€ ์—†๋Š” ๊ฒƒ์„ ์ˆจ๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
30
+ * ํ•ด์†Œ๊ธฐ๊ฐ€ ์—†์œผ๋ฉด **๊ทธ ์‚ฌ์‹ค์„ ๋‚ธ๋‹ค**(`unresolved`). ๋งํฌ๋ฅผ ์ง€์šฐ๋ฉด ํ™”๋ฉด์€ ใ€Œ๊ทธ๋Ÿฐ ๊ด€๊ณ„๊ฐ€ ์—†๋‹คใ€๋กœ
31
+ * ์ฝ๊ณ , ์‹ค์ œ๋กœ๋Š” ใ€Œ์•„๋ฌด๋„ ๋‹ตํ•  ์ˆ˜ ์—†๋‹คใ€๋‹ค. ๊ทธ ๋‘˜์€ ์‚ฌ๋žŒ์ด ํ•  ์ผ์ด ๋‹ค๋ฅด๋‹ค.
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.registerExternalResolver = registerExternalResolver;
35
+ exports.externalResolverEntities = externalResolverEntities;
36
+ exports.clearExternalResolvers = clearExternalResolvers;
37
+ exports.resolveExternal = resolveExternal;
38
+ exports.externalIncoming = externalIncoming;
39
+ const resolvers = new Map();
40
+ /**
41
+ * ํ•ด์†Œ๊ธฐ๋ฅผ ๊ฝ‚๋Š”๋‹ค โ€” **๋ถ€ํŒ…์—์„œ ํ•œ ๋ฒˆ.**
42
+ *
43
+ * ๊ฐ™์€ `entity` ๋ฅผ ๋‘ ๋ฒˆ ๊ฝ‚์œผ๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์ด๊ธด๋‹ค. ๊ทธ๊ฒƒ์ด ๊ฐœ๋ฐœ ์ค‘ ์žฌ์ ์žฌ์˜ ์ •์ƒ ๋™์ž‘์ด๊ณ , ์šด์˜์—์„œ
44
+ * ์ผ์–ด๋‚˜๋ฉด ๋‘ ์ œํ’ˆ์ด ๊ฐ™์€ ๋Œ€์ƒ์„ ์ž๊ธฐ ๊ฒƒ์ด๋ผ ๋งํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ **๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค** โ€” ์กฐ์šฉํžˆ ๋ฎ์œผ๋ฉด
45
+ * ์–ด๋А ์ชฝ์ด ๋‹ตํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.
46
+ */
47
+ function registerExternalResolver(r, warn) {
48
+ const entity = String(r?.entity ?? '').trim();
49
+ if (!entity) {
50
+ warn?.('[external-resolver] entity ์—†๋Š” ํ•ด์†Œ๊ธฐ๋Š” ๊ฝ‚์ง€ ์•Š๋Š”๋‹ค โ€” ์•„๋ฌด ๊ด€๊ณ„์—๋„ ์•ˆ ๋ถ™๋Š”๋‹ค');
51
+ return;
52
+ }
53
+ if (resolvers.has(entity)) {
54
+ warn?.(`[external-resolver] '${entity}' ํ•ด์†Œ๊ธฐ๋ฅผ ๋ฎ์–ด์“ด๋‹ค โ€” ๋‘ ์ œํ’ˆ์ด ๊ฐ™์€ ๋Œ€์ƒ์„ ๋‹ตํ•˜๋ ค ํ•˜๋ฉด ๊ทธ์ค‘ ํ•˜๋‚˜๋งŒ ๋‹ตํ•œ๋‹ค`);
55
+ }
56
+ resolvers.set(entity, { ...r, entity });
57
+ }
58
+ /** ์ง€๊ธˆ ๊ฝ‚ํ˜€ ์žˆ๋Š” ๊ฒƒ๋“ค โ€” ใ€Œ๋ฌด์—‡์„ ํ’€ ์ˆ˜ ์žˆ๋‚˜ใ€๋ฅผ ๋ฐ–์—์„œ ์žด ์ˆ˜ ์žˆ๊ฒŒ. */
59
+ function externalResolverEntities() {
60
+ return [...resolvers.keys()].sort();
61
+ }
62
+ /** ์‹œํ—˜์ด ์žฌ๊ธฐ๋™์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ฒŒ. */
63
+ function clearExternalResolvers() {
64
+ resolvers.clear();
65
+ }
66
+ /**
67
+ * ๊ทธ id ๋“ค์„ ํ‘ผ๋‹ค โ€” **๋ชป ํ’€๋ฉด ๋ชป ํ‘ผ๋‹ค๊ณ  ๋งํ•œ๋‹ค.**
68
+ *
69
+ * ํ•ด์†Œ๊ธฐ๊ฐ€ ํ„ฐ์ ธ๋„ 360 ์ „์ฒด๋ฅผ ์ฃฝ์ด์ง€ ์•Š๋Š”๋‹ค. ํ•œ ๊ด€๊ณ„๊ฐ€ ๋‹ต์„ ๋ชป ํ•˜๋Š” ๊ฒƒ๊ณผ ํ™”๋ฉด์ด ์•ˆ ๋œจ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ
70
+ * ์‚ฌ๊ณ ์ด๊ณ , ๋’ค์—ฃ๊ฒƒ์ด ํ›จ์”ฌ ๋‚˜์˜๋‹ค.
71
+ */
72
+ async function resolveExternal(entity, domainId, ids, warn) {
73
+ const r = resolvers.get(entity);
74
+ if (!r?.resolve)
75
+ return { unresolved: 'no-resolver' };
76
+ try {
77
+ return { refs: await r.resolve(domainId, ids) };
78
+ }
79
+ catch (e) {
80
+ warn?.(`[external-resolver] '${entity}' ํ•ด์†Œ๊ฐ€ ์‹คํŒจํ–ˆ๋‹ค โ€” ${String(e?.message ?? e)}`);
81
+ return { unresolved: 'failed' };
82
+ }
83
+ }
84
+ /**
85
+ * ๋ฐ–์—์„œ ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค์„ ๋ชจ์€๋‹ค.
86
+ *
87
+ * ๊ฝ‚ํžŒ ๊ฒƒ์ด ์—†์œผ๋ฉด **๋นˆ ๋ฐฐ์—ด์ด์ง€ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋‹ค** โ€” ๋ฐ–์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด ์—†๋Š” ๋Œ€์ƒ์ด ์ •์ƒ์ด๋‹ค.
88
+ * ๋‹ค๋งŒ ใ€Œํ•ด์†Œ๊ธฐ๊ฐ€ ์—†์–ด์„œ ๋ชจ๋ฅธ๋‹คใ€์™€ ใ€Œ์—†๋‹คใ€๋Š” ๋‹ค๋ฅด๋ฏ€๋กœ, ๊ทธ ๊ตฌ๋ณ„์€ `externalResolverEntities()` ๋กœ
89
+ * ๋ฐ–์—์„œ ์žฐ๋‹ค.
90
+ */
91
+ async function externalIncoming(domainId, instanceId, axis, itemId, warn) {
92
+ const out = [];
93
+ for (const r of resolvers.values()) {
94
+ if (!r.incoming)
95
+ continue;
96
+ try {
97
+ const got = await r.incoming(domainId, instanceId, axis, itemId);
98
+ /* ๋นˆ ๋ฌถ์Œ์€ ์‹ฃ์ง€ ์•Š๋Š”๋‹ค โ€” ์—ฌ๊ธฐ์„œ๋Š” ใ€Œ๊ทธ ์ œํ’ˆ์ด ์ด ์ถ•์„ ์•ˆ ๋ณธ๋‹คใ€๋Š” ๋œป์ด๊ณ  ํ•  ๋ง์ด ์—†๋‹ค. */
99
+ for (const g of got ?? [])
100
+ if (g && g.total > 0)
101
+ out.push(g);
102
+ }
103
+ catch (e) {
104
+ warn?.(`[external-resolver] '${r.entity}' ์˜ ๋“ค์–ด์˜ค๋Š” ๊ด€๊ณ„ ์กฐํšŒ๊ฐ€ ์‹คํŒจํ–ˆ๋‹ค โ€” ${String(e?.message ?? e)}`);
105
+ }
106
+ }
107
+ return out;
108
+ }
109
+ //# sourceMappingURL=external-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-resolver.js","sourceRoot":"","sources":["../../../server/service/twin-model/external-resolver.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;AA4DH,4DAUC;AAGD,4DAEC;AAGD,wDAEC;AAQD,0CAcC;AASD,4CAmBC;AA/ED,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAA;AAErD;;;;;;GAMG;AACH,SAAgB,wBAAwB,CAAC,CAAmB,EAAE,IAA4B;IACxF,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,EAAE,CAAC,2DAA2D,CAAC,CAAA;QACnE,OAAM;IACR,CAAC;IACD,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,IAAI,EAAE,CAAC,wBAAwB,MAAM,8CAA8C,CAAC,CAAA;IACtF,CAAC;IACD,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;AACzC,CAAC;AAED,8CAA8C;AAC9C,SAAgB,wBAAwB;IACtC,OAAO,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;AACrC,CAAC;AAED,wBAAwB;AACxB,SAAgB,sBAAsB;IACpC,SAAS,CAAC,KAAK,EAAE,CAAA;AACnB,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,QAAgB,EAChB,GAAsB,EACtB,IAA4B;IAE5B,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,CAAC,EAAE,OAAO;QAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,CAAA;IACrD,IAAI,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAA;IACjD,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAI,EAAE,CAAC,wBAAwB,MAAM,gBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,CAAA;QAC/E,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAA;IACjC,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,UAAkB,EAClB,IAAY,EACZ,MAAc,EACd,IAA4B;IAE5B,MAAM,GAAG,GAAuB,EAAE,CAAA;IAClC,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,CAAC,QAAQ;YAAE,SAAQ;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;YAChE,yDAAyD;YACzD,KAAK,MAAM,CAAC,IAAI,GAAG,IAAI,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC9D,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,IAAI,EAAE,CAAC,wBAAwB,CAAC,CAAC,MAAM,0BAA0B,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,CAAA;QAC7F,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/*\n * **board ๋ฐ–์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ด€๊ณ„๋ฅผ ํ‘ธ๋Š” ์ž๋ฆฌ** โ€” ์„ ์–ธ์€ ์žˆ๊ณ  ์ฝ”๋“œ๊ฐ€ 0๊ณณ์ด๋˜ ์ด์Œ์ƒˆ.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ์žˆ์—ˆ๋‚˜ (2026-09-05 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ณ„์•ฝ์ด `target: { kind: 'external', entity: โ€ฆ }` ๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ฃผ์„์— ใ€Œํ•ด์†Œ๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€ ํ•œ๋‹คใ€๊ณ \n * ์ ์–ด ๋‘์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ **`headless-twin/server` ์–ด๋””์—๋„ `kind === 'external'` ์„ ๋‹ค๋ฃจ๋Š” ์ฝ”๋“œ๊ฐ€\n * ์—†์—ˆ๋‹ค**(0๊ณณ).\n *\n * `space.area` ๊ฐ€ ๋„๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ ์ด์œ ๋Š” ์ด์Œ์ƒˆ๊ฐ€ ์žˆ์–ด์„œ๊ฐ€ ์•„๋‹ˆ๋ผ **ํ˜ธ์ŠคํŠธ์—์„œ ๊ทธ๊ฒƒ์ด ํ‰๋ฒ”ํ•œ FK\n * ๋ผ์„œ**๋‹ค. TypeORM ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ์—ฐํžˆ ๋‹ตํ•ด ์ค€ ๊ฒƒ์ด์ง€ ์„ ์–ธ์ด ๊ธธ์„ ๋‚ธ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.\n *\n * โ”€โ”€ ์™œ ์ง€๊ธˆ ์ฑ„์šฐ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์•„์นจ์—๋Š” ใ€Œ์•„๋ฌด๋„ ์•ˆ ๋ง‰ํ˜”์œผ๋‹ˆ ๊ธ‰ํ•˜์ง€ ์•Š๋‹คใ€๋กœ ์ ์—ˆ๋‹ค. **๊ทธ ํŒ๋‹จ์ด ๊ทœ๋ชจ๋ฅผ ์ž‘๊ฒŒ ์žก์€ ๊ฒƒ์ด์—ˆ๋‹ค.**\n *\n * 360(ํ•œ ๋Œ€์ƒ์— ๊ฑธ๋ฆฐ ๊ฒƒ์„ ํ•œ์ž๋ฆฌ์—)์˜ ์†Œ๋น„์ฒ˜๋Š” ๋ฌดํ•œํžˆ ๋Š˜์–ด๋‚œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ฐ ์ œํ’ˆ์˜ ์ž๊ธฐ ์ €์žฅ์†Œ๊ฐ€\n * ๊ด€๊ณ„์˜ ์›์ฒœ์ด ๋œ๋‹ค โ€” MES ์˜ ์‹ค์ ยท์ƒํƒœ ๊ตฌ๊ฐ„ยท์ •๋น„ ๊ณ„ํš์ด ๊ทธ๋ ‡๊ณ , ๋‹ค์Œ ์ œํ’ˆ๋„ ๊ทธ๋Ÿด ๊ฒƒ์ด๋‹ค.\n *\n * ๊ทธ๋•Œ **์„ ์–ธ์€ ใ€Œ๋ฐ–์„ ๊ฐ€๋ฆฌํ‚จ๋‹คใ€๊ณ  ๋งํ•˜๋Š”๋ฐ ํ‘ธ๋Š” ๊ธธ์ด ์—†์œผ๋ฉด ์ œํ’ˆ๋งˆ๋‹ค ์ž๊ธฐ ๊ธธ์„ ๋‚ธ๋‹ค.** ๊ทธ๊ฒƒ์ด\n * ์ •ํ™•ํžˆ ใ€Œ๋ฌดํ•œํžˆ ๊ฐˆ๋ฆฐ๋‹คใ€๋‹ค. ์ด ํŒŒ์ผ์ด ๊ทธ ๊ฐˆ๋ฆผ์„ ๋ง‰๋Š”๋‹ค.\n *\n * โ”€โ”€ ์ปค๋„์€ ์–ด๋А ํ‘œ์ธ์ง€ ๋ชจ๋ฅธ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ณ„์•ฝ์€ ใ€Œ์ด ์ถ•์ด ๋ฐ–์„ ๊ฐ€๋ฆฌํ‚จ๋‹คใ€๊นŒ์ง€๋งŒ ์•ˆ๋‹ค. **ใ€Œ์–ด๋А ํ‘œ์˜ ์–ด๋А ์นธใ€์€ ์ œํ’ˆ์ด ์•ˆ๋‹ค.** ๊ทธ๋ž˜์„œ ์ œํ’ˆ์ด\n * ๋ถ€ํŒ…์—์„œ ํ•ด์†Œ๊ธฐ๋ฅผ ๊ฝ‚๋Š”๋‹ค โ€” ์žฅ๋ถ€ ๊ธฐ๋ก๊ธฐ(`installIngestWindowWriter`)์™€ ๊ฐ™์€ ๊ทœ์œจ์ด๋‹ค.\n *\n * ์ปค๋„์ด ํ‘œ ์ด๋ฆ„์„ ์•Œ๊ฒŒ ๋˜๋ฉด ํ•œ ์ œํ’ˆ์˜ ์ €์žฅ ๊ตฌ์กฐ์— ๋งค์ด๊ณ , ๋‹ค์Œ ์ œํ’ˆ์ด ๋‹ค๋ฅธ ํ‘œ๋ฅผ ์“ฐ๋ฉด ์ปค๋„์„ ๋˜\n * ๊ณ ์ณ์•ผ ํ•œ๋‹ค.\n *\n * โ”€โ”€ ์—†๋Š” ๊ฒƒ์„ ์ˆจ๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํ•ด์†Œ๊ธฐ๊ฐ€ ์—†์œผ๋ฉด **๊ทธ ์‚ฌ์‹ค์„ ๋‚ธ๋‹ค**(`unresolved`). ๋งํฌ๋ฅผ ์ง€์šฐ๋ฉด ํ™”๋ฉด์€ ใ€Œ๊ทธ๋Ÿฐ ๊ด€๊ณ„๊ฐ€ ์—†๋‹คใ€๋กœ\n * ์ฝ๊ณ , ์‹ค์ œ๋กœ๋Š” ใ€Œ์•„๋ฌด๋„ ๋‹ตํ•  ์ˆ˜ ์—†๋‹คใ€๋‹ค. ๊ทธ ๋‘˜์€ ์‚ฌ๋žŒ์ด ํ•  ์ผ์ด ๋‹ค๋ฅด๋‹ค.\n */\n\n/** ๋ฐ–์— ์‚ฌ๋Š” ๋Œ€์ƒ ํ•˜๋‚˜ โ€” ํ™”๋ฉด์ด ์ด๋ฆ„์„ ๋ณด์ด๊ณ  ๊ฐˆ ๊ณณ์„ ์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ. */\nexport interface ExternalRef {\n id: string\n /** ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์ด๋ฆ„. ์—†์œผ๋ฉด ํ™”๋ฉด์ด id ๋ฅผ ๋ณด์ธ๋‹ค(์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค). */\n name?: string\n /**\n * ๊ทธ ์ œํ’ˆ์—์„œ ์ด๊ฒƒ์„ ์—ด ์ˆ˜ ์žˆ๋Š” ์ž๋ฆฌ โ€” ์—†์œผ๋ฉด ํ™”๋ฉด์ด ๋งํฌ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.\n *\n * ๋ง‰๋‹ค๋ฅธ ๋งํฌ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ด ์นธ์˜ ์š”์ ์ด๋‹ค. ๋ˆŒ๋Ÿฌ์„œ ์•„๋ฌด ์ผ๋„ ์•ˆ ์ผ์–ด๋‚˜๋ฉด ์‚ฌ๋žŒ์€ ๊ทธ๊ฒƒ์„\n * ๊ฒฐํ•จ์œผ๋กœ ์ฝ๋Š”๋‹ค.\n */\n href?: string\n /** ๊ทธ id ๊ฐ€ ์‹ค์ œ๋กœ ์žˆ๋‚˜ โ€” **์—†์œผ๋ฉด ์—†๋‹ค๊ณ  ๋งํ•œ๋‹ค.** ๋‹ต์—์„œ ๋นผ์ง€ ์•Š๋Š”๋‹ค. */\n missing?: boolean\n}\n\n/**\n * ๋ฐ–์—์„œ ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค โ€” ๋“ค์–ด์˜ค๋Š” ๊ด€๊ณ„ ํ•œ ๋ฌถ์Œ.\n *\n * `tense` ๋ฅผ **์ œํ’ˆ์ด ์„ ์–ธํ•œ๋‹ค**(๊ณ„์•ฝ์˜ `RelationTense`). ์‹ค์ ยท์ƒํƒœ ๊ตฌ๊ฐ„์€ ์ง€๋‚œ ์ผ์ด๊ณ  ์ •๋น„ ๊ณ„ํšยท\n * ์ง€์‹œ๋Š” ์•ž์˜ ์ผ์ด๋‹ค โ€” ใ€Œ๊ฑธ๋ฆฐ ๊ฒƒ์ด ์—ดใ€์ด ๋‘ ๋œป์ด ๋˜๋Š” ์ž๋ฆฌ์ด๋ฏ€๋กœ ๋ฌถ์Œ์ด ์Šค์Šค๋กœ ๋งํ•ด์•ผ ํ•œ๋‹ค.\n */\nexport interface ExternalIncoming {\n /** ๊ด€๊ณ„์˜ ์ด๋ฆ„(i18n ํ‚ค) โ€” ๊ณ„์•ฝ์˜ `via` ์™€ ๊ฐ™์€ ๊ทœ์น™. ์ œํ’ˆ์€ ์ž๊ธฐ ์ ‘๋‘๋ฅผ ์“ด๋‹ค. */\n via: string\n /** ์–ด๋””์„œ ์˜ค๋‚˜ โ€” ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์ถ• ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ ๊ทธ ์ œํ’ˆ์˜ ์ถ• ํ‚ค๋‹ค. */\n from: string\n /** ์–ธ์ œ์˜ ์ผ์ธ๊ฐ€. ์•ˆ ์ฃผ๋ฉด ใ€Œ์„ ์–ธ์ด ๋งํ•˜์ง€ ์•Š์•˜๋‹คใ€๋‹ค โ€” `standing` ์œผ๋กœ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. */\n tense?: 'past' | 'future' | 'standing'\n ids: string[]\n /** ์ „์ฒด ์ˆ˜ โ€” `ids` ๊ฐ€ ์ž˜๋ ธ์–ด๋„ ๋ช‡์ธ์ง€ ๋งํ•œ๋‹ค. */\n total: number\n}\n\n/**\n * ํ•œ external ๋Œ€์ƒ์„ ํ‘ธ๋Š” ์ œํ’ˆ ์ชฝ ๊ตฌํ˜„.\n *\n * ๋‘˜ ๋‹ค ์„ ํƒ์ด๋‹ค. ์ด๋ฆ„๋งŒ ๋Œ€ ์ค„ ์ˆ˜ ์žˆ๋Š” ์ œํ’ˆ๊ณผ ๋“ค์–ด์˜ค๋Š” ๊ด€๊ณ„๋งŒ ๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ œํ’ˆ์ด ๋‹ค ์žˆ๋‹ค โ€” ํ•˜๋‚˜๋งŒ\n * ๊ฝ‚์•„๋„ ๊ทธ๋งŒํผ์€ ๋‹ตํ•ด์ง„๋‹ค.\n */\nexport interface ExternalResolver {\n /** ๊ณ„์•ฝ์˜ `target.entity` ์™€ **๊ฐ™์€ ๋‚ฑ๋ง**. ๋‹ค๋ฅด๋ฉด ์•„๋ฌด ๊ด€๊ณ„์—๋„ ์•ˆ ๋ถ™๋Š”๋‹ค. */\n entity: string\n /** ์ด id ๋“ค์ด ๋ฌด์—‡์ธ๊ฐ€. */\n resolve?(domainId: string, ids: readonly string[]): Promise<ExternalRef[]>\n /** ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค. */\n incoming?(domainId: string, instanceId: string, axis: string, itemId: string): Promise<ExternalIncoming[]>\n}\n\nconst resolvers = new Map<string, ExternalResolver>()\n\n/**\n * ํ•ด์†Œ๊ธฐ๋ฅผ ๊ฝ‚๋Š”๋‹ค โ€” **๋ถ€ํŒ…์—์„œ ํ•œ ๋ฒˆ.**\n *\n * ๊ฐ™์€ `entity` ๋ฅผ ๋‘ ๋ฒˆ ๊ฝ‚์œผ๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์ด๊ธด๋‹ค. ๊ทธ๊ฒƒ์ด ๊ฐœ๋ฐœ ์ค‘ ์žฌ์ ์žฌ์˜ ์ •์ƒ ๋™์ž‘์ด๊ณ , ์šด์˜์—์„œ\n * ์ผ์–ด๋‚˜๋ฉด ๋‘ ์ œํ’ˆ์ด ๊ฐ™์€ ๋Œ€์ƒ์„ ์ž๊ธฐ ๊ฒƒ์ด๋ผ ๋งํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ **๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค** โ€” ์กฐ์šฉํžˆ ๋ฎ์œผ๋ฉด\n * ์–ด๋А ์ชฝ์ด ๋‹ตํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.\n */\nexport function registerExternalResolver(r: ExternalResolver, warn?: (msg: string) => void): void {\n const entity = String(r?.entity ?? '').trim()\n if (!entity) {\n warn?.('[external-resolver] entity ์—†๋Š” ํ•ด์†Œ๊ธฐ๋Š” ๊ฝ‚์ง€ ์•Š๋Š”๋‹ค โ€” ์•„๋ฌด ๊ด€๊ณ„์—๋„ ์•ˆ ๋ถ™๋Š”๋‹ค')\n return\n }\n if (resolvers.has(entity)) {\n warn?.(`[external-resolver] '${entity}' ํ•ด์†Œ๊ธฐ๋ฅผ ๋ฎ์–ด์“ด๋‹ค โ€” ๋‘ ์ œํ’ˆ์ด ๊ฐ™์€ ๋Œ€์ƒ์„ ๋‹ตํ•˜๋ ค ํ•˜๋ฉด ๊ทธ์ค‘ ํ•˜๋‚˜๋งŒ ๋‹ตํ•œ๋‹ค`)\n }\n resolvers.set(entity, { ...r, entity })\n}\n\n/** ์ง€๊ธˆ ๊ฝ‚ํ˜€ ์žˆ๋Š” ๊ฒƒ๋“ค โ€” ใ€Œ๋ฌด์—‡์„ ํ’€ ์ˆ˜ ์žˆ๋‚˜ใ€๋ฅผ ๋ฐ–์—์„œ ์žด ์ˆ˜ ์žˆ๊ฒŒ. */\nexport function externalResolverEntities(): string[] {\n return [...resolvers.keys()].sort()\n}\n\n/** ์‹œํ—˜์ด ์žฌ๊ธฐ๋™์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ฒŒ. */\nexport function clearExternalResolvers(): void {\n resolvers.clear()\n}\n\n/**\n * ๊ทธ id ๋“ค์„ ํ‘ผ๋‹ค โ€” **๋ชป ํ’€๋ฉด ๋ชป ํ‘ผ๋‹ค๊ณ  ๋งํ•œ๋‹ค.**\n *\n * ํ•ด์†Œ๊ธฐ๊ฐ€ ํ„ฐ์ ธ๋„ 360 ์ „์ฒด๋ฅผ ์ฃฝ์ด์ง€ ์•Š๋Š”๋‹ค. ํ•œ ๊ด€๊ณ„๊ฐ€ ๋‹ต์„ ๋ชป ํ•˜๋Š” ๊ฒƒ๊ณผ ํ™”๋ฉด์ด ์•ˆ ๋œจ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ\n * ์‚ฌ๊ณ ์ด๊ณ , ๋’ค์—ฃ๊ฒƒ์ด ํ›จ์”ฌ ๋‚˜์˜๋‹ค.\n */\nexport async function resolveExternal(\n entity: string,\n domainId: string,\n ids: readonly string[],\n warn?: (msg: string) => void\n): Promise<{ refs?: ExternalRef[]; unresolved?: 'no-resolver' | 'failed' }> {\n const r = resolvers.get(entity)\n if (!r?.resolve) return { unresolved: 'no-resolver' }\n try {\n return { refs: await r.resolve(domainId, ids) }\n } catch (e: any) {\n warn?.(`[external-resolver] '${entity}' ํ•ด์†Œ๊ฐ€ ์‹คํŒจํ–ˆ๋‹ค โ€” ${String(e?.message ?? e)}`)\n return { unresolved: 'failed' }\n }\n}\n\n/**\n * ๋ฐ–์—์„œ ์ด ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋“ค์„ ๋ชจ์€๋‹ค.\n *\n * ๊ฝ‚ํžŒ ๊ฒƒ์ด ์—†์œผ๋ฉด **๋นˆ ๋ฐฐ์—ด์ด์ง€ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋‹ค** โ€” ๋ฐ–์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด ์—†๋Š” ๋Œ€์ƒ์ด ์ •์ƒ์ด๋‹ค.\n * ๋‹ค๋งŒ ใ€Œํ•ด์†Œ๊ธฐ๊ฐ€ ์—†์–ด์„œ ๋ชจ๋ฅธ๋‹คใ€์™€ ใ€Œ์—†๋‹คใ€๋Š” ๋‹ค๋ฅด๋ฏ€๋กœ, ๊ทธ ๊ตฌ๋ณ„์€ `externalResolverEntities()` ๋กœ\n * ๋ฐ–์—์„œ ์žฐ๋‹ค.\n */\nexport async function externalIncoming(\n domainId: string,\n instanceId: string,\n axis: string,\n itemId: string,\n warn?: (msg: string) => void\n): Promise<ExternalIncoming[]> {\n const out: ExternalIncoming[] = []\n for (const r of resolvers.values()) {\n if (!r.incoming) continue\n try {\n const got = await r.incoming(domainId, instanceId, axis, itemId)\n /* ๋นˆ ๋ฌถ์Œ์€ ์‹ฃ์ง€ ์•Š๋Š”๋‹ค โ€” ์—ฌ๊ธฐ์„œ๋Š” ใ€Œ๊ทธ ์ œํ’ˆ์ด ์ด ์ถ•์„ ์•ˆ ๋ณธ๋‹คใ€๋Š” ๋œป์ด๊ณ  ํ•  ๋ง์ด ์—†๋‹ค. */\n for (const g of got ?? []) if (g && g.total > 0) out.push(g)\n } catch (e: any) {\n warn?.(`[external-resolver] '${r.entity}' ์˜ ๋“ค์–ด์˜ค๋Š” ๊ด€๊ณ„ ์กฐํšŒ๊ฐ€ ์‹คํŒจํ–ˆ๋‹ค โ€” ${String(e?.message ?? e)}`)\n }\n }\n return out\n}\n"]}
@@ -104,10 +104,21 @@ async function projectStructure(domainId, instanceId, model, sourceRef) {
104
104
  const equipment = (model?.equipment ?? [])
105
105
  .filter((m) => m?.id)
106
106
  .map((m) => {
107
+ /*
108
+ * โ”€โ”€ ์„ค๋น„๋Š” ์ž๋ฆฌ์—๋„ ๊ตฌ์—ญ์—๋„ ์„ค ์ˆ˜ ์žˆ๋‹ค (2026-09-06) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
109
+ * ์ž๋ฆฌ ๋ชฉ๋ก์—์„œ ๋จผ์ € ์ฐพ๊ณ , ์—†์œผ๋ฉด ๊ตฌ์—ญ์—์„œ ์ฐพ๋Š”๋‹ค. `locations.parentId` ๊ฐ€ ์ด๋ฏธ ๊ฐ™์€ ๊ทœ์œจ์„
110
+ * ์“ด๋‹ค(ยง`parentIsLocation`).
111
+ *
112
+ * ์‹ค๋ฌผ์ด ์žˆ๋‹ค โ€” `EQ-CAM-SHOWER-01`(์—์–ด์ƒค์›Œ)์ด `LINE-CAM`(๊ตฌ์—ญ)์— ๋”ธ๋ ค ์žˆ๊ณ , ๋ผ์ธ ์ „์ฒด์—
113
+ * ๋ถ™๋Š” ์„ค๋น„๋Š” ์ž๋ฆฌ ํ•˜๋‚˜๋ฅผ ๊ณ ๋ฅผ ์ˆ˜ ์—†๋‹ค. ๊ทธ๋™์•ˆ ์ž๋ฆฌ์—์„œ๋งŒ ์ฐพ์•„์„œ **๋Š์–ด์ง„ ์ฐธ์กฐ๋กœ ๋ณด๊ณ **ํ–ˆ๋‹ค.
114
+ *
115
+ * ๋งˆ์Šคํ„ฐ๊ฐ€ `homeLocationKind: 'area'` ๋กœ ๋งํ•ด ์ฃผ์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ์กฐํšŒ๋กœ ํŒ์ •ํ•œ๋‹ค โ€” ์˜› ํŠธ์œˆ์˜
116
+ * model ์—๋Š” ๊ทธ ์นธ์ด ์—†๊ณ , ์žˆ๋Š” ๊ฒƒ์„ ๋ชป ์ฐพ์•˜๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์˜๋‹ค.
117
+ */
107
118
  const home = m.homeLocation ? locOf.get(m.homeLocation) : undefined;
108
- /* ๋Š์–ด์ง„ ๊ธฐ์ค€ ์ž๋ฆฌ๋Š” **์ด๋ฆ„์„ ๋Œ€๊ณ ** ๋ณด๊ณ ํ•œ๋‹ค. ์˜ˆ์ „์—๋Š” ํ™”๋ฉด์ด ๊ฒฝ๊ณ ํ•  ๋ฟ์ด์—ˆ๊ณ 
109
- ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ๋“ค์–ด์˜จ ๋ฐ์ดํ„ฐ๋Š” ์•„๋ฌด๋„ ์•ˆ ๋ดค๋‹ค. */
110
- if (m.homeLocation && !home)
119
+ const homeArea = m.homeLocation && !home ? areaOf.get(m.homeLocation) : undefined;
120
+ /* ๋Š์–ด์ง„ ๊ธฐ์ค€ ์ž๋ฆฌ๋Š” **์ด๋ฆ„์„ ๋Œ€๊ณ ** ๋ณด๊ณ ํ•œ๋‹ค โ€” ์ž๋ฆฌ์—๋„ ๊ตฌ์—ญ์—๋„ ์—†์„ ๋•Œ๋งŒ์ด๋‹ค. */
121
+ if (m.homeLocation && !home && !homeArea)
111
122
  unresolvedHome.push(`${m.id}โ†’${m.homeLocation}`);
112
123
  return eqRepo.create({
113
124
  ...scope,
@@ -122,6 +133,8 @@ async function projectStructure(domainId, instanceId, model, sourceRef) {
122
133
  /* ๊ฒฐ๊ณผ๊นŒ์ง€ โ€” ์ฐธ์กฐ๋งŒ ์žˆ์œผ๋ฉด "๋ฌด์—‡์œผ๋กœ ๊ฒ€์ฆํ•œ๋‹ค" ๊นŒ์ง€๊ณ , ์ž๊ฒฉ ์„ฑ๋ฆฝ์€ ๊ฒฐ๊ณผ๊ฐ€ ๋งํ•œ๋‹ค. */
123
134
  testResults: m.testResults ?? null,
124
135
  homeLocation: home ? { id: home.id } : null,
136
+ /* ๋‘˜ ๋‹ค ์ฐจ๋Š” ์ผ์€ ์—†๋‹ค โ€” ์ž๋ฆฌ์—์„œ ์ฐพ์•˜์œผ๋ฉด ๊ตฌ์—ญ์€ ์•ˆ ๋ณธ๋‹ค. */
137
+ homeArea: homeArea ? { id: homeArea.id } : null,
125
138
  mtbfMs: m.mtbfMs ?? null,
126
139
  mttrMs: m.mttrMs ?? null,
127
140
  /* ์„ ์–ธ๋œ ์ •์ฒด์„ฑ โ€” ์˜ˆ์ „์—๋Š” ์„ ์–ธ์— ์—†๋Š” `gs1Id` ๋ฅผ ์ฝ์–ด ์ด ์นธ์ด ๋Š˜ ๋น„์–ด ์žˆ์—ˆ๋‹ค. */
@@ -1 +1 @@
1
- {"version":3,"file":"project-structure.js","sourceRoot":"","sources":["../../../server/service/twin-model/project-structure.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinArea } from '../twin-space/twin-area.js'\nimport { TwinLocation } from './twin-location.js'\nimport { TwinEquipment } from './twin-equipment.js'\nimport { TwinOperation } from './twin-operation.js'\nimport { readBoardEquipment } from '@operato/ops-contract'\n\n/*\n * ๊ตฌ์กฐ ํˆฌ์˜ โ€” `model`(์ปค๋„ ์ž…๋ ฅ ๋ฌธ์„œ) โ†’ **ํ‘œ์ค€ ์—”ํ‹ฐํ‹ฐ ํ–‰**(ADR-0032).\n *\n * โ”€โ”€ ์™œ ์ „๋Ÿ‰ ๊ต์ฒด์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ–‰๋“ค์€ **์›๋ณธ์—์„œ ์˜จ ์บ์‹œ**๋‹ค(ADR-0032-D). ์›๋ณธ์ด ์ง„์‹ค์ด๋ฏ€๋กœ diff ๋กœ ์•„๋ผ๋Š” ๊ฒƒ๋ณด๋‹ค\n * **๋งค๋ฒˆ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ**์ด ๋งž๋‹ค โ€” diff ๋Š” \"์šฐ๋ฆฌ ์ชฝ์— ๋‚จ๊ฒจ์•ผ ํ•  ๊ฒƒ์ด ์žˆ๋‹ค\" ๋Š” ์ „์ œ๋ฅผ\n * ๊น”๊ณ , ๊ทธ ์ „์ œ๊ฐ€ ์†Œ์œ  ์นจ๋ฒ”์˜ ์‹œ์ž‘์ด๋‹ค.\n *\n * ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด ์„œ๋ช…(`TwinStructure.signature`)์ด ๊ฐ™์„ ๋•Œ ๊ฑด๋„ˆ๋›ฐ๋Š” ์žฅ์น˜๊ฐ€ ์ด๋ฏธ ์žˆ์œผ๋ฏ€๋กœ\n * ๊ทธ๊ฒƒ์„ ์•ž์— ๋‘”๋‹ค. ์—ฌ๊ธฐ์„œ diff ๋ฅผ ๋ฐœ๋ช…ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์„ค๋น„๊ฐ€ ์ž๋ฆฌ๋ฅผ FK ๋กœ ๊ฐ€๋ฆฌํ‚ค๋ฏ€๋กœ **์ž๋ฆฌ๋ฅผ ๋จผ์ €** ๋„ฃ๋Š”๋‹ค. ์ง€์šฐ๋Š” ๊ฒƒ์€ ๋ฐ˜๋Œ€ ์ˆœ์„œ๋‹ค.\n * (์ž๋ฆฌ ์‚ญ์ œ ์‹œ ์„ค๋น„์˜ `homeLocation` ์€ `SET NULL` ์ด์ง€๋งŒ, ์ „๋Ÿ‰ ๊ต์ฒด์—์„œ๋Š” ๋‘˜ ๋‹ค ์ง€์šด๋‹ค.)\n */\nexport interface ProjectionReport {\n locations: number\n equipment: number\n operations: number\n /** ์ž๋ฆฌ๋ฅผ ๋ชป ์ฐพ์•„ ๊ธฐ์ค€ ์ž๋ฆฌ๋ฅผ ๋น„์šด ์„ค๋น„ โ€” **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค.** */\n unresolvedHome: string[]\n /** ๊ตฌ์—ญ์„ ๋ชป ์ฐพ์•„ ๋น„์šด ์ž๋ฆฌ. ๊ตฌ์—ญ์€ model ๋ฐ–(ํ˜ธ์ŠคํŠธ ๊ฐœ๋…)์ด๋ผ ์–ด๊ธ‹๋‚  ์ˆ˜ ์žˆ๋‹ค. */\n unresolvedArea: string[]\n}\n\n/**\n * ์ด ํŠธ์œˆ์˜ ๊ตฌ์กฐ ํ–‰์„ **์›๋ณธ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฆฐ๋‹ค.**\n *\n * `sourceRef` ๋Š” ์–ด๋А ์›๋ณธ์—์„œ ์™”๋Š”์ง€๋‹ค(`ReferenceMaster.source` = instanceId). ์—†๋Š” ํ–‰์€\n * ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค โ€” ์บ์‹œ๋ผ๋Š” ์‚ฌ์‹ค์„ ๊ตฌ์กฐ๋กœ ์ง€ํ‚จ๋‹ค.\n */\nexport async function projectStructure(domainId: string, instanceId: string, model: any, sourceRef: string): Promise<ProjectionReport> {\n const instance = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!instance) throw new Error(`cannot project structure: twin instance \"${instanceId}\" is not registered`)\n\n /*\n * **๊ฐ™์€ id ๊ฐ€ ๋‘˜์ด๋ฉด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค** โ€” ์ œ์•ฝ ์œ„๋ฐ˜ ๋ฌธ๊ตฌ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์‹ค์ธก(2026-08-18): ํ˜„์žฅ ๊ฐ’์„ ๊ทธ ํ˜„์žฅ์˜ ํŠธ์œˆ ์ „๋ถ€์— ์–น๋‹ค๊ฐ€ ํ•œ ํŠธ์œˆ์—์„œ ํˆฌ์˜์ด ํ„ฐ์กŒ๋‹ค. ์˜ฌ๋ผ์˜จ ๊ฒƒ์€\n * `SQLITE_CONSTRAINT: UNIQUE constraint failed: twin_equipment...` ๋ฟ์ด๋ผ **๋ฌด์—‡์ด ์ž˜๋ชป๋๋Š”์ง€ ์•„๋ฌด๋„\n * ์•Œ ์ˆ˜ ์—†์—ˆ๋‹ค.** ์›์ธ์€ ๊ทธ ๋ชจ๋ธ์— ์„ค๋น„ `load-1` ์ด ๋‘ ๋ฒˆ ๋“ค์–ด ์žˆ๋˜ ๊ฒƒ์ด๋‹ค(id ๋Š” ํŠธ์œˆ ์•ˆ์—์„œ ์œ ์ผํ•ด์•ผ\n * ํ•œ๋‹ค). ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ํ•˜๋‚˜๋งŒ ๋‚จ๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๊ฒƒ์€ ๋ชจ๋ธ๋ง ์˜ค๋ฅ˜๋ฅผ ๊ฐ์ถ”๋Š” ์ผ์ด๊ณ , ์–ด๋А ์ชฝ์ด ๋งž๋Š”์ง€ ์šฐ๋ฆฌ๋Š”\n * ๋ชจ๋ฅธ๋‹ค.\n */\n const dupOf = (list: any[] | undefined, what: string): string | undefined => {\n const seen = new Set<string>()\n for (const e of list ?? []) {\n const id = String(e?.id ?? '')\n if (!id) continue\n if (seen.has(id)) return `twin \"${instanceId}\" has two ${what} with id \"${id}\" โ€” ids must be unique within a twin, so the model cannot be projected`\n seen.add(id)\n }\n return undefined\n }\n const dupMsg = dupOf(model?.locations, 'locations') ?? dupOf(readBoardEquipment(model), 'equipment')\n if (dupMsg) throw new Error(dupMsg)\n\n const locRepo = getRepository(TwinLocation)\n const eqRepo = getRepository(TwinEquipment)\n const opRepo = getRepository(TwinOperation)\n const scope = { domain: { id: domainId } as any, instance: { id: instance.id } as any }\n const ingestedAt = new Date()\n\n /*\n * ์ „๋Ÿ‰ ๊ต์ฒด โ€” ์ด ํ–‰๋“ค์€ **์›๋ณธ์—์„œ ์˜จ ์บ์‹œ**์ด๋ฏ€๋กœ ๋งค๋ฒˆ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฆฐ๋‹ค.\n * diff ๋กœ ์•„๋ผ๋Š” ๊ฒƒ์€ \"์šฐ๋ฆฌ ์ชฝ์— ๋‚จ๊ฒจ์•ผ ํ•  ๊ฒƒ์ด ์žˆ๋‹ค\" ๋Š” ์ „์ œ๋ฅผ ๊น”๊ณ , ๊ทธ ์ „์ œ๊ฐ€ ์†Œ์œ  ์นจ๋ฒ”์˜ ์‹œ์ž‘์ด๋‹ค.\n *\n * **๊ด€์ธก์œผ๋กœ ์ž๋ž€ ์ž์›์€ ์—ฌ๊ธฐ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.** ์ปค๋„์€ ๋งˆ์Šคํ„ฐ์— ์—†๋˜ ์„ค๋น„๋„ ์ด๋ฒคํŠธ๋กœ ์•Œ๊ฒŒ ๋˜์ง€๋งŒ\n * (`observed-reducer` ์˜ `origin: 'observed'`), ๊ทธ๊ฒƒ์„ ์ด ํ‘œ์— ๋ฐ€์–ด ๋„ฃ์œผ๋ฉด **์“ฐ๊ธฐ ๊ฒฝ๋กœ๊ฐ€ ๋‘˜**์ด ๋˜๊ณ \n * ํ‹ฑ ๋ฃจํ”„์—์„œ DB ๋กœ ์“ฐ๋Š” ๊ธธ์ด ์ƒ๊ธด๋‹ค(ADR-0032-D ์œ„๋ฐ˜). ๊ทธ ์ฐจ์ด๋Š” **์กฐํšŒ ์‹œ์ ์— ๋น„๊ตํ•ด ๋ณด๊ณ **ํ•œ๋‹ค โ€”\n * ์ˆจ๊ฒจ์•ผ ํ•  ๋ถˆ์ผ์น˜๊ฐ€ ์•„๋‹ˆ๋ผ \"์›๋ณธ์ด ๋ชจ๋ฅด๋Š” ์„ค๋น„๊ฐ€ ์‹คํ–‰ ์ค‘์ด๋‹ค\" ๋Š” ์‚ฌ์‹ค์ด๋‹ค.\n */\n await eqRepo.delete(scope)\n await opRepo.delete(scope)\n await locRepo.delete(scope)\n\n /* ๊ตฌ์—ญ์€ model ๋ฐ–์— ์‚ฐ๋‹ค(ํ˜ธ์ŠคํŠธ์˜ TwinArea). ์ด๋ฆ„์œผ๋กœ ์ฐพ์•„ FK ๋ฅผ ์ž‡๋Š”๋‹ค. */\n const areas = await getRepository(TwinArea).find({ where: { domain: { id: domainId } as any } })\n const areaOf = new Map(areas.map(a => [a.areaId, a]))\n const unresolvedArea: string[] = []\n\n /*\n * โ”€โ”€ ์ „๊ธฐ ์ƒ๋ฅ˜๋ฅผ ใ€Œ๊ตฌ์—ญใ€์œผ๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์ž๋ฆฌ์˜ ๋ถ€๋ชจ๊ฐ€ **๋‹ค๋ฅธ ์ž๋ฆฌ**์ผ ์ˆ˜ ์žˆ๋‹ค(๋ถ„๊ธฐ์˜ ์ƒ๋ฅ˜๋Š” ์ˆ˜์ „์ด๋‹ค). ๊ทธ ๋ถ€๋ชจ๋ฅผ ๊ตฌ์—ญ ํ‘œ์—์„œ ์ฐพ์œผ๋ฉด ๋‹น์—ฐํžˆ\n * ์—†๊ณ , ์˜ˆ์ „์—๋Š” ๊ทธ๊ฒƒ์„ ๋งค๋ฒˆ ใ€Œ๊ตฌ์—ญ์ด ์ด ํŠธ์œˆ์— ์—†๋‹คใ€๋กœ ๊ฒฝ๊ณ ํ–ˆ๋‹ค โ€” ์—๋„ˆ์ง€ ํŠธ์œˆ์„ ์ธ์ œ์ŠคํŠธํ•  ๋•Œ๋งˆ๋‹ค\n * ๋ถ„๊ธฐ ์ˆ˜๋งŒํผ ๊ฑฐ์ง“ ๊ฒฝ๋ณด๊ฐ€ ๋‚ฌ๋‹ค. ๊ฒฝ๋ณด๊ฐ€ ์†Œ์Œ์ด ๋˜๋ฉด **์‚ฌ๋žŒ์ด ๊ฒฝ๋ณด ์ž์ฒด๋ฅผ ์ฝ์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.**\n *\n * ์ž๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ถ€๋ชจ๋Š” ๊ณ„์ธต(์ž๋ฆฌ โŠƒ ์ž๋ฆฌ)์ด๊ณ , ๊ตฌ์—ญ์€ model ๋ฐ–์˜ ๋‹ค๋ฅธ ํ‘œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ถ€๋ชจ๊ฐ€ ์ด ๋ชจ๋ธ์˜\n * ์ž๋ฆฌ์ด๋ฉด ๊ตฌ์—ญ ํ•ด์„์„ **์‹œ๋„ํ•˜์ง€ ์•Š๋Š”๋‹ค**(์—†๋Š” ๊ฒƒ์„ ๋ชป ์ฐพ์•˜๋‹ค๊ณ  ๋งํ•˜์ง€ ์•Š๋Š”๋‹ค).\n */\n const locationIds = new Set((model?.locations ?? []).filter((l: any) => l?.id).map((l: any) => String(l.id)))\n\n const locations: TwinLocation[] = (model?.locations ?? [])\n .filter((l: any) => l?.id)\n .map((l: any) => {\n const parentIsLocation = l.parentId ? locationIds.has(String(l.parentId)) : false\n const area = l.parentId && !parentIsLocation ? areaOf.get(l.parentId) : undefined\n if (l.parentId && !parentIsLocation && !area) unresolvedArea.push(`${l.id}โ†’${l.parentId}`)\n return locRepo.create({\n ...scope,\n locationId: l.id,\n /* **์ด๋ฆ„์„ ์˜ฎ๊ธด๋‹ค.** ๋ฒ„๋ฆฌ๊ณ  ์žˆ์—ˆ๋‹ค โ€” ๊ทธ๋ž˜์„œ ํ™”๋ฉด์— ์ž๋ฆฌ id ๋งŒ ๋‚จ์•˜๋‹ค(ยงname ์ฃผ์„ ์ฐธ์กฐ). */\n name: l.name ?? null,\n description: l.description ?? null,\n type: l.type,\n capacity: l.capacity ?? null,\n parallelism: l.parallelism ?? null,\n area: area ? ({ id: area.id } as any) : null,\n gs1Id: l.gs1Id ?? null,\n /* ์ž๋ฆฌ์˜ ์†์„ฑ๋„ ์˜ฎ๊ธด๋‹ค โ€” ์˜ฎ๊ธฐ์ง€ ์•Š์œผ๋ฉด ๊ณ„์•ฝ์ „๋ ฅยท์š”๊ธˆ์ด ํ•ญ๋ชฉ ํŒจ๋„์—์„œ ์‚ฌ๋ผ์ง„๋‹ค(๋“ค์–ด์˜จ ๊ฒƒ์ด ์—†๋Š” ๋ˆ„๋ฝ). */\n properties: l.properties ?? null,\n sourceRef,\n ingestedAt\n } as any)\n })\n const savedLocations = locations.length ? await locRepo.save(locations, { chunk: 500 }) : []\n const locOf = new Map(savedLocations.map(l => [l.locationId, l]))\n\n const unresolvedHome: string[] = []\n const equipment: TwinEquipment[] = (model?.equipment ?? [])\n .filter((m: any) => m?.id)\n .map((m: any) => {\n const home = m.homeLocation ? locOf.get(m.homeLocation) : undefined\n /* ๋Š์–ด์ง„ ๊ธฐ์ค€ ์ž๋ฆฌ๋Š” **์ด๋ฆ„์„ ๋Œ€๊ณ ** ๋ณด๊ณ ํ•œ๋‹ค. ์˜ˆ์ „์—๋Š” ํ™”๋ฉด์ด ๊ฒฝ๊ณ ํ•  ๋ฟ์ด์—ˆ๊ณ \n ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ๋“ค์–ด์˜จ ๋ฐ์ดํ„ฐ๋Š” ์•„๋ฌด๋„ ์•ˆ ๋ดค๋‹ค. */\n if (m.homeLocation && !home) unresolvedHome.push(`${m.id}โ†’${m.homeLocation}`)\n return eqRepo.create({\n ...scope,\n equipmentId: m.id,\n name: m.name ?? null,\n description: m.description ?? null,\n kind: m.kind,\n /* ์†์„ฑ๋„ ์˜ฎ๊ธด๋‹ค โ€” ํ–‰์— ์ž๋ฆฌ๊ฐ€ ์—†์–ด ํ˜๋ฆฌ๊ณ  ์žˆ์—ˆ๋‹ค(์†Œ๋น„์ฒ˜๊ฐ€ ์‹ค์ œ๋กœ ์ฝ๋Š” ์‚ฌ์‹ค์ด๋‹ค: ์ฃผํ–‰ ์†๋„). */\n properties: m.properties ?? null,\n /* ์‹œํ—˜ ์ฐธ์กฐ๋„ ํ•จ๊ป˜ โ€” ํ˜๋ฆฌ๋ฉด ๋ช…์„ธ ์ชฝ์—์„œ \"๋ˆ„๊ฐ€ ๋‚˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋‚˜\" ์— ์ด ์„ค๋น„๊ฐ€ ๋น ์ง„๋‹ค. */\n testSpecificationIds: m.testSpecificationIds ?? null,\n /* ๊ฒฐ๊ณผ๊นŒ์ง€ โ€” ์ฐธ์กฐ๋งŒ ์žˆ์œผ๋ฉด \"๋ฌด์—‡์œผ๋กœ ๊ฒ€์ฆํ•œ๋‹ค\" ๊นŒ์ง€๊ณ , ์ž๊ฒฉ ์„ฑ๋ฆฝ์€ ๊ฒฐ๊ณผ๊ฐ€ ๋งํ•œ๋‹ค. */\n testResults: m.testResults ?? null,\n homeLocation: home ? ({ id: home.id } as any) : null,\n mtbfMs: m.mtbfMs ?? null,\n mttrMs: m.mttrMs ?? null,\n /* ์„ ์–ธ๋œ ์ •์ฒด์„ฑ โ€” ์˜ˆ์ „์—๋Š” ์„ ์–ธ์— ์—†๋Š” `gs1Id` ๋ฅผ ์ฝ์–ด ์ด ์นธ์ด ๋Š˜ ๋น„์–ด ์žˆ์—ˆ๋‹ค. */\n identity: (m as any).identity ?? null,\n sourceRef,\n ingestedAt\n } as any)\n })\n if (equipment.length) await eqRepo.save(equipment, { chunk: 500 })\n\n const operations: TwinOperation[] = (model?.operations ?? [])\n .filter((o: any) => o?.key)\n .map((o: any, i: number) =>\n opRepo.create({\n ...scope,\n operationKey: o.key,\n /*\n * ๊ณต์ •์€ ๋งˆ์Šคํ„ฐ๊ฐ€ `label` ๋กœ ๋งํ•œ๋‹ค โ€” ํ–‰์—์„œ๋Š” **๊ทœ์•ฝ์˜ ์ด๋ฆ„ ํ•˜๋‚˜๋งŒ** ๋‘”๋‹ค.\n *\n * ํ•œ๋™์•ˆ `label` ์ปฌ๋Ÿผ๋„ ํ•จ๊ป˜ ๋‚จ๊ฒจ ๋’€๋”๋‹ˆ ์กฐํšŒ ํ™”๋ฉด์— \"์ด๋ฆ„\" ์—ด์ด **๋‘ ๊ฐœ** ๋–ด๋‹ค(๊ฐ™์€ ๊ฐ’์ด\n * ๋‘ ๋ฒˆ). ์–ดํœ˜๋ฅผ ํ•˜๋‚˜๋กœ ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด์„œ ๋‘˜์„ ๋‚จ๊ธฐ๋ฉด ๋ฐ˜๋“œ์‹œ ์ด๋ ‡๊ฒŒ ์ƒˆ์–ด ๋‚˜์˜จ๋‹ค.\n */\n name: o.name ?? o.label ?? null,\n description: o.description ?? null,\n intent: o.intent ?? null,\n locationType: o.locationType ?? null,\n resourceType: o.resourceType ?? null,\n /* ์†Œ์š”์‹œ๊ฐ„์€ ISO 8601 ๋ฌธ์ž์—ด์ด ์ •๋ณธ โ€” ๋ถ„์œผ๋กœ ์ค„์ด๋ฉด ์ดˆ๊ฐ€ ์˜ค๋ฅ˜ ์—†์ด ์‚ฌ๋ผ์ง„๋‹ค. */\n duration: o.duration ?? null,\n variability: o.variability ?? null,\n parameters: o.parameters ?? null,\n /* **๋„ค ์ž์› ๋ช…์„ธ๋ฅผ ํ•จ๊ป˜ ์˜ฎ๊ธด๋‹ค.** ์…‹์ด ๋น ์ ธ ์žˆ์–ด์„œ ์กฐํšŒ ํ™”๋ฉด์ด \"์›๋ณธ์ด ๋งํ•œ ๊ฐ’\" ์ด๋ผ ์ ๊ณ ๋„\n ๋„ท ์ค‘ ํ•˜๋‚˜๋งŒ ๋ณด์˜€๋‹ค โ€” ์‚ฌ๋žŒ์ด ํ•„์š”ํ•œ ๊ณต์ •์„ ๋ณด๊ณ  ์‚ฌ๋žŒ์ด ํ•„์š” ์—†๋‹ค๊ณ  ๊ฒฐ๋ก  ๋‚ด๊ฒŒ ๋œ๋‹ค. */\n personnelSpecification: o.personnelSpecification ?? null,\n physicalAssetSpecification: o.physicalAssetSpecification ?? null,\n materialSpecification: o.materialSpecification ?? null,\n seq: i,\n sourceRef,\n ingestedAt\n } as any)\n )\n if (operations.length) await opRepo.save(operations, { chunk: 500 })\n\n return {\n locations: savedLocations.length,\n equipment: equipment.length,\n operations: operations.length,\n unresolvedHome,\n unresolvedArea\n }\n}\n"]}
1
+ {"version":3,"file":"project-structure.js","sourceRoot":"","sources":["../../../server/service/twin-model/project-structure.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinArea } from '../twin-space/twin-area.js'\nimport { TwinLocation } from './twin-location.js'\nimport { TwinEquipment } from './twin-equipment.js'\nimport { TwinOperation } from './twin-operation.js'\nimport { readBoardEquipment } from '@operato/ops-contract'\n\n/*\n * ๊ตฌ์กฐ ํˆฌ์˜ โ€” `model`(์ปค๋„ ์ž…๋ ฅ ๋ฌธ์„œ) โ†’ **ํ‘œ์ค€ ์—”ํ‹ฐํ‹ฐ ํ–‰**(ADR-0032).\n *\n * โ”€โ”€ ์™œ ์ „๋Ÿ‰ ๊ต์ฒด์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ–‰๋“ค์€ **์›๋ณธ์—์„œ ์˜จ ์บ์‹œ**๋‹ค(ADR-0032-D). ์›๋ณธ์ด ์ง„์‹ค์ด๋ฏ€๋กœ diff ๋กœ ์•„๋ผ๋Š” ๊ฒƒ๋ณด๋‹ค\n * **๋งค๋ฒˆ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ**์ด ๋งž๋‹ค โ€” diff ๋Š” \"์šฐ๋ฆฌ ์ชฝ์— ๋‚จ๊ฒจ์•ผ ํ•  ๊ฒƒ์ด ์žˆ๋‹ค\" ๋Š” ์ „์ œ๋ฅผ\n * ๊น”๊ณ , ๊ทธ ์ „์ œ๊ฐ€ ์†Œ์œ  ์นจ๋ฒ”์˜ ์‹œ์ž‘์ด๋‹ค.\n *\n * ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด ์„œ๋ช…(`TwinStructure.signature`)์ด ๊ฐ™์„ ๋•Œ ๊ฑด๋„ˆ๋›ฐ๋Š” ์žฅ์น˜๊ฐ€ ์ด๋ฏธ ์žˆ์œผ๋ฏ€๋กœ\n * ๊ทธ๊ฒƒ์„ ์•ž์— ๋‘”๋‹ค. ์—ฌ๊ธฐ์„œ diff ๋ฅผ ๋ฐœ๋ช…ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์„ค๋น„๊ฐ€ ์ž๋ฆฌ๋ฅผ FK ๋กœ ๊ฐ€๋ฆฌํ‚ค๋ฏ€๋กœ **์ž๋ฆฌ๋ฅผ ๋จผ์ €** ๋„ฃ๋Š”๋‹ค. ์ง€์šฐ๋Š” ๊ฒƒ์€ ๋ฐ˜๋Œ€ ์ˆœ์„œ๋‹ค.\n * (์ž๋ฆฌ ์‚ญ์ œ ์‹œ ์„ค๋น„์˜ `homeLocation` ์€ `SET NULL` ์ด์ง€๋งŒ, ์ „๋Ÿ‰ ๊ต์ฒด์—์„œ๋Š” ๋‘˜ ๋‹ค ์ง€์šด๋‹ค.)\n */\nexport interface ProjectionReport {\n locations: number\n equipment: number\n operations: number\n /** ์ž๋ฆฌ๋ฅผ ๋ชป ์ฐพ์•„ ๊ธฐ์ค€ ์ž๋ฆฌ๋ฅผ ๋น„์šด ์„ค๋น„ โ€” **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค.** */\n unresolvedHome: string[]\n /** ๊ตฌ์—ญ์„ ๋ชป ์ฐพ์•„ ๋น„์šด ์ž๋ฆฌ. ๊ตฌ์—ญ์€ model ๋ฐ–(ํ˜ธ์ŠคํŠธ ๊ฐœ๋…)์ด๋ผ ์–ด๊ธ‹๋‚  ์ˆ˜ ์žˆ๋‹ค. */\n unresolvedArea: string[]\n}\n\n/**\n * ์ด ํŠธ์œˆ์˜ ๊ตฌ์กฐ ํ–‰์„ **์›๋ณธ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฆฐ๋‹ค.**\n *\n * `sourceRef` ๋Š” ์–ด๋А ์›๋ณธ์—์„œ ์™”๋Š”์ง€๋‹ค(`ReferenceMaster.source` = instanceId). ์—†๋Š” ํ–‰์€\n * ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค โ€” ์บ์‹œ๋ผ๋Š” ์‚ฌ์‹ค์„ ๊ตฌ์กฐ๋กœ ์ง€ํ‚จ๋‹ค.\n */\nexport async function projectStructure(domainId: string, instanceId: string, model: any, sourceRef: string): Promise<ProjectionReport> {\n const instance = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!instance) throw new Error(`cannot project structure: twin instance \"${instanceId}\" is not registered`)\n\n /*\n * **๊ฐ™์€ id ๊ฐ€ ๋‘˜์ด๋ฉด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค** โ€” ์ œ์•ฝ ์œ„๋ฐ˜ ๋ฌธ๊ตฌ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์‹ค์ธก(2026-08-18): ํ˜„์žฅ ๊ฐ’์„ ๊ทธ ํ˜„์žฅ์˜ ํŠธ์œˆ ์ „๋ถ€์— ์–น๋‹ค๊ฐ€ ํ•œ ํŠธ์œˆ์—์„œ ํˆฌ์˜์ด ํ„ฐ์กŒ๋‹ค. ์˜ฌ๋ผ์˜จ ๊ฒƒ์€\n * `SQLITE_CONSTRAINT: UNIQUE constraint failed: twin_equipment...` ๋ฟ์ด๋ผ **๋ฌด์—‡์ด ์ž˜๋ชป๋๋Š”์ง€ ์•„๋ฌด๋„\n * ์•Œ ์ˆ˜ ์—†์—ˆ๋‹ค.** ์›์ธ์€ ๊ทธ ๋ชจ๋ธ์— ์„ค๋น„ `load-1` ์ด ๋‘ ๋ฒˆ ๋“ค์–ด ์žˆ๋˜ ๊ฒƒ์ด๋‹ค(id ๋Š” ํŠธ์œˆ ์•ˆ์—์„œ ์œ ์ผํ•ด์•ผ\n * ํ•œ๋‹ค). ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ํ•˜๋‚˜๋งŒ ๋‚จ๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๊ฒƒ์€ ๋ชจ๋ธ๋ง ์˜ค๋ฅ˜๋ฅผ ๊ฐ์ถ”๋Š” ์ผ์ด๊ณ , ์–ด๋А ์ชฝ์ด ๋งž๋Š”์ง€ ์šฐ๋ฆฌ๋Š”\n * ๋ชจ๋ฅธ๋‹ค.\n */\n const dupOf = (list: any[] | undefined, what: string): string | undefined => {\n const seen = new Set<string>()\n for (const e of list ?? []) {\n const id = String(e?.id ?? '')\n if (!id) continue\n if (seen.has(id)) return `twin \"${instanceId}\" has two ${what} with id \"${id}\" โ€” ids must be unique within a twin, so the model cannot be projected`\n seen.add(id)\n }\n return undefined\n }\n const dupMsg = dupOf(model?.locations, 'locations') ?? dupOf(readBoardEquipment(model), 'equipment')\n if (dupMsg) throw new Error(dupMsg)\n\n const locRepo = getRepository(TwinLocation)\n const eqRepo = getRepository(TwinEquipment)\n const opRepo = getRepository(TwinOperation)\n const scope = { domain: { id: domainId } as any, instance: { id: instance.id } as any }\n const ingestedAt = new Date()\n\n /*\n * ์ „๋Ÿ‰ ๊ต์ฒด โ€” ์ด ํ–‰๋“ค์€ **์›๋ณธ์—์„œ ์˜จ ์บ์‹œ**์ด๋ฏ€๋กœ ๋งค๋ฒˆ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฆฐ๋‹ค.\n * diff ๋กœ ์•„๋ผ๋Š” ๊ฒƒ์€ \"์šฐ๋ฆฌ ์ชฝ์— ๋‚จ๊ฒจ์•ผ ํ•  ๊ฒƒ์ด ์žˆ๋‹ค\" ๋Š” ์ „์ œ๋ฅผ ๊น”๊ณ , ๊ทธ ์ „์ œ๊ฐ€ ์†Œ์œ  ์นจ๋ฒ”์˜ ์‹œ์ž‘์ด๋‹ค.\n *\n * **๊ด€์ธก์œผ๋กœ ์ž๋ž€ ์ž์›์€ ์—ฌ๊ธฐ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.** ์ปค๋„์€ ๋งˆ์Šคํ„ฐ์— ์—†๋˜ ์„ค๋น„๋„ ์ด๋ฒคํŠธ๋กœ ์•Œ๊ฒŒ ๋˜์ง€๋งŒ\n * (`observed-reducer` ์˜ `origin: 'observed'`), ๊ทธ๊ฒƒ์„ ์ด ํ‘œ์— ๋ฐ€์–ด ๋„ฃ์œผ๋ฉด **์“ฐ๊ธฐ ๊ฒฝ๋กœ๊ฐ€ ๋‘˜**์ด ๋˜๊ณ \n * ํ‹ฑ ๋ฃจํ”„์—์„œ DB ๋กœ ์“ฐ๋Š” ๊ธธ์ด ์ƒ๊ธด๋‹ค(ADR-0032-D ์œ„๋ฐ˜). ๊ทธ ์ฐจ์ด๋Š” **์กฐํšŒ ์‹œ์ ์— ๋น„๊ตํ•ด ๋ณด๊ณ **ํ•œ๋‹ค โ€”\n * ์ˆจ๊ฒจ์•ผ ํ•  ๋ถˆ์ผ์น˜๊ฐ€ ์•„๋‹ˆ๋ผ \"์›๋ณธ์ด ๋ชจ๋ฅด๋Š” ์„ค๋น„๊ฐ€ ์‹คํ–‰ ์ค‘์ด๋‹ค\" ๋Š” ์‚ฌ์‹ค์ด๋‹ค.\n */\n await eqRepo.delete(scope)\n await opRepo.delete(scope)\n await locRepo.delete(scope)\n\n /* ๊ตฌ์—ญ์€ model ๋ฐ–์— ์‚ฐ๋‹ค(ํ˜ธ์ŠคํŠธ์˜ TwinArea). ์ด๋ฆ„์œผ๋กœ ์ฐพ์•„ FK ๋ฅผ ์ž‡๋Š”๋‹ค. */\n const areas = await getRepository(TwinArea).find({ where: { domain: { id: domainId } as any } })\n const areaOf = new Map(areas.map(a => [a.areaId, a]))\n const unresolvedArea: string[] = []\n\n /*\n * โ”€โ”€ ์ „๊ธฐ ์ƒ๋ฅ˜๋ฅผ ใ€Œ๊ตฌ์—ญใ€์œผ๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์ž๋ฆฌ์˜ ๋ถ€๋ชจ๊ฐ€ **๋‹ค๋ฅธ ์ž๋ฆฌ**์ผ ์ˆ˜ ์žˆ๋‹ค(๋ถ„๊ธฐ์˜ ์ƒ๋ฅ˜๋Š” ์ˆ˜์ „์ด๋‹ค). ๊ทธ ๋ถ€๋ชจ๋ฅผ ๊ตฌ์—ญ ํ‘œ์—์„œ ์ฐพ์œผ๋ฉด ๋‹น์—ฐํžˆ\n * ์—†๊ณ , ์˜ˆ์ „์—๋Š” ๊ทธ๊ฒƒ์„ ๋งค๋ฒˆ ใ€Œ๊ตฌ์—ญ์ด ์ด ํŠธ์œˆ์— ์—†๋‹คใ€๋กœ ๊ฒฝ๊ณ ํ–ˆ๋‹ค โ€” ์—๋„ˆ์ง€ ํŠธ์œˆ์„ ์ธ์ œ์ŠคํŠธํ•  ๋•Œ๋งˆ๋‹ค\n * ๋ถ„๊ธฐ ์ˆ˜๋งŒํผ ๊ฑฐ์ง“ ๊ฒฝ๋ณด๊ฐ€ ๋‚ฌ๋‹ค. ๊ฒฝ๋ณด๊ฐ€ ์†Œ์Œ์ด ๋˜๋ฉด **์‚ฌ๋žŒ์ด ๊ฒฝ๋ณด ์ž์ฒด๋ฅผ ์ฝ์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.**\n *\n * ์ž๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ถ€๋ชจ๋Š” ๊ณ„์ธต(์ž๋ฆฌ โŠƒ ์ž๋ฆฌ)์ด๊ณ , ๊ตฌ์—ญ์€ model ๋ฐ–์˜ ๋‹ค๋ฅธ ํ‘œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ถ€๋ชจ๊ฐ€ ์ด ๋ชจ๋ธ์˜\n * ์ž๋ฆฌ์ด๋ฉด ๊ตฌ์—ญ ํ•ด์„์„ **์‹œ๋„ํ•˜์ง€ ์•Š๋Š”๋‹ค**(์—†๋Š” ๊ฒƒ์„ ๋ชป ์ฐพ์•˜๋‹ค๊ณ  ๋งํ•˜์ง€ ์•Š๋Š”๋‹ค).\n */\n const locationIds = new Set((model?.locations ?? []).filter((l: any) => l?.id).map((l: any) => String(l.id)))\n\n const locations: TwinLocation[] = (model?.locations ?? [])\n .filter((l: any) => l?.id)\n .map((l: any) => {\n const parentIsLocation = l.parentId ? locationIds.has(String(l.parentId)) : false\n const area = l.parentId && !parentIsLocation ? areaOf.get(l.parentId) : undefined\n if (l.parentId && !parentIsLocation && !area) unresolvedArea.push(`${l.id}โ†’${l.parentId}`)\n return locRepo.create({\n ...scope,\n locationId: l.id,\n /* **์ด๋ฆ„์„ ์˜ฎ๊ธด๋‹ค.** ๋ฒ„๋ฆฌ๊ณ  ์žˆ์—ˆ๋‹ค โ€” ๊ทธ๋ž˜์„œ ํ™”๋ฉด์— ์ž๋ฆฌ id ๋งŒ ๋‚จ์•˜๋‹ค(ยงname ์ฃผ์„ ์ฐธ์กฐ). */\n name: l.name ?? null,\n description: l.description ?? null,\n type: l.type,\n capacity: l.capacity ?? null,\n parallelism: l.parallelism ?? null,\n area: area ? ({ id: area.id } as any) : null,\n gs1Id: l.gs1Id ?? null,\n /* ์ž๋ฆฌ์˜ ์†์„ฑ๋„ ์˜ฎ๊ธด๋‹ค โ€” ์˜ฎ๊ธฐ์ง€ ์•Š์œผ๋ฉด ๊ณ„์•ฝ์ „๋ ฅยท์š”๊ธˆ์ด ํ•ญ๋ชฉ ํŒจ๋„์—์„œ ์‚ฌ๋ผ์ง„๋‹ค(๋“ค์–ด์˜จ ๊ฒƒ์ด ์—†๋Š” ๋ˆ„๋ฝ). */\n properties: l.properties ?? null,\n sourceRef,\n ingestedAt\n } as any)\n })\n const savedLocations = locations.length ? await locRepo.save(locations, { chunk: 500 }) : []\n const locOf = new Map(savedLocations.map(l => [l.locationId, l]))\n\n const unresolvedHome: string[] = []\n const equipment: TwinEquipment[] = (model?.equipment ?? [])\n .filter((m: any) => m?.id)\n .map((m: any) => {\n /*\n * โ”€โ”€ ์„ค๋น„๋Š” ์ž๋ฆฌ์—๋„ ๊ตฌ์—ญ์—๋„ ์„ค ์ˆ˜ ์žˆ๋‹ค (2026-09-06) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ž๋ฆฌ ๋ชฉ๋ก์—์„œ ๋จผ์ € ์ฐพ๊ณ , ์—†์œผ๋ฉด ๊ตฌ์—ญ์—์„œ ์ฐพ๋Š”๋‹ค. `locations.parentId` ๊ฐ€ ์ด๋ฏธ ๊ฐ™์€ ๊ทœ์œจ์„\n * ์“ด๋‹ค(ยง`parentIsLocation`).\n *\n * ์‹ค๋ฌผ์ด ์žˆ๋‹ค โ€” `EQ-CAM-SHOWER-01`(์—์–ด์ƒค์›Œ)์ด `LINE-CAM`(๊ตฌ์—ญ)์— ๋”ธ๋ ค ์žˆ๊ณ , ๋ผ์ธ ์ „์ฒด์—\n * ๋ถ™๋Š” ์„ค๋น„๋Š” ์ž๋ฆฌ ํ•˜๋‚˜๋ฅผ ๊ณ ๋ฅผ ์ˆ˜ ์—†๋‹ค. ๊ทธ๋™์•ˆ ์ž๋ฆฌ์—์„œ๋งŒ ์ฐพ์•„์„œ **๋Š์–ด์ง„ ์ฐธ์กฐ๋กœ ๋ณด๊ณ **ํ–ˆ๋‹ค.\n *\n * ๋งˆ์Šคํ„ฐ๊ฐ€ `homeLocationKind: 'area'` ๋กœ ๋งํ•ด ์ฃผ์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ์กฐํšŒ๋กœ ํŒ์ •ํ•œ๋‹ค โ€” ์˜› ํŠธ์œˆ์˜\n * model ์—๋Š” ๊ทธ ์นธ์ด ์—†๊ณ , ์žˆ๋Š” ๊ฒƒ์„ ๋ชป ์ฐพ์•˜๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์˜๋‹ค.\n */\n const home = m.homeLocation ? locOf.get(m.homeLocation) : undefined\n const homeArea = m.homeLocation && !home ? areaOf.get(m.homeLocation) : undefined\n /* ๋Š์–ด์ง„ ๊ธฐ์ค€ ์ž๋ฆฌ๋Š” **์ด๋ฆ„์„ ๋Œ€๊ณ ** ๋ณด๊ณ ํ•œ๋‹ค โ€” ์ž๋ฆฌ์—๋„ ๊ตฌ์—ญ์—๋„ ์—†์„ ๋•Œ๋งŒ์ด๋‹ค. */\n if (m.homeLocation && !home && !homeArea) unresolvedHome.push(`${m.id}โ†’${m.homeLocation}`)\n return eqRepo.create({\n ...scope,\n equipmentId: m.id,\n name: m.name ?? null,\n description: m.description ?? null,\n kind: m.kind,\n /* ์†์„ฑ๋„ ์˜ฎ๊ธด๋‹ค โ€” ํ–‰์— ์ž๋ฆฌ๊ฐ€ ์—†์–ด ํ˜๋ฆฌ๊ณ  ์žˆ์—ˆ๋‹ค(์†Œ๋น„์ฒ˜๊ฐ€ ์‹ค์ œ๋กœ ์ฝ๋Š” ์‚ฌ์‹ค์ด๋‹ค: ์ฃผํ–‰ ์†๋„). */\n properties: m.properties ?? null,\n /* ์‹œํ—˜ ์ฐธ์กฐ๋„ ํ•จ๊ป˜ โ€” ํ˜๋ฆฌ๋ฉด ๋ช…์„ธ ์ชฝ์—์„œ \"๋ˆ„๊ฐ€ ๋‚˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋‚˜\" ์— ์ด ์„ค๋น„๊ฐ€ ๋น ์ง„๋‹ค. */\n testSpecificationIds: m.testSpecificationIds ?? null,\n /* ๊ฒฐ๊ณผ๊นŒ์ง€ โ€” ์ฐธ์กฐ๋งŒ ์žˆ์œผ๋ฉด \"๋ฌด์—‡์œผ๋กœ ๊ฒ€์ฆํ•œ๋‹ค\" ๊นŒ์ง€๊ณ , ์ž๊ฒฉ ์„ฑ๋ฆฝ์€ ๊ฒฐ๊ณผ๊ฐ€ ๋งํ•œ๋‹ค. */\n testResults: m.testResults ?? null,\n homeLocation: home ? ({ id: home.id } as any) : null,\n /* ๋‘˜ ๋‹ค ์ฐจ๋Š” ์ผ์€ ์—†๋‹ค โ€” ์ž๋ฆฌ์—์„œ ์ฐพ์•˜์œผ๋ฉด ๊ตฌ์—ญ์€ ์•ˆ ๋ณธ๋‹ค. */\n homeArea: homeArea ? ({ id: homeArea.id } as any) : null,\n mtbfMs: m.mtbfMs ?? null,\n mttrMs: m.mttrMs ?? null,\n /* ์„ ์–ธ๋œ ์ •์ฒด์„ฑ โ€” ์˜ˆ์ „์—๋Š” ์„ ์–ธ์— ์—†๋Š” `gs1Id` ๋ฅผ ์ฝ์–ด ์ด ์นธ์ด ๋Š˜ ๋น„์–ด ์žˆ์—ˆ๋‹ค. */\n identity: (m as any).identity ?? null,\n sourceRef,\n ingestedAt\n } as any)\n })\n if (equipment.length) await eqRepo.save(equipment, { chunk: 500 })\n\n const operations: TwinOperation[] = (model?.operations ?? [])\n .filter((o: any) => o?.key)\n .map((o: any, i: number) =>\n opRepo.create({\n ...scope,\n operationKey: o.key,\n /*\n * ๊ณต์ •์€ ๋งˆ์Šคํ„ฐ๊ฐ€ `label` ๋กœ ๋งํ•œ๋‹ค โ€” ํ–‰์—์„œ๋Š” **๊ทœ์•ฝ์˜ ์ด๋ฆ„ ํ•˜๋‚˜๋งŒ** ๋‘”๋‹ค.\n *\n * ํ•œ๋™์•ˆ `label` ์ปฌ๋Ÿผ๋„ ํ•จ๊ป˜ ๋‚จ๊ฒจ ๋’€๋”๋‹ˆ ์กฐํšŒ ํ™”๋ฉด์— \"์ด๋ฆ„\" ์—ด์ด **๋‘ ๊ฐœ** ๋–ด๋‹ค(๊ฐ™์€ ๊ฐ’์ด\n * ๋‘ ๋ฒˆ). ์–ดํœ˜๋ฅผ ํ•˜๋‚˜๋กœ ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด์„œ ๋‘˜์„ ๋‚จ๊ธฐ๋ฉด ๋ฐ˜๋“œ์‹œ ์ด๋ ‡๊ฒŒ ์ƒˆ์–ด ๋‚˜์˜จ๋‹ค.\n */\n name: o.name ?? o.label ?? null,\n description: o.description ?? null,\n intent: o.intent ?? null,\n locationType: o.locationType ?? null,\n resourceType: o.resourceType ?? null,\n /* ์†Œ์š”์‹œ๊ฐ„์€ ISO 8601 ๋ฌธ์ž์—ด์ด ์ •๋ณธ โ€” ๋ถ„์œผ๋กœ ์ค„์ด๋ฉด ์ดˆ๊ฐ€ ์˜ค๋ฅ˜ ์—†์ด ์‚ฌ๋ผ์ง„๋‹ค. */\n duration: o.duration ?? null,\n variability: o.variability ?? null,\n parameters: o.parameters ?? null,\n /* **๋„ค ์ž์› ๋ช…์„ธ๋ฅผ ํ•จ๊ป˜ ์˜ฎ๊ธด๋‹ค.** ์…‹์ด ๋น ์ ธ ์žˆ์–ด์„œ ์กฐํšŒ ํ™”๋ฉด์ด \"์›๋ณธ์ด ๋งํ•œ ๊ฐ’\" ์ด๋ผ ์ ๊ณ ๋„\n ๋„ท ์ค‘ ํ•˜๋‚˜๋งŒ ๋ณด์˜€๋‹ค โ€” ์‚ฌ๋žŒ์ด ํ•„์š”ํ•œ ๊ณต์ •์„ ๋ณด๊ณ  ์‚ฌ๋žŒ์ด ํ•„์š” ์—†๋‹ค๊ณ  ๊ฒฐ๋ก  ๋‚ด๊ฒŒ ๋œ๋‹ค. */\n personnelSpecification: o.personnelSpecification ?? null,\n physicalAssetSpecification: o.physicalAssetSpecification ?? null,\n materialSpecification: o.materialSpecification ?? null,\n seq: i,\n sourceRef,\n ingestedAt\n } as any)\n )\n if (operations.length) await opRepo.save(operations, { chunk: 500 })\n\n return {\n locations: savedLocations.length,\n equipment: equipment.length,\n operations: operations.length,\n unresolvedHome,\n unresolvedArea\n }\n}\n"]}