프로젝트/엑셀구글시트 자동화 웹사이트

Excel & Google Sheets 자동화 웹앱 개발기

ksc-dev 2026. 5. 23. 19:24

🚀 프로젝트 개요

엑셀 파일 업로드와 Google Sheets 연동을 하나의 웹앱에서 처리하는 자동화 도구를 만들고 있다.

목표는 단순하다:

“엑셀을 업로드하면 자동으로 정리되고, 필요하면 구글 시트까지 연결되는 시스템”


🧱 기술 스택

Frontend

  • Vue 3 (Composition API)
  • Vite
  • TailwindCSS
  • SheetJS (xlsx 처리)

Backend (예정)

  • Express
  • Google Sheets API
  • TypeScript

1️⃣ 엑셀 파일 업로드 및 파싱 (FileReader + SheetJS)

브라우저에서 엑셀 파일을 직접 읽고 JSON으로 변환하는 구조를 사용했다.

핵심 흐름은 다음과 같다:

File → ArrayBuffer → SheetJS → JSON Array
 

구현 구조

 
const handleFile = (e) => {
  const file = e.target.files[0]
  const reader = new FileReader()

  reader.readAsArrayBuffer(file)

  reader.onload = (e) => {
    const workbook = XLSX.read(e.target.result)
    const sheetName = workbook.SheetNames[0]

    rows.value = XLSX.utils.sheet_to_json(
      workbook.Sheets[sheetName]
    )
  }
}
 

💡 핵심 포인트

  • FileReader는 비동기이기 때문에 onload 안에서 처리해야 한다
  • SheetJS는 첫 번째 시트를 기본으로 처리하면 대부분 충분하다
  • sheet_to_json()이 자동으로 객체 배열을 만들어준다

2️⃣ 데이터 처리 파이프라인 설계 (processData)

엑셀 데이터는 단순 출력이 아니라 “가공된 결과”가 필요하다.

그래서 아래 3단계 파이프라인을 설계했다:

raw data → dedup → filter → sort → processed data
 

🔹 1. 중복 제거

JSON 기반 비교 방식:

 
result = result.filter((row, i, arr) => {
  return (
    arr.findIndex(
      r => JSON.stringify(r) === JSON.stringify(row)
    ) === i
  )
})
 

👉 같은 객체 구조를 가진 행 제거


🔹 2. 필터 처리

 
if (filterCol.value && filterVal.value) {
  result = result.filter(row =>
    String(row[filterCol.value]).includes(filterVal.value)
  )
}
 

👉 특정 컬럼 기준 검색 필터


🔹 3. 정렬

 
if (sortCol.value) {
  result = result.sort((a, b) => {
    return String(a[sortCol.value])
      .localeCompare(String(b[sortCol.value]))
  })
}
 

👉 문자열 기준 정렬 (한글/영문 모두 대응)


💡 설계 핵심

  • raw data와 processed data를 분리
  • UI는 processed만 바라보도록 설계
  • 데이터 흐름을 단방향으로 유지

3️⃣ Excel 다운로드 기능 (SheetJS writeFile)

가공된 데이터를 다시 엑셀 파일로 저장하는 기능이다.

SheetJS는 읽기/쓰기 구조가 완전히 대칭이다:

sheet_to_json ↔ json_to_sheet
 

🔹 다운로드 로직

 
const downloadFile = () => {
  const ws = XLSX.utils.json_to_sheet(processed.value)
  const wb = XLSX.utils.book_new()

  XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
  XLSX.writeFile(wb, 'result.xlsx', {
    compression: true
  })
}
 

💡 핵심 포인트

  • JSON 배열 → 엑셀 시트 자동 변환
  • 첫 번째 객체의 key가 자동으로 헤더가 된다
  • writeFile은 내부적으로 Blob을 생성해 다운로드를 트리거한다

4️⃣ 백엔드 설계 방향 (Express + Google Sheets API)

프론트에서 엑셀 처리를 끝낸 후, 다음 단계는 Google Sheets 연동이다.


📦 서버 역할

Express 서버는 단순하지만 중요한 역할을 한다:

1. API Key 보호

  • Google Service Account 키를 서버에만 저장

2. 데이터 중간 처리

  • 프론트 ↔ Google Sheets 사이 Proxy 역할

📌 API 구조 설계

GET  /api/sheets/:id     → 시트 읽기
POST /api/sheets/write   → 시트 쓰기
 

🔐 Google Sheets API (서비스 계정 방식)

 
const auth = new google.auth.JWT({
  email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
  key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n'),
  scopes: ['https://www.googleapis.com/auth/spreadsheets']
})
 

📌 데이터 변환 구조

 
const [headers, ...rows] = response.data.values

const formatted = rows.map(row =>
  Object.fromEntries(
    headers.map((h, i) => [h, row[i] ?? ''])
  )
)
 

💡 핵심 포인트

  • Google Sheets는 2D 배열 구조
  • 첫 행 = header
  • 나머지 = 데이터
  • Object.fromEntries로 JSON 변환

📌 전체 구조 요약

[Vue 3]
   ↓
Excel Upload → SheetJS → JSON
   ↓
Process Pipeline (dedup → filter → sort)
   ↓
Processed Data
   ↓
Download (xlsx)

AND

[Express]
   ↓
Google Sheets API
   ↓
Read / Write Spreadsheet
 

🧠 오늘 배운 핵심

  • FileReader는 반드시 onload에서 처리해야 한다
  • SheetJS는 read/write 구조가 대칭이다
  • 데이터 처리는 반드시 raw / processed 분리해야 한다
  • JSON 기반 dedup은 교육용, 실무는 key 기반
  • Express는 단순 API proxy 역할로 시작하는 게 좋다

 

🚀 서비스 링크

 

client

 

excel-sheets-web.vercel.app