← Home

TAB 프로젝트 재해복구 런북 (랩탑 고장 대비)

Key Insight

이 프로젝트는 David님의 랩탑을 “서버”로 쓴다 — Windows 작업 스케줄러가 매시간 사이트를 재빌드·배포하고, 10분마다 Q&A를 동기화한다. 이 문서의 목적은 **“랩탑이 갑자기 고장나도, 아래 절차를 그대로 따르면 새 컴퓨터에서 동일한 상태로 100% 복구된다”**를 보장하는 것. 2026-08-26 감사에서 사용자가 믿고 있던 구글 드라이브 동기화가 실제로는 꺼져 있었던 것을 발견하고 이 문서를 작성했다 — “동기화하고 있다고 믿는 것”과 “실제로 동기화되는 것”은 다르므로, 이 문서의 절차는 최소 1회 실제로 검증(§6)해야 신뢰할 수 있다.

1. 전체 구조 — 무엇이 어디에 있는가

graph TD
    A["David 랩탑 (유일한 '서버')"] -->|"매시간 실행"| B["TAB-Wiki-Rebuild<br>작업 스케줄러"]
    A -->|"10분마다 실행"| C["TAB-Wiki-QuerySync<br>작업 스케줄러"]
    B --> D["rebuild-site.ps1"]
    D -->|"git push (신규)"| E1["GitHub: 04_GuWiki"]
    D -->|"git push (신규)"| E2["GitHub: 05_SalesReport"]
    D -->|"git push (신규)"| E3["GitHub: quartz-site"]
    D -->|"wrangler pages deploy"| F["Cloudflare Pages<br>turboairbrain.uk"]
    D -->|"Google Sheets API 읽기"| G["Google Sheets<br>Sales Data"]
    G -.->|"인증키: turboair-brain-*.json<br>(랩탑 로컬 전용, git 없음)"| D
    D -.->|"Resend API 발송<br>키: resend-local-key.txt<br>(랩탑 로컬 전용, git 없음)"| H["이메일 알림"]

핵심 판단: GitHub(E1~E3)와 Cloudflare Pages(F)는 클라우드에 있으므로 랩탑이 죽어도 그 자체로는 안전하다. 진짜 위험은 (1) 랩탑에만 있고 git에는 절대 없는 2개 시크릿 파일, (2) 랩탑에만 있는 2개 작업 스케줄러 설정, (3) 아직 push 안 된 로컬 변경사항 — 이 세 가지뿐이다.

2. 랩탑에만 존재하는 것 (git에 없음, 별도 백업 필수)

2.1 시크릿 파일 2개

파일위치용도재발급 방법
turboair-brain-75890882fe10.jsonC:\Users\David\quartz-site\Google 서비스 계정 키 — TAB 대시보드 매시간 Sales Data 시트 읽기 (scripts/pull-sales-data.mjs)Google Cloud Console → IAM 및 관리자 → 서비스 계정 → 해당 계정 → 키 → 새 키 만들기(JSON). 기존 키를 잃어버려도 재발급 가능 — Sheet 공유 대상에 새 키의 이메일이 이미 등록돼 있다면 바로 작동.
resend-local-key.txtC:\Users\David\quartz-site\Resend API 키 — 답변 업데이트 알림메일 발송(notify-answer-updates.ps1). Cloudflare Pages의 RESEND_API_KEY 시크릿과는 별도 사본(Cloudflare 시크릿은 값을 다시 읽을 수 없어서 로컬용으로 하나 더 발급함)Resend 대시보드(resend.com) → API Keys → Create API Key. 파일 안에 키 값만 한 줄로 저장하면 됨.

이 두 파일은 .gitignore로 의도적 제외됨

quartz-site/.gitignore에 turboair-brain-*.json, resend-local-key.txt 패턴이 명시돼 있다 — 클라우드 자격증명을 git 히스토리에 남기지 않기 위한 정상적인 보안 관행이다. 하지만 그 말은 곧 이 두 파일이 사라지면 GitHub 어디에도 사본이 없다는 뜻. §3에서 별도 백업 절차를 다룬다.

2.2 작업 스케줄러 2개 (2026-09-18 기준 실제 설정값)

TAB-Wiki-Rebuild (매시간, 사이트 재빌드+배포):

  • 실행: wscript.exe "C:\Users\David\quartz-site\rebuild-site-silent.vbs"
  • 트리거: 09:00~18:00, 매 정시마다 독립된 Daily 트리거 10개 (New-ScheduledTaskTrigger -Daily -At <매 정시> ×10 — 09:00, 10:00, …, 18:00 각각 별개 트리거).

    2026-09-18 수정 — 왜 "1개 트리거 + 1시간 반복"이 아니라 "10개 독립 트리거"인가

    원래는 매일 09:00:00 시작 + PT1H 간격으로 PT9H1M 반복(트리거 1개) 구조였다. 이 구조의 함정: Windows 작업 스케줄러는 반복 트리거가 한 번이라도 지연 실행되면(예: 랩탑이 잠자기 상태라 정시에 못 깨어남 → StartWhenAvailable로 뒤늦게 캐치업 실행), 그날 나머지 반복 시각 전체가 그 지연분만큼 그대로 밀린다(절대 시각이 아니라 마지막 실제 실행시각 기준으로 다음 반복을 계산하는 것으로 보임). 실제로 2026-09-18 새벽 랩탑이 절전 상태로 09:00을 넘겼고(원인: 배터리(DC) 전원일 때 절전 해제 타이머가 꺼져 있어 WakeToRun이 못 깨움 — 아래 참고), 09:26경 수동으로 깨어난 뒤 09:28에 지연 캐치업 실행됐는데, 이후 10시·11시 실행도 정시(10:00/11:00)가 아니라 계속 09:28 기준 +1시간(10:32, 11:32…)으로 밀려 있었다. 트리거를 정시마다 독립된 10개로 바꾸면 한 시각이 밀려도(또는 놓쳐도) 다른 시각은 각자의 절대 정시에 그대로 실행되어 드리프트가 전파되지 않는다.

  • 실행 계정: David (Limited 권한, Interactive 로그온)
  • WakeToRun: True — 랩탑이 잠자기 상태여도 깨워서 실행 (2026-08-25 세션에서 이 설정 자체가 빠져있어 갱신이 멈췄던 버그를 수정하며 켠 값 — 재현 시 반드시 켤 것)
  • 전원 설정(2026-09-18 추가): powercfg /setdcvalueindex SCHEME_CURRENT SUB_SLEEP RTCWAKE 1 로 배터리(DC) 전원에서도 “절전 모드 해제 타이머 허용”을 켜 둘 것 — 기본값은 AC만 켜져 있고 DC(배터리)는 꺼져 있어, 랩탑이 충전기 없이 밤새 켜져 있으면 WakeToRun이 있어도 정시에 못 깨어난다. 재현 시 이 명령을 반드시 실행.

TAB-Wiki-QuerySync (10분마다, Q&A/피드백 KV 동기화):

  • 실행: wscript.exe "C:\Users\David\quartz-site\sync-queries-silent.vbs"
  • 트리거: 2026-08-04 09:52:51 시작, 10분(PT10M) 간격으로 3650일간 반복 → 사실상 상시 10분 주기
  • 실행 계정: David (Limited 권한, Interactive 로그온)
  • WakeToRun: False — 의도적으로 끔 (밤새 랩탑을 계속 깨워두면 안 되므로, 매시간 작업 하나로 충분하다고 판단)

TAB-Weekly-Digest (매주 월요일 09:00, 주간 동향 보고서 생성+배포):

  • 실행: wscript.exe "C:\Users\David\quartz-site\run-weekly-digest-silent.vbs" → run-weekly-digest.ps1이 claude -p "/weekly-digest"를 헤드리스로 호출.
  • 트리거: 매주 월요일 09:00.
  • 실행 계정: David (Limited 권한, Interactive 로그온), WakeToRun: True.

2026-09-21 인시던트 — Claude Code "trust dialog" 미승인으로 헤드리스 실행이 조용히 무력화됨

09-21 09:00 정기 실행이 실패(발행 안 됨). 원인: ~/.claude.json의 projects["...04_GuWiki"].hasTrustDialogAccepted가 false였음 — Claude Code는 프로젝트 폴더가 “신뢰됨” 상태가 아니면 그 프로젝트의 .claude/settings.json에 정의된 permissions.allow(2026-09-14에 추가한 weekly-metrics.mjs 실행 허용 + WebSearch/WebFetch) 전체를 무시한다. 대화형 세션에서는 사람이 신뢰 대화상자를 한 번 클릭하면 되지만, claude -p(헤드리스)는 이 대화상자를 절대 띄우지 않고 그냥 그 상태로 계속 진행하기 때문에, 이 값이 애초에 true로 세팅돼 있지 않으면 스케줄러로 도는 모든 헤드리스 자동화가 원인 모를 권한 오류로 조용히 실패한다. 재현 시 필수 1회 설정: 새 컴퓨터에서 이 자동화를 다시 살릴 때는, 위 신뢰값을 미리 true로 심어둘 것 — 공식 문서에 나온 지원되는 방법이다(~/.claude.json을 직접 열어 해당 프로젝트 경로 키의 hasTrustDialogAccepted를 true로 설정). Windows 경로 대소문자(c: vs C:)가 다르면 서로 다른 프로젝트로 취급되므로, 이 자동화가 실제로 쓰는 정확한 경로 표기(run-weekly-digest.ps1의 Set-Location $vaultPath 기준 — 대문자 C:)로 맞춰 설정해야 한다. 추가 방어책: run-weekly-digest.ps1의 claude 호출에 --permission-mode dontAsk 플래그를 추가해(2026-09-21), 신뢰 문제가 재발해도 무한 대기 없이 즉시 실패가 로그에 명확히 남도록 했다 — 다만 이건 증상 완화일 뿐, 실제 수정은 위 신뢰값 설정이다.

세 .vbs 파일 모두 powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -File "<대상 .ps1>"를 창 없이(hidden) 실행하는 얇은 래퍼이며, quartz-site 저장소에 커밋되어 있으므로 git에서 복구된다 — 스케줄러 “등록” 자체만 새로 하면 된다(§4 참고).

2.3 커밋되지 않은 로컬 변경사항

rebuild-site.ps1에 2026-08-26부터 자동 커밋+푸시 스텝이 추가되어(§5), 매시간 리빌드마다 3개 저장소의 변경사항이 자동으로 GitHub에 올라간다. 다만 자동화가 붙기 전에 한 작업이거나, 자동화가 어떤 이유로 실패한 구간의 작업물은 여전히 수동 확인이 필요할 수 있다 — 랩탑이 정상일 때 가끔 git status로 3개 저장소 모두 깨끗한지 확인하는 습관을 권장.

3. 시크릿 파일 이중 백업 (사람이 직접 해야 하는 부분)

이 2개 파일은 자동화로 대신 처리하지 않는다 — 클라우드 자격증명을 임의로 어딘가에 복사해두는 것은 David님이 신뢰하는 저장소(비밀번호 관리자 등)에 직접 넣는 게 안전하다.

  1. C:\Users\David\quartz-site\turboair-brain-75890882fe10.json 파일을 엽니다(메모장으로도 열림 — 평문 JSON).
  2. C:\Users\David\quartz-site\resend-local-key.txt 파일을 엽니다(키 값 한 줄).
  3. 두 내용을 1Password/Bitwarden 같은 비밀번호 관리자의 “보안 노트(Secure Note)“로 각각 저장 — 제목에 “TAB 프로젝트”를 포함시켜 나중에 쉽게 찾을 수 있게.
  4. (선택) 관리자를 안 쓴다면, 최소한 두 파일을 구글 드라이브의 별도 비공개 폴더(예: “TAB 백업 - 절대 공유 금지”)에 수동 업로드 — §4의 폴더 백업(미러링)과는 별개로, 시크릿은 항상 명시적으로 챙기는 편이 안전하다.

이 단계는 자동화 스크립트가 대신 할 수 없어 사람이 한 번 직접 수행해야 완료됨.

4. 구글 드라이브 폴더 백업(미러링) 켜기

2026-08-26 조사에서 Drive File Stream 앱은 실행 중이었지만 “내 컴퓨터 폴더 백업” 대상이 비어 있어 세 프로젝트 폴더가 전혀 동기화되지 않고 있었다. 설정 방법:

  1. 작업 표시줄 트레이에서 Google Drive 아이콘 클릭 → 설정(톱니바퀴) → 환경설정.
  2. 왼쪽 메뉴에서 “내 컴퓨터 폴더” (또는 “Folders from your computer” / “폴더 백업”) 선택.
  3. “폴더 추가”로 아래 3개 폴더를 추가:
    • C:\Users\David\Desktop\Vaults\04_GuWiki
    • C:\Users\David\Desktop\Vaults\05_SalesReport
    • C:\Users\David\quartz-site
  4. 백업 옵션은 “고화질로 업로드”가 아니라(사진 전용 옵션) 파일 그대로 백업하는 기본 옵션 유지.
  5. 완료 후 G:\내 드라이브 밑에 “컴퓨터 백업” 관련 항목이 생기는지, 실제로 파일 개수가 늘어나는지(예: 04_GuWiki 389개 파일) 확인.

이건 git 히스토리는 없는 “현재 상태 스냅샷” 백업이지만, .gitignore된 시크릿 파일까지 통째로 포함된다는 장점이 있다 — §3의 수동 백업과 상호 보완.

5. Git 자동 push (이미 구현됨, 2026-08-26)

rebuild-site.ps1에 4번째 스텝으로 자동 커밋+푸시가 추가되어, 매시간 리빌드마다 3개 저장소의 변경사항이 있으면 자동으로 git add -A → git commit → git push된다.

quartz-site의 content/ 폴더는 반드시 제외

quartz-site/content/는 볼트 전체를 robocopy로 미러링한 폴더로, .gitignore에 일부러 안 올라가 있다(올리면 Quartz 빌드 자체가 깨지는 별도 이슈, 2026-08-18 인시던트). 그래서 quartz-site 저장소에서는 git add -A -- . ':!content'처럼 content/를 pathspec으로 명시적으로 제외해야 한다 — 이 스텝을 처음 구현하고 실제로 실행해본 결과 content/가 267개 파일로 통째로 스테이징되는 걸 확인하고 즉시 수정했다. 이 파일을 향후 수정할 일이 있다면 이 예외 처리를 반드시 유지할 것.

6. 복구 절차 — 새 컴퓨터에서 처음부터

랩탑이 완전히 죽었다고 가정하고, 새 컴퓨터에서 아래 순서대로 진행한다.

  1. Node.js, Git, PowerShell 설치 (Windows라면 PowerShell은 기본 포함).
  2. 3개 저장소 clone:
    git clone https://github.com/DavidByeon0228/04_GuWiki.git "C:\Users\David\Desktop\Vaults\04_GuWiki"
    git clone https://github.com/DavidByeon0228/05_SalesReport.git "C:\Users\David\Desktop\Vaults\05_SalesReport"
    git clone https://github.com/DavidByeon0228/quartz-site.git "C:\Users\David\quartz-site"
    
  3. quartz-site 의존성 설치: cd C:\Users\David\quartz-site && npm install
  4. 시크릿 파일 복원: §3에서 백업해 둔 비밀번호 관리자(또는 Drive 백업 폴더)에서 아래 2개 파일을 꺼내 C:\Users\David\quartz-site\에 그대로 저장:
    • turboair-brain-75890882fe10.json
    • resend-local-key.txt
  5. Cloudflare 인증: npx wrangler login (브라우저 로그인 창이 뜬다 — Cloudflare 계정으로 로그인하면 토큰이 로컬에 새로 생성됨, 기존 토큰을 옮길 필요 없음).
  6. 작업 스케줄러 3개 재등록 — §2.2의 값 그대로 Windows 작업 스케줄러 GUI 또는 PowerShell Register-ScheduledTask로 재생성(TAB-Wiki-Rebuild, TAB-Wiki-QuerySync, TAB-Weekly-Digest). TAB-Wiki-Rebuild·TAB-Weekly-Digest는 WakeToRun을 반드시 켤 것.
  7. Claude Code 프로젝트 신뢰(trust) 값 설정 — 이 단계를 빼먹으면 §2.2의 TAB-Weekly-Digest 경고에 적힌 사고가 그대로 재현된다. ~/.claude.json에서 projects["C:/Users/David/Desktop/Vaults/04_GuWiki"].hasTrustDialogAccepted를 true로 설정(공식 문서에 나온 지원되는 방법 — 대화형으로 그 폴더에서 claude를 한 번 실행해 신뢰 대화상자를 수동으로 수락해도 동일한 효과). 이 값이 false인 채로 있으면 TAB-Weekly-Digest(및 향후 추가될 모든 헤드리스 claude -p 자동화)가 .claude/settings.json의 permissions.allow를 전부 무시해 조용히 실패한다.
  8. 수동으로 한 번 실행해서 검증: cd C:\Users\David\quartz-site; .\rebuild-site.ps1 실행 → rebuild.log 마지막 줄이 === Rebuild + deploy completed successfully ===인지, Deploy exit code: 0인지 확인.
  9. 사이트 라이브 확인: turboairbrain.uk 접속해서 TAB 대시보드/답변보기가 정상 로딩되는지 브라우저로 직접 확인.

7. 이번에 하지 않기로 한 것

랩탑이 자동화의 단일 장애점(SPOF)이라는 근본 구조 자체는 이번 작업 범위에서 제외했다 — rebuild-site.ps1/notify-answer-updates.ps1을 GitHub Actions 같은 클라우드 스케줄러로 이전하면 랩탑이 꺼져 있어도 사이트가 계속 최신 상태를 유지할 수 있지만, 스크립트 포팅과 시크릿의 GitHub Actions Secrets 이관이 필요한 별도 규모의 프로젝트라 David님이 의도적으로 이번 범위에서 제외(2026-08-26). 이 문서의 절차만으로도 “고장 → 새 컴퓨터에서 복구”는 완전히 가능하다 — 다만 복구하는 동안(수 시간~하루)은 자동 갱신이 멈춘다는 차이가 있을 뿐.