# GeoIP REST (Go Fiber)

간단한 GeoIP 조회 API입니다. 기본은 `GeoLite2-City.mmdb`를 사용해 IP를 나라/지역/도시/위도/경도로 매핑하며, 선택적으로 PostgreSQL + `maxminddb_fdw`로 가져온 데이터를 조회할 수 있습니다. 초기 적재 후에는 DB만으로 조회가 가능하도록 읽기 전용 테이블과 함수가 생성됩니다.

## 요구 사항
- Go 1.25+
- `GeoLite2-City.mmdb` (레포지토리 루트에 위치)
- Docker / Docker Compose (컨테이너 실행 시)

## 설치 및 실행
### 로컬 (Go)
```bash
go mod tidy            # 필요한 경우 go.sum 생성
PORT=8080 GEOIP_DB_PATH=./GeoLite2-City.mmdb go run ./cmd/server
```

### Docker 최초 실행시
```bash
docker network create --driver bridge --attachable geo-ip
``` 

### Docker Compose (PostgreSQL + FDW + API)
```bash
docker compose up --build
```
- 서비스
  - `postgres` (5432): `Dockerfile.postgres`로 `maxminddb_fdw`를 빌드하여 확장 설치 후 `GeoLite2-City.mmdb`를 FDW로 읽고, 로컬 테이블로 적재합니다. 초기 적재 완료 후 mmdb 없이도 DB에서 조회가 가능합니다.
  - `api` (8080): 기본적으로 Postgres 백엔드(`GEOIP_BACKEND=postgres`)를 사용해 조회합니다.
- 볼륨
  - `./GeoLite2-City.mmdb:/data/GeoLite2-City.mmdb:ro` (Postgres 초기 적재용)
  - `pgdata` (DB 데이터 지속)

## 환경 변수
- 공통
  - `PORT` (기본 `8080`): 서버 리스닝 포트
  - `GEOIP_BACKEND` (`mmdb`|`postgres`, 기본 `mmdb`)
- MMDB 모드
  - `GEOIP_DB_PATH` (기본 `/data/GeoLite2-City.mmdb`): GeoIP 데이터베이스 경로
- Postgres 모드
  - `DATABASE_URL`: 예) `postgres://geoip_readonly:geoip_readonly@postgres:5432/geoip?sslmode=disable`
  - `GEOIP_LOOKUP_QUERY` (선택): 기본은 `geoip.lookup_city($1)` 사용

## 사용법
- 헬스체크: `GET /health`
- 조회: `GET /lookup?ip=<IPv4|IPv6>`  
  - `ip` 생략 시 호출자 IP를 사용

예시:
```bash
curl "http://localhost:8080/lookup?ip=1.1.1.1"
```

응답 예시:
```json
{
  "IP": "1.1.1.1",
  "Country": "Australia",
  "Region": "Queensland",
  "City": "South Brisbane",
  "Address": "South Brisbane, Queensland, Australia",
  "Latitude": -27.4748,
  "Longitude": 153.017
}
```

## 개발 참고
- 주요 코드: `cmd/server/main.go`, `internal/geo` (MMDB/Postgres resolver)
- 테스트 실행: `go test ./...`
  - Postgres 통합 테스트 실행 시 `GEOIP_TEST_DATABASE_URL`을 설정하면 DB 백엔드 조회 테스트가 수행됩니다(미설정 시 skip).
- 컨테이너 빌드: `docker build -t geoip:local .`

## Postgres/FDW 쿼리 예시
- 단건 조회 함수 (CIDR 매칭): `SELECT * FROM geoip.lookup_city('1.1.1.1');`
- 원시 테이블 조회: `SELECT * FROM geoip.city_blocks LIMIT 5;`
- API는 `lookup_city(inet)`를 사용하여 가장 구체적인 네트워크(prefix) 한 건을 반환합니다.

## 보안 및 운영 주의사항
- GeoLite2 라이선스 준수: `GeoLite2-City.mmdb` 교체 시 기존 파일을 대체하여 재시작하세요.
- Postgres 포트(5432) 외부 노출 시 방화벽/보안 그룹으로 제한하고 강한 비밀번호를 사용하세요.
- DB는 읽기 전용 계정(`geoip_readonly`)을 기본으로 사용하며, 초기 스키마에서 `default_transaction_read_only`를 강제합니다.
