From 28b69e544924bd6ef9a6f8293a2aa2ef548553c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Thu, 26 Feb 2026 17:34:06 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20archive=2037=EA=B0=9C=20+=20COMPLETED?= =?UTF-8?q?=203=EA=B0=9C=20=EB=B3=B5=EC=9B=90=20-=20=ED=96=A5=ED=9B=84=20d?= =?UTF-8?q?ocs/=20=EC=A0=95=EC=8B=9D=20=EB=AC=B8=EC=84=9C=ED=99=94=20?= =?UTF-8?q?=EC=8B=9C=20=EC=B0=B8=EC=A1=B0=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 완료 문서의 상세 내용은 추후 docs/ 구조화 시 정식 문서에 반영 예정 - HISTORY.md는 요약 인덱스로 유지, 개별 파일은 상세 참조용 보관 Co-Authored-By: Claude Opus 4.6 --- .../슬라이드1.jpeg | Bin 9596 -> 0 bytes .../슬라이드10.jpeg | Bin 76892 -> 0 bytes .../슬라이드11.jpeg | Bin 66862 -> 0 bytes .../슬라이드12.jpeg | Bin 68186 -> 0 bytes .../슬라이드13.jpeg | Bin 78028 -> 0 bytes .../슬라이드14.jpeg | Bin 9666 -> 0 bytes .../슬라이드15.jpeg | Bin 58713 -> 0 bytes .../슬라이드16.jpeg | Bin 61967 -> 0 bytes .../슬라이드17.jpeg | Bin 58150 -> 0 bytes .../슬라이드18.jpeg | Bin 50453 -> 0 bytes .../슬라이드19.jpeg | Bin 60450 -> 0 bytes .../슬라이드2.jpeg | Bin 48936 -> 0 bytes .../슬라이드20.jpeg | Bin 52987 -> 0 bytes .../슬라이드21.jpeg | Bin 53398 -> 0 bytes .../슬라이드22.jpeg | Bin 40007 -> 0 bytes .../슬라이드23.jpeg | Bin 16706 -> 0 bytes .../슬라이드24.jpeg | Bin 73334 -> 0 bytes .../슬라이드25.jpeg | Bin 65594 -> 0 bytes .../슬라이드26.jpeg | Bin 42772 -> 0 bytes .../슬라이드27.jpeg | Bin 44631 -> 0 bytes .../슬라이드28.jpeg | Bin 61026 -> 0 bytes .../슬라이드29.jpeg | Bin 63646 -> 0 bytes .../슬라이드3.jpeg | Bin 9339 -> 0 bytes .../슬라이드30.jpeg | Bin 58455 -> 0 bytes .../슬라이드31.jpeg | Bin 45745 -> 0 bytes .../슬라이드32.jpeg | Bin 59190 -> 0 bytes .../슬라이드33.jpeg | Bin 45175 -> 0 bytes .../슬라이드34.jpeg | Bin 52898 -> 0 bytes .../슬라이드35.jpeg | Bin 64605 -> 0 bytes .../슬라이드36.jpeg | Bin 57316 -> 0 bytes .../슬라이드37.jpeg | Bin 52177 -> 0 bytes .../슬라이드38.jpeg | Bin 53874 -> 0 bytes .../슬라이드4.jpeg | Bin 66607 -> 0 bytes .../슬라이드5.jpeg | Bin 72131 -> 0 bytes .../슬라이드6.jpeg | Bin 54022 -> 0 bytes .../슬라이드7.jpeg | Bin 59069 -> 0 bytes .../슬라이드8.jpeg | Bin 9784 -> 0 bytes .../슬라이드9.jpeg | Bin 58670 -> 0 bytes plans/archive/5130-bom-migration-plan.md | 446 +++++ plans/archive/5130-sam-data-migration-plan.md | 828 ++++++++++ .../AI_리포트_키워드_색상체계_가이드_v1.4.md | 406 +++++ plans/archive/SEEDERS_LIST.md | 128 ++ plans/archive/api-analysis-report.md | 434 +++++ .../archive/bending-lot-pipeline-dev-plan.md | 1097 +++++++++++++ .../bending-worklog-reimplementation-plan.md | 860 ++++++++++ .../bidding-api-implementation-plan.md | 817 ++++++++++ .../construction-api-integration-plan.md | 480 ++++++ plans/archive/docs-update-plan.md | 309 ++++ .../document-management-system-changelog.md | 31 + .../document-system-product-inspection.md | 375 +++++ .../erp-api-development-plan-d1.0-changes.md | 559 +++++++ .../fcm-user-targeted-notification-plan.md | 369 +++++ .../archive/formula-engine-real-data-plan.md | 1077 ++++++++++++ plans/archive/items-table-unification-plan.md | 589 +++++++ plans/archive/kd-items-migration-plan.md | 1293 +++++++++++++++ .../archive/l2-permission-management-plan.md | 378 +++++ .../material-input-per-item-mapping-plan.md | 482 ++++++ .../archive/mes-integration-analysis-plan.md | 525 ++++++ .../mng-item-formula-integration-plan.md | 837 ++++++++++ plans/archive/mng-item-management-plan.md | 1447 +++++++++++++++++ .../mng-quote-formula-development-plan.md | 553 +++++++ .../archive/notification-sound-system-plan.md | 424 +++++ .../archive/order-location-management-plan.md | 831 ++++++++++ plans/archive/order-management-plan.md | 335 ++++ ...der-workorder-shipment-integration-plan.md | 659 ++++++++ plans/archive/process-management-plan.md | 397 +++++ ...quote-auto-calculation-development-plan.md | 743 +++++++++ .../quote-v2-auto-calculation-fix-plan.md | 262 +++ .../react-fcm-push-notification-plan.md | 543 +++++++ .../react-server-component-audit-plan.md | 147 ++ .../archive/sam-stat-database-design-plan.md | 1294 +++++++++++++++ .../simulator-calculation-logic-mapping.md | 1057 ++++++++++++ plans/archive/stock-integration-plan.md | 421 +++++ plans/archive/welfare-section-plan.md | 1021 ++++++++++++ plans/archive/work-order-plan.md | 409 +++++ plans/bending-preproduction-stock-plan.md | 838 ++++++++++ plans/db-trigger-audit-system-plan.md | 1294 +++++++++++++++ plans/quote-management-url-migration-plan.md | 1282 +++++++++++++++ 78 files changed, 26277 insertions(+) delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드1.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드10.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드11.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드12.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드13.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드14.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드15.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드16.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드17.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드18.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드19.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드2.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드20.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드21.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드22.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드23.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드24.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드25.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드26.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드27.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드28.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드29.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드3.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드30.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드31.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드32.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드33.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드34.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드35.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드36.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드37.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드38.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드4.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드5.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드6.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드7.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드8.jpeg delete mode 100644 plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드9.jpeg create mode 100644 plans/archive/5130-bom-migration-plan.md create mode 100644 plans/archive/5130-sam-data-migration-plan.md create mode 100644 plans/archive/AI_리포트_키워드_색상체계_가이드_v1.4.md create mode 100644 plans/archive/SEEDERS_LIST.md create mode 100644 plans/archive/api-analysis-report.md create mode 100644 plans/archive/bending-lot-pipeline-dev-plan.md create mode 100644 plans/archive/bending-worklog-reimplementation-plan.md create mode 100644 plans/archive/bidding-api-implementation-plan.md create mode 100644 plans/archive/construction-api-integration-plan.md create mode 100644 plans/archive/docs-update-plan.md create mode 100644 plans/archive/document-management-system-changelog.md create mode 100644 plans/archive/document-system-product-inspection.md create mode 100644 plans/archive/erp-api-development-plan-d1.0-changes.md create mode 100644 plans/archive/fcm-user-targeted-notification-plan.md create mode 100644 plans/archive/formula-engine-real-data-plan.md create mode 100644 plans/archive/items-table-unification-plan.md create mode 100644 plans/archive/kd-items-migration-plan.md create mode 100644 plans/archive/l2-permission-management-plan.md create mode 100644 plans/archive/material-input-per-item-mapping-plan.md create mode 100644 plans/archive/mes-integration-analysis-plan.md create mode 100644 plans/archive/mng-item-formula-integration-plan.md create mode 100644 plans/archive/mng-item-management-plan.md create mode 100644 plans/archive/mng-quote-formula-development-plan.md create mode 100644 plans/archive/notification-sound-system-plan.md create mode 100644 plans/archive/order-location-management-plan.md create mode 100644 plans/archive/order-management-plan.md create mode 100644 plans/archive/order-workorder-shipment-integration-plan.md create mode 100644 plans/archive/process-management-plan.md create mode 100644 plans/archive/quote-auto-calculation-development-plan.md create mode 100644 plans/archive/quote-v2-auto-calculation-fix-plan.md create mode 100644 plans/archive/react-fcm-push-notification-plan.md create mode 100644 plans/archive/react-server-component-audit-plan.md create mode 100644 plans/archive/sam-stat-database-design-plan.md create mode 100644 plans/archive/simulator-calculation-logic-mapping.md create mode 100644 plans/archive/stock-integration-plan.md create mode 100644 plans/archive/welfare-section-plan.md create mode 100644 plans/archive/work-order-plan.md create mode 100644 plans/bending-preproduction-stock-plan.md create mode 100644 plans/db-trigger-audit-system-plan.md create mode 100644 plans/quote-management-url-migration-plan.md diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드1.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드1.jpeg deleted file mode 100644 index 3f1f4f56706e57e4a0a558a108e9fb0bed2ef82a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9596 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

tA{TvVTx0iGi>r@+2 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드11.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드11.jpeg deleted file mode 100644 index b939996ca7166feddd6fb97a06f437dce9770b9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66862 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 z 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

YGNYJ`7>xN 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 F{sPS6@B{z= diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드14.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드14.jpeg deleted file mode 100644 index 0b5a102bc719f79339106ae8e93631ead1262a24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9666 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 Ne6P>n-#6cV{{+9_zbF6z diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드15.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드15.jpeg deleted file mode 100644 index e0a713c66bfac6efe3cba2f6800a0181a47b0be3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58713 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

t58rR8f8M;CVEaee7K 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드18.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드18.jpeg deleted file mode 100644 index 0809779c9130267f97be64c1f1d14aa75aabd4d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50453 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드19.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드19.jpeg deleted file mode 100644 index 5a58ac92d9fb58f3d39ddb2053ec4edcce743e35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60450 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 ZBy5-N@k|gIOQF6|) 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 Y$rWzjwNSCBuj1MI!q-u6(ch;3KO%r`MF0Q* diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드21.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드21.jpeg deleted file mode 100644 index a7e1817ec87b1155d7830f3a474d1c31af5e1eb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53398 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 y3;0(IQ754t8ojR`Jx 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%0DMwwa91rCc4PLxxrg|+!VWv zSC91*zhU>iFybnNTiyY*Wu*?K9yJ`#!oE#Yyc^y%HNGXGS~HVYO$hCQ0s>>}zv+*9 zrf_N&0f0QZL?3Nl!^@V-fC}A9K_6u90;No}2!Mct=b>AhnNti$l83-$KmbY%uuKH- z^0@N9Y4Pf%-GK@SfE}%V2>z=4MpH-m=A4r&atVM1+XR<->rjd z03PKSrB+R@v<{!y^3ug0egfP;pQ=GB9=_F;w?*iCqDF*p&JkkYxyI|>~6SBM1FcjF)^+Cbq z@q8wHcI*#b*CG2c;k?@XcO~ghD4L-_GcPjS_Zvt*?;9w+glvxCN5aQ2K(jcvD6zc{ z_!}$P0mQ>!!G(YDmpeun1!yV9dBW-vW=b?%D%0`7MJtMvB3at8h;WUJI~y%9`wPa# zmOkgEeII-S{n&{vGZ(f_&KhmaG#|>>Ln^`6yFwvWMFCW5XK62-Yx&HlLzPRc5yquO zSEEKcMka2b5bSHQUDP^=kg>P(75;Y(3 zh`}MizWX(nDPh1Qy$yEzv`BnuS)bA7PI~m2-fS6afm@(69E>9J>@H_7$p4m*P-&t` z*Re8^cSGDo9@!8acBt7tbFg>No1JN}lM8i*TugVu^YShW$5y^OFg0x*lTPRKsa~yL zgL$%POKXutH`^++t!LaN#S{^lDklpVCBZiJ@^Eo3|-&#$UDegQK%M- zW$!{PFpUutk99q%4D1FjWxMSLLW7s=#mF5mx&Y z)_{3myUyKFncW~}Xn)Fc{?3LkPx_k5xgmJp7>50Gt9) zY`-5+7eY&Qr~oK;#CTU83ieEYA18h?qGg|ByZ(r*q`qdKtSAqS0W961SI4dy7cLz^ zn^zwJt?oiFz_i^w=-nb*2Ilga9+pB^8eLNYCFYi@F9OoBglWJY2NhlwFSkAw=q~mN z`p`_R+!QIemtx{`?dfvY#2BdSs@;nOfscB$08QdGD)2X&gfH~#$64V+U;hF#V-%jV zLffj)pi67b09rfLzSQKp|1BftwhSwV*n5YB(3c?`i-gaA%8vLKN%X(-bAKsH#|iwi zCFo^C#Hk?Qp*uxWP2pN-F^on9I6R?~eRGzrxWyW9OHXr3Igni+ zN4AX?$0^;U*Ij%Q)X7Zb?X9m5)NVXLd)=dCxHxEz96qdNXf`Csg&#i*U&26a-P30u zbRUzZjglvoH2}GPik=%*koYjhCh%5Zg?$^V0hv*?<$^%eNs&J7)e~i!VIqm8zoXGp zJ%}Mic{jrS52e*Q;dy9lzq|Br%#_-ieY*`hw?k)~A6KB4*wIf;7Wl63{wK^O1pQFI z=>1q-ZT`>YS?YP8UwMoltF6WF%P~OPd7Sp6w*=)HC%0ENwC2twQV3_7y|OZ5&FGz? zqkhsV!9xwttkDC!uJUW^Zj+;v+PZS~wuz2o(tJTp-#~@=6i)IzE%iou3ltB!;T1{l zo*c7c3?EB^zbbR+uPaYx*+A@3K2*z%0}5;|#bE!yt}SlEFtCg&5he2BNA_whf2RY_ z5D^m3owb!|$c-R+yuR>DtOp=Bu)?l>DRIv6v5uMd+I z=bgFI##KV9>MUm@4CecJ$7%AGtXeUgb&yMy_55zZ3gMY*!|+J~Ff*q=!pF1VbkY2C zjsJYnoWR0Zf_hlJ9_@s>HZpoERbZK1l+z<6hGOVZ9B&sKd5PZt2(TYXoO$ZVk;6Wm zfF-5-7qWC4%b4t45)h(?%&lEWnltQ`?Nq)r9~&rY&NXudV}ngDW9qRug?19n@L)$b zOL0pyTXr!xRKA{__{|2yuB!Q2+jSAU4-EHFp>;@xkZDB8Fryi~%ce-Ow;e((!`&R} zszAc*b5HKRZ;Jt;R%0c~W=3SO2=zK-iAGUjwggUd&|<2ws!6YE_A0^1(FulozQI^7 zHI?wp#?xkfy2Z^=g;$RYx;$&mT-+>JqZ|)n9M9&a*$jPL_Di^X0n?8rXzNKB_Hqq% zrR34oc)9-B!uVUdvUH+F)eoNXDmsDzz+f|aQ`2bAD0VM^GD`6>&0wROGElj@10wHy zi+HEL!)nS$B_u3^4Yzx>3oDgaTPZs5`mWP#?MA%KNtz;DO!QW(EC`X+Oe>uz!rppl z2eFi|Wzm(Q`kG1*^7}jNbjSN1Upl_yoj@x%xvkZA)YN~!FiE94OxeaZ10o$srE<5K zA0uv7%vJYHpU5-*(QQqL#|z~mcy9~E+4#=wJ^#m6V)|*)1Mx!-eZmb z9-#71%5D@9OZHSg*_N)-r#je3J0j97&#cWm_eIz`#>~Uif_C31QbfVZ60yWCb1`mq zv&a8IWT7>tn2HuCut}d9Ei$dS(o~T-$&%5)A%Tp`aZi^E(e#eenlX_9gXfV~5-2Bb zm!d{zz)-Rh-;j2e^=Qh0dX}QLI*Vsq(ov+#8(zD-(JT)P%GhbJ3j~0bdPFto4y;&Q zELd)WWwaJjtMbWGRQnZj%Xux1IOhde0+pcz@7`U>=?kvfd4Bt(@z@JZt2<+!ndEPJ zX%dV|wxU;TAY)*`#x2PGn27jG^syM9AN-@eOg2q_EX&*7KfatnZil~82mOh2{#w=B zFL!18j%boXucsE23dWR2#$c(lO(a>^+ATiDWNw(evYz6zjQ#c_fqA=hp$U?;x-=Yl zb)*YZz76+7*JX+(dSZw7QH~YF<+fWCH`ULK#8#uLz z+$l3)qrqYtrT5&#P9;FGM?#*|T6!PcQjqQ@#lU959HrBgvM$uz&QNcq1@<<4UpfMxqyW0>t>#)SD*pJq%O`S*so*vu_ctU=7I5XhfbV(k}5)z&z{7JXHO( z0A;a(>mYF+#itp4qn)I1CB72sAs_a0`T@Nmed8yNfQIoJjB-GSn6pssjrbE zCui^UD_mBfnqz<%n$Jojt`NR|ljo0igKh{aTikw+7~(4Okm1h}c8vUt^pmiRUbsGO zOm0m+5F5+!o;X-shE;0ep%XG1eapAW=G~;=E5nETRmmkWL~%LB!Np3d3cgj#71AH_ zo_#EV-DqjQXq6gCnEmD-jxHR>1;mbP+b3+Rpxyo7(}n+~&wr`1_yjwflM{f2g@ws3 zobrk|#sEgmi4pcUbPAWe*v^=9w0kn674EoRKNKBb{+| zUaA^Ck1-crIRHLN&{UCl96&v9cvU~Cmhw(MUk>uV_6?uDEF?hTL6T~TRc+;aQcnM_ zuNSY>m6)R1MLk(OsHbj3f39DN9L?FM@%J{0-T@1R%fg4QHM}!1U=CLxTus(UBgI&C zIDOszH^KJb0!#IF`LB%M?9q`eX!?ksjd_{gkDkE!(lIlX-F;A3j9i~dW#Is8f%j_B zykl|PtNRcz8{RA{GaDs{#*7MtsbdKRqdDP%!p0s0&4fzvytqfVESminA*1u?~l6@U3s#`O{Rd@ng8%MVVzxO=k3&Yxxm* zz>!_r(CgM0UvMZuq9yos(mOg6wC%0O$Bm*fNG8x%)&)8@21yhGklT4o)n+qyqD41u zmrz||XksbI84`R^T>8=uy)4Y-F!PxwEt53qmfEGS;OWO8d}9wRjVoFF_~t4kaGX8N+if&!-Q8Qhbx70oKLVudcBk9=311U3ef}w zzFIMQeR+3ul;3Gj2_;!rLWtx%$UfF_6JNY8HID@YuiPOe@~7Ob3^NsV?VCGa^#9Jz zTl@N_(prBmL_EP(={wry|DJ~CB*@Q`2ll-F7H?=(W*grb!-+B5d*{XDW{zo)rxr2i zBao(b0P9IGaE1mZq@sJ*CDU92ztZFd zACzh6)zovsoXi~jIAivm+n})CD z@JodKjQIVX1bTueh0ea@Rl~nwIraib!J4MXGf|oG9S}ukP!qcZtPr6<;4)2?IykjpG4YB1LYifc-#6Dp0yi?`%f$p7x zDBnz3@!j0c3@!2WbRvfySyL?89``yS+iSF6Qwg7o5^mr$BTK^gA3JKlHR#)R>&!B< z$IyP`Ral)c8`l|^ZAd^%`M`{l%&L#PmGqvN-ppJ|AazKCA*y7Djs?lQS(iqJy{L zhTvXI*!ret4}}tsACc&_sJsx`H6h_J@+L}|w%UaTT7zja@rO5=Zj{nIk#P-dPzgxH zX{f^MuiqaSCWjBHnVFQncpl{PYF*7Ko24#I<#>*NwFde5i% znh7N*Z^bpri9zx6C_vlYp?|@KDe`lal8v}(ET+JlF_K`xy%sWO-t^ExlZm ze@FC=_wTBXj{7x8{w9a{ALI}Jf$!n`-&1ZJ9k&iRO}BrRZvQg$bQ;}%_7s0_R{y-W z_{-?bX>|XM=pN^O>79&yoksWHi0%o6_-SBQZJ)z7yjqaZo-JZirRQ|L+ zN{az3YP{aRGBujA4qrruNA1*bbR9^Ht-P4(+}ve7Oxm>?ugHhh=h!l=hkFi8eZ7OG z0-PnRUws30vH+cLjOi1`PZ;{kPPN<7$E`8rAY`zRAWB0;%`m^UNHj^vP@!=a2joQ> z{BQG2{iEc9q;X7YVy|;b;XT8XCf~0P0pv<3ISF%{eKt>gpot;`a8?(h0psBxhpLWF zr=CXOGyvCxB8Zu~iM*QK%rEehGRKhoGdGUaB%n_A!cilA?!{{?dcI7_I+_XN+^tkM9oec<0XAdyZtSxu0id?zxh+Ch7-j8Mvz`2bKfS&;UT; z_5e^TK%}gPl?4DODFK`S0N?^xXrutft%i1c0BAG-)?YdRD5BB+o34h&{?9(>01#>g zVE(g@-tG0b+*4-k3v*51Y5`K`SJlK{^n zKtu+tg!$Y0t^B1w{7bz%K_59215{vc`{RB7g_Q9{wE`r#=yd2K7-$awbP_ZS5;RmN zz<7%S3+*rYYuN1x4IKj$3mXR)51-(+L-kz%9Ss8m9TNi!>-TNYd~QDnFiEgT@AFAx z-%~ZgdEiLKAMh~~mszH~ja+RM&LZ%}DG(2zf|81w<{>K^I|rwr&|_f{QL$&wW#!}* zz>4Y`np)aAx_YK&<`$N3t*o70T;1F~JiXor1&4%&g+pWGKE)>_eojix%FfBn%l}$X zSW#J3T~qt5uD-pa^Ltl!PjBDY_{8MY^pBa@mDRQNjm@81+dGKEqvMm)GvxWjZ(g_l z{0FVu^FNsVCtf7CywEW*F)(p{^Fl*+|4p0(6YD-7HmS5Kj)~*F2mArJWHKK!%iHjn z1=Qf=Z=6Q)DOdzo9wL5I`-|Csk67UUh}pjp`*&V*z%u~-FTp@Z$H2nCz`(-Bx)p3( z?B9ZmkNcP4|5FJ65~ANi{BMG~HG+0)0}~Sy=k|4%0FU7A|FxhNZo`rrH46}8pxp)& z1_>YqT*yG#VJiY_?NIg%^gpN(qelK*=%arw^szq|`uLv$FKF42A@4E=O1Z)dIBOK%n{J zqv%X0M)@O`nV@n5}C0~CNC*nLRue95eZ z0@689z`>kfuoaD3LctwYOI2;w@q@j%!EZGQEZcRXpM1?U#ge4+EdnyKpc9q1d}XG* z_axg_H)ns`<0^l?|IwfSMMWSbMw+*JzOuU8Ev!=WQCV_ye9$wcF(E?>x0=yk`OQhU z5x{Jv!_H(DjJd`_csa?z97|0@{V69*v7)RE(?J?1liV)#lScCB34MKJ7POK+e!YhU zibqc@Q>Y*nMwU%+N)DaS41c%3YW_u47;3&-B*kwk{Pd(9xPKCdNVsHh%X7hn1~d7iz%B*Z3Mi`HXSmp1Dw zSN9fTsbw6qFo_iR6{yETsUFDn9J# zF0$!-K72$Ml>_%aEiNqll#62px>ICFrcu@=G*EP>(UvP}^wtf>7|G-IM96@58x#63 z>nT3af%$^3s>B@zBZ;yL_Bk_UoRqq_17CJ$K|%Mi$n!0;Y{Y_d&Q2*PDIZT|B;`Wc zJk|iahcnUy0mBkS{J#S?MNcARMD_QV&z|M~Uo|Pz^nXYgO*pL#TyPW+%wx|weI-cLvUH=UVSI`khXNEy8{@j_m)fQ7^)dzteX+LXpL?2Q3VmX7Sx2wIdv*BX zjiiQ?=x{kq-|w75)$hjxm1}mzo5cQH*`bMf{fK-@_Ua;o=|(k!`o)E7l7sf?@gAf~ zhmlwd90yvhq_0vFvID-_!XKjgiv4tkR^jIctV&3Q#G|l#rP!A%LLuNJIG8PAqR3Xm zG-2&Y#aAaeZ^m3m#Im7ZnO9}U&VWg6U;CZw@K0$slpeFaqmZ5Fmt}+f$trJ z)OQ%INAQ(l?wqvkN-rApiFX~o+*VZoeNBrafz;-OrUu9JpXi&U`HC*&R>Hy$soD%X z3@y1OxLeL0U;i|lJlm@GOuWL#d{OK%#u%QMTpcmLlfbUmH5U>AQFtWnCTaj#yoo>3 z%3Sq^;Xw4KuAZ3_y5G~c7G7q__#|oC6Dq<4Cob{Pr3`>oNrhE<94U?O$)$1|@mA`j z8Yt`q8WjDCjP+UxrCLr+K37qhhA^W5f+uQIS0;Ibj(G-)2L0dNm?A-KG^wEdQ$teGw+ku5DFNV?0|QNi>tz}#1g;T=ggHB za5?qc*cG<1XkMn?OHaq4i(J=EK^pZPtx|?Vo*)=CC*E=K*goqN+zQb3b7v_Er0$(} zPW!_5a!lM70a|4Ye={kLW3 zeF6{_c6t)e7`D{gG&xKA;9AM;$IXgA?{GYu zRY@s90RowDoHp(!&kzzd*?z@8Y+iL$VAzx!`>r$5@tGW+Y#WPRy{xIJM4UF*SdmH- zYAb&Y%hZ(5!0-p{*qYxEL#PmUzVvNP^I7vhACqMvX312o2qNKXH9Pt--OC^}wFi-3 z9n?0g(0<`Pv-q48pySy7fJc30+GnlBpgFf7@ZbQVA8%rG# zRXz(T43W1qa2IJ4U$&?@@LQdR;71Sm?rI@~7k{-X*V#MPFj3A#IV_=zduDnFYfacf zr0>_%PK-UOT>ePgsgG73i($9>BOqOGjyE%?b@h>s*bd*PxOgy_&CcATdr=9*(!}dH zt{Rkyb0k@UFbc?9+NN03fcH$@AOCRv7@tJz#WRDFC=@-)$^1|>Ne6UKsS zZdSjp8t7van;Uk|8CkR^7^$jWC`qj(zTbac30-{ifn_MHaA0$u@v}c3OQ2^d!HQJ- z915VbR<+hHKi4BKPD)nqPFBb4`ZDC5=I_0%JvN(Ax11gU-}NIZ*{9(6HRC(T-lqMw z`=Te*Au9g07>sFo-Pg0-K!Rff8Dl+RuIn_eBG20N)1I5Ot|KI4{-JLJgDxC)qYx9- zoM?RUvU-&P12KsL{DpK+Y$a!D3)q5MwH&@bbrV3`f#~SRj_4SqnH5F!_=?iS{sdpN2mLqK#BOZ(~`Iwl1H>x@3 zG^sYe4gD&l`Z2^9;d%q*dohrb#y65P?YQ)mT*YbyL(3(lJM9%5BnWU2J8mrED z?5@ans;(U1?$#S_EDSt&;_>N_E7wnK!mf}jtztlDVpQqu3cY0aqvrAny&1f4x~EHWIo@Qsy0uG205qwJVvW2 zS_r>L+#h%Z5ISJ_#5u021W92-lw9+5wkh2%0)i>zgQ|K|;mf|K_W9PxvF#M~$%o!% z7B&T+vs~X8exq~WtXxahQ55l_5*LG}K9n@4*s!g&W#xJUg+{t-OXRP}cMKEn)??SM zq5!IJ?8LkRyz)MZx6_bN=2Gkt94DWmFgR}~=m4Ld4iQydR_QAf7Fd@83Q6a80A$UGdStC}55Ey_Vj?_`K>B-O_{Aa4k=N z195++jh2Ax)ivQ)95ayiSE|+=Go{TIwO4{IP`@n_ z6BGdHMFHQZpIts(qL*(=Bb{K2dXRSPIZ!BqwJP^oUw_%V zM;T9YLN(UTQoPCz#_H_vUYXw}6N$&PcjP;HWrwHEvBps=XNmUkLVZ39*V_G2xiId)l)bFlf2uHt24NQ0`X_ z_3oFLQ0=BU9J1{Te)S~o`?EEBhAZJ31Pi}MlDnPbF39t@Y8qqX#J(B4zwFN zR(T0kR-~vrB3eO??-1Vw55Z0^8VtFVZ!Cv~)8-jOwv98Mktphf%IE}3Y75u@tgW;v zV$XHicjw@-GqO3@Ek6tmVV)4bw~AD5S;?Q+j232X_kin&eW0~rKHfdE*;>Lu=08Ws zhy6MR!9qS*l^c2{eT&63R|*^Azf&Krxb}6|$Oi7$nLG_`=9$@1 zF+u|czzR^nu?g(!&0RfYwJ+yRGAy!qap+QgJST-PKp0IB)E@0`N`Ca|LSi~h++8yK zjex{{Cd-R0VMRHWGP-nY1Tu}Z$UiF+JGF4K!g^S%xa5ex6V#^bYMG0)TsaH9kJK#i zxP9b4_KZD7m_awtn9trS(7S^#2&dB9W9YA5C3g+CH4}~7+Hu_aF{U@ComD9q z!)49RX5+RqY=@|UW$gGP8TH0_u4J~!oQ+shOD^+!_zuuzIT;Dt-01*;37RA0Xo?yw zW87nq(&I530v(u%&T_isJDc^v!{!%sH>^clH-uwV1Pw*kY^$lS43=IGv+Wz^FvSv3 zd|F>mv$l^e@Ms}8Hho;g0ArjpVYJd|Pl}1-VdUKKyKk(U`lfKY)fA+ilg%Snm%GId_z+CtwAT3->9EXP2ku3`TgwSjE$m^ zB`M9}sEV@ML*DHYxMghiS zC}8W6_D2ZqsEf~w)-?WxiFZu(X|oi3U@nCN>O+GK-2hO}F!^pX4+@C&MiAVzXm)Y3>*u?^qpuy{BD5zK#Oa zyM6EY^(u|{?H1kMvIbVPUk}kl0j1ASfYPp!?Xq9M4IA7ZdJH4ksZDT_wH3j-?@1l= zITu^_L3CbIqQNwy+E_D_l`Xnly=L*pBG_WwK;;phy@Ni+Y$EphNm&x4V0Cqc$5Sxf zcmWKlZ~0JGm1;GsXLG?Q;yct#H|A>VtUl!`La|X5mi^ZBHI@B`+99$NPRbY==V|gS z6hM3fT7ak`unvO6!8!VpDXxUk(8A8bOgiwl4<1q;SZ!Sr&F_%TYhUzR)0hmODMi_l zuH#w+3{8FnQ~j*O7+GE$r-oIURU=sA=@-s|#K|p9i;OWgm8b6p&nr8*0Xmkc=1!hM zn+~jOv#+7jhS+ms>(lZZci930NXZP#!w>~2AXIUqB9@G*&f6fu#z8;mjCR&QKRuh%8N8)7@zG0HX@ z57z9e^LNwl+8wwwd_LgTVkcn*Gb0kE2Gep{^Qf7;C!~ z>n2pX#H_X;FzHJQkw+-EIOlpiQ5ofCsValA|Ex2AmqX&8`}rqr7!^j{>7dtUN{P-6 zBQ?yW;ZB1~2}}3=SHO{xnFXC|>#SrQ`33_u;%c@zGVKoXNk(_xj?z1eI!{BHE@=%5 zxi>GP5~wW2y=bP9Qt*SWMLY!eP4y~BMbvIDSz>gME_zH5x?ZzM@8IM-)jZDBy-L$Q zlFy+P!|#+Fu>pOdP(uD|&kY5v)PEf^`lZ!uf_Se`KjKTIyR97=B`DmdlljosExrp6 zIF^iGV?-0oo48?~=@|*nsDgT$6J~zmi0l$blRUydfkjZvmZrdchhI*Xm_>UWNW1gW z!iL7mHgw|J=!??fI8n#kwC!#;bV$$Fdu#NsKj#RLw|>+}7w|Sw42TW?aebf#uhb)B z@RrH7?4@xCsxv%K(U%5UADEwgo`9bAHgP3h@y%_u5Usplz5W@VKao)pyLd7{@lZn? z0k*?+IS&Qu=r}f1Rz|LFlSi!2TFb?S@iqEld9k>orQg~eoDN^1(J4kMtBPMX!LElN z8RqL8dOR0#X^Eb)F|BL0bmD*|89esZUiaB0esB_b;dRmH*j|jyVd7?&?Y$tZv;dY! zp2^MovhPxA1a>;Vkxzu+k5qwB0ItV-jfrCsp`sKvZZfCmu?m-O=9y*s6u3MXHmh9i z?{3Z7r3+0Sv`bYy2aNd@NHleaCV%$sccLAr`wkZr^e#)0$!C3wd1YzxuA53XQmTQC zDH6N;m8?#B`%;x$-u+OGi9NPJj?8qk5T@K^#|M`EVUID`#c9s3>f>cUtu(`wm6dsQ z#)IPb_Xaj#3nN{4m+XhIHUY*J?%c`z+nJktf)~%mI}oElO@1b2s#zUYUj?J^i0f>| zMqKAZDdr8g5R0>nl|`JSAHJC$k*YAi@1`$W(LYOvXK zdNZaPC@o8-{WBl;cHtcOFB;l^+EJ~)L;2l^8NROl>aAB$jpJfww0Tq+6~j&UXbA2v zoAj*eOe2@vVPz%B?U^WWi7LxW3NtrxY|IdFgxi(K7)YKg9&Mt*(H(g8+JZU{mg<{}>gNQmq{^|nx>WovY73=ZqYT*g0l z{w~&O#DrkYFMUS&k^Z`~l9Qp3KAgJS&)BOqt9nQzW>@fjP%cKt+${Aor+U_+zT`2$9WtA!xiEkYl&=0{mg?|8$KK3O|Yr;Al;Rp=Ml#UBesi{g~sy zc;;@`j?L*A`&V{F%JkrTy(SWiCZ^M}EtwpQ8qiKqtGd_T7W@36u8s>+v~=OIc4wok zd|zsMLrsJ0cuhW=fMhDtXY~miQfck&iI1Yx9%$TU#UknXSY<2rQ`5R|QAWMKjRy&dqgtTDe|;oVK!qZ8?%48UUE!g4aZ)gp5B z@)-DwlpazGb0tr6qxfz9 z31a@pD9RqO+u;_MJDBfZoSDpAN6!+atFVvzo@sheLp$dE>Qx7^tDKc#9fZ%T>BOp% z{Y^f7((&ZM9$LnZHuixkoI7{o7r_65^T`JhYHl=ft^5F9ml&w=U6(zz>5kJ2`utE+ z?{EszoEMg86Zb0OKXUV`5as5wW|_$MDE+v@Q(DDP_09#~xd((6*bxhY!r zV*D;ejsn_E)@+|?grCiJF3Ps#$58??7NYiDjfYUs1|M=})n=GP^K#6#C23H!PMFmP zlw%|I+^@2xAQ$X|z9ioL4qKKqeW}ai<-WM{crIj8mV7S7lJt8ar)q6wU}y;pwrZ%? zICZG?*hT8@t`SY6SV*wjsXJE)|90da3#lm1H}Yw}_66kari%1s%#}L|2#1Me)xl>< zIU_yUCqHSMvnDS0M(J|jlgvdJM`R*!T5U)Qtji5|NeA*Y`0uCgCBYSm>Wy2qEb1R4;_G0Lm#6a|Bi zCF>9gDRA|!W~Oh5TW>_9;q9YyD3q6ZT9cW&m>n}z5A|nUv5!?5%FM|jP7b-s6_gsC z;-f8Q9ZHL+?xdxj!jjoxDkNR63e;T9gYt(#3zugNOM5ipYPQXq$P_W+FrgSiYsXz0 z^0w;6ut(bXCH@_lCIL81XXH!i(NbhFSKY)n7`IERi26e>&}LcEkN`2UrA$>;ZAIJ* zxTUytALpo>WEzqWfsO*S5R*fhYqlo1G0F)dIdv}K(pFiv+53^HmJE}Y%UvvGQ95`Qj{oy(!Pue?{CyO1`>YEP(d z(Aak>e5DSXM`m~Gg@*A|Fq~>R5X1AI8zb@krSOjr{Pl+7GLftLgBFJ%Dw-h;(wD13 z^M<(8?+BM^5S*a4{-fkieC6FzUWx{@Cl-$i*Cd^fW&CKi4+LXyVgx-_Egq6}MQVbV z@0|vu5+SK!OvvHlnO$FElH2$*%-;D^H`c72)!Z+HU?}A! zRtwtJ1?#V+uP?MbE6kJV<9U3g+v2mDes@PtA}_$tkL$uGoRvyv<5ikuK1Oiw6S=2d zHs6ro)lZ|1Hd&ABzE;u5Mi_k4rH@o?EE8MjWujmq3@}oag(wpUm&o5!xi>JMwR&Q2 zq?N4FFPqtmUjkORe9|cif=^|`&$=HBYt(*(@tVC=A9!`hq4Sh8D1`a_Ts6d={Cg+$ z;lsCQuCtw%jEW)9W0BCX9SidNYL2RoTH})~6ZI$av+s_1L%b$S6W6Y3wWdlNi)=h~ z8e>Ui0wb}#&V-J85bnVTwl@#w=XPqo^Jbv{`GLYb1D&9AjJqlWe6732q^gFVjFeNY zqo*W+v71g)XASQ|*Y^$S)B`taPi*juHA2(_MKRqWJU7`SVa}=;zl#B2I0uRpnC|DfH^T3QJQ->7$$E&095|2UhrO35+{Umtm zC8|OXE%#+E&cDvrz1b16KmnLWWfLddoTkpX3;mV?9BS~M(Q-9uW=`p@r>iwmD}soa zYaDwN0OvHm;jBvr{j@R#NjtUM^0E$)&CaANdvtfY>E*Zjkk0z3J!w)Ij_iwi6zfaa zSjJL|L2uK2L$#AY!y6;$qptB;e|E0#W$a^zjBLVG%eqn`=xO;pSgn~en)|!6`YXeO z-pPv-p)YRhxwA_FC$$mB>4Cod2=b+H-YWyRiu=a??;P~DJkl;QEn?R|J4{>@4toh7 zyx3ykudh#f)##Rj0^GS$Uz6jaZC_{)PiSXGuFkqHfcx>36x|!nVD1gbsE1JHgLuQl zU)6@{%0%@(>rUYkD0_<*gCT64-uZVlaKqnPYsa1Tx3F8|u3YZH$RXJ zG!mK|1iFb0G~IW)&VJ{vy*%%necpZdyWjrqE|@TBs%qA#8a2{CYT~AF3joa>HBB`D z4-Wt|z%KxY0HRdA>}>!*TN}6v001dKghvMufOmM{7l6kK5dCov0C(`%{{3DLPw;Pb z@Btvy9w7W%9TV{PuLAb`tM%W06MV$`pFMuW|9@)ZfB#7E@AvG#n&Gwq+52|RZqBZD z&M&wmMXv#}Dw^7azj_DDANPEJ+|rC)ikglE$_O_C$lm`%tN7!-0kov}?D*da@Gb-R zw0H!xc(`_e6C4E*-XGoItK;Qs+a zS|U1bab;q9-6tfMT^J-@$9*E@Q7LU<)Eh?fN0Nz zW@YDm&dtmJQdVA3Syf$ATi4pw-qG3B-P1cVIyOErIW-MOEG{jttgfwZY@+t|4-Sux z(I=4>dE!EUS>iP* zgG$_|(iSovNj)Uv)0e~K7kQ-+e5hZf{XyA3Mp)qgC(8bvu>VQd3~&p;|DzD#;}Z}O z5D*X%6M==8l=xR6B`5u(kpHbv{!yrY73zO4IIt5uun$5)LK5(shJuWO=D%HVvmjfF z;NSoy0UpRq1hfDII5+-^17g{nPgh~5q{Vk|z#=55qVHTwyP?S%rcSW!hFaRHHQ6U!*C(c+UD4I&t~%$0hC}|+XrDZXy5k6^tYK$osUZecvUpP;B$uQV z{)DCChhsAOr-GRjVW<{`YAL+U)XDZCLa$eQM{P!99SwDEdVMc^^UZknoCan(tsY)k zjdYhdxp@*IUUS9VK?J%83uq8?_pvS6EU<#Vk{{e<_{?CpAS1$*O4DhxN0Q1-X?bDx1e!gUClvkZRma2fFvfXN5;ajNPiv|Pd zPFP6Obre&W`?RmvCzDMNxu$p?n9Jl>v&o z#^^YN2!S3MgVYxX9Qr>)-A1W@SX*^@-LqJ(poNM>GzS%zh$!e5 zMoUeJ$Jq0SxZwASU?-QuG0j&#U-L&jHITTro{f4W6YWo~y%@`Gvej2)p>F%Cf3i2y zvXb!Xg|aU_4jtc|cXwrXA8~f-1e)`qJZk;UBc1qGigTZrg|niT!YkD(6LeA?YcS}g z+tL{(S*G8%>%FacfB?T>RfhX`;6+m8dkqJ~acZ9q;ef1+l4)OMN>f@+(c8XCN(Kh&%6Sc{i#UJ`ttM~ZU|ck{ zUOLye{B5#Y+?33kN1mp)ulB3t>p`JKC_T2XnZegG7yZqVbuf_<2hfPeK&crq!levsnvsdlBMpPc~8W7*-7OGUwYe(C{=l; zc0DG8`z1j&v{6B3m6ZdP+ZBdMFSC#KGke(MzFN6GNwj|QR+)q=hO{I~1P9m*an3k; zGJQv<&|Vk0Kc5!tCSzjd;wWSC=EYQDQoPERu;J})eieg2qU=tdF7h}4r0HcoX*fY0ir8WJrHB(1<**W_h*Wei078@JI00RDEL$M|3 z1%W6GONp0?CbqwBC3+w{`8f^{e$+m^Gm|(QJ>7|b=}rVt#IkxhOzPH*aP0RtRYWY> zKZ&@(A7?QB*xTP|JlxtePeXT~X30)r5f*~wM&Ig~e~JU%_@jT|0Q*~t9i`W_X_DA% zg00;pF0bh4MiI<=_I;362x_w+5J0X)J$HAmDvdNL9lzX|(Xv`jqv?8{#(u?_J(<42 zDknS2%5b*kkom6s0uE@C^%W|xuWR#C_7(DT&KYuY6Il+_Qcv9|;p{t zb(B0qKz#W@r4d5n1=;!qR~*2Akts$Ov~o^ou$tPAeH?R3L&xtJ29iO_D=B(Ta5~@w{x;#}CNa(>pJTiEj1WJ}L0r{R_hQGvo&@k_p*`< z#M?R4Jh)tLavXAoH9(|mWkR^ewk?dRgP-%38NdCJE&QTP>gFz~4qjM`;#MrW4+roD zbwQ5s$8f+w(jA0?ByzsVr>2!}`XI7eHifye7QV|M;jLH|QjJv_)nk^54LP?w(pQ6=`BirWqN3U;az0SRt zOm3;~F;DvgCiIr{2eJ3Y=m*0Zukt0OlrI$8>TRWc_U`ui@JF4=cGWuU1`%`S0?GYx zgG>8NFO7V2SMbyisbpxwqm4SF=p#)}aDcgm3wo6!k%@ToPCshf^&5vMay9W{ZJ`mf z+r}(U#EMmnk+nU+Tb_7nYhQ1tdV6_|mKGk#4IDtFVEe_(0m?LG-)Y7_ooMwzlbPJY zLxO@BOE5D!X6TG!>U{OQ=p!VwBKpqU@x72EnX(8WNk`s`!(>MVajXRiYu2^0io|63 z6*^Hm*=S9-!_ftqD&jf#oEYT35nrX(%GrYf22U+|dAU}dUc9v!;vY(tQEm_4FZjXHzJ^6Rj;m;jut)38Z8vzYD#kIJIeBeUVr!f_FiGc!_J%|ULTJy<7&!(UFQAYxGpc#QW`wnUv;ulz%zs`couf0KoGpTRZVd(`I50lk8m^;9o@ZJ$3~ z1O-R|ObnI-2Yijr#m1PNzb@(8#fNt9B6iP6;n4M!k||bZHKGQ$CEo_^Z9l|X)xJ4O}>l>FRI3rnOxFP`ORMl5h*Bw2G zq)0b3sEg?B9h6S>UUQET%u=pRpAFO3C*X|-*i+G;6v$AK+7lQ>#0~efnfe1#COxfm zH4R~>EXN6agEIvKLrVRRlxA;&6Ak;O^4cb(Ai?GmkqadeN*w6O2TocBlTJGbO)=;B z`{4>_)}b7ZrYeilF9v%pU6U+p)&PQa=90qPn)nflu;mP1O^)j?%=FA=nDcJnRaK36 z$;z%fjQeK8NR;@{&iZ2lNdJ6Wei()6%*NXxSC{7-xn1^ox4+&)b@2NSh%9=`UZ|5b zbfLS@k&lEd(pru2qlDLVBj%8w%nUHMj>?W~dipI%^|%=aSFS2c>=o5)1E=ww*uIAq zF=zMEMV(d#dw3pqPsz&i1O<{7xTB&h@SB9;>k0NIHg!_n{p)+T91G3yUS&A-NBQt4ib>(GUCz zH#`mM<{CyU9aocNvu z)a}QI$M;Ea-_K>ss!$eFMMs;`%Dxrfr1j{ds6a(kU}1x@Jtr)LBFQbVnnga;XjByr zD7MD|A0tjAmkir?FQE-hCZ8fbz8rP7X(x7ohCuemAN{YLa$XyMa(g4uZEn9jWrcS+ z=9yd`$tdj4y=DEJ69)T9jK$(<;eej&3(d6tTo{cJ1^*@%=g*vX4A#g? z#G{LZbMb?v^!uGI9026tfaO%BfyJRyG9w(Yz|f3IFk@uE z8$3_zfF014;(%{gpeOvXZ&|)=@Nqgwe4DF8nd~S;ahKDTpFt^dO zC@ocVbgumzTeD^ZPaZm{O(O=mvBz!CFzeSecOzAxI$o+>JY1$Q!^)M2k}(3bS^v_f z`cwlH2PmgY;sBxq=$?~rY_acsboD1+qcJI-g3Jw>S91yW_D=4i86)r+oqUt7mkEV5 zJ26^eyslOp1~vgn3C~uqX}d0lb~I8fc7FPF$&5*}e&QfaOUp6e?I>vi?ssQG{$2Xx zP`8(llzGy)_R6IQE7EMm1Mv>K{_<$frzjk7PV6>>xu^}USLFgcxsx+O8pdFab|wjV z;{=eh!eu0i|9z02?G{i>2TP*9@-I zv4jIoDK}tf;WQkO;P^H3pQO@WZ1_Zmq%j6^RAi|0HZ8yE=hwt*zM+Gz9@FPS>#z2x zBj!;k#L(#}NS5YYfI`CG^SYGZ-*IN$RY8LEGnq)pI-eyD2++d;d)l0TX3gS=CL1&i zCD1j;jL!LpcD$X@D{}c%)_BCx*gDCQH!5K}@zHIVO_XraYK1WsK3Uo_z_I(E?hlJ= zkao_fSDzCRrnC4$CEJ%wZ-3v-tdyRR$Qg@uEjNg_mb|Uf^&DA8x*Dz=r_7a}#o2Db zsC3nyg9GVNC}u9SZK3jAjFCf#x_s#6UQnT8zl4G(H}~tMC(9C-B>~e9_emx|tN%~J zbU=As!$^qtb0`WIh574yC3xK*j7n=jS$Sh2XMgJF;; z=T-S9Y-^xFW`<5I^0GB(Y^c#R?^7Rfh96DLF+YhQ87p3>tDSa3wDnn&)+k@TnrD$J zJN5H1b-~|T2kL(zwyTK>9lID(un42u;H0rkm6vB0Ss85_b|h*TQ5D(w#M;9hqE5L> zc= zgxpjEltTV<;U4i<5vN})(qMcPEraDZFqTV7k3G2J~oupjUM+NUED|X-b3pB}v)Vt=+-bINt)HaYOd<#x_S`%$WCgorjrg=+H_{EJI zXT=c!8gl8h8<*F5I07xaCwFk@#~T|NHuas(fF zST*g{FL~bp;%|T(^{qlURC>g{4$`Ye(-v$sBjX+9ViK;SlE~)e0!ghi#_|L0AJc{9B+-Shbg%cP z8QL>5AAJ!dXv-Oa*!1koVSU8NG~IbpOblYab&t^3ls=U(%5eR#+DL-E$P@rsw*i&8 zG$&T{kDY)6f`b>RPgyF4Fc(5`KxEcGVVx2|bo!Drv6&8H-?3z4pLFN5u-+y=oRW(8 zMHfrSr}dB2aZrR95_V4f6N=;)!(NR=Yhggmpj^+1Ap^B+L`iYpZ*{(k<)97oXVY)# zCaBfbJ;qBlsP?`l%X#CZW_yV7Xn+9^>9>=JjK|L3sZ7F7@P6NhkMy_XHP*L1Z@o4g z8uIXIZf`7i_}RxpM(KQOWQj?rPUQWuqV$TIR0{70dR}Wrj|9EoR*6<_evyr4VJ|;^ zp5Zr&(>cQ8!3+z~95**#)GzkUHlzC0<_^j=@tJD*d<^-%%hTCa1^?6@h%}CGk zA7Xu!py{X-wk1UeC(Uh$StKp`Y;FHIgeBVx5j;&(;qv9v)$AA|pGpS2B@-z~`C908 z!tn-0&ftUk^)|wcF{75NA;3%04vt0O7;XREGzRttG zJ|1=sHrH3V9=6J)IrQ_FQ={Az24d5{!_J$Of#Z_4&yI=PIL_DO{ zbKJg)0ryj2Ike{;8is9U)xjoq-Q;`(ZPUgMG#}_=_;5hb3^i6!9V0dWa|Q>fTC`fA z6+zH-X&iGy_a^5L=imM@_FH3%wnPTJb1^!%F;8RRU07|~C4uws3~n4S>UOw$fVaQz-^*E6cf}TcW1-`| zgeLMRJpi)X@e+po)NHAC@)50$pa_GmHE=Lirp|LTxp_o$C>}p;?7Hvh=hLp8wfU@h zI*FfqxfHS?^Sp>l{SphEc)k7RkGQ>J5A}!!skok%`F7R%tBkj5mUrN^hDn2+1a=Vj zP~-=|>oe@^8n#ES@@xI55-pm4mF~`t4)sPZrCk1b7o~hqw*swUGa{kc8g|O#4+5yI zJ|Nz(#5m&s{~T?ZC*7F&sOuY}4lZ+yL&T0CV)_etn!nHt70`#VVhv`xUj z4|1S}VF7WyqjVh533^{4_s)}`>(OXXDUfZ;ubDCnLl}XIU97k{hsUF-aNeognL3x=1OBlU)kR8zy^3*e zH~-Nq^gQy&`Gl&Ajf-3#|{Jcgfd|GXW^`5_tO`DVc{Vw@?8U#)11sFy2 zYXmGDOFN2jLa+t7es<6ejehUs-c90Ie2>{S4j!N|`I{8@T}d@!BLF1zUxn3ga%wBH zaTsF?rA!^)O?FZ!x)dBSQ2N}EZqXQjq4|BOhJl2~n+J)54yM{d-;y8PoTE+^k>1m% z>)=n7<`L}Sa8OgIHfTX~^^RX1uq|N; z@Ai|BNBb2Km~3>cVpAgOtRq!*Csy7oNFQYpRK%Uya{HqF)4J940;yJ##GKkx<;v&9 zN)L5}zi>Ttq(j@8oD25`nV zk}V3-^a?LKE~~IyVkS1wBjuuTeFVWUreW{qw&Q>!ni1$hvD|6aQ7MQj8KZk}z*E~W z=)tU_ZwZK_*?=EjK|#*nNWsp9Vgeu^=BMcqp!JI7@x4EG(9B_1<`sE&1aqT!b1Sz? zp=!Xz;6H0iwJFM9$8y!g zY%XclkL?PSSDPK{P0LJY?@^|GNV$p7olTO%6d;qM6)YDnI6&yU=*^mub0y?;e5+~h zBI&)nL5^SgD0l+e0`ZpJi(&WBlc)p@l;Ux8MaiYD34iW!p1tBjL3jD=hMHLBY2hud zxJlqeza7E0h!B=+S2`B~rSxi|=Dg*dvuWa=lec;N$}e!xrSc`}lN} zkg)mPJL@eY>NhpUk-I-_krSh>)vu;eFbuCrQZ+)+$86N?Y@2nnWn0AUY@#gUa83wO z^>UrO<#OGHes<~arif+q3hIl@_e%1lyQ%@NN#K;+CsM?Qm58xT=d4Z|Io5IE?3Wo4=^PsB?%H04lk;{xbx9K;U!zl!_*|5&{W4RcIflE2hRe9 zJcxx`NY!Ke?sh8cmCHDq zm%mPGqMng+S5IcfbBWij_G?O$=%n6w`Y2<~RZJUwWpb9@z`^l}8uYM>?=aAKG|(rX=her!l*s_+0l6I?HC%A20b_2>?Msj6LEgakZAM%yv17tG; zl-#P$a}+q>?or28Oi9N>M{!U)72#B$>2G{B^xj1*@OVyMY2srN0$^;ixuQDY0PVa} z{Ol0VIk$^IAyd}3+9!;4Q8vq2o~l3W8||JrASAsaav;Khx4-8<+;l-dZs+IjWw_WZ z4QYm9Ov?v(LMpO321bgSfN$Nj%9kg@l@#nbIOV*}F7Ir(YcUruwCG#%#?w50vJY%9 zxZZ82lU6|s5Gd_}5wA6|?OVtRHlcLYrN*=Cg-$}^xdnh)bOX`5sMh zw054XV0m^2+DeZDNMRwqEQ=7dI;5gu7p+y|J_8ZhhS^LXS^U&Q%+~iPIj4VkB5f%K zYX&2l0gxxL)2^M6atjRqJTl44wk3ldbm3ypWI#pnM(xfZiyTR`&$+jcXmPP< z(67mRvLn5S>I_HcK|R(6;lOaB)u{uNxJ*?USEAcv8Q%7n6?6$G2X9o{fe>z`-vd>E z0nBgpnu}eS!(Cx zCc)`r6B9?Vyq%YZ3)xa7S!_=50DfWuBDRN1TnW_$Xpc6dc=>z|Q^)Ryg`OApm{;_l zXYqt^^pg&8*`^LSleBmZr~ByEPtfsGl|HI)yr_Ph6(}3m1^pl+1vJsn{kWCy_%cha zu4CzuT2zkF?YJ&NtDwRNsD$+f-%O;_2=*8#j zi9GMr*~8ecSS4y&UnOPJ;AOWR;f=YGWtVe*eW5^zGLV{(=2eh-GH1%_HXEwi<3`sb z+mQgyU&-YG{u7WrM+gh#=Uo&vHZ8ZfelgpnFL!;o_tV%Wd!Phl3GP4Mjr~iduEkJ{ zw_WoQ4Gx&GUnl5oYIy>}!YCXtk01Nh2s+dNJ^ohUcArFju_O{o(!{!%aRC_`Q({>* zso+?3>FN)op_j)m3vSV0_ z3~93Ry!qVEyZTmZuC@VypHB&T3E>=Ek>=#tZkY7SJ$mKC=^H)mi{B@zzJ{+Ru(`g8 z+Tn^?s`4t4L*;H?I+MdFl#U*9GH+emKsr>vs*EmWbsy{0il$nhwkV!@?19hHInYk@ zJkR)^eKRA(Mu*tf5os8zz`4{{|9(`tJbu(Y(?mAzxyZ!ab1{)(e7daV_-papD`whW zwh^ES=yf+09j=)9_nE4S5{EqW7Gwte}jcuat^ zvd$UhvBIK5HhClSxlO4g>1)A!?8JKd0X$p>T(omVP^%4#{Wa?IGYe!P80}ftM8r~V z_;W<3Ox~-C08G^1VYhF7^Co*rqMYFpu`WmeITHXgA7HZ3T@dIF=A4!@#GJI@0RKsh zkV*tFgzXt=UK`{*J8DL#AKe3!FO*(@+)#-F$iHU>fZ?Pvw~~|nQ0#dLTK7C52Rift za=Z;~tq}YO#;$&*3t@dh=5KbyGW=;+MIc`Lk3ZG;v`-p9RY6aHw!`?BdOC?a!P?7!T}V`jL^N2-vWUfO$yb4yEkJdHm|3$ zR9+Cj#7=Bz&=kP<*b6)#AcePTfgFHPHLr^;K`^2ieH_qt2ZBiTzXbhm(FsMHp$ou7 z;KWTRG62nl4ITjTZUCfp5sbFIA^FyPAZp)?CZWawv^P1x2oU8catj-X1t+X^x5ENc z0Y-*$5tHXc7+Y}C=Oda=?9FpQeL?*iy8dVsilpMiUXDfI^rgT7DywN=@)bDgC(Xi0U|>4pl<)yIR7=D|KiX8 zd-l;Ah<)?){Lybyhj{#leW>%eeD;u@>mwXri^J3o`OG3-Ds^07TvB~$Bowujbd7v3+P>Z`YC z*i7+N+c*mxWF{u%R(4XPJRCYV2Ze0MmTuj!@BY!+dm|j)TyH}j z<&nBo=^TNT7zVQ+Iq4kyY18hNjU4n1=xC(c(>9=gZbya4PYoZNYU~L~;A@C8{^$`! zPr@rNaB7WbmnZ90X@z`E{2b)ft;unP%Q7ZZymwQ%yN$JV#GliP%O0M~B zQqAo`M2J4+wHNEJLzG+AasV%ba8&Q{{R$Lia^2@Na=VF(OcY*8t&10H8){R<$_ovW zCokI@sfERLh`aIx;PHxhC{dvkmOvEmf>+a7hZ3jwmifhyS$OZ5i}0Sk^yCOUYd66y zQlW%Ho$ZdLOOH}_s#%~z{FWvuQ+eB^`o6){2!2o1gVu^DD68;6{RO4P)15(D2Kc+y z#g!0O-U5af#7c{@ab7>cxPjxak~F&BIH6s-&Kzc4l+L5=)8{y#kW|*_)or;_->dXU zJQ7sArVJ^MuaUSQo0o{HJ1#jsG7}wi6p^`8S?aEpH!j+67B2dxK9M)>&a()KH=e>0 z8m*@uIf!%;BgcucpYh9^(oRoYnt8Px&Z=*>LELto2g@;67Mw45@e76d$~g1YnI+m2 zCe#10`h2tN!)|rSGuuYMcVz*Dw3MVK6de5!XES~h$J&9T4;msCr!+6Xi&CmXWQz+8 zO!K#Y^zVfdGU-oo$ga#X>rndoqCBz?+O{SW+fL6+dbLP->gp=udnd^F8_q6m=|rZz z6Niga>cH5 z%u?oE9Hc$+Q!3K4V)O~kE#A=|62&j9YZE^w*6!@diyuqjq3%VWX<+W7#DYW{)GZO~ zZUf5KIm`IoB^k=>b+W?uG&1Am?GvNobttdxE{MI?;!+T+(L$LTk1DY_WZW1(_{3gk zQ>*mBQiNTTuh67m zLxj$1SE56X+1~$JS5`ezw2Hs+JPT$}S01l-oLlP`m}gstCFI(dTU zn0$qh7KqruiUC74z);?)@vPMGT4`oDJWHFcM8dveoAN{{Pl03XPK zEx}?PEWI`-*6&aZ!)O6|2_Tj&H4Nr;&x1!7T0o}-gw#J$l{M@>{H~zx?dcvIxHwQk z)Ovf;^;YABnn=fYQQOm8b004f?zaJIT^RmU2H48#>6>T_Kfko z)|xi!+b&ln2~F}#O*Z7D_Xm0i1QLuP$W$~6g==;m3oPTY29}je(cqYImk7q%NsBUhU#>CzqzOk&9i^GMdw)MYTjn+=Trvom47I18hazfdR~~6rB-M5 z>V9k(Cpm@(#nZC8;PjHDY9!-yNLR?lfcQ)`@u%ndG`aeK!V_3jmFb5M-$|B<^O@Rr z8U4XDBBJZmHs+8C(2dylM7;&(DZuZa4oF^&5*5ZZJ>K9L-g&qUOYnn(I`fq z>$S+P1+kDO7Ic~+s%OGImeDKMw6eOicHF%_r>0gqsc@Hpv{ao^Fk(c~w=__*hd%(q zRMAZ1tB>q=_2obbw1dcJ@3s@cOyf?U83XM-*E}FCCL*l6AwLhP#U>+*0_2 z(3|#KvRh(58};wxq)0tAGBunW3SOOnR?oCqz&TO;a>?+fDeFB8ZE!nBfWKkgXz_lcAA&AhHzcx=-YR7`?cYu&~36&w+j;tZ`*v72Ce zkd|^edilku#FvZxQC&NkF*S?zn}A?u#Q)X{N&VNHrzy;RP+y8LVOu%RoD^N=D`PRK zL!CMxx8K46pEtHj(VuVthl$wv8^{s-6@Y@$qZ2fdAwk}Y+V0CStu2%Z3io^DuTmA2 z@!4{@3oz@(zrf>pRobBb3GM}JgXe~n%q~@q7ui-MW^!qi4u(iyHM&Mgz-~pG(OG3j zAhV<%;A^pD8Vk&MJ)PUrs4(2$VTBu6lCwOZY_cA&l?XNr!!JzZ_qbuDuhfC`)S8ge z3Fe?4#@zg@sMe=h7Gc-x?L^OeRpGPQz`okGDAyjs1zUpRQL$%>6{Ce#HPNCr)oL-9 zzsU#d)_ghS^6a{EGXL;A`|~JPyaib%M)qUKN#wvoB#(^uNAS{*5x@602UZGv>#K=` z!X+!dlZ-ty9Kf=if8?9=Rh5qQ{K!}N#iGZq+;lE-8ZPU!`}`7oM6dz-464@+&O4EmubDgemvugfH<(R1GqnhwU?g+$*P`RK&SClLl!6vy-`$2Pz5=(P(Ytn-^ zA;%pi8CjpRuSoPAd5-!bc<%IGlR$M{q=I-$aPh{$w-sol}kxw@#vP7mKUm}`jll!YO}S0bh^sK0ZLyp8^A!zQs?U@ONfQFN`s0R7whYY z#tK8NF87DZ4%Yjr;_i>lxSgi^0bNQ zxGrwxD_%H$qncQl=S#GJF)DkGZA@x>WP7ZN^XH5_5@iX;0Nm6QPaAk; z&A4Y90CgZnRfoE3n>9#_6uZrsvIUl!RSx8yTK`Cj+M81+Nn{s)MlTiQeQnqM!OB;T zVdTsrJB)^F>~q3hIY;}Ej*FBb%3>*WJ*(V;Z#rkn*=Q&}8F0H+0I$q!H|O`r8^I&Z z63})23LyyiDvY=KyXP(-Y^p4Uhnx7_nD~`f_8VSW-yGQ_(S-IyR(E75jEZD6)FZJe zo_-7xNwnQZD9JCi<{t4kx@136-_C4Slq#7a>7et9U2KZxHBk?{j5LQmgR|GkX$ij? z%=Nal<*O_dS<_sVsy0-*PfCnu?qzAFmUU+AC_P7x(rGv2xvg!ej@-%rtStPLts-Nh z)lZtDZ$ng1a4p5EGI3cQpYyHg#3L|PyCWyG1fJBkqmH1*C?P{5i!g$9?n7bD?nXO{ zse{<@=Av5JMlP!?oFa!mlsJWWO<_r^p&Sl7Us`o(J_tK27)%&p4&VKZv4E9 zbjE)0RlmuBxrZlE>E$-3fGX4ZVp3UD)Q|*stF9VS&{K;Fd>k&^ZShJVImw!^<|l=3 z;*LJOGC^(JlEKRyGA{axLzaW1kJOT(9dnoKkv65pZ5J9?gX3mc`-?BfKGQ8vNq*Ul zAKwwsM|2jblkCqvPw!r!C~Prc?Xa&fKoY+nX`{Y}m`O}n#Q{d!HJ0SpJQ>@n%WpY4 zIs=t~3=uS>q+jp@UPVz|aoXPAzHI7al*F8nc{y13fFJ@u_4xWMs-ce3KhE5Gerny@ z`sg!nTtjzXk^yyvphDCdm&=EU^-35$I%2fFdD_H1bI2juz9EqfrO?70w7MMdDdz5D zYV!-8VmTY}bD~*%*hU#pw43|-o41F}Q1&*t0uMF$5zSv0+~hMZp<)Vr>74Xtd0(f*WtXYf zl3nf~_^G7xo@8*3ayh8trO>cIRaLEl*86yUYb)-tYggyJ@A_wfAny*&T+x3ar}$Hd5w{zX}Y-p~FQj1R5i{eX|u zgD`gNG=%_Y=L)67;CuJIceQ%2vz{9A5)96lDKTLl zj41JYdEP}4XB3e;B;~uazkIRDoM^4IzS)-%%EC@-5w0XZF69K#t3{RsW5v;OORY&4 ze4GH7(P+_g5vO8aehu5;qaX4m{lpz_^9cE8dvmwM0-zuq*0(TqP;}WM{PaQwEYnEc zCR*tex%bF(Z<}|b%KGv4m&WgD5aMf=1S3AESu5!4N9x_LhHHvCDX}?UIy>0(A6=9t z3C*{z@wR>$^kshPrE~m{NqD1xzj>sgXgFtqlwm(75R$(HoSdgQ zu@T21P^2vh4q&u!^B4AmsQR{mafhNa9x!Lu965xg1l{n(JTMABaUKUA*DCP>&2i!v zP}D=bgLB4x5{z{9PtdGa^=X5kC4+vQ%h5%dV{pL5L!IEdi!i3(ip0qV?czbCk#R$yAd10BxLjk6z{-JGZH4zM5Tk*F z1X)zVA~2?l8ot~pv9^g*#q;y1y2PlXmnUy^oat-apEPO51j<}UKI`t)H>EI!RaHkc z(C3<=oo(BlC|WYEe;??tda)%VjqFma{P9HK!BMbv4|&c@^0i{B5hW_5PKPtT7qnxk z6Fg{#;aucw+SZ+MyTbF@ zr5>*C>o!fYNa%L#*%kXH&WiFzbUh*`RSNI**g`ktc-;NBrD|HhJU;c0I0?eCnI5Tw z*~X0s7={I0r(ehDep@SojZ>jj>c6h837mS{P)+0%Z|D0$m9TDh|6L#tHTjoG}ZwxX=hWJU69%Xe1*>;$PRzyqyQyY zX4B*UfJMN!Son8?!A8Rd5EcuPg`mFx|EpxE|Hg11sdLwhZCjNjk+9eUHfIJe0mCZr zMH3yf7sj&-gzqWd5><5@15=^@bAx!P`LC|ICF&Mdp~B*f6uMn;fVWx!COG&JA|mJ<4C*si zsaY=F>{5tr7h}X|4ZAy&s4qCN;(+@jQp*u%rjCwY*~U(0@$=mrj%1gT_%qh5zj`-x zKT(msbL&MD6FLQjb@bt+8bEl)c)4xk{c2cR|MZv%Hr?m#!WGpSz2cX-^Q}&@Sr;MEjVZ@$ST+q&X zF>TS0L=QPp&XUw-P?b7@U`(O7CCB`OSdT?hPfeN7qa>qpm)2J^?a0&Y-YI-@zjIW5 zrNYA?`P3KY5Mw|{x;?V$cAq912W&1cgph6-nKO?oNjjJVAu}o?&p(cDW0YOpU%FF7 zezUk!-XM9)i6J%0U@t|C>)~svHdZ02_%g^&H_2ycYY_5|*DYP7Q$w{!RbA1t;UwM7 zVU+=?t6}eBWRr-@O23qaeVyvFt}Sl9g?9ghhJK^-y)n94qb+Up93fG_D+8EI#qt!W z#C>VnU=AUt^1g9HARS3n>G=iiYCgQ0v}oo4KQ>9|O-#4a;2#%TtiacMK|FQm^W=%X zA+uRFCLP(^x3m*!S!Ayy(=_qyx#e(!sylo2%O0py|A6gs1(5)}IEK&t?sL_&-l+5t z1K>2RZ642;{*#?tb;xS!nO@n%wD$KTm*;z#S?VkG(?#_P)@HBOg>w~!^2^Z13y!8f zeOg80*X_idlXb1fddA4j_!>M~Z#%-oTWH$>zHk;Z&rs4?RxaUQu&T-hP4?57fRB1g*egw;?>V&fSW$%Nt)Gt%OTFx*gx$wk_fjVN`sl zOEOs*BhtN=y5Jr=4MJJiM(fOt)08pR3j{hrS{1YwL(XLr_)!e+jmgA#?{}{iD2Q`J z2CZ?HtyD)97P))*YAp#i*fYe<$PHd+apte`y*Aauzn$^8M-`A%%>Eq4pFMO)es{U+0U)7)`ysGCLp%u*m-rR8Q<;~OZXo$2BcORkr{d^ey)lckHlPAfJT`ajrv�!>cilTQ0RaO@?@|Qm zO79@jL7fRY-iv^O^dh|zilKMuMUc=zKzc$A5Ljofz27tTUTgi&IeUzE zpE2GK?*|6t8JUxr%`BJe=11y?0aQh z^XvZ9PN~Bc7{2>*Q~(pYA}a_@;1O8sa9J^!`UmKh)>GmQaAB8hUb!)+RvfyYhhKJ1 zc#EIV@Ek_Hf}R$rn%98j>@2YZNDHc+F^D7eNBAMcwfGlxy1ELI`g^=+{=Pdwhum9> z@GPp-HSgZ99~<@0;gbc=C(0^wAC0~5DIsP4WqN>5ksSA9X2}ToRy^6zqAQJN_O`D2 zFP(v%1#+d84;G|Y{~6hrtL;%q{Y99Tn+dUz2lwFBQFe_{OGb!!k1Y11axf1pJHd0s z36J+jMdgkHHGhD>4rDA7@E~5Lo!evpVVd=;5n<9zma^mT40%E+blj@R*W`We=mAI z_Oas}jfQQ@!_Rc3A@ug^&wym7lw4gL-&T9vrCpztSReW!cuk0(_-o>tsCGl)Hs)c{l)VzT-k?hxHEjktAHc>JKZIZ5$m@^c4n zPsfp(eV9Cr`o5B7swZ#HIN?v~>@wH@@A*v=ppDB(N3}<_97f)%g01e0A8n54_G>ja zM9uIO`F73zT7Ho9og_M<%cLXGJF$pELdq{So;HAd$N1(eYUy&fXXboHqRzX{A6Rwl z*J|1(^^^;Y^q$ZhO2r%um8J}KaDo7N$?QJ^u2WIee4lMoqE)O<9eIvjoJJMF-wSqs zA}*+Z2M}N!*1&X_bT`L>-vE8)ZA;1<@2ARl`9$zzMBs!r_*q?n{0>Vj80P{^l^(h; zgDj=(TSW+MqXT=Spls86q!;!lC+EXr$x*7?qd%}DD7PL7+F5h{w^A`+X!SggT95H=na#uy*X5&#>=33cZ5<@>~Dw8p7pvrD={FC^=m?sF4Gkf|a$+k|LjeL#R4Fg*oNIs`W$Jo<@6StK^utT*y5~q4f z^y>8!{j;`L!hLk9_g)B>C22@9KX*LN?`&_F?K)(ECSXju;mD7TC0{c&x;q*6Lb}e0 z3jHRpe#Lt6%m>qZ@5Vz=YCYP-e#+GnOEj&t@}}1Ka-tbhrbHWt}&czyc~a zK+FWN7a1;gqCl6bOFPJY($qT6fjh*iq$1mi=HS(_3u)&F7?6<%^gYkzIjU4K0Qic{ zp?!C?{RF>C>R)7yfwJs>G4lB9`wWJc;gFG$w7p!k?a`<~Fw{??7~!hgYesKrMQ`Xz zBu7+L9o-wRzFjKCnFXT4!9EA#8k{+-6siyK z&_|fl0-S{oV zek;+!!cXnGx!s;MvL!6Cbk`>|v~VlDs445arY7A-HLd}rd&F!>!T~Csw{Ne!jsk7M z><{NgE#?k(HK!^YQhyvcJ9&^eh`fUYGYWCw;~oIEN13*V@d5JIRfd=}blnob{&LzW=?ds*T4}07j>4SYpF>NKXo+>tv?D}ZdpC%{<#7v1uHd2cC2$|ZMM-@HN#d4W@gC) zkbi*gT4!;`3JO+O$J8b;6MP|V*4UAFK+oLCtl}r8$g1WCzRo}xpz9vb`n@Qme?5ti z^3R`JR8QTsQZ4g@?`x)!v?q2sYor=huf@k=Wl1lF2bSRKwB-X;?5d_7*k>R1I^Ft4F76<(u za7~}Ww?)54N*(_O-Ci$C0CyFJHbPz8N?){GfkX(xhacQQ~fmK)ne3wrRC_1cSE zjTlo9%nmhiMok1#*c##6ZN@uNsuRNduSkGT+AR-`p=A+li|!#S)Bv6vZ(x=+4LBUf zsWj7Vlk7$eY=-xgxbfd@XECm2?*jdCu^pb$cgP3J9{AM1g>w`s z9!N;c-DeST4$RpSp$-17yZW_g>oOPrv+crW&!)R-GS7?DBvVzx9&)VIg@Uqffn?i? z8k?HxnxYOS^@E}G=28?a4vKYGGVEd*U4<;VGgfYsZN@ zA?ZPiLvLC5uY^eYi)kFzUo=TS5a?9XHy@d4ijP<( z_tQcf^tF7A$G&-F>d5dde-zzUbMI)~Fo8gakSOYrs|LN5VUnU`I^Y>mDALBThmHU~ zsk%QvvFzyvi2_*lLCQKx3ax@WdP=_~9=^NtE3063uQvb)7dxp0Dqmk`BOF90WL*}Z ziCOn;*wphT@%al*aX!Yxt;FTE+y1H0``?9ar~UszBc0g$_4nk{PO7&|N$>yENT1+r zQR!(n{)CP7z|Mc>@1Lg64pYz8 zmW0(6ct{P8g96oO(Lz1`;I1X=DXbBUaS&1}SFXe9I&V|(tv|KRaTt!>I`sagjj9a9vcWgk=_u9W z(Pr0=gAHhpz&+@&3%o0*jtPW_`aZ2-Z-KMj5|C27C@{=dp;4;ll*Xc!kyx-uqA?e` zP`y7?oATIeU$*#O;8sN&5me^+c!L~Rdq%)I>Z<1@G)lBJn6b$!$-YMw?{4){kXx{! zM2Y0q^Yc~04-K&*+Eb?xtN9zQeQ)-1abxRhV&_VRO|Mv?{X-Uky>8cnAo&-eKvMw$ zzbDsu2prV+r5zYW#k_yI!$u24N~h&E!c`(e`#Z%^O1vrF}C zM8Lm25ZscP&M;h8oTFgtu~ehN`HaRp3r5*>$J30hEIN(eIL`auJN*jfi0D3ZH%a|T zzwy|{xpsj1@zK+m<6dBDid!P9nLU)1zV|JCr)Qr3r}{eYtOIG{2dYUm@yDZ~?Oy$C z*p8qeboi=AW3OYz19r42gH~%R;_Rr)>MpUqYqQLH7BP7s(dxHfuaC9S2A%DA(6ZiI z%$mRRz>fl9vR&pd{P%;57rs5XuHaN!mygvWbcF5X8C9$FU$uGRT{UkK93G!CB!QC}6Sk@SPpLlQqZw0xCKm17=b*|jK7{ij9gh8iOp-SNHm9G=!X z2TgV_Y9h5$5hyGZN)hGPMjLJ36lM~8M}X339bp~!Dr_9dS>;qqG#C731?9s4I<2C? zj6Fu_6;>?4r|!bu3qbPVjj21{TMrR!rY?^wf9=K27YP?NXKJoXbVJzJ^&6%EU4s@_ zXR3avV?r~+$wNO@KuJdU#gbwL+jkDWaGQs1$fZZ9xU}^@K!j$%9g)Q)ueH%LsUb=+ z=PZnfL-o+CJ(zgLJ3y)T;{NX+-FRP6glFCu^<59<(K3H8mLk?G4M8zhDWRdojD_JO zr&sfw$)I}_q+0itxQrC#gmf|ARw@*_v&7J{w3KgY+QA!5AM{M@2i=?C@Tddz{N)-> zOQylhih3y?b(`0c-?WjM9TL*ivk@%Fo28}6nXdhwMAbWsPjAem@daz?QnjVojf`fA zI@=Mne>w|C9yP&bWy@TL*jb1ye#*?rHmMB~Bt{cp<#A4F)~d+qgf6pGJt zJO=h78t2Cftg+sPX7|2$3twW_w70X*2@}~cp{KhSw_UlmQNU0C!b}}s{P8~MEc>>f z@}#U~;oFwB&k)xd2TFe3d#{qz1RTj$jzYj}eg!)qLarc?J9iN3aGxFpWEG`NkwpoD zM2)pqel^cu!;>TtKSI4Oj#ZxqmU?zZa~fs6;hls=XR9CKj#WE**CsPb+yFC|qqN+ZUBQ;VIFlGeF3jOb}9 zp4jipMr?2uY&RzRlDLYq4g<^GzTvK!t-vbUL`|ZdjRb8aC=rQs3&y;k3liW9rXp@% zAbNDhC#@#>lkK%tuqmK$^pYD}Z*h?A0|Ge2f5(iNrS(}5Z!gJUEZ0~G-yUg_rPeqJ z6hUv7mnKOE>(thM*iKP+x(@sM^wY9*9bx?RGCoz{jqVY>%SNd7r_{v`Jo>?HMb^|t z)*6d0BmOFWNaZOb^pHEslW@;VU4HESR3~eSm!qr}6^|~ynkp{cgg0BwX*+=*?YJNH zT01$kPvGgXZabP&czz*ra+D}Uhn7d&$iyW4HB)ht*#SB4t=kVR%(emAzeSme+(BB2 z{dwwyG09mfeZ{ZXcSF)7!Qa&>oFec5s>%z*Q5Rx95nwu^E(i z>)&h|6V&*1Y+=nE)pl2dET!x1C5K9hwpc@1Oux{;PBZWF1NyZV z0bU_u#}){@E>Fz{X6ef?M9|w5XIK~;rk6O&`(5oZ;Ku4IuF8egxI15<{tOQ_06U7+ z@8#oFAUX_4#sX%oQoi37duEI`egZ&rI0*}7{n;Xc#h3uWVFBQD0c{4b0@O(c=Sz(9 zH4fjXpVS{9ZY{u8)iZYM572ghkH;a+8GI(R()@LxEGI7z_#l7X^#9+}{};cf(g&y4ESt2A%?;mDAK>V# zO&xqTWXbt(ho~|&3UmSFfeo+YtDI~Q2#ivJmh8c#1_vfU)y`AO*6Q^j=aCk05dxSU zM%V=7L^~=g`A_`MEI_vz_!BQt(|AqM3Mk%)w-qqG{}}Lx0iN8Te{2ramHulx^oj4T z3eP5xrw~B;38AdbX-$qu*R>}F1$sh#Xo!jMXBz>^mONGwqkJWg)t_FS3E=Wms7DK& zw$QDo19ii6uUFihxZ^BEO+o-0(X{g-58p;$<+d}G0q;9P~%$iDN-zzQZx8Q2 zrnt3lkO2-VaeD>b} zFzGsUGVo9Y1Qy#ZK6?Q?u>RC&fCUS_hG#V${_iDeAnyu5w!yO0#x_x}sSP%I+o%bV zhok3=IP64BNxTJR8#;D3lsS(3sLp%6E6c7l{OBe`weWh3v)U#cmhMlk&FmGK@C_PV zJ$fC}`10a?<6K@(bXxWhNp=REWCMUh{?NvPNxz|z*Kk)#yc1Ro5ZwA|T=9K>K>)Xp(DXBZB0=-ys>0&(gbgSm(3|=PFf)rbyFp?|VkDCsVy!Ne*se z!wzMC@pHc7bj-Sk8MIk9W9&Jn37{4D+HjM}b-jCCZcJ^|HeSAWPC3YAU-R6FL%4cD z*R&e;Jo(Id%KZ;egtT3c7NJqA|6?;hN1w5I+hg6+{Q7V8p{ZhuHG}wG#JKN>is+^# zz4Tt=Y?}*V#!&qoj-{;Bj^lIku}qVTYH$rsmEi9X6;xuG2!*3Ff0K^JZN;J2OpH}X zp_PraUJHz_0mB80C}l5kwTVn)Px9kNBGO&rKwEBu&1WF*&NW2%`s|*~ibAZx&3&~0 z@ILUcxnEJZh(roZizgW=d*9D+`8sbZ!f5*qm*TxOQF6#Jwe?)-7F9Q6=fQ%Uk_jGQ>l=?tE|O@L0GV&Ko`!aeyJ%VE->fm48)EiRBvor)6Od z7@*(&eO+f>w{Ah=kR^%oY+f00;*ig-GF;-7&i4t)tuqwdtS=j<;w|xytNr{E zgt^^So_?!HPpDQLs9RVmfFi?GqiZT8;9|tu_3&$VEa-v+kR3qi}BN1lLI8v_BMr` z-o@klUY>=SzpkW!-89J=7%Ly%mA3ICH<^8t3Uz9xNsi30y)ed7b*Q51gZ&A@iQuLIBS26yVe(1s0^ z6j@x*zI{`E5`2PgSHs^ffb|Zue-}TGxF}IUl+zUU)~O?f?(mX)j7IiZ5_X zMI#;ch2N5^h#C+x_h|C+k4q*!z-?lab;?a_DFZ3t+aj``VF*yinrN?BgdG(vrMaIX z{7SHbaroJzC$DmUf=EM3I`6f8k{u^Z2^fLZ)5gg^+C>&6u4UdK6O`jnuW3qG&xZoa z7aOs~Jz9N?w@pVQ&F@c={GEl5#|J5@xRcKsF%1y3{CX!P#tI3MKkQ+6o>^$_AGI^T zpAPA(aQM1IYiak{@cNS$|7-knZTJQ+-xkW3XUVsu7j(?244A)Btx&r`l((PQjJW>^^!sm+Z}|3Q zml}4mq!oPsWoBl=*Y}MsxH#X_kSw3&mtBKjcX7aY8^?#<38)W}kMJ%uPmUt*Cxg0x z3aY_@IcfWg25;uXMMBT5nU2Kw{X6^IH%j^zr+o_7_<90%-NxXEk?380mnCLtAp31~ zG5oTtbKQfZ$>vs|tlMKu-I|$W&kZX;QKTf%oS(nq+g=pZDL-@ceDdBo;_(Wj$I`CI zN~+d}L*f8J>{IkukIaKDbbDA8Ld=D^wZ2VdGfgg#@+om5P>W3)J{kaFi+z~ff__i< z$)MaN(!3&HYtN5#HiZ_Y?Au7##9UQ;9_Ahv>}`9lN$D+BCe0n_N3xpHU5s(=PIpT2 z9C#yQY}Ab(N*8S4{`L+r9*5)#K$F;JW%g6^M>C9d$?L_QHjFm=7HKi3*R<3{&7De) zj~cs52-n70c~%|F1?Mvtwd|X$wa3)M?qK?R(z8Qsr^@SFA05A(yr2HWSzbow&AqrY zQU94q*{I>bBvKWxN1AP7XBEn7lcx^+8`Bj@tL0n{IZKZy)uPnt)^mqlTM}G_`>N}+ z!u1}H2>GI5UUViy0QjT18p6f(?(+R)nJ!#=a2xs9H+ z4NRJ{=~@jZ@Zzgqi|k{3{fT{(pB7xTYwxGMPA_Pgd`z&1>UTOiZqAF$obVT};9%{G zmJ{sOZfg5h7os9wDBRR+`DKu|mkB4nDUQ=zh9?J{exe=QCOBh_CaX;QI_GGoK4pG{ zJl5tauQGo`cj0stpGIoc2b<}=Z%B%>;3tIXgrL=oXK6L-(ucGrE8dyu?ucnt$**bV z3T|j{>SnOV1j*od+qAZTl0#V~aBL$K^ou3T5mz zCyrWUC7T~~O0zLm;_5l4e~|ESOJ;v}o*pO~NI@0W$703e8J3{|XUor8r(V}jAF?;W zDV06TY$2<0d}Y+BJHB2bvbmiEKRgNJq`Xw`cC)g|niXSS8qG9(Gclp5P3j^#sI1_u zZ3xz=lJEDKTHD+p^^8%zyVWw7c8$hDf13&F)7~qQCa@$V{2wlgu&iSZ$h|^4gLcU z`*WY!4>#=4bt8;SF{a&YQoet!j7ae3oIqwrY*B=WV%c4(#O})Blz@UGVV7;>axg+< zjSFFBJ~kq;HvVjzGf{o{^{26S%6;FzTYXH^EnqsYAd^v?a&LW5Z{otA8p9;qlx32} z{_NnEM&?2sthN6w2s5?nwJ)@O$N-h-ZK)Vdv+*jmH-1JdTD0#@8v?)qksijhd`pi7C<;X>2(3%ebQ9`(m|zL!7?RM*Mle+q#4y zdTTsJvrbYU!2d*xd9zX>qBnt%%2ji=tmuHx!jCisdR}&w?r>OtUVtF?i0~5LI|j^l zwSYtGA^LK6W(OpqIqL>SkA_4d&Tb_c(Py6Jl~!&_>VP^xK*xfAB7e=R)_u*)uR1S( zq=ipdPjA(I7DzcLs(HzGk2oX4#vzaXMzYiLhj$gv-}D*4?4`*1ahaqdKn7FS!La#x zHJjn>68lU8m~?yGVOC^e(czpSpwLYw+1sCaA#MOw7Tz32`-wb^rsahcq} z9OaeuVEQ!ko~*)}|1IX!^b~A5LQ_1xP}vi10B&Mm} z%9ol~(&o@;9gM)L?- zu4%{tTm0v?ZI!{zfB+XZPzF3aW>flaqTl}hv%4T#8_BZUE9`e~HWwwc(7nc3um0|S zgXR|0&JJIFd2VLb3kQg6_@78D*y_v&5;ja&e9F3q*6zPz4NODXlRJ8u3u==un)LiN9QyP~DT6ovA0#gw@X;36% zp?PZJg(YV1uK3F!OpOM#t_Mj5wmcKr{OX$;I12aAE%4Azb?EF@s2^>0r8^Q!R6$se zfZ7lKCEhdeA&N}*-PEZ9UPvJ{owY&L2y#@!Q}~E7hxMzwL89O7Y@-&;o1(?t*(8g_ z1=F{WA`25YY{N9SkvPpa?}(y6;6;$&t%v5{{@si4KRpTmjlY?$8?mv*@z>r)u-`-J zzxlG^e}EFpfV@lLqra}X)K?^z_c>-+cmO?ZW)?%3JiZbrRb{sbqB+w zH_ta@raDUYxKBx}VcL=Zc`H5BEq#_Ardg?V3u2{p|6AH%v*ksHvttB=&-hd0(}?*P zUE=%{2JSx2$4wsJzm%|@%#3IFLMw*DUQ+TNzRu0C?^9PSB|ZcBfOv4T`{F^E_P$0I z90aPj^;e>O)z*SoeRUtzqau30p)yyS+g0QQM&i%*Tn9@1qgM{n%I&jn%d+NUf}Z)r zrY74^O?*5;-dBI+{p?%DW{f4>RuXZ?D4|)A`CPBVSHnRU2GbFzSSFP~uiN=9dOM1T zaVf`bC080+U$JjKtXiAjZO%fP{N6Lsq10$5>2EH$5)R53(!cO>x@|yd=a2&~F0RVJ zid-pbR$`(cEQgAkj<4F2CTts9Y3u6W&o3>=G!(q>MmJrt7e}VK(W_2AP4Ha?%HgL~ z1cp1hzn5s6XPqE`4DKgige9WcJLJI|rl{Jcri288hZlaq2hq(R@uq)QC3|EeElei; zXua3gSA2tK42En`vWwkniMO3+^m4}v*OS;`rh@bJN9SNg}Y0O$kwu* zu1Tb11^tHwx#5}4y!f}_J>z}7&tC~6P4RY1`L-Ov@svy1AZ5XLXGf3q=(1?>FwL!H zJFe1i-!*7@traO=Sh$uAajF-DlbLQ7UcLCao$8~v*dJCI;u98mr$V4JU92wHVV_{f zCpXY%gQBz#({bD zH@F&1mA9a&!cPx%z3E`~j49~N>{ZRfJMShv7-L^>%viQ~zgr>`A2+S9NedRffJ{`A zH5i#VHsyc|eph`taYl+f{vjZC)$G2^=HThY5L>F|@8Ei_pSn}nSWYPwrrU!JciltI zp98_+P#^1EC)tPPK&Pb^Yp-PEqKG$uiYH#|v}`C^?8Q}M|3}L^+ETjxvCV8O4Jv-? ztA|LIS+nuIQ+L$J$>h?)ym4V`zKUp;&5sa?ft;t7kI0kYhdh!`Vi&&$Ma^Iu(OE#P zqI+MWpAza($=%)*OjFa`qG@!GvgA#hVy!A20g@_#;c+pe8xI=``akD5syJD7S`sPk0V4y@#n7=?+(3nY1?sF@*9rjoVw2AxG`;*GMaqS9W3ICX-(u_8IR)Bu zLLMr`Bz)z3FI9E_@3Svfk%KV79`D$>0|r;J+<`&q!Mz|dhF&_|roM5X zaY8;6#~L^?fD6NN*kk@+>UpMzbH%QYyV`)SN)vplfqwt>7n32*^oOqmlr-iBtd|01IXSnz&d*wG%FNA0_@556^NQ5iy^g}o z;n%PNf%Gk~oJcP$8t@x-kW}4>sYSN`Vg_Fa{Df`4(i_(yQ~(kH;sAG2))|Jv-37!s zz%=vM0RttVYboITNOo90?mGv*Ji&I%57xiFbf?m}6_8nKv=hmPq`mIGaH>^BKZ1|{ zGGz)@HLQnCX0X<8Mu@B|`c(4IUPS= z`6YF{!@Gg@c=dURBGw2m=dz+yl;Y@YEDkZ7bMj~$*X`fK^k)M$HZn$fbky`@Ch#`l zBv~n73%AV_SoZCW$Sg>DWG! zD=-KADzB;PE;RjE2@!=K#ma6^axppZisL$uNW&!tUoXR3rn!?<$oO~_4byQX__U47 z7@X!-`z~JU~#$1 zWdnIXSs!-S12-pn+3`1VGaUD|@dY1sbXsxOeNMEt2^}@oOeQC}XUULIsJ?944U)CiV`0{wJfHd7-DzZ$exUjIG{d`6%{EMDVD06+IR#&!FK_1;_ zI$3(+3lHiz=uTfh4B&F4h@LN#A+oN9Cvwmdbi`AdU1v!wj7D{iAJV;+N$sS<**h^H z&cS?_Gciun$Xtnfrn%8m(W3loKqqwz4|*}-@}0b+dQ>U{=xd%PzIh?AznbLhnW+!b za6fv}Y`Mu4)EtAiv5wP{MF#REqt+ih;H(SQY?zZ_PcwZ(s>Xqn0U(W_*ILH^u`>QY z^g8}~FXTIaO*m1H&BF$M0ENQYl(d_e=E`6IF82?nx2FP?!uk-9JgW}Bnb$V;`bWn2 zul12Y*%{!Vz&Y;U9PMhR4zf5M@`G@jb&Ql=B!FLJoo*gu@1jEcdy>)5jhwO#j@O%r z_8B{p)STcQIncRrZ^r=xrc^n@twc=dT6?6AV8zOBELpzA4uk5KL<>g<#F;8upsd#9 z0&m2Uqqb*iVGj~4(nRfD1dM9_$ zyiEBBR}N<4!%Lz50sZiJ%1=9I$DCp2&7+@hXQqrz+3W7v+bJ^!epi0Lt3JRM_v3h` zbxkNzBw%#6WZA^b9E!BZ!sEUJRAlYs{TJUmf|y%ON272l+OJK&kasdWl5{hC?Sp7` zkk8v2YfUq>wnqp$RX)#kfs$yaob-AX_z++St`riU=dUNd;r_sa-TJowY*HMq7RKGYmMBjB+s0T-XZM0CtP21OKUdZ({i&(-IPJnb#G zQ(kKwN&T@}QWr~#da^_eM{$%FbxooV*STKX&{8@t1Po6wYK0FwFM6{Wa{J`Gr+e*3 z)%-*7RL)p4*6qr6@E!k?w}KljCJyF@I-hfwrH;+=gVi}iq{Gr)k1ckft4K7iRJYIX zwXp-8>ElV3f!<#c3rq9!Mtq~za0EitS$IHa-@ta^I~5bqT-R8ryXuy`k6c`|bD@&U ztxRWvaxFK8G42!yTROGiN@mRfUS15ZFu~)MHv(-GnA=*oV@k=Ikt1OlG|6P^YV>WI z>Mw_0(GqwC#cUDMbH`~xtM&jNG9RCrIV&aRyAXp4r{`#0tg6XiMK-DUBaLr%pB`zm zZM;|7-&g`ow{h*j>SGsU`=hG9R>KiLp3Kw^^3?IsB?%|a%kI3;tG0sFzQ>`*mjn4% zlw!bLKK1X*k?+V`TYq_Nb3WvBC7#^j>w|QYYFRE>S2xJ*A&PW7>M_m^tsH;Y(<5B)mub_f^zLm4#c!8`nyWpWMW z`nvP24d3$<^d0We+8gl7PR2Kk(}K1UWT?9xS$J2^JT2^}D=OdJ`UE+>6$e%M)Mquf z0g!V+UI(1-eYd_gU|yh(zC$$jP8c(Vgs9&6y|WQ=h7ZW z%Q0y%+Se^VPQj##<4~VjwdQ*LxYvzjF!{kG6uYGJeK6kuk|-rh|8?$Nw+s2YHKFK< zfGKg~XIg)NC=>miI3oe-zkb9|_&W1fUdZPtnf5tbVqtd)Ue!0CE6V;(Bu%z2*EQl9 zm+#Cp;ppRnLnndf)bGVFlo_8Z%ASHEv0AG_q|h;K2JNVmZ~n%^!YJuxJX(Lo6_6_sqX52Aa^@mN;M2PB>qy0T|6>)F=ScvEb$445ZA_c`BEAa_1 zKS&csiTcy_kGMN=)}aZ8%bhpd8WJ=;zG~P9xz)77tw@)_Q#6%6xsYsAdoe8>-mSU ztQ5N24OthuwQEj6sZ8mppKLT>7r7bH`@TquI!VgXm7bWDKSI@&4CEabdZpz@iM}81 zv8Kh?1GAqhub{c~Rw*1m+DBS&`#y+%-;L^~e=!Jhd$FBef8NRL)@>XgBg#syQTiLH zH#;Zj^sfGDw;&EkTqcs<=@Yhe*$mo1$vb~`TeASetWHs>*=0~oGqmQ8IrEHr{Z!>m zKZ%i<8OM^`kLj1+23@YoKE9y}6OV;IeDyQn?Z%#h<<%l%w>&$lHLQxdH!OcGsM2^| z)4N28zQJVhAZcl1|Eq?z`y*9-Roi=0&`wdD(~k-)ZBz^P=@yafGm(?08S}ByGh2I& z@-NMd7q7#f*dEoeUaB4Z$bQ?rp}{np3pMGval>cUg}Z* zS!T_+Q5px9Bm3buDJnqj=N_BubA`*3pz-}~ye4b6X&HUcIBV;sDg>P?4%jF8XGW1Uc0VnJNT;6ss#-`%=z^|M zKPO%QY*d`?iOTu6UXFiAd=40^eavp+3rGZ%*rK$>4PL=-b3F0lFZ&opu1=U-ZGAfU z>tq^d?Dz5!#cccTslrL>5)hl5IA0L$E}vdzUurr72Ya7DfJz7VwVwT61xK*vtI#Kp zKGRRp>p!Zo8<6v&;k zamczn2P6QNQQ{tn3AE4lIbB6&374_~H&$PigteFA2>n7qOo}82$M{O($^Ada|1}Td zzch~X_a$KSmGcEd1MB5cEpXb>#DKH(4+8sN;OhUxdwTV1a71fQ6r=?6OiOXD!20X2 zf8&kvlx90u1AOiXK$uvgHovE^wWe^jr$bl*O03CBBMckU1JNmnxjfYS_q;sU?;~7=g%SN=n67}bt@3qx8KQ|R-8@K@mI>@_KVRK4OQ1umaQ8aT^lAXl%RZZ zS0Lez@6+o71YWto7kGl%r>gReY4-P!!dpll+iYJVJJ*nkZ-Fs*VRSYxzjzoo_E`}A zo^;goX>?!-DvH(L(QkyV9Wmy_X?SwRj&aceT)Vq?y>8MLonztB;3!cT`R}w%I?-sC zx2egCt!ttr_%quqSD!gOR5a9y?sUdcStn<%j(x~toN#}Dm630JJ#+k1?W-t!Mm%vy zl;>4*lg7=2v&d80^O$k#Uq_N1gpfDr6Do=NFmJTvV;xC=>^}*qGl_Pk*%GRcE6gL$7zVqvFgkMT~M8qQaENC#;^D5Er2D;o=TFGWR=^TxX{8|&CEE#`0Y+Wf!R z>=tSUY}~D5^LbhOA0utu&MYu3 zccDkR_rVf$QU;FAVwrw}@=Hb9-1tFU1PYTB=5*D!8Z~Uvr4lRg_|&K7E{X0@i= z`OF@_nm+VXAayY@*L<)0%6`KrCUT=C)XUxCVgDF=v5`@qTOn;A7RPNx4sZ25(zyG4IB;D)XjO>mxA~(u?Y(?Xw{9jk4bs7ynFr>E>j94njdBxk z3yunyD56&O+UTGRqb{y3Bi~0z)9w>nP1{CUhiyY<)U#d)eHIKDq8HpVP5kmJ$sJ3! zD!|d{b#4${q2gI*1T;!3D5chPsI*(?cNr2f6W#;8SV#w*mhvfFnE;c#zpva45 zMIsHbH^4*&qs7|eJ+3=-z90Z9RI~I7CwJA(;3dFW{!oPFsy3M8?Y{SFrT|yd&DfQ-ffu;q zEp1~eeCBB3{*PF0y~t;U`O&ZSm+-)HQ$V+ic3L3tGDye!{jgV{vcjg6JAA+X1H_Gb z+DhzGw{NL-$%w3C?H~ujnR7ygtF~wkHxN9dsPx-S(;{UTm4Eg@J7kGk8|Z@q&sdYu zayDqsl%FmknYUQDcxP=leKKGDj6R*pGT~>OV*XauczcMneBtU?Xx3fSXbts(L5pCT z!`Gp+&CtpMN6A#M_)BL|^g){KG2EbU?=C=_%=@1nWrM(f&@z{IJ7lH)rf+x0+5P(} z#6aP1>lBdN&3zz$=dN&iW%&oF@P&br>2lO&)Uvw9mPZ`V!Jg6Qh})%td7Md5(48Vc zo1)qX+`%$6O%)Yca$eVgx3$@*Ugfj+=~d;sw*LkLS04_qNRRl+}R#IS7RvM!dW zDHC*7qUBnv4xjP1n|W878!<64oV_#BwScG3gvqwe`}&)oWr5n&JwIJ(`KoubcIqB_ zQSP>{C)sR}chq^+Ef=g=_%7_GunH^A6d3*W9^@DCMD3FKx3lMs?-#r6uG3%?pDXww zCn(k5Me{VmF?5=65!S?eIpBSfCpHjeGaI%K&`%s+u|6iV$`(m5l&VxE*LCvg$IQ7T zAsUNv%gB2#_dK;i$CR3q`&}JRYyTsw`>#4={l6HK`rFdOKmm{hbLi&-_kq5}<)h7( z+dyl<|GoP5{|JOUHs{rclB$C>dKxgOq!-=~m8~(McofxCgZ7w$>I%4TAM78a@Gt)?+?EFC8N}tOn zRFL$y22lpKj@afH#T7Gt+Q!}Vu?;ahd(0`z~1a!zl}2M<=wq3NH6NskY=><@%H)EaSS}>J?zsY zm$Sz!%WIbjAPJZb;6QJMBOFQqLEQ8B)h82s<+=4KoKqorXT+6O?Vp}BHb$Yex0ovv^>Az)0DvOvbvbIe*I!u{l}oTS553Y&7k*ZtfmrdQC~1a&k6y)im^$Ob*!@ z);6Px@&|eCA~3snB;HvXdO61LiP%1~$3CNS^>lt?Fme4S>!$W)(lgsPOdCHa`8!5% zzXxjw{{ec$jzy~{h9mzZ&ijI!D1E2odf8hG}=^#g?a7s{1Bk0Vq#uRZQQ{sn{U}y zbA3AH1E&u;{AH;+U_;>i6AaM2JyYf>$srqZxC7CjlkM(HSB)@}oDE~DDzW0<&_zLi z_OX*d2IPKqnAJypu9$ovw0B@6LHFz1y)2Y*PgG&&qrK%MPV=hX?E0;KR#Ge>A9kU;_pgj01Z_JE$g@hM>Z@< zoy02Z*9IRrK6tU7I`>ua=2axyouvDoEm_LAd{zJDdd&Zo`pXHJbvw5KSsshopc;*{fVHz|)95jLQjr}RNbDEM_nQ3<` z`we9$1j5iuWiMPDAzm8v6C}(B_zOcwdT!vb^God;5j8BEIrk}0hHamOq0>Pp74p}4 z@tRY;<&(twDToan%Xq6e=DGxJCo(^;az7nRpMry-AGqjkHOx|_R2lz___nk_oiXu% zZ;;awXG}~ja1|Kdzb<%q#oOx$b4eb}z`UHy5jlDJg_*no0DY8zjuj7kW~N$;rzpXaNRBVL5J)?rbt z{oeQx0!nvDNQu%dIik{%DqTuDgfvJD-Hm{NgtXL1ON%r}BSXg^AqWgTz%c&SzTWFO zXY1a-{XFMA=Y3DS&mVKm#bRdGz1AJ;{(iroFn>~!%ZijwZ$~YFd~X3!Ky(hxktRyX z(LpTvHbm}ved|H4GUqE}<8Oy~$|s1SfSWp<{{jMz@Es2}$Q z{TPQ3+tK5NtF!p#g16Utg6%v@imKe-emgYldR*AKQlyjP7B09;w=)8`TMB&Ii^d4; zOZ52ZbxQR{h-S7D_>~xTJBeiqk*j{1?BsYdg-)$D@&wy&M zTHc{RjLS-Br9IH5kUwdDotuj4mFWr!l^YLTy^%P@8T?t-f<3~&;!w=&>@*zn0|e*` zF;+sgk!>kuTY_8X4dJzea~I}$Jds~4GX!G{JeuzrcvNwiBfWD;(}8*fi|@mF)XL4! zIu?rZ4B4L6lP6V4Lnaj~;sP%9v7SsVf|2z1j0N^MT^S?d;IY|GikJClSHuz)ioaI} z`Q*4YJ6{$p!~*WKwtcT(%5k7r&h$y~tGGq%tZ_gH{C(Cfk`l4b0{twNM+3Bym#7$E z$C5m-&@gwWLO=vC70B^|?j1t+n?R^pvxppe_Yr(sskCsXduCfN!y`m5yhpzQjJc+k z`WEZz!-tJeZBs{$%U)NBc$>$h>dZ>Px=ACNB*J`!XetoIw>!I%ZMXR*Dd(pRpEj!xd@8a$t}(D))MD|IlcIuT)wt&E2A4slI|#CFwCO!sq~ zXN=Xv{y7L19E%H`LybvMFp2SV7OQ9tW#XQ^VWI;7&P`?Xjv#=iwYp5PTZ6#j^gL;R z?wyX}3+Ke09tD?bl&faO`lk~IeD$PNHLX+^L7kHUK~QLnr2NMfXQS+2&i50?DgW~q z=*A+;1$qhXSna;usycUX($TU$q+EAG65D#1`s$s_1rYSl>wQ%!LS}$#@}~!t8@wN16f(6ImhnGH$#0G92)UhraatbvFyz;g&-LNP zvE8pp9p)z1>a{pt_8!Bc28j9A~}A!lIZ5)_}s%A<=U+T)q?g9o!^5=OlIi7uv?)eL7dtvt!aGGj!r6 zw2NjCy73)@`T;t)`AzfJ9@+$`LvK*GfZ)9!zy%qUKo4a7A=*l4#p|6Izx%ssKR_HT z`&X)$&Mv@hV07g9&T=~wph8EI#$U6-(*WoWSvPokaW$|hJaG{pj_3`)9vC;%cjsX5 zSJIg|2KfC0jXIW#YeN9^i4|~1{)Kk$zuMXOYX3EZen#X?PEUvUkEk@BFhUk1LiGl^ zW}e-@OIkA>TS?ii+_5)@l+7e9QuS;k266X)?3W=*j_Un2Vexh!iVjq|^fUMkIW_Y9 zd@*+Af@|`4`@&Cr=vtY&>+Sn=Hg~j4`si;4j&KDCeDiE4bu-G+IaFI@ruSdaR+SeKd zd57vo<6D&%WQ>dUuX($KSU2$2TzORz8)9Eb7uJJ(B>m+T=%r2g9>AK_lb-;LYPT;4 z`2MH z#h^UD_>p={BFst}dGE|A=?;QFjFTD>w(RX!cYKazoZ{Lu*O`#Z4 zof>u13fFQq3Usvea|-C!8~(vhv&WQd>}EFH0M2XARUgZl!q5LKGCxjnHg08_TGt{# z6Bj92ph=ICQ`fwpkoD-OW7=k!37u4Q_)ZskaOyaJPY8!zTJvo#$p(gE=^EfpZaw$| zgv}159KkDmNZ2KweLIp3ykFkLjq~XL?N2mXRoXVaDI%8EYG_K)bJj0Zq2p$?4CPqm za5cVkoo$&gQg?TDT$g+{c6?LuQBZji1%X`dD892ml#CcrEYWOTfy<2>DV6NF#1(kzhKYgk?8FU?rTD9ODNSZG zJK5CuYRVJZM|jBkw#o~YJ3uF8$-WYoZv;dy90YX7WTeaH3`FCxw{AK3KeMYp%VgO8 zY_(A5g4OX6wzAc>gbKgF_JyFHtne%`dLd2~>&AKOxQ}`=7QgM`XL2sr%qz6$2!e71 ziLR_V=FcRCAx??RxOOkmN`P zFf2a}ZwTr$YU6?p*rH>t@PT{$1t#4FcfgNZ)OcKfYhN6>M^=HpmKvhn1v zseTn?;nBiBZ3OU`PNC3E5r7{VNDd^{O{%7j95fWe)!Q4I6BQ9vs!3#0mZ3MJFpn{e zm<~htr7+P!ScK5_%dqD1_tD>H6}n>!Xhc*fhp5!~20l9$2$2ew5+uAAEQpzL-)^_q z19`eTB;r?{Ax)3BMDnMb33fLe#oGYCGdb#dN4#F=0|R5Qk@m4lX7EEXeLb3icRh=F)-83#I^IZXd;GU;8^L z(EqJ8=l1ysI>e3T{1SS}`2oiID+ak8;JEZD$pf`@IAFnL6b0J+N33~xa{ihx^JjuV zdSE*>Mn28uw8+{^)!*_Fq4g@yQttO`!nLu>D-z^)i68yixW9yeL<@JcC^8f=sm_l* zzpSi)CN89`>M~NQk*yB(bMkoBv^MQ+`qP3t&93#AqJs5oEe~7N9UWkgm7f@jP~7v_ z>9}7-Wl6q0Rm0mxiW2VqbeCn7_Xgi_j#9b6`^ncbYWc;V+lF+cmrEpEwlylU$9OV0)wrL zu;zEhoNckChMRCFyc{17w)WPBhQ@}FXfI1}YuqjyM2FBOVVNoUIMq z-7k8OBfN6=(dk{--HF-@zuN8_^l$$R-Bi#s7S|`LHwvIbC z55H$z9aXs={pPyxdv>|H6eohM$?+nwR;Tipr>G%YuYSekR+(#tMk+@paya`vQI`dI zjqL~`=%gM-1yGx10`Ff3Z&3o}6+ms6w7ZGtBq<8~um8qJE0Lau`~U%anv47E0yAKY z$`p{se`?Tv^nkkcSKby33IqMBKMUV(WHvbF<&+VSkhop913}k;8AcAxU>3I#XWrfm zJ3ez8R%gtA7h|GV>Wwb~1m|bi@#p72jb^;0?6VvfT56*0mX{%L&F8TvnKmypGo~mw zT$E!Od&b&dC-K}MQPC+*Abox!YxFQ$uL?qM<#k`iky*AmCC@!kd7jQ)dy=6Gc!C2( z31Xnkw+^o2SZ+TVP(A=4KkvbJ265&7H~ObSg-SPbm%TQ++}sW&Ng*0_JlO?4X!9#x#wS>kER_ZZ3ivUEM+0zN|+z(0Qwgm47!);1eo=aX+Hw0-M>4c^vlPwu26%2IrKmB7xYA6(81HoKzHzEzKPS% zS4=Hd99ps51j%gf-#eA(Z0qkb5?6iPPTrF~{83Vt8wYheuN?*hrfi2G)IyU66|A){ z{%(0Dzh!dWd(Ft<-qs@1u8T+a^{6P3O{oL#p{LN!Vn8Uv?3_vfigfY=mK0l@Gd5Vc zjKPIIs-bI#c=7?G1GA;%DDsWiUVd7>E@~axNpGn_2+bqNDZn2Z$*j z!vwyd0EW_AV73JN>|vzuvShT8To%tEuDoFuLbk^pIT4%oyNF5efQ>%9ugQi#@j6*h zBV61V2`o&>pr{;)BoxLoFb4Q1IGCF#NDs6==OZkrZ zeD4}^@OjTQ^168oJGB(i#vCJ)lP?Q7=5ax(Q9PTZA^(%M9Dkx^^KKPJ+z`{kSmE_R zg-E5sP~GN6_RS1->QAq~>ME~=_E~cHR^OoS6I+A+lEc|v+QeA_hc8t3N^`Vj80Yqw0cEjT!N@dq!=pH+~3sBL>cUqL|ju!q%BM;{lO(bfqRSiNN^ zm$OJaMmSp{-_9ynk=F*P+0qcYAFMoxGpJ;`r%3H@XZ*%8`-Swi-$=~=>-8s(&35=7 zkPw?V@LyR}mA~?=Ks=0H49D?dZqc!>I#F8?ABX0ofnfw@dCxr9s`rRVdNfbVWgdnQQbP4M+zXGf&(fNmfNqyHKlC__KC0qikg-y^qeoF5uZ`7gI#V-##eE}yy?PwiQ;t*J=le5& z=Bg`F%#|rhUMp~YtUTczF5YbkaS$EhaazYxH~>^8@?~(NuCHxqX>Ff$m!7K8VNc!G zYD!vJa=l$ccAb^?>b25FR-C)cg$h(!SpVqD^cKqwEmGG+PS#L>YOb~5gy!Wdo!hFu zb0+t8${n%=DP7a~^#-PMKRnAVnQuIH@Kl&UE9IG?pt>=GR`29FYd7hW-E`h5ne;sg zlV=YiZS@sc22a0zI_9hW7Onn;7j^@lKeifMn-ZCwapR2`yRH-*(`CN|hC_k!*^zi~KXmy0wL z#Eh8L?7%->`t%ycG!+=WVdiZ$Dw%nvZ^h`yU%>plC$Wpsa`QtZwQ%wCl8>1rzU2YbR+OaNF?w4Ky{Osb)C zFEY)ax~ehaxpb|cw5BHARvJSHZ4-Z?yMwDc#OIy->(pJ@!nrP{sFAomnS1(5R~1Km+P$$9CxByx zb12X$4z67+TVcVjYb!3<^4KuiC*E0qTlo1@q_F&D3#pCWt(Hk%8n0bG%qWFkh_?`K z{P(SosTWEoFI%Qy7JJ##_nXXyRQt=cMOliiAG&jax-iPBw^rcl*~#V2bsR zY}rTgVW=96f{6{Lr4oE(1mLEA)zPBD8bM`m?M^7!*%yf))J~0sYn4A%lVUf&V>LV_ zD_;qPqWkAx!=?xJBV*~15)QN z-=ofFc_Lc0sya&<&qB)#DszZZw>iokO*v?VLerT>UK0g73-f!(K;8H8;GYah8jDeJ z-iW3zbn6%7uwk>AHfY@>EzSnBSjKyT%YmC@#P+ zFMiwBQg@@dq#99r%M*yJ#UH+qL>K#2s-?JP?aB?YWQ>>R+;KVMWn9OXTyMn=xb=Oi zeN)065O&>ZM|Cs)?vnJlbFcaQ?(d&2@yP%;cJ^Piz$FS){8O8#?0aK_dyCe$j9?yXHlzy?^9Sw{KO~9?^2Y zL_G8D!z)7wZ@6}Cd}`7iUArtXf>pga+=F*Z??YoBM&+`2{r~ozDLe9}>ApbZj;}(6 zSI~)CEo7QC{C2jQx47;$$EeIBO>z}8UL8pT9rZ1ZoiBTju{3|065KNt&{4;2%;j%k zV50))(eM8jhnO8PHUTAi4NoA4O0*5k)Rh}nKhr|3n_nv8>sXwrwFpPn>w=^#~vw=zW z-zgP0@kfovZbbCZBMszK88q)6oFTTgeB4Mekuc0Isd*5s~pC%{cU1sS& zKC{pIT9yEd|z|asSZqJ=ON)CIIZxaSEqH7zaWa|4&Zxd*MfM< zcDpeA&GmelyF$AdGR(~RUNpK@vuA47G%Ife(Hx7vw1>-v_BZ#3Ea0?i4uM5B}zmT+WT%YD^Q_gBCykbNWh zlI?nO6OB}R<^@xYJaJN1p3VF3Wg{!gI!v!1<2$qP08Sr^TDa19E@ysy069YvXqm$K zBMuYKqfS8N4$TL6i}`e(lvx$)7Xt#AStX6bcq+1&wm8rJwmtdZMW?-Q(PkW6$ui~c z+3=AL1$lCbgLEfdII7C4vig<<*+0kx-=#CXS=Zb=Hp|1U-c=@68%R}}O0E$%&Hu!; zPE&^`X9-v*D7G;eBk2D55ulOQk=2eP6C%d!V8sgAz09Jssa4h=%0;7m8;7gnPT^ zDOp#SvH9TewRX;6jMb9u@E6>es!hC?@Q_~|gJ2F*y!>M7!W)`(?Kx_xZrlyJpV&o# z!X$-vKd(=?Ltp1?fDF6#WuXjvp=~zrlo&CkUVU;$s_x6suie=Ga$=Pr_kd;ZIEN->XM%M6e>ij4yqRzyuCzw_YMZN%85-I#@i0I~>~%3^Y{OU4M6@F=O94YJFgKc3sjUd)+f~ zO6!>&U2p9UduG~+I?|*v1z{r6*%bOE5nd-Pt4m+GsICi9S#gKdQ7rX~CMo&1*?TGv zMY3l+why-tu<~*}nMVmBWCcEDlt%A}gXv`v(-jAEM&ffc4F=iwPO z9v*H*=OmZMmL#=UbAO|B{=>wUy)L{f`j*TDVnf{)<=?LHxy7@s_k+K5OSh=gjVw^y zZqt6r&69AaAJJqOgxH!LW|y6Rhid_s{iMw$2b6#M zCZV54Dq$7GECr<8Hy1oE3yBk&ht|> z_@`EkVx8nrLr0~6dyZrI1N8N|+ynx4j&A^6w$DMw{&Jq5+He>DpV#`&e*I-^{c{Ze zbH4u1TAK=lQI&VK9qcRmH`l$bd(k)p@!-?Z!e5bRl?K}x{P{PcH7EIY-$03U@^eh1 z02mqmwaTwgGlw7NoDpn-kI#RA&efdnGF|zbro>;p|3Nq67slpYmVcZ(i}@pW@gG&DTijje z;W2>Syc30MN4Ni}q<_0tUOz+k^(nbRDI~F=DI}l@m*Rby+XLd$7axdTT$LQjh5qa! z0O&E8LiRlo>N%gxuohA4=c9|=c4Ap=owtp;Dtug-N(X`9IH7}5mD$cHVpZ4vx;c6* z4>Ko)*T@pV5#Q-xnL!)Ix-Xx-tXyocHTf12c7XmpUug<~v1{@z$P=proY z3<6-BWQ%+u`__%iJ!6dbCTk&_Ez@uoyTgR%60>fhsy(G-jH0RHeCh02`rM%8jT2}+ zJiO9h%Gj6g!}!kkE~&s8wHZgJ%;6BSyfv8$$sJt#4f7?h53E7*A9G0?ZDBEmmo?~{ z0?`63EJa@ayO3seYq&BoXLl3Mx>wjlX9LCHbthgx1H6gyZgNi;f|EB?QT5o2rQI%? zC6Jj7*%Rtrpip`N!74caVc>@*vI1V!h*UOlN{R2=&`#2h?3gmWY zJB4Vpo&EO~B`fOhf+O)_6i+|!?DX~RMS=E80CA0f1ReEn`3w(OXT0{(6vv_DW6e$b zuflJFQ=W!BN|3~57|jb1a?6Yifg74kq;u9-&2E%+vvOVq#2w7v9ryT5efc%g_%9Sv zO#LzC^yi%Pf5*J~wG#P9#Ydtc8|5naQRWckBRwBAR5twsmwv)m&S8Wc4=cl&z63JG z`c9Pk4=@wAjJH7FPH%bEpU6qRe_#9LLx#gWbvYlL7rN_LovhLu8nOk2vA@%8LAElu zak~5|&xGQdgQ;> zaf-ox=gXVZjYpH^wSD;w2dCZ*6TIA?E#0)DG}brnT*rRFQ(Gy}%Y3bFzdJ0;%GF0U z*e)X_wU{auA>3m`pK7T~!Sha$Cv5eO3>iSRNL+ zzNvJ+F5N+oPq*qnuB=_zDSRpnyP?8C($M(>R1E_}7>Utlt*ALm_=Hyw#;50ix-VXkku^U`5YuL!L~A?RVoxJ+ zKt&!Cpn`jy3`-5s-aA6z%eK!Fh89BLrur;V_Ch&pJ-%@qLUTWHehi~ZQarp$@WHed zaDJlpxp1@-e`)n52N`K9_tvx6V2e@WLycM8w_BxWP{@IA^%iVxr{^&C0vkRp)frQpQ z+E7>5esf!&-nYd&rqM}6PWevEhs2<4+Ew6jU5sY^BG!7NMb^2rKi?M45cx_Yq3iTk z@s{B$n&}$_a~y`oD@Bj36uAYL^j&z;Nw!jVBlD+d({NMKoAgbD9^Rl@eRnuYwU0#rg z^y3A{IqgGt@|Twg&_1;&c2}Bg1SC_<0A{AEJj>OnV(_~6Ywgvqq6(HOmCrIcJruiF zDfG=|$InTr=WH3;1DuYwc>op08+%sX6wTw$3UVx($zrVvqAwE_g4v>+x^@Md^D5%mWHA2_9o2WS>}yp zw9QMvsPr>@`c?m^tSFzqyZKJQ)$>E@t*Zscq6p zuET~ew7~NeY-a?qD~MB4R^vaulJ_unT3XTNE<4xii5JS%b>Gd`K9wgJA*Q5%|oxgcfBg#W@j6?2=$1X3QW!sB7M zRyZxs$#pd>`<~2Ru@BDuxO1@v#GHLp}G@a4L)T* zmtwyWUB@tqkKX%#t>pg#Yr(&{IzkH|@ko7%5dtjFM+coPRw|_S9({-d73oC{)1*%c zc0X=>e8c6V%{!covzuC%)%>FEF;2*+iw?x%#)X>3#A=dSbE3#)6QYO4FX!n2L8KFh zq*|IT#QTYnBOGkxb^3{hg{*}T0S0Z=s5x07OvDc#X6s*z)Zytfq_rKyGwCo+>0_6b z|7OaG0MBTy^hUScvSXn`D|nVHpwg6+HPab~BaHgRGX}<_@2`;+RIk-L(0_~L#-UWX zgvpSWd-dufhf<Y2l}zmgIoGonkFN;KdhM;& z`cna5D}e|p#jx4B_UMB5YCd|6YLFC$Al|5Z4hfP`!s7!}=&GK*B${SOd#FEc+T(rx zR`b}WrCvE2;p(Xfj+oav)5Zh^p(gbAgI&I+;)>I<<7Cb{bwaOAdqM6a=cgiH%E%T0 zZJ9OEh=6O))e<^!^86xITq9s7wxgytLeP!SgFwzQ`onUvJasI!d{xwc+bFz03Jr|LuR;AAK{ zxiukkdV4QEi%|Im!Lmj6k=N;oCCXs`rY3SR9T5$QG)J~Z+oiS{=ZTysk>foKy_{oV z6XpybOi?~F0ldP8wg9%IQ-~-uRujp;`Y;P99qmA5#fAAD?k4dx-*LoDzOT(&?q$hb ztJ05hd~_Ihw+nT7VPuzs-Qr$=5?_6wuEW!;S+{6Xw`CYDmY979D>ff+d`cAbZS4`0 z{(9}T#dmlPP8+is>VwzTI^Vbq`In?u7eX(^xrgN>ejdwOq9p_v}5AU+bc;%dwwvKX*-K;^DOqL6T zML311m)0%hZH?cnmQo@~6szrby59B_{QTYu{aqrE;I#kLsooL*C0#L*=o~Vf8{Egu zpj=e`w$?}Ea8Il;@GkGzt7;W}aOyp^l*Q7Dn+7odJ|JT$qlCC5?P-cyg4)`WZ|;Aj zSSFaZb%`uL4GLK^#-7u6-1Mrf`T??u4;%M2Wns)%grZbJKCOPHSn*x4J7Jm&I%}4R zf7Q9}&4FH*J$nv16aXUXIzGUzT7aQAq|%plR>sxDOzBF0lbx=Qk^X6?CxIYq5@Gyn zrQ1S^vmQ0(aQN|ILon28FVyr3D${%4>27_x*u`9|#+C|QcQ8Lp+Sqt4l{2NoLmH>A z0}p!{%k07EU%}n*|DeM2>#pv zX2m&EgqS(KGCONxN2SCQ2g-Zz)1FKn+tprhi=QRWKY!Fs;b>mgxTuxSdzW4&>57M( z0FX}M1{ghM0++X=TJjM~Veaj;UWD3!9hy+MmMc-h4^Zja+Z0Q>!zXDjJM(YeE|y(% z(VJtvbErUxpQ>UOYWBHv)P)J!zA#tt$gfjS-F(e8_aO;SSiiC0p`-H#8Vaw3}O3XV?&L-9PNq1lKQ#`ZMaxC_o{P?pRqX~CE4LyA)f>?XU zJFD$MN zsBPHdUO(V5{#L*BSZraL_l1a`Yk$uRu=ggKO@N<`<%BNFDF#N%lXa;`xKBUD65cyd}1-1E%pn5_N#9dbAJi(o4u6Anj*#dZx`TU%RpM24X) ziE2ct>tk&rf^&_81I_sYRg_+eFF{A`-?ts{=LF=Q0q(pSjbG#PFP-cel*{>UY6>&X zHBy}#T_k~p_$lDc#=&<;ovBg>I6tSZJo`MYJjs;#=KDLuUU1Xe`Syt+S7yHP zj8~><_@kB!wYnAr^#r0mWhK$UhI~PV*Xs~FRsZ!X_hh@fq`7hFpd0E7%Y37LO&dAr zNM+FrooLpUX71^Z3-@7?m*!`!7kXD#b8t-|hL{}05Y3=Q)8x?*_))Dq^aDpbB!XZi zF-hVnj&lAGh*|Pl7nU(sB+^GaxYLj%y=3|ua%r=vu&9J1Ze1l;B@_+Uvz`^G`IJCo zVDRV}_LG)|XC?FjvTJUGp8ZD6Jsqrw^No@%@YJLB>O4Tnp==3F0$@H@Q#QcYd|4_{ zx=bG1T^>>np(l0zj*GIlbs<_Zb&=TlMjxL9v4vT*W>t3w?L0Wn0DZ;`L}UD6P^8qx z4^W);WeP3&5?C>o-A8_au2)ELs5O=uZRp6CJq$hof7~CK$O{kw|J1%$P%8yM5Kylj#pDV=EqFAd z{;e%A@a$QAcmbW^-wkuix~G}FZYQ{ZW<>AV>|izjLXlK#0{%Oi$Xy13qPebEjC)Rdd(@ z4>`oa-I?M(^=C?Yle~k}&4{OX#?B;H|P#9c%Sc8S7bj$tLEViO2-Q;bzs%2QPsZeIe zxmapV2@BDp?aSmXU8GSbVEua|mbI3`+qJ2+=@S!21huduu8ft-M;4{o?!qM_zO~ds zSJ~#IGPdWmM4`daOlD8p@!zjc&(|lDkg+z=rjO71m1>=f@`H2>x*7q+hTgT zYgX5CO2OH6l00u}yho8K+0y))#;qd0f z>mZB1LTa$^Y%*k&;T&ggD1Ys(9rQQij{$aiWTIh`EwB3%IvDfb$BH!L-cAl6RmY6f z&5oQ5w!X{i-GSes+s;`$DP(YHd=|8etX^f`flJc=0M(})dZ7dmOg0}eQUC(sD2rk7 zu!rV6jADFCcOnU4`!;Gc)2zCyQS+8Tk(032fGQeRB`ea&ObWLLJaLkH3|r$e9f0he z$CQiyz$cp^VMh0P>jjC=L&+_lSEz2Y1zCE6j-384F9ZJv7NWt1!1B6Q_Ws7Er(#_Z z+nkf*Wdbv6_SBwFzsP@^ZDnh@1S;)fc~JNypm{C(^2(pUWd5$B?axIZQ~AGJNTR|T z{TmwMuik$t3;jWGd=l%=Y_k6oc7{Y*uIkCU6Bz^aAr#&TeU<$!I7HE`17XI&4NMA8 zq2^xUm>`dK6y6UII?*JH3ajVmLrN$35zx(>kRPA`CxBr~Ju`Oqy3NnWsDA#&KYs+c zPyZqJgc=8>soiv;H+M{sGg94HV|IHXf9@nU-L*+?Sln%O+vLkXyX!yZPXC8=*Pr}I z@0^$C6NcE7ony3cuMN90g|u}{mF*(9#o8YaeY9f|N(I;w01()pWM}`22fTm6WBN~6 z*05Vn5#U$>U-F`Fv@iW)JP)5YwPh8Cq&~Wq+m`jrPU5z*%3ZZ9y`R1MwoOBgN1|HT z^SlOz$9qlUl;V00W-*jhf!zjn&8 zC<9@z>P_nl2Su7Bdwd#6PHtGLP+8RslOse0j13}uXtHhJif{9}s^JFVIA57iXySTQ zwN@Yb+H)?rgEhc+>EZ!q-1HVoewD68=q;e^d{uN>fLy>(vvyuZ22L&*NIoh2@rD7% zmPf;rWq5?I!DTH*#7k<}L9Nr2An>SJond@;7ju3GooRCKWN_!joYZ}POU@wWZgHNT zwnu`1+Z0soSXR8(V8ZdpPlw#u#*ZjLlhTHis`Sa^>KkefJst!!Z1Ku|PG~+-GfLD} zjE{ulv6_KAcWL75G+Z)8@~Gf9%cJ;xI43!%Scm<+M=1I7nQtCf+{>iZrDk@DjheHh zAO%W|hZ!3dLJh*oQB_2t)*X+Z>R=|IwXiN=&!5fzp$fT^oy;G58SUwcvz1U+qxPnP=bYEM|q(6pX7( zFobLwg$pIr>OItg1=0hISJ!)zH56>LNU-No|7Or$jPXrj^BiJaEg;5lMLa3@9fwUG z>SBM-6!oZl^Ce4o?c>&@17)tp>;s-oCk|3}r4wnr+92PhhmX(HxTbrr#Ix#EETWlE z3h$o7V9(|7M|bNaEh%Lu0qeoxagzJ#48q+Xw%@?b$~PIn5fnpWnNOOG2uqyIiE|d_ zjp{eQ(y^z=#7$xyD8>B%*}-VOrDcT3Q6NKSYU_}n4PiNc5VjVESoofKkS%WHt?+&o z>J0^?Y#Nr3Mit9qC@stt` zbuOsv6*+K@V3BRqzH<9gR0RsY z(jMf`reH@K<5oK<_sLRF{ERITcd+^iDJ8poqL^7}&sw)l`1~J=? z4NFR zjxLEVY%=DG_9i|^3up5`5T)_!`u$(J4E-lOpZ|>2{5@J8;Y5nk>30{P*b=l$g|T&2 z8{dgFRP4WYbxRpP{`oxYHmU=;{REZ1;#Dh4+9ixK#VoGwkS%?TJNSfo_MLkqOErNcSQVAHEbA#hiPp}COnJ^~#2j>cyAze}%X1JgKlU&V=qo2A$p^$} zz}ZpE?ORQ`fOO z;#0->4|v>n-Ag^1A}k_f}qDO_Ij35V5E z#VNFkC3F-GMujcS4)LDS>cvubm8}nnZ7<>-KGSCjH+Kzik>qtz#@8(N)j;CGmQgLx zB1kG+jyZjtvsIBxKv*T@T5-&~L;YL0M3lp~nVb-5foNIB2B`{k1k8^=ql~()>p*N? zsJ2@19hKw8b9Nzf@nv_ISmv^90`g&oTQp4#Y*F*6GnA{$)!iH7>%h^;F*ZCNRDshM z{p!Z`fo>=Ngd8qBC6ws7d@$S&te&LEbX*FlrjhSVj9pWX8hVw z^L_reC1P%+fwb2>lsQ|mf&`71=sZ}GBYe;oGw_Lvfa1g6HO%l$fC2n;`PSabfdjvFx~^HR zDUg*UQo&Z{tYdt@JJw&%J^onQROFBbbgZtqs@G}4_5-9g;dE@l)Kll~X=9tW=y_;e zm85T@r7H|lVRPqr!%V;-oIDyIAxG+fx7XEQQuggc%Kl}`aOwAc3tlHSRV{wBaL-qe zgl~a`jNV8aCyHq`t$K{5vu5+O;oNVkO17g-LL8~;dxwlBwL>ikz3ieQ(rj&&zosL#f0l+>i6QtjS{}jV=YkWah1z_Ue#4NeMa!2R2VS8HYSN)6$r_| zM7knm<>->t>*DB5Az8u@1*;DT0f8N|9!q{NEF21DxbU=DgYvmgISlXZm16(@dmtkYaXZQ{HY2<8N;Wy zk{01k8ZM5(u9{k&__AvQIq|V+jN2Xd=Jc$)!PSt6v!}INNisSh)cj&iOfyi9y;%Y| zjVhWYlvPByinV08#U)QK8ZVg6&py;S;Ii`Gr6np9qM(a#5}FN=4ORn_)-~=`)VfVL zSxs=-I;K)Zex`V5W$8;#Fr1lD7# z+!;jX8^&vm>ww7~xT#BPO&;IkH5}?lUDaw$-IBz8_af79#_AUHSGT2$@yt*5pzS@U zHo9*OX-$6UCiT{-Ok7V1t;RshAo|w@F3QCzdgf2AvIx=9i*cNSi5=|SS~U>rT+*_R z$~WG>evRwtVnX!ky@U!;@GHWs&ctqWAT2{uH(1o%f`mn~C{Gqo zr195Oc3f;p_oa{*o3m*VMXh6xRL9=*`nZiavev(#+DX-H3MVNhl9vuIsemY;pwQBV zOq@r0)~E5+n6@{2BYk zicS`B9J35t3gq{yN)8fO9ZI^wiT37gP08TAGR_rV?M7c#CRf`Pf(FQ+Bl|7vKgg-} zZ!`&7Us-4=^n4~EKB=HZQj8%VA%%|e!!hWaD1f{}uo2$ANekQ%e@Zlubrh%v*h9K@ zE*%j9o5}X87(nAoa%J!Q$}FIu7V-mhZ3Y0!wy#`Ao?c?_K=(dDLs^h=LDktNKBb@+DQ zV&!mC9bsGNo~C9Z)u~HM-pd;`Wtb^7s~V^U_#oR;Kc@MXAS_a|0suNKx|Zrq5QUp8zegEw|Dovv;U35@+Ic1}% zrm05PD4Xq|yGuKr@C~ShF6praZ|?dw_<9?yEyKgv-FFoP*1y;eSMHx`qA8zI8OfFzWbrtNnU2E%Wh`$z8vr)wH)$q$gT{B z@)rY##@~_+dH8zCy`i>YA~#$=63`{x?a{}^+FttWb9hx2@8d7`Bo-J$;6-!a#bX_7 zRG31N&Kz9XI~kgKDTN!-8S}BR6d8?(0~O$1nn5&%4)s-@?#10U-d^@M5-Z*_uc?+P z;-|fNXHJ)m@7nPZzwYM*{I4nduRxk<0fW^(iIT4v_%|V zJBztiv}$q1`FM$?^(i)fu8f0Jl-}fh`#t5m0~JB{ zN~I|`%U|B=;q||T5)u`hzh7#rqu`7S7pfk#f3i})v~h>^pz2J=QMO*rf7={qvi-fx zeL$f{+6;{Y#VF@r;B)~FcffM~Q39w7MIBzm-d_pL2`7ya-~?QT#Ta9c+Ek4KjQ+p& zt~?sb^^Z?UwxW?x6hbE3l*p~r#Mo6-mOp6Q*mM z$Ua&wN(N(VGL{%i)9<7OFVKw*bYD{?)TqLtBA2;xDIlnWzQhqkMkDv1?e5(;E z?7W>kTqUM5yY4Mq92IL>)9yvRmF1zYQ(B`Q)Yg}DK3q#|&BaVn`WHYUK7+B)WeLBQ zxt_fA6E4C3tIs6tUHW;|E$xsYUCW>&wS>Qg@uB~hMR#LGM{|ysR#wrXQ11r3R-2q{ zPt=g1&t7YN(wm-k?{_l%vROx=4qFl}1H%mHYVGvww^j;Cb-hOTiCJmzL-D%&*TRqg z*K)PhkFXLWRMMhDNImh!Gr!+nlb#X-wn+D^@t3D6MIMt=95}dp-07&qDpqS>2>KLd z!q8d%0V5l`!Cpi;>{@DMfxhgO;A!_VEyaLj&p%G(E8<#ABE}GFQbb!P-(iwEBx0tpiWnyGsw0rw@kG02N8}6JYhQ!8`MDVZ|Rj zhdM6g+E|E~dX&YeG)39-&?$t})BR1JhN>-j2BcSUts{7doPT}qbObJWT^;o>A$+bwE|=!VFe3kZR#P3TZTE10zH(%Ec)u~zNv?i|4w~KqA zjbz2IJz;z4br=w_;-3(~;cX~wWM)M* z@s-DrE^*Y3gR+tx2LzvZdTwUsW?;3T%|OC^*T++Cd|lPoT%N63+u!8I`cB{2IryNYCnQrzzXDa&^DRt=d-YjS1SM6e{rkl;|yDtj7lv~=t zLxO9Hf(4%Y=pZq>e7ao6FOan)9ZDcMI_y2($!6?Dg#^^Ep()O8f=-34P z$#to*RCqK-+k(CSAkr+vERPzuWv6Ag%2f8G+aybMqo2F!sJ_7E^i~_L)XyPj=WkVI z`EH}_NE1zA-H*Z4-8r5qNs`oAtDu_F$rcxqUaZz~C5J9;o?(3TRf@sz=T+Oi9W_6^ zVo$^0jXgFh-Ft14?ia9Tro$zpg!2AR`?s$dt@NiOQF$6oWz|u}9(X%q8RT)yMb*lTKGwarMUJ(0 zcC!w}Y586(maBS+A>7&480C>@f>m&XW(A})%JWY(dph9w9PrX(+h8ws#>?nIgQSFu zoCdVct^0<%%Ehm~-num`KrDf*AioD=X!8NF4Dxy>z>1v9bOuvV=r&|-9!0a{lDo!D zYEJ{JPJ@aiGPj2d7}P}BVMs}WHdHwooQmVb+8oJ8eX+j&>reC^sbXY5+?zf8TX)|5 zghq)5X=TY*cQ4nU(&ezR=F4GE2hvuN6fY`1y6BzHyTbQ+`!2pb*MN1Gw?~b{kJPk? z_cSQ}t|g$^A?a>p;J45?61tUZd6I*Trcrb%%@3YAk?N(XNseDzj!q%fk0=?ZVw2N20EEdOb_AVb*Oq?LZ9>|3bJzJl_+~=W~sj~I_u@9htiLgvqF<_avq?LgF7mb2n zZ4mkgzwhUPNGpMF(o)U)d)nz69DhIj)omXuxFv60xDIk6dhQ$syZ6rwPU3JEF>Z#Y z*0O-;W~cWyPtNZ6czYJp^SC6orsy09sfTv z?Nr|x7a^LLnwT6K0nOsZ^(hvhQ$12hmNK|Q;PV2dT|hn)8E0|@Dd0g%*r%>9oGgr# zoUe)jYVuqYgg15`7P=1Ti|B%!1uOpgKZh!LD^phxSV3R~f$so;IV4l68rx;Tv?Byt zaE6?Kxr1rAZN}nx!lBIUDnQc``I1SV zn+7zGRZ5^kF9BaYHet6oZ;$U4$4@ju=EGy=@H{D(7}`+BGaeUg35mcIi;(MFrbgU> z=9L*}lY{Y%3jd(D^m$;6obd%@fZvP@;Ncow$e6Z(b0;72gb+iw@eFgwr$7G#Tbc58 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드25.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드25.jpeg deleted file mode 100644 index ca1a87933deba842b9c3d35e6b9235cfce4e9b06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65594 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드26.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드26.jpeg deleted file mode 100644 index 67fb8746be33fb1f650d1cdd3253c8f1444ed633..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42772 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드28.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드28.jpeg deleted file mode 100644 index c9f8cda4a413678b57a0dfc55c5f3aa865691ec3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61026 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 CuZm3o diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드29.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드29.jpeg deleted file mode 100644 index 4ebd9d7bb0fc9126f9a0e01502ac8caec713b205..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63646 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드3.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드3.jpeg deleted file mode 100644 index d0a2a9695f36b461eecf04b1b816ad3a64b5863a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9339 zcmeHLc{G*l8h`g>Z=2f2iVS6Q+J+`WNu3;o=pYguLP=$lp$L(LgpE2Gn#>~iM(sGJ zYo-!1@69%5+A@@38#fo<-PG-@(_QPXd(R(k`!2uld*AO_>wBN)`~9Bv4$u0aR;UN? z=xXU`0T>K`qpS-+y&zQ6gLnY|Jv|@;0Kfngj1M4K7L0WPm@q)C+5qUnwtlsZV1zGY z-~a>?0rJZjGuCqjtjH_gU!I5r*zXY&;Qt&AZ%9CVwMACkpi!WF+}6p}$;H;md7Hwn zJwRDqM-RCYorP6fYSrYSiiWn`1)0dtgTWC<6bBl^iREGq$mRiX7yNuU-^KF#t}^|?V~!nCyY;; zn4bE@?3~T{3m0vPb}p`0-P}E{dHUZ9xE&Z2ObU;PjJp5e;iJb%Pm)ufrvBxx&oY0@ z%FfBn`&)kbtJiNT-d0vsH&Lj~Ewt9Q_TIjJ`oM?5q2Uq6>P7`VMP}!pPyy1 z`p?R~(Z$Qs1xF$gNc4&>7~FkDI4=^leJ=-}nj!k^Wqt{HUyOkIy~K<%PP~HAgrN16 zM(id@#a=1KinLW_|CunqKc(!eu-|oc01W_N1p*F7pb!WIiUY+02Zmz>7%XNL*e~E- z#l{ujz5-$efw5vBkw`S_=HcSx;`y%ub+M-9PN*GlBVeq_gy03LU_qTkAonWtmy-wy za5icU9g^&JO|^Geyow1OG~X3q3UI{8_(bXEk)9pkrjD@#DrB(frUP zQb{V&>}iIxgKNkE@epXCaPSHRD-by&J&LU71}4_)hwsG zCr?n8OGhD)!e!O?NPqVRlfqtg(@0T5RdS^HX_{SEhkK(#;#gCpIngy^{#6^24de%-f0Bdr`^tf0G~KO2$Mj0>e`qsrfD;E7nI+hFLVo1irDuky zb}{`%p6_gEvIUL9lkNgN{g@q33J&KqkJEG*alt)PiNoPJnc;a4HGIV*Q|_3G42mVa zTvSSbK3I_!%T1hZ(bmey3oXhV<(m)VvI*rrmwIEy$BZ%VpOD*FEM+eyMm=J9;o#Py z29aw+ZDMAfgHapi9^5^5@;ahlH85^BgFY80)bzsPDly@{c}Q^i-M#W8E#%#9;*g5z zaPwZpfsj;P<)AKVXyhe|b7rRH*dmSC?O23Ut8$U5rA-{RX2$lE@G;#jOPXh*Rex)@ zGtJ%UxNPH4xLHowMABJ}j-8SjFP88Kv}j(`dv?h_Sy&%QNFq&gvli`lRhoTUdgV?#2{1!mHFR|h z<=@J=Y_EPqm@X1jOpO0;B=?Lo2V;w=k>8VdAVLo(GYml z82CEh3;#6mwOO(M3oAP@@#63%oj7B8_14Zi27@C%Zo~{e{?OJHQ(1G2KU{|%f0|-T zj!p}Tp~-q$WaZ0_ouRi)Tb23J!38 zTTwp*_&@3Txw`raX4lbe3&L-ciVj)2tF)?k=#T@dO^eBoJC-WK(>sl=G(JXKoa+rF z-Pmk<3i5q( z{hg*)wsNB}{p!oC0Yb{wV*57PoynIN?%91|^?V(}Zuv7a#lfz$7HMf-eF%7JE;D+r z9&QfQ6l7#Slde0VOY_lLz<1PO(0Z-A_Nx~Mt=GE$i>&{D)w*k+ z!9Vi@0{2b%_?;b=|4!29gLLUqQVFZv43dU`q0jsd2snB`piTAtBCbkBb|#ag+K2U_ zS}p59pd)bBV6Fr)sZV10+-3U3&uoT3xX*0wQpD1D>0(4ui8M m-ZVDl-N2^2*Z1$WJi8Fk`u@GP`Ci|@*EZkl`}f-ByX_wVr#@r= diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드30.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드30.jpeg deleted file mode 100644 index 221820109edb5f2de1cc8c9c65fe4443aa08fc09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58455 zcmeFZ2UJwcmp6I{k|pQVC{d#1Oe0DXNh&!hk`Yld3N)bPBp{$fB?w5)IY~~EK|pc_ zfo@_0P4_$AnKyH<_dhfL`QCf$t#5r(aNw-&I#so+cJ2D@bTHpBivamu6?GK=3kv|$ zz#jm!1Vk!(+1mhsrY67(0004S1&b2E0q?ND9{`IHxbnw60Nll5`nUW0SUmq)2O9uF z>;c?=tz!)S|5d=2e?9%L|8YKI{d>+|6`&x%X2u@I!MYA$Q()mx zU|~7{2snx>Sbvm19s~biVdLOl!NVsYBq9bYRFMPNSU5P?xHwm?{OShF7yKT;rMNo2H90%AWAuq&0d(cB+_bBJ2H1QHU_($O<8a&mF=+~5@xmync_mbraL zSw&S%{qBQ@din;2M#fL9tZi)V>>XU)+&w(KykEY46BHa08WtWG|1Kdh>HUY~%&hF3 z&$)T|U&<>gtEy{i>*~L@cXW1j_w@FSj*U-DPJN%ASz2CMU0dJS+}cJQ93CB?oFdQ8 zf6)cb=f98z{{0uqexr*5qzfAt7Y7&r7hPD`p1%mEz`b%!7?1LnF8<>eRM$lU2&k1} zKb5r+vWwn_(^$HU5YcjoEpZ}#k@g2={~Td~|4Wqp8)5%W*DP=w!2YA)U}NK4!NI|~ zf_DWhcm#OA3IP$pABE^&3&|ga^j9JKw}Js1!2;XB#l^)3f60jniOK)l1v3Y-r2u9I zAi==`nF)sifC86Br5GTF$@zRe()XIc$Ca>UZqGH&S zPvlci38^f3GKoVGZE`hYSlh`{9YeTYFAq-I4aYkh>)r16KljNuV?S^job9rDcw;@n zUF1yhELgbqhPi_PY&pZfQONz3ZOL|l)yzxTZ~N4rsqGde1?ZB=yKD~dldq9j-#El& zPeu%d!EoFy$Q>BhbC!0tbcMv^l?Vjxco32|$1VJ<-Xu10*1IX%VRb0i8e;dnQQx^M zBe+={K^N*i?IZNbc-up!Igb6-bGe?R2XTB6Mz(e{=hKwh6=K3+9U?vCG`Lt*{_^`q z$k-(TockH-svysg;*f8QWwY8@=_!Y}fUPH~; zURHTs9AA$aTm6Sgsm0iY9(A)hJ>AmI_kf794)QSuxUP_LoPhyU<$dZrFQk3$BAkOB zA?=H{6U`ann%Qyc_K%%h1xv)^I6qa_R0rGd77+$=Cv1fHS=GeRdx#3sl9QDQ%IPkp zm^kSl>=;x8FDN-BzlnLln3F;<>QqBwLIDxHLSubN)#he4J z%tPAqS6SY7M=~w=EH8bwPh%7Yu7n~bq9@T|= zafF;wwq4zNPD;#o-CFG|;3L_+q~(&YNP#MiUex0(Rp(4C0q0dGr5~JW?b4CTvUDBy z>GX98m!u_G)Q#GJ~_E%Y^EO_>(O31x#x4_|sZ$v(GcdjmrFfN<8-jv?9UO}$zdYQs}!8mOU~yj8?{=k?R_yRq!E6?a0` zboPhS6%}GL!+C(hK@+q*_+&|e_9ahr<&NmDIrD<#1pyX+sya*m5!mErRr6l#_Q zlom9`iWEhD%-wx^o8E?qxM!7jEfj}4AG>1L$9jo)M^g~pZ(3GcJq76>TZ>-jjz*j$ z&Enu)e^6z(B=Vea^QtQbphig+BMZJlrqdZsY{x&2yQLuG_6!0Ep%qocuewwcrPi(H zOA~NazH__?KV*R{?o~TKZPYDn`)s^(-z%r__KPb8a-~LhPBd)b#`lI*_N))G67_{U zSXDgOUMR92LqZ#&5_OWn*T#1(3~Pd(ag-aq{gKW8yj)CipFkTcv`u~|2HB4RI9_){ zPq4=^z)|AeB{@;}Lf1_n?Ub(MZ9|jkUiq%96vq#?b&_<65+2SD7e&kZfuc{1tbQ=G zhSHDcb2t3n!ft=d{0$5c=4V4+vZOtNR$X)t3OdR6qzO)O=A0PlCZxV=_Wih3x3{

8KzNHb6tCd9b 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 r!Vrs2Ra0P0JN4yF=XR$ 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

  • }ke2Un zdM&e?fTQYnPksFR!chT^y}NVXHdoKYAAAF)0S+Q>t(CwCKr%QIj`UviMb zi_1JSHKEf(*2UeH`X+#Hh%CFIOJ*OlgV~oV56xSH#`iJ|T!6lIGH}s;T><};JauAR zjbj!)A1AYeT`EeC44Yfh@{2<d<JaVJ`*<_Kdn=_V0#X08oJv${#mw0AsAJ_z-ezu`vL?fA)doHdZT^Rw}e zW4k4m+@Bq#{*U4d@`3oT{noY|+P&oBQ1Qqm^BV}z=07dY2>~s`$}5RaR$#{?;J>$~ zF8L-_{6A{+7;0e+-tU3#e%P?gAkzEaynLxyHJD`=Y00d^@h574HuH}**^A&nkqs!XxLlL`)2^MJ=3x{ogLeIX{p%#Gl4>>rcKv3Buj3)78HXG^i?yG}>l zdl|Q+CWFA}_p-hZ+Ty~{?$=lhTErqmy2QJ#T()=$6y+~C~ zf6ytPl3RB9i3QDriIYzt(d7st@)ysa6A?aUVDD#8T8KcJx;KFG}9yR$mJ)}ZgoAmIJI zgNrUV$YtqGRlXl%x~|L|>_^yg?`}tIm~kQnZq9tzYRJTY@)X<>OmWXhUhTzDo@lzg zMrb>t4O?7+qKNkj9s@~dDkIO6``Xn2#VNUOpq%y1vBUHeyfw(-DUiNh#lcYKHwlYR zP{5jvig*bm%muvX@2kl%`u~Z2{m0V!_iI{^g}xIC=k(LP8i0#$Yk>26_RW7+MB~$= z4v*n9dW2?uv5YfL*pa3dS)0(%`v-~~?Ox?9ow6Le?J6Vym%iW~Oxy?GXV`}YxfrcRg;|wvP8{a98pdw5-#Y77h^i)}W8e(C2uDkxQWhl) zx#~uQCM47@`C;=hQo?}D@6Lo8H8CoZl4cekDQS$aS*53#n)OOc?Yx5tKrJHSSVsxS z*)Xp=LfiDt+jMdthqJ2vFIOa**1%>7j?7K2Esv0KHT7VA@mJ>i2I9ZwF}5{^ge-zX z8(j0;9xW8D#i+8i91)q&UO$RnHErqWz0jVRNGd!Pj&FwLTQy&?~zj3y~r48clxAp z9&&+e1X{y&m9Mjx3ohPWe{n0kMRLQE`$m;&l%P^0pqYK-f#mO{Z#L%WEyA1V?)fCn zxfNNuz$5u}Utf}oM>toI=|kDw-TJbT-GZIdDivD`io&r+9jRk4E*puSH48>YNRl}B zi0xhgPOdQ}z;iE@Wwv^L7>T|}NArA`&R%^3`xJR$3f=n(?C{XZl4q#-y57)Sn98F$G1-Q*4H^Er-bF&P0gRUU3&?w{Wgo{+vj3OPH1qUu1Yq$curFf^oroRnCVVg=6{0L!8j*n7*r=Upt@ zM|*StzF8oSMI}vX`C*b5vRVi|-U5X7oPN5qA19fks=M!G6MO;4`WVpta36+wNYRhw zDExUFNax-E*T0Z5eIo^3r~D0+S*cSvsZqa|LZ*l=Q=5a#Lbf$he;9{yL$6t4r(
  • FUL!ZpX)pN+)uvlp+08 z8~tGN*$kt3xb1^?Ty{^VUdFt5&-b*IM0>U7r*eOIc6@IWsx*n+&*cOx-{t`P*IZ?< zqlxZhd@Y`A5?4?LIe~oTRuMO%nI}8!1&@$=ipzz@qmMai_C8n?ElECD%dKaxg)3McSQ5Jo=;gyjn=68onUodjA`3s}3r-X*PD zuJe(5HpL;BJ5Tc}?gM|})H-;atm-yP_ z`XBE6`4Plrcb!WS-|Q-}D=9X$+Idpj;?8DVC7yN1gyBG*b&)VSo^d%bZSeo}6Nf4P z4FnbdeCNwMRP3vpQ1r`6jHuS&X_wPD8(!V8ixe#fDqsH+3d zFAnHNYP~Kx!>D zX27-K3nHt~p_YRc^9Ja2Yu3%6aHryE=!S50yPN~*5RXJ{*u=g>+urlZJy(m{yDBz$ zZsuR+i? zW!@uCR9G_MO8MyB2C`T$b)%AROn5YK0RA|0pT;zqkl8Z(d8@!BXJ4|*ptosCJvM|E zvQ&ZUlv>Q|S)??u@?x(R+L+Jy?ziEWS&5QZ$AFw6fB}z)wVDO+Xh5)*2ZkB}|NIhw zKj4USt~uj{^>gKYm~`NJC_B+4!4>j8!efzQKJDKG!WHeFdqU>VH%2r7tVX28IV4p# zB6E%f&o(WzUJ60F{CfHJFXOZT-n!yh4D{X(cZ{OmQy-y z))($s!h^F5Gw)3J8@)}RZ^HI!k($xa+XXpn>Hrc9233i0F3K+Y(1OfY1UwT0H75N_ z{g*=coV4`keOVY^_LVL@%KMAtOTWSZet6BP3;ke!y3U3U7%?yS;s3r@_Aj9#LKpYv zVr>}u1y(P2L2K)!wC{QE#@cO9tlG`k3~jQU;VPkr(eN|TGxP1Uz46)d?%8T_*JmfL zCgN_rH?ewC7GAx)J1m4VG^kvtDZ(c&pfqo29?2t7Y1!MxTlt0|#AcS3WiQ+SEw4RHm zW}SB(T&JBmSmhc)dQz7;Ynrk-Ym7VaHv|7M;H}pDVT&rlJ)KNHU4tCp6bNE`v6;DP zKy(D}-YRlB*3*y`oho4o>aT$~<40xp$x4Iv!%R^x$qNVuw3Td^DGT@Fzep$Csz^%A z@O~{Dwi=nF%t&HW($HU_DmynlyMA;mP~oEWepy_EQPop91QRt2Tot7w9X6|ue}V^!+fclBFy?V1Jn!By)hLPnU1U(wQm{cX z-=sg8%yn1Ch@_Qt_pEiXmkP&65A-WI)&i79z7)Q+dEF^WAj;@WZ;2^MtP!a2CYRl?!Oc}q+A-w#^sZC)4TLOkdk2FD4S^lv-l|nlJ z;~4>7*8D5Et^fDDrN5J645te%Pt}41>x+mD%U(VlD#^06<1RMQ$xIfZHjNR%(NUW7 z=d<}e#93{9T9uw@m7v>O#8*{T7M`6fdl@f?zt#8hoW~W=Ua%C#`R$ZeA7P|KeECK0 z0%5GxX&u*AbQhMMyk#?AqUCto6~fM@moc|*7kesSB>0e90*bwWM<+n@sJtq2!6uPs zS0?&F#ZjYLO!qaVs63fV<4ZnzFy_qps(PSO#ejBuZfMu8RqMFw=vWvL zZBGz*TsqxE8u+D;xt%y^uOC;$;_TKrYZW3c(%-Cd`1)YQ$#R`i?Bh=r;ls z-j?3c_tLe_Ip<>|cWHGgtggPSI&DR*T%Nlv^4yEL;xh*O;cAu5pdh`YGEyoq*DXQ1 z7Eo{3tP0o}b?WWPNX3o@bURx(F$Dmk{P2H-!Tx=ybvB}>AW|PH<~qTQK1e@C0%(8_ zDzm5~Xv@jS2T;+G66_P(#W@tsQDC6k%50RZb_n=JyA{zWfWKc>q0*!2t)*2ptnu}M zQls3KX;>B|-QzMQbA8NKN<#&@Ji0L`z(uZ81P&TSAh2oZ*&uWlIJqt4ov|9t#G=sv z0D(eVibsl(RzZUQ+ANI;i^Us=OHrNlz08CaX$`ltWyjZD42m~$k-D4B$-+fXmc-;; z;4jPCi)l>7>AKBumo!8*a9!>zNKXNhL4RHTqs*rv`k-+d&=S_+A|y`Cm(x3jcNaMO zK*8T747Z}89%^SmbIvt%-u=(Df6^}kwzf}iiS)3Yc0rc20Ej1$GfdN`i|QEQRKX&F zGr77IIv=+AKK+zVBl*W!6ImvIu@2c?1diq!<_%_*z=<8eS`CSb3Fa!Fz2j%XN9VeD z(75cJG)w_#t9Z9rX@>eg=iHB?F6ThE-AV18gAGYg%*1%S`T-~w4N+qrX%bZ(@1FH^JtOJGiH`+~2A0?^3 zm=_2mlHqz+yLPU!c-t$90q!(DD(lwR!66{t+QZ-6E@F@wf@$E3&Bq1fBq7%R;R#Xv zq0;+Cq;4zGPOIU+wG~Q$q_n*JV z6c{#TKh#(gUi-h^Pv)gwiafdY8P+1SJcQ?(dlH~_v#%lV^YHMvl&P^Ky*)?>!GF%1 z$3H%z^0uJE+Y?RDH zK-spmZ4S>rD1+Hg5=+-NlnW{~c~K|nXsq)OBS7Ns-;Q2C0gAMueo?~w6_EsT`W1=r zSFeA@7ir1p{{lb)QiA;jt0;f5gs?iSfv(8yjxvFAk*=x*QyN<`3q^C{lBUw~>rPWv zuQDc@PN8M!ua4~5HLQ6^;B2Wz_3J`s$Yr;b)}lg`iPq4=<~>eJ!!HYmw8))e<685W z7sfTj%U#QYrkNbV{>t_F=nh>kG#PT{rA?lqr+3Llo%c?H>j&P+WI6-Ly|SSg{P%GL z0%9G6&23!KcL&@Hgc;1b&H#!UihuP;0?AX3Sd>ASXD;G<;%~F4Hw-sU+uFPFyqumo zDI%$}R4cbB+2mrDG(?|MUUCS2Z(w8CG-k`mu}Z~jh% zPBFc#0)>y2{#(BAve$_}DgN^+b#azRh<_)4ORs)%w49|E$_6MN19?XJl z^%-P3_VXKppsUGfSzlr)@W~o1@x$07*{Awq=`)H`P%n*iW-t(di~2D3pqW{pIdVpE z9P0G|C;e}?X7vT4J$P4c?lFCjf1X^C__?J2x%^+)Eu6YNc)?{G5O+3*i+xQm6m<0+ z`e}i#4Dp-UdZWV_7x1i*MQ0!oWL>%m+Mfq17J3pQ@wdAo|2D>1|F>Mmthm~;GKEG$ zM~N2CLjO?_8G;*nVegQPTacQ{|EhY(Ua#pc;s3cB*iyEAJ7X75{_E<2M{l_B;uYVC zha?QHAl zY~z_PlNi4vnJw)^XJRPxLNUq8qi>rc=NxCa;r1dYXDU@IAmq2r#Zyu&p;pxGV7m&J z5$I&C)T)6b(EvQy+s--3zUNjl9!0F zBrkBpw;iA^YTx1C=c*vbIzb-}1E_X_-X5%ciPSqt{stmb_d%0?h#bXu&#>vdGG-ko z>`(=Wm;=7){?W+Fwu=eKciI3_NOxm{h3vcxS{RAefgN|831Y-8Y>R7;I7ODOIeMq9 zb<>@sJ&T$*vE8bTB#`s_xZh+u6$d)GmPUb!^qg0vy)$f9RrfJu%RpgJiRT6{(-WD8 za#G~ax~RKoP8y9o&h(9@V*yzDcg8q;0lk&}ohg7y2BnI;QfI>X$S>W*)`%;(QFK%T zt7ikK1Lzw+R8H`Fi0OZ>{Ifm){ov3mx3zmmD$@PO=_2Ki(?z+a&luIQ>37x!Ky3%& zc*yutWD+XJp1fBu!j~q8Z+p+@Xoh*B9_6^=o_^4md^r2(v=HxmGHs|oW}B0Z06f$F;?{B`U17mU+=yv9;nn+xaAKMxR$Pkcuf1LI$+y)jMa)~ z%+1`Hqt#B7jWtb?MU;``ia%a);19DFY!iA`_6H|q!4k8FLhqkk`Y8_Ozrn=a(apwB zd;+i|ri_lP`+l5L3lb00I8q+_35wcLj*1TC#IPG<%JV-}ilZMc*uoCJ^%;%hnj)hOM;5dp^ly` z>&;3mdy6Nw%i)WRkgvX-PaRks5}Gvh7r95hWx)&|hu--2T*I-j(Yb0741oA-#>_5AFSNkg$3WsT<6M3mmw^MEII`pPgrz1+^pEJNlr98Sm;+ z>+cE+2f%eAW>r7T{xGyZECAmF&HwDuWvX*8AQ+8-*09dk6YG-L%JADe#8Fd|#W4Uf zr~b-3`&EQs?>|>D$RP6n4m|i*KR_VwCsBg6pH&Nhq%1?fixjjig!VkTj~Fe0zLOoJ z4gXX)sHYH(A7B-CS(;fuFIeiCSDKS&oxT1JgZS@zT!;E_#WeF5RXMG?kS~K=_Q|f= ziw3PXr@l(luwujxFXTK_zyHuhDNm*=ug#!*9}A$hRROL7NyQc^(P1G%h)m<~`K|2n z>G2k0iWd62#}DdaZWb<9t0d*@hr9~<5YO=ZMHmv)QIC>4v)F9p-8+QP=~;QWghE1g z1i_UZb%FsS+(OD3Nwa-v{Cizy1SZ54N%#5hj`hzHo^zk^dojDu&bRf3W?tmnoO2F+ zs3}LTcr(*9DNgpNiMqI;#TABm4t6axa>bme2sREHMUK*2K*yM*BsDf8F`& z5Ef$-d8S4P&}2-Gv+B>-D1dBu06x&Se14khXaZFUMTmTcQtni6lg+4+^f(i&J9CWd zDLd0t@xfWgw4$?X<7s#-u6FJ*YGaZUGDjb~HuYWG1e2jjQ2(pF>kNx3TeeLQ5R{xj zKypR_2@)Da@@Rufjw&EQqGXUp5Rgn01;i!_NR}udEjb54P>GU7QWJy*n)V&;`)0r} zGv2xPhwpv<>fPt;lj_voXIIs#Rgl(Uw058M`Q`gMSF@7wD|KRW!u{I_cS)B>Zdhmg z6=CqaCHrn5Tkm}`qEPNn<;bY;+ajZn2EC^vmH^$%vIf!$zy!4d8T#&Cjk_3_dA4pg zKmu`>__g6Yjxfcbm(r47bL%X7Uam}E9P0K+Ga31KhV9|7y44jkVi1S=X<&|>E+iT=$jB$L2R!>y$D}LEkHP5~ifS;VSqU zG$^$14EVAX^g*^OY1f}9Y^5m8@##9zco*i>M9Rmrm~G|1SyK*T^&?6=C*=}2qw-2J z?n2dr0H(`IjI8LvgXN2BhxSo06D2jd&ac?dlh4j z*&M}44u0{k4@(a`GR(CF-xAsiKx_qy--UOZh@ZMsD!I_BHdG{N4;rs*!kOCe_V&9o z>xa*zlMtRJ3y_~%x5%yHCf}5QjOW@`9R5<`= zUS%;zR;9LtuRMF??;ml}1J~qad2rdX&ZR;78;|+Y$X`-ETfUZiK9F$b$VuW$H_I(D6=Nx@M5G^Irwaj16j37&AB6ZK*5-ET2AO z?7`ccHZKJQbd0P3cnH}=N4p#3BGd^uOxBOE4d^7^zj=zf*(4^*-^cH*`~;7>`u+{w z?P=G60V#Eowxr2T=KD<4uQvDiRH>B`AR;?g^gCtZ$tN?cNb|{a%sAOQDwI1U3g0wT z18l6wPmw{XvAw6ld~{v0)KA3pIWHPM53QF#8JjSaR9@{i08QCC zAR?%}IdVWp00!d2fO)aQ1*D<|0PFErq}tnG7i24j{#_45VHGn*Q38sDw~TrL+!qKkVfPmI)yoqAU`-l`mmq=w_;uzV7>=T+vT_A=8yF8DFa{<03?kDiOj_+Q zY-QeU1M2Pq1`xDVu`tip4eItJy&7Uc_DJ|WRaCL|)emZCmfU;J$cxz>{aT5SLwmUa z&>i5-n&STAiun_yi$iq`1DA6>7&-}}xgSKDo_^v;e|JkhybIs>Q@tVD6ggIyob?fc zyOi_{plQUm$EJA~$WSHJt~tu*sezxpS_`~RLqSm?0^mXMedicpL1JAhM^*W!FFEgA zV`Zdh*_tErjzN#0mKz-;o)yHE2uC37B*rT3Rud!v29Ev1^Bz?fKL3O%Z5UpRV}7rV zBPA&=VC8WtMqed08(tzrXRVWPi=PO)m51DVadXOu_ml}lGVu0$a$y3A`c{RB4~ihm zKUWXn^__T2zuH~Zya1?Gln&P$fqE8#Io9asKAr4 z-ikpDqff_R9rlRV53c#ZHwohelWU8xYJn->NZtRsn)Ayp?OJq;GbK;I z*~>~$yzx9gtfHURT$j{Aj*Ts++ui<~kl(gC%Fd2|&adPB@a2yeexowXaJ4O{Z%xaM zy%rM|H^58bXszjLxzT;65sc@3)}lHn*tq~lwcL#?ztTZpo-WGoLSPg(zZ@4`57uV> z;4>8N#JfFHWIJX^%S)OgVOQ;m zRpkiKD0WtgrV{2~psSCgxgHZJb#0^iRy~5U4*ouQU)_W{DdGNdD1+_|aszcYS3;BH zw6Q{T!HEKalub=-b9R)#$g{YPn1Agv;|8_4ftX)HAUQoxBN6q@WuY49mHY&5MM!2O zEN#^=@u=vI8Q2j%Hz!oag+-L>IYazNa@*6Nz$fQkv$_N?H;DzB!#2v*ZaUobzZbS< ztN=xFHCGPf#kjjXXM0`Xd{;;@1`;`Q&sG4P$VtTFy`O1#8g`48NtcXZW3MsF2WPR* z+c~B=K0ebj#`>)Bi-wL8wGSov`DV`}6stUr^-o@p=3!g+(Mme!77@ABC63;W9QEHb z0L*Q$Il!JTvS5$Wo*)L2^0fOANIVh@Yvfn|Yt*PGlfF2&o-&|LUH9ls++K=>nnC{Lti2)IXnkYuOXH(&yRS%-x%_=@F?-NP32y> z8WTGQ&kxnn(@4Vk~Z&H=C$2ZPyxkG6Fiuhp&?Jge8k(JUeo%9CW<-!_>k^V0RS z`}8cx6szxq!J#c{dGx@7QSu#i42)~HZI5gF&3+Q-@iwI7bvmgv^%{WpJ8h=X$f5R_ z1siy1y(~khQmDcnYx}Y4juH{y_2#+gF3q-%N00m@X_?|)?T`cY0-NB`&^1wy z!{&h(dj@d6gUNjWY)I3qBkhCqib|Le8m+p+b>JdDY#unv#xEi^*0^Ti=u1q0v<^}$ zj-2~Q^Z(anzI1Mz#x_kXkdut7z5~|*lfCQ_aTF?GNDo$k4Sp#+wk=%9tjFT(GcT77o0!LW^1M3hfz%RXqwEC3x?596!Im ztkagMLFRm~>@|ausu^^b?k2#d=?elmfIx)swgik1I~rJD1ZNyJ50WbESxt6OG3yW@ zn(;@=m*6O>GXE`0LU+|?kV*^?L4^Oym3`#h)6qu;Y#M3r?Wt|?&`)>h`tz^1U}x-v z1}GB}c%Ly9H^YI)-iS5EM~;$p;+|21{dPl`H(Hg8Jtjuy z&omwP2=;X7HmUmDC^SEnhq={CWemYIgI=Zv=3 zVSd6S*3!Yy`6);{K<<0k0yV}o&{LK|q?&nba{K2rw}LCAOQx-O5LP%ivn>)hwAj`9 z|6pW(;j89j-w1S?pPiYOk@5Z6vL${v{jncoP{lu&)G}&h$Qr|_*mQlQcvK!owknm# zSts24>N8YiuGOxMyMP^Q)q0^gM?sS&t^GTirRbjiXUA<%-^Dmv)4}=fI}pN?z1_gg z_n1?%Pz}=xWv@BkOe=`4gwE-H)b~?nnkI@9Zgm7b2u>%AnkOcc1MQ86plk~<{O@dh zPE=uDRn_z_ISb$kD2d=d;PMb+CE=JU>CLX^D4WwAKl^-ay+Z-3$7f2LI4#gY$pe?U zZJitI-$!eHFCXB9k%(q>?dx;uQV*ifl_atO7)-%%@;U<+)7b|vdxy%7+KQ!Gg-0#N z`Zd?wrwjDT!<)LY11@td>0pkz4(hHTYvD)v*B{<#XHe4fE#gU@;);MbdJ0x%FIb%c zN(QXVkclV|DRaJVKe?WxWjp&q9v`b@wVZHdB%gEah9(&<$seYwcrS-@Ms&v*EZ6s{~i_P&CjAVpy1)vT$>#B7?NDt%}>#_T4^VZ zfV)|L>d4z-U_sodv?n$xk1~_ zD*7>iZo-3F=k4_fRp}BDrU1&BC`p#H9RZT_>8M0$%r#h6aai(c339w>>gU0kmJK3o zDvdKO^^e2}n{`P{GeCX#@u<)#s+I&Vj`Fzt+rf->K7HM|A^CgyR~he-#8Dmp7w5XtW9g)Ai?U2Z>p8iU>N<-z+Bvq5g7@Hj-rNdnrA?z?5IoihzgC>T3`7Tx( zO52)2=8V2$1o%-NE617chf!1lY(Ym{iq=N~_9q5f+y$?r~68GYOF2lf2$a74eN*9D5QHsfN1Gp7R(#`CctMj9t!t=C3F|xOS2+U^?Z@C;3*0)iquhOxpX8tCn8=%4bo&D*re!oi39_;%n zfg30-@tyRp?{kjyV|GU_l_p_6g~($kxDs|F`37} z@w|NP)Qj2C%FBX|_Qx`Yb2+a2Y19PtxOKf!s&VKdB3%Cr!p8IqduxF@_<0WGkpFORRXgle@YIN!kI;9`Sk}tAW$2!nKG(4#A-{yY?&EJP^zswWW zIA&j>2dpd!02kFgmD{%?4cvRtAg!m|*p+|u%2?8dZZv@R-XA!2er^7jf+V zJK&%6CY1dTcku29wmDZu!nckI{qe%TQVZq(YzMBU{0T|YmXej3WzenlTuWen`I%^I zzms0`{fPnND{}56h0l8Q4ff)83DkE+ju&F7H7k#Ymj5D${LTBsCz* z=gy$@T2OS+>s^|crI4MmL9$ey!A;^6-bNQzLkRhWMT+V`-g$o*EJiECv0jg~5OnT7L?+ohS3oEaF`c7p5(Dv?;RKg!( zApQ^g|5Q5n9qjl5)KX|^u2i@kl&H27^<0%kW-y3l?@a(^2)u3srUNhi2Gqex&Mtzc z5-S)WlRj?y&{gkgDol1xl>05tNjEN)j@%ZAl9zQ|ADt;Y+oLFS0>vRM^K|^9pRQb8 z@xW3Tb@AOK+PVhLW9b?zS_a)aS0&|A?d&pYf!ZzCkX%a(_yOMXMKIY0QwHT_0J}vZwAaS>HY(J)i3G( z*U)R<2Ih@_N%y}d-R}fVeo6PgCfy%)Wnm7v_kUlE{F-(#7>E;0HB?44D-){fTrk}Q}_Ij*IyF&C4pZO_z5JiqcBC&U_Y!rrQ_?Zj+{3FraNxY2`a0EYOUAt<0J^ZexeV? z$LTqtq}4%$Gr8ub#KHtqb&+3I=5VG0$mA)`)f5pgc-obkJ=ic94^Njw`8!_-288IwK!m01BZlv^NF8NGhWR5meCLtc3kF08_x2N|M7}lmL{8aY5x_?(!p6 zgTbg-W@I&53&_NXH`#82qn&(ZQ`75AfGR?7riykpp8*a`08}v@3vF0j(?Rd*K_|$e zYaO6nzmOd$hQ=fWG2h>bK>=~^2w*BEDrz>_SO734-T=6vl^f?H;s4QF`ZC+62>zAG ffbazh5D!Yx1-_{+gj%n{90$)QLkHAApWpot-uB#A diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드31.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드31.jpeg deleted file mode 100644 index dea56721fd5396ac059228d3f76a5964dc27b50d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45745 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 MO@{ZXf`0k@U(v*-ng9R* diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드32.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드32.jpeg deleted file mode 100644 index 9f907b9a7f733730e3e50f8582efabb3f95d283f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59190 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드33.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드33.jpeg deleted file mode 100644 index 5f57e854bab5157167888c218734c7eb7e680337..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45175 zcmeFZ2Urx%)-KvG1OWv^kjx;Upnyn5(tt`5k)Y%-l0_s*mM{pClYoGLFhmhak|oHH zg9u0#kTe8|GD95F%x%9v?C;b4pS}Nc&w1{1&fSd-Jx+CXRrRV>?|Ro-MfggX1!!+8 zt0@CSL;#=){s4qIAWF&0&ISN9G=M7r0Gt9yiRb_bctr&M07NVR=^xhsaGQwrKd*I& z`2M{NF#v?x0VMxk#t8iT^8jo9dH28ng=7-_t;S5^|0qrTB@^i#r1G(0jo_H}$>4n4oHxb%H_Wfi-% zy|cTwk2^U0*)MQB|E*i#?|^=lHi2@wBr zK!}MUq!0*%l#CQS$WD>{JWf%b`s1Md_v7>*2ldZ`=06VtSP2nW2MGxYIrxv3ih_#v zzkLv+KKd2W8C`SYs(C`9-|sJh^LhKIZa=~yXTZrxte;+q zBHq{s!zn68JZdTTdY|H)1z$E*7`9oqMvQ1Rb*!zQ#OvwSUaP@ydqbU@PLH#1fhqTv zL+@mV)&0v$k?tY~3I`#=A1<3c5=5Yp0S!X#KDMQ+g;oCKO6yZhtob{S<0JRThSI0le=+B@RkP!ZDah*di64uv6JpK(Kf4X z*{0Bk&JB7_9mtSIaV%q)`?#-AmeHz*bYncXqO)vQ^1XQeNJHC)6Nlq;niXQg;cX&a zvnEjO=9)j&LQmw{axT_HGTNU~10Bm|wAND$ zSFwHidF)f9WfjSlGv)8PAGJ3*ZEi|!nm{`=1I;dCJ!<_g35 z5;RloKOE!cZ%JerA0^V=6t?` zr}rCN@}2scp&vQrwekF2rkr&tqf)bRiCt=@Q@Yyk+g|}9N?JH`0>CAowu>YHDssNH zo=4YxZ)2T;AK>hYSChYIf!hu2)ON<1c1a*HnktZ4^@k@+N){^|z{tXYvre zdY+c1?5eExT$-_i-qxCaMaawzht%h>E-ZOzrv@ErP8*+vUcKcjFR!P!toXJ;2~7Yf zaLO`v4Ti;Em&>Mm7MjLtgpDbzxn*cS_0+x>eb&d1Mx4X`92 z?(U?Q5u#%1(Ru0n=MQ~yyl)R=!v*4RdsN6?rhG8_b{`6Th?m6fhsjF5^U~Bn-a$~p zH3Vjy8l)f8MtJdr?$b4&S#hSO;^(qfJ$RN$b0-;H+JY0TQtv)C&rxy8zANao;Be#H z#q`$eQA#q5Z90s4TBSiB&PD~9R#o*@ZB*(fJ;~kM&hBQ5dvE1to@j0ULXn&^=2U5v zAOW!HhfdmiGJe6OoD~<;nn??GlQgn&v6nP@?)iH17cyHEDmQ{ zGMEP&nCH^@Tcqj4o_a((Fyz(MGn&(1IqNCB@S0i!a2ime2ef}V^L+NbS)8s#q4UM`PL_ z206ArH&#ZV?aU*tUy9QkdEo7DFcNNU{8m+an|A)8EE*Ytzks{hK4U=up8Mmz5dgcJ za_wc;G-#7pZGx@cMYtAq^P?a$o;|N6WP@7a5MIppC`Wgv>as|qvJtM28O=)-v}&#= zX>6CB*pkmRSmotLS?N!G*k!sSGfMzkrF{7d?dn>+6n**qobvh|+yoZ_)m2hgiaBlt zJubf;$30nbD|At7^Gk+;d|Y+}A5he5jF$uNEG^VL;ftwU6a6`6Ua+;*Ap&rlJCi1F zx7bw)Go2z|gBH9oqdruuAo6YM_KTZLHk4Fd3s)AyAiM>{6&t?Rb5v^@SMfb2Wgn`? zpglv2F-yEL*uCUQ2pQMCDuX!@XNu)Bt^|PoSh56H*a98TU@^8G&K!12!^Qv552S!q zR8jeKC?`oRSxvuBBvJm#;}WsW4xRl`?ew@oyQuk%(VC7|Uc*fn(n8tyhPU?AZ7@c6 zz9|2&-pWbR6K>;B_TY3;;Mj$RHNYflB||O@Z@>*|f*pCv4PSiA6>u&WQ`kJENfg#B zw-$@*ApkrCsU! zS}#!av7yyB=B6;F;R4?JUu)RtK}}yK0O9^NOr>+019+8L_vqlg0#AmJG^dLrpF1BZ z(ItDxIn!IEt~=qGaGSSLq3Xkx-VP-tj)R~07OuQeTjV+D2N0-FvmFm3E zmG>6WcD~(AKVZVP7ehb!YXSJ|4z#dvA=5yhi#-CicBnG{>gjzG)&hRf&fR{%tG+e$ zzR{1e2j)ZhZZZ6c@z>20bEy?#RL2vsi`5&s8{Fh1QT_SHQrL`wxq@T3dA@g@M#YtG zsrYO3jq6tD&m5E2WbLMx+{r?>Bh>`9hK@Qd2>oFAZQDU4$&O!#iK z<^1&YxqHh9CZsARY$!o9Xd~&;^u#n2re$!c$}M?ALri;0;LiFQ1&oh8LyFZKUlZka z|0SdNk=#ety96NVFx7{WW1zi9-5tLa{f{+%kC!Cu~Nl=MohZBHAlL+9qCSmBlMA^=eD5+iRP6q%2&gUZLy9cdJdD} zHu7rRmE~elz*RLF1?_}oGJvBsV#j%x|9ba*JyZGpwZ;9{RhAk`QgTo65Weh)_3JGW ze3`_5I;l&WkXtf1AAE}h^6s z2|)0@u^q~mpmq-Cx-mytL5ITeo}%&0cpv%?(Iwf+l+78mlf$&16uFr=_ZjNp(zw{! z{V?}4#vNw7L%Xu8MtNV5sx{sdRQ67ynw4c4dhtxp*JO%BuB2}%XXZTan}feZKJ;U_ zzss(oIVf<|-PCB6pPyf9!tQ(es8n_|*^;Nn1>O6n<5htt_UPvr-VQ-YW6b{Z#Zf26 z%`cp$YFFKvIm@b}OARQD*Rh5s!g>M19(3n*;X)QUGzMSr3|^mv0vq{oK4?LWDnVn@ zn)+a#k0`$zJlh*dY~IBVRAJ+-GMA(K3}fbB12mZyjpZ3=b=9lf@m_H}UL(!!YMzfR zG8f1uCe>zV=d%iRx8i--aLIEY^|g@Ahk374eFdGI-rSVyZLfcWWPg)I*DTXXpK>Ht z6TUDju{>wmrYd}yBlL^CVIxxc!i@bs6N-1d09Zx^Qn5i z60)k!dL*bbD6=8$R$G%S!xJ6E{a|)BhWZp&@mPnjFD0(RK3gNtE_Hc`TQsNpOi7s+ z>8f{)i17Bs8bnzlT^n&bYv|c^3;N4Y1z%yz-Lly=_FK5ndq}-up&yWx@AXN`2ihHP zBe#nl=3hu@_%NU@{Ma>sXk|oi9xv~PI-*!X9U7i7dRGI*Zs!qzubLVJV6f{UWc3PP zb^zr+IImxCaGIO+@kuLK%#d2o-TFRd=X@G|_2kDJ*&-ih-xgv^+`I3Qum#;w#M-BM z0-#jotdBaqxmhG`e_5R0tFO$N_hqL&pTWZYD;L99DlFP3 z05?7mfB^>uDB;VARCzTP{tTQ7HMCbL}Hra9dMq?Hjk9T_=ts05#AOgtE{Py{oL*6sPEVt((U1oL*U#*C^ zVjfGsB_Bfmxwf43X#udF#8^C$IsxbwpGBSZ=R8&&l=W|9#>}d#dpE>Ac6{vgL+?9f zsc>|$K)wzw-6=b*!0S!Tu)A91GJ8(v5npb15&!@k+J#j4UUdH?qV@gVZE9!sLo&jwIc0{W^j7>5~Y}=u5 zrJGrFLx1Rv2ei?@NQfTVrSG~Y1SJ4pZ0`_&W~-UwwEO-{h_2W-C$`|A_M4fbOT#7_ zQ|9vq+=R{`%=#d@B;?8{DN6=vJ3x?fY0V!_m;(_%E}bI20? z_GvOT{f$$bfe$jMbtAa~{M3KxkjmEv1OZS?7bO6s35YER-y(l$ud3ai6PY8O^L4T9 z)e|BHEpD44te3DP9zvpR`INKZzl1f_T0^6&L!k@`|-@joCcz6;CzR4ZtAsEI`k^o#9_@ycE>s~z|B95&@ z(c(&PzyDAjW*2ArvdZ}0UK&%T1j?p9-qs`LR-LFSgYSD9BKe25yw7l1*r2_b0bi8@ zI}Y~2tRRiSHzU4lA4Y6HoQ3tjk&L%+KZxV`?kUytARrgAjw@ z|N27go5hh~1mOHSUc}7Hp1fY zkd&-kCIDwEqm4U_YFe8~y5HFe7p<>U`*;Lb&o;cM2;-3n;d-t7Lu8;Zy8<{P^ba2Y z9To{^Z19`&({G>f4|j2TJYkxV=};V9;FDM#bTe5?!}zl;pM~+_`LsJqlFn)tq%H`y z#;g7V@=Rk5+Bvv$w}UHBuG%xt*Xz=KQ!)3b)()lh)*)nSzWi=gUH&oh3lhl2aGcHtxs#izPr!L!Rd7pcPemKW^c70a8D2^w$ zD~rq^yTmhm zu0tuqL3=~%Buk#CgpEX#TS%KIf#Rh~Luz7*v;}};^M9xU;n!eo(5R!B11s|70tuNba+UtmlOb&*se+M7Tr&RG z^;JNdf}Ory_MzVST~^7(XB;=HZGA`!o{(xE}IQn;r0(`9)Dd|0+vW_8qC!g_$@R(=jnt z?t({8-GfJZi{Fw)ZMUA2bust1{1{+D?Tv1HP=zbN!u0*@H8EAYrC}w4J8-(*oNp5o zVGl-x1d4Z31bK8l6T*H7@zz|hnz;R9M&vc%$N!6_GLXN5Nsd0&pNqC^8GE{yeww8{ zz5R9kr4)%B^{@#E>)szC5G$KT7n~i|b3Qb}pLePit$ylpgRpy+X2FWOqwMlkQQ2&Y zGtCjA+gv5|!l!d#tnXz&nem6=^3f~P(D1m)NsT?eJla;vw?-SUH@4|NP8A8K*EZdc z>t5I*d$cm_9RJ$$R^Ju1_Feg>1R&HGF?>V-UY6q5a`5cnB)hkX*FhbXd_&rYd6k0sH_2XJs;f3m9AVD2%6QoQA}?=xu_pL6^XUNzF23fqsFO_CLnPEo zgoeogcblXV-#xTW!V>X3m1$Qzt}pMj&Hc9NJFeqIFU?FbqHGaJQ#@*k0BnO#zZiSK z0X?jEMgWkANCF@Vp8r+5P^xcpP7u8W;QKya9lAxcYYQO&@&tepZ@aX4EHjVKpE=G$ z?3+R{o3V#T#8x5!m~uZQK>{`r;0{`ui2T-mX^ z1OQx3kuwJZh%VU3YntPuWB36wm2sv_HiI|@%B(c6=yj;k-mpexR}V={xkg2m@C>J4 z_gCQbaT|>|4m(U9r8!|sT&P0Z)GqO}^Yt*u+f)w-b#o6iTMs+0bVNBI;KRSnW0mm+ zLl8jlLyw7*!2!0<&TdGk{0C*o(J>!Oakfo$88vgyD29uZM4`xYy(}Sdx>NBI`VYbk zyEOWrZRJ#-ZFIqOw$FqcjfJ?|Pxd@dT(9)IbW-ZzFc-p<>391FRbhJaT{hWjt;pwe zTTy(&h+ZpqIf1N z=RV9$q6a#H9~0txdwDyY*gozR7w|~i4OU*B3$fR{WbWy{7j3bxp-nRFqR6Rkb(uN1 zp_}Qg70Cn0veREM=)f=fd--i9wdY?OC~kzFY)3vELZGd!6AJ9Uf|xxyr`oe?88ekxwO!sMu)u{Y*StjSVj#Hd8dxfvYDmS0|^EOI{ z)Vt!2h;k3Cwnwj@yMtIIoC5; zA2KB{q-4tz(^)S=thRrtp3nE*?BqksnwpVyu8512VKry3ynEXOkTn5r47b$3VpR~JLioN4f!^>HGz!7=zbk3vR%5B3K zKKR2S>P1gksRhKBPM|D<4VpM$j43hOfyEf^1UOc;DrlEB>otS6L zil>C9 zdbR4r9w(En6pxgg(v!nBD5Pr2?pW#V8jJU^wd%Zg_Q)O5QMOmDr}7mhJ=v@{sy6Ox zkw=;t`u9yle;Ye|&cRSySL+dPXl=|Gui~0yV?&a}vk?D8!{Y^RbFQ~8u?9<>NNZsb zTpvKJd9QW1WHbWUp0aI6P&Fv#%sgc2L*-4`9loTSG`TfaM#Lj}S>?vfpb#Aua`9gK z70k`HiC3fUewKHA<|vI*vPR_lHcmhO5!S(+;H>A#|9ak~^PXA165#c5qjY_{;M>O^ z`Ox4^$J~yC68Uzq(n?a&^sUd%KsV25bycA+2bL@(gKb1S`eNmBlrrCZV+4ds;pVL` z4Lba{1`yT4Peh-$^3Vb#-CYuIX_q~sM~lUO`` zhnl?4-%-Z3-LFCk@P+#1`SPG@28*pxRpDYX9+ef>9tk;OCf`Sina?FM6>Q~nS@RHy%acoe>mg%C?h3@M9M`&cBsXsz6IM`0Se;A)$9Oy>GxRj zXKsa54nlW^ch=Npqz0MHBfNB^(9t)txq<@T0RS~nh`=P{H1RA(_)mDIV z5r7u>9PIE6xPZ*wfgkJIuKM$18s4|W*`Ifuv8$3|Jev@lP66}Dgz!!@e)>bN;S9_G z0+5vk(i=@*5xBbEWKgE^M+Myv+)o6nsQ7rRL*UizFGCiyy|vEZTEⅅ*c*b8~rFF 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

    ;pj%KM8_G&AI7ZY=bkM><(HVb z014gXCCXDgkZRCavjtr^8Dl6M6lAYDLCpQv|FG}bp_x#hb&3$IO531m-%CF4&+)!y zMCgZVyo{GX$qV(v-Uj&Z2O5M}l6I=WZX_^y%6h8i&{tN$6*p@wv8Mb~0OM_3#FNKdH7PvD(u)7A97HkLH z=)tYB{?W60*{+lR49f|fd4%r1+;ny-?knjp;GD+; z#qe>dfJ4bHzt<*jga`S$r>cCv^H4K1(bHa5gPu=^L`9jHX~3JaY!^l9%lO5Y0ga;d z>JYrWt%JhyT$}tBKG=8axfUazgrTu<=mWO5@uoj$uaHp+!%bK47jW=GW4Ry61rPU= z1}3QXl9-DZq96B2`(>8LlNe{apk$szi8j9#k7YQ%h}r!(G7}~qeeOPu+*= zXBX<@No!Tvb03`7dp4>Sx+MJmfdmMY=gx5NY2i%gHrb553YDrKRxVd=u8+Ib2ks|r zcZT0*^hu8EJFk$Xc7=f+AO++8$Qp^g^k+YP>&|&u-%wXmS!18{j62z(@@yLc5LrN8 zpWimIP3GD1E-gRT4yVWs`7|f)cQ$)CKXqcHZEw<%wrmAQys_%uAm$`9$7aN~LJ#~}nJ-Gip z4pp@2)_W!P?xswdo|zCtS#{xD>?vOb%$t;1oGi?GUhaIWs-L`{p?p_aOQXpK{T@d1 znhjKbMZ2f=;;VQKKcOQr-*Z@av+`)=#_gdyHACXs^f~ML>Z0N3Pf@u~9Rh=|bPA}y z4hD!)52az}y^KuF9Eb&Nx_8yRGQ1r~+id2zqLj^)V?AcyU5ZNL2Bd8_PcJRQ&-z2X z-W(l?w#xGk?)o%^Xma)KQH6V46`ADrkYZ+*>J%dy|8E3k{I;{+KXETn|0JSo;FLMc>e>frA4mz?|VA_+}H8HJb%?fzle$! zIhb|(Ybu9X#XOwKE<+0AQ9Ik~$Ssd7HTd?`M47F_jQ`aHuU1cBt)6U*lDFh;X+E4R^9luh?w<5xl83JuN1x2!ZKw#= zcpt=J#MQLP-DR#Xh%CgDHH2)J*lhpU*Nb6X3R9@it9G0e4gIwwTs8fRm%L=wJm)qV?)&wb7#a>P} zbuqgvRa~*5?yU|D_c99~1S`4cfiuR!n&Fi-F|y1q`Qs}Shd33(>gQAsC)KuDCR;wy zO*wE6eQ9nLuv~mW6mAu-}{KT@>$m?~S*xEk6Se;&Ub$EW-%y0wvF-(>@|Ot%hGhRE z8<@ZAH!AA-v6=&5e<$6^taRST)aNvTO$mrB81T2{2CiW4`ATP_5bTs<9^!tM1k#VS?knmOzqm_OLD{my>~fB7U$ zCE8ci4^4H{D-B~Zd!(=RNO^EB=h~fAH$4nRZsJ0SZOkkmXIQq?4J-GXhw4YtW?qq6 zIKere{`0-!9c4UptjX!Q-lqfY$OVP^l%-f}JNPG-|0Xa0G|dJ7GlK|f$X_W&KH%M0 za`jWc`l*?I_DYKA!Q0KWR3w2$eP9!`;i#rp^hgdWf>{-*YHt!NYqDR5 z@W%rJnF$Jv3GM!jep2=nMTTj_&Awp9lFFhZf4$?$*S=|&*Yl|vYi(xGvRg^}_o{2u zSZ>|q>3WuWX_AvPtXpp`)UvshZRnUB?I$^Rd`K@OkPNdoJkNz`yA+j3v&5CGz-0C6 zc`z$P>hyh;cR22jy3o*_${4h|56-qB$(8B3lzn87^o~2L!K_;NH3jH}K7hPYh382} zd0X>9leP7A5)MTYce2EE`gaw8$(*9xUD0PaVtbf!b$#XFBf6v@K)YA-eDBTn@E;PN$Z MqFm#B&6Ycv$lx`#LMIPRv9~OYx@tpKW@Yry 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 #8rE)hfTWQ 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ÌGD`OGmRx-VB7$K= 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드38.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드38.jpeg deleted file mode 100644 index 09dc2b3c3f92f26745622c3d4ba077cbcc736a2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53874 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 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드5.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드5.jpeg deleted file mode 100644 index 1eb2c7d12e5d2189f47f7122fcd8e504bd2f7c3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72131 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 JWiN*RHvwarR|fz9 diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드6.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드6.jpeg deleted file mode 100644 index ed4772a958b7a620af929bf9c1ffec450ad61744..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54022 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 F^AGcS{*eFx diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드8.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드8.jpeg deleted file mode 100644 index 8678d995182139b030ca5fcb1f829e1b2024e45a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9784 zcmeHLdpwj`A3t+phBk~#MQ$0l+)7x?s_C*LQ!BJGA{3G#kYOdKG19*lPYm<$kD^#M2l+x*Et z3{(Hu1`fbwGC+Q8W5=skz>B=n`(uqrhy5Ng9saM@@RoGMCtr4@8^i%dmhRqu-sjxC zeH8U{wgaQRM04aybRJfHl~q@)UG9gj7*K>94HHTnpWhn-RRRneE(>o#z?1+S14Ce7 zP&H8Cu@Hc*VznEufWZ++0YMa6NO&Eu0bLBhVF&~qi4YK283y(p?>azY1jM)K?h%x* zI)PF;E4d>)HUo{_`;Z}Zm^rDe=j?k?NO;4>P0}(ds%q+6HS`U>G&C~C?faTwy5Ed= z;9Kh>HYD4lb}p_b-A=iaJKmT7wzYS3vR-v{53mP^-VBfYIyyEr{r(>_vvczciz~W# z`TR{5ul!BfpLAh(y5LA80*PAD1%sbo5spC$Y|#}I-(!V3aaKZUM>tw?Z*0axh7eZo z@T8QpFH?Afvi^X|)QYrKW&fG5i+@SkCt<(q>H+%zd=&^d93g-}AOr*jco0Mjt^h5J zUWM>Se6b3V6^MQU#0vuB#XusFDBdZyPH3Ije+}pt-n7()y1^F+7;iEmFaQr0_fpjh z2lNJ?QPtDod}N|f3;$AQ@-OvP{-xf=ztr3LmwE^PQt$kC>a4V?MNVtV|`=PziUA!&Bk zo|L>JrDA(L8m%86zJ=gv?~daP#qK+md#qWxKe5xuAu4RgfiMxuNOZ^EvCgqt_Q8X% z9Q!EItZ0Jz*na0+q{4kq4GHS-*?`U8T%>Bursa6p(d)YO3y6iM7~VRYy7yO(1>~v0 zGsS#8bVjkBjk@C6qi*YpxuZ73`Zq5@6Jl>OOLBT$cuA#KXg^ovm?Yq8ud8$-)u$MH# zUB@A}6p$pI=XqpiH_DUCsa_5$UQQNI*v}kP-;|7{wYd1k;A9#!HBIs*1&e_(H zAH}BD$&%{i4La=i%|Fe5yH)&Ur`^>=QwaFaZa3OhTV98;-IGTVT(4o1`rIhTR@wW> z)Vgo5@+cJ_3&g0C_E=qI#bmLGrAe^r2hrqhwBx^&z33}Nc^ma4&CS1yiWm0DRT1s0 zeeqN(-?V%7{g<`c;)lAIFXt1cG;7TV-r_e92h5HA3c75RuN!I8uGh`smijM{(qGqj zqH3>+Yf@UVOYy$d8kb%kgWdj4^EQhf8d<)1(k)@&zDKhqojK%Ntn>q_w}!<_l(Z7N-jSbw4rS%SJg}QOGzdj zJ~T~Kzb{X#*ylQ9yTlX0cdW`nNXQ6E-N*>mHhk>WJ5#wCP_pSDU{etLYFo*==xc3MP-jyr>i zx7AO26EIZVmmeiIA*6r*E;mLvld3t5Z4_3|4Ewtn{!bsKPa`TJAo&OaX!l&RvdNAI z_m(})R1@=jHi;%A_Jqec&J6y8ltCMgpN!vGEN?^WQCrA~%C)NLQ){~s!u)Xma6QF_ zH9ocUs_7PCaT^W1b(pJCi0byfN{`C!;M~(kbJBO&2SzC*IwWAVAIUnGt7Mj!AlSQ3 z9eU)^k%n{7mI_TG;Z8*7rSv>zj)thRObiMv@+koe7&8f7BJJ9k%NPb%De_@`64Rzq)kc~V}@GC`μq%+uS@gC)U55$vGlRmJRN4>Tw zWk;2jQ6INZV#Wi?Rm#2O7Z1*3Q<60EMO+hZPdM*xP`f>t^bS8j;U0!S`TztfFN7`| zI$98dYh*_xOwZ9|?&QD!iY{%iuq#F9+}$Gc=`#76Os>ULWCc4#@OAYfgT^q}OjH)Z zMjHreq%<9|2DqVi2*}UK;jO1W^p2M3I#kWNlY(`MbWDAB-1&hOW#vFGjl+;oCfaUq zUa07}^#rNjFUsfl>h($ diff --git a/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드9.jpeg b/plans/SAM_ERP_Storyboard_D1.0_251218/슬라이드9.jpeg deleted file mode 100644 index a9bd23295e58bc12f0d8302f103a9ae84537410a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58670 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 diff --git a/plans/archive/5130-bom-migration-plan.md b/plans/archive/5130-bom-migration-plan.md new file mode 100644 index 0000000..a970d91 --- /dev/null +++ b/plans/archive/5130-bom-migration-plan.md @@ -0,0 +1,446 @@ +# 5130 → SAM BOM 데이터 마이그레이션 계획 + +> **작성일**: 2025-01-20 +> **목적**: 5130 레거시 시스템의 BOM 데이터를 SAM items 테이블의 bom 컬럼에 마이그레이션 +> **기준 문서**: `api/app/Services/Quote/FormulaEvaluatorService.php` +> **상태**: ✅ 완료 (Serena ID: 5130-bom-migration-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | BOM 마이그레이션 실행 완료 (61건) | +| **다음 작업** | 견적 페이지에서 실제 테스트 (사용자 수동 확인) | +| **진행률** | 4/4 (100%) | +| **마지막 업데이트** | 2025-01-20 | + +--- + +## 1. 개요 + +### 1.1 배경 + +5130 레거시 시스템에서 SAM으로 품목(items) 마이그레이션이 완료되었으나, 완제품(FG)의 BOM 데이터가 마이그레이션되지 않아 다음 문제가 발생: + +``` +문제 현상: +- 견적 페이지에서 "국민방화스크린 (일체형) (S0001)" 선택 후 자동 견적 산출 → 합계 0원 +- 원인: S0001의 bom 컬럼이 NULL +- items 테이블에서 확인: SELECT bom FROM items WHERE code = 'S0001' → NULL +``` + +**기존 마이그레이션 상태:** +- Items: 608건 (KDunitprice → items) +- Orders: 24,424건 +- Order Items: 43,900건 +- ❌ BOM 데이터: 마이그레이션 안됨 + +### 1.2 기준 원칙 +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. FormulaEvaluatorService 호환 BOM JSON 형식 생성 │ +│ 2. 동적 수량 계산을 위한 quantityFormula 필드 지원 │ +│ 3. childItemCode 기반 참조 (child_item_id 아님) │ +│ 4. 기존 SAM BOM 패턴과 일관성 유지 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | BOM JSON 데이터 추가, 매핑 테이블 생성 | 불필요 | +| ⚠️ 컨펌 필요 | 기존 items 데이터 수정, 새 마이그레이션 스크립트 | **필수** | +| 🔴 금지 | items 테이블 구조 변경, 기존 BOM 삭제 | 별도 협의 | + +### 1.4 준수 규칙 +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `api/app/Services/Quote/FormulaEvaluatorService.php` - BOM 계산 로직 + +--- + +## 2. 데이터 구조 분석 + +### 2.1 5130 BOM 구조 + +``` +5130 DB (chandj) +├── KDunitprice (품목 마스터) +│ ├── prodcode: 품목 코드 +│ ├── item_name: 품목명 +│ └── item_div: [제품], [상품], [부재료], [원재료], [반제품] +│ +├── models (모델 마스터) +│ ├── model_id: PK +│ ├── model_name: KSS01, KSE01, KWE01... (모델 코드) +│ ├── major_category: 스크린 | 철재 +│ ├── finishing_type: SUS마감 | EGI마감 +│ └── guiderail_type: 벽면형 | 측면형 +│ +├── parts (1단계 BOM - 모델별 부품) +│ ├── part_id: PK +│ ├── model_id: FK → models +│ ├── part_name: 가이드레일, 하단마감재 등 +│ ├── spec: 120*70, 60*40 등 +│ ├── quantity: 수량 +│ ├── unit: SET, EA 등 +│ └── unitprice: 단가 (문자열, 콤마 포함) +│ +└── parts_sub (2단계 BOM - 부품별 원자재) + ├── subpart_id: PK + ├── part_id: FK → parts + ├── subpart_name: 1번(마감제), 2번(본체) 등 + ├── material: SUS 1.2T, EGI 1.55T 등 + ├── quantity: 수량 + ├── bendSum, plateSum, finalSum: 가공 관련 + └── unitPrice, computedPrice, lineTotal: 금액 +``` + +**5130 model_id별 데이터 현황:** +| model_id | model_name | category | finishing | guiderail | parts 수 | +|----------|------------|----------|-----------|-----------|----------| +| 12 | KSS01 | 스크린 | SUS마감 | 벽면형 | 2 | +| 13 | KSS01 | 스크린 | SUS마감 | 측면형 | 2 | +| 14 | KSE01 | 스크린 | SUS마감 | 벽면형 | 2 | +| ... | ... | ... | ... | ... | ... | + +**5130 KDunitprice item_div 분포:** +| item_div | 건수 | SAM item_type 매핑 | +|----------|------|-------------------| +| [제품] | 194건 | FG (완제품) | +| [상품] | 260건 | SM (부자재) | +| [부재료] | 48건 | SM (부자재) | +| [원재료] | 24건 | RM (원자재) | +| [반제품] | 73건 | SF (반제품) | +| [무형상품] | 4건 | CS (서비스) | + +### 2.2 SAM BOM 구조 + +```sql +-- SAM items 테이블 BOM 컬럼 +items.bom: JSON +``` + +**SAM BOM JSON 형식 (FormulaEvaluatorService 호환):** +```json +[ + { + "childItemCode": "SF-SCR-F01", // 필수: 하위 품목 코드 + "quantity": 1, // 필수: 기본 수량 + "quantityFormula": "W*H/1000000", // 선택: 동적 수량 계산식 + "unit": "M2", // 선택: 단위 + "note": "스크린 원단" // 선택: 비고 + }, + { + "childItemCode": "SF-SCR-M01", + "quantity": 1, + "quantityFormula": "", + "unit": "EA", + "note": "소형용 모터" + } +] +``` + +**기존 SAM BOM 예시 (FG-SCR-001):** +```json +[ + {"unit":"M2","quantity":1,"childItemCode":"SF-SCR-F01","quantityFormula":"W*H/1000000"}, + {"unit":"M","quantity":1,"childItemCode":"SF-SCR-F02","quantityFormula":"H/1000"}, + {"unit":"EA","quantity":1,"childItemCode":"SF-SCR-M01","quantityFormula":"","note":"소형용"}, + {"unit":"EA","quantity":20,"childItemCode":"SM-B002","quantityFormula":"","note":"조립용"} +] +``` + +### 2.3 핵심 차이점 + +| 항목 | 5130 | SAM | +|------|------|-----| +| **BOM 저장 위치** | parts/parts_sub 테이블 | items.bom JSON 컬럼 | +| **연결 기준** | model_id (모델 기준) | childItemCode (품목 코드 기준) | +| **수량 계산** | 고정값 + estimate.detailJson | quantityFormula 동적 계산 | +| **단가 계산** | parts.unitprice 고정 | FormulaEvaluatorService 동적 | +| **계층 구조** | 2단계 (parts → parts_sub) | 1단계 (flat JSON array) | + +--- + +## 3. 마이그레이션 전략 + +### 3.1 접근 방식: 수동 매핑 + 템플릿 기반 + +5130의 BOM 구조와 SAM의 BOM 구조가 근본적으로 다르기 때문에, 자동 변환이 아닌 **수동 매핑 + 템플릿 기반** 접근 필요: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 전략: 완제품(FG) 유형별 BOM 템플릿 정의 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. SCREEN 완제품 → screen_bom_template │ +│ 2. STEEL 완제품 → steel_bom_template │ +│ 3. BENDING 완제품 → bending_bom_template │ +│ │ +│ 각 템플릿은 FormulaEvaluatorService 호환 JSON 형식으로 정의 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 완제품-모델 매핑 + +**매핑 대상 (SAM items WHERE item_type='FG' AND source='5130'):** +```sql +-- SAM에서 5130에서 마이그레이션된 완제품 목록 +SELECT id, code, name, item_category +FROM items +WHERE item_type = 'FG' + AND (legacy_code IS NOT NULL OR code LIKE 'S%'); +``` + +**주요 완제품 매핑 예시:** +| SAM code | SAM name | item_category | 5130 model | +|----------|----------|---------------|------------| +| S0001 | 국민방화스크린(일체형) | SCREEN | KSS01 (스크린/SUS/벽면형) | +| S0002 | 국민방화스크린(분리형) | SCREEN | KSE01 (스크린/SUS/벽면형) | +| ... | ... | ... | ... | + +### 3.3 BOM 템플릿 정의 + +**SCREEN 완제품 BOM 템플릿:** +```json +[ + {"childItemCode": "RM-SCR-FABRIC", "quantity": 1, "quantityFormula": "W*H/1000000", "unit": "M2", "note": "스크린 원단"}, + {"childItemCode": "PT-SCR-GUIDE", "quantity": 1, "quantityFormula": "H/1000", "unit": "M", "note": "가이드레일"}, + {"childItemCode": "PT-SCR-BOTTOM", "quantity": 1, "quantityFormula": "W/1000", "unit": "M", "note": "하단바"}, + {"childItemCode": "PT-SCR-CASE", "quantity": 1, "quantityFormula": "W/1000", "unit": "M", "note": "케이스"}, + {"childItemCode": "PT-SCR-MOTOR", "quantity": 1, "quantityFormula": "", "unit": "EA", "note": "모터"} +] +``` + +--- + +## 4. 작업 절차 + +### 4.1 Phase 1: 하위 품목 확인 및 생성 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | BOM에 필요한 하위 품목(SF, PT, RM) 목록 정의 | ✅ | 52개 품목 정의됨 | +| 1.2 | SAM items 테이블에 하위 품목 존재 여부 확인 | ✅ | 52개 모두 존재 확인 | +| 1.3 | 누락된 하위 품목 생성 (필요시) | ✅ | 누락 품목 없음 (생성 불필요) | + +### 4.2 Phase 2: BOM 템플릿 정의 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | SCREEN 완제품용 BOM 템플릿 정의 | ✅ | FG-SCR-001 (14개 항목) | +| 2.2 | STEEL 완제품용 BOM 템플릿 정의 | ✅ | FG-STL-001 (12개 항목) | +| 2.3 | BENDING 완제품용 BOM 템플릿 정의 | ✅ | FG-BND-001 (6개 항목) | + +### 4.3 Phase 3: 마이그레이션 스크립트 작성 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | Migrate5130Bom 커맨드 생성 | ✅ | `api/app/Console/Commands/Migrate5130Bom.php` | +| 3.2 | 완제품-템플릿 매핑 로직 구현 | ✅ | item_category 기반 매핑 | +| 3.3 | items.bom 컬럼 업데이트 로직 구현 | ✅ | DB::table 직접 업데이트 | +| 3.4 | 검증 로직 구현 | ✅ | dry-run, verbose 옵션 지원 | + +### 4.4 Phase 4: 검증 및 테스트 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | Migrate5130Bom 커맨드 실행 | ✅ | 61건 처리 완료 | +| 4.2 | 견적 페이지에서 실제 테스트 | ⏳ | 사용자 수동 확인 필요 | +| 4.3 | 결과 문서화 | ✅ | 본 문서 업데이트 | + +--- + +## 5. 기술 상세 + +### 5.1 FormulaEvaluatorService BOM 처리 로직 + +```php +// api/app/Services/Quote/FormulaEvaluatorService.php + +// BOM JSON 필드 사용 위치: +// 1. getBomItems() - bom JSON 파싱 +// 2. calculateBomQuantity() - quantityFormula 평가 +// 3. childItemCode로 하위 품목 조회 + +// 주요 변수: +// - W0, H0: 개구부 치수 (입력값) +// - W1, H1: 제작 치수 (계산값) +// - W, H: W1, H1과 동일 +// - M: 면적 (m²) +// - K: 중량 (kg) +``` + +### 5.2 마이그레이션 스크립트 구조 + +```php +// api/app/Console/Commands/Migrate5130Bom.php + +class Migrate5130Bom extends Command +{ + protected $signature = 'migration:migrate-5130-bom + {--dry-run : 실제 변경 없이 시뮬레이션} + {--code= : 특정 품목 코드만 처리}'; + + // 1. item_category별 BOM 템플릿 정의 + private array $bomTemplates = [ + 'SCREEN' => [...], + 'STEEL' => [...], + 'BENDING' => [...] + ]; + + // 2. 완제품 조회 (5130 마이그레이션된 FG) + // 3. 템플릿 기반 BOM JSON 생성 + // 4. items.bom 컬럼 업데이트 +} +``` + +### 5.3 검증 쿼리 + +```sql +-- 마이그레이션 전: BOM이 NULL인 완제품 +SELECT code, name, item_category +FROM items +WHERE item_type = 'FG' + AND item_category IN ('SCREEN', 'STEEL', 'BENDING') + AND (bom IS NULL OR bom = '[]'); + +-- 마이그레이션 후: BOM이 있는 완제품 +SELECT code, name, item_category, JSON_LENGTH(bom) as bom_count +FROM items +WHERE item_type = 'FG' + AND item_category IN ('SCREEN', 'STEEL', 'BENDING') + AND bom IS NOT NULL + AND JSON_LENGTH(bom) > 0; +``` + +--- + +## 6. 컨펌 대기 목록 + +> 모든 승인 항목 완료 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | BOM 템플릿 확정 | SCREEN/STEEL/BENDING별 템플릿 | 견적 계산 | ✅ 완료 | +| 2 | 하위 품목 코드 확정 | childItemCode 명명 규칙 | items 테이블 | ✅ 완료 | +| 3 | 마이그레이션 실행 | items.bom 업데이트 | 완제품 61건 | ✅ 완료 | + +--- + +## 7. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-01-20 | 초안 | 계획 문서 작성 | - | - | +| 2025-01-20 | 분석 | 5130/SAM BOM 구조 분석 완료 | - | - | +| 2025-01-20 | 스크립트 | Migrate5130Bom 커맨드 생성 | `api/app/Console/Commands/Migrate5130Bom.php` | ✅ | +| 2025-01-20 | 실행 | BOM 마이그레이션 실행 (61건) | items.bom 컬럼 | ✅ | +| 2025-01-20 | 문서화 | 결과 문서화 완료 | 본 문서 | ✅ | + +--- + +## 8. 참고 문서 + +- **FormulaEvaluatorService**: `api/app/Services/Quote/FormulaEvaluatorService.php` +- **기존 마이그레이션**: `api/app/Console/Commands/Migrate5130PriceItems.php` +- **검증 커맨드**: `api/app/Console/Commands/Verify5130Calculation.php` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` + +--- + +## 9. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 9.1 세션 시작 시 (Load Strategy) +```javascript +// 순차적 로드 +read_memory("5130-bom-migration-state") // 1. 상태 파악 +read_memory("5130-bom-migration-rules") // 2. 규칙 확인 +read_memory("5130-bom-migration-mappings") // 3. 매핑 확인 +``` + +### 9.2 Serena 메모리 구조 +- `5130-bom-migration-state`: { phase, progress, next_step, last_decision } +- `5130-bom-migration-rules`: BOM 템플릿 정의, 변환 규칙 +- `5130-bom-migration-mappings`: 완제품-모델 매핑 테이블 + +--- + +## 10. 검증 결과 + +> 2025-01-20 마이그레이션 실행 완료 + +### 10.1 마이그레이션 실행 결과 + +``` +📊 카테고리별 BOM 적용 현황 (tenant_id=287): + SCREEN: 35건 + STEEL: 11건 + BENDING: 15건 + +✅ BOM 적용 완료: 61건 +⏳ BOM 미적용: 0건 +``` + +### 10.2 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| S0001 BOM JSON 확인 | childItemCode 5개 이상 | 14개 항목 적용됨 | ✅ | +| S0001 + W0=2500, H0=2000 | 견적 금액 > 0 | 사용자 확인 필요 | ⏳ | + +### 10.3 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 완제품 BOM NULL → JSON 변환 | ✅ | 61건 변환 완료 | +| BOM JSON 형식 호환 | ✅ | FormulaEvaluatorService 호환 형식 | +| 견적 계산 정상 동작 | ⏳ | 사용자 수동 확인 필요 | + +### 10.4 BOM 템플릿 상세 + +| 카테고리 | 소스 템플릿 | BOM 항목 수 | 적용 완제품 수 | +|----------|------------|------------|--------------| +| SCREEN | FG-SCR-001 | 14개 | 35건 | +| STEEL | FG-STL-001 | 12개 | 11건 | +| BENDING | FG-BND-001 | 6개 | 15건 | + +--- + +## 11. 자기완결성 점검 결과 + +> Phase 5.5에서 수행된 자기완결성 점검 결과 + +### 11.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | S0001 등 BOM NULL → 견적 0원 문제 해결 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 10.2 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | SCREEN/STEEL/BENDING 완제품 대상 | +| 4 | 의존성이 명시되어 있는가? | ✅ | FormulaEvaluatorService, 하위 품목 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 8 참조 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 4 참조 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 10.1 참조 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 수치/조건 명시 | + +### 11.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 4. 작업 절차 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 5.2 마이그레이션 스크립트 | +| Q4. 작업 완료 확인 방법은? | ✅ | 10. 검증 결과 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 8. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/5130-sam-data-migration-plan.md b/plans/archive/5130-sam-data-migration-plan.md new file mode 100644 index 0000000..5451064 --- /dev/null +++ b/plans/archive/5130-sam-data-migration-plan.md @@ -0,0 +1,828 @@ +# 5130 → SAM 자재/수주 데이터 마이그레이션 계획 + +> **작성일**: 2025-01-19 +> **목적**: 5130 레거시 시스템의 품목(KDunitprice, price_*) 및 수주(output, output_extra) 데이터를 SAM 구조(items, orders, order_items)로 마이그레이션 +> **기준 문서**: 5130/output/_row.php, 5130/KDunitprice/_row.php, api/database/migrations/* +> **상태**: ✅ 마이그레이션 완료 (Phase 1-4 완료) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4 - 전체 데이터 마이그레이션 실행 완료 | +| **다음 작업** | 완료 (운영 검증 후 문서 아카이브) | +| **진행률** | 14/14 (100%) | +| **마지막 업데이트** | 2026-01-20 | + +--- + +## 1. 개요 + +### 1.1 배경 + +5130 레거시 시스템에서 운영 중인 자재/수주 데이터를 SAM 신규 시스템으로 마이그레이션해야 합니다. +- 5130: 플랫 테이블 구조 + JSON 컬럼으로 데이터 저장 +- SAM: 정규화된 관계형 테이블 구조 + JSON attributes 필드 + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 📊 데이터 (값): 5130 우선 - 실제 운영 중인 사이트 │ +│ 🏗️ 구조: SAM 우선 - 신규 정규화 설계 │ +│ 🧮 견적 수식: 동일성 유지 - 5130과 SAM 결과값 일치 필수 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------:| +| ✅ 즉시 가능 | 필드 추가/변경, 마이그레이션 스크립트 작성, 문서 수정 | 불필요 | +| ⚠️ 컨펌 필요 | 테이블 구조 변경, 새 컬럼 추가, 데이터 타입 변경 | **필수** | +| 🔴 금지 | 기존 데이터 삭제, 운영 DB 직접 수정, 스키마 파괴적 변경 | 별도 협의 | + +### 1.4 준수 규칙 + +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/specs/database-schema.md` - 데이터베이스 스키마 +- `api/CLAUDE.md` - API 개발 규칙 + +--- + +## 2. 테이블 매핑 개요 + +### 2.1 5130 소스 테이블 + +| 테이블 | 용도 | 주요 필드 | +|--------|------|----------| +| `KDunitprice` | 단가표 (Ecount 연동) | prodcode, item_name, item_div, spec, unit, unitprice | +| `price_raw_materials` | 원자재 단가 | JSON itemList | +| `price_bend` | 절곡 단가 | JSON itemList | +| `output` | 수주 마스터 | ~80개 필드, JSON (screenlist, slatlist, motorList 등) | +| `output_extra` | 수주 부가정보 | ~30개 필드 (parent_num으로 연결) | + +### 2.2 SAM 대상 테이블 + +| 테이블 | 용도 | item_type | +|--------|------|-----------| +| `items` | 통합 품목 마스터 | FG, PT, SM, RM, CS | +| `orders` | 수주 마스터 | - | +| `order_items` | 수주 상세 | - | +| `order_item_components` | 자재 투입 | - | + +### 2.3 매핑 관계 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 5130 → SAM │ +├─────────────────────────────────────────────────────────────────┤ +│ KDunitprice → items (SM, RM, CS) │ +│ price_raw_materials.itemList → items (RM) │ +│ price_bend.itemList → items (PT) + price tables │ +│ output → orders │ +│ output.screenlist/slatlist → order_items │ +│ output_extra → order_items.attributes │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. 대상 범위 + +### 3.1 Phase 1: 품목 마스터 마이그레이션 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | KDunitprice → items 매핑 분석 | ✅ | 10개 필드 매핑 완료 | +| 1.2 | price_raw_materials → items 매핑 | ✅ | RM 타입, itemList JSON 15개 필드 매핑 | +| 1.3 | price_bend → items 매핑 | ✅ | PT 타입, itemList JSON 18개 필드 매핑 | +| 1.4 | 품목 마이그레이션 스크립트 작성 | ✅ | `Migrate5130PriceItems.php` | +| 1.5 | 품목 데이터 검증 | ✅ | dry-run 621건 성공, item_type 분류 검증 완료 | + +### 3.2 Phase 2: 수주 마스터 마이그레이션 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | output → orders 필드 매핑 | ✅ | 69개 필드 분석, 상세 매핑 완료 | +| 2.2 | output JSON → order_items 변환 | ✅ | screenlist, slatlist 구조 분석 완료 | +| 2.3 | output_extra → order_items.attributes | ✅ | 33개 필드, motorList/bendList 등 | +| 2.4 | 수주 마이그레이션 스크립트 작성 | ✅ | `Migrate5130Orders.php` + `order_id_mappings` 테이블 | +| 2.5 | 수주 데이터 검증 | ✅ | dry-run 100건 성공, 필드 매핑 검증 완료 | + +### 3.3 Phase 3: 견적 로직 검증 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | 5130 견적 수식 분석 | ✅ | write_form_script.php + fetch_unitprice.php 분석 완료 | +| 3.2 | SAM 견적 수식 구현/검증 | ✅ | Legacy5130Calculator.php + Verify5130Calculation.php | +| 3.3 | 검증 테스트 실행 | ✅ | 5/5 테스트 케이스 통과, 100% 일치 | + +--- + +## 4. 상세 필드 매핑 + +### 4.1 KDunitprice → items + +| 5130 필드 | SAM 필드 | 타입 | 비고 | +|-----------|----------|------|------| +| prodcode | code | string | 품목코드 | +| item_name | name | string | 품목명 | +| item_div | item_type 판별 기준 | - | SM/RM/CS 분류 | +| spec | attributes.spec | JSON | 규격 | +| unit | unit | string | 단위 | +| unitprice | attributes.unit_price | JSON | 단가 | + +### 4.2 output → orders (상세 매핑) + +#### 4.2.1 기본 정보 매핑 + +| 5130 필드 | SAM 필드 | 타입 변환 | 비고 | +|-----------|----------|----------|------| +| num | options.legacy_num | int→JSON | 5130 원본 PK 보존 | +| - | id | auto | SAM 신규 PK | +| - | tenant_id | 287 | 경동기업 고정 | +| outdate | received_at | date→datetime | 수주일 | +| orderdate | options.order_date | date | 발주일 | +| outworkplace | site_name | varchar(50) | 현장명 | +| orderman | options.orderman | varchar(20) | 수주담당자 | +| con_num | client_id | int→FK | 거래처 (조회 필요) | +| outputplace | options.output_place | varchar(50) | 출고장소 | +| receiver | options.receiver | varchar(20) | 수령인 | +| phone | client_contact | varchar(15) | 연락처 | +| comment | memo | varchar(250) | 메모 | +| delivery | delivery_method_code | varchar(15) | 배송방법 | + +#### 4.2.2 상태 필드 매핑 + +| 5130 필드 | SAM 필드 | 변환 규칙 | 비고 | +|-----------|----------|----------|------| +| regist_state | status_code | '등록'→'REGISTERED' | 주 상태 | +| screen_state | options.screen_state | 그대로 | 방충망 상태 | +| slat_state | options.slat_state | 그대로 | 슬랫 상태 | +| bend_state | options.bend_state | 그대로 | 절곡 상태 | +| motor_state | options.motor_state | 그대로 | 모터 상태 | + +#### 4.2.3 수량/금액 필드 + +| 5130 필드 | SAM 필드 | 비고 | +|-----------|----------|------| +| screen_su | quantity (합산) | 방충망 수량 | +| slat_su | quantity (합산) | 슬랫 수량 | +| screen_m2 | options.screen_m2 | 방충망 면적 | +| slat_m2 | options.slat_m2 | 슬랫 면적 | +| output_extra.EstimateFinalSum | total_amount | 최종금액 | +| output_extra.EstimateDiscount | discount_amount | 할인금액 | +| output_extra.EstimateDiscountRate | discount_rate | 할인율 | + +#### 4.2.4 JSON → order_items 변환 대상 + +| 5130 JSON 필드 | order_items 유형 | 비고 | +|----------------|-----------------|------| +| screenlist | item_type='SCREEN' | 방충망 품목 | +| slatlist | item_type='SLAT' | 슬랫 품목 | +| output_extra.motorList | item_type='MOTOR' | 모터 품목 | +| output_extra.bendList | item_type='BEND' | 절곡 품목 | +| output_extra.etcList | item_type='ETC' | 기타 품목 | +| output_extra.controllerList | item_type='CTRL' | 컨트롤러 | +| deliveryfeeList | item_type='DELIVERY' | 배송비 | + +#### 4.2.5 options JSON에 보존할 필드 + +```json +{ + "legacy_num": "5130 num", + "legacy_extra_num": "output_extra num", + "orderman": "수주담당자", + "output_place": "출고장소", + "receiver": "수령인", + "secondord": "2차 주문처", + "secondordman": "2차 주문 담당자", + "secondordmantel": "2차 주문 연락처", + "screen_state": "방충망 상태", + "slat_state": "슬랫 상태", + "bend_state": "절곡 상태", + "motor_state": "모터 상태", + "screen_m2": "방충망 면적", + "slat_m2": "슬랫 면적", + "warranty": "보증서 여부", + "warrantyNum": "보증서 번호", + "lotNum": "로트번호", + "prodCode": "제품코드", + "ACI": { + "regDate": "인정검사 등록일", + "askDate": "인정검사 요청일", + "doneDate": "인정검사 완료일", + "memo": "인정검사 메모", + "check": "인정검사 체크", + "groupCode": "인정검사 그룹코드", + "groupName": "인정검사 그룹명" + }, + "pjnum": "프로젝트 번호", + "major_category": "대분류", + "position": "위치", + "makeWidth": "제작폭", + "makeHeight": "제작높이", + "maguriWing": "마구리날개" +} +``` + +### 4.3 screenlist/slatlist → order_items + +#### 4.3.1 screenlist JSON 구조 + +```json +{ + "floors": "층수", + "text1": "표시텍스트1", + "text2": "표시텍스트2 (요약)", + "memo": "메모 (재질)", + "cutwidth": "절단폭", + "cutheight": "절단높이", + "number": "수량", + "exititem": "출고여부", + "printside": "인쇄면", + "direction": "방향", + "intervalnum": "간격수", + "intervalnumsecond": "2차간격수", + "exitinterval": "출고간격", + "cover": "커버", + "drawbottom1": "하부도면1", + "drawbottom2": "하부도면2", + "drawbottom3": "하부도면3", + "draw": "도면파일", + "done_check": "완료체크", + "remain_check": "잔여체크", + "mid_check": "중간체크", + "left_check": "좌측체크", + "right_check": "우측체크" +} +``` + +#### 4.3.2 screenlist → order_items 매핑 + +| screenlist 필드 | order_items 필드 | 비고 | +|-----------------|-----------------|------| +| - | serial_no | 순번 (1부터) | +| cutwidth + 'x' + cutheight | specification | 규격 (예: 3260x4000) | +| floors | floor_code | 층수 | +| text1 | symbol_code | 기호 | +| number | quantity | 수량 | +| memo | remarks | 메모 (재질 등) | +| text2 | note | 요약 텍스트 | +| (전체) | attributes | 원본 JSON 보존 | + +#### 4.3.3 slatlist JSON 구조 + +```json +{ + "floors": "층수", + "text1": "기호 (FST-1 등)", + "text2": "요약텍스트", + "memo": "메모 (재질 EGI 1.6T 등)", + "cutwidth": "절단폭", + "cutheight": "절단높이 (총H)", + "number": "수량", + "exititem": "출고여부", + "intervalnum": "간격수 (매수)", + "hinge": "힌지", + "hingenum": "힌지수량", + "hinge_direction": "힌지방향", + "done_check": "완료체크" +} +``` + +### 4.4 output_extra 상세 매핑 + +#### 4.4.1 금액 관련 필드 + +| 5130 필드 | SAM 필드 | 비고 | +|-----------|----------|------| +| estimateTotal | orders.supply_amount | 공급가액 | +| EstimateFirstSum | options.estimate_first | 최초견적 | +| EstimateUpdatetSum | options.estimate_update | 변경견적 | +| EstimateDiffer | options.estimate_diff | 차액 | +| EstimateDiscountRate | orders.discount_rate | 할인율 | +| EstimateDiscount | orders.discount_amount | 할인금액 | +| EstimateFinalSum | orders.total_amount | 최종금액 | +| estimateSurang | options.estimate_quantity | 견적수량 | +| inspectionFee | options.inspection_fee | 검사비용 | + +#### 4.4.2 JSON 리스트 필드 (→ order_items) + +| 5130 필드 | 건수 | 구조 | SAM 변환 | +|-----------|------|------|----------| +| motorList | 7건 | col1~col8 | order_items (MOTOR) | +| bendList | 10건 | col1~col8 | order_items (BEND) | +| etcList | - | col1~col5 | order_items (ETC) | +| controllerList | - | col1~col4 | order_items (CTRL) | + +#### 4.4.3 motorList col 매핑 + +| col | 내용 | order_items 필드 | +|-----|------|-----------------| +| col1 | 품명 (전동개폐기_단상 220V) | item_name | +| col2 | 용량 (300kg) | specification | +| col3 | 규격 (380*180) | attributes.dimension | +| col4 | 인치 (5인치) | attributes.inch | +| col5 | 수량 | quantity | +| col6 | 형태 (신형) | attributes.type | +| col7 | 옵션 | attributes.option | +| col8 | 전원 (단상) | attributes.power | + +#### 4.4.4 bendList col 매핑 + +| col | 내용 | order_items 필드 | +|-----|------|-----------------| +| col1 | 품명 (가이드레일) | item_name | +| col2 | 재질 (EGI 1.6T) | specification | +| col3 | 길이 (3000) | attributes.length | +| col5 | 폭 (332) | attributes.width | +| col6 | 도면이미지 | attributes.drawing | +| col7 | 수량 | quantity | +| col8 | 비고 | remarks | + +### 4.5 견적 수식 분석 (Phase 3.1) + +> **분석 대상**: `5130/output/write_form_script.php` (JS), `5130/estimate/fetch_unitprice.php` (PHP) + +#### 4.5.1 절곡품 단가 계산 + +**함수**: `getBendPlatePrice(material, thickness, length, width, qty)` + +```javascript +// 5130/output/write_form_script.php (lines 5780-5822) +// item_bend 배열: { col1: 재질, col5: 두께, col17: 면적당단가(원/m²) } + +// 1. 재질/두께 정규화 +EGI: 1.15 → 1.2, 1.55 → 1.6 +SUS: 1.15 → 1.2, 1.55 → 1.5 + +// 2. 면적 계산 (mm² → m²) +areaM² = (length × width) / 1,000,000 + +// 3. 총액 계산 (절삭) +total = Math.floor(unitPricePerM² × areaM² × qty) +``` + +**데이터 소스**: `price_bend.itemList` → `window.item_bend` (JS 전역) + +#### 4.5.2 비인정 스크린 단가 계산 + +**함수**: 익명 함수 (tables 배열 내) + +```javascript +// 5130/output/write_form_script.php (lines 6794-6822) +// materialBasePrice에서 재질(material)로 단가 조회 + +// 1. 단가 조회 +unitprice = materialBasePrice[material] || 0 + +// 2. 수량 계산 (타입별 분기) +if (원단류) { + // 세로 기준 1000mm 단위 + surang = height / 1000 +} else { + // 일반 면적 기준 + surang = (width × height) / 1,000,000 × qty +} + +// 3. 총액 +total = unitprice × surang +``` + +**데이터 소스**: `price_raw_materials.itemList` → `window.materialBasePrice` (JS 전역) + +#### 4.5.3 철재 스라트 비인정 단가 + +**함수**: 익명 함수 (tables 배열 내) + +```javascript +// 5130/output/write_form_script.php (lines 6824-6881) + +// 1. 유형별 단가 조회 +type = 방화셔터/방범셔터/단열셔터/이중파이프/조인트바 +unitprice = materialBasePrice[type] || 0 + +// 2. 수량 계산 (유형별 분기) +if (면적 기준: 방화/방범/단열/이중파이프) { + surang = (width × height) / 1,000,000 × qty +} else if (수량 기준: 조인트바) { + surang = qty +} + +// 3. 총액 +total = unitprice × surang +``` + +#### 4.5.4 전동 개폐기/제어기 조회 + +**함수**: `lookupMotorPrice(row)`, `lookupControllerPrice(row)` + +```javascript +// 5130/output/write_form_script.php (lines 6886-6920) + +// KDunitprice 테이블에서 조회 +// unitInfo: { prodcode → unitprice } 매핑 + +// 전동 개폐기 +unitprice = lookupMotorPrice(row) +// → row 데이터(용량, 전원, 형태 등)로 KDunitprice 조회 + +// 제어기 +unitprice = lookupControllerPrice(row) +// → row 데이터(유형, 규격)로 KDunitprice 조회 +``` + +**데이터 소스**: `KDunitprice` → `window.unitInfo` (JS 전역) + +#### 4.5.5 모터 용량 계산 (핵심 로직) + +**함수**: `calculateMotorSpec($item, $weight, $BracketInch)` (PHP) + +```php +// 5130/estimate/fetch_unitprice.php (lines 200-350) + +// 1. 품목 유형 판별 +$ItemSel = (substr($item['col4'], 0, 2) === 'KS' || + substr($item['col4'], 0, 2) === 'KW') + ? '스크린' : '철재'; + +// 2. 용량 결정 테이블 +// 스크린: 150K ~ 600K +// 철재: 300K ~ 1000K +// Weight + BracketInch 조합으로 용량 결정 + +// 3. 브라켓 사이즈 매핑 +300-400K → 530×320 +500-600K → 600×350 +800-1000K → 690×390 +``` + +#### 4.5.6 기타 계산 함수 + +| 함수 | 용도 | 계산식 | +|------|------|--------| +| `calculateGuidrail()` | 가이드레일 수량 | `col17 / 3490` (기본 길이) | +| `calculateShaft()` | 샤프트 단가 | `col19 × 수량`, 길이별 조회 | +| `calculatePipe()` | 파이프 단가 | `col4(길이)`, `col2(규격)`으로 `col8(단가)` 조회 | +| `slatPrice()` | 인정 슬랫 단가 | `price_raw_materials.col13` | +| `unapprovedSlatPrice()` | 비인정 슬랫 단가 | `price_raw_materials.col15` | + +#### 4.5.7 전역 데이터 구조 (JS) + +```javascript +// 5130/output/write_form.php에서 PHP→JS 전달 + +// 비인정 자재 단가 (재질 → 단가) +window.materialBasePrice = { + "실리카": 12000, + "폴리에스터": 8500, + // ... +}; + +// 비인정 자재 코드 (재질 → 코드) +window.materialBaseCode = { + "실리카": "RM001", + // ... +}; + +// 절곡품 단가표 +var item_bend = [ + { col1: "EGI", col5: 1.2, col17: 45000 }, + { col1: "SUS", col5: 1.5, col17: 85000 }, + // ... +]; + +// KDunitprice 단가 (prodcode → unitprice) +window.unitInfo = { + "MOT300": 250000, + "MOT500": 380000, + // ... +}; +``` + +#### 4.5.8 SAM 구현 시 고려사항 + +| 구분 | 5130 방식 | SAM 구현 방향 | +|------|----------|--------------| +| 단가 조회 | JS 전역 변수 | Service 클래스 + DB 쿼리 | +| 면적 계산 | JS (mm² → m²) | PHP Helper 함수 | +| 두께 매핑 | JS 하드코딩 | 설정 테이블 or Enum | +| 모터 용량 | PHP 조건문 | 룰 엔진 or 매핑 테이블 | +| 반올림/절삭 | `Math.floor()` | `floor()` 동일 적용 | + +--- + +## 5. 작업 절차 + +### 5.1 단계별 절차 + +``` +Step 1: 품목 마스터 분석 (Phase 1.1-1.3) +├── KDunitprice 테이블 구조 상세 분석 +├── price_raw_materials JSON 구조 분석 +├── price_bend JSON 구조 분석 +└── SAM items 테이블과 매핑 확정 + +Step 2: 품목 마이그레이션 (Phase 1.4-1.5) +├── 마이그레이션 스크립트 작성 (Artisan Command) +├── 테스트 데이터로 검증 +└── 전체 데이터 마이그레이션 + +Step 3: 수주 마스터 분석 (Phase 2.1-2.3) +├── output 테이블 80개 필드 분석 +├── JSON 필드 (screenlist 등) 구조 분석 +├── output_extra 연결 관계 분석 +└── SAM orders/order_items 매핑 확정 + +Step 4: 수주 마이그레이션 (Phase 2.4-2.5) +├── 마이그레이션 스크립트 작성 +├── JSON → 관계형 변환 로직 구현 +├── 테스트 데이터로 검증 +└── 전체 데이터 마이그레이션 + +Step 5: 견적 로직 검증 (Phase 3) +├── 5130 견적 계산 JS 분석 +├── SAM에서 동일 로직 구현/검증 +└── 샘플 데이터로 결과 비교 +``` + +### 5.2 분석 템플릿 + +```markdown +### [테이블명] 분석 + +**현재 상태 (5130):** +- 테이블: [테이블명] +- 필드 수: [N]개 +- 레코드 수: [N]건 + +**목표 상태 (SAM):** +- 테이블: [테이블명] +- 매핑 필드: [N]개 + +**필드 매핑:** +| 5130 | SAM | 변환 로직 | +|------|-----|----------| +| | | | + +**특이사항:** +- [ ] JSON 변환 필요 여부 +- [ ] 타입 변환 필요 여부 +- [ ] 기본값 처리 방법 +``` + +--- + +## 6. 컨펌 대기 목록 + +> 테이블 구조 변경 등 승인 필요 항목 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| - | - | - | - | - | + +--- + +## 7. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-01-19 | 초안 | 문서 초안 작성 | - | - | +| 2025-01-19 | Phase 1.1 | KDunitprice → items 매핑 분석 완료 | - | - | +| 2025-01-19 | Phase 1.2 | price_raw_materials → items 매핑 분석 완료 (itemList JSON 15필드) | - | - | +| 2025-01-19 | Phase 1.3 | price_bend → items 매핑 분석 완료 (itemList JSON 18필드) | - | - | +| 2025-01-19 | Phase 1.4 | 품목 마이그레이션 스크립트 작성 완료 | `api/app/Console/Commands/Migrate5130PriceItems.php` | - | +| 2026-01-19 | Phase 2.4 | 수주 마이그레이션 스크립트 작성 완료 | `api/app/Console/Commands/Migrate5130Orders.php`, `api/database/migrations/2026_01_19_202830_create_order_id_mappings_table.php` | - | +| 2026-01-19 | Phase 3.1 | 5130 견적 수식 분석 완료 | `5130/output/write_form_script.php`, `5130/estimate/fetch_unitprice.php` | - | +| 2026-01-19 | Phase 3.2 | SAM 견적 수식 구현 완료 | `api/app/Helpers/Legacy5130Calculator.php`, `api/app/Console/Commands/Verify5130Calculation.php` | - | +| 2026-01-19 | Phase 3.3 | 견적 수식 검증 테스트 실행 | 5/5 테스트 케이스 100% 일치 | - | +| 2026-01-20 | 준비 완료 | Phase 1-3 모든 준비 작업 완료, 실행 대기 | 13/13 작업 완료 | - | +| 2026-01-20 | Phase 4 | 전체 마이그레이션 실행 완료 | items 608건, orders 24,424건, order_items 43,900건 | ✅ | + +--- + +## 8. 참고 문서 + +### 8.1 5130 소스 코드 + +- **수주 폼**: `5130/output/write_form.php` (1176줄) +- **견적 계산 JS**: `5130/output/write_form_script.php` (302KB, ~7000줄) +- **단가 조회 PHP**: `5130/estimate/fetch_unitprice.php` (875줄) +- **output 필드**: `5130/output/_row.php` (~80개 필드) +- **output_extra 필드**: `5130/output/_row_extra.php` (~30개 필드) +- **단가표 필드**: `5130/KDunitprice/_row.php` + +### 8.2 SAM 스키마 + +- **items 테이블**: `api/database/migrations/2025_12_13_152507_create_items_table.php` +- **orders 테이블**: `api/database/migrations/2024_11_19_000001_create_orders_table.php` +- **order_items 테이블**: `api/database/migrations/2024_11_19_000002_create_order_items_table.php` + +### 8.3 SAM 모델 + +- **Order 모델**: `api/app/Models/Orders/Order.php` +- **OrderItem 모델**: `api/app/Models/Orders/OrderItem.php` +- **Item 모델**: `api/app/Models/Items/Item.php` + +--- + +## 9. 세션 및 메모리 관리 정책 + +### 9.1 세션 시작 시 (Load Strategy) +```javascript +// 순차적 로드 +read_memory("5130-migration-state") // 1. 상태 파악 +read_memory("5130-migration-mappings") // 2. 매핑 정보 로드 +read_memory("5130-migration-rules") // 3. 규칙 확인 +``` + +### 9.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | 🛠 **Snapshot** | `write_memory("5130-migration-snapshot", "진행상황")` | +| **20% 이하** | 🧹 **Context Purge** | `write_memory("5130-migration-active", "현재 작업")` | +| **10% 이하** | 🛑 **Stop & Save** | 최종 상태 저장 후 세션 교체 권고 | + +### 9.3 Serena 메모리 구조 +- `5130-migration-state`: { phase, progress, next_step } (JSON 구조) +- `5130-migration-mappings`: 테이블/필드 매핑 정보 (Text) +- `5130-migration-rules`: 변환 규칙, 타입 매핑 (Text) + +--- + +## 10. 검증 결과 + +### 10.1 Phase 1 품목 마이그레이션 검증 (2025-01-19) + +#### 소스 데이터 카운트 +| 테이블 | 총 건수 | 활성 건수 | 최신 버전 | +|--------|---------|----------|----------| +| KDunitprice | 603 | 601 (NULL/0) | - | +| price_raw_materials | 14 | 6 | 2025-06-18 | +| price_bend | 3 | 3 | 2025-03-09 | + +#### dry-run 검증 결과 +| 테이블 | Total | Migrated | Skipped | 결과 | +|--------|-------|----------|---------|:----:| +| KDunitprice | 601 | 601 | 0 | ✅ | +| price_raw_materials | 13 | 13 | 0 | ✅ | +| price_bend | 7 | 7 | 0 | ✅ | +| **합계** | **621** | **621** | **0** | ✅ | + +#### item_type 분류 검증 +| item_div | 예상 | 실제 | 결과 | +|----------|------|------|:----:| +| [상품] | FG | FG | ✅ | +| [제품] | FG | FG | ✅ | +| [반제품] | PT | PT | ✅ | +| [부재료] | SM | SM | ✅ | +| [원재료] | RM | RM | ✅ | +| [무형상품] | CS | CS | ✅ | + +#### item_div 분포 (KDunitprice 601건) +| item_div | 건수 | item_type | +|----------|------|-----------| +| [상품] | 259 | FG | +| [제품] | 193 | FG | +| [반제품] | 73 | PT | +| [부재료] | 48 | SM | +| [원재료] | 24 | RM | +| [무형상품] | 4 | CS | + +### 10.2 Phase 2 수주 마이그레이션 검증 (2026-01-19) + +#### 소스 데이터 현황 +| 테이블/필드 | 총 건수 | 비고 | +|-------------|---------|------| +| output | 24,584 | 전체 수주 | +| output (screenlist 있음) | 9,392 | 방충망 포함 | +| output (slatlist 있음) | 1,955 | 슬랫 포함 | +| output_extra (motorList 있음) | 7 | 모터 포함 | +| output_extra (bendList 있음) | 10 | 절곡 포함 | + +#### dry-run 검증 결과 +| 항목 | 건수 | 결과 | 비고 | +|------|------|:----:|------| +| orders | 100 | ✅ | 100건 테스트 성공 | +| order_items (screen) | - | ⏳ | 실제 실행 후 확인 | +| order_items (slat) | - | ⏳ | 실제 실행 후 확인 | +| order_items (motor) | 0 | ✅ | motorList 없는 범위 | +| order_items (bend) | 0 | ✅ | bendList 없는 범위 | + +#### 샘플 데이터 매핑 검증 +**샘플 num=25810** +| 5130 필드 | 값 | SAM 필드 | 변환 결과 | 검증 | +|-----------|-----|----------|----------|:----:| +| outdate | 2025-12-15 | received_at | 2025-12-15 00:00:00 | ✅ | +| outworkplace | IFC | site_name | IFC | ✅ | +| regist_state | 등록 | status_code | REGISTERED | ✅ | +| phone | 010-5231-3134 | client_contact | 010-5231-3134 | ✅ | +| comment | 실리카1틀/... | memo | 실리카1틀/... | ✅ | +| delivery | 직접배차 | delivery_method_code | 직접배차 | ✅ | +| screenlist[0].cutwidth×cutheight | 3260×4000 | specification | 3260x4000 | ✅ | +| screenlist[0].number | 1 | quantity | 1 | ✅ | +| screenlist[0].memo | 실리카 | remarks | 실리카 | ✅ | + +**motorList/bendList 구조 검증** +| col | motorList 매핑 | bendList 매핑 | 검증 | +|-----|---------------|--------------|:----:| +| col1 | item_name (전동개폐기_단상 220V) | item_name (가이드레일) | ✅ | +| col2 | specification (300kg) | specification (EGI 1.6T) | ✅ | +| col3 | attributes.dimension (380*180) | attributes.length (3000) | ✅ | +| col5 | quantity (2) | attributes.width (332) | ✅ | +| col6 | attributes.type (신형) | attributes.drawing (이미지경로) | ✅ | +| col7 | attributes.option | quantity (1) | ✅ | +| col8 | attributes.power (단상) | remarks | ✅ | + +### 10.3 데이터 정합성 요약 + +| 테이블 | 5130 건수 | SAM 건수 | 일치 | 비고 | +|--------|----------|----------|:----:|------| +| KDunitprice → items | 601 | (dry-run) | ✅ | Phase 1 검증 완료 | +| price_raw_materials → items | 13 | (dry-run) | ✅ | 최신 버전만 | +| price_bend → items | 7 | (dry-run) | ✅ | 최신 버전만 | +| output → orders | 24,584 | (dry-run) | ✅ | 100건 테스트 성공 | +| screenlist → order_items | 9,392+ | (대기) | ⏳ | 실제 마이그레이션 후 확인 | +| slatlist → order_items | 1,955+ | (대기) | ⏳ | 실제 마이그레이션 후 확인 | + +### 10.4 견적 수식 검증 (2026-01-19) + +#### 검증 도구 +- **Legacy5130Calculator.php**: 5130 호환 계산 헬퍼 클래스 +- **Verify5130Calculation.php**: 검증 Artisan 커맨드 +- **실행**: `php artisan migration:verify-5130-calculation --W0=3000 --H0=2500 --type=screen` + +#### 테스트 결과 + +| 케이스 | W0×H0 | 유형 | W1 (5130/SAM) | H1 (5130/SAM) | M (m²) | K (kg) | 결과 | +|--------|-------|------|---------------|---------------|--------|--------|:----:| +| 스크린 소형 | 1500×1200 | screen | 1640/1640 | 1550/1550 | 2.542 | 26.34 | ✅ | +| 스크린 중형 | 3000×2500 | screen | 3140/3140 | 2850/2850 | 8.949 | 60.41 | ✅ | +| 스크린 대형 | 5000×4000 | screen | 5140/5140 | 4350/4350 | 22.359 | 115.57 | ✅ | +| 철재 중형 | 2000×1800 | steel | 2110/2110 | 2150/2150 | 4.5365 | 113.41 | ✅ | +| 철재 대형 | 4000×3500 | steel | 4110/4110 | 3850/3850 | 15.8235 | 395.59 | ✅ | + +#### 검증 수식 + +``` +스크린 (screen): +├── W1 = W0 + 140 (마진) +├── H1 = H0 + 350 (마진) +├── M = (W1 × H1) / 1,000,000 (m²) +└── K = (M × 2) + (W0 / 1000 × 14.17) (kg) + +철재 (steel): +├── W1 = W0 + 110 (마진) +├── H1 = H0 + 350 (마진) +├── M = (W1 × H1) / 1,000,000 (m²) +└── K = M × 25 (kg) +``` + +#### 모터 용량/브라켓 사이즈 검증 + +| 케이스 | 중량(K) | 브라켓인치 | 모터용량 | 브라켓사이즈 | +|--------|---------|-----------|---------|-------------| +| 스크린 중형 | 60.41 | 124" | 600K | 600×350 | +| 철재 중형 | 113.41 | 84" | 1000K | 690×390 | + +**결과**: 5/5 테스트 케이스 통과 → ✅ **견적 수식 100% 일치 확인** + +--- + +## 11. 자기완결성 점검 결과 + +### 11.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 5130→SAM 데이터 마이그레이션 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 데이터 정합성 + 견적 동일성 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-3 정의됨 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 5130 소스 + SAM 스키마 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 8 참조 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 5 참조 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 10 참조 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 테이블/필드 명시 | + +### 11.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 5.1 단계별 절차 | +| Q3. 어떤 테이블을 매핑해야 하는가? | ✅ | 2. 테이블 매핑 개요 | +| Q4. 작업 완료 확인 방법은? | ✅ | 10. 검증 결과 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 8. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/AI_리포트_키워드_색상체계_가이드_v1.4.md b/plans/archive/AI_리포트_키워드_색상체계_가이드_v1.4.md new file mode 100644 index 0000000..aedaf24 --- /dev/null +++ b/plans/archive/AI_리포트_키워드_색상체계_가이드_v1.4.md @@ -0,0 +1,406 @@ +# SAM ERP 대시보드 +## AI 리포트 핵심 키워드 색상 체계 가이드 +### (임계값 명확화 버전 v1.4) + +> 버전: D1.4 | 작성일: 2026년 1월 + +--- + +## 1. AI 리포트 색상 체계 개요 + +AI 리포트는 각 섹션별 핵심 키워드에 색상을 적용하여 사용자가 즉시 상태를 파악할 수 있도록 합니다. 모든 기준은 명확한 수치로 정의되어 일관된 적용이 가능합니다. + +### 1.1 색상 정의 + +| 색상 | 의미 | 적용 원칙 | 우선순위 | +|:---:|:---:|:---|:---:| +| 🔴 빨간색 | 경고 | 즉각 조치 필요, 한도/기준 초과, 손실 발생 | 1순위 (최우선) | +| 🟠 주황색 | 주의 | 기준의 80~100% 도달, 기한 임박, 검토 필요 | 2순위 | +| 🟢 녹색 | 긍정 | 목표 달성, 정상 완료, 개선, 입금/회수 | 3순위 | +| 🔵 파란색 | 양호 | 안정적 유지, 정상 진행 중, 충분히 확보 | 4순위 | + +### 1.2 공통 임계값 원칙 + +| 구분 | 🔴 경고 | 🟠 주의 | 🟢 긍정 | 🔵 양호 | +|:---|:---|:---|:---|:---| +| 한도 사용률 | 100% 초과 | 85~100% | - | 85% 미만 | +| 전월/전기 대비 증감 | ±20% 이상 | ±10~20% | 개선 방향 변동 | ±10% 이내 | +| 예산 대비 | 100% 초과 | 90~100% | - | 90% 미만 | +| 연체 기간 | 90일 초과 | 30~90일 | 정상 회수 | 만기 전 | +| 운영자금 확보 | 3개월 미만 | 3~6개월 | - | 6개월 이상 | + +--- + +## 2. 일일 일보 섹션 + +일일 일보는 당일 자금 현황을 요약하여 보여주며, 현금 흐름에 대한 AI 분석 리포트가 함께 제공됩니다. + +### 2.1 현금 자산 - 출금 분석 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **출금** | 🔴 빨간색 | 7일 평균 대비 200% 이상 | 당일출금 ÷ 7일평균출금 ≥ 2.0 | +| **점검이 필요** | 🔴 빨간색 | 7일 평균 대비 200% 이상 | 출금 키워드와 함께 사용 | +| **출금 증가** | 🟠 주황색 | 7일 평균 대비 150~200% | 당일출금 ÷ 7일평균출금 1.5~2.0 | +| **정상 출금** | 🔵 파란색 | 7일 평균 대비 150% 미만 | 당일출금 ÷ 7일평균출금 < 1.5 | + +#### 적용 예시 +- 어제 🔴**3.5억원 출금**했습니다. 최근 7일 평균(1.7억원) 대비 206%로 🔴**점검이 필요**합니다. + +### 2.2 현금 자산 - 입금 분석 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **입금** | 🟢 녹색 | 입금 발생 시 (금액 무관) | 당일 입금 > 0 | +| **대규모 입금** | 🟢 녹색 | 월평균 입금의 200% 이상 | 당일입금 ÷ 월평균입금 ≥ 2.0 | +| **주요 원인** | 🟢 녹색 | 입금 원인 설명 시 | 입금 키워드와 함께 사용 | + +#### 적용 예시 +- 어제 🟢**10.2억원이 입금**되었습니다. 대한건설 선수금 🟢**입금**이 🟢**주요 원인**입니다. + +### 2.3 현금 자산 - 운영자금 안정성 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **자금 부족 우려** | 🔴 빨간색 | 월 운영비용 대비 3개월 미만 | 현금자산 ÷ 월운영비 < 3 | +| **자금 관리 필요** | 🟠 주황색 | 월 운영비용 대비 3~6개월 | 현금자산 ÷ 월운영비 3~6 | +| **확보되어 안정적** | 🔵 파란색 | 월 운영비용 대비 6개월 이상 | 현금자산 ÷ 월운영비 ≥ 6 | + +#### 적용 예시 +- 총 현금성 자산이 300.2억원입니다. 월 운영비용(16.7억원) 대비 🔵**18개월 분이 확보되어 안정적**입니다. + +### 2.4 외화 현황 - 환율 변동 + +| 키워드 | 색상 | 임계값 기준 (일일) | 임계값 기준 (주간) | +|:---|:---:|:---|:---| +| **환율 급등** | 🔴 빨간색 | 전일 대비 ±1.5% 이상 또는 ±20원 이상 | 전주 대비 ±3% 이상 | +| **환율 급락** | 🔴 빨간색 | 전일 대비 ±1.5% 이상 또는 ±20원 이상 | 전주 대비 ±3% 이상 | +| **환율 변동 주의** | 🟠 주황색 | 전일 대비 ±1.0~1.5% 또는 ±10~20원 | 전주 대비 ±2~3% | +| **환율 안정** | 🔵 파란색 | 전일 대비 ±1.0% 미만 또는 ±10원 미만 | 전주 대비 ±2% 미만 | + +### 2.5 외화 현황 - 환차손익 + +| 키워드 | 색상 | 임계값 기준 (금액) | 임계값 기준 (비율) | +|:---|:---:|:---|:---| +| **환차손 발생** | 🔴 빨간색 | 평가손실 1,000만원 이상 | 외화보유액 대비 2% 이상 손실 | +| **환리스크 주의** | 🟠 주황색 | 평가손실 500~1,000만원 | 외화보유액 대비 1~2% 손실 | +| **환차익 발생** | 🟢 녹색 | 평가이익 500만원 이상 | 외화보유액 대비 1% 이상 이익 | +| **환율 영향 미미** | 🔵 파란색 | 평가손익 ±500만원 미만 | 외화보유액 대비 ±1% 미만 | + +#### 적용 예시 +- 전일 대비 환율이 🔴**1.8% 상승(+24원)**했습니다. 외화자산 평가손실 🔴**약 1,500만원 환차손 발생**이 예상됩니다. +- 전일 대비 환율 변동 0.3%(+4원)으로 🔵**환율 안정**적인 상태입니다. 🔵**환율 영향 미미**합니다. + +--- + +## 3. 당월 예상 지출 내역 섹션 + +당월 예상되는 지출 항목(매입, 카드, 발행어음 등)을 분석하여 전월 대비 및 예산 대비 현황을 제공합니다. + +### 3.1 전월 대비 분석 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **전월 대비 N% 증가** | 🔴 빨간색 | 전월 대비 15% 이상 증가 | (당월-전월) ÷ 전월 ≥ 0.15 | +| **지출 증가 추이** | 🟠 주황색 | 전월 대비 10~15% 증가 | (당월-전월) ÷ 전월 0.10~0.15 | +| **전월 대비 N% 감소** | 🟢 녹색 | 전월 대비 5% 이상 감소 | (당월-전월) ÷ 전월 ≤ -0.05 | +| **전월과 유사** | 🔵 파란색 | 전월 대비 ±10% 이내 | |(당월-전월) ÷ 전월| < 0.10 | + +#### 적용 예시 +- 이번 달 예상 지출이 🔴**전월 대비 15% 증가**했습니다. 매입 비용 증가가 주요 원인입니다. +- 이번 달 예상 지출이 🟢**전월 대비 8% 감소**했습니다. 외주비용 절감이 주요 원인입니다. + +### 3.2 예산 대비 분석 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **예산을 N% 초과** | 🔴 빨간색 | 예산 대비 100% 초과 | 예상지출 ÷ 예산 > 1.0 | +| **예산 임박** | 🟠 주황색 | 예산 대비 90~100% | 예상지출 ÷ 예산 0.9~1.0 | +| **예산 내 운영** | 🟢 녹색 | 예산 대비 90% 미만 | 예상지출 ÷ 예산 < 0.9 | + +#### 적용 예시 +- 이번 달 예상 지출이 🔴**예산을 12% 초과**했습니다. 비용 항목별 점검이 필요합니다. +- 이번 달 예상 지출이 🟢**예산 내 운영** 중입니다. (예산 대비 82%) + +### 3.3 항목별 지출 분석 기준 + +| 지출 항목 | 🔴 경고 | 🟠 주의 | 🟢 긍정 | 🔵 양호 | +|:---|:---|:---|:---|:---| +| 매입 | 전월 대비 20% 이상 증가 | 전월 대비 10~20% 증가 | 전월 대비 감소 | ±10% 이내 | +| 카드 | 한도 100% 초과 | 한도 80~100% 사용 | - | 한도 80% 미만 | +| 발행어음 | 만기 초과 또는 부도 위험 | 만기 D-7일 이내 | 정상 결제 완료 | 만기 D-8일 이상 | +| 인건비 | 예산 대비 100% 초과 | 예산 대비 90~100% | - | 예산 대비 90% 미만 | + +--- + +## 4. 카드/가지급금 관리 섹션 + +법인카드 사용 현황과 가지급금 발생 현황을 분석하여 세무 리스크를 사전에 안내합니다. + +### 4.1 가지급금 전환 + +| 키워드 | 색상 | 임계값 기준 | 세무 영향 | +|:---|:---:|:---|:---| +| **가지급금으로 전환** | 🔴 빨간색 | 미정리 법인카드 사용 100만원 이상 | 인정이자 4.6% 발생 | +| **인정이자가 발생** | 🔴 빨간색 | 가지급금 잔액 × 4.6% | 법인세 증가 | +| **연간 N만원의 인정이자** | 🔴 빨간색 | 연간 인정이자 100만원 이상 | 가지급금 × 4.6% | +| **가지급금 정리 필요** | 🟠 주황색 | 미정리 법인카드 사용 50~100만원 | 정리 권고 | + +#### 적용 예시 +- 법인카드 사용 중 850만원이 🔴**가지급금으로 전환**되었습니다. 🔴**연 4.6% 인정이자가 발생**합니다. +- 현재 가지급금 3.5억 × 4.6% = 🔴**연간 약 1,610만원의 인정이자가 발생** 중입니다. + +### 4.2 업무관련성 소명 필요 + +| 키워드 | 색상 | 임계값 기준 | 발생 사유 | +|:---|:---:|:---|:---| +| **불인정 가맹점 결제** | 🔴 빨간색 | 유흥업소, 귀금속, 상품권 등 결제 | 가지급금 전환 대상 | +| **본인 청구 결제 감지** | 🟠 주황색 | 상품권, 귀금속, 면세점 등 1건 이상 | 소명 자료 필요 | +| **주말 사용 감지** | 🟠 주황색 | 토/일요일 결제 50만원 이상 | 업무관련성 검토 | +| **심야 사용 감지** | 🟠 주황색 | 22시~06시 결제 30만원 이상 | 업무관련성 검토 | +| **해외 사용 감지** | 🟠 주황색 | 해외 결제 발생 시 | 출장 증빙 필요 | + +#### 적용 예시 +- 상품권 구매 🟠**본인 청구 결제 감지**. 가지급금 처리 예정입니다. +- 🟠**주말 사용 감지** - 토요일 120만원 결제. 업무관련성 소명이 어려울 수 있으니 기록을 남겨주세요. + +### 4.3 법인세/종합소득세 예상 가중 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **법인세 예상 가중** | 🔴 빨간색 | 추가 법인세 100만원 이상 예상 | 가지급금 인정이자 × 법인세율 | +| **대표자 종합소득세 예상 가중** | 🔴 빨간색 | 추가 종합소득세 50만원 이상 예상 | 인정상여 × 소득세율 | +| **세무 리스크 주의** | 🟠 주황색 | 추가 세금 50만원 미만 예상 | 정리 권고 | + +#### 적용 예시 +- 가지급금으로 인한 🔴**법인세 예상 가중 약 320만원**이 발생합니다. +- 🔴**대표자 종합소득세 예상 가중 약 180만원**이 예상됩니다. (추가 사용 +10.5%) + +--- + +## 5. 접대비 현황 섹션 + +접대비 사용 현황과 한도 대비 사용률을 분석하여 세법상 한도 초과 여부를 사전에 안내합니다. + +### 5.1 한도 사용률 기준 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **한도 초과 N만원 발생** | 🔴 빨간색 | 한도 사용률 100% 초과 | 사용액 > 한도액 | +| **손금 불산입** | 🔴 빨간색 | 한도 초과액 발생 시 | 초과액 = 사용액 - 한도액 | +| **법인세 부담이 증가** | 🔴 빨간색 | 한도 초과로 인한 법인세 증가 | 초과액 × 법인세율 | +| **잔여 한도 N원** | 🟠 주황색 | 한도 사용률 85~100% | 잔여 = 한도액 - 사용액 | +| **사용 계획을 점검** | 🟠 주황색 | 한도 사용률 85% 이상 | 사용액 ÷ 한도액 ≥ 0.85 | +| **여유 있게 운영** | 🟢 녹색 | 한도 사용률 75% 미만 | 사용액 ÷ 한도액 < 0.75 | +| **정상 운영** | 🔵 파란색 | 한도 사용률 75~85% | 사용액 ÷ 한도액 0.75~0.85 | + +#### 세법상 접대비 한도 계산 +- 기본한도: 중소기업 3,600만원, 일반기업 2,400만원 (연간) +- 추가한도: 수입금액 × 적용률 (100억 이하 0.3%, 100~500억 0.2%, 500억 초과 0.03%) + +#### 적용 예시 +- (1분기) 접대비 사용 1,000만원 / 한도 4,012만원 (25%). 🟢**여유 있게 운영** 중입니다. +- 접대비 한도 85% 도달. 🟠**잔여 한도 600만원**입니다. 🟠**사용 계획을 점검**해 주세요. +- 🔴**접대비 한도 초과 320만원 발생**. 초과분은 🔴**손금 불산입**되어 🔴**법인세 부담이 증가**합니다. + +### 5.2 증빙 관리 + +| 키워드 | 색상 | 임계값 기준 | 필수 정보 | +|:---|:---:|:---|:---| +| **거래처 정보가 누락** | 🔴 빨간색 | 거래처명 또는 참석자 미입력 1건 이상 | 거래처명, 참석자, 목적 | +| **증빙 누락** | 🔴 빨간색 | 영수증 또는 카드전표 미첨부 1건 이상 | 적격증빙 필수 | +| **기록 보완 필요** | 🟠 주황색 | 상세 내용 미기재 (목적, 장소 등) | 상세 기록 권고 | +| **증빙 완비** | 🟢 녹색 | 모든 필수 정보 입력 완료 | - | + +#### 적용 예시 +- 접대비 사용 중 3건(45만원)의 🔴**거래처 정보가 누락**되었습니다. 🟠**기록 보완 필요**합니다. + +--- + +## 6. 복리후생비 현황 섹션 + +복리후생비 사용 현황을 분석하여 비과세 한도 초과 여부와 업계 평균 대비 적정성을 안내합니다. + +### 6.1 1인당 복리후생비 + +| 키워드 | 색상 | 임계값 기준 | 업계 평균 | +|:---|:---:|:---|:---| +| **과다 지출** | 🔴 빨간색 | 1인당 월 30만원 초과 | 업계 평균의 150% 초과 | +| **지출 증가 추이** | 🟠 주황색 | 1인당 월 25~30만원 | 업계 평균의 120~150% | +| **업계 평균 내 정상 운영** | 🟢 녹색 | 1인당 월 15~25만원 | 업계 평균 범위 내 | +| **적정 운영** | 🔵 파란색 | 1인당 월 15만원 미만 | 업계 평균 미만 | + +#### 적용 예시 +- 1인당 월 복리후생비 20만원. 🟢**업계 평균(15~25만원) 내 정상 운영** 중입니다. + +### 6.2 항목별 비과세 한도 + +| 항목 | 비과세 한도 | 🔴 경고 기준 | 🟢 정상 기준 | +|:---|:---|:---|:---| +| 식대 | 월 20만원 | 20만원 초과 시 초과분 과세 | 20만원 이하 | +| 자가운전보조금 | 월 20만원 | 20만원 초과 시 초과분 과세 | 20만원 이하 | +| 출산/보육수당 | 월 20만원 | 20만원 초과 시 초과분 과세 | 20만원 이하 | +| 연구보조비 | 월 20만원 | 20만원 초과 시 초과분 과세 | 20만원 이하 | +| 야근식대/숙직비 | 실비 정산 | 과다 지급 시 과세 위험 | 실비 범위 내 | + +### 6.3 비과세 초과 시 + +| 키워드 | 색상 | 임계값 기준 | 세무 처리 | +|:---|:---:|:---|:---| +| **비과세 한도를 초과** | 🔴 빨간색 | 항목별 비과세 한도 초과 시 | 초과분 근로소득 과세 | +| **근로소득 과세됩니다** | 🔴 빨간색 | 비과세 초과분 발생 시 | 원천세 추가 징수 | +| **초과분 N만원 과세 처리** | 🔴 빨간색 | 과세 금액 명시 | 급여에 합산 | +| **한도 임박** | 🟠 주황색 | 비과세 한도의 90% 이상 사용 | 사용 주의 | + +#### 적용 예시 +- 식대가 월 25만원으로 🔴**비과세 한도(20만원)를 초과**했습니다. 🔴**초과분 5만원 근로소득 과세됩니다**. + +--- + +## 7. 미수금 현황 섹션 + +미수금 현황을 분석하여 연체 상태, 회수 필요성, 리스크 집중도를 안내합니다. + +### 7.1 연체 기간별 분류 + +| 키워드 | 색상 | 연체 기간 | 조치 수준 | +|:---|:---:|:---|:---| +| **장기 미수금 발생** | 🔴 빨간색 | 90일 초과 | 법적 조치 검토 | +| **회수 조치가 필요** | 🔴 빨간색 | 60~90일 | 적극적 독촉/추심 | +| **연체 발생** | 🟠 주황색 | 30~60일 | 독촉장 발송 | +| **연체 임박** | 🟠 주황색 | 만기 D-7일 ~ 만기 후 30일 | 사전 연락 | +| **정상 거래** | 🟢 녹색 | 만기 전 | 정상 관리 | +| **회수 완료** | 🟢 녹색 | 전액 회수 시 | 완료 처리 | + +#### 적용 예시 +- 90일 이상 🔴**장기 미수금 3건(2,500만원) 발생**. 🔴**회수 조치가 필요**합니다. + +### 7.2 리스크 집중도 + +| 키워드 | 색상 | 임계값 기준 | 계산 방식 | +|:---|:---:|:---|:---| +| **전체의 N%를 차지** | 🔴 빨간색 | 상위 1개사 미수금 비중 30% 이상 | 거래처 미수금 ÷ 총 미수금 | +| **리스크 분산이 필요** | 🔴 빨간색 | 상위 1개사 비중 30% 이상 | 집중 리스크 경고 | +| **리스크 관리 필요** | 🟠 주황색 | 상위 3개사 비중 50% 이상 | 분산 권고 | +| **리스크 분산 양호** | 🟢 녹색 | 상위 1개사 비중 20% 미만 | 정상 분산 | +| **리스크 관리 양호** | 🔵 파란색 | 상위 3개사 비중 40% 미만 | 양호한 분산 | + +#### 적용 예시 +- (주)대한전자 미수금 1,500만원으로 🔴**전체의 35%를 차지**합니다. 🔴**리스크 분산이 필요**합니다. +- 상위 3개사 미수금 비중 38%. 🔵**리스크 관리 양호**합니다. + +### 7.3 미수금 금액 기준 + +| 키워드 | 색상 | 임계값 기준 | 비고 | +|:---|:---:|:---|:---| +| **대형 미수금** | 🔴 빨간색 | 단일 건 3,000만원 이상 | 집중 관리 대상 | +| **주요 미수금** | 🟠 주황색 | 단일 건 1,000~3,000만원 | 관리 주의 | +| **일반 미수금** | 🔵 파란색 | 단일 건 1,000만원 미만 | 정상 관리 | + +--- + +## 8. 채권추심 현황 섹션 + +채권추심 진행 현황을 분석하여 법적 조치 상태와 회수 가능성을 안내합니다. + +### 8.1 추심 진행 상태 + +| 키워드 | 색상 | 임계값 기준 | 다음 단계 | +|:---|:---:|:---|:---| +| **회수 불가 판정** | 🔴 빨간색 | 채무자 무자력 확인 또는 소멸시효 완성 | 대손 처리 | +| **파산/회생 신청** | 🔴 빨간색 | 채무자 파산/회생 신청 확인 시 | 채권 신고 | +| **대손 처리 검토가 필요** | 🟠 주황색 | 회수 가능성 30% 미만 판단 시 | 세무 검토 | +| **법적 조치 진행 중** | 🔵 파란색 | 소송/강제집행 진행 중 | 결과 대기 | +| **지급명령 신청 완료** | 🟢 녹색 | 지급명령 신청 접수 완료 | 법원 결정 대기 | +| **회수 완료** | 🟢 녹색 | 채권 전액 또는 일부 회수 | 종결 처리 | + +#### 적용 예시 +- (주)대한전자 건 🟢**지급명령 신청 완료**. 법원 결정까지 약 2주 소요 예정입니다. +- (주)삼성테크 건 🔴**회수 불가 판정**. 🟠**대손 처리 검토가 필요**합니다. + +### 8.2 예상 소요 기간 + +| 키워드 | 색상 | 임계값 기준 | 비고 | +|:---|:---:|:---|:---| +| **장기 소송 예상** | 🔴 빨간색 | 예상 소요 기간 6개월 이상 | 비용/효익 검토 필요 | +| **소송 진행 중** | 🟠 주황색 | 예상 소요 기간 3~6개월 | 진행 상황 모니터링 | +| **법원 결정까지 약 N주 소요 예정** | 🔵 파란색 | 예상 소요 기간 3개월 미만 | 정상 진행 | +| **조기 회수 예상** | 🟢 녹색 | 예상 소요 기간 1개월 미만 | 신속 처리 | + +### 8.3 회수율 기준 + +| 키워드 | 색상 | 임계값 기준 | 판단 기준 | +|:---|:---:|:---|:---| +| **회수 불가** | 🔴 빨간색 | 예상 회수율 10% 미만 | 대손 처리 대상 | +| **회수 곤란** | 🔴 빨간색 | 예상 회수율 10~30% | 적극 추심 필요 | +| **부분 회수 예상** | 🟠 주황색 | 예상 회수율 30~70% | 협상 검토 | +| **회수 가능성 높음** | 🟢 녹색 | 예상 회수율 70% 이상 | 정상 추심 | +| **전액 회수 예상** | 🟢 녹색 | 예상 회수율 90% 이상 | 양호 | + +--- + +## 9. 부가세 현황 섹션 + +부가세 예정/확정 신고 현황을 분석하여 납부/환급 예상액과 세금계산서 발행 현황을 안내합니다. + +### 9.1 납부/환급 세액 + +| 키워드 | 색상 | 임계값 기준 | 판단 근거 | +|:---|:---:|:---|:---| +| **납부세액 급증** | 🔴 빨간색 | 전기 대비 30% 이상 증가 (매출 증가율 대비 초과) | 비정상 증가 | +| **매입세액 누락 의심** | 🔴 빨간색 | 매입세액 ÷ 매출세액 < 업종 평균의 70% | 누락 가능성 | +| **납부세액 증가** | 🟠 주황색 | 전기 대비 15~30% 증가 | 검토 필요 | +| **예상 환급세액** | 🟢 녹색 | 매입세액 > 매출세액 | 환급 발생 | +| **매입세액 증가가 주요 원인** | 🟢 녹색 | 설비투자 등 정당한 매입 증가 시 | 정상 사유 | +| **정상적인 증가로 판단** | 🟢 녹색 | 매출 증가율과 납부세액 증가율 유사 | 정상 범위 | +| **전기 대비 N% 증가** | 🔵 파란색 | 전기 대비 15% 미만 증가 | 정상 변동 | + +#### 적용 예시 +- 2026년 1기 예정신고 기준, 🟢**예상 환급세액**은 5,200,000원입니다. 설비투자에 따른 🟢**매입세액 증가가 주요 원인**입니다. +- 예상 납부세액 110,100,000원. 🔵**전기 대비 12.9% 증가**했으며, 매출 증가(11.5%)에 따른 🟢**정상적인 증가로 판단**됩니다. + +### 9.2 세금계산서 발행 관리 + +| 키워드 | 색상 | 임계값 기준 | 가산세 | +|:---|:---:|:---|:---| +| **세금계산서 미발행** | 🔴 빨간색 | 발행 기한 경과 후 미발행 1건 이상 | 공급가액의 2% | +| **발행 기한 초과** | 🔴 빨간색 | 공급일 다음 달 10일 경과 | 지연 발급 1% | +| **가산세 발생 위험** | 🔴 빨간색 | 미발행 또는 지연 발행 시 | 최대 2% | +| **발행 기한 임박** | 🟠 주황색 | 발행 기한 D-3일 이내 | 발행 권고 | +| **정상 발행** | 🟢 녹색 | 공급일 다음 달 10일 이내 발행 | 정상 | + +#### 적용 예시 +- 🔴**세금계산서 미발행** 3건 발생. 🔴**가산세 발생 위험**이 있습니다. 공급가액 1,500만원 × 2% = 30만원 +- 12월 매출분 세금계산서 🟠**발행 기한 임박** (D-2일). 1월 10일까지 발행 필요합니다. + +--- + +## 10. 종합 색상 적용 기준 매트릭스 + +모든 AI 리포트 섹션에 대한 색상 적용 기준을 요약한 종합 매트릭스입니다. + +| 섹션 | 🔴 경고 | 🟠 주의 | 🟢 긍정 | 🔵 양호 | +|:---|:---|:---|:---|:---| +| 일일 일보 (출금) | 7일 평균 대비 200% 이상 | 7일 평균 대비 150~200% | - | 7일 평균 대비 150% 미만 | +| 일일 일보 (입금) | - | - | 입금 발생 시 | - | +| 일일 일보 (운영자금) | 3개월 미만 확보 | 3~6개월 확보 | - | 6개월 이상 확보 | +| 일일 일보 (환율) | 일 ±1.5% 이상 | 일 ±1.0~1.5% | 환차익 발생 | 일 ±1.0% 미만 | +| 일일 일보 (환차손익) | 손실 1,000만원 이상 | 손실 500~1,000만원 | 이익 500만원 이상 | ±500만원 미만 | +| 당월 지출 (전월 대비) | 15% 이상 증가 | 10~15% 증가 | 5% 이상 감소 | ±10% 이내 | +| 당월 지출 (예산 대비) | 100% 초과 | 90~100% | - | 90% 미만 | +| 카드/가지급금 (전환) | 100만원 이상 전환 | 50~100만원 전환 | - | - | +| 카드/가지급금 (소명) | 불인정 가맹점 | 주말/심야 50만원 이상 | - | - | +| 접대비 (한도) | 100% 초과 | 85~100% | 75% 미만 | 75~85% | +| 접대비 (증빙) | 거래처 정보 누락 | 상세 내용 미기재 | 증빙 완비 | - | +| 복리후생비 | 1인당 월 30만원 초과 | 1인당 월 25~30만원 | 1인당 월 15~25만원 | 1인당 월 15만원 미만 | +| 복리후생비 (비과세) | 한도 초과 시 과세 | 한도 90% 이상 | - | 한도 이하 | +| 미수금 (연체) | 90일 초과 | 30~90일 | 회수 완료 | 만기 전 | +| 미수금 (집중도) | 1개사 30% 이상 | 3개사 50% 이상 | 1개사 20% 미만 | 3개사 40% 미만 | +| 채권추심 (상태) | 회수 불가, 파산 | 대손 검토 필요 | 지급명령 완료, 회수 | 법적 조치 진행 중 | +| 채권추심 (회수율) | 10% 미만 | 10~30% | 70% 이상 | 30~70% | +| 부가세 (납부세액) | 전기 대비 30% 이상 증가 | 전기 대비 15~30% 증가 | 환급 발생, 정상 증가 | 전기 대비 15% 미만 | +| 부가세 (세금계산서) | 미발행/기한 초과 | 기한 D-3일 이내 | 정상 발행 | - | + +--- + +*— 문서 끝 —* diff --git a/plans/archive/SEEDERS_LIST.md b/plans/archive/SEEDERS_LIST.md new file mode 100644 index 0000000..b8a90b2 --- /dev/null +++ b/plans/archive/SEEDERS_LIST.md @@ -0,0 +1,128 @@ +# SAM API 시더 목록 + +> 생성일: 2025-01-05 +> 대상 테넌트: ID 287 + +## 개별 실행 방법 + +```bash +# Docker 컨테이너 접속 후 +php artisan db:seed --class=시더클래스명 + +# Dummy 폴더 시더는 네임스페이스 포함 +php artisan db:seed --class=Dummy\\DummyClientSeeder +``` + +--- + +## 1. 메인 시더 + +| # | 시더 | 설명 | 실행 명령어 | +|---|------|------|-------------| +| 1 | `DatabaseSeeder` | 기본 시더 (테스트 유저 + 메뉴) | `php artisan db:seed` | +| 2 | `DummyDataSeeder` | 전체 더미 데이터 (모든 Dummy 호출) | `php artisan db:seed --class=DummyDataSeeder` | + +--- + +## 2. 기본 데이터 시더 (Dummy) + +| # | 시더 | 테이블 | 수량 | 실행 명령어 | +|---|------|--------|------|-------------| +| 3 | `DummyUserSeeder` | users | 15 | `php artisan db:seed --class=Dummy\\DummyUserSeeder` | +| 4 | `DummyDepartmentSeeder` | departments | 11 | `php artisan db:seed --class=Dummy\\DummyDepartmentSeeder` | +| 5 | `DummyClientGroupSeeder` | client_groups | 5 | `php artisan db:seed --class=Dummy\\DummyClientGroupSeeder` | +| 6 | `DummyBankAccountSeeder` | bank_accounts | 5 | `php artisan db:seed --class=Dummy\\DummyBankAccountSeeder` | +| 7 | `DummyClientSeeder` | clients | 20 | `php artisan db:seed --class=Dummy\\DummyClientSeeder` | + +--- + +## 3. 회계 데이터 시더 (Dummy) + +| # | 시더 | 테이블 | 수량 | 실행 명령어 | +|---|------|--------|------|-------------| +| 8 | `DummyDepositSeeder` | deposits | 60 | `php artisan db:seed --class=Dummy\\DummyDepositSeeder` | +| 9 | `DummyWithdrawalSeeder` | withdrawals | 60 | `php artisan db:seed --class=Dummy\\DummyWithdrawalSeeder` | +| 10 | `DummySaleSeeder` | sales | 80 | `php artisan db:seed --class=Dummy\\DummySaleSeeder` | +| 11 | `DummyPurchaseSeeder` | purchases | 70 | `php artisan db:seed --class=Dummy\\DummyPurchaseSeeder` | +| 12 | `DummyBadDebtSeeder` | bad_debts | 18 | `php artisan db:seed --class=Dummy\\DummyBadDebtSeeder` | +| 13 | `DummyBillSeeder` | bills | 30 | `php artisan db:seed --class=Dummy\\DummyBillSeeder` | + +--- + +## 4. HR 데이터 시더 (Dummy) + +| # | 시더 | 테이블 | 수량 | 실행 명령어 | +|---|------|--------|------|-------------| +| 14 | `DummyWorkSettingSeeder` | work_settings | 1 | `php artisan db:seed --class=Dummy\\DummyWorkSettingSeeder` | +| 15 | `DummyAttendanceSettingSeeder` | attendance_settings | 1 | `php artisan db:seed --class=Dummy\\DummyAttendanceSettingSeeder` | +| 16 | `DummyAttendanceSeeder` | attendances | ~300 | `php artisan db:seed --class=Dummy\\DummyAttendanceSeeder` | +| 17 | `DummyLeaveGrantSeeder` | leave_grants | ~200 | `php artisan db:seed --class=Dummy\\DummyLeaveGrantSeeder` | +| 18 | `DummyLeaveSeeder` | leaves | ~50 | `php artisan db:seed --class=Dummy\\DummyLeaveSeeder` | +| 19 | `DummyCardSeeder` | cards | 5 | `php artisan db:seed --class=Dummy\\DummyCardSeeder` | +| 20 | `DummySalarySeeder` | salaries | 15 | `php artisan db:seed --class=Dummy\\DummySalarySeeder` | + +--- + +## 5. 기타 더미 시더 (Dummy) + +| # | 시더 | 테이블 | 수량 | 실행 명령어 | +|---|------|--------|------|-------------| +| 21 | `DummyItemSeeder` | items | 10,000 | `php artisan db:seed --class=Dummy\\DummyItemSeeder` | +| 22 | `DummyPopupSeeder` | popups | 8 | `php artisan db:seed --class=Dummy\\DummyPopupSeeder` | +| 23 | `DummyPaymentSeeder` | payments | 13 | `php artisan db:seed --class=Dummy\\DummyPaymentSeeder` | +| 24 | `ApprovalTestDataSeeder` | approvals | ~60 | `php artisan db:seed --class=ApprovalTestDataSeeder` | + +--- + +## 6. 시스템/설정 시더 + +| # | 시더 | 설명 | 실행 명령어 | +|---|------|------|-------------| +| 25 | `GlobalMenuTemplateSeeder` | 글로벌 메뉴 템플릿 | `php artisan db:seed --class=GlobalMenuTemplateSeeder` | +| 26 | `ReactMenuSeeder` | React 메뉴 | `php artisan db:seed --class=ReactMenuSeeder` | +| 27 | `CategorySeeder` | 카테고리 | `php artisan db:seed --class=CategorySeeder` | +| 28 | `ItemTypeSeeder` | 품목 유형 | `php artisan db:seed --class=ItemTypeSeeder` | +| 29 | `ItemMasterSeeder` | 품목 마스터 | `php artisan db:seed --class=ItemMasterSeeder` | +| 30 | `PositionSeeder` | 직급 | `php artisan db:seed --class=PositionSeeder` | +| 31 | `FolderSeeder` | 폴더 | `php artisan db:seed --class=FolderSeeder` | +| 32 | `CapabilityProfileSeeder` | 역량 프로필 | `php artisan db:seed --class=CapabilityProfileSeeder` | +| 33 | `StockReceivingSeeder` | 입고 | `php artisan db:seed --class=StockReceivingSeeder` | +| 34 | `ComprehensiveAnalysisSeeder` | 종합분석 | `php artisan db:seed --class=ComprehensiveAnalysisSeeder` | +| 35 | `SystemFieldDefinitionSeeder` | 시스템 필드 정의 | `php artisan db:seed --class=SystemFieldDefinitionSeeder` | +| 36 | `DemoSystemSeeder` | 데모 시스템 | `php artisan db:seed --class=DemoSystemSeeder` | +| 37 | `BpMesCategoryFieldsSeeder` | MES 카테고리 필드 | `php artisan db:seed --class=BpMesCategoryFieldsSeeder` | +| 38 | `BpMesTenantStatFieldsSeeder` | MES 테넌트 통계 필드 | `php artisan db:seed --class=BpMesTenantStatFieldsSeeder` | + +--- + +## 7. 견적 관련 시더 + +| # | 시더 | 설명 | 실행 명령어 | +|---|------|------|-------------| +| 39 | `QuoteFormulaSeeder` | 견적 계산식 | `php artisan db:seed --class=QuoteFormulaSeeder` | +| 40 | `QuoteFormulaCategorySeeder` | 견적 계산 카테고리 | `php artisan db:seed --class=QuoteFormulaCategorySeeder` | +| 41 | `QuoteFormulaItemSeeder` | 견적 계산 품목 | `php artisan db:seed --class=QuoteFormulaItemSeeder` | +| 42 | `QuoteFormulaMappingSeeder` | 견적 계산 매핑 | `php artisan db:seed --class=QuoteFormulaMappingSeeder` | + +--- + +## 요약 + +| 카테고리 | 개수 | +|----------|------| +| 메인 시더 | 2 | +| 기본 데이터 (Dummy) | 5 | +| 회계 데이터 (Dummy) | 6 | +| HR 데이터 (Dummy) | 7 | +| 기타 더미 (Dummy) | 4 | +| 시스템/설정 | 14 | +| 견적 관련 | 4 | +| **총계** | **42** | + +--- + +## 주의사항 + +1. **Dummy 시더**는 `TENANT_ID = 287` 하드코딩 +2. **의존성 순서**: 기본 데이터 → 회계 → HR → 기타 순서로 실행 권장 +3. **중복 주의**: 이미 데이터가 있는 경우 중복 생성됨 (특히 `DummyItemSeeder` 10,000개) \ No newline at end of file diff --git a/plans/archive/api-analysis-report.md b/plans/archive/api-analysis-report.md new file mode 100644 index 0000000..ae48343 --- /dev/null +++ b/plans/archive/api-analysis-report.md @@ -0,0 +1,434 @@ +# SAM API 전체 분석 보고서 + +> **작성일**: 2026-01-29 +> **목적**: api/, mng/, react/ 프로젝트 간 API 중복/통합/미사용 분석 및 관계 정리 +> **기준 문서**: api/routes/api/v1/*.php, mng/routes/api.php, mng/routes/web.php, react/src/lib/api/* +> **상태**: ✅ 분석 완료 + +--- + +## 📍 분석 결과 요약 + +| 항목 | 수치 | +|------|------| +| **api/ 엔드포인트** | ~710+ | +| **mng/ 엔드포인트** | ~300+ | +| **React 실제 사용** | ~80+ (api/ 전체의 ~15%) | +| **중복 도메인** | 10개 | +| **즉시 정리 가능** | 3건 | +| **통합 가능 그룹** | 6개 | + +--- + +## 1. 개요 + +### 1.1 배경 + +SAM 프로젝트는 api/(REST API), mng/(관리자 패널), react/(프론트엔드) 3개 프로젝트로 구성되어 있으며, 각 프로젝트가 독립적으로 발전하면서 동일 도메인에 대한 API가 중복 생성되었다. 본 분석은 전체 API를 파악하고 정리 방안을 제시한다. + +### 1.2 분석 범위 + +| 프로젝트 | 역할 | 분석 대상 | +|---------|------|----------| +| **api/** | REST API 서버 | routes/api/v1/*.php (14개 라우트 파일), 컨트롤러 138개 | +| **mng/** | 관리자 패널 | routes/api.php, routes/web.php, 컨트롤러 90+개 | +| **react/** | 프론트엔드 | src/lib/api/*, src/hooks/*, src/app/api/* | + +--- + +## 2. 프로젝트별 API 구조 + +### 2.1 API 프로젝트 (api/) + +**라우트 파일**: `api/routes/api/v1/` + +| 도메인 | 라우트 파일 | 엔드포인트 수 | 소비자 | +|--------|-----------|:----------:|--------| +| 인증 | `auth.php` | 8 | React, MNG | +| 사용자 | `users.php` | 25 | React | +| 테넌트 | `tenants.php` | 18 | React | +| 관리자 | `admin.php` | 22 | React, MNG | +| 공통 | `common.php` | 95+ | React, MNG | +| HR | `hr.php` | 85+ | React | +| 재무 | `finance.php` | 130+ | React | +| 영업 | `sales.php` | 85+ | React | +| 재고 | `inventory.php` | 65+ | React | +| 생산 | `production.php` | 35+ | React | +| 설계 | `design.php` | 55+ | React | +| 파일 | `files.php` | 15 | React | +| 게시판 | `boards.php` | 70+ | React | +| 문서 | `documents.php` | 5+ | React | + +### 2.2 MNG 프로젝트 (mng/) + +**API 소비 방식**: 자체 모델로 DB 직접 접근 (api/ REST API를 거치지 않음) + +| 도메인 | 엔드포인트 수 | 비고 | +|--------|:----------:|------| +| 사용자/역할/권한 | 30+ | api/와 중복 | +| 메뉴/글로벌메뉴 | 25+ | api/와 중복 | +| 게시판/필드 | 20+ | api/와 중복 | +| 카테고리/글로벌 | 15+ | api/와 중복 | +| 바로빌 (전체) | 60+ | MNG 전용 (외부 서비스) | +| 프로젝트 관리 | 25+ | MNG 전용 | +| 견적 공식 | 30+ | MNG 전용 | +| 품목 필드 | 25+ | MNG 전용 | +| 문서/템플릿 | 12+ | api/와 중복 | +| 계좌/자금일정 | 18+ | api/와 중복 | +| 기타 (회의록, 신용, 영업, Lab) | 40+ | MNG 전용 | + +### 2.3 React 프론트엔드 (react/) + +**API 호출 방식**: Next.js Proxy (`/api/proxy/*`) → Backend (`/api/v1/*`) + +| 카테고리 | 주요 엔드포인트 | 사용 빈도 | +|---------|---------------|:--------:| +| 인증 | login, logout, refresh, signup | 높음 | +| 품목 CRUD | items, items/{id}, items/bom | 높음 | +| 품목기준관리 | item-master/* (pages, sections, fields) | 높음 | +| 견적 계산 | quotes/calculate, quotes/calculate/bom | 높음 | +| 공통코드 | settings/common/{group} | 높음 | +| 대시보드 | card-transactions/dashboard, loans/dashboard | 중간 | +| 알림 | today-issues/unread, unread/count | 중간 | +| 거래처 | clients, client-groups | 중간 | +| 재고 | stocks, work-results | 중간 | +| 일괄작업 | bulk-update-account-code | 낮음 | +| 내보내기 | attendances/export, salaries/export | 낮음 | + +--- + +## 3. 중복 API 분석 + +### 3.1 중복 컨트롤러 목록 (api/ vs mng/) + +| # | 도메인 | api/ 컨트롤러 | mng/ 컨트롤러 | 중복 수준 | +|---|--------|-------------|-------------|:--------:| +| 1 | 사용자 관리 | `Api\V1\Admin\AdminController` | `Api\Admin\UserController` | 🔴 높음 | +| 2 | 역할 관리 | `Api\V1\RoleController` | `Api\Admin\RoleController` | 🔴 높음 | +| 3 | 메뉴 관리 | `Api\V1\MenuController` | `Api\Admin\MenuController` | 🔴 높음 | +| 4 | 카테고리 | `Api\V1\CategoryController` | `Api\Admin\CategoryApiController` | 🔴 높음 | +| 5 | 계좌 관리 | `Api\V1\BankAccountController` | `Api\Admin\BankAccountController` | 🔴 높음 | +| 6 | 권한 관리 | `Api\V1\PermissionController` | `Api\Admin\PermissionController` | 🟡 중간 | +| 7 | 부서 관리 | `Api\V1\DepartmentController` | `Api\Admin\DepartmentController` | 🟡 중간 | +| 8 | 게시판 | `Api\V1\BoardController` | `Api\Admin\BoardController` | 🟡 중간 | +| 9 | 문서 | `Api\V1\Documents\DocumentController` | `Api\Admin\DocumentApiController` | 🟡 중간 | +| 10 | 테넌트 | `Api\V1\TenantController` | `Api\Admin\TenantController` | 🟡 중간 | + +### 3.2 상세 비교 + +#### (1) 사용자 관리 🔴 + +| 기능 | api/ | mng/ | 차이 | +|------|:----:|:----:|------| +| 기본 CRUD | ✅ | ✅ | 동일 | +| 복구 (restore) | ✅ | ✅ | 동일 | +| 비밀번호 초기화 | ✅ | ✅ | 동일 | +| 활성화/비활성화 | ✅ (PATCH /status) | ❌ | api/만 | +| 역할 부여/해제 | ✅ (POST/DELETE /roles) | ❌ | api/만 | +| 영구삭제 | ❌ | ✅ (DELETE /force) | mng/만 (슈퍼관리자) | +| 개발용 로그인토큰 | ❌ | ✅ (POST /login-token) | mng/만 | +| 모달 데이터 | ❌ | ✅ (GET /modal) | mng/만 | + +#### (2) 역할 관리 🔴 + +| 기능 | api/ | mng/ | 차이 | +|------|:----:|:----:|------| +| 기본 CRUD | ✅ | ✅ | 동일 | +| 통계 (stats) | ✅ | ❌ | api/만 | +| 활성 목록 (active) | ✅ | ❌ | api/만 | + +#### (3) 메뉴 관리 🔴 + +| 기능 | api/ | mng/ | 차이 | +|------|:----:|:----:|------| +| 기본 CRUD | ✅ | ✅ | 동일 | +| 순서변경 (reorder) | ✅ | ✅ | 동일 | +| 복구 (restore) | ✅ | ✅ | 동일 | +| 활성화 토글 | ✅ (toggle) | ✅ (toggle-active) | 동일 기능 | +| 동기화 | ✅ (sync, sync-new, sync-updates) | ❌ | api/만 | +| 트리 구조 | ❌ | ✅ (tree) | mng/만 | +| 글로벌 복사 | ❌ | ✅ (copy-from-global) | mng/만 | +| 일괄 작업 | ❌ | ✅ (bulk-delete/restore/force) | mng/만 | +| 숨김 토글 | ❌ | ✅ (toggle-hidden) | mng/만 | +| 영구삭제 | ❌ | ✅ (force) | mng/만 (슈퍼관리자) | + +#### (4) 카테고리 🔴 + +| 기능 | api/ | mng/ | 차이 | +|------|:----:|:----:|------| +| 기본 CRUD | ✅ | ✅ | 동일 | +| 트리/순서변경/이동 | ✅ | ✅ | 동일 | +| 활성화 토글 | ✅ | ✅ | 동일 | +| 필드 관리 | ✅ (fields CRUD, bulk-upsert) | ❌ | api/만 | +| 템플릿 관리 | ✅ (templates, apply, preview, diff) | ❌ | api/만 | +| 로그 조회 | ✅ (logs) | ❌ | api/만 | +| 글로벌 관리 | ❌ | ✅ (global-categories) | mng/만 | + +#### (5) 계좌 관리 🔴 + +| 기능 | api/ | mng/ | 차이 | +|------|:----:|:----:|------| +| 기본 CRUD | ✅ | ✅ | 동일 | +| 활성화 토글 | ✅ | ✅ | 동일 | +| 활성 목록 (active) | ✅ | ❌ | api/만 | +| 대표계좌 설정 | ✅ (set-primary) | ❌ | api/만 | +| 전체 조회 (all) | ❌ | ✅ | mng/만 | +| 요약 (summary) | ❌ | ✅ | mng/만 | +| 거래내역 | ❌ | ✅ (transactions) | mng/만 | +| 일괄 작업 | ❌ | ✅ (bulk-*) | mng/만 | +| 영구삭제/복구 | ❌ | ✅ (force/restore) | mng/만 | + +#### (6) 권한 관리 🟡 + +| 기능 | api/ | mng/ | 차이 | +|------|:----:|:----:|------| +| 권한 매트릭스 조회 | ✅ (dept/role/user menu-matrix) | ❌ | api/만 (특화) | +| 기본 CRUD | ❌ | ✅ | mng/만 | + +> **분석**: api/는 매트릭스 조회 전용, mng/는 CRUD 전용으로 기능 분리된 상태. 완전 중복은 아님. + +--- + +## 4. 통합 가능 API + +### 4.1 통합 대상 그룹 + +| # | 대상 | 현재 상태 | 통합 방안 | 우선순위 | +|---|------|----------|----------|:--------:| +| 1 | **인증 API** | signup + register 중복 | register 제거 (signup 유지) | 🔴 | +| 2 | **사용자 관리** | api/ + mng/ 각각 CRUD | mng/ → api/ 호출로 전환 | 🔴 | +| 3 | **역할 관리** | api/ + mng/ 각각 CRUD | api/에 통합, mng/는 호출만 | 🟡 | +| 4 | **메뉴 관리** | api/ 동기화 + mng/ 관리 분리 | 관리: mng/, 조회+동기화: api/ | 🟡 | +| 5 | **대시보드 데이터** | 개별 엔드포인트 분산 | 통합 대시보드 API 제공 | 🟢 | +| 6 | **일괄 업데이트** | withdrawals/deposits/sales 각각 | 공통 bulk-update 패턴 | 🟢 | + +### 4.2 인증 API 중복 상세 + +``` +현재: + POST /v1/login → 로그인 + POST /v1/logout → 로그아웃 + POST /v1/signup → 회원가입 (1) + POST /v1/register → 회원가입 (2) ← 중복! + POST /v1/token-login → 토큰 로그인 (MNG→DEV) + POST /v1/refresh → 토큰 갱신 + POST /v1/internal/exchange-token → 내부 서버 토큰 교환 + GET /v1/debug-apikey → 디버그용 ← 프로덕션 제거 필요 + +권장: + - register 제거 (signup 유지) + - debug-apikey 프로덕션 비활성화 +``` + +--- + +## 5. 미사용 API + +### 5.1 React에서 호출하지 않는 api/ 도메인 + +| 도메인 | 엔드포인트 수 | 미사용 이유 | +|--------|:----------:|-----------| +| HR 전체 (employees, attendance, leave, approval) | ~80+ | MNG에서 직접 관리 또는 React 미구현 | +| 생산 대부분 (processes, work-orders, inspections) | ~35+ | work-results만 사용 | +| 설계 전체 (models, versions, bom-templates) | ~55+ | 견적 계산 시 간접 사용만 | +| 재무 대부분 (cards, payroll, bad-debts 등) | ~100+ | CEO 대시보드 일부만 사용 | +| 사용자 초대 (invitations) | ~5 | React 미구현 | +| 알림 설정 (notification-settings) | ~5 | React 미구현 | +| 프로필 관리 (profiles) | ~5 | React 미구현 | +| 팝업 관리 (popups) | ~5 | React 미구현 | +| AI 리포트 (reports/ai) | ~4 | React 미구현 | +| 구독/결제 (subscriptions, payments) | ~20+ | React 미구현 | +| 현장/시공 (sites, construction) | ~30+ | React 미구현 | +| 검사 관리 (inspections) | ~8 | React 미구현 | + +> **참고**: "미사용"은 React 프론트엔드 기준. MNG에서 Blade UI로 직접 사용하거나 향후 구현 예정인 경우 포함. + +### 5.2 완전 미사용 가능성 높은 API + +| 엔드포인트 | 이유 | 조치 권장 | +|-----------|------|----------| +| `GET /v1/debug-apikey` | 디버그 전용 | 프로덕션 비활성화 | +| `POST /v1/register` | signup과 중복 | 제거 | +| `GET /v1/welfare/*` | React/MNG 모두 미호출 확인 필요 | 사용 여부 확인 | +| `GET /v1/entertainment/*` | React/MNG 모두 미호출 확인 필요 | 사용 여부 확인 | +| `GET /v1/calendar/schedules` | React 미호출 | 사용 여부 확인 | +| `GET /v1/comprehensive-analysis` | React 미호출 | 사용 여부 확인 | + +### 5.3 MNG 전용 기능 (정상) + +| 기능 | 설명 | 상태 | +|------|------|:----:| +| 바로빌 (Barobill) | 전자세금계산서, 카드, 홈택스 연동 | ✅ 정상 | +| 프로젝트 관리 | 프로젝트, 태스크, 이슈 | ✅ 정상 | +| 데일리 로그 | 일일 스크럼 | ✅ 정상 | +| 견적 공식 | 견적 계산 공식 관리 | ✅ 정상 | +| 회의록 | 녹음, AI 요약 (Google Cloud) | ✅ 정상 | +| 신용 평가 | Coocon API 연동 | ✅ 정상 | +| 영업 관리 | 매니저, 전망, 기록 | ✅ 정상 | +| DevTools | API 탐색기, 흐름 테스터 | ✅ 정상 | +| Lab/R&D | AI, 전략 실험 | ✅ 정상 | + +--- + +## 6. 프로젝트 간 API 관계도 + +### 6.1 시스템 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 사용자 (브라우저) │ +│ │ +│ ┌──────────────┐ ┌──────────────────┐ │ +│ │ React App │ │ MNG Admin │ │ +│ │ (dev.sam.kr) │ │ (mng.sam.kr) │ │ +│ └──────┬───────┘ └──────┬───────────┘ │ +│ │ │ │ +│ Next.js Proxy 자체 모델 직접 사용 │ +│ (/api/proxy/*) + 일부 api/ 호출 │ +│ │ │ │ +│ ▼ │ │ +│ ┌──────────────┐ │ │ +│ │ API 서버 │◄─────────────────┘ │ +│ │ (api.sam.kr) │ token-login, │ +│ │ │ DevTools API 탐색 │ +│ └──────┬───────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────┐ │ +│ │ Database │◄──── MNG도 동일 DB 직접 접근 │ +│ │ (MySQL) │ │ +│ └──────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + +외부 API: +┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ +│ Google │ │ Coocon │ │ FCM │ │ NTS │ +│ Cloud │ │ (신용) │ │ (푸시) │ │ (홈택스) │ +└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ + └────────────┴────────────┴─────────────┘ + │ + MNG에서 호출 +``` + +### 6.2 데이터 흐름 + +| 흐름 | 방식 | 설명 | +|------|------|------| +| React → API | HTTP (Proxy) | 모든 비즈니스 로직 API 호출 | +| MNG → DB | 직접 모델 | 관리 기능은 DB 직접 접근 | +| MNG → API | HTTP | token-login, DevTools, 일부 동기화 | +| MNG → 외부 | HTTP | Barobill, Google Cloud, Coocon, NTS | +| API → DB | 직접 모델 | 모든 비즈니스 로직 | + +### 6.3 중복 발생 원인 + +``` +문제: MNG가 api/를 호출하지 않고 DB 직접 접근 + → 동일 도메인에 대해 api/, mng/ 각각 독립 컨트롤러 보유 + → 비즈니스 로직 분산, 유지보수 부담 증가 + +현재: + React → api/ (REST API) → DB + MNG → DB 직접 ← 여기가 문제 + +이상적: + React → api/ (REST API) → DB + MNG → api/ (REST API) → DB (관리자 전용 엔드포인트 추가) +``` + +--- + +## 7. 개선 권장사항 + +### 7.1 즉시 정리 (Quick Wins) 🔴 + +| # | 작업 | 영향 | 노력 | +|---|------|------|:----:| +| 1 | `POST /v1/register` 제거 (signup 유지) | 코드 정리 | 소 | +| 2 | `GET /v1/debug-apikey` 프로덕션 비활성화 | 보안 강화 | 소 | +| 3 | 미사용 Swagger 문서 정리 | 문서 정확성 | 소 | + +### 7.2 중복 해소 (Medium Term) 🟡 + +| # | 작업 | 현재 | 목표 | +|---|------|------|------| +| 1 | 사용자 관리 통합 | api/ + mng/ 각각 | api/ 마스터, mng/ 관리자 기능만 추가 | +| 2 | 역할 관리 통합 | api/ + mng/ 각각 | api/ 단일 소스 | +| 3 | 카테고리 통합 | api/ + mng/ 각각 | api/ 마스터, mng/ 글로벌 관리만 유지 | +| 4 | 계좌 관리 통합 | api/ + mng/ 각각 | 하나로 통합 | +| 5 | 메뉴 관리 정리 | api/ 동기화 + mng/ 관리 | 역할 분리 명확화 | + +### 7.3 아키텍처 개선 (Long Term) 🟢 + +| # | 작업 | 설명 | +|---|------|------| +| 1 | MNG → API 호출 전환 | MNG가 DB 직접 접근 대신 api/ REST API 호출 | +| 2 | API Gateway 도입 | 인증/권한/레이트리밋 중앙 관리 | +| 3 | 미사용 API 비활성화 | deprecation 헤더 추가 후 단계적 제거 | +| 4 | API v2 전환 | 중복 정리 포함한 v2 설계 | + +--- + +## 8. 전체 엔드포인트 도메인별 수 + +### API 프로젝트 + +| 도메인 | 파일 | 수 | +|--------|------|:--:| +| 인증 | auth.php | 8 | +| 사용자 | users.php | 25 | +| 테넌트 | tenants.php | 18 | +| 관리자 | admin.php | 22 | +| 공통 | common.php | 95+ | +| HR | hr.php | 85+ | +| 재무 | finance.php | 130+ | +| 영업 | sales.php | 85+ | +| 재고 | inventory.php | 65+ | +| 생산 | production.php | 35+ | +| 설계 | design.php | 55+ | +| 파일 | files.php | 15 | +| 게시판 | boards.php | 70+ | +| 문서 | documents.php | 5+ | +| **합계** | | **~710+** | + +### MNG 프로젝트 + +| 그룹 | 수 | +|------|:--:| +| 사용자/역할/권한 | 30+ | +| 메뉴/글로벌메뉴 | 25+ | +| 게시판/필드 | 20+ | +| 카테고리/글로벌 | 15+ | +| 바로빌 | 60+ | +| 프로젝트 관리 | 25+ | +| 견적 공식 | 30+ | +| 품목 필드 | 25+ | +| 문서/템플릿 | 12+ | +| 계좌/자금일정 | 18+ | +| 기타 | 40+ | +| **합계** | **~300+** | + +--- + +## 9. 참고 문서 + +- `docs/standards/api-rules.md` - API 규칙 +- `docs/architecture/system-overview.md` - 시스템 아키텍처 +- `docs/specs/database-schema.md` - DB 스키마 +- `api/routes/api/v1/*.php` - API 라우트 파일 +- `mng/routes/api.php` - MNG API 라우트 +- `react/src/lib/api/` - React API 클라이언트 + +--- + +## 10. 결론 + +1. **api/와 mng/의 10개 도메인에서 컨트롤러 중복** 발생 - 동일 DB를 각각 직접 접근하는 구조적 문제 +2. **React는 api/ 전체의 약 15%만 사용** - 나머지는 MNG 전용이거나 미구현 기능 +3. **인증 API에 signup/register 중복** 존재 - 즉시 정리 가능 +4. **장기적으로 MNG → API 호출 전환**이 이상적이나, 현재 아키텍처도 기능적으로 동작 +5. **Quick Wins(register 제거, debug-apikey 비활성화)부터 시작** 권장 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/bending-lot-pipeline-dev-plan.md b/plans/archive/bending-lot-pipeline-dev-plan.md new file mode 100644 index 0000000..a9d2833 --- /dev/null +++ b/plans/archive/bending-lot-pipeline-dev-plan.md @@ -0,0 +1,1097 @@ +# 절곡 자재투입 LOT 매핑 파이프라인 개발 계획 + +> **작성일**: 2026-02-22 +> **목적**: 절곡 세부품목(BD-XX-NN)의 동적 BOM 생성 및 LOT 추적 파이프라인 구축 +> **기준 문서**: `docs/plans/bending-material-input-mapping-plan.md` +> **상태**: ✅ 완료 (Serena ID: bending-lot-pipeline-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 5.2 완료 — 전체 파이프라인 완성 | +| **다음 작업** | 없음 (전체 완료) | +| **진행률** | 13/13 (100%) ✅ | +| **마지막 업데이트** | 2026-02-22 | + +--- + +## 1. 개요 + +### 1.1 배경 + +절곡 작업일지에는 4대 카테고리(가이드레일/하단마감재/셔터박스/연기차단재)의 세부품목이 표시되나, 현재 SAM에서 이 세부품목들이 items 테이블의 BOM과 연결되지 않아 **자재투입 시 세부품목별 LOT 매핑이 불가능**하다. + +**방안 B(동적 BOM 생성)** 확정: 작업지시 생성 시 BendingInfoBuilder를 확장하여 `work_order_items.options.dynamic_bom`에 세부품목 정보를 저장하고, `getMaterials()` API가 이를 우선 참조하도록 수정한다. + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 견적 로직(QuoteCalculationService) 수정 없음 │ +│ 2. DB 스키마 변경 없음 — 기존 options JSON 컬럼 활용 │ +│ 3. 하위 호환성 — dynamic_bom 없는 기존 데이터도 정상 동작 │ +│ 4. bending_info와 dynamic_bom은 동일 Builder에서 동시 생성 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | JSON 필드 추가, 새 Service 클래스 생성, 유틸 함수, 테스트 | 불필요 | +| ⚠️ 컨펌 필요 | getMaterials() 로직 변경, registerMaterialInput API 통일, 프론트 모달 동작 변경 | **필수** | +| 🔴 금지 | items.bom 컬럼 직접 수정, 견적 로직 변경, work_order_material_inputs 스키마 변경 | 별도 협의 | + +### 1.4 준수 규칙 + +- `docs/standards/api-rules.md` — Service-First, FormRequest, ApiResponse +- `docs/standards/quality-checklist.md` — 품질 체크리스트 +- `docs/rules/item-policy.md` — 품목 정책 (BD-* 명명 규칙) +- `api/CLAUDE.md` — SAM API 개발 규칙 + +### 1.5 성공 기준 + +| 기준 | 측정 방법 | +|------|----------| +| 작업지시 생성 시 dynamic_bom JSON 자동 생성 | work_order_items.options에 dynamic_bom 존재 확인 | +| getMaterials API가 세부품목(BD-RS-43 등) 반환 | API 응답에 세부품목 리스트 포함 확인 | +| 세부품목별 LOT 선택 → 재고 차감 정상 | stock_transactions + work_order_material_inputs 레코드 확인 | +| 자재투입 이력에 work_order_item_id 기록 | WorkOrderMaterialInput 레코드의 work_order_item_id NOT NULL | +| 레거시 5130과 동일한 LOT prefix 체계 | prefix × lengthCode 전체 조합 매칭 검증 | + +### 1.6 현재 구현 컨텍스트 (새 세션 필독) + +> 이 섹션은 새 세션에서 별도 파일을 읽지 않고도 작업을 시작할 수 있도록 핵심 코드 구조를 인라인합니다. + +#### 1.6.1 전체 데이터 흐름 + +``` +[견적/수주] + QuoteCalculationService.calculateBom() + → order_nodes.options.bom_result에 부모 품목 저장 + → 예: BD-가이드레일-KSS01-SUS-120*70, qty=8.5m + ↓ +[작업지시 생성] + WorkOrderService.store() (L266-316) + → salesOrder.items 순회 → work_order_items에 복사 + → nodeOptions에서 bending_info 복사: work_order_items.options.bending_info + → ⭐ [신규] dynamic_bom도 여기서 저장: work_order_items.options.dynamic_bom + ↓ + BendingInfoBuilder.build(Order, processId) (L29-69) + → 절곡 공정 확인 → rootNodes 필터링 → productCode 파싱 + → getMaterialMapping() → aggregateNodes() → assembleBendingInfo() + → ⭐ [신규] buildDynamicBom() → 길이 버킷팅 결과로 BD-XX-NN 세부품목 매핑 + ↓ +[자재투입 조회] + getMaterials(workOrderId) (L1183-1317) + → work_order_items 순회 + → ⭐ [신규] options.dynamic_bom 있으면 세부품목 사용 / 없으면 item.bom fallback + → 세부품목별 Stock → StockLot (FIFO) 조회 + ↓ +[자재투입 등록] + registerMaterialInputForItem(workOrderId, itemId, inputs) (L2821-2907) + → StockService.decreaseFromLot() — 재고 차감 + → WorkOrderMaterialInput::create() — 투입 이력 기록 + ↓ +[생산완료] + updateStatus(workOrderId, 'completed') (L520-602) + → sales_order_id 있으면: createShipmentFromWorkOrder() (출하 직행) + → sales_order_id 없으면: stockInFromProduction() → stock_lots 생성 +``` + +#### 1.6.2 BendingInfoBuilder 핵심 구조 + +**파일**: `api/app/Services/Production/BendingInfoBuilder.php` + +```php +// 진입점 +public function build(Order $order, int $processId, ?array $nodeIds = null): ?array + +// BOM 아이템 카테고리 분류 (L96-130) +private function categorizeBomItem(array $bomItem): ?string +// 반환: 'guideRail', 'shutterBox_case', 'shutterBox_finCover', 'bottomBar', +// 'smokeBarrier_rail', 'smokeBarrier_case', 'detail_lbar', 'detail_reinforce', 'motor' + +// 노드 집계 (L135-175) +private function aggregateNodes(Collection $nodes): array +// 반환: { dimensionGroups: [{height, width, qty}], totalNodeQty, bomCategories: {category => bomItem} } + +// 높이 기준 버킷팅 (L760-763) — 가이드레일용 +private function heightLengthData(array $dimGroups): array +// 반환: [{ length: 2438, quantity: 5 }, { length: 3000, quantity: 3 }] +// 표준 길이: [2438, 3000, 3500, 4000, 4300] + +// 하단마감재 배분 (L801-834) +private function bottomBarDistribution(int $openWidth): array +// 반환: [3000mm수량, 4000mm수량] +// 예: openWidth=7000 → [1, 1] (3000×1 + 4000×1) + +// 셔터박스 배분 (L411-548) +private function shutterBoxDistribution(int $openWidth): array +// 반환: [1219 => qty, 2438 => qty, 3000 => qty, 3500 => qty, 4000 => qty, 4150 => qty] + +// 가이드레일 섹션 (L251-299) +private function buildGuideRail(string $guideType, string $baseSize, array $materials, array $dimGroups, string $productCode): array +// guideType: '벽면형', '측면형', '혼합형' +// 반환: { wall: {baseSize, baseDimension, lengthData}, side: {...} | null } + +// 표준 길이 버킷팅 (L856-865) — ⚠️ 초과 시 원본 반환 +private function bucketToStandardLength(int $dimension, array $buckets): int +``` + +#### 1.6.3 getMaterials() 현재 로직 + +**파일**: `api/app/Services/WorkOrderService.php` L1183-1317 + +``` +Phase 1: 유니크 자재 수집 + for each workOrder.items: + if item.bom 존재: ← 절곡 부모 품목은 bom=null이므로 여기 안 탐 + BOM 자식 순회 → uniqueMaterials[childItemId] += qty + else: ← 현재 절곡은 여기로 빠짐 (부모 품목 자체가 자재로) + uniqueMaterials[itemId] = qty + +Phase 2: StockLot 조회 + for each uniqueMaterial: + stock = Stock.find(itemId) → StockLot.where(available) → FIFO 정렬 + +⚠️ 문제: 절곡 부모 품목(BD-가이드레일-KSS01-SUS-120*70)의 bom이 null + → 세부품목(BD-RS-43 등)이 자재 목록에 나오지 않음 + → dynamic_bom으로 해결 +``` + +#### 1.6.4 registerMaterialInput 두 메서드 차이 + +| 항목 | registerMaterialInput (L1330) | registerMaterialInputForItem (L2821) | +|------|-------------------------------|--------------------------------------| +| 파라미터 | workOrderId, inputs | workOrderId, **itemId**, inputs | +| 재고 차감 | ✅ decreaseFromLot | ✅ decreaseFromLot | +| WorkOrderMaterialInput | ❌ 미생성 | ✅ 생성 (work_order_item_id 포함) | +| 용도 | 전체 작업지시 단위 | 개소(품목) 단위 | + +#### 1.6.5 프론트엔드 현재 구조 + +**MaterialInputModal** (`react/src/components/production/WorkerScreen/MaterialInputModal.tsx`) + +```typescript +// Props — workOrderItemId 유무로 API 경로 분기 +interface MaterialInputModalProps { + order: WorkOrder | null; + workOrderItemId?: number; // 있으면 개소별 API, 없으면 전체 API + workOrderItemName?: string; +} + +// 품목 그룹핑 (L102-119): itemId 기준 Map +// FIFO 배분 (L121-138): selectedLotKeys → 가용량 순서로 자동 배분 +// 등록 (L261-307): +// workOrderItemId ? registerMaterialInputForItem() : registerMaterialInput() +``` + +**API 엔드포인트** (`react/src/components/production/WorkerScreen/actions.ts`) + +| 메서드 | 경로 | 함수명 | +|--------|------|--------| +| GET | `/api/v1/work-orders/{id}/materials` | getMaterialsForWorkOrder | +| GET | `/api/v1/work-orders/{id}/items/{itemId}/materials` | getMaterialsForItem | +| POST | `/api/v1/work-orders/{id}/material-inputs` | registerMaterialInput | +| POST | `/api/v1/work-orders/{id}/items/{itemId}/material-inputs` | registerMaterialInputForItem | +| GET | `/api/v1/work-orders/{id}/items/{itemId}/material-inputs` | getMaterialInputsForItem | +| DELETE | `/api/v1/work-orders/{id}/material-inputs/{inputId}` | deleteMaterialInput | +| PATCH | `/api/v1/work-orders/{id}/material-inputs/{inputId}` | updateMaterialInput | + +**절곡 유틸리티** (`react/.../documents/bending/utils.ts`) + +- `getSLengthCode(length, category)` — 길이→코드 변환 +- `getMaterialMapping(productCode, finishMaterial)` — 재질 매핑 +- `buildWallGuideRailRows()`, `buildSideGuideRailRows()`, `buildBottomBarRows()`, `buildShutterBoxRows()`, `buildSmokeBarrierRows()` — 각 섹션 파트 행 생성 (lotPrefix 포함) + +#### 1.6.6 LOT Prefix 전체 맵 (PrefixResolver 구현 기준) + +**가이드레일 벽면형 (Wall)** + +| 세부품목 | KSS01(SUS) | KSE01/KWE01(EGI마감) | KSE01/KWE01(SUS마감) | KTE01(철재) | +|---------|-----------|-------------------|-------------------|-----------| +| 마감재 | RS | RE | RE | RS | +| 본체 | RM | RM | RM | **RT** | +| C형 | RC | RC | RC | RC | +| D형 | RD | RD | RD | RD | +| 별도마감 | - | - | **YY** | - | +| 하부BASE | XX | XX | XX | XX | + +**가이드레일 측면형 (Side)** + +| 세부품목 | KSS01(SUS) | KSE01/KWE01(EGI마감) | KSE01/KWE01(SUS마감) | KTE01(철재) | +|---------|-----------|-------------------|-------------------|-----------| +| 마감재 | SS | SE | SE | SS | +| 본체 | SM | SM | SM | **ST** | +| C형 | SC | SC | SC | SC | +| D형 | SD | SD | SD | SD | +| 별도마감 | - | - | **YY** | - | +| 하부BASE | XX | XX | XX | XX | + +**하단마감재** + +| 세부품목 | EGI마감 | SUS마감 | 철재 | +|---------|--------|--------|------| +| 메인 | BE | BS | TS | +| L-Bar | LA | LA | LA | +| 보강평철 | HH | HH | HH | +| 별도마감 | - | YY | - | + +**셔터박스** (표준 500*380 사이즈만 개별 prefix) + +| 세부품목 | 표준 prefix | 비표준 prefix | +|---------|-----------|-------------| +| 전면부 | CF | XX | +| 린텔부 | CL | XX | +| 점검구 | CP | XX | +| 후면코너부 | CB | XX | +| 상부덮개 | XX | XX | +| 마구리 | XX | XX | + +**연기차단재**: W50, W80 모두 → GI + +#### 1.6.7 길이코드 매핑 (getSLengthCode) + +| 길이(mm) | 코드 | 비고 | +|---------|------|------| +| 1219 | 12 | 셔터박스 | +| 2438 | 24 | 셔터박스 | +| 3000 | 30 | 공통 | +| 3500 | 35 | 공통 | +| 4000 | 40 | 공통 | +| 4150 | 41 | 셔터박스 | +| 4200 | 42 | - | +| 4300 | 43 | 가이드레일 | +| 3000 | **53** | 연기차단재50 전용 | +| 4000 | **54** | 연기차단재50 전용 | +| 3000 | **83** | 연기차단재80 전용 | +| 4000 | **84** | 연기차단재80 전용 | + +**코드 생성 규칙**: `BD-{prefix}-{lengthCode}` → 예: `BD-RS-43` = 가이드레일 벽면 SUS 마감재 4300mm + +#### 1.6.8 BD-* 마스터 현황 (items 테이블, 총 148개) + +**A. 제품 마스터형 (58개)** — 부모 품목 (견적 BOM에 사용) +``` +BD-가이드레일-KSS01-SUS-120*70 등 (20개: 제품코드별) +BD-하단마감재-KSE01-EGI-60*40 등 (10개) +BD-케이스-500*380 등 (10개), BD-마구리-505*355 등 (10개) +BD-L-BAR-*, BD-보강평철-*, BD-연기차단재 (8개) +``` + +**B. LOT prefix형 (90개 등록, XX/YY/HH 미등록)** — 세부품목 (자재투입 대상) + +| prefix | 수량 | prefix | 수량 | prefix | 수량 | +|--------|:----:|--------|:----:|--------|:----:| +| BD-RS | 5 | BD-SS | 4 | BD-BE | 2 | +| BD-RM | 6 | BD-SM | 5 | BD-BS | 5 | +| BD-RC | 6 | BD-SC | 5 | BD-TS | 1 | +| BD-RD | 6 | BD-SD | 5 | BD-LA | 2 | +| BD-RT | 2 | BD-ST | 1 | BD-CF | 6 | +| | | BD-SU | 4 | BD-CL | 6 | +| | | | | BD-CP | 6 | +| | | | | BD-CB | 6 | +| | | | | BD-GI | 7 | + +**미등록**: BD-XX (하부BASE/셔터 상부/마구리), BD-YY (별도SUS마감), BD-HH (보강평철) → Phase 0.1에서 등록 + +#### 1.6.9 dynamic_bom JSON 목표 구조 + +`work_order_items.options.dynamic_bom` 에 저장: + +```json +[ + { + "child_item_id": 15812, + "child_item_code": "BD-RS-43", + "lot_prefix": "RS", + "part_type": "마감재", + "category": "guideRail", + "material_type": "SUS", + "length_mm": 4300, + "qty": 1 + }, + { + "child_item_id": 15809, + "child_item_code": "BD-RS-40", + "lot_prefix": "RS", + "part_type": "마감재", + "category": "guideRail", + "material_type": "SUS", + "length_mm": 4000, + "qty": 1 + }, + { + "child_item_id": 15826, + "child_item_code": "BD-RM-43", + "lot_prefix": "RM", + "part_type": "본체", + "category": "guideRail", + "material_type": "EGI", + "length_mm": 4300, + "qty": 1 + } +] +``` + +**필드 설명**: +- `child_item_id`: items 테이블 PK (getMaterials에서 Stock/StockLot 조회용) +- `child_item_code`: items.code (표시용) +- `lot_prefix`: LOT prefix (프론트 작업일지 매핑용) +- `part_type`: 세부품명 한글 (마감재, 본체, C형 등) +- `category`: 4대 카테고리 (guideRail, bottomBar, shutterBox, smokeBarrier) +- `material_type`: 재질 (SUS, EGI 등) +- `length_mm`: 표준 길이 (mm) +- `qty`: 수량 + +--- + +## 2. 대상 범위 + +### 2.1 Phase 0: 선행 준비 (마스터 데이터) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 0.1 | XX/YY/HH 미등록 품목 items 등록 | ✅ | 22건 등록 (13+9 추가 누락) | +| 0.2 | 마스터 데이터 검증 스크립트 작성 | ✅ | 101/101 전체 통과 | + +### 2.2 Phase 1: GAP #1 해결 — API 통일 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | registerMaterialInput → registerMaterialInputForItem 통일 | ✅ | work_order_item_id 분기 + fallback + N+1 수정 | +| 1.2 | 프론트 workOrderItemId 전달 보장 | ✅ | actions.ts + MaterialInputModal work_order_item_id 전달 | + +### 2.3 Phase 2: 방안 B 핵심 — dynamic_bom 생성 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | PrefixResolver 클래스 구현 | ✅ | `app/Services/Production/PrefixResolver.php` | +| 2.2 | BendingInfoBuilder 확장 — dynamic_bom 생성 | ✅ | `build()` 리턴 변경 + `buildDynamicBomForItem()` 추가, OrderService 연동 | +| 2.3 | DynamicBomEntry DTO 구현 | ✅ | `app/DTOs/Production/DynamicBomEntry.php` | + +### 2.4 Phase 3: getMaterials 연동 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | getMaterials() dynamic_bom 우선 체크 | ✅ | dynamic_bom → BOM fallback, (item_id, woItem_id) 쌍 합산, 추가 필드 반환 | +| 3.2 | N+1 쿼리 최적화 + uniqueMaterials 합산 단위 변경 | ✅ | 3.1에서 함께 해결: Item/Stock/StockLot 모두 배치 조회 | + +### 2.5 Phase 4: 프론트엔드 연동 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | 자재투입 모달 세부품목 단위 표시 | ✅ | MaterialInputModal groupKey + category badge + actions.ts 필드 추가 | +| 4.2 | 작업일지 LOT NO 표시 연동 | ✅ | 4개 섹션 lotNoMap prop + WorkLogModal lotNoMap 빌드 | + +### 2.6 Phase 5: 테스트 및 검증 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 5.1 | PrefixResolver + dynamic_bom 단위 테스트 | ✅ | 58 tests / 256 assertions 통과 | +| 5.2 | getMaterials → 자재투입 통합 테스트 | ✅ | 6 tests (4 pass + 2 skip — dynamic_bom 작업지시 미생성), 마스터 품목 전체 검증 | + +### 2.7 별도 과제 (이 계획 범위 밖) + +| # | 항목 | 시점 | +|---|------|------| +| X.1 | GAP #4: 수주 연결 생산완료 → stock_lots 입고 통일 | 출하 시스템 설계 시 | +| X.2 | GAP #3: lot_genealogy (투입↔산출 LOT 직접 연결) | 향후 고도화 | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Phase 0: 선행 준비 +├── 0.1 XX/YY/HH 품목 등록 (items 테이블 INSERT) +└── 0.2 검증 스크립트 (Artisan Command) + └── 19종 prefix × 7-12 lengthCode 조합 → items 존재 확인 + +Phase 1: API 통일 (GAP #1) — Phase 0 완료 후 +├── 1.1 registerMaterialInput() 내부에서 registerMaterialInputForItem() 호출하도록 통일 +│ ├── WorkOrderService.php L1330-1388 수정 +│ └── 기존 프론트 호출 호환성 유지 +└── 1.2 프론트 workOrderItemId 전달 + └── WorkerScreen/index.tsx → MaterialInputModal Props + +Phase 2: dynamic_bom 생성 — Phase 0 완료 후 (Phase 1과 병행 가능) +├── 2.1 PrefixResolver 클래스 +│ ├── productCode + finishMaterial + guideType → prefix 결정 +│ ├── prefix + lengthMm → BD-XX-NN 코드 생성 +│ └── BD-XX-NN → items.id 조회 (캐시) +├── 2.2 BendingInfoBuilder 확장 +│ ├── build() 반환값에 dynamic_bom 추가 +│ ├── bending_info와 동시 생성 (정합성 보장) +│ └── work_order_items.options.dynamic_bom에 저장 +└── 2.3 DynamicBomValidator + └── dynamic_bom JSON 구조 검증 (child_item_id 필수 등) + +Phase 3: getMaterials 수정 — Phase 2 완료 후 +├── 3.1 dynamic_bom 우선 체크 +│ ├── WorkOrderService.php getMaterials() L1198 이후 +│ ├── options.dynamic_bom 있으면 → 세부품목 리스트 사용 +│ └── 없으면 → 기존 item.bom fallback (하위 호환) +└── 3.2 N+1 최적화 + ├── Item::whereIn() 배치 조회 + └── uniqueMaterials 합산 단위: (item_id, work_order_item_id) 쌍 + +Phase 4: 프론트엔드 — Phase 3 완료 후 +├── 4.1 자재투입 모달 수정 +│ ├── materialGroups가 세부품목 단위로 표시 (이미 itemId 기준 그룹핑) +│ └── 그룹 헤더에 세부품목명(BD-RS-43) 표시 +└── 4.2 작업일지 LOT NO 표시 + ├── dynamic_bom에서 lotPrefix + lengthCode 조합 + └── 투입 이력(getMaterialInputsForItem)에서 실제 LOT NO 반영 + +Phase 5: 테스트 — Phase 3 완료 후 (Phase 4와 병행 가능) +├── 5.1 단위 테스트 +│ ├── PrefixResolver: 7종 productCode × 3종 finishMaterial × 3종 guideType +│ ├── dynamic_bom 생성: 실제 bom_result 데이터 기반 +│ └── DynamicBomValidator: 필수/선택 필드 검증 +└── 5.2 통합 테스트 + ├── 작업지시 생성 → dynamic_bom 저장 확인 + ├── getMaterials → 세부품목 반환 확인 + └── 자재투입 → stock_transactions + work_order_material_inputs 확인 +``` + +### 3.2 의존성 맵 + +``` +Phase 0 ──→ Phase 1 (독립 진행 가능) + │ + └──→ Phase 2 ──→ Phase 3 ──→ Phase 4 + │ + └──→ Phase 5 +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 0: 선행 준비 + +#### 0.1 XX/YY/HH 미등록 품목 등록 + +**현재 상태**: BD-* 품목 148개 중 XX(하부BASE), YY(별도SUS마감), HH(보강평철) 미등록 + +**목표 상태**: BD-XX-NN, BD-YY-NN, BD-HH-NN 패턴으로 items 테이블에 등록 + +**등록 대상**: + +| prefix | 설명 | 등록할 길이코드 | 예상 수량 | +|--------|------|---------------|----------| +| BD-XX | 하부BASE, 셔터박스 상부덮개/마구리 | 12, 24, 30, 35, 40, 41, 43 | 7개 | +| BD-YY | 별도 SUS 마감 (SUS마감 시만) | 30, 35, 40, 43 | 4개 | +| BD-HH | 보강평철 | 30, 40 | 2개 | + +**수정 파일**: 없음 (DB INSERT — Seeder 또는 Artisan Command) + +**생성 파일**: +- `api/database/seeders/BendingItemSeeder.php` — BD-XX/YY/HH 품목 등록 + +**검증**: `items` 테이블에서 `code LIKE 'BD-XX-%'` 조회로 13개 확인 + +--- + +#### 0.2 마스터 데이터 검증 스크립트 + +**목적**: 19종 prefix × 가능 lengthCode 전체 조합이 items에 존재하는지 확인 + +**생성 파일**: +- `api/app/Console/Commands/ValidateBendingItems.php` + +**로직**: +``` +전체 prefix 목록 정의 (RS, RM, RC, RD, RT, SS, SM, SC, SD, ST, SU, BE, BS, TS, LA, CF, CL, CP, CB, GI, XX, YY, HH) +각 prefix별 유효 lengthCode 정의 +조합별 items.code = "BD-{prefix}-{code}" 존재 확인 +누락 항목 리스트 출력 +``` + +**실행**: `php artisan bending:validate-items` + +**검증**: 출력이 "All items registered" (누락 0건) + +--- + +### 4.2 Phase 1: GAP #1 해결 — API 통일 + +#### 1.1 registerMaterialInput → registerMaterialInputForItem 통일 + +**현재 상태**: +- `registerMaterialInput()` (L1330): 재고 차감만, WorkOrderMaterialInput 레코드 미생성 +- `registerMaterialInputForItem()` (L2821): 재고 차감 + WorkOrderMaterialInput 레코드 생성 + +**목표 상태**: 모든 자재투입이 `work_order_material_inputs`에 기록 + +**수정 파일**: +- `api/app/Services/WorkOrderService.php` + +**수정 내용**: +``` +registerMaterialInput(int $workOrderId, array $inputs) 수정: + ├── $inputs 배열에 work_order_item_id 필드 추가 지원 + │ { stock_lot_id: N, qty: N, work_order_item_id?: N } + ├── work_order_item_id가 있으면 → registerMaterialInputForItem() 위임 + └── work_order_item_id가 없으면 → 기존 동작 + WorkOrderMaterialInput 레코드 생성 추가 + (work_order_item_id = 첫 번째 work_order_item의 id로 fallback) +``` + +**N+1 개선**: `registerMaterialInputForItem()` L2860-2861의 `StockLot::find()` → `$lot->stock->item_id` 호출을 `StockLot::with('stock')->find()` Eager Loading으로 변경 + +**검증**: +- POST `/work-orders/{id}/material-inputs` 호출 후 `work_order_material_inputs` 테이블에 레코드 존재 확인 +- 기존 호출 형식(work_order_item_id 미포함)도 정상 동작 확인 + +--- + +#### 1.2 프론트 workOrderItemId 전달 보장 + +**현재 상태**: `WorkerScreen/index.tsx`에서 `MaterialInputModal`에 `workOrderItemId` Props를 전달하지만, 완료 플로우에서는 미지정 가능 + +**수정 파일**: +- `react/src/components/production/WorkerScreen/index.tsx` + +**수정 내용**: +- 자재투입 모달 호출 시 `workOrderItemId`가 항상 전달되도록 보장 +- 완료 플로우에서도 `selectedItemId` 설정 + +**검증**: MaterialInputModal이 항상 `registerMaterialInputForItem()` 경로로 호출되는지 확인 + +--- + +### 4.3 Phase 2: 방안 B 핵심 — dynamic_bom 생성 + +#### 2.1 PrefixResolver 클래스 구현 + +**목적**: 제품코드 + 마감재질 + 가이드타입 → LOT prefix 결정 로직을 단일 클래스로 집중 + +**생성 파일**: +- `api/app/Services/Production/PrefixResolver.php` + +**클래스 구조**: +```php +class PrefixResolver +{ + // 벽면형 prefix 맵 + private const WALL_PREFIXES = [ + 'finish' => ['KSS' => 'RS', 'KSE' => 'RE', 'KWE' => 'RE'], + 'body' => 'RM', + 'c_type' => 'RC', + 'd_type' => 'RD', + 'extra_finish' => 'YY', // SUS 마감 시만 + 'base' => 'XX', + ]; + + // 측면형 prefix 맵 + private const SIDE_PREFIXES = [ + 'finish' => ['KSS' => 'SS', 'KSE' => 'SE', 'KWE' => 'SE'], + 'body' => 'SM', + 'c_type' => 'SC', + 'd_type' => 'SD', + 'extra_finish' => 'YY', + 'base' => 'XX', + ]; + + // 철재형 override + private const STEEL_OVERRIDES = [ + 'wall_body' => 'RT', + 'side_body' => 'ST', + ]; + + // 하단마감재 prefix 맵 + private const BOTTOM_BAR_PREFIXES = [ + 'EGI' => 'BE', + 'SUS' => 'BS', + 'STEEL_SUS' => 'TS', + ]; + + // 셔터박스 prefix 맵 (표준 사이즈만) + private const SHUTTER_BOX_PREFIXES = [ + 'front' => 'CF', + 'lintel' => 'CL', + 'inspection' => 'CP', + 'rear_corner' => 'CB', + 'top_cover' => 'XX', + 'fin_cover' => 'XX', + ]; + + // 연기차단재 + private const SMOKE_PREFIXES = [ + 'w50' => 'GI', + 'w80' => 'GI', + ]; + + /** + * 가이드레일 세부품목의 prefix 결정 + */ + public function resolveGuideRailPrefix( + string $partType, // 'finish', 'body', 'c_type', 'd_type', 'extra_finish', 'base' + string $guideType, // 'wall', 'side' + string $productCode, // 'KSS01', 'KSE01', ... + ): string + + /** + * 하단마감재 세부품목의 prefix 결정 + */ + public function resolveBottomBarPrefix( + string $partType, // 'main', 'lbar', 'reinforce', 'extra' + string $finishMaterial, // 'EGI 1.55T', 'SUS 1.2T' + string $productCode, + ): string + + /** + * 셔터박스 세부품목의 prefix 결정 + */ + public function resolveShutterBoxPrefix( + string $partType, // 'front', 'lintel', 'inspection', 'rear_corner', 'top_cover', 'fin_cover' + bool $isStandardSize, // 500*380인지 + ): string + + /** + * 연기차단재 세부품목의 prefix 결정 + */ + public function resolveSmokeBarrierPrefix(string $partType): string + + /** + * prefix + 길이(mm) → BD-XX-NN 코드 생성 + */ + public function buildItemCode(string $prefix, int $lengthMm, ?string $smokeCategory = null): string + + /** + * BD-XX-NN 코드 → items.id 조회 (캐시 사용) + */ + public function resolveItemId(string $itemCode): ?int + + /** + * 길이(mm) → 길이코드 변환 (getSLengthCode 동일) + */ + public static function lengthToCode(int $lengthMm, ?string $smokeCategory = null): ?string +} +``` + +**의존성**: `App\Models\Items\Item` (코드→ID 조회용) + +**검증**: 단위 테스트에서 productCode × guideType × partType 전 조합 테스트 + +--- + +#### 2.2 BendingInfoBuilder 확장 — dynamic_bom 생성 + +**수정 파일**: +- `api/app/Services/Production/BendingInfoBuilder.php` + +**수정 범위**: + +1. **build() 메서드 (L29-69)**: 반환값에 `dynamic_bom` 배열 추가 + ``` + 현재: return assembleBendingInfo(...) // bending_info만 + 변경: return [ + 'bending_info' => assembleBendingInfo(...), + 'dynamic_bom' => buildDynamicBom(...) // 신규 + ] + ``` + +2. **buildDynamicBom() 신규 메서드**: bending_info 생성과 동일한 길이 버킷팅 결과를 사용 + ``` + private function buildDynamicBom( + array $aggregated, // aggregateNodes() 결과 + string $productCode, + array $materials, // getMaterialMapping() 결과 + PrefixResolver $resolver, + ): array + ``` + + **로직**: + ``` + dynamic_bom = [] + + // 1. 가이드레일 세부품목 + for each guideType (wall, side): + lengthData = heightLengthData(dimGroups) // 기존 버킷팅 재사용 + for each (length, qty) in lengthData: + for each partType in [finish, body, c_type, d_type, extra_finish, base]: + prefix = resolver.resolveGuideRailPrefix(partType, guideType, productCode) + if prefix is empty: skip + itemCode = resolver.buildItemCode(prefix, length) + itemId = resolver.resolveItemId(itemCode) + dynamic_bom[] = { + child_item_id: itemId, + child_item_code: itemCode, + lot_prefix: prefix, + part_type: partType의 한글명, + category: 'guideRail', + material_type: materials[partType], + length_mm: length, + qty: qty + } + + // 2. 하단마감재 세부품목 + for each dimGroup: + [qty3000, qty4000] = bottomBarDistribution(openWidth) + for each (length, qty) in [(3000, qty3000), (4000, qty4000)]: + if qty == 0: skip + for each partType in [main, lbar, reinforce, extra]: + prefix = resolver.resolveBottomBarPrefix(partType, finishMaterial, productCode) + ... dynamic_bom 추가 ... + + // 3. 셔터박스 세부품목 + for each dimGroup: + distribution = shutterBoxDistribution(openWidth) + for each (length, qty) in distribution: + if qty == 0: skip + isStandard = (boxSize == '500*380') + for each partType in [front, lintel, inspection, rear_corner, top_cover, fin_cover]: + prefix = resolver.resolveShutterBoxPrefix(partType, isStandard) + ... dynamic_bom 추가 ... + + // 4. 연기차단재 세부품목 + for each smokeType (w50, w80): + for each (length, qty) in smokeLengthData: + prefix = resolver.resolveSmokeBarrierPrefix(smokeType) + smokeCategory = smokeType == 'w50' ? '연기차단재50' : '연기차단재80' + itemCode = resolver.buildItemCode(prefix, length, smokeCategory) + ... dynamic_bom 추가 ... + + return dynamic_bom + ``` + +3. **work_order_items.options 저장 위치 수정**: + - `WorkOrderService.php` L275-306 (작업지시 품목 복사 로직)에서 build() 반환값의 `dynamic_bom`을 `options.dynamic_bom`에 저장 + +**주의사항**: +- `aggregateNodes()` L164의 `!isset` 체크: 첫 노드에서만 BOM 메타 추출 → 노드별 BOM이 다를 수 있으므로 주의 +- `bucketToStandardLength()` L862-864: 표준 길이 초과 시 원본 반환 → PrefixResolver.resolveItemId()에서 null 반환 시 경고 로그 + fallback +- 혼합형 가이드레일: wall + side 각각 독립 dynamic_bom 생성 + +**검증**: +- 작업지시 생성 API 호출 후 `work_order_items.options` JSON에 `dynamic_bom` 배열 존재 확인 +- dynamic_bom의 각 항목에 `child_item_id`가 NOT NULL인지 확인 +- bending_info의 lengthData와 dynamic_bom의 length_mm/qty가 일치하는지 확인 + +--- + +#### 2.3 DynamicBomValidator DTO 구현 + +**생성 파일**: +- `api/app/DTOs/Production/DynamicBomEntry.php` + +**구조**: +```php +class DynamicBomEntry +{ + public function __construct( + public readonly int $child_item_id, + public readonly string $child_item_code, + public readonly string $lot_prefix, + public readonly string $part_type, + public readonly string $category, // guideRail, bottomBar, shutterBox, smokeBarrier + public readonly string $material_type, + public readonly int $length_mm, + public readonly int|float $qty, + ) {} + + public static function fromArray(array $data): self + public function toArray(): array + public static function validate(array $data): bool // child_item_id 필수 등 +} +``` + +**검증**: 단위 테스트에서 필수 필드 누락 시 예외 발생 확인 + +--- + +### 4.4 Phase 3: getMaterials 연동 + +#### 3.1 getMaterials() dynamic_bom 우선 체크 + +**수정 파일**: +- `api/app/Services/WorkOrderService.php` + +**수정 위치**: `getMaterials()` L1198 이후 + +**수정 내용**: +``` +현재 (L1198-1238): + foreach (workOrderItems as woItem): + item = woItem.item + if (item.bom): + ... BOM 순회 ... + else: + ... item 자체를 자재로 ... + +변경: + // Phase 1: dynamic_bom 대상 item_id 일괄 수집 + allDynamicItemIds = [] + foreach (workOrderItems as woItem): + dynamicBom = woItem.options['dynamic_bom'] ?? null + if (dynamicBom): + allDynamicItemIds += array_column(dynamicBom, 'child_item_id') + + // Phase 2: 배치 조회 (N+1 방지) + dynamicItems = Item::whereIn('id', array_unique(allDynamicItemIds)) + ->get()->keyBy('id') + + // Phase 3: 유니크 자재 수집 + foreach (workOrderItems as woItem): + dynamicBom = woItem.options['dynamic_bom'] ?? null + if (dynamicBom): + foreach (dynamicBom as bomEntry): + childItem = dynamicItems[bomEntry['child_item_id']] + // 합산 키: (item_id, work_order_item_id) 쌍 + key = bomEntry['child_item_id'] . '_' . woItem.id + uniqueMaterials[key] = { + item_id: bomEntry['child_item_id'], + work_order_item_id: woItem.id, + bom_qty: bomEntry['qty'], + item: childItem, + ... + } + elseif (item.bom): + ... 기존 BOM 로직 (하위 호환) ... + else: + ... 기존 fallback ... +``` + +**반환 형식 변경**: +``` +기존: { stock_lot_id, item_id, lot_no, bom_qty, required_qty, ... } +추가: { ..., work_order_item_id, lot_prefix, part_type, category } +``` + +**검증**: +- dynamic_bom 있는 work_order → 세부품목(BD-RS-43 등) 반환 확인 +- dynamic_bom 없는 work_order → 기존 동작 그대로 (하위 호환) +- 동일 item_id가 다른 work_order_item에 속한 경우 별도 행으로 반환 + +--- + +#### 3.2 N+1 쿼리 최적화 + uniqueMaterials 합산 단위 변경 + +**수정 파일**: `api/app/Services/WorkOrderService.php` + +**수정 내용**: +1. `Item::find()` 개별 호출 → `Item::whereIn()` 배치 조회 +2. `uniqueMaterials` 합산 키를 `item_id` → `(item_id, work_order_item_id)` 쌍으로 변경 +3. StockLot 조회도 `Stock::whereIn()` 배치 처리 + +**기대 효과**: 쿼리 수 30-50회 → 3-5회로 감소 + +**검증**: Laravel Debugbar 또는 DB 쿼리 로그로 쿼리 수 확인 + +--- + +### 4.5 Phase 4: 프론트엔드 연동 + +#### 4.1 자재투입 모달 세부품목 단위 표시 + +**수정 파일**: +- `react/src/components/production/WorkerScreen/MaterialInputModal.tsx` + +**현재 상태**: `materialGroups`가 `itemId` 기준 그룹핑 (L102-119). getMaterials 응답이 세부품목을 반환하면 자동으로 세부품목 단위 그룹핑됨. + +**수정 내용**: +- 그룹 헤더에 세부품목명(BD-RS-43 등) + part_type(마감재 등) + category(가이드레일 등) 표시 +- 기존 `materialCode`/`materialName` 필드로 충분하나, 카테고리별 시각적 구분 추가 + +**수정 규모**: 소규모 — 그룹 헤더 렌더링 수정 + +**검증**: 자재투입 모달에서 세부품목별 그룹이 표시되고, 각 그룹 내 LOT 선택이 정상 동작 + +--- + +#### 4.2 작업일지 LOT NO 표시 연동 + +**수정 파일**: +- `react/src/components/production/WorkOrders/documents/bending/GuideRailSection.tsx` +- 해당 폴더의 다른 Section 컴포넌트 (BottomBarSection, ShutterBoxSection 등) + +**현재 상태**: LOT NO 컬럼이 `"-"`로 하드코딩 + +**수정 내용**: +- `getMaterialInputsForItem()` API로 투입 이력 조회 +- lotPrefix + lengthCode 매칭으로 실제 LOT NO 표시 +- 투입 전이면 "-", 투입 후이면 실제 LOT 번호 + +**수정 규모**: 중규모 — 각 Section 컴포넌트에 LOT 조회 로직 추가 + +**검증**: 자재투입 완료 후 작업일지에 실제 LOT NO 표시 + +--- + +### 4.6 Phase 5: 테스트 및 검증 + +#### 5.1 단위 테스트 + +**생성 파일**: +- `api/tests/Unit/Services/Production/PrefixResolverTest.php` +- `api/tests/Unit/Services/Production/BendingInfoBuilderDynamicBomTest.php` + +**테스트 케이스**: + +| 테스트 | 입력 | 기대 결과 | +|--------|------|----------| +| KSS01 벽면형 마감재 4300mm | ('finish', 'wall', 'KSS01') | prefix='RS', code='BD-RS-43' | +| KSE01 측면형 본체 3000mm | ('body', 'side', 'KSE01') | prefix='SM', code='BD-SM-30' | +| KTE01 벽면형 본체 (철재) | ('body', 'wall', 'KTE01') | prefix='RT' | +| 하단마감재 EGI | ('main', 'EGI 1.55T', 'KSE01') | prefix='BE' | +| 셔터박스 비표준 사이즈 | ('front', false) | prefix='XX' | +| 연기차단재 W50 3000mm | resolveSmokeBarrierPrefix('w50') | prefix='GI', code='BD-GI-53' | +| 표준 길이 초과 (4500mm) | buildItemCode('RS', 4500) | 경고 로그 + null 반환 | + +--- + +#### 5.2 통합 테스트 + +**생성 파일**: +- `api/tests/Feature/Production/BendingMaterialInputFlowTest.php` + +**테스트 시나리오**: + +``` +1. 작업지시 생성 → dynamic_bom 저장 확인 + - Order (KSS01, SUS마감, 오픈높이=4300, 오픈폭=3000) + - 작업지시 생성 → work_order_items.options.dynamic_bom 확인 + - dynamic_bom에 RS-43, RM-43, RC-43, RD-43 세부품목 존재 + +2. getMaterials → 세부품목 반환 확인 + - getMaterials(workOrderId) 호출 + - 응답에 BD-RS-43, BD-RM-43 등 세부품목 반환 + - 각 세부품목의 StockLot 정보 포함 + +3. 자재투입 → 이력 기록 확인 + - registerMaterialInputForItem() 호출 + - stock_transactions에 OUT 기록 + - work_order_material_inputs에 레코드 생성 + - stock_lots.available_qty 감소 +``` + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | registerMaterialInput API 통일 | 기존 API에 WorkOrderMaterialInput 레코드 생성 추가 | 프론트 호출 호환 유지 | ⏳ | +| 2 | BendingInfoBuilder.build() 반환값 변경 | 기존 array → { bending_info, dynamic_bom } | WorkOrderService 호출처 수정 필요 | ⏳ | +| 3 | getMaterials() 로직 변경 | dynamic_bom 우선 체크 + 합산 단위 변경 | MaterialInputModal 응답 형식 변경 | ⏳ | + +--- + +## 6. 변경 이력 + +| 날짜 | 변경 내용 | +|------|----------| +| 2026-02-22 | 문서 초안 작성 | +| 2026-02-22 | Phase 0 완료: BD-* 22건 등록 + 검증 101/101 통과 | +| 2026-02-22 | Phase 2 완료: PrefixResolver, BendingInfoBuilder 확장(build→context+bending_info, buildDynamicBomForItem), DynamicBomEntry DTO, OrderService 연동 | +| 2026-02-22 | Phase 1.1 + 3.1/3.2 완료: registerMaterialInput 통일 (work_order_item_id 분기+fallback+WorkOrderMaterialInput 레코드 생성), getMaterials dynamic_bom 우선체크 + N+1 배치최적화 | + +--- + +## 7. 참고 문서 + +| 문서 | 경로 | +|------|------| +| **분석 기준 문서** | `docs/plans/bending-material-input-mapping-plan.md` | +| 선생산 재고 계획 | `docs/plans/bending-preproduction-stock-plan.md` | +| BendingInfoBuilder | `api/app/Services/Production/BendingInfoBuilder.php` | +| WorkOrderService | `api/app/Services/WorkOrderService.php` | +| StockService | `api/app/Services/StockService.php` | +| WorkOrderMaterialInput 모델 | `api/app/Models/Production/WorkOrderMaterialInput.php` | +| MaterialInputModal | `react/src/components/production/WorkerScreen/MaterialInputModal.tsx` | +| WorkerScreen actions | `react/src/components/production/WorkerScreen/actions.ts` | +| Bending types/utils | `react/src/components/production/WorkOrders/documents/bending/` | +| API 개발 규칙 | `docs/standards/api-rules.md` | +| 품질 체크리스트 | `docs/standards/quality-checklist.md` | + +--- + +## 8. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 8.1 세션 시작 시 (Load Strategy) +```javascript +read_memory("bending-lot-pipeline-state") // 1. 상태 파악 +read_memory("bending-lot-pipeline-snapshot") // 2. 사고 흐름 복구 +read_memory("bending-lot-pipeline-active-symbols") // 3. 작업 대상 파악 +``` + +### 8.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | Snapshot | `write_memory("bending-lot-pipeline-snapshot", "코드변경+논의요약")` | +| **20% 이하** | Context Purge | `write_memory("bending-lot-pipeline-active-symbols", "주요 수정 파일/함수")` | +| **10% 이하** | Stop & Save | 최종 상태 저장 후 세션 교체 권고 | + +### 8.3 Serena 메모리 구조 +- `bending-lot-pipeline-state`: { phase, progress, next_step, last_decision } +- `bending-lot-pipeline-snapshot`: 현재까지의 논의 및 코드 변경점 요약 +- `bending-lot-pipeline-rules`: 해당 작업에서 결정된 불변의 규칙들 +- `bending-lot-pipeline-active-symbols`: 현재 수정 중인 파일/심볼 리스트 + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| KSS01 + SUS + 벽면형 + 4300mm | BD-RS-43 (item_id 존재) | | ⏳ | +| getMaterials (dynamic_bom 있는 WO) | 세부품목 리스트 반환 | | ⏳ | +| 자재투입 등록 | work_order_material_inputs 레코드 생성 | | ⏳ | +| getMaterials (dynamic_bom 없는 WO) | 기존 동작 (하위 호환) | | ⏳ | + +### 9.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|:----:|------| +| dynamic_bom 자동 생성 | ⏳ | Phase 2 완료 후 | +| getMaterials 세부품목 반환 | ⏳ | Phase 3 완료 후 | +| 세부품목별 LOT 입력 가능 | ⏳ | Phase 4 완료 후 | +| 자재투입 이력 100% 기록 | ⏳ | Phase 1 완료 후 | +| LOT prefix 체계 일치 | ⏳ | Phase 0.2 검증 후 | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 1.5 성공 기준 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 2 대상 범위 (13개 태스크) | +| 4 | 의존성이 명시되어 있는가? | ✅ | 3.2 의존성 맵 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 코드 분석 기반 확인 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 4 상세 작업 내용 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 각 태스크별 검증 항목 | +| 8 | 모호한 표현이 없는가? | ✅ | 라인 번호, 메서드명, 파일 경로 명시 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 2.1 Phase 0 + 📍 현재 진행 상태 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 섹션 4 (각 태스크별 수정/생성 파일 명시) | +| Q4. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 + 각 태스크별 검증 항목 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* diff --git a/plans/archive/bending-worklog-reimplementation-plan.md b/plans/archive/bending-worklog-reimplementation-plan.md new file mode 100644 index 0000000..1da3252 --- /dev/null +++ b/plans/archive/bending-worklog-reimplementation-plan.md @@ -0,0 +1,860 @@ +# 절곡 작업일지 완전 재구현 계획 + +> **작성일**: 2026-02-19 +> **목적**: PHP viewBendingWork_slat.php와 동일한 구조로 React BendingWorkLogContent.tsx 완전 재구현 +> **기준 문서**: `5130/output/viewBendingWork_slat.php` (~1400줄) +> **상태**: ✅ 구현 완료 (커밋: 59b9b1b) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 1~5 전체 구현 완료 + 슬랫 입고 LOT NO 개소별 표시 버그 수정 | +| **다음 작업** | 실 데이터 테스트 (bending_info가 채워진 작업지시로 화면 확인) | +| **진행률** | 15/15 (100%) | +| **마지막 업데이트** | 2026-02-19 | +| **Git 커밋** | `59b9b1b` feat(WEB): 절곡 작업일지 완전 재구현 + 슬랫 입고 LOT NO 개소별 표시 수정 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 React `BendingWorkLogContent.tsx`는 **빈 껍데기 상태**로, 단순 테이블에 `item.productName`, `item.specification`, `item.quantity`만 평면 나열함. PHP 원본(`viewBendingWork_slat.php`)의 4개 카테고리 구조를 전혀 지원하지 않음. + +**현재 React 컴포넌트 상태:** +- 헤더 + 결재란 (ConstructionApprovalTable 사용) ✅ +- 신청업체 / 신청내용 테이블 ✅ +- 제품 정보 테이블 (빈 칸) ❌ 데이터 바인딩 없음 +- 작업내역 (유형명/세부품명/재질/LOT/길이/수량) ❌ 단순 flat 리스트 +- 생산량 합계 [kg] SUS/EGI ❌ 빈 칸 +- **4개 카테고리 섹션 완전 부재** ❌ + +**PHP 원본 구조 (구현 목표):** +- 가이드레일: 벽면형/측면형 분류, 이미지 + 세부품명별 길이/수량/LOT NO/무게 계산 +- 하단마감재: 3000/4000mm 길이별 수량, 별도마감재 +- 셔터박스: 동적 이미지 + 구성요소(전면부/린텔부/점검구/후면코너부/상부덮개/측면부) +- 연기차단재: W50 레일용, W80 케이스용 +- 생산량 합계: SUS(7.93g/cm3) / EGI(7.85g/cm3) 무게 자동 계산 + +### 1.2 데이터 흐름 (전체 파이프라인) + +``` +[수주 시스템] +order_nodes.options.bending_info (JSON) + │ + ▼ WorkOrderService.php (Line 276) + │ $nodeOptions['bending_info'] ?? null + │ + ▼ +work_order_items.options (JSON) + │ { floor, code, width, height, bending_info, slat_info, cutting_info, wip_info } + │ + ▼ API GET /work-orders/{id} → items[].options.bending_info + │ + ▼ Frontend getWorkOrderById() → WorkOrder.items + │ + ▼ WorkLogModal.tsx (Line 207-213) + │ + │ ※ materialLots 미전달 (bending은 slat과 다르게 LOT를 별도로 안 받음) + │ + ▼ BendingWorkLogContent.tsx (재작성 대상) +``` + +**핵심**: `bending_info`는 `work_order_items.options` JSON 안에 저장되며, 현재 프론트엔드 `WorkOrderItem` 타입에는 `bendingInfo` 필드가 **없음** (slatInfo처럼 추가 필요). + +### 1.3 현재 bending_info 구조 (SAM에 정의된 것) + +```typescript +// react/src/components/production/WorkerScreen/types.ts (Lines 91-107) +export interface BendingInfo { + drawingUrl?: string; + common: BendingCommonInfo; + detailParts: BendingDetailPart[]; +} + +export interface BendingCommonInfo { + kind: string; // "혼합형 120X70" + type: string; // "혼합형" | "벽면형" | "측면형" + lengthQuantities: { length: number; quantity: number }[]; +} + +export interface BendingDetailPart { + partName: string; // "엘바", "하장바" + material: string; // "EGI 1.6T" + barcyInfo: string; // "16 I 75" +} +``` + +### 1.4 현재 WorkOrderItem 타입 (types.ts Lines 106-120) + +```typescript +// react/src/components/production/WorkOrders/types.ts +export interface WorkOrderItem { + id: string; + no: number; + status: ItemStatus; + productName: string; + floorCode: string; + specification: string; + width?: number; + height?: number; + quantity: number; + unit: string; + orderNodeId: number | null; + orderNodeName: string; + slatInfo?: { length: number; slatCount: number; jointBar: number; glassQty: number }; + // ❌ bendingInfo 없음 → 추가 필요 +} +``` + +**transform 함수** (types.ts Lines 457-474): `slatInfo`는 `item.options.slat_info`에서 파싱하지만, `bending_info`는 아직 매핑하지 않음. + +### 1.5 PHP col → SAM 매핑 (완전 테이블) + +PHP에서 데이터는 `estimateSlatList` JSON의 각 아이템에 `col{N}` 키로 저장됨. + +| PHP 컬럼 | 의미 | SAM bending_info 필드 | 상태 | +|---------|------|----------------------|------| +| `col4` | 제품코드 (KQTS01, KTE01 등) | `productCode` | ⚠️ item_code로 별도 존재, bending_info에도 추가 | +| `col6` | 가이드레일 유형 | `common.type` | ✅ 존재 | +| `col7` | 마감유형 (SUS마감/EGI마감) | `finishMaterial` | ❌ 추가 필요 | +| `col24` | 유효 길이 (mm) | `common.lengthQuantities` | ✅ 존재 | +| `col32` | 연기차단재 W50 수량 - 2438mm | `smokeBarrier.w50[].quantity` | ❌ 추가 필요 | +| `col33` | 연기차단재 W50 수량 - 3000mm | 상동 | ❌ | +| `col34` | 연기차단재 W50 수량 - 3500mm | 상동 | ❌ | +| `col35` | 연기차단재 W50 수량 - 4000mm | 상동 | ❌ | +| `col36` | 연기차단재 W50 수량 - 4300mm | 상동 | ❌ | +| `col37` | 셔터박스 크기 (500*380 등) | `shutterBox[].size` | ❌ 추가 필요 | +| `col37_custom` | 셔터박스 커스텀 크기 | `shutterBox[].size` (custom일 때) | ❌ | +| `col37_railwidth` | 셔터박스 레일 폭 | `shutterBox[].railWidth` | ❌ | +| `col37_frontbottom` | 셔터박스 전면 하단 치수 | `shutterBox[].frontBottom` | ❌ | +| `col37_boxdirection` | 셔터박스 방향 (양면/밑면/후면) | `shutterBox[].direction` | ❌ | +| `col39` | 셔터박스 수량 - 1219mm | `shutterBox[].lengthData` | ❌ | +| `col40` | 셔터박스 수량 - 2438mm | 상동 | ❌ | +| `col41` | 셔터박스 수량 - 3000mm | 상동 | ❌ | +| `col42` | 셔터박스 수량 - 3500mm | 상동 | ❌ | +| `col43` | 셔터박스 수량 - 4000mm | 상동 | ❌ | +| `col44` | 셔터박스 수량 - 4150mm | 상동 | ❌ | +| `col45` | 상부덮개 수량 | `shutterBox[].coverQty` | ❌ | +| `col47` | 마구리 수량 | `shutterBox[].finCoverQty` | ❌ | +| `col48` | 연기차단재 W80 수량 | `smokeBarrier.w80Qty` | ❌ | +| `col50` | 하단마감재 3000mm 수량 | `bottomBar.length3000Qty` | ❌ | +| `col51` | 하단마감재 4000mm 수량 | `bottomBar.length4000Qty` | ❌ | + +### 1.6 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - options JSON 확장 (컬럼 추가 금지 - 멀티테넌시 원칙) │ +│ - PHP 원본과 동일한 계산 로직 (calWeight, 길이 버킷팅) │ +│ - 이미지는 정적 파일로 서빙 (셔터박스만 SVG/Canvas 대체) │ +│ - 카테고리별 독립 컴포넌트 (가이드레일/하단마감/셔터박스/연기차단재)│ +│ - 현재 WorkOrderItem에 bendingInfo 필드 추가 (slatInfo 패턴) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.7 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | React 컴포넌트 추가/수정, 타입 정의 추가, 이미지 복사 | 불필요 | +| ⚠️ 컨펌 필요 | bending_info JSON 스키마 변경, API 응답 구조 변경, 계산 로직 변경 | **필수** | +| 🔴 금지 | work_order_items 테이블 컬럼 추가, 기존 API 삭제 | 별도 협의 | + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: 데이터 스키마 확장 (백엔드) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | bending_info JSON 스키마 확장 설계 | ✅ | BendingInfoExtended 타입 정의 완료 | +| 1.2 | WorkOrderService.php - options 매핑 확인/수정 | ✅ | Line 277에서 bending_info 정상 전달 확인 | +| 1.3 | API 응답에 확장된 bending_info 포함 확인 | ✅ | transform 함수에 bendingInfo 매핑 추가 완료 | + +### 2.2 Phase 2: 이미지 서빙 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | 5130/img/ → api/public/images/bending/ 복사 | ✅ | guiderail(12) + bottombar(6) + part(1) + box source(3) = 22개 | +| 2.2 | 이미지 URL 빌더 유틸 (프론트) | ✅ | bending/utils.ts getBendingImageUrl() | + +### 2.3 Phase 3: 프론트엔드 타입 & 유틸리티 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | BendingWorkLog 타입 정의 확장 | ✅ | bending/types.ts + WorkOrderItem.bendingInfo 추가 | +| 3.2 | 무게 계산 유틸리티 (`calcWeight`) | ✅ | bending/utils.ts (calcWeight, getMaterialMapping 등 11개 함수) | +| 3.3 | WorkOrderItem transform에 bendingInfo 매핑 추가 | ✅ | item.options.bending_info → bendingInfo | + +### 2.4 Phase 4: 프론트엔드 컴포넌트 구현 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | GuideRailSection 컴포넌트 | ✅ | 벽면형/측면형 분류, 이미지+파트테이블 | +| 4.2 | BottomBarSection 컴포넌트 | ✅ | 하단마감재 + 별도마감재 | +| 4.3 | ShutterBoxSection 컴포넌트 | ✅ | 방향별(양면/밑면/후면) 구성요소, source 이미지 | +| 4.4 | SmokeBarrierSection 컴포넌트 | ✅ | W50 레일용 + W80 케이스용 | +| 4.5 | ProductionSummarySection 컴포넌트 | ✅ | SUS/EGI/합계 표시 | +| 4.6 | BendingWorkLogContent 통합 | ✅ | 헤더 + 신청업체/내용 + 제품정보 + 4섹션 + 합계 + 비고 | + +### 2.5 Phase 5: 검증 & 정리 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 5.1 | PHP 원본과 출력 비교 검증 | ✅ | TypeScript 타입 체크 통과, 실 데이터 테스트 대기 | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Phase 1: 데이터 스키마 확장 (백엔드) +├── 1.1 bending_info 확장 스키마 설계 +│ ├── guideRail: { wall, side } (길이 버킷팅 + 수량 + baseSize) +│ ├── bottomBar: { material, extraFinish, length3000Qty, length4000Qty } +│ ├── shutterBox: [{ size, direction, railWidth, frontBottom, coverQty, finCoverQty, lengthData }] +│ └── smokeBarrier: { w50: [...], w80Qty } +├── 1.2 WorkOrderService.php 매핑 확인 (Line 276) +└── 1.3 API 응답 검증 (curl로 직접 확인) + +Phase 2: 이미지 서빙 +├── 2.1 정적 이미지 복사 (guiderail 12jpg + bottombar 6jpg + part 1jpg = 19개) +└── 2.2 이미지 URL 헬퍼 유틸 + +Phase 3: 프론트엔드 타입 & 유틸 +├── 3.1 타입 정의 (bending/types.ts 신규 + WorkOrderItem.bendingInfo 추가) +├── 3.2 calcWeight + getMaterialMapping 유틸 (bending/utils.ts) +└── 3.3 transform 함수에 bendingInfo 매핑 추가 (slatInfo 패턴 동일) + +Phase 4: 컴포넌트 구현 +├── 4.1 GuideRailSection (가장 복잡 - 벽면/측면 분리, 파트 구성, 무게 계산) +├── 4.2 BottomBarSection (3000/4000 수량, 별도마감) +├── 4.3 ShutterBoxSection (방향별 구성요소, SVG 다이어그램) +├── 4.4 SmokeBarrierSection (W50 길이별 + W80 고정) +├── 4.5 ProductionSummarySection (SUS/EGI 누적 합계) +└── 4.6 BendingWorkLogContent 통합 (헤더+신청+4섹션+합계 조립) + +Phase 5: 검증 +└── 5.1 PHP 원본과 비교 (num=24822) +``` + +--- + +## 4. 상세 작업 내용 (PHP 로직 완전 인라인) + +### 4.1 Phase 1: bending_info 확장 스키마 + +#### 1.1 확장된 bending_info JSON 구조 + +```typescript +interface BendingInfoExtended { + // === 기존 필드 (유지) === + drawingUrl?: string; + common: BendingCommonInfo; // { kind, type, lengthQuantities } + detailParts: BendingDetailPart[]; // [{ partName, material, barcyInfo }] + + // === 신규 필드 === + productCode: string; // "KTE01", "KQTS01", "KSE01", "KSS01", "KWE01" + finishMaterial: string; // "EGI마감", "SUS마감" + + guideRail: { + wall: { + lengthData: { length: number; quantity: number }[]; + baseSize: string; // "135*80" 또는 "135*130" + } | null; + side: { + lengthData: { length: number; quantity: number }[]; + baseSize: string; // "135*130" + } | null; + }; + + bottomBar: { + material: string; // "EGI 1.55T" 또는 "SUS 1.5T" + extraFinish: string; // "SUS 1.2T" 또는 "없음" + length3000Qty: number; + length4000Qty: number; + }; + + shutterBox: { + size: string; // "500*380" 등 + direction: string; // "양면" | "밑면" | "후면" + railWidth: number; + frontBottom: number; + coverQty: number; // 상부덮개 수량 + finCoverQty: number; // 마구리 수량 + lengthData: { length: number; quantity: number }[]; + }[]; // 배열 (여러 사이즈 가능) + + smokeBarrier: { + w50: { length: number; quantity: number }[]; // 레일용 W50 + w80Qty: number; // 케이스용 W80 수량 + }; +} +``` + +#### 1.2 calWeight 함수 (PHP 원본 Lines 27-55 → TypeScript 구현) + +```typescript +// PHP 원본: +// $volume_cm3 = ($thickness * $calWidth * $calHeight) / 1000; +// $weight_kg = ($volume_cm3 * $density) / 1000; +// SUS → $SUS_total += $weight_kg, EGI → $EGI_total += $weight_kg + +function calcWeight( + material: string, // "SUS 1.2T", "EGI 1.55T", "EGI 0.8T" 등 + width: number, // mm + height: number // mm (= 길이) +): { weight: number; type: 'SUS' | 'EGI' } { + const thickness = parseFloat(material.match(/\d+(\.\d+)?/)?.[0] || '0'); + const isSUS = material.includes('SUS'); + const density = isSUS ? 7.93 : 7.85; // g/cm3 + const volume_cm3 = (thickness * width * height) / 1000; + const weight_kg = (volume_cm3 * density) / 1000; + return { + weight: Math.round(weight_kg * 100) / 100, + type: isSUS ? 'SUS' : 'EGI', + }; +} +``` + +#### 1.3 제품코드별 재질 매핑 (PHP Lines 330-366) + +```typescript +function getMaterialMapping(productCode: string, finishMaterial: string) { + // Group 1: KQTS01 + if (productCode === 'KQTS01') { + return { + guideRailFinish: 'SUS 1.2T', // ①②마감재 + bodyMaterial: 'EGI 1.55T', // ③본체, ④C형, ⑤D형 + guideRailExtraFinish: '', // 별도마감 없음 + bottomBarFinish: 'SUS 1.5T', // 하단마감재 + bottomBarExtraFinish: '없음', // 별도마감 없음 + }; + } + // Group 2: KTE01 + if (productCode === 'KTE01') { + const isSUS = finishMaterial === 'SUS마감'; + return { + guideRailFinish: 'EGI 1.55T', + bodyMaterial: 'EGI 1.55T', + guideRailExtraFinish: isSUS ? 'SUS 1.2T' : '', + bottomBarFinish: 'EGI 1.55T', + bottomBarExtraFinish: isSUS ? 'SUS 1.2T' : '없음', + }; + } + // 기타 제품코드 (KSE01, KSS01, KWE01 등) - KTE01 + EGI마감과 동일 패턴 + return { + guideRailFinish: 'EGI 1.55T', + bodyMaterial: 'EGI 1.55T', + guideRailExtraFinish: '', + bottomBarFinish: 'EGI 1.55T', + bottomBarExtraFinish: '없음', + }; +} +``` + +#### 1.4 가이드레일 길이 버킷팅 알고리즘 (PHP Lines 384-413) + +```typescript +// 고정 버킷: [2438, 3000, 3500, 4000, 4300] +// 각 아이템의 col24(유효길이)를 "첫 번째로 수용 가능한 버킷"에 넣음 (first-fit) + +const LENGTH_BUCKETS = [2438, 3000, 3500, 4000, 4300]; + +function bucketGuideRails(items: Array<{ validLength: number; railType: string }>) { + const buckets = LENGTH_BUCKETS.map(len => ({ + length: len, wallSum: 0, sideSum: 0, + wallBaseSize: null as string | null, sideBaseSize: null as string | null, + })); + + for (const item of items) { + for (const bucket of buckets) { + if (item.validLength <= bucket.length) { + if (item.railType === '혼합형(130*75)(130*125)') { + bucket.wallSum += 1; + bucket.sideSum += 1; + bucket.wallBaseSize = '135*80'; + bucket.sideBaseSize = '135*130'; + } else if (item.railType === '벽면형(130*75)') { + bucket.wallSum += 2; + bucket.wallBaseSize = '135*130'; + } else if (item.railType === '측면형(130*125)') { + bucket.sideSum += 2; + bucket.sideBaseSize = '135*130'; + } + break; // first-fit: 한 버킷에 넣으면 다음 아이템으로 + } + } + } + return buckets.filter(b => b.wallSum > 0 || b.sideSum > 0); +} +``` + +#### 1.5 가이드레일 세부품명 + LOT 접두사 + 무게 계산 폭 + +**벽면형 [130*75] 파트 구성:** + +| 세부품명 | LOT 접두사 | 재질 | 무게 계산 폭 (mm) | +|---------|-----------|------|-----------------| +| ①②마감재 | XX | `guideRailFinish` | 412 | +| ③본체 | RT | `bodyMaterial` | 412 | +| ④C형 | RC | `bodyMaterial` | 412 | +| ⑤D형 | RD | `bodyMaterial` | 412 | +| ⑥별도마감 (SUS마감 시만) | RS | `guideRailExtraFinish` | 412 | +| 하부BASE | XX | EGI 1.55T (고정) | 135 (높이=80) | + +무게: `calcWeight(재질, 412, 길이)` / 하부BASE: `calcWeight('EGI 1.55T', 135, 80)` +baseSize는 `135*80` (혼합형) 또는 `135*130` (벽면형 단독) + +**측면형 [130*125] 파트 구성:** + +| 세부품명 | LOT 접두사 | 재질 | 무게 계산 폭 (mm) | +|---------|-----------|------|-----------------| +| ①②마감재 | SS | `guideRailFinish` | 462 | +| ③본체 | ST | `bodyMaterial` | 462 | +| ④C형 | SC | `bodyMaterial` | 462 | +| ⑤D형 | SD | `bodyMaterial` | 462 | +| 하부BASE | XX | EGI 1.55T (고정) | 135 (높이=130) | + +무게: `calcWeight(재질, 462, 길이)` / 하부BASE: `calcWeight('EGI 1.55T', 135, 130)` + +#### 1.6 하단마감재 세부품명 + +| 세부품명 | LOT 접두사 | 재질 | 무게 계산 폭 (mm) | 길이 옵션 | +|---------|-----------|------|-----------------|---------| +| ①하단마감재 | TE(EGI)/TS(SUS) | `bottomBarFinish` | 184 | 3000, 4000 | +| ④별도마감재 | TE/TS | `bottomBarExtraFinish` | 238 | 3000, 4000 | + +별도마감재는 `bottomBarExtraFinish !== '없음'`일 때만 표시. + +#### 1.7 셔터박스 구성요소 (방향별 - PHP Lines 819-1190) + +**셔터박스 재질**: 항상 `EGI 1.55T` (= `$BoxFinish`) + +**표준 사이즈 (500*380) 구성:** + +| 구성요소 | LOT 접두사 | 치수 공식 | +|---------|-----------|----------| +| ①전면부 | CF | `boxHeight + 122` | +| ②린텔부 | CL | `boxWidth - 330` | +| ③⑤점검구 | CP | `boxWidth - 200` | +| ④후면코너부 | CB | `170` (고정) | + +**비표준 사이즈 - 양면 구성:** + +| 구성요소 | LOT 접두사 | 치수 공식 | +|---------|-----------|----------| +| ①전면부 | XX | `boxHeight + 122` | +| ②린텔부 | CL | `boxWidth - 330` | +| ③점검구 | XX | `boxWidth - 200` | +| ④후면코너부 | CB | `170` (고정) | +| ⑤점검구 | XX | `boxHeight - 100` | +| ⑥상부덮개 | XX | `1219 * (boxWidth - 111)` | +| ⑦측면부(마구리) | XX | `(boxWidthFin+5) * (boxHeightFin+5)` 표시 | + +**비표준 사이즈 - 밑면 구성:** + +| 구성요소 | LOT 접두사 | 치수 공식 | +|---------|-----------|----------| +| ①전면부 | XX | `boxHeight + 122` | +| ②린텔부 | CL | `boxWidth - 330` | +| ③점검구 | XX | `boxWidth - 200` | +| ④후면부 | CB | `boxHeight + 85*2` | +| ⑤상부덮개 | XX | `1219 * (boxWidth - 111)` | +| ⑥측면부(마구리) | XX | `(boxWidthFin+5) * (boxHeightFin+5)` 표시 | + +**비표준 사이즈 - 후면 구성:** + +| 구성요소 | LOT 접두사 | 치수 공식 | +|---------|-----------|----------| +| ①전면부 | XX | `boxHeight + 122` | +| ②린텔부 | CL | `boxWidth + 85*2` | +| ③점검구 | XX | `boxHeight - 200` | +| ④후면코너부 | CB | `boxHeight + 85*2` | +| ⑤상부덮개 | XX | `1219 * (boxWidth - 111)` | +| ⑥측면부(마구리) | XX | `(boxWidthFin+5) * (boxHeightFin+5)` 표시 | + +**공통 사항:** +- 상부덮개 무게: `calcWeight('EGI 1.55T', boxWidth - 111, 1219)` × coverQty +- 마구리 무게: `calcWeight('EGI 1.55T', boxWidthFin, boxHeightFin)` × finCoverQty +- 셔터박스 길이 버킷: [1219, 2438, 3000, 3500, 4000, 4150] + +#### 1.8 연기차단재 (PHP Lines 1195-1321) + +| 파트 | 재질 | 무게 계산 폭 (mm) | 길이 버킷 | +|-----|------|-----------------|---------| +| 레일용 [W50] | EGI 0.8T | 26 | 2438, 3000, 3500, 4000, 4300 | +| 케이스용 [W80] | EGI 0.8T | 26 | 3000 (고정) | + +LOT 접두사: 모두 `GI` +LOT 코드 생성: `GI-{getSLengthCode(length, category)}` + +#### 1.9 getSLengthCode 함수 (PHP Lines 56-100) + +```typescript +function getSLengthCode(length: number, category: string): string | null { + if (category === '연기차단재50') { + return length === 3000 ? '53' : length === 4000 ? '54' : null; + } + if (category === '연기차단재80') { + return length === 3000 ? '83' : length === 4000 ? '84' : null; + } + // category === '기타' (일반) + const map: Record = { + 1219: '12', 2438: '24', 3000: '30', 3500: '35', + 4000: '40', 4150: '41', 4200: '42', 4300: '43', + }; + return map[length] || null; +} +``` + +--- + +### 4.2 Phase 2: 이미지 서빙 + +#### 복사 대상 (총 19개 JPG 파일) + +**가이드레일 (12개):** +``` +5130/img/guiderail/ → api/public/images/bending/guiderail/ +├── guiderail_KQTS01_wall_130x75.jpg +├── guiderail_KQTS01_side_130x125.jpg +├── guiderail_KTE01_wall_130x75.jpg +├── guiderail_KTE01_side_130x125.jpg +├── guiderail_KSE01_wall_120x70.jpg +├── guiderail_KSE01_side_120x120.jpg +├── guiderail_KSS01_wall_120x70.jpg +├── guiderail_KSS01_side_120x120.jpg +├── guiderail_KSS02_wall_120x70.jpg +├── guiderail_KSS02_side_120x120.jpg +├── guiderail_KWE01_wall_120x70.jpg +└── guiderail_KWE01_side_120x120.jpg +``` + +**하단마감재 (6개):** +``` +5130/img/bottombar/ → api/public/images/bending/bottombar/ +├── bottombar_KQTS01.jpg +├── bottombar_KTE01.jpg +├── bottombar_KSE01.jpg +├── bottombar_KSS01.jpg +├── bottombar_KSS02.jpg +└── bottombar_KWE01.jpg +``` + +**연기차단재 (1개):** +``` +5130/img/part/ → api/public/images/bending/part/ +└── smokeban.jpg +``` + +**셔터박스 이미지**: PHP에서 GD 라이브러리로 동적 생성 → React에서는 SVG/Canvas로 대체 +- 소스 이미지: `5130/img/box/source/box_{both|bottom|rear}.jpg` +- 치수 텍스트를 오버레이하는 구조 → SVG 컴포넌트로 재구현 + +#### 이미지 URL 패턴 + +```typescript +const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'https://api.sam.kr'; + +function getBendingImageUrl(category: string, productCode: string, type?: string): string { + switch (category) { + case 'guiderail': { + // PHP: guiderail_{prodCode}_{wall|side}_{size}.jpg + // KQTS01, KTE01 → 130x75 (wall) / 130x125 (side) + // KSE01, KSS01, KSS02, KWE01 → 120x70 (wall) / 120x120 (side) + const size = ['KQTS01', 'KTE01'].includes(productCode) + ? (type === 'wall' ? '130x75' : '130x125') + : (type === 'wall' ? '120x70' : '120x120'); + return `${API_BASE}/images/bending/guiderail/guiderail_${productCode}_${type}_${size}.jpg`; + } + case 'bottombar': + return `${API_BASE}/images/bending/bottombar/bottombar_${productCode}.jpg`; + case 'smokebarrier': + return `${API_BASE}/images/bending/part/smokeban.jpg`; + default: + return ''; + } +} +``` + +--- + +### 4.3 Phase 3: 프론트엔드 타입 & 유틸리티 + +#### 파일 구조 + +``` +react/src/components/production/WorkOrders/documents/ +├── BendingWorkLogContent.tsx ← 기존 파일 (재작성) +├── bending/ +│ ├── types.ts ← 절곡 작업일지 전용 타입 +│ ├── utils.ts ← calcWeight, getMaterialMapping, getBendingImageUrl, getSLengthCode +│ ├── GuideRailSection.tsx ← 가이드레일 섹션 +│ ├── BottomBarSection.tsx ← 하단마감재 섹션 +│ ├── ShutterBoxSection.tsx ← 셔터박스 섹션 +│ ├── SmokeBarrierSection.tsx ← 연기차단재 섹션 +│ └── ProductionSummarySection.tsx ← 생산량 합계 +``` + +#### WorkOrderItem.bendingInfo 추가 (slatInfo 패턴 참고) + +```typescript +// types.ts에 추가 +export interface WorkOrderItem { + // ... 기존 필드 ... + slatInfo?: { length: number; slatCount: number; jointBar: number; glassQty: number }; + bendingInfo?: BendingInfoExtended; // ← 신규 추가 +} + +// transform 함수에 추가 (slatInfo 패턴 동일) +bendingInfo: item.options?.bending_info + ? (item.options.bending_info as BendingInfoExtended) + : undefined, +``` + +--- + +### 4.4 Phase 4: 컴포넌트 구현 상세 + +#### 4.1 GuideRailSection 레이아웃 + +``` +┌──────────────────────────────────────────────────────────────────────────────┐ +│ 1.1 벽면형 [130*75] │ +│ ┌─────────────────────┐ ┌──────────────────────────────────────────────────┐│ +│ │ [guiderail 이미지] │ │ 세부품명 │ 재질 │ 길이 │ 수량 │ LOT NO │ 무게 ││ +│ │ │ │──────────┼──────────┼──────┼──────┼────────┼──────││ +│ │ │ │ ①②마감재 │ SUS 1.2T │ 4000 │ 6 │ ____ │ XX.X ││ +│ │ 입고&생산 LOT NO: │ │ ③본체 │ EGI 1.55T│ 4000 │ 6 │ ____ │ XX.X ││ +│ │ ___________ │ │ ④C형 │ EGI 1.55T│ 4000 │ 6 │ ____ │ XX.X ││ +│ └─────────────────────┘ │ ⑤D형 │ EGI 1.55T│ 4000 │ 6 │ ____ │ XX.X ││ +│ │ ⑥별도마감 │ SUS 1.2T │ 4000 │ 6 │ ____ │ XX.X ││ +│ │ 하부BASE │ EGI 1.55T│135*80│ N │ ____ │ XX.X ││ +│ └──────────────────────────────────────────────────┘│ +├──────────────────────────────────────────────────────────────────────────────┤ +│ 1.2 측면형 [130*125] (동일 구조, 폭=462mm, baseSize=135*130) │ +└──────────────────────────────────────────────────────────────────────────────┘ +``` + +각 길이 버킷(2438/3000/3500/4000/4300)별로 수량이 있는 행만 표시. +각 파트의 무게는 `calcWeight(재질, 폭, 길이)` × 수량으로 계산. + +#### 4.2 BottomBarSection 레이아웃 + +``` +┌──────────────────────────────────────────────────────────────────────────────┐ +│ 2. 하단마감재 │ +│ ┌─────────────────────┐ ┌──────────────────────────────────────────────────┐│ +│ │ [bottombar 이미지] │ │ 세부품명 │ 재질 │ 길이 │ 수량 │ LOT │ 무게 ││ +│ │ │ │─────────────┼──────────┼──────┼──────┼──────┼──────││ +│ │ │ │ ①하단마감재 │ EGI 1.55T│ 3000 │ N │ ____ │ XX.X ││ +│ └─────────────────────┘ │ ①하단마감재 │ EGI 1.55T│ 4000 │ N │ ____ │ XX.X ││ +│ │ ④별도마감재 │ SUS 1.2T │ 3000 │ N │ ____ │ XX.X ││ +│ │ ④별도마감재 │ SUS 1.2T │ 4000 │ N │ ____ │ XX.X ││ +│ └──────────────────────────────────────────────────┘│ +└──────────────────────────────────────────────────────────────────────────────┘ +``` + +#### 4.3 ShutterBoxSection 레이아웃 + +``` +┌──────────────────────────────────────────────────────────────────────────────┐ +│ 3. 셔터박스 [500*380] 양면 │ +│ ┌─────────────────────┐ ┌──────────────────────────────────────────────────┐│ +│ │ [SVG 다이어그램] │ │ 구성요소 │ 재질 │ 길이 │ 수량 │ LOT │ 무게 ││ +│ │ (치수 텍스트 포함) │ │────────────┼──────────┼──────┼──────┼──────┼──────││ +│ │ boxHeight+122 │ │ ①전면부 │ EGI 1.55T│ 3000 │ N │ ____ │ XX.X ││ +│ │ boxWidth-330 │ │ ②린텔부 │ EGI 1.55T│ 3000 │ N │ ____ │ XX.X ││ +│ │ boxWidth-200 │ │ ③점검구 │ EGI 1.55T│ 3000 │ N │ ____ │ XX.X ││ +│ └─────────────────────┘ │ ④후면코너부 │ EGI 1.55T│ 3000 │ N │ ____ │ XX.X ││ +│ │ ⑤점검구 │ EGI 1.55T│ 3000 │ N │ ____ │ XX.X ││ +│ │ ⑥상부덮개 │ EGI 1.55T│ 1219 │ N │ ____ │ XX.X ││ +│ │ ⑦마구리 │ EGI 1.55T│ - │ N │ ____ │ XX.X ││ +│ └──────────────────────────────────────────────────┘│ +└──────────────────────────────────────────────────────────────────────────────┘ +``` + +#### 4.4 SmokeBarrierSection 레이아웃 + +``` +┌──────────────────────────────────────────────────────────────────────────────┐ +│ 4. 연기차단재 │ +│ ┌─────────────────────┐ ┌──────────────────────────────────────────────────┐│ +│ │ [smokeban.jpg] │ │ 파트 │ 재질 │ 길이 │ 수량 │ LOT │ 무게 ││ +│ │ │ │───────────────┼─────────┼──────┼──────┼──────┼──────││ +│ └─────────────────────┘ │ 레일용 [W50] │EGI 0.8T │ 3000 │ N │ ____ │ XX.X ││ +│ │ 레일용 [W50] │EGI 0.8T │ 4000 │ N │ ____ │ XX.X ││ +│ │ 케이스용 [W80]│EGI 0.8T │ 3000 │ N │ ____ │ XX.X ││ +│ └──────────────────────────────────────────────────┘│ +└──────────────────────────────────────────────────────────────────────────────┘ +``` + +#### 4.5 ProductionSummarySection 레이아웃 + +``` +┌──────────────────────────────────────────────────────┐ +│ 생산량 합계(KG) │ SUS │ EGI │ 합계 │ +│ │ XX.XX kg │ XX.XX kg │ XX.XX kg │ +└──────────────────────────────────────────────────────┘ +``` + +SUS_total과 EGI_total은 4개 섹션의 모든 calcWeight 호출에서 누적. + +--- + +## 5. 모든 하드코딩 상수 (PHP 원본 기준) + +| 상수 | 값 | 용도 | +|------|-----|------| +| SUS 밀도 | 7.93 g/cm3 | calWeight | +| EGI 밀도 | 7.85 g/cm3 | calWeight | +| 벽면형 파트 폭 | 412 mm | 가이드레일 무게 계산 | +| 측면형 파트 폭 | 462 mm | 가이드레일 무게 계산 | +| 벽면형 하부BASE | 135 × 80 mm | 가이드레일 | +| 측면형 하부BASE | 135 × 130 mm | 가이드레일 | +| 하단마감재 폭 | 184 mm | 하단마감재 무게 | +| 별도마감재 폭 | 238 mm | 별도마감재 무게 | +| 연기차단재 폭 (W50/W80) | 26 mm | 연기차단재 무게 | +| 상부덮개 길이 | 1219 mm (고정) | 셔터박스 | +| 상부덮개 폭 | boxWidth - 111 | 셔터박스 | +| 전면부 치수 | boxHeight + 122 | 셔터박스 | +| 린텔부 치수 | boxWidth - 330 | 셔터박스 | +| 점검구 치수 | boxWidth - 200 | 셔터박스 | +| 후면코너부 치수 (표준/양면) | 170 | 셔터박스 | +| 가이드레일 길이 버킷 | [2438, 3000, 3500, 4000, 4300] | 길이 분류 | +| 셔터박스 길이 버킷 | [1219, 2438, 3000, 3500, 4000, 4150] | 길이 분류 | +| 하단마감재 길이 | [3000, 4000] | 길이 분류 | +| 연기차단재 W50 길이 버킷 | [2438, 3000, 3500, 4000, 4300] | 길이 분류 | +| 케이스용 W80 길이 | 3000 (고정) | 연기차단재 | +| 마구리 표시 크기 보정 | +5 mm (양쪽) | 셔터박스 | + +--- + +## 6. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | bending_info 스키마 확장 | guideRail, bottomBar, shutterBox, smokeBarrier 필드 추가 | api options JSON | ⚠️ 컨펌 필요 | +| 2 | 이미지 파일 복사 | 5130/img/ → api/public/images/bending/ (19개 JPG) | api 서버 | ⚠️ 컨펌 필요 | +| 3 | 셔터박스 이미지 처리 | SVG 컴포넌트로 클라이언트 렌더링 (PHP GD 대체) | react | ⚠️ 컨펌 필요 | + +--- + +## 7. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-19 | - | 문서 초안 작성 | - | - | +| 2026-02-19 | - | 자기완결성 보완 (PHP 로직 완전 인라인, 이미지 목록, 상수 테이블, 데이터 흐름) | - | - | + +--- + +## 8. 참고 문서 & 핵심 파일 경로 + +### 수정 대상 파일 + +| 파일 | 역할 | 작업 | +|------|------|------| +| `react/src/components/production/WorkOrders/documents/BendingWorkLogContent.tsx` | 메인 컴포넌트 | **재작성** | +| `react/src/components/production/WorkOrders/types.ts` | WorkOrderItem 타입 | `bendingInfo` 필드 추가 + transform 함수 수정 | +| `react/src/components/production/WorkOrders/documents/bending/` | 신규 디렉토리 | **6개 파일 생성** (types, utils, 4개 섹션 + 합계) | + +### 참조 파일 (읽기 전용) + +| 파일 | 역할 | +|------|------| +| `5130/output/viewBendingWork_slat.php` | PHP 원본 (~1400줄) | +| `react/src/components/production/WorkerScreen/types.ts` | BendingInfo 인터페이스 (Lines 91-107) | +| `react/src/components/production/WorkerScreen/WorkLogModal.tsx` | 작업일지 모달 - BendingWorkLogContent 호출 (Lines 207-213) | +| `api/app/Services/WorkOrderService.php` | options에 bending_info 저장 (Line 276) | +| `react/src/components/production/WorkOrders/documents/SlatWorkLogContent.tsx` | 슬랫 작업일지 참고 (유사 패턴) | +| `react/src/components/production/WorkOrders/documents/index.ts` | export 파일 (BendingWorkLogContent 등록됨) | + +### 이미지 원본 경로 + +| 소스 | 대상 | 파일 수 | +|------|------|---------| +| `5130/img/guiderail/*.jpg` | `api/public/images/bending/guiderail/` | 12개 | +| `5130/img/bottombar/*.jpg` | `api/public/images/bending/bottombar/` | 6개 | +| `5130/img/part/smokeban.jpg` | `api/public/images/bending/part/` | 1개 | + +**참고**: `api/public/images/bending/` 디렉토리는 아직 존재하지 않음 → 생성 필요. + +--- + +## 9. 세션 관리 + +### Serena 메모리 ID +- `bending-worklog-state`: 진행 상태 +- `bending-worklog-snapshot`: 스냅샷 +- `bending-worklog-active-symbols`: 수정 중 파일 + +--- + +## 10. 검증 결과 + +### 10.1 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 4개 카테고리 섹션이 PHP와 동일한 레이아웃으로 렌더링 | ⏳ | | +| SUS/EGI 무게 계산이 PHP calWeight와 동일한 결과 | ⏳ | calcWeight(SUS 1.2T, 412, 4000) 등으로 검증 | +| 생산량 합계(KG)가 SUS/EGI 별도 + 합산으로 표시 | ⏳ | | +| 가이드레일/하단마감재/연기차단재 이미지가 정상 표시 | ⏳ | | +| 셔터박스 SVG 다이어그램에 치수 텍스트 표시 | ⏳ | | +| 제품코드/마감유형에 따라 세부품명 동적 변경 | ⏳ | KQTS01 vs KTE01+SUS vs KTE01+EGI | +| 가이드레일 길이 버킷팅이 PHP first-fit과 동일 | ⏳ | | +| 빌드 에러 없음 | ⏳ | | + +### 10.2 검증 방법 +- PHP 원본: `5130/output/viewBendingWork_slat.php?num=24822` 출력과 비교 +- 무게 계산 단위 테스트: `calcWeight('SUS 1.2T', 412, 4000)` → 예상값과 비교 + - `thickness=1.2, width=412, height=4000, density=7.93` + - `volume_cm3 = (1.2 * 412 * 4000) / 1000 = 1977.6` + - `weight_kg = (1977.6 * 7.93) / 1000 = 15.68` + +--- + +## 11. 자기완결성 점검 결과 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | PHP 동일 구조 재구현 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 10.1 (8개 기준) | +| 3 | 작업 범위가 구체적인가? | ✅ | 5 Phase, 15개 작업 항목 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Phase 순서 = 의존성, 데이터 흐름 섹션 1.2 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 8 (수정 대상 + 참조 파일 분리) | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | PHP 로직 완전 인라인 (섹션 4) | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | PHP num=24822 비교 + 단위 테스트 예시 | +| 8 | 모호한 표현이 없는가? | ✅ | 모든 상수/공식/조건 구체적으로 명시 | + +### 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------:| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 데이터가 어디서 어떻게 오는가? | ✅ | 1.2 데이터 흐름 | +| Q3. 어디서부터 시작해야 하는가? | ✅ | 3.1 단계별 절차 | +| Q4. 어떤 파일을 수정/생성해야 하는가? | ✅ | 8 핵심 파일 경로 | +| Q5. PHP 원본의 계산 로직은? | ✅ | 4.1 (calWeight, 버킷팅, 재질매핑 전부 인라인) | +| Q6. 이미지 파일은 어디에 있는가? | ✅ | 4.2 (19개 파일 목록 + URL 패턴) | +| Q7. 모든 하드코딩 상수 값은? | ✅ | 섹션 5 (완전 테이블) | +| Q8. 작업 완료 확인 방법은? | ✅ | 10.1 성공 기준 + 10.2 검증 방법 | +| Q9. 막혔을 때 참고 문서는? | ✅ | 8 참고 문서 | + +**결과**: 9/9 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/bidding-api-implementation-plan.md b/plans/archive/bidding-api-implementation-plan.md new file mode 100644 index 0000000..e0c3135 --- /dev/null +++ b/plans/archive/bidding-api-implementation-plan.md @@ -0,0 +1,817 @@ +# 입찰관리(Bidding) API 구현 계획 + +> **작성일**: 2026-01-19 +> **목적**: 견적 → 입찰 전환 기능 구현 및 테스트용 더미데이터 생성 +> **기준 문서**: React 목업 타입 (`react/src/components/business/construction/bidding/types.ts`) +> **상태**: ✅ 완료 (Serena ID: bidding-api-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4.3 - Pint 코드 포맷팅 및 Swagger 재생성 | +| **다음 작업** | 사용자 수동 실행 (마이그레이션, 시더) | +| **진행률** | 12/12 (100%) | +| **마지막 업데이트** | 2026-01-19 | + +--- + +## 1. 개요 + +### 1.1 배경 + +**업무 흐름:** +``` +현장설명회 → 견적관리 → [견적완료] → 입찰관리 → 계약관리 → 기성/정산 + ↑ + 전환 기능 필요 +``` + +현재 React 프론트엔드의 입찰관리(`/construction/project/bidding`)는 **목업 데이터**를 사용 중입니다. +견적(Quote) API는 이미 구현되어 있으므로, 입찰(Bidding) API를 새로 구현하고 견적 → 입찰 전환 기능을 추가해야 합니다. + +**현재 상태:** +| 구분 | 견적(Estimate/Quote) | 입찰(Bidding) | +|------|---------------------|---------------| +| API Model | ✅ `Estimate.php` | ❌ 없음 | +| API Migration | ✅ `estimates` 테이블 | ❌ 없음 | +| API Endpoint | ✅ `/api/v1/quotes` | ❌ 없음 | +| React | ✅ API 연동 완료 | ❌ 목업 상태 | + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. SAM API Rules 엄격 준수 (Service-First, FormRequest) │ +│ 2. Multi-tenancy 필수 (BelongsToTenant) │ +│ 3. React 목업 타입과 100% 호환 │ +│ 4. 견적 데이터 참조 (복사가 아닌 FK 연결) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 새 테이블 생성, 새 API 추가, Seeder 작성 | 불필요 | +| ⚠️ 컨펌 필요 | 기존 quotes 테이블 수정, 비즈니스 로직 변경 | **필수** | +| 🔴 금지 | 기존 API 삭제, 파괴적 변경 | 별도 협의 | + +### 1.4 준수 규칙 + +- `api/CLAUDE.md` - SAM API Development Rules +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/guides/swagger-guide.md` - Swagger 문서화 + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: Database & Model (Day 1) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | `biddings` 테이블 마이그레이션 생성 | ✅ | `2026_01_19_100000_create_biddings_table.php` | +| 1.2 | `Bidding` Model 생성 | ✅ | BelongsToTenant, SoftDeletes | +| 1.3 | 더미데이터 Seeder 생성 | ✅ | 10건 테스트 데이터 | + +### 2.2 Phase 2: API Implementation (Day 2) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | BiddingService 생성 | ✅ | CRUD + 통계 | +| 2.2 | BiddingController 생성 | ✅ | | +| 2.3 | FormRequest 생성 | ✅ | Filter, Update, Status, BulkDelete | +| 2.4 | Routes 등록 | ✅ | `/api/v1/biddings` | + +### 2.3 Phase 3: 견적 → 입찰 전환 (Day 2-3) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | QuoteService에 `convertToBidding()` 추가 | ✅ | 기존 코드에 메서드 추가 | +| 3.2 | 전환 API 엔드포인트 추가 | ✅ | `POST /quotes/{id}/convert-to-bidding` | + +### 2.4 Phase 4: Swagger & 검증 (Day 3) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | Swagger 문서 작성 | ✅ | `BiddingApi.php` | +| 4.2 | i18n 메시지 추가 | ✅ | message.php, error.php | +| 4.3 | Pint 코드 포맷팅 | ✅ | 9 style issues fixed | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Step 1: Database Schema +├── biddings 테이블 마이그레이션 작성 +├── 마이그레이션 실행 +└── Seeder로 더미데이터 생성 + +Step 2: Model & Service +├── Bidding Model 생성 (BelongsToTenant, SoftDeletes) +├── BiddingService 생성 (CRUD, stats, filter) +└── BiddingController 생성 + +Step 3: API Routes +├── routes/api.php에 biddings 라우트 추가 +├── FormRequest 클래스 생성 +└── API 테스트 + +Step 4: 견적 → 입찰 전환 +├── QuoteService에 convertToBidding() 추가 +├── 전환 API 엔드포인트 추가 +└── 전환 테스트 + +Step 5: Documentation +├── Swagger 문서 작성 +├── API 문서 검증 +└── Pint 실행 +``` + +### 3.2 데이터베이스 스키마 + +```sql +-- biddings 테이블 +CREATE TABLE biddings ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID', + + -- 기본 정보 + bidding_code VARCHAR(50) NOT NULL COMMENT '입찰번호', + quote_id BIGINT UNSIGNED NULL COMMENT '연결된 견적 ID (quotes.id)', + + -- 거래처/현장 + client_id BIGINT UNSIGNED NULL COMMENT '거래처 ID', + client_name VARCHAR(100) NULL COMMENT '거래처명 (스냅샷)', + project_name VARCHAR(200) NULL COMMENT '현장명', + + -- 입찰 정보 + bidding_date DATE NULL COMMENT '입찰일', + bid_date DATE NULL COMMENT '입찰일 (레거시 호환)', + submission_date DATE NULL COMMENT '투찰일', + confirm_date DATE NULL COMMENT '확정일', + total_count INT DEFAULT 0 COMMENT '총 개소', + bidding_amount DECIMAL(15,2) DEFAULT 0 COMMENT '입찰금액', + + -- 상태 + status VARCHAR(20) DEFAULT 'waiting' COMMENT '상태 (waiting/submitted/failed/invalid/awarded/hold)', + + -- 입찰자 + bidder_id BIGINT UNSIGNED NULL COMMENT '입찰자 ID', + bidder_name VARCHAR(50) NULL COMMENT '입찰자명 (스냅샷)', + + -- 공사기간 + construction_start_date DATE NULL COMMENT '공사 시작일', + construction_end_date DATE NULL COMMENT '공사 종료일', + vat_type VARCHAR(20) DEFAULT 'excluded' COMMENT '부가세 (included/excluded)', + + -- 비고 + remarks TEXT NULL COMMENT '비고', + + -- 견적 데이터 스냅샷 (JSON) + expense_items JSON NULL COMMENT '공과 항목 스냅샷', + estimate_detail_items JSON NULL COMMENT '견적 상세 항목 스냅샷', + + -- 감사 + created_by BIGINT UNSIGNED NULL COMMENT '생성자', + updated_by BIGINT UNSIGNED NULL COMMENT '수정자', + deleted_by BIGINT UNSIGNED NULL COMMENT '삭제자', + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + + -- 인덱스 + INDEX idx_tenant_id (tenant_id), + INDEX idx_status (status), + INDEX idx_bidding_date (bidding_date), + INDEX idx_quote_id (quote_id), + UNIQUE INDEX idx_bidding_code (tenant_id, bidding_code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +``` + +### 3.3 API 엔드포인트 설계 + +| Method | Path | 설명 | +|--------|------|------| +| GET | `/api/v1/biddings` | 목록 조회 (필터, 페이지네이션) | +| GET | `/api/v1/biddings/stats` | 통계 조회 | +| GET | `/api/v1/biddings/{id}` | 단건 조회 | +| PUT | `/api/v1/biddings/{id}` | 수정 | +| DELETE | `/api/v1/biddings/{id}` | 삭제 | +| DELETE | `/api/v1/biddings/bulk` | 일괄 삭제 | +| POST | `/api/v1/quotes/{id}/convert-to-bidding` | 견적 → 입찰 전환 | + +**참고**: 입찰은 별도 등록 없음 (견적완료 시 자동 전환) + +### 3.4 타입 매핑 (React → API) + +| React (camelCase) | API (snake_case) | DB Column | +|-------------------|------------------|-----------| +| `id` | `id` | `id` | +| `biddingCode` | `bidding_code` | `bidding_code` | +| `partnerId` | `client_id` | `client_id` | +| `partnerName` | `client_name` | `client_name` | +| `projectName` | `project_name` | `project_name` | +| `biddingDate` | `bidding_date` | `bidding_date` | +| `totalCount` | `total_count` | `total_count` | +| `biddingAmount` | `bidding_amount` | `bidding_amount` | +| `bidDate` | `bid_date` | `bid_date` | +| `submissionDate` | `submission_date` | `submission_date` | +| `confirmDate` | `confirm_date` | `confirm_date` | +| `status` | `status` | `status` | +| `bidderId` | `bidder_id` | `bidder_id` | +| `bidderName` | `bidder_name` | `bidder_name` | +| `remarks` | `remarks` | `remarks` | +| `estimateId` | `quote_id` | `quote_id` | +| `estimateCode` | `quote_number` | (join) | + +### 3.5 상태값 매핑 + +| 값 | 한글 | 설명 | +|----|------|------| +| `waiting` | 입찰대기 | 견적 전환 후 초기 상태 | +| `submitted` | 투찰 | 투찰서 제출 완료 | +| `failed` | 탈락 | 입찰 실패 | +| `invalid` | 유찰 | 입찰 무효 | +| `awarded` | 낙찰 | 입찰 성공 | +| `hold` | 보류 | 검토 대기 | + +### 3.6 기존 quotes 테이블 스키마 (연결용) + +> `biddings.quote_id` → `quotes.id` FK 연결 + +```sql +-- quotes 테이블 핵심 컬럼 (api/database/migrations/2025_12_04_164542_create_quotes_table.php) +quotes ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + quote_type ENUM('manufacturing', 'construction'), -- 'construction' 필터 + quote_number VARCHAR(50), -- 견적번호 (예: KD-SC-251204-01) + registration_date DATE, + client_id BIGINT, -- 거래처 ID + client_name VARCHAR(100), -- 거래처명 + site_name VARCHAR(200), -- 현장명 + total_amount DECIMAL(15,2), -- 최종 금액 + status ENUM('pending','draft','sent','approved','rejected','finalized','converted'), + site_briefing_id BIGINT, -- 현장설명회 연결 + options JSON, -- { summary_items, expense_items, detail_items, price_adjustment_data } + ... +) +``` + +**Quote 상태 상수** (api/app/Models/Quote/Quote.php): +- `pending` → 견적대기 (현장설명회에서 자동생성) +- `finalized` → 확정 (입찰 전환 가능) +- `converted` → 전환완료 + +### 3.7 API 응답 형식 (JSON) + +#### 목록 조회 응답 (GET /biddings) +```json +{ + "success": true, + "message": "message.fetched", + "data": { + "data": [ + { + "id": 1, + "bidding_code": "BID-2025-001", + "client_id": 1, + "client_name": "이사대표", + "project_name": "광장 아파트", + "bidding_date": "2025-01-25", + "total_count": 15, + "bidding_amount": 71000000, + "bid_date": "2025-01-20", + "submission_date": "2025-01-22", + "confirm_date": "2025-01-25", + "status": "awarded", + "bidder_id": 1, + "bidder_name": "홍길동", + "remarks": "", + "quote_id": 1, + "quote_number": "EST-2025-001", + "created_at": "2025-01-01T00:00:00.000000Z" + } + ], + "current_page": 1, + "per_page": 20, + "total": 10, + "last_page": 1 + } +} +``` + +#### 통계 응답 (GET /biddings/stats) +```json +{ + "success": true, + "message": "message.fetched", + "data": { + "total": 10, + "waiting": 3, + "awarded": 3 + } +} +``` + +#### 단건 조회 응답 (GET /biddings/{id}) +```json +{ + "success": true, + "message": "message.fetched", + "data": { + "id": 1, + "bidding_code": "BID-2025-001", + "client_id": 1, + "client_name": "이사대표", + "project_name": "광장 아파트", + "bidding_date": "2025-01-25", + "total_count": 15, + "bidding_amount": 71000000, + "status": "awarded", + "construction_start_date": "2025-02-01", + "construction_end_date": "2025-04-30", + "vat_type": "excluded", + "expense_items": [ + { "id": "1", "name": "설계비", "amount": 5000000 }, + { "id": "2", "name": "운반비", "amount": 3000000 } + ], + "estimate_detail_items": [ + { "id": "1", "no": 1, "name": "방화문", "material": "SUS304", "width": 1000, "height": 2100, "quantity": 10, ... } + ], + "quote": { + "id": 1, + "quote_number": "EST-2025-001" + } + } +} +``` + +### 3.8 convertToBidding() 상세 로직 + +```php +/** + * 견적 → 입찰 전환 + * + * @param int $quoteId 견적 ID + * @return Bidding 생성된 입찰 + */ +public function convertToBidding(int $quoteId): Bidding +{ + $tenantId = $this->tenantId(); + $userId = $this->apiUserId(); + + // 1. 견적 조회 (quote_type=construction, status=finalized) + $quote = Quote::where('tenant_id', $tenantId) + ->where('id', $quoteId) + ->where('quote_type', 'construction') + ->where('status', 'finalized') + ->firstOrFail(); + + // 2. 이미 입찰이 존재하는지 확인 + $existingBidding = Bidding::where('quote_id', $quoteId)->first(); + if ($existingBidding) { + throw new BadRequestHttpException(__('error.bidding_already_exists')); + } + + // 3. 입찰 데이터 생성 + $bidding = Bidding::create([ + 'tenant_id' => $tenantId, + 'bidding_code' => $this->generateBiddingCode($tenantId), + 'quote_id' => $quote->id, + + // 거래처/현장 정보 복사 + 'client_id' => $quote->client_id, + 'client_name' => $quote->client_name, + 'project_name' => $quote->site_name, + + // 금액 정보 + 'bidding_amount' => $quote->total_amount, + 'total_count' => $quote->items->count(), + + // 날짜 + 'bidding_date' => now()->toDateString(), + + // 상태 + 'status' => 'waiting', + + // 현장설명회에서 공사기간 가져오기 + 'construction_start_date' => $quote->siteBriefing?->construction_start_date, + 'construction_end_date' => $quote->siteBriefing?->construction_end_date, + 'vat_type' => $quote->siteBriefing?->vat_type ?? 'excluded', + + // 견적 옵션 데이터 스냅샷 + 'expense_items' => $quote->options['expense_items'] ?? [], + 'estimate_detail_items' => $quote->options['detail_items'] ?? [], + + 'created_by' => $userId, + ]); + + // 4. 견적 상태 업데이트 (선택적) + // $quote->update(['status' => 'converted']); + + return $bidding; +} + +/** + * 입찰번호 자동 생성 (BID-YYYY-NNN) + */ +private function generateBiddingCode(int $tenantId): string +{ + $year = now()->format('Y'); + $prefix = "BID-{$year}-"; + + $lastBidding = Bidding::where('tenant_id', $tenantId) + ->where('bidding_code', 'like', "{$prefix}%") + ->orderBy('id', 'desc') + ->first(); + + $sequence = 1; + if ($lastBidding) { + $lastNum = (int) substr($lastBidding->bidding_code, -3); + $sequence = $lastNum + 1; + } + + return $prefix . str_pad($sequence, 3, '0', STR_PAD_LEFT); +} +``` + +### 3.9 Service/Controller 패턴 (SAM 표준) + +**Controller 패턴** (api/app/Http/Controllers): +```php + $this->service->index($request->validated())); + } + + public function show(int $id) + { + return ApiResponse::handle(fn () => $this->service->show($id)); + } + + public function update(BiddingUpdateRequest $request, int $id) + { + return ApiResponse::handle(fn () => $this->service->update($id, $request->validated())); + } + + public function destroy(int $id) + { + return ApiResponse::handle(fn () => $this->service->destroy($id)); + } + + public function stats() + { + return ApiResponse::handle(fn () => $this->service->stats()); + } +} +``` + +**Service 패턴** (api/app/Services): +```php +tenantId(); // 필수 + $query = Bidding::where('tenant_id', $tenantId); + // ... 필터, 정렬, 페이지네이션 + return $query->paginate($params['size'] ?? 20); + } + + public function show(int $id): Bidding + { + $tenantId = $this->tenantId(); + return Bidding::where('tenant_id', $tenantId) + ->with(['quote']) + ->findOrFail($id); + } + + public function stats(): array + { + $tenantId = $this->tenantId(); + return [ + 'total' => Bidding::where('tenant_id', $tenantId)->count(), + 'waiting' => Bidding::where('tenant_id', $tenantId)->where('status', 'waiting')->count(), + 'awarded' => Bidding::where('tenant_id', $tenantId)->where('status', 'awarded')->count(), + ]; + } +} +``` + +### 3.10 더미데이터 (Seeder용 10건) + +> React 목업 기준 (`react/src/components/business/construction/bidding/actions.ts`) + +```php +// api/database/seeders/BiddingSeeder.php +$biddings = [ + [ + 'bidding_code' => 'BID-2025-001', + 'client_name' => '이사대표', + 'project_name' => '광장 아파트', + 'bidding_date' => '2025-01-25', + 'total_count' => 15, + 'bidding_amount' => 71000000, + 'bid_date' => '2025-01-20', + 'submission_date' => '2025-01-22', + 'confirm_date' => '2025-01-25', + 'status' => 'awarded', + 'bidder_name' => '홍길동', + 'remarks' => '', + ], + [ + 'bidding_code' => 'BID-2025-002', + 'client_name' => '야사건설', + 'project_name' => '대림아파트', + 'bidding_date' => '2025-01-20', + 'total_count' => 22, + 'bidding_amount' => 100000000, + 'bid_date' => '2025-01-18', + 'submission_date' => null, + 'confirm_date' => null, + 'status' => 'waiting', + 'bidder_name' => '김철수', + 'remarks' => '', + ], + [ + 'bidding_code' => 'BID-2025-003', + 'client_name' => '여의건설', + 'project_name' => '현장아파트', + 'bidding_date' => '2025-01-18', + 'total_count' => 18, + 'bidding_amount' => 85000000, + 'bid_date' => '2025-01-15', + 'submission_date' => '2025-01-16', + 'confirm_date' => '2025-01-18', + 'status' => 'awarded', + 'bidder_name' => '홍길동', + 'remarks' => '', + ], + [ + 'bidding_code' => 'BID-2025-004', + 'client_name' => '이사대표', + 'project_name' => '송파타워', + 'bidding_date' => '2025-01-15', + 'total_count' => 30, + 'bidding_amount' => 120000000, + 'bid_date' => '2025-01-12', + 'submission_date' => '2025-01-13', + 'confirm_date' => '2025-01-15', + 'status' => 'failed', + 'bidder_name' => '이영희', + 'remarks' => '가격 경쟁력 부족', + ], + [ + 'bidding_code' => 'BID-2025-005', + 'client_name' => '야사건설', + 'project_name' => '강남센터', + 'bidding_date' => '2025-01-12', + 'total_count' => 25, + 'bidding_amount' => 95000000, + 'bid_date' => '2025-01-10', + 'submission_date' => '2025-01-11', + 'confirm_date' => null, + 'status' => 'submitted', + 'bidder_name' => '홍길동', + 'remarks' => '', + ], + [ + 'bidding_code' => 'BID-2025-006', + 'client_name' => '여의건설', + 'project_name' => '목동센터', + 'bidding_date' => '2025-01-10', + 'total_count' => 12, + 'bidding_amount' => 78000000, + 'bid_date' => '2025-01-08', + 'submission_date' => '2025-01-09', + 'confirm_date' => '2025-01-10', + 'status' => 'invalid', + 'bidder_name' => '김철수', + 'remarks' => '입찰 조건 미충족', + ], + [ + 'bidding_code' => 'BID-2025-007', + 'client_name' => '이사대표', + 'project_name' => '서초타워', + 'bidding_date' => '2025-01-08', + 'total_count' => 35, + 'bidding_amount' => 150000000, + 'bid_date' => '2025-01-05', + 'submission_date' => null, + 'confirm_date' => null, + 'status' => 'waiting', + 'bidder_name' => '이영희', + 'remarks' => '', + ], + [ + 'bidding_code' => 'BID-2025-008', + 'client_name' => '야사건설', + 'project_name' => '청담프로젝트', + 'bidding_date' => '2025-01-05', + 'total_count' => 40, + 'bidding_amount' => 200000000, + 'bid_date' => '2025-01-03', + 'submission_date' => '2025-01-04', + 'confirm_date' => '2025-01-05', + 'status' => 'awarded', + 'bidder_name' => '홍길동', + 'remarks' => '', + ], + [ + 'bidding_code' => 'BID-2025-009', + 'client_name' => '여의건설', + 'project_name' => '잠실센터', + 'bidding_date' => '2025-01-03', + 'total_count' => 20, + 'bidding_amount' => 88000000, + 'bid_date' => '2025-01-01', + 'submission_date' => null, + 'confirm_date' => null, + 'status' => 'hold', + 'bidder_name' => '김철수', + 'remarks' => '검토 대기 중', + ], + [ + 'bidding_code' => 'BID-2025-010', + 'client_name' => '이사대표', + 'project_name' => '역삼빌딩', + 'bidding_date' => '2025-01-01', + 'total_count' => 10, + 'bidding_amount' => 65000000, + 'bid_date' => '2024-12-28', + 'submission_date' => null, + 'confirm_date' => null, + 'status' => 'waiting', + 'bidder_name' => '이영희', + 'remarks' => '', + ], +]; + +// 통계 요약: +// - total: 10건 +// - waiting: 3건 (BID-002, 007, 010) +// - awarded: 3건 (BID-001, 003, 008) +// - submitted: 1건 (BID-005) +// - failed: 1건 (BID-004) +// - invalid: 1건 (BID-006) +// - hold: 1건 (BID-009) +``` + +--- + +## 4. 상세 작업 내용 + +> 각 Phase 진행 후 이 섹션에 상세 내용 추가 + +### 4.1 Phase 1: Database & Model + +#### 1.1 마이그레이션 파일 생성 +- **상태**: ⏳ 대기 +- **파일**: `api/database/migrations/2026_01_19_XXXXXX_create_biddings_table.php` + +#### 1.2 Model 생성 +- **상태**: ⏳ 대기 +- **파일**: `api/app/Models/Bidding/Bidding.php` + +#### 1.3 Seeder 생성 +- **상태**: ⏳ 대기 +- **파일**: `api/database/seeders/BiddingSeeder.php` +- **데이터**: React 목업 기준 10건 + +--- + +## 5. 컨펌 대기 목록 + +> API 내부 로직 변경 등 승인 필요 항목 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | QuoteService 수정 | `convertToBidding()` 메서드 추가 | api/Quote | ⏳ 대기 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-19 | - | 문서 초안 작성 | - | - | + +--- + +## 7. 참고 문서 + +- **SAM API Rules**: `api/CLAUDE.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **Swagger 가이드**: `docs/guides/swagger-guide.md` +- **React 목업 타입**: `react/src/components/business/construction/bidding/types.ts` +- **React 목업 데이터**: `react/src/components/business/construction/bidding/actions.ts` +- **기존 견적 API**: `react/src/components/business/construction/estimates/actions.ts` + +--- + +## 8. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 8.1 세션 시작 시 (Load Strategy) +```javascript +read_memory("bidding-api-state") // 1. 상태 파악 +read_memory("bidding-api-snapshot") // 2. 사고 흐름 복구 +``` + +### 8.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | 🛠 Snapshot | 현재까지 코드 변경점 저장 | +| **20% 이하** | 🧹 Context Purge | 활성 심볼 저장 | +| **10% 이하** | 🛑 Stop & Save | 최종 상태 저장 | + +### 8.3 Serena 메모리 구조 +- `bidding-api-state`: { phase, progress, next_step } +- `bidding-api-snapshot`: 현재까지의 코드 변경점 요약 + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 API 테스트 케이스 + +| 엔드포인트 | 입력 | 예상 결과 | 실제 결과 | 상태 | +|-----------|------|----------|----------|------| +| GET /biddings | - | 목록 반환 | | ⏳ | +| GET /biddings/stats | - | 통계 반환 | | ⏳ | +| GET /biddings/{id} | id=1 | 단건 반환 | | ⏳ | +| PUT /biddings/{id} | 수정 데이터 | 수정 성공 | | ⏳ | +| POST /quotes/{id}/convert-to-bidding | quote_id | 입찰 생성 | | ⏳ | + +### 9.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| Bidding API CRUD 동작 | ⏳ | | +| 견적 → 입찰 전환 동작 | ⏳ | | +| 더미데이터 10건 생성 | ⏳ | | +| Swagger 문서 완성 | ⏳ | | +| Pint 통과 | ⏳ | | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 견적→입찰 전환 + 더미데이터 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 9.2 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-4 정의 | +| 4 | 의존성이 명시되어 있는가? | ✅ | quotes API 의존 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 7. 참고 문서 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 3.1 절차 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 9.1 테스트 케이스 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 파일/API 명시 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 현재 진행 상태 + 3.1 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 2. 대상 범위 | +| Q4. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/construction-api-integration-plan.md b/plans/archive/construction-api-integration-plan.md new file mode 100644 index 0000000..f217f7a --- /dev/null +++ b/plans/archive/construction-api-integration-plan.md @@ -0,0 +1,480 @@ +# 시공사 페이지 API 연동 계획 + +> **작성일**: 2026-01-08 +> **목적**: 시공사 8개 페이지 Mock → API 연동 +> **기준 문서**: `docs/standards/api-rules.md`, `docs/guides/swagger-guide.md` +> **상태**: ✅ 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 3.4: 노임관리 API 연동 완료 ✅ | +| **다음 작업** | 🎉 **전체 완료** | +| **진행률** | 8/8 (100%) | +| **마지막 업데이트** | 2026-01-12 | + +--- + +## 0. 전제 조건 (Prerequisites) + +### 0.1 환경 확인 +```bash +# Docker 컨테이너 상태 확인 +docker ps | grep sam + +# API 서버 접속 확인 +curl -I http://api.sam.kr/api/health + +# React 개발 서버 확인 +curl -I http://react.sam.kr +``` + +**체크리스트:** +- [ ] Docker 컨테이너 실행 중 (api, react, mysql) +- [ ] api.sam.kr 접속 가능 (200 응답) +- [ ] react.sam.kr 접속 가능 (200 응답) +- [ ] 데이터베이스 연결 정상 + +### 0.2 권한 및 인증 +- [ ] API 개발 권한 (`api/` 디렉토리 수정 가능) +- [ ] React 개발 권한 (`react/` 디렉토리 수정 가능) +- [ ] Sanctum 토큰 발급 방법 숙지 (테스트용) + +### 0.3 필수 도구 +- PHP 8.4+, Composer +- Node.js 20+, pnpm +- Git + +--- + +## 1. 개요 + +### 1.1 배경 +시공사 메뉴의 8개 페이지가 현재 모두 Mock 데이터를 사용하고 있으며, 실제 API 연동이 필요함. +(물량검토관리는 Frontend/기획 미존재로 제외) + +### 1.2 기준 원칙 +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - Service-First: 비즈니스 로직 → Service Layer │ +│ - Multi-tenancy: BelongsToTenant 필수 │ +│ - FormRequest: Controller 검증 금지 │ +│ - Server Actions: React에서 'use server' 패턴 사용 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | actions.ts Mock→API 변경, 타입 수정 | 불필요 | +| ⚠️ 컨펌 필요 | 새 API 엔드포인트 생성, DB 스키마 변경 | **필수** | +| 🔴 금지 | 기존 API 삭제, 테이블 구조 변경 | 별도 협의 | + +### 1.4 준수 규칙 +- `docs/standards/api-rules.md` - API 개발 규칙 ✅ 존재 +- `docs/guides/swagger-guide.md` - Swagger 작성 가이드 ✅ 존재 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 ✅ 존재 + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: 계약관리 (Contract) + +| # | 작업 항목 | 상태 | 서브 문서 | +|---|----------|:----:|----------| +| 1.1 | 계약관리 (contract) | ✅ | [contract-plan.md](./sub/contract-plan.md) | +| 1.2 | 인수인계보고서관리 (handover-report) | ✅ | [handover-report-plan.md](./sub/handover-report-plan.md) | + +### 2.2 Phase 2: 발주관리 (Order) + +| # | 작업 항목 | 상태 | 서브 문서 | +|---|----------|:----:|----------| +| 2.1 | 현장관리 (site-management) | ✅ | [site-management-plan.md](./sub/site-management-plan.md) | +| 2.2 | 구조검토관리 (structure-review) | ✅ | [structure-review-plan.md](./sub/structure-review-plan.md) | +| 2.3 | 물량검토관리 (quantity-review) | ❌ 제외 | Frontend/기획 미존재 | + +### 2.3 Phase 3: 기준정보 (Base Info) + +| # | 작업 항목 | 상태 | 서브 문서 | +|---|----------|:----:|----------| +| 3.1 | 카테고리관리 (categories) | ✅ | [categories-plan.md](./sub/categories-plan.md) | +| 3.2 | 품목관리 (items) | ✅ | [items-plan.md](./sub/items-plan.md) | +| 3.3 | 단가관리 (pricing) | ✅ | [pricing-plan.md](./sub/pricing-plan.md) | +| 3.4 | 노임관리 (labor) | ✅ | [labor-plan.md](./sub/labor-plan.md) | + +--- + +## 3. API 현황 분석 + +### 3.1 기존 API (연동 가능) + +| API | 경로 | 상태 | 대상 컴포넌트 | +|-----|------|:----:|--------------| +| categories | `/api/construction/categories` | ✅ 존재 | 카테고리관리 | +| pricing | `/api/construction/pricing` | ✅ 존재 | 단가관리 | + +### 3.2 신규 개발 필요 API + +| API | 예상 경로 | 우선순위 | 대상 컴포넌트 | +|-----|----------|:--------:|--------------| +| contracts | `/api/construction/contracts` | ✅ 완료 | 계약관리 | +| handover-reports | `/api/construction/handover-reports` | ✅ 완료 | 인수인계보고서 | +| sites | `/api/construction/sites` | ✅ 완료 | 현장관리 | +| structure-reviews | `/api/construction/structure-reviews` | ✅ 완료 | 구조검토관리 | +| quantity-reviews | `/api/construction/quantity-reviews` | ❌ 제외 | 물량검토관리 (Frontend/기획 미존재) | +| items | `/api/construction/items` | 🟢 낮음 | 품목관리 | +| labor | `/api/construction/labor` | 🟢 낮음 | 노임관리 | + +--- + +## 4. 작업 절차 + +### 4.1 단계별 절차 (상세) + +``` +Step 1: 서브 문서 확인 +├── docs/plans/sub/{module}-plan.md 읽기 +├── 현재 Mock 데이터 구조 확인 +└── 필요한 API 엔드포인트 파악 + +Step 2: API 엔드포인트 확인/생성 +├── api/routes/api.php에서 기존 API 확인 +├── 없으면: +│ ├── Controller 생성: php artisan make:controller Api/Construction/{Name}Controller +│ ├── Service 생성: app/Services/Construction/{Name}Service.php +│ ├── FormRequest 생성: php artisan make:request Api/Construction/{Name}Request +│ └── Model 확인/생성 +└── Swagger 문서 작성 + +Step 3: React actions.ts 수정 +├── react/src/components/business/construction/{module}/actions.ts 열기 +├── Mock 데이터 상수 제거 (MOCK_XXX) +├── API 호출 로직 구현: +│ └── const response = await fetch('/api/construction/{endpoint}', {...}) +└── 에러 핸들링 추가 + +Step 4: 타입 정합성 확인 +├── API 응답과 프론트엔드 타입 매칭 +├── types.ts 수정 (snake_case → camelCase 변환 등) +└── 컴포넌트 수정 (필요시) + +Step 5: 테스트 및 검증 +├── API 직접 호출 테스트 (curl/Postman) +├── UI 동작 확인 (브라우저) +└── 에러 케이스 테스트 +``` + +### 4.2 첫 번째 작업 시작점 + +**Phase 1.1 계약관리 시작:** +```bash +# 1. 서브 문서 읽기 +cat docs/plans/sub/contract-plan.md + +# 2. 현재 Mock 확인 +cat react/src/components/business/construction/contract/actions.ts + +# 3. API 존재 여부 확인 +grep -n "contracts" api/routes/api.php + +# 4. 없으면 Controller 생성 +cd api && php artisan make:controller Api/Construction/ContractController --resource +``` + +--- + +## 5. 환경 정보 + +### 5.1 프로젝트 구조 + +``` +SAM/ +├── api/ # Laravel 12 REST API +│ ├── app/Http/Controllers/Api/Construction/ +│ ├── app/Services/Construction/ +│ └── routes/api.php +│ +├── react/ # Next.js 15 Frontend +│ └── src/ +│ ├── app/[locale]/(protected)/construction/ +│ │ ├── project/contract/ # 계약관리 +│ │ ├── project/contract/handover-report/ # 인수인계 +│ │ ├── order/site-management/ # 현장관리 +│ │ ├── order/structure-review/ # 구조검토 +│ │ ├── order/order-management/ # 발주관리 +│ │ └── order/base-info/ # 기준정보 +│ │ ├── categories/ +│ │ ├── items/ +│ │ ├── pricing/ +│ │ └── labor/ +│ └── components/business/construction/ +│ +└── docs/plans/ # 계획 문서 + ├── construction-api-integration-plan.md # 메인 (현재 문서) + └── sub/ # 서브 문서 (9개) +``` + +### 5.2 개발 환경 + +| 항목 | 값 | +|------|-----| +| 도메인 | sam.kr (로컬) | +| API | api.sam.kr | +| React | react.sam.kr | +| PHP | 8.4+ | +| Laravel | 12 | +| Next.js | 15 | + +--- + +## 6. 컴포넌트 분석 요약 + +### 6.1 계약관리 (Contract) + +| 컴포넌트 | Mock 상태 | 주요 기능 | +|----------|:--------:|----------| +| ContractListClient | ✅ Mock | 목록, 검색, 삭제, 필터 | +| 인수인계보고서 | ✅ Mock | 목록, 상세, 삭제 | + +### 6.2 발주관리 (Order) + +| 컴포넌트 | Mock 상태 | 주요 기능 | +|----------|:--------:|----------| +| SiteManagementListClient | ✅ Mock | 현장 목록, 통계, 삭제 | +| StructureReviewListClient | ✅ Mock | 구조검토 목록, 상태 관리 | +| OrderManagementClient | ✅ Mock | 발주 목록, 필터, 삭제 | + +### 6.3 기준정보 (Base Info) + +| 컴포넌트 | Mock 상태 | API 존재 | 주요 기능 | +|----------|:--------:|:-------:|----------| +| CategoryManagementClient | ✅ Mock | ✅ | 카테고리 CRUD, 순서 변경 | +| ItemManagementClient | ✅ Mock | ❌ | 품목 CRUD, 카테고리 연결 | +| PricingListClient | ✅ Mock | ✅ | 단가 CRUD, 버전 관리 | +| LaborManagementClient | ✅ Mock | ❌ | 노임 CRUD, 단가 관리 | + +--- + +## 7. 성공 기준 + +### 7.1 각 페이지 완료 조건 + +| # | 조건 | 확인 방법 | +|---|------|----------| +| 1 | Mock 데이터 완전 제거 | `grep -r "MOCK_" actions.ts` 결과 없음 | +| 2 | API 호출 성공 | 네트워크 탭에서 200 응답 확인 | +| 3 | UI에서 데이터 정상 표시 | 목록에 실제 데이터 표시 | +| 4 | CRUD 동작 정상 | 생성/조회/수정/삭제 모두 동작 | +| 5 | 에러 핸들링 동작 | 네트워크 끊김 시 에러 메시지 표시 | + +### 7.2 전체 완료 조건 + +- [ ] 8개 페이지 모두 API 연동 완료 (4/8) +- [ ] Swagger 문서 작성 완료 +- [ ] 기본 동작 테스트 통과 +- [ ] 코드 리뷰 완료 + +### 7.3 품질 기준 + +- API 응답 시간: < 500ms +- 에러 발생 시 사용자 친화적 메시지 표시 +- TypeScript 타입 에러 0개 +- ESLint 경고 0개 + +--- + +## 8. 검증 방법 + +### 8.1 API 테스트 (curl) + +```bash +# 1. 인증 토큰 획득 (테스트용) +TOKEN=$(curl -s -X POST "http://api.sam.kr/api/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"email":"test@test.com","password":"password"}' | jq -r '.token') + +# 2. 계약 목록 조회 +curl -X GET "http://api.sam.kr/api/construction/contracts" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/json" + +# 3. 계약 상세 조회 +curl -X GET "http://api.sam.kr/api/construction/contracts/1" \ + -H "Authorization: Bearer $TOKEN" + +# 4. 계약 생성 +curl -X POST "http://api.sam.kr/api/construction/contracts" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"title":"테스트 계약","partner_id":1}' +``` + +### 8.2 UI 테스트 체크리스트 + +``` +□ 페이지 접속 시 로딩 스피너 표시 +□ 데이터 로딩 완료 후 목록 표시 +□ 검색 기능 동작 +□ 필터 기능 동작 +□ 페이지네이션 동작 +□ 상세 보기 동작 +□ 생성 폼 동작 +□ 수정 폼 동작 +□ 삭제 확인 및 동작 +□ 에러 발생 시 메시지 표시 +``` + +### 8.3 에러 케이스 테스트 + +| 케이스 | 예상 동작 | 확인 방법 | +|--------|----------|----------| +| 네트워크 끊김 | 에러 메시지 표시 | 네트워크 탭에서 Offline 모드 | +| 401 인증 오류 | 로그인 페이지 리다이렉트 | 토큰 만료 상태에서 접속 | +| 404 데이터 없음 | "데이터 없음" 표시 | 존재하지 않는 ID 접근 | +| 500 서버 오류 | 에러 메시지 표시 | API 강제 에러 발생 | + +--- + +## 9. 세션 관리 + +### 9.1 새 세션 시작 시 + +```bash +# 1. 메인 문서 읽기 (현재 진행 상태 확인) +cat docs/plans/construction-api-integration-plan.md | head -30 + +# 2. "다음 작업" 확인 +grep "다음 작업" docs/plans/construction-api-integration-plan.md + +# 3. 해당 서브 문서 읽기 +cat docs/plans/sub/{다음작업}-plan.md + +# 4. 작업 시작 +``` + +### 9.2 작업 중 체크포인트 + +| 시점 | 행동 | +|------|------| +| 작업 완료 시 | 메인 문서 "현재 진행 상태" 업데이트 | +| 서브 작업 완료 시 | 서브 문서 상태 (⏳→✅) 업데이트 | +| 컨펌 필요 시 | "컨펌 대기 목록"에 추가 | +| 세션 종료 전 | 변경 이력에 기록 | + +### 9.3 세션 종료 시 + +```bash +# 1. 진행 상태 업데이트 +# - 📍 현재 진행 상태 섹션의 "마지막 완료 작업", "다음 작업" 수정 +# - 대상 범위의 상태 아이콘 수정 (⏳ → ✅ 또는 🔄) + +# 2. 변경 이력 추가 +# | 2026-01-08 | 1.1 | 계약관리 API 연동 완료 | contract/actions.ts | - | + +# 3. 커밋 (승인 후) +git add . && git commit -m "feat: [시공사] 1.1 계약관리 - API 연동" +``` + +### 9.4 컨텍스트 관리 (Serena 메모리) + +```javascript +// 세션 시작 시 로드 +read_memory("construction-api-state") + +// 작업 중 저장 (30분마다 또는 주요 완료 시) +write_memory("construction-api-state", { + phase: "1.1", + status: "진행중", + lastCompleted: "Controller 생성", + nextStep: "Service 로직 구현" +}) + +// 컨텍스트 30% 이하 시 +write_memory("construction-api-snapshot", "현재까지 진행 상황 요약...") +``` + +--- + +## 10. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-08 | 초안 | 문서 초안 작성, 9개 컴포넌트 분석 | - | - | +| 2026-01-08 | 보완 | 전제조건, 성공기준, 검증방법, 세션관리 추가 | - | - | +| 2026-01-09 | 1.1 | 계약관리 API 연동 완료 (Backend + Frontend) | api/, react/ | ✅ | +| 2026-01-09 | 1.2 | 인수인계보고서 Frontend API 연동 완료 | react/ | ✅ | +| 2026-01-09 | 2.1 | 현장관리 API 연동 완료 (Backend + Frontend) | api/, react/ | ✅ | +| 2026-01-09 | 2.2 | 구조검토관리 API 연동 완료 (Backend + Frontend) | api/, react/ | ✅ | +| 2026-01-09 | 2.3 | 물량검토관리 제외 (Frontend/기획 미존재) | docs/ | ✅ | +| 2026-01-09 | 3.1 | 카테고리관리 API 연동 완료 (HTTP 메서드 수정) | react/ | ✅ | +| 2026-01-09 | 3.2 | 품목관리 API 연동 완료 (apiClient.delete body 지원 추가) | react/ | ✅ | +| 2026-01-09 | 3.3 | 단가관리 Backend API 보완 (stats, bulkDestroy 추가) | api/ | ✅ | + +--- + +## 11. 참고 문서 + +| 문서 | 경로 | 용도 | +|------|------|------| +| API 규칙 | `docs/standards/api-rules.md` | API 개발 표준 | +| Swagger 가이드 | `docs/guides/swagger-guide.md` | API 문서화 | +| 품질 체크리스트 | `docs/standards/quality-checklist.md` | 완료 전 점검 | +| 빠른 시작 | `docs/quickstart/quick-start.md` | 환경 설정 | +| 개발 명령어 | `docs/quickstart/dev-commands.md` | 자주 쓰는 명령어 | + +--- + +## 12. 서브 문서 링크 + +| Phase | 문서 | 경로 | API 상태 | +|-------|------|------|:--------:| +| 1.1 | 계약관리 | [./sub/contract-plan.md](./sub/contract-plan.md) | ✅ 완료 | +| 1.2 | 인수인계보고서 | [./sub/handover-report-plan.md](./sub/handover-report-plan.md) | ❌ 신규 | +| 2.1 | 현장관리 | [./sub/site-management-plan.md](./sub/site-management-plan.md) | ⚠️ 확인필요 | +| 2.2 | 구조검토관리 | [./sub/structure-review-plan.md](./sub/structure-review-plan.md) | ❌ 신규 | +| 2.3 | 발주관리 | [./sub/order-management-plan.md](./sub/order-management-plan.md) | ❌ 신규 | +| 3.1 | 카테고리관리 | [./sub/categories-plan.md](./sub/categories-plan.md) | ✅ 존재 | +| 3.2 | 품목관리 | [./sub/items-plan.md](./sub/items-plan.md) | ❌ 신규 | +| 3.3 | 단가관리 | [./sub/pricing-plan.md](./sub/pricing-plan.md) | ✅ 존재 | +| 3.4 | 노임관리 | [./sub/labor-plan.md](./sub/labor-plan.md) | ❌ 신규 | + +--- + +## 13. 자기완결성 점검 결과 + +### 13.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 참조 섹션 | +|---|----------|:----:|----------| +| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 7. 성공 기준 | +| 3 | 작업 범위가 구체적인가? | ✅ | 2. 대상 범위 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 0. 전제 조건 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 11. 참고 문서 (검증됨) | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 4. 작업 절차 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 8. 검증 방법 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 명령어 포함 | + +### 13.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 4.2 첫 번째 작업 시작점 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 5.1 프로젝트 구조 + 서브 문서 | +| Q4. 작업 완료 확인 방법은? | ✅ | 7. 성공 기준, 8. 검증 방법 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 11. 참고 문서 | + +**결과: 5/5 통과 → ✅ 자기완결성 확보** + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* +*보완일: 2026-01-08* \ No newline at end of file diff --git a/plans/archive/docs-update-plan.md b/plans/archive/docs-update-plan.md new file mode 100644 index 0000000..1713e06 --- /dev/null +++ b/plans/archive/docs-update-plan.md @@ -0,0 +1,309 @@ +# docs/architecture 문서 업데이트 계획 + +> **작성일**: 2025-12-26 +> **목적**: 현재 시스템 상태와 문서 동기화 +> **기준 문서**: docs/INDEX.md +> **상태**: 🔄 진행중 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4 전체 완료 | +| **다음 작업** | 없음 (완료) | +| **진행률** | 13/13 (100%) ✅ | +| **마지막 업데이트** | 2025-12-26 | + +--- + +## 1. 개요 + +### 1.1 배경 +- 2025-12-13 admin 프로젝트 → mng 프로젝트 전환 완료 +- 문서에 아직 admin 참조가 남아있어 동기화 필요 +- 기술 스택 버전 업데이트 반영 필요 + +### 1.2 기준 원칙 +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 문서 업데이트 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - 현재 시스템 상태와 100% 동기화 │ +│ - admin → mng 전환 완전 반영 │ +│ - 버전 정보 최신화 (React 19.2.1, Next.js 15.5.7) │ +│ - 상호 참조 링크 일관성 유지 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 날짜 갱신, 오타 수정, 버전 업데이트 | 불필요 | +| ⚠️ 컨펌 필요 | 구조 변경, 새 섹션 추가, 문서 삭제 | **필수** | +| 🔴 금지 | 비즈니스 로직 변경, 정책 변경 | 별도 협의 | + +### 1.4 준수 규칙 +- `docs/INDEX.md` - 문서 인덱스 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: 핵심 문서 업데이트 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | system-overview.md - admin→mng 전환 | ✅ | 완료 | +| 1.2 | dev-commands.md - admin→mng 변경 | ✅ | 완료 | +| 1.3 | quick-start.md - claudedocs→docs 경로 수정 | ✅ | 완료 | + +### 2.2 Phase 2: 보조 문서 업데이트 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | INDEX.md - 프로젝트 구조 미세 조정 | ✅ | Admin 참조 제거 | +| 2.2 | quality-checklist.md - 날짜 갱신 | ✅ | 2025-12-26 | +| 2.3 | swagger-guide.md - 날짜 갱신 | ✅ | 2025-12-26 | + +### 2.3 Phase 3: 검증 및 정리 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | security-policy.md - 날짜 갱신 | ✅ | 2025-12-26 | +| 3.2 | database-schema.md - 테이블 수 업데이트 | ✅ | 92개→171개 | + +### 2.4 Phase 4: 오래된 파일 정리/아카이브 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | history/2025-09/ 문서 검토 | ✅ | 참조용 유지 | +| 4.2 | history/2025-11/ 문서 검토 | ✅ | 아카이브로 적절 | +| 4.3 | admin 참조 파일 식별 및 정리 | ✅ | 4개 파일 수정 완료 | +| 4.4 | 완료된 plans/ 문서 정리 | ✅ | D0.8→history, index 업데이트 | +| 4.5 | 중복/불필요 문서 정리 | ✅ | 빈 디렉토리 6개 삭제 | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Step 1: Phase 1 - 핵심 문서 업데이트 +├── 1.1 system-overview.md 전면 업데이트 +│ ├── admin/ 설명 → mng/ 설명 +│ ├── Filament v4 → Pure Blade + Tailwind +│ ├── Docker 서비스 구성 업데이트 +│ └── 저장소 구조 업데이트 +├── 1.2 dev-commands.md 수정 +│ ├── Admin Application → MNG Application +│ └── admin/ 경로 → mng/ 경로 +└── 1.3 quick-start.md 수정 + ├── claudedocs/ → docs/ 경로 + └── 프로젝트 구조 업데이트 + +Step 2: Phase 2 - 보조 문서 업데이트 +├── 2.1 INDEX.md 미세 조정 +├── 2.2 quality-checklist.md 날짜 갱신 +└── 2.3 swagger-guide.md 날짜 갱신 + +Step 3: Phase 3 - 검증 및 정리 +├── 3.1 security-policy.md 날짜 갱신 +├── 3.2 database-schema.md 테이블 수 확인 +└── 3.3 모든 문서 일관성 검증 + +Step 4: Phase 4 - 오래된 파일 정리/아카이브 +├── 4.1 history/2025-09/ 문서 검토 +│ └── 구버전 스키마, 체크포인트 확인 +├── 4.2 history/2025-11/ 문서 검토 +│ └── item-master 관련 아카이브 정리 +├── 4.3 admin 참조 파일 정리 +│ └── mng로 미전환된 파일 식별/수정 +├── 4.4 완료된 plans/ 문서 정리 +│ └── 완료된 계획 문서 삭제/아카이브 +└── 4.5 중복/불필요 문서 정리 + └── 통합 가능 문서 식별 및 처리 +``` + +### 3.2 문서 업데이트 템플릿 + +```markdown +### [항목 ID] 항목명 + +**현재 상태:** +- [현재 상태 설명] + +**목표 상태:** +- [목표 상태 설명] + +**변경 사항:** +- [ ] ✅ [즉시 가능 항목] +- [ ] ⚠️ [컨펌 필요 항목] +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 1: 핵심 문서 업데이트 + +#### 1.1 system-overview.md +- **상태**: ⏳ 대기 +- **주요 변경**: + - [ ] admin/ 섹션 → mng/ 섹션으로 전환 + - [ ] 기술 스택: Filament v4 → Pure Blade + Tailwind CSS 3.x + - [ ] Docker 서비스: design, php73 추가 + - [ ] React 버전: 19.2.0 → 19.2.1 + - [ ] Next.js 버전: 15 → 15.5.7 + - [ ] 도메인 매핑: admin.sam.kr → mng 서비스 설명 + - [ ] 저장소 구조: admin → mng + +#### 1.2 dev-commands.md +- **상태**: ⏳ 대기 +- **주요 변경**: + - [ ] "Admin Application (admin/)" → "MNG Application (mng/)" + - [ ] admin/ 경로 → mng/ 경로 + - [ ] 업데이트 날짜 갱신 + +#### 1.3 quick-start.md +- **상태**: ⏳ 대기 +- **주요 변경**: + - [ ] claudedocs/SAM/ 경로 → docs/ 경로 + - [ ] 프로젝트 구조에 mng, design, planning 추가 + - [ ] admin/ 참조 → mng/ 참조 + - [ ] 업데이트 날짜 갱신 + +### 4.2 Phase 4: 오래된 파일 정리/아카이브 + +#### 4.1 history/2025-09/ 문서 검토 +- **상태**: ⏳ 대기 +- **대상 파일**: + - `history/2025-09/checkpoint.md` - 구버전 체크포인트 + - `history/2025-09/database-schema.md` - 구버전 스키마 (참조용 유지 검토) +- **조치**: 아카이브 적합성 검토, 불필요시 삭제 + +#### 4.2 history/2025-11/ 문서 검토 +- **상태**: ⏳ 대기 +- **대상 파일**: + - `history/2025-11/item-master-gap-analysis.md` + - `history/2025-11/item-master-spec.md` + - `history/2025-11/front-requests/` 디렉토리 + - `history/2025-11/item-master-archived/` 디렉토리 +- **조치**: 현재 유효성 검토, 아카이브 정리 + +#### 4.3 admin 참조 파일 식별 및 정리 +- **상태**: ⏳ 대기 +- **검색 대상**: docs/ 전체에서 "admin" 키워드 포함 파일 +- **조치**: mng로 전환 또는 deprecated 표시 + +#### 4.4 완료된 plans/ 문서 정리 +- **상태**: ⏳ 대기 +- **대상 파일**: + - 완료된 계획 문서 식별 + - 현재 진행중인 문서 유지 +- **조치**: 완료된 계획은 삭제 또는 history/로 이동 + +#### 4.5 중복/불필요 문서 정리 +- **상태**: ⏳ 대기 +- **검토 대상**: + - 내용이 중복된 문서 + - 더 이상 유효하지 않은 문서 + - 통합 가능한 문서 +- **조치**: 통합, 삭제, 또는 아카이브 + +--- + +## 5. 컨펌 대기 목록 + +> 구조 변경 등 승인 필요 항목 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| - | - | - | - | - | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-12-26 | - | 계획 문서 초안 작성 | - | - | +| 2025-12-26 | Phase 4 | 오래된 파일 정리/아카이브 작업 추가 | docs-update-plan.md | - | +| 2025-12-26 | Phase 1 | 핵심 문서 3개 업데이트 완료 | system-overview.md, dev-commands.md, quick-start.md | ✅ | +| 2025-12-26 | Phase 2 | 보조 문서 3개 업데이트 완료 | INDEX.md, quality-checklist.md, swagger-guide.md | ✅ | +| 2025-12-26 | Phase 3 | 검증 및 정리 완료 | security-policy.md, database-schema.md | ✅ | +| 2025-12-26 | Phase 4.1-4.2 | history/ 문서 검토 완료 | - | ✅ | +| 2025-12-26 | Phase 4.4 | plans/ 정리 완료 | D0.8→history, index_plans.md 업데이트 | ✅ | +| 2025-12-26 | Phase 4.3 | admin 참조 파일 정리 | docker-setup, git-conventions, project-launch-roadmap, remote-work-setup | ✅ | + +--- + +## 7. 참고 문서 + +- **문서 인덱스**: `docs/INDEX.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **Serena 메모리**: `docs-update-analysis.md` + +--- + +## 8. 세션 관리 정책 + +### 8.1 세션 시작 시 +``` +list_memories() → 기존 상태 확인 +read_memory("docs-update-analysis") → 분석 결과 로드 +이 계획 문서 읽기 → 컨텍스트 로드 +``` + +### 8.2 작업 중 +- 변경 이력 실시간 업데이트 +- Phase/항목별 상태 업데이트 +- 컨펌 필요 시 대기 목록 추가 + +### 8.3 세션 종료 시 +``` +변경 이력에 최종 업데이트 기록 +write_memory("docs-update-progress") → Serena에 저장 +``` + +### 8.4 Serena 메모리 구조 +``` +docs-update-analysis.md # 분석 결과 (완료) +docs-update-progress.md # 진행 상황 (작업 중 업데이트) +``` + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 문서 일관성 체크 + +| 문서 | admin 참조 | mng 반영 | 날짜 최신화 | 링크 유효 | +|------|:----------:|:--------:|:-----------:|:---------:| +| system-overview.md | | | | | +| dev-commands.md | | | | | +| quick-start.md | | | | | +| INDEX.md | | | | | +| quality-checklist.md | | | | | +| swagger-guide.md | | | | | +| security-policy.md | | | | | +| database-schema.md | | | | | + +### 9.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| admin 참조 완전 제거 | | | +| mng 반영 완료 | | | +| 버전 정보 최신화 | | | +| 상호 참조 링크 유효 | | | + +--- + +*이 문서는 /plan 스킬로 생성되었습니다.* diff --git a/plans/archive/document-management-system-changelog.md b/plans/archive/document-management-system-changelog.md new file mode 100644 index 0000000..ee81f29 --- /dev/null +++ b/plans/archive/document-management-system-changelog.md @@ -0,0 +1,31 @@ +# 문서관리 시스템 - 변경 이력 + +> **본 문서**: `docs/plans/document-management-system-plan.md`의 변경 이력 +> **최종 업데이트**: 2026-02-12 + +--- + +## 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 관련 섹션 | 승인 | +|------|------|----------|----------|------| +| 2026-01-31 | 초안 | 기존 시스템 분석 기반 계획 문서 전면 재작성 | 본 문서 | - | +| 2026-01-31 | Phase 1.1 완료 | 양식 편집 UI 5개 탭 전체 CRUD 확인 (사실상 완료) | 섹션 3.1, 11.1 | - | +| 2026-01-31 | Phase 1.2 완료 | viewJS.php 라우팅 분석 + EGI/SUS 대표 2종 상세 분석 + 공통패턴 추출 | 섹션 3.1, 11.2 | - | +| 2026-01-31 | Phase 1.3 완료 | IncomingInspectionTemplateSeeder 생성. EGI(ID:7), SUS(ID:8) 2종 시드 완료. 결재2+기본필드10+섹션+항목+컬럼 전체 | 섹션 3.1 | - | +| 2026-01-31 | Phase 1.4 완료 | 미리보기 기능 기존 구현 확인. 모달로 결재란+기본정보+검사이미지+검사테이블(complex)+Footer 모두 렌더링 | 섹션 3.1 | - | +| 2026-01-31 | Phase 1.5 완료 | 양식 복제 기능. duplicate() 메서드 + 라우트 + 테이블 버튼 + JS 함수 추가 | 섹션 3.1 | - | +| 2026-01-31 | Phase 2.1 완료 | 문서 생성 기능 보완. ①문서번호 카테고리별 prefix(IQC/PRD/SLS/PUR, YYMMDD-순번) ②결재라인 초기화(template.approvalLines→document_approvals) ③기본필드 뷰 속성 불일치 수정(field_type/label/default_value 매핑, Str::slug로 field_key 생성) ④섹션 title 참조 수정 | 섹션 3.2 | - | +| 2026-01-31 | Phase 2.2 완료 | 문서 데이터 입력 UI. ①섹션별 동적 검사 테이블 렌더링(complex/select/check/measurement/text 컬럼 타입 지원) ②서브 라벨 행(complex 컬럼의 n1/n2/n3) ③정적 컬럼 자동 매핑(NO/검사항목/검사기준/검사방식/검사주기→item속성) ④종합판정+비고 Footer ⑤JS 폼 데이터 수집(기본필드+섹션데이터+체크박스) ⑥백엔드 saveDocumentData() 공통 메서드(section_id/column_id/row_index EAV 저장) | 섹션 3.2 | - | +| 2026-01-31 | Phase 2.3 완료 | 결재 워크플로우. ①API: submit(DRAFT→PENDING), approve(단계별 승인, 전체 완료 시 APPROVED), reject(반려 사유 필수, REJECTED) ②edit.blade: 결재 제출 버튼 + JS ③show.blade: 승인/반려 버튼, 반려 모달, 결재 현황 속성 수정(step/role/acted_at), 상태 배지 CSS ④재제출 시 결재라인 상태 초기화 ⑤라우트: submit/approve/reject 3개 추가 | 섹션 3.2 | - | +| 2026-01-31 | Phase 2.4 완료 | 문서 목록/검색/필터. ①날짜 범위 필터(date_from/date_to) API + UI 추가 ②DRAFT 문서 삭제 버튼 + deleteDocument() JS (showDeleteConfirm + fetch DELETE) ③기존 구현 확인: 상태/템플릿/검색/페이징 정상 동작 | 섹션 3.2 | - | +| 2026-01-31 | Phase 3.1 완료 | 중간검사 양식 구조 설계. ①5130 레거시 4종(절곡/스크린/슬랫/조인트바) viewMidInspect*.php 전체 분석 ②검사항목·기준·판정방식·공차·이미지 문서화 ③컬럼 구조(check/complex/select) 매핑 설계 ④4종 비교표 + 양식 시스템 매핑 전략(Option A/B/C) ⑤공통 구조(결재3단계, 기본필드7개, Footer) 정의 | 섹션 5.2 | - | +| 2026-01-31 | Phase 3.2 완료 | 5130 중간검사 데이터 이관 설계. ①JSON 공통 배열 구조 분석([0]결재/[1]입력값/[2]num/[3]table/[4]log/[5]checkbox) ②JSON→EAV 매핑 테이블(결재→document_approvals, 기본필드/측정값/체크박스→document_data) ③데이터 변환 규칙(날짜mm/dd→datetime, boolean→string, 이름→user_id) ④6단계 이관 프로세스 설계 ⑤절곡품 inputValue named object vs 나머지 flat array 차이 문서화 ⑥주의사항 5건 | 섹션 5.3 | - | +| 2026-01-31 | Phase 3.3 완료 | 중간검사 양식 시드 데이터. MidInspectionTemplateSeeder 생성. ①조인트바(ID:10, 1섹션6항목8컬럼, 고정기준값4개) ②슬랫(ID:11, 1섹션5항목7컬럼, 고정2+도면1) ③스크린(ID:12, 1섹션6항목8컬럼, 겉모양3+치수3) ④절곡품(ID:13, 4섹션11항목7컬럼, 구성품별 분리) ⑤공통: 결재3단계(판매→생산→품질), 기본필드7개, Footer(부적합+종합판정) | 섹션 3.3 | - | +| 2026-01-31 | Phase 3.4 완료 | 검사 기준 이미지 이관. 5130/img/inspection/ → mng/public/img/inspection/ (27개 파일). 가이드레일(벽면/측면×6변형), 하단마감재(4), 케이스(4), 절곡기준서(2), 스크린/슬랫/조인트바(각1), L-BAR(1), 연기차단재(1) | 섹션 5.4 | - | +| 2026-01-31 | Phase 4.1 완료 | API 엔드포인트 설계. ①DocumentTemplate 모델 6개(Template+ApprovalLine+BasicField+Section+SectionItem+Column) ②DocumentTemplateService(list+show) ③DocumentTemplateController(index+show) ④IndexRequest FormRequest ⑤라우트 2개(GET /v1/document-templates, GET /v1/document-templates/{id}) ⑥DocumentTemplateApi.php Swagger(7개 스키마) ⑦Document 결재 워크플로우 활성화(submit/approve/reject/cancel 4개 엔드포인트) ⑧ApproveRequest+RejectRequest FormRequest ⑨DocumentApi.php Swagger에 결재 4개 추가 ⑩Document.template() 참조 경로 수정 | 섹션 3.4, 4.1, 7 | - | +| 2026-01-31 | Phase 4.2 완료 | mng JSON 기반 문서 화면. ①show.blade.php 섹션 테이블 읽기전용 렌더링(complex/select/check/measurement/text 5가지 컬럼 타입) ②select 판정값 배지(적합=초록, 부적합=빨강) ③check 체크마크 SVG ④measurement mono 폰트 ⑤정적 컬럼 매핑(NO/검사항목/기준/방식/주기/규격/분류) ⑥종합판정+비고 Footer(마지막 섹션에 표시) ⑦검사 기준 이미지 표시 ⑧버그 3건 수정: field_key→Str::slug, field_type→field_type, section.name→title | 섹션 3.4 | - | +| 2026-01-31 | Phase 4.3 완료 | 문서 데이터 입력/저장 연동 검증. Phase 2.2~2.3에서 이미 완전 구현 확인: ①edit.blade.php JS 폼 수집(기본필드+섹션데이터+체크박스) ②fetch POST/PATCH→DocumentApiController ③saveDocumentData() EAV 저장(section_id/column_id/row_index) ④판정(적합/부적합) select+종합판정 Footer 저장 정상 ⑤6.2 결정사항 #2(프론트 입력, 결과만 저장) 적용됨. 추가 코드 작업 없음 | 섹션 3.4 | - | +| 2026-02-10 | Phase 5 계획 수립 | Phase 5 확장 계획 수립. ①마스터 진행 관리 문서 신규 생성(document-system-master.md) ②중간검사(PQC) 상세 계획(document-system-mid-inspection.md) ③제품검사(FQC) 상세 계획(document-system-product-inspection.md) ④작업일지 상세 계획(document-system-work-log.md) ⑤핵심 결정사항 5건: 조인트바=슬랫하위유지, 제품검사=개소별1문서, 작업일지=하이브리드, 제품검사=품질검사 동일, 기타문서=추후정의 ⑥기존 plan 문서 Phase 5 섹션 업데이트 | 섹션 3.5, 마스터 문서 | - | +| 2026-02-10 | 방안1 채택 | 검사기준서↔테이블컬럼 연동 분석 및 방안1 결정. ①edit.blade.php 분석(검사기준서 탭=section_fields+items, 테이블컬럼 탭=columns, 완전 독립) ②이슈 수정: 스키마 불일치→section_fields 누락이 실제 원인(컬럼은 모두 존재) ③방안1 채택: items.measurement_type→columns 자동 파생, 테이블컬럼 탭은 확인/미세조정용 ④Phase 5.0 신설(3개 작업: 자동파생 JS, 시더 section_fields 추가, 탭 모드 전환) ⑤결정사항 #9/#10 추가 ⑥4개 문서 업데이트(master, mid-inspection, product-inspection, changelog) | 마스터 섹션 7.5, 결정사항 | - | +| 2026-02-12 | Phase 5.2 전체 완료 | 제품검사(FQC) 폼 구현 5/5 완료. ①5.2.1 ProductInspectionTemplateSeeder(template_id:65, 결재3+기본필드7+섹션2+항목11) ②5.2.2 mng 양식 편집/미리보기 검증 ③5.2.3 API bulk-create-fqc+fqc-status 엔드포인트(DocumentService.bulkCreateFqc/fqcStatus) ④5.2.4 React fqcActions.ts+FqcDocumentContent.tsx 신규, InspectionReportModal/ProductInspectionInputModal 듀얼모드(FQC양식/legacy하드코딩) 전환 ⑤5.2.5 InspectionDetail FQC 진행현황 통계바+개소별 상태뱃지(합격/불합격/진행중/미생성)+조회버튼. OrderSettingItem.orderId 기반 자동 활성화, 없으면 legacy fallback | Phase 5.2, 마스터 문서 | - | \ No newline at end of file diff --git a/plans/archive/document-system-product-inspection.md b/plans/archive/document-system-product-inspection.md new file mode 100644 index 0000000..e43682b --- /dev/null +++ b/plans/archive/document-system-product-inspection.md @@ -0,0 +1,375 @@ +# Phase 5.2: 제품검사(FQC) 폼 구현 계획 + +> **작성일**: 2026-02-10 +> **마스터 문서**: [`document-system-master.md`](./document-system-master.md) +> **상태**: 🔄 진행 중 +> **선행 조건**: Phase 5.0 (공통: 검사기준서↔컬럼 연동) 완료 필요, Phase 5.1과 병렬 진행 가능 +> **최종 분석일**: 2026-02-12 + +--- + +## 1. 개요 + +### 1.1 목적 +mng에서 제품검사(FQC) 양식 템플릿을 관리하고, React 품질관리 화면(`/quality/inspections`)에서 수주건의 **개소별** 제품검사 문서를 생성/입력/결재할 수 있도록 한다. + +### 1.2 제품검사 = 품질검사 +- 동일 개념. "제품검사(FQC: Final Quality Control)"로 통일 +- 수주건(Order) + 개소(OrderItem) 단위로 관리 +- **전수검사**: 수주 50개소 → 제품검사 문서 50건 생성 + +### 1.3 현재 상태 (2026-02-12 분석) + +| 항목 | 상태 | 비고 | +|------|:----:|------| +| React InspectionManagement | ✅ | `components/quality/InspectionManagement/` - 요청관리 CRUD (목록/등록/상세/캘린더) | +| React ProductInspectionDocument | ✅ | `quality/qms/components/documents/` - 하드코딩 11개 항목 | +| React 제품검사 모달 | ✅ | InspectionReportModal, ProductInspectionInputModal | +| React 문서시스템 뷰어 | ✅ | `components/document-system/` - DocumentViewer, TemplateInspectionContent | +| API Inspection 모델 | ✅ | `/api/v1/inspections` - JSON 기반, 단순 status (waiting→completed) | +| API Document 모델 | ✅ | EAV 정규화, 결재 워크플로우 (DRAFT→APPROVED) | +| mng 양식 템플릿 | ❌ | 미존재 (신규 생성 필요) | +| 개소별 문서 자동생성 | ❌ | 미구현 | + +### 1.4 핵심 발견 사항 + +**두 개의 독립적 검사 시스템 존재:** + +| 시스템 | 데이터 모델 | 특징 | +|--------|------------|------| +| InspectionManagement | `inspections` 테이블 (JSON) | 요청관리, 단순 상태, 결재 없음 | +| Document System | `documents` 테이블 (EAV) | 양식 기반, 결재 워크플로우, 이력 관리 | + +**세 가지 검사항목 세트 발견:** + +| 출처 | 항목 | 용도 | +|------|------|------| +| types.ts ProductInspectionData | 겉모양(가공/재봉/조립/연기차단재/하단마감재), 모터, 재질/치수, 시험 | 공장출하검사 | +| 계획문서 (이 문서) | 외관, 작동, 개폐속도, 방연/차연/내화, 안전, 비상개방, 전기배선, 설치, 부속 | **설치 후 최종검사 ← 채택** | +| QMS ProductInspectionDocument | 가공상태, 외관검사, 절단면, 도포상태, 조립, 슬릿, 규격치수, 마감처리, 내벽/마감/배색시트 | 제조품질검사 | + +### 1.5 통합 전략 (확정) + +> **InspectionManagement의 요청관리 흐름(목록/등록/상세/캘린더)은 유지하고, +> 검사 성적서 생성/입력/결재만 documents 시스템으로 전환한다.** + +- `inspections` 테이블: 검사 요청/일정/상태 관리 (meta 정보) → **유지** +- `documents` 테이블: 검사 성적서 (양식 기반 상세 데이터, 결재) → **신규 연동** +- 연결: `documents.linkable_type = 'order_item'`, `document_links`로 Order/Inspection 연결 +- 기존 InspectionReportModal/ProductInspectionInputModal → TemplateInspectionContent 기반 전환 + +### 1.6 성공 기준 +1. mng에서 제품검사 양식 편집/미리보기 정상 동작 +2. 수주 1건 선택 시 개소(OrderItem) 수만큼 Document 자동생성 +3. 각 Document에 해당 개소의 정보(층-부호, 규격, 수량) 자동매핑 +4. 개소별 검사 데이터 입력/저장/조회 가능 +5. 결재 워크플로우 정상 동작 +6. 기존 InspectionManagement 요청관리 기능 정상 유지 + +--- + +## 2. 데이터 흐름 + +``` +Order (수주) +├─ order_no: "KD-TS-260210-01" +├─ client_name: "발주처명" +├─ site_name: "현장명" +├─ quantity: 50 (총 개소 수) +└─ items: OrderItem[] (50건) + ├─ [0] floor_code="1F", symbol_code="A", specification="W7400×H2950" + ├─ [1] floor_code="1F", symbol_code="B", specification="W5200×H3100" + └─ [49] ... + +제품검사 요청 시: + ↓ +Document (50건 자동생성) +├─ Document[0] +│ ├─ template_id → 제품검사 양식 +│ ├─ linkable_type = 'App\Models\OrderItem' +│ ├─ linkable_id = OrderItem[0].id +│ ├─ document_no = "FQC-260210-01" +│ ├─ title = "제품검사 - 1F-A (W7400×H2950)" +│ └─ document_data (EAV) +│ ├─ 기본필드: 납품명, 제품명, 발주처, LOT NO, 로트크기, 검사일자, 검사자 +│ ├─ 검사데이터: 11개 항목별 적합/부적합 +│ └─ Footer: 종합판정(합격/불합격) +├─ Document[1] → OrderItem[1] +└─ Document[49] → OrderItem[49] + ++ document_links 연결: + ├─ link_key="order" → Order.id + └─ link_key="inspection" → Inspection.id (있는 경우) +``` + +### 2.1 linkable 다형성 연결 + +| 필드 | 값 | 설명 | +|------|-----|------| +| `linkable_type` | `App\Models\OrderItem` | OrderItem 모델 | +| `linkable_id` | OrderItem.id | 개소 PK | + +추가로 `document_links` 테이블을 통해: +- Order(수주) 연결: link_key="order" +- Inspection(검사요청) 연결: link_key="inspection" (InspectionManagement에서 연결 시) +- Process(공정) 연결: link_key="process" (해당되는 경우) + +--- + +## 3. 작업 항목 + +| # | 작업 | 상태 | 완료 기준 | 비고 | +|---|------|:----:|----------|------| +| 5.2.1 | mng 제품검사 양식 시더 생성 | ✅ | ProductInspectionTemplateSeeder 작성 (template_id: 65). 결재3+기본필드7+섹션2+항목11+section_fields | 2026-02-12 | +| 5.2.2 | mng 양식 편집/미리보기 검증 | ✅ | 양식 edit → 미리보기 → 저장 정상 동작 확인 | 2026-02-12 | +| 5.2.3 | API 개소별 문서 일괄생성 | ✅ | `POST /api/v1/documents/bulk-create-fqc` + `GET /api/v1/documents/fqc-status`. DocumentService에 bulkCreateFqc/fqcStatus 추가 | 2026-02-12 | +| 5.2.4 | React 제품검사 모달 → 양식 기반 전환 | ✅ | fqcActions.ts + FqcDocumentContent.tsx 신규. InspectionReportModal/ProductInspectionInputModal 듀얼모드(FQC/legacy) | 2026-02-12 | +| 5.2.5 | 개소 목록/진행현황 UI | ✅ | InspectionDetail에 FQC 진행현황 통계 바 + 개소별 상태 뱃지(합격/불합격/진행중/미생성) + 조회 버튼 | 2026-02-12 | + +--- + +## 4. 제품검사 항목 (설치 후 최종검사 11항목 - 확정) + +| # | 카테고리 | 검사항목 | 검사기준 | 검사방식 | 측정유형 | +|---|---------|---------|---------|---------|---------| +| 1 | 외관 | 외관검사 | 사용상 결함이 없을 것 | visual | checkbox | +| 2 | 기능 | 작동상태 | 정상 작동 | visual | checkbox | +| 3 | 기능 | 개폐속도 | 규정 속도 범위 이내 | visual | checkbox | +| 4 | 성능 | 방연성능 | 기준 적합 | visual | checkbox | +| 5 | 성능 | 차연성능 | 기준 적합 | visual | checkbox | +| 6 | 성능 | 내화성능 | 기준 적합 | visual | checkbox | +| 7 | 안전 | 안전장치 | 정상 작동 | visual | checkbox | +| 8 | 안전 | 비상개방 | 정상 작동 | visual | checkbox | +| 9 | 설치 | 전기배선 | 규정 적합 | visual | checkbox | +| 10 | 설치 | 설치상태 | 규정 적합 | visual | checkbox | +| 11 | 부속 | 부속품 | 누락 없음 | visual | checkbox | + +**특성:** +- 모든 항목이 visual/checkbox (적합/부적합) +- numeric 측정값 없음 → columns 구조가 중간검사보다 훨씬 단순 +- **columns 자동 파생(방안1)**: checkbox → 판정(select) 컬럼 + +**결재라인**: 작성(품질) → 검토(품질QC) → 승인(경영) +**Footer**: 부적합 내용 + 종합판정(합격/불합격) +**자동판정**: 모든 항목 적합 → 합격, 1개라도 부적합 → 불합격 + +### 4.1 양식 시더 구조 (MidInspectionTemplateSeeder 패턴) + +```php +// ProductInspectionTemplateSeeder +[ + 'name' => '제품검사 성적서', + 'category' => '품질/제품검사', + 'title' => '제 품 검 사 성 적 서', + 'company_name' => '케이디산업', + 'footer_remark_label' => '부적합 내용', + 'footer_judgement_label' => '종합판정', + 'footer_judgement_options' => ['합격', '불합격'], + + 'approval_lines' => [ + ['name' => '작성', 'dept' => '품질', 'role' => '담당자', 'sort_order' => 1], + ['name' => '검토', 'dept' => '품질', 'role' => 'QC', 'sort_order' => 2], + ['name' => '승인', 'dept' => '경영', 'role' => '대표', 'sort_order' => 3], + ], + + 'basic_fields' => [ + ['label' => '납품명', 'field_type' => 'text'], + ['label' => '제품명', 'field_type' => 'text'], + ['label' => '발주처', 'field_type' => 'text'], + ['label' => 'LOT NO', 'field_type' => 'text'], + ['label' => '로트크기', 'field_type' => 'text'], + ['label' => '검사일자', 'field_type' => 'date'], + ['label' => '검사자', 'field_type' => 'text'], + ], + + 'sections' => [ + [ + 'title' => '제품검사 기준서', + 'items' => [], // 기준서 섹션 (빈 섹션, 향후 확장) + ], + [ + 'title' => '제품검사 DATA', + 'items' => [ + ['category' => '외관', 'item' => '외관검사', ...], + // ... 11개 항목 (모두 visual/checkbox) + ], + ], + ], + + // columns는 자동 파생 (Phase 5.0 방안1) + // checkbox → [NO, 검사항목, 검사기준, 판정(select)] +] +``` + +--- + +## 5. 개소별 문서 일괄생성 로직 + +### 5.1 API 엔드포인트 (계획) + +``` +POST /api/v1/orders/{orderId}/create-fqc +Request: { template_id: number } +Response: { documents: Document[], created_count: number } +``` + +### 5.2 생성 로직 + +```php +// 1. Order + OrderItems 조회 +$order = Order::with('items')->findOrFail($orderId); + +// 2. 개소별 Document 생성 +foreach ($order->items as $index => $orderItem) { + $document = Document::create([ + 'template_id' => $templateId, + 'document_no' => "FQC-" . date('ymd') . "-" . str_pad($index + 1, 2, '0', STR_PAD_LEFT), + 'title' => "제품검사 - {$orderItem->floor_code}-{$orderItem->symbol_code} ({$orderItem->specification})", + 'status' => DocumentStatus::DRAFT, + 'linkable_type' => OrderItem::class, + 'linkable_id' => $orderItem->id, + ]); + + // 3. 기본필드 자동매핑 + $autoFillData = [ + '납품명' => $order->title, + '제품명' => $orderItem->item_name, + '발주처' => $order->client_name, + 'LOT NO' => $order->order_no, + '로트크기' => "1 EA", + ]; + + // 4. document_data에 기본필드 저장 + foreach ($autoFillData as $key => $value) { + DocumentData::create([ + 'document_id' => $document->id, + 'field_key' => Str::slug($key), + 'field_value' => $value, + ]); + } + + // 5. document_links 연결 + DocumentLink::create([ + 'document_id' => $document->id, + 'link_key' => 'order', + 'linkable_type' => Order::class, + 'linkable_id' => $order->id, + ]); + + // 6. 결재라인 초기화 + // ... (기존 패턴 재사용) +} +``` + +### 5.3 개소 진행현황 조회 + +``` +GET /api/v1/orders/{orderId}/fqc-status +Response: { + total: 50, + inspected: 30, + passed: 28, + failed: 2, + pending: 20, + items: [ + { order_item_id: 1, floor_code: "1F", symbol_code: "A", document_id: 101, status: "APPROVED", result: "합격" }, + { order_item_id: 2, floor_code: "1F", symbol_code: "B", document_id: 102, status: "DRAFT", result: null }, + ... + ] +} +``` + +--- + +## 6. 핵심 파일 경로 + +### mng +| 파일 | 용도 | 상태 | +|------|------|:----:| +| `mng/database/seeders/ProductInspectionTemplateSeeder.php` | 제품검사 양식 시더 | 🔄 작성 중 | +| `mng/database/seeders/MidInspectionTemplateSeeder.php` | 참조 패턴 (중간검사) | ✅ | + +### api +| 파일 | 용도 | 상태 | +|------|------|:----:| +| `api/app/Models/Order.php` | 수주 모델 | ✅ | +| `api/app/Models/OrderItem.php` | 수주 상세(개소) 모델 | ✅ | +| `api/app/Models/Documents/Document.php` | 문서 모델 | ✅ | +| `api/app/Models/Qualitys/Inspection.php` | 기존 검사 모델 (IQC/PQC/FQC) | ✅ | +| `api/app/Http/Controllers/Api/V1/OrderController.php` | 수주 컨트롤러 (createFqc 추가 필요) | ⏳ | +| `api/app/Services/DocumentService.php` | 문서 생성 서비스 | ✅ | + +### react +| 파일 | 용도 | 상태 | +|------|------|:----:| +| `react/src/components/quality/InspectionManagement/` | 품질검사 요청관리 (15+ 파일) | ✅ 유지 | +| `react/src/components/quality/InspectionManagement/InspectionList.tsx` | 검사 목록 | ✅ 유지 | +| `react/src/components/quality/InspectionManagement/InspectionDetail.tsx` | 검사 상세 | 🔄 수정 필요 | +| `react/src/components/quality/InspectionManagement/modals/InspectionReportModal.tsx` | 성적서 모달 | 🔄 전환 필요 | +| `react/src/components/quality/InspectionManagement/modals/ProductInspectionInputModal.tsx` | 입력 모달 | 🔄 전환 필요 | +| `react/src/components/document-system/viewer/DocumentViewer.tsx` | 문서 뷰어 | ✅ | +| `react/src/components/document-system/content/TemplateInspectionContent.tsx` | 양식 기반 렌더링 | ✅ | +| `react/src/app/[locale]/(protected)/quality/qms/components/documents/ProductInspectionDocument.tsx` | 하드코딩 문서 | ❌ 대체 예정 | + +--- + +## 7. 기존 Inspection 모델과의 관계 (통합 전략) + +### 7.1 현재 구조 + +``` +inspections 테이블 (JSON 기반) +├─ inspection_type: IQC/PQC/FQC +├─ status: waiting → in_progress → completed +├─ meta: { ... } (JSON) +├─ items: { ... } (JSON - 검사 결과) +└─ extra: { ... } (JSON) + +documents 테이블 (EAV 정규화) +├─ template_id → document_templates +├─ status: DRAFT → PENDING → APPROVED/REJECTED +├─ linkable_type + linkable_id (다형성) +├─ document_data (EAV - 섹션/컬럼/행 기반) +└─ document_approvals (결재 이력) +``` + +### 7.2 통합 후 구조 + +``` +InspectionManagement (요청관리 레이어) - 유지 +├─ 검사 목록/등록/상세/캘린더 +├─ inspections 테이블 (요청/일정/상태) +└─ API: /api/v1/inspections (CRUD) + +Document System (성적서 레이어) - 신규 연동 +├─ 양식 기반 검사 데이터 입력 +├─ documents 테이블 (EAV + 결재) +├─ linkable → OrderItem (개소별) +└─ document_links → Order, Inspection + +연결 포인트: +├─ InspectionDetail에서 "성적서 작성/조회" 시 → Document System 호출 +├─ InspectionReportModal → TemplateInspectionContent 기반 전환 +└─ ProductInspectionInputModal → 양식 기반 입력으로 전환 +``` + +--- + +## 8. 변경 이력 + +| 날짜 | 내용 | +|------|------| +| 2026-02-10 | Phase 5.2 계획 문서 신규 생성 | +| 2026-02-10 | 방안1 반영: 시더에 section_fields 필수, columns 자동 파생. 선행조건 Phase 5.0 추가 | +| 2026-02-12 | 코드베이스 분석 반영: InspectionManagement 발견, 3개 검사항목 세트 정리, 통합 전략 확정 | +| 2026-02-12 | 설치 후 최종검사 11항목 확정, documents 기반 통합 방향 확정 | +| 2026-02-12 | 5.2.1 ProductInspectionTemplateSeeder 작성 완료 (template_id: 65) | +| 2026-02-12 | 5.2.2 mng 양식 편집/미리보기 검증 완료 | +| 2026-02-12 | 5.2.3 API bulk-create-fqc + fqc-status 엔드포인트 구현 완료 | +| 2026-02-12 | 5.2.4 React fqcActions.ts + FqcDocumentContent + 모달 듀얼모드 전환 완료 | +| 2026-02-12 | 5.2.5 InspectionDetail FQC 진행현황 통계 바 + 개소별 상태/조회 UI 완료 | +| 2026-02-12 | **Phase 5.2 전체 완료 (5/5)** | + +--- + +*이 문서는 /plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/erp-api-development-plan-d1.0-changes.md b/plans/archive/erp-api-development-plan-d1.0-changes.md new file mode 100644 index 0000000..d0920b6 --- /dev/null +++ b/plans/archive/erp-api-development-plan-d1.0-changes.md @@ -0,0 +1,559 @@ +# SAM ERP API 개발 작업 계획 - D1.0 변경사항 + +> **작성일**: 2025-12-19 +> **기준 문서**: SAM_ERP_Storyboard_D1.0_251218 (38페이지) +> **이전 버전**: SAM_ERP_Storyboard_D0.8_251216 (85페이지) +> **상태**: ✅ Phase 5 완료 | ✅ Phase 6 완료 | ✅ Phase 7 완료 | ✅ Phase 8 완료 + +--- + +## 📚 참고 문서 + +### 핵심 참고 문서 +| 문서 | 경로 | 용도 | +|------|------|------| +| **기존 개발 계획** | [`erp-api-development-plan.md`](./erp-api-development-plan.md) | D0.8 기준 Phase 1-4 | +| **개발 공통 정책** | [`../guides/PROJECT_DEVELOPMENT_POLICY.md`](../guides/PROJECT_DEVELOPMENT_POLICY.md) | 개발 표준 및 정책 | +| **D0.8 스토리보드** | [`SAM_ERP_Storyboard_D0.8_251216/`](./SAM_ERP_Storyboard_D0.8_251216/) | 이전 버전 UI 참조 | +| **D1.0 스토리보드** | [`SAM_ERP_Storyboard_D1.0_251218/`](./SAM_ERP_Storyboard_D1.0_251218/) | 최신 UI/UX 참조 | + +### 기존 코드 참조 +| 항목 | 경로 | 상태 | +|------|------|------| +| `Board` 모델 | `api/app/Models/Boards/Board.php` | ✅ 존재 | +| `BoardSetting` 모델 | `api/app/Models/Boards/BoardSetting.php` | ✅ 존재 | +| `BoardComment` 모델 | `api/app/Models/Boards/BoardComment.php` | ✅ 존재 | +| `Plan` 모델 | `api/app/Models/Tenants/Plan.php` | ✅ 존재 | +| `Subscription` 모델 | `api/app/Models/Tenants/Subscription.php` | ✅ 존재 | +| `PushNotificationSetting` | `api/app/Models/PushNotificationSetting.php` | ✅ 존재 | + +--- + +## 📊 D1.0 개발 범위 요약 + +| Phase | 구분 | 항목수 | 신규 테이블 | API 수 | 상태 | +|-------|------|--------|------------|--------|------| +| Phase 5 | 기본 확장 | 4개 | 1개 | ~14개 | ✅ 완료 | +| Phase 6 | 핵심 신규 | 2개 | 4개 | ~17개 | ✅ 완료 | +| Phase 7 | 게시판 연동 | 2개 | 0개 | ~15개 | ✅ 완료 | +| Phase 8 | SaaS 확장 | 3개 | 1개 | ~10개 | ✅ 완료 | +| **합계** | | **12개** | **~5개** | **~71개** | | + +--- + +## 🚀 Phase 5: D1.0 기본 확장 ✅ 완료 + +> 기존 테이블/모델 활용, API 추가 중심 +> **완료일: 2025-12-22** (기존 구현 확인) + +### 5.1 사용자 초대 기능 ✅ +> 슬라이드: 2 | 경로: 인사관리 > 사원관리 > 사용자 초대 +> **완료일: 2025-12-19** + +- [x] **테이블 생성** + - [x] `user_invitations` 마이그레이션 (2025_12_19_100001) + - [x] 마이그레이션 실행 및 검증 + +- [x] **모델 생성** + - [x] `UserInvitation` 모델 (BelongsToTenant) + - [x] 관계 정의 (inviter, role, tenant) + - [x] 토큰 생성 헬퍼 (`generateToken()`) + - [x] 상태 상수 (pending, accepted, expired, cancelled) + +- [x] **서비스 구현** + - [x] `UserInvitationService` 생성 + - [x] 이메일 초대 발송 로직 (`invite()`) + - [x] 초대 수락 로직 (`accept()`) + - [x] 토큰 만료 처리 (`expirePendingInvitations()`) + - [x] 초대 재발송 로직 (`resend()`) + +- [x] **API 엔드포인트** (5개) + - [x] `POST /v1/users/invite` - 사용자 초대 (이메일 발송) + - [x] `GET /v1/users/invitations` - 초대 목록 + - [x] `POST /v1/users/invitations/{token}/accept` - 초대 수락 + - [x] `DELETE /v1/users/invitations/{id}` - 초대 취소 + - [x] `POST /v1/users/invitations/{id}/resend` - 초대 재발송 + +- [x] **Swagger 문서** + - [x] `UserInvitationApi.php` 작성 + - [x] 스키마 정의 (UserInvitation, InviteRequest, AcceptRequest) + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +### 5.2 알림설정 확장 ✅ +> 슬라이드: 19-22 | 경로: 기준정보 > 알림설정 +> **완료일: 2025-12-19** + +- [x] **테이블 확장** + - [x] `notification_settings` 테이블 확인/생성 + +- [x] **모델 생성/수정** + - [x] `NotificationSetting` 모델 (BelongsToTenant) + - [x] 카테고리별 그룹화 메서드 + +- [x] **서비스 구현** + - [x] `NotificationSettingService` 생성 + - [x] 카테고리별 조회/수정 로직 + - [x] 사용자별 기본값 생성 로직 + +- [x] **API 엔드포인트** (3개) + - [x] `GET /v1/users/me/notification-settings` - 알림 설정 조회 + - [x] `PUT /v1/users/me/notification-settings` - 알림 설정 수정 + - [x] `PUT /v1/users/me/notification-settings/bulk` - 알림 일괄 설정 + +- [x] **Swagger 문서** + - [x] `NotificationSettingApi.php` 작성 + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +### 5.3 계정정보 수정 (탈퇴/사용중지) ✅ +> 슬라이드: 24 | 경로: 계정정보 +> **완료일: 2025-12-19** + +- [x] **서비스 구현** + - [x] `AccountService` 생성/확장 + - [x] 회원 탈퇴 로직 (`withdraw()`) + - [x] 사용 중지 로직 (`suspend()`) + - [x] 약관 동의 정보 관리 (`getAgreements()`, `updateAgreements()`) + +- [x] **API 엔드포인트** (4개) + - [x] `POST /v1/account/withdraw` - 회원 탈퇴 + - [x] `POST /v1/account/suspend` - 사용 중지 (특정 테넌트) + - [x] `GET /v1/account/agreements` - 약관 동의 정보 조회 + - [x] `PUT /v1/account/agreements` - 약관 동의 정보 수정 + +- [x] **Swagger 문서** + - [x] `AccountApi.php` 확장 + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +### 5.4 매출 상세 확장 (거래명세서) ✅ +> 슬라이드: 9 | 경로: 회계관리 > 매출관리 > 매출 상세 +> **완료일: 2025-12-19** + +**기존 구성요소:** +- `Sale` 모델, `SaleService` 존재 +- `TaxInvoice` 모델 존재 (세금계산서) + +- [x] **서비스 확장** + - [x] `SaleService` 확장 + - [x] 거래명세서 조회 로직 (`getStatement()`) + - [x] 거래명세서 발행 로직 (`issueStatement()`) + - [x] 거래명세서 이메일 발송 로직 (`sendStatement()`) + +- [x] **API 엔드포인트** (3개) + - [x] `GET /v1/sales/{id}/statement` - 거래명세서 조회 + - [x] `POST /v1/sales/{id}/statement/issue` - 거래명세서 발행 + - [x] `POST /v1/sales/{id}/statement/send` - 거래명세서 이메일 발송 + +- [x] **Swagger 문서** + - [x] `SaleApi.php` 확장 (거래명세서 관련 추가) + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +## 🔨 Phase 6: D1.0 핵심 신규 개발 (예상 2-3주) + +> 신규 테이블 + API 전체 신규 구현 + +### 6.1 악성채권 추심관리 ✅ +> 슬라이드: 10-13 | 경로: 회계관리 > 악성채권 추심관리 +> **완료일: 2025-12-19** (commit: c0af888) + +- [x] **테이블 생성** (3개) + - [x] `bad_debts` 마이그레이션 (2025_12_19_160001) + - [x] `bad_debt_documents` 마이그레이션 (2025_12_19_160002) + - [x] `bad_debt_memos` 마이그레이션 (2025_12_19_160003) + - [x] 마이그레이션 실행 및 검증 + +- [x] **모델 생성** (3개) + - [x] `BadDebt` 모델 (BelongsToTenant, SoftDeletes) + - 상태 상수: collecting, legal_action, recovered, bad_debt + - 관계: client, assignedUser, creator, documents, memos + - [x] `BadDebtDocument` 모델 + - 문서 유형: business_license, tax_invoice, additional + - [x] `BadDebtMemo` 모델 + +- [x] **서비스 구현** + - [x] `BadDebtService` 생성 (307줄) + - [x] 악성채권 등록/수정/삭제 로직 + - [x] 상태 전이 로직 (추심중→법적조치→회수완료/대손처리) + - [x] 요약 통계 (총 채권, 상태별 금액) + - [x] 서류 첨부/삭제 로직 + - [x] 메모 추가/삭제 로직 + +- [x] **API 엔드포인트** (11개) + - [x] `GET /v1/bad-debts` - 악성채권 목록 + - [x] `POST /v1/bad-debts` - 악성채권 등록 + - [x] `GET /v1/bad-debts/summary` - 상단 요약 (총 채권, 상태별 금액) + - [x] `GET /v1/bad-debts/{id}` - 악성채권 상세 + - [x] `PUT /v1/bad-debts/{id}` - 악성채권 수정 + - [x] `DELETE /v1/bad-debts/{id}` - 악성채권 삭제 + - [x] `PATCH /v1/bad-debts/{id}/toggle` - 설정 ON/OFF + - [x] `POST /v1/bad-debts/{id}/documents` - 서류 첨부 + - [x] `DELETE /v1/bad-debts/{id}/documents/{docId}` - 서류 삭제 + - [x] `POST /v1/bad-debts/{id}/memos` - 메모 추가 + - [x] `DELETE /v1/bad-debts/{id}/memos/{memoId}` - 메모 삭제 + +- [x] **Swagger 문서** + - [x] `BadDebtApi.php` 작성 (433줄) + - [x] 스키마 정의 (BadDebt, BadDebtDocument, BadDebtMemo, Summary) + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +### 6.2 팝업관리 ✅ +> 슬라이드: 15-16 | 경로: 기준정보 > 팝업관리 +> **완료일: 2025-12-19** + +- [x] **테이블 생성** (1개) + - [x] `popups` 마이그레이션 + ```sql + -- popups (팝업) + id, tenant_id, target_type, target_id, + title, content, status, + started_at, ended_at, options, + created_by, updated_by, deleted_by, + created_at, updated_at, deleted_at + ``` + - [x] 마이그레이션 실행 및 검증 + +- [x] **모델 생성** + - [x] `Popup` 모델 (BelongsToTenant, SoftDeletes) + - target_type: all, department + - status: active, inactive + - 활성 팝업 스코프 (기간 + 상태 체크) + +- [x] **서비스 구현** + - [x] `PopupService` 생성 + - [x] 팝업 CRUD 로직 + - [x] 활성 팝업 조회 로직 (로그인 후 노출용) + - [x] 기간 유효성 검사 로직 + +- [x] **API 엔드포인트** (6개) + - [x] `GET /v1/popups` - 팝업 목록 (관리자용) + - [x] `POST /v1/popups` - 팝업 등록 + - [x] `GET /v1/popups/active` - 활성 팝업 목록 (사용자용) + - [x] `GET /v1/popups/{id}` - 팝업 상세 + - [x] `PUT /v1/popups/{id}` - 팝업 수정 + - [x] `DELETE /v1/popups/{id}` - 팝업 삭제 + +- [x] **Swagger 문서** + - [x] `PopupApi.php` 작성 + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +## 📋 Phase 7: D1.0 게시판 연동 ✅ 완료 +> **완료일: 2025-12-19** + +> 기존 Board 모델 활용, API 엔드포인트 추가 + +**기존 구성요소 (api 프로젝트):** +- `Board` 모델: is_system, board_type, board_code, name, extra_settings +- `BoardSetting` 모델: 커스텀 필드 정의 +- `BoardComment` 모델: 댓글 +- `Post` 모델: 게시글 + +### 7.1 게시판관리 ✅ +> 슬라이드: 17-18 | 경로: 기준정보 > 게시판관리 +> **완료일: 2025-12-19** (기존 구현 활용) + +- [x] **기존 모델 확인/확장** + - [x] `Board` 모델 확인 + - [x] `BoardSetting` 모델 확인 + - [x] 필요 필드 이미 존재 + +- [x] **서비스 구현** + - [x] `BoardService` 존재 (테넌트별 게시판 CRUD 로직) + +- [x] **API 엔드포인트** (5개) + - [x] `GET /v1/boards` - 게시판 목록 + - [x] `POST /v1/boards` - 게시판 생성 + - [x] `GET /v1/boards/{id}` - 게시판 상세 + - [x] `PUT /v1/boards/{id}` - 게시판 수정 + - [x] `DELETE /v1/boards/{id}` - 게시판 삭제 + +- [x] **Swagger 문서** + - [x] `BoardApi.php` 작성 완료 + +--- + +### 7.2 게시판 (사용자용) ✅ +> 슬라이드: 3-7 | 경로: 게시판 +> **완료일: 2025-12-19** + +- [x] **기존 모델 확인/확장** + - [x] `Post` 모델 확인 + - [x] 상단 노출 필드 (is_notice) + - [x] 조회수 필드 (views) + +- [x] **서비스 구현** + - [x] `PostService` 존재 + - [x] 게시글 CRUD 로직 + - [x] 상단 노출 로직 + - [x] 조회수 증가 로직 + - [x] 나의 게시글 조회 로직 ✅ 추가됨 + +- [x] **API 엔드포인트** (10개) + - [x] `GET /v1/boards` - 게시판 목록 (탭용) + - [x] `GET /v1/boards/{code}/posts` - 게시글 목록 + - [x] `POST /v1/boards/{code}/posts` - 게시글 등록 + - [x] `GET /v1/boards/{code}/posts/{id}` - 게시글 상세 + - [x] `PUT /v1/boards/{code}/posts/{id}` - 게시글 수정 + - [x] `DELETE /v1/boards/{code}/posts/{id}` - 게시글 삭제 + - [x] `GET /v1/posts/my` - 나의 게시글 ✅ 신규 추가 + - [x] `GET /v1/boards/{code}/posts/{id}/comments` - 댓글 목록 + - [x] `POST /v1/boards/{code}/posts/{id}/comments` - 댓글 등록 + - [x] `PUT /v1/boards/{code}/posts/{id}/comments/{commentId}` - 댓글 수정 + - [x] `DELETE /v1/boards/{code}/posts/{id}/comments/{commentId}` - 댓글 삭제 + +- [x] **Swagger 문서** + - [x] `BoardApi.php` 작성 완료 + - [x] `PostApi.php` 작성 완료 + +--- + +### 7.3 고객센터 → 게시판관리로 대체 ⏭️ +> 슬라이드: 30-38 | 경로: 고객센터 + +**결정사항:** 고객센터 기능은 기존 게시판관리 시스템으로 구현 +- 공지사항, 이벤트, FAQ, 1:1 문의 → 게시판 유형(board_code)으로 관리 +- 별도 SupportAPI 불필요, 기존 Board/Post API 활용 + +--- + +## 💼 Phase 8: D1.0 SaaS 확장 (예상 1-2주) + +> 기존 Plan/Subscription/Payment 모델 활용 + +### 8.1 구독관리 ✅ +> 슬라이드: 28 | 경로: 구독관리 +> **완료일: 2025-12-22** (기존 구현 확인) + +**기존 구성요소:** +- `Plan` 모델: name, code, price, features(json) +- `Subscription` 모델: tenant_id, plan_id, started_at, ended_at, status +- `DataExport` 모델: 데이터 내보내기 + +- [x] **서비스 확장** + - [x] `SubscriptionService` 확장 (432줄) + - [x] 현재 구독 정보 조회 로직 (`current()`) + - [x] 사용량 조회 로직 (`usage()`) + - [x] 자료 내보내기 로직 (`createExport()`, `getExport()`) + - [x] 서비스 해지 로직 (`cancel()`) + +- [x] **API 엔드포인트** (5개 + 추가 6개) + - [x] `GET /v1/subscriptions/current` - 현재 구독 정보 + - [x] `GET /v1/subscriptions/usage` - 사용량 조회 + - [x] `POST /v1/subscriptions/export` - 자료 내보내기 요청 + - [x] `GET /v1/subscriptions/export/{id}` - 내보내기 상태 조회 + - [x] `POST /v1/subscriptions/{id}/cancel` - 서비스 해지 + - [x] `GET /v1/subscriptions` - 구독 목록 (추가) + - [x] `POST /v1/subscriptions` - 구독 등록 (추가) + - [x] `GET /v1/subscriptions/{id}` - 구독 상세 (추가) + - [x] `POST /v1/subscriptions/{id}/renew` - 구독 갱신 (추가) + - [x] `POST /v1/subscriptions/{id}/suspend` - 일시정지 (추가) + - [x] `POST /v1/subscriptions/{id}/resume` - 재개 (추가) + +- [x] **Swagger 문서** + - [x] `SubscriptionApi.php` 작성 (526줄) + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- +### 8.2 결제내역 ✅ +> 슬라이드: 29 | 경로: 결제내역 +> **완료일: 2025-12-22** (기존 구현 확인) + +**기존 구성요소:** +- `Payment` 모델: subscription_id, amount, payment_method, paid_at, status + +- [x] **서비스 확장** + - [x] `PaymentService` 확장 (357줄) + - [x] 결제 내역 목록 조회 로직 (`index()`) + - [x] 거래명세서 생성 로직 (`statement()`) + - [x] 결제 요약 통계 (`summary()`) + +- [x] **API 엔드포인트** (2개 + 추가 6개) + - [x] `GET /v1/payments` - 결제 내역 목록 + - [x] `GET /v1/payments/{id}/statement` - 거래명세서 조회 + - [x] `GET /v1/payments/summary` - 결제 요약 통계 (추가) + - [x] `GET /v1/payments/{id}` - 결제 상세 (추가) + - [x] `POST /v1/payments` - 결제 등록 (추가) + - [x] `POST /v1/payments/{id}/complete` - 완료 처리 (추가) + - [x] `POST /v1/payments/{id}/cancel` - 취소 (추가) + - [x] `POST /v1/payments/{id}/refund` - 환불 (추가) + +- [x] **Swagger 문서** + - [x] `PaymentApi.php` 작성 (455줄) + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +### 8.3 회사 추가 ✅ +> 슬라이드: 25-27 | 경로: 회사정보 +> **완료일: 2025-12-22** + +- [x] **테이블 생성** (1개) + - [x] `company_requests` 마이그레이션 + ```sql + -- company_requests (회사 추가 신청) + id, user_id, business_number, company_name, ceo_name, + address, phone, email, status, message, reject_reason, + barobill_response(json), approved_by, created_tenant_id, + processed_at, created_at, updated_at + ``` + - [x] 마이그레이션 실행 및 검증 + +- [x] **모델 생성** + - [x] `CompanyRequest` 모델 + - 상태 상수: pending, approved, rejected + - 관계: user, approver, createdTenant + - 스코프: pending(), approved(), rejected() + +- [x] **서비스 구현** + - [x] `CompanyService` 생성 + - [x] 사업자등록번호 유효성 검사 (바로빌 연동 + 체크섬 검증) + - [x] 회사 추가 신청 로직 + - [x] 신청 승인 로직 (테넌트 자동 생성 + 사용자 연결) + - [x] 신청 반려 로직 + - [x] 신청 목록 조회 (관리자용/사용자용) + +- [x] **API 엔드포인트** (7개) + - [x] `POST /v1/companies/check` - 사업자등록번호 유효성 검사 + - [x] `POST /v1/companies/request` - 회사 추가 신청 + - [x] `GET /v1/companies/requests` - 신청 목록 (관리자용) + - [x] `GET /v1/companies/requests/{id}` - 신청 상세 + - [x] `POST /v1/companies/requests/{id}/approve` - 승인 + - [x] `POST /v1/companies/requests/{id}/reject` - 반려 + - [x] `GET /v1/companies/my-requests` - 내 신청 목록 + +- [x] **Swagger 문서** + - [x] `CompanyApi.php` 작성 + +- [ ] **테스트** + - [ ] Feature 테스트 작성 + - [ ] 수동 API 테스트 + +--- + +## 📋 기획 확인 필요 항목 + +> ⚠️ API 구현 전 비즈니스 로직 확정 필요 + +### D1.0 신규 확인 필요 +- [ ] 사용자 초대 시 권한 범위 (테넌트 단위 vs 전사) +- [ ] 악성채권 자동 판정 조건 (연체일수 기준, 기본 90일?) +- [ ] 팝업 노출 우선순위 (복수 팝업 시) +- [ ] 서비스 해지 시 데이터 보관 기간 +- [ ] 자료 내보내기 포맷 (Excel, CSV, JSON) +- [ ] 상단 노출 게시글 최대 개수 (기본 5개) +- [ ] 1:1 문의 상담분류 목록 (문의하기, 신고하기, 건의사항, 서비스 오류) + +### 기존 확인 사항 (D0.8) +- [ ] 테넌트: 신청→승인→만료→해지 전이 조건 +- [ ] 전자결재→회계: 지출결의서 승인 시 출금 자동 생성? +- [ ] 바로빌 API 비용 확인 + +--- + +## 📝 작업 일지 + +### 2025-12-19 +- [x] D1.0 스토리보드 분석 완료 (38페이지) +- [x] D0.8 대비 변경사항 식별 (신규 8개, 수정 4개) +- [x] D1.0 개발 계획 문서 작성 (Phase 5-8) +- [x] 기존 코드베이스 분석 (Board, Plan, Subscription 모델 확인) +- [x] Phase 6.1 악성채권 추심관리 API 개발 완료 (commit: c0af888) +- [x] Phase 6.2 팝업관리 API 개발 완료 +- [x] Phase 7.1 게시판관리 - 기존 구현 확인 완료 +- [x] Phase 7.2 게시판(사용자용) - 기존 구현 확인 + `/posts/my` API 추가 (commit: c15a245) +- [x] Phase 7.3 고객센터 → 게시판관리로 대체 결정 +- [x] Phase 8 SaaS 확장 분석 시작 + +### 2025-12-22 +- [x] Phase 8.1 구독관리 - 기존 구현 확인 완료 +- [x] Phase 8.2 결제내역 - 기존 구현 확인 완료 +- [x] Phase 8.3 회사 추가 API 개발 완료 (commit: 7781253) + - company_requests 테이블 생성 + - CompanyRequest 모델 생성 + - CompanyService 생성 (바로빌 연동 + 테넌트 생성) + - 7개 API 엔드포인트 구현 + - Swagger 문서 작성 +- [x] Phase 5 전체 기존 구현 확인 완료 + - 5.1 사용자 초대: 5개 API (invite, invitations, accept, cancel, resend) + - 5.2 알림설정: 3개 API (notification-settings, update, bulk) + - 5.3 계정정보: 4개 API (withdraw, suspend, agreements) + - 5.4 매출 거래명세서: 3개 API (statement, issue, send) +- [x] D1.0 Phase 5-8 전체 API 개발 완료! + +--- + +## ✅ 완료 기준 + +### Phase 5 완료 조건 (기본 확장) ✅ +- [x] 사용자 초대 API 구현 완료 ✅ 2025-12-19 +- [x] 알림설정 API 확장 완료 ✅ 2025-12-19 +- [x] 계정정보 API 확장 완료 ✅ 2025-12-19 +- [x] 매출 거래명세서 API 구현 완료 ✅ 2025-12-19 +- [x] Swagger 문서 완성 ✅ 2025-12-19 +- [x] Pint 코드 포맷팅 완료 ✅ + +### Phase 6 완료 조건 (핵심 신규) +- [x] 악성채권 추심관리 전체 구현 ✅ 2025-12-18 +- [x] 팝업관리 전체 구현 ✅ 2025-12-19 +- [x] 마이그레이션 검증 완료 +- [x] Swagger 문서 완성 + +### Phase 7 완료 조건 (게시판 연동) ✅ +- [x] 게시판관리 API 구현 완료 ✅ 2025-12-19 +- [x] 게시판 (사용자용) API 구현 완료 ✅ 2025-12-19 +- [x] 고객센터 → 게시판관리로 대체 결정 ✅ 2025-12-19 + +### Phase 8 완료 조건 (SaaS 확장) ✅ +- [x] 구독관리 API 구현 완료 ✅ 2025-12-22 +- [x] 결제내역 API 구현 완료 ✅ 2025-12-22 +- [x] 회사 추가 API 구현 완료 ✅ 2025-12-22 +- [x] 자료 내보내기 기능 구현 ✅ (SubscriptionService에 포함) + +### 전체 완료 조건 +- [ ] 모든 D1.0 API 구현 완료 (~71개) +- [ ] Swagger 문서 100% +- [ ] 통합 테스트 통과 +- [ ] 프론트엔드 연동 준비 완료 + +--- + +## 🔗 관련 링크 + +- **기존 개발 계획**: [`erp-api-development-plan.md`](./erp-api-development-plan.md) +- **API Swagger UI**: http://sam.kr/api-docs/index.html +- **개발 공통 정책**: [`../guides/PROJECT_DEVELOPMENT_POLICY.md`](../guides/PROJECT_DEVELOPMENT_POLICY.md) +- **D1.0 스토리보드**: [`SAM_ERP_Storyboard_D1.0_251218/`](./SAM_ERP_Storyboard_D1.0_251218/) \ No newline at end of file diff --git a/plans/archive/fcm-user-targeted-notification-plan.md b/plans/archive/fcm-user-targeted-notification-plan.md new file mode 100644 index 0000000..59389e2 --- /dev/null +++ b/plans/archive/fcm-user-targeted-notification-plan.md @@ -0,0 +1,369 @@ +# FCM 사용자별 알림 발송 계획 + +> **작성일**: 2026-01-28 +> **목적**: FCM 푸시 알림을 테넌트 전체 브로드캐스트에서 사용자별 타겟 발송으로 변경 +> **상태**: ✅ 구현 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4 - FCM 발송 로직 수정 완료 | +| **다음 작업** | 테스트 검증 | +| **진행률** | 8/8 (100%) | +| **마지막 업데이트** | 2026-01-28 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 TodayIssue 생성 시 FCM 푸시 알림이 **테넌트 전체 사용자** 중 알림 설정이 켜진 모든 사용자에게 발송됨. + +**문제점**: +- 결재요청 알림이 결재자가 아닌 사람에게도 발송됨 +- 기안 승인/반려/완료 알림이 기안자가 아닌 사람에게도 발송됨 +- 불필요한 알림으로 사용자 경험 저하 + +### 1.2 목표 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 목표 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 이슈 타입에 따라 특정 대상자에게만 FCM 발송 │ +│ 2. 사용자별 알림 설정(ON/OFF)이 정상 동작하도록 보장 │ +│ 3. 근태 알림은 제외 (정책 미확정) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 발송 대상 정책 + +| 이슈 타입 | 현재 | 변경 후 대상 | +|-----------|------|-------------| +| **결재요청** | 테넌트 전체 | **결재자(나)** - ApprovalStep.user_id | +| **기안 승인** | 테넌트 전체 | **기안자** - Approval.drafter_id | +| **기안 반려** | 테넌트 전체 | **기안자** - Approval.drafter_id | +| **기안 완료** | 테넌트 전체 | **기안자** - Approval.drafter_id | +| 수주등록 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 추심이슈 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 안전재고 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 지출승인 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 세금신고 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 신규업체 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 입금 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| 출금 | 테넌트 전체 | 테넌트 전체 (변경 없음) | +| **근태 알림** | - | **제외** (정책 미확정) | + +### 1.4 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 필드 추가, 로직 수정, 문서 수정 | 불필요 | +| ⚠️ 컨펌 필요 | 마이그레이션, 새 테이블/컬럼 | **필수** | +| 🔴 금지 | 기존 테이블 구조 변경, 파괴적 변경 | 별도 협의 | + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: 데이터베이스 변경 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | TodayIssue 테이블에 `target_user_id` 컬럼 추가 | ✅ | nullable, FK | +| 1.2 | 마이그레이션 파일 생성 | ✅ | 2026_01_28_132426 | + +### 2.2 Phase 2: 모델 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | TodayIssue 모델에 target_user_id 추가 | ✅ | fillable, relation, scopes | +| 2.2 | TodayIssue::createIssue() 메서드에 targetUserId 파라미터 추가 | ✅ | | + +### 2.3 Phase 3: Observer 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | handleApprovalStepChange() - 결재요청 시 결재자 지정 | ✅ | step->user_id 전달 | +| 3.2 | 기안 승인/반려/완료 알림 추가 (기안자 지정) | ✅ | ApprovalIssueObserver 신규 | + +### 2.4 Phase 4: FCM 발송 로직 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | sendFcmNotification() - target_user_id 있으면 해당 사용자만 | ✅ | | +| 4.2 | getEnabledUserTokens() - 특정 사용자 필터링 로직 추가 | ✅ | | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Step 1: 데이터베이스 변경 +├── today_issues 테이블에 target_user_id 컬럼 추가 +├── 마이그레이션 실행 +└── 검증: 테이블 구조 확인 + +Step 2: TodayIssue 모델 수정 +├── target_user_id fillable 추가 +├── targetUser() relation 추가 +└── createIssue() 파라미터 추가 + +Step 3: TodayIssueObserverService 수정 +├── createIssueWithFcm() 파라미터 추가 +├── handleApprovalStepChange() 수정 - 결재자 지정 +├── 기안 상태 변경 알림 추가 (신규) +└── 근태 알림 비활성화 + +Step 4: FCM 발송 로직 수정 +├── sendFcmNotification() 수정 +├── getEnabledUserTokens() 수정 - targetUserId 파라미터 추가 +└── 검증: 대상자만 수신 확인 +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 1: 데이터베이스 변경 + +**마이그레이션 파일**: +```php +// database/migrations/xxxx_add_target_user_id_to_today_issues_table.php + +Schema::table('today_issues', function (Blueprint $table) { + $table->unsignedBigInteger('target_user_id') + ->nullable() + ->after('source_id') + ->comment('특정 대상 사용자 ID (null이면 테넌트 전체)'); + + $table->foreign('target_user_id') + ->references('id') + ->on('users') + ->onDelete('cascade'); + + $table->index(['tenant_id', 'target_user_id']); +}); +``` + +### 4.2 Phase 2: TodayIssue 모델 수정 + +```php +// app/Models/Tenants/TodayIssue.php + +protected $fillable = [ + // ... 기존 필드 + 'target_user_id', // 추가 +]; + +public function targetUser(): BelongsTo +{ + return $this->belongsTo(User::class, 'target_user_id'); +} + +public static function createIssue( + int $tenantId, + string $sourceType, + ?int $sourceId, + string $badge, + string $content, + ?string $path = null, + bool $needsApproval = false, + ?\DateTime $expiresAt = null, + ?int $targetUserId = null // 추가 +): self { + // ... 기존 로직 + target_user_id 저장 +} +``` + +### 4.3 Phase 3: Observer 수정 + +**결재요청 - 결재자에게만**: +```php +// handleApprovalStepChange() 수정 + +$this->createIssueWithFcm( + tenantId: $approval->tenant_id, + sourceType: TodayIssue::SOURCE_APPROVAL, + sourceId: $step->id, + badge: TodayIssue::BADGE_APPROVAL_REQUEST, + content: __('message.today_issue.approval_pending', [...]), + path: '/approval/inbox', + needsApproval: true, + expiresAt: null, + targetUserId: $step->user_id // 결재자 +); +``` + +**기안 승인/반려/완료 - 기안자에게만** (신규): +```php +// handleApprovalStatusChange() 신규 메서드 + +public function handleApprovalStatusChange(Approval $approval): void +{ + $badge = match($approval->status) { + 'approved' => TodayIssue::BADGE_DRAFT_APPROVED, + 'rejected' => TodayIssue::BADGE_DRAFT_REJECTED, + 'completed' => TodayIssue::BADGE_DRAFT_COMPLETED, + default => null, + }; + + if (!$badge) return; + + $this->createIssueWithFcm( + tenantId: $approval->tenant_id, + sourceType: TodayIssue::SOURCE_APPROVAL, + sourceId: $approval->id, + badge: $badge, + content: __('message.today_issue.'.$approval->status, [...]), + path: '/approval/draft', + needsApproval: false, + expiresAt: Carbon::now()->addDays(7), + targetUserId: $approval->drafter_id // 기안자 + ); +} +``` + +### 4.4 Phase 4: FCM 발송 로직 수정 + +```php +// sendFcmNotification() 수정 + +public function sendFcmNotification(TodayIssue $issue): void +{ + // target_user_id가 있으면 해당 사용자만, 없으면 테넌트 전체 + $tokens = $this->getEnabledUserTokens( + $issue->tenant_id, + $issue->notification_type, + $issue->target_user_id // 추가 + ); + + // ... 기존 발송 로직 +} + +// getEnabledUserTokens() 수정 + +private function getEnabledUserTokens( + int $tenantId, + string $notificationType, + ?int $targetUserId = null // 추가 +): array { + $query = PushDeviceToken::withoutGlobalScopes() + ->where('tenant_id', $tenantId) + ->where('is_active', true) + ->whereNull('deleted_at'); + + // 특정 대상자가 지정된 경우 + if ($targetUserId !== null) { + $query->where('user_id', $targetUserId); + } + + $tokens = $query->get(); + + // 알림 설정 확인 후 필터링 + $enabledTokens = []; + foreach ($tokens as $token) { + if ($this->isNotificationEnabledForUser($tenantId, $token->user_id, $notificationType)) { + $enabledTokens[] = $token->token; + } + } + + return $enabledTokens; +} +``` + +--- + +## 5. 제외 항목 + +### 5.1 근태 알림 (정책 미확정) + +다음 알림 타입은 이번 작업에서 **제외**: +- 연차 알림 +- 출근 알림 +- 지각 알림 +- 결근 알림 + +**사유**: 정책이 모호하여 추후 별도 작업 + +### 5.2 알림 소리 커스터마이징 + +현재는 **하드코딩된 채널별 알림음** 사용: +- `push_urgent`: 긴급 (신규업체) +- `push_payment`: 결재 +- `push_sales_order`: 수주 +- `push_default`: 기타 + +**추후 작업**: 사용자별 알림 설정의 `soundType` 값 기준으로 발송 + +--- + +## 6. 영향받는 파일 + +### API (api/) + +| 파일 | 변경 내용 | +|------|----------| +| `database/migrations/2026_01_28_132426_add_target_user_id_to_today_issues_table.php` | 신규 - 마이그레이션 | +| `app/Models/Tenants/TodayIssue.php` | target_user_id 추가, 신규 뱃지 상수, targetUser 관계, forUser/targetedTo 스코프 | +| `app/Services/TodayIssueObserverService.php` | createIssueWithFcm, sendFcmNotification, getEnabledUserTokens 수정, handleApprovalStatusChange 추가 | +| `app/Observers/TodayIssue/ApprovalIssueObserver.php` | 신규 - 기안 상태 변경 Observer | +| `app/Providers/AppServiceProvider.php` | ApprovalIssueObserver 등록 | +| `lang/ko/message.php` | 신규 메시지 키 추가 (draft_approved/rejected/completed) | + +### React (react/) - 변경 없음 + +프론트엔드 알림 설정 UI는 이미 사용자별로 구현되어 있음. + +--- + +## 7. 검증 방법 + +### 7.1 테스트 시나리오 + +| # | 시나리오 | 예상 결과 | +|---|----------|----------| +| 1 | A가 B에게 결재 요청 | B에게만 FCM 발송 | +| 2 | B가 A의 기안 승인 | A에게만 FCM 발송 | +| 3 | B가 A의 기안 반려 | A에게만 FCM 발송 | +| 4 | 수주 등록 | 테넌트 전체 (알림 ON인 사용자만) | +| 5 | A가 알림 OFF → 수주 등록 | A에게는 발송 안됨 | + +### 7.2 성공 기준 + +- [ ] 결재요청 알림이 결재자에게만 발송됨 +- [ ] 기안 상태 변경 알림이 기안자에게만 발송됨 +- [ ] 사용자별 알림 설정(ON/OFF)이 정상 동작함 +- [ ] 기존 브로드캐스트 이슈(수주, 입금 등)는 정상 동작함 + +--- + +## 8. 참고 문서 + +- `api/app/Services/TodayIssueObserverService.php` - 현재 발송 로직 +- `api/app/Models/NotificationSetting.php` - 알림 설정 모델 +- `react/src/components/settings/NotificationSettings/types.ts` - 프론트엔드 알림 설정 타입 + +--- + +## 9. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-28 | - | 계획 문서 초안 작성 | - | - | +| 2026-01-28 | Phase 1 | target_user_id 컬럼 추가 마이그레이션 | migrations/2026_01_28_132426_* | ✅ | +| 2026-01-28 | Phase 2 | TodayIssue 모델 수정 (fillable, relation, scopes) | TodayIssue.php | ✅ | +| 2026-01-28 | Phase 3 | Observer 수정 (결재자/기안자 타겟팅) | TodayIssueObserverService.php, ApprovalIssueObserver.php | ✅ | +| 2026-01-28 | Phase 4 | FCM 발송 로직 수정 | TodayIssueObserverService.php | ✅ | +| 2026-01-28 | 신규 | ApprovalIssueObserver 생성 | ApprovalIssueObserver.php | ✅ | +| 2026-01-28 | i18n | 기안 상태 알림 메시지 추가 | lang/ko/message.php | ✅ | + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/formula-engine-real-data-plan.md b/plans/archive/formula-engine-real-data-plan.md new file mode 100644 index 0000000..7114c42 --- /dev/null +++ b/plans/archive/formula-engine-real-data-plan.md @@ -0,0 +1,1077 @@ +# 수식 엔진 실제 데이터 연동 계획 + +> **작성일**: 2026-02-19 +> **목적**: FormulaEvaluatorService의 테스트 데이터(SF-/SM-)를 실제 품목(BD-)으로 재구성 +> **기준 문서**: `docs/features/quotes/README.md`, `docs/rules/item-policy.md` +> **상태**: ✅ 완료 (Phase 1-3,5 완료 / Phase 4 후순위 보류) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 문서 최종 업데이트 및 검증 결과 반영 | +| **다음 작업** | 없음 (Phase 4 Generic 데이터는 후순위 보류) | +| **진행률** | 4/5 완료 (Phase 1-3,5 ✅ / Phase 4 ⏭️ 후순위) | +| **마지막 업데이트** | 2026-02-20 17:00 | + +--- + +## 1. 개요 + +### 1.1 배경 + +수식 엔진(FormulaEvaluatorService)에는 두 가지 실행 경로가 있다: +- **Generic 경로**: `quote_formula_*` 4개 테이블 기반 (데이터 드리븐) +- **Kyungdong 경로**: `KyungdongFormulaHandler` 코드 기반 (tenant_id=287 전용) + +**현재 문제:** +1. Generic 경로의 `quote_formula_items` (24건)이 모두 삭제된 SF-/SM- 테스트 품목을 참조 +2. `quote_formula_ranges` (12건)도 모두 SF- 코드 반환 +3. `quote_formula_mappings`는 비어있음 +4. Mapping 수식(id:20,21)이 참조하는 product_id 468, 473도 삭제됨 +5. Kyungdong 핸들러는 BD- 품목을 참조하지만, EST- 코드 일부가 items 테이블에 미등록 +6. 핸들러가 `KyungdongFormulaHandler`로 하드코딩 → 업체 추가 시 확장 불가 구조 + +### 1.2 두 경로 비교 + +| 구분 | Generic 경로 | Kyungdong 경로 | +|------|-------------|---------------| +| **진입 조건** | 전용 핸들러 없는 tenant | 전용 핸들러 있는 tenant | +| **BOM 구성** | quote_formula_items + items.bom 전개 | 코드 기반 동적 조립 | +| **모델 인식** | 없음 (단일 수식 세트) | 모델/마감/타입별 분기 | +| **아이템 참조** | SF-/SM- (삭제됨) | BD- 동적 코드 조합 + EST- 코드 | +| **단가 조회** | prices 테이블 + items.attributes | EstimatePriceService | +| **핸들러 해석** | FormulaHandlerFactory → null → Generic | FormulaHandlerFactory → Tenant{id}/FormulaHandler | +| **상태** | ⏭️ FG.bom 비어있음 (후순위) | ✅ 정비 완료 | + +### 1.3 실행 흐름 (MNG → API) + +#### 현재 (Before) +``` +FormulaEvaluatorService::calculateBomWithDebug() + │ + ├─ if ($tenantId === 287) ← 하드코딩! + │ └─ new KyungdongFormulaHandler() ← 직접 생성! + │ + └─ else → Generic 10단계 +``` + +#### 목표 (After) - Strategy + Factory, Zero Config +``` +[MNG 품목관리 UI] + │ 사용자가 FG 선택 + W0/H0/QTY/MP 입력 + ▼ +ItemManagementApiController::calculateFormula() (mng, 라인 60-86) + │ $item->code, {W0, H0, QTY, MP}, session('selected_tenant_id') + ▼ +FormulaApiService::calculateBom() (mng, 라인 24-82) + │ POST https://nginx/api/v1/quotes/calculate/bom + │ Headers: X-API-KEY, X-TENANT-ID + ▼ +FormulaEvaluatorService::calculateBomWithDebug() (api, 라인 592-596) + │ + ├─ FormulaHandlerFactory::make($tenantId) + │ │ class_exists("Handlers\Tenant{$tenantId}\FormulaHandler") ? + │ │ + │ ├─ 핸들러 존재 → calculateTenantBom($handler, ...) + │ │ └─ Tenant287/FormulaHandler::calculateDynamicItems() + │ │ ├─ calculateSteelItems() → BD- 절곡품 (10종) + │ │ ├─ calculatePartItems() → EST- 부자재 (5종) + │ │ └─ 모터/제어기/주자재/검사비 + │ │ + │ └─ 핸들러 없음 (null) → 10단계 Generic 계산 (라인 613-791) + │ └─ quote_formula_* 테이블 (DB 드리븐) + │ + ▼ +[BOM 결과 JSON 반환] +``` + +#### 핸들러 자동 발견 원리 +``` +FormulaHandlerFactory::make(287) + → class_exists("App\Services\Quote\Handlers\Tenant287\FormulaHandler") + → YES → new Tenant287\FormulaHandler() + → 인터페이스 TenantFormulaHandler 구현 보장 + +FormulaHandlerFactory::make(999) + → class_exists("App\Services\Quote\Handlers\Tenant999\FormulaHandler") + → NO → return null → Generic DB 경로 +``` + +**업체 추가 시**: `Handlers/Tenant{id}/FormulaHandler.php` 파일 1개만 생성. 설정/매핑 불필요. + +### 1.4 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 업체별 핸들러 구조화 (Tenant{id} 기반 자동 발견, Zero Config) │ +│ 2. 경동(287) 핸들러가 실제 운영 로직 (우선 정비) │ +│ 3. Generic 경로는 핸들러 없는 테넌트용 (DB 드리븐, 후순위) │ +│ 4. 품목 마스터에 실제 품목이 모두 등록되어야 함 │ +│ 5. 수식 데이터는 실제 품목 코드만 참조 │ +│ 6. 기존 테스트 데이터는 삭제하지 않음 (완전 이관 후 별도 삭제) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.5 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | items 테이블에 EST- 품목 등록, 핸들러 디렉토리 구조 변경(이동) | 불필요 | +| ⚠️ 컨펌 필요 | 인터페이스/팩토리 신규 생성, FormulaEvaluatorService 분기 로직 변경, quote_formula_* 데이터 추가 | **필수** | +| 🔴 금지 | 테이블 스키마 변경, 핸들러 핵심 계산 로직 변경 | 별도 협의 | + +--- + +## 2. 현황 분석 + +### 2.1 items 테이블 현황 (tenant_id=287) + +| 코드 접두어 | item_type | 건수 | 설명 | 상태 | +|------------|-----------|------|------|------| +| FG- | FG | 18 | 완제품 (7모델 × 타입/마감 조합) | ✅ 정상 | +| BD- | PT | 58 | 절곡물 (모델별 가이드레일/케이스/마구리 등) | ✅ 정상 | +| PT- (레거시) | PT | ~650 | 레거시 부품 (5자리 숫자 코드) | ✅ 정상 | +| RM- | RM | 28 | 원자재 | ✅ 정상 | +| SM- | SM | 61 | 부자재 (레거시) | ✅ 정상 | +| CS- | CS | 4 | 소모품 | ✅ 정상 | +| SF- | - | 0 | 삭제됨 (테스트 데이터) | ❌ 삭제 완료 | +| EST- | PT | 72 | 부자재 (모터/제어기/샤프트/앵글/파이프/원자재 등) | ✅ 등록 완료 | + +### 2.2 KyungdongFormulaHandler가 참조하는 미등록 품목 + +> **중요**: 핸들러는 `EST-` 접두어를 사용 (이전 문서의 `ST-`는 오류) + +#### EST- 코드 (items 미등록, 핸들러가 동적 생성) + +| 코드 패턴 | 라인 | 메서드 | 용도 | 대안 | +|-----------|------|--------|------|------| +| `EST-SMOKE-케이스용` | 519 | calculateSteelItems | 케이스용 연기차단재 | `BD-케이스용 연기차단재` (id:15587) | +| `EST-SMOKE-레일용` | 557 | calculateSteelItems | 가이드레일용 연기차단재 | `BD-가이드레일용 연기차단재` (id:15572) | +| `EST-SHAFT-{size}인치-{length}` | 795 | calculatePartItems | 감기샤프트 | 신규 등록 | +| `EST-PIPE-1.4-{length}` | 854,868 | calculatePartItems | 앵글파이프 | 신규 등록 | +| `EST-ANGLE-BRACKET-{type}` | 891 | calculatePartItems | 모터받침 앵글 | 신규 등록 | +| `EST-ANGLE-MAIN-{type}-{size}` | 912 | calculatePartItems | 부자재 앵글 | 신규 등록 | +| `EST-INSPECTION` | 1010 | calculateDynamicItems | 검사비 | 신규 등록 | +| `EST-RAW-스크린-{type}` | 1019 | calculateDynamicItems | 스크린 원단 | 신규 등록 | +| `EST-RAW-슬랫-{type}` | 1025 | calculateDynamicItems | 슬랫 원단 | 신규 등록 | +| `EST-MOTOR-{voltage}-{capacity}` | 1044 | calculateDynamicItems | 모터 | 신규 등록 | +| `EST-CTRL-{type}` | 1062 | calculateDynamicItems | 제어기 | 신규 등록 | +| `EST-CTRL-뒷박스` | 1087 | calculateDynamicItems | 뒷박스 제어기 | 신규 등록 | + +#### 레거시 숫자 코드 (items 등록됨) + +| 코드 | 라인 | items.id | items.name | item_type | unit | 용도 | +|------|------|----------|-----------|-----------|------|------| +| `00035` | 564 | 14939 | 철재용하장바(SUS)3000 | PT | EA | 하장바 SUS | +| `00036` | 564 | 14940 | 철재용하장바(SUS1.2T) | SM | M | 하장바 EGI | +| `00021` | 619 | 14928 | 평철12T | PT | M | 무게평철12T | +| `90201` | 631 | 15188 | KD환봉(30파이) | PT | EA | 환봉 30파이 (기본) | +| `90202` | 628 | 15189 | KD환봉 | PT | EA | 환봉 35파이 | +| `90203` | 629 | 15190 | KD환봉 | PT | EA | 환봉 45파이 | +| `90204` | 630 | 15191 | KD환봉 | PT | EA | 환봉 50파이 | +| `00013` | - | 14922 | 점검구3 | PT | EA | 점검구 (핸들러에서 미사용) | + +### 2.3 quote_formula_* 현황 + +#### quote_formulas (21건, tenant_id=1) + +| id | type | variable | name | formula | output_type | +|----|------|----------|------|---------|-------------| +| 1 | input | PC | 제품 카테고리 | (없음) | variable | +| 2 | input | W0 | 오픈사이즈 폭 | (없음) | variable | +| 3 | input | H0 | 오픈사이즈 높이 | (없음) | variable | +| 4 | input | GT | 가이드레일 설치유형 | (없음) | variable | +| 5 | input | MP | 모터 전원 | (없음) | variable | +| 6 | input | CT | 연동제어기 | (없음) | variable | +| 7 | input | QTY | 수량 | (없음) | variable | +| 8 | calculation | W1_SCREEN | 제작폭 W1 (스크린) | W0 + 140 | variable | +| 9 | calculation | W1_STEEL | 제작폭 W1 (철재) | W0 + 110 | variable | +| 10 | calculation | H1 | 제작높이 H1 | H0 + 350 | variable | +| 11 | calculation | W | 제작폭 (W) | IF(PC=="스크린", W0+140, W0+110) | variable | +| 12 | calculation | H | 제작높이 (H) | H0 + 350 | variable | +| 13 | calculation | M | 면적 (M) | W * H / 1000000 | variable | +| 14 | calculation | K_SCREEN | 중량 K (스크린) | M * 2 + W0 / 1000 * 14.17 | variable | +| 15 | calculation | K_STEEL | 중량 K (철재) | M * 25 | variable | +| 16 | calculation | K | 중량 (K) | IF(PC=="스크린", M*2+W0/1000*14.17, M*25) | variable | +| 17 | range | MOTOR | 모터 자동선택 | K | item | +| 18 | range | GUIDE | 가이드레일 자동선택 | H | item | +| 19 | range | CASE | 케이스 자동선택 | W | item | +| 20 | mapping | BOM_SCR_001 | FG-SCR-001 BOM 매핑 | (없음) | item | +| 21 | mapping | BOM_STL_001 | FG-STL-001 BOM 매핑 | (없음) | item | + +- id 20: product_id=468 (삭제됨) +- id 21: product_id=473 (삭제됨) + +#### quote_formula_items (24건) - 전부 삭제된 코드 + +| id | formula_id | item_code | item_name | sort | +|----|-----------|-----------|-----------|------| +| 1 | 20 | SF-SCR-F01 | 스크린 원단 | 1 | +| 2 | 20 | SF-SCR-F02 | 가이드레일 (좌) | 2 | +| 3 | 20 | SF-SCR-F03 | 가이드레일 (우) | 3 | +| 4 | 20 | SF-SCR-F04 | 케이스 | 4 | +| 5 | 20 | SF-SCR-F05 | 하부프레임 | 5 | +| 6 | 20 | SF-SCR-M01 | 모터 (소형) | 6 | +| 7 | 20 | SF-SCR-C01 | 제어반 | 7 | +| 8 | 20 | SF-SCR-S01 | 셋팅박스 | 8 | +| 9 | 20 | SF-SCR-SW01 | 권선드럼 | 9 | +| 10 | 20 | SF-SCR-B01 | 브라켓 세트 | 10 | +| 11 | 20 | SF-SCR-SW01 | 스위치 | 11 | +| 12 | 20 | SM-B002 | 볼트 M8x25 | 12 | +| 13 | 20 | SM-N002 | 너트 M8 | 13 | +| 14 | 20 | SM-W002 | 와셔 M8 | 14 | +| 15 | 21 | SF-STL-P01 | 도어 패널 | 1 | +| 16 | 21 | SF-STL-F01 | 문틀 프레임 | 2 | +| 17 | 21 | SF-STL-G01 | 유리창 | 3 | +| 18 | 21 | SF-STL-H01 | 힌지 | 4 | +| 19 | 21 | SF-STL-L01 | 잠금장치 | 5 | +| 20 | 21 | SF-STL-C01 | 도어클로저 | 6 | +| 21 | 21 | SF-STL-S01 | 실링재 | 7 | +| 22 | 21 | SF-STL-PT01 | 파우더 도장 | 8 | +| 23 | 21 | SM-B002 | 볼트 M8x25 | 9 | +| 24 | 21 | SM-N002 | 너트 M8 | 10 | + +#### quote_formula_ranges (12건) - 전부 삭제된 코드 + +| id | formula_id | condition_variable | min | max | result_value | +|----|-----------|-------------------|-----|-----|--------------| +| 1 | 17 (MOTOR) | K | 0 | 30 | SF-SCR-M01 | +| 2 | 17 | K | 30 | 50 | SF-SCR-M02 | +| 3 | 17 | K | 50 | 80 | SF-SCR-M03 | +| 4 | 17 | K | 80 | 9999 | SF-SCR-M04 | +| 5 | 18 (GUIDE) | H | 0 | 2500 | SF-SCR-F02 | +| 6 | 18 | H | 2500 | 3500 | SF-SCR-F02 | +| 7 | 18 | H | 3500 | 4500 | SF-SCR-F02 | +| 8 | 18 | H | 4500 | 9999 | SF-SCR-F02 | +| 9 | 19 (CASE) | W | 0 | 2000 | SF-SCR-F04 | +| 10 | 19 | W | 2000 | 3000 | SF-SCR-F04 | +| 11 | 19 | W | 3000 | 4000 | SF-SCR-F04 | +| 12 | 19 | W | 4000 | 9999 | SF-SCR-F04 | + +#### quote_formula_mappings (0건) - 비어있음 + +### 2.4 FG 모델 매트릭스 + +| 모델 | 카테고리 | 마감 | 가이드레일 타입 | BD 부품 수 | +|------|---------|------|---------------|-----------| +| KSS01 | 스크린 | SUS | 벽면/측면 | 4 (가이드레일×2, 하단마감재, L-BAR) | +| KSS02 | 스크린 | SUS | 벽면/측면 | 4 | +| KSE01 | 스크린 | SUS+EGI | 벽면/측면 | 8 | +| KWE01 | 스크린 | SUS+EGI | 벽면/측면 | 8 | +| KQTS01 | 철재 | SUS | 벽면/측면 | 3 (가이드레일×2, 하단마감재) | +| KTE01 | 철재 | SUS+EGI | 벽면/측면 | 6 | +| KDSS01 | (FG없음) | SUS | 벽면/측면 | 4 | + +### 2.5 가이드레일 규격 매핑 (모델별) + +``` +KSS01/KSS02/KSE01/KWE01 → 벽면: 120*70, 측면: 120*120 +KTE01/KQTS01 → 벽면: 130*75, 측면: 130*125 +KDSS01 → 벽면: 150*150, 측면: 150*212 +``` + +--- + +## 3. 대상 범위 + +### Phase 1: 누락 품목 등록 (items 테이블) ✅ 완료 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | EST-SMOKE 코드 → Phase 3.1로 이관 (핸들러 코드 수정) | ⏭️ | Phase 3에서 처리 | +| 1.2 | EST-MOTOR 품목 등록 (150K~2000K, 전압별) | ✅ | 21건 확인 (220V 8종 + 380V 13종) | +| 1.3 | EST-CTRL 품목 등록 (제어기 종류별) | ✅ | 20건 확인 (기본3 + 방범9 + 방화4 + 기타4) | +| 1.4 | EST-SHAFT 품목 등록 (인치×길이별) | ✅ | 16건 확인 (3~12인치) | +| 1.5 | EST-PIPE 품목 등록 | ✅ | 3건 확인 (1.4T×2 + 2T×1) | +| 1.6 | EST-ANGLE 품목 등록 | ✅ | 8건 확인 (BRACKET 4 + MAIN 4) | +| 1.7 | EST-INSPECTION 품목 등록 | ✅ | 1건 확인 | +| 1.8 | EST-RAW 원자재 품목 등록 | ✅ | 6건 확인 (스크린3 + 슬랫3) | + +### Phase 2: 핸들러 구조화 (Strategy + Factory, Zero Config) ✅ 완료 + +> **설계 원칙**: tenant_id 기반 자동 발견. 설정/매핑/options 없이 클래스 존재 여부만으로 라우팅. + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | `TenantFormulaHandler` 인터페이스 생성 | ✅ | `Contracts/TenantFormulaHandler.php` | +| 2.2 | `FormulaHandlerFactory` 생성 (class_exists 자동 발견) | ✅ | `FormulaHandlerFactory.php` (35줄) | +| 2.3 | `KyungdongFormulaHandler` → `Tenant287/FormulaHandler`로 이동 | ✅ | namespace + implements 완료, 원본 삭제 | +| 2.4 | `FormulaEvaluatorService` 분기 로직 변경 | ✅ | KYUNGDONG_TENANT_ID 상수 제거, Factory::make() 사용 | +| 2.5 | `calculateKyungdongBom()` → `calculateTenantBom()` 일반화 | ✅ | 메서드명 + 파라미터(handler) + 문자열 일반화 | + +### Phase 3: 핸들러 아이템 코드 정비 (Tenant287/FormulaHandler) ✅ 완료 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | EST-SMOKE 코드 → BD- 코드로 변경 | ✅ | BD-케이스용 연기차단재(id:15587), BD-가이드레일용 연기차단재(id:15572) | +| 3.2 | 레거시 숫자 코드(00035, 00036 등) 유지 | ✅ | items 테이블에 등록됨, 변경 불필요 | +| 3.3 | lookupItem 실패 시 Log::warning() 추가 | ✅ | tenant_id, code 포함 경고 로그 | +| 3.4 | tinker E2E 테스트 통과 | ✅ | 17건, 1,167,934원 (KQTS01-SUS-벽면형) | + +### Phase 4: Generic 수식 데이터 재구성 (quote_formula_* 테이블) ⏭️ 후순위 + +> **분석 결과**: Generic 경로는 `items.bom` JSON 필드 기반이나, FG 품목의 bom 필드가 비어있음. +> `quote_formula_*` 테이블은 독립 수식 평가 기능용으로, 메인 BOM 계산 경로에서 직접 사용하지 않음. +> Tenant 287은 핸들러 경로를 사용하므로 현재 실질적 영향 없음. 다른 테넌트 추가 시 진행. + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | 실제 FG 제품용 mapping 수식 신규 생성 | ⏭️ | 다른 테넌트 추가 시 | +| 4.2 | quote_formula_items에 실제 BD- 코드 BOM 세트 추가 | ⏭️ | FG.bom 필드 구성 선행 필요 | +| 4.3 | quote_formula_ranges에 실제 BD- 코드 범위 추가 | ⏭️ | | +| 4.4 | quote_formula_mappings 구성 (FG → BD 모델별 매핑) | ⏭️ | | +| 4.5 | FormulaEvaluatorService 모델 인식 로직 추가 | ⏭️ | | + +### Phase 5: 통합 테스트 및 검증 ✅ 완료 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 5.1 | 7모델 전수 BOM 계산 테스트 (벽면형) | ✅ | 7모델 전부 PASS (18건씩, 1.1M~1.3M원) | +| 5.1b | 측면형 + 대형 규격 테스트 (3000×3000, QTY=2) | ✅ | 3모델 PASS (18건씩, 2.9M~3.2M원) | +| 5.2 | Factory 엣지 케이스 테스트 | ✅ | tenant 0/-1/999999→null, 287→Handler | +| 5.3 | SF-/SM- 잔여 참조 점검 (코드 기준) | ✅ | api/Services/Quote/ 내 참조 0건 | +| 5.4 | React 견적관리 BOM 테스트 | ⏭️ | Phase 4 후순위와 함께 | + +--- + +## 4. 작업 절차 + +### 4.1 단계별 절차 + +``` +Phase 1: 누락 품목 등록 +├── 1.1 EST-SMOKE → BD- 매핑 (코드만 변경, 품목 신규 등록 불필요) +├── 1.2~1.8 EST- 품목 등록 (items 테이블 INSERT) +│ ├── 코드: EST- 접두어 유지 (핸들러 코드와 일치) +│ ├── item_type: PT, tenant_id: 287 +│ └── options: { lot_managed: false, consumption_method: "none" } +└── 등록 후 lookupItem() 호출로 매핑 확인 + +Phase 2: 핸들러 구조화 (Strategy + Factory, Zero Config) +├── 2.1 TenantFormulaHandler 인터페이스 생성 +│ └── Contracts/TenantFormulaHandler.php (신규) +├── 2.2 FormulaHandlerFactory 생성 +│ └── class_exists("Handlers\Tenant{$tenantId}\FormulaHandler") 자동 발견 +├── 2.3 KyungdongFormulaHandler → Tenant287/FormulaHandler 이동 +│ ├── namespace 변경: Handlers → Handlers\Tenant287 +│ ├── implements TenantFormulaHandler 추가 +│ └── 클래스 docblock에 "경동기업 (tenant_id: 287)" 명시 +├── 2.4 FormulaEvaluatorService 분기 로직 변경 +│ ├── 제거: private const KYUNGDONG_TENANT_ID = 287 +│ ├── 제거: if ($tenantId === self::KYUNGDONG_TENANT_ID) +│ └── 추가: $handler = FormulaHandlerFactory::make($tenantId) +└── 2.5 calculateKyungdongBom() → calculateTenantBom($handler, ...) 일반화 + +Phase 3: 핸들러(Tenant287) 아이템 코드 정비 +├── 3.1 EST-SMOKE 코드 변경 (2곳) +│ ├── 라인 519: 'EST-SMOKE-케이스용' → 'BD-케이스용 연기차단재' +│ └── 라인 557: 'EST-SMOKE-레일용' → 'BD-가이드레일용 연기차단재' +├── 3.2 레거시 코드 검토 (00035, 00036, 00021, 90201~90204) +│ └── 현재 items 테이블에 등록되어 있으므로 동작함. 변경 여부 검토만. +├── 3.3 lookupItem()에 미등록 품목 경고 로깅 추가 +│ └── 라인 42-48: null 반환 시 Log::warning() +└── 3.4 MNG 연동 테스트 (https://mng.sam.kr/item-management) + +Phase 4: Generic 수식 데이터 재구성 (기존 데이터 유지, 실제 데이터 추가) +├── 4.1 실제 FG 제품용 mapping 수식 신규 생성 (quote_formulas INSERT) +├── 4.2~4.4 실제 데이터 INSERT (기존 테스트 데이터와 병행) +│ ├── quote_formula_items: BD-/EST- 코드 기반 BOM 구성 +│ ├── quote_formula_ranges: 실제 규격별 BD- 코드 반환 +│ └── quote_formula_mappings: FG 모델 → BD 부품 매핑 +└── 4.5 FormulaEvaluatorService에 모델 인식 로직 추가 + +Phase 5: 통합 테스트 +├── 5.1 MNG 품목관리 - 7모델 전수 테스트 +├── 5.2 React 견적관리 - BOM 계산 테스트 +├── 5.3 단가 정합성 검증 +└── 5.4 잔여 테스트 데이터 참조 점검 +``` + +### 4.2 EST- 품목 등록 상세 + +#### items INSERT 템플릿 + +```sql +INSERT INTO items (tenant_id, item_type, code, name, unit, is_active, created_at, updated_at) +VALUES (287, 'PT', '{code}', '{name}', '{unit}', 1, NOW(), NOW()); +``` + +#### 등록 대상 품목 목록 + +``` +EST-MOTOR-{voltage}-{capacity}: 모터 (전압-용량) +├── EST-MOTOR-220V-150K 150K 모터 220V +├── EST-MOTOR-220V-300K 300K 모터 220V +├── EST-MOTOR-220V-400K 400K 모터 220V +├── EST-MOTOR-220V-500K 500K 모터 220V +├── EST-MOTOR-220V-600K 600K 모터 220V +├── EST-MOTOR-380V-500K 500K 모터 380V +├── EST-MOTOR-380V-600K 600K 모터 380V +├── EST-MOTOR-380V-800K 800K 모터 380V +├── EST-MOTOR-380V-1000K 1000K 모터 380V +└── item_type: PT, unit: EA + +EST-CTRL-{type}: 제어기 +├── EST-CTRL-뒷박스 뒷박스 제어기 +├── EST-CTRL-일반 일반 제어기 +├── EST-CTRL-동보 동보 제어기 +├── EST-CTRL-자탈 자탈 제어기 +├── EST-CTRL-셋팅 셋팅 박스 +└── item_type: PT, unit: EA + +EST-SHAFT-{inch}인치-{length}: 감기샤프트 +├── EST-SHAFT-3인치-300 3인치 300mm +├── EST-SHAFT-4인치-3000 4인치 3000mm +├── EST-SHAFT-4인치-4500 4인치 4500mm +├── EST-SHAFT-4인치-6000 4인치 6000mm +├── EST-SHAFT-5인치-6000 5인치 6000mm +├── EST-SHAFT-5인치-7000 5인치 7000mm +├── EST-SHAFT-5인치-8200 5인치 8200mm +└── item_type: PT, unit: EA + +EST-PIPE-1.4-{length}: 앵글파이프 +├── EST-PIPE-1.4-3000 1.4T 3000mm +├── EST-PIPE-1.4-4500 1.4T 4500mm (핸들러에 없지만 패턴상 추가) +├── EST-PIPE-1.4-6000 1.4T 6000mm +└── item_type: PT, unit: EA + +EST-ANGLE-BRACKET-{type}: 모터받침 앵글 +├── EST-ANGLE-BRACKET-스크린용 +├── EST-ANGLE-BRACKET-철제300K +├── EST-ANGLE-BRACKET-철제400K +├── EST-ANGLE-BRACKET-철제500K이상 +└── item_type: PT, unit: EA + +EST-ANGLE-MAIN-{type}-{size}: 부자재 앵글 +├── EST-ANGLE-MAIN-앵글3T-2.5 +├── EST-ANGLE-MAIN-앵글3T-10 +├── EST-ANGLE-MAIN-앵글4T-2.5 +└── item_type: PT, unit: EA + +EST-INSPECTION: 검사비 +└── item_type: PT, unit: EA + +EST-RAW-스크린-{type}: 스크린 원단 +├── EST-RAW-스크린-실리카 +└── item_type: PT, unit: ㎡ + +EST-RAW-슬랫-{type}: 슬랫 원단 +├── EST-RAW-슬랫-방화 +└── item_type: PT, unit: ㎡ +``` + +> **참고**: 핸들러가 동적으로 코드를 조합하므로, 실제 사용되는 코드 조합만 등록. +> 등록 후 `lookupItem()` 호출 시 item_id/name이 정상 반환되는지 확인. + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 핸들러 구조화 | 인터페이스 + 팩토리 신규, 핸들러 이동 | Services/Quote/ 전체 | ✅ 완료 | +| 2 | FormulaEvaluatorService 분기 변경 | if(287) → Factory::make() | 전체 테넌트 | ✅ 완료 | +| 3 | EST- 품목 코드 체계 | 72건 이미 등록 확인 | items 테이블 | ✅ 완료 (사전 등록됨) | +| 4 | EST-SMOKE → BD- 코드 변경 | 핸들러 라인 519, 557 변경 | Tenant287/FormulaHandler | ✅ 완료 | +| 5 | 레거시 숫자코드 유지 | 00035, 00036 등 유지 결정 | Tenant287/FormulaHandler | ✅ 유지 (items에 등록됨) | +| 6 | Generic 경로에 모델 인식 추가 | 후순위 보류 (Phase 4) | 핸들러 없는 테넌트 | ⏭️ 후순위 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-19 | - | 문서 초안 작성 | - | - | +| 2026-02-19 | - | 자기완결성 보완 (부록 추가) | - | - | +| 2026-02-20 | Phase 1 | EST- 품목 72건 이미 등록 확인 → Phase 1 완료 | items 테이블 | ✅ | +| 2026-02-20 | Phase 2 | TenantFormulaHandler 인터페이스 + FormulaHandlerFactory 생성 | Contracts/TenantFormulaHandler.php, FormulaHandlerFactory.php | ✅ | +| 2026-02-20 | Phase 2 | KyungdongFormulaHandler → Tenant287/FormulaHandler 이동 | Handlers/Tenant287/FormulaHandler.php (신규), Handlers/KyungdongFormulaHandler.php (삭제) | ✅ | +| 2026-02-20 | Phase 2 | FormulaEvaluatorService 분기 로직 변경 (if(287) → Factory::make()) | FormulaEvaluatorService.php | ✅ | +| 2026-02-20 | Phase 2 | calculateKyungdongBom() → calculateTenantBom() 일반화 | FormulaEvaluatorService.php | ✅ | +| 2026-02-20 | Phase 3 | EST-SMOKE-케이스용 → BD-케이스용 연기차단재 (id:15587) | Tenant287/FormulaHandler.php | ✅ | +| 2026-02-20 | Phase 3 | EST-SMOKE-레일용 → BD-가이드레일용 연기차단재 (id:15572) | Tenant287/FormulaHandler.php | ✅ | +| 2026-02-20 | Phase 3 | lookupItem() 미등록 품목 Log::warning() 추가 | Tenant287/FormulaHandler.php | ✅ | +| 2026-02-20 | Phase 4 | Generic 경로 분석 → items.bom 기반, FG.bom 비어있음 → 후순위 결정 | - | ⏭️ | +| 2026-02-20 | Phase 5 | 벽부형 7모델 + 측면형 3모델 tinker 통합 테스트 PASS | - | ✅ | +| 2026-02-20 | Phase 5 | Factory 엣지케이스 + SF-/SM- 잔존 참조 점검 완료 | - | ✅ | +| 2026-02-20 | - | 문서 최종 업데이트 (검증결과, 변경이력, 상태 반영) | formula-engine-real-data-plan.md | ✅ | + +--- + +## 7. 참고 문서 + +- **견적 시스템**: `docs/features/quotes/README.md` +- **품목 정책**: `docs/rules/item-policy.md` +- **DB 스키마**: `docs/specs/database-schema.md` +- **빠른 시작**: `docs/quickstart/quick-start.md` + +--- + +## 8. 관련 파일 및 코드 위치 + +### 8.1 API (api/) - 핵심 코드 위치 + +| 파일 | 메서드 | 라인 | 역할 | +|------|--------|------|------| +| `Services/Quote/FormulaEvaluatorService.php` | `calculateBomWithDebug()` | 592-596 | 메인 엔트리 | +| 같은 파일 | (경동 분기 if문) | 609-611 | **Phase 2에서 Factory로 교체** | +| 같은 파일 | `calculateKyungdongBom()` | 1574-1881 | **Phase 2에서 calculateTenantBom()으로 일반화** | +| 같은 파일 | `KYUNGDONG_TENANT_ID` | 35 | **Phase 2에서 제거** | +| 같은 파일 | `expandBomWithFormulas()` | 1261-1333 | items.bom 재귀 전개 (Generic, 유지) | +| 같은 파일 | `calculateCategoryPrice()` | 812-862 | 카테고리 그룹 기반 단가 (유지) | +| 같은 파일 | `getItemPrice()` | 1066-1097 | 단가 조회 (유지) | +| **신규** `Contracts/TenantFormulaHandler.php` | - | - | **Phase 2에서 생성** | +| **신규** `FormulaHandlerFactory.php` | `make()` | - | **Phase 2에서 생성** | +| `Handlers/KyungdongFormulaHandler.php` | - | - | **→ `Handlers/Tenant287/FormulaHandler.php`로 이동** | +| `Handlers/Tenant287/FormulaHandler.php` | `calculateDynamicItems()` | 963 | **메인 엔트리** (이동 후) | +| 같은 파일 | `calculateSteelItems()` | 448 | 절곡품 10종 계산 | +| 같은 파일 | `calculatePartItems()` | 778 | 부자재 5종 계산 | +| 같은 파일 | `lookupItem()` | 35-49 | 품목 코드 → id/name 조회 (캐싱) | +| 같은 파일 | `withItemMapping()` | 72-87 | 아이템에 item_code/item_id 매핑 | +| 같은 파일 | `getGuideRailSpecs()` | 666-672 | 모델별 가이드레일 규격 매핑 | +| 같은 파일 | `calculateGuideRails()` | 675-730 | 가이드레일 타입별 계산 | +| `Services/Quote/EstimatePriceService.php` | (전체) | - | 단가 조회 서비스 (유지) | +| `Services/FormulaApiService.php` | `calculateBom()` | - | API 서버 호출 래퍼 (유지) | + +### 8.2 MNG (mng/) + +| 파일 | 메서드 | 라인 | 역할 | +|------|--------|------|------| +| `Controllers/Api/Admin/ItemManagementApiController.php` | `calculateFormula()` | 60-86 | 수식 BOM 계산 API | +| `Services/FormulaApiService.php` | `calculateBom()` | 24-82 | POST /api/v1/quotes/calculate/bom | +| `Services/ItemManagementService.php` | `getBomTree()` | - | BOM 트리 조회 (items.bom) | +| `views/item-management/index.blade.php` | JS `calculateFormula()` | - | 프론트 수식 계산 호출 | + +### 8.3 DB 테이블 스키마 + +#### items 테이블 + +| 컬럼 | 타입 | NULL | 설명 | +|------|------|------|------| +| id | bigint unsigned | NO | PK | +| tenant_id | bigint unsigned | NO | 테넌트 | +| item_type | varchar(15) | NO | FG/PT/SM/RM/CS | +| code | varchar(100) | NO | 품목 코드 | +| name | varchar(255) | NO | 품목명 | +| unit | varchar(20) | YES | 단위 (EA/M/㎡) | +| category_id | bigint unsigned | YES | 카테고리 FK | +| process_type | varchar(20) | YES | 공정 유형 | +| item_category | varchar(50) | YES | 품목 카테고리 | +| bom | json | YES | BOM JSON (FG는 현재 NULL) | +| attributes | json | YES | 동적 속성 | +| options | json | YES | 관리 옵션 | +| is_active | tinyint(1) | NO | 활성 (기본 1) | + +#### quote_formula_items 테이블 + +| 컬럼 | 타입 | NULL | 설명 | +|------|------|------|------| +| id | bigint unsigned | NO | PK | +| formula_id | bigint unsigned | NO | quote_formulas FK | +| item_code | varchar(50) | NO | 품목 코드 | +| item_name | varchar(200) | NO | 품목명 | +| specification | varchar(100) | YES | 규격 | +| unit | varchar(20) | NO | 단위 | +| quantity_formula | varchar(500) | NO | 수량 수식 | +| unit_price_formula | varchar(500) | YES | 단가 수식 | +| sort_order | int unsigned | NO | 정렬 | + +#### quote_formula_ranges 테이블 + +| 컬럼 | 타입 | NULL | 설명 | +|------|------|------|------| +| id | bigint unsigned | NO | PK | +| formula_id | bigint unsigned | NO | quote_formulas FK | +| min_value | decimal(15,4) | NO | 최소값 | +| max_value | decimal(15,4) | NO | 최대값 | +| condition_variable | varchar(50) | NO | 조건 변수 (K/H/W) | +| result_value | varchar(500) | NO | 결과값 (품목 코드) | +| result_type | enum('fixed','formula') | NO | 결과 유형 | +| sort_order | int unsigned | NO | 정렬 | + +#### quote_formula_mappings 테이블 + +| 컬럼 | 타입 | NULL | 설명 | +|------|------|------|------| +| id | bigint unsigned | NO | PK | +| formula_id | bigint unsigned | NO | quote_formulas FK | +| source_variable | varchar(50) | NO | 원본 변수 | +| source_value | varchar(200) | NO | 원본 값 | +| result_value | varchar(500) | NO | 결과값 | +| result_type | enum('fixed','formula') | NO | 결과 유형 | +| sort_order | int unsigned | NO | 정렬 | + +#### quote_formulas 테이블 + +| 컬럼 | 타입 | NULL | 설명 | +|------|------|------|------| +| id | bigint unsigned | NO | PK | +| tenant_id | bigint unsigned | NO | 테넌트 | +| category_id | bigint unsigned | NO | 카테고리 FK | +| product_id | bigint unsigned | YES | 매핑 대상 제품 FK | +| name | varchar(200) | NO | 수식명 | +| variable | varchar(50) | NO | 변수명 | +| type | enum('input','calculation','range','mapping') | NO | 유형 | +| formula | text | YES | 수식 표현식 | +| output_type | enum('variable','item') | NO | 출력 유형 | +| sort_order | int unsigned | NO | 정렬 | +| is_active | tinyint(1) | NO | 활성 | + +--- + +## 9. 검증 결과 + +### 9.1 테스트 케이스 (tinker 수동 실행) + +#### 벽부형 7모델 (W0=2000, H0=2500, QTY=1) + +| 모델 | FG 코드 | BOM 항목수 | 총 금액 | 상태 | +|------|---------|----------|--------|------| +| KQTS01 | FG-KQTS01-벽면형-SUS | 18건 | 1,167,934원 | ✅ | +| KSS01 | FG-KSS01-벽면형-SUS | 18건 | ~1.1M원 | ✅ | +| KSS02 | FG-KSS02-벽면형-SUS | 18건 | ~1.1M원 | ✅ | +| KSE01 | FG-KSE01-벽면형-SUS | 18건 | ~1.2M원 | ✅ | +| KSE01-EGI | FG-KSE01-벽면형-EGI | 18건 | ~1.2M원 | ✅ | +| KWE01 | FG-KWE01-벽면형-SUS | 18건 | ~1.2M원 | ✅ | +| KTE01 | FG-KTE01-벽면형-SUS | 18건 | ~1.3M원 | ✅ | + +#### 측면형 + 대형 규격 (W0=4000, H0=5000, QTY=2) + +| 모델 | FG 코드 | BOM 항목수 | 총 금액 | 상태 | +|------|---------|----------|--------|------| +| KQTS01 | FG-KQTS01-측면형-SUS | 18건 | ~2.9M원 | ✅ | +| KSE01 | FG-KSE01-측면형-SUS | 18건 | ~3.1M원 | ✅ | +| KTE01-EGI | FG-KTE01-측면형-EGI | 18건 | ~3.2M원 | ✅ | + +#### Factory 엣지 케이스 + +| tenant_id | 예상 | 실제 | 상태 | +|-----------|------|------|------| +| 287 | Tenant287\FormulaHandler 인스턴스 | ✅ 정상 반환 | ✅ | +| 0 | null | null | ✅ | +| -1 | null | null | ✅ | +| 999999 | null | null | ✅ | + +#### SF-/SM- 잔존 참조 점검 + +| 검색 범위 | 패턴 | 결과 | 상태 | +|-----------|------|------|------| +| api/app/Services/Quote/ | SF- / SM- 코드 참조 | 0건 | ✅ | + +### 9.2 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| FormulaHandlerFactory::make(287)이 Tenant287 핸들러 반환 | ✅ | 자동 발견 정상 동작 | +| FormulaHandlerFactory::make(999)이 null 반환 → Generic 경로 | ✅ | 미등록 테넌트 정상 | +| tinker에서 FG 선택 시 BOM 계산 성공 | ✅ | 벽부 7모델 + 측면 3모델 전수 PASS | +| BOM 결과의 모든 item_code가 items에 존재 | ✅ | BD- 코드 정상 매핑 (lookupItem null 없음) | +| React 견적관리 BOM 벌크 계산 정상 | ⏭️ | Phase 4 후순위와 함께 | +| SF-/SM- 코드 참조 잔존 없음 | ✅ | api/Services/Quote/ 내 0건 확인 | + +--- + +## 부록 A. FG 품목 전체 목록 (18건) + +| id | code | model | guiderail | finishing | major_category | legacy_model_id | +|----|------|-------|-----------|-----------|---------------|-----------------| +| 15515 | FG-KSS01-벽면형-SUS | KSS01 | 벽면형 | SUS마감 | 스크린 | 12 | +| 15516 | FG-KSS01-측면형-SUS | KSS01 | 측면형 | SUS마감 | 스크린 | 13 | +| 15517 | FG-KSE01-벽면형-SUS | KSE01 | 벽면형 | SUS마감 | 스크린 | 14 | +| 15518 | FG-KSE01-벽면형-EGI | KSE01 | 벽면형 | EGI마감 | 스크린 | 15 | +| 15519 | FG-KSE01-측면형-SUS | KSE01 | 측면형 | SUS마감 | 스크린 | 16 | +| 15520 | FG-KSE01-측면형-EGI | KSE01 | 측면형 | EGI마감 | 스크린 | 17 | +| 15521 | FG-KWE01-벽면형-SUS | KWE01 | 벽면형 | SUS마감 | 스크린 | 18 | +| 15522 | FG-KWE01-벽면형-EGI | KWE01 | 벽면형 | EGI마감 | 스크린 | 19 | +| 15523 | FG-KWE01-측면형-SUS | KWE01 | 측면형 | SUS마감 | 스크린 | 20 | +| 15524 | FG-KWE01-측면형-EGI | KWE01 | 측면형 | EGI마감 | 스크린 | 21 | +| 15525 | FG-KQTS01-벽면형-SUS | KQTS01 | 벽면형 | SUS마감 | 철재 | 22 | +| 15526 | FG-KQTS01-측면형-SUS | KQTS01 | 측면형 | SUS마감 | 철재 | 23 | +| 15527 | FG-KTE01-측면형-SUS | KTE01 | 측면형 | SUS마감 | 철재 | 24 | +| 15528 | FG-KTE01-벽면형-SUS | KTE01 | 벽면형 | SUS마감 | 철재 | 25 | +| 15529 | FG-KTE01-측면형-EGI | KTE01 | 측면형 | EGI마감 | 철재 | 26 | +| 15530 | FG-KTE01-벽면형-EGI | KTE01 | 벽면형 | EGI마감 | 철재 | 27 | +| 15531 | FG-KSS02-측면형-SUS | KSS02 | 측면형 | SUS마감 | 스크린 | 28 | +| 15532 | FG-KSS02-벽면형-SUS | KSS02 | 벽면형 | SUS마감 | 스크린 | 29 | + +--- + +## 부록 B. BD- 품목 전체 목록 (58건, 모두 item_type=PT) + +### 가이드레일 (17건) + +| id | code | name | +|----|------|------| +| 15589 | BD-가이드레일-KDSS01-SUS-150*150 | 가이드레일 KDSS01 SUS 150*150 | +| 15590 | BD-가이드레일-KDSS01-SUS-150*212 | 가이드레일 KDSS01 SUS 150*212 | +| 15592 | BD-가이드레일-KQTS01-SUS-130*125 | 가이드레일 KQTS01 SUS 130*125 | +| 15593 | BD-가이드레일-KQTS01-SUS-130*75 | 가이드레일 KQTS01 SUS 130*75 | +| 15596 | BD-가이드레일-KSE01-SUS-120*120 | 가이드레일 KSE01 SUS 120*120 | +| 15597 | BD-가이드레일-KSE01-SUS-120*70 | 가이드레일 KSE01 SUS 120*70 | +| 15598 | BD-가이드레일-KSE01-EGI-120*120 | 가이드레일 KSE01 EGI 120*120 | +| 15599 | BD-가이드레일-KSE01-EGI-120*70 | 가이드레일 KSE01 EGI 120*70 | +| 15603 | BD-가이드레일-KSS01-SUS-120*120 | 가이드레일 KSS01 SUS 120*120 | +| 15604 | BD-가이드레일-KSS01-SUS-120*70 | 가이드레일 KSS01 SUS 120*70 | +| 15607 | BD-가이드레일-KSS02-SUS-120*120 | 가이드레일 KSS02 SUS 120*120 | +| 15608 | BD-가이드레일-KSS02-SUS-120*70 | 가이드레일 KSS02 SUS 120*70 | +| 15610 | BD-가이드레일-KTE01-SUS-130*125 | 가이드레일 KTE01 SUS 130*125 | +| 15611 | BD-가이드레일-KTE01-SUS-130*75 | 가이드레일 KTE01 SUS 130*75 | +| 15612 | BD-가이드레일-KTE01-EGI-130*125 | 가이드레일 KTE01 EGI 130*125 | +| 15613 | BD-가이드레일-KTE01-EGI-130*75 | 가이드레일 KTE01 EGI 130*75 | +| 15617 | BD-가이드레일-KWE01-SUS-120*120 | 가이드레일 KWE01 SUS 120*120 | +| 15618 | BD-가이드레일-KWE01-SUS-120*70 | 가이드레일 KWE01 SUS 120*70 | +| 15619 | BD-가이드레일-KWE01-EGI-120*120 | 가이드레일 KWE01 EGI 120*120 | +| 15620 | BD-가이드레일-KWE01-EGI-120*70 | 가이드레일 KWE01 EGI 120*70 | + +### 하단마감재 (10건) + +| id | code | name | +|----|------|------| +| 15591 | BD-하단마감재-KDSS01-SUS-140*78 | 하단마감재 KDSS01 SUS 140*78 | +| 15594 | BD-하단마감재-KQTS01-SUS-60*30 | 하단마감재 KQTS01 SUS 60*30 | +| 15600 | BD-하단마감재-KSE01-SUS-64*43 | 하단마감재 KSE01 SUS 64*43 | +| 15601 | BD-하단마감재-KSE01-EGI-60*40 | 하단마감재 KSE01 EGI 60*40 | +| 15605 | BD-하단마감재-KSS01-SUS-60*40 | 하단마감재 KSS01 SUS 60*40 | +| 15609 | BD-하단마감재-KSS02-SUS-60*40 | 하단마감재 KSS02 SUS 60*40 | +| 15614 | BD-하단마감재-KTE01-SUS-64*34 | 하단마감재 KTE01 SUS 64*34 | +| 15615 | BD-하단마감재-KTE01-EGI-60*30 | 하단마감재 KTE01 EGI 60*30 | +| 15621 | BD-하단마감재-KWE01-SUS-64*43 | 하단마감재 KWE01 SUS 64*43 | +| 15622 | BD-하단마감재-KWE01-EGI-60*40 | 하단마감재 KWE01 EGI 60*40 | + +### L-BAR (5건) + +| id | code | name | +|----|------|------| +| 15588 | BD-L-BAR-KDSS01-17*100 | L-BAR KDSS01 17*100 | +| 15595 | BD-L-BAR-KSE01-17*60 | L-BAR KSE01 17*60 | +| 15602 | BD-L-BAR-KSS01-17*60 | L-BAR KSS01 17*60 | +| 15606 | BD-L-BAR-KSS02-17*60 | L-BAR KSS02 17*60 | +| 15616 | BD-L-BAR-KWE01-17*60 | L-BAR KWE01 17*60 | + +### 케이스 (11건) + +| id | code | name | +|----|------|------| +| 15577 | BD-케이스-500*350 | 케이스 500*350 | +| 15578 | BD-케이스-500*380 | 케이스 500*380 | +| 15579 | BD-케이스-600*500 | 케이스 600*500 | +| 15580 | BD-케이스-600*550 | 케이스 600*550 | +| 15581 | BD-케이스-650*500 | 케이스 650*500 | +| 15582 | BD-케이스-650*550 | 케이스 650*550 | +| 15583 | BD-케이스-700*550 | 케이스 700*550 | +| 15584 | BD-케이스-700*600 | 케이스 700*600 | +| 15585 | BD-케이스-780*600 | 케이스 780*600 | +| 15586 | BD-케이스-780*650 | 케이스 780*650 | +| 15587 | BD-케이스용 연기차단재 | 케이스용 연기차단재 | + +### 마구리 (10건) + +| id | code | name | +|----|------|------| +| 15565 | BD-마구리-505*355 | 마구리 505*355 | +| 15566 | BD-마구리-505*385 | 마구리 505*385 | +| 15567 | BD-마구리-605*555 | 마구리 605*555 | +| 15568 | BD-마구리-655*555 | 마구리 655*555 | +| 15569 | BD-마구리-705*605 | 마구리 705*605 | +| 15570 | BD-마구리-785*685 | 마구리 785*685 | +| 15573 | BD-마구리-655*505 | 마구리 655*505 | +| 15574 | BD-마구리-705*555 | 마구리 705*555 | +| 15575 | BD-마구리-785*605 | 마구리 785*605 | +| 15576 | BD-마구리-785*655 | 마구리 785*655 | + +### 기타 (5건) + +| id | code | name | +|----|------|------| +| 15571 | BD-보강평철-50 | 보강평철 50 | +| 15572 | BD-가이드레일용 연기차단재 | 가이드레일용 연기차단재 | + +--- + +## 부록 C. 코드 변경 포인트 + +### C.1 EST-SMOKE → BD- 변경 (Phase 3.1) + +**파일**: `api/app/Services/Quote/Handlers/Tenant287/FormulaHandler.php` (이동 후) + +``` +라인 519: 'EST-SMOKE-케이스용' → 'BD-케이스용 연기차단재' (id: 15587) +라인 557: 'EST-SMOKE-레일용' → 'BD-가이드레일용 연기차단재' (id: 15572) +``` + +### C.2 레거시 숫자 코드 매핑 (Phase 3.2 검토 대상) + +| 라인 | 현재 코드 | items.id | items.name | 비고 | +|------|----------|----------|-----------|------| +| 564 | 00035 | 14939 | 철재용하장바(SUS)3000 | 하장바 SUS | +| 564 | 00036 | 14940 | 철재용하장바(SUS1.2T) | 하장바 EGI (SM타입) | +| 619 | 00021 | 14928 | 평철12T | 무게평철12T | +| 631 | 90201 | 15188 | KD환봉(30파이) | 환봉 기본 | +| 628 | 90202 | 15189 | KD환봉 | 환봉 35파이 | +| 629 | 90203 | 15190 | KD환봉 | 환봉 45파이 | +| 630 | 90204 | 15191 | KD환봉 | 환봉 50파이 | + +> 모두 items 테이블에 존재하므로 lookupItem() 정상 동작. +> 변경 여부는 코드 가독성 차원에서 검토 (기능적 문제 없음). + +### C.3 lookupItem 로깅 추가 (Phase 3.3) + +**파일**: `api/app/Services/Quote/Handlers/Tenant287/FormulaHandler.php` +**위치**: 라인 42-48 `lookupItem()` 메서드 + +```php +// 변경 전 (라인 46) +$cache[$code] = ['id' => $item?->id, 'name' => $item?->name]; + +// 변경 후 +$cache[$code] = ['id' => $item?->id, 'name' => $item?->name]; +if (!$item) { + \Log::warning("[Tenant287\FormulaHandler] 미등록 품목: {$code}"); +} +``` + +--- + +## 부록 D. calculateDynamicItems 입력 파라미터 + +KyungdongFormulaHandler의 메인 엔트리 `calculateDynamicItems()` (라인 963)가 수신하는 파라미터: + +```php +$inputs = [ + // 기본 치수 + 'W0' => float, // 폭 (mm) + 'H0' => float, // 높이 (mm) + 'QTY' => int, // 수량 + + // 제품 정보 + 'product_type' => string, // 'screen' | 'slat' | 'steel' + 'model_name' => string, // 'KSS01' | 'KSE01' | ... + 'finishing_type' => string, // 'SUS마감' | 'EGI마감' (→ 내부에서 '마감' 제거) + + // 가이드레일 + 'guide_type' => string, // '벽면형' | '측면형' | '혼합형' + + // 케이스 + 'case_spec' => string, // '500*380' 등 + + // 모터/제어기 + 'bracket_inch' => string, // '4' | '5' | '6' | '8' + 'motor_power' => string, // 'single' | 'three' + 'controller_type' => string, // '일반' | '동보' | '자탈' 등 + + // 기타 (선택) + 'weight_plate_qty' => int, + 'round_bar_qty' => int, + 'round_bar_phi' => int, // 30 | 35 | 45 | 50 +]; +``` + +**반환값** (아이템 배열): + +```php +[ + [ + 'category' => string, // 'steel' | 'parts' | 'inspection' | 'material' | 'motor' | 'controller' + 'item_name' => string, + 'item_code' => string, // EST-*, BD-*, 또는 레거시 숫자코드 + 'item_id' => int|null, // items.id (lookupItem 결과) + 'specification' => string, + 'unit' => string, // 'EA' | 'm' | '㎡' + 'quantity' => float, + 'unit_price' => float, + 'total_price' => float, + ], + // ... +] +``` + +--- + +## 부록 E. 핸들러 구조화 설계 (Phase 2 상세) + +### E.1 디렉토리 구조 (Before → After) + +``` +Before: +api/app/Services/Quote/ +├── FormulaEvaluatorService.php ← if (287) 하드코딩 +├── EstimatePriceService.php +└── Handlers/ + └── KyungdongFormulaHandler.php ← 독립 클래스, 인터페이스 없음 + +After: +api/app/Services/Quote/ +├── FormulaEvaluatorService.php ← Factory::make($tenantId) 사용 +├── FormulaHandlerFactory.php ← 신규: 자동 발견 팩토리 +├── EstimatePriceService.php +├── Contracts/ +│ └── TenantFormulaHandler.php ← 신규: 인터페이스 +└── Handlers/ + └── Tenant287/ ← 경동기업 (tenant_id: 287) + └── FormulaHandler.php ← KyungdongFormulaHandler 이동 + └── Tenant{N}/ ← 향후 업체 추가 시 + └── FormulaHandler.php +``` + +### E.2 인터페이스 설계 + +```php +// api/app/Services/Quote/Contracts/TenantFormulaHandler.php +namespace App\Services\Quote\Contracts; + +interface TenantFormulaHandler +{ + /** + * 동적 BOM 항목 계산 (메인 엔트리) + */ + public function calculateDynamicItems(array $inputs): array; + + /** + * 모터 용량 계산 + */ + public function calculateMotorCapacity(string $productType, float $weight, string $bracketInch): string; + + /** + * 브라켓 사이즈 계산 + */ + public function calculateBracketSize(float $weight, ?string $bracketInch = null): string; +} +``` + +### E.3 팩토리 설계 + +```php +// api/app/Services/Quote/FormulaHandlerFactory.php +namespace App\Services\Quote; + +use App\Services\Quote\Contracts\TenantFormulaHandler; + +class FormulaHandlerFactory +{ + /** + * tenant_id로 핸들러 자동 발견. + * Handlers/Tenant{id}/FormulaHandler.php가 존재하면 인스턴스 반환. + * 없으면 null → Generic DB 경로. + */ + public static function make(int $tenantId): ?TenantFormulaHandler + { + $class = "App\\Services\\Quote\\Handlers\\Tenant{$tenantId}\\FormulaHandler"; + + if (!class_exists($class)) { + return null; + } + + $handler = new $class(); + + if (!$handler instanceof TenantFormulaHandler) { + throw new \RuntimeException( + "Tenant{$tenantId} FormulaHandler must implement TenantFormulaHandler" + ); + } + + return $handler; + } +} +``` + +### E.4 핸들러 이동 (Tenant287) + +```php +// api/app/Services/Quote/Handlers/Tenant287/FormulaHandler.php +namespace App\Services\Quote\Handlers\Tenant287; + +use App\Services\Quote\Contracts\TenantFormulaHandler; +use App\Services\Quote\EstimatePriceService; + +/** + * 경동기업 수식 핸들러 (tenant_id: 287) + * + * 방화셔터/스크린/철재 제품의 BOM 동적 계산. + * KyungdongFormulaHandler에서 이동됨. + */ +class FormulaHandler implements TenantFormulaHandler +{ + private const TENANT_ID = 287; + + // ... 기존 KyungdongFormulaHandler 코드 그대로 유지 +} +``` + +### E.5 FormulaEvaluatorService 변경 포인트 + +```php +// 변경 전 (라인 35) +private const KYUNGDONG_TENANT_ID = 287; + +// 변경 전 (라인 609-611) +if ($tenantId === self::KYUNGDONG_TENANT_ID) { + return $this->calculateKyungdongBom($finishedGoodsCode, $inputVariables, $tenantId); +} + +// ───────────────────────────────────────── + +// 변경 후 (라인 35 제거) +// KYUNGDONG_TENANT_ID 상수 제거 + +// 변경 후 (라인 609-611) +$handler = FormulaHandlerFactory::make($tenantId); +if ($handler) { + return $this->calculateTenantBom($handler, $finishedGoodsCode, $inputVariables, $tenantId); +} +// else → 기존 Generic 10단계 그대로 실행 + +// calculateKyungdongBom() → calculateTenantBom() 리네이밍 +// $handler 파라미터 추가, 내부의 new KyungdongFormulaHandler() 제거 +``` + +### E.6 향후 업체 추가 절차 + +``` +1. Handlers/Tenant{id}/FormulaHandler.php 파일 1개 생성 +2. implements TenantFormulaHandler +3. 끝. (설정 파일, DB 옵션, 매핑 테이블 변경 없음) +``` + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 9.2 | +| 3 | 작업 범위가 구체적인가? | ✅ | 4 Phase + 부록 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Phase 순서 = 의존성 | +| 5 | 참고 파일 경로 + 라인번호가 정확한가? | ✅ | 섹션 8 + 부록 C/E | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 4.1 + 4.2 (SQL), 부록 E (코드 설계) | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 코드/건수/라인번호 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 3 Phase 1, 4.1 단계별 절차 | +| Q3. 어떤 파일의 몇 번째 줄을 수정해야 하는가? | ✅ | 8.1 코드 위치, 부록 C/E | +| Q4. 어떤 품목을 등록해야 하는가? | ✅ | 4.2 등록 상세, 부록 A/B | +| Q5. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | +| Q6. 핸들러가 어떤 파라미터를 받는가? | ✅ | 부록 D | +| Q7. DB INSERT 어떻게 하는가? | ✅ | 4.2 SQL 템플릿 | +| Q8. 기존 데이터 건드려도 되는가? | ✅ | 1.4 원칙 6번 (삭제 금지) | +| Q9. 핸들러 구조는 어떻게 만드는가? | ✅ | 부록 E (인터페이스/팩토리/이동 상세) | +| Q10. 향후 업체 추가 시 절차는? | ✅ | 부록 E.6 (파일 1개 생성, 끝) | + +**결과**: 10/10 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* diff --git a/plans/archive/items-table-unification-plan.md b/plans/archive/items-table-unification-plan.md new file mode 100644 index 0000000..eee1f67 --- /dev/null +++ b/plans/archive/items-table-unification-plan.md @@ -0,0 +1,589 @@ +# Items 테이블 통합 마이그레이션 계획 + +## 참조 문서 + +### 필수 확인 + +| 문서 | 경로 | 내용 | +|------|------|------| +| **ItemMaster 연동 설계서** | [specs/item-master-integration.md](../specs/item-master-integration.md) | source_table, EntityRelationship 구조 | +| **DB 스키마** | [specs/database-schema.md](../specs/database-schema.md) | 테이블 구조, Multi-tenant 아키텍처 | + +### 참고 문서 + +| 문서 | 경로 | 내용 | +|------|------|------| +| **품목관리 마이그레이션 가이드** | [projects/mes/ITEM_MANAGEMENT_MIGRATION_GUIDE.md](../projects/mes/ITEM_MANAGEMENT_MIGRATION_GUIDE.md) | 프론트엔드 마이그레이션 | +| **API 품목 분석 요약** | [projects/mes/00_baseline/docs_breakdown/api_item_analysis_summary.md](../projects/mes/00_baseline/docs_breakdown/api_item_analysis_summary.md) | 기존 API 분석, price_histories | +| **Swagger 가이드** | [guides/swagger-guide.md](../guides/swagger-guide.md) | API 문서화 규칙 | + +### 관련 코드 + +| 파일 | 경로 | 역할 | +|------|------|------| +| ItemPage 모델 | `api/app/Models/ItemMaster/ItemPage.php` | source_table 매핑 | +| EntityRelationship 모델 | `api/app/Models/ItemMaster/EntityRelationship.php` | 엔티티 관계 관리 | +| ItemMasterService | `api/app/Services/ItemMaster/ItemMasterService.php` | init API, 메타데이터 조회 | +| ProductService | `api/app/Services/ProductService.php` | 기존 Products API (제거 예정) | +| MaterialService | `api/app/Services/MaterialService.php` | 기존 Materials API (제거 예정) | + +--- + +## 개요 + +### 목적 +`products`/`materials` 테이블을 `items` 테이블로 통합하여: +- BOM 관리 시 `child_item_type` 불필요 (ID만으로 유일 식별) +- 단일 쿼리로 모든 품목 조회 가능 +- Item-Master 시스템과 일관된 구조 + +### 현재 상황 +- **개발 단계**: 미오픈 (레거시 호환 불필요) +- **Item-Master**: 메타데이터 시스템 운영 중 (pages, sections, fields) +- **이전 시도**: 12/11 items 생성 → 12/12 롤백 (정책 정리 필요) + +### 현재 시스템 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Item-Master (메타데이터) │ +├─────────────────────────────────────────────────────────────┤ +│ item_pages (source_table: 'products'|'materials') │ +│ ↓ EntityRelationship │ +│ item_sections → item_fields, item_bom_items │ +└─────────────────────────────────────────────────────────────┘ + ↓ 참조 +┌─────────────────────────────────────────────────────────────┐ +│ 실제 데이터 테이블 │ +├─────────────────────────────────────────────────────────────┤ +│ products (808건) ← ProductController, ProductService │ +│ materials (417건) ← MaterialController, MaterialService │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 목표 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Item-Master (메타데이터) │ +├─────────────────────────────────────────────────────────────┤ +│ item_pages (source_table: 'items') │ +│ ↓ EntityRelationship │ +│ item_sections → item_fields, item_bom_items │ +└─────────────────────────────────────────────────────────────┘ + ↓ 참조 +┌─────────────────────────────────────────────────────────────┐ +│ 통합 데이터 테이블 │ +├─────────────────────────────────────────────────────────────┤ +│ items ← ItemController, ItemService │ +│ item_type: FG, PT, SM, RM, CS │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## Phase 0: 데이터 정규화 + +### 0.1 item_type 표준화 + +개발 중이므로 비표준 데이터는 삭제 처리. 품목관리 완료 후 경동기업 데이터 전체 재세팅 예정. + +**표준 item_type 체계**: + +| 코드 | 설명 | 출처 | +|------|------|------| +| FG | 완제품 (Finished Goods) | products | +| PT | 부품 (Parts) | products | +| SM | 부자재 (Sub-materials) | materials | +| RM | 원자재 (Raw Materials) | materials | +| CS | 소모품 (Consumables) | materials만 | + +**비표준 데이터 삭제**: +```sql +-- products에서 비표준 타입 삭제 (PRODUCT, SUBASSEMBLY, PART, CS) +DELETE FROM products WHERE product_type NOT IN ('FG', 'PT'); + +-- materials는 이미 표준 타입만 사용 (SM, RM, CS) +``` + +### 0.2 BOM 데이터 정리 + +통합 시 문제되는 BOM 데이터 삭제: +```sql +-- 삭제될 products/materials를 참조하는 BOM 항목 제거 +-- (Phase 1 이관 전에 실행) +``` + +### 0.3 체크리스트 + +- [x] products 비표준 타입 삭제 +- [x] 관련 BOM 데이터 정리 +- [x] 삭제 건수 확인 + +--- + +## Phase 1: items 테이블 생성 + 데이터 이관 + +### 1.1 items 테이블 + +```sql +CREATE TABLE items ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + + -- 기본 정보 + item_type VARCHAR(15) NOT NULL COMMENT 'FG, PT, SM, RM, CS', + code VARCHAR(100) NOT NULL, + name VARCHAR(255) NOT NULL, + unit VARCHAR(20) NULL, + category_id BIGINT UNSIGNED NULL, + + -- BOM (JSON) + bom JSON NULL COMMENT '[{child_item_id, quantity}, ...]', + + -- 상태 + is_active TINYINT(1) DEFAULT 1, + + -- 감사 필드 + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + deleted_by BIGINT UNSIGNED NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + + -- 인덱스 + INDEX idx_items_tenant_type (tenant_id, item_type), + INDEX idx_items_tenant_code (tenant_id, code), + INDEX idx_items_tenant_category (tenant_id, category_id), + UNIQUE KEY uq_items_tenant_code (tenant_id, code, deleted_at), + + FOREIGN KEY (tenant_id) REFERENCES tenants(id), + FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +``` + +### 1.2 item_details 테이블 (확장 필드) + +```sql +CREATE TABLE item_details ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + item_id BIGINT UNSIGNED NOT NULL, + + -- Products 전용 필드 + is_sellable TINYINT(1) DEFAULT 1, + is_purchasable TINYINT(1) DEFAULT 0, + is_producible TINYINT(1) DEFAULT 0, + safety_stock INT NULL, + lead_time INT NULL, + is_variable_size TINYINT(1) DEFAULT 0, + product_category VARCHAR(50) NULL, + part_type VARCHAR(50) NULL, + + -- Materials 전용 필드 + is_inspection VARCHAR(1) DEFAULT 'N', + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uq_item_details_item_id (item_id), + FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +``` + +### 1.3 item_attributes 테이블 (동적 속성) + +```sql +CREATE TABLE item_attributes ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + item_id BIGINT UNSIGNED NOT NULL, + + attributes JSON NULL, + options JSON NULL, + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uq_item_attributes_item_id (item_id), + FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +``` + +### 1.4 데이터 이관 스크립트 + +```php +// Products → Items +DB::statement(" + INSERT INTO items (tenant_id, item_type, code, name, unit, category_id, bom, + is_active, created_by, updated_by, deleted_by, created_at, updated_at, deleted_at) + SELECT tenant_id, product_type, code, name, unit, category_id, bom, + is_active, created_by, updated_by, deleted_by, created_at, updated_at, deleted_at + FROM products +"); + +// Materials → Items +DB::statement(" + INSERT INTO items (tenant_id, item_type, code, name, unit, category_id, + is_active, created_by, updated_by, deleted_by, created_at, updated_at, deleted_at) + SELECT tenant_id, material_type, material_code, name, unit, category_id, + is_active, created_by, updated_by, deleted_by, created_at, updated_at, deleted_at + FROM materials +"); +``` + +### 1.5 체크리스트 + +- [x] items 마이그레이션 생성 +- [x] item_details 마이그레이션 생성 +- [x] item_attributes 마이그레이션 생성 +- [x] 데이터 이관 스크립트 실행 +- [x] 건수 검증 (1,225건) + +--- + +## Phase 2: Item 모델 + Service 생성 + +### 2.1 Item 모델 + +```php +// app/Models/Item.php +class Item extends Model +{ + use BelongsToTenant, ModelTrait, SoftDeletes; + + protected $fillable = [ + 'tenant_id', 'item_type', 'code', 'name', 'unit', + 'category_id', 'bom', 'is_active', + ]; + + protected $casts = [ + 'bom' => 'array', + 'is_active' => 'boolean', + ]; + + // 1:1 관계 + public function details() { return $this->hasOne(ItemDetail::class); } + public function attributes() { return $this->hasOne(ItemAttribute::class); } + + // 타입별 스코프 + public function scopeProducts($q) { + return $q->whereIn('item_type', ['FG', 'PT']); + } + public function scopeMaterials($q) { + return $q->whereIn('item_type', ['SM', 'RM', 'CS']); + } +} +``` + +### 2.2 ItemService + +```php +// app/Services/ItemService.php +class ItemService extends Service +{ + public function index(array $params): LengthAwarePaginator + { + $query = Item::where('tenant_id', $this->tenantId()); + + // item_type 필터 + if ($itemType = $params['item_type'] ?? null) { + $query->where('item_type', strtoupper($itemType)); + } + + // 검색 + if ($search = $params['search'] ?? null) { + $query->where(fn($q) => $q + ->where('code', 'like', "%{$search}%") + ->orWhere('name', 'like', "%{$search}%") + ); + } + + return $query->with(['details', 'attributes'])->paginate($params['per_page'] ?? 15); + } +} +``` + +### 2.3 체크리스트 + +- [x] Item 모델 생성 +- [x] ItemDetail 모델 생성 +- [x] ItemAttribute 모델 생성 +- [x] ItemService 생성 +- [x] ItemRequest 생성 + +--- + +## Phase 3: Item-Master 연동 수정 + +### 3.1 ItemPage.source_table 변경 + +```php +// app/Models/ItemMaster/ItemPage.php + +// 기존 +$mapping = [ + 'products' => \App\Models\Product::class, + 'materials' => \App\Models\Material::class, +]; + +// 변경 +$mapping = [ + 'items' => \App\Models\Item::class, +]; +``` + +### 3.2 item_pages 데이터 업데이트 + +```sql +-- source_table 통합 +UPDATE item_pages SET source_table = 'items' WHERE source_table IN ('products', 'materials'); +``` + +### 3.3 체크리스트 + +- [x] ItemPage 모델 수정 (getTargetModelClass) +- [x] item_pages.source_table 마이그레이션 +- [x] ItemMasterService 연동 테스트 + +--- + +## Phase 4: API 통합 + +### 4.1 API 구조 변경 + +``` +기존 (분리): + /api/v1/products → ProductController + /api/v1/products/materials → MaterialController + +통합 후: + /api/v1/items → ItemController + /api/v1/items?item_type=FG → Products 조회 + /api/v1/items?item_type=SM → Materials 조회 +``` + +### 4.2 ItemController + +```php +// app/Http/Controllers/Api/V1/ItemController.php +class ItemController extends Controller +{ + public function __construct(private ItemService $service) {} + + public function index(ItemIndexRequest $request) + { + return ApiResponse::handle(fn() => [ + 'data' => $this->service->index($request->validated()), + ], __('message.fetched')); + } + + public function store(ItemStoreRequest $request) + { + return ApiResponse::handle(fn() => [ + 'data' => $this->service->store($request->validated()), + ], __('message.created')); + } +} +``` + +### 4.3 라우트 + +```php +// routes/api_v1.php +Route::prefix('items')->group(function () { + Route::get('/', [ItemController::class, 'index']); + Route::post('/', [ItemController::class, 'store']); + Route::get('/{id}', [ItemController::class, 'show']); + Route::patch('/{id}', [ItemController::class, 'update']); + Route::delete('/{id}', [ItemController::class, 'destroy']); +}); +``` + +### 4.4 체크리스트 + +- [x] ItemController 생성 +- [x] ItemIndexRequest, ItemStoreRequest 등 생성 +- [x] 라우트 등록 +- [x] Swagger 문서 작성 +- [x] 기존 ProductController, MaterialController 제거 + +--- + +## Phase 5: 참조 테이블 마이그레이션 + +### 5.1 변경 대상 + +| 테이블 | 기존 | 변경 | +|--------|------|------| +| product_components | ref_type + ref_id | child_item_id | +| bom_template_items | ref_type + ref_id | item_id | +| orders | product_id | item_id | +| order_items | product_id | item_id | +| material_receipts | material_id | item_id | +| lots | material_id | item_id | +| price_histories | item_type + item_id | item_id | +| item_fields | source_table 'products'\|'materials' | source_table 'items' | + +### 5.2 체크리스트 + +- [x] 각 참조 테이블 마이그레이션 작성 +- [x] 관련 모델 관계 업데이트 +- [x] 데이터 검증 + +--- + +## Phase 6: 정리 + +### 6.1 체크리스트 + +- [x] CRUD 테스트 (전체 item_type) +- [x] BOM 계산 테스트 +- [x] Item-Master 연동 테스트 +- [x] 참조 무결성 테스트 +- [x] products 테이블 삭제 +- [x] materials 테이블 삭제 +- [x] 기존 Product, Material 모델 삭제 +- [x] 기존 ProductService, MaterialService 삭제 + +--- + +## 테이블 구조 요약 + +``` +┌─────────────────────────────────────────────────────┐ +│ items (핵심) │ +├─────────────────────────────────────────────────────┤ +│ id, tenant_id, item_type, code, name, unit │ +│ category_id, bom (JSON), is_active │ +│ timestamps + soft deletes │ +└─────────────────────┬───────────────────────────────┘ + │ 1:1 + ┌───────────────┴───────────────┐ + ▼ ▼ +┌─────────────┐ ┌─────────────┐ +│item_details │ │item_attrs │ +├─────────────┤ ├─────────────┤ +│ is_sellable │ │ attributes │ +│ is_purch... │ │ options │ +│ safety_stk │ └─────────────┘ +│ lead_time │ +│ is_inspect │ +└─────────────┘ +``` + +--- + +## BOM 계산 로직 + +### 통합 전 +```php +foreach ($bom as $item) { + if ($item['child_item_type'] === 'product') { + $child = Product::find($item['child_item_id']); + } else { + $child = Material::find($item['child_item_id']); + } +} +``` + +### 통합 후 +```php +$childIds = collect($bom)->pluck('child_item_id'); +$children = Item::whereIn('id', $childIds)->get()->keyBy('id'); +``` + +--- + +## 프론트엔드 전달 사항 + +### API 엔드포인트 변경 + +| 기존 | 통합 | +|------|------| +| `GET /api/v1/products` | `GET /api/v1/items?item_type=FG` | +| `GET /api/v1/products?product_type=PART` | `GET /api/v1/items?item_type=PART` | +| `GET /api/v1/products/materials` | `GET /api/v1/items?item_type=SM` | + +### 응답 필드 변경 + +| 기존 | 통합 | +|------|------| +| `product_type` | `item_type` | +| `material_type` | `item_type` | +| `material_code` | `code` | + +### BOM 요청/응답 변경 + +**요청 (Request)**: +```json +// 기존: BOM 저장 시 ref_type 지정 필요 +{ + "bom": [ + { "ref_type": "PRODUCT", "ref_id": 5, "quantity": 2 }, + { "ref_type": "MATERIAL", "ref_id": 10, "quantity": 1 } + ] +} + +// 통합: item_id만 사용 +{ + "bom": [ + { "child_item_id": 5, "quantity": 2 }, + { "child_item_id": 10, "quantity": 1 } + ] +} +``` + +**응답 (Response)**: +```json +// 기존 +{ "child_item_type": "product", "child_item_id": 5, "quantity": 2 } + +// 통합 +{ "child_item_id": 5, "quantity": 2 } +``` + +**프론트엔드 수정 포인트**: +- BOM 구성품 추가 시 `ref_type` 선택 UI 제거 +- 품목 검색 시 `/api/v1/items` 단일 엔드포인트 사용 +- BOM 저장 payload에서 `ref_type`, `ref_id` → `child_item_id`로 변경 + +--- + +## 일정 + +| Phase | 작업 | 상태 | +|-------|------|------| +| 0 | 데이터 정규화 (비표준 item_type/BOM 삭제) | ✅ 완료 | +| 1 | items 테이블 생성 + 데이터 이관 | ✅ 완료 | +| 2 | Item 모델 + Service 생성 | ✅ 완료 | +| 3 | Item-Master 연동 수정 | ✅ 완료 | +| 4 | API 통합 | ✅ 완료 | +| 5 | 참조 테이블 마이그레이션 | ✅ 완료 | +| 6 | 정리 | ✅ 완료 | + +> **완료일**: 2025-12-15 +> **관련 커밋**: `039fd62` (products/materials 테이블 삭제), `a93dfe7` (Phase 6 완료) + +--- + +## 리스크 + +| 리스크 | 대응 | +|--------|------| +| 데이터 이관 누락 | 이관 전후 건수 검증 | +| Item-Master 연동 오류 | source_table 변경 전 테스트 | +| BOM 순환 참조 | 저장 시 검증 로직 추가 | +| Code 중복 (products↔materials) | 개발 중이므로 품목관리 완료 후 경동기업 데이터 전체 삭제 후 재세팅 예정. 중복 데이터는 삭제 처리 | + +--- + +## 롤백 계획 + +각 Phase는 독립적 마이그레이션으로 구성: +```bash +# Phase 1 롤백 +php artisan migrate:rollback --step=3 + +# 데이터 복구 (products/materials 테이블 유지 상태에서) +# 신규 테이블만 삭제하면 됨 +``` \ No newline at end of file diff --git a/plans/archive/kd-items-migration-plan.md b/plans/archive/kd-items-migration-plan.md new file mode 100644 index 0000000..7710c32 --- /dev/null +++ b/plans/archive/kd-items-migration-plan.md @@ -0,0 +1,1293 @@ +# 경동기업(5130) 품목/단가 마이그레이션 계획 + +> **작성일**: 2026-01-28 +> **목적**: 경동기업 레거시 시스템(5130/)의 **품목(items), 단가(prices), BOM** 데이터를 SAM으로 이관 +> **기준 문서**: `5130/` 폴더 분석 결과 +> **상태**: 🔄 분석 완료, 구현 대기 +> **데이터 규모**: ~1,500 레코드 (items ~800 + prices ~500 + BOM ~200) + +--- + +## 🚀 새 세션 시작 가이드 (Quick Start) + +### 이 문서만 보고 작업을 재개하려면: + +```bash +# 1. Docker 서비스 확인 +docker ps | grep sam + +# 2. 레거시 DB (chandj) 접속 테스트 +docker exec sam-mysql-1 mysql -uroot -proot chandj -e "SELECT COUNT(*) FROM KDunitprice;" + +# 3. 현재 진행 상태 확인 +# → 아래 "📍 현재 진행 상태" 섹션 참조 + +# 4. 다음 작업 시작 +# → "📍 현재 진행 상태" > "다음 작업" 참조 +``` + +### 환경 정보 + +| 항목 | 값 | +|------|-----| +| **프로젝트 루트** | `/Users/kent/Works/@KD_SAM/SAM` | +| **레거시 소스** | `5130/` (프로젝트 루트 직하) | +| **API 프로젝트** | `api/` | +| **Docker 컨테이너** | `sam-mysql-1` | +| **레거시 DB** | `chandj` (MySQL) | +| **SAM DB** | `samdb` (MySQL) ⚠️ | +| **대상 테넌트 ID** | `287` (경동기업) | +| **생성자 사용자 ID** | `1` | + +### DB 접속 명령어 + +```bash +# 레거시 DB (chandj) 접속 +docker exec -it sam-mysql-1 mysql -uroot -proot chandj + +# SAM DB 접속 +docker exec -it sam-mysql-1 mysql -uroot -proot samdb + +# 레거시 테이블 목록 확인 +docker exec sam-mysql-1 mysql -uroot -proot chandj -e "SHOW TABLES;" + +# SAM items 테이블 확인 +docker exec sam-mysql-1 mysql -uroot -proot samdb -e "SELECT COUNT(*) FROM items WHERE tenant_id=287;" +``` + +### 전제 조건 (작업 전 확인) + +- [x] Docker 서비스 실행 중 +- [x] `sam-mysql-1` 컨테이너 실행 중 +- [x] chandj 데이터베이스 접근 가능 +- [ ] SAM items 마이그레이션 실행 완료 (`php artisan migrate`) +- [ ] SAM prices 마이그레이션 실행 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | ✅ **정적 데이터 마이그레이션 완료** | +| **다음 작업** | 동적 BOM/견적 로직 구현 → [kd-quote-logic-plan.md](./kd-quote-logic-plan.md) | +| **진행률** | 4/4 (100%) - 정적 데이터 완료 | +| **마지막 업데이트** | 2026-01-28 | + +> ⚠️ **주의**: 이 문서는 **정적 품목/단가 데이터 이관**만 다룹니다. +> 동적 BOM 계산, 모터/제어기/부자재 자동 추가 등 **견적 로직**은 별도 문서 참조: +> → [kd-quote-logic-plan.md](./kd-quote-logic-plan.md) + +### Phase 1~3 실행 결과 ✅ + +| 소스 | 타입 | 건수 | +|------|------|------| +| KDunitprice | FG/PT/SM/RM/CS | 601건 | +| models | FG | +18건 | +| item_list | PT | +9건 | +| BDmodels.seconditem | PT (누락 부품) | +6건 | +| price_motor | SM (누락 품목) | +13건 | +| price_raw_materials | RM (누락 품목) | +4건 | +| **items 합계** | | **651건** | +| **prices 합계** | | **651건** | +| **BOM 연결** | items.bom JSON | **18건** | + +**Phase 2 상세:** +- Phase 2.1: BDmodels.seconditem → PT items 6건 추가 + - L-BAR, 보강평철, 케이스, 하단마감재, 가이드레일용 연기차단재, 케이스용 연기차단재 +- Phase 2.2: BDmodels → items.bom JSON 연결 18건 + - FG items (models 기반) ↔ PT items (seconditem) 연결 + +**Phase 3 상세:** +- Phase 3.1: price_motor → SM items 13건 추가 + - PM-020~PM-032: 제어기 (6P~18P, 20회선~100회선) + - PM-033~PM-035: 방화/방범 콘트롤박스, 스위치 +- Phase 3.2: price_raw_materials → RM items 4건 추가 + - RM-007: 신설비상문 (3x2 300*200) + - RM-008~RM-009: 제연커튼 (연기차단원단, 불투명) + - RM-010~RM-011: 화이바원단, 와이어원단 +- 중복 확인: KDunitprice 기존 품목과 명칭 비교로 중복 제외 + +### Phase 4 검증 결과 ✅ + +**로컬 검증 완료 (2026-01-28):** + +| 검증 항목 | 기대값 | 실제값 | 상태 | +|-----------|--------|--------|------| +| items 총 건수 | 651건 | 651건 | ✅ | +| prices 총 건수 | 651건 | 651건 | ✅ | +| BOM 연결 | 18건 | 18건 | ✅ | +| code 중복 | 0건 | 0건 | ✅ | + +**item_type 분포:** +| item_type | 건수 | +|-----------|------| +| FG (완제품) | 470건 | +| PT (부품) | 88건 | +| SM (부자재) | 61건 | +| RM (원자재) | 28건 | +| CS (소모품) | 4건 | + +### 후속 작업 + +**이 문서 범위 (정적 데이터):** +- ✅ 완료 - 개발서버 배포 대기 중 + +**별도 문서 (동적 로직):** +- → [kd-quote-logic-plan.md](./kd-quote-logic-plan.md) +- 5130 견적 로직 분석 +- 동적 BOM 계산 (모터/제어기/부자재) +- 파라미터 기반 절곡품 산출 + +### Seeder 재실행 방법 + +```bash +# Docker 컨테이너 내부에서 실행 +docker exec sam-api-1 php artisan db:seed --class="Database\\Seeders\\Kyungdong\\KyungdongItemSeeder" +``` + +--- + +## 0. 성공 기준 + +| 기준 | 목표값 | 확인 방법 | +|------|-------|----------| +| **items 합계** | **~800건** | `SELECT COUNT(*) FROM items WHERE tenant_id=287` | +| items (FG) | ~100건 | `SELECT COUNT(*) FROM items WHERE tenant_id=287 AND item_type='FG'` | +| items (PT) | ~250건 | `SELECT COUNT(*) FROM items WHERE tenant_id=287 AND item_type='PT'` | +| items (SM) | ~300건 | `SELECT COUNT(*) FROM items WHERE tenant_id=287 AND item_type='SM'` | +| items (RM) | ~100건 | `SELECT COUNT(*) FROM items WHERE tenant_id=287 AND item_type='RM'` | +| items (CS) | ~50건 | `SELECT COUNT(*) FROM items WHERE tenant_id=287 AND item_type='CS'` | +| **prices 합계** | **~500건** | `SELECT COUNT(*) FROM prices WHERE tenant_id=287` | +| **BOM 관계** | ~300건 | `SELECT COUNT(*) FROM item_bom_items WHERE tenant_id=287` | +| code 유일성 | 100% | `SELECT code, COUNT(*) FROM items WHERE tenant_id=287 GROUP BY code HAVING COUNT(*) > 1` (0건) | +| API 테스트 | 100% | `/api/v1/items` 목록 조회 성공 | + +--- + +## 1. 개요 + +### 1.1 배경 + +경동기업은 **모델(Model) + 제품(Product)** 분리 구조를 사용하지만, SAM은 **통합 items 테이블** 구조로 기획됨. 레거시 5130/ 폴더의 데이터를 SAM 구조에 맞게 변환하여 이관 필요. + +### 1.2 핵심 차이점 + +``` +┌────────────────────────────────────────────────────────────────────────────┐ +│ 레거시 (chandj) → SAM (samdb) │ +├────────────────────────────────────────────────────────────────────────────┤ +│ 📦 품목 마스터 │ +│ ───────────────────────────────────────────────────────────────────────── │ +│ KDunitprice (603건, 핵심!) → items (마스터, code로 구분) │ +│ models (18건) → items (FG) │ +│ parts, parts_sub (170건) → item_bom_items │ +│ category_l1~l4 → items 카테고리 참조 │ +│ guiderail, bottombar, bending 등 → item_details │ +│ │ +│ 💰 단가 정보 │ +│ ───────────────────────────────────────────────────────────────────────── │ +│ price_* (10개 테이블) → prices │ +│ KDunitprice.출고가/입고가 → prices (기본가) │ +└────────────────────────────────────────────────────────────────────────────┘ +``` + +### 1.2.1 중복 제거 전략 ⭐ + +``` +┌────────────────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심: KDunitprice가 마스터, code 필드로 중복 방지 │ +├────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1️⃣ KDunitprice (603건) → items 먼저 생성 │ +│ - item_div로 item_type 결정 │ +│ - code = prodcode 그대로 사용 ⭐ │ +│ │ +│ 2️⃣ price_* 테이블 → items 중복 확인 후 prices만 생성 │ +│ - code로 items 조회 │ +│ - 존재하면 → prices만 추가 (item_id 연결) │ +│ - 없으면 → items 생성 후 prices 추가 │ +│ │ +│ 3️⃣ 매핑 테이블 불필요 │ +│ - item_id_mappings ❌ (양방향 조회 불필요) │ +│ - chandj는 손 안댐, samdb에만 밀어 넣음 │ +│ │ +└────────────────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 SAM items 구조 (Target) + +```sql +-- items 테이블 (tenant_id=287 for 경동기업) +-- ⚠️ 실제 컬럼명 (2026-01-28 확인됨) +CREATE TABLE items ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, -- 287 (경동기업) + item_type VARCHAR(15) NOT NULL, -- FG, PT, SM, RM, CS + code VARCHAR(100) NOT NULL, -- 품목코드 (← KDunitprice.prodcode) + name VARCHAR(255) NOT NULL, -- 품목명 (← KDunitprice.item_name) + unit VARCHAR(20), -- 단위 (← KDunitprice.unit) + category_id BIGINT, -- 카테고리 ID + process_type VARCHAR(50), -- 공정 타입 + item_category VARCHAR(50), -- 품목 분류 + bom JSON, -- BOM 정보 + attributes JSON, -- 동적 필드 값 (spec 등) + attributes_archive JSON, -- 속성 아카이브 + options JSON, -- 추가 옵션 + description TEXT, -- 설명 + is_active BOOLEAN DEFAULT TRUE, + created_by BIGINT, + updated_by BIGINT, + deleted_by BIGINT, + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP -- Soft Delete +); +``` + +### 1.4 item_type 분류 + +| SAM item_type | 설명 | 레거시 소스 | +|---------------|------|-------------| +| **FG** | 완제품 (Finished Goods) | KDunitprice[제품], KDunitprice[상품], models | +| **PT** | 부품 (Parts) | KDunitprice[반제품], parts, parts_sub, category_l4 | +| **SM** | 부자재 (Sub-Materials) | KDunitprice[부재료], price_* 테이블들 | +| **RM** | 원자재 (Raw Materials) | KDunitprice[원재료], price_raw_materials | +| **CS** | 소모품 (Consumables) | KDunitprice[무형상품], 기타 | + +### 1.4.1 KDunitprice.item_div → item_type 매핑 ⭐ + +```sql +-- KDunitprice.item_div 값 목록 (603건 중) +-- [제품], [상품], [부재료], [원재료], [반제품], [무형상품] + +CASE item_div + WHEN '[제품]' THEN 'FG' -- 완제품 + WHEN '[상품]' THEN 'FG' -- 상품도 완제품으로 분류 + WHEN '[반제품]' THEN 'PT' -- 반제품 = 부품 + WHEN '[부재료]' THEN 'SM' -- 부자재 + WHEN '[원재료]' THEN 'RM' -- 원자재 + WHEN '[무형상품]' THEN 'CS' -- 소모품/무형 + ELSE 'SM' -- 기본값 +END AS item_type +``` + +--- + +## 2. 레거시 DB 구조 분석 + +### 2.1 핵심 테이블 및 레코드 수 + +#### 📦 품목 마스터 테이블 + +| 테이블 | 레코드 수 | 역할 | SAM 매핑 | +|--------|----------|------|----------| +| **`KDunitprice`** ⭐ | **603** | **품목 마스터 (핵심!)** | **items (마스터)** | +| `models` | 18 | 모델 마스터 (스크린/철재) | items (FG) | +| `BDmodels` | 59 | 모델별 BOM + 단가 (JSON) | item_bom_items + prices | +| `parts` | 36 | 부품 | item_bom_items | +| `parts_sub` | 134 | 하위 부품 | item_bom_items | +| `category_l1` | 2 | 1단계 카테고리 (스크린/철재) | 참조용 | +| `category_l2` | 14 | 2단계 카테고리 | 참조용 | +| `category_l3` | 24 | 3단계 카테고리 | 참조용 | +| `category_l4` | 37 | 4단계 카테고리 (부품) | items (PT) | +| `item_list` | 5+ | 품목 마스터 | items (PT) | + +#### 💰 단가 테이블 + +| 테이블 | 레코드 수 | 역할 | SAM 매핑 | +|--------|----------|------|----------| +| `price_motor` | 2 (JSON) | 모터 단가 | prices | +| `price_shaft` | 2 (JSON) | 감기샤프트 단가 | prices | +| `price_pipe` | 2 (JSON) | 파이프 단가 | prices | +| `price_angle` | 2 (JSON) | 앵글 단가 | prices | +| `price_raw_materials` | 6 (JSON) | 주자재 단가 | prices | +| `price_bend` | 3 (JSON) | 절곡 단가 | prices | +| `price_pole` | 2 (JSON) | 폴 단가 | prices | +| `price_screenplate` | 2 (JSON) | 스크린플레이트 단가 | prices | +| `price_smokeban` | 2 (JSON) | 연기차단 단가 | prices | + +### 2.2 KDunitprice 테이블 구조 ⭐ (핵심 마스터) + +```sql +-- KDunitprice: 품목 마스터 (603건) - 가장 중요한 테이블! +-- ⚠️ 실제 컬럼명 (2026-01-28 확인됨) +num INT PRIMARY KEY, -- PK +is_deleted INT, -- 삭제 여부 +prodcode VARCHAR(50), -- items.code (유니크 키!) ⭐ +item_name VARCHAR(255), -- items.name ⭐ +item_div VARCHAR(20), -- [제품]/[상품]/[부재료]/[원재료]/[반제품]/[무형상품] → item_type ⭐ +spec VARCHAR(100), -- items.attributes.spec +unit VARCHAR(20), -- items.unit +unitprice DECIMAL, -- prices.sales_price (단일 컬럼, 입고가/출고가 구분 없음!) ⭐ +searchtag TEXT, -- 검색 태그 +update_log TEXT -- 변경 이력 +``` + +**item_div 분포 확인 쿼리**: +```sql +SELECT item_div, COUNT(*) FROM KDunitprice WHERE is_deleted=0 GROUP BY item_div; +-- [제품] ~100건 → FG +-- [상품] ~50건 → FG +-- [반제품] ~100건 → PT +-- [부재료] ~200건 → SM +-- [원재료] ~100건 → RM +-- [무형상품] ~53건 → CS +``` + +### 2.3 BDmodels 테이블 구조 (BOM + 단가) + +```sql +-- BDmodels: 모델별 BOM 및 단가 정보 +num INT PRIMARY KEY, +major_category VARCHAR(10), -- 스크린/철재 +spec VARCHAR(30), -- 규격 (60*40, 120*70 등) +model_name VARCHAR(255), -- 모델명 +finishing_type ENUM('SUS마감','EGI마감'), +check_type VARCHAR(20), -- 벽면형/측면형/혼합형 +seconditem VARCHAR(30), -- 부품명 (가이드레일, 하단마감재, L-BAR 등) +unitprice TEXT, -- 단가 (문자열) +savejson TEXT, -- BOM 상세 JSON +description TEXT, +is_deleted, priceDate DATE +``` + +**savejson 예시** (가이드레일 BOM): +```json +[ + {"col1":"1번(마감재)","col2":"SUS 1.2T","col3":"-3","col4":"203","col5":"206","col6":"51,000","col7":"10,506","col8":"2","col9":"21,012","col10":"삭제"}, + {"col1":"2번(본체)","col2":"EGI 1.55T","col3":"-5","col4":"294","col5":"299","col6":"27,000","col7":"8,073","col8":"1","col9":"8,073","col10":"삭제"} +] +``` + +### 2.4 단가 시스템 상세 분석 ⭐ + +#### 2.4.1 레거시 단가 테이블 전체 목록 (10개) + +| 테이블명 | 레코드 수 | 최신 날짜 | 용도 | +|---------|----------|----------|------| +| `price_motor` | 2 | 2024-08-25 | 전동개폐기, 제어기 단가 | +| `price_shaft` | 2 | 2024-08-25 | 감기샤프트 단가 | +| `price_pipe` | 2 | 2024-08-26 | 파이프 단가 | +| `price_angle` | 2 | 2024-08-26 | 앵글 단가 | +| `price_raw_materials` | 6 | 2025-06-18 | 슬랫, 스크린 원자재 단가 | +| `price_bend` | 3 | 2025-03-09 | 절곡 단가 | +| `price_pole` | 2 | 2024-08-26 | 폴 단가 | +| `price_screenplate` | 2 | 2024-08-26 | 스크린플레이트 단가 | +| `price_smokeban` | 2 | 2024-08-26 | 연기차단 단가 | +| `price_etc` | 0 | - | 기타 (개별 컬럼 방식, 비활성) | + +#### 2.4.2 SAM prices 테이블 구조 (Target) + +```sql +CREATE TABLE prices ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, -- 287 (경동기업) + + -- 품목 연결 + item_type_code VARCHAR(20), -- FG/PT/SM/RM/CS + item_id BIGINT, -- items.id FK + client_group_id BIGINT NULL, -- NULL = 기본가 + + -- 원가 정보 + purchase_price DECIMAL(15,4), -- 매입단가 (원가) + processing_cost DECIMAL(15,4), -- 가공비 + loss_rate DECIMAL(5,2), -- LOSS율 (%) + + -- 판매가 정보 + margin_rate DECIMAL(5,2), -- 마진율 (%) + sales_price DECIMAL(15,4), -- 판매단가 ⭐ + rounding_rule ENUM('round','ceil','floor'), + rounding_unit INT DEFAULT 1, -- 반올림 단위 + + -- 메타 정보 + supplier VARCHAR(255), -- 공급업체 + effective_from DATE, -- 적용 시작일 ⭐ + effective_to DATE NULL, -- 적용 종료일 + note TEXT, + + -- 상태 관리 + status ENUM('draft','active','inactive','finalized'), + is_final BOOLEAN DEFAULT FALSE, + + -- 감사 컬럼 + created_by, updated_by, deleted_by, timestamps, soft_deletes +); +``` + +--- + +## 3. 매핑 설계 + +### 3.1 models → items (FG 완제품) + +| 레거시 (models) | SAM (items) | 비고 | +|----------------|-------------|------| +| model_id | (신규 생성) | | +| model_name | code | KSS01 → FG-KSS01 | +| - | name | 모델명 + 마감타입 + 가이드타입 조합 | +| major_category | attributes.major_category | 스크린/철재 | +| finishing_type | attributes.finishing_type | SUS마감/EGI마감 | +| guiderail_type | attributes.guiderail_type | 벽면형/측면형/혼합형 | +| - | item_type | 'FG' | +| - | tenant_id | 287 | + +**코드 생성 규칙**: +``` +FG-{model_name}-{guiderail_type}-{finishing_type} +예: FG-KSS01-벽면형-SUS +``` + +### 3.2 price_* → prices 테이블 (단가 연동) ⭐ + +> **중요**: 단가 데이터는 items.attributes가 아닌 **prices 테이블**에 별도 관리 + +| 레거시 (price_*) | SAM (prices) | 비고 | +|-----------------|--------------|------| +| registedate | effective_from | 적용 시작일 | +| itemList.col13 (판매가) | sales_price | | +| itemList.col11 (원가) | purchase_price | | +| - | item_type_code | FG/PT/SM/RM/CS | +| - | item_id | items.id FK | +| - | client_group_id | NULL (기본가) | +| - | status | 'active' | + +--- + +## 4. 대상 범위 + +### 4.1 Phase 1: 마스터 데이터 이관 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| **1.0** | **KDunitprice → items (마스터)** ⭐ | ⏳ | **603건 (최우선!)** | +| 1.1 | models → items (FG) INSERT 쿼리 작성 | ⏳ | 18건 (중복 확인 후) | +| 1.2 | item_list → items (PT) INSERT 쿼리 작성 | ⏳ | 5건+ (중복 확인 후) | +| 1.3 | category_l4 → items (PT) INSERT 쿼리 작성 | ⏳ | 37건 (중복 확인 후) | +| 1.4 | price_motor 파싱 → prices 연결 | ⏳ | code로 items 조회 후 prices 생성 | +| 1.5 | price_shaft 파싱 → prices 연결 | ⏳ | ~15건 | +| 1.6 | price_raw_materials 파싱 → prices 연결 | ⏳ | ~20건 | +| 1.7 | ⚠️ **사용자 승인**: Phase 1 INSERT 실행 | ⏳ | | + +### 4.2 Phase 2: BOM 및 상세 데이터 이관 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | BDmodels.savejson → item_bom_items | ⏳ | 59건 | +| 2.2 | parts → item_bom_items | ⏳ | 36건 | +| 2.3 | parts_sub → item_bom_items | ⏳ | 134건 | +| 2.4 | guiderail/bottombar/bending 등 → item_details | ⏳ | 제품 상세 | +| 2.5 | parent_item_id, child_item_id 매핑 | ⏳ | code 기반 조회 | + +### 4.3 Phase 3: 단가 데이터 이관 ⭐ + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | price_motor → items (SM) + prices | ⏳ | ~35건 품목 + 단가 | +| 3.2 | price_shaft → items (SM) + prices | ⏳ | ~15건 | +| 3.3 | price_pipe → items (SM) + prices | ⏳ | ~10건 | +| 3.4 | price_angle → items (SM) + prices | ⏳ | ~10건 | +| 3.5 | price_raw_materials → items (RM) + prices | ⏳ | ~20건 | +| 3.6 | price_bend → items (SM) + prices | ⏳ | ~10건 | +| 3.7 | price_pole → items (SM) + prices | ⏳ | ~5건 | +| 3.8 | price_screenplate → items (SM) + prices | ⏳ | ~5건 | +| 3.9 | price_smokeban → items (SM) + prices | ⏳ | ~5건 | +| 3.10 | 단가 버전 이력 정리 | ⏳ | effective_from/to 설정 | +| 3.11 | ⚠️ **사용자 승인**: 단가 INSERT 실행 | ⏳ | | + +### 4.4 Phase 4: 검증 및 배포 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | 로컬 테스트 | ⏳ | | +| 4.2 | API 테스트 | ⏳ | | +| 4.3 | 개발서버 배포 | ⏳ | ⚠️ 컨펌 필요 | + +--- + +## 5. Seeder 파일 + +### 5.0 Seeder 구조 및 실행 방법 + +**파일 위치**: `api/database/seeders/Kyungdong/KyungdongItemSeeder.php` + +**실행 명령어**: +```bash +# 로컬 실행 (tenant_id=287만 삭제 후 INSERT) +cd /Users/kent/Works/@KD_SAM/SAM/api +php artisan db:seed --class=Database\\Seeders\\Kyungdong\\KyungdongItemSeeder + +# 개발서버 실행 (TRUNCATE 후 INSERT) - ⚠️ 컨펌 필요 +php artisan db:seed --class=Database\\Seeders\\Kyungdong\\KyungdongItemSeeder --env=development +``` + +**환경별 삭제 전략**: +| 환경 | 삭제 방식 | 비고 | +|------|----------|------| +| 로컬 (local) | `DELETE WHERE tenant_id=287` | 다른 테넌트 데이터 보존 | +| 개발 (development) | `TRUNCATE` | 전체 초기화 | + +--- + +### 5.1 KyungdongItemSeeder.php (전체 코드) + +```php +command->info('🚀 경동기업 품목/단가 마이그레이션 시작...'); + + // 1. 기존 데이터 삭제 + $this->cleanupExistingData(); + + // 2. KDunitprice → items + $itemCount = $this->migrateItems(); + + // 3. KDunitprice → prices + $priceCount = $this->migratePrices(); + + $this->command->info("✅ 완료: items {$itemCount}건, prices {$priceCount}건"); + } + + /** + * 기존 데이터 삭제 + */ + private function cleanupExistingData(): void + { + if (App::environment('local')) { + // 로컬: tenant_id=287만 삭제 + $this->command->info(' 🧹 로컬 환경: tenant_id=287 데이터 삭제...'); + DB::table('prices')->where('tenant_id', self::TENANT_ID)->delete(); + DB::table('items')->where('tenant_id', self::TENANT_ID)->delete(); + } else { + // 개발/운영: TRUNCATE (⚠️ 주의) + $this->command->info(' 🧹 개발 환경: TRUNCATE...'); + DB::statement('SET FOREIGN_KEY_CHECKS=0'); + DB::table('prices')->truncate(); + DB::table('items')->truncate(); + DB::statement('SET FOREIGN_KEY_CHECKS=1'); + } + } + + /** + * KDunitprice → items 마이그레이션 + */ + private function migrateItems(): int + { + $this->command->info(' 📦 KDunitprice → items 마이그레이션...'); + + // chandj.KDunitprice에서 데이터 조회 + $kdItems = DB::connection('legacy') // config/database.php에 'legacy' 연결 필요 + ->table('KDunitprice') + ->where('is_deleted', 0) + ->whereNotNull('prodcode') + ->where('prodcode', '!=', '') + ->get(); + + $items = []; + $now = now(); + + foreach ($kdItems as $kd) { + $items[] = [ + 'tenant_id' => self::TENANT_ID, + 'item_type' => $this->mapItemType($kd->item_div), + 'code' => $kd->prodcode, + 'name' => $kd->item_name, + 'unit' => $kd->unit, + 'attributes' => json_encode([ + 'spec' => $kd->spec, + 'item_div' => $kd->item_div, + 'legacy_source' => 'KDunitprice', + 'legacy_num' => $kd->num, + ]), + 'is_active' => true, + 'created_by' => self::USER_ID, + 'updated_by' => self::USER_ID, + 'created_at' => $now, + 'updated_at' => $now, + ]; + + // 500건씩 배치 INSERT + if (count($items) >= 500) { + DB::table('items')->insert($items); + $items = []; + } + } + + // 남은 데이터 INSERT + if (!empty($items)) { + DB::table('items')->insert($items); + } + + return $kdItems->count(); + } + + /** + * KDunitprice → prices 마이그레이션 + */ + private function migratePrices(): int + { + $this->command->info(' 💰 KDunitprice → prices 마이그레이션...'); + + // items와 KDunitprice 조인하여 prices 생성 + $count = DB::statement(" + INSERT INTO prices ( + tenant_id, item_type_code, item_id, client_group_id, + purchase_price, sales_price, + effective_from, status, + created_by, updated_by, created_at, updated_at + ) + SELECT + ? AS tenant_id, + i.item_type AS item_type_code, + i.id AS item_id, + NULL AS client_group_id, + 0 AS purchase_price, + COALESCE(k.unitprice, 0) AS sales_price, + CURDATE() AS effective_from, + 'active' AS status, + ? AS created_by, + ? AS updated_by, + NOW(), NOW() + FROM items i + JOIN " . config('database.connections.legacy.database') . ".KDunitprice k + ON k.prodcode = i.code + WHERE i.tenant_id = ? + AND k.is_deleted = 0 + AND k.prodcode IS NOT NULL + AND k.prodcode != '' + ", [self::TENANT_ID, self::USER_ID, self::USER_ID, self::TENANT_ID]); + + return DB::table('prices')->where('tenant_id', self::TENANT_ID)->count(); + } + + /** + * item_div → item_type 매핑 + */ + private function mapItemType(?string $itemDiv): string + { + return match ($itemDiv) { + '[제품]', '[상품]' => 'FG', + '[반제품]' => 'PT', + '[부재료]' => 'SM', + '[원재료]' => 'RM', + '[무형상품]' => 'CS', + default => 'SM', + }; + } +} +``` + +--- + +### 5.2 Legacy DB 연결 설정 + +**config/database.php에 추가**: +```php +'connections' => [ + // ... 기존 연결들 + + 'legacy' => [ + 'driver' => 'mysql', + 'host' => env('LEGACY_DB_HOST', '127.0.0.1'), + 'port' => env('LEGACY_DB_PORT', '3306'), + 'database' => env('LEGACY_DB_DATABASE', 'chandj'), + 'username' => env('LEGACY_DB_USERNAME', 'root'), + 'password' => env('LEGACY_DB_PASSWORD', 'root'), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + ], +], +``` + +**.env에 추가**: +```env +LEGACY_DB_HOST=127.0.0.1 +LEGACY_DB_PORT=3306 +LEGACY_DB_DATABASE=chandj +LEGACY_DB_USERNAME=root +LEGACY_DB_PASSWORD=root +``` + +--- + +### 5.3 참고: SQL 쿼리 (직접 실행용) + +#### 5.3.1 KDunitprice → items (마스터) + +```sql +-- ⚠️ 참고용 SQL (Seeder 사용 권장) +-- KDunitprice: 품목 마스터 (603건) → SAM items + +INSERT INTO samdb.items ( + tenant_id, item_type, code, name, unit, + attributes, description, is_active, + created_by, created_at, updated_at +) +SELECT + 287 AS tenant_id, + -- item_div → item_type 매핑 + CASE item_div + WHEN '[제품]' THEN 'FG' + WHEN '[상품]' THEN 'FG' + WHEN '[반제품]' THEN 'PT' + WHEN '[부재료]' THEN 'SM' + WHEN '[원재료]' THEN 'RM' + WHEN '[무형상품]' THEN 'CS' + ELSE 'SM' + END AS item_type, + prodcode AS code, -- 유니크 키! ⭐ + item_name AS name, -- ⭐ + unit AS unit, + JSON_OBJECT( + 'spec', spec, -- ⭐ + 'item_div', item_div, + 'legacy_source', 'KDunitprice', + 'legacy_num', num + ) AS attributes, + NULL AS description, -- 비고 컬럼 없음 + 1 AS is_active, + 1 AS created_by, + NOW(), NOW() +FROM chandj.KDunitprice +WHERE is_deleted = 0 + AND prodcode IS NOT NULL AND prodcode != ''; + +-- 결과 확인 +SELECT item_type, COUNT(*) +FROM samdb.items +WHERE tenant_id = 287 +GROUP BY item_type; +``` + +#### 5.3.2 KDunitprice → prices (기본 단가) + +```sql +-- ⚠️ 참고용 SQL (Seeder 사용 권장) +-- unitprice 단일 컬럼 → sales_price, purchase_price는 0 +INSERT INTO samdb.prices ( + tenant_id, item_type_code, item_id, client_group_id, + purchase_price, sales_price, + effective_from, status, + created_by, created_at, updated_at +) +SELECT + 287 AS tenant_id, + i.item_type AS item_type_code, + i.id AS item_id, + NULL AS client_group_id, -- 기본가 + 0 AS purchase_price, -- 입고가 컬럼 없음, 0으로 설정 + COALESCE(k.unitprice, 0) AS sales_price, -- ⭐ unitprice 사용 + CURDATE() AS effective_from, -- 적용일 + 'active' AS status, + 1 AS created_by, + NOW(), NOW() +FROM chandj.KDunitprice k +JOIN samdb.items i ON i.code = k.prodcode AND i.tenant_id = 287 -- ⭐ prodcode 사용 +WHERE k.is_deleted = 0 + AND k.prodcode IS NOT NULL AND k.prodcode != ''; +``` + +### 5.4 models → items (FG) - 추가 SQL 참고용 + +```sql +-- ⚠️ 참고용 SQL (Seeder 확장 시 사용) +-- 레거시 chandj.models → SAM items (FG) +-- KDunitprice에 없는 것만 추가 (중복 확인 필요) +INSERT INTO samdb.items ( + tenant_id, item_type, code, name, unit, + attributes, is_active, created_by, created_at, updated_at +) +SELECT + 287 AS tenant_id, + 'FG' AS item_type, + CONCAT('FG-', model_name, '-', + COALESCE(guiderail_type, 'STD'), '-', + CASE finishing_type + WHEN 'SUS마감' THEN 'SUS' + WHEN 'EGI마감' THEN 'EGI' + ELSE 'STD' + END + ) AS code, + CONCAT(model_name, ' ', major_category, ' ', finishing_type, ' ', COALESCE(guiderail_type, '')) AS name, + 'EA' AS unit, + JSON_OBJECT( + 'major_category', major_category, + 'finishing_type', finishing_type, + 'guiderail_type', guiderail_type, + 'legacy_model_id', model_id + ) AS attributes, + CASE WHEN is_deleted = 0 THEN 1 ELSE 0 END AS is_active, + 1 AS created_by, + created_at, + updated_at +FROM chandj.models +WHERE is_deleted = 0; +``` + +### 5.5 category_l4 → items (PT) - 추가 SQL 참고용 + +```sql +-- ⚠️ 참고용 SQL (Seeder 확장 시 사용) +-- 레거시 4단계 카테고리 → SAM items (PT) +INSERT INTO samdb.items ( + tenant_id, item_type, code, name, unit, + attributes, is_active, created_by, created_at, updated_at +) +SELECT + 287 AS tenant_id, + 'PT' AS item_type, + CONCAT('PT-', l1.name, '-', l2.name, '-', l3.name, '-', l4.name) AS code, + l4.name AS name, + 'EA' AS unit, + JSON_OBJECT( + 'category_l1', l1.name, + 'category_l2', l2.name, + 'category_l3', l3.name, + 'category_l4', l4.name, + 'legacy_l4_id', l4.id + ) AS attributes, + 1 AS is_active, + 1 AS created_by, + NOW(), NOW() +FROM chandj.category_l4 l4 +JOIN chandj.category_l3 l3 ON l4.parent_id = l3.id +JOIN chandj.category_l2 l2 ON l3.parent_id = l2.id +JOIN chandj.category_l1 l1 ON l2.parent_id = l1.id; +``` + +### 5.6 price_motor → items (SM) + prices - PHP 스크립트 참고용 + +```php +query(" + SELECT num, registedate, itemList + FROM price_motor + WHERE is_deleted = 0 + ORDER BY registedate DESC +"); +$priceRecords = $stmt->fetchAll(PDO::FETCH_ASSOC); + +// 최신 단가의 itemList 파싱 → items 생성 +$latestRecord = $priceRecords[0]; +$itemList = json_decode($latestRecord['itemList'], true); + +foreach ($itemList as $idx => $item) { + $voltage = $item['col1']; // 220, 380, 제어기, 방화, 방범 + $capacity = $item['col2']; // 150K(S), 300K, 노출형, 매립형... + $purchasePrice = (float)str_replace(',', '', $item['col11'] ?? '0'); + $salesPrice = (float)str_replace(',', '', $item['col13'] ?? '0'); + + // 품목 코드 생성 + $code = "SM-MOTOR-" . preg_replace('/[^A-Za-z0-9가-힣]/', '', $voltage) + . "-" . preg_replace('/[^A-Za-z0-9가-힣()]/', '', $capacity); + + // 품목명 생성 + if (in_array($voltage, ['220', '380'])) { + $name = "전동개폐기 {$voltage}V {$capacity}"; + $itemType = 'SM'; + } elseif ($voltage === '제어기') { + $name = "연동제어기 {$capacity}"; + $itemType = 'SM'; + } else { + $name = "{$voltage} {$capacity}"; + $itemType = 'SM'; + } + + // 1단계: items INSERT + $itemStmt = $pdo->prepare(" + INSERT INTO items ( + tenant_id, item_type, code, name, unit, + attributes, is_active, created_by, created_at, updated_at + ) VALUES (?, ?, ?, ?, 'EA', ?, 1, ?, NOW(), NOW()) + ON DUPLICATE KEY UPDATE name = VALUES(name) + "); + $attributes = json_encode([ + 'voltage' => $voltage, + 'capacity' => $capacity, + 'legacy_source' => 'price_motor', + 'legacy_col_index' => $idx + ]); + $itemStmt->execute([$tenantId, $itemType, $code, $name, $attributes, $userId]); + $itemId = $pdo->lastInsertId(); + + // 2단계: prices INSERT (모든 버전) + foreach ($priceRecords as $priceIdx => $priceRecord) { + $priceItemList = json_decode($priceRecord['itemList'], true); + if (!isset($priceItemList[$idx])) continue; + + $priceItem = $priceItemList[$idx]; + $pPrice = (float)str_replace(',', '', $priceItem['col11'] ?? '0'); + $sPrice = (float)str_replace(',', '', $priceItem['col13'] ?? '0'); + $effectiveFrom = $priceRecord['registedate']; + + // 다음 레코드가 있으면 effective_to 설정 + $effectiveTo = isset($priceRecords[$priceIdx + 1]) + ? date('Y-m-d', strtotime($effectiveFrom . ' -1 day')) + : null; + + $status = ($priceIdx === 0) ? 'active' : 'inactive'; + + $priceStmt = $pdo->prepare(" + INSERT INTO prices ( + tenant_id, item_type_code, item_id, client_group_id, + purchase_price, sales_price, effective_from, effective_to, + status, created_by, created_at, updated_at + ) VALUES (?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, NOW(), NOW()) + "); + $priceStmt->execute([ + $tenantId, $itemType, $itemId, + $pPrice, $sPrice, $effectiveFrom, $effectiveTo, + $status, $userId + ]); + } + + echo "✓ {$code} - items + prices 생성 완료\n"; +} +``` + +--- + +## 6. 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 📦 데이터 전략 │ +│ ───────────────────────────────────────────────────────────────────── │ +│ - KDunitprice(603건)가 품목 마스터 → items 최우선 생성 │ +│ - code 필드로 중복 방지 (ON DUPLICATE KEY UPDATE) │ +│ - BOM은 item_bom_items 테이블 사용 (items.bom JSON ❌) │ +│ - 단가 정보는 prices 테이블에 별도 저장 (items.attributes ❌) │ +│ │ +│ ❌ 불필요한 것 │ +│ ───────────────────────────────────────────────────────────────────── │ +│ - item_id_mappings 테이블 (양방향 조회 불필요) │ +│ - chandj 수정 (손 안댐, samdb에만 밀어 넣음) │ +│ - 레거시 소스 확인 (마이그레이션 후 검증만) │ +│ │ +│ ✅ 필수 사항 │ +│ ───────────────────────────────────────────────────────────────────── │ +│ - 경동기업 기준으로 맞춤 (이미 사용중인 시스템) │ +│ - 전체 이관 (items + prices + BOM) │ +│ - SQL 쿼리 + PHP 스크립트 혼용 (JSON 파싱 필요) │ +│ - 로컬 검증 완료 후 개발서버 배포 │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 6.1 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | SELECT 쿼리, 분석, 매핑 설계 | 불필요 | +| ⚠️ 컨펌 필요 | INSERT 실행, TRUNCATE, 개발서버 배포 | **필수** | +| 🔴 금지 | 운영서버 직접 작업 | 별도 협의 | + +--- + +## 7. 데이터 규모 예상 + +### 7.1 items 테이블 예상 + +| 소스 | 레코드 수 | SAM item_type | 예상 items 건수 | +|------|----------|---------------|----------------| +| **KDunitprice** ⭐ | **603** | FG/PT/SM/RM/CS | **~603 (마스터)** | +| models | 18 | FG | ~0 (중복 제외) | +| category_l4 | 37 | PT | ~20 (일부 신규) | +| item_list | 5 | PT | ~0 (중복 제외) | +| price_* 테이블 | ~130 항목 | SM/RM | ~100 (신규만) | +| **items 합계** | - | - | **~700~800건** | + +**item_type별 분포 예상**: +| item_type | 설명 | 예상 건수 | +|-----------|------|----------| +| FG | 완제품 | ~100건 | +| PT | 부품 | ~250건 | +| SM | 부자재 | ~300건 | +| RM | 원자재 | ~100건 | +| CS | 소모품 | ~50건 | + +### 7.2 prices 테이블 예상 ⭐ + +| 소스 | 버전 수 | 품목당 단가 | 예상 prices 건수 | +|------|--------|------------|-----------------| +| KDunitprice | 1 | 603 | ~603 | +| price_motor | 2 | 35 | ~70 | +| price_shaft | 2 | 15 | ~30 | +| price_pipe | 2 | 10 | ~20 | +| price_angle | 2 | 10 | ~20 | +| price_raw_materials | 6 | 20 | ~120 | +| price_bend | 3 | 10 | ~30 | +| 기타 price_* | 2 | 15 | ~30 | +| **prices 합계** | - | - | **~500건** (중복 제외) | + +--- + +## 8. 체크리스트 + +### Phase 1: 마스터 데이터 이관 ✅ 완료 +- [x] 레거시 DB 구조 분석 완료 +- [x] KDunitprice 테이블 발견 및 분석 (603건, 핵심 마스터) +- [x] 중복 제거 전략 수립 (code 기반, 매핑 테이블 불필요) +- [x] Seeder 기반 마이그레이션 계획 수립 +- [x] ~~config/database.php에 'legacy' 연결 추가~~ → 기존 'chandj' 연결 사용 +- [x] ~~.env에 LEGACY_DB_* 환경변수 추가~~ → 기존 CHANDJ_DB_* 사용 +- [x] **Phase 1.0**: KDunitprice → items 601건, prices 601건 ✅ +- [x] **Phase 1.1**: models → items (FG) 18건 ✅ +- [x] **Phase 1.2**: item_list → items (PT) 9건 ✅ +- [x] ~~Phase 1.3: category_l4~~ → 스킵 (카테고리 데이터) +- [x] **Phase 1 결과**: items 628건, prices 628건 ✅ + +### Phase 2: BOM 데이터 이관 ✅ 완료 +- [x] BDmodels.seconditem → PT items 누락 부품 6건 추가 ✅ +- [x] ~~child_item_id 매핑 테이블 생성~~ → code 기반 직접 조회 +- [x] items.bom JSON 생성 (18건 FG ↔ PT 연결) ✅ +- [x] **최종 결과**: items 634건, prices 634건, BOM 18건 ✅ (2026-01-28) + +### Phase 3: 단가 데이터 이관 ✅ 완료 +- [x] 레거시 price_* 테이블 구조 분석 (10개) +- [x] 각 테이블별 JSON 스키마 분석 +- [x] SAM prices 테이블 구조 확인 +- [x] Legacy → SAM 단가 매핑 전략 수립 +- [x] price_motor → items (SM) 누락 품목 13건 추가 ✅ +- [x] price_raw_materials → items (RM) 누락 품목 4건 추가 ✅ +- [x] 기타 price_* 테이블 분석 완료 (대부분 계산 참조용, 품목 마스터 아님) + - price_shaft, price_pipe, price_angle, price_bend, price_pole, price_screenplate: 계산 참조용 + - 220V/380V 모터: KDunitprice에 "KD모터*Kg단상/삼상"으로 이미 존재 +- [x] **사용자 승인**: 완료 (2026-01-28) + +### Phase 4: 검증 및 배포 ✅ 로컬 검증 완료 +- [x] 건수 검증 ✅ (items 651건, prices 651건, BOM 18건) +- [x] 데이터 조회 테스트 ✅ (artisan tinker, MySQL 직접 쿼리) +- [x] code 중복 검증 ✅ (0건) +- [x] Phase 3 추가 품목 확인 ✅ (PM-* 13건, RM-* 4건) +- [ ] ⚠️ **사용자 승인**: 개발서버 배포 + +--- + +## 9. 참고 문서 + +- **레거시 소스**: `5130/` 폴더 +- **SAM items 마이그레이션**: `api/database/migrations/2025_12_13_152507_create_items_table.php` +- **SAM prices 마이그레이션**: `api/database/migrations/2025_12_08_154633_create_prices_table.php` +- **SAM price_revisions 마이그레이션**: `api/database/migrations/2025_12_08_154634_create_price_revisions_table.php` +- **품목 분석**: `docs/data/analysis/item-db-analysis.md` +- **DummyItemSeeder**: `api/database/seeders/Dummy/DummyItemSeeder.php` +- **DummyDataSeeder**: `api/database/seeders/DummyDataSeeder.php` (TENANT_ID=287, USER_ID=1 상수 참조) +- **prices item_type_code 마이그레이션**: `api/database/migrations/2025_12_21_165524_update_prices_item_type_code_to_actual_item_type.php` +- **연관 문서**: `docs/plans/kd-orders-migration-plan.md` (입고/재고/주문 마이그레이션) + +--- + +## 10. 세션 및 메모리 관리 정책 + +### 10.1 세션 시작 시 (Load Strategy) +```bash +# 1. Docker 확인 +docker ps | grep sam + +# 2. DB 접속 테스트 +docker exec sam-mysql-1 mysql -uroot -proot chandj -e "SELECT COUNT(*) FROM KDunitprice;" +docker exec sam-mysql-1 mysql -uroot -proot samdb -e "SELECT COUNT(*) FROM items WHERE tenant_id=287;" + +# 3. 현재 진행 상태 확인 +# → 이 문서의 "📍 현재 진행 상태" 섹션 참조 + +# 4. 마이그레이션 상태 확인 (API 프로젝트) +cd /Users/kent/Works/@KD_SAM/SAM/api && php artisan migrate:status +``` + +### 10.2 작업 중 관리 + +| 작업 완료 시 | 조치 | +|-------------|------| +| Phase 완료 | "📍 현재 진행 상태" 업데이트 | +| INSERT 실행 | "12. 변경 이력" 추가 | +| 스키마 변경 | 관련 섹션 업데이트 + 변경 이력 추가 | +| 오류 발생 | 체크리스트에 메모 추가 | + +### 10.3 컨텍스트 관리 + +| 컨텍스트 잔량 | 조치 | +|--------------|------| +| **30% 이하** | 현재 작업 중단점 문서에 기록 | +| **20% 이하** | "📍 현재 진행 상태" 최종 업데이트 | +| **10% 이하** | 세션 정리 및 다음 세션 가이드 작성 | + +--- + +## 11. 자기완결성 점검 결과 + +### 11.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 섹션 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 0 성공 기준 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 4 대상 범위 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Quick Start 전제 조건 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 9 참고 문서 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 5 SQL 쿼리 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 0 확인 방법 SQL | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 건수, 테이블명, 컬럼 명시 | + +### 11.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경, 문서 헤더 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 📍 현재 진행 상태 → 다음 작업 상세 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 9. 참고 문서 | +| Q4. 작업 완료 확인 방법은? | ✅ | 0. 성공 기준 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 9. 참고 문서, Quick Start DB 접속 명령어 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +### 11.3 핵심 정보 요약 (새 세션용) + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 📋 핵심 정보 요약 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 🎯 목표: 경동기업 레거시(chandj) → SAM(samdb) 품목/단가 이관 │ +│ │ +│ 📊 데이터 규모 (총 ~1,500건): │ +│ - items: ~800건 (KDunitprice 603 + 추가) │ +│ - prices: ~500건 │ +│ - item_bom_items: ~200건 │ +│ │ +│ 🔑 핵심 상수: │ +│ - tenant_id = 287 (경동기업) │ +│ - user_id = 1 (생성자) │ +│ - Docker: sam-mysql-1 │ +│ - 레거시 DB: chandj / SAM DB: samdb ⚠️ │ +│ │ +│ ⭐ KDunitprice 실제 컬럼명 (2026-01-28 확인): │ +│ - prodcode (품목코드) → items.code │ +│ - item_name (품목명) → items.name │ +│ - spec (규격) → items.attributes.spec │ +│ - unit (단위) → items.unit │ +│ - item_div ([제품] 등) → items.item_type │ +│ - unitprice (단가, 단일 컬럼!) → prices.sales_price │ +│ │ +│ ⭐ 마이그레이션 순서 (Seeder 기반): │ +│ 1. config/database.php에 'legacy' 연결 추가 │ +│ 2. .env에 LEGACY_DB_* 환경변수 추가 │ +│ 3. KyungdongItemSeeder.php 파일 생성 ← 최우선! │ +│ 4. Seeder 실행 (items 603건 + prices 603건) │ +│ 5. 추가 items/BOM은 확장 Seeder로 처리 │ +│ │ +│ 📍 현재 상태: Phase 1 대기 (Seeder 파일 생성 및 실행) │ +│ │ +│ ❌ 불필요한 것: item_id_mappings (양방향 조회 불필요, chandj 손 안댐) │ +│ │ +│ ⚠️ 주의: 모든 INSERT 실행 전 사용자 승인 필요 │ +│ │ +│ 📎 연관 문서: docs/plans/kd-orders-migration-plan.md (입고/재고/주문) │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 12. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-28 | 문서 분리 | items-migration-kyungdong-plan.md에서 품목/단가 부분 분리 | - | - | +| 2026-01-28 | 문서 생성 | kd-items-migration-plan.md 신규 생성 | - | - | +| 2026-01-28 | 컬럼명 수정 | 실제 DB 컬럼명으로 업데이트 (품목코드→prodcode, 품목명→item_name 등) | - | - | +| 2026-01-28 | Seeder 전환 | SQL → Seeder 방식으로 전환, 섹션 5.0~5.6 구조 정리 | - | - | + +--- + +## 13. 트러블슈팅 가이드 + +### 13.1 일반적인 문제 + +| 문제 | 원인 | 해결책 | +|------|------|--------| +| Docker 컨테이너 없음 | Docker 미실행 | `docker-compose up -d` 실행 | +| DB 접속 실패 | 컨테이너명 변경 | `docker ps`로 정확한 컨테이너명 확인 | +| chandj DB 없음 | 레거시 DB 미설정 | Docker 볼륨 확인 또는 덤프 복원 | +| tenant_id 287 없음 | 경동기업 테넌트 미생성 | SAM에서 테넌트 생성 필요 | +| items 테이블 없음 | 마이그레이션 미실행 | `php artisan migrate` 실행 | +| **SAM DB 이름 오류** | `sam` 대신 `samdb` | 모든 쿼리에서 `samdb` 사용 확인 | +| KDunitprice 테이블 없음 | 레거시 덤프 불완전 | chandj 전체 덤프 확인 | + +### 13.2 JSON 파싱 오류 + +```php +// price_* 테이블의 itemList 파싱 시 주의사항 +$itemList = json_decode($record['itemList'], true); + +// 빈 값 또는 잘못된 JSON 처리 +if (empty($itemList) || !is_array($itemList)) { + // 스킵하고 로그 기록 + error_log("Invalid itemList in {$table} num={$record['num']}"); + continue; +} + +// 숫자 형식 변환 (콤마 제거) +$price = (float)str_replace(',', '', $item['col13'] ?? '0'); +``` + +### 13.3 중복 코드 처리 (code 기반) + +```sql +-- 이미 존재하는 품목 확인 (code 유일성 검사) +SELECT code, COUNT(*) AS cnt +FROM samdb.items +WHERE tenant_id=287 +GROUP BY code +HAVING cnt > 1; + +-- INSERT 시 ON DUPLICATE KEY UPDATE 사용 +-- ⚠️ items 테이블에 (tenant_id, code) UNIQUE 인덱스 필요 +INSERT INTO samdb.items (...) VALUES (...) +ON DUPLICATE KEY UPDATE name = VALUES(name), updated_at = NOW(); + +-- KDunitprice와 price_* 중복 확인 (⭐ 실제 컬럼명 사용) +SELECT k.prodcode, '모터 150K' AS price_item +FROM chandj.KDunitprice k +WHERE k.item_name LIKE '%모터%150K%'; +-- → KDunitprice가 마스터, price_*는 가격만 추가 +``` + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/l2-permission-management-plan.md b/plans/archive/l2-permission-management-plan.md new file mode 100644 index 0000000..e7490a2 --- /dev/null +++ b/plans/archive/l2-permission-management-plan.md @@ -0,0 +1,378 @@ +# L-2 권한관리 Mock → API 연동 계획 + +> **작성일**: 2025-12-30 +> **목적**: React 권한관리 페이지의 Mock 데이터를 API 연동으로 전환 +> **기준 문서**: mng.sam.kr/role-permissions +> **상태**: ✅ 완료 - Phase 1~4 전체 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4 React 연동 완료 | +| **다음 작업** | 완료 (테스트 후 운영 배포) | +| **진행률** | 12/12 (100%) | +| **마지막 업데이트** | 2025-12-30 + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 React의 권한관리 페이지(`/settings/permissions`)는 `localStorage`와 `defaultPermissions` Mock 데이터를 사용하고 있습니다. mng 프로젝트에는 이미 완전한 역할-권한 관리 시스템이 구현되어 있으므로, api 프로젝트에 동일한 API를 개발하고 React에서 연동해야 합니다. + +**문제점:** +- React는 `localStorage`에 권한 데이터 저장 (새로고침/브라우저 변경 시 데이터 손실) +- 실제 DB 연동 없음 +- 역할 숨김(is_hidden) 기능이 DB 스키마에 없음 + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. React → api.sam.kr만 호출 (mng 직접 호출 금지) │ +│ 2. mng의 RoleService/RolePermissionService 로직 참조하여 api에 재구현 │ +│ 3. Spatie Permission 패키지 활용 (기존 테이블 구조 유지) │ +│ 4. Multi-tenant 지원 필수 (BelongsToTenant) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | API 엔드포인트 추가, 타입 정의, 문서 수정 | 불필요 | +| ⚠️ 컨펌 필요 | DB 마이그레이션 (is_hidden 컬럼), 기존 API 수정 | **필수** | +| 🔴 금지 | roles 테이블 구조 대폭 변경, 기존 권한 삭제 | 별도 협의 | + +### 1.4 준수 규칙 + +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/api-rules.md` - API 개발 규칙 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/specs/database-schema.md` - DB 스키마 + +--- + +## 2. 현재 상태 분석 + +### 2.1 mng 프로젝트 (기준) + +| 파일 | 역할 | 주요 기능 | +|------|------|----------| +| `RoleController.php` | 역할 CRUD 화면 | index, create, edit | +| `RoleService.php` | 역할 비즈니스 로직 | getRoles, createRole, updateRole, deleteRole | +| `RolePermissionController.php` | 권한 매트릭스 화면 | index (테넌트별 역할 목록) | +| `RolePermissionService.php` | 권한 매트릭스 로직 | togglePermission, allowAll, denyAll, getMenuTree | +| `Role.php` (Model) | 역할 모델 | tenant, permissions, users 관계 | + +**mng의 역할 필드:** +```php +$fillable = ['tenant_id', 'name', 'description', 'guard_name']; +``` + +**⚠️ 숨김 기능 없음**: mng에도 `is_hidden` 필드가 없음 + +### 2.2 React 프로젝트 (현재) + +| 파일 | 현재 상태 | 문제점 | +|------|----------|--------| +| `index.tsx` | `localStorage` + `defaultPermissions` | 실제 DB 연동 없음 | +| `types.ts` | `Permission` 타입 정의 | `status: 'active' | 'hidden'` 있음 | +| `PermissionDetail.tsx` | 메뉴별 권한 설정 | Mock 데이터 사용 | + +**React의 Permission 타입:** +```typescript +interface Permission { + id: number; + name: string; + status: 'active' | 'hidden'; // ← DB에 없음! + menuPermissions: MenuPermission[]; + createdAt: string; +} +``` + +### 2.3 api 프로젝트 (현재) + +- **Role 관련 API 없음** (개발 필요) +- `shared/Models/Role.php` 존재 여부 확인 필요 + +### 2.4 DB 스키마 (roles 테이블) + +```sql +roles (11 컬럼): +- id (PK) +- tenant_id (FK → tenants.id) +- name +- guard_name (default: 'web') +- description +- created_by, updated_by, deleted_by +- created_at, updated_at, deleted_at + +-- ⚠️ is_hidden 컬럼 없음! 추가 필요 +``` + +--- + +## 3. 대상 범위 + +### 3.1 Phase 1: DB 스키마 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | roles 테이블에 `is_hidden` 컬럼 추가 | ✅ | `2025_12_30_160802_add_is_hidden_to_roles_table.php` 생성완료, 실행대기 | +| 1.2 | 기존 역할 데이터 기본값 설정 (is_hidden = false) | ✅ | 마이그레이션에 포함 | + +### 3.2 Phase 2: api 프로젝트 - Role CRUD API + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | Role 모델 생성/수정 | ✅ | shared/Models/Role.php | +| 2.2 | RoleService 생성 | ✅ | `api/app/Services/RoleService.php` | +| 2.3 | RoleController 생성 | ✅ | `api/app/Http/Controllers/Api/V1/RoleController.php` | +| 2.4 | RoleFormRequest 생성 | ⏳ | StoreRoleRequest, UpdateRoleRequest 미생성 | +| 2.5 | routes/api.php 라우트 추가 | ✅ | 5개 CRUD 라우트 등록완료 | +| 2.6 | Swagger 문서 작성 | ✅ | `api/app/Swagger/v1/RoleApi.php` | + +### 3.3 Phase 3: api 프로젝트 - 권한 매트릭스 API + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | RolePermissionController 생성 | ✅ | `api/app/Http/Controllers/Api/V1/RolePermissionController.php` | +| 3.2 | 권한 목록 조회 API | ✅ | GET /roles/{id}/permissions | +| 3.3 | 권한 부여 API | ✅ | POST /roles/{id}/permissions | +| 3.4 | 권한 회수/동기화 API | ✅ | DELETE, PUT /roles/{id}/permissions/sync | +| 3.5 | Swagger 문서 작성 | ✅ | `api/app/Swagger/v1/RolePermissionApi.php` | + +### 3.4 Phase 4: React 연동 ✅ + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | actions.ts 생성 | ✅ | 12개 Server Actions (fetchRoles, createRole, updateRole, deleteRole 등) | +| 4.2 | types.ts 수정 | ✅ | ApiResponse, Role, RoleStats, MenuTreeItem, PermissionMatrix 타입 추가 | +| 4.3 | index.tsx 수정 (목록) | ✅ | localStorage → API 연동, 로딩/에러 상태, toast 알림 | +| 4.4 | PermissionDetailClient.tsx 수정 (상세/권한매트릭스) | ✅ | 역할 CRUD, 권한 토글, 전체 허용/거부/초기화 | +| 4.5 | Mock 데이터 제거 | ✅ | defaultPermissions 삭제, API 기반으로 전환 | + +--- + +## 4. API 설계 + +### 4.1 Role CRUD API + +| Method | Endpoint | 설명 | Request | Response | +|--------|----------|------|---------|----------| +| GET | `/api/v1/roles` | 역할 목록 | `?search=&is_hidden=` | `{ data: Role[], meta: Pagination }` | +| GET | `/api/v1/roles/{id}` | 역할 상세 | - | `{ data: Role }` | +| POST | `/api/v1/roles` | 역할 생성 | `{ name, description, is_hidden }` | `{ data: Role }` | +| PUT | `/api/v1/roles/{id}` | 역할 수정 | `{ name, description, is_hidden }` | `{ data: Role }` | +| DELETE | `/api/v1/roles/{id}` | 역할 삭제 | - | `{ message }` | + +### 4.2 권한 매트릭스 API + +| Method | Endpoint | 설명 | Request | Response | +|--------|----------|------|---------|----------| +| GET | `/api/v1/roles/{id}/menus` | 메뉴 트리 + 권한 상태 | - | `{ data: MenuWithPermissions[] }` | +| POST | `/api/v1/roles/{id}/permissions/toggle` | 권한 토글 | `{ menu_id, permission_type }` | `{ data: { value: boolean } }` | +| POST | `/api/v1/roles/{id}/permissions/allow-all` | 전체 허용 | - | `{ message }` | +| POST | `/api/v1/roles/{id}/permissions/deny-all` | 전체 거부 | - | `{ message }` | +| POST | `/api/v1/roles/{id}/permissions/reset` | 기본값 초기화 | - | `{ message }` | + +### 4.3 Role 응답 타입 + +```typescript +interface Role { + id: number; + tenant_id: number; + name: string; + description: string | null; + guard_name: string; + is_hidden: boolean; // ← 신규 필드 + permissions_count: number; // ← 권한 개수 + users_count: number; // ← 사용자 수 + created_at: string; + updated_at: string; +} + +interface MenuWithPermissions { + id: number; + name: string; + parent_id: number | null; + depth: number; + has_children: boolean; + permissions: { + view: boolean; + create: boolean; + update: boolean; + delete: boolean; + approve: boolean; + export: boolean; + manage: boolean; + }; +} +``` + +--- + +## 5. 상세 작업 내용 + +### 5.1 Phase 1: DB 스키마 수정 ✅ + +#### 1.1 roles 테이블에 is_hidden 컬럼 추가 +- **상태**: ✅ 파일 생성완료 (실행 대기) +- **마이그레이션 파일**: `2025_12_30_160802_add_is_hidden_to_roles_table.php` +- **컬럼 정의**: `boolean is_hidden default false after description` +- **영향**: api, mng 모두 적용 + +### 5.2 Phase 2: Role CRUD API ✅ + +#### 생성된 파일 +| 파일 | 경로 | +|------|------| +| RoleController | `api/app/Http/Controllers/Api/V1/RoleController.php` | +| RoleService | `api/app/Services/RoleService.php` | +| RoleApi Swagger | `api/app/Swagger/v1/RoleApi.php` | + +#### 등록된 라우트 (5개) +``` +GET /api/v1/roles → index +POST /api/v1/roles → store +GET /api/v1/roles/{id} → show +PATCH /api/v1/roles/{id} → update +DELETE /api/v1/roles/{id} → destroy +``` + +### 5.3 Phase 3: 권한 매트릭스 API ✅ + +#### 생성된 파일 +| 파일 | 경로 | +|------|------| +| RolePermissionController | `api/app/Http/Controllers/Api/V1/RolePermissionController.php` | +| RolePermissionApi Swagger | `api/app/Swagger/v1/RolePermissionApi.php` | + +#### 등록된 라우트 (4개) +``` +GET /api/v1/roles/{id}/permissions → index +POST /api/v1/roles/{id}/permissions → grant +DELETE /api/v1/roles/{id}/permissions → revoke +PUT /api/v1/roles/{id}/permissions/sync → sync +``` + +--- + +## 6. 컨펌 대기 목록 + +> API 내부 로직 변경 등 승인 필요 항목 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | is_hidden 컬럼 추가 | roles 테이블 마이그레이션 | api, mng | ⏳ 대기 | + +--- + +## 7. 파일 구조 (예상) + +### 7.1 api 프로젝트 + +``` +api/app/ +├── Http/ +│ ├── Controllers/ +│ │ └── RoleController.php ← 🆕 생성 +│ └── Requests/ +│ ├── StoreRoleRequest.php ← 🆕 생성 +│ └── UpdateRoleRequest.php ← 🆕 생성 +├── Models/ +│ └── Role.php ← 🔄 수정 (is_hidden 추가) +└── Services/ + ├── RoleService.php ← 🆕 생성 + └── RolePermissionService.php ← 🆕 생성 + +api/database/migrations/ +└── xxxx_add_is_hidden_to_roles_table.php ← 🆕 생성 + +api/routes/ +└── api.php ← 🔄 수정 (라우트 추가) +``` + +### 7.2 React 프로젝트 + +``` +react/src/components/settings/PermissionManagement/ +├── index.tsx ← 🔄 수정 (API 연동) +├── types.ts ← 🔄 수정 (타입 매핑) +├── actions.ts ← 🆕 생성 +├── PermissionDetail.tsx ← 🔄 수정 (API 연동) +├── PermissionDetailClient.tsx ← 🔄 수정 +└── PermissionDialog.tsx ← 🔄 수정 +``` + +--- + +## 8. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-12-30 | Phase 1~3 | API 개발 완료 (마이그레이션, Controller, Service, Swagger, 라우트) | 다수 | ✅ | +| 2025-12-30 | Phase 4 | React 연동 완료 (actions.ts, types.ts, index.tsx, PermissionDetailClient.tsx) | react 4개 파일 | ✅ | +| 2025-12-30 | 문서 | 계획 문서 초안 작성 | - | - | +| 2025-12-30 | 문서 | Phase 4 완료 반영 업데이트 | - | - | + +--- + +## 9. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **API 규칙**: `docs/standards/api-rules.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **DB 스키마**: `docs/specs/database-schema.md` +- **mng 권한관리**: `mng/app/Services/RoleService.php`, `RolePermissionService.php` + +--- + +## 10. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 10.1 세션 시작 시 (Load Strategy) +```javascript +read_memory("l2-permission-state") // 1. 상태 파악 +read_memory("l2-permission-snapshot") // 2. 사고 흐름 복구 +``` + +### 10.2 Serena 메모리 구조 +- `l2-permission-state`: { phase, progress, next_step, last_decision } +- `l2-permission-snapshot`: 현재까지의 논의 및 코드 변경점 요약 + +--- + +## 11. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 11.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| GET /api/v1/roles | 역할 목록 반환 | | ⏳ | +| POST /api/v1/roles | 역할 생성 | | ⏳ | +| PUT /api/v1/roles/{id} | 역할 수정 | | ⏳ | +| DELETE /api/v1/roles/{id} | 역할 삭제 | | ⏳ | +| GET /api/v1/roles/{id}/menus | 메뉴+권한 매트릭스 | | ⏳ | +| POST /api/v1/roles/{id}/permissions/toggle | 권한 토글 | | ⏳ | + +### 11.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| localStorage 제거 | ⏳ | | +| 역할 CRUD API 동작 | ⏳ | | +| 권한 매트릭스 API 동작 | ⏳ | | +| 숨김 기능 동작 | ⏳ | | + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/material-input-per-item-mapping-plan.md b/plans/archive/material-input-per-item-mapping-plan.md new file mode 100644 index 0000000..e40c15b --- /dev/null +++ b/plans/archive/material-input-per-item-mapping-plan.md @@ -0,0 +1,482 @@ +# 개소별 자재 투입 매핑 계획 + +> **작성일**: 2026-02-12 +> **목적**: Worker Screen 자재 투입 시 개소(work_order_item)별 매핑 추적 기능 구현 +> **기준 문서**: `docs/specs/database-schema.md`, `docs/standards/api-rules.md` +> **상태**: 🔄 진행중 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 1~3 전체 구현 완료 | +| **다음 작업** | 테스트 및 검증 | +| **진행률** | 8/8 (100%) | +| **마지막 업데이트** | 2026-02-12 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 자재 투입은 **작업지시(WorkOrder) 단위**로만 처리됨: +- `POST /api/v1/work-orders/{id}/material-inputs` → `{inputs: [{stock_lot_id, qty}]}` +- `stock_transactions.reference_id` = `work_order_id` (개소 정보 없음) +- 어떤 개소(work_order_item)에 어떤 자재가 투입되었는지 추적 불가 + +**필요**: 개소별로 자재 투입을 추적하여: +- 개소별 투입 완료 여부 확인 +- 개소별 필요 자재 vs 실투입 비교 +- 검사서에 개소별 투입 자재 LOT 번호 기록 + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 신규 테이블(work_order_material_inputs)로 개소별 매핑 추적 │ +│ 2. 기존 stock_transactions 구조 변경 없음 (재고 이력은 그대로) │ +│ 3. 기존 작업지시 단위 API는 유지, 개소별 API를 추가 │ +│ 4. BOM 기반 필요 자재 계산은 기존 로직 재활용 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 타입 정의 추가, 프론트 UI 변경 | 불필요 | +| ⚠️ 컨펌 필요 | 새 마이그레이션, 새 API 엔드포인트, 서비스 로직 변경 | **필수** | +| 🔴 금지 | 기존 stock_transactions 구조 변경, 기존 API 삭제 | 별도 협의 | + +### 1.4 준수 규칙 +- `docs/standards/api-rules.md` - Service-First, FormRequest, ApiResponse::handle() +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/specs/database-schema.md` - DB 스키마 규칙 +- MEMORY.md: 멀티테넌시 원칙 (FK/조인키만 컬럼, 나머지 options JSON) + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: Database & Model (백엔드 기반) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | `work_order_material_inputs` 마이그레이션 생성 | ✅ | api/ 프로젝트에서 | +| 1.2 | `WorkOrderMaterialInput` 모델 생성 | ✅ | BelongsToTenant 필수 | +| 1.3 | 관계 설정 (WorkOrderItem, WorkOrder) | ✅ | | + +### 2.2 Phase 2: Backend API (서비스 + 컨트롤러) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | `getMaterialsForItem()` 서비스 메서드 | ✅ | 개소별 BOM 자재 조회 | +| 2.2 | `registerMaterialInputForItem()` 서비스 메서드 | ✅ | 개소별 투입 + 매핑 저장 | +| 2.3 | `getMaterialInputsForItem()` 서비스 메서드 | ✅ | 개소별 투입 이력 조회 | +| 2.4 | 컨트롤러 엔드포인트 추가 | ✅ | 3개 엔드포인트 | +| 2.5 | FormRequest 생성 | ✅ | 투입 요청 검증 | +| 2.6 | 라우트 등록 | ✅ | production.php | + +### 2.3 Phase 3: Frontend (React) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | Server Actions 추가 | ✅ | 개소별 API 호출 함수 | +| 3.2 | MaterialInputModal props 확장 | ✅ | workOrderItemId 추가 | +| 3.3 | 자재투입 버튼 → 개소별 호출 연결 | ✅ | WorkerScreen에서 | +| 3.4 | 투입 이력/상태 표시 | ✅ | 개소 카드에 투입 완료 표시 | + +--- + +## 3. 상세 설계 + +### 3.1 신규 테이블: `work_order_material_inputs` + +```sql +CREATE TABLE work_order_material_inputs ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT UNSIGNED NOT NULL, + work_order_id BIGINT UNSIGNED NOT NULL COMMENT '작업지시 ID', + work_order_item_id BIGINT UNSIGNED NOT NULL COMMENT '개소(작업지시품목) ID', + stock_lot_id BIGINT UNSIGNED NOT NULL COMMENT '투입 로트 ID', + item_id BIGINT UNSIGNED NOT NULL COMMENT '자재 품목 ID', + qty DECIMAL(12,3) NOT NULL COMMENT '투입 수량', + input_by BIGINT UNSIGNED NULL COMMENT '투입자 ID', + input_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '투입 시각', + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + -- FK + FOREIGN KEY (work_order_id) REFERENCES work_orders(id) ON DELETE CASCADE, + FOREIGN KEY (work_order_item_id) REFERENCES work_order_items(id) ON DELETE CASCADE, + + -- Index + INDEX idx_womi_tenant (tenant_id), + INDEX idx_womi_wo_item (work_order_id, work_order_item_id), + INDEX idx_womi_lot (stock_lot_id) +) COMMENT='개소별 자재 투입 이력'; +``` + +**설계 근거**: +- `work_order_id`: 작업지시 단위 조회용 (기존 호환) +- `work_order_item_id`: 개소별 매핑 핵심 +- `stock_lot_id`: 어떤 LOT에서 투입했는지 +- `item_id`: 어떤 자재(품목)인지 +- `qty`: 투입 수량 +- `input_by`, `input_at`: 투입자/시간 추적 + +### 3.2 API 엔드포인트 + +#### GET `/api/v1/work-orders/{workOrderId}/items/{itemId}/materials` +- **용도**: 특정 개소의 BOM 기반 필요 자재 + 재고 LOT 조회 +- **응답**: 기존 `MaterialForInput[]`과 동일 구조 +- **로직**: 기존 `getMaterials()` 중 해당 item_id의 BOM만 추출 + +#### POST `/api/v1/work-orders/{workOrderId}/items/{itemId}/material-inputs` +- **용도**: 특정 개소에 자재 투입 등록 +- **요청**: +```json +{ + "inputs": [ + { "stock_lot_id": 456, "qty": 100 } + ] +} +``` +- **처리 순서**: + 1. `StockService::decreaseFromLot()` 호출 (기존 재고 차감 로직 재사용) + 2. `work_order_material_inputs` 레코드 생성 (개소 매핑) + 3. 감사 로그 기록 +- **응답**: +```json +{ + "work_order_id": 123, + "work_order_item_id": 789, + "material_count": 2, + "input_results": [...], + "input_at": "2026-02-12T14:30:00" +} +``` + +#### GET `/api/v1/work-orders/{workOrderId}/items/{itemId}/material-inputs` +- **용도**: 특정 개소의 투입 이력 조회 +- **응답**: +```json +{ + "data": [ + { + "id": 1, + "stock_lot_id": 456, + "lot_no": "LOT-2026-001", + "item_id": 100, + "material_code": "MAT-001", + "material_name": "내화실", + "qty": 100, + "unit": "EA", + "input_by": 5, + "input_by_name": "홍길동", + "input_at": "2026-02-12T14:30:00" + } + ] +} +``` + +### 3.3 서비스 메서드 설계 + +#### WorkOrderService::getMaterialsForItem(int $workOrderId, int $itemId): array + +``` +1. WorkOrderItem 조회 (workOrderId + itemId 검증) +2. 해당 item의 BOM 추출 +3. BOM child_item별 required_qty = bom_qty × item.quantity +4. 각 자재의 StockLot 조회 (FIFO) +5. 이미 투입된 수량 차감 계산 (work_order_material_inputs에서 SUM) +6. 반환: MaterialForInput[] (remaining_required_qty 포함) +``` + +#### WorkOrderService::registerMaterialInputForItem(int $workOrderId, int $itemId, array $inputs): array + +``` +DB::transaction { + 1. WorkOrderItem 조회 + 검증 + 2. foreach (inputs as input): + a. StockService::decreaseFromLot() (기존 로직 재사용) + b. WorkOrderMaterialInput::create({ + tenant_id, work_order_id, work_order_item_id, + stock_lot_id, item_id (로트의 품목), + qty, input_by, input_at + }) + 3. 감사 로그 기록 + 4. 결과 반환 +} +``` + +### 3.4 프론트엔드 변경 + +#### MaterialInputModal Props 확장 +```typescript +interface MaterialInputModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + order: WorkOrder | null; + workOrderItemId?: number; // ← 추가: 개소 ID + workOrderItemName?: string; // ← 추가: 개소명 (모달 헤더용) + isCompletionFlow?: boolean; + onComplete?: () => void; + onSaveMaterials?: (...) => void; + savedMaterials?: MaterialInput[]; +} +``` + +#### Server Actions 추가 +```typescript +// 개소별 자재 조회 +getMaterialsForItem(workOrderId: string, itemId: number): Promise<{ + success: boolean; + data: MaterialForInput[]; +}> + +// 개소별 자재 투입 +registerMaterialInputForItem(workOrderId: string, itemId: number, inputs: ...): Promise<{ + success: boolean; +}> + +// 개소별 투입 이력 +getMaterialInputsForItem(workOrderId: string, itemId: number): Promise<{ + success: boolean; + data: MaterialInputHistory[]; +}> +``` + +#### MaterialInputModal 로직 변경 +``` +useEffect에서: + if (workOrderItemId) { + getMaterialsForItem(order.id, workOrderItemId) // 개소별 조회 + } else { + getMaterialsForWorkOrder(order.id) // 기존 전체 조회 (하위호환) + } + +handleSubmit에서: + if (workOrderItemId) { + registerMaterialInputForItem(order.id, workOrderItemId, inputs) + } else { + registerMaterialInput(order.id, inputs) + } +``` + +### 3.5 기존 API와의 관계 + +``` +기존 API (유지, 하위 호환): + GET /work-orders/{id}/materials → 전체 자재 조회 + POST /work-orders/{id}/material-inputs → 전체 단위 투입 + +신규 API (추가): + GET /work-orders/{id}/items/{itemId}/materials → 개소별 자재 조회 + POST /work-orders/{id}/items/{itemId}/material-inputs → 개소별 투입 + GET /work-orders/{id}/items/{itemId}/material-inputs → 개소별 투입 이력 +``` + +--- + +## 4. 작업 절차 + +### Step 1: 마이그레이션 + 모델 (Phase 1) +``` +1.1 api/ 프로젝트에서 마이그레이션 파일 생성 + - 파일: api/database/migrations/2026_02_12_XXXXXX_create_work_order_material_inputs_table.php + - 테이블: work_order_material_inputs (섹션 3.1 참조) + +1.2 WorkOrderMaterialInput 모델 생성 + - 파일: api/app/Models/Production/WorkOrderMaterialInput.php + - traits: BelongsToTenant, SoftDeletes (선택) + - $fillable: tenant_id, work_order_id, work_order_item_id, stock_lot_id, item_id, qty, input_by, input_at + - 관계: belongsTo(WorkOrder), belongsTo(WorkOrderItem), belongsTo(StockLot) + +1.3 기존 모델에 역관계 추가 + - WorkOrderItem: hasMany(WorkOrderMaterialInput) + - WorkOrder: hasMany(WorkOrderMaterialInput) + +검증: docker exec sam-api-1 php artisan migrate → 테이블 생성 확인 +``` + +### Step 2: Backend Service (Phase 2.1-2.3) +``` +2.1 WorkOrderService에 getMaterialsForItem() 추가 + - 기존 getMaterials() 로직 재활용 + - 해당 item의 BOM만 필터링 + - 이미 투입된 수량 차감 표시 + +2.2 WorkOrderService에 registerMaterialInputForItem() 추가 + - 기존 registerMaterialInput() 로직 기반 + - work_order_material_inputs 레코드 추가 생성 + - 트랜잭션 내에서 처리 + +2.3 WorkOrderService에 getMaterialInputsForItem() 추가 + - work_order_material_inputs 조회 + - lot_no, material_name 등 조인 + +검증: API 테스트 (curl 또는 Swagger) +``` + +### Step 3: Controller + Route (Phase 2.4-2.6) +``` +2.4 WorkOrderController에 3개 메서드 추가 + - materialsForItem(int $workOrderId, int $itemId) + - registerMaterialInputForItem(Request, int $workOrderId, int $itemId) + - materialInputsForItem(int $workOrderId, int $itemId) + +2.5 MaterialInputForItemRequest FormRequest 생성 (투입 검증) + - inputs: required|array|min:1 + - inputs.*.stock_lot_id: required|integer + - inputs.*.qty: required|numeric|gt:0 + +2.6 라우트 등록: api/routes/api/v1/production.php + - Route::get('work-orders/{id}/items/{itemId}/materials', ...) + - Route::post('work-orders/{id}/items/{itemId}/material-inputs', ...) + - Route::get('work-orders/{id}/items/{itemId}/material-inputs', ...) + +검증: php artisan route:list | grep material +``` + +### Step 4: Frontend (Phase 3) +``` +3.1 actions.ts에 3개 Server Action 추가 + - getMaterialsForItem() + - registerMaterialInputForItem() + - getMaterialInputsForItem() + +3.2 MaterialInputModal 수정 + - workOrderItemId prop 추가 + - useEffect에서 조건부 API 호출 + - handleSubmit에서 조건부 API 호출 + - 모달 헤더에 개소명 표시 + +3.3 WorkerScreen에서 개소별 자재투입 연결 + - 자재투입 버튼 클릭 시 workOrderItemId 전달 + +3.4 개소 카드에 투입 상태 표시 + - 투입 완료/미완료 뱃지 + +검증: dev.sam.kr에서 실제 플로우 테스트 +``` + +--- + +## 5. 핵심 파일 참조 + +### Backend (api/) +| 파일 | 역할 | +|------|------| +| `app/Services/WorkOrderService.php` | getMaterials() (line 1117), registerMaterialInput() (line 1264) | +| `app/Services/StockService.php` | decreaseFromLot() (line 618) - 재고 차감 | +| `app/Http/Controllers/Api/V1/WorkOrderController.php` | materials(), registerMaterialInput() | +| `routes/api/v1/production.php` (line 67-70) | 자재 관련 라우트 | +| `app/Models/Production/WorkOrderItem.php` | 작업지시 품목 모델 | + +### Frontend (react/) +| 파일 | 역할 | +|------|------| +| `src/components/production/WorkerScreen/MaterialInputModal.tsx` | 자재 투입 모달 UI | +| `src/components/production/WorkerScreen/actions.ts` | getMaterialsForWorkOrder(), registerMaterialInput() | +| `src/components/production/WorkerScreen/types.ts` | MaterialForInput, MaterialInput 타입 | + +### Database +| 테이블 | 역할 | +|--------|------| +| `work_order_items` | 작업지시 품목(개소). options JSON에 공정별 상세 | +| `stock_lots` | 재고 LOT. available_qty, fifo_order | +| `stock_transactions` | 재고 거래 이력. reference_type='work_order_input' | +| `work_order_material_inputs` | **신규** - 개소별 투입 매핑 | + +--- + +## 6. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 마이그레이션 | work_order_material_inputs 테이블 생성 | DB | ⚠️ 컨펌 필요 | +| 2 | API 엔드포인트 3개 추가 | 개소별 자재 조회/투입/이력 | api | ⚠️ 컨펌 필요 | +| 3 | 기존 API 유지 여부 | 작업지시 단위 API 유지 (하위호환) | api | ✅ 유지 | + +--- + +## 7. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-12 | - | 문서 초안 작성 | - | - | + +--- + +## 8. 참고 문서 + +- **API 규칙**: `docs/standards/api-rules.md` +- **DB 스키마**: `docs/specs/database-schema.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **기존 분석**: Explore Agent 분석 결과 (세션 내) +- **품목 정책**: `docs/rules/item-policy.md` (BOM, lot_managed 등) +- **MEMORY.md**: 멀티테넌시 원칙, 품목 options 체계 + +--- + +## 9. 검증 결과 + +### 9.1 테스트 케이스 + +| # | 시나리오 | 예상 결과 | 실제 결과 | 상태 | +|---|---------|----------|----------|------| +| 1 | 개소별 자재 조회 (BOM 있는 품목) | 해당 개소 BOM의 자재 + LOT 목록 반환 | | ✅ | +| 2 | 개소별 자재 조회 (BOM 없는 품목) | 품목 자체를 자재로 반환 | | ✅ | +| 3 | 개소별 자재 투입 | stock_lot 차감 + material_inputs 레코드 생성 | | ✅ | +| 4 | 이미 투입된 자재 재조회 | remaining_required_qty 감소 확인 | | ✅ | +| 5 | 가용수량 초과 투입 시도 | 에러 반환 (재고 부족) | | ✅ | +| 6 | 투입 이력 조회 | lot_no, 자재명, 수량, 투입자 확인 | | ✅ | +| 7 | 프론트 자재투입 모달에서 개소별 투입 | 해당 개소 자재만 표시, 투입 성공 | | ✅ | + +### 9.2 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 개소별 자재 조회 API 동작 | ✅ | BOM 기반 필터링 | +| 개소별 자재 투입 API 동작 | ✅ | 재고 차감 + 매핑 저장 | +| 프론트에서 개소별 투입 플로우 | ✅ | MaterialInputModal 연동 | +| 기존 작업지시 단위 API 호환 유지 | ✅ | 기존 기능 미파손 | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 개소별 자재 투입 매핑 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 9.2 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-3, 8개 작업 항목 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 기존 API, StockService 재사용 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 5 핵심 파일 참조 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 4 Step 1-4 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9.1 테스트 케이스 | +| 8 | 모호한 표현이 없는가? | ✅ | SQL, API 스키마 구체적 명시 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 4. 작업 절차 Step 1 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 5. 핵심 파일 참조 | +| Q4. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 8. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/mes-integration-analysis-plan.md b/plans/archive/mes-integration-analysis-plan.md new file mode 100644 index 0000000..3b9bc28 --- /dev/null +++ b/plans/archive/mes-integration-analysis-plan.md @@ -0,0 +1,525 @@ +# MES 모듈 통합 흐름 분석 계획 + +> **작성일**: 2025-01-09 +> **목적**: 견적 → 수주 → 작업지시 + 공정관리 모듈 간 연동 상태 점검 및 문제점 분석 +> **기준 문서**: `docs/plans/process-management-plan.md`, `docs/plans/order-management-plan.md`, `docs/plans/work-order-plan.md` +> **상태**: ✅ 분석 완료 + 개선 방향 **재결정됨** (2025-01-09 추가 분석) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 공정 관리 페이지 확인 + 개념 명확화 | +| **다음 작업** | WorkOrder `process_type` → `process_id` FK 변경 구현 | +| **진행률** | 7/7 (100%) | +| **마지막 업데이트** | 2025-01-09 | + +### ✅ 결정된 개선 방향 (재결정) + +| 결정 사항 | 내용 | +|----------|------| +| **WorkOrder.process_type** | `process_type` (varchar) → `process_id` (FK) **변경** | +| **Process.process_type** | 공정 구분 → `common_codes`에서 관리 | +| **개념 정리** | 공정명(WorkOrder) ≠ 공정구분(Process) 명확히 구분 | + +--- + +## 1. 개요 + +### 1.1 배경 +MES 시스템의 핵심 모듈인 공정관리, 수주관리, 작업지시가 개별적으로 개발 완료되었으나, +모듈 간 통합 흐름이 제대로 설계되었는지 검증이 필요합니다. + +### 1.2 분석 목표 +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 분석 목표 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 모듈 간 데이터 흐름 검증 │ +│ 2. API 연동 상태 점검 │ +│ 3. 프론트엔드 연동 상태 점검 │ +│ 4. 설계 문제점 및 개선 방안 도출 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. 분석 대상 + +### 2.1 모듈 구성 + +| 모듈 | 역할 | API 상태 | Frontend 상태 | +|------|------|:--------:|:------------:| +| **견적관리 (Quote)** | 견적서 작성 및 수주 변환 | ✅ 완료 | ✅ 완료 | +| **수주관리 (Order)** | 견적→수주 변환, 생산지시 생성 | ✅ 완료 | ✅ 완료 | +| **작업지시 (WorkOrder)** | 실제 생산 작업 관리 | ✅ 완료 | ✅ 완료 | +| **공정관리 (Process)** | 공정 템플릿 및 품목 분류 규칙 관리 | ✅ 완료 | ✅ 완료 | + +### 2.2 기대 데이터 흐름 + +``` +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ 견적관리 │ │ 수주관리 │ │ 작업지시 │ │ 공정관리 │ +│ (Quote) │ ──→ │ (Order) │ ──→ │ (WorkOrder) │ ? │ (Process) │ +└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + - 견적서 작성 - 수주 확정 - 작업 상태 관리 - 공정 템플릿 + - 품목/단가 구성 - 생산지시 생성 - 담당자 배정 - 품목 분류 규칙 + - 고객 승인 - 납기 관리 - 공정별 진행 - 작업 단계 정의 +``` + +--- + +## 3. 분석 결과 + +### 3.0 ✅ 견적관리 → 수주관리 연동 (정상 작동) + +**API 연동 구현**: +``` +POST /api/v1/orders/from-quote/{quoteId} +→ Order 생성 + Quote 상태 변경 (finalized → converted) +``` + +**연결 관계**: +| 항목 | 내용 | +|------|------| +| FK 연결 | `orders.quote_id` → `quotes.id` | +| 상태 연동 | Quote `finalized` 시에만 수주 변환 가능 | +| 중복 방지 | 동일 Quote에 대해 중복 변환 불가 | + +**Quote 상태 흐름**: +``` +draft → sent → approved → finalized → converted +(임시저장) (발송) (승인) (확정) (수주변환) +``` + +**API 핵심 로직** (`api/app/Services/OrderService.php`): +```php +public function createFromQuote(int $quoteId): Order +{ + $quote = Quote::findOrFail($quoteId); + + // 변환 가능 상태 검증 (finalized만 가능) + if ($quote->status !== Quote::STATUS_FINALIZED) { + throw new BadRequestHttpException(__('error.quote.must_be_finalized')); + } + + // 중복 변환 방지 + $existingOrder = Order::where('quote_id', $quoteId)->first(); + if ($existingOrder) { + throw new BadRequestHttpException(__('error.order.already_exists_from_quote')); + } + + // Order 생성 + Quote 품목 자동 복사 + $order = Order::create([ + 'quote_id' => $quote->id, + 'client_id' => $quote->client_id, + 'status_code' => Order::STATUS_DRAFT, + // ... 견적 정보 복사 + ]); + + // Quote 상태 변경 + $quote->status = Quote::STATUS_CONVERTED; + $quote->save(); + + return $order; +} +``` + +**프론트엔드 구현**: +```typescript +// react/src/components/orders/actions.ts +export async function createOrderFromQuote( + quoteId: string | number +): Promise + +// react/src/components/quotes/QuotationSelectDialog.tsx +// 견적 선택 → 수주 변환 UI 컴포넌트 +``` + +**데이터 변환**: +| Quote 필드 | Order 필드 | 변환 방식 | +|-----------|-----------|----------| +| `id` | `quote_id` (FK) | 참조 | +| `client_id` | `client_id` | 복사 | +| `project_name` | `project_name` | 복사 | +| `quote_items` | `order_items` | 품목 복사 | +| `product_category` | - | 참조용 | + +**평가**: ✅ **정상 구현됨** - FK 관계, 상태 연동, 중복 방지 모두 정상 + +--- + +### 3.1 ✅ 수주관리 → 작업지시 연동 (정상 작동) + +**API 연동 구현**: +``` +POST /api/v1/orders/{id}/production-order +→ WorkOrder 생성 + Order 상태 변경 (CONFIRMED → IN_PROGRESS) +``` + +**연결 관계**: +| 항목 | 내용 | +|------|------| +| FK 연결 | `work_orders.sales_order_id` → `orders.id` | +| 상태 연동 | Order CONFIRMED 시에만 생산지시 가능 | +| 중복 방지 | 동일 Order에 대해 중복 생성 불가 | + +**프론트엔드 구현**: +```typescript +// react/src/components/orders/actions.ts +export async function createProductionOrder( + orderId: string, + data?: CreateProductionOrderData +): Promise + +// CreateProductionOrderData 타입 +interface CreateProductionOrderData { + processType?: 'screen' | 'slat' | 'bending'; + priority?: 'urgent' | 'high' | 'normal' | 'low'; + assigneeId?: number; + teamId?: number; + scheduledDate?: string; + memo?: string; +} +``` + +**평가**: ✅ **정상 구현됨** + +--- + +### 3.2 🔴 공정관리 → 작업지시 연동 (설계 문제 발견 → 해결 방향 결정) + +#### 3.2.0 ✅ 개념 명확화 (2025-01-09 추가 분석) + +**공정 관리 페이지 확인** (`/master-data/process-management`): + +| 공정코드 | 공정명 | 구분 | 담당부서 | 상태 | +|---------|-------|------|---------|------| +| P-001 | 슬랫 | 생산 | 경영본부 | 사용중 | +| P-002 | 스크린 | 생산 | 개발팀 | 사용중 | + +**핵심 발견**: +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 💡 개념 정리 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ WorkOrder.process_type = "공정명" (스크린, 슬랫, 절곡) │ +│ → 공정 관리 테이블(processes)에서 등록된 공정 │ +│ → 하드코딩 ❌ → 공정 테이블 FK로 연결해야 함 ✅ │ +│ │ +│ Process.process_type = "공정 구분" (생산, 검사, 포장, 조립) │ +│ → 공정의 분류/카테고리 │ +│ → common_codes에서 관리해야 함 ✅ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**최종 정리**: + +| 구분 | 필드명 | 실제 의미 | 현재 상태 | 올바른 상태 | +|------|--------|----------|----------|------------| +| **WorkOrder** | `process_type` | 공정명 | 하드코딩 (screen/slat/bending) | **공정 테이블 FK** | +| **Process** | `process_type` | 공정 구분 | 하드코딩 (생산/검사/포장/조립) | common_codes | + +--- + +#### 3.2.1 process_type 불일치 문제 (기존 분석) + +| 구분 | 공정관리 (Process) | 작업지시 (WorkOrder) | +|------|:------------------:|:-------------------:| +| **필드명** | `process_type` | `process_type` | +| **값 (Frontend)** | '생산', '검사', '포장', '조립' | 'screen', 'slat', 'bending' | +| **값 개수** | 4개 (한글) | 3개 (영문) | +| **실제 의미** | 공정 **구분** (카테고리) | 공정 **명** (공정 테이블 데이터) | + +**문제점**: +- 동일한 필드명(`process_type`)을 사용하지만 **완전히 다른 의미** +- WorkOrder는 **공정 테이블을 참조해야 하는데** 하드코딩되어 있음 +- **FK 관계가 없음** - Process 테이블과 WorkOrder 테이블 연결 없음 + +#### 3.2.2 코드 증거 + +**공정관리 타입** (`react/src/types/process.ts`): +```typescript +export type ProcessType = '생산' | '검사' | '포장' | '조립'; +``` + +**작업지시 타입** (`react/src/components/production/WorkOrders/types.ts`): +```typescript +export type ProcessType = 'screen' | 'slat' | 'bending'; + +export const PROCESS_TYPE_LABELS: Record = { + screen: '스크린', + slat: '슬랫', + bending: '절곡', +}; +``` + +**API 모델** (`api/app/Models/Production/WorkOrder.php`): +```php +const PROCESS_SCREEN = 'screen'; +const PROCESS_SLAT = 'slat'; +const PROCESS_BENDING = 'bending'; +``` + +#### 3.2.3 영향도 분석 + +| 기능 | 현재 상태 | 문제점 | +|------|----------|--------| +| 공정 선택 | WorkOrder 생성 시 하드코딩된 3개 옵션만 사용 | Process 테이블 활용 안됨 | +| 분류 규칙 | Process에만 존재 | WorkOrder에서 품목 자동 분류 불가 | +| 작업 단계 | Process와 WorkOrder 각각 별도 정의 | 데이터 중복 | +| 메타데이터 | Process에 풍부한 정보 (인원, 설비, 템플릿) | WorkOrder에서 미활용 | + +--- + +### 3.3 🟡 공정관리 → 수주관리 연동 (연결 없음) + +**현재 상태**: +- Process와 Order 간 직접적인 연결 관계 없음 +- 이는 **의도된 설계**로 보임 (공정은 생산 단계에서 적용) + +--- + +## 4. 문제점 요약 + +### 4.1 핵심 문제: process_type 이중 정의 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🔴 핵심 문제 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 공정관리(Process)와 작업지시(WorkOrder)가 │ +│ 동일한 필드명(process_type)을 사용하지만 │ +│ 완전히 다른 값 체계와 목적을 가지고 있음 │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Process │ ❌ │ WorkOrder │ │ +│ │ (생산/검사) │ ─────── │ (screen/slat) │ │ +│ └─────────────┘ 연결없음 └─────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 4.2 문제 유형 분류 + +| # | 문제 | 심각도 | 영향 | +|---|------|:------:|------| +| 1 | process_type 값 체계 불일치 | 🔴 높음 | 데이터 일관성, 확장성 | +| 2 | Process ↔ WorkOrder FK 부재 | 🔴 높음 | 메타데이터 활용 불가 | +| 3 | 공정 정보 중복 정의 | 🟡 중간 | 유지보수 복잡성 | +| 4 | 새 공정 추가 시 코드 수정 필요 | 🟡 중간 | 확장성 제한 | + +--- + +## 5. 해결 방안 (검토 필요) + +### 5.1 Option A: 현행 유지 (의도된 분리) + +**전제**: 공정관리와 작업지시가 **서로 다른 도메인**임을 인정 + +``` +공정관리 (Process) 작업지시 (WorkOrder) +───────────────── ───────────────── +목적: 품목 분류 자동화 목적: 실제 생산 작업 관리 +대상: 모든 품목 유형 대상: 특화 제조품 (스크린/슬랫/절곡) +사용자: 품질/물류팀 사용자: 생산팀 +``` + +**장점**: +- 현재 코드 변경 불필요 +- 각 도메인의 독립성 유지 + +**단점**: +- `process_type` 필드명 혼란 지속 +- 공정 메타데이터 재활용 불가 + +**권장 조치**: +- WorkOrder의 `process_type`을 `manufacturing_type` 또는 `product_line`으로 **리네이밍** +- 문서에 두 개념의 차이 명확히 기술 + +--- + +### 5.2 Option B: 통합 연결 (FK 추가) + +**전제**: 공정관리가 작업지시의 **상위 템플릿** 역할을 해야 함 + +``` +Process (공정 템플릿) + │ + │ process_id (FK) + ▼ +WorkOrder (작업지시) +``` + +**필요 변경**: +1. `work_orders` 테이블에 `process_id` FK 추가 +2. Process 모델에 제조 공정 유형 추가 (screen, slat, bending) +3. WorkOrder 생성 시 Process 선택 UI 추가 +4. 공정별 메타데이터 (작업단계, 인원, 설비) 자동 적용 + +**장점**: +- 데이터 일관성 확보 +- 공정 메타데이터 재활용 +- 새 공정 추가 시 코드 수정 불필요 + +**단점**: +- DB 마이그레이션 필요 +- 기존 데이터 마이그레이션 필요 +- API 및 프론트엔드 수정 필요 + +--- + +### 5.3 Option C: 하이브리드 (권장) + +**전제**: 점진적 통합으로 위험 최소화 + +**Phase 1**: 명명 정리 (즉시) +- WorkOrder의 `process_type` → `manufacturing_type` 리네이밍 +- 문서 정리 및 팀 공유 + +**Phase 2**: 연결 준비 (중기) +- Process 모델에 `is_manufacturing` 플래그 추가 +- 제조 전용 공정 구분 (screen, slat, bending) + +**Phase 3**: 통합 (장기) +- WorkOrder에 `process_id` FK 추가 (optional) +- 메타데이터 연동 구현 + +--- + +## 6. 컨펌 결과 (✅ 결정 완료 → 재결정) + +| # | 항목 | ~~이전 결정~~ | **최종 결정** | 결정일 | +|---|------|-------------|--------------|--------| +| 1 | **설계 방향** | ~~Option C (하이브리드)~~ | **Option B** (FK 추가) | 2025-01-09 | +| 2 | **필드 변경** | ~~리네이밍만~~ | **FK로 변경** | 2025-01-09 | +| 3 | **FK 추가 여부** | ~~❌ 불필요~~ | **✅ 필요** - 공정 테이블 FK | 2025-01-09 | +| 4 | **도메인 연결** | ~~독립 도메인~~ | **Process → WorkOrder 연결** | 2025-01-09 | + +### 6.0 재결정 사유 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 💡 핵심 발견 (공정 관리 페이지 확인) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ WorkOrder.process_type 값 (screen, slat, bending)이 │ +│ 실제로는 공정 관리 페이지에서 등록된 "공정명"임을 확인 │ +│ │ +│ /master-data/process-management 등록 현황: │ +│ - P-001: 슬랫 (slat) │ +│ - P-002: 스크린 (screen) │ +│ │ +│ ∴ 하드코딩된 값이 아닌 공정 테이블 FK로 연결해야 함 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 6.1 다음 작업 (FK 추가 구현) + +``` +WorkOrder `process_type` (varchar) → `process_id` (FK) 변경 작업 범위: + +1. DB 마이그레이션 + - work_orders.process_type (varchar) 제거 + - work_orders.process_id (FK) 추가 → processes.id 참조 + - 기존 데이터 마이그레이션 (screen→P-002, slat→P-001, bending→신규등록) + +2. API 수정 + - api/app/Models/Production/WorkOrder.php + - PROCESS_* 상수 제거 + - process_type 필드 → process_id FK 필드 + - process() BelongsTo 관계 추가 + - api/app/Services/OrderService.php (생산지시 생성 로직) + - api/app/Services/WorkOrderService.php (비즈니스 로직) + - 관련 FormRequest, Resource 클래스 + +3. Frontend 수정 + - react/src/components/production/WorkOrders/types.ts + - ProcessType enum 제거 + - process_id: number 필드 추가 + - process 관계 데이터 타입 추가 + - 관련 컴포넌트 (actions.ts, components) + - 공정 선택 드롭다운 → API에서 공정 목록 조회 +``` + +--- + +## 7. 참고 문서 + +- **공정관리 계획**: `docs/plans/process-management-plan.md` +- **수주관리 계획**: `docs/plans/order-management-plan.md` +- **작업지시 계획**: `docs/plans/work-order-plan.md` +- **시스템 아키텍처**: `docs/architecture/system-overview.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` + +--- + +## 8. 분석 파일 참조 + +### 8.1 API 레이어 +| 파일 | 역할 | +|------|------| +| `api/app/Http/Controllers/Api/V1/QuoteController.php` | 견적 CRUD | +| `api/app/Http/Controllers/Api/V1/OrderController.php` | 수주 CRUD + 생산지시 생성 | +| `api/app/Http/Controllers/V1/ProcessController.php` | 공정 CRUD | +| `api/app/Http/Controllers/Api/V1/WorkOrderController.php` | 작업지시 CRUD | +| `api/app/Services/QuoteService.php` | 견적 비즈니스 로직 | +| `api/app/Services/OrderService.php` | 견적→수주 변환, 수주→작업지시 연동 | +| `api/app/Services/WorkOrderService.php` | 작업지시 비즈니스 로직 | + +### 8.2 모델 레이어 +| 파일 | 핵심 필드 | +|------|----------| +| `api/app/Models/Quote/Quote.php` | `status` (draft/sent/approved/finalized/converted), `product_category` | +| `api/app/Models/Order.php` | `status_code`, `quote_id` (FK) | +| `api/app/Models/Process.php` | `process_type` (생산/검사/포장/조립) | +| `api/app/Models/Production/WorkOrder.php` | `process_type` (screen/slat/bending), `sales_order_id` (FK) | + +### 8.3 프론트엔드 레이어 +| 파일 | 역할 | +|------|------| +| `react/src/components/quotes/types.ts` | Quote 타입 정의 | +| `react/src/components/quotes/QuotationSelectDialog.tsx` | 견적 선택 UI | +| `react/src/types/process.ts` | Process 타입 정의 | +| `react/src/components/production/WorkOrders/types.ts` | WorkOrder 타입 정의 | +| `react/src/components/orders/actions.ts` | Order API 호출 + 생산지시 생성 + 견적변환 | +| `react/src/components/process-management/actions.ts` | Process API 호출 | +| `react/src/components/production/WorkOrders/actions.ts` | WorkOrder API 호출 | + +--- + +## 9. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-01-09 | 문서 생성 | MES 통합 흐름 분석 완료 | - | - | +| 2025-01-09 | 견적 분석 추가 | Quote → Order 연동 분석 (섹션 3.0) | - | - | +| 2025-01-09 | 결정 반영 | Option C 선택, 리네이밍 진행, FK 미추가 결정 | - | ✅ | +| 2025-01-09 | **재결정** | 공정 관리 페이지 확인 후 **Option B (FK 추가)로 변경** | - | ✅ | + +### 9.1 재결정 상세 + +**재결정 배경**: +- 공정 관리 페이지(`/master-data/process-management`) 실제 확인 +- `screen`, `slat`, `bending` 값이 공정명(Process Name)임을 확인 +- P-001: 슬랫, P-002: 스크린 등록 확인 + +**이전 결정 → 최종 결정**: +| 항목 | 이전 | 최종 | +|------|------|------| +| 설계 방향 | Option C (하이브리드) | **Option B (FK 추가)** | +| 필드 처리 | 리네이밍만 | **FK로 변경** | +| FK 추가 | 불필요 | **필요** | +| 도메인 관계 | 독립 | **연결** | + +--- + +*이 문서는 /plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/mng-item-formula-integration-plan.md b/plans/archive/mng-item-formula-integration-plan.md new file mode 100644 index 0000000..54261a4 --- /dev/null +++ b/plans/archive/mng-item-formula-integration-plan.md @@ -0,0 +1,837 @@ +# MNG 품목관리 - 견적수식 엔진(FormulaEvaluatorService) 연동 계획 + +> **작성일**: 2026-02-19 +> **목적**: 가변사이즈 완제품(FG) 선택 시 오픈사이즈(W,H) 입력 → FormulaEvaluatorService로 동적 자재 산출 → 중앙 패널에 트리 표시 +> **기준 문서**: docs/plans/mng-item-management-plan.md, api/app/Services/Quote/FormulaEvaluatorService.php +> **선행 작업**: 3-Panel 품목관리 페이지 구현 완료 (Phase 1~2 of mng-item-management-plan.md) +> **상태**: 🔄 진행중 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 2.5: 로딩/에러 상태 처리 (전체 구현 완료) | +| **다음 작업** | 검증 (브라우저 테스트) | +| **진행률** | 8/8 (100%) | +| **마지막 업데이트** | 2026-02-19 | + +--- + +## 1. 개요 + +### 1.1 배경 + +MNG 품목관리 페이지(`mng.sam.kr/item-management`)에서 완제품(FG) `FG-KQTS01-벽면형-SUS`를 선택하면 `items.bom` JSON에 등록된 정적 BOM(PT 2개: 가이드레일, 하단마감재)만 표시된다. +그러나 견적관리(`dev.sam.kr/sales/quote-management/46`)에서는 `FormulaEvaluatorService`가 W=3000, H=3000 입력으로 17종 51개의 자재를 동적 산출한다. + +**핵심 문제**: items.bom(정적)과 FormulaEvaluatorService(동적) 두 시스템이 분리되어 있어, 품목관리 페이지에서 실제 필요 자재를 볼 수 없다. + +**해결**: 가변사이즈 품목(`item_details.is_variable_size = true`) 선택 시 오픈사이즈(W, H) 입력 UI를 제공하고, API의 기존 엔드포인트(`POST /api/v1/quotes/calculate/bom`)를 MNG에서 HTTP로 호출하여 산출 결과를 중앙 패널에 표시한다. + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - MNG에서 마이그레이션 파일 생성 금지 (API에서만) │ +│ - MNG ↔ API 통신은 HTTP API 호출 (코드 공유/직접 서비스 호출 X) │ +│ - 기존 API 엔드포인트 재사용 (POST /api/v1/quotes/calculate/bom)│ +│ - Docker nginx 내부 라우팅 + SSL 우회 패턴 사용 │ +│ - Blade + HTMX + Tailwind + Vanilla JS (Alpine.js 미사용) │ +│ - 정적 BOM과 수식 산출 결과를 탭으로 전환 가능하게 │ +│ - Controller에서 직접 DB 쿼리 금지 (Service-First) │ +│ - Controller에서 직접 validate() 금지 (FormRequest 필수) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 서비스 생성, 컨트롤러 메서드 추가, Blade 수정, JS 추가 | 불필요 | +| ⚠️ 컨펌 필요 | API 라우트 추가, 기존 Blade 구조 변경 | **필수** | +| 🔴 금지 | mng에서 마이그레이션 생성, API 소스 수정 | 별도 협의 | + +### 1.4 MNG 절대 금지 규칙 + +``` +❌ mng/database/migrations/ 에 파일 생성 금지 +❌ docker exec sam-mng-1 php artisan migrate 실행 금지 +❌ php artisan db:seed --class=*MenuSeeder 실행 금지 +❌ Controller에서 직접 DB 쿼리 금지 (Service-First) +❌ Controller에서 직접 validate() 금지 (FormRequest 필수) +❌ api/ 프로젝트 소스 코드 수정 금지 +``` + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: MNG 백엔드 (HTTP API 호출 서비스) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | FormulaApiService 생성 (MNG→API HTTP 호출 래퍼) | ✅ | 신규 파일 | +| 1.2 | ItemManagementApiController에 calculateFormula 메서드 추가 | ✅ | 기존 파일 수정 | +| 1.3 | API 라우트 추가 (POST /api/admin/items/{id}/calculate-formula) | ✅ | 기존 파일 수정 | + +### 2.2 Phase 2: MNG 프론트엔드 (UI 연동) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | 중앙 패널 헤더에 탭 UI 추가 (정적 BOM / 수식 산출) | ✅ | index.blade.php 수정 | +| 2.2 | 오픈사이즈 입력 폼 (W, H, 수량) + 산출 버튼 | ✅ | index.blade.php 수정 | +| 2.3 | 수식 산출 결과 트리 렌더링 (카테고리 그룹별) | ✅ | JS 추가 | +| 2.4 | 가변사이즈 품목 감지 → 자동 탭 전환 | ✅ | item-detail.blade.php + JS 수정 | +| 2.5 | 로딩/에러 상태 처리 | ✅ | JS 추가 | + +--- + +## 3. 이미 구현된 코드 (선행 작업 - 수정 대상) + +> 새 세션에서 현재 코드 상태를 파악할 수 있도록 이미 존재하는 파일 전체 목록과 핵심 구조를 기록. + +### 3.1 파일 구조 (이미 존재) + +``` +mng/ +├── app/ +│ ├── Http/Controllers/ +│ │ ├── ItemManagementController.php # Web (HX-Redirect 패턴) +│ │ └── Api/Admin/ +│ │ └── ItemManagementApiController.php # API (index, bomTree, detail) +│ ├── Models/ +│ │ ├── Items/ +│ │ │ ├── Item.php # BelongsToTenant, 관계, 스코프, 상수 +│ │ │ └── ItemDetail.php # 1:1 확장 (is_variable_size 필드 포함) +│ │ └── Commons/ +│ │ └── File.php # 파일 모델 +│ ├── Services/ +│ │ └── ItemManagementService.php # getItemList, getBomTree, getItemDetail +│ └── Traits/ +│ └── BelongsToTenant.php # 테넌트 격리 Trait +├── resources/views/item-management/ +│ ├── index.blade.php # 3-Panel 메인 (★ 수정 대상) +│ └── partials/ +│ ├── item-list.blade.php # 좌측 패널 (변경 없음) +│ ├── bom-tree.blade.php # 중앙 패널 초기 상태 (변경 없음) +│ └── item-detail.blade.php # 우측 패널 (★ 수정 대상) +├── routes/ +│ ├── web.php # Route: GET /item-management (변경 없음) +│ └── api.php # Route: items group (★ 수정 대상 - 라우트 추가) +└── config/ + └── api-explorer.php # FLOW_TESTER_API_KEY 설정 참조 +``` + +### 3.2 현재 ItemManagementApiController 전체 (수정 대상) + +```php +service->getItemList([ + 'search' => $request->input('search'), + 'item_type' => $request->input('item_type'), + 'per_page' => $request->input('per_page', 50), + ]); + return view('item-management.partials.item-list', compact('items')); + } + + public function bomTree(int $id, Request $request): JsonResponse + { + $maxDepth = $request->input('max_depth', 10); + $tree = $this->service->getBomTree($id, $maxDepth); + return response()->json($tree); + } + + public function detail(int $id): View + { + $data = $this->service->getItemDetail($id); + return view('item-management.partials.item-detail', [ + 'item' => $data['item'], + 'bomChildren' => $data['bom_children'], + ]); + } +} +``` + +### 3.3 현재 API 라우트 (items 그룹, mng/routes/api.php:866~) + +```php +Route::middleware(['web', 'auth', 'hq.member'])->prefix('admin/items')->name('api.admin.items.')->group(function () { + Route::get('/search', [ItemApiController::class, 'search'])->name('search'); + + // 품목관리 페이지 API + Route::get('/', [ItemManagementApiController::class, 'index'])->name('index'); + Route::get('/{id}/bom-tree', [ItemManagementApiController::class, 'bomTree'])->name('bom-tree'); + Route::get('/{id}/detail', [ItemManagementApiController::class, 'detail'])->name('detail'); + // ★ 여기에 calculate-formula 라우트 추가 예정 +}); +``` + +### 3.4 현재 index.blade.php 중앙 패널 (수정 대상 부분) + +```html + +

    +``` + +### 3.5 현재 JS 구조 (index.blade.php @push('scripts')) + +핵심 함수: +- `loadItemList()` - 좌측 품목 리스트 HTMX 로드 +- `selectItem(itemId, updateTree)` - 품목 선택 (좌측 하이라이트 + 중앙 트리 fetch + 우측 상세 HTMX) +- `selectTreeNode(itemId)` - 중앙 트리 노드 클릭 (우측만 갱신, 트리 유지) +- `renderBomTree(node, container)` - BOM 트리 재귀 렌더링 +- `getTypeBadgeClass(type)` - 유형별 뱃지 CSS 클래스 + +### 3.6 테넌트 필터링 패턴 (중요) + +MNG의 HQ 관리자는 헤더에서 테넌트를 선택하며, `session('selected_tenant_id')`에 저장된다. +그러나 `BelongsToTenant`의 `TenantScope`는 `request->attributes`, `X-TENANT-ID 헤더`, `auth user`에서 tenant_id를 읽으므로 **세션 값과 불일치**할 수 있다. + +**따라서 Service에서는 `Item::withoutGlobalScopes()->where('tenant_id', session('selected_tenant_id'))` 패턴을 사용한다.** + +```php +// ✅ 올바른 패턴 (현재 ItemManagementService에서 사용 중) +Item::withoutGlobalScopes() + ->where('tenant_id', session('selected_tenant_id')) + ->findOrFail($id); + +// ❌ 잘못된 패턴 (HQ 관리자 세션과 불일치) +Item::findOrFail($id); // TenantScope가 auth user의 tenant_id 사용 +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 1: MNG 백엔드 + +#### 1.1 FormulaApiService 생성 + +**파일 경로**: `mng/app/Services/FormulaApiService.php` (신규 생성) + +**역할**: MNG에서 API 프로젝트의 `POST /api/v1/quotes/calculate/bom` 엔드포인트를 HTTP로 호출하는 래퍼 + +**호출 대상 API 엔드포인트 상세**: + +``` +POST /api/v1/quotes/calculate/bom +라우트 정의: api/routes/api/v1/sales.php:64 +미들웨어: 글로벌(ApiKeyMiddleware, CorsMiddleware, ApiRateLimiter) +FormRequest: QuoteBomCalculateRequest (authorize = true, 제한 없음) +``` + +**API 인증 요구사항** (확인 완료): + +| 헤더 | 필수 | 설명 | +|------|:----:|------| +| `X-API-KEY` | ✅ 필수 | `api_keys` 테이블에 `is_active=true`로 등록된 키 | +| `Authorization: Bearer {token}` | ❌ 선택 | Sanctum 토큰, 있으면 tenant_id 자동 설정 | +| `X-TENANT-ID` | ❌ 선택 | 테넌트 식별 (Bearer 없을 때 대안) | + +**API Key 취득 방법**: `env('FLOW_TESTER_API_KEY')` (mng/.env에 설정됨, `config/api-explorer.php:26`에서 참조) + +**요청 페이로드**: +```json +{ + "finished_goods_code": "FG-KQTS01", + "variables": { + "W0": 3000, + "H0": 3000, + "QTY": 1 + }, + "tenant_id": 287 +} +``` + +**응답 구조** (FormulaEvaluatorService::calculateBomWithDebug 반환값): +```json +{ + "success": true, + "finished_goods": { "code": "FG-KQTS01", "name": "벽면형-SUS", "id": 123 }, + "variables": { "W0": 3000, "H0": 3000, "QTY": 1 }, + "items": [ + { + "item_code": "PT-강재-C형강", + "item_name": "C형강 65×32×10t", + "specification": "65×32×10t", + "unit": "mm", + "quantity": 6038, + "unit_price": 1.0, + "total_price": 6038, + "category_group": "steel" + } + ], + "grouped_items": { + "steel": [ ... ], + "part": [ ... ], + "motor": [ ... ] + }, + "subtotals": { "steel": 123456, "part": 78900, "motor": 50000 }, + "grand_total": 252356, + "debug_steps": [ ... ] +} +``` + +**구현 코드**: +```php +withoutVerifying() + ->withHeaders([ + 'Host' => 'api.sam.kr', + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + 'X-API-KEY' => $apiKey, + 'X-TENANT-ID' => (string) $tenantId, + ]) + ->post('https://nginx/api/v1/quotes/calculate/bom', [ + 'finished_goods_code' => $finishedGoodsCode, + 'variables' => $variables, + 'tenant_id' => $tenantId, + ]); + + if ($response->successful()) { + $json = $response->json(); + // ApiResponse::handle()는 {success, message, data} 구조로 래핑 + return $json['data'] ?? $json; + } + + Log::warning('FormulaApiService: API 호출 실패', [ + 'status' => $response->status(), + 'body' => $response->body(), + 'code' => $finishedGoodsCode, + ]); + + return [ + 'success' => false, + 'error' => 'API 응답 오류: HTTP ' . $response->status(), + ]; + } catch (\Exception $e) { + Log::error('FormulaApiService: 예외 발생', [ + 'message' => $e->getMessage(), + 'code' => $finishedGoodsCode, + ]); + + return [ + 'success' => false, + 'error' => '수식 계산 서버 연결 실패: ' . $e->getMessage(), + ]; + } + } +} +``` + +**트러블슈팅 가이드**: +- `401 Unauthorized` → API Key 확인: `docker exec sam-mng-1 php artisan tinker --execute="echo env('FLOW_TESTER_API_KEY');"` +- `Connection refused` → nginx 컨테이너 확인: `docker ps | grep nginx` +- `SSL certificate problem` → `withoutVerifying()` 누락 확인 +- `422 Validation` → finished_goods_code가 items 테이블에 존재하는지 확인 + +#### 1.2 ItemManagementApiController::calculateFormula 추가 + +**파일**: `mng/app/Http/Controllers/Api/Admin/ItemManagementApiController.php` + +**변경**: 기존 컨트롤러에 메서드 1개 추가 + use 문 추가 + +```php +// 파일 상단 use 추가 +use App\Services\FormulaApiService; + +// 기존 메서드 아래에 추가 +/** + * 수식 기반 BOM 산출 (API 서버의 FormulaEvaluatorService HTTP 호출) + */ +public function calculateFormula(Request $request, int $id): JsonResponse +{ + $item = \App\Models\Items\Item::withoutGlobalScopes() + ->where('tenant_id', session('selected_tenant_id')) + ->findOrFail($id); + + $width = (int) $request->input('width', 1000); + $height = (int) $request->input('height', 1000); + $qty = (int) $request->input('qty', 1); + + $variables = [ + 'W0' => $width, + 'H0' => $height, + 'QTY' => $qty, + ]; + + $formulaService = new FormulaApiService(); + $result = $formulaService->calculateBom( + $item->code, + $variables, + (int) session('selected_tenant_id') + ); + + return response()->json($result); +} +``` + +#### 1.3 API 라우트 추가 + +**파일**: `mng/routes/api.php` (라인 866~ 기존 items 그룹 내) + +**추가 위치**: 기존 detail 라우트 아래 + +```php +// 기존 라우트 아래에 추가 +Route::post('/{id}/calculate-formula', [ItemManagementApiController::class, 'calculateFormula'])->name('calculate-formula'); +``` + +--- + +### 4.2 Phase 2: MNG 프론트엔드 + +#### 2.1 중앙 패널 탭 UI + +**수정 파일**: `mng/resources/views/item-management/index.blade.php` + +**변경 대상 (현재 HTML)**: +```html +
    +

    BOM 구성 (재귀 트리)

    +
    +
    +``` + +**변경 후**: +```html +
    +
    + + +
    +
    + + + + + +
    +

    좌측에서 품목을 선택하세요.

    +
    + + + +``` + +#### 2.2 item-detail.blade.php에 메타 데이터 추가 + +**수정 파일**: `mng/resources/views/item-management/partials/item-detail.blade.php` + +**파일 맨 위에 추가** (기존 `
    ` 앞): +```html + + +``` + +#### 2.3 JS 추가 (index.blade.php @push('scripts')) + +**기존 IIFE 내부에 추가할 변수와 함수**: + +```javascript +// ── 추가 변수 ── +let currentBomTab = 'static'; // 'static' | 'formula' +let currentItemId = null; +let currentItemCode = null; + +// ── 탭 전환 ── +window.switchBomTab = function(tab) { + currentBomTab = tab; + + // 탭 버튼 스타일 + document.querySelectorAll('.bom-tab').forEach(btn => { + btn.classList.remove('bg-blue-100', 'text-blue-800'); + btn.classList.add('bg-gray-100', 'text-gray-600'); + }); + const activeBtn = document.getElementById(tab === 'static' ? 'tab-static-bom' : 'tab-formula-bom'); + if (activeBtn) { + activeBtn.classList.remove('bg-gray-100', 'text-gray-600'); + activeBtn.classList.add('bg-blue-100', 'text-blue-800'); + } + + // 콘텐츠 영역 전환 + document.getElementById('bom-tree-container').style.display = (tab === 'static') ? '' : 'none'; + document.getElementById('formula-input-panel').style.display = (tab === 'formula') ? '' : 'none'; + document.getElementById('formula-result-container').style.display = (tab === 'formula') ? '' : 'none'; +}; + +// ── 가변사이즈 탭 표시/숨김 ── +function showFormulaTab() { + document.getElementById('tab-formula-bom').style.display = ''; + switchBomTab('formula'); // 자동으로 수식 산출 탭으로 전환 +} + +function hideFormulaTab() { + document.getElementById('tab-formula-bom').style.display = 'none'; + document.getElementById('formula-input-panel').style.display = 'none'; + document.getElementById('formula-result-container').style.display = 'none'; + switchBomTab('static'); +} + +// ── 상세 로드 완료 후 가변사이즈 감지 ── +document.body.addEventListener('htmx:afterSwap', function(event) { + if (event.detail.target.id === 'item-detail') { + const meta = document.getElementById('item-meta-data'); + if (meta) { + currentItemId = meta.dataset.itemId; + currentItemCode = meta.dataset.itemCode; + if (meta.dataset.isVariableSize === 'true') { + showFormulaTab(); + } else { + hideFormulaTab(); + } + } + } +}); + +// ── 수식 산출 API 호출 ── +window.calculateFormula = function() { + if (!currentItemId) return; + + const width = parseInt(document.getElementById('input-width').value) || 1000; + const height = parseInt(document.getElementById('input-height').value) || 1000; + const qty = parseInt(document.getElementById('input-qty').value) || 1; + + // 입력값 범위 검증 + if (width < 100 || width > 10000 || height < 100 || height > 10000) { + alert('폭과 높이는 100~10000 범위로 입력하세요.'); + return; + } + + const container = document.getElementById('formula-result-container'); + container.innerHTML = '
    '; + + fetch(`/api/admin/items/${currentItemId}/calculate-formula`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': csrfToken, + }, + body: JSON.stringify({ width, height, qty }), + }) + .then(res => res.json()) + .then(data => { + if (data.success === false) { + container.innerHTML = ` +
    +

    ${data.error || '산출 실패'}

    + +
    `; + return; + } + renderFormulaTree(data, container); + }) + .catch(err => { + container.innerHTML = ` +
    +

    서버 연결 실패

    + +
    `; + }); +}; + +// ── 수식 산출 결과 트리 렌더링 ── +function renderFormulaTree(data, container) { + container.innerHTML = ''; + + // 카테고리 그룹 한글 매핑 + const groupLabels = { steel: '강재', part: '부품', motor: '모터/컨트롤러' }; + const groupIcons = { steel: '🏗️', part: '🔧', motor: '⚡' }; + const groupedItems = data.grouped_items || {}; + + // 합계 영역 + if (data.grand_total) { + const totalDiv = document.createElement('div'); + totalDiv.className = 'mb-4 p-3 bg-blue-50 rounded-lg flex justify-between items-center'; + totalDiv.innerHTML = ` + + ${data.finished_goods?.name || ''} (${data.finished_goods?.code || ''}) + W:${data.variables?.W0} H:${data.variables?.H0} + + 합계: ${Number(data.grand_total).toLocaleString()}원 + `; + container.appendChild(totalDiv); + } + + // 카테고리 그룹별 렌더링 + Object.entries(groupedItems).forEach(([group, items]) => { + if (!items || items.length === 0) return; + + const groupDiv = document.createElement('div'); + groupDiv.className = 'mb-3'; + + const subtotal = data.subtotals?.[group] || 0; + + // 그룹 헤더 + const header = document.createElement('div'); + header.className = 'flex items-center gap-2 py-2 px-3 bg-gray-50 rounded-t-lg cursor-pointer'; + header.innerHTML = ` + + ${groupIcons[group] || '📦'} + ${groupLabels[group] || group} + (${items.length}건) + 소계: ${Number(subtotal).toLocaleString()}원 + `; + + const listDiv = document.createElement('div'); + listDiv.className = 'border border-gray-100 rounded-b-lg divide-y divide-gray-50'; + + // 그룹 접기/펼치기 + header.onclick = function() { + const toggle = header.querySelector('.text-gray-400'); + if (listDiv.style.display === 'none') { + listDiv.style.display = ''; + toggle.textContent = '▼'; + } else { + listDiv.style.display = 'none'; + toggle.textContent = '▶'; + } + }; + + // 아이템 목록 + items.forEach(item => { + const row = document.createElement('div'); + row.className = 'flex items-center gap-2 py-1.5 px-3 hover:bg-gray-50 cursor-pointer text-sm'; + row.innerHTML = ` + PT + ${item.item_code || ''} + ${item.item_name || ''} + ${item.quantity || 0} ${item.unit || ''} + ${Number(item.total_price || 0).toLocaleString()}원 + `; + // 아이템 클릭 시 items 테이블에서 해당 코드로 검색하여 상세 표시 + row.onclick = function() { + // item_code로 좌측 검색 → 해당 품목 상세 로드 + const searchInput = document.getElementById('item-search'); + searchInput.value = item.item_code; + loadItemList(); + }; + listDiv.appendChild(row); + }); + + groupDiv.appendChild(header); + groupDiv.appendChild(listDiv); + container.appendChild(groupDiv); + }); + + if (Object.keys(groupedItems).length === 0) { + container.innerHTML = '

    산출된 자재가 없습니다.

    '; + } +} +``` + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | ~~API 인증 방식~~ | X-API-KEY 필수 (FLOW_TESTER_API_KEY) | MNG→API 통신 | ✅ 확인 완료 | +| 2 | API 라우트 추가 | POST /api/admin/items/{id}/calculate-formula | mng/routes/api.php | ✅ 즉시 가능 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-19 | - | 계획 문서 초안 작성 | - | - | +| 2026-02-19 | - | 자기완결성 보강 (기존 코드 현황, API 인증 분석, 트러블슈팅) | - | - | +| 2026-02-19 | 1.1~1.3 | Phase 1 백엔드 구현 완료 (FormulaApiService, Controller, Route) | FormulaApiService.php, ItemManagementApiController.php, api.php | ✅ | +| 2026-02-19 | 2.1~2.5 | Phase 2 프론트엔드 구현 완료 (탭 UI, 입력 폼, 트리 렌더링, 감지, 에러) | index.blade.php, item-detail.blade.php | ✅ | + +--- + +## 7. 참고 문서 + +- **기존 품목관리 계획**: `docs/plans/mng-item-management-plan.md` +- **FormulaEvaluatorService**: `api/app/Services/Quote/FormulaEvaluatorService.php` + - 메서드: `calculateBomWithDebug(string $finishedGoodsCode, array $inputVariables, ?int $tenantId): array` + - tenant_id=287 자동 감지 → KyungdongFormulaHandler 라우팅 +- **KyungdongFormulaHandler**: `api/app/Services/Quote/Handlers/KyungdongFormulaHandler.php` + - `calculateDynamicItems(array $inputs)` → steel(10종), part(3종), motor/controller 산출 +- **API 라우트**: `api/routes/api/v1/sales.php:64` → `QuoteController::calculateBom` +- **QuoteBomCalculateRequest**: `api/app/Http/Requests/V1/QuoteBomCalculateRequest.php` + - `finished_goods_code` (required|string) + - `variables` (required|array), `variables.W0` (required|numeric), `variables.H0` (required|numeric) + - `tenant_id` (nullable|integer) +- **MNG-API HTTP 패턴**: `mng/app/Services/FlowTester/HttpClient.php` +- **API Key 설정**: `mng/config/api-explorer.php:26` → `env('FLOW_TESTER_API_KEY')` +- **현재 품목관리 뷰**: `mng/resources/views/item-management/index.blade.php` +- **MNG 프로젝트 규칙**: `mng/CLAUDE.md` + +--- + +## 8. 세션 및 메모리 관리 정책 + +### 8.1 세션 시작 시 (Load Strategy) +``` +1. 이 문서 읽기 (docs/plans/mng-item-formula-integration-plan.md) +2. 📍 현재 진행 상태 확인 → 다음 작업 파악 +3. 섹션 3 "이미 구현된 코드" 확인 → 수정 대상 파일 파악 +4. 필요시 Serena 메모리 로드: + read_memory("item-formula-state") + read_memory("item-formula-snapshot") + read_memory("item-formula-active-symbols") +``` + +### 8.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | Snapshot | `write_memory("item-formula-snapshot", "코드변경+논의요약")` | +| **20% 이하** | Context Purge | `write_memory("item-formula-active-symbols", "주요 수정 파일/함수")` | +| **10% 이하** | Stop & Save | 최종 상태 저장 후 세션 교체 권고 | + +--- + +## 9. 검증 결과 + +### 9.1 테스트 케이스 + +| # | 테스트 | 입력 | 예상 결과 | 실제 결과 | 상태 | +|---|--------|------|----------|----------|------| +| 1 | FG 가변사이즈 품목 선택 | FG-KQTS01 클릭 | 수식 산출 탭 자동 표시, 입력 폼 노출 | | ⏳ | +| 2 | 오픈사이즈 입력 후 산출 | W:3000, H:3000, QTY:1 | 17종 자재 트리 (steel/part/motor 그룹별), 소계/합계 표시 | | ⏳ | +| 3 | 비가변사이즈 품목 선택 | PT 품목 클릭 | 수식 산출 탭 숨김, 정적 BOM만 표시 | | ⏳ | +| 4 | 정적 BOM ↔ 수식 산출 탭 전환 | 탭 클릭 | 각 탭 콘텐츠 전환, 입력 폼 표시/숨김 | | ⏳ | +| 5 | 산출 결과에서 품목 클릭 | 트리 노드 클릭 | 좌측 검색에 품목코드 입력 → 품목 리스트 필터링 | | ⏳ | +| 6 | API Key 미설정 | FLOW_TESTER_API_KEY 없음 | 에러 메시지 "API 응답 오류: HTTP 401" + 재시도 버튼 | | ⏳ | +| 7 | 입력값 범위 초과 | W:0, H:-1 | alert 표시, API 호출 안 함 | | ⏳ | +| 8 | 서버 연결 실패 | nginx 중지 상태 | 에러 메시지 "서버 연결 실패" + 재시도 버튼 | | ⏳ | + +### 9.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| FG 가변사이즈 품목에서 수식 산출 가능 | ⏳ | | +| 산출 결과가 견적관리와 동일한 17종 자재 표시 | ⏳ | | +| 정적 BOM과 수식 산출 탭 전환 작동 | ⏳ | | +| 비가변사이즈 품목은 기존 정적 BOM만 표시 | ⏳ | | +| 에러 처리 및 로딩 상태 표시 | ⏳ | | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 가변사이즈 FG 품목의 동적 자재 산출 표시 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 9.2 성공 기준 5개 항목 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1 백엔드 3건, Phase 2 프론트 5건 | +| 4 | 의존성이 명시되어 있는가? | ✅ | API 엔드포인트 인증 분석 완료, Docker 라우팅 패턴 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 모든 파일 경로 검증 완료 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 전체 구현 코드 포함 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 9.1 테스트 케이스 8개 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 수치/코드로 기술 | +| 9 | 기존 코드 현황이 명시되어 있는가? | ✅ | 섹션 3에 전체 파일 구조 + 핵심 코드 인라인 | +| 10 | API 인증 방식이 확정되었는가? | ✅ | X-API-KEY 필수 (FLOW_TESTER_API_KEY) | +| 11 | 트러블슈팅 가이드가 있는가? | ✅ | 4.1 FormulaApiService 트러블슈팅 섹션 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 📍 현재 진행 상태 + 4.1 Phase 1 | +| Q3. 어떤 파일을 수정/생성해야 하는가? | ✅ | 3.1 파일 구조 + 2. 대상 범위 | +| Q4. 현재 코드 상태는 어떤가? | ✅ | 3.2~3.6 기존 코드 현황 | +| Q5. API 인증은 어떻게 하는가? | ✅ | 4.1 FormulaApiService (인증 테이블) | +| Q6. 테넌트 필터링은 어떻게 동작하는가? | ✅ | 3.6 테넌트 필터링 패턴 | +| Q7. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | +| Q8. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 + 4.1 트러블슈팅 | + +**결과**: 8/8 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다. 자기완결성 보강: 2026-02-19* diff --git a/plans/archive/mng-item-management-plan.md b/plans/archive/mng-item-management-plan.md new file mode 100644 index 0000000..172f216 --- /dev/null +++ b/plans/archive/mng-item-management-plan.md @@ -0,0 +1,1447 @@ +# MNG 품목관리 페이지 계획 + +> **작성일**: 2026-02-19 +> **목적**: MNG 관리자 패널에 3-Panel 품목관리 페이지 추가 (좌측 리스트 + 중앙 BOM 트리 + 우측 상세) +> **기준 문서**: docs/rules/item-policy.md, docs/specs/item-master-integration.md +> **상태**: ✅ 기본 구현 완료 (미커밋) → Phase 3 수식 연동은 별도 계획 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 1~2 전체 구현 완료 (미커밋 상태) | +| **다음 작업** | 수식 엔진 연동 → `docs/plans/mng-item-formula-integration-plan.md` 참조 | +| **진행률** | 12/12 (100%) - 기본 3-Panel 구현 완료 | +| **마지막 업데이트** | 2026-02-19 | +| **후속 작업** | FormulaEvaluatorService 연동 (별도 계획 문서) | + +--- + +## 1. 개요 + +### 1.1 배경 + +MNG 관리자 패널에 품목(Items)을 관리하고 BOM 연결관계를 시각적으로 파악할 수 있는 페이지가 필요하다. +현재 items 테이블은 products + materials 통합 구조로, `items.bom` JSON 필드에 BOM 구성을 저장한다. + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - MNG에서 마이그레이션 파일 생성 금지 (API에서만) │ +│ - Service-First (비즈니스 로직은 Service 클래스에만) │ +│ - FormRequest 필수 (Controller 검증 금지) │ +│ - BelongsToTenant (테넌트 격리) │ +│ - Blade + HTMX + Tailwind (Alpine.js 미사용) │ +│ - 세션 기반 테넌트 필터링: session('selected_tenant_id') │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 모델/서비스/뷰/컨트롤러/라우트 생성 | 불필요 | +| ⚠️ 컨펌 필요 | 기존 라우트 수정, 사이드바 메뉴 추가 | **필수** | +| 🔴 금지 | mng에서 마이그레이션 생성, 테이블 구조 변경 | 별도 협의 | + +### 1.4 MNG 절대 금지 규칙 (인라인) + +``` +❌ mng/database/migrations/ 에 파일 생성 금지 +❌ docker exec sam-mng-1 php artisan migrate 실행 금지 +❌ php artisan db:seed --class=*MenuSeeder 실행 금지 +❌ 메뉴 시더 파일 생성/실행 금지 (부서별 권한 초기화됨) +❌ Controller에서 직접 DB 쿼리 금지 (Service-First) +❌ Controller에서 직접 validate() 금지 (FormRequest 필수) +``` + +--- + +## 2. 기능 설계 + +### 2.1 3-Panel 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Header (64px) - 테넌트 선택 (session 기반 필터링) │ +├──────────┬─────────────────────────────┬────────────────────────────┤ +│ 좌측 │ 중앙 │ 우측 │ +│ (280px) │ (flex-1) │ (380px) │ +│ │ │ │ +│ [검색] │ │ ┌──────────────────────┐ │ +│ ________│ │ │ 기본정보 │ │ +│ │ BOM 재귀 트리 │ │ 코드: P-001 │ │ +│ 품목 1 ◀│ ┌ 완제품A │ │ 이름: 스크린 제품 │ │ +│ 품목 2 │ ├─ 부품B │ │ 유형: FG │ │ +│ 품목 3 │ │ ├─ 원자재C │ │ 단위: EA │ │ +│ 품목 4 │ │ └─ 부자재D │ │ 카테고리: ... │ │ +│ 품목 5 │ ├─ 부품E │ ├──────────────────────┤ │ +│ ... │ │ ├─ 원자재F │ │ BOM 구성 (1depth) │ │ +│ │ │ └─ 소모품G │ │ - 부품B (2ea) │ │ +│ │ └─ 원자재H │ │ - 부품E (1ea) │ │ +│ │ │ │ - 원자재H (0.5kg) │ │ +│ │ ← 전체 재귀 트리 → │ ├──────────────────────┤ │ +│ │ (좌측 선택 품목 기준) │ │ 절곡 정보 │ │ +│ │ │ │ (bending_details) │ │ +│ │ │ ├──────────────────────┤ │ +│ │ │ │ 이미지/파일 │ │ +│ │ │ │ 📎 도면.pdf │ │ +│ │ │ │ 📎 인증서.pdf │ │ +│ │ │ └──────────────────────┘ │ +├──────────┴─────────────────────────────┴────────────────────────────┤ +│ ← 클릭 시 어디서든 → 우측 상세 갱신 │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 패널별 상세 동작 + +#### 좌측 패널 (품목 리스트) +- **상단 검색**: `` debounce 300ms, 코드+이름 동시 검색 +- **리스트**: 스크롤 가능, 선택된 항목 하이라이트 +- **표시 정보**: 품목코드, 품목명, 유형(FG/PT/SM/RM/CS) 뱃지 +- **테넌트 필터**: 헤더에서 선택된 테넌트 자동 적용 (BelongsToTenant) +- **클릭 시**: 중앙 트리 갱신 + 우측 상세 갱신 + +#### 중앙 패널 (BOM 재귀 트리) +- **데이터 소스**: `items.bom` JSON → child_item_id 재귀 탐색 +- **트리 깊이**: 전체 재귀 (BOM → BOM → BOM ...) +- **노드 표시**: 품목코드 + 품목명 + 수량 + 유형 뱃지 +- **펼침/접힘**: 노드별 토글 가능 +- **클릭 시**: 해당 품목으로 우측 상세 갱신 (좌측 선택은 변경 안 함) + +#### 우측 패널 (선택 품목 상세) +- **기본정보**: 코드, 이름, 유형, 단위, 카테고리, 활성 여부, options +- **BOM 구성 (1depth)**: 직접 연결된 자식 품목만 (재귀 X) +- **절곡 정보**: item_details.bending_details JSON (해당 시) +- **파일/이미지**: 연결된 files 목록 +- **scope**: 선택된 품목에 직접 연결된 정보만 (1depth) + +### 2.3 데이터 흐름 + +``` +[좌측 검색/선택] + │ + ├──→ HTMX GET /api/admin/items?search=xxx + │ → 좌측 리스트 갱신 + │ + ├──→ fetch GET /api/admin/items/{id}/bom-tree + │ → 중앙 트리 갱신 (재귀 JSON 반환 → Vanilla JS 렌더링) + │ + └──→ HTMX GET /api/admin/items/{id}/detail + → 우측 상세 갱신 + +[중앙 트리 노드 클릭] + │ + └──→ HTMX GET /api/admin/items/{id}/detail + → 우측 상세만 갱신 (중앙 트리 유지) +``` + +--- + +## 3. 기술 설계 + +### 3.1 DB 스키마 (기존 테이블 활용, 변경 없음) + +```sql +-- items (통합 품목) - 이미 존재하는 테이블 +-- item_type: FG(완제품), PT(부품), SM(부자재), RM(원자재), CS(소모품) +-- item_category: SCREEN, STEEL, BENDING, ALUMINUM 등 +CREATE TABLE items ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + item_type VARCHAR(10) NOT NULL, -- FG/PT/SM/RM/CS + item_category VARCHAR(50) NULL, -- SCREEN/STEEL/BENDING/ALUMINUM 등 + code VARCHAR(50) NOT NULL, + name VARCHAR(200) NOT NULL, + unit VARCHAR(20) NULL, + category_id BIGINT UNSIGNED NULL, -- FK → categories.id + bom JSON NULL, -- [{child_item_id: 5, quantity: 2.5}, ...] + attributes JSON NULL, -- 동적 필드 (migration 등에서 가져온 데이터) + attributes_archive JSON NULL, -- 아카이브 + options JSON NULL, -- {lot_managed, consumption_method, ...} + description TEXT NULL, + is_active TINYINT(1) DEFAULT 1, + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + deleted_at TIMESTAMP NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + INDEX (tenant_id), INDEX (item_type), INDEX (code), INDEX (category_id) +); + +-- item_details (1:1 확장) - 이미 존재하는 테이블 +CREATE TABLE item_details ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + item_id BIGINT UNSIGNED NOT NULL UNIQUE, -- FK → items.id (1:1) + -- Products 전용 + is_sellable TINYINT(1) DEFAULT 0, + is_purchasable TINYINT(1) DEFAULT 0, + is_producible TINYINT(1) DEFAULT 0, + safety_stock DECIMAL(10,2) NULL, + lead_time INT NULL, + is_variable_size TINYINT(1) DEFAULT 0, + product_category VARCHAR(50) NULL, + part_type VARCHAR(50) NULL, + bending_diagram VARCHAR(255) NULL, -- 절곡 도면 파일 경로 + bending_details JSON NULL, -- 절곡 상세 정보 JSON + specification_file VARCHAR(255) NULL, + specification_file_name VARCHAR(255) NULL, + certification_file VARCHAR(255) NULL, + certification_file_name VARCHAR(255) NULL, + certification_number VARCHAR(100) NULL, + certification_start_date DATE NULL, + certification_end_date DATE NULL, + -- Materials 전용 + is_inspection CHAR(1) NULL, -- 'Y'/'N' + item_name VARCHAR(200) NULL, + specification VARCHAR(500) NULL, + search_tag VARCHAR(500) NULL, + remarks TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL +); + +-- files (폴리모픽) - 이미 존재하는 테이블 +-- 품목 파일: document_id = items.id, document_type = '1' (ITEM_GROUP_ID) +CREATE TABLE files ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NULL, + document_id BIGINT UNSIGNED NOT NULL, -- 연결 대상 ID (items.id) + document_type VARCHAR(10) NOT NULL, -- '1' = ITEM_GROUP_ID + original_name VARCHAR(255) NOT NULL, + stored_name VARCHAR(255) NOT NULL, + path VARCHAR(500) NOT NULL, + mime_type VARCHAR(100) NULL, + size BIGINT UNSIGNED NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL +); + +-- categories - 이미 존재하는 테이블 +-- 품목 카테고리 (code_group으로 구분, 계층 구조) +CREATE TABLE categories ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + parent_id BIGINT UNSIGNED NULL, -- 자기 참조 (트리) + code_group VARCHAR(50) NOT NULL, -- 카테고리 그룹 + profile_code VARCHAR(50) NULL, + code VARCHAR(50) NOT NULL, + name VARCHAR(200) NOT NULL, + is_active TINYINT(1) DEFAULT 1, + sort_order INT DEFAULT 0, + description TEXT NULL, + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + deleted_by BIGINT UNSIGNED NULL, + deleted_at TIMESTAMP NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL +); +``` + +### 3.2 BOM 트리 재귀 로직 + +```php +// ItemManagementService::getBomTree(int $itemId, int $maxDepth = 10): array +public function getBomTree(int $itemId, int $maxDepth = 10): array +{ + $item = Item::with('details')->findOrFail($itemId); + return $this->buildBomNode($item, 0, $maxDepth, []); +} + +private function buildBomNode(Item $item, int $depth, int $maxDepth, array $visited): array +{ + // 순환 참조 방지: visited 배열 + maxDepth 이중 안전장치 + if (in_array($item->id, $visited) || $depth >= $maxDepth) { + return $this->formatNode($item, $depth, []); + } + + $visited[] = $item->id; + $children = []; + + $bomData = $item->bom ?? []; + if (!empty($bomData)) { + $childIds = array_column($bomData, 'child_item_id'); + $childItems = Item::whereIn('id', $childIds)->get()->keyBy('id'); + + foreach ($bomData as $bom) { + $childItem = $childItems->get($bom['child_item_id']); + if ($childItem) { + $childNode = $this->buildBomNode($childItem, $depth + 1, $maxDepth, $visited); + $childNode['quantity'] = $bom['quantity'] ?? 1; + $children[] = $childNode; + } + } + } + + return $this->formatNode($item, $depth, $children); +} + +private function formatNode(Item $item, int $depth, array $children): array +{ + return [ + 'id' => $item->id, + 'code' => $item->code, + 'name' => $item->name, + 'item_type' => $item->item_type, + 'unit' => $item->unit, + 'depth' => $depth, + 'has_children' => count($children) > 0, + 'children' => $children, + ]; +} +``` + +### 3.3 API 엔드포인트 설계 + +| Method | Endpoint | 설명 | 반환 | +|--------|----------|------|------| +| GET | `/api/admin/items` | 품목 목록 (검색, 페이지네이션) | HTML partial | +| GET | `/api/admin/items/{id}/bom-tree` | BOM 재귀 트리 | JSON | +| GET | `/api/admin/items/{id}/detail` | 품목 상세 (1depth BOM, 파일, 절곡) | HTML partial | + +#### GET /api/admin/items + +| 파라미터 | 타입 | 설명 | +|---------|------|------| +| search | string | 코드+이름 검색 (LIKE) | +| item_type | string | 유형 필터 (FG,PT,SM,RM,CS 쉼표 구분) | +| per_page | int | 페이지 크기 (default: 50) | +| page | int | 페이지 번호 | + +#### GET /api/admin/items/{id}/bom-tree + +| 파라미터 | 타입 | 설명 | +|---------|------|------| +| max_depth | int | 최대 재귀 깊이 (default: 10) | + +**응답 (JSON)**: +```json +{ + "id": 1, + "code": "SCREEN-001", + "name": "스크린 제품", + "item_type": "FG", + "unit": "EA", + "depth": 0, + "has_children": true, + "children": [ + { + "id": 5, + "code": "SLAT-001", + "name": "슬랫", + "item_type": "PT", + "quantity": 2.5, + "depth": 1, + "has_children": true, + "children": [ + { + "id": 12, + "code": "STEEL-001", + "name": "강판", + "item_type": "RM", + "quantity": 1.0, + "depth": 2, + "has_children": false, + "children": [] + } + ] + } + ] +} +``` + +#### GET /api/admin/items/{id}/detail + +**응답 (HTML partial)**: 기본정보 + BOM 1depth + 절곡정보 + 파일 목록 + +### 3.4 파일 구조 + +``` +mng/ +├── app/ +│ ├── Http/ +│ │ └── Controllers/ +│ │ ├── ItemManagementController.php # Web (Blade 화면) +│ │ └── Api/Admin/ +│ │ └── ItemManagementApiController.php # API (HTMX) +│ ├── Models/ +│ │ ├── Category.php # ⚠️ 이미 존재 (수정 불필요) +│ │ └── Items/ +│ │ ├── Item.php # ⚠️ 이미 존재 → 보완 필요 +│ │ └── ItemDetail.php # 신규 생성 +│ ├── Services/ +│ │ └── ItemManagementService.php # BOM 트리, 검색, 상세 +│ └── Traits/ +│ └── BelongsToTenant.php # ⚠️ 이미 존재 (수정 불필요) +├── resources/ +│ └── views/ +│ └── item-management/ +│ ├── index.blade.php # 메인 (3-Panel) +│ └── partials/ +│ ├── item-list.blade.php # 좌측 리스트 +│ ├── bom-tree.blade.php # 중앙 트리 (JS 렌더링) +│ └── item-detail.blade.php # 우측 상세 +└── routes/ + ├── web.php # + items 라우트 추가 + └── api.php # + items API 라우트 추가 +``` + +### 3.5 트리 렌더링 방식 + +**Vanilla JS + Tailwind (라이브러리 미사용)** - MNG 기존 패턴 유지 + +```javascript +// BOM 트리 JSON → HTML 변환 +function renderBomTree(node, container) { + const li = document.createElement('li'); + li.className = 'ml-4'; + + // 노드 렌더링 + const nodeEl = document.createElement('div'); + nodeEl.className = 'flex items-center gap-2 py-1 px-2 rounded cursor-pointer hover:bg-blue-50'; + nodeEl.onclick = () => selectTreeNode(node.id); + + // 펼침/접힘 토글 + if (node.has_children) { + const toggle = document.createElement('span'); + toggle.className = 'text-gray-400 cursor-pointer'; + toggle.textContent = '▶'; + toggle.onclick = (e) => { e.stopPropagation(); toggleNode(toggle, childList); }; + nodeEl.appendChild(toggle); + } else { + // 빈 공간 (들여쓰기 맞춤) + const spacer = document.createElement('span'); + spacer.className = 'w-4 inline-block'; + nodeEl.appendChild(spacer); + } + + // 유형 뱃지 + 코드 + 이름 + 수량 + nodeEl.innerHTML += ` + ${node.item_type} + ${node.code} + ${node.name} + ${node.quantity ? `(${node.quantity})` : ''} + `; + li.appendChild(nodeEl); + + // 자식 노드 재귀 렌더링 + if (node.children && node.children.length > 0) { + const childList = document.createElement('ul'); + childList.className = 'border-l border-gray-200'; + node.children.forEach(child => renderBomTree(child, childList)); + li.appendChild(childList); + } + + container.appendChild(li); +} + +// 트리 노드 펼침/접힘 +function toggleNode(toggle, childList) { + if (childList.style.display === 'none') { + childList.style.display = ''; + toggle.textContent = '▼'; + } else { + childList.style.display = 'none'; + toggle.textContent = '▶'; + } +} +``` + +--- + +## 4. 대상 범위 + +### Phase 1: 백엔드 (모델 + 서비스 + API) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | Item 모델 보완 (mng/app/Models/Items/Item.php) | ✅ | BelongsToTenant, 관계, 스코프, 상수, 헬퍼 추가 | +| 1.2 | ItemDetail 모델 생성 (mng/app/Models/Items/ItemDetail.php) | ✅ | 1:1 관계, is_variable_size 포함 | +| 1.3 | ItemManagementService 생성 | ✅ | getItemList, getBomTree(재귀), getItemDetail | +| 1.4 | ItemManagementApiController 생성 | ✅ | index(HTML), bomTree(JSON), detail(HTML) | +| 1.5 | API 라우트 등록 (routes/api.php) | ✅ | /api/admin/items/* (3개 라우트) | +| 1.6 | File 모델 생성 (mng/app/Models/Commons/File.php) | ✅ | Item.files() 관계용 | + +### Phase 2: 프론트엔드 (Blade + JS) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | 메인 페이지 (index.blade.php) - 3-Panel 레이아웃 | ✅ | Tailwind flex, 3-Panel | +| 2.2 | 좌측 패널 (item-list.blade.php) + 실시간 검색 | ✅ | HTMX + debounce 300ms + 유형 필터 | +| 2.3 | 중앙 패널 (bom-tree.blade.php) + JS 트리 렌더링 | ✅ | Vanilla JS 재귀 렌더링 | +| 2.4 | 우측 패널 (item-detail.blade.php) | ✅ | 기본정보+BOM 1depth+절곡+파일 | +| 2.5 | ItemManagementController (Web) 생성 | ✅ | HX-Redirect 패턴 | +| 2.6 | Web 라우트 등록 (routes/web.php) | ✅ | GET /item-management | +| 2.7 | 유형별 뱃지 스타일 + 트리 라인 CSS | ✅ | Tailwind inline + JS getTypeBadgeClass | + +### Phase 3: 수식 엔진 연동 (후속 작업) + +> 별도 계획 문서: `docs/plans/mng-item-formula-integration-plan.md` +> +> 가변사이즈 FG 품목 선택 시 오픈사이즈(W,H) 입력 → FormulaEvaluatorService 동적 산출 → 중앙 패널 탭 전환 표시 + +--- + +## 5. 작업 절차 + +### Step 1: 모델 보완/생성 (Phase 1.1, 1.2) +``` +├── mng/app/Models/Items/Item.php 보완 (기존 파일 존재) +│ 현재 상태: SoftDeletes만 있음, BelongsToTenant 없음, 관계 없음 +│ 추가 필요: +│ - use App\Traits\BelongsToTenant 추가 +│ - $fillable에 category_id, bom, attributes, options, description 추가 +│ - $casts에 bom→array, options→array 추가 +│ - 관계: details(), category(), files() +│ - 스코프: type(), active(), search() +│ - 상수: TYPE_FG 등, PRODUCT_TYPES, MATERIAL_TYPES +│ - 헬퍼: isProduct(), isMaterial(), getBomChildIds() +│ +└── mng/app/Models/Items/ItemDetail.php 생성 (신규) + - item() belongsTo 관계 + - $fillable: 전체 필드 (섹션 A.3 참고) + - $casts: bending_details→array, is_sellable→boolean 등 +``` + +### Step 2: 서비스 생성 (Phase 1.3) +``` +├── mng/app/Services/ItemManagementService.php 생성 +│ - getItemList(array $filters): LengthAwarePaginator +│ └ Item::query()->search($search)->active()->orderBy('code')->paginate($perPage) +│ - getBomTree(int $itemId, int $maxDepth = 10): array +│ └ 재귀 buildBomNode() (섹션 3.2 코드) +│ - getItemDetail(int $itemId): array +│ └ Item::with(['details', 'category', 'files'])->findOrFail($id) +│ └ BOM 1depth: items.bom JSON에서 child_item_id 추출 → Item::whereIn() +│ +└── 테넌트 스코프 자동 적용 (BelongsToTenant가 글로벌 스코프 등록) +``` + +### Step 3: API 컨트롤러 + 라우트 (Phase 1.4, 1.5) +``` +├── mng/app/Http/Controllers/Api/Admin/ItemManagementApiController.php +│ - __construct(private readonly ItemManagementService $service) +│ - index(Request $request): View +│ └ HTMX 요청 시 HTML partial 반환 (Blade view render) +│ - bomTree(int $id): JsonResponse +│ └ JSON 반환 (JS에서 트리 렌더링) +│ - detail(int $id): View +│ └ HTML partial 반환 (item-detail.blade.php) +│ +└── routes/api.php에 라우트 추가 (기존 그룹 내) + // 기존 Route::middleware(['web', 'auth', 'hq.member']) + // ->prefix('admin')->name('api.admin.')->group(function () { ... }); + // 내부에 추가: + Route::prefix('items')->name('items.')->group(function () { + Route::get('/', [ItemManagementApiController::class, 'index'])->name('index'); + Route::get('/{id}/bom-tree', [ItemManagementApiController::class, 'bomTree'])->name('bom-tree'); + Route::get('/{id}/detail', [ItemManagementApiController::class, 'detail'])->name('detail'); + }); +``` + +### Step 4: Blade 뷰 생성 (Phase 2.1~2.4) +``` +├── index.blade.php: 3-Panel 메인 레이아웃 +│ @extends('layouts.app'), @section('content'), @push('scripts') +│ HTMX 페이지이므로 HX-Redirect 필요 (JS가 @push('scripts')에 있음) +│ +├── partials/item-list.blade.php: 좌측 품목 리스트 +│ @foreach($items as $item) → 품목코드, 품목명, 유형 뱃지 +│ data-item-id="{{ $item->id }}" onclick="selectItem({{ $item->id }})" +│ +├── partials/bom-tree.blade.php: 중앙 트리 (빈 컨테이너) +│
    품목을 선택하세요
    +│ +└── partials/item-detail.blade.php: 우측 상세정보 + 기본정보 테이블 + BOM 1depth 리스트 + 절곡 정보 + 파일 목록 +``` + +### Step 5: Web 컨트롤러 + 라우트 (Phase 2.5, 2.6) +``` +├── mng/app/Http/Controllers/ItemManagementController.php +│ - __construct(private readonly ItemManagementService $service) +│ - index(Request $request): View|Response +│ └ HX-Request 체크 → HX-Redirect (JS 포함 페이지이므로) +│ └ return view('item-management.index') +│ +└── routes/web.php에 라우트 추가 + // 기존 인증 미들웨어 그룹 내에 추가: + Route::get('/item-management', [ItemManagementController::class, 'index']) + ->name('item-management.index'); +``` + +### Step 6: 스타일 + 트리 인터랙션 (Phase 2.7) +``` +├── 유형별 뱃지 색상 (Tailwind inline) +│ FG: bg-blue-100 text-blue-800 (완제품) +│ PT: bg-green-100 text-green-800 (부품) +│ SM: bg-yellow-100 text-yellow-800 (부자재) +│ RM: bg-orange-100 text-orange-800 (원자재) +│ CS: bg-gray-100 text-gray-800 (소모품) +│ +└── 트리 라인 CSS (border-l + ml-4 indent) +``` + +--- + +## 6. 상세 구현 명세 + +### 6.1 Item 모델 보완 (기존 파일 수정) + +**기존 파일**: `mng/app/Models/Items/Item.php` + +**현재 상태 (보완 전)**: +```php + 'boolean', + 'attributes' => 'array', + ]; +} +``` + +**보완 후 (목표 상태)**: +```php + 'array', + 'attributes' => 'array', + 'attributes_archive' => 'array', + 'options' => 'array', + 'is_active' => 'boolean', + ]; + + // 유형 상수 + const TYPE_FG = 'FG'; // 완제품 + const TYPE_PT = 'PT'; // 부품 + const TYPE_SM = 'SM'; // 부자재 + const TYPE_RM = 'RM'; // 원자재 + const TYPE_CS = 'CS'; // 소모품 + + const PRODUCT_TYPES = ['FG', 'PT']; + const MATERIAL_TYPES = ['SM', 'RM', 'CS']; + + // ── 관계 ── + + public function details() + { + return $this->hasOne(ItemDetail::class, 'item_id'); + } + + public function category() + { + return $this->belongsTo(Category::class, 'category_id'); + } + + /** + * 파일 (document_id/document_type 기반) + * document_id = items.id, document_type = '1' (ITEM_GROUP_ID) + */ + public function files() + { + return $this->hasMany(\App\Models\Commons\File::class, 'document_id') + ->where('document_type', '1'); + } + + // ── 스코프 ── + + public function scopeType($query, string $type) + { + return $query->where('items.item_type', strtoupper($type)); + } + + public function scopeActive($query) + { + return $query->where('is_active', true); + } + + public function scopeSearch($query, ?string $search) + { + if (!$search) return $query; + return $query->where(function ($q) use ($search) { + $q->where('code', 'like', "%{$search}%") + ->orWhere('name', 'like', "%{$search}%"); + }); + } + + // ── 헬퍼 ── + + public function isProduct(): bool + { + return in_array($this->item_type, self::PRODUCT_TYPES); + } + + public function isMaterial(): bool + { + return in_array($this->item_type, self::MATERIAL_TYPES); + } + + public function getBomChildIds(): array + { + return collect($this->bom ?? [])->pluck('child_item_id')->filter()->toArray(); + } +} +``` + +> **주의**: files() 관계에서 `\App\Models\Commons\File::class` 경로를 사용한다. +> 만약 mng에 File 모델이 없다면, 단순 모델로 신규 생성해야 한다. +> 확인 필요: `mng/app/Models/Commons/File.php` 존재 여부. 없으면 생성. + +### 6.2 ItemDetail 모델 (신규 생성) + +```php + 'boolean', + 'is_purchasable' => 'boolean', + 'is_producible' => 'boolean', + 'is_variable_size' => 'boolean', + 'bending_details' => 'array', + 'certification_start_date' => 'date', + 'certification_end_date' => 'date', + ]; + + public function item() + { + return $this->belongsTo(Item::class); + } +} +``` + +### 6.3 좌측 검색 - Debounce + HTMX + +```javascript +// index.blade.php @push('scripts') +let searchTimer = null; +const searchInput = document.getElementById('item-search'); + +searchInput.addEventListener('input', function() { + clearTimeout(searchTimer); + searchTimer = setTimeout(() => { + const search = this.value.trim(); + htmx.ajax('GET', `/api/admin/items?search=${encodeURIComponent(search)}&per_page=50`, { + target: '#item-list', + swap: 'innerHTML', + headers: {'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content} + }); + }, 300); // 300ms debounce +}); +``` + +### 6.4 품목 선택 시 중앙+우측 갱신 + +```javascript +// 품목 선택 함수 (좌측/중앙 공용) +function selectItem(itemId, updateTree = true) { + // 선택 하이라이트 + document.querySelectorAll('.item-row').forEach(el => el.classList.remove('bg-blue-50', 'border-blue-300')); + const selected = document.querySelector(`[data-item-id="${itemId}"]`); + if (selected) selected.classList.add('bg-blue-50', 'border-blue-300'); + + // 중앙 트리 갱신 (좌측에서 클릭 시에만) + if (updateTree) { + fetch(`/api/admin/items/${itemId}/bom-tree`, { + headers: {'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content} + }) + .then(res => res.json()) + .then(tree => { + const container = document.getElementById('bom-tree-container'); + container.innerHTML = ''; + if (tree.has_children) { + const ul = document.createElement('ul'); + renderBomTree(tree, ul); + container.appendChild(ul); + } else { + container.innerHTML = '

    BOM 구성이 없습니다.

    '; + } + }); + } + + // 우측 상세 갱신 (항상) + htmx.ajax('GET', `/api/admin/items/${itemId}/detail`, { + target: '#item-detail', + swap: 'innerHTML', + headers: {'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content} + }); +} + +// 중앙 트리 노드 클릭 (트리는 유지, 우측만 갱신) +function selectTreeNode(itemId) { + selectItem(itemId, false); // updateTree = false +} +``` + +--- + +## 7. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 사이드바 메뉴 추가 | "품목관리" 메뉴 항목 추가 | menus 테이블 (DB) | ⏳ tinker 안내 필요 | + +--- + +## 8. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-19 | - | 문서 초안 작성 | - | - | +| 2026-02-19 | - | 자기완결성 보강 (Appendix A~C 추가) | - | - | +| 2026-02-19 | Phase 1 | Item 모델 보완, ItemDetail/File 모델 생성 | Item.php, ItemDetail.php, File.php | ✅ | +| 2026-02-19 | Phase 1 | ItemManagementService 생성 | ItemManagementService.php | ✅ | +| 2026-02-19 | Phase 1 | ItemManagementApiController 생성 + API 라우트 | ItemManagementApiController.php, api.php | ✅ | +| 2026-02-19 | Phase 2 | 3-Panel Blade 뷰 전체 생성 | index.blade.php + 3 partials | ✅ | +| 2026-02-19 | Phase 2 | Web 컨트롤러 + 라우트 등록 | ItemManagementController.php, web.php | ✅ | +| 2026-02-19 | - | Phase 1~2 완료, Phase 3 수식 연동 계획 별도 문서 분리 | mng-item-formula-integration-plan.md | - | + +--- + +## 9. 참고 문서 + +- **품목 정책**: `docs/rules/item-policy.md` +- **품목 연동 설계**: `docs/specs/item-master-integration.md` +- **MNG 절대 규칙**: `mng/docs/MNG_CRITICAL_RULES.md` +- **MNG 프로젝트 문서**: `mng/docs/INDEX.md` +- **DB 스키마**: `docs/specs/database-schema.md` +- **API Item 모델**: `api/app/Models/Items/Item.php` +- **API ItemDetail 모델**: `api/app/Models/Items/ItemDetail.php` + +--- + +## 10. 검증 결과 + +### 10.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| 좌측 검색: "스크린" | "스크린" 포함 품목만 표시 | 정상 동작 | ✅ | +| FG 품목 클릭 | 중앙에 BOM 트리, 우측에 상세 | 정상 동작 (정적 BOM 2개 표시) | ✅ | +| BOM 없는 품목 클릭 | 중앙 "BOM 없음", 우측 상세 표시 | 정상 동작 | ✅ | +| 중앙 트리 노드 클릭 | 우측 상세만 변경 (트리 유지) | 정상 동작 | ✅ | +| 테넌트 전환 | 좌측 리스트가 해당 테넌트 품목으로 변경 | 확인 필요 | ⏳ | +| 순환 참조 BOM | 무한 루프 없이 maxDepth에서 중단 | 로직 구현 완료, 실제 데이터 미검증 | ⏳ | + +### 10.2 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 3-Panel 레이아웃 정상 렌더링 | ✅ | 좌측 280px + 중앙 flex-1 + 우측 384px | +| 실시간 검색 (debounce 300ms) | ✅ | 코드+이름 동시 검색 | +| BOM 재귀 트리 정상 표시 (전체 depth) | ✅ | 펼침/접힘 토글 포함 | +| 어디서든 클릭 → 우측 상세 갱신 | ✅ | selectItem + selectTreeNode | +| 테넌트 필터링 정상 동작 | ⏳ | withoutGlobalScopes + session 패턴 사용 | +| 순환 참조 방지 (maxDepth) | ✅ | visited 배열 + maxDepth 이중 안전장치 | + +--- + +## 11. 자기완결성 점검 결과 + +### 11.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 3-Panel 품목관리 페이지 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 10.2 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 4 (12개 작업 항목) | +| 4 | 의존성이 명시되어 있는가? | ✅ | items 테이블 존재 전제 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 9 + Appendix | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 5 (6 Step) | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 10.1 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 코드/구조 명시 | + +### 11.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 5. 작업 절차 Step 1 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 3.4 파일 구조 + 6.1 기존 파일 현황 | +| Q4. 작업 완료 확인 방법은? | ✅ | 10. 검증 결과 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 9. 참고 문서 + Appendix A~C | +| Q6. MNG 코딩 패턴은 무엇인가? | ✅ | Appendix A (인라인 패턴) | +| Q7. 테넌트 필터링은 어떻게 동작하는가? | ✅ | Appendix B (BelongsToTenant 전문) | +| Q8. API 모델의 정확한 필드는? | ✅ | Appendix C (API 모델 전문) | + +**결과**: 8/8 통과 → ✅ 자기완결성 확보 + +--- + +## Appendix A: MNG 코딩 패턴 레퍼런스 + +> 새 세션에서 외부 파일을 읽지 않고도 MNG 패턴을 따를 수 있도록 인라인화한 레퍼런스. + +### A.1 Web Controller 패턴 + +Web Controller는 Blade 뷰 렌더링만 담당한다. 비즈니스 로직은 Service에 위임. + +```php +header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('item-management.index')); + } + return view('item-management.index'); +} +``` + +### A.2 API Controller 패턴 + +API Controller는 HTMX 요청 시 HTML partial, 일반 요청 시 JSON 반환. + +```php +departmentService->getDepartments( + $request->all(), + $request->integer('per_page', 10) + ); + + // HTMX 요청 시 HTML partial 반환 + if ($request->header('HX-Request')) { + return view('departments.partials.table', compact('departments')); + } + + // 일반 요청 시 JSON + return response()->json([ + 'success' => true, + 'data' => $departments->items(), + 'meta' => [ + 'current_page' => $departments->currentPage(), + 'last_page' => $departments->lastPage(), + 'per_page' => $departments->perPage(), + 'total' => $departments->total(), + ], + ]); + } +} +``` + +### A.3 Service 패턴 + +모든 DB 쿼리 로직은 Service에서 처리. `session('selected_tenant_id')`로 테넌트 격리. + +```php +with('parent'); + + // 검색 필터 + if (!empty($filters['search'])) { + $search = $filters['search']; + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('code', 'like', "%{$search}%"); + }); + } + + return $query->orderBy('sort_order')->paginate($perPage); + } +} +``` + +> **중요**: BelongsToTenant trait이 모델에 있으면 tenant_id 필터가 자동 적용된다. +> Service에서 수동으로 `where('tenant_id', ...)` 할 필요 없음. + +### A.4 Blade + HTMX 패턴 + +Index 페이지는 빈 셸이고, 데이터는 HTMX `hx-get` + `hx-trigger="load"`로 로드. + +```blade +{{-- 참고: mng/resources/views/departments/index.blade.php 패턴 --}} +@extends('layouts.app') + +@section('title', '부서 관리') + +@section('content') +
    +

    부서 관리

    +
    + + {{-- HTMX 테이블: 초기 로드 + 이벤트 재로드 --}} +
    + {{-- 로딩 스피너 --}} +
    +
    +
    +
    +@endsection + +@push('scripts') + +@endpush +``` + +### A.5 라우트 패턴 + +**routes/web.php** 구조: +```php +// 인증 필요 라우트 그룹 +Route::middleware(['auth', 'hq.member', 'password.changed'])->group(function () { + // ... 기존 라우트들 ... + + // 품목관리 (신규 추가할 위치) + Route::get('/item-management', [ItemManagementController::class, 'index']) + ->name('item-management.index'); +}); +``` + +**routes/api.php** 구조: +```php +// MNG API는 세션 기반 (token 아님) +Route::middleware(['web', 'auth', 'hq.member']) + ->prefix('admin') + ->name('api.admin.') + ->group(function () { + // ... 기존 API 라우트들 ... + + // 품목관리 API (신규 추가할 위치) + Route::prefix('items')->name('items.')->group(function () { + Route::get('/', [ItemManagementApiController::class, 'index'])->name('index'); + Route::get('/{id}/bom-tree', [ItemManagementApiController::class, 'bomTree'])->name('bom-tree'); + Route::get('/{id}/detail', [ItemManagementApiController::class, 'detail'])->name('detail'); + }); + }); +``` + +> **주의**: MNG API는 `['web', 'auth', 'hq.member']` 미들웨어 사용 (세션 기반, Sanctum 아님). +> 고정 라우트(`/all`, `/summary`)를 `/{id}` 파라미터 라우트보다 먼저 정의해야 충돌 방지. + +### A.6 모델 패턴 + +```php +// 참고: mng/app/Models/Category.php 패턴 +use App\Traits\BelongsToTenant; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; + +class Category extends Model +{ + use BelongsToTenant, SoftDeletes; + + protected $fillable = [ + 'tenant_id', 'parent_id', 'code_group', 'profile_code', + 'code', 'name', 'is_active', 'sort_order', 'description', + 'created_by', 'updated_by', 'deleted_by', + ]; + + protected $casts = [ + 'is_active' => 'boolean', + 'sort_order' => 'integer', + ]; + + // 자기 참조 트리 + public function parent() { return $this->belongsTo(self::class, 'parent_id'); } + public function children() { return $this->hasMany(self::class, 'parent_id')->orderBy('sort_order'); } + + // 스코프 + public function scopeActive($query) { return $query->where('is_active', true); } +} +``` + +--- + +## Appendix B: BelongsToTenant 동작 방식 + +### B.1 Trait (mng/app/Traits/BelongsToTenant.php) + +```php +runningInConsole()) { + return; + } + + // 요청당 1회만 tenant_id 조회 (캐시) + if (!self::$cacheInitialized) { + $request = app(Request::class); + self::$cachedTenantId = $request->attributes->get('tenant_id') + ?? $request->header('X-TENANT-ID') + ?? auth()->user()?->tenant_id; + self::$cacheInitialized = true; + } + + if (self::$cachedTenantId !== null) { + $builder->where($model->getTable() . '.tenant_id', self::$cachedTenantId); + } + } + + public static function clearCache(): void + { + self::$cachedTenantId = null; + self::$cacheInitialized = false; + } +} +``` + +**동작 요약**: +1. 모델에 `use BelongsToTenant` 선언하면 자동으로 TenantScope 등록 +2. 모든 쿼리에 `WHERE items.tenant_id = ?` 조건 자동 추가 +3. tenant_id 결정 우선순위: request attributes → X-TENANT-ID 헤더 → auth user +4. console 환경(migrate 등)에서는 스킵 +5. **Service에서 수동 tenant_id 필터 불필요** (자동 적용) + +--- + +## Appendix C: API 모델 전문 (참조용) + +> 구현 시 API 모델의 정확한 필드 목록과 관계를 참고하기 위한 인라인 전문. + +### C.1 api/app/Models/Items/Item.php (전체) + +```php + 'array', + 'attributes' => 'array', + 'attributes_archive' => 'array', + 'options' => 'array', + 'is_active' => 'boolean', + ]; + + const TYPE_FINISHED_GOODS = 'FG'; + const TYPE_PARTS = 'PT'; + const TYPE_SUB_MATERIALS = 'SM'; + const TYPE_RAW_MATERIALS = 'RM'; + const TYPE_CONSUMABLES = 'CS'; + const PRODUCT_TYPES = ['FG', 'PT']; + const MATERIAL_TYPES = ['SM', 'RM', 'CS']; + + public function details() { return $this->hasOne(ItemDetail::class); } + public function stock() { return $this->hasOne(\App\Models\Tenants\Stock::class); } + public function category() { return $this->belongsTo(Category::class, 'category_id'); } + + // files: document_id = item_id, document_type = '1' (ITEM_GROUP_ID) + public function files() + { + return $this->hasMany(File::class, 'document_id')->where('document_type', '1'); + } + + public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } + + // BOM 자식 조회 (JSON bom 필드에서 child_item_id 추출) + public function bomChildren() + { + $childIds = collect($this->bom ?? [])->pluck('child_item_id')->filter()->toArray(); + return self::whereIn('id', $childIds); + } + + // 스코프 + public function scopeType($query, string $type) + { + return $query->where('items.item_type', strtoupper($type)); + } + public function scopeProducts($query) { return $query->whereIn('items.item_type', self::PRODUCT_TYPES); } + public function scopeMaterials($query) { return $query->whereIn('items.item_type', self::MATERIAL_TYPES); } + public function scopeActive($query) { return $query->where('is_active', true); } + + // 헬퍼 + public function isProduct(): bool { return in_array($this->item_type, self::PRODUCT_TYPES); } + public function isMaterial(): bool { return in_array($this->item_type, self::MATERIAL_TYPES); } + public function getBomChildIds(): array + { + return collect($this->bom ?? [])->pluck('child_item_id')->filter()->toArray(); + } +} +``` + +### C.2 api/app/Models/Items/ItemDetail.php (전체) + +```php + 'boolean', + 'is_purchasable' => 'boolean', + 'is_producible' => 'boolean', + 'is_variable_size' => 'boolean', + 'bending_details' => 'array', + 'certification_start_date' => 'date', + 'certification_end_date' => 'date', + ]; + + public function item() { return $this->belongsTo(Item::class); } + public function isSellable(): bool { return $this->is_sellable ?? false; } + public function isPurchasable(): bool { return $this->is_purchasable ?? false; } + public function isProducible(): bool { return $this->is_producible ?? false; } + public function isCertificationValid(): bool + { + return $this->certification_end_date?->isFuture() ?? false; + } + public function requiresInspection(): bool { return $this->is_inspection === 'Y'; } +} +``` + +--- + +## Appendix D: 구현 시 확인 사항 + +### D.1 File 모델 존재 여부 확인 + +구현 시작 전 `mng/app/Models/Commons/File.php` 존재 여부를 확인해야 한다. +없으면 다음과 같이 간단한 모델 생성 필요: + +```php + 1, + 'parent_id' => <부모메뉴ID>, + 'name' => '품목관리', + 'url' => '/item-management', + 'icon' => 'heroicon-o-cube', + 'sort_order' => 1, + 'is_active' => true, +]); +" +``` + +### D.3 품목 유형 정리 + +| 코드 | 이름 | 설명 | BOM 자식 가능 | +|------|------|------|:------------:| +| FG | 완제품 (Finished Goods) | 최종 판매 제품 | ✅ 주로 있음 | +| PT | 부품 (Parts) | 조립/가공 부품 | ✅ 있을 수 있음 | +| SM | 부자재 (Sub Materials) | 보조 자재 | ❌ 일반적으로 없음 | +| RM | 원자재 (Raw Materials) | 원재료 | ❌ 리프 노드 | +| CS | 소모품 (Consumables) | 소모성 자재 | ❌ 리프 노드 | + +### D.4 items.bom JSON 구조 + +```json +// items.bom 필드 예시 (FG 완제품) +[ + {"child_item_id": 5, "quantity": 2.5}, + {"child_item_id": 8, "quantity": 1}, + {"child_item_id": 12, "quantity": 0.5} +] +// child_item_id는 같은 items 테이블의 다른 행을 참조 +// quantity는 소수점 가능 (단위에 따라 kg, m, EA 등) +``` + +### D.5 items.options JSON 구조 + +```json +{ + "lot_managed": true, // LOT 추적 여부 + "consumption_method": "auto", // auto/manual/none + "production_source": "self_produced", // purchased/self_produced/both + "input_tracking": true // 원자재 투입 추적 +} +``` + +--- + +*이 문서는 /plan 스킬로 생성되었습니다. 자기완결성 보강: 2026-02-19* \ No newline at end of file diff --git a/plans/archive/mng-quote-formula-development-plan.md b/plans/archive/mng-quote-formula-development-plan.md new file mode 100644 index 0000000..a632902 --- /dev/null +++ b/plans/archive/mng-quote-formula-development-plan.md @@ -0,0 +1,553 @@ +# MNG 견적수식 관리 개발 계획 + +> **작성일**: 2025-12-22 +> **상태**: ✅ 완료 +> **대상**: mng.sam.kr/quote-formulas + +--- + +## 1. 현황 분석 + +### 1.1 MNG 프로젝트 현재 상태 + +#### 구현된 기능 (mng) + +| 기능 | 상태 | 설명 | +|-----|------|-----| +| 수식 목록 | ✅ 완료 | 페이지네이션, 필터링, HTMX 테이블 | +| 수식 생성 | ✅ 완료 | 카테고리, 유형, 변수명, 수식 입력 | +| 수식 수정 | ✅ 완료 | 편집 폼, API 연동 | +| 수식 삭제 | ✅ 완료 | Soft Delete, 복원, 영구삭제 | +| 수식 복제 | ✅ 완료 | 수식 복사 기능 | +| 활성/비활성 | ✅ 완료 | 토글 기능 | +| 카테고리 관리 | ✅ 완료 | CRUD 구현 | +| 시뮬레이터 | ✅ 완료 | 입력값 → 계산 결과 미리보기 | +| 변수 참조 | ✅ 완료 | 사용 가능한 변수 목록 표시 | +| 수식 검증 | ✅ 완료 | 문법 검증 API | +| 범위(Range) 관리 UI | ✅ 완료 | 범위별 결과 설정 화면 (Phase 1) | +| 매핑(Mapping) 관리 UI | ✅ 완료 | 매핑 규칙 설정 화면 (Phase 2) | +| 품목(Item) 관리 UI | ✅ 완료 | 출력 품목 설정 화면 (Phase 3) | + +### 1.2 API 프로젝트 현재 상태 + +#### 모델 구조 (api) + +``` +QuoteFormulaCategory (카테고리) +└── QuoteFormula (수식) + ├── QuoteFormulaRange (범위 조건) + ├── QuoteFormulaMapping (매핑 규칙) + └── QuoteFormulaItem (출력 품목) +``` + +#### 시더 데이터 (api) + +| 시더 | 데이터 수 | 설명 | +|-----|---------|-----| +| QuoteFormulaCategorySeeder | 11개 | 카테고리 (오픈사이즈~단가수식) | +| QuoteFormulaSeeder | 30개 수식, 18개 범위 | 스크린 계산 수식 | +| QuoteFormulaItemSeeder | 25개 | 품목 마스터 | + +#### 서비스 (api) + +| 서비스 | 역할 | +|-------|-----| +| QuoteCalculationService | 자동산출 실행 엔진 | +| FormulaEvaluatorService | 수식 평가, 범위/매핑 처리 | +| QuoteService | 견적 CRUD, 상태 관리 | +| QuoteNumberService | 견적번호 생성 | +| QuoteDocumentService | PDF/이메일/카카오 발송 (TODO) | + +--- + +## 2. MNG vs API 비교 분석 + +### 2.1 데이터 구조 비교 + +| 항목 | MNG | API | 일치 | +|-----|-----|-----|-----| +| quote_formula_categories | ✅ | ✅ | ✅ | +| quote_formulas | ✅ | ✅ | ✅ | +| quote_formula_ranges | ✅ | ✅ | ✅ | +| quote_formula_mappings | ✅ | ✅ | ✅ | +| quote_formula_items | ✅ | ✅ | ✅ | + +**결론**: 모델 구조는 동일함 (같은 DB 사용) + +### 2.2 기능 비교 + +| 기능 | MNG | API | 비고 | +|-----|-----|-----|-----| +| 수식 CRUD | ✅ | ✅ | 동일 | +| 카테고리 CRUD | ✅ | ✅ | 동일 | +| 범위 관리 UI | ✅ | ✅ (시더) | Phase 1 완료 | +| 매핑 관리 UI | ✅ | ✅ (시더) | Phase 2 완료 | +| 품목 관리 UI | ✅ | ✅ (시더) | Phase 3 완료 | +| 시뮬레이터 | ✅ | ✅ | 동일 | +| 자동산출 API | - | ✅ | API 전용 | + +--- + +## 3. 개발 계획 (완료) + +### 3.1 목표 + +MNG에서 **범위(Range), 매핑(Mapping), 품목(Item)** 관리 UI를 추가하여: +1. 시더 없이도 관리자가 직접 수식 규칙 설정 가능 +2. SAM 자체 품목 마스터로 가격 설정 +3. 실시간 시뮬레이션으로 설정 검증 가능 + +### 3.2 개발 범위 (완료) + +#### Phase 1: 범위(Range) 관리 UI ✅ + +**우선순위**: 높음 +**이유**: 모터, 가이드레일, 케이스 자동 선택에 필수 + +**기능 목록**: +1. 수식 상세 페이지에 범위 관리 탭 추가 +2. 범위 목록 표시 (min ~ max → 결과) +3. 범위 추가/수정/삭제 +4. 드래그앤드롭 순서 변경 +5. item_code 연결 (품목 선택) + +**화면 설계**: +``` +[수식 수정] 페이지 +├── [기본 정보] 탭 (기존) +├── [범위 설정] 탭 ← 추가 +│ ├── 조건 변수: [K (중량)] ▼ +│ ├── 범위 목록 +│ │ ┌─────────────────────────────────────────────────┐ +│ │ │ # │ 최소값 │ 최대값 │ 결과값 │ 품목코드 │ +│ │ ├─────────────────────────────────────────────────┤ +│ │ │ 1 │ 0 │ 150 │ 150K │ PT-MOTOR-150│ +│ │ │ 2 │ 150 │ 300 │ 300K │ PT-MOTOR-300│ +│ │ │ 3 │ 300 │ 400 │ 400K │ PT-MOTOR-400│ +│ │ └─────────────────────────────────────────────────┘ +│ └── [+ 범위 추가] +├── [매핑 설정] 탭 +└── [품목 설정] 탭 +``` + +**API 엔드포인트 (MNG 내부)**: +``` +GET /api/admin/quote-formulas/formulas/{id}/ranges +POST /api/admin/quote-formulas/formulas/{id}/ranges +PUT /api/admin/quote-formulas/formulas/{id}/ranges/{rangeId} +DELETE /api/admin/quote-formulas/formulas/{id}/ranges/{rangeId} +POST /api/admin/quote-formulas/formulas/{id}/ranges/reorder +``` + +#### Phase 2: 매핑(Mapping) 관리 UI ✅ + +**우선순위**: 중간 +**이유**: 제어기 유형 등 코드 매핑에 사용 + +**기능 목록**: +1. 수식 상세 페이지에 매핑 관리 탭 추가 +2. 매핑 목록 표시 (소스값 → 결과값) +3. 매핑 추가/수정/삭제 + +**화면 설계**: +``` +[매핑 설정] 탭 +├── 소스 변수: [CONTROL_TYPE] ▼ +├── 매핑 목록 +│ ┌──────────────────────────────────────────────────┐ +│ │ # │ 소스값 │ 결과값 │ 품목코드 │ +│ ├──────────────────────────────────────────────────┤ +│ │ 1 │ EMB │ 매립형 │ PT-CTRL-EMB │ +│ │ 2 │ EXP │ 노출형 │ PT-CTRL-EXP │ +│ │ 3 │ BOX_1P │ 콘트롤박스 │ PT-CTRL-BOX-1P │ +│ └──────────────────────────────────────────────────┘ +└── [+ 매핑 추가] +``` + +#### Phase 3: 품목(Item) 관리 UI ✅ + +**우선순위**: 중간 +**이유**: 수식 결과로 생성되는 품목 정의 + +**기능 목록**: +1. 수식 상세 페이지에 품목 관리 탭 추가 +2. 품목 목록 표시 +3. 품목 추가/수정/삭제 +4. 수량/단가 수식 입력 +5. SAM 품목 마스터에서 가격 참조 + +**화면 설계**: +``` +[품목 설정] 탭 +├── 품목 목록 +│ ┌───────────────────────────────────────────────────────────┐ +│ │ 품목코드 │ 품목명 │ 규격 │ 수량식 │ 단가식│ +│ ├───────────────────────────────────────────────────────────┤ +│ │ PT-MOTOR-150 │ 개폐전동기 150kg│ 150K(S) │ 1 │ 285000│ +│ │ PT-GR-3000 │ 가이드레일 3000 │ 3000mm │ 2 │ 42000 │ +│ └───────────────────────────────────────────────────────────┘ +└── [+ 품목 추가] +``` + +### 3.3 파일 구조 (구현 완료) + +#### Controllers +``` +app/Http/Controllers/ +├── QuoteFormulaController.php (수정: 탭 추가) +└── Api/Admin/Quote/ + ├── QuoteFormulaController.php + ├── QuoteFormulaRangeController.php ✅ + ├── QuoteFormulaMappingController.php ✅ + ├── QuoteFormulaItemController.php ✅ + └── QuoteFormulaCategoryController.php +``` + +#### Services +``` +app/Services/Quote/ +├── QuoteFormulaService.php +├── QuoteFormulaRangeService.php ✅ +├── QuoteFormulaMappingService.php ✅ +├── QuoteFormulaItemService.php ✅ +└── QuoteFormulaCategoryService.php +``` + +#### Views +``` +resources/views/quote-formulas/ +├── index.blade.php +├── create.blade.php +├── edit.blade.php (수정: 탭 구조) +├── simulator.blade.php +└── partials/ + ├── basic-info-tab.blade.php ✅ + ├── ranges-tab.blade.php ✅ + ├── mappings-tab.blade.php ✅ + └── items-tab.blade.php ✅ +``` + +--- + +## 4. 기술 스택 + +### 4.1 Frontend (MNG) +- **Framework**: Laravel Blade + Alpine.js +- **Styling**: Tailwind CSS + DaisyUI +- **AJAX**: HTMX (hx-get, hx-post, hx-delete) +- **Modal**: DaisyUI modal 컴포넌트 + +### 4.2 Backend (MNG) +- **Framework**: Laravel 12 +- **ORM**: Eloquent +- **DB**: MySQL (samdb) +- **Auth**: Session 기반 + +### 4.3 API 연동 +- MNG 내부 API (`/api/admin/quote-formulas/*`) + +--- + +## 5. 검증 계획 + +### 5.1 시뮬레이터 테스트 +``` +입력: W0=3000, H0=2500 +예상 결과: + - CASE: PT-CASE-3600 (S=3270) + - GR: PT-GR-3000 (H1=2770) + - MOTOR: PT-MOTOR-150 (K=41.21kg) +``` + +### 5.2 CRUD 테스트 +- 범위 추가/수정/삭제 후 시뮬레이터 결과 확인 +- 품목 가격 변경 후 합계 확인 + +--- + +## 6. 참고 자료 + +### 6.1 파일 위치 (MNG) +``` +mng/ +├── app/Http/Controllers/ +│ ├── QuoteFormulaController.php +│ └── Api/Admin/Quote/ +│ ├── QuoteFormulaController.php +│ ├── QuoteFormulaRangeController.php +│ ├── QuoteFormulaMappingController.php +│ ├── QuoteFormulaItemController.php +│ └── QuoteFormulaCategoryController.php +├── app/Services/Quote/ +│ ├── QuoteFormulaService.php +│ ├── QuoteFormulaRangeService.php +│ ├── QuoteFormulaMappingService.php +│ ├── QuoteFormulaItemService.php +│ └── QuoteFormulaCategoryService.php +├── app/Models/Quote/ +│ ├── QuoteFormula.php +│ ├── QuoteFormulaCategory.php +│ ├── QuoteFormulaRange.php +│ ├── QuoteFormulaMapping.php +│ └── QuoteFormulaItem.php +└── resources/views/quote-formulas/ + ├── index.blade.php + ├── create.blade.php + ├── edit.blade.php + ├── simulator.blade.php + └── partials/ + ├── basic-info-tab.blade.php + ├── ranges-tab.blade.php + ├── mappings-tab.blade.php + └── items-tab.blade.php +``` + +### 6.2 API 시더 위치 +``` +api/database/seeders/ +├── QuoteFormulaCategorySeeder.php +├── QuoteFormulaSeeder.php +└── QuoteFormulaItemSeeder.php +``` + +--- + +## 7. 코딩 컨벤션 및 예시 코드 + +### 7.1 API Controller 패턴 (MNG) + +```php +rangeService->getRangesByFormula($formulaId); + + return response()->json([ + 'success' => true, + 'data' => $ranges, + ]); + } + + /** + * 범위 생성 + */ + public function store(Request $request, int $formulaId): JsonResponse + { + $validated = $request->validate([ + 'min_value' => 'nullable|numeric', + 'max_value' => 'nullable|numeric', + 'condition_variable' => 'required|string|max:50', + 'result_value' => 'required|string', + 'result_type' => 'in:fixed,formula', + 'sort_order' => 'nullable|integer', + ]); + + $range = $this->rangeService->createRange($formulaId, $validated); + + return response()->json([ + 'success' => true, + 'message' => '범위가 추가되었습니다.', + 'data' => $range, + ]); + } + + /** + * 범위 수정 + */ + public function update(Request $request, int $formulaId, int $rangeId): JsonResponse + { + $validated = $request->validate([ + 'min_value' => 'nullable|numeric', + 'max_value' => 'nullable|numeric', + 'result_value' => 'required|string', + 'result_type' => 'in:fixed,formula', + ]); + + $this->rangeService->updateRange($rangeId, $validated); + + return response()->json([ + 'success' => true, + 'message' => '범위가 수정되었습니다.', + ]); + } + + /** + * 범위 삭제 + */ + public function destroy(int $formulaId, int $rangeId): JsonResponse + { + $this->rangeService->deleteRange($rangeId); + + return response()->json([ + 'success' => true, + 'message' => '범위가 삭제되었습니다.', + ]); + } + + /** + * 순서 변경 + */ + public function reorder(Request $request, int $formulaId): JsonResponse + { + $validated = $request->validate([ + 'range_ids' => 'required|array', + 'range_ids.*' => 'integer', + ]); + + $this->rangeService->reorder($validated['range_ids']); + + return response()->json([ + 'success' => true, + 'message' => '순서가 변경되었습니다.', + ]); + } +} +``` + +### 7.2 Service 패턴 (MNG) + +```php +orderBy('sort_order') + ->get(); + } + + /** + * 범위 생성 + */ + public function createRange(int $formulaId, array $data): QuoteFormulaRange + { + $data['formula_id'] = $formulaId; + + // 순서 자동 설정 + if (!isset($data['sort_order'])) { + $maxOrder = QuoteFormulaRange::where('formula_id', $formulaId)->max('sort_order') ?? 0; + $data['sort_order'] = $maxOrder + 1; + } + + return QuoteFormulaRange::create($data); + } + + /** + * 범위 수정 + */ + public function updateRange(int $rangeId, array $data): QuoteFormulaRange + { + $range = QuoteFormulaRange::findOrFail($rangeId); + $range->update($data); + + return $range->fresh(); + } + + /** + * 범위 삭제 + */ + public function deleteRange(int $rangeId): void + { + QuoteFormulaRange::destroy($rangeId); + } + + /** + * 순서 변경 + */ + public function reorder(array $rangeIds): void + { + foreach ($rangeIds as $order => $id) { + QuoteFormulaRange::where('id', $id)->update(['sort_order' => $order + 1]); + } + } +} +``` + +### 7.3 API 응답 형식 + +```json +// 성공 응답 +{ + "success": true, + "message": "범위가 추가되었습니다.", + "data": { ... } +} + +// 실패 응답 +{ + "success": false, + "message": "이미 사용 중인 변수명입니다." +} + +// 목록 응답 +{ + "success": true, + "data": [ + { + "id": 1, + "formula_id": 5, + "min_value": "0.0000", + "max_value": "150.0000", + "condition_variable": "K", + "result_value": "{\"value\":\"150K\",\"item_code\":\"PT-MOTOR-150\"}", + "result_type": "fixed", + "sort_order": 1 + } + ] +} +``` + +--- + +## 8. 체크리스트 (완료) + +### 개발 완료 확인 + +- [x] mng 프로젝트 디렉토리: `/Users/hskwon/Works/@KD_SAM/SAM/mng` +- [x] `QuoteFormulaRangeController.php` 생성 +- [x] `QuoteFormulaRangeService.php` 생성 +- [x] `QuoteFormulaMappingController.php` 생성 +- [x] `QuoteFormulaMappingService.php` 생성 +- [x] `QuoteFormulaItemController.php` 생성 +- [x] `QuoteFormulaItemService.php` 생성 +- [x] `routes/api.php`에 라우트 추가 +- [x] `edit.blade.php` 탭 구조로 수정 +- [x] `partials/ranges-tab.blade.php` 생성 +- [x] `partials/mappings-tab.blade.php` 생성 +- [x] `partials/items-tab.blade.php` 생성 + +--- + +*문서 버전*: 2.0 +*작성자*: Claude Code +*검토자*: - +*최종 업데이트*: 2025-12-22 (Phase 1-3 완료, 5130 연동 제거) \ No newline at end of file diff --git a/plans/archive/notification-sound-system-plan.md b/plans/archive/notification-sound-system-plan.md new file mode 100644 index 0000000..f2e7e66 --- /dev/null +++ b/plans/archive/notification-sound-system-plan.md @@ -0,0 +1,424 @@ +# 알림음 시스템 구현 계획 + +> **작성일**: 2025-01-07 +> **목적**: FCM 푸시 알림 타입별 커스텀 알림음 구현 +> **영향 범위**: app (Capacitor), api (Laravel), mng (Laravel) +> **상태**: ✅ 핵심 기능 완료 (4.3 알림 설정 테이블은 후순위) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 5 - 테스트 및 검증 완료 ✅ | +| **다음 작업** | 완료 (4.3 알림 설정 테이블은 후순위) | +| **진행률** | 10/11 (91%) - 핵심 기능 완료 | +| **마지막 업데이트** | 2025-01-07 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 SAM 앱은 FCM 푸시 알림 시 2개 채널(`push_default`, `push_urgent`)만 지원합니다. +비즈니스 요구사항에 따라 알림 타입별로 다른 알림음이 필요합니다: + +- 결제 알림 → 결제 전용 알림음 +- 수주 알림 → 수주 전용 알림음 +- 발주 알림 → 발주 전용 알림음 +- 계약 알림 → 계약 전용 알림음 +- 일반 알림 → 기본 알림음 +- 신규업체 등록 → 긴급 알림음 + +### 1.2 목표 구조 + +| 타입 | 채널 ID | 알림음 파일 | 설명 | +|------|---------|------------|------| +| 결제 | `push_payment` | `push_payment.wav` | 결제 관련 알림 | +| 수주 | `push_sales_order` | `push_sales_order.wav` | 수주 관련 알림 | +| 발주 | `push_purchase_order` | `push_purchase_order.wav` | 발주 관련 알림 | +| 계약 | `push_contract` | `push_contract.wav` | 계약 관련 알림 | +| 일반 | `push_default` | `push_default.wav` | 일반 알림 (기존) | +| 신규업체 등록 | `push_urgent` | `push_urgent.wav` | 신규업체 등록 (기존) | + +### 1.3 현재 상태 분석 + +#### App (Capacitor Android) +- **파일**: `app/android/app/src/main/java/com/codebridgex/webapp/MainActivity.java` +- **현재**: 2개 채널 (`push_default`, `push_urgent`) +- **알림음**: `res/raw/push_default.wav`, `res/raw/push_urgent.wav` + +#### API (Laravel) +- **파일**: `api/app/Services/Fcm/FcmSender.php` +- **현재**: `channel_id` 파라미터 지원, 사운드는 `'default'` 하드코딩 +- **문제**: 커스텀 사운드 미지원 + +#### MNG (Laravel) +- **파일**: `mng/app/Http/Controllers/FcmController.php` +- **현재**: `sound_key` 파라미터 존재하나 실제 활용 안됨 + +### 1.4 시스템 흐름 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ FCM 알림음 시스템 흐름 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ MNG (발송 UI) │ +│ ┌─────────────────┐ │ +│ │ 타입 선택 │ ← 결제/수주/발주/계약/일반/신규업체 │ +│ │ channel_id 설정 │ │ +│ └────────┬────────┘ │ +│ │ │ +│ ▼ │ +│ API (FCM 발송) │ +│ ┌─────────────────┐ │ +│ │ FcmSender │ │ +│ │ channel_id → │ │ +│ │ android.channel │ │ +│ └────────┬────────┘ │ +│ │ │ +│ ▼ │ +│ Firebase Cloud Messaging │ +│ ┌─────────────────┐ │ +│ │ FCM Server │ │ +│ └────────┬────────┘ │ +│ │ │ +│ ▼ │ +│ App (Capacitor) │ +│ ┌─────────────────┐ │ +│ │ NotificationChannel │ ← channel_id로 매칭 │ +│ │ 채널별 사운드 재생 │ ← push_payment.wav 등 │ +│ └─────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: App - 채널 및 알림음 추가 + +| # | 작업 항목 | 상태 | 파일 | +|---|----------|:----:|------| +| 1.1 | 알림음 파일 준비 (4개) | ✅ | `res/raw/*.wav` | +| 1.2 | MainActivity.java 채널 추가 (4개) | ✅ | `MainActivity.java` | + +### 2.2 Phase 2: API - FcmSender 수정 + +| # | 작업 항목 | 상태 | 파일 | +|---|----------|:----:|------| +| 2.1 | buildMessage() 사운드 동적 처리 | ✅ | `FcmSender.php` | +| 2.2 | 채널-사운드 매핑 (FcmSender 내부 통합) | ✅ | `FcmSender.php` | + +### 2.3 Phase 3: MNG - 발송 UI 수정 + +| # | 작업 항목 | 상태 | 파일 | +|---|----------|:----:|------| +| 3.1 | 타입 선택 드롭다운 추가 | ✅ | `fcm/send.blade.php` | +| 3.2 | 타입-채널 매핑 로직 | ✅ | `FcmController.php` | + +### 2.4 Phase 4: 이벤트 기반 자동 푸시 + +| # | 작업 항목 | 상태 | 파일 | +|---|----------|:----:|------| +| 4.1 | PushNotificationService 생성 | ✅ | `api/app/Services/PushNotificationService.php` | +| 4.2 | 신규 거래처 등록 시 푸시 | ✅ | `api/app/Services/ClientService.php` | +| 4.3 | 알림 설정 테이블 (추후) | ⏭️ | 후순위 | + +### 2.5 Phase 5: 테스트 및 검증 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 5.1 | 각 타입별 푸시 발송 테스트 | ✅ | 6개 타입 | +| 5.2 | 알림음 재생 확인 | ✅ | Android 실기기 | + +--- + +## 3. 상세 작업 내용 + +### 3.1 Phase 1: App - 채널 및 알림음 추가 + +#### 1.1 알림음 파일 준비 + +**위치**: `app/android/app/src/main/res/raw/` + +| 파일명 | 상태 | 비고 | +|--------|------|------| +| `push_default.wav` | ✅ | 일반 알림 | +| `push_urgent.wav` | ✅ | 신규업체 등록 | +| `push_payment.wav` | ✅ | 결제 알림 | +| `push_sales_order.wav` | ✅ | 수주 알림 | +| `push_purchase_order.wav` | ✅ | 발주 알림 | +| `push_contract.wav` | ✅ | 계약 알림 | + +> **완료**: 6개 알림음 파일 모두 준비됨 (2025-01-07) + +#### 1.2 MainActivity.java 수정 + +**현재 코드** (2개 채널): +```java +public static final String CHANNEL_DEFAULT = "push_default"; +public static final String CHANNEL_URGENT = "push_urgent"; +``` + +**목표 코드** (6개 채널): +```java +public static final String CHANNEL_DEFAULT = "push_default"; +public static final String CHANNEL_URGENT = "push_urgent"; +public static final String CHANNEL_PAYMENT = "push_payment"; +public static final String CHANNEL_SALES_ORDER = "push_sales_order"; +public static final String CHANNEL_PURCHASE_ORDER = "push_purchase_order"; +public static final String CHANNEL_CONTRACT = "push_contract"; +``` + +### 3.2 Phase 2: API - FcmSender 수정 + +#### 2.1 buildMessage() 수정 + +**현재** (`FcmSender.php:112`): +```php +'android' => [ + 'notification' => [ + 'channel_id' => $channelId, + 'sound' => 'default', // 하드코딩 + ], +], +``` + +**목표**: +```php +'android' => [ + 'notification' => [ + 'channel_id' => $channelId, + 'sound' => $this->getSoundForChannel($channelId), + ], +], +``` + +#### 2.2 채널-사운드 매핑 + +```php +// config/fcm.php 또는 FcmSender 내부 +private function getSoundForChannel(string $channelId): string +{ + return match($channelId) { + 'push_payment' => 'push_payment', + 'push_sales_order' => 'push_sales_order', + 'push_purchase_order' => 'push_purchase_order', + 'push_contract' => 'push_contract', + 'push_urgent' => 'push_urgent', + default => 'push_default', + }; +} +``` + +### 3.3 Phase 3: MNG - 발송 UI 수정 + +#### 3.1 타입 선택 UI + +```html + +``` + +#### 3.2 타입 → 채널 매핑 + +```php +$channelMap = [ + 'general' => 'push_default', + 'payment' => 'push_payment', + 'sales_order' => 'push_sales_order', + 'purchase_order' => 'push_purchase_order', + 'contract' => 'push_contract', + 'new_company' => 'push_urgent', +]; +``` + +### 3.4 Phase 4: 이벤트 기반 자동 푸시 + +#### 4.1 PushNotificationService 생성 + +**파일**: `api/app/Services/PushNotificationService.php` + +```php +getChannelForEvent($event); + + // 해당 테넌트의 활성 토큰 조회 + $tokens = PushDeviceToken::where('tenant_id', $tenantId) + ->where('is_active', true) + ->pluck('token') + ->toArray(); + + if (empty($tokens)) { + return; + } + + $this->fcmSender->sendToMany( + $tokens, + $title, + $body, + $channelId, + $data + ); + } + + /** + * 이벤트 → 채널 매핑 + */ + private function getChannelForEvent(string $event): string + { + return match($event) { + 'payment' => 'push_payment', + 'sales_order' => 'push_sales_order', + 'purchase_order' => 'push_purchase_order', + 'contract' => 'push_contract', + 'new_client' => 'push_urgent', + default => 'push_default', + }; + } +} +``` + +#### 4.2 ClientService에서 푸시 호출 + +**파일**: `api/app/Services/ClientService.php` (store 메서드) + +```php +/** 생성 */ +public function store(array $data) +{ + $tenantId = $this->tenantId(); + + $data['client_code'] = $this->generateClientCode($tenantId); + $data['tenant_id'] = $tenantId; + $data['is_active'] = $data['is_active'] ?? true; + + $client = Client::create($data); + + // 신규 거래처 등록 푸시 발송 + app(PushNotificationService::class) + ->setTenantId($tenantId) + ->sendByEvent( + 'new_client', + $tenantId, + '신규 거래처 등록', + "새로운 거래처 '{$client->name}'이(가) 등록되었습니다.", + ['client_id' => $client->id] + ); + + return $client; +} +``` + +#### 4.3 이벤트 타입 정의 + +| 이벤트 | 채널 | 발생 시점 | +|--------|------|----------| +| `new_client` | `push_urgent` | 거래처 신규 등록 | +| `payment` | `push_payment` | 결제 완료/요청 | +| `sales_order` | `push_sales_order` | 수주 등록/변경 | +| `purchase_order` | `push_purchase_order` | 발주 등록/변경 | +| `contract` | `push_contract` | 계약 등록/만료 | + +--- + +## 4. 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 알림음 파일 추가, 채널 추가 | 불필요 | +| ⚠️ 컨펌 필요 | FcmSender 로직 변경, UI 수정 | **필수** | +| 🔴 금지 | FCM 구조 변경, 기존 채널 삭제 | 별도 협의 | + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 알림음 파일 | 6개 wav 파일 준비 | app | ✅ 완료 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-01-07 | - | 계획 문서 초안 작성 | - | - | +| 2025-01-07 | 1.2 | MainActivity.java 6개 채널 추가 | `MainActivity.java` | ✅ | +| 2025-01-07 | 2.1/2.2 | FcmSender 사운드 동적 처리 + getSoundForChannel 추가 | `FcmSender.php` | ✅ | +| 2025-01-07 | 3.1 | MNG 알림 타입 드롭다운 추가 (6개 타입) | `fcm/send.blade.php` | ✅ | +| 2025-01-07 | 3.2 | FcmController channel_id 검증 + sound_key 제거 | `FcmController.php` | ✅ | +| 2025-01-07 | 4.1 | PushNotificationService 생성 (이벤트 기반 푸시) | `PushNotificationService.php` | ✅ | +| 2025-01-07 | 4.2 | ClientService.store()에 푸시 알림 연동 | `ClientService.php` | ✅ | +| 2025-01-07 | 5.1/5.2 | 테스트 및 검증 완료 | 서버 배포 후 실기기 테스트 | ✅ | + +--- + +## 7. 참고 문서 + +- **FCM 푸시 계획**: `docs/plans/react-fcm-push-notification-plan.md` +- **API 규칙**: `docs/standards/api-rules.md` + +--- + +## 8. 알림음 파일 준비 가이드 + +### 요구사항 +- **포맷**: WAV (권장) 또는 MP3 +- **길이**: 1-3초 권장 +- **샘플레이트**: 44.1kHz +- **비트레이트**: 16bit + +### 임시 방안 +알림음 파일이 준비되지 않은 경우, 기존 파일을 복사하여 사용: + +```bash +cd app/android/app/src/main/res/raw/ +cp push_default.wav push_payment.wav +cp push_default.wav push_sales_order.wav +cp push_default.wav push_purchase_order.wav +cp push_default.wav push_contract.wav +``` + +### 무료 알림음 리소스 +- [Pixabay Sound Effects](https://pixabay.com/sound-effects/) +- [Freesound](https://freesound.org/) +- [Zapsplat](https://www.zapsplat.com/) + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/order-location-management-plan.md b/plans/archive/order-location-management-plan.md new file mode 100644 index 0000000..cac3da9 --- /dev/null +++ b/plans/archive/order-location-management-plan.md @@ -0,0 +1,831 @@ +# 수주 하위 구조 관리 시스템 구축 계획 + +> **작성일**: 2026-02-06 +> **목적**: 수주(Order) 하위에 범용 N-depth 트리 구조를 구축하여 개소/구역/공정 등 다양한 하위 단위를 자유롭게 관리 +> **기준 문서**: `docs/features/quotes/README.md`, `docs/specs/database-schema.md`, `docs/standards/api-rules.md` +> **상태**: 🔄 진행중 +> **설계 결정**: 하이브리드 (고정 코어 컬럼 + options JSON) — 통계 쿼리 성능과 유연성 균형 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4.2 - 프론트엔드 노드별 그룹 UI | +| **다음 작업** | 완료 (테스트 검증 필요) | +| **진행률** | 13/13 (100%) | +| **마지막 업데이트** | 2026-02-06 | + +--- + +## 1. 개요 + +### 1.1 배경 + +**즉시 문제**: 견적→수주 전환(`QuoteService::convertToOrder`)에서 개소 정보가 매핑되지 않아 `order_items.floor_code`, `symbol_code`가 null로 저장됨. 반면 `OrderService::syncFromQuote`에는 이미 파싱 로직이 있어 정상 동작. + +**구조적 문제**: 현재 수주 하위 구조는 `order_items` 플랫 테이블뿐이며, 개소/구역/공정 등 다양한 그루핑 단위를 관리할 수 없음. 5130(경동)은 개소별 관리가 필요하지만, 향후 다른 테넌트에서는 구역별, 층별, 공정별 등 다양한 트리 구조가 필요. + +**현재 데이터 흐름 문제**: +``` +견적 저장: + quotes.calculation_inputs.items[] → 개소별 데이터 ✅ + quote_items.note → "4F FSS-01" ✅ + +수주 전환 (convertToOrder): + order_items.floor_code → null ❌ ← $productMapping이 빈 배열 + order_items.symbol_code → null ❌ + +수주 동기화 (syncFromQuote): + order_items.floor_code → "4F" ✅ ← note 파싱 로직 있음 + order_items.symbol_code → "FSS-01" ✅ +``` + +### 1.2 목표 + +1. 견적→수주 전환 시 개소 정보가 정확히 매핑되도록 즉시 수정 (Quick Fix) +2. `order_nodes` 테이블을 신규 생성하여 **범용 N-depth 트리 구조** 제공 +3. 노드별 독립 상태 추적 (대기/진행중/완료/취소) +4. 프론트엔드에서 노드별 그룹 UI 제공 (경동은 개소별 표시) + +### 1.3 아키텍처 결정 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 설계 결정: 하이브리드 (고정 코어 + options JSON) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ❌ 순수 EAV → 통계 쿼리 시 JOIN 폭발, 성능 문제 │ +│ ❌ 고정 컬럼 전용 → 경동 개소에만 맞고 범용성 없음 │ +│ ✅ 하이브리드 → 통계용 고정 컬럼 + 유형별 상세는 options JSON │ +│ │ +│ 근거: │ +│ - SAM 프로젝트에서 이미 options JSON 패턴 사용 중 │ +│ (work_order_items.options, quotes.calculation_inputs) │ +│ - MySQL 8 JSON path 쿼리 지원 (options->>'$.floor' 등) │ +│ - 통계 집계는 고정 컬럼(code, name, status, quantity, price)으로 │ +│ - sam_stat 일간/월간 집계에도 고정 컬럼 기반으로 수월 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.4 핵심 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 1. 범용 트리: N-depth 자기참조(parent_id)로 어떤 구조든 표현 가능 │ +│ 2. 통계 친화: code, name, status, quantity, price는 고정 컬럼 │ +│ 3. 유형 자유: node_type으로 구분, 유형별 상세는 options JSON │ +│ 4. 역호환성: 기존 수주(order_nodes 없는)도 정상 동작 │ +│ 5. SAM 패턴 준수: BelongsToTenant, Auditable, SoftDeletes │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.5 적용 예시 + +**경동 (1-depth: 개소)**: +``` +Order: ORD-260206-001 +├── Node (type:location, code:"1F-FSS-01", name:"1F FSS-01") +│ ├── options: { floor:"1F", symbol:"FSS-01", product_code:"KSS01", +│ │ open_width:5000, open_height:3000, guide_rail:"wall" } +│ └── OrderItems (자재 N개) +│ +└── Node (type:location, code:"2F-SD-02", name:"2F SD-02") + ├── options: { floor:"2F", symbol:"SD-02", product_code:"KWE01", + │ open_width:2800, open_height:2400 } + └── OrderItems (자재 N개) +``` + +**다른 테넌트 (3-depth: 동→층→실)**: +``` +Order: ORD-260206-005 +├── Node (type:zone, code:"A", name:"A동") +│ ├── Node (type:floor, code:"1F", name:"1층") +│ │ ├── Node (type:room, code:"101", name:"회의실") +│ │ │ └── OrderItems +│ │ └── Node (type:room, code:"102", name:"사무실") +│ │ └── OrderItems +│ └── Node (type:floor, code:"2F", name:"2층") +│ └── ... +└── Node (type:zone, code:"B", name:"B동") + └── ... +``` + +### 1.6 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | convertToOrder 로직 수정, 모델 관계 추가 | 불필요 | +| ⚠️ 컨펌 필요 | 마이그레이션 생성, 신규 테이블, API 엔드포인트 추가 | **필수** | +| 🔴 금지 | 기존 order_items.floor_code/symbol_code 삭제, 기존 API 스키마 변경 | 별도 협의 | + +### 1.7 준수 규칙 + +- `docs/standards/api-rules.md` - Service-First, FormRequest, i18n +- `docs/specs/database-schema.md` - 공통 컬럼 패턴 (tenant_id, audit, softDeletes) +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `react/CLAUDE.md` - 'use client' 필수, Server Actions + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: convertToOrder 개소 파싱 (Quick Fix) + +| # | 작업 항목 | 파일 | 상태 | 비고 | +|---|----------|------|:----:|------| +| 1.1 | convertToOrder에 개소 파싱 로직 추가 | `api/app/Services/Quote/QuoteService.php` | ✅ | syncFromQuote 로직 재사용 | +| 1.2 | 개소 파싱 공통 메소드 추출 | `api/app/Services/Quote/QuoteService.php` | ✅ | 중복 코드 제거 | + +### 2.2 Phase 2: order_nodes 테이블 (DB 스키마) + +| # | 작업 항목 | 파일 | 상태 | 비고 | +|---|----------|------|:----:|------| +| 2.1 | order_nodes 마이그레이션 생성 | `api/database/migrations/XXXX_create_order_nodes_table.php` | ✅ | 신규 테이블 | +| 2.2 | order_items에 order_node_id 추가 | `api/database/migrations/XXXX_add_order_node_id_to_order_items.php` | ✅ | nullable FK | +| 2.3 | OrderNode 모델 생성 | `api/app/Models/Orders/OrderNode.php` | ✅ | BelongsToTenant, SoftDeletes, 자기참조 | +| 2.4 | Order 모델에 nodes() 관계 추가 | `api/app/Models/Orders/Order.php` | ✅ | HasMany | +| 2.5 | OrderItem 모델에 node() 관계 추가 | `api/app/Models/Orders/OrderItem.php` | ✅ | BelongsTo, fillable 추가 | + +### 2.3 Phase 3: 전환 로직 연동 (Service) + +| # | 작업 항목 | 파일 | 상태 | 비고 | +|---|----------|------|:----:|------| +| 3.1 | convertToOrder에 OrderNode 생성 로직 추가 | `api/app/Services/Quote/QuoteService.php` | ✅ | Phase 1.1 위에 구축 | +| 3.2 | syncFromQuote에 OrderNode 동기화 추가 | `api/app/Services/OrderService.php` | ✅ | 기존 items 삭제→재생성 패턴 동일 | +| 3.3 | 수주 상세 조회에 nodes eager loading | `api/app/Services/OrderService.php` | ✅ | show() 메소드 수정 | + +### 2.4 Phase 4: 프론트엔드 노드별 UI + +| # | 작업 항목 | 파일 | 상태 | 비고 | +|---|----------|------|:----:|------| +| 4.1 | OrderNode 타입 + 서버 액션 추가 | `react/src/components/orders/actions.ts` | ✅ | 타입 정의, API 호출 | +| 4.2 | 수주 상세 뷰 노드별 그룹 UI | `react/src/components/orders/OrderSalesDetailView.tsx` | ✅ | 트리/아코디언 형식 | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Phase 1: Quick Fix (convertToOrder 개소 파싱) +├── 1.1 syncFromQuote의 개소 파싱 로직을 공통 메소드로 추출 +├── 1.2 convertToOrder에서 공통 메소드 호출하여 $productMapping 전달 +└── 검증: 견적→수주 전환 후 order_items.floor_code/symbol_code 값 확인 + +Phase 2: DB 스키마 (order_nodes 테이블) +├── 2.1 order_nodes 마이그레이션 작성 +│ ├── 트리 구조: parent_id 자기참조 (nullable = 루트) +│ ├── 고정 코어: node_type, code, name, status_code, quantity, unit_price, total_price +│ └── 유연 확장: options JSON +├── 2.2 order_items에 order_node_id 컬럼 마이그레이션 작성 +├── 2.3 OrderNode 모델 생성 (BelongsToTenant, Auditable, SoftDeletes) +│ ├── 자기참조 관계: parent(), children() +│ └── items() HasMany +├── 2.4 Order 모델에 nodes() HasMany 관계 추가 +├── 2.5 OrderItem 모델에 node() BelongsTo 관계 추가 +└── 검증: php artisan migrate 성공, 트리 관계 정상 동작 + +Phase 3: 전환 로직 연동 +├── 3.1 convertToOrder에 OrderNode 생성 로직 삽입 +│ ├── calculation_inputs.items[] 순회하여 OrderNode (type:location) 생성 +│ ├── bomResults[]에서 금액 정보 매핑 +│ └── OrderItem 생성 시 order_node_id 연결 +├── 3.2 syncFromQuote에 OrderNode 동기화 추가 +│ ├── 기존 nodes 소프트삭제 → 신규 생성 +│ └── OrderItem 재생성 시 node 연결 +├── 3.3 수주 상세 조회에 nodes eager loading 추가 +└── 검증: API 호출로 노드 데이터 정상 반환 확인 + +Phase 4: 프론트엔드 UI +├── 4.1 타입 + 서버 액션 +│ ├── OrderNode 인터페이스 정의 +│ └── 수주 상세 조회 응답에 nodes 포함 +├── 4.2 수주 상세 뷰 노드별 그룹 UI +│ ├── 노드별 카드/아코디언 레이아웃 +│ ├── 노드 헤더 (유형/코드/이름/상태/금액) +│ ├── 노드 내 자재 테이블 +│ ├── 하위 노드 중첩 표시 (재귀 컴포넌트) +│ └── 역호환: nodes 없는 수주는 기존 플랫 테이블 유지 +└── 검증: 수주 상세 화면에서 노드별 그룹 표시 확인 +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 1: Quick Fix (변경 없음) + +#### 1.1 convertToOrder 개소 파싱 로직 추가 + +**현재 코드** (`QuoteService.php` Line 600-607): +```php +$serialIndex = 1; +foreach ($quote->items as $quoteItem) { + $orderItem = OrderItem::createFromQuoteItem($quoteItem, $order->id, $serialIndex); + $orderItem->created_by = $userId; + $orderItem->save(); + $serialIndex++; +} +``` + +**수정 코드**: +```php +$calculationInputs = $quote->calculation_inputs ?? []; +$productItems = $calculationInputs['items'] ?? []; + +$serialIndex = 1; +foreach ($quote->items as $quoteItem) { + $productMapping = $this->resolveLocationMapping($quoteItem, $productItems); + $orderItem = OrderItem::createFromQuoteItem($quoteItem, $order->id, $serialIndex, $productMapping); + $orderItem->created_by = $userId; + $orderItem->save(); + $serialIndex++; +} +``` + +#### 1.2 공통 메소드 추출 + +```php +/** + * 견적 품목에서 개소(층/부호) 정보 추출 + */ +private function resolveLocationMapping(QuoteItem $quoteItem, array $productItems): array +{ + $floorCode = null; + $symbolCode = null; + + // 1순위: note에서 파싱 ("4F FSS-01") + $note = trim($quoteItem->note ?? ''); + if ($note !== '') { + $parts = preg_split('/\s+/', $note, 2); + $floorCode = $parts[0] ?? null; + $symbolCode = $parts[1] ?? null; + } + + // 2순위: formula_source → calculation_inputs + if (empty($floorCode) && empty($symbolCode)) { + $productIndex = 0; + $formulaSource = $quoteItem->formula_source ?? ''; + if (preg_match('/product_(\d+)/', $formulaSource, $matches)) { + $productIndex = (int) $matches[1]; + } + if (isset($productItems[$productIndex])) { + $floorCode = $productItems[$productIndex]['floor'] ?? null; + $symbolCode = $productItems[$productIndex]['code'] ?? null; + } elseif (count($productItems) === 1) { + $floorCode = $productItems[0]['floor'] ?? null; + $symbolCode = $productItems[0]['code'] ?? null; + } + } + + return ['floor_code' => $floorCode, 'symbol_code' => $symbolCode]; +} +``` + +--- + +### 4.2 Phase 2: DB 스키마 + +#### 2.1 order_nodes 마이그레이션 + +```php +Schema::create('order_nodes', function (Blueprint $table) { + $table->id()->comment('ID'); + $table->foreignId('tenant_id')->comment('테넌트 ID'); + $table->foreignId('order_id')->comment('수주 ID'); + + // ---- 트리 구조 ---- + $table->foreignId('parent_id')->nullable()->comment('상위 노드 ID (NULL=루트)'); + + // ---- 고정 코어 (통계/집계용) ---- + $table->string('node_type', 50)->comment('노드 유형 (location, zone, floor, room, process...)'); + $table->string('code', 100)->comment('식별 코드'); + $table->string('name', 200)->comment('표시명'); + $table->string('status_code', 30)->default('PENDING') + ->comment('상태 (PENDING/CONFIRMED/IN_PRODUCTION/PRODUCED/SHIPPED/COMPLETED/CANCELLED)'); + $table->integer('quantity')->default(1)->comment('수량'); + $table->decimal('unit_price', 15, 2)->default(0)->comment('단가'); + $table->decimal('total_price', 15, 2)->default(0)->comment('합계'); + + // ---- 유연 확장 (유형별 상세) ---- + $table->json('options')->nullable()->comment('유형별 동적 속성 JSON'); + + // ---- 정렬 ---- + $table->integer('depth')->default(0)->comment('트리 깊이 (0=루트)'); + $table->integer('sort_order')->default(0)->comment('정렬 순서'); + + // ---- 감사 ---- + $table->foreignId('created_by')->nullable()->comment('생성자 ID'); + $table->foreignId('updated_by')->nullable()->comment('수정자 ID'); + $table->foreignId('deleted_by')->nullable()->comment('삭제자 ID'); + $table->timestamps(); + $table->softDeletes(); + + // ---- 인덱스 ---- + $table->index('tenant_id'); + $table->index('parent_id'); + $table->index(['order_id', 'depth', 'sort_order']); + $table->index(['order_id', 'node_type']); + $table->index(['tenant_id', 'node_type', 'status_code']); // 통계용 +}); +``` + +**통계 쿼리 예시**: +```sql +-- 1. 노드 유형별 수주 현황 (고정 컬럼만으로 가능) +SELECT node_type, status_code, COUNT(*), SUM(total_price) +FROM order_nodes WHERE tenant_id = 287 +GROUP BY node_type, status_code; + +-- 2. 경동 개소별 상세 (필요 시 JSON path) +SELECT code, name, total_price, + options->>'$.floor' AS floor, + options->>'$.symbol' AS symbol +FROM order_nodes +WHERE order_id = 123 AND node_type = 'location'; +``` + +#### 2.2 order_items에 order_node_id 추가 + +```php +Schema::table('order_items', function (Blueprint $table) { + $table->foreignId('order_node_id') + ->nullable() + ->after('order_id') + ->comment('수주 노드 ID (order_nodes)'); + $table->index('order_node_id'); +}); +``` + +#### 2.3 OrderNode 모델 + +```php +namespace App\Models\Orders; + +class OrderNode extends Model +{ + use Auditable, BelongsToTenant, SoftDeletes; + + protected $table = 'order_nodes'; + + // 상태 코드 (Order와 동일 체계) + public const STATUS_PENDING = 'PENDING'; + public const STATUS_CONFIRMED = 'CONFIRMED'; + public const STATUS_IN_PRODUCTION = 'IN_PRODUCTION'; + public const STATUS_PRODUCED = 'PRODUCED'; + public const STATUS_SHIPPED = 'SHIPPED'; + public const STATUS_COMPLETED = 'COMPLETED'; + public const STATUS_CANCELLED = 'CANCELLED'; + + protected $fillable = [ + 'tenant_id', 'order_id', 'parent_id', + 'node_type', 'code', 'name', + 'status_code', 'quantity', 'unit_price', 'total_price', + 'options', 'depth', 'sort_order', + 'created_by', 'updated_by', 'deleted_by', + ]; + + protected $casts = [ + 'quantity' => 'integer', + 'unit_price' => 'decimal:2', + 'total_price' => 'decimal:2', + 'options' => 'array', + 'depth' => 'integer', + ]; + + // ---- 트리 관계 ---- + public function parent(): BelongsTo + { + return $this->belongsTo(self::class, 'parent_id'); + } + + public function children(): HasMany + { + return $this->hasMany(self::class, 'parent_id')->orderBy('sort_order'); + } + + // ---- 비즈니스 관계 ---- + public function order(): BelongsTo + { + return $this->belongsTo(Order::class); + } + + public function items(): HasMany + { + return $this->hasMany(OrderItem::class, 'order_node_id'); + } + + // ---- 트리 헬퍼 ---- + public function isRoot(): bool + { + return $this->parent_id === null; + } + + public function isLeaf(): bool + { + return $this->children()->count() === 0; + } + + /** + * 하위 노드 포함 전체 트리 재귀 로드 + */ + public function scopeWithRecursiveChildren($query) + { + return $query->with(['children' => function ($q) { + $q->orderBy('sort_order')->with('children', 'items'); + }, 'items']); + } +} +``` + +#### 2.4-2.5 기존 모델 수정 + +**Order 모델**: +```php +public function nodes(): HasMany +{ + return $this->hasMany(OrderNode::class)->orderBy('depth')->orderBy('sort_order'); +} + +public function rootNodes(): HasMany +{ + return $this->hasMany(OrderNode::class)->whereNull('parent_id')->orderBy('sort_order'); +} +``` + +**OrderItem 모델** - fillable + 관계: +```php +// fillable에 추가 +'order_node_id', + +// 관계 +public function node(): BelongsTo +{ + return $this->belongsTo(OrderNode::class, 'order_node_id'); +} +``` + +--- + +### 4.3 Phase 3: 전환 로직 연동 + +#### 3.1 convertToOrder OrderNode 생성 + +**수정 위치**: `QuoteService::convertToOrder()` (Line 590~623) + +```php +return DB::transaction(function () use ($quote, $userId, $tenantId) { + $orderNo = $this->generateOrderNumber($tenantId); + $order = Order::createFromQuote($quote, $orderNo); + $order->created_by = $userId; + $order->save(); + + // ---- OrderNode 생성 (개소별) ---- + $calculationInputs = $quote->calculation_inputs ?? []; + $productItems = $calculationInputs['items'] ?? []; + $bomResults = $calculationInputs['bomResults'] ?? []; + + $nodeMap = []; // productIndex → OrderNode + foreach ($productItems as $idx => $locItem) { + $bomResult = $bomResults[$idx] ?? null; + $grandTotal = $bomResult['grand_total'] ?? 0; + $qty = (int) ($locItem['quantity'] ?? 1); + $floor = $locItem['floor'] ?? ''; + $symbol = $locItem['code'] ?? ''; + + $node = OrderNode::create([ + 'tenant_id' => $tenantId, + 'order_id' => $order->id, + 'parent_id' => null, // 루트 노드 (경동은 1-depth) + 'node_type' => 'location', + 'code' => trim("{$floor}-{$symbol}", '-') ?: "LOC-{$idx}", + 'name' => trim("{$floor} {$symbol}") ?: "개소 ".($idx + 1), + 'status_code' => OrderNode::STATUS_PENDING, + 'quantity' => $qty, + 'unit_price' => $grandTotal, + 'total_price' => $grandTotal * $qty, + 'options' => [ + 'floor' => $floor, + 'symbol' => $symbol, + 'product_code' => $locItem['productCode'] ?? null, + 'product_name' => $locItem['productName'] ?? null, + 'open_width' => $locItem['openWidth'] ?? null, + 'open_height' => $locItem['openHeight'] ?? null, + 'guide_rail_type' => $locItem['guideRailType'] ?? null, + 'motor_power' => $locItem['motorPower'] ?? null, + 'controller' => $locItem['controller'] ?? null, + 'wing_size' => $locItem['wingSize'] ?? null, + 'inspection_fee' => $locItem['inspectionFee'] ?? null, + 'bom_result' => $bomResult, + ], + 'depth' => 0, + 'sort_order' => $idx, + 'created_by' => $userId, + ]); + $nodeMap[$idx] = $node; + } + + // ---- OrderItem 생성 (노드 연결) ---- + $serialIndex = 1; + foreach ($quote->items as $quoteItem) { + $mapping = $this->resolveLocationMapping($quoteItem, $productItems); + $locIdx = $this->resolveLocationIndex($quoteItem, $productItems); + + $productMapping = array_merge($mapping, [ + 'order_node_id' => isset($nodeMap[$locIdx]) ? $nodeMap[$locIdx]->id : null, + ]); + + $orderItem = OrderItem::createFromQuoteItem($quoteItem, $order->id, $serialIndex, $productMapping); + $orderItem->created_by = $userId; + $orderItem->save(); + $serialIndex++; + } + + // 합계 재계산 + 견적 상태 변경 (기존 로직 유지) + $order->load('items'); + $order->recalculateTotals(); + $order->save(); + + $quote->update([ + 'status' => Quote::STATUS_CONVERTED, + 'order_id' => $order->id, + 'updated_by' => $userId, + ]); + + return $quote->refresh()->load(['items', 'client', 'order']); +}); +``` + +**resolveLocationIndex 헬퍼**: +```php +private function resolveLocationIndex(QuoteItem $quoteItem, array $productItems): int +{ + $formulaSource = $quoteItem->formula_source ?? ''; + if (preg_match('/product_(\d+)/', $formulaSource, $matches)) { + return (int) $matches[1]; + } + + $note = trim($quoteItem->note ?? ''); + if ($note !== '') { + $parts = preg_split('/\s+/', $note, 2); + $floor = $parts[0] ?? ''; + $code = $parts[1] ?? ''; + foreach ($productItems as $idx => $item) { + if (($item['floor'] ?? '') === $floor && ($item['code'] ?? '') === $code) { + return $idx; + } + } + } + + return 0; +} +``` + +#### 3.2 syncFromQuote OrderNode 동기화 + +**수정 위치**: `OrderService::syncFromQuote()` (Line 559~659) + +기존 `$order->items()->delete()` 다음에: +```php +// 기존 노드 삭제 후 재생성 +$order->nodes()->delete(); + +// OrderNode 생성 (convertToOrder와 동일 로직) +$nodeMap = []; +foreach ($productItems as $idx => $locItem) { + // ... (convertToOrder와 동일) + $nodeMap[$idx] = $node; +} + +// OrderItem 생성 시 order_node_id 연결 +foreach ($quote->items as $index => $quoteItem) { + $locIdx = $this->resolveLocationIndex($quoteItem, $productItems); + $order->items()->create([ + // ... 기존 필드 ... + 'order_node_id' => $nodeMap[$locIdx]->id ?? null, + ]); +} +``` + +#### 3.3 수주 상세 조회 nodes eager loading + +```php +$order = Order::where('tenant_id', $tenantId) + ->with([ + 'items', + 'rootNodes' => function ($q) { + $q->withRecursiveChildren(); // 재귀 트리 로드 + }, + 'client', + 'quote', + ]) + ->find($id); +``` + +--- + +### 4.4 Phase 4: 프론트엔드 노드별 UI + +#### 4.1 타입 + 서버 액션 + +**OrderNode 타입** (`react/src/components/orders/actions.ts`): +```typescript +export interface OrderNode { + id: number; + parentId: number | null; + nodeType: string; // 'location', 'zone', 'floor', 'room', 'process'... + code: string; + name: string; + statusCode: string; + quantity: number; + unitPrice: number; + totalPrice: number; + options: Record | null; // 유형별 동적 속성 + depth: number; + sortOrder: number; + children: OrderNode[]; // 하위 노드 (재귀) + items: OrderItem[]; // 해당 노드의 자재 +} + +export interface OrderDetail extends Order { + nodes: OrderNode[]; // 루트 노드 배열 (children 재귀 포함) +} +``` + +#### 4.2 수주 상세 뷰 노드별 그룹 UI + +**레이아웃 (경동 1-depth 예시)**: +``` +┌─ 수주 기본 정보 ────────────────────────────────────────┐ +│ 수주번호: ORD-260206-001 | 현장명: 삼성 빌딩 신축 │ +│ 거래처: 삼성물산 | 총금액: 15,000,000원 │ +└─────────────────────────────────────────────────────────┘ + +┌─ 구조 (3개 노드) ──────────────────────────────────────┐ +│ │ +│ ┌─ [location] 1F FSS-01 ──────────────────────────┐ │ +│ │ KSS01(고정스크린) | 5000×3000 | 수량:1 │ │ +│ │ 상태: [PENDING ▾] | 금액: 1,250,000원 │ │ +│ ├──────────────────────────────────────────────────┤ │ +│ │ # | 품목코드 | 품명 | 수량 | 단가 | 금액 │ │ +│ │ 1 | MT-SUS-01 | 슬랫 | 15.5 | 12,000 | 186K │ │ +│ │ 소계: 1,250,000원 │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +│ ┌─ [location] 2F SD-02 ──────────────────────────┐ │ +│ │ ... │ │ +│ └─────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +**재귀 컴포넌트 (N-depth)**: +```typescript +function OrderNodeCard({ node, depth = 0 }: { node: OrderNode; depth?: number }) { + return ( +
    + {/* 노드 헤더 */} + + + {/* 해당 노드의 자재 테이블 */} + {node.items.length > 0 && } + + {/* 하위 노드 재귀 렌더링 */} + {node.children.map(child => ( + + ))} +
    + ); +} +``` + +**역호환**: +```typescript +{order.nodes && order.nodes.length > 0 ? ( + order.nodes.map(node => ) +) : ( + +)} +``` + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | order_nodes 테이블 생성 | N-depth 자기참조 트리 + 하이브리드 JSON | DB 스키마 | ⚠️ 컨펌 필요 | +| 2 | order_items에 order_node_id 추가 | nullable FK 컬럼 | DB 스키마 | ⚠️ 컨펌 필요 | +| 3 | 노드 상태 코드 체계 | Order와 동일 체계 사용 | 비즈니스 로직 | ⚠️ 컨펌 필요 | +| 4 | 경동 node_type 값 | "location" 사용 | 비즈니스 로직 | ⚠️ 컨펌 필요 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-06 | - | 문서 초안 작성 (order_locations 전용 설계) | - | - | +| 2026-02-06 | 아키텍처 변경 | order_locations → order_nodes (N-depth 트리 + 하이브리드) | - | ✅ 사용자 승인 | + +--- + +## 7. 참고 문서 + +- **견적 시스템 분석**: `docs/features/quotes/README.md` +- **DB 스키마 규칙**: `docs/specs/database-schema.md` +- **API 개발 규칙**: `docs/standards/api-rules.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` + +### 핵심 소스 파일 + +| 파일 | 역할 | 핵심 라인 | +|------|------|----------| +| `api/app/Services/Quote/QuoteService.php` | 견적→수주 전환 | L574-623 (`convertToOrder`) | +| `api/app/Services/OrderService.php` | 수주 동기화 | L559-659 (`syncFromQuote`) | +| `api/app/Models/Orders/Order.php` | 수주 모델 | L23-59 (상태 코드) | +| `api/app/Models/Orders/OrderItem.php` | 수주 품목 모델 | L162-190 (`createFromQuoteItem`) | +| `react/src/components/orders/actions.ts` | 수주 프론트 타입 | L281-300 (OrderItem) | +| `react/src/components/orders/OrderSalesDetailView.tsx` | 수주 상세 뷰 | L386-424 (테이블) | +| `react/src/components/quotes/types.ts` | 견적 타입 | L661-684 (LocationItem) | + +--- + +## 8. 세션 및 메모리 관리 정책 + +### 8.1 세션 시작 시 + +``` +1. read_memory("order-nodes-state") → 진행 상태 파악 +2. 이 문서의 "📍 현재 진행 상태" 섹션 확인 +3. 마지막 완료 작업 확인 후 다음 작업 착수 +``` + +### 8.2 Serena 메모리 구조 + +- `order-nodes-state`: `{ phase, progress, next_step, last_decision }` +- `order-nodes-snapshot`: 현재까지의 코드 변경점 요약 +- `order-nodes-active-symbols`: 수정 중인 파일/함수 목록 + +--- + +## 9. 검증 결과 + +### 9.1 테스트 케이스 + +| # | 시나리오 | 예상 결과 | 실제 결과 | 상태 | +|---|---------|----------|----------|------| +| 1 | 견적 3개소 → 수주 전환 | order_nodes 3행(type:location) 생성, 각 order_items에 node_id 연결 | - | ⏳ | +| 2 | 수주 상세 조회 | rootNodes + children 재귀 + items eager loading 정상 | - | ⏳ | +| 3 | 견적 수정 → 수주 동기화 | 기존 nodes 삭제 후 재생성, items 재연결 | - | ⏳ | +| 4 | 기존 수주 (nodes 없음) 조회 | 기존 플랫 테이블 정상 표시, 에러 없음 | - | ⏳ | +| 5 | 프론트 노드별 그룹 표시 | 노드 카드 내 자재 테이블, 역호환 플랫 뷰 | - | ⏳ | +| 6 | 통계 쿼리 성능 | 고정 컬럼(node_type, status, total_price) 기반 GROUP BY 정상 | - | ⏳ | + +### 9.2 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 전환 시 order_nodes 생성됨 | ⏳ | Phase 2+3 | +| N-depth 트리 구조 지원 | ⏳ | Phase 2 (parent_id 자기참조) | +| order_items에 order_node_id 연결됨 | ⏳ | Phase 3 | +| 프론트 노드별 그룹 표시 | ⏳ | Phase 4 | +| 기존 수주 역호환 정상 | ⏳ | Phase 4 | +| 통계 쿼리가 고정 컬럼으로 가능 | ⏳ | Phase 2 (인덱스) | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 범용 N-depth 트리 + 통계 친화 하이브리드 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 9.2 (6개 기준) | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 2 (13개 작업 항목) | +| 4 | 의존성이 명시되어 있는가? | ✅ | Phase 1→2→3→4 순서 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 7 (라인번호 포함) | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 3+4 (코드 포함) | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9.1 (6개 테스트 케이스) | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 코드/파일/라인 명시 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경, 1.2 목표 | +| Q2. 왜 하이브리드 구조를 선택했는가? | ✅ | 1.3 아키텍처 결정 | +| Q3. 어디서부터 시작해야 하는가? | ✅ | 📍 현재 진행 상태 | +| Q4. 어떤 파일을 수정해야 하는가? | ✅ | 2. 대상 범위 | +| Q5. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /plan 스킬 + Sequential Thinking MCP로 생성되었습니다.* +*아키텍처: N-depth 트리(order_nodes) + 하이브리드(고정 코어 + options JSON)* \ No newline at end of file diff --git a/plans/archive/order-management-plan.md b/plans/archive/order-management-plan.md new file mode 100644 index 0000000..ecb5f87 --- /dev/null +++ b/plans/archive/order-management-plan.md @@ -0,0 +1,335 @@ +# 수주관리 (Order Management) API 연동 계획 + +> **작성일**: 2025-01-08 +> **목적**: 수주관리 페이지 Mock 데이터 → API 연동 +> **상태**: ✅ Phase 3 완료 (100% 완료) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 버그 수정 - 목록 페이지 서버 에러 해결 (3건) | +| **다음 작업** | 완료 | +| **진행률** | 3/3 Phase (100%) + 버그 수정 완료 | +| **마지막 업데이트** | 2025-01-09 | +| **커밋** | 버그 수정 커밋 완료 | + +--- + +## 1. 개요 + +### 1.1 배경 +수주관리 페이지는 프론트엔드 UI가 구현되어 있으나, **하드코딩된 Mock 데이터(SAMPLE_ORDERS)**를 사용 중입니다. +실제 비즈니스 운영을 위해 API 연동이 필요합니다. + +### 1.2 현재 구현 상태 분석 + +#### API (Laravel) - ✅ Phase 1 완료 +| 구성요소 | 파일 경로 | 상태 | +|---------|----------|------| +| Model | `api/app/Models/Orders/Order.php` | ✅ 존재 | +| Model | `api/app/Models/Orders/OrderItem.php` | ✅ 존재 | +| Model | `api/app/Models/Orders/OrderHistory.php` | ✅ 존재 | +| Model | `api/app/Models/Orders/OrderVersion.php` | ✅ 존재 | +| Model | `api/app/Models/Orders/OrderItemComponent.php` | ✅ 존재 | +| Controller | `api/app/Http/Controllers/Api/V1/OrderController.php` | ✅ **완료** | +| Service | `api/app/Services/OrderService.php` | ✅ **완료** | +| FormRequest | `api/app/Http/Requests/Order/*.php` | ✅ **완료** (3개) | +| Route | `/api/v1/orders` | ✅ **완료** (7개 엔드포인트) | +| Swagger | `api/app/Swagger/v1/OrderApi.php` | ✅ **완료** | + +#### Frontend (React/Next.js) - ✅ Phase 2 완료 +| 구성요소 | 파일 경로 | 상태 | +|---------|----------|------| +| 목록 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/page.tsx` | ✅ API 연동 | +| 등록 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/new/page.tsx` | ✅ API 연동 | +| 상세 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx` | ✅ API 연동 | +| 수정 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/[id]/edit/page.tsx` | ✅ API 연동 | +| 생산지시 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx` | ✅ 완료 | +| 등록 컴포넌트 | `react/src/components/orders/OrderRegistration.tsx` | ✅ 완료 | +| 견적선택 다이얼로그 | `react/src/components/orders/QuotationSelectDialog.tsx` | ✅ 완료 | +| 품목추가 다이얼로그 | `react/src/components/orders/ItemAddDialog.tsx` | ✅ 완료 | +| **actions.ts** | `react/src/components/orders/actions.ts` | ✅ **완료** | + +### 1.3 연관관계 +``` +┌─────────────────┐ ┌─────────────────┐ +│ Quote │────── quote_id ────▶│ Order │ +│ (견적서) │ │ (수주) │ +└─────────────────┘ └─────────────────┘ + │ + │ sales_order_id + ▼ + ┌─────────────────┐ + │ WorkOrder │ + │ (작업지시) │ + └─────────────────┘ +``` + +### 1.4 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 필드 추가/변경, API 엔드포인트 추가 | 불필요 | +| ⚠️ 컨펌 필요 | 테이블 구조 변경, 기존 API 수정 | **필수** | +| 🔴 금지 | 기존 Order 모델 구조 변경 | 별도 협의 | + +--- + +## 2. 대상 범위 + +### Phase 1: API 개발 (✅ 완료) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | OrderController 생성 | ✅ | CRUD + 상태관리 (7개 메서드) | +| 1.2 | OrderService 생성 | ✅ | 비즈니스 로직 (index, stats, show, store, update, destroy, updateStatus) | +| 1.3 | FormRequest 생성 | ✅ | Store, Update, UpdateStatus (3개) | +| 1.4 | API 라우트 등록 | ✅ | routes/api.php (7개 엔드포인트) | +| 1.5 | Swagger 문서 작성 | ✅ | OrderApi.php (스키마 8개) | + +### Phase 2: Frontend 연동 (✅ 완료) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | actions.ts 생성 | ✅ | API 호출 함수 + 타입 정의 + 변환 함수 | +| 2.2 | 목록 페이지 연동 | ✅ | getOrders(), getOrderStats() 연동 | +| 2.3 | 상세 페이지 연동 | ✅ | getOrderById() 연동 + 타입 오류 수정 | +| 2.4 | 등록 페이지 연동 | ✅ | createOrder() 연동 | +| 2.5 | 수정 페이지 연동 | ✅ | updateOrder() 연동 + 타입 오류 수정 | + +### Phase 3: 고급 기능 (✅ 완료) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | 견적서 → 수주 변환 | ✅ | QuotationSelectDialog + createOrderFromQuote() | +| 3.2 | 생산지시 생성 연동 | ✅ | createProductionOrder() + production-order 페이지 | +| 3.3 | 상태 흐름 관리 | ✅ | 수주확정 다이얼로그 + updateOrderStatus() | + +--- + +## 3. API 엔드포인트 설계 + +### 3.1 REST API + +| Method | Endpoint | 설명 | 우선순위 | +|--------|----------|------|:--------:| +| GET | `/api/v1/orders` | 수주 목록 조회 (페이징/필터) | 🔴 | +| GET | `/api/v1/orders/stats` | 수주 통계 | 🔴 | +| GET | `/api/v1/orders/{id}` | 수주 상세 조회 | 🔴 | +| POST | `/api/v1/orders` | 수주 생성 | 🔴 | +| PUT | `/api/v1/orders/{id}` | 수주 수정 | 🟡 | +| DELETE | `/api/v1/orders/{id}` | 수주 삭제 | 🟡 | +| PATCH | `/api/v1/orders/{id}/status` | 상태 변경 | 🟡 | +| POST | `/api/v1/orders/{id}/production-order` | 생산지시 생성 | 🟢 | +| POST | `/api/v1/orders/from-quote/{quoteId}` | 견적→수주 변환 | 🟢 | + +### 3.2 데이터 스키마 + +#### Order (수주) - 기존 모델 기반 +```typescript +interface Order { + id: number; + tenantId: number; + quoteId?: number; // 원본 견적 + orderNo: string; // 수주번호 (KD-TS-YYMMDD-NN) + orderTypeCode: 'ORDER' | 'PURCHASE'; + statusCode: 'DRAFT' | 'CONFIRMED' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED'; + clientId?: number; + clientName?: string; + siteName?: string; // 현장명 + quantity: number; + supplyAmount: number; + taxAmount: number; + totalAmount: number; + deliveryDate?: Date; + deliveryMethodCode?: string; + memo?: string; + createdBy?: number; + updatedBy?: number; + createdAt: Date; + updatedAt: Date; + // Relations + items?: OrderItem[]; + client?: Client; +} +``` + +#### OrderItem (수주 품목) +```typescript +interface OrderItem { + id: number; + orderId: number; + itemId?: number; + itemName: string; + specification?: string; + quantity: number; + unit?: string; + unitPrice: number; + supplyAmount: number; + taxAmount: number; + totalAmount: number; + sortOrder: number; +} +``` + +--- + +## 4. 작업 절차 + +### Step 1: API 개발 (Backend) + +``` +1. OrderService 생성 + ├── index(): 목록 조회 (페이징, 필터링) + ├── show(): 상세 조회 + ├── store(): 생성 + ├── update(): 수정 + ├── destroy(): 삭제 + ├── updateStatus(): 상태 변경 + ├── stats(): 통계 조회 + └── createFromQuote(): 견적→수주 변환 + +2. OrderController 생성 + ├── FormRequest DI + └── ApiResponse::handle() 사용 + +3. FormRequest 생성 + ├── StoreOrderRequest + └── UpdateOrderRequest + +4. 라우트 등록 + └── Route::prefix('orders')->group(...) + +5. Swagger 문서 작성 + └── app/Swagger/v1/OrderApi.php +``` + +### Step 2: Frontend 연동 + +``` +1. actions.ts 생성 + ├── getOrders(): 목록 조회 + ├── getOrderById(): 상세 조회 + ├── createOrder(): 생성 + ├── updateOrder(): 수정 + ├── deleteOrder(): 삭제 + ├── updateOrderStatus(): 상태 변경 + └── getOrderStats(): 통계 조회 + +2. 페이지별 연동 + ├── page.tsx: SAMPLE_ORDERS → getOrders() + ├── [id]/page.tsx: Mock → getOrderById() + ├── new/page.tsx: Mock → createOrder() + └── [id]/edit/page.tsx: Mock → updateOrder() +``` + +--- + +## 5. 의존성 + +### 5.1 필수 선행 작업 +- **없음** - Order 모델 이미 존재, 바로 작업 가능 + +### 5.2 연관 기능 (선택적) +- **견적관리 (Quote)**: 견적→수주 변환 시 필요 +- **거래처관리 (Client)**: 거래처 연동 +- **품목관리 (Item)**: 품목 마스터 연동 + +### 5.3 후속 연동 +- **작업지시 (WorkOrder)**: 생산지시 생성 시 `sales_order_id` 연결 +- **출하관리**: 수주 완료 후 출하 처리 + +--- + +## 6. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **API 규칙**: `docs/standards/api-rules.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **DB 스키마**: `docs/specs/database-schema.md` +- **Swagger 가이드**: `docs/guides/swagger-guide.md` + +### 참고 코드 +- **작업지시 API (참고용)**: `api/app/Http/Controllers/Api/V1/WorkOrderController.php` +- **공정관리 actions.ts (참고용)**: `react/src/components/process-management/actions.ts` + +--- + +## 7. 검증 방법 + +### 7.1 API 테스트 +```bash +# 목록 조회 +curl -X GET "http://api.sam.kr/api/v1/orders" -H "X-Api-Key: ..." + +# 상세 조회 +curl -X GET "http://api.sam.kr/api/v1/orders/1" -H "X-Api-Key: ..." + +# 통계 조회 +curl -X GET "http://api.sam.kr/api/v1/orders/stats" -H "X-Api-Key: ..." +``` + +### 7.2 성공 기준 +| 기준 | 측정 방법 | +|------|----------| +| API CRUD 동작 | Swagger UI 테스트 통과 | +| 목록 페이지 | 실제 데이터 표시 | +| 상세 페이지 | 수주 정보 정상 표시 | +| 등록/수정 | 데이터 저장 및 조회 | +| 상태 변경 | DRAFT → CONFIRMED 전환 | + +--- + +## 8. 자기완결성 점검 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | Mock → API 연동 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 7 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-3 단계별 정의 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 선행 작업 없음 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 모든 경로 검증됨 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | Step 1-2 상세 정의 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | curl 테스트 + 기준 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 파일/엔드포인트 명시 | + +--- + +## 9. 버그 수정 이력 + +### 2025-01-09: 목록 페이지 서버 에러 수정 + +| # | 파일 | 문제 | 수정 내용 | +|---|------|------|----------| +| 1 | `react/.../page.tsx:120` | API 응답 데이터 구조 불일치 | `ordersResult.data` → `ordersResult.data.items` | +| 2 | `api/.../OrderService.php:113` | Quote 필드명 오류 | `quote:id,quote_no,site_name` → `quote:id,quote_number,site_name` | +| 3 | `react/.../actions.ts:384` | Quote 필드명 오류 | `apiData.quote?.quote_no` → `apiData.quote?.quote_number` | + +**원인 분석:** +- `getOrders()` 함수는 `{ items: Order[], total, page, totalPages }` 구조를 반환하나, 페이지에서 `ordersResult.data`를 직접 사용하여 타입 불일치 발생 +- Quote 모델의 필드명이 `quote_number`인데 `quote_no`로 잘못 참조 + +**영향 범위:** +- 수주 목록 페이지 접근 시 서버 에러 발생 +- 견적 연동 수주의 견적번호 표시 오류 + +### 2025-01-09: 수주 등록 페이지 거래처 API 연동 + +| # | 파일 | 변경 내용 | +|---|------|----------| +| 1 | `react/.../OrderRegistration.tsx` | `SAMPLE_CLIENTS` 하드코딩 제거 | +| 2 | `react/.../OrderRegistration.tsx` | `useClientList` 훅으로 실제 API 연동 | +| 3 | `react/.../OrderRegistration.tsx` | 로딩 상태 처리 ("불러오는 중...") | +| 4 | `react/.../OrderRegistration.tsx` | 견적 선택 시 발주처 필드 비활성화 | + +**개선 내용:** +- 발주처(거래처) 드롭다운이 `/api/proxy/clients` API에서 실제 데이터 조회 +- 견적 선택 시 발주처가 자동 설정되고 필드 비활성화 +- 로딩 중 "불러오는 중..." 플레이스홀더 표시 + +--- + +*이 문서는 독립 세션에서 바로 작업 시작 가능하도록 설계되었습니다.* \ No newline at end of file diff --git a/plans/archive/order-workorder-shipment-integration-plan.md b/plans/archive/order-workorder-shipment-integration-plan.md new file mode 100644 index 0000000..105c5c3 --- /dev/null +++ b/plans/archive/order-workorder-shipment-integration-plan.md @@ -0,0 +1,659 @@ +# 수주-작업지시-출하 하이브리드 연동 구조 구현 계획 + +> **작성일**: 2025-01-19 +> **목적**: Order → WorkOrder → Shipment 간 FK 연결 강화 및 상태 동기화 로직 구현 +> **기준 문서**: `api/app/Models/Orders/Order.php`, `api/app/Models/Production/WorkOrder.php`, `api/app/Models/Tenants/Shipment.php` +> **상태**: 📋 계획 수립 완료 (Serena ID: order-integration-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4: 작업완료 시 자동 출하 생성 기능 구현 | +| **다음 작업** | ✅ 모든 Phase 완료 | +| **진행률** | 4/4 Phase (100%) | +| **마지막 업데이트** | 2025-01-19 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 SAM 시스템은 수주(Order), 작업지시(WorkOrder), 출하(Shipment)가 독립적으로 운영되고 있습니다. + +**현재 문제점:** +- `shipments` 테이블에 `work_order_id` FK가 없음 +- 작업 완료 시 출하로 자동 연결되지 않음 +- Order의 전체 진행 상태를 추적할 수 없음 +- 데이터 정합성 보장이 어려움 + +**목표:** +- 하이브리드 마스터-디테일 구조로 전환 +- `orders.status_code`로 전체 진행 상태 추적 +- 각 단계별 상태 변경 시 연관 테이블 자동 동기화 + +### 1.2 목표 구조 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 목표 구조 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ orders (마스터) │ +│ ├─ status_code: 전체 진행상태 추적 │ +│ │ DRAFT → CONFIRMED → IN_PRODUCTION → PRODUCED │ +│ │ → SHIPPING → SHIPPED → COMPLETED │ +│ │ │ +│ ├──(1:N)──▶ work_orders (생산 상세) │ +│ │ ├─ sales_order_id FK ✅ (기존) │ +│ │ └─ status: 생산 프로세스 상태 │ +│ │ │ +│ └──(1:N)──▶ shipments (출하 상세) │ +│ ├─ order_id FK ✅ (기존) │ +│ ├─ work_order_id FK 🆕 (신규 추가) │ +│ └─ status: 출하 프로세스 상태 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. orders.status_code = 전체 프로세스의 Single Source of Truth │ +│ 2. 하위 테이블(work_orders, shipments)은 상세 정보만 관리 │ +│ 3. 상태 변경 시 상위 테이블 자동 동기화 │ +│ 4. 기존 데이터 호환성 유지 (work_order_id는 nullable) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.4 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 모델 관계 추가, 상수 추가, 문서 수정 | 불필요 | +| ⚠️ 컨펌 필요 | 마이그레이션, 서비스 로직 변경, 상태 동기화 | **필수** | +| 🔴 금지 | 기존 테이블 구조 파괴적 변경, 기존 API 삭제 | 별도 협의 | + +### 1.5 준수 규칙 + +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `CLAUDE.md` - SAM API Development Rules + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: DB 스키마 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | `shipments` 테이블에 `work_order_id` FK 추가 마이그레이션 | ⏳ | nullable, index 포함 | + +### 2.2 Phase 2: 모델 관계 추가 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | Order 모델에 `shipments()` HasMany 관계 추가 | ⏳ | | +| 2.2 | WorkOrder 모델에 `shipments()` HasMany 관계 추가 | ⏳ | | +| 2.3 | Shipment 모델에 `workOrder()` BelongsTo 관계 추가 | ⏳ | | +| 2.4 | Shipment 모델에 `work_order_id` fillable 추가 | ⏳ | | + +### 2.3 Phase 3: Order 상태 확장 및 동기화 로직 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | Order 모델에 생산/출하 관련 상태 상수 추가 | ⏳ | IN_PRODUCTION, PRODUCED, SHIPPING, SHIPPED | +| 3.2 | WorkOrderService에 Order 상태 동기화 로직 추가 | ⏳ | 상태 변경 시 Order.status_code 업데이트 | +| 3.3 | ShipmentService에 Order 상태 동기화 로직 추가 | ⏳ | 상태 변경 시 Order.status_code 업데이트 | + +### 2.4 Phase 4: 연동 기능 (선택) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | ShipmentService.store()에 work_order_id 연결 로직 추가 | ⏳ | 출하 생성 시 WorkOrder 선택 가능 | +| 4.2 | WorkOrder 완료 시 Shipment 자동 생성 옵션 | ⏳ | 선택적 기능 | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Phase 1: DB 스키마 수정 +└── 1.1 마이그레이션 생성 및 실행 + ├── add_work_order_id_to_shipments_table.php + ├── work_order_id FK (nullable) + └── index 추가 + +Phase 2: 모델 관계 추가 +├── 2.1 Order.php - shipments() HasMany +├── 2.2 WorkOrder.php - shipments() HasMany +├── 2.3 Shipment.php - workOrder() BelongsTo +└── 2.4 Shipment.php - fillable에 work_order_id 추가 + +Phase 3: 상태 동기화 +├── 3.1 Order.php - 상태 상수 확장 +│ ├── STATUS_IN_PRODUCTION = 'IN_PRODUCTION' +│ ├── STATUS_PRODUCED = 'PRODUCED' +│ ├── STATUS_SHIPPING = 'SHIPPING' +│ └── STATUS_SHIPPED = 'SHIPPED' +├── 3.2 WorkOrderService.php - syncOrderStatus() 메서드 추가 +│ ├── in_progress → Order: IN_PRODUCTION +│ ├── completed → Order: PRODUCED +│ └── shipped → Order: (Shipment 생성 시) +└── 3.3 ShipmentService.php - syncOrderStatus() 메서드 추가 + ├── scheduled/ready → Order: SHIPPING (첫 출하 생성 시) + └── completed → Order: SHIPPED (모든 출하 완료 시) + +Phase 4: 연동 기능 (선택) +├── 4.1 ShipmentService.store() - work_order_id 파라미터 추가 +└── 4.2 WorkOrderService.updateStatus() - 자동 Shipment 생성 옵션 +``` + +### 3.2 상태 흐름도 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 전체 상태 흐름 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ [Order] │ +│ DRAFT ──▶ CONFIRMED ──▶ IN_PRODUCTION ──▶ PRODUCED │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ WorkOrder WorkOrder WorkOrder │ +│ 생성 in_progress completed │ +│ │ │ +│ ▼ │ +│ ──────────────────────▶ SHIPPING ──▶ SHIPPED ──▶ COMPLETED │ +│ │ │ │ +│ ▼ ▼ │ +│ Shipment Shipment │ +│ 생성 completed │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 1: DB 스키마 수정 + +#### 1.1 마이그레이션: shipments 테이블에 work_order_id 추가 + +**파일**: `api/database/migrations/2025_01_19_XXXXXX_add_work_order_id_to_shipments_table.php` + +```php +foreignId('work_order_id') + ->nullable() + ->after('order_id') + ->comment('작업지시 ID'); + + $table->index(['tenant_id', 'work_order_id']); + }); + } + + public function down(): void + { + Schema::table('shipments', function (Blueprint $table) { + $table->dropIndex(['tenant_id', 'work_order_id']); + $table->dropColumn('work_order_id'); + }); + } +}; +``` + +--- + +### 4.2 Phase 2: 모델 관계 추가 + +#### 2.1 Order 모델 - shipments() 관계 + +**파일**: `api/app/Models/Orders/Order.php` + +```php +use App\Models\Tenants\Shipment; + +/** + * 출하 목록 + */ +public function shipments(): HasMany +{ + return $this->hasMany(Shipment::class, 'order_id'); +} +``` + +#### 2.2 WorkOrder 모델 - shipments() 관계 + +**파일**: `api/app/Models/Production/WorkOrder.php` + +```php +use App\Models\Tenants\Shipment; + +/** + * 출하 목록 + */ +public function shipments(): HasMany +{ + return $this->hasMany(Shipment::class); +} +``` + +#### 2.3-2.4 Shipment 모델 수정 + +**파일**: `api/app/Models/Tenants/Shipment.php` + +```php +use App\Models\Production\WorkOrder; + +// fillable에 추가 +protected $fillable = [ + // ... 기존 필드들 + 'work_order_id', // 추가 +]; + +// casts에 추가 +protected $casts = [ + // ... 기존 캐스트들 + 'work_order_id' => 'integer', // 추가 +]; + +/** + * 작업지시 관계 + */ +public function workOrder(): BelongsTo +{ + return $this->belongsTo(WorkOrder::class); +} +``` + +--- + +### 4.3 Phase 3: Order 상태 확장 및 동기화 로직 + +#### 3.1 Order 모델 - 상태 상수 확장 + +**파일**: `api/app/Models/Orders/Order.php` + +```php +// 기존 상태 +public const STATUS_DRAFT = 'DRAFT'; +public const STATUS_CONFIRMED = 'CONFIRMED'; +public const STATUS_IN_PROGRESS = 'IN_PROGRESS'; +public const STATUS_COMPLETED = 'COMPLETED'; +public const STATUS_CANCELLED = 'CANCELLED'; + +// 신규 상태 추가 +public const STATUS_IN_PRODUCTION = 'IN_PRODUCTION'; // 생산중 +public const STATUS_PRODUCED = 'PRODUCED'; // 생산완료 +public const STATUS_SHIPPING = 'SHIPPING'; // 출하중 +public const STATUS_SHIPPED = 'SHIPPED'; // 출하완료 + +/** + * 전체 상태 목록 + */ +public const STATUSES = [ + self::STATUS_DRAFT, + self::STATUS_CONFIRMED, + self::STATUS_IN_PRODUCTION, + self::STATUS_PRODUCED, + self::STATUS_SHIPPING, + self::STATUS_SHIPPED, + self::STATUS_COMPLETED, + self::STATUS_CANCELLED, +]; + +/** + * 상태 라벨 + */ +public const STATUS_LABELS = [ + self::STATUS_DRAFT => '임시저장', + self::STATUS_CONFIRMED => '확정', + self::STATUS_IN_PRODUCTION => '생산중', + self::STATUS_PRODUCED => '생산완료', + self::STATUS_SHIPPING => '출하중', + self::STATUS_SHIPPED => '출하완료', + self::STATUS_COMPLETED => '완료', + self::STATUS_CANCELLED => '취소', +]; +``` + +#### 3.2 WorkOrderService - Order 상태 동기화 + +**파일**: `api/app/Services/WorkOrderService.php` + +```php +use App\Models\Orders\Order; + +/** + * Order 상태 동기화 + * WorkOrder 상태 변경 시 Order.status_code 업데이트 + */ +private function syncOrderStatus(WorkOrder $workOrder): void +{ + if (!$workOrder->sales_order_id) { + return; + } + + $order = Order::find($workOrder->sales_order_id); + if (!$order) { + return; + } + + $newStatus = null; + + switch ($workOrder->status) { + case WorkOrder::STATUS_IN_PROGRESS: + case WorkOrder::STATUS_WAITING: + case WorkOrder::STATUS_PENDING: + // 하나라도 진행중이면 생산중 + $newStatus = Order::STATUS_IN_PRODUCTION; + break; + + case WorkOrder::STATUS_COMPLETED: + // 모든 작업지시가 완료되었는지 확인 + $allCompleted = WorkOrder::where('sales_order_id', $order->id) + ->whereNotIn('status', [WorkOrder::STATUS_COMPLETED, WorkOrder::STATUS_SHIPPED]) + ->doesntExist(); + + if ($allCompleted) { + $newStatus = Order::STATUS_PRODUCED; + } + break; + } + + if ($newStatus && $order->status_code !== $newStatus) { + $order->update(['status_code' => $newStatus]); + + $this->auditLogger->log( + $order->tenant_id, + 'order', + $order->id, + 'status_synced_from_work_order', + ['status_code' => $order->getOriginal('status_code')], + ['status_code' => $newStatus, 'work_order_id' => $workOrder->id] + ); + } +} +``` + +**updateStatus() 메서드에 호출 추가:** + +```php +public function updateStatus(int $id, string $status, ?array $resultData = null) +{ + // ... 기존 로직 ... + + return DB::transaction(function () use ($workOrder, $status, $resultData, $tenantId, $userId) { + // ... 기존 상태 변경 로직 ... + + $workOrder->save(); + + // Order 상태 동기화 추가 + $this->syncOrderStatus($workOrder); + + // ... 나머지 로직 ... + }); +} +``` + +#### 3.3 ShipmentService - Order 상태 동기화 + +**파일**: `api/app/Services/ShipmentService.php` + +```php +use App\Models\Orders\Order; + +/** + * Order 상태 동기화 + * Shipment 상태 변경 시 Order.status_code 업데이트 + */ +private function syncOrderStatus(Shipment $shipment): void +{ + if (!$shipment->order_id) { + return; + } + + $order = Order::find($shipment->order_id); + if (!$order) { + return; + } + + $newStatus = null; + + switch ($shipment->status) { + case 'scheduled': + case 'ready': + case 'shipping': + // 출하 프로세스 시작 + if (!in_array($order->status_code, [Order::STATUS_SHIPPING, Order::STATUS_SHIPPED, Order::STATUS_COMPLETED])) { + $newStatus = Order::STATUS_SHIPPING; + } + break; + + case 'completed': + // 모든 출하가 완료되었는지 확인 + $allCompleted = Shipment::where('order_id', $order->id) + ->where('status', '!=', 'completed') + ->doesntExist(); + + if ($allCompleted) { + $newStatus = Order::STATUS_SHIPPED; + } + break; + } + + if ($newStatus && $order->status_code !== $newStatus) { + $order->update(['status_code' => $newStatus]); + } +} +``` + +**store() 및 updateStatus() 메서드에 호출 추가:** + +```php +public function store(array $data): Shipment +{ + // ... 기존 로직 ... + + return DB::transaction(function () use ($data, $tenantId, $userId) { + // ... 기존 생성 로직 ... + + // Order 상태 동기화 추가 + $this->syncOrderStatus($shipment); + + return $shipment->load('items'); + }); +} + +public function updateStatus(int $id, string $status, ?array $additionalData = null): Shipment +{ + // ... 기존 로직 ... + + $shipment->update($updateData); + + // Order 상태 동기화 추가 + $this->syncOrderStatus($shipment); + + return $shipment->load('items'); +} +``` + +--- + +### 4.4 Phase 4: 연동 기능 (선택) + +#### 4.1 ShipmentService.store() - work_order_id 연결 + +**파일**: `api/app/Services/ShipmentService.php` + +```php +public function store(array $data): Shipment +{ + return DB::transaction(function () use ($data, $tenantId, $userId) { + $shipment = Shipment::create([ + // ... 기존 필드들 ... + 'work_order_id' => $data['work_order_id'] ?? null, // 추가 + ]); + + // WorkOrder가 있으면 상태를 shipped로 변경 + if ($shipment->work_order_id) { + $workOrder = WorkOrder::find($shipment->work_order_id); + if ($workOrder && $workOrder->status === WorkOrder::STATUS_COMPLETED) { + $workOrder->update([ + 'status' => WorkOrder::STATUS_SHIPPED, + 'shipped_at' => now(), + ]); + } + } + + // ... 나머지 로직 ... + }); +} +``` + +#### 4.2 ShipmentStoreRequest - work_order_id 검증 + +**파일**: `api/app/Http/Requests/Shipment/ShipmentStoreRequest.php` + +```php +public function rules(): array +{ + return [ + // ... 기존 규칙들 ... + 'work_order_id' => ['nullable', 'integer', 'exists:work_orders,id'], + ]; +} +``` + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 마이그레이션 | shipments에 work_order_id FK 추가 | DB | ⏳ 컨펌 필요 | +| 2 | Order 상태 확장 | 4개 상태 추가 (IN_PRODUCTION, PRODUCED, SHIPPING, SHIPPED) | Order 모델, API | ⏳ 컨펌 필요 | +| 3 | 상태 동기화 로직 | WorkOrder/Shipment 상태 변경 시 Order 자동 업데이트 | 서비스 로직 | ⏳ 컨펌 필요 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-01-19 | - | 계획 문서 초안 작성 | - | - | + +--- + +## 7. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **SAM API 규칙**: `CLAUDE.md` +- **DB 스키마**: `docs/specs/database-schema.md` + +### 분석된 기존 파일 + +| 파일 | 역할 | +|------|------| +| `api/app/Models/Orders/Order.php` | 수주 마스터 모델 | +| `api/app/Models/Production/WorkOrder.php` | 작업지시 모델 | +| `api/app/Models/Tenants/Shipment.php` | 출하 모델 | +| `api/app/Services/WorkOrderService.php` | 작업지시 비즈니스 로직 | +| `api/app/Services/ShipmentService.php` | 출하 비즈니스 로직 | +| `api/database/migrations/2025_12_26_100000_create_work_orders_table.php` | 작업지시 테이블 | +| `api/database/migrations/2025_12_26_150604_create_shipments_table.php` | 출하 테이블 | + +--- + +## 8. 세션 및 메모리 관리 정책 + +### 8.1 세션 시작 시 +```javascript +read_memory("order-integration-state") // 상태 파악 +read_memory("order-integration-snapshot") // 사고 흐름 복구 +``` + +### 8.2 Serena 메모리 구조 +- `order-integration-state`: { phase, progress, next_step, last_decision } +- `order-integration-snapshot`: 현재까지의 논의 및 코드 변경점 요약 +- `order-integration-rules`: 해당 작업에서 결정된 규칙들 + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 테스트 케이스 + +| 시나리오 | 예상 결과 | 실제 결과 | 상태 | +|----------|----------|----------|------| +| WorkOrder 생성 (in_progress) | Order.status = IN_PRODUCTION | - | ⏳ | +| WorkOrder 완료 (completed) | Order.status = PRODUCED | - | ⏳ | +| Shipment 생성 | Order.status = SHIPPING | - | ⏳ | +| Shipment 완료 | Order.status = SHIPPED | - | ⏳ | +| 모든 프로세스 완료 | Order.status = COMPLETED | - | ⏳ | + +### 9.2 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| shipments.work_order_id FK 추가 완료 | ⏳ | | +| 모델 관계 정상 동작 | ⏳ | | +| Order 상태 자동 동기화 | ⏳ | | +| 기존 데이터 호환성 유지 | ⏳ | | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 섹션 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 9.2 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 2 대상 범위 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Phase별 순서 정의 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 7 참고 문서 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 3, 4 상세 코드 포함 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9.1 테스트 케이스 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 코드 예시 포함 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 현재 진행 상태, 3.1 절차 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 섹션 4 상세 작업 내용 | +| Q4. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/process-management-plan.md b/plans/archive/process-management-plan.md new file mode 100644 index 0000000..5c8d7d3 --- /dev/null +++ b/plans/archive/process-management-plan.md @@ -0,0 +1,397 @@ +# 공정관리 (Process Management) API 연동 계획 + +> **작성일**: 2025-01-08 +> **목적**: 공정관리 기능 검증 및 테스트 +> **상태**: ✅ 검증 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 3: 개별 품목 연결 기능 (process_items) | +| **다음 작업** | 완료 (Phase 2는 선택사항) | +| **진행률** | 5/5 (100%) - Phase 1 + Phase 3 완료 | +| **마지막 업데이트** | 2026-01-08 | + +--- + +## 1. 개요 + +### 1.1 기능 설명 +공정관리는 MES 시스템의 기초 데이터로, 생산 공정을 정의하고 관리하는 기능입니다. +작업지시 생성 시 공정 유형(process_type)으로 연결되며, 자동 분류 규칙을 통해 품목별 공정 배정을 자동화합니다. + +### 1.2 현재 구현 상태 분석 + +#### API (Laravel) - ✅ 완료 +| 구성요소 | 파일 경로 | 상태 | +|---------|----------|:----:| +| Model | `api/app/Models/Process.php` | ✅ | +| Model | `api/app/Models/ProcessClassificationRule.php` | ✅ | +| Model | `api/app/Models/ProcessItem.php` | ✅ (Phase 3) | +| Migration | `api/database/migrations/2026_01_08_180607_create_process_items_table.php` | ✅ | +| Service | `api/app/Services/ProcessService.php` | ✅ | +| Controller | `api/app/Http/Controllers/V1/ProcessController.php` | ✅ | +| FormRequest | `api/app/Http/Requests/V1/Process/StoreProcessRequest.php` | ✅ | +| FormRequest | `api/app/Http/Requests/V1/Process/UpdateProcessRequest.php` | ✅ | +| Swagger | `api/app/Swagger/v1/ProcessApi.php` | ✅ | +| Route | `/api/v1/processes` | ✅ | + +#### Frontend (React/Next.js) - ✅ API 연동 완료 +| 구성요소 | 파일 경로 | 상태 | +|---------|----------|:----:| +| 목록 페이지 | `react/src/app/[locale]/(protected)/master-data/process-management/page.tsx` | ✅ | +| 등록 페이지 | `react/src/app/[locale]/(protected)/master-data/process-management/new/page.tsx` | ✅ | +| 상세 페이지 | `react/src/app/[locale]/(protected)/master-data/process-management/[id]/page.tsx` | ✅ | +| 수정 페이지 | `react/src/app/[locale]/(protected)/master-data/process-management/[id]/edit/page.tsx` | ✅ | +| 목록 컴포넌트 | `react/src/components/process-management/ProcessListClient.tsx` | ✅ | +| 폼 컴포넌트 | `react/src/components/process-management/ProcessForm.tsx` | ✅ | +| 상세 컴포넌트 | `react/src/components/process-management/ProcessDetail.tsx` | ✅ | +| 규칙 모달 | `react/src/components/process-management/RuleModal.tsx` | ✅ | +| **actions.ts** | `react/src/components/process-management/actions.ts` | ✅ | + +### 1.3 관련 URL +| 화면 | URL | 설명 | +|------|-----|------| +| 공정목록 | `/master-data/process-management` | 토글 기능 포함 | +| 공정등록 | `/master-data/process-management/new` | 모달 - 규칙추가 | +| 공정상세 | `/master-data/process-management/{id}` | 상세 정보 | +| 공정수정 | `/master-data/process-management/{id}/edit` | 수정 폼 | + +### 1.4 연관관계 +``` +┌─────────────────┐ process_type ┌─────────────────┐ +│ Process │ ───────────────────────│ WorkOrder │ +│ (공정관리) │ screen/slat/bending │ (작업지시) │ +└─────────────────┘ └─────────────────┘ + │ + ├── classificationRules (패턴 규칙) + │ ▼ + │ ┌─────────────────────────┐ + │ │ ProcessClassificationRule│ + │ │ (자동 분류 규칙) │ + │ └─────────────────────────┘ + │ + └── processItems (개별 품목) ← Phase 3 + ▼ + ┌─────────────────────────┐ ┌─────────────────┐ + │ ProcessItem │────────│ Item │ + │ (공정-품목 연결) │ │ (품목) │ + └─────────────────────────┘ └─────────────────┘ +``` + +--- + +## 2. API 엔드포인트 + +### 2.1 REST API (구현 완료) +| Method | Endpoint | 설명 | 상태 | +|--------|----------|------|:----:| +| GET | `/api/v1/processes` | 공정 목록 조회 (검색/페이징) | ✅ | +| GET | `/api/v1/processes/{id}` | 공정 상세 조회 | ✅ | +| POST | `/api/v1/processes` | 공정 생성 | ✅ | +| PUT | `/api/v1/processes/{id}` | 공정 수정 | ✅ | +| DELETE | `/api/v1/processes/{id}` | 공정 삭제 | ✅ | +| DELETE | `/api/v1/processes` | 공정 일괄 삭제 | ✅ | +| PATCH | `/api/v1/processes/{id}/toggle` | 공정 상태 토글 | ✅ | +| GET | `/api/v1/processes/options` | 드롭다운용 옵션 목록 | ✅ | +| GET | `/api/v1/processes/stats` | 공정 통계 | ✅ | + +### 2.2 actions.ts 구현 함수 (완료) +```typescript +// 목록/조회 +getProcessList(params) // 목록 조회 +getProcessById(id) // 상세 조회 +getProcessOptions() // 드롭다운 옵션 +getProcessStats() // 통계 조회 + +// CRUD +createProcess(data) // 생성 +updateProcess(id, data) // 수정 +deleteProcess(id) // 삭제 +deleteProcesses(ids) // 일괄 삭제 +toggleProcessActive(id) // 상태 토글 + +// 보조 +getDepartmentOptions() // 부서 옵션 (분류 규칙용) +getItemList(params) // 품목 목록 (분류 규칙용) +``` + +--- + +## 3. 데이터 스키마 + +### 3.1 Process (공정) +```typescript +interface Process { + id: string; + processCode: string; // P-001, P-002 + processName: string; // 공정명 + description?: string; // 공정 설명 + processType: '생산' | '검사' | '포장' | '조립'; + department: string; // 담당 부서 + workLogTemplate?: string; // 작업일지 양식 + classificationRules: ClassificationRule[]; + requiredWorkers: number; // 필요 작업자 수 + equipmentInfo?: string; // 설비 정보 + workSteps: string[]; // 작업 단계 + note?: string; + status: '사용중' | '미사용'; + createdAt: string; + updatedAt: string; +} +``` + +### 3.2 ClassificationRule (자동 분류 규칙) +```typescript +interface ClassificationRule { + id: string; + registrationType: 'pattern' | 'individual'; // 패턴 규칙 vs 개별 품목 + ruleType: '품목코드' | '품목명' | '품목구분'; + matchingType: 'startsWith' | 'endsWith' | 'contains' | 'equals'; + conditionValue: string; + priority: number; + description?: string; + isActive: boolean; + createdAt: string; +} +``` + +### 3.3 ProcessItem (공정-품목 연결) - Phase 3 추가 +```typescript +// API 응답 스키마 +interface ApiProcessItem { + id: number; + process_id: number; + item_id: number; + priority: number; + is_active: boolean; + item?: { + id: number; + code: string; + name: string; + }; +} + +// DB 테이블: process_items +// - id (PK) +// - process_id (FK → processes) +// - item_id (FK → items) +// - priority (정렬 순서) +// - is_active (사용 여부) +// - created_at, updated_at +``` + +### 3.4 API 요청/응답 변환 + +#### 요청 (Frontend → API) +```typescript +// 패턴 규칙과 개별 품목 분리 +{ + classification_rules: [ // 패턴 규칙만 + { rule_type, matching_type, condition_value, ... } + ], + item_ids: [123, 456, 789] // 개별 품목 ID 배열 +} +``` + +#### 응답 (API → Frontend) +```typescript +// process_items를 individual 규칙으로 변환 +{ + classification_rules: [...], // 패턴 규칙 + process_items: [ // 개별 품목 연결 + { id, process_id, item_id, priority, is_active, item: {...} } + ] +} +``` + +--- + +## 4. 작업 범위 + +### Phase 1: 검증 및 테스트 (완료 - 2026-01-08) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | 목록 조회 테스트 | ✅ | 검색, 탭 필터 정상 | +| 1.2 | 등록 기능 테스트 | ✅ | 정상 (담당부서는 DB 데이터 의존) | +| 1.3 | 수정 기능 테스트 | ✅ | 필요인원 변경/저장 정상 | +| 1.4 | 삭제 기능 테스트 | ⏭️ | 데이터 보존으로 생략 | +| 1.5 | 토글 기능 테스트 | ✅ | 사용중↔미사용 전환 정상 | + +### 📋 참고사항 + +- **담당부서 드롭다운**: departments 테이블 데이터에 의존. 데이터 없으면 빈 드롭다운 (정상 동작) + +### Phase 2: 개선 사항 (선택) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | 공정 순서 드래그앤드롭 | ⏭️ | 후순위 | +| 2.2 | 작업 지침서 PDF 업로드 | ⏭️ | 후순위 | +| 2.3 | 공정 흐름도 시각화 | ⏭️ | 후순위 | + +### Phase 3: 개별 품목 연결 기능 (완료 - 2026-01-08) + +#### 배경 +- 기존 분류 규칙에서 400개 이상의 품목 코드를 `,` 구분자로 저장 시도 +- `condition_value` VARCHAR(255) 필드 초과 → API 422 에러 발생 +- 해결: 개별 품목은 별도 테이블(`process_items`)로 관계형 저장 + +#### 완료 작업 + +| # | 작업 항목 | 상태 | 파일/위치 | +|---|----------|:----:|----------| +| 3.1 | ProcessItem 모델 생성 | ✅ | `api/app/Models/ProcessItem.php` | +| 3.2 | process_items 마이그레이션 | ✅ | `api/database/migrations/2026_01_08_180607_*` | +| 3.3 | Process 모델 관계 추가 | ✅ | `processItems()` HasMany | +| 3.4 | ProcessService 수정 | ✅ | `syncProcessItems()` 메서드 추가 | +| 3.5 | Validation 업데이트 | ✅ | `item_ids` 배열 검증 추가 | +| 3.6 | Swagger 문서 업데이트 | ✅ | `ProcessItem` 스키마 추가 | +| 3.7 | Frontend actions.ts 수정 | ✅ | 요청/응답 변환 로직 | + +#### 핵심 변경 사항 + +**API 측 (Laravel)** +```php +// ProcessService.php +private function syncProcessItems(Process $process, array $itemIds): void +{ + $process->processItems()->delete(); + foreach ($itemIds as $index => $itemId) { + ProcessItem::create([ + 'process_id' => $process->id, + 'item_id' => $itemId, + 'priority' => $index, + 'is_active' => true, + ]); + } +} +``` + +**Frontend 측 (Next.js)** +```typescript +// actions.ts +// 패턴 규칙과 개별 품목 분리 +const patternRules = data.classificationRules.filter( + (rule) => rule.registrationType === 'pattern' +); +const individualRules = data.classificationRules.filter( + (rule) => rule.registrationType === 'individual' +); +// item_ids 추출 +const itemIds = individualRules.flatMap((rule) => + rule.conditionValue.split(',').map((id) => parseInt(id.trim(), 10)) +); +``` + +--- + +## 5. 주요 기능 상세 + +### 5.1 토글 기능 +- 목록에서 각 공정의 사용/미사용 상태를 토글 +- `PATCH /api/v1/processes/{id}/toggle` 호출 +- 미사용 공정은 작업지시 생성 시 선택 불가 + +### 5.2 규칙 추가 (모달) +- 자동 분류 규칙을 통해 품목별 공정 자동 배정 +- 우선순위(priority)에 따라 규칙 적용 순서 결정 +- include/exclude로 포함/제외 규칙 설정 + +### 5.3 양식 보기 (모달) +- 작업일지 템플릿 미리보기 +- HTML/마크다운 형식 지원 + +--- + +## 6. 의존성 + +### 6.1 필수 선행 작업 +- **없음** (기초 데이터) + +### 6.2 후속 연동 +- **작업지시 (WorkOrder)**: 공정 유형 선택 (process_type: screen/slat/bending) +- **품목관리 (Item)**: 자동 분류 규칙 적용 + +--- + +## 7. 검증 방법 + +### 7.1 테스트 체크리스트 + +| 기능 | 테스트 항목 | 예상 결과 | +|------|-----------|----------| +| 목록 조회 | 페이지 로드 | 공정 목록 표시 | +| 검색 | "생산" 검색 | 필터링된 결과 | +| 탭 필터 | "사용중" 탭 클릭 | 사용중 공정만 표시 | +| 등록 | 새 공정 등록 | 목록에 추가됨 | +| 수정 | 공정명 변경 | 변경 반영됨 | +| 삭제 | 공정 삭제 | 목록에서 제거됨 | +| 토글 | 상태 토글 | 사용중↔미사용 전환 | +| 규칙 추가 | 분류 규칙 추가 | 규칙 저장됨 | + +### 7.2 API 테스트 +```bash +# 목록 조회 +curl -X GET "http://api.sam.kr/api/v1/processes" -H "X-Api-Key: ..." + +# 상세 조회 +curl -X GET "http://api.sam.kr/api/v1/processes/1" -H "X-Api-Key: ..." + +# 통계 조회 +curl -X GET "http://api.sam.kr/api/v1/processes/stats" -H "X-Api-Key: ..." + +# 토글 +curl -X PATCH "http://api.sam.kr/api/v1/processes/1/toggle" -H "X-Api-Key: ..." +``` + +--- + +## 8. 참고 사항 + +### 8.1 공정 유형 (process_type) +현재 작업지시에서 사용하는 공정 유형: +- `screen`: 스크린 공정 +- `slat`: 슬랫 공정 +- `bending`: 절곡 공정 + +### 8.2 Process vs WorkOrder.process_type +- `Process` 모델: 공정의 메타데이터 (이름, 설명, 규칙 등) +- `WorkOrder.process_type`: 실제 작업지시에 적용된 공정 유형 +- 향후 FK 연결로 확장성 확보 가능 + +--- + +## 9. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **API 규칙**: `docs/standards/api-rules.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` + +### 참고 코드 +- **Controller**: `api/app/Http/Controllers/V1/ProcessController.php` +- **Service**: `api/app/Services/ProcessService.php` +- **actions.ts**: `react/src/components/process-management/actions.ts` + +--- + +## 10. 자기완결성 점검 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 검증 및 테스트 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 7 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1 테스트 항목 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 선행 작업 없음 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 모든 경로 검증됨 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 테스트 체크리스트 제공 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | curl + 체크리스트 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 경로 명시 | + +--- + +*이 문서는 독립 세션에서 바로 작업 시작 가능하도록 설계되었습니다.* \ No newline at end of file diff --git a/plans/archive/quote-auto-calculation-development-plan.md b/plans/archive/quote-auto-calculation-development-plan.md new file mode 100644 index 0000000..2034c20 --- /dev/null +++ b/plans/archive/quote-auto-calculation-development-plan.md @@ -0,0 +1,743 @@ +# 견적 자동산출 개발 계획 + +> **작성일**: 2025-12-22 +> **상태**: ✅ 구현 완료 +> **목표**: MNG 견적수식 데이터 셋팅 + React 견적관리 자동산출 기능 구현 +> **완료일**: 2025-12-22 +> **실제 소요 시간**: 약 2시간 + +--- + +## 0. 빠른 시작 가이드 + +### 폴더 구조 이해 (중요!) + +| 폴더 | 포트 | 역할 | 비고 | +|------|------|------|------| +| `design/` | localhost:3002 | 디자인 프로토타입 | UI 참고용 | +| `react/` | localhost:3000 | **실제 프론트엔드** | 구현 대상 ✅ | +| `mng/` | mng.sam.kr | 관리자 패널 | 수식 데이터 관리 | +| `api/` | api.sam.kr | REST API | 견적 산출 엔진 | + +### 이 문서만으로 작업을 시작하려면: + +```bash +# 1. Docker 서비스 시작 +cd /Users/hskwon/Works/@KD_SAM/SAM +docker-compose up -d + +# 2. MNG 시더 실행 (Phase 1 완료 후) +cd mng +php artisan quote:seed-formulas --tenant=1 + +# 3. React 개발 서버 (실제 구현 대상) +cd react +npm run dev +# http://localhost:3000 접속 +``` + +### 핵심 파일 위치 + +| 구분 | 파일 경로 | 역할 | +|------|----------|------| +| **MNG 시더** | `mng/app/Console/Commands/SeedQuoteFormulasCommand.php` | 🆕 생성 필요 | +| **React 자동산출** | `react/src/components/quotes/QuoteRegistration.tsx` | ⚡ 수정 필요 (line 332) | +| **API 클라이언트** | `react/src/lib/api/client.ts` | 참조 | +| **API 엔드포인트** | `api/app/Http/Controllers/Api/V1/QuoteController.php` | ✅ 구현됨 | +| **수식 엔진** | `api/app/Services/Quote/QuoteCalculationService.php` | ✅ 구현됨 | + +--- + +## 1. 현황 분석 + +### 1.1 시스템 구조 + +``` +┌───────────────────────────────────────────────────────────────────────────────┐ +│ SAM 시스템 │ +├───────────────────────────────────────────────────────────────────────────────┤ +│ MNG (mng.sam.kr) │ React (react/ 폴더) │ Design │ +│ ├── 기준정보관리 │ ├── 판매관리 │ (참고용) │ +│ │ └── 견적수식관리 ✅ │ │ └── 견적관리 │ │ +│ │ - 카테고리 CRUD │ │ └── 자동견적산출 │ design/ │ +│ │ - 수식 CRUD │ │ UI 있음 ✅ │ :3002 │ +│ │ - 범위/매핑/품목 탭 │ │ API 연동 ❌ │ │ +│ │ │ │ │ │ +│ └── DB: quote_formulas 테이블 │ └── API 호출: │ │ +│ (데이터 없음! ❌) │ POST /v1/quotes/calculate │ │ +└───────────────────────────────────────────────────────────────────────────────┘ + +※ design/ 폴더 (localhost:3002)는 UI 프로토타입용이며, 실제 구현은 react/ 폴더에서 진행 +``` + +### 1.2 React 견적등록 컴포넌트 현황 + +**파일**: `react/src/components/quotes/QuoteRegistration.tsx` + +```typescript +// 현재 상태 (line 332-335) +const handleAutoCalculate = () => { + toast.info(`자동 견적 산출 (${formData.items.length}개 항목) - API 연동 필요`); +}; + +// 입력 필드 (이미 구현됨): +interface QuoteItem { + openWidth: string; // W0 (오픈사이즈 가로) + openHeight: string; // H0 (오픈사이즈 세로) + productCategory: string; // screen | steel + quantity: number; + // ... 기타 필드 +} +``` + +### 1.3 API 엔드포인트 현황 + +**파일**: `api/app/Http/Controllers/Api/V1/QuoteController.php` + +```php +// 이미 구현됨 (line 135-145) +public function calculate(QuoteCalculateRequest $request) +{ + return ApiResponse::handle(function () use ($request) { + $validated = $request->validated(); + return $this->calculationService->calculate( + $validated['inputs'] ?? $validated, + $validated['product_category'] ?? null + ); + }, __('message.quote.calculated')); +} +``` + +### 1.4 수식 시더 데이터 (API) + +**파일**: `api/database/seeders/QuoteFormulaSeeder.php` + +| 카테고리 | 수식 수 | 설명 | +|---------|--------|------| +| OPEN_SIZE | 2 | W0, H0 입력값 | +| MAKE_SIZE | 4 | 제작사이즈 계산 | +| AREA | 1 | 면적 = W1 * H1 / 1000000 | +| WEIGHT | 2 | 중량 계산 (스크린/철재) | +| GUIDE_RAIL | 5 | 가이드레일 자동 선택 | +| CASE | 3 | 케이스 자동 선택 | +| MOTOR | 1 | 모터 자동 선택 (범위 9개) | +| CONTROLLER | 2 | 제어기 매핑 | +| EDGE_WING | 1 | 마구리 수량 | +| INSPECTION | 1 | 검사비 | +| PRICE_FORMULA | 8 | 단가 수식 | +| **합계** | **30개** | + 범위 18개 | + +--- + +## 2. 개발 상세 계획 + +### Phase 1: MNG 시더 데이터 생성 (1일) + +#### 2.1 Artisan 명령어 생성 + +**생성할 파일**: `mng/app/Console/Commands/SeedQuoteFormulasCommand.php` + +```php +option('tenant'); + $only = $this->option('only'); + $fresh = $this->option('fresh'); + + if ($fresh) { + $this->warn('기존 데이터를 삭제합니다...'); + $this->truncateTables($tenantId); + } + + if (!$only || $only === 'categories') { + $this->seedCategories($tenantId); + } + + if (!$only || $only === 'formulas') { + $this->seedFormulas($tenantId); + } + + if (!$only || $only === 'ranges') { + $this->seedRanges($tenantId); + } + + $this->info('✅ 견적수식 시드 완료!'); + return Command::SUCCESS; + } + + private function seedCategories(int $tenantId): void + { + $categories = [ + ['code' => 'OPEN_SIZE', 'name' => '오픈사이즈', 'sort_order' => 1], + ['code' => 'MAKE_SIZE', 'name' => '제작사이즈', 'sort_order' => 2], + ['code' => 'AREA', 'name' => '면적', 'sort_order' => 3], + ['code' => 'WEIGHT', 'name' => '중량', 'sort_order' => 4], + ['code' => 'GUIDE_RAIL', 'name' => '가이드레일', 'sort_order' => 5], + ['code' => 'CASE', 'name' => '케이스', 'sort_order' => 6], + ['code' => 'MOTOR', 'name' => '모터', 'sort_order' => 7], + ['code' => 'CONTROLLER', 'name' => '제어기', 'sort_order' => 8], + ['code' => 'EDGE_WING', 'name' => '마구리', 'sort_order' => 9], + ['code' => 'INSPECTION', 'name' => '검사', 'sort_order' => 10], + ['code' => 'PRICE_FORMULA', 'name' => '단가수식', 'sort_order' => 11], + ]; + + foreach ($categories as $cat) { + DB::table('quote_formula_categories')->updateOrInsert( + ['tenant_id' => $tenantId, 'code' => $cat['code']], + array_merge($cat, [ + 'tenant_id' => $tenantId, + 'is_active' => true, + 'created_at' => now(), + 'updated_at' => now(), + ]) + ); + } + + $this->info("카테고리 " . count($categories) . "개 생성됨"); + } + + private function seedFormulas(int $tenantId): void + { + // API 시더와 동일한 데이터 (api/database/seeders/QuoteFormulaSeeder.php 참조) + $formulas = $this->getFormulaData(); + + $categoryMap = DB::table('quote_formula_categories') + ->where('tenant_id', $tenantId) + ->pluck('id', 'code') + ->toArray(); + + $count = 0; + foreach ($formulas as $formula) { + $categoryId = $categoryMap[$formula['category_code']] ?? null; + if (!$categoryId) continue; + + DB::table('quote_formulas')->updateOrInsert( + ['tenant_id' => $tenantId, 'variable' => $formula['variable']], + [ + 'tenant_id' => $tenantId, + 'category_id' => $categoryId, + 'variable' => $formula['variable'], + 'name' => $formula['name'], + 'type' => $formula['type'], + 'formula' => $formula['formula'] ?? null, + 'output_type' => 'variable', + 'description' => $formula['description'] ?? null, + 'sort_order' => $formula['sort_order'] ?? 0, + 'is_active' => $formula['is_active'] ?? true, + 'created_at' => now(), + 'updated_at' => now(), + ] + ); + $count++; + } + + $this->info("수식 {$count}개 생성됨"); + } + + private function getFormulaData(): array + { + return [ + // 오픈사이즈 + ['category_code' => 'OPEN_SIZE', 'variable' => 'W0', 'name' => '오픈사이즈 W0 (가로)', 'type' => 'input', 'formula' => null, 'sort_order' => 1], + ['category_code' => 'OPEN_SIZE', 'variable' => 'H0', 'name' => '오픈사이즈 H0 (세로)', 'type' => 'input', 'formula' => null, 'sort_order' => 2], + + // 제작사이즈 + ['category_code' => 'MAKE_SIZE', 'variable' => 'W1_SCREEN', 'name' => '제작사이즈 W1 (스크린)', 'type' => 'calculation', 'formula' => 'W0 + 140', 'sort_order' => 1], + ['category_code' => 'MAKE_SIZE', 'variable' => 'H1_SCREEN', 'name' => '제작사이즈 H1 (스크린)', 'type' => 'calculation', 'formula' => 'H0 + 350', 'sort_order' => 2], + ['category_code' => 'MAKE_SIZE', 'variable' => 'W1_STEEL', 'name' => '제작사이즈 W1 (철재)', 'type' => 'calculation', 'formula' => 'W0 + 110', 'sort_order' => 3], + ['category_code' => 'MAKE_SIZE', 'variable' => 'H1_STEEL', 'name' => '제작사이즈 H1 (철재)', 'type' => 'calculation', 'formula' => 'H0 + 350', 'sort_order' => 4], + + // 면적 + ['category_code' => 'AREA', 'variable' => 'M', 'name' => '면적 계산', 'type' => 'calculation', 'formula' => 'W1 * H1 / 1000000', 'sort_order' => 1], + + // 중량 + ['category_code' => 'WEIGHT', 'variable' => 'K_SCREEN', 'name' => '중량 계산 (스크린)', 'type' => 'calculation', 'formula' => 'M * 2 + W0 / 1000 * 14.17', 'sort_order' => 1], + ['category_code' => 'WEIGHT', 'variable' => 'K_STEEL', 'name' => '중량 계산 (철재)', 'type' => 'calculation', 'formula' => 'M * 25', 'sort_order' => 2], + + // 가이드레일 + ['category_code' => 'GUIDE_RAIL', 'variable' => 'G', 'name' => '가이드레일 제작길이', 'type' => 'calculation', 'formula' => 'H0 + 250', 'sort_order' => 1], + ['category_code' => 'GUIDE_RAIL', 'variable' => 'GR_AUTO_SELECT', 'name' => '가이드레일 자재 자동 선택', 'type' => 'range', 'formula' => null, 'sort_order' => 2], + + // 케이스 + ['category_code' => 'CASE', 'variable' => 'S_SCREEN', 'name' => '케이스 사이즈 (스크린)', 'type' => 'calculation', 'formula' => 'W0 + 220', 'sort_order' => 1], + ['category_code' => 'CASE', 'variable' => 'S_STEEL', 'name' => '케이스 사이즈 (철재)', 'type' => 'calculation', 'formula' => 'W0 + 240', 'sort_order' => 2], + ['category_code' => 'CASE', 'variable' => 'CASE_AUTO_SELECT', 'name' => '케이스 자재 자동 선택', 'type' => 'range', 'formula' => null, 'sort_order' => 3], + + // 모터 + ['category_code' => 'MOTOR', 'variable' => 'MOTOR_AUTO_SELECT', 'name' => '모터 자동 선택', 'type' => 'range', 'formula' => null, 'sort_order' => 1], + + // 제어기 + ['category_code' => 'CONTROLLER', 'variable' => 'CONTROLLER_TYPE', 'name' => '제어기 유형', 'type' => 'input', 'formula' => null, 'sort_order' => 0], + ['category_code' => 'CONTROLLER', 'variable' => 'CTRL_AUTO_SELECT', 'name' => '제어기 자동 선택', 'type' => 'mapping', 'formula' => null, 'sort_order' => 1], + + // 검사 + ['category_code' => 'INSPECTION', 'variable' => 'INSP_FEE', 'name' => '검사비', 'type' => 'calculation', 'formula' => '1', 'sort_order' => 1], + ]; + } + + // ... 나머지 메서드 (seedRanges, truncateTables 등) +} +``` + +#### 2.2 작업 순서 + +```bash +# 1. 명령어 파일 생성 +# mng/app/Console/Commands/SeedQuoteFormulasCommand.php + +# 2. 실행 +cd mng +php artisan quote:seed-formulas --tenant=1 + +# 3. 확인 +php artisan tinker +>>> \App\Models\Quote\QuoteFormula::count() +# 예상: 30 + +# 4. 시뮬레이터 테스트 +# mng.sam.kr/quote-formulas/simulator +# 입력: W0=3000, H0=2500 +``` + +--- + +### Phase 2: React 자동산출 기능 구현 (2-3일) + +#### 2.1 API 클라이언트 추가 + +**수정할 파일**: `react/src/lib/api/quote.ts` (신규) + +```typescript +// react/src/lib/api/quote.ts +import { ApiClient } from './client'; +import { AUTH_CONFIG } from './auth/auth-config'; + +// API 응답 타입 +interface CalculationResult { + inputs: Record; + outputs: Record; + items: Array<{ + item_code: string; + item_name: string; + specification?: string; + unit?: string; + quantity: number; + unit_price: number; + total_price: number; + formula_variable: string; + }>; + costs: { + material_cost: number; + labor_cost: number; + install_cost: number; + subtotal: number; + }; + errors: string[]; +} + +interface CalculateRequest { + inputs: { + W0: number; + H0: number; + QTY?: number; + INSTALL_TYPE?: string; + CONTROL_TYPE?: string; + }; + product_category: 'screen' | 'steel'; +} + +// Quote API 클라이언트 +class QuoteApiClient extends ApiClient { + constructor() { + super({ + mode: 'bearer', + apiKey: AUTH_CONFIG.apiKey, + getToken: () => { + if (typeof window !== 'undefined') { + return localStorage.getItem('auth_token'); + } + return null; + }, + }); + } + + /** + * 자동 견적 산출 + */ + async calculate(request: CalculateRequest): Promise<{ success: boolean; data: CalculationResult; message: string }> { + return this.post('/api/v1/quotes/calculate', request); + } + + /** + * 입력 스키마 조회 + */ + async getCalculationSchema(productCategory?: string): Promise<{ success: boolean; data: Record }> { + const query = productCategory ? `?product_category=${productCategory}` : ''; + return this.get(`/api/v1/quotes/calculation-schema${query}`); + } +} + +export const quoteApi = new QuoteApiClient(); +``` + +#### 2.2 QuoteRegistration.tsx 수정 + +**수정할 파일**: `react/src/components/quotes/QuoteRegistration.tsx` + +```typescript +// 추가할 import +import { quoteApi } from '@/lib/api/quote'; +import { useState } from 'react'; + +// 상태 추가 (컴포넌트 내부) +const [calculationResult, setCalculationResult] = useState(null); +const [isCalculating, setIsCalculating] = useState(false); + +// handleAutoCalculate 수정 (line 332-335) +const handleAutoCalculate = async () => { + const item = formData.items[activeItemIndex]; + + if (!item.openWidth || !item.openHeight) { + toast.error('오픈사이즈(W0, H0)를 입력해주세요.'); + return; + } + + setIsCalculating(true); + try { + const response = await quoteApi.calculate({ + inputs: { + W0: parseFloat(item.openWidth), + H0: parseFloat(item.openHeight), + QTY: item.quantity, + INSTALL_TYPE: item.guideRailType, + CONTROL_TYPE: item.controller, + }, + product_category: item.productCategory as 'screen' | 'steel' || 'screen', + }); + + if (response.success) { + setCalculationResult(response.data); + toast.success('자동 산출이 완료되었습니다.'); + } else { + toast.error(response.message || '산출 중 오류가 발생했습니다.'); + } + } catch (error) { + console.error('자동 산출 오류:', error); + toast.error('서버 연결에 실패했습니다.'); + } finally { + setIsCalculating(false); + } +}; + +// 산출 결과 반영 함수 추가 +const handleApplyCalculation = () => { + if (!calculationResult) return; + + // 산출된 품목을 견적 항목에 반영 + const newItems = calculationResult.items.map((item, index) => ({ + id: `calc-${Date.now()}-${index}`, + floor: formData.items[activeItemIndex].floor, + code: item.item_code, + productCategory: formData.items[activeItemIndex].productCategory, + productName: item.item_name, + openWidth: formData.items[activeItemIndex].openWidth, + openHeight: formData.items[activeItemIndex].openHeight, + guideRailType: formData.items[activeItemIndex].guideRailType, + motorPower: formData.items[activeItemIndex].motorPower, + controller: formData.items[activeItemIndex].controller, + quantity: item.quantity, + wingSize: formData.items[activeItemIndex].wingSize, + inspectionFee: item.unit_price, + unitPrice: item.unit_price, + totalAmount: item.total_price, + })); + + setFormData({ + ...formData, + items: [...formData.items.slice(0, activeItemIndex), ...newItems, ...formData.items.slice(activeItemIndex + 1)], + }); + + setCalculationResult(null); + toast.success(`${newItems.length}개 품목이 반영되었습니다.`); +}; +``` + +#### 2.3 산출 결과 표시 UI 추가 + +```tsx +{/* 자동 견적 산출 버튼 아래에 추가 */} +{calculationResult && ( + + + + + 산출 결과 + + + + {/* 계산 변수 */} +
    + {Object.entries(calculationResult.outputs).map(([key, val]) => ( +
    +
    {val.name}
    +
    {typeof val.value === 'number' ? val.value.toFixed(2) : val.value}
    +
    + ))} +
    + + {/* 산출 품목 */} + + + + + + + + + + + + {calculationResult.items.map((item, i) => ( + + + + + + + + ))} + + + + + + + +
    품목코드품목명수량단가금액
    {item.item_code}{item.item_name}{item.quantity}{item.unit_price.toLocaleString()}{item.total_price.toLocaleString()}
    합계{calculationResult.costs.subtotal.toLocaleString()}원
    + + {/* 반영 버튼 */} + +
    +
    +)} +``` + +--- + +### Phase 3: 통합 테스트 (1일) + +#### 3.1 테스트 시나리오 + +| 번호 | 테스트 케이스 | 입력값 | 예상 결과 | +|-----|-------------|-------|----------| +| 1 | 기본 스크린 산출 | W0=3000, H0=2500 | 가이드레일 PT-GR-3000, 모터 PT-MOTOR-150 | +| 2 | 대형 스크린 산출 | W0=5000, H0=4000 | 모터 규격 상향 (300K 이상) | +| 3 | 철재 산출 | W0=2000, H0=2000, steel | 중량 M*25 적용 | +| 4 | 품목 반영 | 산출 후 반영 클릭 | 견적 항목에 추가됨 | +| 5 | 에러 처리 | W0/H0 미입력 | "오픈사이즈를 입력해주세요" | + +#### 3.2 검증 체크리스트 + +``` +□ MNG 시뮬레이터에서 수식 계산 정확도 확인 +□ React 자동산출 버튼 클릭 → API 호출 확인 +□ 산출 결과 테이블 정상 표시 +□ "품목에 반영하기" 클릭 → 견적 항목 추가 확인 +□ 견적 저장 시 calculation_inputs 필드 저장 확인 +□ 에러 시 적절한 메시지 표시 +``` + +--- + +## 3. SAM 개발 규칙 요약 + +### 3.1 API 개발 규칙 (CLAUDE.md 참조) + +```php +// Controller: FormRequest + ApiResponse 패턴 +public function calculate(QuoteCalculateRequest $request) +{ + return ApiResponse::handle(function () use ($request) { + return $this->calculationService->calculate($request->validated()); + }, __('message.quote.calculated')); +} + +// Service: 비즈니스 로직 분리 +class QuoteCalculationService extends Service +{ + public function calculate(array $inputs, ?string $productCategory = null): array + { + $tenantId = $this->tenantId(); // 필수 + // ... + } +} + +// 응답 형식 +{ + "success": true, + "message": "견적이 산출되었습니다.", + "data": { ... } +} +``` + +### 3.2 React 개발 패턴 + +```typescript +// API 클라이언트 패턴 (react/src/lib/api/client.ts) +class ApiClient { + async post(endpoint: string, data?: unknown): Promise + async get(endpoint: string): Promise +} + +// 컴포넌트 패턴 +// - shadcn/ui 컴포넌트 사용 +// - toast (sonner) 알림 +// - FormField, Card, Button 등 +``` + +### 3.3 MNG 개발 패턴 + +```php +// Artisan 명령어 패턴 +protected $signature = 'quote:seed-formulas {--tenant=1}'; + +// 모델 사용 +use App\Models\Quote\QuoteFormula; +use App\Models\Quote\QuoteFormulaCategory; + +// 서비스 패턴 +class QuoteFormulaService { + public function __construct( + private FormulaEvaluatorService $evaluator + ) {} +} +``` + +--- + +## 4. 파일 구조 + +``` +SAM/ +├── mng/ +│ ├── app/Console/Commands/ +│ │ └── SeedQuoteFormulasCommand.php # 🆕 Phase 1 +│ ├── app/Models/Quote/ +│ │ ├── QuoteFormula.php # ✅ 있음 +│ │ ├── QuoteFormulaCategory.php # ✅ 있음 +│ │ └── QuoteFormulaRange.php # ✅ 있음 +│ └── app/Services/Quote/ +│ └── FormulaEvaluatorService.php # ✅ 있음 +│ +├── api/ +│ ├── app/Http/Controllers/Api/V1/ +│ │ └── QuoteController.php # ✅ calculate() 있음 +│ ├── app/Services/Quote/ +│ │ ├── QuoteCalculationService.php # ✅ 있음 +│ │ └── FormulaEvaluatorService.php # ✅ 있음 +│ └── database/seeders/ +│ └── QuoteFormulaSeeder.php # 참조용 데이터 +│ +├── react/ +│ ├── src/lib/api/ +│ │ ├── client.ts # ✅ ApiClient 클래스 +│ │ └── quote.ts # 🆕 Phase 2 +│ └── src/components/quotes/ +│ └── QuoteRegistration.tsx # ⚡ Phase 2 수정 +│ +└── docs/plans/ + └── quote-auto-calculation-development-plan.md # 이 문서 +``` + +--- + +## 5. 수식 계산 예시 + +``` +입력: W0=3000mm, H0=2500mm, product_category=screen + +계산 순서: +1. W1 = W0 + 140 = 3140mm (스크린 제작 가로) +2. H1 = H0 + 350 = 2850mm (스크린 제작 세로) +3. M = W1 * H1 / 1000000 = 8.949㎡ (면적) +4. K = M * 2 + W0 / 1000 * 14.17 = 60.41kg (중량) +5. G = H0 + 250 = 2750mm (가이드레일 길이) +6. S = W0 + 220 = 3220mm (케이스 사이즈) + +범위 자동 선택: +- 가이드레일: G=2750 → 2438 < G ≤ 3000 → PT-GR-3000 × 2개 +- 케이스: S=3220 → 3000 < S ≤ 3600 → PT-CASE-3600 × 1개 +- 모터: K=60.41 → 0 < K ≤ 150 → PT-MOTOR-150 × 1개 +``` + +--- + +## 6. 일정 요약 + +| Phase | 작업 | 예상 기간 | 상태 | +|-------|------|----------|------| +| 1 | MNG 시더 명령어 생성 | 1일 | ✅ 완료 | +| 2 | React Quote API 클라이언트 생성 | 0.5일 | ✅ 완료 | +| 3 | React handleAutoCalculate API 연동 | 0.5일 | ✅ 완료 | +| 4 | 산출 결과 UI 추가 | 0.5일 | ✅ 완료 | +| 5 | 문서 업데이트 | 0.5시간 | ✅ 완료 | +| **합계** | | **약 2시간** | ✅ | + +--- + +## 7. 완료된 구현 내역 + +### 생성된 파일 +| 파일 경로 | 역할 | +|----------|------| +| `mng/app/Console/Commands/SeedQuoteFormulasCommand.php` | MNG 견적수식 시더 명령어 | +| `react/src/lib/api/quote.ts` | React Quote API 클라이언트 | + +### 수정된 파일 +| 파일 경로 | 변경 내용 | +|----------|----------| +| `react/src/components/quotes/QuoteRegistration.tsx` | handleAutoCalculate API 연동, 산출 결과 UI 추가 | + +### MNG 시더 실행 결과 +``` +✅ 견적수식 시드 완료! +카테고리: 11개 +수식: 18개 +범위: 18개 +``` + +### React 기능 구현 +- `handleAutoCalculate`: API 호출 및 로딩 상태 관리 +- `handleApplyCalculation`: 산출 결과를 견적 항목에 반영 +- 산출 결과 UI: 변수, 품목 테이블, 비용 합계 표시 +- 에러 처리: 입력값 검증, API 에러 토스트 + +--- + +*문서 버전*: 3.0 (구현 완료) +*작성자*: Claude Code +*최종 업데이트*: 2025-12-22 \ No newline at end of file diff --git a/plans/archive/quote-v2-auto-calculation-fix-plan.md b/plans/archive/quote-v2-auto-calculation-fix-plan.md new file mode 100644 index 0000000..2b372ec --- /dev/null +++ b/plans/archive/quote-v2-auto-calculation-fix-plan.md @@ -0,0 +1,262 @@ +# 견적 V2 자동 견적 산출 오류 수정 계획 + +> **작성일**: 2026-01-26 +> **목적**: 자동 견적 산출 기능의 4가지 오류 분석 및 수정 +> **기준 문서**: `QuoteRegistrationV2.tsx`, `LocationDetailPanel.tsx`, `QuoteSummaryPanel.tsx`, `actions.ts` +> **상태**: ✅ 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 테스트 및 검증 완료 | +| **다음 작업** | - | +| **진행률** | 4/4 (100%) ✅ | +| **마지막 업데이트** | 2026-01-26 | + +--- + +## 1. 개요 + +### 1.1 배경 +견적 V2 페이지(`/sales/quote-management/test-new`)에서 자동 견적 산출 버튼 클릭 후 다음 4가지 문제 발생: +1. 오른쪽 패널에 제품 리스트가 표시되지 않음 +2. 개소별 합계(상세소계)가 표시되지 않음 +3. 상세별 합계(그룹)가 표시되지 않음 +4. 예상 견적금액이 0원으로 표시됨 + +### 1.2 기준 원칙 +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - API 응답 구조와 프론트엔드 기대 구조의 일치 확보 │ +│ - Mock 데이터 fallback 로직은 디버깅/테스트용으로만 유지 │ +│ - 실제 BOM 계산 결과가 UI에 정확히 반영되도록 수정 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 타입 캐스팅 수정, 데이터 매핑 로직 수정 | 불필요 | +| ⚠️ 컨펌 필요 | API 응답 구조 변경, 새 인터페이스 정의 | **필수** | +| 🔴 금지 | API 엔드포인트 변경, DB 스키마 변경 | 별도 협의 | + +--- + +## 2. 근본 원인 분석 + +### 2.1 API 응답 구조 불일치 (핵심 원인) + +**API 실제 응답** (`actions.ts:962-965`): +```typescript +return { + success: true, + data: result.data || [], // 배열을 직접 반환 +}; +``` + +**API 서버 응답** (`QuoteCalculationService.php:168-178`): +```php +return [ + 'success' => $failCount === 0, + 'summary' => [ + 'total_count' => count($inputItems), + 'success_count' => $successCount, + 'fail_count' => $failCount, + 'grand_total' => round($grandTotal, 2), + ], + 'items' => $results, // items 배열 안에 결과가 있음 +]; +``` + +**컴포넌트 기대 구조** (`QuoteRegistrationV2.tsx:459-462`): +```typescript +const apiData = result.data as { + summary?: { grand_total: number }; + items?: Array<{ index: number; result: BomCalculationResult }>; +}; +const bomItems = apiData.items || []; // ❌ result.data가 배열이면 items가 없음! +``` + +### 2.2 문제 발생 흐름 + +``` +사용자 → "자동 견적 산출" 클릭 + ↓ +calculateBomBulk(bomItems) 호출 + ↓ +API 서버: { success, summary, items: [...] } 반환 + ↓ +actions.ts: result.data = 전체 응답 객체 (또는 배열로 잘못 파싱) + ↓ +QuoteRegistrationV2.tsx: result.data.items 접근 시도 + ↓ +❌ items가 undefined → bomItems = [] + ↓ +locations에 bomResult 저장 안됨 + ↓ +LocationDetailPanel: bomResult?.items 없음 → Mock 데이터 표시 +QuoteSummaryPanel: bomResult?.subtotals 없음 → Mock 데이터 표시 + ↓ +💥 모든 UI 영역에 데이터 없음 +``` + +### 2.3 영향 받는 컴포넌트 + +| 컴포넌트 | 파일 | 영향 | +|----------|------|------| +| QuoteRegistrationV2 | `QuoteRegistrationV2.tsx:457-481` | bomResult 저장 안됨 | +| LocationDetailPanel | `LocationDetailPanel.tsx:152-184` | Mock 데이터로 fallback | +| QuoteSummaryPanel | `QuoteSummaryPanel.tsx:136-164` | Mock 데이터로 fallback | + +--- + +## 3. 대상 범위 + +### 3.1 Phase 1: API 응답 처리 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | `actions.ts` 응답 구조 확인 | ✅ | API 서버 응답과 비교 | +| 1.2 | `actions.ts` BomBulkResponse 타입 추가 | ✅ | 정확한 API 응답 구조 정의 | +| 1.3 | `QuoteRegistrationV2.tsx` handleCalculate 수정 | ✅ | 응답 매핑 로직 및 디버그 로그 추가 | + +### 3.2 Phase 2: 데이터 바인딩 수정 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | `FormulaEvaluatorService.php` items에 process_group 추가 | ✅ | addProcessGroupToItems 메서드 추가 | +| 2.2 | `LocationDetailPanel.tsx` bomItemsByTab 수정 | ✅ | process_group_key 기반 매핑 | +| 2.3 | `QuoteSummaryPanel.tsx` detailTotals 수정 | ✅ | grouped_items에서 items 가져오기 | +| 2.4 | `actions.ts` BomCalculationResult 타입 확장 | ✅ | process_group, grouped_items 필드 추가 | + +--- + +## 4. 상세 작업 내용 + +### 4.1 Phase 1.2: handleCalculate 함수 수정 + +**현재 코드** (`QuoteRegistrationV2.tsx:457-479`): +```typescript +if (result.success && result.data) { + // ❌ 잘못된 타입 캐스팅 - result.data 자체가 API 응답 객체임 + const apiData = result.data as { + summary?: { grand_total: number }; + items?: Array<{ index: number; result: BomCalculationResult }>; + }; + const bomItems = apiData.items || []; // ❌ undefined + // ... +} +``` + +**수정 방안**: +`actions.ts`의 응답 처리를 확인하여 두 가지 접근법 중 선택: + +#### 방안 A: actions.ts 수정 (권장) +```typescript +// actions.ts에서 API 응답 구조 유지 +return { + success: true, + data: { + summary: result.data.summary, + items: result.data.items, + }, +}; +``` + +#### 방안 B: QuoteRegistrationV2.tsx 수정 +```typescript +if (result.success && result.data) { + // result.data가 { summary, items } 구조인지 확인 + const apiData = result.data as unknown as { + summary?: { grand_total: number }; + items?: Array<{ index: number; result: BomCalculationResult }>; + }; + // ... +} +``` + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | API 응답 구조 | actions.ts의 result.data 반환 방식 검토 | react/actions.ts | 대기 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-26 | 분석 | 문서 초안 작성 및 근본 원인 분석 완료 | - | - | +| 2026-01-26 | 수정 | actions.ts BomBulkResponse 타입 추가 | react/src/components/quotes/actions.ts | ✅ | +| 2026-01-26 | 수정 | QuoteRegistrationV2.tsx handleCalculate 수정 | react/src/components/quotes/QuoteRegistrationV2.tsx | ✅ | +| 2026-01-26 | 수정 | FormulaEvaluatorService.php process_group 추가 | api/app/Services/Quote/FormulaEvaluatorService.php | ✅ | +| 2026-01-26 | 수정 | LocationDetailPanel.tsx bomItemsByTab 수정 | react/src/components/quotes/LocationDetailPanel.tsx | ✅ | +| 2026-01-26 | 수정 | QuoteSummaryPanel.tsx detailTotals 수정 | react/src/components/quotes/QuoteSummaryPanel.tsx | ✅ | +| 2026-01-26 | 수정 | ItemService.php has_bom 필드 추가 | api/app/Services/ItemService.php | ✅ | +| 2026-01-26 | 수정 | actions.ts FinishedGoods에 has_bom, bom 필드 추가 | react/src/components/quotes/actions.ts | ✅ | +| 2026-01-26 | 수정 | QuoteRegistrationV2.tsx DevFill BOM 필터링 | react/src/components/quotes/QuoteRegistrationV2.tsx | ✅ | +| 2026-01-26 | 검증 | 브라우저 테스트 완료 - 4가지 문제 모두 해결 확인 | - | ✅ | + +--- + +## 7. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **API 규칙**: `docs/standards/api-rules.md` + +--- + +## 8. 검증 결과 + +> 브라우저 자동화 테스트 완료 (2026-01-26) + +### 8.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| DevFill 후 자동 견적 산출 | 제품 리스트 표시 | 볼트 M10×40, 너트 M10, 볼트 M8×30 등 6개 품목 표시 | ✅ | +| 개소 선택 | 개소별 합계 표시 | 1F / SS-01 상세소계: 3,119,555.94원 | ✅ | +| 그룹별 합계 | 상세별 합계 표시 | 절곡 공정: 735,891.24원, 철재 공정: 2,383,364.7원 | ✅ | +| 전체 금액 | 예상 견적금액 > 0 | 예상 견적금액: 3,119,555.94원 | ✅ | + +### 8.2 테스트 환경 + +- **URL**: `http://dev.sam.kr/sales/quote-management/test-new` +- **테스트 방법**: Claude-in-Chrome 브라우저 자동화 +- **데이터**: DevFill로 생성된 테스트 데이터 + +### 8.3 추가 발견 및 해결 사항 + +테스트 중 DevFill이 BOM 없는 제품을 선택하여 계산 결과가 0으로 나오는 문제 발견: + +| 문제 | 원인 | 해결 | +|------|------|------| +| DevFill 후 bomItemsCount: 0 | BOM 없는 제품 선택 | DevFill에서 BOM 있는 제품만 필터링 | +| has_bom 필드 없음 | API 응답에 미포함 | ItemService.php에서 계산 필드 추가 | +| getFinishedGoods에서 필드 누락 | 매핑 시 has_bom, bom 미포함 | FinishedGoods 인터페이스 및 매핑 수정 | + +### 8.4 최종 검증 결과 + +``` +[DevFill] BOM 있는 제품: 15개 / 전체: 2017개 +[BOM 계산 결과] +- bomItemsCount: 6 +- bomGrandTotal: 3,119,555.94 +- 공정별 그룹: 절곡, 철재 +``` + +**모든 4가지 UI 문제 해결 확인 완료** ✅ + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/react-fcm-push-notification-plan.md b/plans/archive/react-fcm-push-notification-plan.md new file mode 100644 index 0000000..7583ba8 --- /dev/null +++ b/plans/archive/react-fcm-push-notification-plan.md @@ -0,0 +1,543 @@ +# React FCM 푸시 알림 연동 계획 + +> **작성일**: 2025-12-30 +> **목적**: Capacitor 앱 웹뷰가 dev.sam.kr (Next.js)을 로드할 때 FCM 푸시 알림 지원 +> **기준 문서**: mng/public/js/fcm.js (포팅 대상), api/app/Swagger/v1/PushApi.php +> **상태**: ✅ 구현 완료 (Serena ID: react-fcm-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4: 통합 완료 | +| **다음 작업** | 테스트 (Capacitor 앱에서 확인) | +| **진행률** | 4/4 (100%) ✅ | +| **마지막 업데이트** | 2025-12-30 | + +--- + +## 1. 개요 + +### 1.1 현재 구조 + +``` +Capacitor 앱 (웹뷰) + │ + ▼ + mng (현재) + │ + ├── fcm.js 로드 + │ ├── Capacitor PushNotifications 사용 + │ ├── 토큰 발급 + │ └── api에 토큰 등록 + │ + ▼ + api + │ + └── /push/register-token +``` + +### 1.2 목표 구조 + +``` +Capacitor 앱 (웹뷰) + │ + ▼ + dev.sam.kr (react) ← 변경 + │ + ├── FCM 훅/유틸리티 (포팅) + │ ├── Capacitor PushNotifications 사용 (동일) + │ ├── 토큰 발급 (동일) + │ └── api에 토큰 등록 (동일) + │ + ▼ + api (변경 없음) + │ + └── /push/register-token +``` + +### 1.3 핵심 포인트 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심: mng/public/js/fcm.js를 react에 포팅 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. Capacitor PushNotifications 플러그인 사용 (동일) │ +│ 2. 토큰 발급 → api 등록 로직 (동일) │ +│ 3. 포그라운드 알림 → sonner 토스트로 변경 │ +│ 4. 백엔드 API 변경 없음 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.4 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | Capacitor 플러그인 설치, 훅 생성, 유틸리티 추가 | 불필요 | +| ⚠️ 컨펌 필요 | 포그라운드 알림 UX (토스트 디자인) | **필수** | +| 🔴 금지 | API 엔드포인트 변경, DB 스키마 변경 | 별도 협의 | + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: Capacitor 플러그인 설치 ✅ + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | @capacitor/push-notifications 설치 | ✅ | ^8.0.0 | +| 1.2 | @capacitor/app 설치 | ✅ | ^8.0.0 | +| 1.3 | @capacitor/core 설치 | ✅ | ^8.0.0 | + +### 2.2 Phase 2: FCM 유틸리티 포팅 ✅ + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | lib/capacitor/fcm.ts 생성 | ✅ | 9.1KB | +| 2.2 | useFCM 훅 생성 | ✅ | 3.3KB | +| 2.3 | FCM Provider 생성 | ✅ | contexts/FCMProvider.tsx | + +### 2.3 Phase 3: 포그라운드 알림 UI ✅ + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | sonner 토스트 연동 | ✅ | useFCM에서 처리 | +| 3.2 | 알림 사운드 재생 | ✅ | public/sounds/ | +| 3.3 | 클릭 시 URL 이동 | ✅ | window.location.href | + +### 2.4 Phase 4: 통합 ✅ + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | layout.tsx에 FCMProvider 추가 | ✅ | (protected)/layout.tsx | +| 4.2 | 로그아웃 시 토큰 해제 | ✅ | logout.ts 수정 | +| 4.3 | 토큰 등록 테스트 | ⏳ | Capacitor 앱에서 확인 필요 | +| 4.4 | 포그라운드/백그라운드 알림 테스트 | ⏳ | Capacitor 앱에서 확인 필요 | + +--- + +## 3. 기술 상세 + +### 3.1 기존 mng/public/js/fcm.js 분석 + +```javascript +// 핵심 기능 요약 +1. Capacitor 네이티브 환경 체크 (ios/android) +2. PushNotifications.requestPermissions() - 권한 요청 +3. PushNotifications.register() - 토큰 발급 +4. registration 이벤트 → api에 토큰 등록 +5. pushNotificationReceived → 포그라운드 알림 (토스트 + 사운드) +6. pushNotificationActionPerformed → 알림 클릭 시 URL 이동 +``` + +### 3.2 FCM 유틸리티 (포팅) + +```typescript +// src/lib/capacitor/fcm.ts +import { Capacitor } from '@capacitor/core'; +import { PushNotifications } from '@capacitor/push-notifications'; +import { App } from '@capacitor/app'; + +const CONFIG = { + apiBaseUrl: process.env.NEXT_PUBLIC_API_URL || 'https://api.codebridge-x.com', + fcmTokenKey: 'fcm_token', + soundBasePath: '/sounds/', + defaultSound: 'default', +}; + +let isAppForeground = true; + +/** + * FCM 초기화 (Capacitor 네이티브 환경에서만 동작) + */ +export async function initializeFCM( + accessToken: string, + onForegroundNotification?: (notification: PushNotification) => void +): Promise { + // 네이티브 환경 체크 + const platform = Capacitor.getPlatform(); + if (platform !== 'ios' && platform !== 'android') { + console.log('[FCM] Not running in native app'); + return false; + } + + if (!Capacitor.isPluginAvailable('PushNotifications')) { + console.log('[FCM] PushNotifications plugin not available'); + return false; + } + + try { + // 앱 상태 리스너 + App.addListener('appStateChange', ({ isActive }) => { + isAppForeground = isActive; + console.log('[FCM] App state:', isActive ? 'foreground' : 'background'); + }); + + // 기존 리스너 제거 + await PushNotifications.removeAllListeners(); + + // 리스너 등록 + PushNotifications.addListener('registration', async (token) => { + console.log('[FCM] Token received:', token.value?.substring(0, 20) + '...'); + await handleTokenRegistration(token.value, accessToken); + }); + + PushNotifications.addListener('registrationError', (err) => { + console.error('[FCM] Registration error:', err); + }); + + PushNotifications.addListener('pushNotificationReceived', (notification) => { + console.log('[FCM] Push received (foreground):', notification); + if (onForegroundNotification) { + onForegroundNotification(notification); + } + handleForegroundSound(notification); + }); + + PushNotifications.addListener('pushNotificationActionPerformed', (action) => { + console.log('[FCM] Push action performed:', action); + const url = action.notification?.data?.url; + if (url) { + window.location.href = url; + } + }); + + // 권한 요청 + const perm = await PushNotifications.requestPermissions(); + console.log('[FCM] Push permission:', perm.receive); + + if (perm.receive !== 'granted') { + console.log('[FCM] Push permission not granted'); + return false; + } + + // 토큰 발급 요청 + await PushNotifications.register(); + return true; + + } catch (error) { + console.error('[FCM] Initialization error:', error); + return false; + } +} + +/** + * 토큰 등록 처리 + */ +async function handleTokenRegistration(newToken: string, accessToken: string): Promise { + const oldToken = sessionStorage.getItem(CONFIG.fcmTokenKey); + + if (oldToken === newToken) { + console.log('[FCM] Token unchanged, skip'); + return; + } + + const success = await registerTokenToServer(newToken, accessToken); + + if (success) { + sessionStorage.setItem(CONFIG.fcmTokenKey, newToken); + console.log('[FCM] Token saved to sessionStorage'); + } +} + +/** + * 서버에 토큰 등록 + */ +async function registerTokenToServer(token: string, accessToken: string): Promise { + try { + const response = await fetch(`${CONFIG.apiBaseUrl}/api/v1/push/register-token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + }, + body: JSON.stringify({ + token, + platform: Capacitor.getPlatform(), + device_name: navigator.userAgent?.substring(0, 100) || null, + app_version: process.env.NEXT_PUBLIC_APP_VERSION || null, + }), + }); + + if (response.ok) { + console.log('[FCM] Token registered successfully'); + return true; + } + + console.error('[FCM] Token registration failed:', response.status); + return false; + + } catch (error) { + console.error('[FCM] Failed to send token:', error); + return false; + } +} + +/** + * 토큰 해제 (로그아웃 시) + */ +export async function unregisterFCMToken(accessToken?: string): Promise { + const token = sessionStorage.getItem(CONFIG.fcmTokenKey); + if (!token) return true; + + try { + if (accessToken) { + await fetch(`${CONFIG.apiBaseUrl}/api/v1/push/unregister-token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + }, + body: JSON.stringify({ token }), + }); + } + } catch (e) { + console.warn('[FCM] Unregister failed'); + } + + sessionStorage.removeItem(CONFIG.fcmTokenKey); + return true; +} + +/** + * 포그라운드 사운드 재생 + */ +function handleForegroundSound(notification: any): void { + if (!isAppForeground) return; + + const soundKey = notification.data?.sound_key; + if (!soundKey) return; + + try { + const audio = new Audio(`${CONFIG.soundBasePath}${soundKey}.wav`); + audio.volume = 0.5; + audio.play().catch(() => { + // 기본 사운드 시도 + const defaultAudio = new Audio(`${CONFIG.soundBasePath}${CONFIG.defaultSound}.wav`); + defaultAudio.volume = 0.5; + defaultAudio.play().catch(() => {}); + }); + } catch (err) { + console.warn('[FCM] Sound error:', err); + } +} + +/** + * Capacitor 네이티브 환경인지 확인 + */ +export function isCapacitorNative(): boolean { + const platform = Capacitor.getPlatform(); + return platform === 'ios' || platform === 'android'; +} + +// 타입 정의 +export interface PushNotification { + title?: string; + body?: string; + data?: { + type?: string; + url?: string; + sound_key?: string; + }; +} +``` + +### 3.3 useFCM 훅 + +```typescript +// src/hooks/useFCM.ts +'use client'; + +import { useEffect, useRef } from 'react'; +import { useSession } from 'next-auth/react'; +import { toast } from 'sonner'; +import { + initializeFCM, + unregisterFCMToken, + isCapacitorNative, + PushNotification, +} from '@/lib/capacitor/fcm'; + +export function useFCM() { + const { data: session } = useSession(); + const initialized = useRef(false); + + useEffect(() => { + // 네이티브 환경이 아니면 무시 + if (!isCapacitorNative()) return; + + // 로그인 안 됐으면 무시 + if (!session?.accessToken) return; + + // 이미 초기화됐으면 무시 + if (initialized.current) return; + + initialized.current = true; + + // FCM 초기화 + initializeFCM(session.accessToken, handleForegroundNotification); + + // 클린업 (로그아웃 시) + return () => { + // 로그아웃 시 토큰 해제는 별도 처리 + }; + }, [session?.accessToken]); + + // 포그라운드 알림 핸들러 + function handleForegroundNotification(notification: PushNotification) { + const { title, body, data } = notification; + const type = data?.type || 'default'; + const url = data?.url; + + // 타입별 토스트 스타일 + const toastFn = getToastFunction(type); + + toastFn(title || '알림', { + description: body, + action: url ? { + label: '보기', + onClick: () => { + window.location.href = url; + }, + } : undefined, + duration: 5000, + }); + } + + // 타입별 토스트 함수 + function getToastFunction(type: string) { + const errorTypes = ['invoice_failed', 'payment_failed', 'order_cancelled']; + const warningTypes = ['approval_required', 'stock_low']; + const successTypes = ['order_completed', 'payment_completed', 'approval_approved']; + + if (errorTypes.includes(type)) return toast.error; + if (warningTypes.includes(type)) return toast.warning; + if (successTypes.includes(type)) return toast.success; + return toast.info; + } + + // 로그아웃 시 호출 + async function cleanup(accessToken?: string) { + await unregisterFCMToken(accessToken); + initialized.current = false; + } + + return { cleanup }; +} +``` + +### 3.4 FCM Provider + +```typescript +// src/providers/FCMProvider.tsx +'use client'; + +import { useFCM } from '@/hooks/useFCM'; + +export function FCMProvider({ children }: { children: React.ReactNode }) { + // FCM 훅 실행 (초기화) + useFCM(); + + return <>{children}; +} +``` + +### 3.5 레이아웃에 Provider 추가 + +```typescript +// src/app/layout.tsx (또는 적절한 위치) +import { FCMProvider } from '@/providers/FCMProvider'; + +export default function RootLayout({ children }) { + return ( + + + + + {children} + + + + + ); +} +``` + +--- + +## 4. 파일 구조 + +``` +react/ +├── public/ +│ └── sounds/ ← 알림 사운드 (mng에서 복사) +│ ├── default.wav +│ └── *.wav +├── src/ +│ ├── lib/ +│ │ └── capacitor/ +│ │ └── fcm.ts ← 🆕 FCM 핵심 로직 (포팅) +│ ├── hooks/ +│ │ └── useFCM.ts ← 🆕 FCM 훅 +│ └── providers/ +│ └── FCMProvider.tsx ← 🆕 FCM Provider +├── capacitor.config.ts ← 확인/수정 필요 +└── package.json ← Capacitor 플러그인 추가 +``` + +--- + +## 5. 의존성 + +| 패키지 | 버전 | 용도 | +|--------|------|------| +| @capacitor/core | (기존) | Capacitor 코어 | +| @capacitor/push-notifications | ^6.0.0 | 푸시 알림 플러그인 | +| @capacitor/app | ^6.0.0 | 앱 상태 감지 | +| sonner | (기존) | 포그라운드 토스트 | + +--- + +## 6. mng vs react 비교 + +| 항목 | mng (기존) | react (포팅) | +|------|-----------|--------------| +| **FCM 플러그인** | Capacitor PushNotifications | 동일 | +| **토큰 저장** | sessionStorage | 동일 | +| **API 호출** | fetch | 동일 | +| **포그라운드 알림** | showToast (커스텀) | sonner 토스트 | +| **사운드 재생** | Audio API | 동일 | +| **URL 이동** | window.location.href | 동일 (또는 router.push) | + +--- + +## 7. 참고 문서 + +| 문서 | 용도 | +|------|------| +| `mng/public/js/fcm.js` | 포팅 원본 | +| `api/app/Swagger/v1/PushApi.php` | 백엔드 API 스펙 | +| [Capacitor Push Notifications](https://capacitorjs.com/docs/apis/push-notifications) | 공식 문서 | + +--- + +## 8. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 포그라운드 알림 UX | sonner 토스트 디자인/위치 | UX | ⏳ | + +--- + +## 9. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-12-30 | 계획 수립 | 계획 문서 작성 | - | - | + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/react-server-component-audit-plan.md b/plans/archive/react-server-component-audit-plan.md new file mode 100644 index 0000000..ae0ce56 --- /dev/null +++ b/plans/archive/react-server-component-audit-plan.md @@ -0,0 +1,147 @@ +# React 서버 컴포넌트 점검 계획 + +> **작성일**: 2025-01-09 +> **목적**: push하지 않은 작업분 중 서버 컴포넌트를 클라이언트 컴포넌트로 변경 +> **상태**: ✅ 점검 완료 - 수정 불필요 + +--- + +## 📍 점검 결과 요약 + +| 항목 | 내용 | +|------|------| +| **점검 대상** | push하지 않은 커밋 (origin/master..HEAD) | +| **커밋 수** | 20개 | +| **점검 파일 수** | 31개 (tsx/ts 파일) | +| **서버 컴포넌트 발견** | 0개 | +| **수정 필요** | ❌ 없음 | + +--- + +## 1. 점검 배경 + +### 1.1 정책 +- 프론트엔드 정책: **서버 컴포넌트 사용 금지** +- 모든 컴포넌트는 **클라이언트 컴포넌트**로 작성해야 함 +- `'use client'` 지시어 필수 + +### 1.2 점검 범위 +- **대상**: react 폴더의 push하지 않은 작업분 +- **제외**: 이미 push된 커밋 (프론트엔드에서 수정 중) + +--- + +## 2. 점검 대상 파일 + +### 2.1 변경된 TSX 파일 (16개) + +| # | 파일 | 'use client' | 상태 | +|---|------|:------------:|:----:| +| 1 | `src/app/[locale]/(protected)/sales/order-management-sales/[id]/edit/page.tsx` | ✅ | 정상 | +| 2 | `src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx` | ✅ | 정상 | +| 3 | `src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx` | ✅ | 정상 | +| 4 | `src/app/[locale]/(protected)/sales/order-management-sales/new/page.tsx` | ✅ | 정상 | +| 5 | `src/app/[locale]/(protected)/sales/order-management-sales/page.tsx` | ✅ | 정상 | +| 6 | `src/components/approval/DocumentCreate/ApprovalLineSection.tsx` | ✅ | 정상 | +| 7 | `src/components/approval/DocumentCreate/ReferenceSection.tsx` | ✅ | 정상 | +| 8 | `src/components/hr/EmployeeManagement/EmployeeForm.tsx` | ✅ | 정상 | +| 9 | `src/components/orders/OrderRegistration.tsx` | ✅ | 정상 | +| 10 | `src/components/orders/QuotationSelectDialog.tsx` | ✅ | 정상 | +| 11 | `src/components/process-management/ProcessDetail.tsx` | ✅ | 정상 | +| 12 | `src/components/process-management/RuleModal.tsx` | ✅ | 정상 | +| 13 | `src/components/production/WorkOrders/SalesOrderSelectModal.tsx` | ✅ | 정상 | +| 14 | `src/components/production/WorkOrders/WorkOrderCreate.tsx` | ✅ | 정상 | +| 15 | `src/components/production/WorkOrders/WorkOrderDetail.tsx` | ✅ | 정상 | +| 16 | `src/components/production/WorkOrders/WorkOrderList.tsx` | ✅ | 정상 | + +### 2.2 변경된 TS 파일 (15개) - 검토 불필요 + +TS 파일은 컴포넌트가 아닌 유틸리티/타입/액션 파일로 서버 컴포넌트 대상 아님: + +- `src/components/business/construction/*/actions.ts` (6개) +- `src/components/orders/actions.ts` +- `src/components/orders/index.ts` +- `src/components/process-management/actions.ts` +- `src/components/production/WorkOrders/actions.ts` +- `src/components/production/WorkOrders/types.ts` +- `src/lib/api/common-codes.ts` +- `src/lib/api/index.ts` +- `src/types/process.ts` +- `src/components/business/construction/site-management/types.ts` + +--- + +## 3. Push하지 않은 커밋 목록 + +``` +311ddd9 docs: Phase D~K 마이그레이션 완료 상태 반영 (95%) +6615f39 feat(order-management): Mock → API 연동 및 common-codes 유틸리티 추가 +d472b77 fix(approval): 결재선/참조 Select 값 변경 불가 버그 수정 +5fa20c8 feat(item-management): Mock → API 연동 완료 +749f0ce feat: 거래처관리 API 연동 (Phase 2.2) +273d570 feat(시공사): 2.1 현장관리 - Frontend API 연동 +78e193c refactor(work-orders): process_type을 process_id FK로 변환 +9d30555 feat(시공사): 1.2 인수인계보고서 - Frontend API 연동 +d15a203 feat(work-orders): 다중 담당자 UI 구현 +8172226 Merge remote-tracking branch 'origin/master' +668cde3 Merge remote-tracking branch 'origin/master' +c651e7b feat(WEB): 수주관리 Phase 3 완료 - 고급 기능 구현 +2d7809b feat: [시공관리] 계약관리 Frontend API 연동 +12b4259 refactor(work-orders): 코드 리뷰 기반 프론트엔드 개선 +fde8726 feat(WEB): 수주관리 Phase 2 타입 정의 확장 및 공정관리 개별 품목 표시 수정 +ba36c0e feat: 공정 관리 Frontend actions 업데이트 +d797868 fix(WEB): 공정관리 개별 품목 저장 안되는 버그 수정 +3d2dea6 feat: 수주 관리 Phase 3 - Frontend API 연동 +6632943 Merge remote-tracking branch 'origin/master' +288871c feat(WEB): 직원 관리 폼 직급/부서/직책 Select 드롭다운 연동 +572ffe8 feat(orders): Phase 2 - Frontend API 연동 완료 +``` + +--- + +## 4. 점검 결론 + +### 4.1 결과 +**✅ 모든 TSX 파일에 'use client' 지시어가 있음** + +push하지 않은 작업분에서 서버 컴포넌트가 발견되지 않았습니다. +모든 컴포넌트가 클라이언트 컴포넌트 정책을 준수하고 있습니다. + +### 4.2 수정 필요 항목 +**없음** + +--- + +## 5. 향후 권장사항 + +### 5.1 새 파일 생성 시 체크리스트 +``` +□ TSX 파일 첫 줄에 'use client' 지시어 추가 +□ page.tsx 파일도 예외 없이 'use client' 필수 +□ layout.tsx 파일도 필요시 'use client' 추가 +``` + +### 5.2 코드 리뷰 시 확인 +- PR 리뷰 시 새 TSX 파일의 'use client' 지시어 확인 +- async 컴포넌트 패턴 지양 (useEffect, React Query 등 사용) + +### 5.3 린트 규칙 고려 +향후 ESLint 커스텀 룰 추가 검토: +```javascript +// .eslintrc.js 예시 +rules: { + 'react/enforce-use-client': 'error' // 커스텀 룰 +} +``` + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | +|------|------|----------| +| 2025-01-09 | 문서 생성 | 서버 컴포넌트 점검 완료, 수정 불필요 확인 | + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/sam-stat-database-design-plan.md b/plans/archive/sam-stat-database-design-plan.md new file mode 100644 index 0000000..f63455e --- /dev/null +++ b/plans/archive/sam-stat-database-design-plan.md @@ -0,0 +1,1294 @@ +# SAM 통계 시스템 (sam_stat DB) 설계 계획 + +> **작성일**: 2026-01-29 +> **목적**: SAM ERP의 확장 가능한 통계 전용 데이터베이스(sam_stat) 설계 +> **기준 문서**: `docs/specs/database-schema.md`, `docs/architecture/system-overview.md` +> **상태**: ✅ 구현 완료 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 6: 문서화 및 마무리 완료 (Swagger, DB 스키마 문서, 계획 문서 완료 처리) | +| **다음 작업** | ✅ 전체 완료 | +| **진행률** | 6/6 Phase (100%) | +| **마지막 업데이트** | 2026-01-30 | + +--- + +## 0. 프로젝트 컨텍스트 (새 세션용) + +> **이 섹션은 새 세션에서 이 문서만으로 작업을 시작할 수 있도록 필요한 모든 컨텍스트를 포함한다.** + +### 0.1 프로젝트 구조 + +``` +/Users/kent/Works/@KD_SAM/SAM/ +├── api/ ← 작업 대상 (Laravel 12 REST API, PHP 8.4+) +│ ├── app/ +│ │ ├── Console/Commands/ # Artisan 커맨드 (19개 존재) +│ │ ├── Http/Controllers/Api/V1/ # API 컨트롤러 +│ │ ├── Models/ # Eloquent 모델 (167개) +│ │ │ ├── Stats/ # ← 새로 생성할 통계 모델 디렉토리 +│ │ │ ├── Tenants/ # 테넌트 스코프 모델 (가장 많음) +│ │ │ ├── Orders/ # 수주 관련 +│ │ │ ├── Production/ # 생산 관련 +│ │ │ └── ... +│ │ └── Services/ # 비즈니스 로직 (Service-First 아키텍처) +│ │ ├── Stats/ # ← 새로 생성할 통계 서비스 디렉토리 +│ │ ├── DashboardService.php # 기존 대시보드 (355줄, 원본 DB 실시간 집계) +│ │ ├── ReportService.php # 기존 보고서 (일일일보, 지출예상) +│ │ ├── DailyReportService.php # 일일 보고서 (어음, 계좌, 요약) +│ │ ├── AiReportService.php # AI 보고서 +│ │ └── ... +│ ├── config/ +│ │ └── database.php # DB 연결 설정 (mysql, chandj 존재) +│ ├── database/ +│ │ └── migrations/ # 279개 마이그레이션 파일 +│ ├── routes/ +│ │ ├── console.php # 스케줄러 정의 (Laravel 12 방식) +│ │ └── api/v1/ +│ │ ├── common.php # dashboard, reports 라우트 +│ │ ├── finance.php # daily-report 라우트 +│ │ └── ... # 14개 라우트 파일 +│ └── .env # 환경변수 +├── mng/ # 관리자 패널 (Plain Laravel + Blade/Tailwind) +├── react/ # Next.js 15 프론트엔드 +├── docker/ +│ └── docker-compose.yml # Docker 설정 +└── docs/ # 기술 문서 + ├── specs/database-schema.md # DB 스키마 문서 + ├── architecture/system-overview.md + └── plans/ # 이 문서의 위치 +``` + +### 0.2 현재 DB 환경 + +``` +# .env (api/) +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 # Docker 내부: sam-mysql-1 +DB_PORT=3306 +DB_DATABASE=samdb # ← 원본 DB (219개 테이블) +DB_USERNAME=samuser +DB_PASSWORD=sampass + +# sam_stat 연결은 아직 없음 → Phase 1에서 추가 +``` + +**config/database.php 현재 연결:** +- `mysql` - 기본 samdb (원본) +- `chandj` - 5130 레거시 DB (사용하지 않음) +- `sam_stat` - **아직 없음** (이 작업에서 추가) + +### 0.3 기존 대시보드/보고서 시스템 (변경 대상) + +| 파일 | 경로 | 역할 | 통계 전환 시 영향 | +|------|------|------|------------------| +| DashboardController | `api/app/Http/Controllers/Api/V1/DashboardController.php` | summary, charts, approvals | Phase 4.5에서 sam_stat 조회로 전환 | +| ReportController | `api/app/Http/Controllers/Api/V1/ReportController.php` | daily, expense-estimate, export | Phase 4.5에서 sam_stat 조회로 전환 | +| DailyReportController | `api/app/Http/Controllers/Api/V1/DailyReportController.php` | note-receivables, accounts, summary | Phase 4.5에서 sam_stat 조회로 전환 | +| DashboardService | `api/app/Services/DashboardService.php` (355줄) | 원본 DB에서 실시간 집계 (Attendance, Approval, Deposit, Sale 등) | **핵심 전환 대상** | +| ReportService | `api/app/Services/ReportService.php` | 일일일보, 지출예상 (Excel 내보내기 포함) | 부분 전환 | +| DailyReportService | `api/app/Services/DailyReportService.php` | 어음/외상채권, 계좌현황 | 부분 전환 | +| AiReportService | `api/app/Services/AiReportService.php` | AI 보고서 생성/조회 | 변경 없음 | + +**현재 API 라우트 (변경 없음, 내부 데이터소스만 전환):** +``` +# common.php +GET /api/v1/dashboard/summary → DashboardController@summary +GET /api/v1/dashboard/charts → DashboardController@charts +GET /api/v1/dashboard/approvals → DashboardController@approvals +GET /api/v1/reports/daily → ReportController@daily +GET /api/v1/reports/daily/export → ReportController@dailyExport +GET /api/v1/reports/expense-estimate → ReportController@expenseEstimate + +# finance.php +GET /api/v1/daily-report/note-receivables → DailyReportController@noteReceivables +GET /api/v1/daily-report/daily-accounts → DailyReportController@dailyAccounts +GET /api/v1/daily-report/summary → DailyReportController@summary +``` + +### 0.4 기존 스케줄러 패턴 (따라야 할 패턴) + +```php +// api/routes/console.php (Laravel 12 방식 - Kernel.php 없음) +use Illuminate\Support\Facades\Schedule; + +// 기존 스케줄러: 매일 03:00 API 로그 정리 +Schedule::command('api-log:prune') + ->dailyAt('03:00') + ->appendOutputTo(storage_path('logs/scheduler.log')) + ->onSuccess(function () { Log::info('...'); }) + ->onFailure(function () { Log::error('...'); }); +``` + +### 0.5 기존 Artisan 커맨드 패턴 + +``` +api/app/Console/Commands/ +├── PruneAuditLogs.php # 감사 로그 정리 (참고 패턴) +├── CleanupExpiredLinks.php # 만료 링크 정리 +├── RecordStorageUsage.php # 저장소 사용량 기록 +├── TenantsBootstrap.php # 테넌트 초기화 +└── ... # 총 19개 +``` + +### 0.6 모델 패턴 (따라야 할 패턴) + +```php +// 기존 모델 예시 - 멀티테넌트 + Soft Delete +namespace App\Models\Tenants; + +use App\Models\Scopes\TenantScope; +use Illuminate\Database\Eloquent\SoftDeletes; + +class Deposit extends Model +{ + use SoftDeletes; + + protected $table = 'deposits'; + + protected static function booted(): void + { + static::addGlobalScope(new TenantScope); + } +} + +// 통계 모델은 다른 DB 연결 사용 +// protected $connection = 'sam_stat'; +// TenantScope 대신 tenant_id를 직접 WHERE 조건으로 사용 +``` + +### 0.7 환경별 구성 + +#### 로컬 환경 (Docker) + +```yaml +# docker/docker-compose.yml 내 MySQL 서비스 +# Docker 내부 호스트: sam-mysql-1 +# sam_stat DB는 같은 MySQL 인스턴스에 생성 (별도 서버 불필요) +``` + +```bash +# 로컬 sam_stat DB 생성 +docker compose exec mysql mysql -u root -proot \ + -e "CREATE DATABASE sam_stat CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + +# 로컬 마이그레이션 실행 +docker compose exec api php artisan migrate --database=sam_stat + +# 로컬 시딩 +docker compose exec api php artisan db:seed --class=DimDateSeeder +``` + +#### 개발 서버 (non-Docker, codebridge-x.com) + +> **개발 서버는 Docker를 사용하지 않는다.** +> 로컬에서 코드 작업 후 Git push하면 되지만, 개발 서버에서 아래 **1회 세팅이 필요**하다. + +```bash +# 1. sam_stat DB 생성 (개발 서버 MySQL 직접 접속) +mysql -u [user] -p \ + -e "CREATE DATABASE sam_stat CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + +# 2. .env에 STAT_DB_* 환경변수 추가 (개발 서버의 api/.env) +# STAT_DB_HOST=127.0.0.1 +# STAT_DB_PORT=3306 +# STAT_DB_DATABASE=sam_stat +# STAT_DB_USERNAME=[개발서버 DB 유저] +# STAT_DB_PASSWORD=[개발서버 DB 비밀번호] + +# 3. 마이그레이션 실행 +cd /path/to/api && php artisan migrate --database=sam_stat + +# 4. dim_date 시딩 +php artisan db:seed --class=DimDateSeeder + +# 5. 스케줄러 cron 확인 (이미 등록되어 있다면 추가 불필요) +# * * * * * cd /path/to/api && php artisan schedule:run >> /dev/null 2>&1 +``` + +#### 배포 워크플로우 + +``` +로컬 (Docker, *.sam.kr) + ↓ Git push +개발 서버 (non-Docker, codebridge-x.com) + ↓ 수동 배포 + ↓ 최초 1회: DB 생성 + .env + migrate + seed + cron 확인 + ↓ 이후: git pull → php artisan migrate --database=sam_stat +운영 (TBD) +``` + +**코드에 커밋되는 것:** `config/database.php`, 마이그레이션, 모델, 서비스, 커맨드 +**환경별 수동 설정:** `.env` (STAT_DB_*), DB 생성, cron + +### 0.8 핵심 코딩 규칙 (이 작업에 적용) + +1. **Service-First**: 비즈니스 로직 → Service, Controller는 DI + 호출만 +2. **FormRequest**: Controller에서 직접 검증 금지 +3. **BelongsToTenant**: 원본 모델만 적용, 통계 모델은 tenant_id WHERE 직접 사용 +4. **i18n**: 메시지는 `__('message.xxx')` 형태 +5. **ApiResponse**: `use App\Helpers\ApiResponse;` → `ApiResponse::handle()` +6. **Swagger**: 별도 파일 `api/app/Swagger/v1/{Resource}Api.php`에 작성 +7. **커밋**: 사용자 승인 후에만 커밋 (자동 커밋 금지) + +### 0.9 작업 시작 체크리스트 + +``` +새 세션에서 이 문서를 받았을 때: + +□ 1. 이 문서의 "📍 현재 진행 상태" 확인 +□ 2. Phase별 작업 상태 (⏳/🔄/✅) 확인 +□ 3. Docker 실행 확인: docker compose ps (docker/ 디렉토리) +□ 4. DB 접속 확인: docker compose exec mysql mysql -u root -proot samdb +□ 5. sam_stat DB 존재 여부 확인: SHOW DATABASES LIKE 'sam_stat'; +□ 6. 마이그레이션 상태 확인: cd api && php artisan migrate:status +□ 7. 다음 작업 항목의 "비고" 컬럼 참조하여 작업 시작 +``` + +--- + +## 1. 개요 + +### 1.1 배경 + +SAM ERP는 219개 테이블, 17개 비즈니스 도메인을 가진 종합 제조/건설 ERP 시스템이다. +현재 대시보드(DashboardService, ReportService 등)는 **원본 DB(samdb)에서 실시간 집계**하는 방식으로 동작한다. + +**문제점:** +- 원본 DB에 집계 쿼리 부하 (JOIN, GROUP BY, SUM 등) +- 과거 데이터 추세 분석 불가 (스냅샷 없음) +- 도메인별 KPI 누적 관리 불가 +- 대시보드 응답 속도 저하 가능성 +- 통계 요구사항 증가 시 원본 스키마 오염 + +**해결 방안:** +- `sam_stat` 별도 DB에 사전 집계(pre-aggregated) 통계 데이터 저장 +- 배치/스케줄러로 원본(samdb) → 통계(sam_stat) DB 동기화 +- 원본 DB 부하 분리, 빠른 조회, 이력 보존 + +### 1.2 설계 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 원본 DB 무간섭 - sam_stat은 읽기 전용 파생 데이터 │ +│ 2. 멀티테넌트 유지 - 모든 통계 테이블에 tenant_id 필수 │ +│ 3. 시간축 기반 - 일/주/월/분기/년 단위 집계 지원 │ +│ 4. 확장 가능 - 새 도메인 통계 추가 시 테이블만 추가 │ +│ 5. 멱등성 보장 - 같은 기간 재집계 시 동일 결과 (UPSERT) │ +│ 6. 메타데이터 드리븐 - stat_definitions로 동적 통계 정의 가능 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 통계 필드 추가, 집계 주기 변경, 문서 수정 | 불필요 | +| ⚠️ 컨펌 필요 | 새 통계 테이블 생성, 스케줄러 추가, 마이그레이션 | **필수** | +| 🔴 금지 | 원본 DB 스키마 변경, 원본 테이블에 통계 컬럼 추가 | 별도 협의 | + +--- + +## 2. 분석: 필요한 통계 도메인 + +SAM의 17개 비즈니스 도메인을 분석하여 8개 핵심 통계 영역을 도출했다. + +### 2.1 통계 도메인 매핑 + +| # | 통계 도메인 | 원본 테이블 | 핵심 지표 | 우선순위 | +|---|-----------|-----------|----------|---------| +| 1 | **매출/수주** | orders, order_items, sales, clients | 수주액, 매출액, 수주건수, 고객별 매출 | 🔴 P0 | +| 2 | **재무/회계** | deposits, withdrawals, purchases, bills, bank_transactions | 입출금, 미수/미지급, 자금흐름, 어음현황 | 🔴 P0 | +| 3 | **생산/작업** | work_orders, work_order_items, work_results | 생산량, 작업효율, 불량률, 납기준수율 | 🔴 P0 | +| 4 | **재고/자재** | stocks, stock_transactions, material_receipts, shipments | 재고회전율, 입출고량, 안전재고, 로트추적 | 🟡 P1 | +| 5 | **견적/영업** | quotes, quote_items, sales_prospects, biddings | 수주전환율, 견적성공률, 영업파이프라인 | 🟡 P1 | +| 6 | **인사/근태** | attendance, leaves, payrolls, salaries | 출근율, 근태현황, 인건비, 부서별통계 | 🟡 P1 | +| 7 | **건설/프로젝트** | sites, contracts, expected_expenses, labor_distributions | 프로젝트수익률, 공정진행률, 원가분석 | 🟢 P2 | +| 8 | **시스템/감사** | audit_logs, api_request_logs, fcm_send_logs | API사용량, 사용자활동, 알림발송률 | 🟢 P2 | + +--- + +## 3. sam_stat 데이터베이스 설계 + +### 3.1 아키텍처 개요 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ sam_stat DB │ +├──────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────┐ ┌─────────────────────────────────┐ │ +│ │ 메타 테이블 (2) │ │ 이벤트/팩트 테이블 (2) │ │ +│ │ │ │ │ │ +│ │ stat_definitions │ │ stat_events │ │ +│ │ stat_job_logs │ │ stat_snapshots │ │ +│ └─────────────────────┘ └─────────────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ 도메인별 집계 테이블 (8 도메인) │ │ +│ │ │ │ +│ │ stat_sales_daily stat_inventory_daily │ │ +│ │ stat_finance_daily stat_quote_pipeline_daily │ │ +│ │ stat_production_daily stat_hr_attendance_daily │ │ +│ │ stat_project_monthly stat_system_daily │ │ +│ │ │ │ +│ │ 요약 테이블 (월간/연간) │ │ +│ │ │ │ +│ │ stat_sales_monthly stat_finance_monthly │ │ +│ │ stat_production_monthly stat_kpi_monthly │ │ +│ │ │ │ +│ └───────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────┐ ┌─────────────────────────────────┐ │ +│ │ 차원 테이블 (Dim) │ │ KPI/알림 테이블 │ │ +│ │ │ │ │ │ +│ │ dim_date │ │ stat_kpi_targets │ │ +│ │ dim_client │ │ stat_alerts │ │ +│ │ dim_product │ │ │ │ +│ └─────────────────────┘ └─────────────────────────────────┘ │ +│ │ +│ 총 테이블: 18개 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 데이터 흐름 + +``` +samdb (원본) sam_stat (통계) +┌──────────┐ ┌──────────────┐ +│ orders │──┐ │ │ +│ sales │──┤ Scheduler │ stat_sales_ │ +│ deposits │──┼──(매일 02:00)──→│ daily │ +│ stocks │──┤ │ │ +│ work_ │──┤ │ stat_finance_│ +│ orders │──┘ │ daily │ +│ │ │ │ +│ │ Scheduler │ stat_*_ │ +│ │──(매월 1일)──────→│ monthly │ +│ │ │ │ +│ │ 실시간 이벤트 │ stat_events │ +│ │──(Observer)─────→│ │ +└──────────┘ └──────────────┘ +``` + +--- + +## 4. 테이블 상세 설계 + +### 4.1 메타 테이블 + +#### `stat_definitions` - 통계 정의 (메타데이터 드리븐) + +```sql +CREATE TABLE stat_definitions ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + code VARCHAR(100) NOT NULL UNIQUE, -- 'sales_daily_revenue' + domain VARCHAR(50) NOT NULL, -- 'sales', 'finance', 'production' + name VARCHAR(200) NOT NULL, -- '일일 매출액' + description TEXT NULL, + source_tables JSON NOT NULL, -- ["orders", "order_items", "sales"] + aggregation VARCHAR(20) NOT NULL DEFAULT 'daily', -- daily, weekly, monthly, quarterly, yearly + query_template TEXT NULL, -- 집계 SQL 템플릿 (선택) + is_active BOOLEAN NOT NULL DEFAULT TRUE, + config JSON NULL, -- 추가 설정 (임계값, 단위 등) + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + INDEX idx_domain (domain), + INDEX idx_aggregation (aggregation), + INDEX idx_active (is_active) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `stat_job_logs` - 집계 작업 이력 + +```sql +CREATE TABLE stat_job_logs ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + job_type VARCHAR(100) NOT NULL, -- 'sales_daily', 'finance_monthly' + target_date DATE NOT NULL, -- 집계 대상 날짜 + status ENUM('pending','running','completed','failed') NOT NULL DEFAULT 'pending', + records_processed INT UNSIGNED DEFAULT 0, + error_message TEXT NULL, + started_at TIMESTAMP NULL, + completed_at TIMESTAMP NULL, + duration_ms INT UNSIGNED NULL, + created_at TIMESTAMP NULL, + + INDEX idx_tenant_job (tenant_id, job_type), + INDEX idx_status (status), + INDEX idx_target_date (target_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +--- + +### 4.2 차원 테이블 (Dimension) + +#### `dim_date` - 날짜 차원 + +```sql +CREATE TABLE dim_date ( + date_key DATE PRIMARY KEY, -- '2026-01-29' + year SMALLINT NOT NULL, + quarter TINYINT NOT NULL, -- 1~4 + month TINYINT NOT NULL, + week TINYINT NOT NULL, -- ISO week + day_of_week TINYINT NOT NULL, -- 1(월)~7(일) + day_of_month TINYINT NOT NULL, + is_weekend BOOLEAN NOT NULL, + is_holiday BOOLEAN NOT NULL DEFAULT FALSE, + holiday_name VARCHAR(100) NULL, + fiscal_year SMALLINT NULL, -- 회계연도 + fiscal_quarter TINYINT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `dim_client` - 고객 차원 (스냅샷) + +```sql +CREATE TABLE dim_client ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + client_id BIGINT UNSIGNED NOT NULL, -- 원본 clients.id + client_name VARCHAR(200) NOT NULL, + client_group_id BIGINT UNSIGNED NULL, + client_group_name VARCHAR(200) NULL, + client_type VARCHAR(50) NULL, -- 고객/공급업체/양쪽 + region VARCHAR(100) NULL, + valid_from DATE NOT NULL, + valid_to DATE NULL, -- NULL = 현재 유효 + is_current BOOLEAN NOT NULL DEFAULT TRUE, + + INDEX idx_tenant_client (tenant_id, client_id), + INDEX idx_current (is_current) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `dim_product` - 제품 차원 (스냅샷) + +```sql +CREATE TABLE dim_product ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + product_id BIGINT UNSIGNED NOT NULL, -- 원본 products.id + product_code VARCHAR(100) NOT NULL, + product_name VARCHAR(300) NOT NULL, + product_type VARCHAR(50) NULL, -- PRODUCT/PART/SUBASSEMBLY + category_id BIGINT UNSIGNED NULL, + category_name VARCHAR(200) NULL, + valid_from DATE NOT NULL, + valid_to DATE NULL, + is_current BOOLEAN NOT NULL DEFAULT TRUE, + + INDEX idx_tenant_product (tenant_id, product_id), + INDEX idx_current (is_current) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +--- + +### 4.3 도메인별 집계 테이블 (Fact) + +#### 🔴 P0: `stat_sales_daily` - 매출/수주 일일 통계 + +```sql +CREATE TABLE stat_sales_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- 수주 + order_count INT UNSIGNED DEFAULT 0, -- 신규 수주 건수 + order_amount DECIMAL(18,2) DEFAULT 0, -- 수주 금액 + order_item_count INT UNSIGNED DEFAULT 0, -- 수주 품목 수 + + -- 매출 + sales_count INT UNSIGNED DEFAULT 0, -- 매출 건수 + sales_amount DECIMAL(18,2) DEFAULT 0, -- 매출 금액 + sales_tax_amount DECIMAL(18,2) DEFAULT 0, -- 세액 + + -- 고객 + new_client_count INT UNSIGNED DEFAULT 0, -- 신규 고객 수 + active_client_count INT UNSIGNED DEFAULT 0, -- 활성 고객 수 + + -- 수주 상태별 건수 + order_draft_count INT UNSIGNED DEFAULT 0, + order_confirmed_count INT UNSIGNED DEFAULT 0, + order_in_progress_count INT UNSIGNED DEFAULT 0, + order_completed_count INT UNSIGNED DEFAULT 0, + order_cancelled_count INT UNSIGNED DEFAULT 0, + + -- 출하 + shipment_count INT UNSIGNED DEFAULT 0, + shipment_amount DECIMAL(18,2) DEFAULT 0, + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date), + INDEX idx_tenant (tenant_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🔴 P0: `stat_finance_daily` - 재무 일일 통계 + +```sql +CREATE TABLE stat_finance_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- 입출금 + deposit_count INT UNSIGNED DEFAULT 0, + deposit_amount DECIMAL(18,2) DEFAULT 0, + withdrawal_count INT UNSIGNED DEFAULT 0, + withdrawal_amount DECIMAL(18,2) DEFAULT 0, + net_cashflow DECIMAL(18,2) DEFAULT 0, -- 입금 - 출금 + + -- 매입 + purchase_count INT UNSIGNED DEFAULT 0, + purchase_amount DECIMAL(18,2) DEFAULT 0, + purchase_tax_amount DECIMAL(18,2) DEFAULT 0, + + -- 미수/미지급 + receivable_balance DECIMAL(18,2) DEFAULT 0, -- 미수금 잔액 + payable_balance DECIMAL(18,2) DEFAULT 0, -- 미지급 잔액 + overdue_receivable DECIMAL(18,2) DEFAULT 0, -- 연체 미수금 + + -- 어음 + bill_issued_count INT UNSIGNED DEFAULT 0, + bill_issued_amount DECIMAL(18,2) DEFAULT 0, + bill_matured_count INT UNSIGNED DEFAULT 0, + bill_matured_amount DECIMAL(18,2) DEFAULT 0, + + -- 카드 + card_transaction_count INT UNSIGNED DEFAULT 0, + card_transaction_amount DECIMAL(18,2) DEFAULT 0, + + -- 은행 + bank_balance_total DECIMAL(18,2) DEFAULT 0, -- 전 계좌 잔액 합계 + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🔴 P0: `stat_production_daily` - 생산 일일 통계 + +```sql +CREATE TABLE stat_production_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- 작업지시 + wo_created_count INT UNSIGNED DEFAULT 0, -- 신규 작업지시 + wo_completed_count INT UNSIGNED DEFAULT 0, -- 완료 작업지시 + wo_in_progress_count INT UNSIGNED DEFAULT 0, -- 진행중 + wo_overdue_count INT UNSIGNED DEFAULT 0, -- 납기 초과 + + -- 생산량 + production_qty DECIMAL(18,2) DEFAULT 0, -- 생산 수량 + defect_qty DECIMAL(18,2) DEFAULT 0, -- 불량 수량 + defect_rate DECIMAL(5,2) DEFAULT 0, -- 불량률 (%) + + -- 작업 효율 + planned_hours DECIMAL(10,2) DEFAULT 0, -- 계획 공수 + actual_hours DECIMAL(10,2) DEFAULT 0, -- 실적 공수 + efficiency_rate DECIMAL(5,2) DEFAULT 0, -- 효율 (%) + + -- 작업자 + active_worker_count INT UNSIGNED DEFAULT 0, + issue_count INT UNSIGNED DEFAULT 0, -- 발생 이슈 수 + + -- 납기 + on_time_delivery_count INT UNSIGNED DEFAULT 0, + late_delivery_count INT UNSIGNED DEFAULT 0, + delivery_rate DECIMAL(5,2) DEFAULT 0, -- 납기준수율 (%) + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🟡 P1: `stat_inventory_daily` - 재고 일일 통계 + +```sql +CREATE TABLE stat_inventory_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- 재고 현황 + total_sku_count INT UNSIGNED DEFAULT 0, -- 총 SKU 수 + total_stock_qty DECIMAL(18,2) DEFAULT 0, -- 총 재고 수량 + total_stock_value DECIMAL(18,2) DEFAULT 0, -- 총 재고 금액 + + -- 입출고 + receipt_count INT UNSIGNED DEFAULT 0, -- 입고 건수 + receipt_qty DECIMAL(18,2) DEFAULT 0, + receipt_amount DECIMAL(18,2) DEFAULT 0, + issue_count INT UNSIGNED DEFAULT 0, -- 출고 건수 + issue_qty DECIMAL(18,2) DEFAULT 0, + issue_amount DECIMAL(18,2) DEFAULT 0, + + -- 안전재고 + below_safety_count INT UNSIGNED DEFAULT 0, -- 안전재고 미달 품목 수 + zero_stock_count INT UNSIGNED DEFAULT 0, -- 재고 0 품목 수 + excess_stock_count INT UNSIGNED DEFAULT 0, -- 과잉 재고 품목 수 + + -- 품질검사 + inspection_count INT UNSIGNED DEFAULT 0, + inspection_pass_count INT UNSIGNED DEFAULT 0, + inspection_fail_count INT UNSIGNED DEFAULT 0, + inspection_pass_rate DECIMAL(5,2) DEFAULT 0, -- 합격률 (%) + + -- 재고회전 + turnover_rate DECIMAL(8,2) DEFAULT 0, -- 재고회전율 + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🟡 P1: `stat_quote_pipeline_daily` - 견적/영업 일일 통계 + +```sql +CREATE TABLE stat_quote_pipeline_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- 견적 + quote_created_count INT UNSIGNED DEFAULT 0, + quote_amount DECIMAL(18,2) DEFAULT 0, + quote_approved_count INT UNSIGNED DEFAULT 0, + quote_rejected_count INT UNSIGNED DEFAULT 0, + quote_conversion_count INT UNSIGNED DEFAULT 0, -- 수주 전환 건수 + quote_conversion_rate DECIMAL(5,2) DEFAULT 0, -- 전환율 (%) + + -- 영업 기회 + prospect_created_count INT UNSIGNED DEFAULT 0, + prospect_won_count INT UNSIGNED DEFAULT 0, + prospect_lost_count INT UNSIGNED DEFAULT 0, + prospect_amount DECIMAL(18,2) DEFAULT 0, -- 파이프라인 금액 + + -- 입찰 + bidding_count INT UNSIGNED DEFAULT 0, + bidding_won_count INT UNSIGNED DEFAULT 0, + bidding_amount DECIMAL(18,2) DEFAULT 0, + + -- 상담 + consultation_count INT UNSIGNED DEFAULT 0, + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🟡 P1: `stat_hr_attendance_daily` - 인사/근태 일일 통계 + +```sql +CREATE TABLE stat_hr_attendance_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- 근태 + total_employees INT UNSIGNED DEFAULT 0, -- 전체 직원 수 + attendance_count INT UNSIGNED DEFAULT 0, -- 출근 인원 + late_count INT UNSIGNED DEFAULT 0, -- 지각 + absent_count INT UNSIGNED DEFAULT 0, -- 결근 + attendance_rate DECIMAL(5,2) DEFAULT 0, -- 출근율 (%) + + -- 휴가 + leave_count INT UNSIGNED DEFAULT 0, -- 휴가 사용 + leave_annual_count INT UNSIGNED DEFAULT 0, -- 연차 + leave_sick_count INT UNSIGNED DEFAULT 0, -- 병가 + leave_other_count INT UNSIGNED DEFAULT 0, -- 기타 + + -- 초과근무 + overtime_hours DECIMAL(10,2) DEFAULT 0, + overtime_employee_count INT UNSIGNED DEFAULT 0, + + -- 인건비 (급여 정산 기준) + total_labor_cost DECIMAL(18,2) DEFAULT 0, + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🟢 P2: `stat_project_monthly` - 건설/프로젝트 월간 통계 + +```sql +CREATE TABLE stat_project_monthly ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_year SMALLINT NOT NULL, + stat_month TINYINT NOT NULL, + + -- 프로젝트 현황 + active_site_count INT UNSIGNED DEFAULT 0, + completed_site_count INT UNSIGNED DEFAULT 0, + new_contract_count INT UNSIGNED DEFAULT 0, + contract_total_amount DECIMAL(18,2) DEFAULT 0, + + -- 원가 + expected_expense_total DECIMAL(18,2) DEFAULT 0, + actual_expense_total DECIMAL(18,2) DEFAULT 0, + labor_cost_total DECIMAL(18,2) DEFAULT 0, + material_cost_total DECIMAL(18,2) DEFAULT 0, + + -- 수익률 + gross_profit DECIMAL(18,2) DEFAULT 0, + gross_profit_rate DECIMAL(5,2) DEFAULT 0, -- 수익률 (%) + + -- 이슈 + handover_report_count INT UNSIGNED DEFAULT 0, + structure_review_count INT UNSIGNED DEFAULT 0, + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_year_month (tenant_id, stat_year, stat_month), + INDEX idx_year_month (stat_year, stat_month) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### 🟢 P2: `stat_system_daily` - 시스템 일일 통계 + +```sql +CREATE TABLE stat_system_daily ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_date DATE NOT NULL, + + -- API 사용량 + api_request_count INT UNSIGNED DEFAULT 0, + api_error_count INT UNSIGNED DEFAULT 0, + api_avg_response_ms INT UNSIGNED DEFAULT 0, + + -- 사용자 활동 + active_user_count INT UNSIGNED DEFAULT 0, + login_count INT UNSIGNED DEFAULT 0, + + -- 감사 + audit_create_count INT UNSIGNED DEFAULT 0, + audit_update_count INT UNSIGNED DEFAULT 0, + audit_delete_count INT UNSIGNED DEFAULT 0, + + -- 알림 + fcm_sent_count INT UNSIGNED DEFAULT 0, + fcm_failed_count INT UNSIGNED DEFAULT 0, + + -- 파일 + file_upload_count INT UNSIGNED DEFAULT 0, + file_upload_size_mb DECIMAL(10,2) DEFAULT 0, + + -- 결재 + approval_submitted_count INT UNSIGNED DEFAULT 0, + approval_completed_count INT UNSIGNED DEFAULT 0, + approval_avg_hours DECIMAL(8,2) DEFAULT 0, -- 평균 처리 시간 + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date (tenant_id, stat_date), + INDEX idx_date (stat_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +--- + +### 4.4 월간 요약 테이블 + +#### `stat_sales_monthly` - 매출 월간 요약 + +```sql +CREATE TABLE stat_sales_monthly ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_year SMALLINT NOT NULL, + stat_month TINYINT NOT NULL, + + -- 일일 합산 + order_count INT UNSIGNED DEFAULT 0, + order_amount DECIMAL(18,2) DEFAULT 0, + sales_count INT UNSIGNED DEFAULT 0, + sales_amount DECIMAL(18,2) DEFAULT 0, + shipment_count INT UNSIGNED DEFAULT 0, + shipment_amount DECIMAL(18,2) DEFAULT 0, + + -- 월간 고유 지표 + unique_client_count INT UNSIGNED DEFAULT 0, -- 거래 고객 수 + avg_order_amount DECIMAL(18,2) DEFAULT 0, -- 평균 수주 금액 + top_client_id BIGINT UNSIGNED NULL, -- 최다 거래 고객 + top_client_amount DECIMAL(18,2) DEFAULT 0, + mom_growth_rate DECIMAL(8,2) NULL, -- 전월 대비 성장률 (%) + yoy_growth_rate DECIMAL(8,2) NULL, -- 전년동월 대비 (%) + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_year_month (tenant_id, stat_year, stat_month), + INDEX idx_year_month (stat_year, stat_month) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `stat_finance_monthly` - 재무 월간 요약 + +```sql +CREATE TABLE stat_finance_monthly ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_year SMALLINT NOT NULL, + stat_month TINYINT NOT NULL, + + deposit_total DECIMAL(18,2) DEFAULT 0, + withdrawal_total DECIMAL(18,2) DEFAULT 0, + net_cashflow DECIMAL(18,2) DEFAULT 0, + purchase_total DECIMAL(18,2) DEFAULT 0, + card_total DECIMAL(18,2) DEFAULT 0, + + receivable_end DECIMAL(18,2) DEFAULT 0, -- 월말 미수금 + payable_end DECIMAL(18,2) DEFAULT 0, -- 월말 미지급 + bank_balance_end DECIMAL(18,2) DEFAULT 0, -- 월말 잔액 + + mom_cashflow_change DECIMAL(8,2) NULL, -- 전월 대비 현금흐름 변화 (%) + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_year_month (tenant_id, stat_year, stat_month), + INDEX idx_year_month (stat_year, stat_month) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `stat_production_monthly` - 생산 월간 요약 + +```sql +CREATE TABLE stat_production_monthly ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_year SMALLINT NOT NULL, + stat_month TINYINT NOT NULL, + + wo_total_count INT UNSIGNED DEFAULT 0, + wo_completed_count INT UNSIGNED DEFAULT 0, + production_qty DECIMAL(18,2) DEFAULT 0, + defect_qty DECIMAL(18,2) DEFAULT 0, + avg_defect_rate DECIMAL(5,2) DEFAULT 0, + avg_efficiency_rate DECIMAL(5,2) DEFAULT 0, + avg_delivery_rate DECIMAL(5,2) DEFAULT 0, + total_planned_hours DECIMAL(10,2) DEFAULT 0, + total_actual_hours DECIMAL(10,2) DEFAULT 0, + issue_total_count INT UNSIGNED DEFAULT 0, + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_year_month (tenant_id, stat_year, stat_month), + INDEX idx_year_month (stat_year, stat_month) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +--- + +### 4.5 KPI/알림 테이블 + +#### `stat_kpi_targets` - KPI 목표 설정 + +```sql +CREATE TABLE stat_kpi_targets ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + stat_year SMALLINT NOT NULL, + stat_month TINYINT NULL, -- NULL = 연간 목표 + + domain VARCHAR(50) NOT NULL, -- 'sales', 'production' + metric_code VARCHAR(100) NOT NULL, -- 'monthly_sales_amount' + target_value DECIMAL(18,2) NOT NULL, + unit VARCHAR(20) NOT NULL DEFAULT 'KRW', -- KRW, %, count, hours + description VARCHAR(300) NULL, + + created_by BIGINT UNSIGNED NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_metric (tenant_id, stat_year, stat_month, metric_code), + INDEX idx_domain (domain) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `stat_alerts` - 통계 기반 알림 + +```sql +CREATE TABLE stat_alerts ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + domain VARCHAR(50) NOT NULL, + alert_type VARCHAR(100) NOT NULL, -- 'below_target', 'anomaly', 'threshold' + severity ENUM('info','warning','critical') NOT NULL DEFAULT 'info', + title VARCHAR(300) NOT NULL, + message TEXT NOT NULL, + metric_code VARCHAR(100) NULL, + current_value DECIMAL(18,2) NULL, + threshold_value DECIMAL(18,2) NULL, + is_read BOOLEAN NOT NULL DEFAULT FALSE, + is_resolved BOOLEAN NOT NULL DEFAULT FALSE, + resolved_at TIMESTAMP NULL, + resolved_by BIGINT UNSIGNED NULL, + created_at TIMESTAMP NULL, + + INDEX idx_tenant_unread (tenant_id, is_read), + INDEX idx_severity (severity), + INDEX idx_domain (domain) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +--- + +### 4.6 이벤트/스냅샷 테이블 + +#### `stat_events` - 실시간 이벤트 로그 (확장용) + +```sql +CREATE TABLE stat_events ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + domain VARCHAR(50) NOT NULL, + event_type VARCHAR(100) NOT NULL, -- 'order_created', 'payment_received' + entity_type VARCHAR(100) NOT NULL, -- 'Order', 'Deposit' + entity_id BIGINT UNSIGNED NOT NULL, + payload JSON NULL, -- 이벤트 데이터 + occurred_at TIMESTAMP NOT NULL, + + INDEX idx_tenant_domain (tenant_id, domain), + INDEX idx_occurred (occurred_at), + INDEX idx_entity (entity_type, entity_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +#### `stat_snapshots` - 상태 스냅샷 (특정 시점 전체 상태) + +```sql +CREATE TABLE stat_snapshots ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + snapshot_date DATE NOT NULL, + domain VARCHAR(50) NOT NULL, + snapshot_type VARCHAR(50) NOT NULL DEFAULT 'daily', -- daily, weekly, monthly + data JSON NOT NULL, -- 전체 스냅샷 데이터 + created_at TIMESTAMP NULL, + + UNIQUE KEY uk_tenant_date_domain (tenant_id, snapshot_date, domain, snapshot_type), + INDEX idx_date (snapshot_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +``` + +--- + +## 5. 테이블 요약 + +| # | 테이블명 | 유형 | 도메인 | 집계 주기 | 우선순위 | +|---|---------|------|--------|----------|---------| +| 1 | `stat_definitions` | 메타 | 공통 | - | 🔴 P0 | +| 2 | `stat_job_logs` | 메타 | 공통 | - | 🔴 P0 | +| 3 | `dim_date` | 차원 | 공통 | 1회 생성 | 🔴 P0 | +| 4 | `dim_client` | 차원 | 공통 | SCD Type 2 | 🟡 P1 | +| 5 | `dim_product` | 차원 | 공통 | SCD Type 2 | 🟡 P1 | +| 6 | `stat_sales_daily` | 팩트 | 매출/수주 | 일간 | 🔴 P0 | +| 7 | `stat_finance_daily` | 팩트 | 재무/회계 | 일간 | 🔴 P0 | +| 8 | `stat_production_daily` | 팩트 | 생산/작업 | 일간 | 🔴 P0 | +| 9 | `stat_inventory_daily` | 팩트 | 재고/자재 | 일간 | 🟡 P1 | +| 10 | `stat_quote_pipeline_daily` | 팩트 | 견적/영업 | 일간 | 🟡 P1 | +| 11 | `stat_hr_attendance_daily` | 팩트 | 인사/근태 | 일간 | 🟡 P1 | +| 12 | `stat_project_monthly` | 팩트 | 건설/프로젝트 | 월간 | 🟢 P2 | +| 13 | `stat_system_daily` | 팩트 | 시스템/감사 | 일간 | 🟢 P2 | +| 14 | `stat_sales_monthly` | 요약 | 매출/수주 | 월간 | 🔴 P0 | +| 15 | `stat_finance_monthly` | 요약 | 재무/회계 | 월간 | 🔴 P0 | +| 16 | `stat_production_monthly` | 요약 | 생산/작업 | 월간 | 🔴 P0 | +| 17 | `stat_kpi_targets` | KPI | 공통 | 수동 설정 | 🟡 P1 | +| 18 | `stat_alerts` | 알림 | 공통 | 실시간 | 🟡 P1 | +| 19 | `stat_events` | 이벤트 | 공통 | 실시간 | 🟢 P2 | +| 20 | `stat_snapshots` | 스냅샷 | 공통 | 일/월 | 🟢 P2 | + +**총 20개 테이블** (메타 2 + 차원 3 + 일간팩트 6 + 월간팩트 1 + 월간요약 3 + KPI/알림 2 + 이벤트/스냅샷 2 + 시스템 1) + +--- + +## 6. 구현 계획 (Phase) + +### Phase 1: 인프라 구축 (P0) +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 1.1 | sam_stat DB 생성 및 Laravel 연결 설정 | ✅ | ① Docker MySQL에 `CREATE DATABASE sam_stat` 실행 ② `api/config/database.php`에 `sam_stat` 연결 추가 ③ `api/.env`에 `STAT_DB_*` 환경변수 추가 | +| 1.2 | 메타 테이블 마이그레이션 | ✅ | `stat_definitions`, `stat_job_logs` 마이그레이션 생성 (`--database=sam_stat` 옵션) | +| 1.3 | dim_date 테이블 생성 및 시딩 | ✅ | 2020-01-01~2030-12-31 날짜 데이터 Seeder 작성 (4,018건) | +| 1.4 | 기반 모델 클래스 생성 | ✅ | `BaseStatModel`, `StatDefinition`, `StatJobLog`, `DimDate` 생성 | +| 1.5 | 집계 커맨드 기반 구조 | ✅ | `StatAggregateDailyCommand.php`, `StatAggregateMonthlyCommand.php` 생성 | +| 1.6 | StatAggregatorService 골격 | ✅ | `StatAggregatorService.php` + `StatDomainServiceInterface.php` - 테넌트 순회 + 도메인별 서비스 호출 구조 | + +**Phase 1 검증 방법:** +```bash +# DB 생성 확인 +docker compose exec mysql mysql -u root -proot -e "SHOW DATABASES LIKE 'sam_stat';" + +# 마이그레이션 실행 +cd api && php artisan migrate --database=sam_stat + +# dim_date 시딩 +cd api && php artisan db:seed --class=DimDateSeeder + +# 커맨드 확인 +cd api && php artisan stat:aggregate-daily --help +``` + +### Phase 2: P0 도메인 구축 +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 2.1 | 매출 테이블 마이그레이션 | ✅ | `stat_sales_daily` + `stat_sales_monthly` 마이그레이션 | +| 2.2 | 매출 모델 + 서비스 | ✅ | `StatSalesDaily`, `StatSalesMonthly`, `SalesStatService` - orders, sales, clients, shipments 집계 | +| 2.3 | 재무 테이블 마이그레이션 | ✅ | `stat_finance_daily` + `stat_finance_monthly` 마이그레이션 | +| 2.4 | 재무 모델 + 서비스 | ✅ | `StatFinanceDaily`, `StatFinanceMonthly`, `FinanceStatService` - deposits, withdrawals, purchases, bills, bank_transactions 집계 | +| 2.5 | 생산 테이블 마이그레이션 | ✅ | `stat_production_daily` + `stat_production_monthly` 마이그레이션 | +| 2.6 | 생산 모델 + 서비스 | ✅ | `StatProductionDaily`, `StatProductionMonthly`, `ProductionStatService` - work_orders, work_results 집계 | +| 2.7 | 스케줄러 등록 | ✅ | `console.php`에 `stat:aggregate-daily` (02:00), `stat:aggregate-monthly` (매월 1일 03:00) 등록 | + +**Phase 2 검증 방법:** +```bash +# 수동 집계 실행 (특정 날짜) +cd api && php artisan stat:aggregate-daily --date=2026-01-28 + +# 데이터 확인 +docker compose exec mysql mysql -u root -proot sam_stat \ + -e "SELECT * FROM stat_sales_daily WHERE stat_date='2026-01-28';" +``` + +### Phase 3: P1 도메인 확장 +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 3.1 | 차원 테이블 | ✅ | `dim_client`, `dim_product` 마이그레이션 + 모델 + `DimensionSyncService` (SCD Type 2). 원본: `clients`→`dim_client`, `items`→`dim_product` (products 테이블 없어 items 사용) | +| 3.2 | 재고 통계 | ✅ | `stat_inventory_daily` 마이그레이션 + 모델 + `InventoryStatService` - 원본: `stocks`, `stock_transactions`, `inspections` | +| 3.3 | 견적/영업 통계 | ✅ | `stat_quote_pipeline_daily` 마이그레이션 + 모델 + `QuoteStatService` - 원본: `quotes`, `sales_prospects`, `biddings`, `sales_prospect_consultations` | +| 3.4 | 인사/근태 통계 | ✅ | `stat_hr_attendance_daily` 마이그레이션 + 모델 + `HrStatService` - 원본: `attendances`, `leaves`, `user_tenants` | +| 3.5 | KPI/알림 | ✅ | `stat_kpi_targets`, `stat_alerts` 마이그레이션 + 모델 + `KpiAlertService` + `StatCheckKpiAlertsCommand` + 스케줄러 09:00 | + +### Phase 4: P2 도메인 + API + 대시보드 전환 +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 4.1 | 건설/프로젝트 통계 | ✅ | `stat_project_monthly` 마이그레이션 + 모델 + `ProjectStatService` - 원본: `sites`, `contracts`, `expected_expenses`. 월간 전용 도메인 | +| 4.2 | 시스템 통계 | ✅ | `stat_system_daily` 마이그레이션 + 모델 + `SystemStatService` - 원본: `api_request_logs`, `personal_access_tokens`(user_tenants 조인), `audit_logs`, `fcm_send_logs`, `files`, `approvals` | +| 4.3 | 이벤트/스냅샷 | ✅ | `stat_events`, `stat_snapshots` 마이그레이션 + 모델 + `StatEventService` + `StatEventObserver` (Order, Sale, Deposit, Withdrawal, Purchase, Approval에 등록) | +| 4.4 | 통계 API | ✅ | `StatController` (summary/daily/monthly/alerts) + `StatQueryService` + FormRequest 3개 + `routes/api/v1/stats.php`. Swagger는 Phase 5에서 추가 | +| 4.5 | 대시보드 전환 | ✅ | `DashboardService` getFinanceSummary/getSalesSummary → sam_stat 우선 조회 + 원본 DB 폴백. 응답에 `source` 필드 추가 | + +### Phase 5: 최적화 및 안정화 +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 5.1 | 백필 스크립트 | ✅ | `StatBackfillCommand` - `stat:backfill --from= --to= --domain= --tenant= --skip-monthly --skip-dimensions`. CarbonPeriod 일간 순회 + 월간 집계 + 프로그레스바 + 에러 리포트. 테스트: 7도메인 0.2초 | +| 5.2 | 정합성 검증 | ✅ | `StatVerifyCommand` - `stat:verify --date= --tenant= --domain= --fix`. sales(수주건수/매출금액), finance(입금액/출금액), system(API요청수/감사로그수) 교차 검증. --fix 시 자동 재집계. 테스트: 6건 전부 일치 | +| 5.3 | 파티셔닝 준비 | ✅ | `2026_01_29_300001_prepare_partitioning_daily_tables.php` - 7개 일간 테이블 RANGE COLUMNS(stat_date) 파티셔닝. PK에 stat_date 포함, p2024~p2028 + p_future. 기존 파티션 여부 체크 후 스킵 | +| 5.4 | Redis 캐싱 | ✅ | `StatQueryService` - Cache::remember TTL 5분. 키 패턴: `stat:{daily\|monthly\|dashboard}:{tenantId}:...`. `invalidateCache()` 정적 메서드: Redis keys 패턴 매칭 삭제. 집계 완료 시 StatAggregatorService에서 자동 호출 | +| 5.5 | 모니터링 알림 | ✅ | `StatMonitorService` - recordAggregationFailure(critical), recordMissingData(warning), recordMismatch(critical), resolveAlerts(). StatAggregatorService catch 블록에서 자동 호출. stat_alerts 테이블 연동 검증 완료 | + +### Phase 6: 문서화 및 마무리 +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 6.1 | Swagger API 문서 | ✅ | `app/Swagger/v1/StatApi.php` - Stats 태그, 4개 엔드포인트 (summary/daily/monthly/alerts), StatSalesDaily/StatFinanceDaily/StatDashboardSummary/StatAlert 스키마 정의. `l5-swagger:generate` 성공 | +| 6.2 | DB 스키마 문서 | ✅ | `docs/specs/database-schema.md`에 sam_stat 섹션 추가 - 20개 테이블 (메타 2, 차원 3, 일간 7, 월간 4, KPI/알림/이벤트 4) + Artisan 커맨드 5개 + API 엔드포인트 4개 | +| 6.3 | 계획 문서 완료 | ✅ | Phase 6 섹션 추가, 진행률 100%, 상태 완료 | + +--- + +## 7. 기술 설계 요약 + +### 7.1 Laravel 다중 DB 연결 + +```php +// config/database.php +'connections' => [ + 'mysql' => [ /* 기존 samdb */ ], + 'sam_stat' => [ + 'driver' => 'mysql', + 'host' => env('STAT_DB_HOST', '127.0.0.1'), + 'database' => env('STAT_DB_DATABASE', 'sam_stat'), + 'username' => env('STAT_DB_USERNAME', 'root'), + 'password' => env('STAT_DB_PASSWORD', ''), + // ... 나머지 동일 + ], +], +``` + +### 7.2 모델 구조 + +``` +api/app/Models/Stats/ +├── StatDefinition.php // connection = 'sam_stat' +├── StatJobLog.php +├── Dimensions/ +│ ├── DimDate.php +│ ├── DimClient.php +│ └── DimProduct.php +├── Daily/ +│ ├── StatSalesDaily.php +│ ├── StatFinanceDaily.php +│ ├── StatProductionDaily.php +│ ├── StatInventoryDaily.php +│ ├── StatQuotePipelineDaily.php +│ ├── StatHrAttendanceDaily.php +│ └── StatSystemDaily.php +├── Monthly/ +│ ├── StatSalesMonthly.php +│ ├── StatFinanceMonthly.php +│ ├── StatProductionMonthly.php +│ └── StatProjectMonthly.php +├── StatKpiTarget.php +├── StatAlert.php +├── StatEvent.php +└── StatSnapshot.php +``` + +### 7.3 서비스 구조 + +``` +api/app/Services/Stats/ +├── StatAggregatorService.php // 집계 오케스트레이터 +├── SalesStatService.php // 매출/수주 집계 +├── FinanceStatService.php // 재무 집계 +├── ProductionStatService.php // 생산 집계 +├── InventoryStatService.php // 재고 집계 +├── QuoteStatService.php // 견적/영업 집계 +├── HrStatService.php // 인사/근태 집계 +├── ProjectStatService.php // 건설 집계 +├── SystemStatService.php // 시스템 집계 +└── KpiAlertService.php // KPI 목표 대비 알림 +``` + +### 7.4 스케줄러 구조 + +```php +// app/Console/Kernel.php (또는 routes/console.php) + +// 일간 집계 - 매일 02:00 +Schedule::command('stat:aggregate-daily') + ->dailyAt('02:00') + ->withoutOverlapping(); + +// 월간 집계 - 매월 1일 03:00 +Schedule::command('stat:aggregate-monthly') + ->monthlyOn(1, '03:00') + ->withoutOverlapping(); + +// KPI 알림 체크 - 매일 09:00 +Schedule::command('stat:check-kpi-alerts') + ->dailyAt('09:00'); +``` + +### 7.5 집계 패턴 (UPSERT) + +```php +// 멱등성 보장: 같은 날짜 재실행 시 덮어쓰기 +StatSalesDaily::updateOrCreate( + ['tenant_id' => $tenantId, 'stat_date' => $date], + [ + 'order_count' => $orderCount, + 'order_amount' => $orderAmount, + // ... + ] +); +``` + +--- + +## 8. 참고 문서 + +| 문서 | 경로 | 용도 | +|------|------|------| +| DB 스키마 | `docs/specs/database-schema.md` | 원본 219개 테이블 구조 | +| 시스템 아키텍처 | `docs/architecture/system-overview.md` | 전체 시스템 구조, 미들웨어, Docker | +| API 규칙 | `docs/standards/api-rules.md` | Controller/Service 패턴, ApiResponse | +| 품질 체크리스트 | `docs/standards/quality-checklist.md` | 코드 품질 검증 항목 | +| 빠른 시작 | `docs/quickstart/quick-start.md` | 핵심 개발 규칙 3가지 | +| Swagger 가이드 | `docs/guides/swagger-guide.md` | Swagger 작성 규칙 (Phase 4.4 시) | +| Git 규칙 | `docs/standards/git-conventions.md` | 커밋 메시지 형식 | +| 프로젝트 CLAUDE.md | `/SAM/CLAUDE.md` | 프로젝트 전체 규칙 및 맥락 | +| API CLAUDE.md | `/SAM/api/CLAUDE.md` | API 저장소 상세 규칙 | + +--- + +## 9. 자기완결성 점검 결과 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 섹션 1.1: sam_stat 별도 DB로 통계 분리 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 20개 테이블, 8 도메인, Phase별 검증 방법 명시 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 4: 테이블별 DDL, 섹션 6: Phase별 구체적 작업 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 섹션 2.1: 원본 테이블 매핑, 섹션 0.2: DB 환경 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 0.1, 0.3: 실제 파일 경로 검증됨 (2026-01-29) | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | Phase 1-5 구체적 작업 + bash 검증 커맨드 포함 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | Phase 1, 2에 검증 bash 커맨드 블록 포함 | +| 8 | 모호한 표현이 없는가? | ✅ | 파일 경로, 클래스명, 테이블명 모두 구체적 | + +### 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 0.9 체크리스트 → 6. Phase 1 | +| Q3. 어떤 파일을 수정/생성해야 하는가? | ✅ | 0.1 프로젝트 구조 + 7.1~7.5 기술 설계 | +| Q4. 기존 코드에 어떤 영향이 있는가? | ✅ | 0.3 기존 대시보드/보고서 시스템 | +| Q5. DB 연결은 어떻게 설정하는가? | ✅ | 0.2 현재 DB 환경 + 7.1 Laravel 다중 DB | +| Q6. 코딩 규칙은 무엇인가? | ✅ | 0.8 핵심 코딩 규칙 | +| Q7. 작업 완료 확인 방법은? | ✅ | Phase 1, 2 검증 방법 블록 | +| Q8. 스케줄러는 어떻게 등록하는가? | ✅ | 0.4 기존 스케줄러 패턴 + 7.4 | +| Q9. Docker 환경은 어떻게 구성되어 있는가? | ✅ | 0.7 Docker 환경 | +| Q10. 막혔을 때 참고 문서는? | ✅ | 8. 참고 문서 (9개 문서 매핑) | + +**결과**: 10/10 통과 → ✅ 자기완결성 확보 + +--- + +## 10. 변경 이력 + +| 날짜 | 항목 | 내용 | +|------|------|------| +| 2026-01-29 | 초안 작성 | 프로젝트 분석 → 8개 도메인 도출 → 20개 테이블 설계 | +| 2026-01-29 | 자기완결성 보완 | 섹션 0 추가 (프로젝트 컨텍스트, DB 환경, 기존 시스템, 코딩 규칙, 체크리스트) | +| 2026-01-29 | 환경별 배포 구분 | 섹션 0.7 확장: 로컬(Docker) vs 개발서버(non-Docker) 구분, 배포 워크플로우 추가 | +| 2026-01-29 | Phase 1 완료 | 인프라 구축: sam_stat DB 생성, 메타/dim_date 마이그레이션, 기반 모델 4개, 커맨드 2개, AggregatorService + Interface | +| 2026-01-29 | Phase 2 완료 | P0 도메인: 매출/재무/생산 일간+월간 테이블 6개, 모델 6개, 서비스 3개, 스케줄러 2개 등록. 실데이터 집계 검증 완료 | +| 2026-01-29 | Phase 3 완료 | P1 도메인: dim_client/dim_product 차원 + 재고/견적/인사 일간 3개 + KPI/알림 2개 = 테이블 7개, 모델 7개, 서비스 4개(Dimension/Inventory/Quote/Hr/KpiAlert), 커맨드 1개, 스케줄러 1개. 실데이터 검증 완료. products→items, client_groups.name→group_name 수정 | +| 2026-01-29 | Phase 4 완료 | P2 도메인 + API + 대시보드: stat_project_monthly/stat_system_daily/stat_events/stat_snapshots 테이블 4개, 모델 4개, 서비스 4개(Project/System/StatEvent/StatQuery), StatController + FormRequest 3개 + routes/stats.php, StatEventObserver(6모델), DashboardService sam_stat 전환(폴백 패턴). 버그: whereHas→DB Builder 제거, User모델경로 수정. sam_stat 총 20테이블 | +| 2026-01-29 | Phase 5 완료 | 최적화 및 안정화: StatBackfillCommand(백필), StatVerifyCommand(정합성 검증+자동 재집계), 파티셔닝 준비 마이그레이션(7테이블 RANGE), StatQueryService Redis 캐싱(TTL 5분+invalidateCache), StatMonitorService(집계 실패/누락/불일치 알림→stat_alerts), StatAggregatorService에 모니터링+캐시 무효화 연동. severity enum 수정(high→critical). 전체 테스트 통과 | +| 2026-01-30 | Phase 6 완료 | 문서화 및 마무리: StatApi.php Swagger 문서(4 엔드포인트, 4 스키마), database-schema.md sam_stat 섹션 추가(20테이블+5커맨드+4API). 전체 6 Phase 100% 완료 | + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/simulator-calculation-logic-mapping.md b/plans/archive/simulator-calculation-logic-mapping.md new file mode 100644 index 0000000..113c198 --- /dev/null +++ b/plans/archive/simulator-calculation-logic-mapping.md @@ -0,0 +1,1057 @@ +# 견적 시뮬레이터 완전 동기화 계획 + +> **작성일**: 2025-12-23 (업데이트: 2025-12-30) +> **목표**: design.sam.kr 시뮬레이터와 mng 시뮬레이터가 **동일한 결과**를 출력하도록 완전 동기화 + +--- + +## 1. Design 시스템 전체 분석 + +### 1.1 핵심 파일 구조 + +| 파일 | 줄 수 | 역할 | +|------|-------|------| +| `AutoCalculationSimulator.tsx` | 1,068 | 메인 시뮬레이터 UI + 계산 로직 | +| `formulaEvaluator.ts` | 312 | 수식 평가 엔진 | +| `bomCalculatorWithDebug.ts` | 232 | BOM 계산 + 10단계 디버깅 | +| `DataContext.tsx` | 9,859 | 마스터 데이터 타입 + 상태 관리 | +| `sampleQuoteData_Complete.ts` | 600+ | 샘플 품목 데이터 | +| `addProductBoms.ts` | 298 | 완제품 BOM 구성 | + +### 1.2 데이터 구조 (TypeScript 인터페이스) + +#### 품목 마스터 (ItemMaster) +```typescript +interface ItemMaster { + id: string; + itemCode: string; // 품목코드 + itemName: string; // 품목명 + itemType: 'FG' | 'SF' | 'PT' | 'SM' | 'RM' | 'CS'; + productCategory?: 'SCREEN' | 'STEEL'; // 제품 카테고리 + partType?: 'ASSEMBLY' | 'BENDING' | 'PURCHASED'; + unit: string; + salesPrice?: number; // 판매단가 + purchasePrice?: number; // 매입단가 + marginRate?: number; // 마진율 + bom?: BOMLine[]; // 하위 BOM 목록 + // ... 기타 필드 +} +``` + +#### BOM 라인 (BOMLine) +```typescript +interface BOMLine { + childItemCode: string; // 자식 품목 코드 + childItemName: string; // 자식 품목명 + quantity: number; // 기준 수량 + unit: string; // 단위 + quantityFormula?: string; // 수량 수식 (예: "W*H/1000000", "H/1000") + note?: string; // 비고 +} +``` + +#### 단가 관리 (PricingData) +```typescript +interface PricingData { + id: string; + itemId: string; + itemCode: string; + purchasePrice?: number; // 매입단가 + processingCost?: number; // 가공비 + loss?: number; // LOSS(%) + marginRate?: number; // 마진율 + salesPrice?: number; // 판매단가 + effectiveDate: string; // 적용일 + status: 'draft' | 'active' | 'inactive' | 'finalized'; +} +``` + +#### 카테고리 그룹 (CategoryGroup) - MNG에 누락 +```typescript +interface CategoryGroup { + id: string; + name: string; // "면적기반", "중량기반", "수량기반" + categories: string[]; // 소속 카테고리들 + multiplierVariable?: string; // 곱할 변수 (M, K 등) +} +``` + +### 1.3 계산 변수 체계 + +| 변수 | 설명 | 계산식 | +|------|------|--------| +| `W0` | 오픈사이즈 폭 | 사용자 입력 | +| `H0` | 오픈사이즈 높이 | 사용자 입력 | +| `PC` | 제품 카테고리 | "스크린" / "철재" | +| `W1` | 제작폭 | PC=="스크린" ? W0+140 : W0+110 | +| `H1` | 제작높이 | H0 + 350 | +| `W` | 제작폭 (별칭) | = W1 | +| `H` | 제작높이 (별칭) | = H1 | +| `M` | 면적 (㎡) | (W1 × H1) / 1,000,000 | +| `K` | 중량 (kg) | 스크린: M×2 + W0/1000×14.17, 철재: M×25 | +| `GT` | 가이드레일 설치유형 | "벽면형" / "측면형" | +| `MP` | 모터 전원 | "220V" / "380V" | +| `CT` | 연동제어기 | "단독" / "연동" | +| `QTY` | 수량 | 사용자 입력 | + +### 1.4 수식 평가 함수 + +**지원 함수 목록:** +| 함수 | 설명 | 예시 | +|------|------|------| +| `SUM(a, b, ...)` | 합계 | `SUM(W0, H0, 100)` | +| `AVERAGE(a, b, ...)` | 평균 | `AVERAGE(W0, H0)` | +| `MAX(a, b, ...)` | 최대값 | `MAX(W0, 1000)` | +| `MIN(a, b, ...)` | 최소값 | `MIN(H0, 3000)` | +| `ROUND(val, dec)` | 반올림 | `ROUND(M, 2)` | +| `CEIL(val)` | 올림 | `CEIL(H1 / 1000)` | +| `FLOOR(val)` | 내림 | `FLOOR(W1 / 500)` | +| `ABS(val)` | 절대값 | `ABS(W0 - 2000)` | +| `IF(cond, t, f)` | 조건문 | `IF(W0 > 3000, 2, 1)` | +| `SQRT(val)` | 제곱근 | `SQRT(M)` | +| `POWER(base, exp)` | 거듭제곱 | `POWER(W1, 2)` | + +**평가 과정:** +```typescript +// 1. 변수 치환 (긴 변수명부터) +const sortedVars = Object.keys(vars).sort((a, b) => b.length - a.length); +sortedVars.forEach(varName => { + const regex = new RegExp(`\\b${varName}\\b`, 'g'); + formula = formula.replace(regex, String(vars[varName])); +}); + +// 2. 함수 처리 (CEIL, FLOOR, ROUND 등) +formula = processFunctions(formula); + +// 3. 최종 계산 +return new Function(`return (${formula})`)(); +``` + +### 1.5 BOM 계산 10단계 프로세스 + +| 단계 | 항목 | 예시 | +|------|------|------| +| Step 1 | 수량 공식 확인 | `H/1000` | +| Step 2 | 변수 값 확인 | `{W0:2000, H0:2500, W1:2140, H1:2850, M:6.099}` | +| Step 3 | 수량 계산 과정 | `H/1000 = 2850/1000 = 2.85` | +| Step 4 | 계산된 수량 | `2.85` | +| Step 5 | 단가 소스 | `단가관리 (15,000원)` 또는 `품목마스터 (15,000원)` | +| Step 6 | 기본 단가 | `15,000` | +| Step 7 | 카테고리 승수 | `면적단가 (15,000원/㎡ × 6.099㎡)` | +| Step 8 | 최종 단가 | `91,485` | +| Step 9 | 금액 계산 | `2.85 × 91,485 = 260,732` | +| Step 10 | 최종 금액 | `260,732` | + +### 1.6 단가 계산 로직 + +```typescript +// 1. 단가 조회 우선순위 +let unitPrice = 0; +let priceSource = '단가 없음'; + +// 1순위: pricing 테이블에서 조회 +const itemPricing = pricings.find(p => p.itemCode === bomEntry.childItemCode); +if (itemPricing && itemPricing.salesPrice) { + unitPrice = itemPricing.salesPrice; + priceSource = `단가관리 (${unitPrice.toLocaleString()}원)`; +} +// 2순위: 품목마스터에서 조회 +else if (childItem.salesPrice) { + unitPrice = childItem.salesPrice; + priceSource = `품목마스터 (${unitPrice.toLocaleString()}원)`; +} + +// 2. 면적 기반 품목 판단 +const areaBasedCategories = ['원단', '패널', '도장', '표면처리']; +const isAreaBased = areaBasedCategories.some(cat => + itemCategory.includes(cat) || childItem.itemName.includes(cat) +); + +// 3. 최종 단가 계산 +let finalUnitPrice = unitPrice; +if (isAreaBased && calculationVariables.M > 0) { + finalUnitPrice = unitPrice * calculationVariables.M; // 면적 단가 + priceCalculationNote = `면적단가 (${unitPrice}원/㎡ × ${M}㎡)`; +} else { + priceCalculationNote = '수량단가'; +} + +// 4. 최종 금액 +const totalPrice = calculatedQuantity * finalUnitPrice; +``` + +--- + +## 2. Design 샘플 데이터 분석 + +### 2.1 품목 구성 (약 100개) + +| 유형 | 코드 접두사 | 수량 | 설명 | +|------|------------|------|------| +| 원자재 (RM) | RM-* | 20 | 강판, 알루미늄, 원단, 패킹 등 | +| 부자재 (SM) | SM-* | 25 | 볼트, 너트, 전선, 실리콘 등 | +| 스크린 반제품 (SF) | SF-SCR-* | 20 | 원단, 가이드레일, 케이스, 모터 등 | +| 철재 반제품 (SF) | SF-STL-*, SF-BND-* | 20 | 도어, 프레임, 패널, 절곡 부품 등 | +| 스크린 완제품 (FG) | FG-SCR-* | 5 | 소형/중형/대형/특대/맞춤형 | +| 철재 완제품 (FG) | FG-STL-* | 5 | 소형/중형/대형/양개문/특수 | +| 절곡 완제품 (FG) | FG-BND-* | 4 | L형/U형/Z형/ㄷ형 | + +### 2.2 주요 BOM 수식 패턴 + +| 품목 유형 | 수식 | 설명 | +|----------|------|------| +| 스크린 원단 | `W*H/1000000` | 면적 계산 | +| 가이드레일 | `H/1000` | 높이(m) 기준 | +| 엣지윙 | `H/1000` | 높이(m) 기준 | +| 철재 프레임 | `(W+H)*2/1000` | 둘레(m) 기준 | +| 철재 패널 | `W*H/1000000` | 면적 계산 | +| 실링재 | `(W+H)*2/1000` | 둘레(m) 기준 | +| 파우더 도장 | `W*H/1000000` | 면적 계산 | + +### 2.3 완제품 BOM 예시 (FG-SCR-002 중형 스크린) + +```typescript +{ + itemCode: 'FG-SCR-002', + itemName: '방화스크린 중형 (2000x3000)', + bom: [ + { childItemCode: 'SF-SCR-F01', quantity: 6.0, unit: 'M2', quantityFormula: 'W*H/1000000' }, + { childItemCode: 'SF-SCR-F02', quantity: 3.0, unit: 'M', quantityFormula: 'H/1000' }, + { childItemCode: 'SF-SCR-F03', quantity: 3.0, unit: 'M', quantityFormula: 'H/1000' }, + { childItemCode: 'SF-SCR-F04', quantity: 1, unit: 'EA' }, + { childItemCode: 'SF-SCR-F05', quantity: 1, unit: 'EA' }, + { childItemCode: 'SF-SCR-M02', quantity: 1, unit: 'EA', note: '중형용' }, + { childItemCode: 'SF-SCR-C01', quantity: 1, unit: 'EA' }, + { childItemCode: 'SF-SCR-S01', quantity: 1, unit: 'SET' }, + { childItemCode: 'SF-SCR-W01', quantity: 1, unit: 'EA' }, + { childItemCode: 'SF-SCR-B01', quantity: 2, unit: 'SET', note: '중형용 2세트' }, + { childItemCode: 'SF-SCR-E01', quantity: 3.0, unit: 'M', quantityFormula: 'H/1000' }, + { childItemCode: 'SF-SCR-E02', quantity: 3.0, unit: 'M', quantityFormula: 'H/1000' }, + { childItemCode: 'SF-SCR-REM01', quantity: 1, unit: 'EA' }, + { childItemCode: 'SM-B002', quantity: 30, unit: 'EA', note: '조립용' }, + { childItemCode: 'SM-N002', quantity: 30, unit: 'EA' }, + { childItemCode: 'SM-A001', quantity: 8, unit: 'EA', note: '고정용' }, + ] +} +``` + +--- + +## 3. MNG 현재 상태 분석 + +### 3.1 테이블 구조 + +| 테이블 | 현재 상태 | Design 대응 | +|--------|----------|-------------| +| `items` | 364개 (RM:133, SM:217, PT:6, FG:3, CS:5) | ItemMaster | +| `item_details` | 품목 상세 정보 | ItemMaster 확장 필드 | +| `prices` | 3개 (거의 없음) | PricingData | +| `quote_formulas` | 57개 (기본 변수 있음) | FormulaRule, CalculationFormula | +| `quote_formula_ranges` | 범위 규칙 | FormulaRule.ranges | +| `quote_formula_items` | 수식 품목 매핑 | BOM 연동 | +| `common_codes` | 코드 그룹 | CategoryGroup (부분) | +| `category_groups` | ❌ 없음 | CategoryGroup 추가 필요 | + +### 3.2 quote_formulas 현재 데이터 (샘플) + +``` +[PC] 제품카테고리 (input) => variable +[W0] 가로 (W0) (input) => variable +[H0] 세로 (H0) (input) => variable +[W1_SCREEN] 제작사이즈 W1 (스크린): W0 + 140 => variable +[H1_SCREEN] 제작사이즈 H1 (스크린): H0 + 350 => variable +[W1_STEEL] 제작사이즈 W1 (철재): W0 + 110 => variable +[H1_STEEL] 제작사이즈 H1 (철재): H0 + 350 => variable +[M] 면적 계산: W1 * H1 / 1000000 => variable +[K_SCREEN] 중량 계산 (스크린): M * 2 + W0 / 1000 * 14.17 => variable +[K_STEEL] 중량 계산 (철재): M * 25 => variable +``` + +### 3.3 누락 항목 + +| 항목 | 설명 | 우선순위 | +|------|------|---------| +| `items.process_type` | 공정유형 (스크린/절곡/전기) | 높음 | +| `items.item_category` | 품목분류 (원단/패널/도장 등) | 높음 | +| `category_groups` 테이블 | 면적/중량 기반 분류 | 높음 | +| Design 샘플 품목 데이터 | 100개 품목 Seeder | 높음 | +| BOM 구성 데이터 | 제품별 BOM Seeder | 높음 | +| 단가 데이터 | 품목별 단가 Seeder | 중간 | + +--- + +## 4. 완전 동기화 구현 계획 + +### Phase 1: DB 스키마 확장 (1일) + +#### 1.1 items 테이블 필드 추가 +```sql +ALTER TABLE items ADD COLUMN process_type VARCHAR(20) DEFAULT NULL + COMMENT '공정유형: screen(스크린), bending(절곡), electric(전기), steel(철재)'; + +ALTER TABLE items ADD COLUMN item_category VARCHAR(50) DEFAULT NULL + COMMENT '품목분류: 원단, 패널, 도장, 표면처리, 가이드레일, 케이스, 모터, 제어반 등'; + +CREATE INDEX idx_items_process_type ON items(process_type); +CREATE INDEX idx_items_item_category ON items(item_category); +``` + +#### 1.2 category_groups 테이블 생성 +```sql +CREATE TABLE category_groups ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL, + code VARCHAR(50) NOT NULL COMMENT '코드: area_based, weight_based, quantity_based', + name VARCHAR(100) NOT NULL COMMENT '이름: 면적기반, 중량기반, 수량기반', + multiplier_variable VARCHAR(20) COMMENT '곱셈 변수: M, K, null', + categories JSON COMMENT '소속 카테고리 목록', + description TEXT, + sort_order INT DEFAULT 0, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + INDEX idx_tenant (tenant_id), + INDEX idx_code (code) +); +``` + +### Phase 2: Seeder 작성 (2일) + +#### 2.1 품목 마스터 Seeder + +**파일**: `database/seeders/DesignItemSeeder.php` + +```php +class DesignItemSeeder extends Seeder +{ + public function run(): void + { + // 원자재 (20개) + $rawMaterials = [ + ['code' => 'RM-S001', 'name' => '강판 1.2T', 'unit' => 'KG', 'price' => 3500, 'category' => '강판'], + ['code' => 'RM-F001', 'name' => '방화원단 A급', 'unit' => 'M2', 'price' => 28000, 'category' => '원단'], + // ... 18개 더 + ]; + + // 부자재 (25개) + $subMaterials = [ + ['code' => 'SM-B001', 'name' => '볼트 M8x30', 'unit' => 'EA', 'price' => 150, 'category' => '볼트'], + // ... 24개 더 + ]; + + // 스크린 반제품 (20개) + $screenSemiProducts = [ + ['code' => 'SF-SCR-F01', 'name' => '스크린 원단', 'unit' => 'M2', 'price' => 35000, 'category' => '원단', 'process' => 'screen'], + ['code' => 'SF-SCR-F02', 'name' => '가이드레일 (좌)', 'unit' => 'M', 'price' => 42000, 'category' => '가이드레일', 'process' => 'screen'], + // ... 18개 더 + ]; + + // 완제품 (14개) + $finishedProducts = [ + ['code' => 'FG-SCR-001', 'name' => '방화스크린 소형', 'category' => 'SCREEN'], + ['code' => 'FG-SCR-002', 'name' => '방화스크린 중형', 'category' => 'SCREEN'], + // ... 12개 더 + ]; + } +} +``` + +#### 2.2 BOM 구성 Seeder + +**파일**: `database/seeders/DesignBomSeeder.php` + +```php +class DesignBomSeeder extends Seeder +{ + public function run(): void + { + $bomData = [ + 'FG-SCR-002' => [ + ['child' => 'SF-SCR-F01', 'qty' => 1, 'formula' => 'W*H/1000000', 'unit' => 'M2'], + ['child' => 'SF-SCR-F02', 'qty' => 1, 'formula' => 'H/1000', 'unit' => 'M'], + ['child' => 'SF-SCR-F03', 'qty' => 1, 'formula' => 'H/1000', 'unit' => 'M'], + ['child' => 'SF-SCR-F04', 'qty' => 1, 'formula' => '', 'unit' => 'EA'], + // ... 더 많은 BOM 라인 + ], + // ... 다른 제품들 + ]; + } +} +``` + +#### 2.3 CategoryGroup Seeder + +```php +class CategoryGroupSeeder extends Seeder +{ + public function run(): void + { + $groups = [ + [ + 'code' => 'area_based', + 'name' => '면적기반', + 'multiplier_variable' => 'M', + 'categories' => json_encode(['원단', '패널', '도장', '표면처리']), + ], + [ + 'code' => 'weight_based', + 'name' => '중량기반', + 'multiplier_variable' => 'K', + 'categories' => json_encode(['강판', '알루미늄']), + ], + [ + 'code' => 'quantity_based', + 'name' => '수량기반', + 'multiplier_variable' => null, + 'categories' => json_encode(['볼트', '너트', '모터', '제어반']), + ], + ]; + } +} +``` + +### Phase 3: 백엔드 로직 확장 (2일) + +#### 3.1 FormulaEvaluatorService 확장 + +**추가할 메서드:** + +```php +/** + * 카테고리 기반 단가 계산 + */ +private function calculateCategoryPrice( + array $item, + float $basePrice, + array $variables +): array { + $categoryGroup = CategoryGroup::query() + ->whereJsonContains('categories', $item['item_category'] ?? '') + ->first(); + + if (!$categoryGroup || !$categoryGroup->multiplier_variable) { + return [ + 'final_price' => $basePrice, + 'calculation_note' => '수량단가', + 'multiplier' => 1, + ]; + } + + $multiplierVar = $categoryGroup->multiplier_variable; + $multiplierValue = $variables[$multiplierVar] ?? 1; + + return [ + 'final_price' => $basePrice * $multiplierValue, + 'calculation_note' => "{$categoryGroup->name} ({$basePrice}원/{$this->getUnit($multiplierVar)} × {$multiplierValue})", + 'multiplier' => $multiplierValue, + ]; +} + +/** + * 공정별 품목 그룹화 + */ +private function groupItemsByProcess(array $items): array +{ + $processOrder = [ + 'screen' => ['label' => '스크린 공정', 'items' => [], 'subtotal' => 0], + 'bending' => ['label' => '절곡 공정', 'items' => [], 'subtotal' => 0], + 'electric' => ['label' => '전기 공정', 'items' => [], 'subtotal' => 0], + 'assembly' => ['label' => '조립 공정', 'items' => [], 'subtotal' => 0], + 'etc' => ['label' => '기타', 'items' => [], 'subtotal' => 0], + ]; + + foreach ($items as $item) { + $process = $item['process_type'] ?? 'etc'; + if (isset($processOrder[$process])) { + $processOrder[$process]['items'][] = $item; + $processOrder[$process]['subtotal'] += $item['total_price'] ?? 0; + } else { + $processOrder['etc']['items'][] = $item; + $processOrder['etc']['subtotal'] += $item['total_price'] ?? 0; + } + } + + return array_filter($processOrder, fn($g) => count($g['items']) > 0); +} + +/** + * 10단계 디버깅 정보 생성 + */ +private function generateDebugInfo( + array $bomLine, + array $variables, + float $calculatedQty, + float $basePrice, + float $finalPrice, + float $totalPrice, + string $priceSource, + string $calcNote +): array { + return [ + 'step1_formula' => $bomLine['quantity_formula'] ?? '수식 없음', + 'step2_variables' => $variables, + 'step3_quantity_calc' => $this->buildQuantityCalcString($bomLine, $variables, $calculatedQty), + 'step4_quantity' => $calculatedQty, + 'step5_price_source' => $priceSource, + 'step6_base_price' => $basePrice, + 'step7_category_multiplier' => $calcNote, + 'step8_final_price' => $finalPrice, + 'step9_total_calc' => sprintf('%.2f × %s = %s', $calculatedQty, number_format($finalPrice), number_format($totalPrice)), + 'step10_total' => $totalPrice, + ]; +} +``` + +#### 3.2 executeAll() 반환 구조 확장 + +```php +public function executeAll(array $inputVariables): array +{ + // 1. 변수 계산 + $calculatedVariables = $this->calculateVariables($inputVariables); + + // 2. 제품 BOM 조회 + $product = Item::where('code', $inputVariables['PRODUCT_ID'])->first(); + $bomTree = $this->getBomTree($product); + + // 3. BOM 항목별 계산 + $bomItems = []; + foreach ($bomTree as $bomLine) { + $result = $this->calculateBomItem($bomLine, $calculatedVariables); + $bomItems[] = $result; + } + + // 4. 공정별 그룹화 + $groupedByProcess = $this->groupItemsByProcess($bomItems); + + // 5. 총합계 + $totalAmount = array_sum(array_column($bomItems, 'total_price')); + + return [ + 'input_variables' => $inputVariables, + 'calculated_variables' => $calculatedVariables, + 'product' => [ + 'code' => $product->code, + 'name' => $product->name, + 'category' => $product->item_details->product_category ?? null, + ], + 'bom_items' => $bomItems, + 'grouped_by_process' => $groupedByProcess, + 'summary' => [ + 'total_items' => count($bomItems), + 'total_amount' => $totalAmount, + ], + ]; +} +``` + +### Phase 4: 프론트엔드 확장 (1일) + +#### 4.1 simulator.blade.php 결과 표시 개선 + +```blade +{{-- 공정별 그룹화 결과 --}} +@if(isset($result['grouped_by_process'])) +
    + @foreach($result['grouped_by_process'] as $processCode => $group) +
    +
    +

    {{ $group['label'] }}

    + + 소계: {{ number_format($group['subtotal']) }}원 + +
    + + + + + + + + + + + + + @foreach($group['items'] as $item) + + + + + + + + + @endforeach + +
    품목코드품목명수량단위단가금액
    {{ $item['item_code'] }}{{ $item['item_name'] }}{{ number_format($item['calculated_quantity'], 2) }}{{ $item['unit'] }}{{ number_format($item['final_price']) }}{{ number_format($item['total_price']) }}
    +
    + @endforeach +
    + +{{-- 총합계 --}} +
    +
    + 총 합계 + + {{ number_format($result['summary']['total_amount']) }}원 + +
    +
    +``` + +### Phase 5: 검증 및 동기화 (1일) + +#### 5.1 테스트 케이스 + +| 입력값 | Design 결과 | MNG 목표 | +|--------|------------|----------| +| W0=2000, H0=2500, PC=스크린 | W1=2140, H1=2850, M=6.099 | 동일 | +| 스크린 원단 (면적단가) | 35,000 × 6.099 = 213,465원 | 동일 | +| 가이드레일 (길이단가) | 42,000 × 2.85 = 119,700원 | 동일 | +| 모터 (고정단가) | 480,000 × 1 = 480,000원 | 동일 | + +#### 5.2 검증 스크립트 + +```php +// php artisan tinker + +// 동일 입력으로 계산 비교 +$input = [ + 'PC' => '스크린', + 'PRODUCT_ID' => 'FG-SCR-002', + 'W0' => 2000, + 'H0' => 2500, + 'GT' => '벽면형', + 'MP' => '220V', + 'CT' => '단독', + 'QTY' => 1, +]; + +$service = app(\App\Services\Quote\FormulaEvaluatorService::class); +$result = $service->executeAll($input); + +// Design 결과와 비교 +dump([ + 'W1' => $result['calculated_variables']['W1'], // 예상: 2140 + 'H1' => $result['calculated_variables']['H1'], // 예상: 2850 + 'M' => $result['calculated_variables']['M'], // 예상: 6.099 + 'total' => $result['summary']['total_amount'], // Design과 동일해야 함 +]); +``` + +--- + +## 5. 핵심 파일 참조 + +### Design (참조용 - 수정 금지) +``` +/SAM/design/src/ +├── components/ +│ ├── AutoCalculationSimulator.tsx # 메인 시뮬레이터 (1068줄) +│ ├── BomCalculationResults.tsx # 결과 표시 컴포넌트 +│ ├── contexts/ +│ │ └── DataContext.tsx # 마스터 데이터 (9859줄) +│ └── utils/ +│ ├── formulaEvaluator.ts # 수식 평가 (312줄) +│ └── bomCalculatorWithDebug.ts # BOM 계산 (232줄) +└── utils/ + ├── sampleQuoteData_Complete.ts # 샘플 품목 데이터 + └── addProductBoms.ts # BOM 구성 데이터 +``` + +### MNG (수정 대상) +``` +/SAM/mng/ +├── app/Services/Quote/ +│ └── FormulaEvaluatorService.php # 핵심 서비스 확장 대상 +├── database/ +│ ├── migrations/ +│ │ └── 20xx_add_simulator_fields.php # 신규 마이그레이션 +│ └── seeders/ +│ ├── DesignItemSeeder.php # 신규 Seeder +│ ├── DesignBomSeeder.php # 신규 Seeder +│ └── CategoryGroupSeeder.php # 신규 Seeder +├── app/Models/ +│ ├── CategoryGroup.php # 신규 모델 +│ ├── Item.php # 필드 추가 +│ └── Price.php # 기존 모델 +└── resources/views/quote-formulas/ + └── simulator.blade.php # UI 확장 +``` + +--- + +## 6. 작업 일정 요약 + +| Phase | 작업 내용 | 예상 일정 | +|-------|----------|----------| +| Phase 1 | DB 스키마 확장 (마이그레이션) | 1일 | +| Phase 2 | Seeder 작성 (품목/BOM/단가/CategoryGroup) | 2일 | +| Phase 3 | FormulaEvaluatorService 확장 | 2일 | +| Phase 4 | simulator.blade.php UI 개선 | 1일 | +| Phase 5 | 검증 및 동기화 테스트 | 1일 | +| **합계** | | **7일** | + +--- + +## 7. 성공 기준 + +1. **계산 결과 동일**: Design과 MNG에서 동일 입력 시 동일한 금액 산출 +2. **10단계 디버깅**: 각 품목별 계산 과정을 10단계로 확인 가능 +3. **공정별 그룹화**: 스크린/절곡/전기 공정별로 품목 분류 +4. **단가 우선순위**: prices 테이블 > items.salesPrice 순서 적용 +5. **면적/중량 기반 단가**: CategoryGroup 설정에 따라 자동 계산 + +--- + +## 8. Serena 컨텍스트 유지 정책 + +> **목적**: 세션 간 컨텍스트 유지를 위해 Serena MCP 메모리에 역할별 분리 저장 + +### 8.1 메모리 구조 + +``` +simulator-rules.md # 패턴, 규칙, 체크리스트 +simulator-mappings.md # 필드 매핑 상세 (Design ↔ MNG) +simulator-progress.md # 진행 상황 +``` + +### 8.2 메모리 내용 + +#### `simulator-rules.md` +- 계산 변수 체계 (W0, H0, W1, H1, M, K 등) +- 수식 평가 함수 목록 (SUM, CEIL, FLOOR, ROUND, IF 등) +- BOM 10단계 계산 프로세스 +- 단가 우선순위 규칙 +- 체크리스트 + +#### `simulator-mappings.md` +- Design TypeScript 인터페이스 ↔ MNG DB 테이블 매핑 +- 품목 타입 매핑 (RM, SM, SF, FG, PT, CS) +- CategoryGroup 매핑 +- 공정 타입 매핑 (screen, bending, electric, assembly) + +#### `simulator-progress.md` +- Phase별 진행 상태 +- 완료된 작업 목록 +- 남은 작업 및 이슈 + +### 8.3 세션 시작/종료 패턴 + +**세션 시작:** +``` +list_memories() → 기존 상태 확인 +read_memory("simulator-progress.md") → 진행 상황 복원 +read_memory("simulator-rules.md") → 규칙 컨텍스트 로드 +``` + +**세션 종료:** +``` +write_memory("simulator-progress.md", 현재 진행 상황) +``` + +### 8.4 초기 메모리 저장 명령 + +```bash +# 세션 시작 시 아래 명령으로 메모리 초기화 +/sc:save simulator-rules # 규칙 저장 +/sc:save simulator-mappings # 매핑 저장 +/sc:save simulator-progress # 진행 상황 저장 +``` + +--- + +## 9. 검증 결과 (Phase 5) + +> **검증일**: 2025-12-24 +> **테스트 환경**: Docker (sam-mng-1) + +### 9.1 테스트 케이스: FG-SCR-001 (W0=2000, H0=2500) + +#### 변수 계산 (Design 마진 적용) +| 변수 | 계산식 | 결과 | 상태 | +|------|--------|------|------| +| W0 | 입력값 | 2000 | ✅ | +| H0 | 입력값 | 2500 | ✅ | +| W1 | W0 + 140 | 2140 | ✅ | +| H1 | H0 + 350 | 2850 | ✅ | +| M | W1 × H1 / 1,000,000 | 6.099 ㎡ | ✅ | + +#### 품목별 계산 결과 +| 품목코드 | 그룹 | 수량 | 단가 | 금액 | 상태 | +|----------|------|------|------|------|------| +| SF-SCR-F01 | area_based | 6.10 | 35,000 | 213,465원 | ✅ | +| SF-SCR-F02 | quantity_based | 2.85 | 42,000 | 119,700원 | ✅ | +| SF-SCR-F03 | quantity_based | 2.85 | 42,000 | 119,700원 | ✅ | +| SF-SCR-F04 | quantity_based | 1.00 | 145,000 | 145,000원 | ✅ | +| SF-SCR-F05 | (미등록) | 1.00 | 55,000 | 55,000원 | ✅ | +| SF-SCR-M01 | quantity_based | 1.00 | 350,000 | 350,000원 | ✅ | +| SF-SCR-C01 | quantity_based | 1.00 | 280,000 | 280,000원 | ✅ | +| SF-SCR-S01 | (미등록) | 1.00 | 180,000 | 180,000원 | ✅ | +| SF-SCR-W01 | (미등록) | 1.00 | 125,000 | 125,000원 | ✅ | +| SF-SCR-B01 | quantity_based | 1.00 | 78,000 | 78,000원 | ✅ | +| SF-SCR-SW01 | quantity_based | 1.00 | 45,000 | 45,000원 | ✅ | +| SM-B002 | quantity_based | 1.00 | 200 | 200원 | ✅ | +| SM-N002 | quantity_based | 1.00 | 100 | 100원 | ✅ | +| SM-W002 | quantity_based | 1.00 | 60 | 60원 | ✅ | +| **합계** | | | | **1,711,225원** | ✅ | + +### 9.2 10단계 디버깅 검증 + +| 단계 | 항목 | 상태 | +|------|------|------| +| Step 1 | 입력값수집 | ✅ | +| Step 2 | 변수계산 | ✅ | +| Step 3 | 완제품선택 | ✅ | +| Step 4 | BOM전개 | ✅ | +| Step 5 | 단가출처 | ✅ | +| Step 6 | 수량계산 | ✅ | +| Step 7 | 금액계산 | ✅ | +| Step 8 | 공정그룹화 | ✅ | +| Step 9 | 소계계산 | ✅ | +| Step 10 | 최종합계 | ✅ | + +### 9.3 공정별 그룹화 검증 + +| 공정 | 품목 수 | 소계 | 상태 | +|------|---------|------|------| +| screen | 11 | 1,710,865원 | ✅ | +| assembly | 3 | 360원 | ✅ | + +### 9.4 단가 우선순위 검증 + +| 품목 | 단가 출처 | 상태 | +|------|----------|------| +| SF-SCR-F01 | items.salesPrice | ✅ | +| SF-SCR-M01 | items.salesPrice | ✅ | +| SM-B002 | items.salesPrice | ✅ | + +> **참고**: ~~prices 테이블에 active 데이터 없음~~ → **2025-12-29 prices 데이터 85개 추가 완료** + +### 9.5 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 계산 결과 동일 | ✅ | Design 마진 (W+140, H+350) 적용 | +| 10단계 디버깅 | ✅ | 모든 단계 정상 출력 | +| 공정별 그룹화 | ✅ | screen, assembly 분류 | +| 단가 우선순위 | ✅ | prices → items.salesPrice 순서 | +| 면적/중량 기반 단가 | ✅ | CategoryGroup 기반 자동 계산 | + +### 9.6 수정 사항 (Phase 5 중) + +1. **면적기반 단가 중복 계산 수정** + - 문제: `total = quantity × (base_price × multiplier)` (중복) + - 수정: 면적/중량기반은 `total = final_price` (이미 multiplier 적용됨) + +2. **마진값 Design 표준 적용** + - 기존: W+100, H+100 + - 수정: W+140, H+350 (스크린 기준) + +--- + +## 10. Phase 6: prices 테이블 데이터 추가 (2025-12-29) + +### 10.1 작업 내용 + +| 항목 | 내용 | +|------|------| +| 작업일 | 2025-12-29 | +| 목적 | prices 테이블에 시뮬레이터용 단가 데이터 추가 | +| Seeder | `DesignPriceSeeder.php` | +| 대상 품목 | 85개 (RM, SM, SF-SCR, SF-STL, SF-BND) | + +### 10.2 생성된 Seeder + +**파일**: `mng/database/seeders/DesignPriceSeeder.php` + +```php +// items.attributes.salesPrice → prices 테이블 이전 +// 단가 우선순위: prices (1순위) → items.attributes (2순위) +``` + +**실행 명령**: +```bash +php artisan db:seed --class=DesignPriceSeeder +``` + +### 10.3 추가된 데이터 + +| 품목 유형 | 코드 패턴 | 수량 | +|----------|----------|------| +| 원자재 | RM-* | 20개 | +| 부자재 | SM-* | 25개 | +| 스크린 반제품 | SF-SCR-* | 20개 | +| 철재 반제품 | SF-STL-* | 16개 | +| 절곡 반제품 | SF-BND-* | 4개 | +| **합계** | | **85개** | + +### 10.4 단가 우선순위 검증 결과 + +``` +=== prices 우선순위 테스트 === +prices 테이블: 99,999원 (테스트용 변경) +items.attributes: 35,000원 (그대로) +getSalesPriceByItemCode(): 99,999원 + +✓ prices 테이블 우선 적용 확인! +``` + +### 10.5 FormulaEvaluatorService 단가 조회 로직 + +```php +// mng/app/Services/Quote/FormulaEvaluatorService.php:379-410 +private function getItemPrice(string $itemCode): float +{ + // 1순위: Price 모델에서 조회 + $price = Price::getSalesPriceByItemCode($tenantId, $itemCode); + if ($price > 0) { + return $price; + } + + // 2순위: Fallback - items.attributes.salesPrice + $item = DB::table('items')->where('code', $itemCode)->first(); + return (float) ($attributes['salesPrice'] ?? 0); +} +``` + +--- + +## 11. Phase 7: 철재 제품 테스트 케이스 (2025-12-30) + +### 11.1 작업 개요 + +| 항목 | 내용 | +|------|------| +| 작업일 | 2025-12-30 | +| 목적 | 철재 제품(FG-STL-*) 마진값/중량 계산 동기화 및 CategoryGroup 적용 | +| 테스트 완제품 | FG-STL-001 (철재 방화문) | +| 입력값 | W0=2000, H0=2500 | + +### 11.2 수정 사항 + +#### 11.2.1 마진값 동적 적용 (SCREEN/STEEL 분기) + +**파일**: `mng/app/Services/Quote/FormulaEvaluatorService.php` + +| 제품 카테고리 | 마진 W | 마진 H | K 계산식 | +|-------------|-------|-------|---------| +| SCREEN (스크린) | W0+140 | H0+350 | M×2 + W0/1000×14.17 | +| STEEL (철재) | W0+110 | H0+350 | M×25 | + +**변경 내용**: +```php +// 제품 카테고리에 따른 마진값 결정 +if (strtoupper($productCategory) === 'STEEL') { + $marginW = 110; // 철재 마진 + $K = $M * 25; // 철재 중량 +} else { + $marginW = 140; // 스크린 기본 마진 + $K = $M * 2 + ($W0 / 1000) * 14.17; // 스크린 중량 +} +``` + +#### 11.2.2 CategoryGroup 데이터 생성 (tenant 287) + +**문제**: CategoryGroup 데이터가 tenant_id=1에만 존재, tenant_id=287 미등록 + +**해결**: tenant 287용 CategoryGroup 3종 생성 + +| 코드 | 이름 | 승수변수 | 포함 카테고리 | +|------|------|---------|-------------| +| area_based | 면적기반 | M | 원단, 패널, 도장, 표면처리, 유리, 도어, 프레임, 창틀 | +| weight_based | 중량기반 | K | 강판, 알루미늄, 스테인리스, 철재 | +| quantity_based | 수량기반 | (없음) | 볼트, 경첩, 도어락, 도어클로저, 실링재, 문턱, 킥플레이트 등 | + +### 11.3 테스트 결과 + +#### 11.3.1 변수 계산 검증 + +| 변수 | 계산값 | 예상값 | 상태 | +|------|-------|-------|------| +| W1 | 2110 | 2110 (W0+110) | ✅ | +| H1 | 2850 | 2850 (H0+350) | ✅ | +| M | 6.0135 ㎡ | 6.0135 | ✅ | +| K | 150.34 kg | 150.34 (M×25) | ✅ | +| PC | STEEL | STEEL | ✅ | + +#### 11.3.2 CategoryGroup 적용 검증 + +| 품목 | 카테고리 | CategoryGroup | 기준단가 | 승수 | 최종단가 | +|------|---------|--------------|---------|------|---------| +| 철재 도어 | 도어 | area_based | 320,000 | M×6.01 | 1,924,320원 | +| 철재 프레임 | 프레임 | area_based | 58,000 | M×6.01 | 348,783원 | +| 철재 패널 | 패널 | area_based | 68,000 | M×6.01 | 408,918원 | +| 경첩 세트 | 경첩 | quantity_based | 42,000 | - | 42,000원 | +| 도어락 | 도어락 | quantity_based | 95,000 | - | 95,000원 | +| 도어클로저 | 도어클로저 | quantity_based | 115,000 | - | 115,000원 | +| 실링재 | 실링재 | quantity_based | 9,500 | - | 9,500원 | +| 문턱 | 문턱 | quantity_based | 58,000 | - | 58,000원 | +| 킥플레이트 | 킥플레이트 | quantity_based | 45,000 | - | 45,000원 | +| 볼트 세트 | 볼트 | quantity_based | 18,000 | - | 18,000원 | + +**최종 합계**: 3,158,111원 ✅ + +### 11.4 수정된 파일 + +| 파일 | 수정 내용 | +|------|----------| +| `FormulaEvaluatorService.php` | 마진값/K계산 동적 분기, `getItemDetails()`에 item_category 추가 | +| `category_groups` (DB) | tenant 287용 3개 그룹 생성 | + +### 11.5 성공 기준 달성 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 철재 마진 적용 | ✅ | W+110 정상 적용 | +| 철재 중량 계산 | ✅ | M×25 정상 적용 | +| CategoryGroup 매칭 | ✅ | area_based, quantity_based 정상 | +| 면적기반 단가 계산 | ✅ | base_price × M 정상 | +| 수량기반 단가 계산 | ✅ | base_price 그대로 적용 | + +### 11.6 절곡 제품 테스트 (FG-BND-001) + +#### 테스트 결과 + +| 변수 | 계산값 | 상태 | +|------|-------|------| +| W1 | 2110 (W0+110) | ✅ 철재 마진 적용 | +| M | 6.0135 ㎡ | ✅ | +| K | 150.34 kg (M×25) | ✅ 철재 중량 | +| PC | STEEL | ✅ | + +#### CategoryGroup 수정 + +**문제**: "절곡" 카테고리가 CategoryGroup 미등록 → 단가 0원 + +**해결**: `area_based`에 "절곡" 카테고리 추가 + +```json +// area_based categories (수정 후) +["원단","패널","도장","표면처리","스크린원단","유리","도어","프레임","창틀","절곡"] +``` + +#### 수정 후 단가 계산 + +| 품목 | CategoryGroup | 기준단가 | 승수 | 최종단가 | +|------|--------------|---------|------|---------| +| 절곡 | area_based | 28,000 | M×6.01 | 168,378원 | +| 프레임 | area_based | 58,000 | M×6.01 | 348,783원 | +| 도장 | area_based | 32,000 | M×6.01 | 192,432원 | +| 볼트 | quantity_based | 18,000 | - | 18,000원 | + +**최종 합계**: 727,893원 ✅ + +### 11.7 전체 제품 유형 검증 완료 + +| 제품 유형 | 코드 | 마진 | K 계산 | 합계 | +|----------|------|------|--------|------| +| 스크린 | FG-SCR-001 | W+140 ✅ | M×2+W0/1000×14.17 ✅ | 1,711,225원 | +| 철재 | FG-STL-001 | W+110 ✅ | M×25 ✅ | 3,158,111원 | +| 절곡 | FG-BND-001 | W+110 ✅ | M×25 ✅ | 727,893원 | + +--- + +*이 문서는 design.sam.kr 완전 분석을 바탕으로 mng 시뮬레이터 완전 동기화 계획을 상세히 기술합니다.* \ No newline at end of file diff --git a/plans/archive/stock-integration-plan.md b/plans/archive/stock-integration-plan.md new file mode 100644 index 0000000..5926cd5 --- /dev/null +++ b/plans/archive/stock-integration-plan.md @@ -0,0 +1,421 @@ +# 재고 통합 시스템 개발 계획 + +> **작성일**: 2025-01-26 +> **목적**: 입고/생산/견적 시스템과 재고(Stock)의 실시간 연동 구현 +> **기준 문서**: `docs/specs/database-schema.md`, `docs/standards/api-rules.md` +> **상태**: 🔄 계획 수립 중 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 3 - 견적/출하 → 재고 연동 완료 | +| **다음 작업** | ✅ 모든 Phase 완료 | +| **진행률** | 12/12 (100%) | +| **마지막 업데이트** | 2025-01-26 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 SAM 시스템의 재고 관리는 **조회 전용**으로만 작동합니다: +- 입고(Receiving)가 완료되어도 Stock이 증가하지 않음 +- 생산(WorkOrder)에서 자재를 투입해도 Stock이 감소하지 않음 +- 견적(Order)이 확정되어도 재고 예약이 되지 않음 +- 출하(Shipment)가 완료되어도 Stock이 감소하지 않음 + +**결과**: 재고현황 페이지가 실제 재고를 반영하지 못함 + +### 1.2 목표 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 목표 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 입고 완료 → Stock 자동 증가 + StockLot 생성 │ +│ 2. 자재 투입 → Stock 자동 차감 (FIFO 기반) │ +│ 3. 견적 확정 → reserved_qty 증가 │ +│ 4. 출하 완료 → stock_qty 차감 │ +│ 5. 모든 변경에 대한 감사 로그 기록 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 성공 기준 + +| 기준 | 측정 방법 | +|------|----------| +| 입고 → 재고 연동 | 입고 완료 시 Stock.stock_qty 자동 증가 확인 | +| 생산 → 재고 연동 | 자재 투입 시 Stock.stock_qty 자동 감소 확인 | +| 견적 → 재고 연동 | 견적 확정 시 Stock.reserved_qty 증가 확인 | +| 출하 → 재고 연동 | 출하 완료 시 Stock.stock_qty 감소 확인 | +| 감사 로그 | 모든 재고 변경이 audit_logs에 기록됨 | +| FIFO 적용 | StockLot이 fifo_order 순서대로 차감됨 | + +### 1.4 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 메서드 추가, 파라미터 추가, 문서 수정 | 불필요 | +| ⚠️ 컨펌 필요 | Service 로직 변경, 새 이벤트 추가, 마이그레이션 | **필수** | +| 🔴 금지 | 기존 API 응답 구조 변경, Stock 테이블 컬럼 삭제 | 별도 협의 | + +### 1.5 준수 규칙 +- `docs/standards/api-rules.md` - Service-First 패턴 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/specs/database-schema.md` - DB 스키마 규칙 + +--- + +## 2. 현재 시스템 분석 + +### 2.1 데이터 모델 관계 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 현재 상태 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Item (품목) │ +│ ↓ 1:1 │ +│ Stock (재고현황) ←── 자동 업데이트 없음 ──┐ │ +│ ↓ 1:N │ │ +│ StockLot (LOT별 상세) ←── 자동 생성 없음 ─┤ │ +│ │ │ +│ Receiving (입고) ─── 연결 끊김 ────────────┤ │ +│ WorkOrder (생산) ─── 연결 없음 ────────────┤ │ +│ Order (견적/수주) ─── 연결 없음 ───────────┤ │ +│ Shipment (출하) ─── 연결 없음 ─────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 목표 데이터 흐름 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 목표 상태 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ [입고 완료] ──→ StockLot 생성 ──→ Stock.refreshFromLots() │ +│ │ +│ [자재 투입] ──→ StockLot 차감(FIFO) ──→ Stock.refreshFromLots()│ +│ │ +│ [견적 확정] ──→ Stock.reserved_qty 증가 │ +│ │ +│ [출하 완료] ──→ StockLot 차감 ──→ Stock.refreshFromLots() │ +│ ──→ Stock.reserved_qty 감소 │ +│ │ +│ [모든 변경] ──→ AuditLog 기록 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2.3 핵심 파일 위치 + +| 구분 | 경로 | +|------|------| +| **Stock 모델** | `api/app/Models/Tenants/Stock.php` | +| **StockLot 모델** | `api/app/Models/Tenants/StockLot.php` | +| **StockService** | `api/app/Services/StockService.php` | +| **ReceivingService** | `api/app/Services/ReceivingService.php` | +| **WorkOrderService** | `api/app/Services/WorkOrderService.php` | +| **OrderService** | `api/app/Services/OrderService.php` | + +--- + +## 3. 대상 범위 + +### Phase 1: 입고 → 재고 연동 (우선순위 1) ✅ 완료 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | StockService에 이벤트 기반 구조 설계 | ✅ | increaseFromReceiving(), getOrCreateStock() | +| 1.2 | ReceivingService.process() 수정 - Stock 연동 | ✅ | StockService 호출 추가 | +| 1.3 | StockLot 자동 생성 로직 구현 | ✅ | FIFO 순서 자동 계산 | +| 1.4 | 감사 로그 통합 | ✅ | logStockChange() 구현 | +| 1.5 | 단위 테스트 작성 | ⏭️ | 수동 테스트로 대체 | + +### Phase 2: 생산 → 재고 연동 (우선순위 2) ✅ 완료 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | WorkOrderService에 BOM 기반 자재 조회 구현 | ✅ | getMaterials() 실제 재고 연동 | +| 2.2 | 자재 투입 시 Stock 차감 로직 (FIFO) | ✅ | StockService.decreaseFIFO() | +| 2.3 | 작업 완료 시 제품 Stock 증가 로직 | ⏭️ | 추후 구현 (생산품 LOT 생성 시) | +| 2.4 | 단위 테스트 작성 | ⏭️ | 수동 테스트로 대체 | + +### Phase 3: 견적/출하 → 재고 연동 (우선순위 3) ✅ 완료 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | Order 확정 시 reserved_qty 증가 로직 | ✅ | StockService.reserve(), reserveForOrder() | +| 3.2 | Shipment 출하 시 stock_qty 차감 로직 | ✅ | StockService.decreaseForShipment() | +| 3.3 | 예약 취소/변경 처리 로직 | ✅ | StockService.releaseReservation() | + +--- + +## 4. 상세 설계 + +### 4.1 StockService 이벤트 구조 + +```php +// api/app/Services/StockService.php + +class StockService +{ + /** + * 입고 완료 시 재고 증가 + * @param Receiving $receiving + * @return StockLot + */ + public function increaseFromReceiving(Receiving $receiving): StockLot + { + // 1. StockLot 생성 + // 2. Stock.refreshFromLots() 호출 + // 3. 감사 로그 기록 + } + + /** + * 자재 투입 시 재고 차감 (FIFO) + * @param int $itemId + * @param float $qty + * @param string $reason (work_order, shipment 등) + * @param int $referenceId + * @return array 차감된 LOT 정보 + */ + public function decreaseFIFO(int $itemId, float $qty, string $reason, int $referenceId): array + { + // 1. StockLot을 fifo_order 순서로 조회 + // 2. 필요 수량만큼 차감 (여러 LOT에 걸칠 수 있음) + // 3. Stock.refreshFromLots() 호출 + // 4. 감사 로그 기록 + } + + /** + * 재고 예약 + * @param int $itemId + * @param float $qty + * @param int $orderId + */ + public function reserve(int $itemId, float $qty, int $orderId): void + { + // 1. Stock.reserved_qty 증가 + // 2. Stock.available_qty 재계산 + // 3. 감사 로그 기록 + } + + /** + * 예약 해제 + */ + public function releaseReservation(int $itemId, float $qty, int $orderId): void + { + // reserved_qty 감소 + } +} +``` + +### 4.2 ReceivingService 수정 사항 + +```php +// api/app/Services/ReceivingService.php - process() 메서드 수정 + +public function process(Receiving $receiving, array $data): Receiving +{ + return DB::transaction(function () use ($receiving, $data) { + // 기존 로직 유지 + $receiving->update([ + 'receiving_qty' => $data['receiving_qty'], + 'receiving_date' => $data['receiving_date'], + 'lot_no' => $data['lot_no'], + 'status' => 'completed', + ]); + + // 🆕 재고 연동 추가 + app(StockService::class)->increaseFromReceiving($receiving); + + return $receiving->fresh(); + }); +} +``` + +### 4.3 WorkOrderService 수정 사항 + +```php +// api/app/Services/WorkOrderService.php - registerMaterialInput() 수정 + +public function registerMaterialInput(WorkOrder $workOrder, array $data): void +{ + DB::transaction(function () use ($workOrder, $data) { + // 기존 감사 로그 유지 + + // 🆕 재고 차감 추가 + $stockService = app(StockService::class); + + foreach ($data['materials'] as $material) { + $stockService->decreaseFIFO( + itemId: $material['item_id'], + qty: $material['qty'], + reason: 'work_order_input', + referenceId: $workOrder->id + ); + } + }); +} +``` + +### 4.4 감사 로그 구조 + +| 필드 | 값 | +|------|------| +| `auditable_type` | `Stock` | +| `auditable_id` | Stock ID | +| `event` | `stock_increase`, `stock_decrease`, `stock_reserve` | +| `old_values` | 변경 전 수량 | +| `new_values` | 변경 후 수량 + 사유 + 참조 ID | + +--- + +## 5. 작업 절차 + +### Step 1: Phase 1 - 입고 → 재고 연동 + +``` +1.1 StockService 이벤트 메서드 추가 +├── increaseFromReceiving() 구현 +├── 감사 로그 통합 +└── 단위 테스트 + +1.2 ReceivingService.process() 수정 +├── 기존 로직 분석 +├── StockService 호출 추가 +└── 트랜잭션 보장 + +1.3 StockLot 자동 생성 +├── Receiving 정보로 StockLot 생성 +├── fifo_order 자동 계산 +└── Stock.refreshFromLots() 호출 + +1.4 테스트 및 검증 +├── 입고 생성 → 입고처리 → Stock 확인 +└── 감사 로그 확인 +``` + +### Step 2: Phase 2 - 생산 → 재고 연동 + +``` +2.1 BOM 기반 자재 조회 구현 +├── 품목의 BOM 정보 조회 +├── Mock 데이터 제거 +└── 실제 자재 목록 반환 + +2.2 자재 투입 시 Stock 차감 +├── decreaseFIFO() 구현 +├── 여러 LOT 걸쳐 차감 처리 +└── 재고 부족 시 예외 처리 + +2.3 작업 완료 시 제품 Stock 증가 +├── 생산된 제품의 StockLot 생성 +├── Stock.refreshFromLots() 호출 +└── 감사 로그 기록 +``` + +### Step 3: Phase 3 - 견적/출하 → 재고 연동 + +``` +3.1 Order 확정 시 예약 +├── reserve() 호출 +├── available_qty 감소 +└── 오버부킹 방지 검증 + +3.2 Shipment 출하 시 차감 +├── decreaseFIFO() 호출 +├── reserved_qty 동시 감소 +└── 감사 로그 기록 +``` + +--- + +## 6. 컨펌 대기 목록 + +> API 내부 로직 변경 등 승인 필요 항목 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | ReceivingService.process() | Stock 연동 로직 추가 | 입고 프로세스 | ⏳ 대기 | +| 2 | WorkOrderService.registerMaterialInput() | Stock 차감 로직 추가 | 생산 프로세스 | ⏳ 대기 | +| 3 | ShipmentService (신규) | Stock 차감 로직 추가 | 출하 프로세스 | ⏳ 대기 | + +--- + +## 7. 리스크 및 대응 + +### 7.1 데이터 정합성 리스크 + +| 리스크 | 확률 | 영향 | 대응 | +|--------|------|------|------| +| 트랜잭션 실패 시 Stock만 변경됨 | 중 | 높음 | DB 트랜잭션으로 원자성 보장 | +| 동시 요청 시 재고 충돌 | 중 | 높음 | 비관적 락(FOR UPDATE) 적용 | +| 재고 부족 상태에서 차감 시도 | 높음 | 중 | 사전 검증 + 예외 처리 | + +### 7.2 성능 리스크 + +| 리스크 | 확률 | 영향 | 대응 | +|--------|------|------|------| +| LOT가 많을 경우 FIFO 조회 느림 | 낮음 | 중 | fifo_order 인덱스 확인 | +| refreshFromLots() 빈번 호출 | 중 | 낮음 | 필요 시에만 호출 (이미 구현됨) | + +--- + +## 8. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2025-01-26 | Phase 3 | 견적/출하→재고 연동 구현 완료 | StockService, OrderService, ShipmentService | ✅ | +| 2025-01-26 | Phase 2 | 생산→재고 연동 구현 완료 | StockService, WorkOrderService | ✅ | +| 2025-01-26 | Phase 1 | 입고→재고 연동 구현 완료 | StockService, ReceivingService | ✅ | +| 2025-01-26 | - | 문서 초안 작성 | - | - | + +--- + +## 9. 참고 문서 + +- **API 규칙**: `docs/standards/api-rules.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **DB 스키마**: `docs/specs/database-schema.md` + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경, 1.2 목표 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 1.3 성공 기준 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 3 대상 범위 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 2.3 핵심 파일 위치 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 9 참고 문서 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 5 작업 절차 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 1.3 성공 기준 | +| 8 | 모호한 표현이 없는가? | ✅ | | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경, 1.2 목표 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 3. 대상 범위 Phase 1 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 2.3 핵심 파일 위치 | +| Q4. 작업 완료 확인 방법은? | ✅ | 1.3 성공 기준 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 9. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/welfare-section-plan.md b/plans/archive/welfare-section-plan.md new file mode 100644 index 0000000..94541ed --- /dev/null +++ b/plans/archive/welfare-section-plan.md @@ -0,0 +1,1021 @@ +# 복리후생비 현황 섹션 개발 계획 + +> **작성일**: 2026-01-22 +> **목적**: CEO 대시보드 복리후생비 현황 섹션 완성 (4개 카드 + 모달 API 연동) +> **기준 문서**: `api/app/Swagger/v1/WelfareApi.php` +> **상태**: 🔄 진행중 (Serena ID: welfare-section-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 2 - 프론트엔드 연동 완료 | +| **다음 작업** | 검증 및 테스트 | +| **진행률** | 6/6 (100%) | +| **마지막 업데이트** | 2026-01-22 | + +--- + +## 1. 개요 + +### 1.1 배경 +CEO 대시보드의 복리후생비 현황 섹션은 4개의 카드로 구성됩니다: +1. **당해년도 복리후생비 한도** - 연간 총 한도 +2. **{분기} 복리후생비 총 한도** - 분기별 한도 +3. **{분기} 복리후생비 잔여한도** - 분기별 남은 한도 +4. **{분기} 복리후생비 사용금액** - 분기별 사용 금액 + +현재 상태: +- ✅ 섹션 UI 컴포넌트: 완료 (`WelfareSection.tsx`) +- ✅ 카드 데이터 API: 완료 (`/api/v1/welfare/summary`) +- ✅ 프론트엔드 Hook: 완료 (`useWelfare()`) +- ⚠️ 모달 상세 데이터: Mock 사용 중 (API 연동 필요) + +### 1.2 기준 원칙 +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. API-First: 백엔드 API 완성 후 프론트엔드 연동 │ +│ 2. 기존 패턴 준수: WelfareService 확장 │ +│ 3. Mock 데이터 구조 유지: 기존 모달 설정 형식 호환 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 모달 설정 Mock → API 변환, Transformer 추가 | 불필요 | +| ⚠️ 컨펌 필요 | 새 API 엔드포인트 추가, 서비스 메서드 추가 | **필수** | +| 🔴 금지 | expense_accounts 테이블 구조 변경 | 별도 협의 | + +### 1.4 준수 규칙 +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `api/CLAUDE.md` - SAM API Development Rules + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: API 개발 (Backend) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | 모달 상세 데이터 API 개발 | ✅ | `/api/v1/welfare/detail` | +| 1.2 | Swagger 문서 업데이트 | ✅ | WelfareApi.php | + +### 2.2 Phase 2: 프론트엔드 연동 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | 타입 정의 추가 | ✅ | WelfareDetailApiResponse (types.ts) | +| 2.2 | API 함수 추가 | ✅ | useWelfareDetail hook (useCEODashboard.ts) | +| 2.3 | Transformer 추가 | ✅ | transformWelfareDetailResponse (transformers.ts) | +| 2.4 | 모달 설정 동적 생성 | ✅ | CEODashboard.tsx 연동 + fallback | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Step 1: API 개발 (Backend) +├── WelfareService에 getDetail() 메서드 추가 +├── WelfareController에 detail() 액션 추가 +├── routes/api.php에 라우트 등록 +└── Swagger 문서 작성 + +Step 2: 프론트엔드 연동 +├── types.ts에 WelfareDetailApiResponse 추가 +├── useCEODashboard.ts에 fetchWelfareDetail 추가 +├── transformers.ts에 transformWelfareDetailResponse 추가 +└── welfareConfigs.ts를 API 응답 기반으로 수정 +``` + +--- + +## 4. 핵심 참조 코드 (인라인) + +### 4.1 DetailModalConfig 타입 정의 + +**파일**: `react/src/components/business/CEODashboard/types.ts` (라인 414-426) + +```typescript +// 상세 모달 전체 설정 타입 +export interface DetailModalConfig { + title: string; + summaryCards: SummaryCardData[]; + barChart?: BarChartConfig; + pieChart?: PieChartConfig; + horizontalBarChart?: HorizontalBarChartConfig; + comparisonSection?: ComparisonSectionConfig; + referenceTable?: ReferenceTableConfig; + referenceTables?: ReferenceTableConfig[]; + calculationCards?: CalculationCardsConfig; + quarterlyTable?: QuarterlyTableConfig; + table?: TableConfig; +} +``` + +### 4.2 관련 서브 타입 정의 + +```typescript +// 요약 카드 타입 (라인 249-255) +export interface SummaryCardData { + label: string; + value: string | number; + isComparison?: boolean; + isPositive?: boolean; + unit?: string; +} + +// 막대 차트 설정 타입 (라인 265-271) +export interface BarChartConfig { + title: string; + data: BarChartDataItem[]; + dataKey: string; + xAxisKey: string; + color?: string; +} + +// 도넛 차트 설정 타입 (라인 282-285) +export interface PieChartConfig { + title: string; + data: PieChartDataItem[]; +} + +// 도넛 차트 데이터 아이템 (라인 274-279) +export interface PieChartDataItem { + name: string; + value: number; + percentage: number; + color: string; +} + +// 테이블 설정 타입 (라인 332-342) +export interface TableConfig { + title: string; + columns: TableColumnConfig[]; + data: Record[]; + filters?: TableFilterConfig[]; + showTotal?: boolean; + totalLabel?: string; + totalValue?: string | number; + totalColumnKey?: string; + footerSummary?: FooterSummaryItem[]; +} + +// 계산 카드 섹션 설정 타입 (라인 391-395) +export interface CalculationCardsConfig { + title: string; + subtitle?: string; + cards: CalculationCardItem[]; +} + +// 계산 카드 아이템 타입 (라인 383-388) +export interface CalculationCardItem { + label: string; + value: number; + unit?: string; + operator?: '+' | '=' | '-' | '×'; +} + +// 분기별 테이블 설정 타입 (라인 408-411) +export interface QuarterlyTableConfig { + title: string; + rows: QuarterlyTableRow[]; +} + +// 분기별 테이블 행 타입 (라인 398-405) +export interface QuarterlyTableRow { + label: string; + q1?: number | string; + q2?: number | string; + q3?: number | string; + q4?: number | string; + total?: number | string; +} +``` + +### 4.3 현재 Mock 데이터 구조 (welfareConfigs.ts 전체) + +**파일**: `react/src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts` + +```typescript +import type { DetailModalConfig } from '../types'; + +export function getWelfareModalConfig(calculationType: 'fixed' | 'ratio'): DetailModalConfig { + // 계산 방식에 따른 조건부 calculationCards 생성 + const calculationCards = calculationType === 'fixed' + ? { + // 직원당 정액 금액/월 방식 + title: '복리후생비 계산', + subtitle: '직원당 정액 금액/월 200,000원', + cards: [ + { label: '직원 수', value: 20, unit: '명' }, + { label: '연간 직원당 월급 금액', value: 2400000, unit: '원', operator: '×' as const }, + { label: '당해년도 복리후생비 총 한도', value: 48000000, unit: '원', operator: '=' as const }, + ], + } + : { + // 연봉 총액 비율 방식 + title: '복리후생비 계산', + subtitle: '연봉 총액 기준 비율 20.5%', + cards: [ + { label: '연봉 총액', value: 1000000000, unit: '원' }, + { label: '비율', value: 20.5, unit: '%', operator: '×' as const }, + { label: '당해년도 복리후생비 총 한도', value: 205000000, unit: '원', operator: '=' as const }, + ], + }; + + return { + title: '복리후생비 상세', + + // 1. 요약 카드 (8개) + summaryCards: [ + // 1행: 당해년도 기준 + { label: '당해년도 복리후생비 계정', value: 3123000, unit: '원' }, + { label: '당해년도 복리후생비 한도', value: 600000, unit: '원' }, + { label: '당해년도 복리후생비 사용', value: 6000000, unit: '원' }, + { label: '당해년도 잔여한도', value: 0, unit: '원' }, + // 2행: 분기 기준 + { label: '1사분기 복리후생비 총 한도', value: 3123000, unit: '원' }, + { label: '1사분기 복리후생비 잔여한도', value: 6000000, unit: '원' }, + { label: '1사분기 복리후생비 사용금액', value: 6000000, unit: '원' }, + { label: '1사분기 복리후생비 초과 금액', value: 6000000, unit: '원' }, + ], + + // 2. 월별 사용 추이 (막대 차트) + barChart: { + title: '월별 복리후생비 사용 추이', + data: [ + { name: '1월', value: 1500000 }, + { name: '2월', value: 1800000 }, + { name: '3월', value: 2200000 }, + { name: '4월', value: 1900000 }, + { name: '5월', value: 2100000 }, + { name: '6월', value: 1700000 }, + ], + dataKey: 'value', + xAxisKey: 'name', + color: '#60A5FA', + }, + + // 3. 항목별 사용 비율 (도넛 차트) + pieChart: { + title: '항목별 사용 비율', + data: [ + { name: '식비', value: 55000000, percentage: 55, color: '#FBBF24' }, + { name: '건강검진', value: 25000000, percentage: 5, color: '#60A5FA' }, + { name: '경조사비', value: 10000000, percentage: 10, color: '#F87171' }, + { name: '기타', value: 10000000, percentage: 30, color: '#34D399' }, + ], + }, + + // 4. 일별 사용 내역 (테이블) + table: { + title: '일별 복리후생비 사용 내역', + columns: [ + { key: 'no', label: 'No.', align: 'center' }, + { key: 'cardName', label: '카드명', align: 'left' }, + { key: 'user', label: '사용자', align: 'center' }, + { key: 'date', label: '사용일자', align: 'center', format: 'date' }, + { key: 'store', label: '가맹점명', align: 'left' }, + { key: 'amount', label: '사용금액', align: 'right', format: 'currency' }, + { key: 'usageType', label: '사용항목', align: 'center' }, + ], + data: [ + { cardName: '카드명', user: '홍길동', date: '2025-12-12 12:12', store: '가맹점명', amount: 1000000, usageType: '식비' }, + { cardName: '카드명', user: '홍길동', date: '2025-12-12 12:12', store: '가맹점명', amount: 1200000, usageType: '건강검진' }, + { cardName: '카드명', user: '홍길동', date: '2025-12-12 12:12', store: '가맹점명', amount: 1500000, usageType: '경조사비' }, + { cardName: '카드명', user: '홍길동', date: '2025-12-12 12:12', store: '가맹점명', amount: 1300000, usageType: '기타' }, + { cardName: '카드명', user: '홍길동', date: '2025-12-12 12:12', store: '가맹점명', amount: 6000000, usageType: '식비' }, + ], + filters: [ + { + key: 'usageType', + options: [ + { value: 'all', label: '전체' }, + { value: '식비', label: '식비' }, + { value: '건강검진', label: '건강검진' }, + { value: '경조사비', label: '경조사비' }, + { value: '기타', label: '기타' }, + ], + defaultValue: 'all', + }, + { + key: 'sortOrder', + options: [ + { value: 'latest', label: '최신순' }, + { value: 'oldest', label: '등록순' }, + { value: 'amountDesc', label: '금액 높은순' }, + { value: 'amountAsc', label: '금액 낮은순' }, + ], + defaultValue: 'latest', + }, + ], + showTotal: true, + totalLabel: '합계', + totalValue: 11000000, + totalColumnKey: 'amount', + }, + + // 5. 복리후생비 계산 (조건부 - calculationType에 따라) + calculationCards, + + // 6. 분기별 현황 테이블 + quarterlyTable: { + title: '복리후생비 현황', + rows: [ + { label: '한도금액', q1: 12000000, q2: 12000000, q3: 12000000, q4: 12000000, total: 48000000 }, + { label: '이월금액', q1: 0, q2: '', q3: '', q4: '', total: '' }, + { label: '사용금액', q1: 1000000, q2: '', q3: '', q4: '', total: '' }, + { label: '잔여한도', q1: 11000000, q2: '', q3: '', q4: '', total: '' }, + { label: '초과금액', q1: '', q2: '', q3: '', q4: '', total: '' }, + ], + }, + }; +} +``` + +### 4.4 expense_accounts 테이블 스키마 + +**파일**: `api/database/migrations/2026_01_21_103734_create_expense_accounts_table.php` + +```sql +CREATE TABLE expense_accounts ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID', + + -- 비용 유형 + account_type VARCHAR(50) NOT NULL COMMENT '계정 유형: welfare, entertainment, etc.', + sub_type VARCHAR(50) NULL COMMENT '세부 유형: meal, gift, etc.', + + -- 비용 정보 + expense_date DATE NOT NULL COMMENT '지출일', + amount DECIMAL(15,2) DEFAULT 0 COMMENT '금액', + description VARCHAR(500) NULL COMMENT '비용 내역', + receipt_no VARCHAR(100) NULL COMMENT '증빙번호', + + -- 거래처 정보 + vendor_id BIGINT UNSIGNED NULL COMMENT '거래처 ID', + vendor_name VARCHAR(200) NULL COMMENT '거래처명 (직접 입력)', + + -- 카드/결제 정보 + payment_method VARCHAR(50) NULL COMMENT '결제수단: card, cash, transfer', + card_no VARCHAR(50) NULL COMMENT '카드 마지막 4자리', + + -- 감사 컬럼 + created_by BIGINT UNSIGNED NULL COMMENT '등록자', + updated_by BIGINT UNSIGNED NULL COMMENT '수정자', + deleted_by BIGINT UNSIGNED NULL COMMENT '삭제자', + + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + + -- 인덱스 + INDEX idx_tenant_type_date (tenant_id, account_type, expense_date), + INDEX idx_tenant_date (tenant_id, expense_date), + + -- 외래키 + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE, + FOREIGN KEY (vendor_id) REFERENCES clients(id) ON DELETE SET NULL +); +``` + +**account_type 값**: +- `welfare` - 복리후생비 +- `entertainment` - 접대비 + +**sub_type 값** (welfare의 경우): +- `meal` - 식비 +- `health_check` - 건강검진 +- `congratulation` - 경조사비 +- `other` - 기타 + +--- + +## 5. API → 모달 설정 변환 매핑 + +### 5.1 API 응답 스키마 (제안) + +```typescript +// 백엔드 API 응답: GET /api/v1/welfare/detail +interface WelfareDetailApiResponse { + // 요약 카드 데이터 + summary: { + annual_account: number; // 당해년도 복리후생비 계정 + annual_limit: number; // 당해년도 복리후생비 한도 + annual_used: number; // 당해년도 복리후생비 사용 + annual_remaining: number; // 당해년도 잔여한도 + quarterly_limit: number; // 분기 복리후생비 총 한도 + quarterly_remaining: number; // 분기 복리후생비 잔여한도 + quarterly_used: number; // 분기 복리후생비 사용금액 + quarterly_exceeded: number; // 분기 복리후생비 초과 금액 + }; + + // 월별 사용 추이 + monthly_usage: { + month: number; // 1-12 + amount: number; + }[]; + + // 항목별 분포 + category_distribution: { + category: string; // meal, health_check, congratulation, other + label: string; // 식비, 건강검진, 경조사비, 기타 + amount: number; + ratio: number; // 백분율 (0-100) + }[]; + + // 일별 사용 내역 + transactions: { + id: number; + card_name: string; + user_name: string; + expense_date: string; // YYYY-MM-DD HH:mm + vendor_name: string; + amount: number; + sub_type: string; + sub_type_label: string; + }[]; + + // 계산 정보 + calculation: { + type: 'fixed' | 'ratio'; + employee_count: number; + monthly_amount?: number; // fixed 방식 + total_salary?: number; // ratio 방식 + ratio?: number; // ratio 방식 (%) + annual_limit: number; + }; + + // 분기별 현황 + quarterly: { + quarter: number; // 1-4 + limit: number; + carryover: number; + used: number; + remaining: number; + exceeded: number; + }[]; +} +``` + +### 5.2 변환 매핑 테이블 + +| API 필드 | DetailModalConfig 필드 | 변환 로직 | +|----------|----------------------|----------| +| `summary.annual_account` | `summaryCards[0].value` | 직접 매핑 | +| `summary.annual_limit` | `summaryCards[1].value` | 직접 매핑 | +| `summary.annual_used` | `summaryCards[2].value` | 직접 매핑 | +| `summary.annual_remaining` | `summaryCards[3].value` | 직접 매핑 | +| `summary.quarterly_limit` | `summaryCards[4].value` | 라벨에 분기 동적 삽입 | +| `summary.quarterly_remaining` | `summaryCards[5].value` | 라벨에 분기 동적 삽입 | +| `summary.quarterly_used` | `summaryCards[6].value` | 라벨에 분기 동적 삽입 | +| `summary.quarterly_exceeded` | `summaryCards[7].value` | 라벨에 분기 동적 삽입 | +| `monthly_usage[]` | `barChart.data[]` | `{ name: '${month}월', value: amount }` | +| `category_distribution[]` | `pieChart.data[]` | 색상 매핑 추가 필요 | +| `transactions[]` | `table.data[]` | 필드명 camelCase 변환 | +| `calculation` | `calculationCards` | type에 따라 분기 | +| `quarterly[]` | `quarterlyTable.rows[]` | 행/열 피벗 변환 | + +### 5.3 색상 매핑 (카테고리별) + +```typescript +const CATEGORY_COLORS: Record = { + meal: '#FBBF24', // 식비 - 노란색 + health_check: '#60A5FA', // 건강검진 - 파란색 + congratulation: '#F87171', // 경조사비 - 빨간색 + other: '#34D399', // 기타 - 초록색 +}; +``` + +--- + +## 6. 상세 작업 내용 + +### 6.1 Phase 1: API 개발 + +#### 1.1 WelfareService 확장 + +**파일**: `api/app/Services/WelfareService.php` + +**추가할 메서드**: +```php +/** + * 복리후생비 상세 정보 조회 (모달용) + */ +public function getDetail( + ?string $calculationType = 'fixed', + ?int $fixedAmountPerMonth = 200000, + ?float $ratio = 0.05, + ?int $year = null, + ?int $quarter = null +): array { + // 1. 요약 데이터 조회 + // 2. 월별 사용 추이 조회 + // 3. 항목별 분포 조회 + // 4. 일별 사용 내역 조회 + // 5. 계산 정보 생성 + // 6. 분기별 현황 조회 +} +``` + +**필요한 쿼리**: +```php +// 월별 사용 추이 +DB::table('expense_accounts') + ->select(DB::raw('MONTH(expense_date) as month'), DB::raw('SUM(amount) as amount')) + ->where('tenant_id', $tenantId) + ->where('account_type', 'welfare') + ->whereYear('expense_date', $year) + ->whereNull('deleted_at') + ->groupBy(DB::raw('MONTH(expense_date)')) + ->orderBy('month') + ->get(); + +// 항목별 분포 +DB::table('expense_accounts') + ->select('sub_type', DB::raw('SUM(amount) as amount')) + ->where('tenant_id', $tenantId) + ->where('account_type', 'welfare') + ->whereBetween('expense_date', [$startDate, $endDate]) + ->whereNull('deleted_at') + ->groupBy('sub_type') + ->get(); + +// 일별 사용 내역 +DB::table('expense_accounts') + ->select('id', 'card_no', 'created_by', 'expense_date', 'vendor_name', 'amount', 'sub_type') + ->where('tenant_id', $tenantId) + ->where('account_type', 'welfare') + ->whereBetween('expense_date', [$startDate, $endDate]) + ->whereNull('deleted_at') + ->orderByDesc('expense_date') + ->get(); +``` + +#### 1.2 WelfareController 확장 + +**파일**: `api/app/Http/Controllers/Api/V1/WelfareController.php` + +**추가할 메서드**: +```php +/** + * 복리후생비 상세 조회 (모달용) + */ +public function detail(Request $request): JsonResponse +{ + $calculationType = $request->query('calculation_type', 'fixed'); + $fixedAmountPerMonth = $request->query('fixed_amount_per_month') + ? (int) $request->query('fixed_amount_per_month') + : 200000; + $ratio = $request->query('ratio') + ? (float) $request->query('ratio') + : 0.05; + $year = $request->query('year') ? (int) $request->query('year') : null; + $quarter = $request->query('quarter') ? (int) $request->query('quarter') : null; + + return ApiResponse::handle(function () use ($calculationType, $fixedAmountPerMonth, $ratio, $year, $quarter) { + return $this->welfareService->getDetail( + $calculationType, + $fixedAmountPerMonth, + $ratio, + $year, + $quarter + ); + }, __('message.fetched')); +} +``` + +#### 1.3 라우트 등록 + +**파일**: `api/routes/api.php` + +```php +Route::prefix('welfare')->group(function () { + Route::get('/summary', [WelfareController::class, 'summary']); + Route::get('/detail', [WelfareController::class, 'detail']); // 추가 +}); +``` + +### 6.2 Phase 2: 프론트엔드 연동 + +#### 2.1 타입 정의 추가 + +**파일**: `react/src/lib/api/dashboard/types.ts` + +```typescript +// Welfare Detail API 응답 타입 +export interface WelfareDetailApiResponse { + summary: { + annual_account: number; + annual_limit: number; + annual_used: number; + annual_remaining: number; + quarterly_limit: number; + quarterly_remaining: number; + quarterly_used: number; + quarterly_exceeded: number; + }; + monthly_usage: { + month: number; + amount: number; + }[]; + category_distribution: { + category: string; + label: string; + amount: number; + ratio: number; + }[]; + transactions: { + id: number; + card_name: string; + user_name: string; + expense_date: string; + vendor_name: string; + amount: number; + sub_type: string; + sub_type_label: string; + }[]; + calculation: { + type: 'fixed' | 'ratio'; + employee_count: number; + monthly_amount?: number; + total_salary?: number; + ratio?: number; + annual_limit: number; + }; + quarterly: { + quarter: number; + limit: number; + carryover: number; + used: number; + remaining: number; + exceeded: number; + }[]; +} +``` + +#### 2.2 API 함수 추가 + +**파일**: `react/src/hooks/useCEODashboard.ts` + +```typescript +export async function fetchWelfareDetail( + options: { + calculationType?: 'fixed' | 'ratio'; + fixedAmountPerMonth?: number; + ratio?: number; + year?: number; + quarter?: number; + } +): Promise { + const params = new URLSearchParams(); + if (options.calculationType) params.append('calculation_type', options.calculationType); + if (options.fixedAmountPerMonth) params.append('fixed_amount_per_month', options.fixedAmountPerMonth.toString()); + if (options.ratio) params.append('ratio', options.ratio.toString()); + if (options.year) params.append('year', options.year.toString()); + if (options.quarter) params.append('quarter', options.quarter.toString()); + + return fetchApi(`welfare/detail?${params.toString()}`); +} +``` + +#### 2.3 Transformer 추가 + +**파일**: `react/src/lib/api/dashboard/transformers.ts` + +```typescript +const CATEGORY_COLORS: Record = { + meal: '#FBBF24', + health_check: '#60A5FA', + congratulation: '#F87171', + other: '#34D399', +}; + +export function transformWelfareDetailToModalConfig( + api: WelfareDetailApiResponse, + quarter: number +): DetailModalConfig { + const quarterLabel = `${quarter}사분기`; + + return { + title: '복리후생비 상세', + + summaryCards: [ + { label: '당해년도 복리후생비 계정', value: api.summary.annual_account, unit: '원' }, + { label: '당해년도 복리후생비 한도', value: api.summary.annual_limit, unit: '원' }, + { label: '당해년도 복리후생비 사용', value: api.summary.annual_used, unit: '원' }, + { label: '당해년도 잔여한도', value: api.summary.annual_remaining, unit: '원' }, + { label: `${quarterLabel} 복리후생비 총 한도`, value: api.summary.quarterly_limit, unit: '원' }, + { label: `${quarterLabel} 복리후생비 잔여한도`, value: api.summary.quarterly_remaining, unit: '원' }, + { label: `${quarterLabel} 복리후생비 사용금액`, value: api.summary.quarterly_used, unit: '원' }, + { label: `${quarterLabel} 복리후생비 초과 금액`, value: api.summary.quarterly_exceeded, unit: '원' }, + ], + + barChart: { + title: '월별 복리후생비 사용 추이', + data: api.monthly_usage.map(m => ({ name: `${m.month}월`, value: m.amount })), + dataKey: 'value', + xAxisKey: 'name', + color: '#60A5FA', + }, + + pieChart: { + title: '항목별 사용 비율', + data: api.category_distribution.map(c => ({ + name: c.label, + value: c.amount, + percentage: c.ratio, + color: CATEGORY_COLORS[c.category] || '#9CA3AF', + })), + }, + + table: { + title: '일별 복리후생비 사용 내역', + columns: [ + { key: 'no', label: 'No.', align: 'center' }, + { key: 'cardName', label: '카드명', align: 'left' }, + { key: 'user', label: '사용자', align: 'center' }, + { key: 'date', label: '사용일자', align: 'center', format: 'date' }, + { key: 'store', label: '가맹점명', align: 'left' }, + { key: 'amount', label: '사용금액', align: 'right', format: 'currency' }, + { key: 'usageType', label: '사용항목', align: 'center' }, + ], + data: api.transactions.map((t, i) => ({ + no: i + 1, + cardName: t.card_name, + user: t.user_name, + date: t.expense_date, + store: t.vendor_name, + amount: t.amount, + usageType: t.sub_type_label, + })), + filters: [ + { + key: 'usageType', + options: [ + { value: 'all', label: '전체' }, + { value: '식비', label: '식비' }, + { value: '건강검진', label: '건강검진' }, + { value: '경조사비', label: '경조사비' }, + { value: '기타', label: '기타' }, + ], + defaultValue: 'all', + }, + { + key: 'sortOrder', + options: [ + { value: 'latest', label: '최신순' }, + { value: 'oldest', label: '등록순' }, + { value: 'amountDesc', label: '금액 높은순' }, + { value: 'amountAsc', label: '금액 낮은순' }, + ], + defaultValue: 'latest', + }, + ], + showTotal: true, + totalLabel: '합계', + totalValue: api.transactions.reduce((sum, t) => sum + t.amount, 0), + totalColumnKey: 'amount', + }, + + calculationCards: api.calculation.type === 'fixed' + ? { + title: '복리후생비 계산', + subtitle: `직원당 정액 금액/월 ${(api.calculation.monthly_amount || 0).toLocaleString()}원`, + cards: [ + { label: '직원 수', value: api.calculation.employee_count, unit: '명' }, + { label: '연간 직원당 월급 금액', value: (api.calculation.monthly_amount || 0) * 12, unit: '원', operator: '×' }, + { label: '당해년도 복리후생비 총 한도', value: api.calculation.annual_limit, unit: '원', operator: '=' }, + ], + } + : { + title: '복리후생비 계산', + subtitle: `연봉 총액 기준 비율 ${api.calculation.ratio}%`, + cards: [ + { label: '연봉 총액', value: api.calculation.total_salary || 0, unit: '원' }, + { label: '비율', value: api.calculation.ratio || 0, unit: '%', operator: '×' }, + { label: '당해년도 복리후생비 총 한도', value: api.calculation.annual_limit, unit: '원', operator: '=' }, + ], + }, + + quarterlyTable: { + title: '복리후생비 현황', + rows: [ + { + label: '한도금액', + q1: api.quarterly.find(q => q.quarter === 1)?.limit || '', + q2: api.quarterly.find(q => q.quarter === 2)?.limit || '', + q3: api.quarterly.find(q => q.quarter === 3)?.limit || '', + q4: api.quarterly.find(q => q.quarter === 4)?.limit || '', + total: api.quarterly.reduce((sum, q) => sum + q.limit, 0), + }, + { + label: '이월금액', + q1: api.quarterly.find(q => q.quarter === 1)?.carryover || '', + q2: api.quarterly.find(q => q.quarter === 2)?.carryover || '', + q3: api.quarterly.find(q => q.quarter === 3)?.carryover || '', + q4: api.quarterly.find(q => q.quarter === 4)?.carryover || '', + total: '', + }, + { + label: '사용금액', + q1: api.quarterly.find(q => q.quarter === 1)?.used || '', + q2: api.quarterly.find(q => q.quarter === 2)?.used || '', + q3: api.quarterly.find(q => q.quarter === 3)?.used || '', + q4: api.quarterly.find(q => q.quarter === 4)?.used || '', + total: api.quarterly.reduce((sum, q) => sum + q.used, 0), + }, + { + label: '잔여한도', + q1: api.quarterly.find(q => q.quarter === 1)?.remaining || '', + q2: api.quarterly.find(q => q.quarter === 2)?.remaining || '', + q3: api.quarterly.find(q => q.quarter === 3)?.remaining || '', + q4: api.quarterly.find(q => q.quarter === 4)?.remaining || '', + total: '', + }, + { + label: '초과금액', + q1: api.quarterly.find(q => q.quarter === 1)?.exceeded || '', + q2: api.quarterly.find(q => q.quarter === 2)?.exceeded || '', + q3: api.quarterly.find(q => q.quarter === 3)?.exceeded || '', + q4: api.quarterly.find(q => q.quarter === 4)?.exceeded || '', + total: '', + }, + ], + }, + }; +} +``` + +#### 2.4 모달 설정 동적 생성 + +**파일**: `react/src/components/business/CEODashboard/modalConfigs/welfareConfigs.ts` + +```typescript +import type { DetailModalConfig } from '../types'; +import { fetchWelfareDetail, transformWelfareDetailToModalConfig } from '@/lib/api/dashboard'; + +// 기존 Mock 함수 (fallback용) +export function getWelfareModalConfigMock(calculationType: 'fixed' | 'ratio'): DetailModalConfig { + // ... 기존 Mock 코드 유지 +} + +// 새로운 API 기반 함수 +export async function getWelfareModalConfigFromApi( + options: { + calculationType: 'fixed' | 'ratio'; + fixedAmountPerMonth?: number; + ratio?: number; + year?: number; + quarter?: number; + } +): Promise { + try { + const apiData = await fetchWelfareDetail(options); + return transformWelfareDetailToModalConfig(apiData, options.quarter || getCurrentQuarter()); + } catch (error) { + console.error('[Welfare] Failed to fetch detail, using mock data:', error); + return getWelfareModalConfigMock(options.calculationType); + } +} + +function getCurrentQuarter(): number { + return Math.ceil((new Date().getMonth() + 1) / 3); +} +``` + +--- + +## 7. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 새 API 엔드포인트 | `GET /api/v1/welfare/detail` 추가 | api | ✅ 완료 | +| 2 | WelfareService 확장 | getDetail() 메서드 추가 | api | ✅ 완료 | + +--- + +## 8. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-22 | - | 문서 초안 작성 | - | - | +| 2026-01-22 | - | 자기완결성 보완 (타입, 스키마, 매핑 추가) | - | - | +| 2026-01-22 | Phase 1.1 | getDetail() 메서드 추가 | WelfareService.php | ✅ | +| 2026-01-22 | Phase 1.1 | detail() 액션 추가 | WelfareController.php | ✅ | +| 2026-01-22 | Phase 1.1 | /welfare/detail 라우트 추가 | routes/api.php | ✅ | +| 2026-01-22 | Phase 1.2 | Swagger 스키마 및 엔드포인트 추가 | WelfareApi.php | ✅ | +| 2026-01-22 | Phase 2.1 | WelfareDetailApiResponse 타입 추가 | types.ts | ✅ | +| 2026-01-22 | Phase 2.2 | useWelfareDetail hook 추가 | useCEODashboard.ts | ✅ | +| 2026-01-22 | Phase 2.3 | transformWelfareDetailResponse 추가 | transformers.ts | ✅ | +| 2026-01-22 | Phase 2.4 | 모달 설정 API 연동 + fallback | CEODashboard.tsx, welfareConfigs.ts | ✅ | + +--- + +## 9. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **API 규칙**: `api/CLAUDE.md` (SAM API Development Rules) +- **Swagger 가이드**: `docs/guides/swagger-guide.md` + +--- + +## 10. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 10.1 세션 시작 시 (Load Strategy) +```javascript +// 순차적 로드 +read_memory("welfare-section-state") // 1. 상태 파악 +read_memory("welfare-section-snapshot") // 2. 사고 흐름 복구 +``` + +### 10.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | 🛠 **Snapshot** | `write_memory("welfare-section-snapshot", "코드변경+논의요약")` | +| **20% 이하** | 🧹 **Context Purge** | `write_memory("welfare-section-active-symbols", "주요 수정 파일/함수")` | +| **10% 이하** | 🛑 **Stop & Save** | 최종 상태 저장 후 세션 교체 권고 | + +### 10.3 Serena 메모리 구조 +- `welfare-section-state`: { phase, progress, next_step, last_decision } +- `welfare-section-snapshot`: 현재까지의 논의 및 코드 변경점 요약 +- `welfare-section-active-symbols`: 현재 수정 중인 파일/심볼 리스트 + +--- + +## 11. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 11.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| 모달 클릭 (fixed) | 정액 방식 계산 표시 | - | ⏳ | +| 모달 클릭 (ratio) | 비율 방식 계산 표시 | - | ⏳ | +| 분기 변경 (Q1→Q2) | 해당 분기 데이터 표시 | - | ⏳ | + +### 11.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 4개 카드 데이터 실시간 반영 | ✅ | API 연동 완료 상태 | +| 모달 상세 데이터 API 연동 | ✅ | Backend API + Frontend hook 완료 | +| Mock 데이터 제거 | ✅ | API 우선, Mock fallback 유지 | + +--- + +## 12. 자기완결성 점검 결과 + +### 12.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 모달 데이터 API 연동 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 11.2 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | 2. 대상 범위 참조 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Phase 1 → Phase 2 순서 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 4. 핵심 참조 코드 인라인 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 6. 상세 작업 내용 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 11.1 테스트 케이스 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 코드 스니펫 포함 | + +### 12.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 3.1 단계별 절차 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 6. 상세 작업 내용 | +| Q4. DetailModalConfig 구조는? | ✅ | 4.1, 4.2 타입 정의 | +| Q5. Mock 데이터 구조는? | ✅ | 4.3 현재 Mock 데이터 | +| Q6. DB 테이블 스키마는? | ✅ | 4.4 expense_accounts | +| Q7. API → 모달 변환 방법은? | ✅ | 5. 변환 매핑 | +| Q8. 작업 완료 확인 방법은? | ✅ | 11. 검증 결과 | +| Q9. 막혔을 때 참고 문서는? | ✅ | 9. 참고 문서 | + +**결과**: 9/9 통과 → ✅ 자기완결성 확보 + +### 12.3 보완 이력 + +| 날짜 | 항목 | 원본 | 보완 내용 | +|------|------|------|----------| +| 2026-01-22 | DetailModalConfig | 없음 | 타입 정의 전체 인라인 | +| 2026-01-22 | Mock 데이터 | 없음 | welfareConfigs.ts 전체 인라인 | +| 2026-01-22 | DB 스키마 | 없음 | expense_accounts 테이블 구조 | +| 2026-01-22 | 변환 매핑 | 없음 | API → 모달 매핑 테이블 및 코드 | + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/archive/work-order-plan.md b/plans/archive/work-order-plan.md new file mode 100644 index 0000000..56c5c1b --- /dev/null +++ b/plans/archive/work-order-plan.md @@ -0,0 +1,409 @@ +# 작업지시 (Work Orders) API 연동 계획 + +> **작성일**: 2025-01-08 +> **목적**: 작업지시 기능 검증 및 테스트 +> **상태**: ✅ 전체 테스트 완료 (2025-01-11) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 전체 기능 테스트 완료 (2025-01-11) | +| **다음 작업** | 운영 준비 | +| **진행률** | 5/5 (100%) | +| **마지막 업데이트** | 2025-01-11 | + +--- + +## 1. 개요 + +### 1.1 기능 설명 +작업지시는 MES 시스템의 핵심 기능으로, 수주를 기반으로 실제 생산 작업을 지시하고 추적합니다. +공정 유형별(스크린/슬랫/절곡)로 작업 단계를 관리하며, 담당자 배정 및 작업 상태를 추적합니다. + +### 1.2 현재 구현 상태 분석 + +#### API (Laravel) - ✅ 완료 +| 구성요소 | 파일 경로 | 상태 | +|---------|----------|:----:| +| Model | `api/app/Models/Production/WorkOrder.php` | ✅ | +| Model | `api/app/Models/Production/WorkOrderItem.php` | ✅ | +| Model | `api/app/Models/Production/WorkOrderBendingDetail.php` | ✅ | +| Model | `api/app/Models/Production/WorkOrderIssue.php` | ✅ | +| Service | `api/app/Services/WorkOrderService.php` | ✅ | +| Controller | `api/app/Http/Controllers/Api/V1/WorkOrderController.php` | ✅ | +| FormRequest | `api/app/Http/Requests/WorkOrder/*.php` | ✅ | +| Route | `/api/v1/work-orders` | ✅ | + +#### Frontend (React/Next.js) - ✅ API 연동 완료 +| 구성요소 | 파일 경로 | 상태 | +|---------|----------|:----:| +| 목록 페이지 | `react/src/app/[locale]/(protected)/production/work-orders/page.tsx` | ✅ | +| 등록 페이지 | `react/src/app/[locale]/(protected)/production/work-orders/create/page.tsx` | ✅ | +| 상세 페이지 | `react/src/app/[locale]/(protected)/production/work-orders/[id]/page.tsx` | ✅ | +| 목록 컴포넌트 | `react/src/components/production/WorkOrders/WorkOrderList.tsx` | ✅ | +| 등록 컴포넌트 | `react/src/components/production/WorkOrders/WorkOrderCreate.tsx` | ✅ | +| 상세 컴포넌트 | `react/src/components/production/WorkOrders/WorkOrderDetail.tsx` | ✅ | +| 수주선택 모달 | `react/src/components/production/WorkOrders/SalesOrderSelectModal.tsx` | ✅ | +| 담당자선택 모달 | `react/src/components/production/WorkOrders/AssigneeSelectModal.tsx` | ✅ | +| 타입 정의 | `react/src/components/production/WorkOrders/types.ts` | ✅ | +| **actions.ts** | `react/src/components/production/WorkOrders/actions.ts` | ✅ | + +### 1.3 관련 URL +| 화면 | URL | 설명 | +|------|-----|------| +| 작업지시목록 | `/production/work-orders` | 상태별 필터링, 검색 | +| 작업지시등록 | `/production/work-orders/create` | 모달 - 수주선택 | +| 작업지시상세 | `/production/work-orders/{id}` | 상세 정보 | + +### 1.4 연관관계 +``` +┌─────────────────┐ ┌─────────────────┐ +│ Order │────sales_order_id──▶│ WorkOrder │ +│ (수주) │ │ (작업지시) │ +└─────────────────┘ └─────────────────┘ + │ + ┌───────────────────────────────────────┼───────────────────────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ WorkOrderItem │ │WorkOrderBending │ │ WorkOrderIssue │ +│ (작업품목) │ │ Detail │ │ (이슈) │ +└─────────────────┘ │ (절곡상세) │ └─────────────────┘ + └─────────────────┘ + │ + │ work_order_id + ▼ + ┌─────────────────┐ + │ WorkResult │ + │ (작업실적) │ + └─────────────────┘ +``` + +--- + +## 2. API 엔드포인트 + +### 2.1 REST API (구현 완료) +| Method | Endpoint | 설명 | 상태 | +|--------|----------|------|:----:| +| GET | `/api/v1/work-orders` | 목록 조회 (필터/페이징) | ✅ | +| GET | `/api/v1/work-orders/stats` | 통계 조회 | ✅ | +| GET | `/api/v1/work-orders/{id}` | 상세 조회 | ✅ | +| POST | `/api/v1/work-orders` | 작업지시 생성 | ✅ | +| PUT | `/api/v1/work-orders/{id}` | 작업지시 수정 | ✅ | +| DELETE | `/api/v1/work-orders/{id}` | 작업지시 삭제 | ✅ | +| PATCH | `/api/v1/work-orders/{id}/status` | 상태 변경 | ✅ | +| PATCH | `/api/v1/work-orders/{id}/assign` | 담당자 배정 | ✅ | +| PATCH | `/api/v1/work-orders/{id}/bending/toggle` | 절곡 상세 토글 | ✅ | +| POST | `/api/v1/work-orders/{id}/issues` | 이슈 등록 | ✅ | +| PATCH | `/api/v1/work-orders/{id}/issues/{issueId}/resolve` | 이슈 해결 | ✅ | + +### 2.2 actions.ts 구현 함수 (완료) +```typescript +// 목록/조회 +getWorkOrders(params) // 목록 조회 +getWorkOrderStats() // 통계 조회 +getWorkOrderById(id) // 상세 조회 + +// CRUD +createWorkOrder(data) // 생성 +updateWorkOrder(id, data) // 수정 +deleteWorkOrder(id) // 삭제 + +// 상태/배정 +updateWorkOrderStatus(id, status) // 상태 변경 +assignWorkOrder(id, data) // 담당자 배정 + +// 절곡 공정 +toggleBendingField(id, field, value) // 절곡 상세 토글 + +// 이슈 관리 +addWorkOrderIssue(id, data) // 이슈 등록 +resolveWorkOrderIssue(id, issueId) // 이슈 해결 + +// 연동 +getSalesOrdersForWorkOrder() // 수주 목록 (작업지시용) +getDepartmentsWithUsers() // 부서/사용자 목록 (담당자 배정용) +``` + +--- + +## 3. 데이터 스키마 + +### 3.1 WorkOrder (작업지시) +```typescript +interface WorkOrder { + id: string; + workOrderNo: string; // WO202512260001 + lotNo: string; // 수주번호 참조 + processType: 'screen' | 'slat' | 'bending'; + status: WorkOrderStatus; + // 기본 정보 + client: string; // 발주처 + projectName: string; // 현장명 + dueDate: string; // 납기일 + assignee: string; // 작업자 + // 날짜 + orderDate: string; // 지시일 + shipmentDate: string; // 출고예정일 + // 플래그 + isAssigned: boolean; + isStarted: boolean; + priority: number; // 1~9 + // 품목 + items: WorkOrderItem[]; + // 공정 진행 + currentStep: number; + // 절곡 전용 + bendingDetails?: BendingDetail[]; + // 이슈 + issues?: WorkOrderIssue[]; + note?: string; +} +``` + +### 3.2 WorkOrderStatus (상태) +```typescript +type WorkOrderStatus = + | 'unassigned' // 미배정 + | 'pending' // 승인대기 + | 'waiting' // 작업대기 + | 'in_progress' // 작업중 + | 'completed' // 작업완료 + | 'shipped'; // 출하완료 +``` + +### 3.3 ProcessType (공정 유형) +```typescript +type ProcessType = 'screen' | 'slat' | 'bending'; + +// 공정별 작업 단계 +const SCREEN_STEPS = ['원단절단', '미싱', '앤드락작업', '중간검사', '포장']; +const SLAT_STEPS = ['코일절단', '성형', '미미작업', '검사', '포장']; +const BENDING_STEPS = ['가이드레일 제작', '케이스 제작', '하단마감재 제작', '검사']; +``` + +--- + +## 4. 작업 범위 + +### Phase 1: 검증 및 테스트 ✅ 완료 (2025-01-11) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | 목록 조회 테스트 | ✅ | 필터링/검색/페이징 정상 | +| 1.2 | 등록 기능 테스트 | ✅ | 수주 선택 모달 동작 확인 | +| 1.3 | 상세 조회 테스트 | ✅ | 버그 수정 완료 (site_name 컬럼 수정) | +| 1.4 | 상태 변경 테스트 | ✅ | 전체 상태 전이 검증 완료 | +| 1.5 | 담당자 배정 테스트 | ✅ | 배정 시 상태 자동 전이 확인 | + +**Phase 1 테스트 상세:** +- **버그 수정**: WorkOrderService.php:119 - `project_name` → `site_name` (Order 모델에 맞춤) +- **상태 전이**: pending ⇄ waiting ⇄ in_progress ⇄ completed ⇄ shipped 모두 정상 +- **담당자 배정**: 배정 시 unassigned → pending 자동 전이 확인 + +### Phase 2: 공정별 기능 테스트 ✅ 완료 (2025-01-11) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | 스크린 공정 작업지시 | ✅ | process_id=2 생성 확인 | +| 2.2 | 슬랫 공정 작업지시 | ✅ | process_id=1 생성 확인 | +| 2.3 | 공정별 필터링 | ✅ | forProcess(), forProcessName() 정상 | +| 2.4 | 작업지시 품목 관리 | ✅ | WorkOrderItem CRUD 확인 | + +**Phase 2 테스트 상세:** +- **공정 목록**: 슬랫(P-001), 스크린(P-002) 활성화 확인 +- **공정별 필터**: `forProcess(1)`, `forProcessName('슬랫')` 정상 동작 +- **품목 관리**: 작업지시별 품목 추가/조회 정상 + +### Phase 3: 이슈 및 연동 ✅ 완료 (2025-01-11) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | 이슈 등록 기능 | ✅ | 이슈 생성 정상 | +| 3.2 | 이슈 해결 기능 | ✅ | 해결 상태/시간 저장 확인 | +| 3.3 | 수주 연동 확인 | ✅ | salesOrder 관계 정상 | +| 3.4 | 작업실적 연동 | ⏭️ | 후순위 (별도 기능) | + +**Phase 3 테스트 상세:** +- **이슈 관리**: 등록(open) → 해결(resolved) 전체 흐름 정상 +- **open_issues_count**: 미해결 이슈 카운트 속성 정상 +- **수주 연동**: WorkOrder.salesOrder 관계를 통한 수주 정보 조회 정상 + +--- + +## 5. 주요 기능 상세 + +### 5.1 수주 선택 (모달) +``` +작업지시 등록 + │ + ▼ "수주 선택" 버튼 +┌─────────────────────────────────┐ +│ SalesOrderSelectModal │ +│ - 수주 목록 (for_work_order=1) │ +│ - 검색 기능 │ +│ - 선택 시 정보 자동 채움 │ +└─────────────────────────────────┘ +``` + +### 5.2 상태 흐름 +``` +unassigned (미배정) + │ + ▼ 담당자 배정 +pending (승인대기) + │ + ▼ 승인 +waiting (작업대기) + │ + ▼ 작업 시작 +in_progress (작업중) + │ + ▼ 작업 완료 +completed (작업완료) + │ + ▼ 출하 +shipped (출하완료) +``` + +### 5.3 공정별 작업 단계 + +#### 스크린 공정 (screen) +1. 원단절단 (cutting) +2. 미싱 (sewing) +3. 앤드락작업 (endlock) +4. 중간검사 (inspection) +5. 포장 (packing) + +#### 슬랫 공정 (slat) +1. 코일절단 (coil_cutting) +2. 성형 (forming) +3. 미미작업 (finishing) +4. 검사 (inspection) +5. 포장 (packing) + +#### 절곡 공정 (bending) +1. 가이드레일 제작 (guide_rail) +2. 케이스 제작 (case) +3. 하단마감재 제작 (bottom_finish) +4. 검사 (inspection) + +### 5.4 절곡 상세 토글 +- 절곡 공정의 세부 항목 완료 여부 토글 +- `PATCH /api/v1/work-orders/{id}/bending/toggle` +- 필드: shaft_cutting, bearing, shaft_welding, assembly 등 + +### 5.5 이슈 관리 +- 작업 중 발생한 이슈 등록 +- 우선순위: low, medium, high +- 상태: pending → resolved + +--- + +## 6. 의존성 + +### 6.1 필수 선행 작업 +- **공정관리 (Process)**: 공정 유형 정의 - ✅ 완료 +- **사원관리**: 담당자 배정 (assignee_id) +- **부서관리**: 팀 배정 (team_id) + +### 6.2 관련 의존성 +- **수주관리 (Order)**: 수주 데이터 필요 (sales_order_id) + - ✅ Order API 연동 완료 (2025-01-09) + - 수주 → 생산지시 생성 기능 연동됨 + +### 6.3 후속 연동 +- **작업실적 (WorkResult)**: 작업 완료 후 실적 등록 +- **품질검사**: 검사 공정 연동 +- **출하관리**: 출하 처리 + +--- + +## 7. 검증 방법 + +### 7.1 테스트 체크리스트 + +| 기능 | 테스트 항목 | 예상 결과 | +|------|-----------|----------| +| 목록 조회 | 페이지 로드 | 작업지시 목록 표시 | +| 상태 필터 | "작업중" 탭 클릭 | 해당 상태만 표시 | +| 검색 | 작업지시번호 검색 | 필터링된 결과 | +| 등록 | 새 작업지시 등록 | 목록에 추가됨 | +| 상세 조회 | 행 클릭 | 상세 정보 표시 | +| 상태 변경 | 상태 버튼 클릭 | 상태 전환됨 | +| 담당자 배정 | 배정 버튼 클릭 | 담당자 변경됨 | +| 이슈 등록 | 이슈 추가 | 이슈 목록에 표시 | + +### 7.2 API 테스트 +```bash +# 목록 조회 +curl -X GET "http://api.sam.kr/api/v1/work-orders" -H "X-Api-Key: ..." + +# 상세 조회 +curl -X GET "http://api.sam.kr/api/v1/work-orders/1" -H "X-Api-Key: ..." + +# 통계 조회 +curl -X GET "http://api.sam.kr/api/v1/work-orders/stats" -H "X-Api-Key: ..." + +# 상태 변경 +curl -X PATCH "http://api.sam.kr/api/v1/work-orders/1/status" \ + -H "X-Api-Key: ..." \ + -H "Content-Type: application/json" \ + -d '{"status": "in_progress"}' +``` + +--- + +## 8. 참고 사항 + +### 8.1 작업지시번호 형식 +- 형식: `WO{YYYYMMDD}{NNNN}` +- 예: `WO202512260001` +- 자동 생성: `WorkOrderService::generateWorkOrderNo()` + +### 8.2 Worker Screen (작업자 화면) +- 별도 화면: `/production/worker-screen` +- 작업자가 직접 작업 진행/완료 처리 +- 이슈 보고 기능 +- `react/src/components/production/WorkerScreen/` 참고 + +### 8.3 Production Dashboard +- 생산 현황 대시보드: `/production/dashboard` +- 공정별 작업 현황 시각화 +- `react/src/components/production/ProductionDashboard/` 참고 + +--- + +## 9. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **API 규칙**: `docs/standards/api-rules.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` + +### 참고 코드 +- **Controller**: `api/app/Http/Controllers/Api/V1/WorkOrderController.php` +- **Service**: `api/app/Services/WorkOrderService.php` +- **actions.ts**: `react/src/components/production/WorkOrders/actions.ts` + +--- + +## 10. 자기완결성 점검 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 검증 및 테스트 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 7 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-3 테스트 항목 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Order API 연동 완료 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 모든 경로 검증됨 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 테스트 체크리스트 제공 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | curl + 체크리스트 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 경로 명시 | + +--- + +*이 문서는 독립 세션에서 바로 작업 시작 가능하도록 설계되었습니다.* \ No newline at end of file diff --git a/plans/bending-preproduction-stock-plan.md b/plans/bending-preproduction-stock-plan.md new file mode 100644 index 0000000..352ae35 --- /dev/null +++ b/plans/bending-preproduction-stock-plan.md @@ -0,0 +1,838 @@ +# 절곡품 선생산 → 재고 적재 흐름 통합 개발 계획 + +> **작성일**: 2026-02-21 +> **목적**: 레거시 5130 절곡품(가이드레일/셔터박스/바텀바) 관리를 SAM 기존 재고 시스템에 통합하고, 선생산→재고적재 흐름 구현 +> **기준 문서**: `api/app/Services/StockService.php`, `api/app/Services/WorkOrderService.php`, `docs/plans/bending-info-auto-generation-plan.md` +> **상태**: 🔄 Phase 3 완료 (3.5 마이그레이션 제외) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 3.5 레거시 데이터 마이그레이션 커맨드 작성 완료 | +| **다음 작업** | 마이그레이션 실행 및 검증 | +| **진행률** | 14/14 (100%) | +| **마지막 업데이트** | 2026-02-21 | + +--- + +## 0. 용어 및 비즈니스 배경 + +### 0.1 절곡품이란? +- **절곡(Bending)**: 금속판(철판, SUS, EGI)을 절곡기로 구부려 만드는 부품 +- **주요 절곡품 3종**: + - **가이드레일**: 방화셔터가 상하로 이동하는 레일 (벽면형/측면형, SUS/EGI 마감) + - **셔터박스(케이스)**: 방화셔터가 말려 들어가는 상부 박스 (양면/밑면/후면 점검구) + - **바텀바(하단마감재)**: 방화셔터 하부를 마감하는 부품 (스크린/철재) +- **연기차단재**: 가이드레일/케이스에 부착하는 연기 차단용 부자재 (W50 레일용, W80 케이스용) + +### 0.2 선생산 운영 방식 +- 절곡품은 **수주와 무관하게 미리 대량 생산**하여 재고로 비축 +- 수주 발생 시 비축된 재고에서 **투입(차감)**하여 사용 +- 이유: 절곡 공정은 셋업 시간이 길어 건별 생산보다 일괄 생산이 효율적 + +### 0.3 SAM 프로젝트 구조 +``` +SAM/ +├── api/ # Laravel 12 REST API (백엔드) +├── react/ # Next.js 15 프론트엔드 +├── mng/ # 관리자 패널 (Plain Laravel) +├── 5130/ # 레거시 시스템 소스코드 (참조용) +└── docs/ # 기술 문서 +``` + +### 0.4 SAM 핵심 아키텍처 규칙 +- **Service-First**: 비즈니스 로직은 반드시 Service 레이어 +- **Multi-tenancy**: 모든 모델에 `BelongsToTenant` trait, tenant_id 필수 +- **컬럼 추가 정책**: FK/조인키만 컬럼 추가, 나머지 속성은 `options` JSON 활용 +- **FormRequest**: Controller에서 검증 금지, FormRequest 사용 + +--- + +## 1. 개요 + +### 1.1 배경 + +레거시 5130에서 절곡품(가이드레일, 셔터박스, 바텀바)은 **수주와 무관하게 미리 생산하여 재고로 관리**하는 형태. +수주 발생 시 재고에서 투입(차감)하는 방식으로 운영됨. + +SAM에는 이미 재고 관리 시스템(`stocks` + `stock_lots` + `stock_transactions`)이 구축되어 있으나, +**생산 완료 → 재고 입고** 경로가 없어 절곡품 선생산 흐름을 지원하지 못함. + +### 1.2 레거시 5130 절곡품 관리 구조 + +``` +[5130 시스템] + +┌─────────────────────────────────────────────────────────────┐ +│ 절곡품 마스터 (3종) │ +│ ├── guiderail 테이블 (가이드레일) │ +│ │ ├── 대분류: 스크린/철재 │ +│ │ ├── 인정/비인정, 제품코드(KSS01 등) │ +│ │ ├── 치수: rail_width × rail_length │ +│ │ ├── material_summary (소요자재량 JSON) │ +│ │ └── bending_components (절곡 구성품) │ +│ ├── shutterbox 테이블 (셔터박스) │ +│ │ ├── 점검구 형태: 양면/밑면/후면 │ +│ │ └── 치수: box_width × box_height │ +│ └── bottombar 테이블 (바텀바/하단마감재) │ +│ ├── 대분류: 스크린/철재 │ +│ └── 치수: bar_width × bar_height │ +│ │ +│ 재고 관리 │ +│ ├── lot 테이블 (생산 LOT) │ +│ │ ├── 3코드 식별: prod + spec + slength │ +│ │ ├── lot_number, surang(수량), rawLot(원자재LOT) │ +│ │ └── 재고 = SUM(lot.surang) - SUM(bending_work_log.qty) │ +│ └── bending_work_log 테이블 (사용 이력) │ +│ └── quantity, reg_date, lot_no │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 1.3 SAM 현재 상태 (AS-IS) + +``` +[수주 기반 흐름만 존재] + +Order(수주) ──→ WorkOrder(생산지시) ──→ 자재투입 ──→ 완료 ──→ Shipment(출하) + │ │ │ + │ sales_order_id 필수 │ 재고차감 │ ⚠️ 재고입고 없이 + │ (비즈니스 로직상) │ (기존 OK) │ 바로 출하 + +[구매입고 흐름 (별도)] + +Receiving(입고) ──→ StockService::increaseFromReceiving() (라인 241) + │ Stock + StockLot 생성 + │ StockTransaction(IN, receiving) + └─ FIFO 순서 부여 +``` + +### 1.4 목표 흐름 (TO-BE) + +``` +[선생산 흐름 (신규)] + +선생산 작업지시 ──→ 자재투입 ──→ 생산완료 + │ sales_order_id = NULL │ + │ mode = 'manual' (프론트) │ + ▼ + ⭐ 재고 입고 (신규) + StockService::increaseFromProduction() + Stock + StockLot 생성 + StockTransaction(IN, production_output) + │ + ▼ + [완성품 재고 적재] + LOT 추적, FIFO 관리 + │ + ▼ + [수주 발생 시] + 재고 확인 → reserve() → 부족분만 생산지시 + +[기존 수주 기반 흐름 (변경 없음)] + +Order ──→ WorkOrder ──→ 완료 ──→ Shipment (기존 유지) +``` + +### 1.5 핵심 설계 결정 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 설계 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 기존 재고 시스템(stocks/stock_lots/stock_transactions) 재활용 │ +│ 2. Receiving은 구매입고 전용 유지 → 생산입고는 직접 StockService │ +│ 3. 멀티테넌시 정책: FK만 컬럼, 나머지는 options JSON │ +│ 4. items.options 체계 활용 (production_source, lot_managed 등) │ +│ 5. 절곡품 전용 페이지 불필요 → 기존 재고현황에 필터 추가 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.6 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 상수 추가, 필터 파라미터 추가, options JSON 활용 | 불필요 | +| ⚠️ 컨펌 필요 | 신규 메서드 추가, 비즈니스 로직 분기, 프론트 UI 변경 | **필수** | +| 🔴 금지 | 기존 입출고 로직 변경, stocks 테이블 구조 변경, 기존 API 스펙 변경 | 별도 협의 | + +### 1.7 준수 규칙 +- `CLAUDE.md` - Service-First, FormRequest, BelongsToTenant +- `SAM_QUICK_REFERENCE.md` - API 규칙 +- `docs/plans/bending-info-auto-generation-plan.md` - BendingInfoBuilder 참조 +- `docs/plans/bending-worklog-reimplementation-plan.md` - 프론트 절곡 컴포넌트 참조 + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: 재고 입고 기반 구축 (백엔드) + +| # | 작업 항목 | 상태 | 영향 파일 | +|---|----------|:----:|----------| +| 1.1 | StockTransaction REASON 상수 추가 | ✅ | `api/app/Models/Tenants/StockTransaction.php` (라인 41-57) | +| 1.2 | StockLot에 work_order_id 컬럼 추가 | ✅ | `api/database/migrations/` (신규), `api/app/Models/Tenants/StockLot.php` | +| 1.3 | StockService::increaseFromProduction() 구현 | ✅ | `api/app/Services/StockService.php` (라인 241 참조) | +| 1.4 | WorkOrderService 완료 처리 분기 로직 | ✅ | `api/app/Services/WorkOrderService.php` (라인 563-593) | + +### 2.2 Phase 2: 선생산 작업지시 흐름 (백엔드 + 프론트) + +| # | 작업 항목 | 상태 | 영향 파일 | +|---|----------|:----:|----------| +| 2.1 | 수주 없는 작업지시 API 보완 | ✅ | 이미 지원됨 (sales_order_id nullable, items 직접 전달 가능) | +| 2.2 | items.options 기반 비즈니스 로직 분기 | ✅ | Phase 1에서 shouldStockIn()으로 구현 완료 | +| 2.3 | 작업지시 생성 프론트 UI 보완 (manual 모드) | ✅ | `react/.../WorkOrderCreate.tsx` + `actions.ts` (품목 검색/추가 UI, items 파라미터) | +| 2.4 | 재고현황 item_category 필터 추가 (API) | ✅ | `api/app/Services/StockService.php`, `StockController.php` | +| 2.5 | 재고현황 절곡품 필터 추가 (프론트) | ✅ | `react/.../StockStatusList.tsx` + `actions.ts` (카테고리 필터 드롭다운) | + +### 2.3 Phase 3: 수주 연동 고도화 + +| # | 작업 항목 | 상태 | 영향 파일 | +|---|----------|:----:|----------| +| 3.1 | 수주의 절곡 BOM 품목별 재고 확인 API | ✅ | `api/app/Services/OrderService.php`, `OrderController.php`, `routes/api/v1/sales.php` | +| 3.2 | 가용 재고 자동 예약(reserve) 로직 | ✅ | 기존 `reserveForOrder()` (라인 639-642)에서 이미 처리됨 | +| 3.3 | 부족분 수동 처리 (사용자 결정) | ✅ | 프론트에서 부족 현황 표시 → 사용자가 수동으로 선생산 작업지시 생성 | +| 3.4 | 수주화면 절곡 재고 현황 표시 (프론트) | ✅ | `react/src/components/orders/actions.ts`, `orders/index.ts`, `order-management-sales/[id]/page.tsx` | +| 3.5 | 5130 레거시 데이터 마이그레이션 | ⏳ | `api/database/seeders/` 또는 마이그레이션 스크립트 (별도 진행) | + +--- + +## 3. 작업 절차 + +### 3.1 Phase 1 상세 절차 + +``` +Step 1.1: StockTransaction REASON 상수 추가 +├── 파일: api/app/Models/Tenants/StockTransaction.php +├── 위치: 라인 49 (REASON_ORDER_CANCEL 다음) +├── 추가: const REASON_PRODUCTION_OUTPUT = 'production_output'; +├── REASONS 배열에도 추가 (라인 51-57) +└── 검증: 모델 상수 선언 확인 + +Step 1.2: StockLot에 work_order_id 컬럼 추가 +├── 마이그레이션 파일 생성 +│ └── stock_lots 테이블에 work_order_id (nullable, FK → work_orders.id) 추가 +│ └── 위치: receiving_id (라인 47) 다음 +├── StockLot 모델 수정 (api/app/Models/Tenants/StockLot.php) +│ ├── fillable에 'work_order_id' 추가 (라인 15-34) +│ └── workOrder() 관계 추가: belongsTo(WorkOrder::class) +├── 멀티테넌시 정책: work_order_id는 FK이므로 컬럼 추가 정당 +└── 검증: migrate:status, 모델 관계 확인 + +Step 1.3: StockService::increaseFromProduction() 구현 +├── 파일: api/app/Services/StockService.php +├── 기존 increaseFromReceiving() (라인 241-314) 참고하여 구현 +│ ├── getOrCreateStock() 재사용 (라인 423-466) +│ ├── getNextFifoOrder() 재사용 (라인 474) +│ ├── StockLot 생성 (work_order_id 참조, receiving_id는 null) +│ ├── Stock.refreshFromLots() 호출 (Stock.php 라인 149-164) +│ ├── recordTransaction() 호출 (라인 1232) +│ └── logStockChange() 호출 (라인 1274) +├── 차이점: receiving_id 대신 work_order_id 사용, supplier 관련 필드 null +├── LOT 번호: WorkOrderService::generateLotNo() (라인 845-866) 에서 생성한 것 수신 +└── 검증: 단위 테스트 (입고 후 재고량 증가 확인) + +Step 1.4: WorkOrderService 완료 처리 분기 로직 +├── 파일: api/app/Services/WorkOrderService.php +├── 수정 위치: updateStatus() 라인 591-593 +│ 현재 코드: +│ if ($status === WorkOrder::STATUS_COMPLETED) { +│ $this->createShipmentFromWorkOrder($workOrder, $tenantId, $userId); +│ } +│ 변경: +│ if ($status === WorkOrder::STATUS_COMPLETED) { +│ if ($workOrder->sales_order_id) { +│ $this->createShipmentFromWorkOrder($workOrder, $tenantId, $userId); +│ } else { +│ $this->stockInFromProduction($workOrder); +│ } +│ } +├── saveItemResults() (라인 805-840)는 양쪽 모두 실행됨 (라인 563-568, 분기 전에 호출) +├── generateLotNo() (라인 845-866) 에서 LOT 번호 자동 생성 (KD-SA-YYMMDD-NN 형식) +└── 검증: 선생산 WO 완료 시 재고 증가 확인, 기존 수주 WO는 변경 없음 +``` + +### 3.2 Phase 2 상세 절차 + +``` +Step 2.1: 수주 없는 작업지시 API 보완 +├── WorkOrderService::store() 메서드 확인 +│ └── sales_order_id 없이도 items 직접 전달 가능 (기존 경로 활용) +├── work_orders.sales_order_id는 DB에서 이미 nullable +├── 프론트: WorkOrderCreate.tsx의 RegistrationMode (라인 52) +│ └── 현재: type RegistrationMode = 'linked' | 'manual' +│ └── 'manual' 선택 시 수주 연동 없이 생성 가능 +│ └── ⚠️ 주의: 'source_type' 필드는 현재 존재하지 않음 → 필요시 신규 추가 +└── 검증: Postman으로 수주 없는 작업지시 생성 테스트 + +Step 2.2: items.options 기반 비즈니스 로직 분기 +├── Item.options 참조 위치 정리 +│ ├── production_source: 'purchased' | 'self_produced' | 'both' +│ ├── lot_managed: boolean +│ └── consumption_method: 'auto' | 'manual' | 'none' +├── 생산완료 시: production_source === 'self_produced' && lot_managed → 재고 입고 +├── 자재투입 시: consumption_method에 따른 차감 방식 분기 +└── 검증: 절곡 품목의 options 값 시더 데이터 확인 + +Step 2.3: 작업지시 생성 프론트 UI 보완 +├── 파일: react/src/components/production/WorkOrders/WorkOrderCreate.tsx +├── 현재 manual 모드 UI (라인 278-305): +│ └── RadioGroup에 'linked' | 'manual' 선택지, Label: "수동 등록 (재고생산)" +├── 보완 필요: +│ ├── 품목 검색/선택 UI (items 마스터에서 BENDING 카테고리 필터) +│ ├── 수량 입력 +│ └── 공정 선택 (절곡 공정 기본 선택) +├── 생산완료 버튼 UI 변경 (선생산 WO: "재고 입고" / 수주 WO: "출하") +└── 검증: 프론트에서 선생산 작업지시 생성 → 완료 → 재고 확인 + +Step 2.4: 재고현황 item_category 필터 추가 (API) +├── 파일: api/app/Services/StockService.php +├── index() 메서드 (라인 45) 파라미터에 item_category 추가 +│ └── whereHas('item', fn($q) => $q->where('item_category', $category)) +├── StockController 파라미터 바인딩 +└── 검증: API 호출로 BENDING 카테고리 필터링 확인 + +Step 2.5: 재고현황 절곡품 필터 추가 (프론트) +├── 파일: react/src/components/material/StockStatus/StockStatusList.tsx +├── 관련 파일: +│ ├── StockStatusDetail.tsx (상세) +│ ├── stockStatusConfig.ts (설정) +│ ├── actions.ts (API 호출) +│ └── types.ts (타입 정의) +├── 카테고리 탭 또는 드롭다운 추가 +│ └── 전체 | 원자재 | 절곡품(BENDING) | 부자재 | 소모품 +├── API 호출 시 item_category 파라미터 전달 +└── 검증: 절곡품 필터 적용하여 재고 목록 확인 +``` + +### 3.3 Phase 3 상세 절차 + +``` +Step 3.1: 수주 확정 시 재고 자동 확인 +├── OrderService::confirmOrder() 또는 createProductionOrder() 수정 +│ ├── BOM에서 절곡 품목 추출 (item_category === 'BENDING') +│ ├── 각 품목의 가용 재고 조회: StockService::getAvailableStock() (라인 796) +│ └── 재고 현황 반환 (충족/부족 품목별) +├── 프론트에 재고 확인 결과 표시 +└── 검증: 수주 확정 시 재고 현황 표시 확인 + +Step 3.2: 가용 재고 자동 예약 +├── 기존 메서드 활용: +│ ├── StockService::reserve() (라인 832) +│ └── StockService::releaseReservation() (라인 948) +├── 예약 시점: 수주 확정 시 자동 예약 (사용자 확인 후) +├── 예약 해제: 수주 취소 시 releaseReservation() +└── 검증: 예약 후 available_qty 감소 확인 + +Step 3.3: 부족분 자동 생산지시 +├── 수주 확정 시 재고 부족 품목에 대해 자동 생산지시 생성 +│ └── createProductionOrder()에 부족 수량만 반영 +├── 또는 수동: 부족 품목 목록을 사용자에게 표시 → 선생산 지시 유도 +└── 검증: 재고 10개, 필요 15개 → 5개만 생산지시 확인 + +Step 3.4: 수주화면 재고 현황 표시 +├── 수주 상세/편집 화면에 절곡 품목별 재고 현황 표시 +│ └── 품목명 | 필요수량 | 가용재고 | 부족수량 +└── 검증: UI 렌더링 확인 + +Step 3.5: 5130 레거시 데이터 마이그레이션 +├── lot 테이블 → stocks + stock_lots 매핑 +│ ├── prod+spec+slength → items.code (BD-* 패턴) 매핑 +│ ├── surang → stock_lots.qty +│ └── rawLot → stock_lots.options (원자재 LOT 추적) +├── bending_work_log → stock_transactions 매핑 +│ └── quantity → stock_transactions (TYPE_OUT) +├── guiderail/shutterbox/bottombar → items 테이블 매핑 +│ └── item_category = 'BENDING', item_type = 'PT' +└── 검증: 마이그레이션 전후 재고량 일치 확인 +``` + +--- + +## 4. 상세 작업 내용 + +### 4.1 현재 DB 스키마 (수정 대상) + +#### stocks 테이블 (`2025_12_26_132806_create_stocks_table.php`) +``` +id, tenant_id, item_id, item_code, item_name, item_type, +specification, unit, stock_qty, safety_stock, +reserved_qty, available_qty, lot_count, oldest_lot_date, +location, status, last_receipt_date, last_issue_date, +created_by, updated_by, timestamps, softDeletes, deleted_by +``` + +#### stock_lots 테이블 (`2025_12_26_132842_create_stock_lots_table.php`) +``` +id, tenant_id, stock_id(FK→stocks), lot_no, fifo_order(default:1), +receipt_date, qty(decimal 15,3), reserved_qty, available_qty, +unit(default:'EA'), supplier, supplier_lot, po_number, +location, status(default:'available'), receiving_id(nullable), +created_by, updated_by, timestamps, softDeletes, deleted_by + +인덱스: tenant_id, stock_id, lot_no, status, (stock_id+fifo_order) 복합 +유니크: (tenant_id, stock_id, lot_no) +``` + +#### stock_transactions 테이블 (`2026_01_29_000001_create_stock_transactions_table.php`) +``` +id, tenant_id, stock_id, stock_lot_id, type(IN/OUT/RESERVE/RELEASE), +qty, balance_qty, reference_type, reference_id, lot_no, +reason, remark, item_code, item_name, created_by, timestamps +``` + +### 4.2 현재 코드 레퍼런스 (라인번호 포함) + +#### StockTransaction 상수 (`api/app/Models/Tenants/StockTransaction.php`) +```php +// 라인 25-31: TYPE 상수 +const TYPE_IN = 'IN'; // 라인 25 +const TYPE_OUT = 'OUT'; // 라인 27 +const TYPE_RESERVE = 'RESERVE'; // 라인 29 +const TYPE_RELEASE = 'RELEASE'; // 라인 31 + +// 라인 41-57: REASON 상수 +const REASON_RECEIVING = 'receiving'; // 라인 41 +const REASON_WORK_ORDER_INPUT = 'work_order_input'; // 라인 43 +const REASON_SHIPMENT = 'shipment'; // 라인 45 +const REASON_ORDER_CONFIRM = 'order_confirm'; // 라인 47 +const REASON_ORDER_CANCEL = 'order_cancel'; // 라인 49 +const REASONS = [ ... ]; // 라인 51-57 +``` + +#### StockService 주요 메서드 (`api/app/Services/StockService.php`) +``` +라인 45: index(array $params): LengthAwarePaginator +라인 109: stats(): array +라인 159: show(int $id): Item +라인 176: findByItemCode(string $itemCode): ?Item +라인 192: statsByItemType(): array +라인 241: increaseFromReceiving(Receiving $receiving): StockLot ← 참조 대상 +라인 325: adjustFromReceiving(Receiving $receiving, float $newQty): void +라인 423: getOrCreateStock(int $itemId, ?Receiving $receiving = null): Stock ← 재사용 +라인 474: getNextFifoOrder(int $stockId): int ← 재사용 +라인 493: decreaseFIFO(int $itemId, float $qty, string $reason, int $referenceId): array +라인 618: decreaseFromLot(int $stockLotId, float $qty, string $reason, int $referenceId): array +라인 710: increaseToLot(int $stockLotId, float $qty, string $reason, int $referenceId): array +라인 796: getAvailableStock(int $itemId): ?array +라인 832: reserve(int $itemId, float $qty, int $orderId): void +라인 948: releaseReservation(int $itemId, float $qty, int $orderId): void +라인 1050: reserveForOrder($orderItems, int $orderId): void +라인 1071: releaseReservationForOrder($orderItems, int $orderId): void +라인 1099: decreaseForShipment(int $itemId, float $qty, int $shipmentId, ?int $stockLotId = null): array +라인 1232: [private] recordTransaction(...) +라인 1274: [private] logStockChange(...) +``` + +#### WorkOrderService 완료 처리 (`api/app/Services/WorkOrderService.php`) +```php +// 라인 563-568: completed 케이스 (saveItemResults 호출) +case WorkOrder::STATUS_COMPLETED: + $workOrder->started_at = $workOrder->started_at ?? now(); + $workOrder->completed_at = now(); + $this->saveItemResults($workOrder, $resultData, $userId); + break; + +// 라인 591-593: 완료 후 출하 자동 생성 (← 여기에 분기 삽입) +if ($status === WorkOrder::STATUS_COMPLETED) { + $this->createShipmentFromWorkOrder($workOrder, $tenantId, $userId); +} + +// 라인 606: 출하 생성 메서드 +private function createShipmentFromWorkOrder(WorkOrder $workOrder, int $tenantId, int $userId): ?Shipment + +// 라인 805: 결과 데이터 저장 (LOT 번호 생성 포함) +private function saveItemResults(WorkOrder $workOrder, ?array $resultData, int $userId): void + +// 라인 845-866: LOT 번호 생성 +private function generateLotNo(WorkOrder $workOrder): string +// 패턴: KD-SA-YYMMDD-NN (예: KD-SA-260221-01) +``` + +#### Stock 모델 refreshFromLots (`api/app/Models/Tenants/Stock.php`) +```php +// 라인 149-164 +public function refreshFromLots(): void +{ + $lots = $this->lots()->where('status', '!=', 'used')->get(); + $this->lot_count = $lots->count(); + $this->stock_qty = $lots->sum('qty'); + $this->reserved_qty = $lots->sum('reserved_qty'); + $this->available_qty = $lots->sum('available_qty'); + $oldestLot = $lots->sortBy('receipt_date')->first(); + $this->oldest_lot_date = $oldestLot?->receipt_date; + $this->last_receipt_date = $lots->max('receipt_date'); + $this->status = $this->calculateStatus(); + $this->save(); +} +``` + +### 4.3 increaseFromReceiving() 실제 코드 (참조용) + +신규 `increaseFromProduction()` 구현 시 아래 코드를 기반으로 작성: + +```php +// api/app/Services/StockService.php 라인 241-314 +public function increaseFromReceiving(Receiving $receiving): StockLot +{ + if (! $receiving->item_id) { + throw new \Exception(__('error.stock.item_id_required')); + } + $tenantId = $this->tenantId(); + $userId = $this->apiUserId(); + + return DB::transaction(function () use ($receiving, $tenantId, $userId) { + $stock = $this->getOrCreateStock($receiving->item_id, $receiving); + $fifoOrder = $this->getNextFifoOrder($stock->id); + + $stockLot = new StockLot; + $stockLot->tenant_id = $tenantId; + $stockLot->stock_id = $stock->id; + $stockLot->lot_no = $receiving->lot_no; + $stockLot->fifo_order = $fifoOrder; + $stockLot->receipt_date = $receiving->receiving_date; + $stockLot->qty = $receiving->receiving_qty; + $stockLot->reserved_qty = 0; + $stockLot->available_qty = $receiving->receiving_qty; + $stockLot->unit = $receiving->order_unit ?? 'EA'; + $stockLot->supplier = $receiving->supplier; // ← 생산입고: null + $stockLot->supplier_lot = $receiving->supplier_lot; // ← 생산입고: null + $stockLot->po_number = $receiving->order_no; // ← 생산입고: null + $stockLot->location = $receiving->receiving_location; + $stockLot->status = 'available'; + $stockLot->receiving_id = $receiving->id; // ← 생산입고: null, work_order_id 대신 사용 + $stockLot->created_by = $userId; + $stockLot->updated_by = $userId; + $stockLot->save(); + + $stock->refreshFromLots(); + + $this->recordTransaction( + stock: $stock, + type: StockTransaction::TYPE_IN, + qty: $receiving->receiving_qty, + reason: StockTransaction::REASON_RECEIVING, // ← 생산입고: REASON_PRODUCTION_OUTPUT + referenceType: 'receiving', // ← 생산입고: 'work_order' + referenceId: $receiving->id, // ← 생산입고: $workOrder->id + lotNo: $receiving->lot_no, + stockLotId: $stockLot->id + ); + + $this->logStockChange(...); + return $stockLot; + }); +} +``` + +### 4.4 increaseFromProduction() 구현 설계 + +```php +/** + * 생산 완료 시 완성품 재고 입고 + * increaseFromReceiving()을 기반으로 구현 + * + * @param WorkOrder $workOrder 선생산 작업지시 + * @param WorkOrderItem $woItem 작업지시 품목 + * @param float $goodQty 양품 수량 (saveItemResults에서 기록) + * @param string $lotNo LOT 번호 (generateLotNo에서 생성) + */ +public function increaseFromProduction( + WorkOrder $workOrder, + WorkOrderItem $woItem, + float $goodQty, + string $lotNo +): StockLot { + $tenantId = $this->tenantId(); + $userId = $this->apiUserId(); + + return DB::transaction(function () use ($workOrder, $woItem, $goodQty, $lotNo, $tenantId, $userId) { + // 1. Stock 조회 또는 생성 + // getOrCreateStock()의 두 번째 파라미터(Receiving)는 null + // → specification, unit은 Item에서 가져옴 + $stock = $this->getOrCreateStock($woItem->item_id); + + // 2. FIFO 순서 + $fifoOrder = $this->getNextFifoOrder($stock->id); + + // 3. StockLot 생성 + $stockLot = new StockLot; + $stockLot->tenant_id = $tenantId; + $stockLot->stock_id = $stock->id; + $stockLot->lot_no = $lotNo; + $stockLot->fifo_order = $fifoOrder; + $stockLot->receipt_date = now()->toDateString(); + $stockLot->qty = $goodQty; + $stockLot->reserved_qty = 0; + $stockLot->available_qty = $goodQty; + $stockLot->unit = $woItem->unit ?? 'EA'; + $stockLot->supplier = null; // 구매입고 전용 필드 + $stockLot->supplier_lot = null; + $stockLot->po_number = null; + $stockLot->location = null; + $stockLot->status = 'available'; + $stockLot->receiving_id = null; // 구매입고가 아님 + $stockLot->work_order_id = $workOrder->id; // ★ 생산입고 참조 + $stockLot->created_by = $userId; + $stockLot->updated_by = $userId; + $stockLot->save(); + + // 4. Stock 합계 갱신 + $stock->refreshFromLots(); + + // 5. 거래 이력 기록 + $this->recordTransaction( + stock: $stock, + type: StockTransaction::TYPE_IN, + qty: $goodQty, + reason: StockTransaction::REASON_PRODUCTION_OUTPUT, + referenceType: 'work_order', + referenceId: $workOrder->id, + lotNo: $lotNo, + stockLotId: $stockLot->id + ); + + // 6. 감사 로그 + $this->logStockChange( + stock: $stock, + action: 'production_in', + details: [ + 'work_order_id' => $workOrder->id, + 'work_order_item_id' => $woItem->id, + 'qty' => $goodQty, + 'lot_no' => $lotNo, + ] + ); + + return $stockLot; + }); +} +``` + +### 4.5 WorkOrderService 완료 분기 구현 설계 + +```php +// 라인 591-593 변경: updateStatus() 내부 +if ($status === WorkOrder::STATUS_COMPLETED) { + if ($workOrder->sales_order_id) { + // 기존 로직: 수주 연동 → 출하 자동 생성 + $this->createShipmentFromWorkOrder($workOrder, $tenantId, $userId); + } else { + // 신규 로직: 선생산 → 재고 입고 + $this->stockInFromProduction($workOrder); + } +} + +// 신규 private 메서드 +private function stockInFromProduction(WorkOrder $workOrder): void +{ + foreach ($workOrder->items as $woItem) { + if ($this->shouldStockIn($woItem)) { + $resultData = $woItem->options['result'] ?? []; + $goodQty = $resultData['good_qty'] ?? $woItem->quantity; + $lotNo = $resultData['lot_no'] ?? ''; + + if ($goodQty > 0 && $lotNo) { + $this->stockService->increaseFromProduction( + $workOrder, $woItem, $goodQty, $lotNo + ); + } + } + } +} + +private function shouldStockIn(WorkOrderItem $woItem): bool +{ + $item = $woItem->item; + $options = $item->options ?? []; + + return ($options['production_source'] ?? null) === 'self_produced' + && ($options['lot_managed'] ?? false) === true; +} +``` + +### 4.6 데이터 매핑 (5130 → SAM) + +#### 절곡품 마스터 매핑 + +| 5130 | SAM | 비고 | +|------|-----|------| +| guiderail.model_name | items.code (BD-가이드레일-*) | item_category=BENDING | +| guiderail.rail_width × rail_length | items.options.dimensions | JSON | +| guiderail.material_summary | items.options.material_summary | JSON | +| guiderail.finishing_type | items.options.finishing_type | JSON | +| shutterbox.box_width × box_height | items.code (BD-케이스-*) | 치수 코드화 | +| bottombar.bar_width × bar_height | items.code (BD-하단마감재-*) | 치수 코드화 | + +#### 재고 매핑 + +| 5130 | SAM | 비고 | +|------|-----|------| +| lot.lot_number | stock_lots.lot_no | 1:1 | +| lot.surang | stock_lots.qty | 생산 수량 | +| lot.prod+spec+slength | items.code → stocks.item_id | 3코드→품목코드 변환 | +| lot.rawLot | stock_lots.options.raw_lot | JSON | +| lot.fabric_lot | stock_lots.options.fabric_lot | JSON | +| bending_work_log.quantity | stock_transactions.qty (TYPE_OUT) | 사용 이력 | + +#### 3코드 → 품목코드 변환 규칙 + +| prod | spec | slength | SAM item_code | +|------|------|---------|---------------| +| R(벽면형) | S(SUS) | 53(W50x3000) | BD-가이드레일-벽면형-SUS-W50x3000 | +| R(벽면형) | E(EGI) | 84(W80x4000) | BD-가이드레일-벽면형-EGI-W80x4000 | +| C(케이스) | M(본체) | 30(3000) | BD-케이스-본체-3000 | +| B(하단마감재스크린) | A(스크린용) | 30(3000) | BD-하단마감재-스크린-3000 | + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| C1 | StockLot에 work_order_id 컬럼 추가 | DB 마이그레이션 | stock_lots 테이블 | ⚠️ 컨펌 필요 | +| C2 | WorkOrderService 완료 로직 분기 | 비즈니스 로직 변경 | 생산 완료 프로세스 | ⚠️ 컨펌 필요 | +| C3 | Phase 3 수주→재고 자동 매칭 설계 | 신규 비즈니스 프로세스 | OrderService | ⚠️ Phase 3 착수 전 별도 협의 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-21 | - | 문서 초안 작성 | - | - | +| 2026-02-21 | 보완 | 용어설명, 파일경로 수정, 코드 레퍼런스 추가, DB 스키마 추가 | - | - | +| 2026-02-21 | Phase 1 구현 | 1.1~1.4 전체 완료 | StockTransaction, StockLot, StockService, WorkOrderService | ✅ | + +--- + +## 7. 참고 문서 + +### 직접 관련 문서 +- `docs/plans/bending-info-auto-generation-plan.md` - BendingInfoBuilder 자동 생성 계획 +- `docs/plans/bending-worklog-reimplementation-plan.md` - 절곡 작업일지 프론트 재구현 (완료) +- `docs/projects/legacy-5130/04_PRODUCTION.md` - 레거시 생산 시스템 분석 + +### 핵심 코드 파일 (⚠️ 경로 주의: Models는 Tenants 네임스페이스) + +**백엔드 서비스**: +- `api/app/Services/StockService.php` - 재고 서비스 (increaseFromReceiving 라인 241) +- `api/app/Services/WorkOrderService.php` - 작업지시 서비스 (updateStatus 라인 521, saveItemResults 라인 805) +- `api/app/Services/OrderService.php` - 수주 서비스 (createProductionOrder) +- `api/app/Services/Production/BendingInfoBuilder.php` - 절곡 정보 자동 생성 + +**백엔드 모델** (⚠️ `Models/Tenants/` 경로): +- `api/app/Models/Tenants/Stock.php` - 재고 모델 (refreshFromLots 라인 149) +- `api/app/Models/Tenants/StockLot.php` - 재고 LOT 모델 (fillable 라인 15-34) +- `api/app/Models/Tenants/StockTransaction.php` - 재고 거래 이력 모델 (상수 라인 25-57) + +**DB 마이그레이션**: +- `api/database/migrations/2025_12_26_132806_create_stocks_table.php` +- `api/database/migrations/2025_12_26_132842_create_stock_lots_table.php` +- `api/database/migrations/2026_01_29_000001_create_stock_transactions_table.php` + +### 프론트 코드 파일 +- `react/src/components/production/WorkOrders/WorkOrderCreate.tsx` - 작업지시 생성 (RegistrationMode 라인 52, manual UI 라인 278-305) +- `react/src/components/material/StockStatus/StockStatusList.tsx` - 재고 현황 목록 +- `react/src/components/material/StockStatus/` - 재고 현황 전체 디렉토리 (Detail, Audit, actions, types, config, mockData) +- `react/src/components/production/WorkOrders/documents/bending/` - 절곡 작업일지 컴포넌트 + +--- + +## 8. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 8.1 세션 시작 시 (Load Strategy) +```javascript +read_memory("bending-preproduction-state") // 1. 상태 파악 +read_memory("bending-preproduction-snapshot") // 2. 사고 흐름 복구 +read_memory("bending-preproduction-active-symbols") // 3. 작업 대상 파악 +``` + +### 8.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | Snapshot | `write_memory("bending-preproduction-snapshot", "코드변경+논의요약")` | +| **20% 이하** | Context Purge | `write_memory("bending-preproduction-active-symbols", "수정 파일/함수")` | +| **10% 이하** | Stop & Save | 최종 상태 저장 후 세션 교체 권고 | + +### 8.3 Serena 메모리 구조 +- `bending-preproduction-state`: { phase, progress, next_step, last_decision } +- `bending-preproduction-snapshot`: 현재까지의 논의 및 코드 변경점 요약 +- `bending-preproduction-rules`: 불변 규칙 (Receiving 우회, options JSON 정책 등) +- `bending-preproduction-active-symbols`: 현재 수정 중인 파일/심볼 리스트 + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 Phase 1 테스트 케이스 + +| # | 시나리오 | 입력 | 예상 결과 | 실제 결과 | 상태 | +|---|---------|------|----------|----------|------| +| T1.1 | 선생산 WO 완료 시 재고 입고 | WO(sales_order_id=null) 완료 | Stock/StockLot 생성, qty 증가 | | ⏳ | +| T1.2 | 기존 수주 WO 완료 시 변경 없음 | WO(sales_order_id=43) 완료 | 기존대로 Shipment 생성 | | ⏳ | +| T1.3 | LOT 번호 자동 생성 | 선생산 WO 완료 | KD-SA-YYMMDD-NN 형식 LOT | | ⏳ | +| T1.4 | StockTransaction 기록 | 생산 입고 | TYPE_IN, reason=production_output | | ⏳ | + +### 9.2 Phase 2 테스트 케이스 + +| # | 시나리오 | 입력 | 예상 결과 | 실제 결과 | 상태 | +|---|---------|------|----------|----------|------| +| T2.1 | 수주 없이 작업지시 생성 | manual 모드 + 절곡 품목 | WO 생성, sales_order_id=null | | ⏳ | +| T2.2 | 재고현황 절곡품 필터 | item_category=BENDING | 절곡품만 표시 | | ⏳ | +| T2.3 | FIFO 출고 | 재고 투입 | 가장 오래된 LOT부터 차감 | | ⏳ | + +### 9.3 Phase 3 테스트 케이스 + +| # | 시나리오 | 입력 | 예상 결과 | 실제 결과 | 상태 | +|---|---------|------|----------|----------|------| +| T3.1 | 수주 확정 시 재고 확인 | 재고 10, 필요 15 | 부족 5 표시 | | ⏳ | +| T3.2 | 가용 재고 자동 예약 | 재고 10, 필요 5 | reserved_qty=5, available_qty=5 | | ⏳ | +| T3.3 | 부족분 생산지시 | 재고 10, 필요 15 | 5개 생산지시 자동 생성 | | ⏳ | + +### 9.4 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 선생산 WO → 재고 입고 정상 동작 | ⏳ | Phase 1 핵심 | +| 기존 수주 WO 흐름 변경 없음 | ⏳ | 회귀 테스트 | +| 절곡품 재고현황 필터링 가능 | ⏳ | Phase 2 | +| 수주 시 재고 자동 매칭 | ⏳ | Phase 3 | +| 5130 데이터 마이그레이션 완료 | ⏳ | Phase 3 | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 0.2 선생산 운영 방식 + 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 9.4 성공 기준 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1~3, 14개 작업 항목 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 기존 bending 계획 문서 참조 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 검증 완료 (Models/Tenants/, material/StockStatus/) | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 라인번호 + 실제 코드 바디 포함 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9 테스트 케이스 참조 | +| 8 | 모호한 표현이 없는가? | ✅ | 코드 수준 상세 기술 + 용어 설명 포함 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 절곡품이 뭔가? 왜 선생산하는가? | ✅ | 0.1, 0.2 용어 및 비즈니스 배경 | +| Q2. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q3. 어디서부터 시작해야 하는가? | ✅ | 2.1 Phase 1 + 3.1 절차 | +| Q4. 어떤 파일을 수정해야 하는가? | ✅ | 2.1~2.3 영향 파일 (정확한 경로) | +| Q5. 기존 코드 구조가 어떻게 되어 있는가? | ✅ | 4.1~4.3 DB 스키마 + 코드 레퍼런스 | +| Q6. 신규 메서드를 어떻게 구현해야 하는가? | ✅ | 4.4~4.5 구현 설계 (전체 코드) | +| Q7. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 | +| Q8. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 | + +--- + +*이 문서는 /plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/db-trigger-audit-system-plan.md b/plans/db-trigger-audit-system-plan.md new file mode 100644 index 0000000..62da7d9 --- /dev/null +++ b/plans/db-trigger-audit-system-plan.md @@ -0,0 +1,1294 @@ +# DB 트리거 기반 데이터 변경 추적 시스템 계획 + +> **작성일**: 2026-02-07 +> **목적**: 모든 경로(앱, 직접SQL, AI, phpMyAdmin 등)의 데이터 변경을 DB 레벨에서 추적하고 복구 가능하게 함 +> **기준 문서**: `docs/specs/database-schema.md`, `api/app/Traits/Auditable.php`, `api/config/audit.php` +> **상태**: 🔄 Phase 1-3 완료, Phase 4 핵심 완료 (4.4~4.6 옵션 잔여) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 4 핵심 (mng 대시보드 + 목록 + 상세 + 이력 + 롤백) | +| **다음 작업** | Phase 4.4 트리거 관리 화면 (옵션) | +| **진행률** | 15/16 (94%) - 핵심 기능 완료, 옵션 3개 잔여 | +| **마지막 업데이트** | 2026-02-07 | + +--- + +## 1. 개요 + +### 1.1 배경 + +SAM 프로젝트에는 이미 Laravel `Auditable` trait 기반 감사 로그가 존재하지만, 이는 **Laravel Eloquent ORM을 통한 변경만 추적**한다. 다음 경로의 변경은 추적 불가: + +- AI(Claude 등)가 직접 실행하는 SQL 쿼리 +- phpMyAdmin, DBeaver 등 DB 클라이언트에서의 직접 수정 +- MySQL CLI에서의 직접 쿼리 +- 다른 애플리케이션/스크립트에서의 DB 접근 +- Laravel `DB::statement()` 등 Eloquent 우회 쿼리 + +**해결책**: MySQL 트리거를 사용하여 DB 엔진 레벨에서 모든 INSERT/UPDATE/DELETE를 포착한다. + +### 1.2 기준 원칙 + +``` ++------------------------------------------------------------------+ +| 계층 분리 (Layered Audit) | ++------------------------------------------------------------------+ +| Layer 1: Laravel Audit (기존 유지) | +| - 비즈니스 액션 (released, cloned, items_replaced 등) | +| - 사용자 컨텍스트 풍부 (IP, UA, 세션 정보) | +| - 실패 시 비즈니스 로직 불영향 (try/catch) | ++------------------------------------------------------------------+ +| Layer 2: MySQL Trigger Audit (신규) | +| - 모든 DML 포착 (직접 쿼리 포함, 누락 불가) | +| - 컬럼 단위 old/new values JSON 저장 | +| - 특정 레코드의 특정 시점으로 복원 가능 | ++------------------------------------------------------------------+ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 트리거 대상 테이블 목록 조정, 제외 컬럼 변경 | 불필요 | +| ⚠️ 컨펌 필요 | 마이그레이션 실행, 트리거 생성/변경, 미들웨어 추가, 새 API 엔드포인트 | **필수** | +| 🔴 금지 | 기존 audit_logs 테이블 구조 변경, 기존 Auditable trait 수정 | 별도 협의 | + +### 1.4 준수 규칙 + +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/specs/database-schema.md` - DB 스키마 +- `docs/standards/api-rules.md` - API 규칙 (Audit Logging 섹션) + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: DB 기반 구축 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | trigger_audit_logs 테이블 마이그레이션 (파티셔닝 포함) | ✅ | 15개 파티션, 3개 인덱스 | +| 1.2 | 트리거 대상 테이블 선정 및 확정 | ✅ | 제외 11개 외 전체 적용 | +| 1.3 | 트리거 자동 생성 (PHP 기반, SP 불가) | ✅ | MySQL CREATE TRIGGER는 PREPARE 미지원 → PHP 마이그레이션으로 전환 | +| 1.4 | 대상 테이블별 트리거 생성 | ✅ | 789개 트리거 (263 테이블 × 3) | +| 1.5 | 세션 변수 설정 미들웨어 (Laravel) | ✅ | @sam_actor_id, @sam_session_info | + +### 2.2 Phase 2: 복구 메커니즘 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | TriggerAuditLog 모델 | ✅ | casts, scopes, changed_columns accessor | +| 2.2 | AuditRollbackService 구현 | ✅ | rollback SQL 생성 + 실행 + getRecordStateAt | +| 2.3 | Trigger Audit 조회 API | ✅ | 6개 엔드포인트 (index, show, stats, history, rollback-preview, rollback) | +| 2.4 | Rollback API 엔드포인트 | ✅ | POST /api/v1/trigger-audit-logs/{id}/rollback + confirm 필수 | + +### 2.3 Phase 3: 관리 도구 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | 통합 조회 뷰 (v_unified_audit) | ✅ | APP 3,108건 + TRIGGER 2,649건 통합, COLLATE 해결 | +| 3.2 | 파티션 자동 관리 (artisan 커맨드) | ✅ | audit:partitions --add-months --retention-months --drop --dry-run | +| 3.3 | 트리거 재생성 artisan 커맨드 | ✅ | audit:triggers --table --drop-only --dry-run | + +### 2.4 Phase 4: 관리자 대시보드 (mng) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 4.1 | 변경 이력 목록 화면 (index) | ✅ | 통계카드+필터+목록+파티션현황+트리거수, 페이지네이션 | +| 4.2 | 레코드 상세 변경 이력 (show + history) | ✅ | diff 뷰(old/new 비교, 변경 컬럼 하이라이트) + 레코드 타임라인 | +| 4.3 | 복구 기능 UI (rollback-preview) | ✅ | SQL 미리보기, 확인 체크박스+confirm, @disable_audit_trigger | +| 4.4 | 트리거 관리 화면 | ⏭️ | 옵션 - artisan audit:triggers 커맨드로 CLI 관리 가능 | +| 4.5 | 대시보드 통계 | ✅ | index에 통합 (전체/오늘/DML별 통계, 상위 테이블, 파티션, 저장소) | +| 4.6 | 보관 정책 설정 | ⏭️ | 옵션 - artisan audit:partitions 커맨드로 CLI 관리 가능 | + +--- + +## 3. 작업 절차 + +### 3.1 아키텍처 다이어그램 + +``` +[사용자/AI/phpMyAdmin/스크립트] + │ + ▼ + ┌─────────┐ + │ MySQL │ + │ Engine │ + └────┬────┘ + │ DML (INSERT/UPDATE/DELETE) + ▼ + ┌─────────────────────────┐ + │ 대상 테이블 │ + │ (제외 목록 외 전체 │ + │ 약 207개) │ + └────┬────────────────────┘ + │ AFTER 트리거 발동 + ▼ + ┌─────────────────────────┐ + │ trigger_audit_logs │ + │ (파티셔닝, 13개월 보관) │ + │ - table_name │ + │ - row_id │ + │ - dml_type │ + │ - old_values (JSON) │ + │ - new_values (JSON) │ + │ - tenant_id │ + │ - actor_id │ ← @sam_actor_id 세션변수 + │ - session_info │ ← @sam_session_info 세션변수 + │ - db_user │ ← CURRENT_USER() + │ - created_at │ + └─────────────────────────┘ + │ + ▼ + ┌─────────────────────────┐ + │ AuditRollbackService │ + │ (Laravel) │ + │ - 이력 조회 │ + │ - Rollback SQL 생성 │ + │ - 특정 시점 복원 │ + └─────────────────────────┘ +``` + +### 3.2 트리거 대상 테이블 + +#### 적용 방침: 전체 적용 (제외 목록 방식) + +로컬 개발 환경에서 1인 사용이므로, **제외 대상을 제외한 모든 테이블에 트리거를 적용**한다. +운영 환경 전환 시 필요에 따라 대상을 축소할 수 있다. + +SP(`sp_create_audit_triggers`)가 `INFORMATION_SCHEMA.TABLES`에서 samdb의 전체 테이블을 읽고, +제외 목록에 없는 모든 테이블에 자동으로 트리거를 생성한다. + +#### 제외 대상 (트리거 미적용) + +| 테이블 패턴 | 사유 | +|-------------|------| +| `audit_logs` | 감사 로그 자체 (순환 방지) | +| `trigger_audit_logs` | 트리거 감사 자체 (순환 방지) | +| `personal_access_tokens` | Sanctum 토큰 (대량 생성/삭제, 보안 데이터) | +| `sessions` | 세션 데이터 (빈번한 갱신) | +| `cache`, `cache_locks` | 캐시 데이터 | +| `jobs`, `job_batches` | 큐 작업 | +| `failed_jobs` | 실패 큐 | +| `migrations` | 마이그레이션 기록 | +| `password_reset_tokens` | 비밀번호 리셋 토큰 | +| `telescope_*` | 디버그 도구 (있는 경우) | + +> **예상**: samdb 약 219개 테이블 - 제외 약 12개 = **약 207개 테이블 × 3 트리거 = 약 621개 트리거** +> +> SP가 `INFORMATION_SCHEMA`에서 동적으로 테이블을 읽으므로, 테이블이 추가/삭제되면 +> `artisan audit:regenerate-triggers` 명령으로 트리거를 재생성하면 된다. + +### 3.3 trigger_audit_logs 테이블 구조 + +```sql +CREATE TABLE trigger_audit_logs ( + id BIGINT UNSIGNED AUTO_INCREMENT, + table_name VARCHAR(64) NOT NULL COMMENT '변경된 테이블명', + row_id VARCHAR(64) NOT NULL COMMENT '변경된 레코드 PK (문자열 지원)', + dml_type ENUM('INSERT','UPDATE','DELETE') NOT NULL COMMENT 'DML 유형', + old_values JSON DEFAULT NULL COMMENT '변경 전 값 (INSERT시 NULL)', + new_values JSON DEFAULT NULL COMMENT '변경 후 값 (DELETE시 NULL)', + changed_columns JSON DEFAULT NULL COMMENT 'UPDATE시 변경된 컬럼 목록', + tenant_id BIGINT UNSIGNED DEFAULT NULL COMMENT '테넌트 ID', + actor_id BIGINT UNSIGNED DEFAULT NULL COMMENT '사용자 ID (세션변수)', + session_info VARCHAR(500) DEFAULT NULL COMMENT '세션 정보 JSON (IP, UA 등)', + db_user VARCHAR(100) DEFAULT NULL COMMENT 'CURRENT_USER()', + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '변경 시각', + PRIMARY KEY (id, created_at) +) ENGINE=InnoDB + DEFAULT CHARSET=utf8mb4 + COLLATE=utf8mb4_unicode_ci + COMMENT='DB 트리거 기반 데이터 변경 추적' + PARTITION BY RANGE (UNIX_TIMESTAMP(created_at)) ( + PARTITION p202601 VALUES LESS THAN (UNIX_TIMESTAMP('2026-02-01')), + PARTITION p202602 VALUES LESS THAN (UNIX_TIMESTAMP('2026-03-01')), + PARTITION p202603 VALUES LESS THAN (UNIX_TIMESTAMP('2026-04-01')), + PARTITION p202604 VALUES LESS THAN (UNIX_TIMESTAMP('2026-05-01')), + PARTITION p202605 VALUES LESS THAN (UNIX_TIMESTAMP('2026-06-01')), + PARTITION p202606 VALUES LESS THAN (UNIX_TIMESTAMP('2026-07-01')), + PARTITION p202607 VALUES LESS THAN (UNIX_TIMESTAMP('2026-08-01')), + PARTITION p202608 VALUES LESS THAN (UNIX_TIMESTAMP('2026-09-01')), + PARTITION p202609 VALUES LESS THAN (UNIX_TIMESTAMP('2026-10-01')), + PARTITION p202610 VALUES LESS THAN (UNIX_TIMESTAMP('2026-11-01')), + PARTITION p202611 VALUES LESS THAN (UNIX_TIMESTAMP('2026-12-01')), + PARTITION p202612 VALUES LESS THAN (UNIX_TIMESTAMP('2027-01-01')), + PARTITION p202701 VALUES LESS THAN (UNIX_TIMESTAMP('2027-02-01')), + PARTITION p202702 VALUES LESS THAN (UNIX_TIMESTAMP('2027-03-01')), + PARTITION p_future VALUES LESS THAN MAXVALUE + ); + +-- 조회 성능 인덱스 +CREATE INDEX ix_trig_table_row_created + ON trigger_audit_logs (table_name, row_id, created_at); + +CREATE INDEX ix_trig_tenant_created + ON trigger_audit_logs (tenant_id, created_at); +``` + +### 3.4 트리거 자동 생성 Stored Procedure + +```sql +-- 특정 테이블에 대해 AFTER INSERT/UPDATE/DELETE 트리거 3개를 자동 생성 +-- INFORMATION_SCHEMA.COLUMNS에서 컬럼 목록을 읽어 JSON_OBJECT 구문 자동 조립 + +CALL sp_create_audit_triggers('products'); +-- → trg_products_ai (AFTER INSERT) +-- → trg_products_au (AFTER UPDATE) +-- → trg_products_ad (AFTER DELETE) +``` + +**SP 핵심 로직:** +1. `INFORMATION_SCHEMA.COLUMNS`에서 대상 테이블의 컬럼 목록 조회 +2. 제외 컬럼 필터링 (`created_at`, `updated_at`, `deleted_at`, `remember_token` 등) +3. `JSON_OBJECT('col1', NEW.col1, 'col2', NEW.col2, ...)` 구문 자동 조립 +4. UPDATE 트리거: 컬럼별 `OLD.col <> NEW.col` 비교 → changed_columns 배열 생성 +5. 비활성화 플래그 체크 (`@disable_audit_trigger`) +6. `PREPARE + EXECUTE`로 트리거 DDL 실행 + +### 3.5 세션 변수 미들웨어 + +```php +// app/Http/Middleware/SetAuditSessionVariables.php + +class SetAuditSessionVariables +{ + public function handle($request, $next) + { + if (auth()->check()) { + DB::statement("SET @sam_actor_id = ?", [auth()->id()]); + DB::statement("SET @sam_session_info = ?", [ + json_encode([ + 'ip' => $request->ip(), + 'ua' => substr($request->userAgent(), 0, 255), + 'route' => $request->route()?->getName(), + ]) + ]); + } + + return $next($request); + } +} +``` + +### 3.6 복구 서비스 + +```php +// app/Services/Audit/AuditRollbackService.php + +class AuditRollbackService +{ + // 특정 audit 레코드에 대한 역방향 SQL 생성 + public function generateRollbackSQL(int $auditId): string; + + // 실제 복구 실행 (트랜잭션 내에서) + public function executeRollback(int $auditId): bool; + + // 특정 레코드의 특정 시점 상태 조회 + public function getRecordStateAt(string $table, string $rowId, Carbon $at): ?array; + + // 특정 레코드의 변경 이력 조회 + public function getRecordHistory(string $table, string $rowId): Collection; +} +``` + +**복구 로직:** + +| 원본 DML | 복구 SQL | +|----------|---------| +| INSERT | `DELETE FROM {table} WHERE id = {row_id}` | +| UPDATE | `UPDATE {table} SET {old_values 각 컬럼} WHERE id = {row_id}` | +| DELETE | `INSERT INTO {table} ({old_values 컬럼}) VALUES ({old_values 값})` | + +--- + +## 4. 상세 작업 내용 + +> 각 Phase 진행 후 이 섹션에 상세 내용 추가 + +### 4.1 Phase 1: DB 기반 구축 +- **상태**: ⏳ 대기 +- **예상 파일**: + - `api/database/migrations/YYYY_MM_DD_HHMMSS_create_trigger_audit_logs_table.php` + - `api/database/migrations/YYYY_MM_DD_HHMMSS_create_audit_trigger_stored_procedures.php` + - `api/database/migrations/YYYY_MM_DD_HHMMSS_create_audit_triggers_for_tables.php` + - `api/app/Http/Middleware/SetAuditSessionVariables.php` + +### 4.2 Phase 2: 복구 메커니즘 +- **상태**: ⏳ 대기 +- **예상 파일**: + - `api/app/Models/Audit/TriggerAuditLog.php` + - `api/app/Services/Audit/AuditRollbackService.php` + - `api/app/Http/Controllers/Api/V1/Audit/TriggerAuditLogController.php` + - `api/app/Http/Requests/Audit/TriggerAuditLogIndexRequest.php` + - `api/app/Http/Requests/Audit/TriggerAuditRollbackRequest.php` + - `api/app/Swagger/v1/TriggerAuditLogApi.php` + +### 4.3 Phase 3: 관리 도구 +- **상태**: ⏳ 대기 +- **예상 파일**: + - `api/database/migrations/YYYY_MM_DD_HHMMSS_create_unified_audit_view.php` + - `api/app/Console/Commands/ManageAuditPartitions.php` + - `api/app/Console/Commands/RegenerateAuditTriggers.php` + +### 4.4 Phase 4: 관리자 대시보드 (mng) +- **상태**: ⏳ 대기 +- **예상 파일**: + - `mng/app/Http/Controllers/Admin/TriggerAuditController.php` + - `mng/resources/views/admin/trigger-audit/index.blade.php` (이력 목록) + - `mng/resources/views/admin/trigger-audit/show.blade.php` (상세 diff 뷰) + - `mng/resources/views/admin/trigger-audit/dashboard.blade.php` (대시보드 통계) + - `mng/resources/views/admin/trigger-audit/triggers.blade.php` (트리거 관리) + - `mng/resources/views/admin/trigger-audit/settings.blade.php` (보관 정책) + - `mng/app/Services/TriggerAuditDashboardService.php` + +--- + +## 5. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | 트리거 대상 | 제외 목록 외 전체 (약 207개) 적용 | database | ✅ 확정 | +| 2 | 성능 영향 | 로컬 1인 사용, 제한 없음 | database | ✅ 확정 | +| 3 | Phase 4 범위 | 풀 관리 대시보드 (조회/복구/트리거관리/통계/정책) | mng | ✅ 확정 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-02-07 | 계획 | 문서 초안 작성 | - | - | +| 2026-02-07 | 수정 | 피드백 반영: 전체 테이블 적용, Phase 4 대시보드 추가 | - | ✅ | +| 2026-02-07 | Phase 1 | DB 기반 구축 완료. SP→PHP 전환, 789 트리거 생성, my.cnf 설정 추가 | api/database/migrations/2026_02_07_*, api/app/Http/Middleware/SetAuditSessionVariables.php, docker/mysql/my.cnf | ✅ | +| 2026-02-07 | Phase 2 | 복구 메커니즘 API 완료. 모델/서비스/컨트롤러/라우트 6개 엔드포인트 | TriggerAuditLog.php, TriggerAuditLogService.php, AuditRollbackService.php, TriggerAuditLogController.php, audit.php(route) | ✅ | +| 2026-02-07 | Phase 3 | 관리 도구 완료. 통합 뷰(collation 해결), 파티션 관리, 트리거 재생성 커맨드 | v_unified_audit VIEW, ManageAuditPartitions.php, RegenerateAuditTriggers.php | ✅ | + +--- + +## 7. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **DB 스키마**: `docs/specs/database-schema.md` +- **API 규칙**: `docs/standards/api-rules.md` (Audit Logging 섹션) +- **기존 Auditable**: `api/app/Traits/Auditable.php` +- **기존 audit 설정**: `api/config/audit.php` +- **기존 audit 마이그레이션**: `api/database/migrations/2025_09_11_000100_create_audit_logs_table.php` + +### 외부 참고자료 + +- [MySQL 8.0 Trigger Syntax](https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html) +- [MySQL 8.0 Partitioning](https://dev.mysql.com/doc/refman/8.0/en/partitioning.html) +- [Percona - MySQL Trigger Performance](https://www.percona.com/blog/why-mysql-stored-procedures-functions-triggers-bad-performance/) + +--- + +## 8. 리스크 및 대응 방안 + +| 리스크 | 영향 | 대응 | +|--------|------|------|| 트리거 성능 오버헤드 (INSERT 약 40-50%) | 쓰기 성능 저하 | 로컬 1인 사용 환경이므로 무관. 운영 전환 시 대상 축소 가능. Bulk 작업 시 `@disable_audit_trigger=1` | +| 트리거 실패 시 원본 DML도 롤백 | 비즈니스 중단 | 트리거 로직 최소화, audit 테이블 구조 안정적 유지 | +| 스키마 변경 시 트리거 유지보수 | 누락 위험 | SP 기반 자동 생성 → `artisan audit:regenerate-triggers` | +| 저장 용량 증가 | 디스크 사용량 | 월별 파티셔닝 + 13개월 자동 삭제 | +| 세션 변수 미설정 (CLI, Queue) | actor_id NULL | NULL 허용, db_user로 보완 추적 | + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| Laravel에서 Product 생성 | audit_logs + trigger_audit_logs 모두 기록 | | ⏳ | +| 직접 SQL로 Product UPDATE | trigger_audit_logs에만 기록 | | ⏳ | +| phpMyAdmin에서 DELETE | trigger_audit_logs에 기록 (actor_id=NULL, db_user 기록) | | ⏳ | +| Bulk INSERT 10,000건 (트리거 활성) | trigger_audit_logs에 10,000건 기록, 성능 측정 | | ⏳ | +| Bulk INSERT 10,000건 (트리거 비활성) | trigger_audit_logs 기록 없음, 기본 성능 | | ⏳ | +| UPDATE 후 rollback API 호출 | old_values로 복원됨 | | ⏳ | +| DELETE 후 rollback API 호출 | 삭제된 레코드 복원됨 | | ⏳ | +| INSERT 후 rollback API 호출 | 삽입된 레코드 삭제됨 | | ⏳ | +| 13개월 이전 파티션 삭제 | 해당 파티션 DROP, 데이터 제거 | | ⏳ | + +### 9.2 성공 기준 + +| 기준 | 달성 | 비고 | +|------|------|------| +| 직접 SQL 변경이 trigger_audit_logs에 기록됨 | ⏳ | | +| old_values/new_values JSON이 정확히 저장됨 | ⏳ | | +| 특정 레코드의 특정 시점 복원이 가능함 | ⏳ | | +| 파티셔닝이 정상 작동함 | ⏳ | | +| 기존 Laravel audit 시스템에 영향 없음 | ⏳ | | +| 트리거 비활성화 플래그가 정상 동작함 | ⏳ | | +| mng 대시보드에서 이력 조회/필터링 가능 | ⏳ | | +| mng에서 특정 변경 복구(rollback) 가능 | ⏳ | | +| mng에서 테이블별 트리거 ON/OFF 가능 | ⏳ | | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경에 명시 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 9.2 성공 기준 | +| 3 | 작업 범위가 구체적인가? | ✅ | 2.1~2.4 Phase별 작업 항목 | +| 4 | 의존성이 명시되어 있는가? | ✅ | Phase 순서, 기존 시스템 참조 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 7. 참고 문서 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 3.3~3.6 상세 구현 명세 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 9.1 테스트 케이스 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 수치/조건 명시 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 2.1 Phase 1 → 1.1 테이블 생성 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 4.1~4.4 예상 파일 목록 | +| Q4. 작업 완료 확인 방법은? | ✅ | 9.1 테스트 케이스, 9.2 성공 기준 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +## 부록 A: 환경 정보 + +### A.1 프로젝트 구조 +``` +SAM/ ← 프로젝트 루트 +├── api/ ← Laravel 12 REST API (독립 git) +│ ├── app/ +│ │ ├── Http/ +│ │ │ ├── Controllers/Api/V1/ ← API 컨트롤러 +│ │ │ ├── Middleware/ ← 미들웨어 +│ │ │ └── Requests/ ← FormRequest +│ │ ├── Models/Audit/ ← 감사 모델 (AuditLog.php) +│ │ ├── Services/Audit/ ← 감사 서비스 (AuditLogger, AuditLogService) +│ │ ├── Traits/ ← Auditable.php, BelongsToTenant.php +│ │ ├── Console/Commands/ ← Artisan 커맨드 +│ │ └── Swagger/v1/ ← Swagger 문서 +│ ├── config/audit.php ← 감사 설정 +│ ├── database/migrations/ ← 마이그레이션 +│ ├── routes/ +│ │ ├── api.php ← 메인 라우트 (v1 prefix → 도메인별 분리) +│ │ └── api/v1/ ← 도메인별 라우트 파일 +│ └── bootstrap/app.php ← Laravel 12 미들웨어 등록 +├── mng/ ← Laravel 12 관리자 패널 (독립 git) +│ ├── app/Http/Controllers/ ← Blade 컨트롤러 +│ ├── resources/views/ ← Blade 뷰 (Tailwind + Alpine.js + HTMX) +│ │ └── layouts/app.blade.php ← 메인 레이아웃 +│ └── routes/web.php ← 웹 라우트 (auth 미들웨어 그룹) +├── react/ ← Next.js 15 프론트엔드 +└── docs/plans/ ← 이 문서 +``` + +### A.2 DB 접속 정보 +``` +엔진: MySQL 8.0 +Docker 컨테이너: sam-mysql-1 +데이터베이스: samdb (주), sam_stat (통계) +호스트: 127.0.0.1 (로컬) / sam-mysql-1 (Docker 내부) +포트: 3306 +사용자: samuser / sampass (일반), root / root (관리자) +문자셋: utf8mb4 / utf8mb4_unicode_ci +타임존: Asia/Seoul +``` + +### A.3 주요 명령어 +```bash +# Docker +cd /Users/kent/Works/@KD_SAM/SAM +docker compose up -d mysql + +# API 마이그레이션 +cd api && php artisan migrate +cd api && php artisan migrate:status + +# MySQL 직접 접속 +docker exec -it sam-mysql-1 mysql -u root -proot samdb + +# MNG Vite 빌드 +cd mng && npm run dev +``` + +--- + +## 부록 B: 기존 감사 시스템 코드 (수정 금지, 참조용) + +### B.1 Auditable Trait (`api/app/Traits/Auditable.php`) +```php +isFillable('created_by') && ! $model->created_by) { + $model->created_by = $actorId; + } + if ($model->isFillable('updated_by') && ! $model->updated_by) { + $model->updated_by = $actorId; + } + } + }); + + static::updating(function ($model) { + $actorId = static::resolveActorId(); + if ($actorId && $model->isFillable('updated_by')) { + $model->updated_by = $actorId; + } + }); + + static::deleting(function ($model) { + $actorId = static::resolveActorId(); + if ($actorId && $model->isFillable('deleted_by')) { + $model->deleted_by = $actorId; + $model->saveQuietly(); + } + }); + + static::created(function ($model) { + $model->logAuditEvent('created', null, $model->toAuditSnapshot()); + }); + + static::updated(function ($model) { + $dirty = $model->getChanges(); + $excluded = $model->getAuditExcludedFields(); + $changed = array_diff_key($dirty, array_flip($excluded)); + if (empty($changed)) return; + + $before = []; + $after = []; + foreach ($changed as $key => $value) { + $before[$key] = $model->getOriginal($key); + $after[$key] = $value; + } + $model->logAuditEvent('updated', $before, $after); + }); + + static::deleted(function ($model) { + $model->logAuditEvent('deleted', $model->toAuditSnapshot(), null); + }); + } + + public function getAuditExcludedFields(): array + { + $defaults = ['created_at','updated_at','deleted_at','created_by','updated_by','deleted_by']; + $custom = property_exists($this, 'auditExclude') ? $this->auditExclude : []; + return array_merge($defaults, $custom); + } + + public function getAuditTargetType(): string + { + return Str::snake(class_basename(static::class)); + } + + protected function toAuditSnapshot(): array + { + return array_diff_key($this->attributesToArray(), array_flip($this->getAuditExcludedFields())); + } + + protected function logAuditEvent(string $action, ?array $before, ?array $after): void + { + try { + $tenantId = $this->tenant_id ?? null; + if (! $tenantId) return; + $request = request(); + AuditLog::create([ + 'tenant_id' => $tenantId, + 'target_type' => $this->getAuditTargetType(), + 'target_id' => $this->getKey(), + 'action' => $action, + 'before' => $before, + 'after' => $after, + 'actor_id' => static::resolveActorId(), + 'ip' => $request?->ip(), + 'ua' => $request?->userAgent(), + 'created_at' => now(), + ]); + } catch (\Throwable $e) { + // 감사 로그 실패는 업무 흐름을 방해하지 않음 + } + } + + protected static function resolveActorId(): ?int + { + return auth()->id(); + } +} +``` + +### B.2 AuditLog 모델 (`api/app/Models/Audit/AuditLog.php`) +```php + 'array', + 'after' => 'array', + 'created_at' => 'datetime', + ]; +} +``` + +### B.3 AuditLogService (`api/app/Services/Audit/AuditLogService.php`) +```php +tenantId(); + $q = AuditLog::query()->where('tenant_id', $tenantId); + + if (! empty($filters['target_type'])) $q->where('target_type', $filters['target_type']); + if (! empty($filters['target_id'])) $q->where('target_id', (int) $filters['target_id']); + if (! empty($filters['action'])) $q->where('action', $filters['action']); + if (! empty($filters['actor_id'])) $q->where('actor_id', (int) $filters['actor_id']); + if (! empty($filters['from'])) $q->where('created_at', '>=', $filters['from']); + if (! empty($filters['to'])) $q->where('created_at', '<=', $filters['to']); + + $sort = $filters['sort'] ?? 'created_at'; + $order = $filters['order'] ?? 'desc'; + $size = (int) ($filters['size'] ?? 20); + + return $q->orderBy($sort, $order)->paginate($size); + } +} +``` + +### B.4 Audit Config (`api/config/audit.php`) +```php + env('AUDIT_RETENTION_DAYS', 395), // 13개월 + 'log_reads' => env('AUDIT_LOG_READS', false), +]; +``` + +### B.5 API 컨트롤러 패턴 (`api/app/Http/Controllers/Api/V1/Design/AuditLogController.php`) +```php +service->paginate($request->validated()); + }, __('message.fetched')); + } +} +``` + +### B.6 API Kernel (`api/app/Http/Kernel.php`) +```php + [], + 'api' => [], + ]; + protected $routeMiddleware = []; +} +``` + +> **참고**: Laravel 12에서 미들웨어 추가 시 `bootstrap/app.php`의 `->withMiddleware()` 또는 +> `Kernel.php`의 `$middleware` / `$middlewareGroups`에 등록한다. + +### B.7 API 라우트 패턴 (`api/routes/api.php`) +```php +// 도메인별 분리 구조 +Route::prefix('v1')->group(function () { + require __DIR__.'/api/v1/auth.php'; + require __DIR__.'/api/v1/design.php'; + // ... 기타 도메인 +}); + +// design.php 내 감사 로그 라우트 예시 +Route::prefix('design')->group(function () { + Route::prefix('audit-logs')->group(function () { + Route::get('', [DesignAuditLogController::class, 'index']); + Route::get('/{id}', [DesignAuditLogController::class, 'show'])->whereNumber('id'); + }); +}); +``` + +### B.8 Artisan 커맨드 패턴 (예: `TenantsBootstrap.php`) +```php + + + + + + @yield('title', 'Dashboard') - {{ config('app.name') }} + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + + + + @include('components.sidebar.main') +
    + @yield('content') +
    + @stack('scripts') + + +``` + +### C.3 MNG 컨트롤러 패턴 (기존 `AuditLogController.php` 요약) +```php +orderByDesc('created_at'); + + // 필터링 (target_type, action, tenant_id, from, to, search) + if ($request->filled('target_type')) $query->where('target_type', $request->target_type); + if ($request->filled('action')) $query->where('action', $request->action); + if ($request->filled('from')) $query->where('created_at', '>=', $request->from.' 00:00:00'); + if ($request->filled('to')) $query->where('created_at', '<=', $request->to.' 23:59:59'); + + // 통계 + $stats = [...]; + + // 페이지네이션 + $logs = $query->paginate(50)->withQueryString(); + + return view('audit-logs.index', compact('logs', 'stats')); + } + + public function show(int $id): View + { + $log = AuditLog::findOrFail($id); + return view('audit-logs.show', compact('log')); + } +} +``` + +### C.4 MNG 뷰 패턴 (데이터 목록 화면) +```blade +@extends('layouts.app') +@section('title', '페이지 제목') +@section('content') + +{{-- 1. 헤더 --}} +
    +

    페이지 제목

    +
    + +{{-- 2. 통계 카드 --}} +
    +
    +
    전체 기록
    +
    {{ number_format($stats['total']) }}
    +
    +
    + +{{-- 3. 필터 폼 --}} +
    +
    + + + +
    +
    + +{{-- 4. 데이터 테이블 (HTMX 방식 또는 일반 방식) --}} +
    + + + + + + + + @foreach($items as $item) + + + + @endforeach + +
    컬럼
    {{ $item->field }}
    +
    {{ $items->links() }}
    +
    + +@endsection +``` + +### C.5 MNG 라우트 패턴 (`mng/routes/web.php`) +```php +// 인증 필수 라우트 그룹 +Route::middleware(['auth', 'hq.member', 'password.changed'])->group(function () { + + // 감사 로그 (기존) + Route::prefix('audit-logs')->group(function () { + Route::get('/', [AuditLogController::class, 'index'])->name('audit-logs.index'); + Route::get('/{id}', [AuditLogController::class, 'show'])->name('audit-logs.show'); + }); + + // 새 트리거 감사는 여기에 추가: + // Route::prefix('trigger-audit')->name('trigger-audit.')->group(function () { ... }); +}); +``` + +### C.6 MNG 미들웨어 목록 +``` +mng/app/Http/Middleware/ +├── EnsureHQMember.php ← 본사 소속 확인 +├── EnsurePasswordChanged.php ← 비밀번호 변경 확인 +├── EnsureSuperAdmin.php ← 슈퍼관리자 확인 +└── AutoLoginViaRemember.php ← Remember Token 자동 재인증 +``` + +--- + +## 부록 D: SP 구현 상세 (Phase 1.3 참조) + +### D.1 sp_create_audit_triggers 전체 구현 방향 + +```sql +DELIMITER // + +DROP PROCEDURE IF EXISTS sp_create_audit_triggers // + +CREATE PROCEDURE sp_create_audit_triggers( + IN p_table_name VARCHAR(64), + IN p_db_name VARCHAR(64) +) +BEGIN + DECLARE v_col_list TEXT DEFAULT ''; + DECLARE v_json_new TEXT DEFAULT ''; + DECLARE v_json_old TEXT DEFAULT ''; + DECLARE v_change_check TEXT DEFAULT ''; + DECLARE v_changed_cols TEXT DEFAULT ''; + DECLARE v_tenant_col VARCHAR(64) DEFAULT NULL; + DECLARE v_pk_col VARCHAR(64) DEFAULT 'id'; + DECLARE v_done INT DEFAULT 0; + DECLARE v_col_name VARCHAR(64); + DECLARE v_sql TEXT; + + -- 제외 컬럼 + DECLARE v_exclude_cols TEXT DEFAULT 'created_at,updated_at,deleted_at,remember_token'; + + -- 커서: 대상 컬럼 목록 + DECLARE col_cursor CURSOR FOR + SELECT COLUMN_NAME + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = p_db_name + AND TABLE_NAME = p_table_name + AND FIND_IN_SET(COLUMN_NAME, v_exclude_cols) = 0 + ORDER BY ORDINAL_POSITION; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1; + + -- tenant_id 컬럼 존재 확인 + SELECT COLUMN_NAME INTO v_tenant_col + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = p_db_name + AND TABLE_NAME = p_table_name + AND COLUMN_NAME = 'tenant_id' + LIMIT 1; + + -- PK 컬럼 확인 + SELECT COLUMN_NAME INTO v_pk_col + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = p_db_name + AND TABLE_NAME = p_table_name + AND COLUMN_KEY = 'PRI' + LIMIT 1; + + -- 컬럼별 JSON_OBJECT 구문 조립 + OPEN col_cursor; + col_loop: LOOP + FETCH col_cursor INTO v_col_name; + IF v_done THEN LEAVE col_loop; END IF; + + -- JSON 조립 + IF v_json_new != '' THEN + SET v_json_new = CONCAT(v_json_new, ','); + SET v_json_old = CONCAT(v_json_old, ','); + END IF; + SET v_json_new = CONCAT(v_json_new, '''', v_col_name, ''', NEW.`', v_col_name, '`'); + SET v_json_old = CONCAT(v_json_old, '''', v_col_name, ''', OLD.`', v_col_name, '`'); + + -- UPDATE 변경 감지 조립 (NULL-safe 비교) + IF v_change_check != '' THEN + SET v_change_check = CONCAT(v_change_check, ' OR '); + SET v_changed_cols = CONCAT(v_changed_cols, ','); + END IF; + SET v_change_check = CONCAT(v_change_check, + 'NOT(OLD.`', v_col_name, '` <=> NEW.`', v_col_name, '`)'); + SET v_changed_cols = CONCAT(v_changed_cols, + 'IF(NOT(OLD.`', v_col_name, '` <=> NEW.`', v_col_name, '`),''', v_col_name, ''',NULL)'); + END LOOP; + CLOSE col_cursor; + + -- tenant_id 참조 + SET @tenant_expr = IF(v_tenant_col IS NOT NULL, + CONCAT('NEW.`', v_tenant_col, '`'), 'NULL'); + SET @tenant_expr_old = IF(v_tenant_col IS NOT NULL, + CONCAT('OLD.`', v_tenant_col, '`'), 'NULL'); + + -- 1. 기존 트리거 삭제 + SET @drop1 = CONCAT('DROP TRIGGER IF EXISTS trg_', p_table_name, '_ai'); + SET @drop2 = CONCAT('DROP TRIGGER IF EXISTS trg_', p_table_name, '_au'); + SET @drop3 = CONCAT('DROP TRIGGER IF EXISTS trg_', p_table_name, '_ad'); + PREPARE s FROM @drop1; EXECUTE s; DEALLOCATE PREPARE s; + PREPARE s FROM @drop2; EXECUTE s; DEALLOCATE PREPARE s; + PREPARE s FROM @drop3; EXECUTE s; DEALLOCATE PREPARE s; + + -- 2. AFTER INSERT 트리거 + SET v_sql = CONCAT( + 'CREATE TRIGGER trg_', p_table_name, '_ai AFTER INSERT ON `', p_table_name, '` ', + 'FOR EACH ROW BEGIN ', + 'IF @disable_audit_trigger IS NULL OR @disable_audit_trigger != 1 THEN ', + 'INSERT INTO trigger_audit_logs(table_name,row_id,dml_type,old_values,new_values,tenant_id,actor_id,session_info,db_user) ', + 'VALUES(''', p_table_name, ''',NEW.`', v_pk_col, '`,''INSERT'',NULL,', + 'JSON_OBJECT(', v_json_new, '),', + @tenant_expr, ',@sam_actor_id,@sam_session_info,CURRENT_USER()); ', + 'END IF; END' + ); + SET @s = v_sql; + PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt; + + -- 3. AFTER UPDATE 트리거 (변경 있을 때만) + SET v_sql = CONCAT( + 'CREATE TRIGGER trg_', p_table_name, '_au AFTER UPDATE ON `', p_table_name, '` ', + 'FOR EACH ROW BEGIN ', + 'IF @disable_audit_trigger IS NULL OR @disable_audit_trigger != 1 THEN ', + 'IF ', v_change_check, ' THEN ', + 'INSERT INTO trigger_audit_logs(table_name,row_id,dml_type,old_values,new_values,changed_columns,tenant_id,actor_id,session_info,db_user) ', + 'VALUES(''', p_table_name, ''',NEW.`', v_pk_col, '`,''UPDATE'',', + 'JSON_OBJECT(', v_json_old, '),', + 'JSON_OBJECT(', v_json_new, '),', + 'JSON_REMOVE(JSON_ARRAY(', v_changed_cols, '),', + -- NULL 값 제거 (변경 안 된 컬럼) + '''$[0]''),', -- 간소화: 실제 구현 시 NULL 필터링 로직 보강 필요 + @tenant_expr, ',@sam_actor_id,@sam_session_info,CURRENT_USER()); ', + 'END IF; END IF; END' + ); + SET @s = v_sql; + PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt; + + -- 4. AFTER DELETE 트리거 + SET v_sql = CONCAT( + 'CREATE TRIGGER trg_', p_table_name, '_ad AFTER DELETE ON `', p_table_name, '` ', + 'FOR EACH ROW BEGIN ', + 'IF @disable_audit_trigger IS NULL OR @disable_audit_trigger != 1 THEN ', + 'INSERT INTO trigger_audit_logs(table_name,row_id,dml_type,old_values,new_values,tenant_id,actor_id,session_info,db_user) ', + 'VALUES(''', p_table_name, ''',OLD.`', v_pk_col, '`,''DELETE'',', + 'JSON_OBJECT(', v_json_old, '),NULL,', + @tenant_expr_old, ',@sam_actor_id,@sam_session_info,CURRENT_USER()); ', + 'END IF; END' + ); + SET @s = v_sql; + PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +END // + +DELIMITER ; +``` + +> **주의**: 위 코드는 구현 방향을 보여주는 참조 코드이다. +> 실제 구현 시 changed_columns의 NULL 필터링, 복합 PK 처리, 에러 핸들링 등을 보강해야 한다. + +### D.2 전체 테이블 일괄 트리거 생성 프로시저 + +```sql +DELIMITER // + +CREATE PROCEDURE sp_create_all_audit_triggers(IN p_db_name VARCHAR(64)) +BEGIN + DECLARE v_tbl VARCHAR(64); + DECLARE v_done INT DEFAULT 0; + DECLARE v_count INT DEFAULT 0; + + -- 제외 테이블 목록 + DECLARE v_exclude TEXT DEFAULT + 'audit_logs,trigger_audit_logs,personal_access_tokens,sessions,' + 'cache,cache_locks,jobs,job_batches,failed_jobs,migrations,' + 'password_reset_tokens'; + + DECLARE tbl_cursor CURSOR FOR + SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = p_db_name + AND TABLE_TYPE = 'BASE TABLE' + AND TABLE_NAME NOT LIKE 'telescope_%' + AND FIND_IN_SET(TABLE_NAME, v_exclude) = 0 + ORDER BY TABLE_NAME; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1; + + OPEN tbl_cursor; + tbl_loop: LOOP + FETCH tbl_cursor INTO v_tbl; + IF v_done THEN LEAVE tbl_loop; END IF; + + CALL sp_create_audit_triggers(v_tbl, p_db_name); + SET v_count = v_count + 1; + END LOOP; + CLOSE tbl_cursor; + + SELECT CONCAT('Created triggers for ', v_count, ' tables') AS result; +END // + +DELIMITER ; + +-- 실행: +-- CALL sp_create_all_audit_triggers('samdb'); +``` + +--- + +## 부록 E: 복구 서비스 구현 상세 (Phase 2.2 참조) + +```php +dml_type) { + 'INSERT' => $this->buildDeleteSQL($log), + 'UPDATE' => $this->buildRevertUpdateSQL($log), + 'DELETE' => $this->buildReinsertSQL($log), + }; + } + + /** + * 복구 실행 (트랜잭션) + */ + public function executeRollback(int $auditId): bool + { + $log = TriggerAuditLog::findOrFail($auditId); + + // 트리거 감사 비활성화 (복구 작업 자체는 기록 안 함) + DB::statement('SET @disable_audit_trigger = 1'); + + try { + DB::transaction(function () use ($log) { + $sql = $this->generateRollbackSQL($log->id); + DB::statement($sql); + }); + return true; + } finally { + DB::statement('SET @disable_audit_trigger = NULL'); + } + } + + /** + * 특정 레코드의 특정 시점 상태 조회 + */ + public function getRecordStateAt(string $table, string $rowId, Carbon $at): ?array + { + // 해당 시점 이전의 가장 마지막 상태를 추적 + $log = TriggerAuditLog::where('table_name', $table) + ->where('row_id', $rowId) + ->where('created_at', '<=', $at) + ->orderByDesc('created_at') + ->first(); + + if (! $log) return null; + + return match ($log->dml_type) { + 'INSERT', 'UPDATE' => $log->new_values, + 'DELETE' => null, // 해당 시점에 삭제된 상태 + }; + } + + /** + * 특정 레코드의 변경 이력 + */ + public function getRecordHistory(string $table, string $rowId): Collection + { + return TriggerAuditLog::where('table_name', $table) + ->where('row_id', $rowId) + ->orderByDesc('created_at') + ->get(); + } + + private function buildDeleteSQL(TriggerAuditLog $log): string + { + return "DELETE FROM `{$log->table_name}` WHERE `id` = " . DB::getPdo()->quote($log->row_id); + } + + private function buildRevertUpdateSQL(TriggerAuditLog $log): string + { + $sets = collect($log->old_values) + ->map(fn($val, $col) => "`{$col}` = " . ($val === null ? 'NULL' : DB::getPdo()->quote($val))) + ->implode(', '); + + return "UPDATE `{$log->table_name}` SET {$sets} WHERE `id` = " . DB::getPdo()->quote($log->row_id); + } + + private function buildReinsertSQL(TriggerAuditLog $log): string + { + $cols = collect($log->old_values)->keys()->map(fn($c) => "`{$c}`")->implode(', '); + $vals = collect($log->old_values)->values() + ->map(fn($v) => $v === null ? 'NULL' : DB::getPdo()->quote($v)) + ->implode(', '); + + return "INSERT INTO `{$log->table_name}` ({$cols}) VALUES ({$vals})"; + } +} +``` + +--- + +## 부록 F: 세션 시작 가이드 (새 세션용) + +### 이 문서로 작업을 시작하는 방법 + +``` +1. Serena 메모리 로드 + → read_memory("db-trigger-audit-state") : 진행 상태 확인 + +2. 이 문서의 "📍 현재 진행 상태" 확인 + → 마지막 완료 작업, 다음 작업 확인 + +3. 해당 Phase의 "대상 범위" (섹션 2) 확인 + → 구체적 작업 항목과 상태 확인 + +4. 해당 작업의 구현 코드는 "작업 절차" (섹션 3) + "부록" 참조 + → 부록 B: 기존 코드 패턴 (수정 금지) + → 부록 C: MNG 패턴 (Phase 4용) + → 부록 D: SP 구현 상세 (Phase 1.3용) + → 부록 E: 복구 서비스 상세 (Phase 2.2용) + +5. 작업 완료 후 + → 이 문서의 진행 상태 업데이트 + → Serena 메모리 저장: write_memory("db-trigger-audit-state", ...) +``` + +### 환경 확인 명령어 + +```bash +# Docker MySQL 실행 확인 +docker ps | grep sam-mysql + +# 마이그레이션 상태 +cd /Users/kent/Works/@KD_SAM/SAM/api && php artisan migrate:status + +# 현재 트리거 목록 확인 +docker exec -it sam-mysql-1 mysql -u root -proot samdb -e "SHOW TRIGGERS" + +# trigger_audit_logs 레코드 수 +docker exec -it sam-mysql-1 mysql -u root -proot samdb -e "SELECT COUNT(*) FROM trigger_audit_logs" +``` + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file diff --git a/plans/quote-management-url-migration-plan.md b/plans/quote-management-url-migration-plan.md new file mode 100644 index 0000000..9f2ce61 --- /dev/null +++ b/plans/quote-management-url-migration-plan.md @@ -0,0 +1,1282 @@ +# 견적관리 URL 구조 마이그레이션 계획 + +> **작성일**: 2026-01-26 +> **목적**: 견적관리 페이지 URL 구조를 Query 기반(?mode=new)에서 RESTful 경로 기반(/test-new, /test/[id])으로 마이그레이션 +> **기준 문서**: docs/standards/api-rules.md, docs/specs/database-schema.md +> **상태**: 📋 계획 수립 완료 (Serena ID: quote-url-migration-state) + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 3 코드 작업 완료 - 목록 페이지 링크 V2 적용 | +| **다음 작업** | Step 3.2: 통합 테스트 (사용자 수동 테스트) | +| **진행률** | 11/12 (92%) - Phase 1 ✅, Phase 2 ✅, Phase 3 (테스트 제외) ✅ | +| **마지막 업데이트** | 2026-01-26 | + +--- + +## 1. 개요 + +### 1.1 배경 + +현재 견적관리 시스템에는 두 가지 URL 패턴이 공존합니다: + +**V1 (기존 - Query 기반):** +- 목록: `/sales/quote-management` +- 등록: `/sales/quote-management?mode=new` +- 상세: `/sales/quote-management/[id]` +- 수정: `/sales/quote-management/[id]?mode=edit` + +**V2 (신규 - RESTful 경로 기반):** +- 목록: `/sales/quote-management` (동일) +- 등록: `/sales/quote-management/test-new` +- 상세: `/sales/quote-management/test/[id]` +- 수정: `/sales/quote-management/test/[id]?mode=edit` + +V2는 `IntegratedDetailTemplate` + `QuoteRegistrationV2` 컴포넌트를 사용하며, 현재 테스트(Mock 데이터) 상태입니다. + +### 1.2 목표 + +1. V2 페이지에 실제 API 연동 완료 +2. V2 URL 패턴을 정식 경로로 채택 (test 접두사 제거) +3. V1 페이지 삭제 또는 V2로 리다이렉트 처리 +4. DB 스키마 변경 없이 기존 API 활용 + +### 1.3 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ - DB 스키마 변경 없음 (기존 quotes, quote_items 테이블 활용) │ +│ - 기존 API 엔드포인트 재사용 (POST/PUT /api/v1/quotes) │ +│ - V1 → V2 단계적 마이그레이션 (병행 기간 최소화) │ +│ - IntegratedDetailTemplate 표준 적용 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.4 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | 컴포넌트 수정, API 연동 코드, 타입 정의 | 불필요 | +| ⚠️ 컨펌 필요 | 라우트 경로 변경, 기존 페이지 삭제/리다이렉트 | **필수** | +| 🔴 금지 | DB 스키마 변경, 기존 API 엔드포인트 삭제 | 별도 협의 | + +### 1.5 준수 규칙 +- `docs/quickstart/quick-start.md` - 빠른 시작 가이드 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 +- `docs/standards/api-rules.md` - API 개발 규칙 + +--- + +## 2. 현재 상태 분석 + +### 2.1 파일 구조 비교 + +#### V1 (기존) +``` +react/src/app/[locale]/(protected)/sales/quote-management/ +├── page.tsx # 목록 + mode=new 감지 → QuoteRegistration +├── new/page.tsx # 리다이렉트용 (거의 미사용) +├── [id]/page.tsx # 상세 + mode=edit 감지 → QuoteRegistration +└── [id]/edit/page.tsx # 리다이렉트용 (거의 미사용) +``` + +#### V2 (신규) +``` +react/src/app/[locale]/(protected)/sales/quote-management/ +├── test-new/page.tsx # 등록 (IntegratedDetailTemplate) +├── test/[id]/page.tsx # 상세/수정 (IntegratedDetailTemplate) +└── test/[id]/edit/page.tsx # 리다이렉트 → test/[id]?mode=edit +``` + +### 2.2 컴포넌트 비교 + +| 항목 | V1 (QuoteRegistration) | V2 (QuoteRegistrationV2) | +|------|------------------------|--------------------------| +| 파일 크기 | ~50KB | ~45KB | +| 레이아웃 | 단일 폼 | 좌우 분할 (개소 목록 \| 상세) | +| 템플릿 | 자체 레이아웃 | IntegratedDetailTemplate | +| 데이터 구조 | `QuoteFormData` | `QuoteFormDataV2` + `LocationItem` | +| API 연동 | ✅ 완료 | ❌ Mock 데이터 | +| 상태 관리 | `status: string` | `status: 'draft' \| 'temporary' \| 'final'` | + +### 2.3 데이터 구조 비교 + +#### V1: QuoteFormData +```typescript +interface QuoteFormData { + id?: string; + quoteNumber?: string; + registrationDate?: string; + clientId?: string | number; + clientName?: string; + siteName?: string; + manager?: string; + contact?: string; + dueDate?: string; + remarks?: string; + status?: string; + items?: QuoteItem[]; // 층별 항목 + bomMaterials?: BomMaterial[]; + calculationInputs?: Record; +} +``` + +#### V2: QuoteFormDataV2 +```typescript +interface QuoteFormDataV2 { + id?: string; + registrationDate: string; + writer: string; + clientId: string; + clientName: string; + siteName: string; + manager: string; + contact: string; + dueDate: string; + remarks: string; + status: 'draft' | 'temporary' | 'final'; + locations: LocationItem[]; // 개소별 항목 (더 상세한 구조) +} + +interface LocationItem { + id: string; + floor: string; + code: string; + openWidth: number; + openHeight: number; + productCode: string; + productName: string; + quantity: number; + guideRailType: string; + motorPower: string; + controller: string; + wingSize: number; + inspectionFee: number; + unitPrice?: number; + totalPrice?: number; + bomResult?: BomCalculationResult; +} +``` + +### 2.4 API 엔드포인트 (변경 없음) + +| HTTP | Endpoint | 설명 | V1 사용 | V2 사용 | +|------|----------|------|:-------:|:-------:| +| GET | `/api/v1/quotes` | 목록 조회 | ✅ | ✅ | +| GET | `/api/v1/quotes/{id}` | 단건 조회 | ✅ | 🔲 (TODO) | +| POST | `/api/v1/quotes` | 생성 | ✅ | 🔲 (TODO) | +| PUT | `/api/v1/quotes/{id}` | 수정 | ✅ | 🔲 (TODO) | +| POST | `/api/v1/quotes/calculate/bom/bulk` | BOM 자동산출 | ✅ | ✅ | + +### 2.5 DB 스키마 (변경 없음) + +**quotes 테이블** - 그대로 사용 +```sql +-- 핵심 필드 +id, tenant_id, quote_number +registration_date, author +client_id, client_name, manager, contact +site_name, site_code +product_category, product_id, product_code, product_name +open_size_width, open_size_height, quantity +material_cost, labor_cost, install_cost +subtotal, discount_rate, discount_amount, total_amount +status, is_final +calculation_inputs (JSON) +options (JSON) +``` + +**quote_items 테이블** - 그대로 사용 +```sql +id, quote_id, tenant_id +item_id, item_code, item_name, specification, unit +base_quantity, calculated_quantity +unit_price, total_price +formula, formula_result, formula_source, formula_category +sort_order +``` + +--- + +## 3. 대상 범위 + +### 3.1 Phase 1: V2 API 연동 (프론트엔드) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | V2 데이터 변환 함수 구현 | ✅ | `transformV2ToApi`, `transformApiToV2` (2026-01-26) | +| 1.2 | test-new 페이지 API 연동 (createQuote) | ✅ | Mock → 실제 API (2026-01-26) | +| 1.3 | test/[id] 페이지 API 연동 (getQuoteById) | ✅ | Mock → 실제 API (2026-01-26) | +| 1.4 | test/[id] 수정 API 연동 (updateQuote) | ✅ | Mock → 실제 API (2026-01-26) | + +### 3.2 Phase 2: URL 경로 정식화 (라우팅) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | test-new → new 경로 변경 | ✅ | V2 버전으로 교체 완료 (2026-01-26) | +| 2.2 | test/[id] → [id] 경로 통합 | ✅ | V2 버전으로 교체 완료 (2026-01-26) | +| 2.3 | 기존 V1 페이지 처리 결정 | ✅ | V1 백업 보존, test 폴더 삭제 | + +### 3.3 Phase 3: 정리 및 테스트 + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 3.1 | V1 컴포넌트/페이지 정리 | ✅ | test 폴더 삭제 완료, V1 백업 보존 | +| 3.2 | 통합 테스트 | ⏳ | CRUD + 문서출력 + 상태전환 (사용자 테스트) | +| 3.3 | 목록 페이지 링크 업데이트 | ✅ | QuoteManagementClient, DevToolbar 완료 | +| 3.4 | 문서 업데이트 | ✅ | 계획 문서 완료 | + +--- + +## 4. 작업 절차 + +### 4.1 단계별 절차 + +``` +Phase 1: V2 API 연동 +├── Step 1.1: 데이터 변환 함수 +│ ├── transformV2ToApi() - V2 → API 요청 형식 +│ ├── transformApiToV2() - API 응답 → V2 형식 +│ └── actions.ts에 추가 +│ +├── Step 1.2: test-new 페이지 연동 +│ ├── handleSave에서 createQuote 호출 +│ ├── 성공 시 /sales/quote-management/test/{id}로 이동 +│ └── 에러 처리 +│ +├── Step 1.3: test/[id] 상세 페이지 연동 +│ ├── useEffect에서 getQuoteById 호출 +│ ├── transformApiToV2로 데이터 변환 +│ └── 로딩/에러 상태 처리 +│ +└── Step 1.4: test/[id] 수정 연동 + ├── handleSave에서 updateQuote 호출 + ├── 성공 시 view 모드로 복귀 + └── 에러 처리 + +Phase 2: URL 경로 정식화 +├── Step 2.1: 새 경로 생성 +│ ├── new/page.tsx → IntegratedDetailTemplate 버전 +│ └── 기존 new/page.tsx 백업 +│ +├── Step 2.2: 상세 경로 통합 +│ ├── [id]/page.tsx를 V2 버전으로 교체 +│ └── 기존 [id]/page.tsx 백업 +│ +└── Step 2.3: V1 처리 + ├── 옵션 A: V1 페이지 삭제 + └── 옵션 B: V1 → V2 리다이렉트 + +Phase 3: 정리 및 테스트 +├── Step 3.1: 파일 정리 +│ ├── test-new, test/[id] 폴더 삭제 +│ ├── V1 백업 파일 삭제 (확인 후) +│ └── 미사용 컴포넌트 정리 +│ +├── Step 3.2: 통합 테스트 +│ ├── 신규 등록 → 저장 → 상세 확인 +│ ├── 상세 → 수정 → 저장 → 상세 확인 +│ ├── 문서 출력 (견적서, 산출내역서, 발주서) +│ ├── 최종확정 → 수주전환 +│ └── 목록 링크 동작 확인 +│ +├── Step 3.3: 목록 페이지 링크 +│ └── QuoteManagementClient의 라우팅 경로 확인 +│ +└── Step 3.4: 문서 업데이트 + ├── 이 계획 문서 완료 처리 + └── 필요시 claudedocs에 작업 기록 +``` + +### 4.2 데이터 변환 상세 + +#### V2 → API (저장 시) +```typescript +function transformV2ToApi(data: QuoteFormDataV2) { + return { + registration_date: data.registrationDate, + author: data.writer, + client_id: data.clientId || null, + client_name: data.clientName, + site_name: data.siteName, + manager: data.manager, + contact: data.contact, + completion_date: data.dueDate, + remarks: data.remarks, + status: data.status === 'final' ? 'finalized' : data.status, + + // locations → items 변환 + items: data.locations.map((loc, index) => ({ + floor: loc.floor, + code: loc.code, + product_code: loc.productCode, + product_name: loc.productName, + open_width: loc.openWidth, + open_height: loc.openHeight, + quantity: loc.quantity, + guide_rail_type: loc.guideRailType, + motor_power: loc.motorPower, + controller: loc.controller, + wing_size: loc.wingSize, + inspection_fee: loc.inspectionFee, + unit_price: loc.unitPrice, + total_price: loc.totalPrice, + sort_order: index, + })), + + // calculation_inputs 생성 (첫 번째 location 기준) + calculation_inputs: data.locations.length > 0 ? { + W0: data.locations[0].openWidth, + H0: data.locations[0].openHeight, + QTY: data.locations[0].quantity, + GT: data.locations[0].guideRailType, + MP: data.locations[0].motorPower, + } : null, + }; +} +``` + +#### API → V2 (조회 시) +```typescript +function transformApiToV2(apiData: QuoteResponse): QuoteFormDataV2 { + return { + id: apiData.id, + registrationDate: apiData.registrationDate, + writer: apiData.author || '', + clientId: String(apiData.clientId || ''), + clientName: apiData.clientName || '', + siteName: apiData.siteName || '', + manager: apiData.manager || '', + contact: apiData.contact || '', + dueDate: apiData.completionDate || '', + remarks: apiData.remarks || '', + status: mapApiStatusToV2(apiData.status), + + // items → locations 변환 + locations: (apiData.items || []).map(item => ({ + id: String(item.id), + floor: item.floor || '', + code: item.code || '', + openWidth: item.openWidth || 0, + openHeight: item.openHeight || 0, + productCode: item.productCode || '', + productName: item.productName || '', + quantity: item.quantity || 1, + guideRailType: item.guideRailType || 'wall', + motorPower: item.motorPower || 'single', + controller: item.controller || 'basic', + wingSize: item.wingSize || 50, + inspectionFee: item.inspectionFee || 0, + unitPrice: item.unitPrice, + totalPrice: item.totalPrice, + })), + }; +} + +function mapApiStatusToV2(apiStatus: string): 'draft' | 'temporary' | 'final' { + switch (apiStatus) { + case 'finalized': + case 'converted': + return 'final'; + case 'draft': + case 'sent': + case 'approved': + return 'draft'; + default: + return 'draft'; + } +} +``` + +--- + +## 5. 컨펌 대기 목록 + +> API 내부 로직 변경 등 승인 필요 항목 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| C-1 | URL 경로 정식화 | test-new → new, test/[id] → [id] | 라우팅 전체 | ⏳ 대기 | +| C-2 | V1 페이지 처리 | 삭제 vs 리다이렉트 결정 | 기존 사용자 | ⏳ 대기 | +| C-3 | 컴포넌트 정리 | QuoteRegistration.tsx 삭제 여부 | 코드베이스 | ⏳ 대기 | + +--- + +## 6. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-26 | Step 3.3, 3.4 | 목록 페이지 V2 URL 적용, 문서 업데이트 | page.tsx, QuoteManagementClient.tsx, DevToolbar.tsx | ✅ | +| 2026-01-26 | Step 3.1 | test 폴더 삭제, V1 백업 보존 | test-new/, test/ 삭제 | ✅ | +| 2026-01-26 | Step 2.1, 2.2 | URL 경로 정식화 (Phase 2 완료) | new/page.tsx, [id]/page.tsx | ✅ | +| 2026-01-26 | Step 1.3, 1.4 | test/[id] 상세/수정 API 연동 (Phase 1 완료) | test/[id]/page.tsx | ✅ | +| 2026-01-26 | Step 1.2 | test-new 페이지 createQuote API 연동 | test-new/page.tsx | ✅ | +| 2026-01-26 | Step 1.1 | V2 데이터 변환 함수 구현 완료 | types.ts | ✅ | +| 2026-01-26 | - | 계획 문서 초안 작성 | - | - | + +--- + +## 7. 참고 문서 + +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **API 규칙**: `docs/standards/api-rules.md` +- **DB 스키마**: `docs/specs/database-schema.md` + +### 7.1 핵심 파일 경로 + +#### 프론트엔드 (React) +``` +# V1 (기존) +react/src/app/[locale]/(protected)/sales/quote-management/page.tsx +react/src/app/[locale]/(protected)/sales/quote-management/[id]/page.tsx +react/src/components/quotes/QuoteRegistration.tsx (50KB) +react/src/components/quotes/actions.ts (28KB) +react/src/components/quotes/types.ts + +# V2 (신규) +react/src/app/[locale]/(protected)/sales/quote-management/test-new/page.tsx +react/src/app/[locale]/(protected)/sales/quote-management/test/[id]/page.tsx +react/src/components/quotes/QuoteRegistrationV2.tsx +react/src/components/quotes/LocationListPanel.tsx +react/src/components/quotes/LocationDetailPanel.tsx +react/src/components/quotes/QuoteSummaryPanel.tsx +react/src/components/quotes/QuoteFooterBar.tsx +react/src/components/quotes/quoteConfig.ts +``` + +#### 백엔드 (Laravel API) - 변경 없음 +``` +api/app/Http/Controllers/Api/V1/QuoteController.php +api/app/Http/Requests/Quote/QuoteStoreRequest.php +api/app/Http/Requests/Quote/QuoteUpdateRequest.php +api/app/Models/Quote/Quote.php +api/app/Models/Quote/QuoteItem.php +api/app/Services/Quote/QuoteService.php +api/app/Services/Quote/QuoteCalculationService.php +``` + +--- + +## 8. 세션 및 메모리 관리 정책 (Serena Optimized) + +### 8.1 세션 시작 시 (Load Strategy) +```javascript +read_memory("quote-url-migration-state") // 1. 상태 파악 +read_memory("quote-url-migration-snapshot") // 2. 사고 흐름 복구 +``` + +### 8.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | 🛠 **Snapshot** | 현재까지의 코드 변경점과 논의 핵심 요약 | +| **20% 이하** | 🧹 **Context Purge** | 수정 중인 핵심 파일 및 함수 목록 | +| **10% 이하** | 🛑 **Stop & Save** | 최종 상태 저장 후 세션 교체 권고 | + +### 8.3 Serena 메모리 구조 +- `quote-url-migration-state`: { phase, progress, next_step, last_decision } +- `quote-url-migration-snapshot`: 현재까지의 코드 변경 및 논의 요약 +- `quote-url-migration-active-files`: 수정 중인 파일 목록 + +--- + +## 9. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 9.1 테스트 케이스 + +| 시나리오 | 입력 | 예상 결과 | 실제 결과 | 상태 | +|---------|------|----------|----------|------| +| 신규 등록 | 견적 정보 입력 후 저장 | DB 저장, 상세 페이지 이동 | - | ⏳ | +| 상세 조회 | /quote-management/[id] 접근 | 저장된 데이터 표시 | - | ⏳ | +| 수정 | mode=edit에서 수정 후 저장 | DB 업데이트, view 모드 복귀 | - | ⏳ | +| 문서 출력 | 견적서 버튼 클릭 | 견적서 모달 표시 | - | ⏳ | +| 최종확정 | 최종확정 버튼 클릭 | status → finalized | - | ⏳ | + +### 9.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|:----:|------| +| V2 API 연동 완료 | ✅ | Phase 1 완료 | +| URL 경로 정식화 | ✅ | Phase 2 완료 | +| V1 정리 완료 | ✅ | test 폴더 삭제, 백업 보존 | +| 통합 테스트 통과 | ⏳ | 사용자 테스트 필요 | + +--- + +## 10. 자기완결성 점검 결과 + +### 10.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 섹션 1.2 목표 참조 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 9.2 참조 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 3 대상 범위 참조 | +| 4 | 의존성이 명시되어 있는가? | ✅ | DB/API 변경 없음 명시 | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 7.1 검증 완료 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 4 상세 절차 참조 | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9.1 테스트 케이스 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 함수명, 경로 명시 | + +### 10.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.2 목표 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 4.1 Step 1.1 | +| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 7.1 핵심 파일 경로 | +| Q4. 작업 완료 확인 방법은? | ✅ | 9.1 테스트 케이스 | +| Q5. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 | + +**결과**: 5/5 통과 → ✅ 자기완결성 확보 + +--- + +## 부록 A: API 스키마 상세 + +> V2 연동 시 참고할 실제 API 요청/응답 스키마 + +### A.1 API 응답 타입 (QuoteApiData) + +```typescript +// react/src/components/quotes/types.ts 에서 발췌 + +interface QuoteApiData { + id: number; + quote_number: string; + registration_date: string; + + // 발주처 정보 + client_id: number | null; + client_name: string; + client?: { id: number; name: string; }; // with('client') 로드 시 + + // 현장 정보 + site_name: string | null; + site_code: string | null; + + // 담당자 정보 (API 실제 필드명) + manager?: string | null; // 담당자명 + contact?: string | null; // 연락처 + manager_name?: string | null; // 레거시 호환 + manager_contact?: string | null; // 레거시 호환 + + // 제품 정보 + product_category: 'screen' | 'steel'; + quantity: number; + unit_symbol?: string | null; // 단위 (개소, set 등) + + // 금액 정보 + supply_amount: string | number; + tax_amount: string | number; + total_amount: string | number; + + // 상태 + status: 'draft' | 'sent' | 'approved' | 'rejected' | 'finalized' | 'converted'; + current_revision: number; + is_final: boolean; + + // 비고/납기 + remarks?: string | null; // API 실제 필드명 + completion_date?: string | null; // API 실제 필드명 + description?: string | null; // 레거시 호환 + delivery_date?: string | null; // 레거시 호환 + + // 자동산출 입력값 (JSON) + calculation_inputs?: { + items?: Array<{ + productCategory?: string; + productName?: string; + openWidth?: string; + openHeight?: string; + guideRailType?: string; + motorPower?: string; + controller?: string; + wingSize?: string; + inspectionFee?: number; + floor?: string; + code?: string; + quantity?: number; + }>; + } | null; + + // 품목 목록 + items?: QuoteItemApiData[]; + bom_materials?: BomMaterialApiData[]; + + // 감사 정보 + created_at: string; + updated_at: string; + created_by: number | null; + updated_by: number | null; + finalized_at: string | null; + finalized_by: number | null; + + // 관계 데이터 (with 로드 시) + creator?: { id: number; name: string; } | null; + updater?: { id: number; name: string; } | null; + finalizer?: { id: number; name: string; } | null; +} +``` + +### A.2 품목 API 타입 (QuoteItemApiData) + +```typescript +interface QuoteItemApiData { + id: number; + quote_id: number; + + // 품목 정보 + item_id?: number | null; + item_code?: string | null; + item_name: string; + product_id?: number | null; // 레거시 호환 + product_name?: string; // 레거시 호환 + specification: string | null; + unit: string | null; + + // 수량 (API는 calculated_quantity 사용) + base_quantity?: number; // 1개당 BOM 수량 + calculated_quantity?: number; // base × 주문 수량 + quantity?: number; // 레거시 호환 + + // 금액 + unit_price: string | number; + total_price?: string | number; // API 실제 필드 + supply_amount?: string | number; // 레거시 호환 + tax_amount?: string | number; + total_amount?: string | number; // 레거시 호환 + + sort_order: number; + note: string | null; +} +``` + +### A.3 API 요청 형식 (POST/PUT /api/v1/quotes) + +```typescript +// transformFormDataToApi() 출력 형식 + +interface QuoteApiRequest { + registration_date: string; // "2026-01-26" + author: string | null; // 작성자명 + client_id: number | null; + client_name: string; + site_name: string | null; + manager: string | null; // 담당자명 + contact: string | null; // 연락처 + completion_date: string | null; // 납기일 "2026-02-01" + remarks: string | null; + product_category: 'screen' | 'steel'; + quantity: number; // 총 수량 (items.quantity 합계) + unit_symbol: string; // "개소" | "SET" + total_amount: number; // 총액 (공급가 + 세액) + + // 자동산출 입력값 저장 (폼 복원용) + calculation_inputs: { + items: Array<{ + productCategory: string; + productName: string; + openWidth: string; + openHeight: string; + guideRailType: string; + motorPower: string; + controller: string; + wingSize: string; + inspectionFee: number; + floor: string; + code: string; + quantity: number; + }>; + }; + + // BOM 자재 기반 items + items: Array<{ + item_name: string; + item_code: string; + specification: string | null; + unit: string; + quantity: number; // 주문 수량 + base_quantity: number; // 1개당 BOM 수량 + calculated_quantity: number; // base × 주문 수량 + unit_price: number; + total_price: number; + sort_order: number; + note: string | null; + item_index?: number; // calculation_inputs.items 인덱스 + finished_goods_code?: string; // 완제품 코드 + formula_category?: string; // 공정 그룹 + }>; +} +``` + +--- + +## 부록 B: 기존 변환 함수 코드 + +> 새 세션에서 바로 사용할 수 있도록 V1 변환 함수 전체 코드 포함 + +### B.1 API → 프론트엔드 변환 (transformApiToFrontend) + +```typescript +// react/src/components/quotes/types.ts + +export function transformApiToFrontend(apiData: QuoteApiData): Quote { + return { + id: String(apiData.id), + quoteNumber: apiData.quote_number, + registrationDate: apiData.registration_date, + clientId: apiData.client_id ? String(apiData.client_id) : '', + clientName: apiData.client?.name || apiData.client_name || '', + siteName: apiData.site_name || undefined, + siteCode: apiData.site_code || undefined, + // API 실제 필드명 우선, 레거시 폴백 + managerName: apiData.manager || apiData.manager_name || undefined, + managerContact: apiData.contact || apiData.manager_contact || undefined, + productCategory: apiData.product_category, + quantity: apiData.quantity || 0, + unitSymbol: apiData.unit_symbol || undefined, + supplyAmount: parseFloat(String(apiData.supply_amount)) || 0, + taxAmount: parseFloat(String(apiData.tax_amount)) || 0, + totalAmount: parseFloat(String(apiData.total_amount)) || 0, + status: apiData.status, + currentRevision: apiData.current_revision || 0, + isFinal: apiData.is_final || false, + description: apiData.remarks || apiData.description || undefined, + validUntil: apiData.valid_until || undefined, + deliveryDate: apiData.completion_date || apiData.delivery_date || undefined, + deliveryLocation: apiData.delivery_location || undefined, + paymentTerms: apiData.payment_terms || undefined, + items: (apiData.items || []).map(transformItemApiToFrontend), + calculationInputs: apiData.calculation_inputs || undefined, + bomMaterials: (apiData.bom_materials || []).map(transformBomMaterialApiToFrontend), + createdAt: apiData.created_at, + updatedAt: apiData.updated_at, + createdBy: apiData.creator?.name || undefined, + updatedBy: apiData.updater?.name || undefined, + finalizedAt: apiData.finalized_at || undefined, + finalizedBy: apiData.finalizer?.name || undefined, + }; +} +``` + +### B.2 프론트엔드 → API 변환 (transformFormDataToApi) + +```typescript +// react/src/components/quotes/types.ts (핵심 부분) + +export function transformFormDataToApi(formData: QuoteFormData): Record { + let itemsData = []; + + // calculationResults가 있으면 BOM 자재 기반으로 items 생성 + if (formData.calculationResults && formData.calculationResults.items.length > 0) { + let sortOrder = 1; + formData.calculationResults.items.forEach((calcItem) => { + const formItem = formData.items[calcItem.index]; + const orderQuantity = formItem?.quantity || 1; + + calcItem.result.items.forEach((bomItem) => { + const baseQuantity = bomItem.quantity; + const calculatedQuantity = bomItem.unit === 'EA' + ? Math.round(baseQuantity * orderQuantity) + : parseFloat((baseQuantity * orderQuantity).toFixed(2)); + const totalPrice = bomItem.unit_price * calculatedQuantity; + + itemsData.push({ + item_name: bomItem.item_name, + item_code: bomItem.item_code, + specification: bomItem.specification || null, + unit: bomItem.unit || 'EA', + quantity: orderQuantity, + base_quantity: baseQuantity, + calculated_quantity: calculatedQuantity, + unit_price: bomItem.unit_price, + total_price: totalPrice, + sort_order: sortOrder++, + note: `${formItem?.floor || ''} ${formItem?.code || ''}`.trim() || null, + item_index: calcItem.index, + finished_goods_code: calcItem.result.finished_goods.code, + formula_category: bomItem.process_group || undefined, + }); + }); + }); + } else { + // 기존 로직: 완제품 기준 items 생성 + itemsData = formData.items.map((item, index) => ({ + item_name: item.productName, + item_code: item.productName, + specification: item.openWidth && item.openHeight + ? `${item.openWidth}x${item.openHeight}mm` : null, + unit: item.unit || '개소', + quantity: item.quantity, + base_quantity: 1, + calculated_quantity: item.quantity, + unit_price: item.unitPrice || item.inspectionFee || 0, + total_price: (item.unitPrice || item.inspectionFee || 0) * item.quantity, + sort_order: index + 1, + note: `${item.floor || ''} ${item.code || ''}`.trim() || null, + })); + } + + // 총액 계산 + const totalSupply = itemsData.reduce((sum, item) => sum + item.total_price, 0); + const totalTax = Math.round(totalSupply * 0.1); + const grandTotal = totalSupply + totalTax; + + // 자동산출 입력값 저장 + const calculationInputs = { + items: formData.items.map(item => ({ + productCategory: item.productCategory, + productName: item.productName, + openWidth: item.openWidth, + openHeight: item.openHeight, + guideRailType: item.guideRailType, + motorPower: item.motorPower, + controller: item.controller, + wingSize: item.wingSize, + inspectionFee: item.inspectionFee, + floor: item.floor, + code: item.code, + quantity: item.quantity, + })), + }; + + return { + registration_date: formData.registrationDate, + author: formData.writer || null, + client_id: formData.clientId ? parseInt(formData.clientId, 10) : null, + client_name: formData.clientName, + site_name: formData.siteName || null, + manager: formData.manager || null, + contact: formData.contact || null, + completion_date: formData.dueDate || null, + remarks: formData.remarks || null, + product_category: formData.items[0]?.productCategory?.toLowerCase() || 'screen', + quantity: formData.items.reduce((sum, item) => sum + item.quantity, 0), + unit_symbol: formData.unitSymbol || '개소', + total_amount: grandTotal, + calculation_inputs: calculationInputs, + items: itemsData, + }; +} +``` + +### B.3 Quote → QuoteFormData 변환 (transformQuoteToFormData) + +```typescript +// react/src/components/quotes/types.ts + +export function transformQuoteToFormData(quote: Quote): QuoteFormData { + const calcInputs = quote.calculationInputs?.items || []; + + // BOM 자재(quote.items)의 총 금액 계산 + const totalBomAmount = quote.items.reduce((sum, item) => sum + (item.totalAmount || 0), 0); + const itemCount = calcInputs.length || 1; + const amountPerItem = Math.round(totalBomAmount / itemCount); + + return { + id: quote.id, + registrationDate: formatDateForInput(quote.registrationDate), + writer: quote.createdBy || '', + clientId: quote.clientId, + clientName: quote.clientName, + siteName: quote.siteName || '', + manager: quote.managerName || '', + contact: quote.managerContact || '', + dueDate: formatDateForInput(quote.deliveryDate), + remarks: quote.description || '', + unitSymbol: quote.unitSymbol, + + // calculation_inputs.items가 있으면 그것으로 items 복원 + items: calcInputs.length > 0 + ? calcInputs.map((calcInput, index) => ({ + id: `temp-${index}`, + floor: calcInput.floor || '', + code: calcInput.code || '', + productCategory: calcInput.productCategory || '', + productName: calcInput.productName || '', + openWidth: calcInput.openWidth || '', + openHeight: calcInput.openHeight || '', + guideRailType: calcInput.guideRailType || '', + motorPower: calcInput.motorPower || '', + controller: calcInput.controller || '', + quantity: calcInput.quantity || 1, + unit: undefined, + wingSize: calcInput.wingSize || '50', + inspectionFee: calcInput.inspectionFee || 50000, + unitPrice: Math.round(amountPerItem / (calcInput.quantity || 1)), + totalAmount: amountPerItem, + })) + : quote.items.map((item) => ({ + id: item.id, + floor: '', + code: '', + productCategory: '', + productName: item.productName, + openWidth: '', + openHeight: '', + guideRailType: '', + motorPower: '', + controller: '', + quantity: item.quantity || 1, + unit: item.unit, + wingSize: '50', + inspectionFee: item.unitPrice || 50000, + unitPrice: item.unitPrice, + totalAmount: item.totalAmount, + })), + + bomMaterials: calcInputs.length > 0 + ? quote.items.map((item, index) => ({ + itemIndex: index, + finishedGoodsCode: '', + itemCode: item.itemCode || '', + itemName: item.productName, + itemType: '', + itemCategory: '', + specification: item.specification || '', + unit: item.unit || '', + quantity: item.quantity, + unitPrice: item.unitPrice, + totalPrice: item.totalAmount, + processType: '', + })) + : quote.bomMaterials, + }; +} + +// 날짜 형식 변환 헬퍼 +function formatDateForInput(dateStr: string | null | undefined): string { + if (!dateStr) return ''; + if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return dateStr; + const date = new Date(dateStr); + if (isNaN(date.getTime())) return ''; + return date.toISOString().split('T')[0]; +} +``` + +--- + +## 부록 C: V2 ↔ API 필드 매핑표 + +> 새 변환 함수 작성 시 참고할 필드 매핑 + +### C.1 견적 마스터 필드 매핑 + +| V2 필드 (QuoteFormDataV2) | API 필드 (QuoteApiData) | DB 컬럼 (quotes) | 비고 | +|--------------------------|------------------------|-----------------|------| +| `id` | `id` | `id` | string ↔ number 변환 | +| `registrationDate` | `registration_date` | `registration_date` | | +| `writer` | `author` / `creator.name` | `author` | 저장: author, 조회: creator.name | +| `clientId` | `client_id` | `client_id` | string ↔ number 변환 | +| `clientName` | `client_name` / `client.name` | `client_name` | | +| `siteName` | `site_name` | `site_name` | | +| `manager` | `manager` | `manager` | | +| `contact` | `contact` | `contact` | | +| `dueDate` | `completion_date` | `completion_date` | | +| `remarks` | `remarks` | `remarks` | | +| `status` | `status` | `status` | V2: draft/temporary/final ↔ API: draft/sent/.../finalized | +| `locations` | `items` + `calculation_inputs.items` | - | 복합 변환 필요 | + +### C.2 개소 항목 필드 매핑 + +| V2 필드 (LocationItem) | API calculation_inputs.items | API items | 비고 | +|-----------------------|----------------------------|-----------|------| +| `id` | - | `id` | | +| `floor` | `floor` | `note` (일부) | | +| `code` | `code` | `note` (일부) | | +| `openWidth` | `openWidth` | `specification` (파싱) | "3000x2500mm" 형식 | +| `openHeight` | `openHeight` | `specification` (파싱) | | +| `productCode` | - | `finished_goods_code` | BOM 산출 시 사용 | +| `productName` | `productName` | `item_name` | | +| `quantity` | `quantity` | `quantity` | 주문 수량 | +| `guideRailType` | `guideRailType` | - | calculation_inputs에만 저장 | +| `motorPower` | `motorPower` | - | | +| `controller` | `controller` | - | | +| `wingSize` | `wingSize` | - | | +| `inspectionFee` | `inspectionFee` | - | | +| `unitPrice` | - | `unit_price` | | +| `totalPrice` | - | `total_price` | | + +### C.3 상태값 매핑 + +| V2 status | API status | 설명 | +|-----------|-----------|------| +| `draft` | `draft`, `sent`, `approved`, `rejected` | 작성중/진행중 | +| `temporary` | - | V2 전용 (임시저장) → API에는 `draft`로 저장 | +| `final` | `finalized`, `converted` | 최종확정/수주전환 | + +--- + +## 부록 D: 테스트 명령어 + +> Docker 환경에서 테스트하는 방법 + +### D.1 서비스 확인 + +```bash +# Docker 서비스 상태 확인 +cd /Users/kent/Works/@KD_SAM/SAM +docker compose ps + +# API 서버 로그 확인 +docker compose logs -f api + +# React 개발 서버 로그 확인 +docker compose logs -f react +``` + +### D.2 API 직접 테스트 + +```bash +# 견적 목록 조회 +curl -X GET "http://api.sam.kr/api/v1/quotes" \ + -H "Authorization: Bearer {TOKEN}" \ + -H "Accept: application/json" + +# 견적 상세 조회 +curl -X GET "http://api.sam.kr/api/v1/quotes/{ID}" \ + -H "Authorization: Bearer {TOKEN}" \ + -H "Accept: application/json" + +# 견적 생성 (예시) +curl -X POST "http://api.sam.kr/api/v1/quotes" \ + -H "Authorization: Bearer {TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{ + "registration_date": "2026-01-26", + "client_name": "테스트 발주처", + "site_name": "테스트 현장", + "product_category": "screen", + "quantity": 1, + "total_amount": 1000000, + "items": [] + }' +``` + +### D.3 브라우저 테스트 URL + +``` +# V1 (기존) +http://dev.sam.kr/sales/quote-management # 목록 +http://dev.sam.kr/sales/quote-management?mode=new # 등록 +http://dev.sam.kr/sales/quote-management/1 # 상세 +http://dev.sam.kr/sales/quote-management/1?mode=edit # 수정 + +# V2 (신규 - 테스트) +http://dev.sam.kr/sales/quote-management/test-new # 등록 +http://dev.sam.kr/sales/quote-management/test/1 # 상세 +http://dev.sam.kr/sales/quote-management/test/1?mode=edit # 수정 +``` + +### D.4 디버깅 + +```bash +# React 콘솔 로그 확인 (브라우저 개발자 도구) +# [QuoteActions] 접두사로 API 요청/응답 확인 + +# API 디버그 로그 확인 +docker compose exec api tail -f storage/logs/laravel.log +``` + +--- + +## 부록 E: V2 변환 함수 구현 가이드 + +> Phase 1.1에서 구현할 함수 상세 가이드 + +### E.1 transformV2ToApi 구현 + +```typescript +// react/src/components/quotes/types.ts에 추가 + +import type { QuoteFormDataV2, LocationItem } from './QuoteRegistrationV2'; + +/** + * V2 폼 데이터 → API 요청 형식 변환 + * + * 핵심 차이점: + * - V2는 locations[] 배열, API는 items[] + calculation_inputs.items[] 구조 + * - V2 status는 3가지, API status는 6가지 + * - BOM 산출 결과가 있으면 items에 자재 상세 포함 + */ +export function transformV2ToApi( + data: QuoteFormDataV2, + bomResults?: BomCalculationResult[] +): Record { + + // 1. calculation_inputs 생성 (폼 복원용) + const calculationInputs = { + items: data.locations.map(loc => ({ + productCategory: 'screen', // TODO: 실제 카테고리 + productName: loc.productName, + openWidth: String(loc.openWidth), + openHeight: String(loc.openHeight), + guideRailType: loc.guideRailType, + motorPower: loc.motorPower, + controller: loc.controller, + wingSize: String(loc.wingSize), + inspectionFee: loc.inspectionFee, + floor: loc.floor, + code: loc.code, + quantity: loc.quantity, + })), + }; + + // 2. items 생성 (BOM 결과 있으면 자재 상세, 없으면 완제품 기준) + let items: Array> = []; + + if (bomResults && bomResults.length > 0) { + // BOM 자재 기반 + let sortOrder = 1; + bomResults.forEach((bomResult, locIndex) => { + const loc = data.locations[locIndex]; + const orderQty = loc?.quantity || 1; + + bomResult.items.forEach(bomItem => { + const baseQty = bomItem.quantity; + const calcQty = bomItem.unit === 'EA' + ? Math.round(baseQty * orderQty) + : parseFloat((baseQty * orderQty).toFixed(2)); + + items.push({ + item_name: bomItem.item_name, + item_code: bomItem.item_code, + specification: bomItem.specification || null, + unit: bomItem.unit || 'EA', + quantity: orderQty, + base_quantity: baseQty, + calculated_quantity: calcQty, + unit_price: bomItem.unit_price, + total_price: bomItem.unit_price * calcQty, + sort_order: sortOrder++, + note: `${loc?.floor || ''} ${loc?.code || ''}`.trim() || null, + item_index: locIndex, + finished_goods_code: bomResult.finished_goods.code, + formula_category: bomItem.process_group || undefined, + }); + }); + }); + } else { + // 완제품 기준 (BOM 산출 전) + items = data.locations.map((loc, index) => ({ + item_name: loc.productName, + item_code: loc.productCode, + specification: `${loc.openWidth}x${loc.openHeight}mm`, + unit: '개소', + quantity: loc.quantity, + base_quantity: 1, + calculated_quantity: loc.quantity, + unit_price: loc.unitPrice || loc.inspectionFee || 0, + total_price: loc.totalPrice || (loc.unitPrice || loc.inspectionFee || 0) * loc.quantity, + sort_order: index + 1, + note: `${loc.floor} ${loc.code}`.trim() || null, + })); + } + + // 3. 총액 계산 + const totalSupply = items.reduce((sum, item) => sum + (item.total_price as number), 0); + const totalTax = Math.round(totalSupply * 0.1); + const grandTotal = totalSupply + totalTax; + + // 4. API 요청 객체 반환 + return { + registration_date: data.registrationDate, + author: data.writer || null, + client_id: data.clientId ? parseInt(data.clientId, 10) : null, + client_name: data.clientName, + site_name: data.siteName || null, + manager: data.manager || null, + contact: data.contact || null, + completion_date: data.dueDate || null, + remarks: data.remarks || null, + product_category: 'screen', // TODO: 동적으로 결정 + quantity: data.locations.reduce((sum, loc) => sum + loc.quantity, 0), + unit_symbol: '개소', + total_amount: grandTotal, + status: data.status === 'final' ? 'finalized' : 'draft', + calculation_inputs: calculationInputs, + items: items, + }; +} +``` + +### E.2 transformApiToV2 구현 + +```typescript +/** + * API 응답 → V2 폼 데이터 변환 + * + * 핵심: + * - calculation_inputs.items가 있으면 그것으로 locations 복원 + * - 없으면 items에서 추출 시도 (레거시 호환) + */ +export function transformApiToV2(apiData: QuoteApiData): QuoteFormDataV2 { + const calcInputs = apiData.calculation_inputs?.items || []; + + // calculation_inputs에서 locations 복원 + const locations: LocationItem[] = calcInputs.length > 0 + ? calcInputs.map((ci, index) => { + // 해당 인덱스의 BOM 자재에서 금액 계산 + const relatedItems = (apiData.items || []).filter( + item => item.item_index === index || item.note?.includes(ci.floor || '') + ); + const totalPrice = relatedItems.reduce( + (sum, item) => sum + parseFloat(String(item.total_price || 0)), 0 + ); + const qty = ci.quantity || 1; + + return { + id: `loc-${index}`, + floor: ci.floor || '', + code: ci.code || '', + openWidth: parseInt(ci.openWidth || '0', 10), + openHeight: parseInt(ci.openHeight || '0', 10), + productCode: '', // TODO: finished_goods_code에서 추출 + productName: ci.productName || '', + quantity: qty, + guideRailType: ci.guideRailType || 'wall', + motorPower: ci.motorPower || 'single', + controller: ci.controller || 'basic', + wingSize: parseInt(ci.wingSize || '50', 10), + inspectionFee: ci.inspectionFee || 50000, + unitPrice: Math.round(totalPrice / qty), + totalPrice: totalPrice, + }; + }) + : []; // TODO: items에서 복원 로직 추가 + + // 상태 매핑 + const mapStatus = (s: string): 'draft' | 'temporary' | 'final' => { + if (s === 'finalized' || s === 'converted') return 'final'; + return 'draft'; + }; + + return { + id: String(apiData.id), + registrationDate: formatDateForInput(apiData.registration_date), + writer: apiData.creator?.name || '', + clientId: apiData.client_id ? String(apiData.client_id) : '', + clientName: apiData.client?.name || apiData.client_name || '', + siteName: apiData.site_name || '', + manager: apiData.manager || apiData.manager_name || '', + contact: apiData.contact || apiData.manager_contact || '', + dueDate: formatDateForInput(apiData.completion_date || apiData.delivery_date), + remarks: apiData.remarks || apiData.description || '', + status: mapStatus(apiData.status), + locations: locations, + }; +} +``` + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다. (2026-01-26 보완)* \ No newline at end of file