Skip to content

운영유지 리포트 자동화 구축 가이드

작성일: 2026.01.19
대상: PM, 개발팀, 관리자


1. 전체 프로세스 개요 (Process Overview)

이 시스템은 **고객의 요청(슬라이드)**부터 **최종 리포트(엑셀)**까지의 과정을 자동화합니다.

  1. 요청 (Start): 고객이 구글 슬라이드에서 [운영유지 도구] > [현재 슬라이드를 이슈로 등록] 메뉴 클릭.
  2. 생성: 깃허브에 이슈가 자동으로 등록됨 (슬라이드 링크 포함).
  3. 작업: PM이 내용을 다듬고, 개발자가 작업을 진행.
  4. 완료 (End): 개발자가 이슈를 닫으면(Close), 엑셀 리포트가 자동 작성됨.

2. 준비물 (Prerequisites)

  1. Google 계정: 슬라이드 및 스프레드시트 관리 권한
  2. GitHub 계정:
    • Repo Admin 권한
    • Personal Access Token (Classic): 슬라이드에서 이슈를 만들기 위해 필요 (repo 권한 필수)
  3. 문서: 구글 슬라이드(요청용), 구글 스프레드시트(리포트용)

3. 단계별 구축 가이드 (Step-by-Step)

STEP 1. [보내는 쪽] 구글 슬라이드 설정 (고객 요청용)

고객이 메뉴 클릭 한 번으로 이슈를 등록할 수 있게 스크립트를 설정합니다.

  1. 구글 슬라이드 상단 메뉴 확장 프로그램 > Apps Script 클릭.
  2. Code.gs 내용을 지우고 아래 코드를 붙여넣습니다.
/**
* 설정 영역 (이 부분만 수정하세요)
*/
const GITHUB_TOKEN = "ghp_xxxxxxxxxxxx"; // GitHub Personal Access Token
const 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);
}
  1. 설정 영역 수정 (상단 3개 변수):

    • GITHUB_TOKEN: GitHub Personal Access Token (repo 권한 필수)
    • REPO_OWNER: GitHub 조직명 또는 사용자명
    • REPO_NAME: 레포지토리 이름
  2. 저장 후 슬라이드를 새로고침합니다.

사용 방법

  1. 슬라이드 상단 메뉴에 [🛠️ 운영유지 도구] 메뉴가 생성됩니다.
  2. 요청할 슬라이드를 선택한 상태에서 [👉 현재 슬라이드를 이슈로 등록] 클릭.
  3. 슬라이드 링크 + 텍스트가 포함된 GitHub 이슈가 자동 생성됩니다.

STEP 2. [받는 쪽] 구글 스프레드시트 설정 (리포트용)

  1. 새 스프레드시트를 만들고 시트 이름을 **전체 진행내역**으로 변경합니다.
  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)

  1. 배포 > 새 배포 > 웹 앱
  2. 액세스 권한: 모든 사용자 (Anyone) (필수)
  3. URL 복사.

STEP 3. [연결 고리] 깃허브 Actions 설정

Secret 등록

GitHub Repo > Settings > Secrets > Actions > GOOGLE_SHEET_URL에 위에서 복사한 URL 저장.

Workflow 파일 생성

.github/workflows/maintenance-report.yml 생성 후 아래 코드 저장.

name: Update Maintenance Report
on:
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.json

4. 업무 프로세스 (Workflow)

순서담당자시스템행동결과
1고객슬라이드[운영유지 도구] > [현재 슬라이드를 이슈로 등록] 클릭깃허브에 이슈 생성됨 (제목: [운영유지] 슬라이드 요청사항…)
2PM깃허브이슈 확인 및 제목 수정예: [운영유지]… → 메인 배너 오타 수정
3개발자깃허브작업 수행 후 우측 Labels 지정예: 웹사이트 정보 수정 라벨 선택
4개발자깃허브댓글(조치내역) 작성 후 [Close]이슈 종료
5구글시트(자동) 이슈 정보 전송엑셀 리포트 업데이트 완료

5. 최종 데이터 매핑 결과

엑셀 열항목데이터 출처비고
A번호(자동 생성)1, 2, 3… 순차 부여
E요청사항이슈 제목PM이 수정한 최종 제목
F진행상황링크 + 댓글해당 슬라이드 링크 및 조치 내용
G분기(자동 생성)작업 완료일 기준 (예: 1분기)
J이슈 구분라벨 (Labels)개발자가 선택한 분류 (예: 기능개선)