[{"data":1,"prerenderedAt":2910},["ShallowReactive",2],{"doc:\u002Fproject_management_blueprint":3},{"id":4,"title":5,"body":6,"description":322,"extension":2904,"meta":2905,"navigation":862,"path":2906,"seo":2907,"stem":2908,"__hash__":2909},"docs\u002FPROJECT_MANAGEMENT_BLUEPRINT.md","프로젝트 관리 앱 블루프린트 (재사용 가이드)",{"type":7,"value":8,"toc":2870},"minimark",[9,13,64,67,72,79,174,190,192,196,310,316,429,431,435,440,474,478,486,501,505,511,513,517,524,530,592,594,598,605,645,651,678,685,770,780,808,814,822,824,828,834,1595,1614,1620,1810,1812,1816,1907,1910,2045,2071,2073,2077,2084,2092,2138,2142,2148,2164,2166,2170,2258,2260,2264,2364,2369,2425,2430,2538,2543,2594,2596,2600,2674,2699,2701,2705,2744,2746,2750,2757,2857,2866],[10,11,5],"h1",{"id":12},"프로젝트-관리-앱-블루프린트-재사용-가이드",[14,15,16,34],"blockquote",{},[17,18,19,20,24,25,29,30,33],"p",{},"이 문서는 ",[21,22,23],"code",{},"malgn-noti-mng","로 구현한 ",[26,27,28],"strong",{},"프로젝트 관리 허브 앱","의 일반화된 설계도다.\n특정 프로젝트의 데이터·문구·도메인 내용은 제외하고, ",[26,31,32],{},"다른 프로젝트에 그대로 이식·구현","할 수 있는\n아키텍처 · 메뉴 · 화면 · 스키마 · 디자인 토큰 · 셋업\u002F배포 절차만 담는다.\nClaude Code가 이 문서만 보고 새 프로젝트용 관리 앱을 처음부터 구축할 수 있도록 작성했다.",[17,35,36,39,40,43,44,47,48,51,52,55,56,59,60,63],{},[26,37,38],{},"치환 토큰",": ",[21,41,42],{},"{APP}","=앱\u002FPages 프로젝트명(예: ",[21,45,46],{},"myproj-mng",") · ",[21,49,50],{},"{PROJECT}","=대상 프로젝트 표시명 ·\n",[21,53,54],{},"{D1_NAME}","=D1 DB명 · ",[21,57,58],{},"{D1_ID}","=D1 database_id · ",[21,61,62],{},"{REPO}","=GitHub 레포 URL.",[65,66],"hr",{},[68,69,71],"h2",{"id":70},"_1-이-앱은-무엇인가-목적","1. 이 앱은 무엇인가 (목적)",[17,73,74,75,78],{},"하나의 프로젝트를 운영·조망하는 ",[26,76,77],{},"단일 관리 허브",". 5개 영역으로 구성:",[80,81,82,98],"table",{},[83,84,85],"thead",{},[86,87,88,92,95],"tr",{},[89,90,91],"th",{},"영역",[89,93,94],{},"경로",[89,96,97],{},"한 줄 정의",[99,100,101,115,128,145,161],"tbody",{},[86,102,103,107,112],{},[104,105,106],"td",{},"대시보드",[104,108,109],{},[21,110,111],{},"\u002F",[104,113,114],{},"프로젝트 개요(목표·방향) + 진척 요약 + 바로가기",[86,116,117,120,125],{},[104,118,119],{},"현황판",[104,121,122],{},[21,123,124],{},"\u002Fboard",[104,126,127],{},"단계\u002F작업 진척을 시각 카드·행으로 보는 상태 보드",[86,129,130,133,138],{},[104,131,132],{},"WBS(간트)",[104,134,135],{},[21,136,137],{},"\u002Fwbs",[104,139,140,141,144],{},"일 단위 간트 차트 + 작업 ",[26,142,143],{},"등록\u002F수정\u002F삭제","(CRUD)",[86,146,147,150,155],{},[104,148,149],{},"문서",[104,151,152],{},[21,153,154],{},"\u002Fdocs",[104,156,157,160],{},[21,158,159],{},"doc\u002F"," 마크다운 트리 뷰어",[86,162,163,166,171],{},[104,164,165],{},"작업 이력",[104,167,168],{},[21,169,170],{},"\u002Fhistory",[104,172,173],{},"일자별 작업 이력 타임라인",[17,175,176,179,180,183,184,189],{},[26,177,178],{},"데이터 정본 2종",": ① 구조화 데이터(진척·작업·단계)는 ",[26,181,182],{},"Cloudflare D1",", ② 문서\u002F이력은 ",[26,185,186,188],{},[21,187,159],{}," 마크다운","(@nuxt\u002Fcontent).\n자체 완결형 — 외부 API 의존 없음(원하면 외부 API도 붙일 수 있으나 기본은 자급).",[65,191],{},[68,193,195],{"id":194},"_2-기술-스택","2. 기술 스택",[197,198,199,214,224,234,247,269,285,294,300],"ul",{},[200,201,202,205,206,209,210,213],"li",{},[26,203,204],{},"프레임워크",": Nuxt 3 (",[21,207,208],{},"future.compatibilityVersion: 4",", ",[21,211,212],{},"\u003Cscript setup lang=\"ts\">",", strict TS)",[200,215,216,219,220,223],{},[26,217,218],{},"UI",": Nuxt UI v3 (Reka UI + Tailwind CSS v4). ",[21,221,222],{},"@nuxtjs\u002Ftailwindcss","는 설치 금지(Nuxt UI가 통합 관리)",[200,225,226,229,230,233],{},[26,227,228],{},"상태",": Pinia (",[21,231,232],{},"@pinia\u002Fnuxt",") — 필요 시",[200,235,236,39,239,242,243,246],{},[26,237,238],{},"콘텐츠",[21,240,241],{},"@nuxt\u002Fcontent"," v3 + ",[21,244,245],{},"better-sqlite3","(빌드 타임 SQLite 어댑터)",[200,248,249,252,253,256,257,260,261,264,265,268],{},[26,250,251],{},"DB\u002FORM",": Cloudflare ",[26,254,255],{},"D1"," + ",[26,258,259],{},"Drizzle ORM","(",[21,262,263],{},"drizzle-orm\u002Fd1",") + ",[21,266,267],{},"drizzle-kit","(마이그레이션)",[200,270,271,39,274,209,277,280,281,284],{},[26,272,273],{},"아이콘",[21,275,276],{},"@iconify-json\u002Flucide",[21,278,279],{},"@iconify-json\u002Fheroicons"," (",[21,282,283],{},"i-lucide-*",")",[200,286,287,39,290,293],{},[26,288,289],{},"린트",[21,291,292],{},"@nuxt\u002Feslint"," + ESLint",[200,295,296,299],{},[26,297,298],{},"패키지 매니저",": pnpm",[200,301,302,305,306,309],{},[26,303,304],{},"배포",": Cloudflare Pages (Functions\u002FSSR) — Nitro ",[21,307,308],{},"cloudflare-pages"," 프리셋",[17,311,312,315],{},[21,313,314],{},"package.json"," 핵심:",[317,318,323],"pre",{"className":319,"code":320,"language":321,"meta":322,"style":322},"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","",[21,324,325,333,339,345,351,357,363,369,375,381,387,393,399,405,411,417,423],{"__ignoreMap":322},[326,327,330],"span",{"class":328,"line":329},"line",1,[326,331,332],{},"{\n",[326,334,336],{"class":328,"line":335},2,[326,337,338],{},"  \"scripts\": {\n",[326,340,342],{"class":328,"line":341},3,[326,343,344],{},"    \"dev\": \"nuxt dev\", \"build\": \"nuxt build\", \"preview\": \"nuxt preview\",\n",[326,346,348],{"class":328,"line":347},4,[326,349,350],{},"    \"postinstall\": \"nuxt prepare\", \"typecheck\": \"nuxt typecheck\", \"lint\": \"eslint .\",\n",[326,352,354],{"class":328,"line":353},5,[326,355,356],{},"    \"db:generate\": \"drizzle-kit generate\",\n",[326,358,360],{"class":328,"line":359},6,[326,361,362],{},"    \"db:apply\": \"wrangler d1 migrations apply {D1_NAME} --remote\",\n",[326,364,366],{"class":328,"line":365},7,[326,367,368],{},"    \"db:seed\": \"wrangler d1 execute {D1_NAME} --remote --file=server\u002Fdb\u002Fseed.sql\"\n",[326,370,372],{"class":328,"line":371},8,[326,373,374],{},"  },\n",[326,376,378],{"class":328,"line":377},9,[326,379,380],{},"  \"dependencies\": [\n",[326,382,384],{"class":328,"line":383},10,[326,385,386],{},"    \"@iconify-json\u002Fheroicons\",\"@iconify-json\u002Flucide\",\"@nuxt\u002Fcontent\",\"@nuxt\u002Fui\",\n",[326,388,390],{"class":328,"line":389},11,[326,391,392],{},"    \"@pinia\u002Fnuxt\",\"better-sqlite3\",\"drizzle-orm\",\"nuxt\",\"pinia\",\"vue\",\"vue-router\"\n",[326,394,396],{"class":328,"line":395},12,[326,397,398],{},"  ],\n",[326,400,402],{"class":328,"line":401},13,[326,403,404],{},"  \"devDependencies\": [\"@nuxt\u002Feslint\",\"drizzle-kit\",\"eslint\",\"typescript\",\"vue-tsc\"],\n",[326,406,408],{"class":328,"line":407},14,[326,409,410],{},"  \u002F\u002F 네이티브 빌드 허용 (pnpm v10 비대화형 설치 필수)\n",[326,412,414],{"class":328,"line":413},15,[326,415,416],{},"  \"pnpm\": { \"onlyBuiltDependencies\":\n",[326,418,420],{"class":328,"line":419},16,[326,421,422],{},"    [\"@parcel\u002Fwatcher\",\"better-sqlite3\",\"esbuild\",\"unrs-resolver\",\"vue-demi\"] }\n",[326,424,426],{"class":328,"line":425},17,[326,427,428],{},"}\n",[65,430],{},[68,432,434],{"id":433},"_3-시스템-아키텍처","3. 시스템 아키텍처",[436,437,439],"h3",{"id":438},"렌더링-전략-프리렌더-vs-ssr-핵심-결정","렌더링 전략 (프리렌더 vs SSR) — 핵심 결정",[197,441,442,459],{},[200,443,444,39,452,455,456,458],{},[26,445,446,447,209,450,284],{},"문서\u002F이력 페이지(",[21,448,449],{},"\u002Fdocs\u002F**",[21,451,170],{},[26,453,454],{},"프리렌더(정적)",". 빌드 타임에 ",[21,457,241],{},"가 마크다운을 HTML로 구워 베이크 → 런타임 DB 불필요.",[200,460,461,39,470,473],{},[26,462,463,464,209,466,209,468,284],{},"대시보드\u002F현황판\u002FWBS(",[21,465,111],{},[21,467,124],{},[21,469,137],{},[26,471,472],{},"SSR(Pages Functions)",". 런타임에 D1을 조회하므로 프리렌더하지 않는다.",[436,475,477],{"id":476},"데이터-흐름","데이터 흐름",[317,479,484],{"className":480,"code":482,"language":483},[481],"language-text","브라우저\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","text",[21,485,482],{"__ignoreMap":322},[197,487,488,498],{},[200,489,490,493,494,497],{},[26,491,492],{},"브라우저는 D1에 직접 접근 불가",". 반드시 서버 한 겹(Pages Function + ",[21,495,496],{},"env.DB"," 바인딩) 경유.",[200,499,500],{},"데이터 편집(CRUD)도 같은 API 경유.",[436,502,504],{"id":503},"디렉터리-구조","디렉터리 구조",[317,506,509],{"className":507,"code":508,"language":483},[481],"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",[21,510,508],{"__ignoreMap":322},[65,512],{},[68,514,516],{"id":515},"_4-메뉴-구성도-ia","4. 메뉴 구성도 (IA)",[17,518,519,520,523],{},"상단 GNB(고정 56px): ",[21,521,522],{},"[로고]"," + 네비 + (우측) GitHub 링크.",[317,525,528],{"className":526,"code":527,"language":483},[481],"[로고 {PROJECT}]   대시보드 · 현황판 · WBS · 문서 · 작업 이력            GitHub↗\n",[21,529,527],{"__ignoreMap":322},[197,531,532,589],{},[200,533,534,537,538,541,542,545,546],{},[21,535,536],{},"default.vue","의 ",[21,539,540],{},"nav"," 배열로 정의: ",[21,543,544],{},"{ to, label, icon }",".\n",[197,547,548,557,565,573,581],{},[200,549,550,551,553,554],{},"대시보드 ",[21,552,111],{}," ",[21,555,556],{},"i-lucide-layout-dashboard",[200,558,559,560,553,562],{},"현황판 ",[21,561,124],{},[21,563,564],{},"i-lucide-gauge",[200,566,567,568,553,570],{},"WBS ",[21,569,137],{},[21,571,572],{},"i-lucide-gantt-chart",[200,574,575,576,553,578],{},"문서 ",[21,577,154],{},[21,579,580],{},"i-lucide-book-text",[200,582,583,584,553,586],{},"작업 이력 ",[21,585,170],{},[21,587,588],{},"i-lucide-history",[200,590,591],{},"푸터: 한 줄 카피라이트\u002F설명.",[65,593],{},[68,595,597],{"id":596},"_5-화면별-명세-일반","5. 화면별 명세 (일반)",[436,599,601,602,604],{"id":600},"_51-대시보드-ssr","5.1 대시보드 ",[21,603,111],{}," (SSR)",[197,606,607,613,630,636],{},[200,608,609,612],{},[26,610,611],{},"프로젝트 개요",": 목표 카드(한 줄 목표 + 핵심 키워드 칩) + 방향 카드(불릿). 데이터는 페이지 내 배열 또는 별도 doc.",[200,614,615,39,618,621,622,625,626,629],{},[26,616,617],{},"프로젝트 현황 요약",[21,619,620],{},"AppWbsOverview","(전체 진척% + 단계 박스) — ",[21,623,624],{},"useWbs()","로 ",[21,627,628],{},"\u002Fapi\u002Fboard"," 조회.",[200,631,632,635],{},[26,633,634],{},"바로가기",": 외부 링크 카드(라벨 + URL). 배열로 관리.",[200,637,638,39,641,644],{},[26,639,640],{},"문서 \u002F 최근 작업 이력",[21,642,643],{},"useDocs()","로 doc 목록·최근 history N개 카드.",[436,646,648,649,604],{"id":647},"_52-현황판-board-ssr","5.2 현황판 ",[21,650,124],{},[197,652,653,656,659],{},[200,654,655],{},"상단: 전체 진척률(가중평균) + 완료\u002F진행 중 카운터.",[200,657,658],{},"단계별 진척률(행 스타일) + 단계 상세(그룹\u002F작업 표: 상태·담당·목표\u002F완료일).",[200,660,661,662,664,665,667,668,111,671,111,674,677],{},"데이터: ",[21,663,624],{}," → ",[21,666,628],{},"(D1 ",[21,669,670],{},"board_meta",[21,672,673],{},"stage",[21,675,676],{},"task",").",[436,679,681,682,684],{"id":680},"_53-wbs-간트-wbs-ssr-핵심","5.3 WBS 간트 ",[21,683,137],{}," (SSR) — 핵심",[197,686,687,693,703,709,726,739,760],{},[200,688,689,692],{},[26,690,691],{},"상단 KPI",": 전체 진척 미터 + 완료\u002F진행중\u002F지연\u002F예정 카운트.",[200,694,695,698,699,702],{},[26,696,697],{},"툴바",": 담당 칩(다중 필터) · 상태 세그먼트 · 검색 · 모두 접기\u002F펼치기 · 범례 · ",[26,700,701],{},"＋작업 추가",".",[200,704,705,708],{},[26,706,707],{},"3계층 트리",": Step → 구분(Category) → 작업(Task), 셰브론 접기.",[200,710,711,714,715,718,719,722,723,702],{},[26,712,713],{},"간트",": 일 단위 헤더(월\u002F일\u002F요일, 주말 음영, 오늘 기준선) + 상태색 ",[26,716,717],{},"진척 막대","(채움+%) · 1일=마일스톤(다이아몬드) · 구분\u002FStep ",[26,720,721],{},"롤업 막대"," · 막대 ",[26,724,725],{},"호버 툴팁",[200,727,728,731,732,735,736,702],{},[26,729,730],{},"CRUD",": 행 hover 시 수정\u002F삭제, ＋추가 → 등록\u002F수정 모달. ",[21,733,734],{},"\u002Fapi\u002Fwbs"," 호출 후 ",[21,737,738],{},"refresh()",[200,740,741,39,744,747,748,751,752,755,756,759],{},[26,742,743],{},"상태 규칙",[21,745,746],{},"done","(progress≥100) · ",[21,749,750],{},"plan","(시작 없음\u002F미래) · ",[21,753,754],{},"late","(종료\u003C오늘 & \u003C100%) · ",[21,757,758],{},"active","(그 외).",[200,761,762,765,766,769],{},[26,763,764],{},"진척 집계 규칙(중요)",": 전체\u002F단계 진척은 ",[26,767,768],{},"단계 가중평균","(보드와 일치)으로, 작업 카운트·구분 롤업은 작업 기준. (단순 평균은 화면 단위가 잘게 쪼개진 경우 과소평가됨 — 가중치 권장.)",[436,771,773,774,209,776,779],{"id":772},"_54-문서-docs-docsslug-프리렌더","5.4 문서 ",[21,775,154],{},[21,777,778],{},"\u002Fdocs\u002F[...slug]"," (프리렌더)",[197,781,782,797],{},[200,783,784,39,786,788,789,39,791,664,794,702],{},[21,785,154],{},[21,787,643],{},"로 doc 목록. ",[21,790,778],{},[21,792,793],{},"queryCollection('docs').path('\u002F'+slug)",[21,795,796],{},"\u003CContentRenderer>",[200,798,799,800,803,804,807],{},"링크는 콘텐츠 ",[21,801,802],{},"path","를 그대로 사용(",[21,805,806],{},"\u002Fdocs${doc.path}",")해 대소문자 일관 유지.",[436,809,811,812,779],{"id":810},"_55-작업-이력-history-프리렌더","5.5 작업 이력 ",[21,813,170],{},[197,815,816],{},[200,817,818,821],{},[21,819,820],{},"doc\u002Fhistory\u002Fhistory.yyyyMMdd.md","를 타임라인으로. 파일명에서 날짜 파싱.",[65,823],{},[68,825,827],{"id":826},"_6-데이터-모델-테이블-스키마-d1-drizzle","6. 데이터 모델 · 테이블 스키마 (D1 \u002F Drizzle)",[17,829,830,833],{},[21,831,832],{},"server\u002Fdb\u002Fschema.ts"," (구조만 — 데이터 내용 제외):",[317,835,839],{"className":836,"code":837,"language":838,"meta":322,"style":322},"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",[21,840,841,858,864,870,897,921,941,963,968,988,1008,1040,1065,1098,1128,1154,1158,1178,1209,1238,1269,1294,1319,1355,1360,1365,1371,1392,1416,1448,1488,1517,1542,1565,1590],{"__ignoreMap":322},[326,842,843,847,851,854],{"class":328,"line":329},[326,844,846],{"class":845},"szBVR","import",[326,848,850],{"class":849},"sVt8B"," { sqliteTable, text, integer } ",[326,852,853],{"class":845},"from",[326,855,857],{"class":856},"sZZnC"," 'drizzle-orm\u002Fsqlite-core'\n",[326,859,860],{"class":328,"line":335},[326,861,863],{"emptyLinePlaceholder":862},true,"\n",[326,865,866],{"class":328,"line":341},[326,867,869],{"class":868},"sJ8bj","\u002F\u002F 현황판(board) — 프로젝트 메타 + 단계 + 작업\n",[326,871,872,875,878,882,885,889,891,894],{"class":328,"line":347},[326,873,874],{"class":845},"export",[326,876,877],{"class":845}," const",[326,879,881],{"class":880},"sj4cs"," boardMeta",[326,883,884],{"class":845}," =",[326,886,888],{"class":887},"sScJk"," sqliteTable",[326,890,260],{"class":849},[326,892,893],{"class":856},"'board_meta'",[326,895,896],{"class":849},", {\n",[326,898,899,902,905,907,910,912,915,918],{"class":328,"line":353},[326,900,901],{"class":849},"  id: ",[326,903,904],{"class":887},"integer",[326,906,260],{"class":849},[326,908,909],{"class":856},"'id'",[326,911,677],{"class":849},[326,913,914],{"class":887},"primaryKey",[326,916,917],{"class":849},"(),            ",[326,919,920],{"class":868},"\u002F\u002F 단일 행 = 1\n",[326,922,923,926,928,930,933,935,938],{"class":328,"line":359},[326,924,925],{"class":849},"  projectName: ",[326,927,483],{"class":887},[326,929,260],{"class":849},[326,931,932],{"class":856},"'project_name'",[326,934,677],{"class":849},[326,936,937],{"class":887},"notNull",[326,939,940],{"class":849},"(),\n",[326,942,943,946,948,950,953,955,957,960],{"class":328,"line":365},[326,944,945],{"class":849},"  lastUpdated: ",[326,947,483],{"class":887},[326,949,260],{"class":849},[326,951,952],{"class":856},"'last_updated'",[326,954,677],{"class":849},[326,956,937],{"class":887},[326,958,959],{"class":849},"(),",[326,961,962],{"class":868},"\u002F\u002F YYYY-MM-DD\n",[326,964,965],{"class":328,"line":371},[326,966,967],{"class":849},"})\n",[326,969,970,972,974,977,979,981,983,986],{"class":328,"line":377},[326,971,874],{"class":845},[326,973,877],{"class":845},[326,975,976],{"class":880}," stage",[326,978,884],{"class":845},[326,980,888],{"class":887},[326,982,260],{"class":849},[326,984,985],{"class":856},"'stage'",[326,987,896],{"class":849},[326,989,990,992,994,996,998,1000,1002,1005],{"class":328,"line":383},[326,991,901],{"class":849},[326,993,483],{"class":887},[326,995,260],{"class":849},[326,997,909],{"class":856},[326,999,677],{"class":849},[326,1001,914],{"class":887},[326,1003,1004],{"class":849},"(),               ",[326,1006,1007],{"class":868},"\u002F\u002F step-1 …\n",[326,1009,1010,1013,1015,1017,1020,1022,1024,1027,1029,1031,1034,1036,1038],{"class":328,"line":389},[326,1011,1012],{"class":849},"  no: ",[326,1014,483],{"class":887},[326,1016,260],{"class":849},[326,1018,1019],{"class":856},"'no'",[326,1021,677],{"class":849},[326,1023,937],{"class":887},[326,1025,1026],{"class":849},"(), name: ",[326,1028,483],{"class":887},[326,1030,260],{"class":849},[326,1032,1033],{"class":856},"'name'",[326,1035,677],{"class":849},[326,1037,937],{"class":887},[326,1039,940],{"class":849},[326,1041,1042,1045,1047,1049,1052,1055,1057,1059,1062],{"class":328,"line":395},[326,1043,1044],{"class":849},"  emoji: ",[326,1046,483],{"class":887},[326,1048,260],{"class":849},[326,1050,1051],{"class":856},"'emoji'",[326,1053,1054],{"class":849},"), summary: ",[326,1056,483],{"class":887},[326,1058,260],{"class":849},[326,1060,1061],{"class":856},"'summary'",[326,1063,1064],{"class":849},"),\n",[326,1066,1067,1070,1072,1074,1077,1079,1081,1084,1087,1089,1092,1095],{"class":328,"line":401},[326,1068,1069],{"class":849},"  weight: ",[326,1071,904],{"class":887},[326,1073,260],{"class":849},[326,1075,1076],{"class":856},"'weight'",[326,1078,677],{"class":849},[326,1080,937],{"class":887},[326,1082,1083],{"class":849},"().",[326,1085,1086],{"class":887},"default",[326,1088,260],{"class":849},[326,1090,1091],{"class":880},"0",[326,1093,1094],{"class":849},"),     ",[326,1096,1097],{"class":868},"\u002F\u002F 가중치(%)\n",[326,1099,1100,1103,1105,1107,1110,1112,1114,1116,1118,1120,1122,1125],{"class":328,"line":407},[326,1101,1102],{"class":849},"  progress: ",[326,1104,904],{"class":887},[326,1106,260],{"class":849},[326,1108,1109],{"class":856},"'progress'",[326,1111,677],{"class":849},[326,1113,937],{"class":887},[326,1115,1083],{"class":849},[326,1117,1086],{"class":887},[326,1119,260],{"class":849},[326,1121,1091],{"class":880},[326,1123,1124],{"class":849},"), ",[326,1126,1127],{"class":868},"\u002F\u002F 진행률(%)\n",[326,1129,1130,1133,1135,1137,1140,1142,1144,1146,1148,1150,1152],{"class":328,"line":413},[326,1131,1132],{"class":849},"  sort: ",[326,1134,904],{"class":887},[326,1136,260],{"class":849},[326,1138,1139],{"class":856},"'sort'",[326,1141,677],{"class":849},[326,1143,937],{"class":887},[326,1145,1083],{"class":849},[326,1147,1086],{"class":887},[326,1149,260],{"class":849},[326,1151,1091],{"class":880},[326,1153,1064],{"class":849},[326,1155,1156],{"class":328,"line":419},[326,1157,967],{"class":849},[326,1159,1160,1162,1164,1167,1169,1171,1173,1176],{"class":328,"line":425},[326,1161,874],{"class":845},[326,1163,877],{"class":845},[326,1165,1166],{"class":880}," task",[326,1168,884],{"class":845},[326,1170,888],{"class":887},[326,1172,260],{"class":849},[326,1174,1175],{"class":856},"'task'",[326,1177,896],{"class":849},[326,1179,1181,1183,1185,1187,1189,1191,1193,1196,1198,1200,1203,1205,1207],{"class":328,"line":1180},18,[326,1182,901],{"class":849},[326,1184,483],{"class":887},[326,1186,260],{"class":849},[326,1188,909],{"class":856},[326,1190,677],{"class":849},[326,1192,914],{"class":887},[326,1194,1195],{"class":849},"(), stageId: ",[326,1197,483],{"class":887},[326,1199,260],{"class":849},[326,1201,1202],{"class":856},"'stage_id'",[326,1204,677],{"class":849},[326,1206,937],{"class":887},[326,1208,940],{"class":849},[326,1210,1212,1215,1217,1219,1222,1225,1227,1229,1232,1234,1236],{"class":328,"line":1211},19,[326,1213,1214],{"class":849},"  grp: ",[326,1216,483],{"class":887},[326,1218,260],{"class":849},[326,1220,1221],{"class":856},"'grp'",[326,1223,1224],{"class":849},"), title: ",[326,1226,483],{"class":887},[326,1228,260],{"class":849},[326,1230,1231],{"class":856},"'title'",[326,1233,677],{"class":849},[326,1235,937],{"class":887},[326,1237,940],{"class":849},[326,1239,1241,1244,1246,1248,1251,1253,1255,1257,1259,1261,1264,1266],{"class":328,"line":1240},20,[326,1242,1243],{"class":849},"  status: ",[326,1245,483],{"class":887},[326,1247,260],{"class":849},[326,1249,1250],{"class":856},"'status'",[326,1252,677],{"class":849},[326,1254,937],{"class":887},[326,1256,1083],{"class":849},[326,1258,1086],{"class":887},[326,1260,260],{"class":849},[326,1262,1263],{"class":856},"'pending'",[326,1265,1124],{"class":849},[326,1267,1268],{"class":868},"\u002F\u002F done|in_progress|pending|blocked\n",[326,1270,1272,1275,1277,1279,1282,1285,1287,1289,1292],{"class":328,"line":1271},21,[326,1273,1274],{"class":849},"  owner: ",[326,1276,483],{"class":887},[326,1278,260],{"class":849},[326,1280,1281],{"class":856},"'owner'",[326,1283,1284],{"class":849},"), note: ",[326,1286,483],{"class":887},[326,1288,260],{"class":849},[326,1290,1291],{"class":856},"'note'",[326,1293,1064],{"class":849},[326,1295,1297,1300,1302,1304,1307,1310,1312,1314,1317],{"class":328,"line":1296},22,[326,1298,1299],{"class":849},"  targetDate: ",[326,1301,483],{"class":887},[326,1303,260],{"class":849},[326,1305,1306],{"class":856},"'target_date'",[326,1308,1309],{"class":849},"), completionDate: ",[326,1311,483],{"class":887},[326,1313,260],{"class":849},[326,1315,1316],{"class":856},"'completion_date'",[326,1318,1064],{"class":849},[326,1320,1322,1325,1327,1329,1332,1335,1337,1339,1341,1343,1345,1347,1349,1351,1353],{"class":328,"line":1321},23,[326,1323,1324],{"class":849},"  href: ",[326,1326,483],{"class":887},[326,1328,260],{"class":849},[326,1330,1331],{"class":856},"'href'",[326,1333,1334],{"class":849},"), sort: ",[326,1336,904],{"class":887},[326,1338,260],{"class":849},[326,1340,1139],{"class":856},[326,1342,677],{"class":849},[326,1344,937],{"class":887},[326,1346,1083],{"class":849},[326,1348,1086],{"class":887},[326,1350,260],{"class":849},[326,1352,1091],{"class":880},[326,1354,1064],{"class":849},[326,1356,1358],{"class":328,"line":1357},24,[326,1359,967],{"class":849},[326,1361,1363],{"class":328,"line":1362},25,[326,1364,863],{"emptyLinePlaceholder":862},[326,1366,1368],{"class":328,"line":1367},26,[326,1369,1370],{"class":868},"\u002F\u002F WBS 간트 항목 — 등록\u002F수정\u002F삭제 대상\n",[326,1372,1374,1376,1378,1381,1383,1385,1387,1390],{"class":328,"line":1373},27,[326,1375,874],{"class":845},[326,1377,877],{"class":845},[326,1379,1380],{"class":880}," wbsItem",[326,1382,884],{"class":845},[326,1384,888],{"class":887},[326,1386,260],{"class":849},[326,1388,1389],{"class":856},"'wbs_item'",[326,1391,896],{"class":849},[326,1393,1395,1397,1399,1401,1403,1405,1407,1410,1413],{"class":328,"line":1394},28,[326,1396,901],{"class":849},[326,1398,904],{"class":887},[326,1400,260],{"class":849},[326,1402,909],{"class":856},[326,1404,677],{"class":849},[326,1406,914],{"class":887},[326,1408,1409],{"class":849},"({ autoIncrement: ",[326,1411,1412],{"class":880},"true",[326,1414,1415],{"class":849}," }),\n",[326,1417,1419,1422,1424,1426,1429,1431,1433,1436,1438,1440,1442,1444,1446],{"class":328,"line":1418},29,[326,1420,1421],{"class":849},"  step: ",[326,1423,904],{"class":887},[326,1425,260],{"class":849},[326,1427,1428],{"class":856},"'step'",[326,1430,677],{"class":849},[326,1432,937],{"class":887},[326,1434,1435],{"class":849},"(), grp: ",[326,1437,483],{"class":887},[326,1439,260],{"class":849},[326,1441,1221],{"class":856},[326,1443,677],{"class":849},[326,1445,937],{"class":887},[326,1447,940],{"class":849},[326,1449,1451,1454,1456,1458,1460,1462,1464,1467,1469,1471,1473,1475,1477,1479,1481,1483,1486],{"class":328,"line":1450},30,[326,1452,1453],{"class":849},"  name: ",[326,1455,483],{"class":887},[326,1457,260],{"class":849},[326,1459,1033],{"class":856},[326,1461,677],{"class":849},[326,1463,937],{"class":887},[326,1465,1466],{"class":849},"(), owner: ",[326,1468,483],{"class":887},[326,1470,260],{"class":849},[326,1472,1281],{"class":856},[326,1474,677],{"class":849},[326,1476,937],{"class":887},[326,1478,1083],{"class":849},[326,1480,1086],{"class":887},[326,1482,260],{"class":849},[326,1484,1485],{"class":856},"''",[326,1487,1064],{"class":849},[326,1489,1491,1494,1496,1498,1501,1504,1506,1508,1511,1514],{"class":328,"line":1490},31,[326,1492,1493],{"class":849},"  start: ",[326,1495,483],{"class":887},[326,1497,260],{"class":849},[326,1499,1500],{"class":856},"'start'",[326,1502,1503],{"class":849},"), end: ",[326,1505,483],{"class":887},[326,1507,260],{"class":849},[326,1509,1510],{"class":856},"'end'",[326,1512,1513],{"class":849},"),               ",[326,1515,1516],{"class":868},"\u002F\u002F YYYY-MM-DD | null\n",[326,1518,1520,1522,1524,1526,1528,1530,1532,1534,1536,1538,1540],{"class":328,"line":1519},32,[326,1521,1102],{"class":849},[326,1523,904],{"class":887},[326,1525,260],{"class":849},[326,1527,1109],{"class":856},[326,1529,677],{"class":849},[326,1531,937],{"class":887},[326,1533,1083],{"class":849},[326,1535,1086],{"class":887},[326,1537,260],{"class":849},[326,1539,1091],{"class":880},[326,1541,1064],{"class":849},[326,1543,1545,1548,1550,1552,1554,1557,1559,1561,1563],{"class":328,"line":1544},33,[326,1546,1547],{"class":849},"  note: ",[326,1549,483],{"class":887},[326,1551,260],{"class":849},[326,1553,1291],{"class":856},[326,1555,1556],{"class":849},"), href: ",[326,1558,483],{"class":887},[326,1560,260],{"class":849},[326,1562,1331],{"class":856},[326,1564,1064],{"class":849},[326,1566,1568,1570,1572,1574,1576,1578,1580,1582,1584,1586,1588],{"class":328,"line":1567},34,[326,1569,1132],{"class":849},[326,1571,904],{"class":887},[326,1573,260],{"class":849},[326,1575,1139],{"class":856},[326,1577,677],{"class":849},[326,1579,937],{"class":887},[326,1581,1083],{"class":849},[326,1583,1086],{"class":887},[326,1585,260],{"class":849},[326,1587,1091],{"class":880},[326,1589,1064],{"class":849},[326,1591,1593],{"class":328,"line":1592},35,[326,1594,967],{"class":849},[197,1596,1597,1607],{},[200,1598,1599,1600,1603,1604,702],{},"마이그레이션은 ",[21,1601,1602],{},"pnpm db:generate","(drizzle-kit) → ",[21,1605,1606],{},"server\u002Fdb\u002Fmigrations\u002F",[200,1608,1609,1610,1613],{},"신규 D1엔 ",[21,1611,1612],{},"wrangler d1 migrations apply {D1_NAME} --remote","로 적용. (기존 테이블이 있으면 충돌하므로, 처음 구축 시 migrations apply 사용 권장.)",[17,1615,1616,1619],{},[21,1617,1618],{},"server\u002Futils\u002Fdb.ts"," (공용 D1 접근):",[317,1621,1623],{"className":836,"code":1622,"language":838,"meta":322,"style":322},"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",[21,1624,1625,1637,1652,1670,1697,1722,1759,1774,1806],{"__ignoreMap":322},[326,1626,1627,1629,1632,1634],{"class":328,"line":329},[326,1628,846],{"class":845},[326,1630,1631],{"class":849}," { drizzle } ",[326,1633,853],{"class":845},[326,1635,1636],{"class":856}," 'drizzle-orm\u002Fd1'\n",[326,1638,1639,1641,1644,1647,1649],{"class":328,"line":335},[326,1640,846],{"class":845},[326,1642,1643],{"class":845}," type",[326,1645,1646],{"class":849}," { H3Event } ",[326,1648,853],{"class":845},[326,1650,1651],{"class":856}," 'h3'\n",[326,1653,1654,1656,1659,1662,1665,1667],{"class":328,"line":341},[326,1655,846],{"class":845},[326,1657,1658],{"class":880}," *",[326,1660,1661],{"class":845}," as",[326,1663,1664],{"class":849}," schema ",[326,1666,853],{"class":845},[326,1668,1669],{"class":856}," '..\u002Fdb\u002Fschema'\n",[326,1671,1672,1675,1678,1680,1683,1686,1689,1692,1694],{"class":328,"line":347},[326,1673,1674],{"class":845},"type",[326,1676,1677],{"class":887}," D1Client",[326,1679,884],{"class":845},[326,1681,1682],{"class":887}," Parameters",[326,1684,1685],{"class":849},"\u003C",[326,1687,1688],{"class":845},"typeof",[326,1690,1691],{"class":849}," drizzle>[",[326,1693,1091],{"class":880},[326,1695,1696],{"class":849},"]\n",[326,1698,1699,1701,1704,1707,1709,1713,1716,1719],{"class":328,"line":353},[326,1700,874],{"class":845},[326,1702,1703],{"class":845}," function",[326,1705,1706],{"class":887}," useDb",[326,1708,260],{"class":849},[326,1710,1712],{"class":1711},"s4XuR","event",[326,1714,1715],{"class":845},":",[326,1717,1718],{"class":887}," H3Event",[326,1720,1721],{"class":849},") {\n",[326,1723,1724,1727,1730,1732,1735,1738,1741,1744,1747,1750,1753,1756],{"class":328,"line":359},[326,1725,1726],{"class":845},"  const",[326,1728,1729],{"class":880}," env",[326,1731,884],{"class":845},[326,1733,1734],{"class":849}," event.context.cloudflare?.env ",[326,1736,1737],{"class":845},"as",[326,1739,1740],{"class":849}," { ",[326,1742,1743],{"class":1711},"DB",[326,1745,1746],{"class":845},"?:",[326,1748,1749],{"class":880}," unknown",[326,1751,1752],{"class":849}," } ",[326,1754,1755],{"class":845},"|",[326,1757,1758],{"class":880}," undefined\n",[326,1760,1761,1763,1766,1768,1771],{"class":328,"line":365},[326,1762,1726],{"class":845},[326,1764,1765],{"class":880}," d1",[326,1767,884],{"class":845},[326,1769,1770],{"class":849}," env?.",[326,1772,1773],{"class":880},"DB\n",[326,1775,1776,1779,1782,1785,1788,1791,1793,1795,1798,1800,1803],{"class":328,"line":371},[326,1777,1778],{"class":845},"  return",[326,1780,1781],{"class":849}," d1 ",[326,1783,1784],{"class":845},"?",[326,1786,1787],{"class":887}," drizzle",[326,1789,1790],{"class":849},"(d1 ",[326,1792,1737],{"class":845},[326,1794,1677],{"class":887},[326,1796,1797],{"class":849},", { schema }) ",[326,1799,1715],{"class":845},[326,1801,1802],{"class":880}," null",[326,1804,1805],{"class":868},"   \u002F\u002F dev(바인딩 없음) → null → 시드 폴백\n",[326,1807,1808],{"class":328,"line":377},[326,1809,428],{"class":849},[65,1811],{},[68,1813,1815],{"id":1814},"_7-api-엔드포인트","7. API 엔드포인트",[80,1817,1818,1831],{},[83,1819,1820],{},[86,1821,1822,1825,1828],{},[89,1823,1824],{},"메서드\u002F경로",[89,1826,1827],{},"설명",[89,1829,1830],{},"비고",[99,1832,1833,1850,1863,1882,1895],{},[86,1834,1835,1840,1843],{},[104,1836,1837],{},[21,1838,1839],{},"GET \u002Fapi\u002Fboard",[104,1841,1842],{},"현황판 문서(meta+stages+tasks) 조립",[104,1844,1845,1846,1849],{},"dev는 ",[21,1847,1848],{},"boardSeed"," 폴백",[86,1851,1852,1857,1860],{},[104,1853,1854],{},[21,1855,1856],{},"GET \u002Fapi\u002Fwbs",[104,1858,1859],{},"WBS 항목 목록",[104,1861,1862],{},"dev는 정적 시드 폴백",[86,1864,1865,1870,1873],{},[104,1866,1867],{},[21,1868,1869],{},"POST \u002Fapi\u002Fwbs",[104,1871,1872],{},"항목 등록",[104,1874,1875,1878,1879],{},[21,1876,1877],{},"readBody"," 검증 후 insert·",[21,1880,1881],{},"returning()",[86,1883,1884,1889,1892],{},[104,1885,1886],{},[21,1887,1888],{},"PATCH \u002Fapi\u002Fwbs\u002F:id",[104,1890,1891],{},"항목 수정",[104,1893,1894],{},"부분 업데이트",[86,1896,1897,1902,1905],{},[104,1898,1899],{},[21,1900,1901],{},"DELETE \u002Fapi\u002Fwbs\u002F:id",[104,1903,1904],{},"항목 삭제",[104,1906],{},[17,1908,1909],{},"패턴(예 — GET):",[317,1911,1913],{"className":836,"code":1912,"language":838,"meta":322,"style":322},"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",[21,1914,1915,1943,1957,1982,2023,2041],{"__ignoreMap":322},[326,1916,1917,1919,1922,1925,1927,1930,1932,1934,1937,1940],{"class":328,"line":329},[326,1918,874],{"class":845},[326,1920,1921],{"class":845}," default",[326,1923,1924],{"class":887}," defineEventHandler",[326,1926,260],{"class":849},[326,1928,1929],{"class":845},"async",[326,1931,280],{"class":849},[326,1933,1712],{"class":1711},[326,1935,1936],{"class":849},") ",[326,1938,1939],{"class":845},"=>",[326,1941,1942],{"class":849}," {\n",[326,1944,1945,1947,1950,1952,1954],{"class":328,"line":335},[326,1946,1726],{"class":845},[326,1948,1949],{"class":880}," db",[326,1951,884],{"class":845},[326,1953,1706],{"class":887},[326,1955,1956],{"class":849},"(event)\n",[326,1958,1959,1962,1964,1967,1970,1973,1976,1979],{"class":328,"line":341},[326,1960,1961],{"class":845},"  if",[326,1963,280],{"class":849},[326,1965,1966],{"class":845},"!",[326,1968,1969],{"class":849},"db) ",[326,1971,1972],{"class":845},"return",[326,1974,1975],{"class":849}," { data: ",[326,1977,1978],{"class":868},"\u002F* 정적 시드 *\u002F",[326,1980,1981],{"class":849}," }\n",[326,1983,1984,1986,1989,1991,1994,1997,2000,2002,2004,2007,2010,2012,2015,2018,2020],{"class":328,"line":347},[326,1985,1726],{"class":845},[326,1987,1988],{"class":880}," rows",[326,1990,884],{"class":845},[326,1992,1993],{"class":845}," await",[326,1995,1996],{"class":849}," db.",[326,1998,1999],{"class":887},"select",[326,2001,1083],{"class":849},[326,2003,853],{"class":887},[326,2005,2006],{"class":849},"(wbsItem).",[326,2008,2009],{"class":887},"orderBy",[326,2011,260],{"class":849},[326,2013,2014],{"class":887},"asc",[326,2016,2017],{"class":849},"(wbsItem.sort), ",[326,2019,2014],{"class":887},[326,2021,2022],{"class":849},"(wbsItem.id))\n",[326,2024,2025,2027,2030,2033,2035,2038],{"class":328,"line":353},[326,2026,1778],{"class":845},[326,2028,2029],{"class":849}," { data: rows.",[326,2031,2032],{"class":887},"map",[326,2034,260],{"class":849},[326,2036,2037],{"class":868},"\u002F* DB컬럼 grp→group 등 매핑 *\u002F",[326,2039,2040],{"class":849},") }\n",[326,2042,2043],{"class":328,"line":359},[326,2044,967],{"class":849},[197,2046,2047,2060],{},[200,2048,2049,2050,2053,2054,2057,2058,702],{},"페이지는 ",[21,2051,2052],{},"useFetch('\u002Fapi\u002F...')","로 조회, 변경은 ",[21,2055,2056],{},"$fetch(..., { method })"," 후 ",[21,2059,738],{},[200,2061,2062,2063,2066,2067,2070],{},"컬럼명(",[21,2064,2065],{},"grp",")과 화면 키(",[21,2068,2069],{},"group",")는 API 레이어에서 매핑.",[65,2072],{},[68,2074,2076],{"id":2075},"_8-디자인-가이드-토큰","8. 디자인 가이드 (토큰)",[17,2078,2079,2080,2083],{},"두 개의 토큰 세트를 쓴다. ",[26,2081,2082],{},"둘 다 전역 CSS","로 둔다(§9 주의).",[436,2085,2087,2088,2091],{"id":2086},"_81-앱-전반-appassetscssmaincss-relay-inspired-저밀도-라이트","8.1 앱 전반 — ",[21,2089,2090],{},"app\u002Fassets\u002Fcss\u002Fmain.css"," (Relay-inspired 저밀도 라이트)",[197,2093,2094,2117,2127,2135],{},[200,2095,2096,2097,2100,2101,209,2104,209,2107,2110,2111,209,2114,677],{},"무채색 ink 11단(",[21,2098,2099],{},"--ink-900","…",[21,2102,2103],{},"--ink-50",[21,2105,2106],{},"--paper",[21,2108,2109],{},"--line",") + 단일 그린 액센트(",[21,2112,2113],{},"--accent #00DC82",[21,2115,2116],{},"--accent-ink",[200,2118,2119,2120,256,2123,2126],{},"폰트: Inter(UI) + JetBrains Mono(숫자\u002FID) + Pretendard(한국어). ",[21,2121,2122],{},"@import \"tailwindcss\"; @import \"@nuxt\u002Fui\";",[21,2124,2125],{},"@theme","로 토큰 노출.",[200,2128,2129,39,2132,702],{},[21,2130,2131],{},"app.config.ts",[21,2133,2134],{},"ui.colors.primary\u002Fneutral = 'zinc'",[200,2136,2137],{},"1px hairline, radius 카드 12px, 저밀도.",[436,2139,2141],{"id":2140},"_82-간트-전용-데이터-대시보드-토큰-컴포넌트-스코프-라이트","8.2 간트 전용 — 데이터 대시보드 토큰 (컴포넌트 스코프, 라이트)",[317,2143,2146],{"className":2144,"code":2145,"language":483},[481],"--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",[21,2147,2145],{"__ignoreMap":322},[197,2149,2150,2153],{},[200,2151,2152],{},"막대 = 트랙(연한 상태색) + 채움(진한 상태색, width=progress%). 1일짜리는 다이아몬드. 그룹\u002FStep은 롤업 막대.",[200,2154,2155,2156,2159,2160,2163],{},"고정 좌측 정보 패널(",[21,2157,2158],{},"position:sticky; left:0",") + 고정 헤더(",[21,2161,2162],{},"top:0","), 좌상단 코너는 left+top 동시 고정. z-index: 코너>헤더>좌측열>본문.",[65,2165],{},[68,2167,2169],{"id":2168},"_9-환경구현-주의사항-실전-함정","9. 환경·구현 주의사항 (실전 함정)",[2171,2172,2173,2194,2214,2226,2232,2238,2252],"ol",{},[200,2174,2175,2178,2179,2182,2183,2186,2187,537,2190,2193],{},[26,2176,2177],{},"prose 스타일은 전역 CSS로"," — 컴포넌트 scoped로 두면 별도 CSS 청크로 분리돼 프리렌더된 문서 페이지가 그 청크를 링크하지 않아 ",[26,2180,2181],{},"스타일이 안 먹는다",". ",[21,2184,2185],{},"app\u002Fassets\u002Fcss\u002Fprose.css","를 ",[21,2188,2189],{},"nuxt.config",[21,2191,2192],{},"css","에 등록.",[200,2195,2196,2199,2200,256,2203,2206,2207,2209,2210,2213],{},[26,2197,2198],{},"프리렌더 크롤 끄기"," — ",[21,2201,2202],{},"nitro.prerender.crawlLinks: false",[21,2204,2205],{},"routes","를 직접 열거. 마크다운 내부 상대 링크를 크롤하면 404·대문자 디렉터리(케이스 민감 Cloudflare에서 404)를 만든다. 라우트는 ",[21,2208,159],{}," 트리를 재귀 순회해 ",[26,2211,2212],{},"소문자","로 생성.",[200,2215,2216,2199,2219,2222,2223,2225],{},[26,2217,2218],{},"better-sqlite3 네이티브 빌드",[21,2220,2221],{},"pnpm.onlyBuiltDependencies","에 등록해야 비대화형 설치에서 빌드된다. ",[21,2224,241],{},"가 SQLite 어댑터로 사용.",[200,2227,2228,2231],{},[26,2229,2230],{},"@nuxt\u002Fcontent + Cloudflare"," — 문서 페이지를 전부 프리렌더하면 런타임 콘텐츠 DB가 필요 없다(런타임 콘텐츠 쿼리를 하지 않도록 유지).",[200,2233,2234,2237],{},[26,2235,2236],{},"D1 진위 확인"," — 배포 후 D1 값 1건을 바꿔 응답에 반영되는지로 \"폴백이 아닌 실제 D1\" 확인.",[200,2239,2240,2243,2244,2247,2248,2251],{},[26,2241,2242],{},"로컬 dev 소켓 이슈(특정 샌드박스 한정)"," — macOS 기본 ",[21,2245,2246],{},"$TMPDIR","가 길어 Nuxt vite-node Unix 소켓이 104자 제한 초과 시 ",[21,2249,2250],{},"TMPDIR=\u002Ftmp\u002Fx pnpm dev","로 우회(일반 환경은 불필요).",[200,2253,2254,2257],{},[26,2255,2256],{},"진척 집계 일관성"," — 현황판\u002F대시보드\u002FWBS의 \"전체 진척\"은 동일 산식(가중평균) 사용. 화면을 잘게 쪼갠 WBS의 단순 평균과 단계 가중평균은 크게 달라질 수 있음.",[65,2259],{},[68,2261,2263],{"id":2262},"_10-셋업-절차-claude-code-실행-순서","10. 셋업 절차 (Claude Code 실행 순서)",[317,2265,2269],{"className":2266,"code":2267,"language":2268,"meta":322,"style":322},"language-bash shiki shiki-themes github-light github-dark","# 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","bash",[21,2270,2271,2276,2281,2297,2302,2307,2312,2317,2325,2342,2347,2354,2359],{"__ignoreMap":322},[326,2272,2273],{"class":328,"line":329},[326,2274,2275],{"class":868},"# 0) Nuxt 앱 생성 후 의존성(§2) 설치, pnpm.onlyBuiltDependencies 설정\n",[326,2277,2278],{"class":328,"line":335},[326,2279,2280],{"class":868},"# 1) D1 생성\n",[326,2282,2283,2286,2288,2291,2294],{"class":328,"line":341},[326,2284,2285],{"class":887},"wrangler",[326,2287,1765],{"class":856},[326,2289,2290],{"class":856}," create",[326,2292,2293],{"class":856}," {D1_NAME}",[326,2295,2296],{"class":868},"     # → database_id 확보 → wrangler.toml 작성\n",[326,2298,2299],{"class":328,"line":347},[326,2300,2301],{"class":868},"# 2) 설정 파일: nuxt.config.ts(cloudflare-pages 프리셋 + prerender routes),\n",[326,2303,2304],{"class":328,"line":353},[326,2305,2306],{"class":868},"#    content.config.ts(doc\u002F 매핑), app.config.ts, wrangler.toml(D1 바인딩 DB),\n",[326,2308,2309],{"class":328,"line":359},[326,2310,2311],{"class":868},"#    main.css \u002F prose.css 등록\n",[326,2313,2314],{"class":328,"line":365},[326,2315,2316],{"class":868},"# 3) 스키마 작성(server\u002Fdb\u002Fschema.ts) → 마이그레이션 생성·적용\n",[326,2318,2319,2322],{"class":328,"line":371},[326,2320,2321],{"class":887},"pnpm",[326,2323,2324],{"class":856}," db:generate\n",[326,2326,2327,2329,2331,2334,2337,2339],{"class":328,"line":377},[326,2328,2285],{"class":887},[326,2330,1765],{"class":856},[326,2332,2333],{"class":856}," migrations",[326,2335,2336],{"class":856}," apply",[326,2338,2293],{"class":856},[326,2340,2341],{"class":880}," --remote\n",[326,2343,2344],{"class":328,"line":383},[326,2345,2346],{"class":868},"# 4) 시드 작성(server\u002Fdb\u002Fseed.sql) → 적용\n",[326,2348,2349,2351],{"class":328,"line":389},[326,2350,2321],{"class":887},[326,2352,2353],{"class":856}," db:seed\n",[326,2355,2356],{"class":328,"line":395},[326,2357,2358],{"class":868},"# 5) server\u002Futils\u002Fdb.ts, server\u002Fapi\u002F*, app\u002F* (레이아웃·페이지·컴포넌트·컴포저블) 구현\n",[326,2360,2361],{"class":328,"line":401},[326,2362,2363],{"class":868},"# 6) 빌드·배포(§11)\n",[17,2365,2366,1715],{},[21,2367,2368],{},"wrangler.toml",[317,2370,2374],{"className":2371,"code":2372,"language":2373,"meta":322,"style":322},"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",[21,2375,2376,2381,2386,2391,2396,2400,2405,2410,2415,2420],{"__ignoreMap":322},[326,2377,2378],{"class":328,"line":329},[326,2379,2380],{},"name = \"{APP}\"\n",[326,2382,2383],{"class":328,"line":335},[326,2384,2385],{},"compatibility_date = \"2025-01-01\"\n",[326,2387,2388],{"class":328,"line":341},[326,2389,2390],{},"compatibility_flags = [\"nodejs_compat\"]\n",[326,2392,2393],{"class":328,"line":347},[326,2394,2395],{},"pages_build_output_dir = \"dist\"\n",[326,2397,2398],{"class":328,"line":353},[326,2399,863],{"emptyLinePlaceholder":862},[326,2401,2402],{"class":328,"line":359},[326,2403,2404],{},"[[d1_databases]]\n",[326,2406,2407],{"class":328,"line":365},[326,2408,2409],{},"binding = \"DB\"\n",[326,2411,2412],{"class":328,"line":371},[326,2413,2414],{},"database_name = \"{D1_NAME}\"\n",[326,2416,2417],{"class":328,"line":377},[326,2418,2419],{},"database_id = \"{D1_ID}\"\n",[326,2421,2422],{"class":328,"line":383},[326,2423,2424],{},"migrations_dir = \"server\u002Fdb\u002Fmigrations\"\n",[17,2426,2427,315],{},[21,2428,2429],{},"nuxt.config.ts",[317,2431,2433],{"className":836,"code":2432,"language":838,"meta":322,"style":322},"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",[21,2434,2435,2447,2458,2484,2499,2510,2529,2534],{"__ignoreMap":322},[326,2436,2437,2439,2441,2444],{"class":328,"line":329},[326,2438,874],{"class":845},[326,2440,1921],{"class":845},[326,2442,2443],{"class":887}," defineNuxtConfig",[326,2445,2446],{"class":849},"({\n",[326,2448,2449,2452,2455],{"class":328,"line":335},[326,2450,2451],{"class":849},"  future: { compatibilityVersion: ",[326,2453,2454],{"class":880},"4",[326,2456,2457],{"class":849}," },\n",[326,2459,2460,2463,2466,2468,2471,2473,2476,2478,2481],{"class":328,"line":341},[326,2461,2462],{"class":849},"  modules: [",[326,2464,2465],{"class":856},"'@nuxt\u002Fui'",[326,2467,209],{"class":849},[326,2469,2470],{"class":856},"'@nuxt\u002Fcontent'",[326,2472,209],{"class":849},[326,2474,2475],{"class":856},"'@nuxt\u002Feslint'",[326,2477,209],{"class":849},[326,2479,2480],{"class":856},"'@pinia\u002Fnuxt'",[326,2482,2483],{"class":849},"],\n",[326,2485,2486,2489,2492,2494,2497],{"class":328,"line":347},[326,2487,2488],{"class":849},"  css: [",[326,2490,2491],{"class":856},"'~\u002Fassets\u002Fcss\u002Fmain.css'",[326,2493,209],{"class":849},[326,2495,2496],{"class":856},"'~\u002Fassets\u002Fcss\u002Fprose.css'",[326,2498,2483],{"class":849},[326,2500,2501,2504,2507],{"class":328,"line":353},[326,2502,2503],{"class":849},"  nitro: { preset: ",[326,2505,2506],{"class":856},"'cloudflare-pages'",[326,2508,2509],{"class":849},",\n",[326,2511,2512,2515,2518,2521,2523,2526],{"class":328,"line":359},[326,2513,2514],{"class":849},"    prerender: { crawlLinks: ",[326,2516,2517],{"class":880},"false",[326,2519,2520],{"class":849},", failOnError: ",[326,2522,2517],{"class":880},[326,2524,2525],{"class":849},", routes: prerenderRoutes } }, ",[326,2527,2528],{"class":868},"\u002F\u002F '\u002Fdocs','\u002Fhistory',+doc 트리\n",[326,2530,2531],{"class":328,"line":365},[326,2532,2533],{"class":868},"  \u002F\u002F '\u002F', '\u002Fboard', '\u002Fwbs' 는 프리렌더 제외(SSR)\n",[326,2535,2536],{"class":328,"line":371},[326,2537,967],{"class":849},[17,2539,2540,1715],{},[21,2541,2542],{},"content.config.ts",[317,2544,2546],{"className":836,"code":2545,"language":838,"meta":322,"style":322},"export default defineContentConfig({ collections: {\n  docs: defineCollection({ type: 'page', source: { cwd: '\u003Cdoc 절대경로>', include: '**\u002F*.md' } }),\n} })\n",[21,2547,2548,2560,2589],{"__ignoreMap":322},[326,2549,2550,2552,2554,2557],{"class":328,"line":329},[326,2551,874],{"class":845},[326,2553,1921],{"class":845},[326,2555,2556],{"class":887}," defineContentConfig",[326,2558,2559],{"class":849},"({ collections: {\n",[326,2561,2562,2565,2568,2571,2574,2577,2580,2583,2586],{"class":328,"line":335},[326,2563,2564],{"class":849},"  docs: ",[326,2566,2567],{"class":887},"defineCollection",[326,2569,2570],{"class":849},"({ type: ",[326,2572,2573],{"class":856},"'page'",[326,2575,2576],{"class":849},", source: { cwd: ",[326,2578,2579],{"class":856},"'\u003Cdoc 절대경로>'",[326,2581,2582],{"class":849},", include: ",[326,2584,2585],{"class":856},"'**\u002F*.md'",[326,2587,2588],{"class":849}," } }),\n",[326,2590,2591],{"class":328,"line":341},[326,2592,2593],{"class":849},"} })\n",[65,2595],{},[68,2597,2599],{"id":2598},"_11-배포-cloudflare-pages-d1","11. 배포 (Cloudflare Pages + D1)",[317,2601,2603],{"className":2266,"code":2602,"language":2268,"meta":322,"style":322},"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",[21,2604,2605,2615,2636,2663],{"__ignoreMap":322},[326,2606,2607,2609,2612],{"class":328,"line":329},[326,2608,2321],{"class":887},[326,2610,2611],{"class":856}," build",[326,2613,2614],{"class":868},"                                  # nitro cloudflare-pages → dist\u002F (_worker.js + 프리렌더)\n",[326,2616,2617,2619,2622,2625,2627,2630,2633],{"class":328,"line":335},[326,2618,2285],{"class":887},[326,2620,2621],{"class":856}," pages",[326,2623,2624],{"class":856}," project",[326,2626,2290],{"class":856},[326,2628,2629],{"class":856}," {APP}",[326,2631,2632],{"class":880}," --production-branch=main",[326,2634,2635],{"class":868},"   # 최초 1회\n",[326,2637,2638,2640,2642,2645,2648,2651,2654,2657,2660],{"class":328,"line":341},[326,2639,2285],{"class":887},[326,2641,2621],{"class":856},[326,2643,2644],{"class":856}," deploy",[326,2646,2647],{"class":856}," dist",[326,2649,2650],{"class":880}," --project-name=",[326,2652,2653],{"class":849},"{",[326,2655,2656],{"class":887},"APP}",[326,2658,2659],{"class":880}," --branch=main",[326,2661,2662],{"class":880}," \\\n",[326,2664,2665,2668,2671],{"class":328,"line":347},[326,2666,2667],{"class":880},"  --commit-dirty=true",[326,2669,2670],{"class":880}," --commit-message",[326,2672,2673],{"class":856}," \"\u003Cascii>\"\n",[197,2675,2676,2683,2692],{},[200,2677,2678,2679,2682],{},"인증: wrangler OAuth. ",[21,2680,2681],{},"--commit-message","는 ASCII로 명시(한글 커밋이면 wrangler가 UTF-8 에러).",[200,2684,2685,2686,537,2688,2691],{},"D1 바인딩은 ",[21,2687,2368],{},[21,2689,2690],{},"[[d1_databases]]","로 Pages 배포에 자동 연결.",[200,2693,2694,2695,2698],{},"배포 후 검증: 라우트 200 + ",[21,2696,2697],{},"\u002Fapi\u002F*"," 응답이 D1 기준인지 + 프리렌더 문서 렌더.",[65,2700],{},[68,2702,2704],{"id":2703},"_12-운영-컨벤션-선택","12. 운영 컨벤션 (선택)",[197,2706,2707,2718,2728,2738],{},[200,2708,2709,39,2711,2713,2714,2717],{},[26,2710,165],{},[21,2712,820],{}," — 하루 한 파일, ① 한 줄 요약 → ② 번호 섹션 → ③ 산출물 → ④ 다음 단계. ",[21,2715,2716],{},"doc\u002Fhistory\u002FREADME.md"," 인덱스 갱신.",[200,2719,2720,2723,2724,2727],{},[26,2721,2722],{},"Git",": 단일 ",[21,2725,2726],{},"main",", 커밋·푸시는 요청 시. 무관 파일은 끌어들이지 않기.",[200,2729,2730,2733,2734,2737],{},[26,2731,2732],{},"문서 정본 동기화",": 코드\u002F구조가 바뀌면 관련 ",[21,2735,2736],{},"doc\u002F*.md"," 현행화.",[200,2739,2740,2743],{},[26,2741,2742],{},"CLAUDE.md",": 레포 루트에 프로젝트 목적·스택·구조·컨벤션 요약(이 블루프린트와 별개).",[65,2745],{},[68,2747,2749],{"id":2748},"_13-새-프로젝트로-가져갈-때-치환-체크리스트","13. 새 프로젝트로 가져갈 때 — 치환 체크리스트",[17,2751,2752,2753,2756],{},"이식 시 ",[26,2754,2755],{},"내용만"," 바꾸면 됨(구조·코드·디자인은 재사용):",[197,2758,2761,2784,2799,2805,2820,2830,2839,2847],{"className":2759},[2760],"contains-task-list",[200,2762,2765,553,2769,2771,2772,2771,2774,2771,2776,2778,2779,209,2781,2783],{"className":2763},[2764],"task-list-item",[2766,2767],"input",{"disabled":862,"type":2768},"checkbox",[21,2770,42],{},"·",[21,2773,54],{},[21,2775,58],{},[21,2777,62],{}," 치환 (",[21,2780,2368],{},[21,2782,314],{}," db 스크립트, GNB GitHub 링크)",[200,2785,2787,2789,2790,209,2793,2795,2796,2798],{"className":2786},[2764],[2766,2788],{"disabled":862,"type":2768}," 로고\u002F브랜드(",[21,2791,2792],{},"AppLogoMark.vue",[21,2794,536],{}," 브랜드 텍스트), 앱 타이틀(",[21,2797,2189],{}," head)",[200,2800,2802,2804],{"className":2801},[2764],[2766,2803],{"disabled":862,"type":2768}," 대시보드 목표·기획 방향·바로가기 링크 배열",[200,2806,2808,2810,2811,111,2813,2815,2816,2819],{"className":2807},[2764],[2766,2809],{"disabled":862,"type":2768}," 단계 정의(",[21,2812,670],{},[21,2814,673],{}," 시드 + ",[21,2817,2818],{},"wbsData.ts","의 단계명·가중치 메타)",[200,2821,2823,2825,2826,2829],{"className":2822},[2764],[2766,2824],{"disabled":862,"type":2768}," WBS 초기 작업(",[21,2827,2828],{},"wbs_item"," 시드) — 또는 빈 상태로 시작해 화면에서 CRUD",[200,2831,2833,2835,2836,2838],{"className":2832},[2764],[2766,2834],{"disabled":862,"type":2768}," 담당자 목록·아바타 색 맵(",[21,2837,137],{}," 페이지 상수)",[200,2840,2842,553,2844,2846],{"className":2841},[2764],[2766,2843],{"disabled":862,"type":2768},[21,2845,159],{}," 문서 트리(이 프로젝트의 문서로 교체)",[200,2848,2850,2852,2853,2856],{"className":2849},[2764],[2766,2851],{"disabled":862,"type":2768}," 디자인 액센트색(필요 시 ",[21,2854,2855],{},"main.css","\u002F간트 토큰)",[14,2858,2859],{},[17,2860,2861,2862,2865],{},"구조·아키텍처·스키마·API·디자인 토큰·셋업\u002F배포 절차는 그대로 두고, 위 목록의 ",[26,2863,2864],{},"데이터·문구·브랜드","만 교체하면 새 프로젝트 관리 앱이 된다.",[2867,2868,2869],"style",{},"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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":322,"searchDepth":341,"depth":341,"links":2871},[2872,2873,2874,2879,2880,2892,2893,2894,2899,2900,2901,2902,2903],{"id":70,"depth":335,"text":71},{"id":194,"depth":335,"text":195},{"id":433,"depth":335,"text":434,"children":2875},[2876,2877,2878],{"id":438,"depth":341,"text":439},{"id":476,"depth":341,"text":477},{"id":503,"depth":341,"text":504},{"id":515,"depth":335,"text":516},{"id":596,"depth":335,"text":597,"children":2881},[2882,2884,2886,2888,2890],{"id":600,"depth":341,"text":2883},"5.1 대시보드 \u002F (SSR)",{"id":647,"depth":341,"text":2885},"5.2 현황판 \u002Fboard (SSR)",{"id":680,"depth":341,"text":2887},"5.3 WBS 간트 \u002Fwbs (SSR) — 핵심",{"id":772,"depth":341,"text":2889},"5.4 문서 \u002Fdocs, \u002Fdocs\u002F[...slug] (프리렌더)",{"id":810,"depth":341,"text":2891},"5.5 작업 이력 \u002Fhistory (프리렌더)",{"id":826,"depth":335,"text":827},{"id":1814,"depth":335,"text":1815},{"id":2075,"depth":335,"text":2076,"children":2895},[2896,2898],{"id":2086,"depth":341,"text":2897},"8.1 앱 전반 — app\u002Fassets\u002Fcss\u002Fmain.css (Relay-inspired 저밀도 라이트)",{"id":2140,"depth":341,"text":2141},{"id":2168,"depth":335,"text":2169},{"id":2262,"depth":335,"text":2263},{"id":2598,"depth":335,"text":2599},{"id":2703,"depth":335,"text":2704},{"id":2748,"depth":335,"text":2749},"md",{},"\u002Fproject_management_blueprint",{"title":5,"description":322},"PROJECT_MANAGEMENT_BLUEPRINT","E7V0WU5T8PztVAbrhqycauFOCCpy_4Ti_qLZiUcAqfs",1780990720862]