Skip to content

Commit a22f73f

Browse files
committed
feat: add Google Analytics API secret configuration and update environment setup in README
1 parent f40c36d commit a22f73f

7 files changed

Lines changed: 118 additions & 20 deletions

File tree

.env.development.example

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# ========================================
2+
# 개발 환경 설정 파일
3+
# ========================================
4+
#
5+
# 이 파일을 복사하여 .env.development 파일을 만드세요:
6+
# cp .env.development.example .env.development
7+
#
8+
# 그 다음 VITE_GA_API_SECRET 값을 실제 값으로 변경하세요.
9+
#
10+
# ========================================
11+
# Google Analytics API Secret 발급 방법
12+
# ========================================
13+
#
14+
# 1. https://analytics.google.com/ 접속
15+
# 2. Admin → Data Streams → 해당 스트림 선택
16+
# 3. Measurement Protocol API secrets → Create
17+
# 4. 생성된 Secret value를 아래 VITE_GA_API_SECRET에 입력
18+
#
19+
# ⚠️ 주의: .env.development 파일은 git에 올리지 마세요!
20+
# API Secret은 절대 공유하지 마세요!
21+
#
22+
# ========================================
23+
24+
# 환경 설정 (변경하지 마세요)
25+
VITE_ENVIRONMENT=development
26+
27+
# Google Analytics Measurement Protocol API Secret
28+
# 아래 값을 실제 API Secret으로 교체하세요
29+
VITE_GA_API_SECRET=your_api_secret_here

.env.example

Lines changed: 0 additions & 3 deletions
This file was deleted.

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ gh-pages
1515

1616
# Environment variables
1717
.env
18-
.env.local
18+
.env.*
19+
!.env.*.example
1920

2021
# Editor directories and files
2122
.vscode/*

README.md

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,20 @@
4141
git clone https://github.com/Turtle-Hwan/LinKU.git
4242
cd LinKU
4343
pnpm install
44+
```
45+
46+
### 실행 방법
47+
48+
```bash
49+
# 개발 서버 (Hot reload, console 로그 O, 버전 고정)
4450
pnpm run dev
51+
52+
# 로컬 빌드 테스트 (console 로그 O, 버전 고정)
53+
pnpm run build:local
54+
# → dist 폴더를 chrome://extensions에 로드
55+
56+
# 프로덕션 빌드 (console 로그 X, 버전 자동 증가)
57+
pnpm run build
4558
```
4659

4760
- react 환경으로 구성되어 있어 dev로 실행되는 화면이 그대로 적용됩니다.
@@ -62,6 +75,27 @@ pnpm run dev
6275
"build:gh-pages": "tsc -b && vite build --mode gh-pages",
6376
```
6477

78+
<details>
79+
<summary><b>환경 변수 설정 (Google Analytics)</b></summary>
80+
81+
Google Analytics를 사용하기 위해 환경 변수를 설정해야 합니다:
82+
83+
```bash
84+
# .env.development 파일 생성
85+
cp .env.development.example .env.development
86+
87+
# .env.development 파일을 열어서 VITE_GA_API_SECRET 값을 입력
88+
```
89+
90+
**Google Analytics API Secret 발급 방법:**
91+
92+
1. [Google Analytics](https://analytics.google.com/) 접속
93+
2. Admin → Data Streams → 해당 스트림 선택
94+
3. Measurement Protocol API secrets → Create
95+
4. 생성된 Secret value를 복사하여 `.env.development` 파일에 입력
96+
97+
</details>
98+
6599
<details>
66100
<summary><b>Chrome Extension 자동 배포 설정 (For Maintainers)</b></summary>
67101

@@ -76,20 +110,23 @@ pnpm run dev
76110
### 1단계: Google Cloud Console 설정
77111

78112
#### 1.1 프로젝트 생성
113+
79114
1. [Google Cloud Console](https://console.cloud.google.com/)에 접속
80115
2. 상단의 프로젝트 선택 드롭다운 클릭
81116
3. "새 프로젝트" 선택
82117
4. 프로젝트 이름 입력 (예: `LinKU Chrome Extension`)
83118
5. "만들기" 클릭
84119

85120
#### 1.2 Chrome Web Store API 활성화
121+
86122
1. 좌측 메뉴에서 **"API 및 서비스" > "라이브러리"** 선택
87123
2. 검색창에 `Chrome Web Store API` 입력
88124
3. "Chrome Web Store API" 클릭
89125
4. **"사용"** 버튼 클릭
90126
- ⚠️ 이 단계를 건너뛰면 나중에 API 호출 시 오류 발생!
91127

92128
#### 1.3 OAuth 동의 화면 설정
129+
93130
1. 좌측 메뉴에서 **"API 및 서비스" > "OAuth 동의 화면"** 선택
94131
2. **User Type: "External"** 선택 후 "만들기" 클릭
95132
3. **앱 정보** 입력:
@@ -106,6 +143,7 @@ pnpm run dev
106143
7. "저장 후 계속" 클릭
107144

108145
#### 1.4 OAuth 클라이언트 ID 생성
146+
109147
1. 좌측 메뉴에서 **"API 및 서비스" > "사용자 인증 정보"** 선택
110148
2. 상단의 **"+ 사용자 인증 정보 만들기"** 클릭
111149
3. **"OAuth 클라이언트 ID"** 선택
@@ -118,24 +156,30 @@ pnpm run dev
118156
### 2단계: OAuth Refresh Token 발급
119157

120158
#### 2.1 CLI 도구 실행
159+
121160
터미널에서 다음 명령어 실행:
161+
122162
```bash
123163
npx chrome-webstore-upload-keys
124164
```
125165

126166
#### 2.2 인증 정보 입력
167+
127168
CLI가 다음을 차례로 요청합니다:
169+
128170
1. **Client ID** 입력 (1.4 단계에서 복사한 값 붙여넣기)
129171
2. **Client Secret** 입력 (1.4 단계에서 복사한 값 붙여넣기)
130172
3. **Extension ID** 입력 (아래 참고)
131173

132174
**Extension ID 찾는 방법:**
175+
133176
- [Chrome Web Store Developer Dashboard](https://chrome.google.com/webstore/devconsole)에서 확장 프로그램 선택
134177
- URL의 마지막 부분이 Extension ID입니다
135178
- 예: `https://chrome.google.com/webstore/devconsole/.../fmfbhmifnohhfiblebbdjlioppfppbgh`
136179
→ Extension ID: `fmfbhmifnohhfiblebbdjlioppfppbgh`
137180

138181
#### 2.3 브라우저 OAuth 인증
182+
139183
1. CLI가 자동으로 브라우저를 열고 Google 인증 페이지로 이동
140184
2. **Google 계정 선택** (1.3.6에서 추가한 테스트 사용자 계정)
141185
3. **"앱이 확인되지 않음"** 경고가 나타날 수 있음:
@@ -148,28 +192,32 @@ CLI가 다음을 차례로 요청합니다:
148192
5. 인증 완료 후 터미널로 돌아가서 **Refresh Token** 확인 및 복사
149193

150194
**⚠️ "액세스 차단됨: 앱이 테스트 중" 오류 발생 시:**
195+
151196
- 1.3.6 단계에서 테스트 사용자를 추가하지 않았거나
152197
- 다른 Google 계정으로 로그인한 경우
153198
- → Google Cloud Console로 돌아가서 테스트 사용자 추가 후 다시 시도
154199

155200
### 3단계: GitHub Secrets 설정
156201

157202
#### 3.1 GitHub Repository Settings 접속
203+
158204
1. GitHub 저장소 페이지 접속
159205
2. 상단 메뉴에서 **"Settings"** 클릭
160206
3. 좌측 메뉴에서 **"Secrets and variables" > "Actions"** 선택
161207

162208
#### 3.2 Secrets 추가
209+
163210
**"New repository secret"** 버튼을 클릭하여 다음 4개의 secret을 차례로 추가:
164211

165-
| Name | Value |
166-
|------|-------|
167-
| `CHROME_EXTENSION_ID` | Extension ID (2.2에서 확인한 값) |
168-
| `CHROME_CLIENT_ID` | OAuth Client ID (1.4에서 복사한 값) |
212+
| Name | Value |
213+
| ---------------------- | --------------------------------------- |
214+
| `CHROME_EXTENSION_ID` | Extension ID (2.2에서 확인한 값) |
215+
| `CHROME_CLIENT_ID` | OAuth Client ID (1.4에서 복사한 값) |
169216
| `CHROME_CLIENT_SECRET` | OAuth Client Secret (1.4에서 복사한 값) |
170-
| `CHROME_REFRESH_TOKEN` | Refresh Token (2.3에서 복사한 값) |
217+
| `CHROME_REFRESH_TOKEN` | Refresh Token (2.3에서 복사한 값) |
171218

172219
**각 secret 추가 방법:**
220+
173221
1. **Name** 필드에 위 표의 이름 입력 (대소문자 정확히)
174222
2. **Secret** 필드에 해당 값 붙여넣기
175223
3. **"Add secret"** 클릭
@@ -178,11 +226,13 @@ CLI가 다음을 차례로 요청합니다:
178226
### 4단계: 배포 확인 및 심사 제출
179227

180228
#### 4.1 자동 배포 확인
229+
181230
1. `main` 브랜치에 코드 push/merge
182231
2. GitHub 저장소의 **"Actions"** 탭에서 workflow 실행 확인
183232
3. "Upload Chrome Extension Draft" workflow가 성공적으로 완료되면 ✅
184233

185234
#### 4.2 수동 심사 제출
235+
186236
1. [Chrome Web Store Developer Dashboard](https://chrome.google.com/webstore/devconsole) 접속
187237
2. 확장 프로그램 선택
188238
3. 좌측 메뉴에서 **"패키지"** 탭 확인
@@ -191,6 +241,7 @@ CLI가 다음을 차례로 요청합니다:
191241
6. 심사 완료까지 대기 (보통 24시간~3일 소요)
192242

193243
**💡 Tip:**
244+
194245
- 심사 중일 때 새 커밋이 발생해도 draft만 업데이트되므로 안전
195246
- 심사 완료 후 Developer Dashboard에서 수동으로 배포 가능
196247

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
"version": "1.4.0",
55
"type": "module",
66
"scripts": {
7-
"dev": "vite",
7+
"dev": "vite --mode development",
88
"build": "node scripts/updateVersion.js && tsc -b && vite build --mode production",
9+
"build:local": "tsc -b && vite build --mode development",
910
"watch": "node scripts/updateVersion.js && tsc -b && vite build --watch --mode production",
1011
"build:gh-pages": "tsc -b && vite build --mode gh-pages",
1112
"lint": "eslint .",

public/manifest.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifest_version": 3,
33
"name": "LinKU",
44
"description": "건국대학교 학생들을 위한 건국대, 건대 교내외 페이지 모음 링쿠, LinKU",
5-
"version": "1.4.10",
5+
"version": "1.4.13",
66
"action": {
77
"default_popup": "index.html"
88
},
@@ -19,6 +19,7 @@
1919
"storage"
2020
],
2121
"host_permissions": [
22-
"*://ecampus.konkuk.ac.kr/*"
22+
"*://ecampus.konkuk.ac.kr/*",
23+
"https://www.google-analytics.com/*"
2324
]
2425
}

src/utils/analytics.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ const API_SECRET = import.meta.env.VITE_GA_API_SECRET;
1717
// 세션 타임아웃: 30분
1818
const SESSION_TIMEOUT_MS = 30 * 60 * 1000;
1919

20-
// 디버그 모드 (개발 환경에서만 활성화)
21-
const DEBUG_MODE = import.meta.env.DEV;
20+
// 환경 구분: development (개발/로컬 빌드) / production (배포)
21+
const ENVIRONMENT = import.meta.env.VITE_ENVIRONMENT || "production";
22+
23+
// 디버그 모드 (development 환경에서만 활성화)
24+
const DEBUG_MODE = ENVIRONMENT === "development";
2225

2326
/**
2427
* Client ID 생성 및 가져오기
@@ -98,15 +101,18 @@ export async function sendGAEvent(
98101
): Promise<void> {
99102
// API Secret이 없으면 전송하지 않음
100103
if (!API_SECRET) {
101-
if (DEBUG_MODE) {
102-
console.warn(
103-
"[GA] API Secret not configured. Event not sent:",
104-
eventName
105-
);
106-
}
104+
console.warn(
105+
"[GA] API Secret not configured. Event not sent:",
106+
eventName
107+
);
107108
return;
108109
}
109110

111+
if (DEBUG_MODE) {
112+
console.log("[GA] API Secret configured:", API_SECRET?.substring(0, 4) + "...");
113+
console.log("[GA] Environment:", ENVIRONMENT);
114+
}
115+
110116
try {
111117
const clientId = await getOrCreateClientId();
112118
const sessionId = await getOrCreateSessionId();
@@ -119,6 +125,7 @@ export async function sendGAEvent(
119125
params: {
120126
session_id: sessionId,
121127
engagement_time_msec: 100, // GA4에서 권장하는 최소값
128+
...(DEBUG_MODE && { debug_mode: 1 }), // DebugView 활성화
122129
...eventParams,
123130
},
124131
},
@@ -132,21 +139,32 @@ export async function sendGAEvent(
132139
`${endpoint}?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,
133140
{
134141
method: "POST",
142+
headers: {
143+
"Content-Type": "application/json",
144+
},
135145
body: JSON.stringify(payload),
136146
}
137147
);
138148

139149
if (DEBUG_MODE) {
140150
console.log("[GA] Event sent:", eventName, eventParams);
151+
console.log("[GA] Payload:", JSON.stringify(payload, null, 2));
152+
console.log("[GA] Response status:", response.status, response.statusText);
141153

142154
// Debug endpoint의 응답 확인
143155
if (response.ok) {
144156
const debugResponse = await response.json();
145157
console.log("[GA] Debug response:", debugResponse);
158+
} else {
159+
const errorText = await response.text();
160+
console.error("[GA] Response error:", errorText);
146161
}
147162
}
148163
} catch (error) {
149164
console.error("[GA] Error sending event:", error);
165+
if (DEBUG_MODE && error instanceof Error) {
166+
console.error("[GA] Error details:", error.message, error.stack);
167+
}
150168
}
151169
}
152170

0 commit comments

Comments
 (0)