diff --git a/backend-node/data/mail-sent/1d997eeb-3d61-427d-8b54-119d4372b9b3.json b/backend-node/data/mail-sent/1d997eeb-3d61-427d-8b54-119d4372b9b3.json deleted file mode 100644 index 683ad20c..00000000 --- a/backend-node/data/mail-sent/1d997eeb-3d61-427d-8b54-119d4372b9b3.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "1d997eeb-3d61-427d-8b54-119d4372b9b3", - "sentAt": "2025-10-22T07:13:30.905Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "Fwd: ㄴ", - "htmlContent": "\r\n
\r\n

전달히야야양


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
전달된 메일:

보낸사람: \"이희진\"
날짜: 2025. 10. 22. 오후 12:58:15
제목: ㄴ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ㄴㅇㄹㄴㅇㄹㄴㅇㄹ

\r\n
\r\n ", - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/1e492bb1-d069-4242-8cbf-9829b8f6c7e6.json b/backend-node/data/mail-sent/1e492bb1-d069-4242-8cbf-9829b8f6c7e6.json deleted file mode 100644 index eccdc063..00000000 --- a/backend-node/data/mail-sent/1e492bb1-d069-4242-8cbf-9829b8f6c7e6.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "1e492bb1-d069-4242-8cbf-9829b8f6c7e6", - "sentAt": "2025-10-13T01:08:34.764Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "제목 없음", - "htmlContent": "\n\n\n\n \n \n\n\n \n \n \n \n
\n

ㄴㅇㄹㄴㅇㄹ

\n \"\"\n

ㄴㅇㄹ

ㄴㅇㄹ

\n
\n\n
\n \r\n
\r\n

ㄴㅇㄹ

\r\n
\r\n \n
\n \n\n", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "attachments": [ - { - "filename": "스크린샷 2025-10-13 오전 10.00.06.png", - "originalName": "스크린샷 2025-10-13 오전 10.00.06.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1760317712416-622369845.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/2d848b19-26e1-45ad-8e2c-9205f1f01c87.json b/backend-node/data/mail-sent/2d848b19-26e1-45ad-8e2c-9205f1f01c87.json deleted file mode 100644 index a6fed281..00000000 --- a/backend-node/data/mail-sent/2d848b19-26e1-45ad-8e2c-9205f1f01c87.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "2d848b19-26e1-45ad-8e2c-9205f1f01c87", - "sentAt": "2025-10-02T07:50:25.817Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "ㅣ;ㅏㅓ", - "htmlContent": "\r\n
\r\n

ㅓㅏㅣ

\r\n
\r\n ", - "attachments": [ - { - "filename": "test용 이미지33.jpg", - "originalName": "test용 이미지33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759391422625-269479520_test____________________________33.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "UI_개선사항_문서.md", - "originalName": "UI_개선사항_문서.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759391422626-68453569_UI_______________________________________________.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "test용 이미지2.png", - "originalName": "test용 이미지2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759391422626-168170034_test____________________________2.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "<9d5b8275-e059-3a71-a34a-dea800730aa3@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/331d95d6-3a13-4657-bc75-ab0811712eb8.json b/backend-node/data/mail-sent/331d95d6-3a13-4657-bc75-ab0811712eb8.json deleted file mode 100644 index 5090fdd2..00000000 --- a/backend-node/data/mail-sent/331d95d6-3a13-4657-bc75-ab0811712eb8.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "331d95d6-3a13-4657-bc75-ab0811712eb8", - "sentAt": "2025-10-22T07:18:18.240Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "ㅁㄴㅇㄹㅁㄴㅇㄹ", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹㅁㄴㅇㄹㄴㅇㄹㄴㅇㄹ

\r\n
\r\n ", - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/34f7f149-ac97-442e-b595-02c990082f86.json b/backend-node/data/mail-sent/34f7f149-ac97-442e-b595-02c990082f86.json deleted file mode 100644 index 46b0b1b8..00000000 --- a/backend-node/data/mail-sent/34f7f149-ac97-442e-b595-02c990082f86.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "34f7f149-ac97-442e-b595-02c990082f86", - "sentAt": "2025-10-13T01:04:08.560Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "제목 없음", - "htmlContent": "\n\n\n\n \n \n\n\n \n \n \n \n
\n

텍스트 영역 1

\n 버튼1\n
\n \"\"\n

텍스트 영역2

텍스트 영역3

\n
\n\n
\n \r\n
\r\n

선택메시지 영역

\r\n
\r\n \n
\n \n\n", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "attachments": [ - { - "filename": "한글.txt", - "originalName": "한글.txt", - "size": 0, - "path": "/app/uploads/mail-attachments/1760317447824-27488793.txt", - "mimetype": "text/plain" - } - ], - "status": "success", - "messageId": "<1d7caa77-12f1-a791-a230-162826cf03ea@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/37fce6a0-2301-431b-b573-82bdab9b8008.json b/backend-node/data/mail-sent/37fce6a0-2301-431b-b573-82bdab9b8008.json deleted file mode 100644 index d70b6897..00000000 --- a/backend-node/data/mail-sent/37fce6a0-2301-431b-b573-82bdab9b8008.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "37fce6a0-2301-431b-b573-82bdab9b8008", - "sentAt": "2025-10-02T07:44:38.128Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "asd", - "htmlContent": "\r\n
\r\n

asd

\r\n
\r\n ", - "attachments": [ - { - "filename": "웨이스-임직원-프로파일-이희진.key", - "originalName": "웨이스-임직원-프로파일-이희진.key", - "size": 0, - "path": "/app/uploads/mail-attachments/1759391076653-58189058___________________-___________________________-___________________________-_____________________.key", - "mimetype": "application/x-iwork-keynote-sffkey" - }, - { - "filename": "웨이스-임직원-프로파일-이희진.pptx", - "originalName": "웨이스-임직원-프로파일-이희진.pptx", - "size": 0, - "path": "/app/uploads/mail-attachments/1759391076736-190208246___________________-___________________________-___________________________-_____________________.pptx", - "mimetype": "application/vnd.openxmlformats-officedocument.presentationml.presentation" - }, - { - "filename": "test용 이미지33.jpg", - "originalName": "test용 이미지33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759391076738-240665795_test____________________________33.jpg", - "mimetype": "image/jpeg" - } - ], - "status": "success", - "messageId": "<796cb9a7-df62-31c4-ae6b-b42f383d82b4@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/3f72cbab-b60e-45e7-ac8d-7e441bc2b900.json b/backend-node/data/mail-sent/3f72cbab-b60e-45e7-ac8d-7e441bc2b900.json deleted file mode 100644 index 05eb18c2..00000000 --- a/backend-node/data/mail-sent/3f72cbab-b60e-45e7-ac8d-7e441bc2b900.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "3f72cbab-b60e-45e7-ac8d-7e441bc2b900", - "sentAt": "2025-10-13T01:34:19.363Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "테스트 템플릿이에용22", - "htmlContent": "\n\n\n\n \n \n\n\n \n \n \n \n
\n

안녕안녕하세요 이건 테스트용 템플릿입니다용22

\n \"\"\n

안녕하세용 [222]이안에 뭘 넣어보세용

여기에 뭘 또 입력해보세용[222] 안에 넣어도 돼요

\n
\n\n
\n \r\n
\r\n

ㄴㅇㄹㄴㅇㄹㄴㅇㄹ

\r\n
\r\n \n
\n \n\n", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "attachments": [ - { - "filename": "blender study.docx", - "originalName": "blender study.docx", - "size": 0, - "path": "/app/uploads/mail-attachments/1760319257947-827879690.docx", - "mimetype": "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - } - ], - "status": "success", - "messageId": "<5b3d9f82-8531-f427-c7f7-9446b4f19da4@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/43466fc8-56e8-44a0-875c-dec2c3c8eb78.json b/backend-node/data/mail-sent/43466fc8-56e8-44a0-875c-dec2c3c8eb78.json new file mode 100644 index 00000000..ea3b568f --- /dev/null +++ b/backend-node/data/mail-sent/43466fc8-56e8-44a0-875c-dec2c3c8eb78.json @@ -0,0 +1,20 @@ +{ + "id": "43466fc8-56e8-44a0-875c-dec2c3c8eb78", + "sentAt": "2025-11-28T02:34:02.239Z", + "accountId": "account-1759310844272", + "accountName": "이희진", + "accountEmail": "hjlee@wace.me", + "to": [ + "zian9227@naver.com" + ], + "subject": "임의로 설정한 제목", + "htmlContent": "\n\n\n\n \n \n\n\n \n \n \n \n
\n\n
\n \n \n \n \n \n
\n \n (주)웨이스\n \n 2025. 11. 28.\n
\n
\n
\n naver\n
\n \"\"\n
\n
\n
(주)웨이스
\n \n
\n 대표: 이희진\n \n \n
\n \n
주소주소
\n \n
\n Tel: 전화번호 01010101011010\n | \n Email: 이메일이메일\n
\n \n
© 2025 All rights reserved.
\n
\n \n
\n \n \n \n \n \n \n \n \n
항목내용
\n
\n \n
\n
안내
\n
안내를 합시다 합시다 합시다
\n
\n \n
\n \n
    \n
  1. 첫 번째 항목
  2. 두번째항목
  3. \n
\n
\n \n
\n \n
    \n
  1. 첫 번째 항목
  2. \n
\n
\n \n
\n \n
    \n
  1. 첫 번째 항목
  2. \n
\n
\n \n
\n \n
    \n
  1. 첫 번째 항목
  2. \n
\n
\n \n
\n\n\n", + "templateId": "template-1764296982213", + "templateName": "제목 있음", + "status": "success", + "messageId": "<78b63521-2648-f6eb-eeba-efdeebce8459@wace.me>", + "accepted": [ + "zian9227@naver.com" + ], + "rejected": [] +} \ No newline at end of file diff --git a/backend-node/data/mail-sent/449d9951-51e8-4e81-ada4-e73aed8ff60e.json b/backend-node/data/mail-sent/449d9951-51e8-4e81-ada4-e73aed8ff60e.json deleted file mode 100644 index 29ec634e..00000000 --- a/backend-node/data/mail-sent/449d9951-51e8-4e81-ada4-e73aed8ff60e.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "id": "449d9951-51e8-4e81-ada4-e73aed8ff60e", - "sentAt": "2025-10-13T01:29:25.975Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "테스트 템플릿이에용", - "htmlContent": "\n\n\n\n \n \n\n\n \n \n \n \n
\n
안녕안녕하세요 이건 테스트용 템플릿입니다용
\n \"\"\n

안녕하세용 [뭘 넣은 결과 입니당]이안에 뭘 넣어보세용

여기에 뭘 또 입력해보세용[안에 뭘 넣은 결과입니다.] 안에 넣어도 돼요

\n
\n\n\n", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "status": "success", - "messageId": "<5d52accb-777b-b6c2-aab7-1a2f7b7754ab@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/6dd3673a-f510-4ba9-9634-0b391f925230.json b/backend-node/data/mail-sent/6dd3673a-f510-4ba9-9634-0b391f925230.json deleted file mode 100644 index ee094c49..00000000 --- a/backend-node/data/mail-sent/6dd3673a-f510-4ba9-9634-0b391f925230.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "6dd3673a-f510-4ba9-9634-0b391f925230", - "sentAt": "2025-10-13T01:01:55.097Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "테스트용입니당.", - "htmlContent": "\n\n\n\n \n \n\n\n \n \n \n \n
\n \n \n \n \n
\n

텍스트 영역 1

\n 버튼1\n
\n \"\"\n

텍스트 영역2

텍스트 영역3

\n
\n
\n\n
\n \r\n
\r\n

이건 저장이 안되는군

\r\n
\r\n \n
\n \n\n", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "attachments": [ - { - "filename": "한글-분석.txt", - "originalName": "한글-분석.txt", - "size": 0, - "path": "/app/uploads/mail-attachments/1760317313641-761345104.txt", - "mimetype": "text/plain" - } - ], - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/84ee9619-49ff-4f61-a7fa-0bb0b0b7199a.json b/backend-node/data/mail-sent/84ee9619-49ff-4f61-a7fa-0bb0b0b7199a.json deleted file mode 100644 index 37317a6a..00000000 --- a/backend-node/data/mail-sent/84ee9619-49ff-4f61-a7fa-0bb0b0b7199a.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "84ee9619-49ff-4f61-a7fa-0bb0b0b7199a", - "sentAt": "2025-10-22T04:27:51.044Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "\"이희진\" " - ], - "subject": "Re: ㅅㄷㄴㅅ", - "htmlContent": "\r\n
\r\n

야야야야야야야야ㅑㅇ야ㅑㅇ

\r\n
\r\n

\r\n
\r\n

보낸 사람: \"이희진\"

\r\n

날짜: 2025. 10. 22. 오후 1:03:03

\r\n

제목: ㅅㄷㄴㅅ

\r\n
\r\n undefined\r\n
\r\n ", - "status": "success", - "messageId": "<5fa451ff-7d29-7da4-ce56-ca7391c147af@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/89a32ace-f39b-44fa-b614-c65d96548f92.json b/backend-node/data/mail-sent/89a32ace-f39b-44fa-b614-c65d96548f92.json deleted file mode 100644 index 4ac647c7..00000000 --- a/backend-node/data/mail-sent/89a32ace-f39b-44fa-b614-c65d96548f92.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "89a32ace-f39b-44fa-b614-c65d96548f92", - "sentAt": "2025-10-22T03:49:48.461Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "Fwd: 기상청 API허브 회원가입 인증번호", - "htmlContent": "\r\n
\r\n






---------- 전달된 메시지 ----------


보낸 사람: \"기상청 API허브\"


날짜: 2025. 10. 13. 오후 4:26:45


제목: 기상청 API허브 회원가입 인증번호




undefined

\r\n
\r\n ", - "status": "success", - "messageId": "<9b36ce56-4ef1-cf0c-1f39-2c73bcb521da@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/9eab902e-f77b-424f-ada4-0ea8709b36bf.json b/backend-node/data/mail-sent/9eab902e-f77b-424f-ada4-0ea8709b36bf.json deleted file mode 100644 index ed2e4b14..00000000 --- a/backend-node/data/mail-sent/9eab902e-f77b-424f-ada4-0ea8709b36bf.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "9eab902e-f77b-424f-ada4-0ea8709b36bf", - "sentAt": "2025-10-13T00:53:55.193Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "제목 없음", - "htmlContent": "

텍스트를 입력하세요...

\n 버튼\n
\n \"\"\n

텍스트를 입력하세요...

텍스트를 입력하세요...

\n
\n \r\n
\r\n

어덯게 나오는지 봅시다 추가메시지 영역이빈다.

\r\n
\r\n \n
\n
", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "attachments": [ - { - "filename": "한글.txt", - "originalName": "한글.txt", - "size": 0, - "path": "/app/uploads/mail-attachments/1760316833254-789302611.txt", - "mimetype": "text/plain" - } - ], - "status": "success", - "messageId": "<3d0bef10-2e58-fd63-b175-c1f499af0102@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/a1ca39ad-4467-44e0-963a-fba5037c8896.json b/backend-node/data/mail-sent/a1ca39ad-4467-44e0-963a-fba5037c8896.json deleted file mode 100644 index 31492a08..00000000 --- a/backend-node/data/mail-sent/a1ca39ad-4467-44e0-963a-fba5037c8896.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "a1ca39ad-4467-44e0-963a-fba5037c8896", - "sentAt": "2025-10-02T08:22:14.721Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "ㅁㄴㅇㄹㅁㄴㅇㄹㅁㄴㅇㄹㅁㄴ", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹㅁㄴㅇㄹㄴㅁㅇㄹ

\r\n
\r\n ", - "attachments": [ - { - "filename": "test용 이미지33.jpg", - "originalName": "test용 이미지33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759393332207-791945862_test____________________________33.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "UI_개선사항_문서.md", - "originalName": "UI_개선사항_문서.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759393332208-660280542_UI_______________________________________________.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "test용 이미지2.png", - "originalName": "test용 이미지2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759393332208-149486455_test____________________________2.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/a3a9aab1-4334-46bd-bf50-b867305f66c0.json b/backend-node/data/mail-sent/a3a9aab1-4334-46bd-bf50-b867305f66c0.json deleted file mode 100644 index 1435f837..00000000 --- a/backend-node/data/mail-sent/a3a9aab1-4334-46bd-bf50-b867305f66c0.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "a3a9aab1-4334-46bd-bf50-b867305f66c0", - "sentAt": "2025-10-02T08:41:42.086Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "한글테스트", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹ

\r\n
\r\n ", - "attachments": [ - { - "filename": "UI_개선사항_문서.md", - "originalName": "UI_개선사항_문서.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394500462-50127394_UI_______________________________________________.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "test용 이미지33.jpg", - "originalName": "test용 이미지33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394500463-68744474_test____________________________33.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "test용 이미지2.png", - "originalName": "test용 이미지2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394500463-464487722_test____________________________2.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "<2dbfbf64-69c2-a83d-6bb7-515e4e654628@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/a638f7d0-ee31-47fa-9f72-de66ef31ea44.json b/backend-node/data/mail-sent/a638f7d0-ee31-47fa-9f72-de66ef31ea44.json deleted file mode 100644 index 5cf165c3..00000000 --- a/backend-node/data/mail-sent/a638f7d0-ee31-47fa-9f72-de66ef31ea44.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "a638f7d0-ee31-47fa-9f72-de66ef31ea44", - "sentAt": "2025-10-22T07:21:13.723Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "ㄹㅇㄴㅁㄹㅇㄴㅁ", - "htmlContent": "\r\n
\r\n

ㄹㅇㄴㅁㄹㅇㄴㅁㅇㄹㅇㄴㅁ

\r\n
\r\n ", - "status": "success", - "messageId": "<5ea07d02-78bf-a655-8289-bcbd8eaf7741@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/b1d8f458-076c-4c44-982e-d2f46dcd4b03.json b/backend-node/data/mail-sent/b1d8f458-076c-4c44-982e-d2f46dcd4b03.json deleted file mode 100644 index 8f8d5059..00000000 --- a/backend-node/data/mail-sent/b1d8f458-076c-4c44-982e-d2f46dcd4b03.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "id": "b1d8f458-076c-4c44-982e-d2f46dcd4b03", - "sentAt": "2025-10-02T08:57:48.412Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "ㅁㄴㅇㄹ", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹ

\r\n
\r\n ", - "attachments": [ - { - "filename": "웨이스-임직원-프로파일-이희진.key", - "originalName": "웨이스-임직원-프로파일-이희진.key", - "size": 0, - "path": "/app/uploads/mail-attachments/1759395465488-120933172.key", - "mimetype": "application/x-iwork-keynote-sffkey" - }, - { - "filename": "UI_개선사항_문서.md", - "originalName": "UI_개선사항_문서.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759395465566-306126854.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "test용 이미지33.jpg", - "originalName": "test용 이미지33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759395465566-412984398.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "test용 이미지2.png", - "originalName": "test용 이미지2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759395465567-143883587.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/b75d0b2b-7d8a-461b-b854-2bebdef959e8.json b/backend-node/data/mail-sent/b75d0b2b-7d8a-461b-b854-2bebdef959e8.json deleted file mode 100644 index dbec91a5..00000000 --- a/backend-node/data/mail-sent/b75d0b2b-7d8a-461b-b854-2bebdef959e8.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "b75d0b2b-7d8a-461b-b854-2bebdef959e8", - "sentAt": "2025-10-02T08:49:30.356Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "한글2", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹ

\r\n
\r\n ", - "attachments": [ - { - "filename": "UI_áá¢áá¥á«áá¡áá¡á¼_áá®á«áá¥.md", - "originalName": "UI_áá¢áá¥á«áá¡áá¡á¼_áá®á«áá¥.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394969516-74008147_UI__________________________.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "testáá­á¼ ááµááµááµ33.jpg", - "originalName": "testáá­á¼ ááµááµááµ33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394969516-530544653_test_______________33.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "testáá­á¼ ááµááµááµ2.png", - "originalName": "testáá­á¼ ááµááµááµ2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394969517-260831218_test_______________2.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "<80a431a1-bb4d-31b5-2564-93f8c2539fd4@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/ccdd8961-1b3f-4b88-b838-51d6ed8f1601.json b/backend-node/data/mail-sent/ccdd8961-1b3f-4b88-b838-51d6ed8f1601.json deleted file mode 100644 index d2d4c424..00000000 --- a/backend-node/data/mail-sent/ccdd8961-1b3f-4b88-b838-51d6ed8f1601.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "ccdd8961-1b3f-4b88-b838-51d6ed8f1601", - "sentAt": "2025-10-02T08:47:03.481Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "한글테스트222", - "htmlContent": "\r\n
\r\n

2

\r\n
\r\n ", - "attachments": [ - { - "filename": "UI_áá¢áá¥á«áá¡áá¡á¼_áá®á«áá¥.md", - "originalName": "UI_áá¢áá¥á«áá¡áá¡á¼_áá®á«áá¥.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394821751-229305880_UI__________________________.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "testáá­á¼ ááµááµááµ33.jpg", - "originalName": "testáá­á¼ ááµááµááµ33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394821751-335146895_test_______________33.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "testáá­á¼ ááµááµááµ2.png", - "originalName": "testáá­á¼ ááµááµááµ2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394821753-911076131_test_______________2.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "<69519c70-a5cd-421d-9976-8c7014d69b39@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/e2801ec2-6219-4c3c-83b4-8a6834569488.json b/backend-node/data/mail-sent/e2801ec2-6219-4c3c-83b4-8a6834569488.json deleted file mode 100644 index 1a388699..00000000 --- a/backend-node/data/mail-sent/e2801ec2-6219-4c3c-83b4-8a6834569488.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "e2801ec2-6219-4c3c-83b4-8a6834569488", - "sentAt": "2025-10-13T00:59:46.729Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "제목 없음", - "htmlContent": "

텍스트 영역 1

\n 버튼1\n
\n \"\"\n

텍스트 영역2

텍스트 영역3

\n
\n \r\n
\r\n

추가메시지 영역

\r\n
\r\n \n
\n
", - "templateId": "template-1760315158387", - "templateName": "테스트2", - "attachments": [ - { - "filename": "한글.txt", - "originalName": "한글.txt", - "size": 0, - "path": "/app/uploads/mail-attachments/1760317184642-745285906.txt", - "mimetype": "text/plain" - } - ], - "status": "success", - "messageId": "<1e0abffb-a6cc-8312-d8b4-31c33cb72aa7@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/e93848a8-6901-44c4-b4db-27c8d2aeb8dd.json b/backend-node/data/mail-sent/e93848a8-6901-44c4-b4db-27c8d2aeb8dd.json deleted file mode 100644 index 74c8212f..00000000 --- a/backend-node/data/mail-sent/e93848a8-6901-44c4-b4db-27c8d2aeb8dd.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "id": "e93848a8-6901-44c4-b4db-27c8d2aeb8dd", - "sentAt": "2025-10-22T04:28:42.686Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "\"권은아\" " - ], - "subject": "Re: 매우 졸린 오후예요", - "htmlContent": "\r\n
\r\n

호홋 답장 기능을 구현했다죵
얼른 퇴근하고 싪네여

\r\n
\r\n

\r\n
\r\n

보낸 사람: \"권은아\"

\r\n

날짜: 2025. 10. 22. 오후 1:10:37

\r\n

제목: 매우 졸린 오후예요

\r\n
\r\n undefined\r\n
\r\n ", - "attachments": [ - { - "filename": "test용 이미지2.png", - "originalName": "test용 이미지2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1761107318152-717716316.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "<19981423-259b-0a50-e76d-23c860692c16@wace.me>", - "accepted": [ - "chna8137s@gmail.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/ee0d162c-48ad-4c00-8c56-ade80be4503f.json b/backend-node/data/mail-sent/ee0d162c-48ad-4c00-8c56-ade80be4503f.json deleted file mode 100644 index 45c6a1eb..00000000 --- a/backend-node/data/mail-sent/ee0d162c-48ad-4c00-8c56-ade80be4503f.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "ee0d162c-48ad-4c00-8c56-ade80be4503f", - "sentAt": "2025-10-02T08:48:29.740Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "한글한글", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹㅁㄴㅇㄹㅁㄴㅇㄹ

\r\n
\r\n ", - "attachments": [ - { - "filename": "UI_áá¢áá¥á«áá¡áá¡á¼_áá®á«áá¥.md", - "originalName": "UI_áá¢áá¥á«áá¡áá¡á¼_áá®á«áá¥.md", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394908877-38147683_UI__________________________.md", - "mimetype": "text/x-markdown" - }, - { - "filename": "testáá­á¼ ááµááµááµ33.jpg", - "originalName": "testáá­á¼ ááµááµááµ33.jpg", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394908879-80461065_test_______________33.jpg", - "mimetype": "image/jpeg" - }, - { - "filename": "testáá­á¼ ááµááµááµ2.png", - "originalName": "testáá­á¼ ááµááµááµ2.png", - "size": 0, - "path": "/app/uploads/mail-attachments/1759394908880-475630926_test_______________2.png", - "mimetype": "image/png" - } - ], - "status": "success", - "messageId": "<96205714-1a6b-adb7-7ae5-0e1e3fcb700b@wace.me>", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/fc26aba3-6b6e-47ba-91e8-609ae25e0e7d.json b/backend-node/data/mail-sent/fc26aba3-6b6e-47ba-91e8-609ae25e0e7d.json deleted file mode 100644 index f64daf8c..00000000 --- a/backend-node/data/mail-sent/fc26aba3-6b6e-47ba-91e8-609ae25e0e7d.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "fc26aba3-6b6e-47ba-91e8-609ae25e0e7d", - "sentAt": "2025-10-13T00:21:51.799Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "zian9227@naver.com" - ], - "subject": "test용입니다.", - "htmlContent": "\r\n
\r\n

ㅁㄴㅇㄹ

\r\n
\r\n ", - "templateId": "template-1759302346758", - "templateName": "test", - "attachments": [ - { - "filename": "웨이스-임직원-프로파일-이희진.key", - "originalName": "웨이스-임직원-프로파일-이희진.key", - "size": 0, - "path": "/app/uploads/mail-attachments/1760314910154-84512253.key", - "mimetype": "application/x-iwork-keynote-sffkey" - } - ], - "status": "success", - "messageId": "", - "accepted": [ - "zian9227@naver.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/data/mail-sent/fcea6149-a098-4212-aa00-baef0cc083d6.json b/backend-node/data/mail-sent/fcea6149-a098-4212-aa00-baef0cc083d6.json deleted file mode 100644 index efd9a0c0..00000000 --- a/backend-node/data/mail-sent/fcea6149-a098-4212-aa00-baef0cc083d6.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "fcea6149-a098-4212-aa00-baef0cc083d6", - "sentAt": "2025-10-22T04:24:54.126Z", - "accountId": "account-1759310844272", - "accountName": "이희진", - "accountEmail": "hjlee@wace.me", - "to": [ - "\"DHS\" " - ], - "subject": "Re: 안녕하세여", - "htmlContent": "\r\n
\r\n

어떻게 가는지 궁금한데 이따가 화면 보여주세영

\r\n
\r\n

\r\n
\r\n

보낸 사람: \"DHS\"

\r\n

날짜: 2025. 10. 22. 오후 1:09:49

\r\n

제목: 안녕하세여

\r\n
\r\n undefined\r\n
\r\n ", - "status": "success", - "messageId": "", - "accepted": [ - "ddhhss0603@gmail.com" - ], - "rejected": [] -} \ No newline at end of file diff --git a/backend-node/src/services/mailSendSimpleService.ts b/backend-node/src/services/mailSendSimpleService.ts index b4dce503..4e44006a 100644 --- a/backend-node/src/services/mailSendSimpleService.ts +++ b/backend-node/src/services/mailSendSimpleService.ts @@ -334,9 +334,12 @@ class MailSendSimpleService { if (variables) { buttonText = this.replaceVariables(buttonText, variables); } + // styles 객체 또는 직접 속성에서 색상 가져오기 + const buttonBgColor = component.styles?.backgroundColor || component.backgroundColor || '#007bff'; + const buttonTextColor = component.styles?.color || component.textColor || '#fff'; // 버튼은 왼쪽 정렬 (text-align 제거) html += ``; break; case 'image': @@ -348,6 +351,89 @@ class MailSendSimpleService { case 'spacer': html += `
`; break; + case 'header': + html += ` +
+ + + + + +
+ ${component.logoSrc ? `로고` : ''} + ${component.brandName || ''} + + ${component.sendDate || ''} +
+
+ `; + break; + case 'infoTable': + html += ` +
+ ${component.tableTitle ? `
${component.tableTitle}
` : ''} + + ${(component.rows || []).map((row: any, i: number) => ` + + + + + `).join('')} +
${row.label}${row.value}
+
+ `; + break; + case 'alertBox': + const alertColors: Record = { + info: { bg: '#eff6ff', border: '#3b82f6', text: '#1e40af' }, + warning: { bg: '#fffbeb', border: '#f59e0b', text: '#92400e' }, + danger: { bg: '#fef2f2', border: '#ef4444', text: '#991b1b' }, + success: { bg: '#ecfdf5', border: '#10b981', text: '#065f46' } + }; + const colors = alertColors[component.alertType || 'info']; + html += ` +
+ ${component.alertTitle ? `
${component.alertTitle}
` : ''} +
${component.content || ''}
+
+ `; + break; + case 'divider': + html += `
`; + break; + case 'footer': + html += ` +
+ ${component.companyName ? `
${component.companyName}
` : ''} + ${(component.ceoName || component.businessNumber) ? ` +
+ ${component.ceoName ? `대표: ${component.ceoName}` : ''} + ${component.ceoName && component.businessNumber ? ' | ' : ''} + ${component.businessNumber ? `사업자등록번호: ${component.businessNumber}` : ''} +
+ ` : ''} + ${component.address ? `
${component.address}
` : ''} + ${(component.phone || component.email) ? ` +
+ ${component.phone ? `Tel: ${component.phone}` : ''} + ${component.phone && component.email ? ' | ' : ''} + ${component.email ? `Email: ${component.email}` : ''} +
+ ` : ''} + ${component.copyright ? `
${component.copyright}
` : ''} +
+ `; + break; + case 'numberedList': + html += ` +
+ ${component.listTitle ? `
${component.listTitle}
` : ''} +
    + ${(component.listItems || []).map((item: string) => `
  1. ${item}
  2. `).join('')} +
+
+ `; + break; } }); diff --git a/backend-node/src/services/mailTemplateFileService.ts b/backend-node/src/services/mailTemplateFileService.ts index adb72fff..bd82a7d2 100644 --- a/backend-node/src/services/mailTemplateFileService.ts +++ b/backend-node/src/services/mailTemplateFileService.ts @@ -4,13 +4,35 @@ import path from "path"; // MailComponent 인터페이스 정의 export interface MailComponent { id: string; - type: "text" | "button" | "image" | "spacer"; + type: "text" | "button" | "image" | "spacer" | "header" | "infoTable" | "alertBox" | "divider" | "footer" | "numberedList"; content?: string; text?: string; url?: string; src?: string; height?: number; styles?: Record; + // 헤더 컴포넌트용 + logoSrc?: string; + brandName?: string; + sendDate?: string; + headerBgColor?: string; + // 정보 테이블용 + rows?: Array<{ label: string; value: string }>; + tableTitle?: string; + // 강조 박스용 + alertType?: "info" | "warning" | "danger" | "success"; + alertTitle?: string; + // 푸터용 + companyName?: string; + ceoName?: string; + businessNumber?: string; + address?: string; + phone?: string; + email?: string; + copyright?: string; + // 번호 리스트용 + listItems?: string[]; + listTitle?: string; } // QueryConfig 인터페이스 정의 (사용하지 않지만 타입 호환성 유지) @@ -236,6 +258,89 @@ class MailTemplateFileService { case "spacer": html += `
`; break; + case "header": + html += ` +
+ + + + + +
+ ${comp.logoSrc ? `로고` : ''} + ${comp.brandName || ''} + + ${comp.sendDate || ''} +
+
+ `; + break; + case "infoTable": + html += ` +
+ ${comp.tableTitle ? `
${comp.tableTitle}
` : ''} + + ${(comp.rows || []).map((row, i) => ` + + + + + `).join('')} +
${row.label}${row.value}
+
+ `; + break; + case "alertBox": + const alertColors: Record = { + info: { bg: '#eff6ff', border: '#3b82f6', text: '#1e40af' }, + warning: { bg: '#fffbeb', border: '#f59e0b', text: '#92400e' }, + danger: { bg: '#fef2f2', border: '#ef4444', text: '#991b1b' }, + success: { bg: '#ecfdf5', border: '#10b981', text: '#065f46' } + }; + const colors = alertColors[comp.alertType || 'info']; + html += ` +
+ ${comp.alertTitle ? `
${comp.alertTitle}
` : ''} +
${comp.content || ''}
+
+ `; + break; + case "divider": + html += `
`; + break; + case "footer": + html += ` +
+ ${comp.companyName ? `
${comp.companyName}
` : ''} + ${(comp.ceoName || comp.businessNumber) ? ` +
+ ${comp.ceoName ? `대표: ${comp.ceoName}` : ''} + ${comp.ceoName && comp.businessNumber ? ' | ' : ''} + ${comp.businessNumber ? `사업자등록번호: ${comp.businessNumber}` : ''} +
+ ` : ''} + ${comp.address ? `
${comp.address}
` : ''} + ${(comp.phone || comp.email) ? ` +
+ ${comp.phone ? `Tel: ${comp.phone}` : ''} + ${comp.phone && comp.email ? ' | ' : ''} + ${comp.email ? `Email: ${comp.email}` : ''} +
+ ` : ''} + ${comp.copyright ? `
${comp.copyright}
` : ''} +
+ `; + break; + case "numberedList": + html += ` +
+ ${comp.listTitle ? `
${comp.listTitle}
` : ''} +
    + ${(comp.listItems || []).map(item => `
  1. ${item}
  2. `).join('')} +
+
+ `; + break; } }); diff --git a/backend-node/src/services/screenManagementService.ts b/backend-node/src/services/screenManagementService.ts index a7445637..71550fd6 100644 --- a/backend-node/src/services/screenManagementService.ts +++ b/backend-node/src/services/screenManagementService.ts @@ -70,12 +70,13 @@ export class ScreenManagementService { throw new Error("이미 존재하는 화면 코드입니다."); } - // 화면 생성 (Raw Query) + // 화면 생성 (Raw Query) - REST API 지원 추가 const [screen] = await query( `INSERT INTO screen_definitions ( screen_name, screen_code, table_name, company_code, description, created_by, - db_source_type, db_connection_id - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + db_source_type, db_connection_id, data_source_type, rest_api_connection_id, + rest_api_endpoint, rest_api_json_path + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING *`, [ screenData.screenName, @@ -86,6 +87,10 @@ export class ScreenManagementService { screenData.createdBy, screenData.dbSourceType || "internal", screenData.dbConnectionId || null, + (screenData as any).dataSourceType || "database", + (screenData as any).restApiConnectionId || null, + (screenData as any).restApiEndpoint || null, + (screenData as any).restApiJsonPath || "data", ] ); @@ -1977,6 +1982,11 @@ export class ScreenManagementService { updatedBy: data.updated_by, dbSourceType: data.db_source_type || "internal", dbConnectionId: data.db_connection_id || undefined, + // REST API 관련 필드 + dataSourceType: data.data_source_type || "database", + restApiConnectionId: data.rest_api_connection_id || undefined, + restApiEndpoint: data.rest_api_endpoint || undefined, + restApiJsonPath: data.rest_api_json_path || "data", }; } diff --git a/backend-node/src/types/screen.ts b/backend-node/src/types/screen.ts index ca5a466f..8260f3c6 100644 --- a/backend-node/src/types/screen.ts +++ b/backend-node/src/types/screen.ts @@ -154,6 +154,11 @@ export interface ScreenDefinition { updatedBy?: string; dbSourceType?: "internal" | "external"; dbConnectionId?: number; + // REST API 관련 필드 + dataSourceType?: "database" | "restapi"; + restApiConnectionId?: number; + restApiEndpoint?: string; + restApiJsonPath?: string; } // 화면 생성 요청 @@ -166,6 +171,11 @@ export interface CreateScreenRequest { createdBy?: string; dbSourceType?: "internal" | "external"; dbConnectionId?: number; + // REST API 관련 필드 + dataSourceType?: "database" | "restapi"; + restApiConnectionId?: number; + restApiEndpoint?: string; + restApiJsonPath?: string; } // 화면 수정 요청 diff --git a/frontend/app/(main)/admin/mail/send/page.tsx b/frontend/app/(main)/admin/mail/send/page.tsx index 9f368f13..56922043 100644 --- a/frontend/app/(main)/admin/mail/send/page.tsx +++ b/frontend/app/(main)/admin/mail/send/page.tsx @@ -45,6 +45,7 @@ import { saveDraft, updateDraft, } from "@/lib/api/mail"; +import { API_BASE_URL } from "@/lib/api/client"; import { useToast } from "@/hooks/use-toast"; export default function MailSendPage() { @@ -498,7 +499,7 @@ ${data.originalBody}`; throw new Error("인증 토큰이 없습니다. 다시 로그인해주세요."); } - const response = await fetch("/api/mail/send/simple", { + const response = await fetch(`${API_BASE_URL}/mail/send/simple`, { method: "POST", headers: { Authorization: `Bearer ${authToken}`, @@ -1226,6 +1227,91 @@ ${data.originalBody}`; 여백 ); + + case 'header': + return ( +
+
+
+ {component.logoSrc && 로고} + {component.brandName} +
+ {component.sendDate} +
+
+ ); + + case 'infoTable': + return ( +
+ {component.tableTitle && ( +
{component.tableTitle}
+ )} + + + {component.rows?.map((row: any, i: number) => ( + + + + + ))} + +
{row.label}{row.value}
+
+ ); + + case 'alertBox': + return ( +
+ {component.alertTitle &&
{component.alertTitle}
} +
{component.content}
+
+ ); + + case 'divider': + return ( +
+ ); + + case 'footer': + return ( +
+ {component.companyName &&
{component.companyName}
} + {(component.ceoName || component.businessNumber) && ( +
+ {component.ceoName && 대표: {component.ceoName}} + {component.ceoName && component.businessNumber && |} + {component.businessNumber && 사업자등록번호: {component.businessNumber}} +
+ )} + {component.address &&
{component.address}
} + {(component.phone || component.email) && ( +
+ {component.phone && Tel: {component.phone}} + {component.phone && component.email && |} + {component.email && Email: {component.email}} +
+ )} + {component.copyright &&
{component.copyright}
} +
+ ); + + case 'numberedList': + return ( +
+ {component.listTitle &&
{component.listTitle}
} +
    + {component.listItems?.map((item: string, i: number) => ( +
  1. {item}
  2. + ))} +
+
+ ); default: return null; diff --git a/frontend/components/mail/MailDesigner.tsx b/frontend/components/mail/MailDesigner.tsx index 8d3a38f9..464de85d 100644 --- a/frontend/components/mail/MailDesigner.tsx +++ b/frontend/components/mail/MailDesigner.tsx @@ -19,19 +19,50 @@ import { Trash2, Settings, Upload, - X + X, + GripVertical, + ChevronUp, + ChevronDown, + LayoutTemplate, + Table2, + AlertCircle, + Minus, + Building2, + ListOrdered } from "lucide-react"; import { getMailTemplates } from "@/lib/api/mail"; export interface MailComponent { id: string; - type: "text" | "button" | "image" | "spacer" | "table"; + type: "text" | "button" | "image" | "spacer" | "table" | "header" | "infoTable" | "alertBox" | "divider" | "footer" | "numberedList"; content?: string; text?: string; url?: string; src?: string; height?: number; styles?: Record; + // 헤더 컴포넌트용 + logoSrc?: string; + brandName?: string; + sendDate?: string; + headerBgColor?: string; + // 정보 테이블용 + rows?: Array<{ label: string; value: string }>; + tableTitle?: string; + // 강조 박스용 + alertType?: "info" | "warning" | "danger" | "success"; + alertTitle?: string; + // 푸터용 + companyName?: string; + ceoName?: string; + businessNumber?: string; + address?: string; + phone?: string; + email?: string; + copyright?: string; + // 번호 리스트용 + listItems?: string[]; + listTitle?: string; } export interface QueryConfig { @@ -64,6 +95,10 @@ export default function MailDesigner({ const [subject, setSubject] = useState(""); const [queries, setQueries] = useState([]); const [isLoading, setIsLoading] = useState(false); + + // 드래그 앤 드롭 상태 + const [draggedIndex, setDraggedIndex] = useState(null); + const [dragOverIndex, setDragOverIndex] = useState(null); // 템플릿 데이터 로드 (수정 모드) useEffect(() => { @@ -96,10 +131,18 @@ export default function MailDesigner({ // 컴포넌트 타입 정의 const componentTypes = [ - { type: "text", icon: Type, label: "텍스트", color: "bg-primary/20 hover:bg-blue-200" }, - { type: "button", icon: MousePointer, label: "버튼", color: "bg-success/20 hover:bg-success/30" }, - { type: "image", icon: ImageIcon, label: "이미지", color: "bg-purple-100 hover:bg-purple-200" }, - { type: "spacer", icon: Square, label: "여백", color: "bg-muted hover:bg-muted/80" }, + // 레이아웃 컴포넌트 + { type: "header", icon: LayoutTemplate, label: "헤더", color: "bg-indigo-100 hover:bg-indigo-200", category: "layout" }, + { type: "divider", icon: Minus, label: "구분선", color: "bg-gray-100 hover:bg-gray-200", category: "layout" }, + { type: "spacer", icon: Square, label: "여백", color: "bg-muted hover:bg-muted/80", category: "layout" }, + { type: "footer", icon: Building2, label: "푸터", color: "bg-slate-100 hover:bg-slate-200", category: "layout" }, + // 컨텐츠 컴포넌트 + { type: "text", icon: Type, label: "텍스트", color: "bg-primary/20 hover:bg-blue-200", category: "content" }, + { type: "button", icon: MousePointer, label: "버튼", color: "bg-success/20 hover:bg-success/30", category: "content" }, + { type: "image", icon: ImageIcon, label: "이미지", color: "bg-purple-100 hover:bg-purple-200", category: "content" }, + { type: "infoTable", icon: Table2, label: "정보 테이블", color: "bg-cyan-100 hover:bg-cyan-200", category: "content" }, + { type: "alertBox", icon: AlertCircle, label: "안내 박스", color: "bg-amber-100 hover:bg-amber-200", category: "content" }, + { type: "numberedList", icon: ListOrdered, label: "번호 리스트", color: "bg-emerald-100 hover:bg-emerald-200", category: "content" }, ]; // 컴포넌트 추가 @@ -107,21 +150,75 @@ export default function MailDesigner({ const newComponent: MailComponent = { id: `comp-${Date.now()}`, type: type as any, - content: type === "text" ? "" : undefined, // 🎯 빈 문자열로 시작 (HTML 태그 제거) - text: type === "button" ? "버튼 텍스트" : undefined, // 🎯 더 명확한 기본값 - url: type === "button" || type === "image" ? "" : undefined, // 🎯 빈 문자열로 시작 - src: type === "image" ? "https://placehold.co/600x200/e5e7eb/64748b?text=이미지를+업로드하세요" : undefined, // 🎯 한글 안내 - height: type === "spacer" ? 30 : undefined, // 🎯 기본값 30px로 증가 (더 적절한 간격) + content: type === "text" ? "" : undefined, + text: type === "button" ? "버튼 텍스트" : undefined, + url: type === "button" || type === "image" ? "" : undefined, + src: type === "image" ? "https://placehold.co/600x200/e5e7eb/64748b?text=이미지를+업로드하세요" : undefined, + height: type === "spacer" ? 30 : type === "divider" ? 1 : undefined, styles: { - padding: "10px", + padding: type === "divider" ? "0" : "10px", backgroundColor: type === "button" ? "#007bff" : "transparent", color: type === "button" ? "#fff" : "#333", }, + // 헤더 기본값 + logoSrc: type === "header" ? "" : undefined, + brandName: type === "header" ? "회사명" : undefined, + sendDate: type === "header" ? new Date().toLocaleDateString("ko-KR") : undefined, + headerBgColor: type === "header" ? "#f8f9fa" : undefined, + // 정보 테이블 기본값 + rows: type === "infoTable" ? [{ label: "항목", value: "내용" }] : undefined, + tableTitle: type === "infoTable" ? "" : undefined, + // 안내 박스 기본값 + alertType: type === "alertBox" ? "info" : undefined, + alertTitle: type === "alertBox" ? "안내" : undefined, + // 푸터 기본값 + companyName: type === "footer" ? "회사명" : undefined, + ceoName: type === "footer" ? "" : undefined, + businessNumber: type === "footer" ? "" : undefined, + address: type === "footer" ? "" : undefined, + phone: type === "footer" ? "" : undefined, + email: type === "footer" ? "" : undefined, + copyright: type === "footer" ? `© ${new Date().getFullYear()} All rights reserved.` : undefined, + // 번호 리스트 기본값 + listItems: type === "numberedList" ? ["첫 번째 항목"] : undefined, + listTitle: type === "numberedList" ? "" : undefined, }; setComponents([...components, newComponent]); }; + // 드래그 앤 드롭 핸들러 + const handleDragStart = (index: number) => { + setDraggedIndex(index); + }; + + const handleDragOver = (e: React.DragEvent, index: number) => { + e.preventDefault(); + if (draggedIndex !== null && draggedIndex !== index) { + setDragOverIndex(index); + } + }; + + const handleDrop = (index: number) => { + if (draggedIndex !== null && draggedIndex !== index) { + moveComponent(draggedIndex, index); + } + setDraggedIndex(null); + setDragOverIndex(null); + }; + + const handleDragEnd = () => { + setDraggedIndex(null); + setDragOverIndex(null); + }; + + const moveComponent = (fromIndex: number, toIndex: number) => { + const newComponents = [...components]; + const [movedItem] = newComponents.splice(fromIndex, 1); + newComponents.splice(toIndex, 0, movedItem); + setComponents(newComponents); + }; + // 컴포넌트 삭제 const removeComponent = (id: string) => { setComponents(components.filter(c => c.id !== id)); @@ -189,13 +286,35 @@ export default function MailDesigner({
{/* 왼쪽: 컴포넌트 팔레트 */}
+ {/* 레이아웃 컴포넌트 */} +
+

+ + 레이아웃 +

+
+ {componentTypes.filter(c => c.category === "layout").map(({ type, icon: Icon, label, color }) => ( + + ))} +
+
+ + {/* 컨텐츠 컴포넌트 */}

- 컴포넌트 + 컨텐츠

- {componentTypes.map(({ type, icon: Icon, label, color }) => ( + {componentTypes.filter(c => c.category === "content").map(({ type, icon: Icon, label, color }) => ( +
+ +
+ +
+ + {/* 순서 배지 */} +
+ {index + 1} +
+ {/* 삭제 버튼 */}
-
-

- 추천값:
- • 좁은 간격: 10~20 픽셀
- • 보통 간격: 30~50 픽셀
- • 넓은 간격: 60~100 픽셀 -

+
+
+ )} + + {/* 헤더 컴포넌트 */} + {selected.type === "header" && ( +
+
+ + updateComponent(selected.id, { brandName: e.target.value })} + placeholder="회사명" + className="mt-1" + /> +
+
+ + updateComponent(selected.id, { logoSrc: e.target.value })} + placeholder="https://example.com/logo.png" + className="mt-1" + /> +
+
+ + updateComponent(selected.id, { sendDate: e.target.value })} + className="mt-1" + /> +
+
+ +
+ updateComponent(selected.id, { headerBgColor: e.target.value })} + className="w-16 h-10" + /> + {selected.headerBgColor || "#f8f9fa"} +
+
+
+ )} + + {/* 정보 테이블 컴포넌트 */} + {selected.type === "infoTable" && ( +
+
+ + updateComponent(selected.id, { tableTitle: e.target.value })} + placeholder="예: 주문 정보" + className="mt-1" + /> +
+
+ +
+ {selected.rows?.map((row, i) => ( +
+ { + const newRows = [...(selected.rows || [])]; + newRows[i] = { ...newRows[i], label: e.target.value }; + updateComponent(selected.id, { rows: newRows }); + }} + placeholder="항목명" + className="flex-1" + /> + { + const newRows = [...(selected.rows || [])]; + newRows[i] = { ...newRows[i], value: e.target.value }; + updateComponent(selected.id, { rows: newRows }); + }} + placeholder="값" + className="flex-1" + /> + +
+ ))} + +
+
+
+ )} + + {/* 안내 박스 컴포넌트 */} + {selected.type === "alertBox" && ( +
+
+ +
+ {(["info", "warning", "danger", "success"] as const).map((type) => ( + + ))} +
+
+
+ + updateComponent(selected.id, { alertTitle: e.target.value })} + placeholder="안내 제목" + className="mt-1" + /> +
+
+ +