Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# git-ranker 로컬 도커 실행용 환경변수 템플릿 (SPRING_PROFILES_ACTIVE=local)
# 사용법: cp .env.local.example .env.local 후 값 채우기 (.env.local 은 gitignore 대상)
# 실행: docker compose --env-file .env.local -f docker-compose.local.yml up -d --build

# --- Database (local) ---
DB_NAME=git_ranker
DB_USERNAME=root
DB_PASSWORD=root

# --- GitHub OAuth App (local): 본인 OAuth App 값 ---
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_REDIRECT_URI=http://localhost:8080/login/oauth2/code/github

# --- JWT: JWT_SECRET 은 32바이트 이상 랜덤 시크릿 ---
JWT_SECRET=
JWT_ACCESS_TOKEN_EXPIRATION=900000
JWT_REFRESH_TOKEN_EXPIRATION=86400000

# --- GitHub GraphQL API tokens (comma-separated, 토큰 풀 로테이션) ---
GITHUB_API_TOKENS=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ build/**
!**/src/main/**/build/
!**/src/test/**/build/
.env
.env.*
!.env*.example

### STS ###
.apt_generated
Expand Down
62 changes: 62 additions & 0 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# 로컬 개발용 (SPRING_PROFILES_ACTIVE=local): API + MySQL 두 컨테이너만.
# 운영 스택(docker-compose.yml)과 분리 — 모니터링(Prometheus/Loki/Grafana) 없음.
# 실행: docker compose --env-file .env.local -f docker-compose.local.yml up -d --build
# 검증: curl http://localhost:9090/actuator/health
services:
git-ranker-api:
build: .
container_name: git-ranker-api-local
ports:
- "8080:8080"
- "127.0.0.1:9090:9090"
environment:
SPRING_PROFILES_ACTIVE: local
# application-local.yml이 ${DB_URL}을 읽음 → 컨테이너에선 localhost가 아니라 DB 서비스명으로 구성
DB_URL: jdbc:mysql://git-ranker-db:3306/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET}
GITHUB_REDIRECT_URI: ${GITHUB_REDIRECT_URI}
GITHUB_API_TOKENS: ${GITHUB_API_TOKENS}
JWT_SECRET: ${JWT_SECRET}
JWT_ACCESS_TOKEN_EXPIRATION: ${JWT_ACCESS_TOKEN_EXPIRATION}
JWT_REFRESH_TOKEN_EXPIRATION: ${JWT_REFRESH_TOKEN_EXPIRATION}
TZ: Asia/Seoul
depends_on:
git-ranker-db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/actuator/health"]
interval: 10s
timeout: 5s
retries: 10
networks:
- git-ranker-local-net

git-ranker-db:
image: mysql:8.0
container_name: git-ranker-db-local
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} # 앱이 root로 접속 (DB_USERNAME=root). MySQL 이미지는 MYSQL_USER=root를 거부하므로 root 계정 사용.
TZ: Asia/Seoul
ports:
- "127.0.0.1:3306:3306"
volumes:
- mysql_data_local:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 10
Comment on lines +49 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if mysqladmin ping without password fails in mysql:8.0
docker run --rm -d --name test-mysql -e MYSQL_ROOT_PASSWORD=root mysql:8.0
sleep 15
docker exec test-mysql mysqladmin ping -h localhost || echo "Ping failed without password"
docker stop test-mysql

Repository: alexization/git-ranker

Length of output: 313


🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files docker-compose.local.yml docker-compose.yml .env* 2>/dev/null || true

echo '--- docker-compose.local.yml (relevant section) ---'
nl -ba docker-compose.local.yml | sed -n '1,140p'

echo '--- search for MYSQL env usage ---'
rg -n "MYSQL_ROOT_PASSWORD|DB_PASSWORD|mysqladmin ping|healthcheck|depends_on" -S .

Repository: alexization/git-ranker

Length of output: 315


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- docker-compose.local.yml (lines 1-220) ---'
sed -n '1,220p' docker-compose.local.yml | cat -n

echo '--- docker-compose.yml (lines 1-260) ---'
sed -n '1,260p' docker-compose.yml | cat -n

echo '--- .env.local.example ---'
sed -n '1,220p' .env.local.example | cat -n

echo '--- grep relevant symbols ---'
rg -n "MYSQL_ROOT_PASSWORD|DB_PASSWORD|mysqladmin ping|healthcheck|depends_on|service_healthy" docker-compose.local.yml docker-compose.yml .env.local.example -S

Repository: alexization/git-ranker

Length of output: 10834


MySQL 헬스체크에 비밀번호를 전달해야 합니다.
mysqladmin ping -h localhostMYSQL_ROOT_PASSWORD로 시작한 MySQL에 인증하지 못해 unhealthy 상태에 머물 수 있고, 그 결과 depends_on: service_healthy를 기다리는 API가 시작되지 않을 수 있습니다.
mysqladmin ping -h localhost -uroot -p${DB_PASSWORD}처럼 같은 비밀번호를 넘기세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose.local.yml` around lines 49 - 53, Update the MySQL healthcheck
command to authenticate as root using the configured DB_PASSWORD, while
preserving the existing host and healthcheck timing settings.

networks:
- git-ranker-local-net

networks:
git-ranker-local-net:
driver: bridge

volumes:
mysql_data_local:
21 changes: 14 additions & 7 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,36 @@

| 프로파일 | 용도 | 특징 |
|---|---|---|
| `local` | 로컬 개발 | localhost MySQL, `LOCAL_*` OAuth env, CORS localhost:3000, 쿠키 non-secure |
| `local` | 로컬 개발 | MySQL, OAuth·DB env(`.env.local`), CORS localhost:3000, 쿠키 non-secure |
| `prod` | 운영 | `DB_URL` 등 운영 env, git-ranker.com CORS, secure 쿠키, actuator 노출 축소 |

## 필요 환경 변수 (local)

`spring-dotenv`가 루트 `.env`를 읽는다.
`local`·`prod`가 같은 변수명을 쓰고, 값은 환경별 파일로 구분한다. 로컬 도커는 `--env-file .env.local`로 주입한다(템플릿 `.env.local.example`).

```
LOCAL_DB_USERNAME, LOCAL_DB_PASSWORD
LOCAL_GITHUB_CLIENT_ID, LOCAL_GITHUB_CLIENT_SECRET, LOCAL_GITHUB_REDIRECT_URI
```text
DB_NAME, DB_USERNAME, DB_PASSWORD
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_REDIRECT_URI
JWT_SECRET, JWT_ACCESS_TOKEN_EXPIRATION, JWT_REFRESH_TOKEN_EXPIRATION
GITHUB_API_TOKENS # GitHub GraphQL 토큰 (콤마 구분, 토큰 풀 로테이션)
```

## 실행

```bash
SPRING_PROFILES_ACTIVE=local ./gradlew bootRun # 앱 실행 (8080)
SPRING_PROFILES_ACTIVE=local ./gradlew bootRun # 호스트 직접 실행: 아래 도커 권장. 이 경로는 spring-dotenv가 읽는 .env(로컬 변수 전체)가 필요
./gradlew test # 단위 테스트
./gradlew build # 패키징 (CI는 build -x test)
```

docker-compose 전체 스택(api + db + 모니터링)은 `docker compose up -d`. 서비스: `git-ranker-api`(8080, mgmt 9090), `git-ranker-db`(MySQL 8.0), `prometheus`, `loki`, `promtail`, `grafana`(3001).
로컬 도커(api + db만, `local` 프로파일):

```bash
docker compose --env-file .env.local -f docker-compose.local.yml up -d --build # 기동
docker compose --env-file .env.local -f docker-compose.local.yml down # 정지(-v 추가 시 DB 볼륨 삭제)
```

운영 전체 스택(api + db + 모니터링)은 `docker compose up -d`. 서비스: `git-ranker-api`(8080, mgmt 9090), `git-ranker-db`(MySQL 8.0), `prometheus`, `loki`, `promtail`, `grafana`(3001).

## 주요 엔드포인트

Expand Down
18 changes: 11 additions & 7 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,26 @@ spring:
on-profile: local

datasource:
url: jdbc:mysql://localhost:3306/git_ranker?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul
username: ${LOCAL_DB_USERNAME}
password: ${LOCAL_DB_PASSWORD}
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
Comment on lines +7 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

로컬 실행을 위한 데이터베이스 설정에 기본값을 추가하세요.

.env.local.example 템플릿에는 DB_URL이 정의되어 있지 않아, DEVELOPMENT.md에 안내된 ./gradlew bootRun 명령어로 직접 실행할 경우 환경변수 미해결로 인해 애플리케이션 시작이 실패합니다.
(Docker Compose 환경에서는 docker-compose.local.ymlDB_URL을 주입하므로 동작하지만, 호스트 기기에서의 직접 실행은 실패합니다.)

호스트에서 실행할 때 localhost를 바라보도록 기본값을 제공하는 것을 권장합니다.

🐛 제안하는 수정안
   datasource:
-    url: ${DB_URL}
-    username: ${DB_USERNAME}
-    password: ${DB_PASSWORD}
+    url: ${DB_URL:jdbc:mysql://localhost:3306/${DB_NAME:git_ranker}?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul}
+    username: ${DB_USERNAME:root}
+    password: ${DB_PASSWORD:root}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
datasource:
url: ${DB_URL:jdbc:mysql://localhost:3306/${DB_NAME:git_ranker}?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul}
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD:root}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/application-local.yml` around lines 7 - 9, Update the
local database url configuration to provide a localhost-based default when
DB_URL is unset, while preserving the existing DB_URL value when supplied. Keep
the username and password environment-variable references unchanged.

driver-class-name: com.mysql.cj.jdbc.Driver

jpa:
hibernate:
ddl-auto: update

security:
oauth2:
client:
registration:
github:
client-id: ${LOCAL_GITHUB_CLIENT_ID}
client-secret: ${LOCAL_GITHUB_CLIENT_SECRET}
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope:
- read:user
- user:email
redirect-uri: ${LOCAL_GITHUB_REDIRECT_URI}
redirect-uri: ${GITHUB_REDIRECT_URI}

jwt:
secret: ${JWT_SECRET}
Expand All @@ -39,4 +43,4 @@ app:
authorized-redirect-uri: http://localhost:3000/auth/callback
cookie:
domain: localhost
secure: false
secure: false
Loading