diff --git a/config/config_system.py b/config/config_system.py index a9c528dc..e870fa96 100644 --- a/config/config_system.py +++ b/config/config_system.py @@ -21,7 +21,7 @@ SERVER_PORT = int(os.getenv("SERVER_PORT", "8000")) DEBUG = os.getenv("DEBUG", "False").lower() == "true" # 정적 파일 서빙 (프론트엔드 빌드 결과) -STATIC_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "node_modules", ".build") +STATIC_DIR = os.path.join(os.path.dirname(__file__), "node_modules", ".build") STATIC_URL = "/static" # ───────────────────────────────────────────────────────────────────────── diff --git a/graphify-out/manifest.json b/graphify-out/manifest.json index 564dc9a3..9eb7cbbd 100644 --- a/graphify-out/manifest.json +++ b/graphify-out/manifest.json @@ -10,8 +10,8 @@ "semantic_hash": "" }, "docs/wiki/concepts/a00_app_shell_framework.md": { - "mtime": 1784259049.8622963, - "ast_hash": "56c3c5418a6a54f89afe3732cadaaaec", + "mtime": 1784369023.0, + "ast_hash": "1a73aa816dd5e4270ae6bf8e0ede0b97", "semantic_hash": "" }, "docs/wiki/concepts/a00_app_shell_framework_scaffold.md": { @@ -25,62 +25,62 @@ "semantic_hash": "" }, "docs/wiki/concepts/auth_rbac.md": { - "mtime": 1784259833.4644027, + "mtime": 1784259833.0, "ast_hash": "2c6ad199f866257eca3bec738fcf5f3d", "semantic_hash": "" }, "docs/wiki/concepts/common_util.md": { - "mtime": 1784259848.5701928, - "ast_hash": "941f7272498ffc25ba1deeb94c9c37b3", + "mtime": 1784365180.0, + "ast_hash": "c8a50d203fa7f0d12e562dc9dd077e95", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/files_surface.md": { - "mtime": 1784267731.9194815, + "mtime": 1784267731.0, "ast_hash": "7025d41c372c169b7929ed6baca3b07f", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/logs_monitoring.md": { - "mtime": 1784259355.6293466, - "ast_hash": "d394ba4d2cb09a6651f574352750eba0", + "mtime": 1784348499.0, + "ast_hash": "aaca07904f047b3e583e8cabc5187ecf", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/overview.md": { - "mtime": 1784259347.9511518, + "mtime": 1784259347.0, "ast_hash": "8f35d8e4f659eee10ef9e01411cdc079", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/projects.md": { - "mtime": 1784259359.3317523, + "mtime": 1784259359.0, "ast_hash": "f037e166e7b72002dfa3c7552a0eae43", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/route_profile.md": { - "mtime": 1784259366.082059, + "mtime": 1784259366.0, "ast_hash": "9ba725f36208f26e1c8d0d9f6179325c", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/structure_output.md": { - "mtime": 1784259369.8867612, + "mtime": 1784259369.0, "ast_hash": "92adeedeb94bb3b75b0ba4a42c75ea15", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/unconfirmed/README.md": { - "mtime": 1784259342.919075, + "mtime": 1784259342.0, "ast_hash": "14b964e21ad8705d3fb2c6c818f71750", "semantic_hash": "" }, "docs/wiki/concepts/db_schema/users_auth.md": { - "mtime": 1784259859.5247, + "mtime": 1784259859.0, "ast_hash": "4252d7048a05615e6420fb2853567323", "semantic_hash": "" }, "docs/wiki/concepts/dependencies.md": { - "mtime": 1783850549.0, - "ast_hash": "93732554454116e3543ac2269b9d1f0d", + "mtime": 1784353789.0, + "ast_hash": "c9945009d6cf41f9b9bdc95ed6f31804", "semantic_hash": "" }, "docs/wiki/concepts/design.md": { - "mtime": 1784260030.4069157, + "mtime": 1784260030.0, "ast_hash": "85aec17d904c548e299a4e3810669cc0", "semantic_hash": "" }, @@ -90,28 +90,28 @@ "semantic_hash": "" }, "docs/wiki/concepts/storage_paths.md": { - "mtime": 1784276227.6785357, + "mtime": 1784276227.0, "ast_hash": "a0fe28424a580b6dce5ddbcb66f886e5", "semantic_hash": "" }, "docs/wiki/concepts/ui_templates.md": { - "mtime": 1784264934.0988722, + "mtime": 1784264934.0, "ast_hash": "6cb21cb237d90125d149b1db904a2d74", "semantic_hash": "" }, "docs/wiki/concepts/workflow_state.md": { - "mtime": 1784267747.180053, - "ast_hash": "c1fa859f4d19cea7059daf828b29a41e", + "mtime": 1784367329.0, + "ast_hash": "7c52330d044d3d1cf1bcd06404d64cd8", "semantic_hash": "" }, "docs/wiki/index.md": { - "mtime": 1784273610.479596, - "ast_hash": "635b063e8e9d1e504fa08e04f6e6673f", + "mtime": 1784376234.2042696, + "ast_hash": "fc1c8a3a02abfcf9821f1581b3fe7109", "semantic_hash": "" }, "docs/wiki/log.md": { - "mtime": 1784281064.938371, - "ast_hash": "d0a674d4bde81eea7e8bd2edf76d6287", + "mtime": 1784376236.3120687, + "ast_hash": "cf9f6ba825c065b8c23c481320439afe", "semantic_hash": "" }, "docs/wiki/pages/A01_Home/A01_components.md": { @@ -150,17 +150,17 @@ "semantic_hash": "" }, "docs/wiki/pages/A06_Login/A06_backend.md": { - "mtime": 1784259816.2009697, + "mtime": 1784259816.0, "ast_hash": "8ff447e9f595b09ab8706e6b2153c2e4", "semantic_hash": "" }, "docs/wiki/pages/A06_Login/A06_frontend.md": { - "mtime": 1784259825.8575397, + "mtime": 1784259825.0, "ast_hash": "b77699e691f04c97e2676b56a978d441", "semantic_hash": "" }, "docs/wiki/pages/A07_Register/A07_backend.md": { - "mtime": 1784259843.9720101, + "mtime": 1784259843.0, "ast_hash": "b2ba632dc7648b9925828c57fb94073f", "semantic_hash": "" }, @@ -190,12 +190,12 @@ "semantic_hash": "" }, "docs/wiki/pages/B01_Dashboard/B01_api.md": { - "mtime": 1784259230.2413194, + "mtime": 1784259230.0, "ast_hash": "cec23a7fa764aa9cb89ca556386a9d1e", "semantic_hash": "" }, "docs/wiki/pages/B01_Dashboard/B01_backend.md": { - "mtime": 1784259865.0189633, + "mtime": 1784259865.0, "ast_hash": "d3a676bc366985ef5ec949ae15a3d3cf", "semantic_hash": "" }, @@ -205,12 +205,12 @@ "semantic_hash": "" }, "docs/wiki/pages/B01_Dashboard/B01_dependencies.md": { - "mtime": 1784259237.7637663, + "mtime": 1784259237.0, "ast_hash": "b772aa70b5f90deb37c5324f93d79a80", "semantic_hash": "" }, "docs/wiki/pages/B01_Dashboard/B01_frontend.md": { - "mtime": 1784264944.284991, + "mtime": 1784264944.0, "ast_hash": "720d69c49dce55121af9846763aa3258", "semantic_hash": "" }, @@ -230,13 +230,13 @@ "semantic_hash": "" }, "docs/wiki/pages/B03_FileInput/B03_api.md": { - "mtime": 1784259243.9075582, + "mtime": 1784259243.0, "ast_hash": "96a8eb8ea278e761ddf0a3a0e2693728", "semantic_hash": "" }, "docs/wiki/pages/B03_FileInput/B03_backend.md": { - "mtime": 1784259247.156907, - "ast_hash": "2955910cfa45dad1e46c7a4141c779d6", + "mtime": 1784355935.0, + "ast_hash": "5b3c655277dabf98fcd8ab99ff2fccca", "semantic_hash": "" }, "docs/wiki/pages/B03_FileInput/B03_db.md": { @@ -245,88 +245,88 @@ "semantic_hash": "" }, "docs/wiki/pages/B03_FileInput/B03_dependencies.md": { - "mtime": 1784259157.4293892, + "mtime": 1784259157.0, "ast_hash": "8ba6d765120bd79067f87dad58605dba", "semantic_hash": "" }, "docs/wiki/pages/B03_FileInput/B03_frontend.md": { - "mtime": 1784264939.1710696, + "mtime": 1784264939.0, "ast_hash": "ff5b954b7136ca7f73c842965240400c", "semantic_hash": "" }, "docs/wiki/pages/B04_wf1_Surface/B04_api.md": { - "mtime": 1784281082.294356, - "ast_hash": "688e57fa31f595d8a2eb50fe1534bae8", + "mtime": 1784348304.0, + "ast_hash": "0c432552116e17dabb23da60e6500c0c", "semantic_hash": "" }, "docs/wiki/pages/B04_wf1_Surface/B04_backend.md": { - "mtime": 1784281075.9390342, - "ast_hash": "179006cfa5579947f12703de677b9178", + "mtime": 1784367346.0, + "ast_hash": "27103f91f214fc48dbbdc3402a66598d", "semantic_hash": "" }, "docs/wiki/pages/B04_wf1_Surface/B04_db.md": { - "mtime": 1784267041.957495, - "ast_hash": "50541e6a765c96c40cb34856acc29900", + "mtime": 1784348536.0, + "ast_hash": "26728221e5e83fc1d551535e0fb33bb2", "semantic_hash": "" }, "docs/wiki/pages/B04_wf1_Surface/B04_dependencies.md": { - "mtime": 1783849775.0, - "ast_hash": "15bd0faa0411264c14b0bbd89f7afd46", + "mtime": 1784353769.0, + "ast_hash": "9a6ce9a740a181df1c79d3f336664312", "semantic_hash": "" }, "docs/wiki/pages/B04_wf1_Surface/B04_frontend.md": { - "mtime": 1784278834.8752944, + "mtime": 1784278834.0, "ast_hash": "bb89b16cc5a0d9763cb26c174a537f54", "semantic_hash": "" }, "docs/wiki/pages/B05_wf2_Route/B05_api.md": { - "mtime": 1784259165.6230073, - "ast_hash": "1eeb9b6e80f8a2122b61714669b85e1b", + "mtime": 1784367356.0, + "ast_hash": "e9160c380be1ae99eab6a0459a6e9c4e", "semantic_hash": "" }, "docs/wiki/pages/B05_wf2_Route/B05_backend.md": { - "mtime": 1784259169.115432, - "ast_hash": "50c0d1a2d67fbe66e3885cabae81d6cf", + "mtime": 1784367351.0, + "ast_hash": "601af33ffeac30c1eb81253e62978fe7", "semantic_hash": "" }, "docs/wiki/pages/B05_wf2_Route/B05_db.md": { - "mtime": 1783850658.0, - "ast_hash": "c45788b5db47a7a4f246b0714a2c11e3", + "mtime": 1784365771.0, + "ast_hash": "5e3577c18b306e2a0f1ff2ebf482ccf7", "semantic_hash": "" }, "docs/wiki/pages/B05_wf2_Route/B05_dependencies.md": { - "mtime": 1784259171.929299, - "ast_hash": "96757fcd55e66155d680aa611106b5ce", + "mtime": 1784353784.0, + "ast_hash": "203966b0f821d11a133db6954918b843", "semantic_hash": "" }, "docs/wiki/pages/B05_wf2_Route/B05_frontend.md": { - "mtime": 1784267722.8724308, - "ast_hash": "f72755ed7acf8a7450feac8323fad91c", + "mtime": 1784369027.0, + "ast_hash": "6f17f638d6829f29b66d451c985d6c74", "semantic_hash": "" }, "docs/wiki/pages/B06_wf3_ProfileCross/B06_api.md": { - "mtime": 1784259175.4055898, - "ast_hash": "a5989dca5de549ea7084f4291b554275", + "mtime": 1784376219.635943, + "ast_hash": "880164c5d0ff8fc2046706f6fe62f6f7", "semantic_hash": "" }, "docs/wiki/pages/B06_wf3_ProfileCross/B06_backend.md": { - "mtime": 1784259178.6757984, - "ast_hash": "5a0495ebd2ba0f22c5e87703572ad1ae", + "mtime": 1784376226.78404, + "ast_hash": "269f5d26ec2e7d08a595548ddef63009", "semantic_hash": "" }, "docs/wiki/pages/B06_wf3_ProfileCross/B06_db.md": { - "mtime": 1783850703.0, - "ast_hash": "63b1c8f0287b4b277633da8c4617b03f", + "mtime": 1784376231.4393904, + "ast_hash": "2f7dd1a4d9491782d9e87a62a8099d91", "semantic_hash": "" }, "docs/wiki/pages/B06_wf3_ProfileCross/B06_dependencies.md": { - "mtime": 1784259182.2659357, + "mtime": 1784259182.0, "ast_hash": "1033c52fc6823211db0690aafa706a83", "semantic_hash": "" }, "docs/wiki/pages/B06_wf3_ProfileCross/B06_frontend.md": { - "mtime": 1784264958.5574062, - "ast_hash": "edc082e6e035ebea9f7427393c8c863f", + "mtime": 1784376229.6672938, + "ast_hash": "7443a5902c1d4094d0b92d7639cd0120", "semantic_hash": "" }, "docs/wiki/pages/B07_wf4_DesignDetail/B07_frontend.md": { @@ -340,7 +340,7 @@ "semantic_hash": "" }, "docs/wiki/pages/B08_wf5_Quantity/B08_frontend.md": { - "mtime": 1784280350.6155877, + "mtime": 1784280350.0, "ast_hash": "82f0c3c8358a8f6b16395623d73f049f", "semantic_hash": "" }, @@ -350,13 +350,823 @@ "semantic_hash": "" }, "docs/wiki/pages/B10_Payment/B10_frontend.md": { - "mtime": 1784264923.3316023, + "mtime": 1784264923.0, "ast_hash": "922e565933ffcf90a3fa96307ae4dee3", "semantic_hash": "" }, "docs/wiki/pages/B11_Status/B11_frontend.md": { - "mtime": 1784264926.0308616, + "mtime": 1784264926.0, "ast_hash": "2cf11aa66d6346818c14c62fa8e2b12a", "semantic_hash": "" + }, + "A00_Common/.vite/deps/_metadata.json": { + "mtime": 1783416979.0, + "ast_hash": "48dd460763d1ba0111894f0f54fd2e63", + "semantic_hash": "" + }, + "A00_Common/.vite/deps/package.json": { + "mtime": 1783416979.0, + "ast_hash": "d0707362e90f00edd12435e9d3b9d71c", + "semantic_hash": "" + }, + "A00_Common/app_shell.ts": { + "mtime": 1784371862.691931, + "ast_hash": "4dacd9bd2c3c9552e5878c23df1069c5", + "semantic_hash": "" + }, + "A00_Common/b_page_scaffold.ts": { + "mtime": 1784371862.692441, + "ast_hash": "ba19266140129680b55b16659cdeca4b", + "semantic_hash": "" + }, + "A00_Common/b_workflow_nav.ts": { + "mtime": 1784371862.6932194, + "ast_hash": "15ffdd7d709c6f2b05782d3176347df0", + "semantic_hash": "" + }, + "A00_Common/main.ts": { + "mtime": 1784371862.6942656, + "ast_hash": "e70d2865f735eac9726efd78d7ed0c10", + "semantic_hash": "" + }, + "A00_Common/router.ts": { + "mtime": 1783505305.0, + "ast_hash": "3a07e5a021c346f6a511915f055922d7", + "semantic_hash": "" + }, + "A00_Common/vite-env.d.ts": { + "mtime": 1783234299.818669, + "ast_hash": "0352474ba2918efe13895edbc3780d94", + "semantic_hash": "" + }, + "A01_Home/A01_Home_UI_Page.ts": { + "mtime": 1783423100.0, + "ast_hash": "28b950204c23ad5d84d70136ea566b38", + "semantic_hash": "" + }, + "A02_ProgDetail/A02_ProgDetail_UI_Page.ts": { + "mtime": 1783237318.848724, + "ast_hash": "718c5537d87bebf0806019a11e815068", + "semantic_hash": "" + }, + "A03_CompDetail/A03_CompDetail_UI_Page.ts": { + "mtime": 1783237445.9769812, + "ast_hash": "85e6b5449bacfda98ae58026fa86882c", + "semantic_hash": "" + }, + "A04_NewsHistory/A04_NewsHistory_UI_Page.ts": { + "mtime": 1783237480.2490423, + "ast_hash": "4049d7e7ddcac64effcbbfa368fccfca", + "semantic_hash": "" + }, + "A05_EduDetail/A05_EduDetail_UI_Page.ts": { + "mtime": 1783237514.488196, + "ast_hash": "649868a7b8c71a64db80d1c398700a32", + "semantic_hash": "" + }, + "A06_Login/A06_Login_Api_Fetch.ts": { + "mtime": 1783421640.0, + "ast_hash": "85da5f81a01e70def7e211066ddec9c7", + "semantic_hash": "" + }, + "A06_Login/A06_Login_Router.py": { + "mtime": 1784371862.6952658, + "ast_hash": "25d3b98295ece2998add42d5b02d5da4", + "semantic_hash": "" + }, + "A06_Login/A06_Login_Schema.py": { + "mtime": 1783414472.0, + "ast_hash": "4001c066f5df2f7f90ce13167987f8bc", + "semantic_hash": "" + }, + "A06_Login/A06_Login_UI_Auth_Page.ts": { + "mtime": 1784371862.696359, + "ast_hash": "ecf3be6b6c74e4f49821eb39a44733ec", + "semantic_hash": "" + }, + "A07_Register/A07_Register_Api_Fetch.ts": { + "mtime": 1783421546.0, + "ast_hash": "1342286656a4bc7b26f3f3ab9fba2bbc", + "semantic_hash": "" + }, + "A07_Register/A07_Register_Router.py": { + "mtime": 1784371862.699004, + "ast_hash": "70a5256a2f78ad08a5a2f072bfc9e3f8", + "semantic_hash": "" + }, + "A07_Register/A07_Register_Schema.py": { + "mtime": 1783421495.0, + "ast_hash": "af7b0ddfaaf442781d754840b81ce59c", + "semantic_hash": "" + }, + "A07_Register/A07_Register_UI_Auth_Page.ts": { + "mtime": 1783421565.0, + "ast_hash": "daf482fe0f4146dc0f6403f5a99e4b82", + "semantic_hash": "" + }, + "A07_Register/A07_Register_UI_Page.ts": { + "mtime": 1783237673.7577379, + "ast_hash": "b911eae7a57cc1b24ae71a1fdf20bb98", + "semantic_hash": "" + }, + "A08_Support/A08_Support_Router.py": { + "mtime": 1783418906.0, + "ast_hash": "c490d0a41c3616db1f221e19d07017fb", + "semantic_hash": "" + }, + "A08_Support/A08_Support_Schema.py": { + "mtime": 1783418883.0, + "ast_hash": "e6ab097405511ec7585588e9b899d04d", + "semantic_hash": "" + }, + "A08_Support/A08_Support_UI_Page.ts": { + "mtime": 1783418988.0, + "ast_hash": "a4eb30df878f52e004fc7c03496ff57c", + "semantic_hash": "" + }, + "A09_Security/A09_Security_Api_Fetch.ts": { + "mtime": 1783415135.0, + "ast_hash": "4e3e8642ac23d07167094833b7762ae4", + "semantic_hash": "" + }, + "A09_Security/A09_Security_Router.py": { + "mtime": 1783415590.0, + "ast_hash": "188d62cf69fb770bb24423183cf7e4d8", + "semantic_hash": "" + }, + "A09_Security/A09_Security_Schema.py": { + "mtime": 1783415590.0, + "ast_hash": "27f6edbb97e74f9ec3615f34de2227b9", + "semantic_hash": "" + }, + "A09_Security/A09_Security_Terms.ts": { + "mtime": 1783414968.0, + "ast_hash": "d1ca33930803139d39382b8e02f6b5eb", + "semantic_hash": "" + }, + "A09_Security/A09_Security_UI_Page.ts": { + "mtime": 1783414968.0, + "ast_hash": "af0ada0cd6b3df7a3ebd2b00960b6216", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_Api_Fetch.ts": { + "mtime": 1784371862.7001457, + "ast_hash": "860ee6c6f184622e1d821949d00ff2cb", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_Repository.py": { + "mtime": 1784371862.7011478, + "ast_hash": "6b934081cb58e13bab33f6a6435e2c61", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_Router.py": { + "mtime": 1784371862.7022014, + "ast_hash": "bf9add5702a4cd8d3cb68b8c1f492774", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_Schema.py": { + "mtime": 1784371862.703229, + "ast_hash": "6d4cb5d264f6172e6c7d89493bc0ff6f", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Admin.ts": { + "mtime": 1784371862.703229, + "ast_hash": "97788f7b9050d62e411aab5ed2051858", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Common.ts": { + "mtime": 1784371862.703229, + "ast_hash": "0efca669a90f90a49fe0e2592c5bd162", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Company.ts": { + "mtime": 1784371862.7044973, + "ast_hash": "bf5db444b8531633ef2ad4c9e77eb931", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Helper.ts": { + "mtime": 1784371862.7056584, + "ast_hash": "2c6b3f845142f02687f401f86c901f8a", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Modals.ts": { + "mtime": 1784371862.706769, + "ast_hash": "393432ccf162ec6077541a03d727d7ae", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Page.ts": { + "mtime": 1784371862.707793, + "ast_hash": "62116ab40530d9f091c87fd16a452ddf", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Profile.ts": { + "mtime": 1784371862.707793, + "ast_hash": "a20c529b0c9835d6a7fcecc3cf4a2909", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Projects.ts": { + "mtime": 1784371862.7088647, + "ast_hash": "5cefe93aac7b392130bad296b7546647", + "semantic_hash": "" + }, + "B01_Dashboard/B01_Dashboard_UI_Resources.ts": { + "mtime": 1783587686.6291425, + "ast_hash": "3054f93fbf865e06edc7032d01bd9820", + "semantic_hash": "" + }, + "B02_ProjRegister/B02_ProjRegister_Repository.py": { + "mtime": 1783677088.0, + "ast_hash": "b5b9f982f6407cf25efdffe176c71502", + "semantic_hash": "" + }, + "B02_ProjRegister/B02_ProjRegister_Router.py": { + "mtime": 1783589237.4005332, + "ast_hash": "c91200b99e61930e8254943b7491ded5", + "semantic_hash": "" + }, + "B02_ProjRegister/B02_ProjRegister_Schema.py": { + "mtime": 1783589165.0666614, + "ast_hash": "cccc5f9402eb04efecba085056bb0d2a", + "semantic_hash": "" + }, + "B02_ProjRegister/B02_ProjRegister_UI_Page.ts": { + "mtime": 1783589195.3898335, + "ast_hash": "0e8ab1a73347615578d117e36bf00994", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Api_Fetch.ts": { + "mtime": 1783672626.0, + "ast_hash": "511c359bd81f6f597d63c64a9a7a945d", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Email.py": { + "mtime": 1783599110.3864007, + "ast_hash": "6d19915b85a7b3d2109b7c2dc1ea1edb", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Engine.py": { + "mtime": 1783596209.3112216, + "ast_hash": "d0cf33b03272162dd4b688cf6ad72d73", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Engine_Analyze.py": { + "mtime": 1784371862.7103398, + "ast_hash": "76f7d75cc2dc5d8041a432f4e1568d19", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Repository.py": { + "mtime": 1783596239.7588317, + "ast_hash": "aaa288c15de5edb3719a9d7be9f5f973", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Router.py": { + "mtime": 1784371862.7118456, + "ast_hash": "68c5829f62c0e08124712810d8c5bf1c", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Schema.py": { + "mtime": 1783596181.187815, + "ast_hash": "64b068e7072e95395379b19caed40b8b", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_ServiceWorker.ts": { + "mtime": 1783596513.025032, + "ast_hash": "e42186f9d15ec1022bc00322882ea278", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_Service_WF1.py": { + "mtime": 1784371862.712557, + "ast_hash": "32e9a57eb4937a35e8acf00ad7005604", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_State.ts": { + "mtime": 1783674025.0, + "ast_hash": "4e43c9e52c0aabc140ed931e18478713", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_UI_Page.ts": { + "mtime": 1784371862.7130625, + "ast_hash": "c359a6ddd091e58c469c14deeac1ad5a", + "semantic_hash": "" + }, + "B03_FileInput/B03_FileInput_UI_Support.ts": { + "mtime": 1784371862.7130625, + "ast_hash": "64d2b28e0423f02c4e51ca787fd83db3", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Api_Fetch.ts": { + "mtime": 1784371862.7145033, + "ast_hash": "5fb65b6de4a6b46751f6c12fc448a1bc", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine.py": { + "mtime": 1784371862.7155347, + "ast_hash": "0c3272f97684405915c78b1f9c7ae528", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Contour.py": { + "mtime": 1784371862.7165349, + "ast_hash": "abd2f8a4ed17156d736d0741bc10a89f", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Filter_CSF.py": { + "mtime": 1783250545.7624342, + "ast_hash": "c3456ef16f6d99f5d0764d305d4c850c", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Filter_Grid.py": { + "mtime": 1783248229.843674, + "ast_hash": "413f95f0cbef48fe62dd3cb782954a3d", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Filter_PMF.py": { + "mtime": 1783250767.5307772, + "ast_hash": "3dd1f0fac27923be68cd2b01e2795e44", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Filter_RANSAC.py": { + "mtime": 1783250896.4425025, + "ast_hash": "aae25c9f6cbad2d42e1d22849087c45d", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_GisVector.py": { + "mtime": 1783681631.0, + "ast_hash": "91bc7fda7ec2c74767932447baec3667", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Ground.py": { + "mtime": 1783251572.58446, + "ast_hash": "ba1b1907e032c7fa0e6be6c90a4f73dd", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_ModelBuild.py": { + "mtime": 1783251412.31927, + "ast_hash": "d820a4619914343447b4b7de5d07ca55", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_ModelContext.py": { + "mtime": 1783251412.31927, + "ast_hash": "fb2e12ad33d430eadea2b654fbdea743", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_MvtHelper.py": { + "mtime": 1783681628.0, + "ast_hash": "5d69eca55395f9c145005e08861885c7", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Pipeline.py": { + "mtime": 1784371862.7170405, + "ast_hash": "9f1a6940a925f3d15b2e000b9848de0a", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Smooth.py": { + "mtime": 1783251412.318266, + "ast_hash": "86ddc5c95cb5d0b87ff6eca3f8b221a6", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_Structurize.py": { + "mtime": 1783248152.672701, + "ast_hash": "5b8bc35b11bd89f08f84131a0e81fd15", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Engine_VWorld.py": { + "mtime": 1783681604.0, + "ast_hash": "4100383b096bc40aea3e0721842b60bd", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Repository.py": { + "mtime": 1784371862.718252, + "ast_hash": "eed0e7887079837955600414134020b2", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Router.py": { + "mtime": 1784371862.7196527, + "ast_hash": "40deb5df719ce75a736e4c2f7aec6dfb", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Router_Contour.py": { + "mtime": 1784371862.7208662, + "ast_hash": "43878b93ae7c45d097465fe9013c9ba3", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Router_GIS.py": { + "mtime": 1784371862.7208662, + "ast_hash": "8f35831abd7534830b89b822e48d9572", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Schema.py": { + "mtime": 1784371862.7220292, + "ast_hash": "078bc37f1b87e46c0eba18de11e66059", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_Service.py": { + "mtime": 1784371862.7220292, + "ast_hash": "aff25d583a061a427be88b25bbde0a70", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_UI_Camera.ts": { + "mtime": 1784371862.723084, + "ast_hash": "28e87065fe59f2917e7c4a165a1cb171", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_UI_MapViewer.ts": { + "mtime": 1784371862.723084, + "ast_hash": "5dd35a1dbf882ec182f5497066be252c", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_UI_Page.ts": { + "mtime": 1784371862.7244713, + "ast_hash": "813afafa03a15a28d54bc2575efc32e4", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_UI_TerrainViewer.ts": { + "mtime": 1784371862.7274556, + "ast_hash": "b81950f01aa877da8ff16bacb3696fc2", + "semantic_hash": "" + }, + "B04_wf1_Surface/B04_wf1_Surface_UI_Viewer.ts": { + "mtime": 1784371862.7284577, + "ast_hash": "2b48d1b90147f675ec62ef7bd7dd5c6b", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Api_Fetch.ts": { + "mtime": 1784371862.7289634, + "ast_hash": "cc6349770367b8ec4b9746aa875e2eea", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Debug.py": { + "mtime": 1784371862.7299652, + "ast_hash": "07860ac23101ba802da621025bc374d5", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Engine.py": { + "mtime": 1784371862.7299652, + "ast_hash": "4bdea485263a52587b62a4b190493214", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Engine_Geometry.py": { + "mtime": 1783252313.986228, + "ast_hash": "37cd229216a5c5b9ea36d3413cbb04b1", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Engine_RidgeValley.py": { + "mtime": 1783252726.219655, + "ast_hash": "3033d914817006ff557bb3a30e5129b3", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Engine_Skeleton.py": { + "mtime": 1784371862.731433, + "ast_hash": "2c54dd0920045a39956fe9574d27c8e9", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Engine_Solver.py": { + "mtime": 1783252313.986228, + "ast_hash": "1a2b0e76bfb330dacfebabb72f1b5be6", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Repository.py": { + "mtime": 1784375574.3473394, + "ast_hash": "f810f9ad3d45bab36443db8abb7218da", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Router.py": { + "mtime": 1784371862.733941, + "ast_hash": "8480126cddd2ba075e56f9852c3060ab", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_Schema.py": { + "mtime": 1784371862.73506, + "ast_hash": "5f580db0bf758faab4fb7762fdd638e7", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_UI_Markers.ts": { + "mtime": 1784371862.73506, + "ast_hash": "6140bff561c64430d9b1d38b7be64d8c", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_UI_Page.ts": { + "mtime": 1784371862.7363892, + "ast_hash": "1f35be9f56d933f7f8cd7086464743ec", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_UI_Panel.ts": { + "mtime": 1784371862.7373946, + "ast_hash": "fa18f43da3ebef03f8b3236f0b579138", + "semantic_hash": "" + }, + "B05_wf2_Route/B05_wf2_Route_UI_Viewer.ts": { + "mtime": 1784371862.7390225, + "ast_hash": "3ac599812e510168e1a493d27b1ec51a", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Api_Fetch.ts": { + "mtime": 1784375574.3483717, + "ast_hash": "c963ea01b4e47fda7288da2466413faa", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Engine.py": { + "mtime": 1784375574.3494227, + "ast_hash": "c513b71a9cb135047ec58594d3d88067", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Engine_Sampler.py": { + "mtime": 1783252847.3035698, + "ast_hash": "09be25eece0a09f971bf66dcf9d83d8f", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Engine_Section.py": { + "mtime": 1783252893.2828002, + "ast_hash": "4b8b50006278faec701b3df20bfa9a85", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Repository.py": { + "mtime": 1784375574.350428, + "ast_hash": "f6ecffc9f54db3e1ea7fa682551c134b", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Router.py": { + "mtime": 1784375574.3514285, + "ast_hash": "7d31dd3ca17998ee0d05d53fd16c8a7b", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_Schema.py": { + "mtime": 1784375574.3534284, + "ast_hash": "be78faf37c307783ffc32cdaa3332a46", + "semantic_hash": "" + }, + "B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Page.ts": { + "mtime": 1784375574.3549345, + "ast_hash": "c6902c6082e97f2e794223b03f2dfba6", + "semantic_hash": "" + }, + "B07_wf4_DesignDetail/B07_wf4_DesignDetail_UI_Page.ts": { + "mtime": 1784371862.7403774, + "ast_hash": "a66fe85891a43fc0ac1c9ae2fadea04e", + "semantic_hash": "" + }, + "B08_wf5_Quantity/B08_wf5_Quantity_UI_Page.ts": { + "mtime": 1784371862.7418675, + "ast_hash": "33b2edca2fb2752de09d4cf42a6e1f48", + "semantic_hash": "" + }, + "B09_wf6_Estimation/B09_wf6_Estimation_UI_Page.ts": { + "mtime": 1784371862.7418675, + "ast_hash": "76f0a0873e539d3d2d5fb27c191888ed", + "semantic_hash": "" + }, + "B10_Payment/B10_Payment_UI_Page.ts": { + "mtime": 1784371862.7429183, + "ast_hash": "6466645325404f4703a88a93417d8dba", + "semantic_hash": "" + }, + "B11_Status/B11_Status_UI_Page.ts": { + "mtime": 1784371862.743941, + "ast_hash": "957b7ee41136212b91b60ed2d1fab72e", + "semantic_hash": "" + }, + "common_util/common_util_atomic.py": { + "mtime": 1783250994.605519, + "ast_hash": "8d9aa0a5c2d6ca864bd341267c6b0dfc", + "semantic_hash": "" + }, + "common_util/common_util_auth.py": { + "mtime": 1784371862.74606, + "ast_hash": "c4581646ca72b409715d1703627c4526", + "semantic_hash": "" + }, + "common_util/common_util_auth_repository.py": { + "mtime": 1784371862.7475655, + "ast_hash": "2898ea4436f14bbb938d28b2f14c5293", + "semantic_hash": "" + }, + "common_util/common_util_email.py": { + "mtime": 1783415605.0, + "ast_hash": "6c238daca6bf03c964a6cf2c02a1c9e4", + "semantic_hash": "" + }, + "common_util/common_util_email_templates.py": { + "mtime": 1783419082.0, + "ast_hash": "1aa788a52626e156e1619d4e3f0f93a9", + "semantic_hash": "" + }, + "common_util/common_util_json.py": { + "mtime": 1783244734.2867022, + "ast_hash": "91c303ff3382a3f0cca4596c872936a3", + "semantic_hash": "" + }, + "common_util/common_util_resource_monitor.py": { + "mtime": 1783504247.0, + "ast_hash": "e4689eb9141750dbcf22943a6ce7ea19", + "semantic_hash": "" + }, + "common_util/common_util_storage.py": { + "mtime": 1783673573.0, + "ast_hash": "c03810b60e5d5a47036838346346ce15", + "semantic_hash": "" + }, + "common_util/common_util_surface_confirmation.py": { + "mtime": 1784371862.7481408, + "ast_hash": "1e7d68a2270e9a6833bf17156c250ca1", + "semantic_hash": "" + }, + "common_util/common_util_validate.ts": { + "mtime": 1783237546.0309367, + "ast_hash": "6ad1316290c0476f952e0f81a81e03bd", + "semantic_hash": "" + }, + "common_util/common_util_workflow.py": { + "mtime": 1783244812.2994404, + "ast_hash": "be9ffbd894a166cd3f8763ae85dbe81f", + "semantic_hash": "" + }, + "common_util/common_util_workflow_state.py": { + "mtime": 1783677093.0, + "ast_hash": "4e05dc928abc17da0c2a12485ab11029", + "semantic_hash": "" + }, + "config/config_db.py": { + "mtime": 1783423949.0, + "ast_hash": "ce9915156c7b713b84eace38b68e099c", + "semantic_hash": "" + }, + "config/config_frontend.ts": { + "mtime": 1783673644.0, + "ast_hash": "e5b28cbb92bf2fbcebb36f6a51c91916", + "semantic_hash": "" + }, + "config/config_system.py": { + "mtime": 1784371862.7494447, + "ast_hash": "5aa2b09d55040942e73976a11ee8249a", + "semantic_hash": "" + }, + "db_management/001_create_schema.sql": { + "mtime": 1784371862.7504451, + "ast_hash": "b1d4c4c2e4bbfc412d51f3c84bfa4e36", + "semantic_hash": "" + }, + "db_management/002_auth_security.sql": { + "mtime": 1783418873.0, + "ast_hash": "741d633ee414e9722e5976f2e828a8fb", + "semantic_hash": "" + }, + "db_management/003_register_split.sql": { + "mtime": 1783502148.0, + "ast_hash": "74b3a17442f28d77687f581de27b1242", + "semantic_hash": "" + }, + "db_management/004_dashboard.sql": { + "mtime": 1784371862.751445, + "ast_hash": "386bb088c7ca7d678048d2a051ae69a8", + "semantic_hash": "" + }, + "db_management/005_b03_chunk_upload.sql": { + "mtime": 1783596524.266818, + "ast_hash": "57f83d7b98af96990d1bc69876897fbb", + "semantic_hash": "" + }, + "db_management/006_workflow_state.sql": { + "mtime": 1783676881.0, + "ast_hash": "5ecbe04b699371a577f853b1363b5128", + "semantic_hash": "" + }, + "db_management/007_trusted_device_token.sql": { + "mtime": 1784371862.751445, + "ast_hash": "cb6fca6d4e3b3183128b7282c22b1ec6", + "semantic_hash": "" + }, + "db_management/008_drop_project_automations.sql": { + "mtime": 1784371862.7525203, + "ast_hash": "59745e31a2a2801ebef77e0b03cdc59d", + "semantic_hash": "" + }, + "db_management/009_route_points_xyz.sql": { + "mtime": 1784371862.7525203, + "ast_hash": "9c73619108b4fcbd4b63721dbb8cb960", + "semantic_hash": "" + }, + "db_management/migrate_workflow_state.py": { + "mtime": 1783677101.0, + "ast_hash": "64137c7b017cc3e2c007818796e605fe", + "semantic_hash": "" + }, + "main.py": { + "mtime": 1784357162.0, + "ast_hash": "944ef36ad7b18e4180a1f49413a22cbd", + "semantic_hash": "" + }, + "migrations/001_create_upload_tables.sql": { + "mtime": 1783600548.0, + "ast_hash": "c0891f75d24a00ff3aaf666233be916c", + "semantic_hash": "" + }, + "package.json": { + "mtime": 1783417102.0, + "ast_hash": "21958685f75d3d89d497cf8da68ee15d", + "semantic_hash": "" + }, + "pyproject.toml": { + "mtime": 1783225255.0, + "ast_hash": "2cc68cbb844c44a41f3f035734750e69", + "semantic_hash": "" + }, + "scratch/test_crs_verification.py": { + "mtime": 1784371862.7568798, + "ast_hash": "8d266aebaa74e9a2bcef1eefe6e97184", + "semantic_hash": "" + }, + "scratch/wiki_linter.py": { + "mtime": 1784371862.7568798, + "ast_hash": "ef1b873d05b130e30dd461cced7d62c1", + "semantic_hash": "" + }, + "tsconfig.json": { + "mtime": 1783417261.0, + "ast_hash": "36f7ffbea3824d3bd1a9f8900244e806", + "semantic_hash": "" + }, + "ui_template/ui_template_elements.ts": { + "mtime": 1784371862.7589295, + "ast_hash": "584820cdbcdb5c360def7de1fcfaebf4", + "semantic_hash": "" + }, + "ui_template/ui_template_general_blocks.ts": { + "mtime": 1784371862.7594473, + "ast_hash": "8d5c82ae21fbea2da5d49783572f9c49", + "semantic_hash": "" + }, + "ui_template/ui_template_general_layout.ts": { + "mtime": 1784371862.7604806, + "ast_hash": "a491d4081e5d73c8ed9767324712ec65", + "semantic_hash": "" + }, + "ui_template/ui_template_locale.ts": { + "mtime": 1784375574.3572495, + "ast_hash": "e1934d1e709bc56259272166b9e2aca5", + "semantic_hash": "" + }, + "ui_template/ui_template_overlay.ts": { + "mtime": 1784371862.7630575, + "ast_hash": "76116f4d99e8beaa18f7cb8a433a5d2f", + "semantic_hash": "" + }, + "ui_template/ui_template_workflow_layout.ts": { + "mtime": 1784371862.7646809, + "ast_hash": "3bddec3560e443db6c99a852cbd43c7a", + "semantic_hash": "" + }, + "vite.config.ts": { + "mtime": 1783419145.0, + "ast_hash": "ca2c8f6b3896b7d4636fcf147005c153", + "semantic_hash": "" + }, + "A00_Common/index.html": { + "mtime": 1783335150.0, + "ast_hash": "370b5160117bf7b813b7f9439e5f9ac1", + "semantic_hash": "" + }, + "README.md": { + "mtime": 1784108913.0, + "ast_hash": "4619384b0b9fc2b1fecbc29ee925988d", + "semantic_hash": "" + }, + "requirements.txt": { + "mtime": 1784357162.0, + "ast_hash": "f75f25000ea734fc5e2dfa72cc019735", + "semantic_hash": "" + }, + "resources/legal/marketing_consent.txt": { + "mtime": 1783421488.0, + "ast_hash": "0b3c46af3ff5007be1bd0c2f643dc132", + "semantic_hash": "" + }, + "resources/legal/privacy_policy.txt": { + "mtime": 1783421482.0, + "ast_hash": "1e56e478d669bcec2f52e4e5ffba1465", + "semantic_hash": "" + }, + "resources/legal/terms_of_service.txt": { + "mtime": 1783421474.0, + "ast_hash": "683dafcbabe621641da485afab311c69", + "semantic_hash": "" + }, + "resources/prog_icon.jpg": { + "mtime": 1783331655.0, + "ast_hash": "18a3fd959eb07f8b0a18a86126c7bb6d", + "semantic_hash": "" + }, + "docs/wiki/graphify-out/memory/query_20260718_022949_compare_current_b04_wf1_surface_with_0_old_backend.md": { + "mtime": 1784341789.0, + "ast_hash": "0722820bbdb99abee95661d7a102fe7f", + "semantic_hash": "" + }, + "docs/wiki/graphify-out/memory/query_20260718_044714_\uc81c\uc2dc\ub41c_numpy_2_x_gis_\ud328\ud0a4\uc9c0_\ud540\uc744_\ud604\uc7ac_venv\uc5d0_\uc124\uce58\ud560_\ub54c_\ubb38\uc81c\uac00_\uc788\ub294\uc9c0_\ubd84\uc11d.md": { + "mtime": 1784350034.0, + "ast_hash": "d0623cc53601b82bf8993b6828bac357", + "semantic_hash": "" + }, + "docs/wiki/graphify-out/memory/query_20260718_053304_\ud2b8\ub77c\uc774\uba54\uc2dc_4_12_2\uc640_pyogrio_0_13_0\uc744_\ubc18\uc601\ud558\uace0_setuptools_whit.md": { + "mtime": 1784352784.0, + "ast_hash": "f6d427d6b59463bad1424aed217b987c", + "semantic_hash": "" } } \ No newline at end of file diff --git a/main.py b/main.py index 37e03222..6f024925 100644 --- a/main.py +++ b/main.py @@ -59,6 +59,16 @@ logger = logging.getLogger(__name__) # ───────────────────────────────────────────────────────────────────────── +def _frontend_process_env(root_dir: Path) -> dict[str, str]: + """config/node_modules를 사용하는 프론트엔드 프로세스 환경을 만든다.""" + env = os.environ.copy() + node_modules = root_dir / "config" / "node_modules" + bin_dir = node_modules / ".bin" + env["PATH"] = f"{bin_dir}{os.pathsep}{env.get('PATH', '')}" + env["NODE_PATH"] = str(node_modules) + return env + + def build_frontend() -> bool: """프론트엔드 빌드 (npm run build from project root)""" root_dir = Path(__file__).resolve().parent @@ -69,6 +79,7 @@ def build_frontend() -> bool: "npm run build", shell=True, cwd=str(root_dir), + env=_frontend_process_env(root_dir), capture_output=True, text=True, encoding="utf-8", @@ -103,6 +114,7 @@ def serve_frontend_dev() -> None: "npm run dev", shell=True, cwd=str(root_dir), + env=_frontend_process_env(root_dir), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) @@ -203,11 +215,12 @@ app.add_middleware( # ───────────────────────────────────────────────────────────────────────── # 정적 파일 서빙 (프론트엔드) # ───────────────────────────────────────────────────────────────────────── -if os.path.isdir(STATIC_DIR): - app.mount(STATIC_URL, StaticFiles(directory=STATIC_DIR), name="static") - logger.info(f"✓ 정적 파일 서빙: {STATIC_URL} → {STATIC_DIR}") -else: - logger.warning(f"⚠ 정적 파일 디렉토리 없음: {STATIC_DIR}") +app.mount( + STATIC_URL, + StaticFiles(directory=STATIC_DIR, check_dir=False), + name="static", +) +logger.info(f"✓ 정적 파일 서빙 경로 등록: {STATIC_URL} → {STATIC_DIR}") # ───────────────────────────────────────────────────────────────────────── # 기본 엔드포인트 diff --git a/package.json b/package.json index 78ed25e4..7d17e182 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,11 @@ "description": "임도 설계 및 견적 자동화 프로그램 (프론트엔드)", "type": "module", "scripts": { - "dev": "vite", - "build": "tsc --noEmit && vite build", - "preview": "vite preview", - "typecheck": "tsc --noEmit", - "format": "prettier --write \"../**/*.{ts,css,html}\"" + "dev": "node ./config/node_modules/vite/bin/vite.js --configLoader runner", + "build": "node ./config/node_modules/typescript/bin/tsc --noEmit && node ./config/node_modules/vite/bin/vite.js build --configLoader runner", + "preview": "node ./config/node_modules/vite/bin/vite.js preview --configLoader runner", + "typecheck": "node ./config/node_modules/typescript/bin/tsc --noEmit", + "format": "node ./config/node_modules/prettier/bin/prettier.cjs --write \"../**/*.{ts,css,html}\"" }, "dependencies": { "maplibre-gl": "^5.24.0", diff --git a/scratch/wiki_linter.py b/scratch/wiki_linter.py index 70449366..aee6382d 100644 --- a/scratch/wiki_linter.py +++ b/scratch/wiki_linter.py @@ -1,157 +1,120 @@ import os import re -from pathlib import Path -# 위키 루트 경로 설정 -wiki_root = Path(r"D:\02_Software_Prog\임도설계 및 견적자동화 프로그램 개발\docs\wiki") -raw_root = Path(r"D:\02_Software_Prog\임도설계 및 견적자동화 프로그램 개발\docs\raw") +WIKI_DIR = r"C:\Program_coding\임도설계 및 견적자동화 프로그램 개발\docs\wiki" +PAGES_DIR = os.path.join(WIKI_DIR, "pages") +CONCEPTS_DIR = os.path.join(WIKI_DIR, "concepts") +INDEX_PATH = os.path.join(WIKI_DIR, "index.md") -def load_frontmatter(file_path): - content = file_path.read_text(encoding="utf-8") - # Frontmatter regex - match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL) - if match: - fm_text = match.group(1) - fm = {} - # Simple YAML key-value parser for basic string/list properties - for line in fm_text.splitlines(): - line = line.strip() - if not line or line.startswith("#"): - continue - if ":" in line: - key, val = line.split(":", 1) - key = key.strip() - val = val.strip().strip("'\"") - fm[key] = val - return fm, content[match.end():] - return None, content +errors = [] +warnings = [] +all_wiki_files = {} # relative_path -> absolute_path -def extract_wiki_links(text): - # Matches [[link]] or [[link|alias]] or [[link#section]] or [[link#section|alias]] - links = re.findall(r"\[\[(.*?)\]\]", text) - cleaned_links = [] - for l in links: - # Split alias - if "|" in l: - l = l.split("|")[0] - # Split section - if "#" in l: - l = l.split("#")[0] - l = l.strip() - if l: - cleaned_links.append(l) - return cleaned_links +# Collect all markdown files in wiki/ (ignoring graphify-out and memory directories) +for root, dirs, files in os.walk(WIKI_DIR): + # skip graphify-out or memory + if "graphify-out" in root or "memory" in root: + continue + for file in files: + if file.endswith(".md"): + abs_path = os.path.join(root, file) + rel_path = os.path.relpath(abs_path, WIKI_DIR).replace("\\", "/") + all_wiki_files[rel_path] = abs_path + simple_name = os.path.splitext(rel_path)[0] + all_wiki_files[simple_name] = abs_path -def run_lint(): - print("=== Start Wiki Linting (No PyYAML, Filtered) ===") - - all_files = list(wiki_root.glob("**/*.md")) - index_file = wiki_root / "index.md" - log_file = wiki_root / "log.md" - - # 1. 파일 목록화 및 Frontmatter 체크 - pages = {} - concepts = {} - errors = [] - warnings = [] - - for f in all_files: - rel_path = f.relative_to(wiki_root).as_posix() - # Skip output files generated by graphify in graphify-out - if rel_path.startswith("graphify-out/") or rel_path in ["index.md", "log.md", "AGENTS.md", "CLAUDE.md"]: - continue - - fm, body = load_frontmatter(f) +# Read index.md content +with open(INDEX_PATH, "r", encoding="utf-8") as f: + index_content = f.read() + +# Pattern for wikilinks: [[link]] or [[link|label]] +wikilink_pat = re.compile(r"\[\[([^\]|]+)(?:\|[^\]]+)?\]\]") + +for rel_path, abs_path in list(all_wiki_files.items()): + if "/" not in rel_path and rel_path != "index" and rel_path != "log": + continue + if rel_path in ["index", "log", "index.md", "log.md"]: + continue - # 기본 규칙 검사 - if not fm: - errors.append(f"Missing Frontmatter: {rel_path}") - continue - - # status 값 검사 - status = fm.get("status") + with open(abs_path, "r", encoding="utf-8") as f: + lines = f.readlines() + + line_count = len(lines) + content = "".join(lines) + + # Rule 14: Max 100 lines + if line_count > 100: + warnings.append(f"[Line Count] `{rel_path}.md` exceeds 100 lines ({line_count} lines).") + + # Check YAML Frontmatter via simple regex + frontmatter_match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL) + if not frontmatter_match: + errors.append(f"[Frontmatter] `{rel_path}.md` has no valid YAML frontmatter.") + continue + + fm_text = frontmatter_match.group(1) + + # Simple regex parsing for status & page_id + status_match = re.search(r"^status:\s*(\w+)", fm_text, re.MULTILINE) + page_id_match = re.search(r"^page_id:\s*([^\n\r]+)", fm_text, re.MULTILINE) + + if not status_match: + errors.append(f"[Status] `{rel_path}.md` has no status field in frontmatter.") + else: + status = status_match.group(1).strip() if status not in ["draft", "stable", "stale"]: - errors.append(f"Invalid status '{status}' in {rel_path}. Must be draft, stable, or stale.") + errors.append(f"[Status] `{rel_path}.md` has invalid status '{status}'. Must be draft, stable, or stale.") + elif status == "stale": + warnings.append(f"[Stale Page] `{rel_path}.md` is marked as stale and needs updates from raw inputs.") - # 100줄 제한 검사 (10% 즉 110줄 허용) - lines_count = len(f.read_text(encoding="utf-8").splitlines()) - if lines_count > 110: - warnings.append(f"File exceeds 110 lines ({lines_count} lines): {rel_path}") + # Rule 5: page_id required for pages/ + if "pages/" in rel_path: + if not page_id_match: + errors.append(f"[page_id] `{rel_path}.md` is in pages/ but lacks a 'page_id' field.") - # 페이지와 컨셉 분류 - if "pages/" in rel_path: - pages[rel_path] = { - "fm": fm, - "body": body, - "path": f, - "links": extract_wiki_links(body) - } - # 파일명 형식 규칙 5 검사: {page_id}_{기능명}.md - filename = f.name - page_id = fm.get("page_id") - if not page_id: - errors.append(f"Missing page_id in page: {rel_path}") - else: - expected_prefix = page_id.split("_")[0] # e.g. A01 - if not filename.startswith(expected_prefix): - warnings.append(f"Filename does not match page_id format: {rel_path} (page_id: {page_id})") - else: - concepts[rel_path] = { - "fm": fm, - "body": body, - "path": f, - "links": extract_wiki_links(body) - } - - # 2. 위키 링크 정합성 검증 (Broken Links) - # 개념/페이지 맵 구성 - available_links = {} - for p_rel in pages: - name_no_ext = Path(p_rel).with_suffix("").as_posix() - available_links[name_no_ext] = p_rel - # Also map short form if distinct - short_name = Path(p_rel).name[:-3] - available_links[short_name] = p_rel + # Check for broken wikilinks in content + links = wikilink_pat.findall(content) + for link in links: + link_clean = link.strip().replace("\\", "/").split("#")[0] # ignore anchor for file existence check + if not link_clean: + continue + found = False - for c_rel in concepts: - name_no_ext = Path(c_rel).with_suffix("").as_posix() - available_links[name_no_ext] = c_rel - # Short form - short_name = Path(c_rel).name[:-3] - available_links[short_name] = c_rel - # Subdirectories for concepts like db_schema/* - if "concepts/" in name_no_ext: - available_links[name_no_ext.replace("concepts/", "")] = c_rel + # 1. Absolute link from vault root (e.g. concepts/storage_paths) + if link_clean in all_wiki_files: + found = True + # 2. Simple name match (e.g. storage_paths, B01_frontend) + elif link_clean.split("/")[-1] in all_wiki_files: + found = True + # 3. Handle subpages like [[B01_Dashboard/B01_frontend]] + elif f"pages/{link_clean}" in all_wiki_files: + found = True + elif f"concepts/{link_clean}" in all_wiki_files: + found = True + # 4. Handle nested directory patterns + elif link_clean.startswith("../"): + # Resolve relative link + curr_dir = os.path.dirname(rel_path) + resolved = os.path.normpath(os.path.join(curr_dir, link_clean)).replace("\\", "/") + if resolved in all_wiki_files or resolved.replace("pages/", "") in all_wiki_files: + found = True + + if not found: + errors.append(f"[Broken Link] `{rel_path}.md` contains broken wikilink: [[{link}]]") - # 링크 검사 - for rel_path, info in {**pages, **concepts}.items(): - for link in info["links"]: - if link.startswith("http://") or link.startswith("https://") or link.startswith("file:///"): - continue - normalized_link = link.replace("\\", "/") - if normalized_link not in available_links and f"concepts/{normalized_link}" not in available_links and f"pages/{normalized_link}" not in available_links: - warnings.append(f"Broken Link in {rel_path}: [[{link}]]") + # Check if this file is registered in index.md (avoid orphans) + file_base = os.path.basename(abs_path) + file_name_no_ext = os.path.splitext(file_base)[0] + if file_name_no_ext not in index_content: + # check if relative path is in index + rel_path_no_ext = rel_path.replace(".md", "") + if rel_path_no_ext not in index_content and rel_path_no_ext.split("/")[-1] not in index_content: + warnings.append(f"[Orphan Page] `{rel_path}.md` is not linked or mentioned in index.md.") - # 3. index.md 등록 상태 확인 - index_content = index_file.read_text(encoding="utf-8") if index_file.exists() else "" - for rel_path in pages: - short_name = Path(rel_path).name[:-3] - dir_name = Path(rel_path).parent.name - expected_ref_dir = f"{dir_name}/{short_name}" - if expected_ref_dir not in index_content and f"[[{short_name}]]" not in index_content and short_name not in index_content: - warnings.append(f"Page not indexed in index.md: {rel_path} (Expected link to [[{expected_ref_dir}]] or [[{short_name}]])") - - # 4. 결과 출력 - print(f"\nScanning completed: {len(all_files)} total markdown files.") - print(f"Detected {len(pages)} pages and {len(concepts)} concept documents.") - - print(f"\n--- Errors ({len(errors)}) ---") - for e in errors: - print(f"[ERROR] {e}") - - print(f"\n--- Warnings ({len(warnings)}) ---") - for w in warnings: - print(f"[WARN] {w}") - -if __name__ == "__main__": - run_lint() +print("=== LINT ERRORS ===") +for e in sorted(list(set(errors))): + print(e) +print("\n=== LINT WARNINGS ===") +for w in sorted(list(set(warnings))): + print(w) +print("\nLint completed.") diff --git a/tsconfig.json b/tsconfig.json index ae7d3c7e..44c4d72f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "types": ["node"], + "types": ["node", "vite/client"], + "typeRoots": ["./config/node_modules/@types", "./config/node_modules"], "ignoreDeprecations": "6.0", "baseUrl": ".", @@ -25,17 +26,12 @@ "paths": { "@ui/*": ["ui_template/*"], "@config/*": ["config/*"], - "@util/*": ["common_util/*"] + "@util/*": ["common_util/*"], + "three": ["config/node_modules/@types/three"], + "three/*": ["config/node_modules/@types/three/*"], + "maplibre-gl": ["config/node_modules/maplibre-gl"] } }, - "include": [ - "A00_Common", - "A0*", - "B0*", - "B1*", - "ui_template", - "config/**/*", - "common_util" - ], + "include": ["A00_Common", "A0*", "B0*", "B1*", "ui_template", "config/**/*", "common_util"], "exclude": ["0_old", "node_modules", "venv", "dist"] } diff --git a/vite.config.ts b/vite.config.ts index 35d60a50..5d04666f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,3 @@ -import { defineConfig } from "vite"; import { resolve } from "node:path"; import { fileURLToPath } from "node:url"; @@ -11,14 +10,17 @@ const __dirname = fileURLToPath(new URL(".", import.meta.url)); * - 페이지 폴더(A01_Home 등)는 ../를 통해 접근 * - 0_old(구형 코드), venv(파이썬)는 빌드에서 제외 */ -export default defineConfig({ +export default { root: "A00_Common", publicDir: false, + cacheDir: "config/node_modules/.vite", resolve: { alias: { "@ui": resolve(__dirname, "./ui_template"), "@config": resolve(__dirname, "./config"), "@util": resolve(__dirname, "./common_util"), + three: resolve(__dirname, "./config/node_modules/three"), + "maplibre-gl": resolve(__dirname, "./config/node_modules/maplibre-gl"), }, }, server: { @@ -33,11 +35,11 @@ export default defineConfig({ }, }, build: { - outDir: "../node_modules/.build", + outDir: "../config/node_modules/.build", emptyOutDir: true, target: "es2022", }, optimizeDeps: { exclude: ["0_old"], }, -}); +};