[{"data":1,"prerenderedAt":935},["ShallowReactive",2],{"doc:\u002Fhistory\u002Fhistory.20260511":3},{"id":4,"title":5,"body":6,"description":907,"extension":928,"meta":929,"navigation":930,"path":931,"seo":932,"stem":933,"__hash__":934},"docs\u002Fhistory\u002Fhistory.20260511.md","2026-05-11 — 프로젝트 착수",{"type":7,"value":8,"toc":906},"minimark",[9,13,18,34,37,41,202,206,209,231,234,251,255,269,273,306,310,317,484,515,519,529,585,588,592,607,612,650,654,668,672,707,710,739,743,758,801,805,832,836,842,849,851,855,888,892],[10,11,5],"h1",{"id":12},"_2026-05-11-프로젝트-착수",[14,15,17],"h2",{"id":16},"한-줄-요약","한 줄 요약",[19,20,21,22,26,27,26,30,33],"p",{},"맑은 메시징 SaaS의 세 레포(",[23,24,25],"code",{},"malgn-noti"," \u002F ",[23,28,29],{},"malgn-noti-admin",[23,31,32],{},"malgn-noti-api",")를 부트스트랩하고 첫 배포까지 마쳤다.",[35,36],"hr",{},[14,38,40],{"id":39},"_1-큰-결정","1. 큰 결정",[42,43,44,57],"table",{},[45,46,47],"thead",{},[48,49,50,54],"tr",{},[51,52,53],"th",{},"영역",[51,55,56],{},"결정",[58,59,60,72,92,107,115,133,145,156,171,179,194],"tbody",{},[48,61,62,66],{},[63,64,65],"td",{},"프로젝트 구조",[63,67,68,69],{},"3개 레포(사용자단·운영자단·API) 형제 디렉토리 + GitHub ",[23,70,71],{},"malgnsoft\u002F*",[48,73,74,77],{},[63,75,76],{},"프론트 스택",[63,78,79,91],{},[80,81,82,83,86,87,90],"strong",{},"Nuxt 3.21 + ",[23,84,85],{},"compatibilityVersion: 4"," (Nuxt 4 호환 모드, ",[23,88,89],{},"app\u002F"," 디렉토리)"," + Vue 3.5 + TS 5.9",[48,93,94,97],{},[63,95,96],{},"UI 라이브러리",[63,98,99,102,103,106],{},[80,100,101],{},"Nuxt UI v3 (MIT)"," 단일 — Reka UI + Tailwind v4 통합. ",[23,104,105],{},"@nuxtjs\u002Ftailwindcss"," 미설치",[48,108,109,112],{},[63,110,111],{},"폰트",[63,113,114],{},"Noto Sans KR (Google Fonts)",[48,116,117,120],{},[63,118,119],{},"아이콘",[63,121,122,123,26,126,26,129,132],{},"Iconify — ",[23,124,125],{},"lucide",[23,127,128],{},"heroicons",[23,130,131],{},"bi","(시안 매칭)",[48,134,135,138],{},[63,136,137],{},"API 스택",[63,139,140,141,144],{},"Cloudflare Workers + ",[80,142,143],{},"Hono 4"," + TypeScript",[48,146,147,150],{},[63,148,149],{},"DB",[63,151,152,155],{},[80,153,154],{},"AWS Aurora MySQL 8.0"," (D1 아님)",[48,157,158,161],{},[63,159,160],{},"DB 연결",[63,162,163,166,167,170],{},[80,164,165],{},"Cloudflare Hyperdrive(MySQL)"," + ",[23,168,169],{},"mysql2"," 확정 (RDS Data API 미채택)",[48,172,173,176],{},[63,174,175],{},"Aurora 노출",[63,177,178],{},"퍼블릭 엔드포인트 + SG에 Hyperdrive egress IP 화이트리스트 (개발 단계)",[48,180,181,184],{},[63,182,183],{},"지원 채널",[63,185,186,187,190,191],{},"SMS\u002FLMS\u002FMMS · ",[80,188,189],{},"RCS"," · 알림톡\u002F친구톡 · Email · Push (5) + ",[80,192,193],{},"Flow(복합)",[48,195,196,199],{},[63,197,198],{},"배포 트리거",[63,200,201],{},"wrangler CLI 직접 배포 (GitHub Actions 자동화는 추후)",[14,203,205],{"id":204},"_2-claudemd-3개-작성","2. CLAUDE.md 3개 작성",[19,207,208],{},"세 디렉토리에 프로젝트 컨텍스트 문서를 작성.",[210,211,212,219,225],"ul",{},[213,214,215,218],"li",{},[23,216,217],{},"malgn-noti\u002FCLAUDE.md"," — 사용자단 (Nuxt 3 + Nuxt UI)",[213,220,221,224],{},[23,222,223],{},"malgn-noti-admin\u002FCLAUDE.md"," — 운영자단(BackOffice)",[213,226,227,230],{},[23,228,229],{},"malgn-noti-api\u002FCLAUDE.md"," — API (Workers + Hono + Aurora via Hyperdrive)",[19,232,233],{},"각 문서에 공통 원칙 명시:",[210,235,236,239,242,245,248],{},[213,237,238],{},"NHN\u002FPG\u002FAI 직접 호출은 api 서버만",[213,240,241],{},"시크릿\u002FAppKey는 envelope 암호화 후 DB 저장, 프론트 노출 금지",[213,243,244],{},"Flow(채널 폴백)는 NHN 콘솔이 아니라 우리 백엔드에서 정의·실행",[213,246,247],{},"크레딧 차감은 hold → 확정\u002F환불, append-only 원장 + 멱등키",[213,249,250],{},"admin은 사내망\u002FAccess로 보호",[14,252,254],{"id":253},"_3-nhn-notification-hub-정찰","3. NHN Notification Hub 정찰",[210,256,257,263,266],{},[213,258,259,260],{},"공식 문서 ",[23,261,262],{},"docs.nhncloud.com\u002F...\u002FNotification%20Hub\u002Fko\u002Foverview\u002F",[213,264,265],{},"통합 6채널 (SMS · 알림톡 · RCS · Email · Push · 친구톡), 발송량 제한(SMS 월 5,000 \u002F 알림톡 일 1,000), 플로우(폴백) 기능 확인",[213,267,268],{},"우리 백엔드에서 자체 Flow 엔진 구현하기로 결정 — 멀티 테넌트 한도\u002F감사 통합 위함",[14,270,272],{"id":271},"_4-사용자단-시안-분석-정본화","4. 사용자단 시안 분석 (정본화)",[210,274,275,284,290,296,299],{},[213,276,277,278],{},"외부 시안: ",[279,280,281],"a",{"href":281,"rel":282},"https:\u002F\u002Fmalgn-notifications.pages.dev\u002F#\u002Fpagelists",[283],"nofollow",[213,285,286,287],{},"ViewLogic Router 기반 SPA, 페이지 데이터는 ",[23,288,289],{},"\u002Fsrc\u002Flogic\u002Fpagelists.js",[213,291,292,295],{},[80,293,294],{},"263개 페이지\u002F팝업 · 16 카테고리"," 추출 → 단일 정본(SoT)으로 채택",[213,297,298],{},"1급 도메인: 단발 발송 \u002F 캠페인 \u002F 채널별 이력+통계 \u002F 주소록 \u002F 발신 인프라 6종 \u002F 템플릿+카테고리+샘플+AI \u002F 크레딧 \u002F 결제 \u002F 1:1 문의 \u002F 회원가입+OTP+휴대폰 인증 \u002F ExportJob",[213,300,301,302,305],{},"메모리에 ",[23,303,304],{},"reference_user_console_sitemap.md","로 정본 위치 기록",[14,307,309],{"id":308},"_5-사용자단-nuxt-부트스트랩","5. 사용자단 Nuxt 부트스트랩",[19,311,312,313,316],{},"빈 디렉토리에 Nuxt 프로젝트 직접 작성 (",[23,314,315],{},"nuxi init"," 미사용).",[42,318,319,328],{},[45,320,321],{},[48,322,323,325],{},[51,324,53],{},[51,326,327],{},"산출물",[58,329,330,362,387,406,423,431,447,458,469],{},[48,331,332,335],{},[63,333,334],{},"기본 설정",[63,336,337,340,341,340,344,340,347,340,350,340,353,340,356,340,359],{},[23,338,339],{},"package.json"," · ",[23,342,343],{},"nuxt.config.ts",[23,345,346],{},"tsconfig.json",[23,348,349],{},".gitignore",[23,351,352],{},".editorconfig",[23,354,355],{},".env.example",[23,357,358],{},".npmrc",[23,360,361],{},"eslint.config.mjs",[48,363,364,367],{},[63,365,366],{},"진입",[63,368,369,340,372,375,376,379,380,383,384],{},[23,370,371],{},"app\u002Fapp.vue",[23,373,374],{},"app\u002Fapp.config.ts"," (",[23,377,378],{},"primary: indigo",", ",[23,381,382],{},"neutral: slate",") · ",[23,385,386],{},"app\u002Fassets\u002Fcss\u002Fmain.css",[48,388,389,392],{},[63,390,391],{},"레이아웃 3종",[63,393,394,397,398,401,402,405],{},[23,395,396],{},"default","(AppShell) · ",[23,399,400],{},"auth","(중앙 카드) · ",[23,403,404],{},"blank","(시스템 페이지)",[48,407,408,411],{},[63,409,410],{},"컴포넌트 3종",[63,412,413,416,417,340,420],{},[23,414,415],{},"AppShell.vue","(좌측 사이드바) · ",[23,418,419],{},"AppPagePlaceholder.vue",[23,421,422],{},"AppConfirmDialog.vue",[48,424,425,428],{},[63,426,427],{},"페이지 골격",[63,429,430],{},"50개 페이지 (16카테고리 전체)",[48,432,433,436],{},[63,434,435],{},"composables 3종",[63,437,438,340,441,340,444],{},[23,439,440],{},"useApi",[23,442,443],{},"useExportJob",[23,445,446],{},"useAiTemplate",[48,448,449,452],{},[63,450,451],{},"middleware",[63,453,454,457],{},[23,455,456],{},"auth.global.ts"," (현재 통과 스텁)",[48,459,460,463],{},[63,461,462],{},"store",[63,464,465,468],{},[23,466,467],{},"stores\u002Fauth.ts"," (Pinia)",[48,470,471,474],{},[63,472,473],{},"types",[63,475,476,479,480,483],{},[23,477,478],{},"domain.ts"," (Channel\u002FTenant\u002FUser) · ",[23,481,482],{},"api.ts"," (Paginated\u002FExportJob)",[210,485,486,492,509],{},[213,487,488,491],{},[23,489,490],{},"pnpm install","로 의존성 863개 설치",[213,493,494,497,498,501,502,379,505,508],{},[23,495,496],{},"pnpm typecheck"," 통과 (5개 초기 타입 에러 수정: ",[23,499,500],{},"$Fetch"," 타입, ",[23,503,504],{},"titleTemplate",[23,506,507],{},"process.env",")",[213,510,511,514],{},[23,512,513],{},"pnpm dev","로 dev server 시동 성공 (port 3000)",[14,516,518],{"id":517},"_6-git-연결-github-푸시","6. Git 연결 + GitHub 푸시",[19,520,521,522,166,525,528],{},"세 디렉토리 모두 ",[23,523,524],{},"git init -b main",[23,526,527],{},"origin"," 추가 + 첫 커밋 + 푸시.",[42,530,531,544],{},[45,532,533],{},[48,534,535,538,541],{},[51,536,537],{},"레포",[51,539,540],{},"URL",[51,542,543],{},"첫 커밋",[58,545,546,559,572],{},[48,547,548,550,556],{},[63,549,25],{},[63,551,552],{},[279,553,554],{"href":554,"rel":555},"https:\u002F\u002Fgithub.com\u002Fmalgnsoft\u002Fmalgn-noti",[283],[63,557,558],{},"Nuxt 3 + Nuxt UI 사용자단 부트스트랩",[48,560,561,563,569],{},[63,562,32],{},[63,564,565],{},[279,566,567],{"href":567,"rel":568},"https:\u002F\u002Fgithub.com\u002Fmalgnsoft\u002Fmalgn-noti-api",[283],[63,570,571],{},"CLAUDE.md (Cloudflare Workers + Hono + Aurora MySQL)",[48,573,574,576,582],{},[63,575,29],{},[63,577,578],{},[279,579,580],{"href":580,"rel":581},"https:\u002F\u002Fgithub.com\u002Fmalgnsoft\u002Fmalgn-noti-admin",[283],[63,583,584],{},"CLAUDE.md (BackOffice 관리자단)",[19,586,587],{},"커밋 메시지에 Claude co-author trailer 포함.",[14,589,591],{"id":590},"_7-cloudflare-첫-배포","7. Cloudflare 첫 배포",[19,593,594,597,598,602,603,606],{},[23,595,596],{},"wrangler whoami"," 인증 확인 (",[279,599,601],{"href":600},"mailto:info@malgnsoft.com","info@malgnsoft.com",", account ",[23,604,605],{},"d2b8c5524b...","). 필요 권한(workers\u002Fpages\u002Fd1\u002Fqueues\u002Fhyperdrive) 보유.",[608,609,611],"h3",{"id":610},"_71-사용자단-malgn-noti","7.1 사용자단 (malgn-noti)",[210,613,614,623,633,638,643],{},[213,615,616,618,619,622],{},[23,617,343],{},"에 ",[23,620,621],{},"nitro.preset: 'cloudflare-pages'"," 추가",[213,624,625,628,629,632],{},[23,626,627],{},"pnpm build"," → ",[23,630,631],{},"dist\u002F"," 산출 (1.37 MB \u002F 400 KB gzip)",[213,634,635],{},[23,636,637],{},"wrangler pages project create malgn-noti --production-branch=main",[213,639,640],{},[23,641,642],{},"wrangler pages deploy dist --project-name=malgn-noti --branch=main",[213,644,645,646],{},"production: ",[279,647,648],{"href":648,"rel":649},"https:\u002F\u002Fmalgn-noti.pages.dev",[283],[608,651,653],{"id":652},"_72-운영자단-malgn-noti-admin","7.2 운영자단 (malgn-noti-admin)",[210,655,656,662],{},[213,657,658,661],{},[23,659,660],{},"public\u002Findex.html","로 placeholder 정적 페이지 1개",[213,663,645,664],{},[279,665,666],{"href":666,"rel":667},"https:\u002F\u002Fmalgn-noti-admin.pages.dev",[283],[608,669,671],{"id":670},"_73-api-malgn-noti-api","7.3 API (malgn-noti-api)",[210,673,674,687,695,700],{},[213,675,676,677,680,681,379,684,508],{},"최소 Hono Worker (",[23,678,679],{},"src\u002Findex.ts",": ",[23,682,683],{},"\u002F",[23,685,686],{},"\u002Fhealth",[213,688,689,680,692],{},[23,690,691],{},"wrangler.toml",[23,693,694],{},"nodejs_compat",[213,696,697],{},[23,698,699],{},"wrangler deploy",[213,701,702,703],{},"endpoint: ",[279,704,705],{"href":705,"rel":706},"https:\u002F\u002Fmalgn-noti-api.malgnsoft.workers.dev",[283],[19,708,709],{},"응답 검증:",[210,711,712,718,724,730],{},[213,713,714,717],{},[23,715,716],{},"\u002Fhome"," HTTP 200 (54 KB)",[213,719,720,723],{},[23,721,722],{},"\u002Flogin"," HTTP 200 (auth 레이아웃)",[213,725,726,729],{},[23,727,728],{},"\u002F404"," HTTP 200 (blank 레이아웃)",[213,731,732,735,736],{},[23,733,734],{},"\u002Fapi\u002Fhealth"," ",[23,737,738],{},"{\"ok\":true,\"env\":\"production\",...}",[14,740,742],{"id":741},"_8-시안-디자인-매칭-1차-gnb-도입","8. 시안 디자인 매칭 1차 — GNB 도입",[19,744,745,746,749,750,753,754,757],{},"시안 분석 결과 ",[80,747,748],{},"시안은 사이드바가 아니라 상단 GNB 방식","임을 확인. 우리 ",[23,751,752],{},"AppShell","(좌측 사이드바)을 폐기하고 ",[23,755,756],{},"AppGnb","(상단 가로 네비)로 교체.",[210,759,760,782,792,798],{},[213,761,762,764,765],{},[23,763,386],{},"에 시안 정본의 CSS 변수 도입\n",[210,766,767],{},[213,768,769,772,773,379,776,379,779],{},[23,770,771],{},"--primary-color: #6366f1",", gray 11단, brand ",[23,774,775],{},"sky-soft\u002Fsky\u002Fsky-vivid\u002Findigo",[23,777,778],{},"--gnb-height: 64px",[23,780,781],{},"--content-max: 1320px",[213,783,784,787,788,791],{},[23,785,786],{},"AppGnb.vue"," 작성: 시안 ",[23,789,790],{},".gnb-*"," 클래스 그대로 차용 (sticky, hover dropdown, 사용자 아바타 드롭다운 + 크레딧 표시)",[213,793,794,797],{},[23,795,796],{},"layouts\u002Fdefault.vue","를 GNB 기반으로 갈아끼움",[213,799,800],{},"home 페이지 시안 톤으로 리디자인 (그라데이션 크레딧 카드 + 6채널 빠른 발송 + 2단 콘텐츠)",[14,802,804],{"id":803},"_9-푸터-추가","9. 푸터 추가",[210,806,807,814,823,826,829],{},[213,808,809,810,813],{},"시안 base.css의 ",[23,811,812],{},".footer-upper\u002F.footer-lower"," 클래스 그대로 차용",[213,815,816,819,820,822],{},[23,817,818],{},"AppFooter.vue"," 신규 컴포넌트, ",[23,821,796],{},"에 연결",[213,824,825],{},"상단: 로고 + 슬로건 + 정책 링크 6개",[213,827,828],{},"하단: (주)맑은소프트 로고 + 사업자 정보 7개 + 카피라이트",[213,830,831],{},"검정 배경, 시안과 동일한 톤",[14,833,835],{"id":834},"_10-gnb-메뉴-매핑","10. GNB 메뉴 매핑",[19,837,838,839],{},"스크린샷 기준 시안의 실제 메뉴 9개 구성으로 갱신:\n",[80,840,841],{},"서비스 \u002F 메시지 발송 \u002F 발송 조회·통계 \u002F 주소록 \u002F 발신 정보 \u002F 메시지관리 \u002F 캠페인 관리1 \u002F 캠페인 관리2 \u002F 운영가이드",[19,843,844,845,848],{},"자식 메뉴는 ",[23,846,847],{},"pagelists.js"," 카테고리 기반으로 구성.",[35,850],{},[14,852,854],{"id":853},"산출물-당일-추가","산출물 (당일 추가)",[210,856,857,862,868,882],{},[213,858,859,861],{},[80,860,537],{}," 3개 + 첫 커밋 + 푸시",[213,863,864,867],{},[80,865,866],{},"Cloudflare Pages"," 프로젝트 2개 + Worker 1개 (모두 운영 URL 활성)",[213,869,870,873,874,340,877,340,880],{},[80,871,872],{},"메모리"," 3종: ",[23,875,876],{},"project_malgn_noti_overview.md",[23,878,879],{},"reference_nhn_notification_hub.md",[23,881,304],{},[213,883,884,887],{},[80,885,886],{},"사용자단 코드",": 약 74개 파일 (페이지 50 + 컴포넌트 3 + composables 3 + 레이아웃 3 + 기본 설정)",[14,889,891],{"id":890},"다음-단계로-남긴-것","다음 단계로 남긴 것",[210,893,894,897,900,903],{},[213,895,896],{},"시안과 정확한 GNB 메뉴 정합성 (캠페인 관리 1\u002F2 등 임시 명칭)",[213,898,899],{},"콘텐츠 폭 미세 조정",[213,901,902],{},"인증 페이지 \u002F 발송 페이지 실제 구현",[213,904,905],{},"Aurora 토폴로지(Provisioned vs Serverless v2), 결제 PG\u002FAI 제공자 선정 등 미정 항목",{"title":907,"searchDepth":908,"depth":908,"links":909},"",3,[910,912,913,914,915,916,917,918,923,924,925,926,927],{"id":16,"depth":911,"text":17},2,{"id":39,"depth":911,"text":40},{"id":204,"depth":911,"text":205},{"id":253,"depth":911,"text":254},{"id":271,"depth":911,"text":272},{"id":308,"depth":911,"text":309},{"id":517,"depth":911,"text":518},{"id":590,"depth":911,"text":591,"children":919},[920,921,922],{"id":610,"depth":908,"text":611},{"id":652,"depth":908,"text":653},{"id":670,"depth":908,"text":671},{"id":741,"depth":911,"text":742},{"id":803,"depth":911,"text":804},{"id":834,"depth":911,"text":835},{"id":853,"depth":911,"text":854},{"id":890,"depth":911,"text":891},"md",{},true,"\u002Fhistory\u002Fhistory.20260511",{"title":5,"description":907},"history\u002Fhistory.20260511","D0zBFV6zZ7NfmQVdxENPOr42QgMI7FX3YDFQ-3SYSuw",1780643216573]