운영유지 리포트 자동화 구축 가이드
작성일: 2026.01.19
대상: PM, 개발팀, 관리자
1. 전체 프로세스 개요 (Process Overview)
이 시스템은 **고객의 요청(슬라이드)**부터 **최종 리포트(엑셀)**까지의 과정을 자동화합니다.
- 요청 (Start): 고객이 구글 슬라이드에서 [운영유지 도구] > [현재 슬라이드를 이슈로 등록] 메뉴 클릭.
- 생성: 깃허브에 이슈가 자동으로 등록됨 (슬라이드 링크 포함).
- 작업: PM이 내용을 다듬고, 개발자가 작업을 진행.
- 완료 (End): 개발자가 이슈를 닫으면(Close), 엑셀 리포트가 자동 작성됨.
2. 준비물 (Prerequisites)
- Google 계정: 슬라이드 및 스프레드시트 관리 권한
- GitHub 계정:
- Repo Admin 권한
- Personal Access Token (Classic): 슬라이드에서 이슈를 만들기 위해 필요 (
repo권한 필수)
- 문서: 구글 슬라이드(요청용), 구글 스프레드시트(리포트용)
3. 단계별 구축 가이드 (Step-by-Step)
STEP 1. [보내는 쪽] 구글 슬라이드 설정 (고객 요청용)
고객이 메뉴 클릭 한 번으로 이슈를 등록할 수 있게 스크립트를 설정합니다.
- 구글 슬라이드 상단 메뉴
확장 프로그램>Apps Script클릭. Code.gs내용을 지우고 아래 코드를 붙여넣습니다.
/** * 설정 영역 (이 부분만 수정하세요) */const GITHUB_TOKEN = "ghp_xxxxxxxxxxxx"; // GitHub Personal Access Tokenconst REPO_OWNER = "your-org-name"; // GitHub 조직명 또는 사용자명const REPO_NAME = "your-repo-name"; // 레포지토리 이름
/** * 1. 슬라이드 메뉴 만들기 * 슬라이드를 새로고침하면 상단 메뉴에 [운영유지 도구]가 생깁니다. */function onOpen() { SlidesApp.getUi() .createMenu("🛠️ 운영유지 도구") .addItem("👉 현재 슬라이드를 이슈로 등록", "createIssueFromSlide") .addToUi();}
/** * 2. 이슈 생성 메인 함수 */function createIssueFromSlide() { var ui = SlidesApp.getUi();
// 현재 보고 있는 슬라이드 정보 가져오기 var presentation = SlidesApp.getActivePresentation(); var slide = presentation.getSelection().getCurrentPage();
if (!slide) { ui.alert("슬라이드를 선택한 상태에서 실행해주세요."); return; }
var slideId = slide.getObjectId(); var presentationId = presentation.getId(); var directLink = "https://docs.google.com/presentation/d/" + presentationId + "/edit#slide=id." + slideId;
// 슬라이드 내의 텍스트들을 긁어모으기 (요약용) var slideText = ""; var shapes = slide.getShapes(); shapes.forEach(function (shape) { if (shape.getText()) { slideText += "- " + shape.getText().asString().trim() + "\n"; } });
// 깃허브 이슈 제목과 내용 구성 var today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD var issueTitle = "[운영유지] 슬라이드 요청사항 (" + today + ")";
var issueBody = "### 1. 요청 슬라이드 링크\n" + "👉 [바로가기](" + directLink + ")\n\n" + "### 2. 슬라이드 텍스트 추출 (참고용)\n" + (slideText ? slideText : "(텍스트 없음)") + "\n\n" + "---\n*Generated by Google Slides Automation*";
// 깃허브 API 전송 try { var response = sendToGitHub(issueTitle, issueBody); var responseData = JSON.parse(response.getContentText());
// 성공 시 알림 및 생성된 이슈 링크 보여주기 ui.alert( "✅ 이슈 생성 완료!\n\n이슈 번호: #" + responseData.number + "\n(깃허브에서 확인하세요)", ); } catch (e) { ui.alert("❌ 오류 발생: " + e.toString()); }}
/** * 3. 깃허브 API 호출 헬퍼 함수 */function sendToGitHub(title, body) { var url = "https://api.github.com/repos/" + REPO_OWNER + "/" + REPO_NAME + "/issues";
var payload = { title: title, body: body, };
var options = { method: "post", contentType: "application/json", headers: { Authorization: "token " + GITHUB_TOKEN, }, payload: JSON.stringify(payload), };
return UrlFetchApp.fetch(url, options);}-
설정 영역 수정 (상단 3개 변수):
GITHUB_TOKEN: GitHub Personal Access Token (repo권한 필수)REPO_OWNER: GitHub 조직명 또는 사용자명REPO_NAME: 레포지토리 이름
-
저장 후 슬라이드를 새로고침합니다.
사용 방법
- 슬라이드 상단 메뉴에 [🛠️ 운영유지 도구] 메뉴가 생성됩니다.
- 요청할 슬라이드를 선택한 상태에서 [👉 현재 슬라이드를 이슈로 등록] 클릭.
- 슬라이드 링크 + 텍스트가 포함된 GitHub 이슈가 자동 생성됩니다.
STEP 2. [받는 쪽] 구글 스프레드시트 설정 (리포트용)
- 새 스프레드시트를 만들고 시트 이름을 **
전체 진행내역**으로 변경합니다. - **1행(헤더)**을 아래 순서대로 작성합니다. (A열 ~ N열)
Apps Script 설정
확장 프로그램 > Apps Script 클릭 후 아래 코드 붙여넣기.
function doPost(e) { var sheetName = "전체 진행내역";
try { var data = JSON.parse(e.postData.contents); var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName(sheetName);
if (!sheet) { sheet = ss.getSheets()[0]; }
// 날짜 예쁘게 바꾸기 (2026-01-19 -> 1월, 19일) // 날짜 객체를 반환하도록 수정해서 분기 계산에 씀 function parseDateObj(dateStr) { if (!dateStr) return null; try { return new Date(dateStr); } catch (err) { return null; } }
var createdDate = parseDateObj(data.created_at); var closedDate = parseDateObj(data.closed_at);
// 엑셀에 적을 텍스트 ("1월", "19일") var createdMonth = createdDate ? createdDate.getMonth() + 1 + "월" : "-"; var createdDay = createdDate ? createdDate.getDate() + "일" : "-";
var closedMonth = closedDate ? closedDate.getMonth() + 1 + "월" : "-"; var closedDay = closedDate ? closedDate.getDate() + "일" : "-";
// 1. 분기 계산 (작업월 기준) var quarter = "-"; if (closedDate) { var m = closedDate.getMonth() + 1; quarter = Math.ceil(m / 3) + "분기"; // 1~3월=1분기, 4~6월=2분기... }
// 2. 번호 자동 매기기 // 현재 시트의 행 개수를 세어서 번호를 만듭니다. (헤더가 1줄 있다고 가정) // 만약 데이터가 하나도 없으면 1번, 있으면 그 다음 번호 var lastRow = sheet.getLastRow(); var newNo = lastRow - 1; if (newNo < 1) newNo = 1; // 혹시 계산이 꼬이면 1번부터
// 링크 + 댓글 내용 var resolutionText = data.html_url + "\n\n[조치내역]\n" + data.resolution;
// 3. 헤더에 맞춘 정위치 배열 var rowData = [ newNo, // A: 번호 (1, 2, 3... 자동부여) createdMonth, // B: 요청월 createdDay, // C: 요청일 "", // D: 요청자 data.title, // E: 요청사항 resolutionText, // F: 진행상황 quarter, // G: 분기 구분 closedMonth, // H: 작업월 closedDay, // I: 작업일 data.labels, // J: 이슈 구분 (라벨) "", // K: 이슈 항목 (빈칸) "완료", // L: 진행 단계 "", // M: 소요시간 data.assignee, // N: 담당자 ];
sheet.appendRow(rowData); return ContentService.createTextOutput("Success"); } catch (error) { return ContentService.createTextOutput("Error: " + error.toString()); }}배포 (Deployment)
- 배포 > 새 배포 > 웹 앱
- 액세스 권한: 모든 사용자 (Anyone) (필수)
- URL 복사.
STEP 3. [연결 고리] 깃허브 Actions 설정
Secret 등록
GitHub Repo > Settings > Secrets > Actions > GOOGLE_SHEET_URL에 위에서 복사한 URL 저장.
Workflow 파일 생성
.github/workflows/maintenance-report.yml 생성 후 아래 코드 저장.
name: Update Maintenance Reporton: issues: types: [closed]jobs: report_to_sheet: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Send Data env: GH_TOKEN: ${{ github.token }} ISSUE: ${{ github.event.issue.number }} URL: ${{ secrets.GOOGLE_SHEET_URL }} run: | DATA=$(gh issue view "$ISSUE" --json title,createdAt,closedAt,url,assignees,labels,comments) TITLE=$(echo "$DATA" | jq -r '.title') CREATED=$(echo "$DATA" | jq -r '.createdAt') CLOSED=$(echo "$DATA" | jq -r '.closedAt') LINK=$(echo "$DATA" | jq -r '.url') ASSIGN=$(echo "$DATA" | jq -r '.assignees[0].login // "미지정"') COMMENT=$(echo "$DATA" | jq -r '.comments[-1].body // "내용 없음"') LABELS=$(echo "$DATA" | jq -r '.labels[].name' | paste -sd "," -)
jq -n --arg t "$TITLE" --arg c "$CREATED" --arg cl "$CLOSED" --arg u "$LINK" --arg a "$ASSIGN" --arg r "$COMMENT" --arg l "$LABELS" --arg n "$ISSUE" \ '{number: $n, title: $t, created_at: $c, closed_at: $cl, html_url: $u, assignee: $a, resolution: $r, labels: $l}' > payload.json
curl -L -X POST "$URL" -H 'Content-Type: application/json' -d @payload.json4. 업무 프로세스 (Workflow)
| 순서 | 담당자 | 시스템 | 행동 | 결과 |
|---|---|---|---|---|
| 1 | 고객 | 슬라이드 | [운영유지 도구] > [현재 슬라이드를 이슈로 등록] 클릭 | 깃허브에 이슈 생성됨 (제목: [운영유지] 슬라이드 요청사항…) |
| 2 | PM | 깃허브 | 이슈 확인 및 제목 수정 | 예: [운영유지]… → 메인 배너 오타 수정 |
| 3 | 개발자 | 깃허브 | 작업 수행 후 우측 Labels 지정 | 예: 웹사이트 정보 수정 라벨 선택 |
| 4 | 개발자 | 깃허브 | 댓글(조치내역) 작성 후 [Close] | 이슈 종료 |
| 5 | 봇 | 구글시트 | (자동) 이슈 정보 전송 | 엑셀 리포트 업데이트 완료 |
5. 최종 데이터 매핑 결과
| 엑셀 열 | 항목 | 데이터 출처 | 비고 |
|---|---|---|---|
| A | 번호 | (자동 생성) | 1, 2, 3… 순차 부여 |
| E | 요청사항 | 이슈 제목 | PM이 수정한 최종 제목 |
| F | 진행상황 | 링크 + 댓글 | 해당 슬라이드 링크 및 조치 내용 |
| G | 분기 | (자동 생성) | 작업 완료일 기준 (예: 1분기) |
| J | 이슈 구분 | 라벨 (Labels) | 개발자가 선택한 분류 (예: 기능개선) |