[{"data":1,"prerenderedAt":4940},["ShallowReactive",2],{"docs:all":3},[4,818,2099],{"id":5,"title":6,"body":7,"description":793,"extension":811,"meta":812,"navigation":813,"path":814,"seo":815,"stem":816,"__hash__":817},"docs\u002Fhistory\u002Fhistory.20260610.md","2026-06-10 — 쏠쏠(SolSol) 리브랜딩 + Cloudflare 연결 + 현황판·WBS 전면 재작성",{"type":8,"value":9,"toc":792},"minimark",[10,14,58,63,206,210,270,278,323,331,377,381,428,432,448,455,514,518,560,564,643,646,759,763],[11,12,6],"h1",{"id":13},"_2026-06-10-쏠쏠solsol-리브랜딩-cloudflare-연결-현황판wbs-전면-재작성",[15,16,17],"blockquote",{},[18,19,20,24,25,29,30,33,34,37,38,41,42,45,46,49,50,53,54,57],"p",{},[21,22,23],"strong",{},"한 줄 요약"," — 관리 허브를 ",[26,27,28],"code",{},"malgn-noti","\u002F",[26,31,32],{},"malgn-helper","에서 ",[21,35,36],{},"쏠쏠(크리에이터 LMS)"," 로 전면 리브랜딩하고, 전용 Cloudflare 리소스(D1 ",[26,39,40],{},"solsol-project"," + Pages ",[26,43,44],{},"solsol-mng",")를 신설·연결. 기획 스프레드시트(이미지 7장)를 분석해 ",[21,47,48],{},"현황판(7단계·78작업)"," 과 ",[21,51,52],{},"WBS 간트(5트랙·32항목)"," 를 새로 작성하고, 진척률을 dev ",[26,55,56],{},"\u002Fprogress"," 실측치(종합 베타 44%)에 맞춘 뒤 WBS 마감을 8월말까지 연장.",[59,60,62],"h2",{"id":61},"_1-리브랜딩-solsol-쏠쏠","1. 리브랜딩 — solsol \u002F 쏠쏠",[64,65,66,80,143,167,188],"ul",{},[67,68,69,72,73,75,76,79],"li",{},[21,70,71],{},"CLAUDE.md",": ",[26,74,32],{}," → ",[26,77,78],{},"solsol"," 전체 치환(제목·DB명·Pages 프로젝트명·doc 경로).",[67,81,82,85,86,89,90,93,94,89,97,75,100,29,103,106,107,89,110,75,113,116,117],{},[21,83,84],{},"코드·데이터 일괄 치환","(",[26,87,88],{},"app\u002F","·",[26,91,92],{},"server\u002F"," 12개 파일): ",[26,95,96],{},"malgn-noti*",[26,98,99],{},"malgn-notifications",[26,101,102],{},"solsol*",[26,104,105],{},"solsol-notifications",", 브랜딩 ",[26,108,109],{},"맑은노티",[26,111,112],{},"맑은 메시징",[26,114,115],{},"쏠쏠",".\n",[64,118,119,126],{},[67,120,121,122,125],{},"화면 제목·GNB 로고 워드마크·주석·",[26,123,124],{},"projectName"," 폴백·바로가기 URL.",[67,127,128,89,131,89,134,75,137,139,140,142],{},[26,129,130],{},"wrangler.toml",[26,132,133],{},"package.json",[26,135,136],{},"drizzle.config.ts",[26,138,44],{}," \u002F ",[26,141,40],{},".",[67,144,145,85,148,89,151,154,155,89,157,89,159,89,161,75,163,29,165,142],{},[21,146,147],{},"docs 마크다운",[26,149,150],{},"PROJECT_MANAGEMENT_BLUEPRINT.md",[26,152,153],{},"history\u002FREADME.md","): ",[26,156,28],{},[26,158,32],{},[26,160,109],{},[26,162,112],{},[26,164,78],{},[26,166,115],{},[67,168,169,172,173,176,177,29,180,183,184,187],{},[21,170,171],{},"유지",": 회사명 ",[26,174,175],{},"맑은소프트",", GitHub 조직 ",[26,178,179],{},"malgnsoft",[26,181,182],{},"*.malgnsoft.workers.dev",", 과거 이력 메모(",[26,185,186],{},"맑은메시지 TF"," 등).",[67,189,190,193,194,197,198,201,202,205],{},[21,191,192],{},"로고",": GNB 워드마크에서 ",[26,195,196],{},"message"," 제거 → ",[21,199,200],{},"쏠쏠 프로젝트 관리"," 만 노출(미사용 ",[26,203,204],{},".brand-message"," CSS·주석 정리).",[59,207,209],{"id":208},"_2-cloudflare-연결-신규-리소스","2. Cloudflare 연결 (신규 리소스)",[64,211,212,228,241,255],{},[67,213,214,215,218,219,29,221,223,224,227],{},"계정 ",[26,216,217],{},"info@malgnsoft.com",". 기존 ",[26,220,28],{},[26,222,32],{}," 리소스는 미변경, ",[21,225,226],{},"solsol 신규 생성"," 선택.",[67,229,230,233,234,236,237,240],{},[21,231,232],{},"D1"," ",[26,235,40],{}," 생성(",[26,238,239],{},"e682bf78-753f-4087-b5fa-58bdccd75fb3",", APAC) → 마이그레이션 2건 적용 + 시드.",[67,242,243,233,246,248,249,142],{},[21,244,245],{},"Pages",[26,247,44],{}," 생성 → 프로덕션 ",[250,251,252],"a",{"href":252,"rel":253},"https:\u002F\u002Fsolsol-mng.pages.dev",[254],"nofollow",[67,256,257,259,260,89,263,89,266,269],{},[26,258,130],{}," 의 ",[26,261,262],{},"database_id",[26,264,265],{},"database_name",[26,267,268],{},"name"," 을 solsol 로 갱신.",[59,271,273,274,277],{"id":272},"_3-현황판board-전면-재작성-크리에이터-lms","3. 현황판(",[26,275,276],{},"\u002Fboard",") 전면 재작성 — 크리에이터 LMS",[64,279,280,306,312],{},[67,281,282,283,286,287,290,291,294,295,298,299,302,303,142],{},"기획 스프레드시트(이미지 7장) 분석: ",[21,284,285],{},"쏠쏠 = 멀티 테넌트 크리에이터 LMS SaaS",". 4개 앱 — Brand site(",[26,288,289],{},"solsol.so",") · Customer Admin(강사, ",[26,292,293],{},"ceo.solsol.so\u002F@slug",") · Customer Front(수강생, ",[26,296,297],{},"{slug}.solsol.so",") · BackOffice(운영, ",[26,300,301],{},"so.solsol.so","). 결제 토스 · 정산 펌뱅킹 · 본인인증 NICE · 알림 NHN · 동영상 위캔디오 · GitHub ",[26,304,305],{},"malgnsoft\u002Fcreatorlms",[67,307,308,311],{},[21,309,310],{},"7단계 · 78작업",": 기획·정책 \u002F 화면설계 \u002F 디자인 \u002F 퍼블리싱 \u002F 개발 설계 \u002F 서비스 개발 \u002F 운영·계약. 담당자·일자·정책을 스프레드시트에서 이식.",[67,313,314,315,318,319,322],{},"대시보드(",[26,316,317],{},"index.vue",") 목표·기능 칩·기획 방향·바로가기, ",[26,320,321],{},"board.vue"," 부제·링크를 LMS 기준으로 교체.",[59,324,326,327,330],{"id":325},"_4-wbs-간트wbs-전면-재작성","4. WBS 간트(",[26,328,329],{},"\u002Fwbs",") 전면 재작성",[64,332,333,346,358],{},[67,334,335,72,338,341,342,345],{},[21,336,337],{},"누락 발견",[26,339,340],{},"seed.sql"," 에 ",[26,343,344],{},"wbs_item"," INSERT 가 0건 → D1 간트가 비어 있던 문제. 시드에 포함하도록 수정.",[67,347,348,349,352,353,357],{},"개발 간트(이미지 7) 전사: ",[21,350,351],{},"5트랙 32항목"," — 서버·공통 \u002F Customer Admin \u002F Customer Front \u002F Brand site \u002F BackOffice·인프라. 주차(W01~)를 날짜로 환산, 우선순위",[354,355,356],"span",{},"상\u002F중\u002F하","·담당·비고 반영.",[67,359,360,85,363,89,366,89,369,372,373,376],{},[26,361,362],{},"wbsData.ts",[26,364,365],{},"wbsSteps",[26,367,368],{},"wbsStageMeta",[26,370,371],{},"wbsGantt","), ",[26,374,375],{},"wbs.vue","(담당자·색·기준일 6\u002F10·STEP 1~5·부제) 갱신.",[59,378,380],{"id":379},"_5-진척률-실측-반영","5. 진척률 실측 반영",[64,382,383,402,417],{},[67,384,385,386,390,391,116,394],{},"출처: ",[250,387,388],{"href":388,"rel":389},"https:\u002F\u002Fbackoffice.solsol-dev.workers.dev\u002Fprogress",[254]," (CreatorLMS 개발 진행률, 2026-06-07) — ",[21,392,393],{},"종합 베타 44%",[64,395,396,399],{},[67,397,398],{},"앱 전체%: Customer-Admin 45% · BackOffice 66% · Customer-Front 17% · Brand 2%.",[67,400,401],{},"메뉴 실측: CA 사용자 95 · 운영 92 · 콘텐츠 85 · 상품 78 · 판매 55 · 설정 35 · 정산 10 \u002F CF 일반강의 55 · 공지 90.",[67,403,404,405,408,409,412,413,416],{},"현황판 단계 진척·Step 6 작업 상태(CA 인증+사용자 ",[21,406,407],{},"완료",", CF 상품목록 ",[21,410,411],{},"진행중",", Brand 인증+가입 ",[21,414,415],{},"대기"," 등)와 WBS 간트 항목 진척·트랙 메타를 실측에 정렬.",[67,418,419,420,423,424,427],{},"결과: 현황판 가중평균 ",[21,421,422],{},"56.5%","(기획·설계 완료 + 개발 44%), WBS 간트 KPI ",[21,425,426],{},"43.9%","(≈ 종합 베타 44%).",[59,429,431],{"id":430},"_6-wbs-마감-8월말-연장","6. WBS 마감 8월말 연장",[64,433,434,441],{},[67,435,436,437,440],{},"완료 항목은 기존 일정 유지, 미완료 작업을 7~8월로 재분배. 롱폴(Customer Front 커뮤니티·멤버십, Brand 마이페이지·서비스 소개)이 ",[21,438,439],{},"2026-08-31"," 마감.",[67,442,443,444,447],{},"간트 타임라인: ",[21,445,446],{},"2026-04-13 ~ 2026-08-31",". 진척률·트랙 가중치는 실측치 유지.",[59,449,451,452,454],{"id":450},"_7-wbs-ux-개선-풀스크린-스크롤-기준일","7. ",[26,453,329],{}," UX 개선 (풀스크린 · 스크롤 · 기준일)",[64,456,457,469,490,499],{},[67,458,459,462,463,465,466,468],{},[21,460,461],{},"푸터 제거",": 전역 푸터가 ",[26,464,329],{},"(100vh 풀스크린 간트)의 영역 아래에 붙어 바깥 페이지 스크롤을 만들고, 그 스크롤이 간트 내부 sticky(헤더·좌측 담당 영역)를 밀어 올리던 문제 → ",[26,467,329],{},"에서만 푸터를 숨겨 좌측 담당·정보 패널 고정 정상화.",[67,470,471,474,475,478,479,482,483,486,487,489],{},[21,472,473],{},"스크롤 시 상단 접기",": 간트 스크롤 다운 시 ",[21,476,477],{},"GNB + 전체 일정·KPI 헤더","를 함께 위로 접고(스크롤 업 시 복귀), ",[21,480,481],{},"담당(좌측 정보) · 날짜(타임라인 헤더)"," 는 sticky 유지. wbs.vue 가 ",[26,484,485],{},"useState('wbsChromeHidden')"," 로 신호를 발행 → 레이아웃이 GNB 높이를 접고 ",[26,488,329],{}," 영역을 56px만큼 100vh로 확장(전환 0.24s 동기화).",[67,491,492,193,494,197,496,498],{},[21,493,192],{},[26,495,196],{},[21,497,200],{}," 만 노출.",[67,500,501,504,505,75,508,513],{},[21,502,503],{},"기준일",": 부제 기준일을 ",[26,506,507],{},"6\u002F10",[21,509,510],{},[26,511,512],{},"2026.06.10","(yyyy.MM.dd) 표기. 클릭 시 오늘 컬럼이 진척율(좌측 정보) 바로 오른쪽(타임라인 시작)으로 가로 스크롤.",[59,515,517],{"id":516},"_8-wbs-전체-일정으로-확장-5트랙-7단계","8. WBS 전체 일정으로 확장 (5트랙 → 7단계)",[64,519,520,535,549],{},[67,521,522,523,526,527,530,531,534],{},"기존 5개 앱 트랙을 ",[21,524,525],{},"Step 6(서비스 개발)"," 하위 그룹으로 묶고, ",[21,528,529],{},"Step 1~5(기획·정책 \u002F 화면설계 \u002F 디자인 \u002F 퍼블리싱 \u002F 개발 설계)"," 와 ",[21,532,533],{},"Step 7(운영·계약)"," 을 일자와 함께 추가.",[67,536,537,538,541,542,545,546,142],{},"총 ",[21,539,540],{},"62개 항목",", 타임라인 ",[21,543,544],{},"2026-01-23 ~ 2026-08-31","(전 구간). WBS 단계 가중치·진척을 현황판과 동일하게 맞춰 ",[21,547,548],{},"KPI = 프로젝트 전체 진척(가중평균 56.5%)",[67,550,551,89,553,555,556,559],{},[26,552,365],{},[26,554,368],{}," 7단계, ",[26,557,558],{},"STEP_OPTIONS"," 1~7, 담당 필터·부제(\"전체 일정 · 7단계\") 갱신.",[59,561,563],{"id":562},"_9-wbs-계약-항목-추가-cloudflare-재연결-d1-시드-반영","9. WBS 계약 항목 추가 + Cloudflare 재연결 · D1 시드 반영",[64,565,566,591,620],{},[67,567,568,72,571,574,575,578,579,582,583,586,587,590],{},[21,569,570],{},"WBS Step 7 추가",[26,572,573],{},"계약"," 그룹 맨 아래에 작업 ",[26,576,577],{},"000","(id=63·sort=62·담당 미정·일정\u002F진척 없음) 신규. 두 정본 동기화 — ",[26,580,581],{},"app\u002Futils\u002FwbsData.ts","(dev 폴백) + ",[26,584,585],{},"server\u002Fdb\u002Fseed.sql","(D1 정본). ",[26,588,589],{},"boardSeed.ts","는 board(stage\u002Ftask) 전용이라 무관.",[67,592,593,596,597,600,601,603,604,607,608,610,611,85,613,616,617,619],{},[21,594,595],{},"Cloudflare 재인증",": OAuth 토큰 만료 → ",[26,598,599],{},"wrangler login"," 재로그인(",[26,602,217],{},", Account ",[26,605,606],{},"d2b8c552…","). ",[26,609,130],{},"의 ",[26,612,262],{},[26,614,615],{},"e682bf78…",")와 실제 D1 ",[26,618,40],{}," 매칭 확인.",[67,621,622,72,625,628,629,632,633,635,636,638,639,642],{},[21,623,624],{},"D1 시드 반영",[26,626,627],{},"wrangler d1 execute solsol-project --remote --file=server\u002Fdb\u002Fseed.sql"," — 153 쿼리 성공·383 rows written·",[26,630,631],{},"last_row_id=63","(=",[26,634,577],{},"까지 삽입)·7 테이블, APAC(ICN). ",[26,637,340],{},"은 ",[26,640,641],{},"DELETE FROM wbs_item"," 후 전체 재삽입이라 현재 세 정본(seed.sql · wbsData.ts · D1) 일치.",[59,644,645],{"id":645},"산출물",[64,647,648,665,683,721],{},[67,649,650,653,654,85,656,658,659,661,662,142],{},[21,651,652],{},"신규 리소스",": D1 ",[26,655,40],{},[26,657,615],{},"), Pages ",[26,660,44],{}," — ",[250,663,252],{"href":252,"rel":664},[254],[67,666,667,670,671,673,674,676,677,680,681,142],{},[21,668,669],{},"데이터 정합","(단일 생성 스크립트로 동기화): ",[26,672,585],{},"(board + ",[26,675,344],{},") · ",[26,678,679],{},"server\u002Futils\u002FboardSeed.ts"," · ",[26,682,581],{},[67,684,685,72,688,89,690,89,692,89,694,696,697,89,700,89,703,89,706,696,709,89,712,89,715,696,718,142],{},[21,686,687],{},"수정 파일",[26,689,130],{},[26,691,133],{},[26,693,136],{},[26,695,71],{},", ",[26,698,699],{},"app\u002Fpages\u002F{index,board,wbs}.vue",[26,701,702],{},"app\u002Flayouts\u002Fdefault.vue",[26,704,705],{},"app\u002Fcomposables\u002FuseWbs.ts",[26,707,708],{},"app\u002Fpages\u002Fdocs\u002Findex.vue",[26,710,711],{},"server\u002Fapi\u002Fboard.get.ts",[26,713,714],{},"server\u002Fdb\u002Fschema.ts",[26,716,717],{},"server\u002Futils\u002Fdb.ts",[26,719,720],{},"docs\u002FPROJECT_MANAGEMENT_BLUEPRINT.md",[67,722,723,85,726,154,729,75,732,75,735,75,738,75,741,75,744,75,747,75,750,75,753,75,756,142],{},[21,724,725],{},"주요 커밋",[26,727,728],{},"main",[26,730,731],{},"Rebrand to solsol and wire up Cloudflare",[26,733,734],{},"Rewrite board and WBS for SolSol Creator LMS",[26,736,737],{},"Adjust progress to real dev \u002Fprogress data",[26,739,740],{},"Remove 'message' from logo wordmark",[26,742,743],{},"Extend WBS gantt deadlines to end of August",[26,745,746],{},"Hide footer on \u002Fwbs",[26,748,749],{},"Collapse top header + GNB on scroll",[26,751,752],{},"Format 기준일 as yyyy.MM.dd",[26,754,755],{},"Expand WBS to full schedule (7 steps)",[26,757,758],{},"Click 기준일 to scroll to today",[59,760,762],{"id":761},"다음-단계-알려진-한계","다음 단계 \u002F 알려진 한계",[64,764,765,775,789],{},[67,766,767,768,770,771,774],{},"기획·디자인·설계(Step 1~5) 진척은 ",[26,769,56],{}," 미수록 영역이라 이미지·일정 기반 ",[21,772,773],{},"추정치",". 실제 수치 확보 시 정렬 필요.",[67,776,777,89,779,781,782,89,784,89,786,788],{},[26,778,276],{},[26,780,329],{}," 편집(CRUD)은 D1 정본을 직접 갱신 — 데이터 변경 시 ",[26,783,340],{},[26,785,589],{},[26,787,362],{}," 3종 동기화 유지(생성 스크립트 권장).",[67,790,791],{},"WBS 일정은 실측 진척 + 8월말 목표 기준의 재분배안 — 팀 확정 일정으로 보정 필요.",{"title":793,"searchDepth":794,"depth":794,"links":795},"",3,[796,798,799,801,803,804,805,807,808,809,810],{"id":61,"depth":797,"text":62},2,{"id":208,"depth":797,"text":209},{"id":272,"depth":797,"text":800},"3. 현황판(\u002Fboard) 전면 재작성 — 크리에이터 LMS",{"id":325,"depth":797,"text":802},"4. WBS 간트(\u002Fwbs) 전면 재작성",{"id":379,"depth":797,"text":380},{"id":430,"depth":797,"text":431},{"id":450,"depth":797,"text":806},"7. \u002Fwbs UX 개선 (풀스크린 · 스크롤 · 기준일)",{"id":516,"depth":797,"text":517},{"id":562,"depth":797,"text":563},{"id":645,"depth":797,"text":645},{"id":761,"depth":797,"text":762},"md",{},true,"\u002Fhistory\u002Fhistory.20260610",{"title":6,"description":793},"history\u002Fhistory.20260610","Y3die94Lc6t9SPf8b07FSHMX8agy0-yBurpaGt5I6Z4",{"id":819,"title":820,"body":821,"description":2093,"extension":811,"meta":2094,"navigation":813,"path":2095,"seo":2096,"stem":2097,"__hash__":2098},"docs\u002Fhistory\u002FREADME.md","작업 이력 (doc\u002Fhistory\u002F)",{"type":8,"value":822,"toc":2086},[823,831,838,842,851,858,862,865,888,891,2024,2028,2036,2039,2046,2082],[11,824,826,827,830],{"id":825},"작업-이력-dochistory","작업 이력 (",[26,828,829],{},"doc\u002Fhistory\u002F",")",[18,832,833,834,837],{},"날짜별 작업 내역을 누적해 두는 폴더입니다. ",[21,835,836],{},"하루에 한 파일"," 원칙.",[59,839,841],{"id":840},"파일명-규칙","파일명 규칙",[843,844,849],"pre",{"className":845,"code":847,"language":848},[846],"language-text","history.yyyyMMdd.md\n","text",[26,850,847],{"__ignoreMap":793},[18,852,853,854,857],{},"예: ",[26,855,856],{},"history.20260514.md",". 작업이 있는 날만 생성합니다.",[59,859,861],{"id":860},"파일-구조-공통","파일 구조 (공통)",[18,863,864],{},"각 파일은 다음 순서를 따릅니다.",[866,867,868,873,879,884],"ol",{},[67,869,870,872],{},[21,871,23],{}," — 그 날의 가장 큰 변화",[67,874,875,878],{},[21,876,877],{},"번호별 작업 섹션"," — 결정 사항 \u002F 코드 변경 \u002F 배포 \u002F 미세 조정",[67,880,881,883],{},[21,882,645],{}," — 추가·수정된 파일, 배포 버전, 외부 URL",[67,885,886],{},[21,887,762],{},[59,889,890],{"id":890},"인덱스",[892,893,894,907],"table",{},[895,896,897],"thead",{},[898,899,900,904],"tr",{},[901,902,903],"th",{},"날짜",[901,905,906],{},"요약",[908,909,910,948,1001,1012,1032,1047,1061,1076,1091,1102,1113,1124,1196,1394,1729,1896],"tbody",{},[898,911,912,919],{},[913,914,915],"td",{},[250,916,918],{"href":917},".\u002Fhistory.20260610","2026-06-10",[913,920,921,661,924,29,926,75,928,29,930,932,933,935,936,938,939,941,942,944,945,947],{},[21,922,923],{},"쏠쏠(SolSol) 리브랜딩 + Cloudflare 연결 + 현황판·WBS 전면 재작성",[26,925,28],{},[26,927,32],{},[26,929,78],{},[26,931,115],{}," 전체 치환(코드·docs·로고 message 제거) + 전용 D1 ",[26,934,40],{},"·Pages ",[26,937,44],{}," 신설 + 기획 스프레드시트(이미지 7장) 분석 → 크리에이터 LMS 현황판(7단계·78작업)·WBS 간트(5트랙·32항목, 누락된 ",[26,940,344],{}," 시드 추가) 새로 작성 + 진척률 dev ",[26,943,56],{}," 실측(종합 베타 44%) 정렬 + WBS 마감 8월말 연장 + ",[26,946,329],{}," UX(푸터 제거·스크롤 시 GNB·헤더 접기·기준일 yyyy.MM.dd·클릭 시 오늘로 이동)·WBS 전체 일정 7단계 확장(62항목, 1~8월)",[898,949,950,956],{},[913,951,952],{},[250,953,955],{"href":954},".\u002Fhistory.20260605","2026-06-05",[913,957,958,961,962,965,966,968,969,972,973,976,977,85,980,983,984,989,990,992,993,996,997,1000],{},[21,959,960],{},"solsol-mng 관리 레포 신설"," — GitHub 연결 + ",[26,963,964],{},"solsol\u002Fdoc\u002F"," 트리 집약(공통·도메인·이력) + CLAUDE.md 병합·현행화(이력 작성처를 본 레포로 변경, solsol ",[26,967,829],{}," 삭제) + solsol 동일 스택(Nuxt 3 + Tailwind v4 + Nuxt UI v3) + ",[26,970,971],{},"@nuxt\u002Fcontent"," 기반 ",[21,974,975],{},"문서\u002F이력 브라우저 앱"," 스캐폴딩(대시보드·문서·이력 타임라인) + ",[21,978,979],{},"Cloudflare Pages 정적 배포",[250,981,252],{"href":252,"rel":982},[254],", 프리렌더 라우트 직접 열거로 마크다운 내부 링크 크롤·대소문자·파일명 점 이슈 해결) + ",[21,985,986,987,830],{},"쏠쏠 현황판(",[26,988,276],{}," — solsol ",[26,991,329],{}," 읽기 전용 이식(공개 API ",[26,994,995],{},"GET \u002Fwbs"," 라이브) + 대시보드 WBS 현황 요약(",[26,998,999],{},"AppWbsOverview"," 공유)",[898,1002,1003,1009],{},[913,1004,1005],{},[250,1006,1008],{"href":1007},".\u002Fhistory.20260511","2026-05-11",[913,1010,1011],{},"프로젝트 착수 — 세 레포 부트스트랩 + 첫 GitHub 푸시 + Cloudflare 첫 배포 + 시안 GNB 도입",[898,1013,1014,1020],{},[913,1015,1016],{},[250,1017,1019],{"href":1018},".\u002Fhistory.20260512","2026-05-12",[913,1021,1022,1023,29,1026,29,1029,830],{},"시안 정밀 매칭 — 콘텐츠 폭 1200px 통일, Utility Bar 분리, 메뉴 8개, 문서 3종(",[26,1024,1025],{},"FRONTEND",[26,1027,1028],{},"STACK",[26,1030,1031],{},"DESIGN",[898,1033,1034,1040],{},[913,1035,1036],{},[250,1037,1039],{"href":1038},".\u002Fhistory.20260513","2026-05-13",[913,1041,1042,1043,1046],{},"Smart Placement + 발송 페이지 풍부화 — 공용 컴포넌트 21종, ",[26,1044,1045],{},"useChannelMeta",", SMS\u002F알림톡 발송 페이지",[898,1048,1049,1055],{},[913,1050,1051],{},[250,1052,1054],{"href":1053},".\u002Fhistory.20260514","2026-05-14",[913,1056,1057,1058,1060],{},"GitHub 일괄 푸시 + ",[26,1059,829],{}," 폴더 정리",[898,1062,1063,1069],{},[913,1064,1065],{},[250,1066,1068],{"href":1067},".\u002Fhistory.20260518","2026-05-18",[913,1070,1071,1072,1075],{},"디자인 시스템 전면 피벗 — Relay-inspired(핸드오프 정본), 셸+홈+발송 전 채널 적용, ",[26,1073,1074],{},"design-system-pivot"," 푸시",[898,1077,1078,1084],{},[913,1079,1080],{},[250,1081,1083],{"href":1082},".\u002Fhistory.20260519","2026-05-19",[913,1085,1086,1087,1090],{},"디자인 가이드 페이지(",[26,1088,1089],{},"\u002Fguide",", 18섹션 라이브 카탈로그) + Cloudflare Pages 프로덕션 배포",[898,1092,1093,1099],{},[913,1094,1095],{},[250,1096,1098],{"href":1097},".\u002Fhistory.20260520","2026-05-20",[913,1100,1101],{},"발송 페이지 UX 폴리시 2차 + PUSH 부가항목·플로우 관리 + 문서 현행화 + 발송 조회 페이지 재작업·btn-sky 제거 + 통계 페이지 재구성(Chart.js)·폰트 토큰화·zoom 제거 + 발송 템플릿 토글 개선 + 주소록 관리 페이지 강화 + 발신 번호 관리 페이지·등록 마법사 + 그룹 관리 페이지 + RCS 브랜드 관리 페이지 + 이메일 도메인 관리 페이지 (배포 #15~#26)",[898,1103,1104,1110],{},[913,1105,1106],{},[250,1107,1109],{"href":1108},".\u002Fhistory.20260521","2026-05-21",[913,1111,1112],{},"발신 정보 페이지 마무리(발신 프로필·PUSH 인증·080 수신 거부) + 테이블 스타일 A\u002FB\u002FC 정의·발송 조회 툴바 재배치 + GNB 정리 + 수신 거부 관리 3종 + 문자메시지·알림톡 템플릿 관리 페이지 + 미리보기 시각 현재화 + 로그인 페이지 시안 IA 재구성 + 비밀번호 재설정 입력란 보정 + 메시지 관리 5채널 템플릿 페이지(SMS·알림톡·RCS·이메일·PUSH) + 보안 인증 페이지 보정 + 사이트맵 페이지 + 회원가입 5단계 마법사 + 메시지 상세 설정 페이지 + 새 비밀번호 설정 페이지 보정 + 랜딩페이지 만들기 + 문의하기 페이지 \u002Faccount\u002Finquiry 이동 + 나의 페이지 섹션 + 크레딧 충전 플로우 + API 루트 → \u002Fdoc 리다이렉트 (배포 #27~#46 + API)",[898,1114,1115,1121],{},[913,1116,1117],{},[250,1118,1120],{"href":1119},".\u002Fhistory.20260522","2026-05-22",[913,1122,1123],{},"나의 페이지 화면 신규 구성 — 비밀번호 변경·보안로그인 설정·멀티 계정 추가·계약 관리(계약서 확인·3스텝 전자서명 위저드·PDF 미리보기) + 크레딧 관리(A형 내역 테이블·영수증 모달) + 나의 문의(목록·상세 댓글 스레드)·문의하기 LNB + 서비스 담당자 초대 플로우(\u002Finvite 등록 페이지)·문의 등록 완료 페이지 + 사이트맵 현행화 + 운영 가이드 페이지(\u002Fhelp)·GNB 연결 + 비로그인 공개 랜딩 페이지(\u002F, 히어로·장점·채널 단가 비교) (배포 #47~#52)",[898,1125,1126,1132],{},[913,1127,1128],{},[250,1129,1131],{"href":1130},".\u002Fhistory.20260526","2026-05-26",[913,1133,1134,1137,1138,1142,1143,1146,1147,1150,1151,1154,1155,1158,1159,89,1162,89,1165,1168,1169,1172,1173,1176,1177,1180,1181,75,1184,1187,1188,1191,1192,1195],{},[26,1135,1136],{},"solsol-api"," 데이터 모델·초기 DDL·Hyperdrive 연결·첫 프로덕션 배포 — 49 테이블 데이터 모델(TB_·company_id·status INT 1\u002F0\u002F-1 + ",[1139,1140,1141],"em",{},"_state·","_yn·loginid\u002Femail 분리) + Mermaid ERD 9종 + 확장성 전략(월 RANGE 파티셔닝·Hot\u002FWarm\u002FCold·R2 오프로드) + 0000_initial.sql(49 테이블, 파티션 5종) + Hyperdrive(",[26,1144,1145],{},"a2ba4efe...",") 바인딩 + drizzle-orm\u002Fmysql2 + \u002Fhealth\u002Fdb + ",[26,1148,1149],{},"wrangler dev --remote","로 로컬도 실제 Aurora + ",[26,1152,1153],{},"https:\u002F\u002Fsolsol-api.malgnsoft.workers.dev"," 프로덕션 첫 배포(\u002Fhealth\u002Fdb → mysql_version 8.0.42) + ",[26,1156,1157],{},"solsol-api\u002FCLAUDE.md §8.1","에 배포·Git·작업 이력 운영 컨벤션 명문화 + solsol 프론트 배포 #53 (list 툴바 새로고침 버튼 일괄 제거 + guide\u002FDESIGN 갱신) + ",[26,1160,1161],{},"\u002Fadmin\u002Fmigrate",[26,1163,1164],{},"\u002Fadmin\u002Ftables",[26,1166,1167],{},"\u002Fadmin\u002Fpartitions"," 라우트 + 0000_initial.sql Aurora 적용 (49 테이블 + 75 파티션 라이브) + 기본 CRUD API 골격 (errors\u002Fpagination\u002Fauth\u002FDrizzle schema + \u002Fme \u002Fcontacts \u002Fcontact-groups \u002Fsender-phones) + ",[26,1170,1171],{},"\u002Fdoc"," API 가이드(Scalar UI + OpenAPI 3.1) + solsol-api 프로덕션 배포 #2 (Version ",[26,1174,1175],{},"1fdc3b12...",", 가드 작동 확인) + 14개 도메인 라우트 추가(발신정보 5종\u002Foptout-entries\u002Ftemplates 2종\u002Finquiries\u002Fcompany-settings\u002Fpayment-methods\u002Flanding-pages\u002Fcredit-ledger) + Phase 1·2·3 (\u002Fdoc 확장 paths 10→37·schemas 11→45 + signup\u002Flogin + PBKDF2 + JWT HS256 + 발송 이력 read-only with 90일 윈도우 강제) + solsol-api 프로덕션 배포 #3 (Version ",[26,1178,1179],{},"926017d2...",", JWT_SECRET secret, 실제 \u002Fauth\u002Fsignup → \u002Fme 동작 확인) + POST \u002Fsend\u002Fsms 발송 producer(DB 적재까지 — 발신번호 검증·옵트아웃 필터·크레딧 hold·트랜잭션, 알려진 멱등 버그 TODO) + solsol-api 프로덕션 배포 #4·#5 (Version ",[26,1182,1183],{},"4d9e1fbe...",[26,1185,1186],{},"afaa4c89...",", \u002Fsend\u002Fsms 라이브 가드·검증 흐름 9건 + 재배포 검증 4건, jwt.ts linter 캐스트 명시화) + 🐛 멱등 버그 해결 (TB_IDEMPOTENCY + INSERT-then-conflict race-free 패턴, 검증 3건 통과) + NHN SMS 어댑터(mock\u002Freal) + Cloudflare Queues(",[26,1189,1190],{},"solsol-dispatch",") + consumer worker (dispatch_state 천이) + 프로덕션 배포 #6 (Version ",[26,1193,1194],{},"b30dc2a3...",", Producer+Consumer 동시 바인딩 라이브, 큐 e2e는 Cloudflare 1105 회복 후 재검증)",[898,1197,1198,1204],{},[913,1199,1200],{},[250,1201,1203],{"href":1202},".\u002Fhistory.20260604","2026-06-04",[913,1205,1206,1209,1210,1213,1214,1217,1218,1224,1225,1228,1229,1232,1233,75,1235,1238,1239,1242,1243,1246,1247,1250,1251,1254,1255,1258,1259,1262,1263,1266,1267,1270,1271,1274,1275,1278,1279,1282,1283,1286,1287,1290,1291,1294,1295,1298,1299,1302,1303,1250,1306,1309,1310,1313,1314,1302,1317,1320,1321,1324,1325,1328,1329,1332,1333,1336,1337,1340,1341,1344,1345,1348,1349,1352,1353,1356,1357,1360,1361,1364,1365,1332,1368,1371,1372,1340,1375,1250,1378,1381,1382,1385,1386,1389,1390,1393],{},[21,1207,1208],{},"§1"," NICE IPv6 진단 — 6\u002F2 §16의 1007 차단 후속. 사용자 옵션 B(NICE 콘솔에 Cloudflare egress IP 대역 등록) 진행 후 재시도 → 여전히 1007. 진단용 ",[26,1211,1212],{},"\u002Fdiag\u002Fegress"," 임시 endpoint로 ",[26,1215,1216],{},"api.ipify.org"," 8회 호출 → Workers outbound가 ",[21,1219,1220,1221],{},"IPv6 ",[26,1222,1223],{},"2a06:98c0:3600::103"," (Cloudflare 공식 IPv6 ",[26,1226,1227],{},"2a06:98c0::\u002F29"," 소속)임을 확인. NICE에 IPv4만 등록되어 IPv6 출발지 거부가 원인. 사용자에게 Cloudflare IPv6 대역 7개 추가 등록 또는 IP 검사 OFF 안내 후 보류. 진단 endpoint 즉시 제거 + Workers 재배포. CLIENT_ID\u002FSECRET 덮어쓰기(값 일치 보장만). ",[21,1230,1231],{},"§2"," Hyperdrive 교체 — ",[26,1234,1145],{},[26,1236,1237],{},"439b109d...",". 신규 origin host ",[26,1240,1241],{},"malgn-dev-db.apiserver.kr"," (Cloudflare Tunnel 엔드포인트) + ",[26,1244,1245],{},"access_client_id",". Aurora 노출이 \"퍼블릭+SG egress IP 화이트리스트\"에서 \"Tunnel(Access) 기반\"으로 전환 — egress IP 동기화 부담 해소, CLAUDE.md §12 TODO \"SG 갱신 운영 절차\" 항목 자연 달성. 코드 변경 0. 라이브 검증(GET \u002Fhealth\u002Fdb mysql_version 8.0.42 + POST \u002Fauth\u002Fnice\u002Finit DB 쓰기 정상). 정본 3개 동기화 — API CLAUDE.md §3·§8·§12, SCALABILITY.md §6 신규 절(전\u002F후 비교 + 전환 이유 + 운영 영향), MIGRATION.md §1 통로 다이어그램에 Tunnel 단계 추가. Workers 배포 Version ",[26,1248,1249],{},"a457b7dc...",". ",[21,1252,1253],{},"§3"," 관리자단 핸드오프 풀세트 — ",[26,1256,1257],{},"handoff_noti_admin"," (3,129줄 jsx)를 Vue 3 + Nuxt UI v3로 1:1 포팅. 셸 완전 재정비(AppLnb 핸드오프 정본 9 그룹\u002F17 라우트로 교체 + AppTopbar useState 기반 동적 브레드크럼 + useBreadcrumb composable) + 공유 컴포넌트 14종(PageHeader\u002FSectionCard\u002FTabs\u002FSegmented\u002FFilterBar\u002FDateRange\u002FDataTable generic+",[26,1260,1261],{},"#cell-{key}"," scoped slot\u002FPagination\u002FStatusBadge 값→톤 자동 매핑\u002FChannelChip\u002FStatCard accent 7종\u002FDrawer\u002FModal Teleport+scroll lock\u002FField\u002FEmptyState) + 차트 4종(BarChart 그룹 막대\u002FAreaChart SVG path+그라데이션\u002FDonut stroke-dasharray\u002FProgressBar) + ",[21,1264,1265],{},"17 페이지","(대시보드·고객사·고객사 상세·계정·모니터링·발신번호·발신프로필·템플릿검수·결제·채널단가·충전쿠폰·1:1문의·FAQ·공지·통계·운영자·권한그룹·API). app.config.ts ",[26,1268,1269],{},"info: 'indigo'"," 매핑으로 핸드오프 indigo 강조색을 Nuxt UI semantic으로. 18 라우트 라이브 200. ",[21,1272,1273],{},"§4"," 폰트 사이즈 정합화 — 사용자 보고로 두 원인 동시 발견: (a) main.css ",[26,1276,1277],{},"html,body{font-size:13px}","가 Tailwind 토큰(16px base 가정)을 모두 18% 축소시킴 — 핸드오프는 base font-size 명시 없이 16px Tailwind 기본 사용 + ",[26,1280,1281],{},"letter-spacing: -0.01em",". (b) 직전 turn의 cwd가 ",[26,1284,1285],{},"\u002Fsolsol","(사용자단)였고 거기서 빌드한 dist를 ",[26,1288,1289],{},"wrangler pages deploy --project-name=solsol-admin","으로 ",[21,1292,1293],{},"사용자단을 admin 프로젝트에 잘못 배포","한 상태였음(chunk 600개 \u002F AppGnb·AppContractPanel·AppCardAddDialog 등 사용자단 chunk 혼입). 둘 다 정정 — main.css 13px 제거 + letter-spacing -0.01em 추가, admin 디렉토리에서 clean rebuild + 재배포 alias ",[26,1296,1297],{},"8852d5da.solsol-admin.pages.dev"," (chunk 96개로 정상화). 교훈으로 멀티 레포 deploy 가드(prebuild name 체크 + chunk 수 sanity)·base font-size 명시 금지 패턴 정리. solsol-admin 커밋 ",[26,1300,1301],{},"0227cae"," + ",[26,1304,1305],{},"1b63200",[21,1307,1308],{},"§5"," WBS 페이지 편집 — DB 미사용\u002FR2 단일 JSON 객체 정본(",[26,1311,1312],{},"wbs\u002Fwbs.json",", FILES 바인딩). API에 GET 공개 + PATCH 인증 2 라우트 + 142 task 시드(",[26,1315,1316],{},"src\u002Fdata\u002Fwbs-seed.ts",[26,1318,1319],{},"src\u002Froutes\u002Fwbs.ts","). 사용자단은 임베디드 STAGES 제거 → top-level ",[26,1322,1323],{},"await api('\u002Fwbs')"," + AppModal 인라인 편집 다이얼로그(owner·note·href·targetDate·completionDate 5 필드, 빈값=",[26,1326,1327],{},"null","=필드 제거). 비로그인은 읽기 전용 + \"로그인하면 편집 가능\" 힌트. 동시 편집은 last-write-wins. solsol-api 커밋 ",[26,1330,1331],{},"9945db3"," Workers Version ",[26,1334,1335],{},"28f3e6a8...",", solsol 커밋 ",[26,1338,1339],{},"3ed473e"," Pages alias ",[26,1342,1343],{},"02bb58e6",". 후속(§5.9) 목표일·완료일 ",[26,1346,1347],{},"YYYY.MM.DD"," 포맷 통일 + ",[26,1350,1351],{},"\u003Cinput type=\"date\">"," 캘린더 위젯 + API Zod regex ",[26,1354,1355],{},"^\\d{4}\\.\\d{2}\\.\\d{2}$"," 강제. 레거시 ",[26,1358,1359],{},"5\u002F8"," 값은 표시 시 2026 기준 ",[26,1362,1363],{},"2026.05.08","로 자동 변환, 다음 PATCH 시 R2에도 정합화. solsol-api ",[26,1366,1367],{},"3a35464",[26,1369,1370],{},"eb02206c...",", solsol ",[26,1373,1374],{},"08e5c33",[26,1376,1377],{},"98bd09e2",[21,1379,1380],{},"§6"," NHN Notification Hub OAuth 어댑터 + Email 실 발송 + 서비스 담당자 이메일 변경 라우트 — Notification Hub 신규 통합 서비스의 인증이 OAuth2 client_credentials → Bearer 토큰임을 확인 후 어댑터 전면 재작성. ",[26,1383,1384],{},"src\u002Fadapters\u002Fnhn\u002Foauth.ts"," 신규(",[26,1387,1388],{},"https:\u002F\u002Foauth.api.nhncloudservice.com\u002Foauth2\u002Ftoken\u002Fcreate"," Basic Auth + ",[26,1391,1392],{},"scope=appKey:{APP_KEY}"," 토큰 발급 + 메모리 캐시). SMS·Email 어댑터 `POST {base}\u002Fmessage\u002Fv1.0\u002F{SMS",[898,1395,1396,1402],{},[913,1397,1398],{},[250,1399,1401],{"href":1400},".\u002Fhistory.20260602","2026-06-02",[913,1403,1404,1405,1407,1408,1411,1412,1415,1416,1419,1420,607,1423,1425,1426,1429,1430,1433,1434,33,1437,1440,1441,1444,1445,1448,1449,233,1451,1454,1455,1458,1459,1462,1463,1466,1467,1470,1471,1474,1475,1478,1479,1482,1483,1517,1518,1520,1521,1524,1525,1528,1529,1532,1533,233,1535,1538,1539,1542,1543,1546,1547,1550,1551,1554,1555,1558,1559,1562,1563,1566,1567,1570,1571,1574,1575,1578,1579,1582,1583,1586,1587,1590,1591,1594,1595,1598,1599,1602,1603,1606,1607,1610,1611,1613,1614,89,1617,89,1620,89,1623,89,1625,89,1627,1630,1631,1633,1634,1637,1638,607,1641,1644,1645,1648,1649,1651,1652,75,1654,1656,1657,607,1660,233,1663,1665,1666,1669,1670,1672,1673,1676,1677,89,1680,1683,1684,1687,1688,1691,1692,89,1695,89,1698,1701,1702,1704,1705,1708,1709,1712,1713,1716,1717,1720,1721,1724,1725,1728],{},"회원·인증 트랙 첫 날. ",[21,1406,1208],{}," WBS 구조 개편 — 사용자단을 ",[21,1409,1410],{},"5-3A 화면 UI 구성","(목업) + ",[21,1413,1414],{},"5-3M 매트릭스","(도메인별 UI\u002FAPI\u002F연동 한눈에) + ",[21,1417,1418],{},"5-3C 화면 ↔ API 연동","(실 데이터) 3 트랙으로 분리. 5-3-15 단일 항목을 16개 도메인별 5-3C-1~16으로 펼침. Step 5 진척률 55%→40%, 전체 가중평균 45%→38%. Pages 배포 #51(alias ",[26,1421,1422],{},"bca573ce",[21,1424,1231],{}," 로그인 UX 개선 — ",[26,1427,1428],{},"POST \u002Fauth\u002Flogin-by-email"," 신설(이메일+비번 → 회사 자동 찾기, 단일 매치 즉시 토큰 \u002F 복수 매치 시 ",[26,1431,1432],{},"multipleCompanies:true + companies[]","). 프런트 ",[26,1435,1436],{},"login\u002Findex.vue",[21,1438,1439],{},"고객사 ID 필드 완전 제거",", 복수 매치 시 회사 선택 카드 UI. Workers 배포 #10(Version ",[26,1442,1443],{},"a6197cc7...","), Pages 배포 #52(alias ",[26,1446,1447],{},"292da05d","). 라이브 e2e 5 시나리오 통과. WBS 5-3C-4 ⚪→✅. ",[21,1450,1253],{},[26,1452,1453],{},"TB_USER.loginid"," 전역 UNIQUE 정합화 — 정책상 한 이메일이 여러 회사에 가입되어선 안 됨. ",[26,1456,1457],{},"0003_user_loginid_global_unique.sql"," 신규 + 라이브 적용(",[26,1460,1461],{},"uq_user_company_loginid"," 복합 DROP → ",[26,1464,1465],{},"uq_user_loginid"," 단독 ADD). schema.ts에 ",[26,1468,1469],{},".unique('uq_user_loginid')"," 명시. login-by-email 단순화(",[26,1472,1473],{},"for-of"," 다중 verify 루프 제거, ",[26,1476,1477],{},".limit(1)",") + OpenAPI에서 ",[26,1480,1481],{},"MultipleCompaniesResponse"," 삭제 + 프런트 회사 선택 UI(",[1484,1485,1486,1487,1490,1491,1494,1495,1497,1498,89,1501,1504,1505,1508,1509,1512,1513,1516],"del",{},"80줄) 제거. 사전 검증용 임시 데이터 cleanup(회사 8 + 사용자 12). Workers 배포 #11(Version ",[26,1488,1489],{},"f7f42855...","), Pages 배포 #53(alias ",[26,1492,1493],{},"f150ea0a","). 라이브 e2e 4건 통과(signup 정상 \u002F loginid 중복 409 \u002F login-by-email 단일 토큰 \u002F UNIQUE 인덱스 단독 확인). \"한 이메일 = 한 회사 = 한 로그인\". ",[21,1496,1273],{}," 휴대폰 SMS OTP 라우트(",[26,1499,1500],{},"\u002Fauth\u002Fphone-code\u002Fsend",[26,1502,1503],{},"\u002Fverify"," 이메일 OTP와 동일 패턴, ",[26,1506,1507],{},"target_type='phone'",") + signup.vue Step 4 실 API 연동 + useApi.ts 401 처리 분리(",[26,1510,1511],{},"\u002Fauth\u002F*"," 호출은 호출자 처리 — 가입 도중 OTP 잘못 입력 시 페이지 이동 버그 수정) + 가입 완료 화면 고객사 ID 노출 제거 + 토스트 위치(오른쪽 위) + 크기 강화(17px·440px). Workers #12(",[26,1514,1515],{},"84056c86...","), Pages #54","#58. ",[21,1519,1308],{}," NICE 통합인증(휴대폰 본인확인) 인프라 — doc\u002FNICE_AUTH.md 신규 정본(12 섹션) + ",[26,1522,1523],{},"0004_user_nice_auth.sql"," 라이브 적용(TB_NICE_AUTH 신설 + TB_USER에 birthdate\u002Fgender\u002Fnational_info\u002Fci\u002Fmobile_co + UNIQUE ci) + NICE 어댑터(mock\u002Freal, AES-256-GCM + PBKDF2 + HMAC, Workers Web Crypto만) + 3 라우트(init\u002Fcallback\u002Fstatus) + \u002Fauth\u002Fsignup 확장(niceSession 검증·CI 중복 차단·NICE 결과로 이름·휴대폰·생년월일 덮어쓰기·state='consumed' 재사용 차단) + signup.vue Step 4 통째로 NICE 흐름으로 교체(\"본인 인증하기\" 버튼 + popup + 폴링 + 결과 표시) + NICE_MOCK secret 적용(자격증명 발급 전 mock 통과). Workers #13(",[26,1526,1527],{},"2ab47c1f...","), Pages #60(",[26,1530,1531],{},"c9577894","). 라이브 e2e 6 시나리오 통과. ",[21,1534,1380],{},[26,1536,1537],{},"\u002Faccount\u002Fsettings"," 실 API 연동 — 백엔드 ",[26,1540,1541],{},"GET \u002Fme"," 응답을 TB_USER 13 + TB_COMPANY 14 컬럼 풀로 확장 + ",[26,1544,1545],{},"PATCH \u002Fme","(name·phone) + ",[26,1548,1549],{},"PATCH \u002Fme\u002Fcompany","(companyPhone·billingEmail·adReceive, owner\u002Fadmin) 신설. 사용자단 ",[26,1552,1553],{},"AppMemberInfoPanel.vue"," 전면 교체 — 목업 데이터 제거 + useAuthStore 기반 실 데이터 + 광고수신 토글 즉시 PATCH + 저장하기는 변경 필드만 한 번에 PATCH. Workers #14(",[26,1556,1557],{},"22368d14...","), Pages #61(",[26,1560,1561],{},"ea35651d","). 라이브 e2e 5건 통과. WBS 5-3C-7 ⚪→🟢. ",[21,1564,1565],{},"§7"," 사업자등록증 심사 승인 게이트 — 새 정책: 법인\u002F개인사업자 가입 후 승인 받아야 서비스·정보 수정 가능, 개인은 즉시. 0005 라이브 적용(TB_COMPANY에 company_type\u002Fapproval_state\u002Frejected_reason + 기존 5행 'approved' 호환). signup 자동 분기 + PATCH \u002Fme·\u002Fme\u002Fcompany에 승인 게이트 403 + \u002Fme 응답에 승인 정보 노출. 사용자단 — signup.vue Step 5 분기 + AppMemberInfoPanel에 승인 배너(pending=warning, rejected=danger+사유) + 모든 입력 disabled. Workers #15(",[26,1568,1569],{},"6e47d50b...","), Pages #64(",[26,1572,1573],{},"56e94e5b","). 라이브 e2e 8 시나리오 통과(법인 pending \u002F 수정 403 \u002F 개인 통과 \u002F 운영자 승인 후 통과 \u002F 반려 사유 노출). WBS 5-3C-6 ⚪→🟢 + 5-3C-17 ✅. ",[21,1576,1577],{},"§8"," 승인 게이트 전 도메인 일관 적용 — ",[26,1580,1581],{},"requireApproved()"," 미들웨어를 ",[26,1584,1585],{},"src\u002Fmiddleware\u002Fapproval.ts","로 추출 + 18 도메인 라우트에 일괄 적용(",[26,1588,1589],{},"mutate-only"," 옵션 — GET 통과, POST\u002FPATCH\u002FPUT\u002FDELETE만 차단). ",[26,1592,1593],{},"\u002Finquiries","는 예외(승인 관련 문의 가능). 자동화 스크립트(grep + perl)로 18 라우트의 import + use 라인 일관 갱신. Workers #16(",[26,1596,1597],{},"798bf6f5...","). 라이브 e2e 6 시나리오 통과(GET 통과 \u002F POST 4건 403 \u002F 개인 통과 \u002F 문의 작성 차단 안 됨). ",[21,1600,1601],{},"§9"," 사용자단 승인 게이트 UI 일관화 — ",[26,1604,1605],{},"AppApprovalBanner"," 신규(layout 최상단·GNB 위 글로벌 띠, pending=warning·rejected=danger+사유) + ",[26,1608,1609],{},"middleware\u002Fapproval.global.ts"," 신규(차단 페이지 접근 시 ",[26,1612,1537],{},"로 리다이렉트, 허용은 ",[26,1615,1616],{},"\u002Faccount",[26,1618,1619],{},"\u002Fhome",[26,1621,1622],{},"\u002Fhelp",[26,1624,1089],{},[26,1626,329],{},[26,1628,1629],{},"\u002Finquiry",") + ",[26,1632,1619],{}," 미승인 분기(KPI\u002F채널 대신 ",[26,1635,1636],{},"approval-hero"," 큰 안내 카드 + CTA). Pages #65(",[26,1639,1640],{},"2eec9e0b",[21,1642,1643],{},"§10"," 미승인 진입점을 ",[26,1646,1647],{},"\u002Faccount\u002Fcontract","(계약 관리)로 변경 — 정책상 사업자등록증 제출\u002F재제출 화면이 미승인 흐름의 메인. middleware ALLOWED_PREFIXES에서 ",[26,1650,1619],{}," 제거 + 리다이렉트 대상을 ",[26,1653,1537],{},[26,1655,1647],{},". AppApprovalBanner CTA \"계약 관리\". signup.vue Step 5 사업자\u002F개인 분기(\"계약 관리로 이동\" \u002F \"대시보드로 이동\"). \u002Fhome.vue §9의 미승인 분기 코드 제거(미들웨어가 차단해 진입 불가). Pages #66(",[26,1658,1659],{},"5256d66d",[21,1661,1662],{},"§11",[26,1664,1647],{}," 실 API + R2 첨부 인프라 — R2 bucket ",[26,1667,1668],{},"solsol-files"," 생성 + ",[26,1671,130],{}," FILES 바인딩 + ",[26,1674,1675],{},"schema.ts","에 라이브 DDL 매칭(",[26,1678,1679],{},"TB_CONTRACT",[26,1681,1682],{},"TB_CONTRACT_FILE",") + signup corp\u002Fsole 분기에서 'initial' 이용계약 자동 생성. ",[26,1685,1686],{},"\u002Fcontracts"," 라우트 신규 5종(list · ",[1689,1690],"id",{},"\u002Fsign · files list · files upload(multipart) · files download(stream) · files delete) — PDF·10MB 제한, name 접두사(",[26,1693,1694],{},"사업자등록증_…",[26,1696,1697],{},"대부업등록증_…",[26,1699,1700],{},"지급이행보증보험증권_…",")로 종류 구분(",[26,1703,1682],{},"에 kind 컬럼 없음), 회사 단위 권한(companyId 매칭), renew 체결 시 다른 done 자동 expired. OpenAPI 5 paths + 2 schemas. 사용자단 ",[26,1706,1707],{},"AppContractPanel.vue"," 전면 교체 — 목업 제거 + ",[26,1710,1711],{},"await Promise.all"," SSR + FormData 멀티파트 업로드 + 미리보기는 인증 fetch → blob → object URL(iframe Auth 헤더 우회). Workers #17(Version ",[26,1714,1715],{},"7213946f...","), Pages alias ",[26,1718,1719],{},"9808fe42",". 라이브 e2e 4 시나리오 통과(corp signup auto-contract \u002F 파일 업로드 R2 \u002F 파일 목록 \u002F 체결 → done+expires +2y). ",[21,1722,1723],{},"§12"," 사업자등록증 첨부 시 회사 승인 상태 'reviewing' 자동 전이 — ",[26,1726,1727],{},"approval_state"," enum 4단계 확장(`pending → reviewing → approved",[898,1730,1731,1737],{},[913,1732,1733],{},[250,1734,1736],{"href":1735},".\u002Fhistory.20260601","2026-06-01",[913,1738,1739,1741,1742,1745,1746,1748,1749,1752,1753,1756,1757,89,1760,1763,1764,607,1767,233,1769,1772,1773,1775,1776,89,1779,1782,1783,1786,1787,1790,1791,89,1794,1797,1798,1800,1801,233,1803,1805,1806,1809,1810,1812,1813,680,1816,680,1819,1822,1823,1826,1827,1830,1831,1834,1835,1837,1838,1841,1842,1845,1846,1848,1849,1851,1852,680,1855,89,1858,89,1861,1863,1864,1867,1868,1870,1871,89,1874,1876,1877,1880,1881,29,1884,1887,1888,1891,1892,1895],{},[21,1740,1208],{}," WBS 정본화 — ",[26,1743,1744],{},"doc\u002FWBS.md"," 신규(5 단계 가중치·Step 1~5 작업 내역·알려진 한계, ~220 라인) + 사용자단 ",[26,1747,329],{}," 공개 라이브 카탈로그(",[26,1750,1751],{},"solsol\u002Fdoc\u002FWBS.md"," 양식 + ",[26,1754,1755],{},"solsol-pms\u002Fpages\u002Fwbs.vue"," Notion soft SaaS 디자인 차용 — Hero stats·단계별 진행률 오버뷰·Stage 상세·그룹별 작업 카드·상태 칩·외부 링크 + ",[26,1758,1759],{},"layout: blank",[26,1761,1762],{},"auth: false",", ~650 라인). Step 5(서비스 개발)는 원본 채널·도메인 단위 항목(대부분 0%)을 실제 진행에 맞춰 5-1 설계(7) \u002F 5-2 API(16) \u002F 5-3 사용자단(15) \u002F 5-4 관리자단(13) \u002F 5-5 통합·배포(7)의 5 그룹 58 작업으로 재정렬. Cloudflare Pages 배포 #47 (alias ",[26,1765,1766],{},"0ecc825e.solsol.pages.dev",[21,1768,1231],{},[26,1770,1771],{},"0002_export_flow.sql"," DDL — ",[26,1774,1149],{}," 1105 잔류 3회 재시도 모두 실패(Ray ID ",[26,1777,1778],{},"a04a8ca2...",[26,1780,1781],{},"a04a9753...",") → Aurora 직결(",[26,1784,1785],{},"noti"," 계정·SSL REQUIRED)로 우회 점검. 4 신규 테이블(TB_EXPORT_JOB \u002F TB_FLOW_*) ",[21,1788,1789],{},"이미 라이브 적용된 상태 확인"," — 컬럼 100% 일치, 인덱스·FK는 라이브가 더 정교(FK 6 + 의미 인덱스명). 라이브 워커 e2e 검증(",[26,1792,1793],{},"\u002Fexport-jobs",[26,1795,1796],{},"\u002Fflow-definitions"," GET 200 \u002F POST 201) + 테스트 데이터 cleanup + ",[26,1799,1771],{}," 파일을 라이브 정본에 맞춰 동기화. WBS 5-2-11\u002F12 🟢 (CRUD ✅·처리 worker 미) + 5-5-4 ⛔→✅. ",[21,1802,1253],{},[26,1804,1675],{}," 정합화 — export\u002Fflow 4 테이블에 라이브 정본의 인덱스 6 + FK 6 명시화(",[26,1807,1808],{},"solsol-api: 0475bd2",", schema.ts 단일 파일 +22 -4, 컬럼 정의 변경 0, 다른 테이블 변경 0, typecheck 통과, 런타임 영향 0). drizzle-kit introspect drift 12건 → 0. ",[21,1811,1273],{}," 사용자단 인증 백엔드 연동 — ",[26,1814,1815],{},"\u002Fauth\u002Fsignup",[26,1817,1818],{},"\u002Fauth\u002Flogin",[26,1820,1821],{},"\u002Fme"," 실 API 연동(JWT ",[26,1824,1825],{},"auth-token"," 쿠키 + ",[26,1828,1829],{},"useApi()"," Bearer 자동 주입 + 글로벌 미들웨어 1차 가드 + ",[26,1832,1833],{},"plugins\u002Fauth.client.ts"," 클라이언트 부트스트랩 페치). 회원가입 Step 4 → 실 API → 자동 로그인 → ",[26,1836,1619],{},". 로그인은 ",[26,1839,1840],{},"last-company-id"," 쿠키 자동 사용. 첫 SSR 시도에서 ",[26,1843,1844],{},"await auth.fetchMe()","가 Nuxt instance 컨텍스트 손실로 500 → 미들웨어\u002F플러그인 분리로 우회. 6 파일 수정 + 1 신규(",[26,1847,1833],{},"), typecheck 통과, 로컬 + 프로덕션 e2e(쿠키 동봉 시 ",[26,1850,1619],{}," 200 · 없으면 ",[26,1853,1854],{},"\u002Flogin?redirect",[26,1856,1857],{},"\u002Flogin",[26,1859,1860],{},"\u002Fsignup",[26,1862,329],{}," 200). Pages 배포 #49 (alias ",[26,1865,1866],{},"9be4ff61.solsol.pages.dev","). WBS 5-3-15 ⚪ → 🟢. ",[21,1869,1308],{}," 이메일 OTP 인증 — ",[26,1872,1873],{},"POST \u002Fauth\u002Femail-code\u002Fsend",[26,1875,1503],{}," 백엔드 신설(TB_VERIFICATION + SHA-256 코드 해시 + TTL 10분·재발송 시 직전 코드 만료·5회 시도 제한·소비 후 재사용 차단), Drizzle schema.ts에 verification 정의(라이브 정본 정합), OpenAPI 2 paths + 3 schemas, Workers 배포 #9(Version ",[26,1878,1879],{},"83f32a61...","). 프런트 signup.vue ",[26,1882,1883],{},"sendIdCode",[26,1885,1886],{},"confirmIdCode"," 실 API 연동(",[26,1889,1890],{},"mockCode"," 토스트 노출은 NHN_MOCK=1 한정 — production 자동 차단, 로딩 상태 + 재발송 라벨). Pages 배포 #50(alias ",[26,1893,1894],{},"c2100890","). 라이브 e2e 6 시나리오 모두 통과(발송·잘못된 코드 401·올바른 코드 200·소비 후 재시도 401·재발송·DB 행 검증) + 검증 후 임시 NHN_MOCK secret 제거 확인. doc\u002FSIGNUP.md §8 #4 ⚪→✅.",[898,1897,1898,1904],{},[913,1899,1900],{},[250,1901,1903],{"href":1902},".\u002Fhistory.20260527","2026-05-27",[913,1905,1906,661,1909,1912,1913,1916,1917,1920,1921,661,1924,1926,1927,1929,1930,1933,1934,1936,1937,1940,1941,1944,1945,1948,1949,661,1952,1954,1955,1958,1959,661,1962,1964,1965,1967,1968,1971,1972,607,1975,661,1978,1980,1981,1984,1985,1988,1989,1302,1992,233,1995,1302,1998,2000,2001,233,2004,1302,2007,2009,2010,2012,2013,2016,2017,2020,2021,2023],{},[21,1907,1908],{},"트랙 A",[26,1910,1911],{},"solsol-admin"," Nuxt 3 + Nuxt UI v3 부트스트랩 + LNB(256px · 8그룹) + TopBar(64px) 셸 레이아웃(",[26,1914,1915],{},"design_handoff_customer_detail"," 정본 참조) + 첫 실 Nuxt 앱 프로덕션 배포(",[26,1918,1919],{},"https:\u002F\u002Fsolsol-admin.pages.dev",", 이전 정적 placeholder 대체). ",[21,1922,1923],{},"트랙 B",[26,1925,1136],{}," §19 멱등 버그 정식 해결(TB_IDEMPOTENCY + INSERT-then-conflict race-free) + NHN SMS 어댑터(mock\u002Freal) + Cloudflare Queues(",[26,1928,1190],{},") + consumer worker(",[26,1931,1932],{},"dispatch_state"," 천이) + 프로덕션 배포 #6(Version ",[26,1935,1194],{},", Producer+Consumer 동시 바인딩) + NHN webhook 핸들러(",[26,1938,1939],{},"POST \u002Fwebhooks\u002Fnhn\u002Fsms",", HMAC-SHA256 서명 검증·dedup_key 멱등·recv_state 자동 천이) + ",[21,1942,1943],{},"Email · Kakao(알림톡\u002F친구톡) · Push 3채널 동시 추가","(adapter·producer·worker·OpenAPI 4지점, channel branching generic화·EMAIL_PRICING=0.65·KAKAO_PRICING={alimtalk:8,friendtalk:12}·PUSH_PRICING=0.5) + 프로덕션 배포 #7(Version ",[26,1946,1947],{},"12dae362...","). 큐 e2e + 웹훅 검증은 Cloudflare 1105 회복 후 재시도. ",[21,1950,1951],{},"트랙 C",[26,1953,78],{}," 사용자단 추가 작업으로 메시지 관리 랜딩페이지 만들기(목록·기본형\u002F확장형 폼·미리보기) + 문의하기 경로를 ",[26,1956,1957],{},"\u002Faccount\u002Finquiry","로 이동(GNB·푸터·사이트맵 링크 정리) + 나의 페이지 섹션(공통 셸 + 9개 라우트·회원 정보 변경·결제 카드 관리) + 크레딧 충전 플로우(시안 기반 재구성·결제 컨펌·결과 화면) Pages 배포 #44·#45·#46. ",[21,1960,1961],{},"트랙 D",[26,1963,1136],{}," 루트(",[26,1966,29],{},") placeholder JSON을 ",[26,1969,1970],{},"c.redirect('\u002Fdoc')","로 교체해 Scalar API 문서로 302 이동, Workers 재배포(Version ",[26,1973,1974],{},"f3fd3eb4...",[21,1976,1977],{},"트랙 E",[26,1979,1136],{}," §13 working tree WIP 정식 커밋 — ",[21,1982,1983],{},"RCS 채널(5채널째)"," adapter(",[26,1986,1987],{},"rcs.ts"," sms\u002Flms\u002Fmms\u002Ftemplate 4타입)·producer·consumer·webhook + ",[26,1990,1991],{},"RCS_PRICING{sms:12,lms:40,mms:120,template:50}",[21,1993,1994],{},"Export 잡",[26,1996,1997],{},"TB_EXPORT_JOB",[26,1999,1793],{}," CRUD(시안 다운로드 요청 PU 대응, 90일 윈도우 우회) + ",[21,2002,2003],{},"Flow 정의",[26,2005,2006],{},"TB_FLOW_DEFINITION\u002FRUN\u002FSTEP_RUN",[26,2008,1796],{}," CRUD(nodes JSON 검증: order 연속·첫 노드 always·5채널 enum) + OpenAPI 4지점(+230) + ",[26,2011,1771],{}," 마이그레이션 → 단일 배치 커밋 ",[26,2014,2015],{},"1e7bd61","(12 files +1228 −16) + 프로덕션 배포 #8(Version ",[26,2018,2019],{},"95f9f894...","). DDL 적용은 1105 회복 후 ",[26,2022,1161],{}," 경로로 보류(프런트 호출처 0개 — 무영향).",[59,2025,2027],{"id":2026},"작성-시점","작성 시점",[64,2029,2030,2033],{},[67,2031,2032],{},"큰 마일스톤 마무리 직후",[67,2034,2035],{},"그날 끝낼 때 짧게라도 한 줄 요약 + 산출물 목록만이라도",[59,2037,2038],{"id":2038},"검색",[18,2040,2041,2042,2045],{},"특정 결정을 언제 했는지 찾을 때 ",[26,2043,2044],{},"grep",":",[843,2047,2051],{"className":2048,"code":2049,"language":2050,"meta":793,"style":793},"language-bash shiki shiki-themes github-light github-dark","grep -rn \"Smart Placement\" doc\u002Fhistory\u002F\ngrep -rn \"Aurora 노출\" doc\u002Fhistory\u002F\n","bash",[26,2052,2053,2071],{"__ignoreMap":793},[354,2054,2057,2060,2064,2068],{"class":2055,"line":2056},"line",1,[354,2058,2044],{"class":2059},"sScJk",[354,2061,2063],{"class":2062},"sj4cs"," -rn",[354,2065,2067],{"class":2066},"sZZnC"," \"Smart Placement\"",[354,2069,2070],{"class":2066}," doc\u002Fhistory\u002F\n",[354,2072,2073,2075,2077,2080],{"class":2055,"line":797},[354,2074,2044],{"class":2059},[354,2076,2063],{"class":2062},[354,2078,2079],{"class":2066}," \"Aurora 노출\"",[354,2081,2070],{"class":2066},[2083,2084,2085],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":793,"searchDepth":794,"depth":794,"links":2087},[2088,2089,2090,2091,2092],{"id":840,"depth":797,"text":841},{"id":860,"depth":797,"text":861},{"id":890,"depth":797,"text":890},{"id":2026,"depth":797,"text":2027},{"id":2038,"depth":797,"text":2038},"날짜별 작업 내역을 누적해 두는 폴더입니다. 하루에 한 파일 원칙.",{},"\u002Fhistory\u002Freadme",{"title":820,"description":2093},"history\u002FREADME","3MWOVCWBzs6wgdPou3CHN-56Loj7HRksyXmOSnluf3Q",{"id":720,"title":2100,"body":2101,"description":793,"extension":811,"meta":4935,"navigation":813,"path":4936,"seo":4937,"stem":4938,"__hash__":4939},"프로젝트 관리 앱 블루프린트 (재사용 가이드)",{"type":8,"value":2102,"toc":4901},[2103,2106,2150,2153,2157,2164,2250,2266,2268,2272,2377,2382,2488,2490,2494,2499,2533,2537,2543,2558,2562,2568,2570,2574,2581,2587,2646,2648,2652,2659,2698,2704,2730,2737,2821,2831,2859,2865,2873,2875,2879,2884,3640,3659,3664,3853,3855,3859,3950,3953,4088,4114,4116,4120,4127,4135,4181,4185,4191,4207,4209,4213,4298,4300,4304,4402,4406,4462,4467,4575,4580,4631,4633,4637,4711,4736,4738,4742,4779,4781,4785,4792,4889,4898],[11,2104,2100],{"id":2105},"프로젝트-관리-앱-블루프린트-재사용-가이드",[15,2107,2108,2122],{},[18,2109,2110,2111,2113,2114,2117,2118,2121],{},"이 문서는 ",[26,2112,44],{},"로 구현한 ",[21,2115,2116],{},"프로젝트 관리 허브 앱","의 일반화된 설계도다.\n특정 프로젝트의 데이터·문구·도메인 내용은 제외하고, ",[21,2119,2120],{},"다른 프로젝트에 그대로 이식·구현","할 수 있는\n아키텍처 · 메뉴 · 화면 · 스키마 · 디자인 토큰 · 셋업\u002F배포 절차만 담는다.\nClaude Code가 이 문서만 보고 새 프로젝트용 관리 앱을 처음부터 구축할 수 있도록 작성했다.",[18,2123,2124,72,2127,2130,2131,676,2134,2137,2138,2141,2142,2145,2146,2149],{},[21,2125,2126],{},"치환 토큰",[26,2128,2129],{},"{APP}","=앱\u002FPages 프로젝트명(예: ",[26,2132,2133],{},"myproj-mng",[26,2135,2136],{},"{PROJECT}","=대상 프로젝트 표시명 ·\n",[26,2139,2140],{},"{D1_NAME}","=D1 DB명 · ",[26,2143,2144],{},"{D1_ID}","=D1 database_id · ",[26,2147,2148],{},"{REPO}","=GitHub 레포 URL.",[2151,2152],"hr",{},[59,2154,2156],{"id":2155},"_1-이-앱은-무엇인가-목적","1. 이 앱은 무엇인가 (목적)",[18,2158,2159,2160,2163],{},"하나의 프로젝트를 운영·조망하는 ",[21,2161,2162],{},"단일 관리 허브",". 5개 영역으로 구성:",[892,2165,2166,2179],{},[895,2167,2168],{},[898,2169,2170,2173,2176],{},[901,2171,2172],{},"영역",[901,2174,2175],{},"경로",[901,2177,2178],{},"한 줄 정의",[908,2180,2181,2193,2205,2221,2237],{},[898,2182,2183,2186,2190],{},[913,2184,2185],{},"대시보드",[913,2187,2188],{},[26,2189,29],{},[913,2191,2192],{},"프로젝트 개요(목표·방향) + 진척 요약 + 바로가기",[898,2194,2195,2198,2202],{},[913,2196,2197],{},"현황판",[913,2199,2200],{},[26,2201,276],{},[913,2203,2204],{},"단계\u002F작업 진척을 시각 카드·행으로 보는 상태 보드",[898,2206,2207,2210,2214],{},[913,2208,2209],{},"WBS(간트)",[913,2211,2212],{},[26,2213,329],{},[913,2215,2216,2217,2220],{},"일 단위 간트 차트 + 작업 ",[21,2218,2219],{},"등록\u002F수정\u002F삭제","(CRUD)",[898,2222,2223,2226,2231],{},[913,2224,2225],{},"문서",[913,2227,2228],{},[26,2229,2230],{},"\u002Fdocs",[913,2232,2233,2236],{},[26,2234,2235],{},"doc\u002F"," 마크다운 트리 뷰어",[898,2238,2239,2242,2247],{},[913,2240,2241],{},"작업 이력",[913,2243,2244],{},[26,2245,2246],{},"\u002Fhistory",[913,2248,2249],{},"일자별 작업 이력 타임라인",[18,2251,2252,2255,2256,2259,2260,2265],{},[21,2253,2254],{},"데이터 정본 2종",": ① 구조화 데이터(진척·작업·단계)는 ",[21,2257,2258],{},"Cloudflare D1",", ② 문서\u002F이력은 ",[21,2261,2262,2264],{},[26,2263,2235],{}," 마크다운","(@nuxt\u002Fcontent).\n자체 완결형 — 외부 API 의존 없음(원하면 외부 API도 붙일 수 있으나 기본은 자급).",[2151,2267],{},[59,2269,2271],{"id":2270},"_2-기술-스택","2. 기술 스택",[64,2273,2274,2287,2297,2307,2319,2337,2352,2361,2367],{},[67,2275,2276,2279,2280,696,2283,2286],{},[21,2277,2278],{},"프레임워크",": Nuxt 3 (",[26,2281,2282],{},"future.compatibilityVersion: 4",[26,2284,2285],{},"\u003Cscript setup lang=\"ts\">",", strict TS)",[67,2288,2289,2292,2293,2296],{},[21,2290,2291],{},"UI",": Nuxt UI v3 (Reka UI + Tailwind CSS v4). ",[26,2294,2295],{},"@nuxtjs\u002Ftailwindcss","는 설치 금지(Nuxt UI가 통합 관리)",[67,2298,2299,2302,2303,2306],{},[21,2300,2301],{},"상태",": Pinia (",[26,2304,2305],{},"@pinia\u002Fnuxt",") — 필요 시",[67,2308,2309,72,2312,2314,2315,2318],{},[21,2310,2311],{},"콘텐츠",[26,2313,971],{}," v3 + ",[26,2316,2317],{},"better-sqlite3","(빌드 타임 SQLite 어댑터)",[67,2320,2321,2324,2325,1302,2327,85,2330,1630,2333,2336],{},[21,2322,2323],{},"DB\u002FORM",": Cloudflare ",[21,2326,232],{},[21,2328,2329],{},"Drizzle ORM",[26,2331,2332],{},"drizzle-orm\u002Fd1",[26,2334,2335],{},"drizzle-kit","(마이그레이션)",[67,2338,2339,72,2342,696,2345,2348,2349,830],{},[21,2340,2341],{},"아이콘",[26,2343,2344],{},"@iconify-json\u002Flucide",[26,2346,2347],{},"@iconify-json\u002Fheroicons"," (",[26,2350,2351],{},"i-lucide-*",[67,2353,2354,72,2357,2360],{},[21,2355,2356],{},"린트",[26,2358,2359],{},"@nuxt\u002Feslint"," + ESLint",[67,2362,2363,2366],{},[21,2364,2365],{},"패키지 매니저",": pnpm",[67,2368,2369,2372,2373,2376],{},[21,2370,2371],{},"배포",": Cloudflare Pages (Functions\u002FSSR) — Nitro ",[26,2374,2375],{},"cloudflare-pages"," 프리셋",[18,2378,2379,2381],{},[26,2380,133],{}," 핵심:",[843,2383,2387],{"className":2384,"code":2385,"language":2386,"meta":793,"style":793},"language-jsonc shiki shiki-themes github-light github-dark","{\n  \"scripts\": {\n    \"dev\": \"nuxt dev\", \"build\": \"nuxt build\", \"preview\": \"nuxt preview\",\n    \"postinstall\": \"nuxt prepare\", \"typecheck\": \"nuxt typecheck\", \"lint\": \"eslint .\",\n    \"db:generate\": \"drizzle-kit generate\",\n    \"db:apply\": \"wrangler d1 migrations apply {D1_NAME} --remote\",\n    \"db:seed\": \"wrangler d1 execute {D1_NAME} --remote --file=server\u002Fdb\u002Fseed.sql\"\n  },\n  \"dependencies\": [\n    \"@iconify-json\u002Fheroicons\",\"@iconify-json\u002Flucide\",\"@nuxt\u002Fcontent\",\"@nuxt\u002Fui\",\n    \"@pinia\u002Fnuxt\",\"better-sqlite3\",\"drizzle-orm\",\"nuxt\",\"pinia\",\"vue\",\"vue-router\"\n  ],\n  \"devDependencies\": [\"@nuxt\u002Feslint\",\"drizzle-kit\",\"eslint\",\"typescript\",\"vue-tsc\"],\n  \u002F\u002F 네이티브 빌드 허용 (pnpm v10 비대화형 설치 필수)\n  \"pnpm\": { \"onlyBuiltDependencies\":\n    [\"@parcel\u002Fwatcher\",\"better-sqlite3\",\"esbuild\",\"unrs-resolver\",\"vue-demi\"] }\n}\n","jsonc",[26,2388,2389,2394,2399,2404,2410,2416,2422,2428,2434,2440,2446,2452,2458,2464,2470,2476,2482],{"__ignoreMap":793},[354,2390,2391],{"class":2055,"line":2056},[354,2392,2393],{},"{\n",[354,2395,2396],{"class":2055,"line":797},[354,2397,2398],{},"  \"scripts\": {\n",[354,2400,2401],{"class":2055,"line":794},[354,2402,2403],{},"    \"dev\": \"nuxt dev\", \"build\": \"nuxt build\", \"preview\": \"nuxt preview\",\n",[354,2405,2407],{"class":2055,"line":2406},4,[354,2408,2409],{},"    \"postinstall\": \"nuxt prepare\", \"typecheck\": \"nuxt typecheck\", \"lint\": \"eslint .\",\n",[354,2411,2413],{"class":2055,"line":2412},5,[354,2414,2415],{},"    \"db:generate\": \"drizzle-kit generate\",\n",[354,2417,2419],{"class":2055,"line":2418},6,[354,2420,2421],{},"    \"db:apply\": \"wrangler d1 migrations apply {D1_NAME} --remote\",\n",[354,2423,2425],{"class":2055,"line":2424},7,[354,2426,2427],{},"    \"db:seed\": \"wrangler d1 execute {D1_NAME} --remote --file=server\u002Fdb\u002Fseed.sql\"\n",[354,2429,2431],{"class":2055,"line":2430},8,[354,2432,2433],{},"  },\n",[354,2435,2437],{"class":2055,"line":2436},9,[354,2438,2439],{},"  \"dependencies\": [\n",[354,2441,2443],{"class":2055,"line":2442},10,[354,2444,2445],{},"    \"@iconify-json\u002Fheroicons\",\"@iconify-json\u002Flucide\",\"@nuxt\u002Fcontent\",\"@nuxt\u002Fui\",\n",[354,2447,2449],{"class":2055,"line":2448},11,[354,2450,2451],{},"    \"@pinia\u002Fnuxt\",\"better-sqlite3\",\"drizzle-orm\",\"nuxt\",\"pinia\",\"vue\",\"vue-router\"\n",[354,2453,2455],{"class":2055,"line":2454},12,[354,2456,2457],{},"  ],\n",[354,2459,2461],{"class":2055,"line":2460},13,[354,2462,2463],{},"  \"devDependencies\": [\"@nuxt\u002Feslint\",\"drizzle-kit\",\"eslint\",\"typescript\",\"vue-tsc\"],\n",[354,2465,2467],{"class":2055,"line":2466},14,[354,2468,2469],{},"  \u002F\u002F 네이티브 빌드 허용 (pnpm v10 비대화형 설치 필수)\n",[354,2471,2473],{"class":2055,"line":2472},15,[354,2474,2475],{},"  \"pnpm\": { \"onlyBuiltDependencies\":\n",[354,2477,2479],{"class":2055,"line":2478},16,[354,2480,2481],{},"    [\"@parcel\u002Fwatcher\",\"better-sqlite3\",\"esbuild\",\"unrs-resolver\",\"vue-demi\"] }\n",[354,2483,2485],{"class":2055,"line":2484},17,[354,2486,2487],{},"}\n",[2151,2489],{},[59,2491,2493],{"id":2492},"_3-시스템-아키텍처","3. 시스템 아키텍처",[2495,2496,2498],"h3",{"id":2497},"렌더링-전략-프리렌더-vs-ssr-핵심-결정","렌더링 전략 (프리렌더 vs SSR) — 핵심 결정",[64,2500,2501,2518],{},[67,2502,2503,72,2511,2514,2515,2517],{},[21,2504,2505,2506,696,2509,830],{},"문서\u002F이력 페이지(",[26,2507,2508],{},"\u002Fdocs\u002F**",[26,2510,2246],{},[21,2512,2513],{},"프리렌더(정적)",". 빌드 타임에 ",[26,2516,971],{},"가 마크다운을 HTML로 구워 베이크 → 런타임 DB 불필요.",[67,2519,2520,72,2529,2532],{},[21,2521,2522,2523,696,2525,696,2527,830],{},"대시보드\u002F현황판\u002FWBS(",[26,2524,29],{},[26,2526,276],{},[26,2528,329],{},[21,2530,2531],{},"SSR(Pages Functions)",". 런타임에 D1을 조회하므로 프리렌더하지 않는다.",[2495,2534,2536],{"id":2535},"데이터-흐름","데이터 흐름",[843,2538,2541],{"className":2539,"code":2540,"language":848},[846],"브라우저\n  ├─ \u002Fdocs, \u002Fhistory        → (프리렌더 HTML, @nuxt\u002Fcontent 빌드 산출)\n  └─ \u002F, \u002Fboard, \u002Fwbs (SSR)  → useFetch('\u002Fapi\u002F*') → server\u002Fapi\u002F* (Pages Function)\n                                                      └─ useDb(event) → Drizzle → D1({D1_NAME})\n",[26,2542,2540],{"__ignoreMap":793},[64,2544,2545,2555],{},[67,2546,2547,2550,2551,2554],{},[21,2548,2549],{},"브라우저는 D1에 직접 접근 불가",". 반드시 서버 한 겹(Pages Function + ",[26,2552,2553],{},"env.DB"," 바인딩) 경유.",[67,2556,2557],{},"데이터 편집(CRUD)도 같은 API 경유.",[2495,2559,2561],{"id":2560},"디렉터리-구조","디렉터리 구조",[843,2563,2566],{"className":2564,"code":2565,"language":848},[846],"app\u002F\n  app.vue                     # \u003CUApp>\u003CNuxtLayout>\u003CNuxtPage\u002F>\n  app.config.ts               # Nuxt UI 색상 매핑(primary\u002Fneutral)\n  assets\u002Fcss\u002Fmain.css         # 디자인 시스템 토큰(전역)\n  assets\u002Fcss\u002Fprose.css        # 마크다운 prose 스타일(전역 — §9 주의)\n  layouts\u002Fdefault.vue         # GNB(상단 네비) + 푸터\n  components\u002F\n    AppLogoMark.vue           # 로고 마크(인라인 SVG)\n    AppWbsOverview.vue        # 대시보드\u002F현황판 공용 진척 요약(전체% + 단계 박스\u002F행)\n  composables\u002F\n    useDocs.ts                # doc\u002F 콘텐츠 조회 + history 판별·날짜 포맷\n    useWbs.ts                 # \u002Fapi\u002Fboard 조회 + 파생 통계(가중평균·카운트·상태)\n  pages\u002F\n    index.vue                 # 대시보드\n    board.vue                 # 현황판\n    wbs.vue                   # 간트 WBS (+ CRUD UI)\n    docs\u002Findex.vue            # 문서 목록\n    docs\u002F[...slug].vue        # 문서 렌더(ContentRenderer)\n    history\u002Findex.vue         # 작업 이력 타임라인\n  utils\u002FwbsData.ts            # WBS 정적 메타(단계명·가중치) + dev 시드 폴백\nserver\u002F\n  api\u002Fboard.get.ts            # 현황판 데이터(GET)\n  api\u002Fwbs.get.ts              # WBS 목록(GET)\n  api\u002Fwbs.post.ts             # WBS 등록(POST)\n  api\u002Fwbs\u002F[id].patch.ts       # WBS 수정(PATCH)\n  api\u002Fwbs\u002F[id].delete.ts      # WBS 삭제(DELETE)\n  db\u002Fschema.ts                # Drizzle 스키마(정본)\n  db\u002Fmigrations\u002F*             # drizzle-kit 생성 마이그레이션\n  db\u002Fseed.sql                 # 시드(초기 데이터)\n  utils\u002Fdb.ts                 # useDb(event) → Drizzle\u002FD1\n  utils\u002FboardSeed.ts          # dev(D1 없음) 폴백 시드\ncontent.config.ts             # @nuxt\u002Fcontent: 소스를 doc\u002F 로 매핑\nnuxt.config.ts                # 프리렌더 라우트 열거 + cloudflare-pages 프리셋\nwrangler.toml                 # D1 바인딩 + migrations_dir\ndoc\u002F                          # 마크다운 문서 + history\u002F\n",[26,2567,2565],{"__ignoreMap":793},[2151,2569],{},[59,2571,2573],{"id":2572},"_4-메뉴-구성도-ia","4. 메뉴 구성도 (IA)",[18,2575,2576,2577,2580],{},"상단 GNB(고정 56px): ",[26,2578,2579],{},"[로고]"," + 네비 + (우측) GitHub 링크.",[843,2582,2585],{"className":2583,"code":2584,"language":848},[846],"[로고 {PROJECT}]   대시보드 · 현황판 · WBS · 문서 · 작업 이력            GitHub↗\n",[26,2586,2584],{"__ignoreMap":793},[64,2588,2589,2643],{},[67,2590,2591,610,2594,2597,2598,116,2601],{},[26,2592,2593],{},"default.vue",[26,2595,2596],{},"nav"," 배열로 정의: ",[26,2599,2600],{},"{ to, label, icon }",[64,2602,2603,2611,2619,2627,2635],{},[67,2604,2605,2606,233,2608],{},"대시보드 ",[26,2607,29],{},[26,2609,2610],{},"i-lucide-layout-dashboard",[67,2612,2613,2614,233,2616],{},"현황판 ",[26,2615,276],{},[26,2617,2618],{},"i-lucide-gauge",[67,2620,2621,2622,233,2624],{},"WBS ",[26,2623,329],{},[26,2625,2626],{},"i-lucide-gantt-chart",[67,2628,2629,2630,233,2632],{},"문서 ",[26,2631,2230],{},[26,2633,2634],{},"i-lucide-book-text",[67,2636,2637,2638,233,2640],{},"작업 이력 ",[26,2639,2246],{},[26,2641,2642],{},"i-lucide-history",[67,2644,2645],{},"푸터: 한 줄 카피라이트\u002F설명.",[2151,2647],{},[59,2649,2651],{"id":2650},"_5-화면별-명세-일반","5. 화면별 명세 (일반)",[2495,2653,2655,2656,2658],{"id":2654},"_51-대시보드-ssr","5.1 대시보드 ",[26,2657,29],{}," (SSR)",[64,2660,2661,2667,2683,2689],{},[67,2662,2663,2666],{},[21,2664,2665],{},"프로젝트 개요",": 목표 카드(한 줄 목표 + 핵심 키워드 칩) + 방향 카드(불릿). 데이터는 페이지 내 배열 또는 별도 doc.",[67,2668,2669,72,2672,2674,2675,2678,2679,2682],{},[21,2670,2671],{},"프로젝트 현황 요약",[26,2673,999],{},"(전체 진척% + 단계 박스) — ",[26,2676,2677],{},"useWbs()","로 ",[26,2680,2681],{},"\u002Fapi\u002Fboard"," 조회.",[67,2684,2685,2688],{},[21,2686,2687],{},"바로가기",": 외부 링크 카드(라벨 + URL). 배열로 관리.",[67,2690,2691,72,2694,2697],{},[21,2692,2693],{},"문서 \u002F 최근 작업 이력",[26,2695,2696],{},"useDocs()","로 doc 목록·최근 history N개 카드.",[2495,2699,2701,2702,2658],{"id":2700},"_52-현황판-board-ssr","5.2 현황판 ",[26,2703,276],{},[64,2705,2706,2709,2712],{},[67,2707,2708],{},"상단: 전체 진척률(가중평균) + 완료\u002F진행 중 카운터.",[67,2710,2711],{},"단계별 진척률(행 스타일) + 단계 상세(그룹\u002F작업 표: 상태·담당·목표\u002F완료일).",[67,2713,2714,2715,75,2717,2719,2720,29,2723,29,2726,2729],{},"데이터: ",[26,2716,2677],{},[26,2718,2681],{},"(D1 ",[26,2721,2722],{},"board_meta",[26,2724,2725],{},"stage",[26,2727,2728],{},"task",").",[2495,2731,2733,2734,2736],{"id":2732},"_53-wbs-간트-wbs-ssr-핵심","5.3 WBS 간트 ",[26,2735,329],{}," (SSR) — 핵심",[64,2738,2739,2745,2754,2760,2777,2790,2811],{},[67,2740,2741,2744],{},[21,2742,2743],{},"상단 KPI",": 전체 진척 미터 + 완료\u002F진행중\u002F지연\u002F예정 카운트.",[67,2746,2747,2750,2751,142],{},[21,2748,2749],{},"툴바",": 담당 칩(다중 필터) · 상태 세그먼트 · 검색 · 모두 접기\u002F펼치기 · 범례 · ",[21,2752,2753],{},"＋작업 추가",[67,2755,2756,2759],{},[21,2757,2758],{},"3계층 트리",": Step → 구분(Category) → 작업(Task), 셰브론 접기.",[67,2761,2762,2765,2766,2769,2770,2773,2774,142],{},[21,2763,2764],{},"간트",": 일 단위 헤더(월\u002F일\u002F요일, 주말 음영, 오늘 기준선) + 상태색 ",[21,2767,2768],{},"진척 막대","(채움+%) · 1일=마일스톤(다이아몬드) · 구분\u002FStep ",[21,2771,2772],{},"롤업 막대"," · 막대 ",[21,2775,2776],{},"호버 툴팁",[67,2778,2779,2782,2783,2786,2787,142],{},[21,2780,2781],{},"CRUD",": 행 hover 시 수정\u002F삭제, ＋추가 → 등록\u002F수정 모달. ",[26,2784,2785],{},"\u002Fapi\u002Fwbs"," 호출 후 ",[26,2788,2789],{},"refresh()",[67,2791,2792,72,2795,2798,2799,2802,2803,2806,2807,2810],{},[21,2793,2794],{},"상태 규칙",[26,2796,2797],{},"done","(progress≥100) · ",[26,2800,2801],{},"plan","(시작 없음\u002F미래) · ",[26,2804,2805],{},"late","(종료\u003C오늘 & \u003C100%) · ",[26,2808,2809],{},"active","(그 외).",[67,2812,2813,2816,2817,2820],{},[21,2814,2815],{},"진척 집계 규칙(중요)",": 전체\u002F단계 진척은 ",[21,2818,2819],{},"단계 가중평균","(보드와 일치)으로, 작업 카운트·구분 롤업은 작업 기준. (단순 평균은 화면 단위가 잘게 쪼개진 경우 과소평가됨 — 가중치 권장.)",[2495,2822,2824,2825,696,2827,2830],{"id":2823},"_54-문서-docs-docsslug-프리렌더","5.4 문서 ",[26,2826,2230],{},[26,2828,2829],{},"\u002Fdocs\u002F[...slug]"," (프리렌더)",[64,2832,2833,2848],{},[67,2834,2835,72,2837,2839,2840,72,2842,75,2845,142],{},[26,2836,2230],{},[26,2838,2696],{},"로 doc 목록. ",[26,2841,2829],{},[26,2843,2844],{},"queryCollection('docs').path('\u002F'+slug)",[26,2846,2847],{},"\u003CContentRenderer>",[67,2849,2850,2851,2854,2855,2858],{},"링크는 콘텐츠 ",[26,2852,2853],{},"path","를 그대로 사용(",[26,2856,2857],{},"\u002Fdocs${doc.path}",")해 대소문자 일관 유지.",[2495,2860,2862,2863,2830],{"id":2861},"_55-작업-이력-history-프리렌더","5.5 작업 이력 ",[26,2864,2246],{},[64,2866,2867],{},[67,2868,2869,2872],{},[26,2870,2871],{},"doc\u002Fhistory\u002Fhistory.yyyyMMdd.md","를 타임라인으로. 파일명에서 날짜 파싱.",[2151,2874],{},[59,2876,2878],{"id":2877},"_6-데이터-모델-테이블-스키마-d1-drizzle","6. 데이터 모델 · 테이블 스키마 (D1 \u002F Drizzle)",[18,2880,2881,2883],{},[26,2882,714],{}," (구조만 — 데이터 내용 제외):",[843,2885,2889],{"className":2886,"code":2887,"language":2888,"meta":793,"style":793},"language-ts shiki shiki-themes github-light github-dark","import { sqliteTable, text, integer } from 'drizzle-orm\u002Fsqlite-core'\n\n\u002F\u002F 현황판(board) — 프로젝트 메타 + 단계 + 작업\nexport const boardMeta = sqliteTable('board_meta', {\n  id: integer('id').primaryKey(),            \u002F\u002F 단일 행 = 1\n  projectName: text('project_name').notNull(),\n  lastUpdated: text('last_updated').notNull(),\u002F\u002F YYYY-MM-DD\n})\nexport const stage = sqliteTable('stage', {\n  id: text('id').primaryKey(),               \u002F\u002F step-1 …\n  no: text('no').notNull(), name: text('name').notNull(),\n  emoji: text('emoji'), summary: text('summary'),\n  weight: integer('weight').notNull().default(0),     \u002F\u002F 가중치(%)\n  progress: integer('progress').notNull().default(0), \u002F\u002F 진행률(%)\n  sort: integer('sort').notNull().default(0),\n})\nexport const task = sqliteTable('task', {\n  id: text('id').primaryKey(), stageId: text('stage_id').notNull(),\n  grp: text('grp'), title: text('title').notNull(),\n  status: text('status').notNull().default('pending'), \u002F\u002F done|in_progress|pending|blocked\n  owner: text('owner'), note: text('note'),\n  targetDate: text('target_date'), completionDate: text('completion_date'),\n  href: text('href'), sort: integer('sort').notNull().default(0),\n})\n\n\u002F\u002F WBS 간트 항목 — 등록\u002F수정\u002F삭제 대상\nexport const wbsItem = sqliteTable('wbs_item', {\n  id: integer('id').primaryKey({ autoIncrement: true }),\n  step: integer('step').notNull(), grp: text('grp').notNull(),\n  name: text('name').notNull(), owner: text('owner').notNull().default(''),\n  start: text('start'), end: text('end'),               \u002F\u002F YYYY-MM-DD | null\n  progress: integer('progress').notNull().default(0),\n  note: text('note'), href: text('href'),\n  sort: integer('sort').notNull().default(0),\n})\n","ts",[26,2890,2891,2907,2912,2918,2943,2967,2987,3009,3014,3034,3054,3086,3111,3144,3173,3199,3203,3223,3254,3283,3314,3339,3364,3400,3405,3410,3416,3437,3461,3493,3533,3562,3587,3610,3635],{"__ignoreMap":793},[354,2892,2893,2897,2901,2904],{"class":2055,"line":2056},[354,2894,2896],{"class":2895},"szBVR","import",[354,2898,2900],{"class":2899},"sVt8B"," { sqliteTable, text, integer } ",[354,2902,2903],{"class":2895},"from",[354,2905,2906],{"class":2066}," 'drizzle-orm\u002Fsqlite-core'\n",[354,2908,2909],{"class":2055,"line":797},[354,2910,2911],{"emptyLinePlaceholder":813},"\n",[354,2913,2914],{"class":2055,"line":794},[354,2915,2917],{"class":2916},"sJ8bj","\u002F\u002F 현황판(board) — 프로젝트 메타 + 단계 + 작업\n",[354,2919,2920,2923,2926,2929,2932,2935,2937,2940],{"class":2055,"line":2406},[354,2921,2922],{"class":2895},"export",[354,2924,2925],{"class":2895}," const",[354,2927,2928],{"class":2062}," boardMeta",[354,2930,2931],{"class":2895}," =",[354,2933,2934],{"class":2059}," sqliteTable",[354,2936,85],{"class":2899},[354,2938,2939],{"class":2066},"'board_meta'",[354,2941,2942],{"class":2899},", {\n",[354,2944,2945,2948,2951,2953,2956,2958,2961,2964],{"class":2055,"line":2412},[354,2946,2947],{"class":2899},"  id: ",[354,2949,2950],{"class":2059},"integer",[354,2952,85],{"class":2899},[354,2954,2955],{"class":2066},"'id'",[354,2957,2729],{"class":2899},[354,2959,2960],{"class":2059},"primaryKey",[354,2962,2963],{"class":2899},"(),            ",[354,2965,2966],{"class":2916},"\u002F\u002F 단일 행 = 1\n",[354,2968,2969,2972,2974,2976,2979,2981,2984],{"class":2055,"line":2418},[354,2970,2971],{"class":2899},"  projectName: ",[354,2973,848],{"class":2059},[354,2975,85],{"class":2899},[354,2977,2978],{"class":2066},"'project_name'",[354,2980,2729],{"class":2899},[354,2982,2983],{"class":2059},"notNull",[354,2985,2986],{"class":2899},"(),\n",[354,2988,2989,2992,2994,2996,2999,3001,3003,3006],{"class":2055,"line":2424},[354,2990,2991],{"class":2899},"  lastUpdated: ",[354,2993,848],{"class":2059},[354,2995,85],{"class":2899},[354,2997,2998],{"class":2066},"'last_updated'",[354,3000,2729],{"class":2899},[354,3002,2983],{"class":2059},[354,3004,3005],{"class":2899},"(),",[354,3007,3008],{"class":2916},"\u002F\u002F YYYY-MM-DD\n",[354,3010,3011],{"class":2055,"line":2430},[354,3012,3013],{"class":2899},"})\n",[354,3015,3016,3018,3020,3023,3025,3027,3029,3032],{"class":2055,"line":2436},[354,3017,2922],{"class":2895},[354,3019,2925],{"class":2895},[354,3021,3022],{"class":2062}," stage",[354,3024,2931],{"class":2895},[354,3026,2934],{"class":2059},[354,3028,85],{"class":2899},[354,3030,3031],{"class":2066},"'stage'",[354,3033,2942],{"class":2899},[354,3035,3036,3038,3040,3042,3044,3046,3048,3051],{"class":2055,"line":2442},[354,3037,2947],{"class":2899},[354,3039,848],{"class":2059},[354,3041,85],{"class":2899},[354,3043,2955],{"class":2066},[354,3045,2729],{"class":2899},[354,3047,2960],{"class":2059},[354,3049,3050],{"class":2899},"(),               ",[354,3052,3053],{"class":2916},"\u002F\u002F step-1 …\n",[354,3055,3056,3059,3061,3063,3066,3068,3070,3073,3075,3077,3080,3082,3084],{"class":2055,"line":2448},[354,3057,3058],{"class":2899},"  no: ",[354,3060,848],{"class":2059},[354,3062,85],{"class":2899},[354,3064,3065],{"class":2066},"'no'",[354,3067,2729],{"class":2899},[354,3069,2983],{"class":2059},[354,3071,3072],{"class":2899},"(), name: ",[354,3074,848],{"class":2059},[354,3076,85],{"class":2899},[354,3078,3079],{"class":2066},"'name'",[354,3081,2729],{"class":2899},[354,3083,2983],{"class":2059},[354,3085,2986],{"class":2899},[354,3087,3088,3091,3093,3095,3098,3101,3103,3105,3108],{"class":2055,"line":2454},[354,3089,3090],{"class":2899},"  emoji: ",[354,3092,848],{"class":2059},[354,3094,85],{"class":2899},[354,3096,3097],{"class":2066},"'emoji'",[354,3099,3100],{"class":2899},"), summary: ",[354,3102,848],{"class":2059},[354,3104,85],{"class":2899},[354,3106,3107],{"class":2066},"'summary'",[354,3109,3110],{"class":2899},"),\n",[354,3112,3113,3116,3118,3120,3123,3125,3127,3130,3133,3135,3138,3141],{"class":2055,"line":2460},[354,3114,3115],{"class":2899},"  weight: ",[354,3117,2950],{"class":2059},[354,3119,85],{"class":2899},[354,3121,3122],{"class":2066},"'weight'",[354,3124,2729],{"class":2899},[354,3126,2983],{"class":2059},[354,3128,3129],{"class":2899},"().",[354,3131,3132],{"class":2059},"default",[354,3134,85],{"class":2899},[354,3136,3137],{"class":2062},"0",[354,3139,3140],{"class":2899},"),     ",[354,3142,3143],{"class":2916},"\u002F\u002F 가중치(%)\n",[354,3145,3146,3149,3151,3153,3156,3158,3160,3162,3164,3166,3168,3170],{"class":2055,"line":2466},[354,3147,3148],{"class":2899},"  progress: ",[354,3150,2950],{"class":2059},[354,3152,85],{"class":2899},[354,3154,3155],{"class":2066},"'progress'",[354,3157,2729],{"class":2899},[354,3159,2983],{"class":2059},[354,3161,3129],{"class":2899},[354,3163,3132],{"class":2059},[354,3165,85],{"class":2899},[354,3167,3137],{"class":2062},[354,3169,372],{"class":2899},[354,3171,3172],{"class":2916},"\u002F\u002F 진행률(%)\n",[354,3174,3175,3178,3180,3182,3185,3187,3189,3191,3193,3195,3197],{"class":2055,"line":2472},[354,3176,3177],{"class":2899},"  sort: ",[354,3179,2950],{"class":2059},[354,3181,85],{"class":2899},[354,3183,3184],{"class":2066},"'sort'",[354,3186,2729],{"class":2899},[354,3188,2983],{"class":2059},[354,3190,3129],{"class":2899},[354,3192,3132],{"class":2059},[354,3194,85],{"class":2899},[354,3196,3137],{"class":2062},[354,3198,3110],{"class":2899},[354,3200,3201],{"class":2055,"line":2478},[354,3202,3013],{"class":2899},[354,3204,3205,3207,3209,3212,3214,3216,3218,3221],{"class":2055,"line":2484},[354,3206,2922],{"class":2895},[354,3208,2925],{"class":2895},[354,3210,3211],{"class":2062}," task",[354,3213,2931],{"class":2895},[354,3215,2934],{"class":2059},[354,3217,85],{"class":2899},[354,3219,3220],{"class":2066},"'task'",[354,3222,2942],{"class":2899},[354,3224,3226,3228,3230,3232,3234,3236,3238,3241,3243,3245,3248,3250,3252],{"class":2055,"line":3225},18,[354,3227,2947],{"class":2899},[354,3229,848],{"class":2059},[354,3231,85],{"class":2899},[354,3233,2955],{"class":2066},[354,3235,2729],{"class":2899},[354,3237,2960],{"class":2059},[354,3239,3240],{"class":2899},"(), stageId: ",[354,3242,848],{"class":2059},[354,3244,85],{"class":2899},[354,3246,3247],{"class":2066},"'stage_id'",[354,3249,2729],{"class":2899},[354,3251,2983],{"class":2059},[354,3253,2986],{"class":2899},[354,3255,3257,3260,3262,3264,3267,3270,3272,3274,3277,3279,3281],{"class":2055,"line":3256},19,[354,3258,3259],{"class":2899},"  grp: ",[354,3261,848],{"class":2059},[354,3263,85],{"class":2899},[354,3265,3266],{"class":2066},"'grp'",[354,3268,3269],{"class":2899},"), title: ",[354,3271,848],{"class":2059},[354,3273,85],{"class":2899},[354,3275,3276],{"class":2066},"'title'",[354,3278,2729],{"class":2899},[354,3280,2983],{"class":2059},[354,3282,2986],{"class":2899},[354,3284,3286,3289,3291,3293,3296,3298,3300,3302,3304,3306,3309,3311],{"class":2055,"line":3285},20,[354,3287,3288],{"class":2899},"  status: ",[354,3290,848],{"class":2059},[354,3292,85],{"class":2899},[354,3294,3295],{"class":2066},"'status'",[354,3297,2729],{"class":2899},[354,3299,2983],{"class":2059},[354,3301,3129],{"class":2899},[354,3303,3132],{"class":2059},[354,3305,85],{"class":2899},[354,3307,3308],{"class":2066},"'pending'",[354,3310,372],{"class":2899},[354,3312,3313],{"class":2916},"\u002F\u002F done|in_progress|pending|blocked\n",[354,3315,3317,3320,3322,3324,3327,3330,3332,3334,3337],{"class":2055,"line":3316},21,[354,3318,3319],{"class":2899},"  owner: ",[354,3321,848],{"class":2059},[354,3323,85],{"class":2899},[354,3325,3326],{"class":2066},"'owner'",[354,3328,3329],{"class":2899},"), note: ",[354,3331,848],{"class":2059},[354,3333,85],{"class":2899},[354,3335,3336],{"class":2066},"'note'",[354,3338,3110],{"class":2899},[354,3340,3342,3345,3347,3349,3352,3355,3357,3359,3362],{"class":2055,"line":3341},22,[354,3343,3344],{"class":2899},"  targetDate: ",[354,3346,848],{"class":2059},[354,3348,85],{"class":2899},[354,3350,3351],{"class":2066},"'target_date'",[354,3353,3354],{"class":2899},"), completionDate: ",[354,3356,848],{"class":2059},[354,3358,85],{"class":2899},[354,3360,3361],{"class":2066},"'completion_date'",[354,3363,3110],{"class":2899},[354,3365,3367,3370,3372,3374,3377,3380,3382,3384,3386,3388,3390,3392,3394,3396,3398],{"class":2055,"line":3366},23,[354,3368,3369],{"class":2899},"  href: ",[354,3371,848],{"class":2059},[354,3373,85],{"class":2899},[354,3375,3376],{"class":2066},"'href'",[354,3378,3379],{"class":2899},"), sort: ",[354,3381,2950],{"class":2059},[354,3383,85],{"class":2899},[354,3385,3184],{"class":2066},[354,3387,2729],{"class":2899},[354,3389,2983],{"class":2059},[354,3391,3129],{"class":2899},[354,3393,3132],{"class":2059},[354,3395,85],{"class":2899},[354,3397,3137],{"class":2062},[354,3399,3110],{"class":2899},[354,3401,3403],{"class":2055,"line":3402},24,[354,3404,3013],{"class":2899},[354,3406,3408],{"class":2055,"line":3407},25,[354,3409,2911],{"emptyLinePlaceholder":813},[354,3411,3413],{"class":2055,"line":3412},26,[354,3414,3415],{"class":2916},"\u002F\u002F WBS 간트 항목 — 등록\u002F수정\u002F삭제 대상\n",[354,3417,3419,3421,3423,3426,3428,3430,3432,3435],{"class":2055,"line":3418},27,[354,3420,2922],{"class":2895},[354,3422,2925],{"class":2895},[354,3424,3425],{"class":2062}," wbsItem",[354,3427,2931],{"class":2895},[354,3429,2934],{"class":2059},[354,3431,85],{"class":2899},[354,3433,3434],{"class":2066},"'wbs_item'",[354,3436,2942],{"class":2899},[354,3438,3440,3442,3444,3446,3448,3450,3452,3455,3458],{"class":2055,"line":3439},28,[354,3441,2947],{"class":2899},[354,3443,2950],{"class":2059},[354,3445,85],{"class":2899},[354,3447,2955],{"class":2066},[354,3449,2729],{"class":2899},[354,3451,2960],{"class":2059},[354,3453,3454],{"class":2899},"({ autoIncrement: ",[354,3456,3457],{"class":2062},"true",[354,3459,3460],{"class":2899}," }),\n",[354,3462,3464,3467,3469,3471,3474,3476,3478,3481,3483,3485,3487,3489,3491],{"class":2055,"line":3463},29,[354,3465,3466],{"class":2899},"  step: ",[354,3468,2950],{"class":2059},[354,3470,85],{"class":2899},[354,3472,3473],{"class":2066},"'step'",[354,3475,2729],{"class":2899},[354,3477,2983],{"class":2059},[354,3479,3480],{"class":2899},"(), grp: ",[354,3482,848],{"class":2059},[354,3484,85],{"class":2899},[354,3486,3266],{"class":2066},[354,3488,2729],{"class":2899},[354,3490,2983],{"class":2059},[354,3492,2986],{"class":2899},[354,3494,3496,3499,3501,3503,3505,3507,3509,3512,3514,3516,3518,3520,3522,3524,3526,3528,3531],{"class":2055,"line":3495},30,[354,3497,3498],{"class":2899},"  name: ",[354,3500,848],{"class":2059},[354,3502,85],{"class":2899},[354,3504,3079],{"class":2066},[354,3506,2729],{"class":2899},[354,3508,2983],{"class":2059},[354,3510,3511],{"class":2899},"(), owner: ",[354,3513,848],{"class":2059},[354,3515,85],{"class":2899},[354,3517,3326],{"class":2066},[354,3519,2729],{"class":2899},[354,3521,2983],{"class":2059},[354,3523,3129],{"class":2899},[354,3525,3132],{"class":2059},[354,3527,85],{"class":2899},[354,3529,3530],{"class":2066},"''",[354,3532,3110],{"class":2899},[354,3534,3536,3539,3541,3543,3546,3549,3551,3553,3556,3559],{"class":2055,"line":3535},31,[354,3537,3538],{"class":2899},"  start: ",[354,3540,848],{"class":2059},[354,3542,85],{"class":2899},[354,3544,3545],{"class":2066},"'start'",[354,3547,3548],{"class":2899},"), end: ",[354,3550,848],{"class":2059},[354,3552,85],{"class":2899},[354,3554,3555],{"class":2066},"'end'",[354,3557,3558],{"class":2899},"),               ",[354,3560,3561],{"class":2916},"\u002F\u002F YYYY-MM-DD | null\n",[354,3563,3565,3567,3569,3571,3573,3575,3577,3579,3581,3583,3585],{"class":2055,"line":3564},32,[354,3566,3148],{"class":2899},[354,3568,2950],{"class":2059},[354,3570,85],{"class":2899},[354,3572,3155],{"class":2066},[354,3574,2729],{"class":2899},[354,3576,2983],{"class":2059},[354,3578,3129],{"class":2899},[354,3580,3132],{"class":2059},[354,3582,85],{"class":2899},[354,3584,3137],{"class":2062},[354,3586,3110],{"class":2899},[354,3588,3590,3593,3595,3597,3599,3602,3604,3606,3608],{"class":2055,"line":3589},33,[354,3591,3592],{"class":2899},"  note: ",[354,3594,848],{"class":2059},[354,3596,85],{"class":2899},[354,3598,3336],{"class":2066},[354,3600,3601],{"class":2899},"), href: ",[354,3603,848],{"class":2059},[354,3605,85],{"class":2899},[354,3607,3376],{"class":2066},[354,3609,3110],{"class":2899},[354,3611,3613,3615,3617,3619,3621,3623,3625,3627,3629,3631,3633],{"class":2055,"line":3612},34,[354,3614,3177],{"class":2899},[354,3616,2950],{"class":2059},[354,3618,85],{"class":2899},[354,3620,3184],{"class":2066},[354,3622,2729],{"class":2899},[354,3624,2983],{"class":2059},[354,3626,3129],{"class":2899},[354,3628,3132],{"class":2059},[354,3630,85],{"class":2899},[354,3632,3137],{"class":2062},[354,3634,3110],{"class":2899},[354,3636,3638],{"class":2055,"line":3637},35,[354,3639,3013],{"class":2899},[64,3641,3642,3652],{},[67,3643,3644,3645,3648,3649,142],{},"마이그레이션은 ",[26,3646,3647],{},"pnpm db:generate","(drizzle-kit) → ",[26,3650,3651],{},"server\u002Fdb\u002Fmigrations\u002F",[67,3653,3654,3655,3658],{},"신규 D1엔 ",[26,3656,3657],{},"wrangler d1 migrations apply {D1_NAME} --remote","로 적용. (기존 테이블이 있으면 충돌하므로, 처음 구축 시 migrations apply 사용 권장.)",[18,3660,3661,3663],{},[26,3662,717],{}," (공용 D1 접근):",[843,3665,3667],{"className":2886,"code":3666,"language":2888,"meta":793,"style":793},"import { drizzle } from 'drizzle-orm\u002Fd1'\nimport type { H3Event } from 'h3'\nimport * as schema from '..\u002Fdb\u002Fschema'\ntype D1Client = Parameters\u003Ctypeof drizzle>[0]\nexport function useDb(event: H3Event) {\n  const env = event.context.cloudflare?.env as { DB?: unknown } | undefined\n  const d1 = env?.DB\n  return d1 ? drizzle(d1 as D1Client, { schema }) : null   \u002F\u002F dev(바인딩 없음) → null → 시드 폴백\n}\n",[26,3668,3669,3681,3696,3714,3741,3765,3802,3817,3849],{"__ignoreMap":793},[354,3670,3671,3673,3676,3678],{"class":2055,"line":2056},[354,3672,2896],{"class":2895},[354,3674,3675],{"class":2899}," { drizzle } ",[354,3677,2903],{"class":2895},[354,3679,3680],{"class":2066}," 'drizzle-orm\u002Fd1'\n",[354,3682,3683,3685,3688,3691,3693],{"class":2055,"line":797},[354,3684,2896],{"class":2895},[354,3686,3687],{"class":2895}," type",[354,3689,3690],{"class":2899}," { H3Event } ",[354,3692,2903],{"class":2895},[354,3694,3695],{"class":2066}," 'h3'\n",[354,3697,3698,3700,3703,3706,3709,3711],{"class":2055,"line":794},[354,3699,2896],{"class":2895},[354,3701,3702],{"class":2062}," *",[354,3704,3705],{"class":2895}," as",[354,3707,3708],{"class":2899}," schema ",[354,3710,2903],{"class":2895},[354,3712,3713],{"class":2066}," '..\u002Fdb\u002Fschema'\n",[354,3715,3716,3719,3722,3724,3727,3730,3733,3736,3738],{"class":2055,"line":2406},[354,3717,3718],{"class":2895},"type",[354,3720,3721],{"class":2059}," D1Client",[354,3723,2931],{"class":2895},[354,3725,3726],{"class":2059}," Parameters",[354,3728,3729],{"class":2899},"\u003C",[354,3731,3732],{"class":2895},"typeof",[354,3734,3735],{"class":2899}," drizzle>[",[354,3737,3137],{"class":2062},[354,3739,3740],{"class":2899},"]\n",[354,3742,3743,3745,3748,3751,3753,3757,3759,3762],{"class":2055,"line":2412},[354,3744,2922],{"class":2895},[354,3746,3747],{"class":2895}," function",[354,3749,3750],{"class":2059}," useDb",[354,3752,85],{"class":2899},[354,3754,3756],{"class":3755},"s4XuR","event",[354,3758,2045],{"class":2895},[354,3760,3761],{"class":2059}," H3Event",[354,3763,3764],{"class":2899},") {\n",[354,3766,3767,3770,3773,3775,3778,3781,3784,3787,3790,3793,3796,3799],{"class":2055,"line":2418},[354,3768,3769],{"class":2895},"  const",[354,3771,3772],{"class":2062}," env",[354,3774,2931],{"class":2895},[354,3776,3777],{"class":2899}," event.context.cloudflare?.env ",[354,3779,3780],{"class":2895},"as",[354,3782,3783],{"class":2899}," { ",[354,3785,3786],{"class":3755},"DB",[354,3788,3789],{"class":2895},"?:",[354,3791,3792],{"class":2062}," unknown",[354,3794,3795],{"class":2899}," } ",[354,3797,3798],{"class":2895},"|",[354,3800,3801],{"class":2062}," undefined\n",[354,3803,3804,3806,3809,3811,3814],{"class":2055,"line":2424},[354,3805,3769],{"class":2895},[354,3807,3808],{"class":2062}," d1",[354,3810,2931],{"class":2895},[354,3812,3813],{"class":2899}," env?.",[354,3815,3816],{"class":2062},"DB\n",[354,3818,3819,3822,3825,3828,3831,3834,3836,3838,3841,3843,3846],{"class":2055,"line":2430},[354,3820,3821],{"class":2895},"  return",[354,3823,3824],{"class":2899}," d1 ",[354,3826,3827],{"class":2895},"?",[354,3829,3830],{"class":2059}," drizzle",[354,3832,3833],{"class":2899},"(d1 ",[354,3835,3780],{"class":2895},[354,3837,3721],{"class":2059},[354,3839,3840],{"class":2899},", { schema }) ",[354,3842,2045],{"class":2895},[354,3844,3845],{"class":2062}," null",[354,3847,3848],{"class":2916},"   \u002F\u002F dev(바인딩 없음) → null → 시드 폴백\n",[354,3850,3851],{"class":2055,"line":2436},[354,3852,2487],{"class":2899},[2151,3854],{},[59,3856,3858],{"id":3857},"_7-api-엔드포인트","7. API 엔드포인트",[892,3860,3861,3874],{},[895,3862,3863],{},[898,3864,3865,3868,3871],{},[901,3866,3867],{},"메서드\u002F경로",[901,3869,3870],{},"설명",[901,3872,3873],{},"비고",[908,3875,3876,3893,3906,3925,3938],{},[898,3877,3878,3883,3886],{},[913,3879,3880],{},[26,3881,3882],{},"GET \u002Fapi\u002Fboard",[913,3884,3885],{},"현황판 문서(meta+stages+tasks) 조립",[913,3887,3888,3889,3892],{},"dev는 ",[26,3890,3891],{},"boardSeed"," 폴백",[898,3894,3895,3900,3903],{},[913,3896,3897],{},[26,3898,3899],{},"GET \u002Fapi\u002Fwbs",[913,3901,3902],{},"WBS 항목 목록",[913,3904,3905],{},"dev는 정적 시드 폴백",[898,3907,3908,3913,3916],{},[913,3909,3910],{},[26,3911,3912],{},"POST \u002Fapi\u002Fwbs",[913,3914,3915],{},"항목 등록",[913,3917,3918,3921,3922],{},[26,3919,3920],{},"readBody"," 검증 후 insert·",[26,3923,3924],{},"returning()",[898,3926,3927,3932,3935],{},[913,3928,3929],{},[26,3930,3931],{},"PATCH \u002Fapi\u002Fwbs\u002F:id",[913,3933,3934],{},"항목 수정",[913,3936,3937],{},"부분 업데이트",[898,3939,3940,3945,3948],{},[913,3941,3942],{},[26,3943,3944],{},"DELETE \u002Fapi\u002Fwbs\u002F:id",[913,3946,3947],{},"항목 삭제",[913,3949],{},[18,3951,3952],{},"패턴(예 — GET):",[843,3954,3956],{"className":2886,"code":3955,"language":2888,"meta":793,"style":793},"export default defineEventHandler(async (event) => {\n  const db = useDb(event)\n  if (!db) return { data: \u002F* 정적 시드 *\u002F }\n  const rows = await db.select().from(wbsItem).orderBy(asc(wbsItem.sort), asc(wbsItem.id))\n  return { data: rows.map(\u002F* DB컬럼 grp→group 등 매핑 *\u002F) }\n})\n",[26,3957,3958,3986,4000,4025,4066,4084],{"__ignoreMap":793},[354,3959,3960,3962,3965,3968,3970,3973,3975,3977,3980,3983],{"class":2055,"line":2056},[354,3961,2922],{"class":2895},[354,3963,3964],{"class":2895}," default",[354,3966,3967],{"class":2059}," defineEventHandler",[354,3969,85],{"class":2899},[354,3971,3972],{"class":2895},"async",[354,3974,2348],{"class":2899},[354,3976,3756],{"class":3755},[354,3978,3979],{"class":2899},") ",[354,3981,3982],{"class":2895},"=>",[354,3984,3985],{"class":2899}," {\n",[354,3987,3988,3990,3993,3995,3997],{"class":2055,"line":797},[354,3989,3769],{"class":2895},[354,3991,3992],{"class":2062}," db",[354,3994,2931],{"class":2895},[354,3996,3750],{"class":2059},[354,3998,3999],{"class":2899},"(event)\n",[354,4001,4002,4005,4007,4010,4013,4016,4019,4022],{"class":2055,"line":794},[354,4003,4004],{"class":2895},"  if",[354,4006,2348],{"class":2899},[354,4008,4009],{"class":2895},"!",[354,4011,4012],{"class":2899},"db) ",[354,4014,4015],{"class":2895},"return",[354,4017,4018],{"class":2899}," { data: ",[354,4020,4021],{"class":2916},"\u002F* 정적 시드 *\u002F",[354,4023,4024],{"class":2899}," }\n",[354,4026,4027,4029,4032,4034,4037,4040,4043,4045,4047,4050,4053,4055,4058,4061,4063],{"class":2055,"line":2406},[354,4028,3769],{"class":2895},[354,4030,4031],{"class":2062}," rows",[354,4033,2931],{"class":2895},[354,4035,4036],{"class":2895}," await",[354,4038,4039],{"class":2899}," db.",[354,4041,4042],{"class":2059},"select",[354,4044,3129],{"class":2899},[354,4046,2903],{"class":2059},[354,4048,4049],{"class":2899},"(wbsItem).",[354,4051,4052],{"class":2059},"orderBy",[354,4054,85],{"class":2899},[354,4056,4057],{"class":2059},"asc",[354,4059,4060],{"class":2899},"(wbsItem.sort), ",[354,4062,4057],{"class":2059},[354,4064,4065],{"class":2899},"(wbsItem.id))\n",[354,4067,4068,4070,4073,4076,4078,4081],{"class":2055,"line":2412},[354,4069,3821],{"class":2895},[354,4071,4072],{"class":2899}," { data: rows.",[354,4074,4075],{"class":2059},"map",[354,4077,85],{"class":2899},[354,4079,4080],{"class":2916},"\u002F* DB컬럼 grp→group 등 매핑 *\u002F",[354,4082,4083],{"class":2899},") }\n",[354,4085,4086],{"class":2055,"line":2418},[354,4087,3013],{"class":2899},[64,4089,4090,4103],{},[67,4091,4092,4093,4096,4097,4100,4101,142],{},"페이지는 ",[26,4094,4095],{},"useFetch('\u002Fapi\u002F...')","로 조회, 변경은 ",[26,4098,4099],{},"$fetch(..., { method })"," 후 ",[26,4102,2789],{},[67,4104,4105,4106,4109,4110,4113],{},"컬럼명(",[26,4107,4108],{},"grp",")과 화면 키(",[26,4111,4112],{},"group",")는 API 레이어에서 매핑.",[2151,4115],{},[59,4117,4119],{"id":4118},"_8-디자인-가이드-토큰","8. 디자인 가이드 (토큰)",[18,4121,4122,4123,4126],{},"두 개의 토큰 세트를 쓴다. ",[21,4124,4125],{},"둘 다 전역 CSS","로 둔다(§9 주의).",[2495,4128,4130,4131,4134],{"id":4129},"_81-앱-전반-appassetscssmaincss-relay-inspired-저밀도-라이트","8.1 앱 전반 — ",[26,4132,4133],{},"app\u002Fassets\u002Fcss\u002Fmain.css"," (Relay-inspired 저밀도 라이트)",[64,4136,4137,4160,4170,4178],{},[67,4138,4139,4140,4143,4144,696,4147,696,4150,4153,4154,696,4157,2729],{},"무채색 ink 11단(",[26,4141,4142],{},"--ink-900","…",[26,4145,4146],{},"--ink-50",[26,4148,4149],{},"--paper",[26,4151,4152],{},"--line",") + 단일 그린 액센트(",[26,4155,4156],{},"--accent #00DC82",[26,4158,4159],{},"--accent-ink",[67,4161,4162,4163,1302,4166,4169],{},"폰트: Inter(UI) + JetBrains Mono(숫자\u002FID) + Pretendard(한국어). ",[26,4164,4165],{},"@import \"tailwindcss\"; @import \"@nuxt\u002Fui\";",[26,4167,4168],{},"@theme","로 토큰 노출.",[67,4171,4172,72,4175,142],{},[26,4173,4174],{},"app.config.ts",[26,4176,4177],{},"ui.colors.primary\u002Fneutral = 'zinc'",[67,4179,4180],{},"1px hairline, radius 카드 12px, 저밀도.",[2495,4182,4184],{"id":4183},"_82-간트-전용-데이터-대시보드-토큰-컴포넌트-스코프-라이트","8.2 간트 전용 — 데이터 대시보드 토큰 (컴포넌트 스코프, 라이트)",[843,4186,4189],{"className":4187,"code":4188,"language":848},[846],"--bg #f4f6f8 · --surface #fff · --surface-2 #f8fafc · --band #eef1f5 · --band-2 #e7ebf0\n--line #e3e8ee · --line-2 #eef1f5 · --ink #1b2330 · --ink-2 #5a6675 · --ink-3 #8a93a3 · --accent #2563eb\n상태: 완료 #16a34a\u002F#d7f0de · 진행중 #2563eb\u002F#d6e4fd · 예정 #94a3b8\u002F#e6eaf0 · 지연 #e0524d\u002F#fadcd9\n주말 #f3f5f8 · 오늘 #f59e0b\n레이아웃: --col-name 300 · --col-who 84 · --col-s\u002Fe 50 · --col-done 56 · --col-prog 86\n--day-w 26 · --row-h 30 · --grp-h 34 · --step-h 38\n담당자 아바타 색: 사람별 고정 색 맵(예: #2563eb\u002F#7c3aed\u002F#0d9488\u002F#d97706\u002F#db2777, 미정 #94a3b8)\n",[26,4190,4188],{"__ignoreMap":793},[64,4192,4193,4196],{},[67,4194,4195],{},"막대 = 트랙(연한 상태색) + 채움(진한 상태색, width=progress%). 1일짜리는 다이아몬드. 그룹\u002FStep은 롤업 막대.",[67,4197,4198,4199,4202,4203,4206],{},"고정 좌측 정보 패널(",[26,4200,4201],{},"position:sticky; left:0",") + 고정 헤더(",[26,4204,4205],{},"top:0","), 좌상단 코너는 left+top 동시 고정. z-index: 코너>헤더>좌측열>본문.",[2151,4208],{},[59,4210,4212],{"id":4211},"_9-환경구현-주의사항-실전-함정","9. 환경·구현 주의사항 (실전 함정)",[866,4214,4215,4235,4254,4266,4272,4278,4292],{},[67,4216,4217,4220,4221,1250,4224,4227,4228,610,4231,4234],{},[21,4218,4219],{},"prose 스타일은 전역 CSS로"," — 컴포넌트 scoped로 두면 별도 CSS 청크로 분리돼 프리렌더된 문서 페이지가 그 청크를 링크하지 않아 ",[21,4222,4223],{},"스타일이 안 먹는다",[26,4225,4226],{},"app\u002Fassets\u002Fcss\u002Fprose.css","를 ",[26,4229,4230],{},"nuxt.config",[26,4232,4233],{},"css","에 등록.",[67,4236,4237,661,4240,1302,4243,4246,4247,4249,4250,4253],{},[21,4238,4239],{},"프리렌더 크롤 끄기",[26,4241,4242],{},"nitro.prerender.crawlLinks: false",[26,4244,4245],{},"routes","를 직접 열거. 마크다운 내부 상대 링크를 크롤하면 404·대문자 디렉터리(케이스 민감 Cloudflare에서 404)를 만든다. 라우트는 ",[26,4248,2235],{}," 트리를 재귀 순회해 ",[21,4251,4252],{},"소문자","로 생성.",[67,4255,4256,661,4259,4262,4263,4265],{},[21,4257,4258],{},"better-sqlite3 네이티브 빌드",[26,4260,4261],{},"pnpm.onlyBuiltDependencies","에 등록해야 비대화형 설치에서 빌드된다. ",[26,4264,971],{},"가 SQLite 어댑터로 사용.",[67,4267,4268,4271],{},[21,4269,4270],{},"@nuxt\u002Fcontent + Cloudflare"," — 문서 페이지를 전부 프리렌더하면 런타임 콘텐츠 DB가 필요 없다(런타임 콘텐츠 쿼리를 하지 않도록 유지).",[67,4273,4274,4277],{},[21,4275,4276],{},"D1 진위 확인"," — 배포 후 D1 값 1건을 바꿔 응답에 반영되는지로 \"폴백이 아닌 실제 D1\" 확인.",[67,4279,4280,4283,4284,4287,4288,4291],{},[21,4281,4282],{},"로컬 dev 소켓 이슈(특정 샌드박스 한정)"," — macOS 기본 ",[26,4285,4286],{},"$TMPDIR","가 길어 Nuxt vite-node Unix 소켓이 104자 제한 초과 시 ",[26,4289,4290],{},"TMPDIR=\u002Ftmp\u002Fx pnpm dev","로 우회(일반 환경은 불필요).",[67,4293,4294,4297],{},[21,4295,4296],{},"진척 집계 일관성"," — 현황판\u002F대시보드\u002FWBS의 \"전체 진척\"은 동일 산식(가중평균) 사용. 화면을 잘게 쪼갠 WBS의 단순 평균과 단계 가중평균은 크게 달라질 수 있음.",[2151,4299],{},[59,4301,4303],{"id":4302},"_10-셋업-절차-claude-code-실행-순서","10. 셋업 절차 (Claude Code 실행 순서)",[843,4305,4307],{"className":2048,"code":4306,"language":2050,"meta":793,"style":793},"# 0) Nuxt 앱 생성 후 의존성(§2) 설치, pnpm.onlyBuiltDependencies 설정\n# 1) D1 생성\nwrangler d1 create {D1_NAME}     # → database_id 확보 → wrangler.toml 작성\n# 2) 설정 파일: nuxt.config.ts(cloudflare-pages 프리셋 + prerender routes),\n#    content.config.ts(doc\u002F 매핑), app.config.ts, wrangler.toml(D1 바인딩 DB),\n#    main.css \u002F prose.css 등록\n# 3) 스키마 작성(server\u002Fdb\u002Fschema.ts) → 마이그레이션 생성·적용\npnpm db:generate\nwrangler d1 migrations apply {D1_NAME} --remote\n# 4) 시드 작성(server\u002Fdb\u002Fseed.sql) → 적용\npnpm db:seed\n# 5) server\u002Futils\u002Fdb.ts, server\u002Fapi\u002F*, app\u002F* (레이아웃·페이지·컴포넌트·컴포저블) 구현\n# 6) 빌드·배포(§11)\n",[26,4308,4309,4314,4319,4335,4340,4345,4350,4355,4363,4380,4385,4392,4397],{"__ignoreMap":793},[354,4310,4311],{"class":2055,"line":2056},[354,4312,4313],{"class":2916},"# 0) Nuxt 앱 생성 후 의존성(§2) 설치, pnpm.onlyBuiltDependencies 설정\n",[354,4315,4316],{"class":2055,"line":797},[354,4317,4318],{"class":2916},"# 1) D1 생성\n",[354,4320,4321,4324,4326,4329,4332],{"class":2055,"line":794},[354,4322,4323],{"class":2059},"wrangler",[354,4325,3808],{"class":2066},[354,4327,4328],{"class":2066}," create",[354,4330,4331],{"class":2066}," {D1_NAME}",[354,4333,4334],{"class":2916},"     # → database_id 확보 → wrangler.toml 작성\n",[354,4336,4337],{"class":2055,"line":2406},[354,4338,4339],{"class":2916},"# 2) 설정 파일: nuxt.config.ts(cloudflare-pages 프리셋 + prerender routes),\n",[354,4341,4342],{"class":2055,"line":2412},[354,4343,4344],{"class":2916},"#    content.config.ts(doc\u002F 매핑), app.config.ts, wrangler.toml(D1 바인딩 DB),\n",[354,4346,4347],{"class":2055,"line":2418},[354,4348,4349],{"class":2916},"#    main.css \u002F prose.css 등록\n",[354,4351,4352],{"class":2055,"line":2424},[354,4353,4354],{"class":2916},"# 3) 스키마 작성(server\u002Fdb\u002Fschema.ts) → 마이그레이션 생성·적용\n",[354,4356,4357,4360],{"class":2055,"line":2430},[354,4358,4359],{"class":2059},"pnpm",[354,4361,4362],{"class":2066}," db:generate\n",[354,4364,4365,4367,4369,4372,4375,4377],{"class":2055,"line":2436},[354,4366,4323],{"class":2059},[354,4368,3808],{"class":2066},[354,4370,4371],{"class":2066}," migrations",[354,4373,4374],{"class":2066}," apply",[354,4376,4331],{"class":2066},[354,4378,4379],{"class":2062}," --remote\n",[354,4381,4382],{"class":2055,"line":2442},[354,4383,4384],{"class":2916},"# 4) 시드 작성(server\u002Fdb\u002Fseed.sql) → 적용\n",[354,4386,4387,4389],{"class":2055,"line":2448},[354,4388,4359],{"class":2059},[354,4390,4391],{"class":2066}," db:seed\n",[354,4393,4394],{"class":2055,"line":2454},[354,4395,4396],{"class":2916},"# 5) server\u002Futils\u002Fdb.ts, server\u002Fapi\u002F*, app\u002F* (레이아웃·페이지·컴포넌트·컴포저블) 구현\n",[354,4398,4399],{"class":2055,"line":2460},[354,4400,4401],{"class":2916},"# 6) 빌드·배포(§11)\n",[18,4403,4404,2045],{},[26,4405,130],{},[843,4407,4411],{"className":4408,"code":4409,"language":4410,"meta":793,"style":793},"language-toml shiki shiki-themes github-light github-dark","name = \"{APP}\"\ncompatibility_date = \"2025-01-01\"\ncompatibility_flags = [\"nodejs_compat\"]\npages_build_output_dir = \"dist\"\n\n[[d1_databases]]\nbinding = \"DB\"\ndatabase_name = \"{D1_NAME}\"\ndatabase_id = \"{D1_ID}\"\nmigrations_dir = \"server\u002Fdb\u002Fmigrations\"\n","toml",[26,4412,4413,4418,4423,4428,4433,4437,4442,4447,4452,4457],{"__ignoreMap":793},[354,4414,4415],{"class":2055,"line":2056},[354,4416,4417],{},"name = \"{APP}\"\n",[354,4419,4420],{"class":2055,"line":797},[354,4421,4422],{},"compatibility_date = \"2025-01-01\"\n",[354,4424,4425],{"class":2055,"line":794},[354,4426,4427],{},"compatibility_flags = [\"nodejs_compat\"]\n",[354,4429,4430],{"class":2055,"line":2406},[354,4431,4432],{},"pages_build_output_dir = \"dist\"\n",[354,4434,4435],{"class":2055,"line":2412},[354,4436,2911],{"emptyLinePlaceholder":813},[354,4438,4439],{"class":2055,"line":2418},[354,4440,4441],{},"[[d1_databases]]\n",[354,4443,4444],{"class":2055,"line":2424},[354,4445,4446],{},"binding = \"DB\"\n",[354,4448,4449],{"class":2055,"line":2430},[354,4450,4451],{},"database_name = \"{D1_NAME}\"\n",[354,4453,4454],{"class":2055,"line":2436},[354,4455,4456],{},"database_id = \"{D1_ID}\"\n",[354,4458,4459],{"class":2055,"line":2442},[354,4460,4461],{},"migrations_dir = \"server\u002Fdb\u002Fmigrations\"\n",[18,4463,4464,2381],{},[26,4465,4466],{},"nuxt.config.ts",[843,4468,4470],{"className":2886,"code":4469,"language":2888,"meta":793,"style":793},"export default defineNuxtConfig({\n  future: { compatibilityVersion: 4 },\n  modules: ['@nuxt\u002Fui', '@nuxt\u002Fcontent', '@nuxt\u002Feslint', '@pinia\u002Fnuxt'],\n  css: ['~\u002Fassets\u002Fcss\u002Fmain.css', '~\u002Fassets\u002Fcss\u002Fprose.css'],\n  nitro: { preset: 'cloudflare-pages',\n    prerender: { crawlLinks: false, failOnError: false, routes: prerenderRoutes } }, \u002F\u002F '\u002Fdocs','\u002Fhistory',+doc 트리\n  \u002F\u002F '\u002F', '\u002Fboard', '\u002Fwbs' 는 프리렌더 제외(SSR)\n})\n",[26,4471,4472,4484,4495,4521,4536,4547,4566,4571],{"__ignoreMap":793},[354,4473,4474,4476,4478,4481],{"class":2055,"line":2056},[354,4475,2922],{"class":2895},[354,4477,3964],{"class":2895},[354,4479,4480],{"class":2059}," defineNuxtConfig",[354,4482,4483],{"class":2899},"({\n",[354,4485,4486,4489,4492],{"class":2055,"line":797},[354,4487,4488],{"class":2899},"  future: { compatibilityVersion: ",[354,4490,4491],{"class":2062},"4",[354,4493,4494],{"class":2899}," },\n",[354,4496,4497,4500,4503,4505,4508,4510,4513,4515,4518],{"class":2055,"line":794},[354,4498,4499],{"class":2899},"  modules: [",[354,4501,4502],{"class":2066},"'@nuxt\u002Fui'",[354,4504,696],{"class":2899},[354,4506,4507],{"class":2066},"'@nuxt\u002Fcontent'",[354,4509,696],{"class":2899},[354,4511,4512],{"class":2066},"'@nuxt\u002Feslint'",[354,4514,696],{"class":2899},[354,4516,4517],{"class":2066},"'@pinia\u002Fnuxt'",[354,4519,4520],{"class":2899},"],\n",[354,4522,4523,4526,4529,4531,4534],{"class":2055,"line":2406},[354,4524,4525],{"class":2899},"  css: [",[354,4527,4528],{"class":2066},"'~\u002Fassets\u002Fcss\u002Fmain.css'",[354,4530,696],{"class":2899},[354,4532,4533],{"class":2066},"'~\u002Fassets\u002Fcss\u002Fprose.css'",[354,4535,4520],{"class":2899},[354,4537,4538,4541,4544],{"class":2055,"line":2412},[354,4539,4540],{"class":2899},"  nitro: { preset: ",[354,4542,4543],{"class":2066},"'cloudflare-pages'",[354,4545,4546],{"class":2899},",\n",[354,4548,4549,4552,4555,4558,4560,4563],{"class":2055,"line":2418},[354,4550,4551],{"class":2899},"    prerender: { crawlLinks: ",[354,4553,4554],{"class":2062},"false",[354,4556,4557],{"class":2899},", failOnError: ",[354,4559,4554],{"class":2062},[354,4561,4562],{"class":2899},", routes: prerenderRoutes } }, ",[354,4564,4565],{"class":2916},"\u002F\u002F '\u002Fdocs','\u002Fhistory',+doc 트리\n",[354,4567,4568],{"class":2055,"line":2424},[354,4569,4570],{"class":2916},"  \u002F\u002F '\u002F', '\u002Fboard', '\u002Fwbs' 는 프리렌더 제외(SSR)\n",[354,4572,4573],{"class":2055,"line":2430},[354,4574,3013],{"class":2899},[18,4576,4577,2045],{},[26,4578,4579],{},"content.config.ts",[843,4581,4583],{"className":2886,"code":4582,"language":2888,"meta":793,"style":793},"export default defineContentConfig({ collections: {\n  docs: defineCollection({ type: 'page', source: { cwd: '\u003Cdoc 절대경로>', include: '**\u002F*.md' } }),\n} })\n",[26,4584,4585,4597,4626],{"__ignoreMap":793},[354,4586,4587,4589,4591,4594],{"class":2055,"line":2056},[354,4588,2922],{"class":2895},[354,4590,3964],{"class":2895},[354,4592,4593],{"class":2059}," defineContentConfig",[354,4595,4596],{"class":2899},"({ collections: {\n",[354,4598,4599,4602,4605,4608,4611,4614,4617,4620,4623],{"class":2055,"line":797},[354,4600,4601],{"class":2899},"  docs: ",[354,4603,4604],{"class":2059},"defineCollection",[354,4606,4607],{"class":2899},"({ type: ",[354,4609,4610],{"class":2066},"'page'",[354,4612,4613],{"class":2899},", source: { cwd: ",[354,4615,4616],{"class":2066},"'\u003Cdoc 절대경로>'",[354,4618,4619],{"class":2899},", include: ",[354,4621,4622],{"class":2066},"'**\u002F*.md'",[354,4624,4625],{"class":2899}," } }),\n",[354,4627,4628],{"class":2055,"line":794},[354,4629,4630],{"class":2899},"} })\n",[2151,4632],{},[59,4634,4636],{"id":4635},"_11-배포-cloudflare-pages-d1","11. 배포 (Cloudflare Pages + D1)",[843,4638,4640],{"className":2048,"code":4639,"language":2050,"meta":793,"style":793},"pnpm build                                  # nitro cloudflare-pages → dist\u002F (_worker.js + 프리렌더)\nwrangler pages project create {APP} --production-branch=main   # 최초 1회\nwrangler pages deploy dist --project-name={APP} --branch=main \\\n  --commit-dirty=true --commit-message \"\u003Cascii>\"\n",[26,4641,4642,4652,4673,4700],{"__ignoreMap":793},[354,4643,4644,4646,4649],{"class":2055,"line":2056},[354,4645,4359],{"class":2059},[354,4647,4648],{"class":2066}," build",[354,4650,4651],{"class":2916},"                                  # nitro cloudflare-pages → dist\u002F (_worker.js + 프리렌더)\n",[354,4653,4654,4656,4659,4662,4664,4667,4670],{"class":2055,"line":797},[354,4655,4323],{"class":2059},[354,4657,4658],{"class":2066}," pages",[354,4660,4661],{"class":2066}," project",[354,4663,4328],{"class":2066},[354,4665,4666],{"class":2066}," {APP}",[354,4668,4669],{"class":2062}," --production-branch=main",[354,4671,4672],{"class":2916},"   # 최초 1회\n",[354,4674,4675,4677,4679,4682,4685,4688,4691,4694,4697],{"class":2055,"line":794},[354,4676,4323],{"class":2059},[354,4678,4658],{"class":2066},[354,4680,4681],{"class":2066}," deploy",[354,4683,4684],{"class":2066}," dist",[354,4686,4687],{"class":2062}," --project-name=",[354,4689,4690],{"class":2899},"{",[354,4692,4693],{"class":2059},"APP}",[354,4695,4696],{"class":2062}," --branch=main",[354,4698,4699],{"class":2062}," \\\n",[354,4701,4702,4705,4708],{"class":2055,"line":2406},[354,4703,4704],{"class":2062},"  --commit-dirty=true",[354,4706,4707],{"class":2062}," --commit-message",[354,4709,4710],{"class":2066}," \"\u003Cascii>\"\n",[64,4712,4713,4720,4729],{},[67,4714,4715,4716,4719],{},"인증: wrangler OAuth. ",[26,4717,4718],{},"--commit-message","는 ASCII로 명시(한글 커밋이면 wrangler가 UTF-8 에러).",[67,4721,4722,4723,610,4725,4728],{},"D1 바인딩은 ",[26,4724,130],{},[26,4726,4727],{},"[[d1_databases]]","로 Pages 배포에 자동 연결.",[67,4730,4731,4732,4735],{},"배포 후 검증: 라우트 200 + ",[26,4733,4734],{},"\u002Fapi\u002F*"," 응답이 D1 기준인지 + 프리렌더 문서 렌더.",[2151,4737],{},[59,4739,4741],{"id":4740},"_12-운영-컨벤션-선택","12. 운영 컨벤션 (선택)",[64,4743,4744,4755,4764,4774],{},[67,4745,4746,72,4748,4750,4751,4754],{},[21,4747,2241],{},[26,4749,2871],{}," — 하루 한 파일, ① 한 줄 요약 → ② 번호 섹션 → ③ 산출물 → ④ 다음 단계. ",[26,4752,4753],{},"doc\u002Fhistory\u002FREADME.md"," 인덱스 갱신.",[67,4756,4757,4760,4761,4763],{},[21,4758,4759],{},"Git",": 단일 ",[26,4762,728],{},", 커밋·푸시는 요청 시. 무관 파일은 끌어들이지 않기.",[67,4765,4766,4769,4770,4773],{},[21,4767,4768],{},"문서 정본 동기화",": 코드\u002F구조가 바뀌면 관련 ",[26,4771,4772],{},"doc\u002F*.md"," 현행화.",[67,4775,4776,4778],{},[21,4777,71],{},": 레포 루트에 프로젝트 목적·스택·구조·컨벤션 요약(이 블루프린트와 별개).",[2151,4780],{},[59,4782,4784],{"id":4783},"_13-새-프로젝트로-가져갈-때-치환-체크리스트","13. 새 프로젝트로 가져갈 때 — 치환 체크리스트",[18,4786,4787,4788,4791],{},"이식 시 ",[21,4789,4790],{},"내용만"," 바꾸면 됨(구조·코드·디자인은 재사용):",[64,4793,4796,4818,4833,4839,4853,4862,4871,4879],{"className":4794},[4795],"contains-task-list",[67,4797,4800,233,4804,89,4806,89,4808,89,4810,4812,4813,696,4815,4817],{"className":4798},[4799],"task-list-item",[4801,4802],"input",{"disabled":813,"type":4803},"checkbox",[26,4805,2129],{},[26,4807,2140],{},[26,4809,2144],{},[26,4811,2148],{}," 치환 (",[26,4814,130],{},[26,4816,133],{}," db 스크립트, GNB GitHub 링크)",[67,4819,4821,4823,4824,696,4827,4829,4830,4832],{"className":4820},[4799],[4801,4822],{"disabled":813,"type":4803}," 로고\u002F브랜드(",[26,4825,4826],{},"AppLogoMark.vue",[26,4828,2593],{}," 브랜드 텍스트), 앱 타이틀(",[26,4831,4230],{}," head)",[67,4834,4836,4838],{"className":4835},[4799],[4801,4837],{"disabled":813,"type":4803}," 대시보드 목표·기획 방향·바로가기 링크 배열",[67,4840,4842,4844,4845,29,4847,4849,4850,4852],{"className":4841},[4799],[4801,4843],{"disabled":813,"type":4803}," 단계 정의(",[26,4846,2722],{},[26,4848,2725],{}," 시드 + ",[26,4851,362],{},"의 단계명·가중치 메타)",[67,4854,4856,4858,4859,4861],{"className":4855},[4799],[4801,4857],{"disabled":813,"type":4803}," WBS 초기 작업(",[26,4860,344],{}," 시드) — 또는 빈 상태로 시작해 화면에서 CRUD",[67,4863,4865,4867,4868,4870],{"className":4864},[4799],[4801,4866],{"disabled":813,"type":4803}," 담당자 목록·아바타 색 맵(",[26,4869,329],{}," 페이지 상수)",[67,4872,4874,233,4876,4878],{"className":4873},[4799],[4801,4875],{"disabled":813,"type":4803},[26,4877,2235],{}," 문서 트리(이 프로젝트의 문서로 교체)",[67,4880,4882,4884,4885,4888],{"className":4881},[4799],[4801,4883],{"disabled":813,"type":4803}," 디자인 액센트색(필요 시 ",[26,4886,4887],{},"main.css","\u002F간트 토큰)",[15,4890,4891],{},[18,4892,4893,4894,4897],{},"구조·아키텍처·스키마·API·디자인 토큰·셋업\u002F배포 절차는 그대로 두고, 위 목록의 ",[21,4895,4896],{},"데이터·문구·브랜드","만 교체하면 새 프로젝트 관리 앱이 된다.",[2083,4899,4900],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":793,"searchDepth":794,"depth":794,"links":4902},[4903,4904,4905,4910,4911,4923,4924,4925,4930,4931,4932,4933,4934],{"id":2155,"depth":797,"text":2156},{"id":2270,"depth":797,"text":2271},{"id":2492,"depth":797,"text":2493,"children":4906},[4907,4908,4909],{"id":2497,"depth":794,"text":2498},{"id":2535,"depth":794,"text":2536},{"id":2560,"depth":794,"text":2561},{"id":2572,"depth":797,"text":2573},{"id":2650,"depth":797,"text":2651,"children":4912},[4913,4915,4917,4919,4921],{"id":2654,"depth":794,"text":4914},"5.1 대시보드 \u002F (SSR)",{"id":2700,"depth":794,"text":4916},"5.2 현황판 \u002Fboard (SSR)",{"id":2732,"depth":794,"text":4918},"5.3 WBS 간트 \u002Fwbs (SSR) — 핵심",{"id":2823,"depth":794,"text":4920},"5.4 문서 \u002Fdocs, \u002Fdocs\u002F[...slug] (프리렌더)",{"id":2861,"depth":794,"text":4922},"5.5 작업 이력 \u002Fhistory (프리렌더)",{"id":2877,"depth":797,"text":2878},{"id":3857,"depth":797,"text":3858},{"id":4118,"depth":797,"text":4119,"children":4926},[4927,4929],{"id":4129,"depth":794,"text":4928},"8.1 앱 전반 — app\u002Fassets\u002Fcss\u002Fmain.css (Relay-inspired 저밀도 라이트)",{"id":4183,"depth":794,"text":4184},{"id":4211,"depth":797,"text":4212},{"id":4302,"depth":797,"text":4303},{"id":4635,"depth":797,"text":4636},{"id":4740,"depth":797,"text":4741},{"id":4783,"depth":797,"text":4784},{},"\u002Fproject_management_blueprint",{"title":2100,"description":793},"PROJECT_MANAGEMENT_BLUEPRINT","RXIvZCrWa6hgLRy6TZMuPF-nO2He0LpdUhBJr-zbky4",1781068740755]