slick-address-kr 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/API-KEY-GUIDE.md CHANGED
@@ -1,428 +1,428 @@
1
- # API 키 관리 가이드
2
-
3
- 웹사이트에서 주소 검색 기능을 사용할 때 API 키를 안전하게 관리하는 방법입니다.
4
-
5
- ---
6
-
7
- ## ⚠️ 중요: API 키 보안
8
-
9
- **문제점:**
10
- - 프론트엔드 코드에 API 키를 직접 넣으면 누구나 볼 수 있습니다
11
- - 악의적인 사용자가 키를 복사하여 악용할 수 있습니다
12
- - API 호출 제한을 초과할 수 있습니다
13
-
14
- **해결책:**
15
- 프로젝트 규모와 상황에 맞는 방법을 선택하세요.
16
-
17
- ---
18
-
19
- ## 방법 1: 백엔드 프록시 서버 (⭐ 가장 안전, 추천)
20
-
21
- API 키를 서버에만 저장하고, 클라이언트는 자체 서버를 통해 주소 API를 호출합니다.
22
-
23
- ### 장점
24
- - ✅ API 키 완전 보호
25
- - ✅ 요청 제한 관리 가능
26
- - ✅ 로깅 및 모니터링 가능
27
- - ✅ 악의적 사용 차단 가능
28
-
29
- ### 단점
30
- - ❌ 백엔드 서버 필요
31
- - ❌ 서버 관리 비용
32
-
33
- ### 구현 예제
34
-
35
- #### Node.js + Express
36
-
37
- ```javascript
38
- // server.js
39
- const express = require('express');
40
- const axios = require('axios');
41
- const cors = require('cors');
42
-
43
- const app = express();
44
- app.use(cors());
45
- app.use(express.json());
46
-
47
- // 환경 변수에서 API 키 로드 (.env 파일)
48
- const JUSO_API_KEY = process.env.JUSO_API_KEY;
49
-
50
- // 프록시 엔드포인트
51
- app.get('/api/address/search', async (req, res) => {
52
- const { keyword, currentPage = 1, countPerPage = 10 } = req.query;
53
-
54
- // 입력 검증
55
- if (!keyword) {
56
- return res.status(400).json({ error: '검색어를 입력하세요' });
57
- }
58
-
59
- try {
60
- // 행정안전부 API 호출 (서버에서만 API 키 사용)
61
- const response = await axios.get('https://business.juso.go.kr/addrlink/addrLinkApi.do', {
62
- params: {
63
- confmKey: JUSO_API_KEY,
64
- currentPage,
65
- countPerPage,
66
- keyword,
67
- resultType: 'json',
68
- }
69
- });
70
-
71
- // 결과 반환
72
- res.json(response.data);
73
- } catch (error) {
74
- console.error('API 호출 오류:', error);
75
- res.status(500).json({ error: '주소 검색 중 오류가 발생했습니다' });
76
- }
77
- });
78
-
79
- app.listen(3000, () => {
80
- console.log('프록시 서버가 3000번 포트에서 실행 중입니다.');
81
- });
82
- ```
83
-
84
- #### .env 파일
85
-
86
- ```env
87
- JUSO_API_KEY=your_actual_api_key_here
88
- ```
89
-
90
- #### 클라이언트 코드 수정
91
-
92
- ```javascript
93
- // api-client.ts 수정
94
- export class AddressApiClient {
95
- private apiUrl = 'http://your-domain.com/api/address/search'; // 본인 서버 URL
96
-
97
- constructor(apiKey?: string) {
98
- // apiKey 파라미터는 사용하지 않음 (서버에서 관리)
99
- }
100
-
101
- async search(keyword: string, currentPage: number = 1, countPerPage: number = 10) {
102
- const params = new URLSearchParams({
103
- keyword: keyword.trim(),
104
- currentPage: currentPage.toString(),
105
- countPerPage: countPerPage.toString(),
106
- });
107
-
108
- const response = await fetch(`${this.apiUrl}?${params.toString()}`);
109
- const data = await response.json();
110
-
111
- return {
112
- results: data.results.juso.map(/* ... */),
113
- totalCount: parseInt(data.results.common.totalCount, 10),
114
- };
115
- }
116
- }
117
- ```
118
-
119
- ---
120
-
121
- ## 방법 2: 환경 변수 사용 (빌드 시)
122
-
123
- Webpack, Vite 등 번들러를 사용하여 빌드 시 API 키를 주입합니다.
124
-
125
- ### 장점
126
- - ✅ 소스 코드에 하드코딩하지 않음
127
- - ✅ 환경별로 다른 키 사용 가능
128
- - ✅ 비교적 간단한 구현
129
-
130
- ### 단점
131
- - ⚠️ 빌드된 파일에는 키가 포함됨
132
- - ⚠️ 개발자 도구로 확인 가능
133
- - ⚠️ 완전한 보안은 아님
134
-
135
- ### React (Create React App)
136
-
137
- ```bash
138
- # .env 파일
139
- REACT_APP_JUSO_API_KEY=your_api_key_here
140
- ```
141
-
142
- ```javascript
143
- // App.js
144
- const finder = new KoreanAddressFinder({
145
- apiKey: process.env.REACT_APP_JUSO_API_KEY,
146
- onSelect: (address) => console.log(address)
147
- });
148
- ```
149
-
150
- ### Vue
151
-
152
- ```bash
153
- # .env 파일
154
- VUE_APP_JUSO_API_KEY=your_api_key_here
155
- ```
156
-
157
- ```javascript
158
- // main.js
159
- const finder = new KoreanAddressFinder({
160
- apiKey: process.env.VUE_APP_JUSO_API_KEY,
161
- onSelect: (address) => console.log(address)
162
- });
163
- ```
164
-
165
- ### Vite
166
-
167
- ```bash
168
- # .env 파일
169
- VITE_JUSO_API_KEY=your_api_key_here
170
- ```
171
-
172
- ```javascript
173
- const finder = new KoreanAddressFinder({
174
- apiKey: import.meta.env.VITE_JUSO_API_KEY,
175
- onSelect: (address) => console.log(address)
176
- });
177
- ```
178
-
179
- ---
180
-
181
- ## 방법 3: 설정 파일 사용 (간단한 프로젝트용)
182
-
183
- 프로젝트 루트에 설정 파일을 만들고 .gitignore에 추가합니다.
184
-
185
- ### 장점
186
- - ✅ 구현이 매우 간단
187
- - ✅ 번들러 없이도 사용 가능
188
-
189
- ### 단점
190
- - ⚠️ 배포 시 설정 파일 관리 필요
191
- - ⚠️ 여전히 클라이언트에 노출됨
192
-
193
- ### 구현 예제
194
-
195
- #### config.js (Git에 올리지 않음)
196
-
197
- ```javascript
198
- // config.js
199
- export const config = {
200
- jusoApiKey: 'your_actual_api_key_here'
201
- };
202
- ```
203
-
204
- #### config.example.js (Git에 올림, 템플릿)
205
-
206
- ```javascript
207
- // config.example.js
208
- export const config = {
209
- jusoApiKey: 'YOUR_API_KEY_HERE' // 이 파일을 config.js로 복사하고 실제 키를 입력하세요
210
- };
211
- ```
212
-
213
- #### .gitignore
214
-
215
- ```
216
- config.js
217
- .env
218
- ```
219
-
220
- #### 사용 방법
221
-
222
- ```javascript
223
- // main.js
224
- import { config } from './config.js';
225
- import { KoreanAddressFinder } from 'korean-address-finder';
226
-
227
- const finder = new KoreanAddressFinder({
228
- apiKey: config.jusoApiKey,
229
- onSelect: (address) => console.log(address)
230
- });
231
-
232
- finder.init();
233
- ```
234
-
235
- ---
236
-
237
- ## 방법 4: 도메인 제한 (행정안전부 API 기능)
238
-
239
- 행정안전부 주소 API는 **승인 시 등록한 도메인에서만** 작동하도록 설정 가능합니다.
240
-
241
- ### 설정 방법
242
-
243
- 1. [주소기반산업지원서비스](https://business.juso.go.kr/) 로그인
244
- 2. 승인키 신청/관리
245
- 3. **사용 도메인 등록** (예: `https://yourdomain.com`)
246
- 4. 저장
247
-
248
- ### 장점
249
- - ✅ 다른 도메인에서 키 악용 불가능
250
- - ✅ 추가 코드 작업 불필요
251
-
252
- ### 단점
253
- - ⚠️ localhost에서 테스트 시 별도 개발용 키 필요
254
- - ⚠️ 도메인 변경 시 재등록 필요
255
-
256
- ---
257
-
258
- ## 권장 방법 (프로젝트별)
259
-
260
- ### 개인 프로젝트 / 작은 웹사이트
261
- → **방법 3 (설정 파일) + 방법 4 (도메인 제한)**
262
-
263
- ```javascript
264
- // config.js (gitignore에 추가)
265
- export const config = {
266
- jusoApiKey: 'devU01TX0FVVEgyMDI1MDExMDE1...'
267
- };
268
- ```
269
-
270
- ### 중소 규모 프로젝트
271
- → **방법 2 (환경 변수) + 방법 4 (도메인 제한)**
272
-
273
- ```bash
274
- # .env
275
- REACT_APP_JUSO_API_KEY=your_key
276
- ```
277
-
278
- ### 대규모 / 상용 서비스
279
- → **방법 1 (백엔드 프록시) ⭐ 필수**
280
-
281
- 서버에서 API 키 관리, 요청 제한, 로깅 구현
282
-
283
- ---
284
-
285
- ## 실전 예제: 간단한 웹사이트
286
-
287
- ### 파일 구조
288
-
289
- ```
290
- my-website/
291
- ├── index.html
292
- ├── config.js # API 키 포함 (gitignore)
293
- ├── config.example.js # 템플릿 (git에 포함)
294
- ├── main.js
295
- └── .gitignore
296
- ```
297
-
298
- ### config.example.js
299
-
300
- ```javascript
301
- export const config = {
302
- // 이 파일을 config.js로 복사하고 아래에 실제 API 키를 입력하세요
303
- // 발급 방법: https://business.juso.go.kr/
304
- jusoApiKey: 'YOUR_API_KEY_HERE'
305
- };
306
- ```
307
-
308
- ### config.js (실제 사용, Git에 올리지 않음)
309
-
310
- ```javascript
311
- export const config = {
312
- jusoApiKey: 'devU01TX0FVVEgyMDI1MDExMDE1MTY0MTExNTM2MjY='
313
- };
314
- ```
315
-
316
- ### .gitignore
317
-
318
- ```
319
- config.js
320
- node_modules/
321
- .env
322
- ```
323
-
324
- ### main.js
325
-
326
- ```javascript
327
- import { config } from './config.js';
328
- import { KoreanAddressFinder } from 'korean-address-finder';
329
-
330
- const finder = new KoreanAddressFinder({
331
- apiKey: config.jusoApiKey,
332
- onSelect: (address) => {
333
- console.log('선택된 주소:', address);
334
- }
335
- });
336
-
337
- finder.init();
338
- ```
339
-
340
- ### 배포 시
341
-
342
- 1. 서버에 `config.js` 파일 직접 생성
343
- 2. 실제 API 키 입력
344
- 3. 파일 권한 설정 (읽기 전용)
345
-
346
- ---
347
-
348
- ## 보안 체크리스트
349
-
350
- 배포 전 확인:
351
-
352
- - [ ] `.gitignore`에 `config.js`, `.env` 추가
353
- - [ ] GitHub/GitLab에 실제 API 키 업로드 안 됨
354
- - [ ] API 키에 도메인 제한 설정
355
- - [ ] 가능하면 백엔드 프록시 사용
356
- - [ ] 환경 변수는 빌드 서버에만 설정
357
- - [ ] API 사용량 모니터링 설정
358
-
359
- ---
360
-
361
- ## 추가 보안 팁
362
-
363
- ### 1. API 사용량 제한
364
-
365
- ```javascript
366
- // 간단한 Rate Limiting
367
- let requestCount = 0;
368
- let lastResetTime = Date.now();
369
-
370
- async function searchWithLimit(keyword) {
371
- const now = Date.now();
372
-
373
- // 1분마다 리셋
374
- if (now - lastResetTime > 60000) {
375
- requestCount = 0;
376
- lastResetTime = now;
377
- }
378
-
379
- // 분당 10회 제한
380
- if (requestCount >= 10) {
381
- alert('너무 많은 요청입니다. 잠시 후 다시 시도하세요.');
382
- return;
383
- }
384
-
385
- requestCount++;
386
- return await apiClient.search(keyword);
387
- }
388
- ```
389
-
390
- ### 2. 디바운싱으로 불필요한 요청 감소
391
-
392
- ```javascript
393
- const finder = new KoreanAddressFinder({
394
- apiKey: config.jusoApiKey,
395
- autocompleteMode: true, // 자동으로 300ms 디바운싱 적용됨
396
- });
397
- ```
398
-
399
- ---
400
-
401
- ## 문제 해결
402
-
403
- ### Q: API 키가 노출되면 어떻게 하나요?
404
-
405
- 1. 즉시 [주소기반산업지원서비스](https://business.juso.go.kr/)에서 키 재발급
406
- 2. 이전 키 비활성화
407
- 3. 새 키로 교체
408
-
409
- ### Q: localhost에서 테스트하려면?
410
-
411
- 1. 개발용 API 키 별도 발급
412
- 2. 도메인에 `localhost` 또는 `127.0.0.1` 등록
413
- 3. 또는 도메인 제한 없는 키 사용 (개발 시에만)
414
-
415
- ### Q: 여러 도메인에서 사용하려면?
416
-
417
- - 도메인마다 별도 키 발급
418
- - 또는 와일드카드 지원 여부 확인 (API 제공자에 문의)
419
-
420
- ---
421
-
422
- ## 마무리
423
-
424
- **개인/소규모 프로젝트**: 설정 파일 + 도메인 제한으로 충분합니다.
425
-
426
- **상용 서비스**: 반드시 백엔드 프록시를 구현하세요!
427
-
428
- 더 자세한 내용은 프로젝트의 `SECURITY.md` 파일을 참조하세요.
1
+ # API 키 관리 가이드
2
+
3
+ 웹사이트에서 주소 검색 기능을 사용할 때 API 키를 안전하게 관리하는 방법입니다.
4
+
5
+ ---
6
+
7
+ ## ⚠️ 중요: API 키 보안
8
+
9
+ **문제점:**
10
+ - 프론트엔드 코드에 API 키를 직접 넣으면 누구나 볼 수 있습니다
11
+ - 악의적인 사용자가 키를 복사하여 악용할 수 있습니다
12
+ - API 호출 제한을 초과할 수 있습니다
13
+
14
+ **해결책:**
15
+ 프로젝트 규모와 상황에 맞는 방법을 선택하세요.
16
+
17
+ ---
18
+
19
+ ## 방법 1: 백엔드 프록시 서버 (⭐ 가장 안전, 추천)
20
+
21
+ API 키를 서버에만 저장하고, 클라이언트는 자체 서버를 통해 주소 API를 호출합니다.
22
+
23
+ ### 장점
24
+ - ✅ API 키 완전 보호
25
+ - ✅ 요청 제한 관리 가능
26
+ - ✅ 로깅 및 모니터링 가능
27
+ - ✅ 악의적 사용 차단 가능
28
+
29
+ ### 단점
30
+ - ❌ 백엔드 서버 필요
31
+ - ❌ 서버 관리 비용
32
+
33
+ ### 구현 예제
34
+
35
+ #### Node.js + Express
36
+
37
+ ```javascript
38
+ // server.js
39
+ const express = require('express');
40
+ const axios = require('axios');
41
+ const cors = require('cors');
42
+
43
+ const app = express();
44
+ app.use(cors());
45
+ app.use(express.json());
46
+
47
+ // 환경 변수에서 API 키 로드 (.env 파일)
48
+ const JUSO_API_KEY = process.env.JUSO_API_KEY;
49
+
50
+ // 프록시 엔드포인트
51
+ app.get('/api/address/search', async (req, res) => {
52
+ const { keyword, currentPage = 1, countPerPage = 10 } = req.query;
53
+
54
+ // 입력 검증
55
+ if (!keyword) {
56
+ return res.status(400).json({ error: '검색어를 입력하세요' });
57
+ }
58
+
59
+ try {
60
+ // 행정안전부 API 호출 (서버에서만 API 키 사용)
61
+ const response = await axios.get('https://business.juso.go.kr/addrlink/addrLinkApi.do', {
62
+ params: {
63
+ confmKey: JUSO_API_KEY,
64
+ currentPage,
65
+ countPerPage,
66
+ keyword,
67
+ resultType: 'json',
68
+ }
69
+ });
70
+
71
+ // 결과 반환
72
+ res.json(response.data);
73
+ } catch (error) {
74
+ console.error('API 호출 오류:', error);
75
+ res.status(500).json({ error: '주소 검색 중 오류가 발생했습니다' });
76
+ }
77
+ });
78
+
79
+ app.listen(3000, () => {
80
+ console.log('프록시 서버가 3000번 포트에서 실행 중입니다.');
81
+ });
82
+ ```
83
+
84
+ #### .env 파일
85
+
86
+ ```env
87
+ JUSO_API_KEY=your_actual_api_key_here
88
+ ```
89
+
90
+ #### 클라이언트 코드 수정
91
+
92
+ ```javascript
93
+ // api-client.ts 수정
94
+ export class AddressApiClient {
95
+ private apiUrl = 'http://your-domain.com/api/address/search'; // 본인 서버 URL
96
+
97
+ constructor(apiKey?: string) {
98
+ // apiKey 파라미터는 사용하지 않음 (서버에서 관리)
99
+ }
100
+
101
+ async search(keyword: string, currentPage: number = 1, countPerPage: number = 10) {
102
+ const params = new URLSearchParams({
103
+ keyword: keyword.trim(),
104
+ currentPage: currentPage.toString(),
105
+ countPerPage: countPerPage.toString(),
106
+ });
107
+
108
+ const response = await fetch(`${this.apiUrl}?${params.toString()}`);
109
+ const data = await response.json();
110
+
111
+ return {
112
+ results: data.results.juso.map(/* ... */),
113
+ totalCount: parseInt(data.results.common.totalCount, 10),
114
+ };
115
+ }
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 방법 2: 환경 변수 사용 (빌드 시)
122
+
123
+ Webpack, Vite 등 번들러를 사용하여 빌드 시 API 키를 주입합니다.
124
+
125
+ ### 장점
126
+ - ✅ 소스 코드에 하드코딩하지 않음
127
+ - ✅ 환경별로 다른 키 사용 가능
128
+ - ✅ 비교적 간단한 구현
129
+
130
+ ### 단점
131
+ - ⚠️ 빌드된 파일에는 키가 포함됨
132
+ - ⚠️ 개발자 도구로 확인 가능
133
+ - ⚠️ 완전한 보안은 아님
134
+
135
+ ### React (Create React App)
136
+
137
+ ```bash
138
+ # .env 파일
139
+ REACT_APP_JUSO_API_KEY=your_api_key_here
140
+ ```
141
+
142
+ ```javascript
143
+ // App.js
144
+ const finder = new KoreanAddressFinder({
145
+ apiKey: process.env.REACT_APP_JUSO_API_KEY,
146
+ onSelect: (address) => console.log(address)
147
+ });
148
+ ```
149
+
150
+ ### Vue
151
+
152
+ ```bash
153
+ # .env 파일
154
+ VUE_APP_JUSO_API_KEY=your_api_key_here
155
+ ```
156
+
157
+ ```javascript
158
+ // main.js
159
+ const finder = new KoreanAddressFinder({
160
+ apiKey: process.env.VUE_APP_JUSO_API_KEY,
161
+ onSelect: (address) => console.log(address)
162
+ });
163
+ ```
164
+
165
+ ### Vite
166
+
167
+ ```bash
168
+ # .env 파일
169
+ VITE_JUSO_API_KEY=your_api_key_here
170
+ ```
171
+
172
+ ```javascript
173
+ const finder = new KoreanAddressFinder({
174
+ apiKey: import.meta.env.VITE_JUSO_API_KEY,
175
+ onSelect: (address) => console.log(address)
176
+ });
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 방법 3: 설정 파일 사용 (간단한 프로젝트용)
182
+
183
+ 프로젝트 루트에 설정 파일을 만들고 .gitignore에 추가합니다.
184
+
185
+ ### 장점
186
+ - ✅ 구현이 매우 간단
187
+ - ✅ 번들러 없이도 사용 가능
188
+
189
+ ### 단점
190
+ - ⚠️ 배포 시 설정 파일 관리 필요
191
+ - ⚠️ 여전히 클라이언트에 노출됨
192
+
193
+ ### 구현 예제
194
+
195
+ #### config.js (Git에 올리지 않음)
196
+
197
+ ```javascript
198
+ // config.js
199
+ export const config = {
200
+ jusoApiKey: 'your_actual_api_key_here'
201
+ };
202
+ ```
203
+
204
+ #### config.example.js (Git에 올림, 템플릿)
205
+
206
+ ```javascript
207
+ // config.example.js
208
+ export const config = {
209
+ jusoApiKey: 'YOUR_API_KEY_HERE' // 이 파일을 config.js로 복사하고 실제 키를 입력하세요
210
+ };
211
+ ```
212
+
213
+ #### .gitignore
214
+
215
+ ```
216
+ config.js
217
+ .env
218
+ ```
219
+
220
+ #### 사용 방법
221
+
222
+ ```javascript
223
+ // main.js
224
+ import { config } from './config.js';
225
+ import { KoreanAddressFinder } from 'korean-address-finder';
226
+
227
+ const finder = new KoreanAddressFinder({
228
+ apiKey: config.jusoApiKey,
229
+ onSelect: (address) => console.log(address)
230
+ });
231
+
232
+ finder.init();
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 방법 4: 도메인 제한 (행정안전부 API 기능)
238
+
239
+ 행정안전부 주소 API는 **승인 시 등록한 도메인에서만** 작동하도록 설정 가능합니다.
240
+
241
+ ### 설정 방법
242
+
243
+ 1. [주소기반산업지원서비스](https://business.juso.go.kr/) 로그인
244
+ 2. 승인키 신청/관리
245
+ 3. **사용 도메인 등록** (예: `https://yourdomain.com`)
246
+ 4. 저장
247
+
248
+ ### 장점
249
+ - ✅ 다른 도메인에서 키 악용 불가능
250
+ - ✅ 추가 코드 작업 불필요
251
+
252
+ ### 단점
253
+ - ⚠️ localhost에서 테스트 시 별도 개발용 키 필요
254
+ - ⚠️ 도메인 변경 시 재등록 필요
255
+
256
+ ---
257
+
258
+ ## 권장 방법 (프로젝트별)
259
+
260
+ ### 개인 프로젝트 / 작은 웹사이트
261
+ → **방법 3 (설정 파일) + 방법 4 (도메인 제한)**
262
+
263
+ ```javascript
264
+ // config.js (gitignore에 추가)
265
+ export const config = {
266
+ jusoApiKey: 'devU01TX0FVVEgyMDI1MDExMDE1...'
267
+ };
268
+ ```
269
+
270
+ ### 중소 규모 프로젝트
271
+ → **방법 2 (환경 변수) + 방법 4 (도메인 제한)**
272
+
273
+ ```bash
274
+ # .env
275
+ REACT_APP_JUSO_API_KEY=your_key
276
+ ```
277
+
278
+ ### 대규모 / 상용 서비스
279
+ → **방법 1 (백엔드 프록시) ⭐ 필수**
280
+
281
+ 서버에서 API 키 관리, 요청 제한, 로깅 구현
282
+
283
+ ---
284
+
285
+ ## 실전 예제: 간단한 웹사이트
286
+
287
+ ### 파일 구조
288
+
289
+ ```
290
+ my-website/
291
+ ├── index.html
292
+ ├── config.js # API 키 포함 (gitignore)
293
+ ├── config.example.js # 템플릿 (git에 포함)
294
+ ├── main.js
295
+ └── .gitignore
296
+ ```
297
+
298
+ ### config.example.js
299
+
300
+ ```javascript
301
+ export const config = {
302
+ // 이 파일을 config.js로 복사하고 아래에 실제 API 키를 입력하세요
303
+ // 발급 방법: https://business.juso.go.kr/
304
+ jusoApiKey: 'YOUR_API_KEY_HERE'
305
+ };
306
+ ```
307
+
308
+ ### config.js (실제 사용, Git에 올리지 않음)
309
+
310
+ ```javascript
311
+ export const config = {
312
+ jusoApiKey: 'devU01TX0FVVEgyMDI1MDExMDE1MTY0MTExNTM2MjY='
313
+ };
314
+ ```
315
+
316
+ ### .gitignore
317
+
318
+ ```
319
+ config.js
320
+ node_modules/
321
+ .env
322
+ ```
323
+
324
+ ### main.js
325
+
326
+ ```javascript
327
+ import { config } from './config.js';
328
+ import { KoreanAddressFinder } from 'korean-address-finder';
329
+
330
+ const finder = new KoreanAddressFinder({
331
+ apiKey: config.jusoApiKey,
332
+ onSelect: (address) => {
333
+ console.log('선택된 주소:', address);
334
+ }
335
+ });
336
+
337
+ finder.init();
338
+ ```
339
+
340
+ ### 배포 시
341
+
342
+ 1. 서버에 `config.js` 파일 직접 생성
343
+ 2. 실제 API 키 입력
344
+ 3. 파일 권한 설정 (읽기 전용)
345
+
346
+ ---
347
+
348
+ ## 보안 체크리스트
349
+
350
+ 배포 전 확인:
351
+
352
+ - [ ] `.gitignore`에 `config.js`, `.env` 추가
353
+ - [ ] GitHub/GitLab에 실제 API 키 업로드 안 됨
354
+ - [ ] API 키에 도메인 제한 설정
355
+ - [ ] 가능하면 백엔드 프록시 사용
356
+ - [ ] 환경 변수는 빌드 서버에만 설정
357
+ - [ ] API 사용량 모니터링 설정
358
+
359
+ ---
360
+
361
+ ## 추가 보안 팁
362
+
363
+ ### 1. API 사용량 제한
364
+
365
+ ```javascript
366
+ // 간단한 Rate Limiting
367
+ let requestCount = 0;
368
+ let lastResetTime = Date.now();
369
+
370
+ async function searchWithLimit(keyword) {
371
+ const now = Date.now();
372
+
373
+ // 1분마다 리셋
374
+ if (now - lastResetTime > 60000) {
375
+ requestCount = 0;
376
+ lastResetTime = now;
377
+ }
378
+
379
+ // 분당 10회 제한
380
+ if (requestCount >= 10) {
381
+ alert('너무 많은 요청입니다. 잠시 후 다시 시도하세요.');
382
+ return;
383
+ }
384
+
385
+ requestCount++;
386
+ return await apiClient.search(keyword);
387
+ }
388
+ ```
389
+
390
+ ### 2. 디바운싱으로 불필요한 요청 감소
391
+
392
+ ```javascript
393
+ const finder = new KoreanAddressFinder({
394
+ apiKey: config.jusoApiKey,
395
+ autocompleteMode: true, // 자동으로 300ms 디바운싱 적용됨
396
+ });
397
+ ```
398
+
399
+ ---
400
+
401
+ ## 문제 해결
402
+
403
+ ### Q: API 키가 노출되면 어떻게 하나요?
404
+
405
+ 1. 즉시 [주소기반산업지원서비스](https://business.juso.go.kr/)에서 키 재발급
406
+ 2. 이전 키 비활성화
407
+ 3. 새 키로 교체
408
+
409
+ ### Q: localhost에서 테스트하려면?
410
+
411
+ 1. 개발용 API 키 별도 발급
412
+ 2. 도메인에 `localhost` 또는 `127.0.0.1` 등록
413
+ 3. 또는 도메인 제한 없는 키 사용 (개발 시에만)
414
+
415
+ ### Q: 여러 도메인에서 사용하려면?
416
+
417
+ - 도메인마다 별도 키 발급
418
+ - 또는 와일드카드 지원 여부 확인 (API 제공자에 문의)
419
+
420
+ ---
421
+
422
+ ## 마무리
423
+
424
+ **개인/소규모 프로젝트**: 설정 파일 + 도메인 제한으로 충분합니다.
425
+
426
+ **상용 서비스**: 반드시 백엔드 프록시를 구현하세요!
427
+
428
+ 더 자세한 내용은 프로젝트의 `SECURITY.md` 파일을 참조하세요.