Conversation
Walkthrough프로덕션 배포 파이프라인을 자동화하도록 CI/CD 워크플로우를 수정하고, 블루/그린 배포 메커니즘을 구현하는 새로운 배포 스크립트를 추가하며, 프로덕션 환경에서 Docker Compose를 비활성화하고 데이터베이스 마이그레이션을 안전화합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant GHA as GitHub Actions
participant Reg as Docker Registry
participant Docker as Docker Engine
participant HC as Health Check
participant Nginx as Nginx
participant Old as Old Container
GHA->>Reg: Pull latest image
Reg-->>GHA: Image pulled
GHA->>Docker: Validate image
Docker-->>GHA: Image valid
GHA->>Nginx: Read current upstream config
Nginx-->>GHA: Active port info
GHA->>Docker: Select blue/green target port
Docker-->>GHA: Target port assigned
GHA->>Docker: Pull and start Docker Compose<br/>on target port
Docker-->>GHA: Container running
GHA->>HC: Health check loop (with retries)
HC-->>GHA: Target port healthy
GHA->>Nginx: Update upstream to<br/>route traffic to new target
Nginx-->>GHA: Upstream updated
GHA->>Old: Stop previous container
Old-->>GHA: Container stopped
GHA->>Docker: Prune unused images
Docker-->>GHA: Cleanup complete
GHA-->>GHA: Deployment successful
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 분 Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ec3d6eb87
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| [ -f "$NGINX_UPSTREAM_FILE" ] || { | ||
| echo -e "${RED}[ERROR] upstream 파일 없음${NC}" | ||
| exit 1 |
There was a problem hiding this comment.
| -- | ||
|
|
||
| CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA cdb_admin; | ||
| -- CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA cdb_admin; |
There was a problem hiding this comment.
Flyway에서 PostGIS extension 생성을 보장하라
이 변경으로 V1 마이그레이션이 postgis extension을 생성하지 않게 되었는데, 애플리케이션은 거리 검색에서 ST_DWithin/ST_Distance 같은 PostGIS 함수를 사용합니다(SouvenirRepository native query). 따라서 새 DB를 V1부터 올리는 환경(신규 prod/stage 또는 ephemeral test DB)에서는 extension이 사전 설치되지 않으면 해당 기능이 function does not exist로 런타임 실패할 수 있어, 마이그레이션에서 extension 보장을 유지하거나 별도 선행 마이그레이션으로 명확히 분리해야 합니다.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
deploy/prod/scripts/deploy.sh (1)
112-119: nginx 설정 파일 무백업 덮어쓰기로 인한 복구 불가능한 상태 발생 위험현재 코드는
nginx -t또는nginx -s reload실패 시 원본 설정을 복구할 방법이 없습니다. 설정 변경 전 백업을 생성하고, 각 단계의 성공 여부를 검증한 후 실패 시 자동 복구하는 절차가 필요합니다.🔧 제안 수정안
+BACKUP_FILE="$(mktemp)" +sudo cp "$NGINX_UPSTREAM_FILE" "$BACKUP_FILE" + sudo tee "$NGINX_UPSTREAM_FILE" > /dev/null <<EOF upstream souzip { server 127.0.0.1:${TARGET_PORT}; } EOF -sudo nginx -t -sudo nginx -s reload +if ! sudo nginx -t; then + echo -e "${RED}[ERROR] nginx 설정 검증 실패, 이전 설정으로 복구합니다.${NC}" + sudo cp "$BACKUP_FILE" "$NGINX_UPSTREAM_FILE" + exit 1 +fi + +if ! sudo nginx -s reload; then + echo -e "${RED}[ERROR] nginx 리로드 실패, 이전 설정으로 복구합니다.${NC}" + sudo cp "$BACKUP_FILE" "$NGINX_UPSTREAM_FILE" + exit 1 +fi + +rm -f "$BACKUP_FILE"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@deploy/prod/scripts/deploy.sh` around lines 112 - 119, Before overwriting NGINX_UPSTREAM_FILE, create a timestamped backup (or tmp copy) of the current file, then write the new upstream (using TARGET_PORT) to a temp file and atomically move it into place only after nginx -t succeeds; if nginx -t or nginx -s reload fails, restore the backup and log the error. Concretely: back up NGINX_UPSTREAM_FILE, write new content to a temp path, run sudo nginx -t against the new file, if the test passes move the temp into NGINX_UPSTREAM_FILE and run sudo nginx -s reload, otherwise restore the backup and abort with a clear error message; ensure all steps check exit codes and clean up temp files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/prod-cicd.yaml:
- Around line 4-9: The workflow is missing a workflow-level concurrency setting,
so multiple pushes can trigger overlapping runs and cause concurrent execution
of the deploy job (risking blue/green and nginx race conditions); add a
top-level concurrency stanza to the workflow (e.g., concurrency: { group:
"deploy-${{ github.ref }}", cancel-in-progress: true }) to serialize runs for
the same branch/ref and ensure the existing deploy job is executed one at a
time.
In `@deploy/prod/scripts/deploy.sh`:
- Around line 11-13: The hardcoded WORK_DIR (and DEPLOY_DIR) in deploy.sh causes
mismatches with the workflow's /home/${{ secrets.GCP_PROD_USER }}/souzip path;
change deploy.sh to compute paths relative to the script location instead of a
fixed user folder by deriving the script directory (e.g., from $0) and setting
WORK_DIR based on that directory, then set DEPLOY_DIR relative to WORK_DIR so
the script works regardless of GCP_PROD_USER or the home path.
- Around line 9-34: The script currently hardcodes :latest which breaks
reproducible deploys; introduce an IMAGE_TAG variable (default from env or CI)
and replace all uses of :latest so docker pull ${REGISTRY}:${IMAGE_TAG} is used,
update NEW_IMAGE to query ${REGISTRY}:${IMAGE_TAG}, and change
docker-compose.blue.yaml and docker-compose.green.yaml image fields to reference
the IMAGE_TAG (e.g., use environment substitution or a template placeholder) so
docker compose pull / docker compose up will use the immutable tag; ensure CI
injects the IMAGE_TAG (commit SHA or semver) and the deploy.sh and any docker
compose pull commands consume that variable (symbols to change: IMAGE_TAG,
REGISTRY, NEW_IMAGE, docker pull invocation, docker-compose.blue.yaml and
docker-compose.green.yaml image fields, and any docker compose pull calls).
In `@src/main/resources/db/migration/V1__init_schema.sql`:
- Around line 32-39: The PostGIS extension creation is commented out in
V1__init_schema.sql which breaks runtime queries used by
SouvenirRepository.findNearbySouvenirs (uses ST_DWithin, ST_Distance,
ST_SetSRID, ST_MakePoint). Re-enable the extension creation (uncomment or add
CREATE EXTENSION IF NOT EXISTS postgis) in V1__init_schema.sql, or alternatively
add a migration check that verifies/creates the extension before any spatial
queries run; ensure the migration uses "CREATE EXTENSION IF NOT EXISTS postgis"
so the findNearbySouvenirs query will succeed.
---
Nitpick comments:
In `@deploy/prod/scripts/deploy.sh`:
- Around line 112-119: Before overwriting NGINX_UPSTREAM_FILE, create a
timestamped backup (or tmp copy) of the current file, then write the new
upstream (using TARGET_PORT) to a temp file and atomically move it into place
only after nginx -t succeeds; if nginx -t or nginx -s reload fails, restore the
backup and log the error. Concretely: back up NGINX_UPSTREAM_FILE, write new
content to a temp path, run sudo nginx -t against the new file, if the test
passes move the temp into NGINX_UPSTREAM_FILE and run sudo nginx -s reload,
otherwise restore the backup and abort with a clear error message; ensure all
steps check exit codes and clean up temp files.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9d03e8dd-4edf-4dbf-abc2-3542b620a9b5
📒 Files selected for processing (4)
.github/workflows/prod-cicd.yamldeploy/prod/scripts/deploy.shsrc/main/resources/application-prod.yamlsrc/main/resources/db/migration/V1__init_schema.sql
| pull_request: | ||
| branches: | ||
| - main | ||
| push: | ||
| branches: | ||
| - main |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for concurrency settings and triggers in the prod-cicd workflow
echo "=== Checking for concurrency settings ==="
rg -nP '^\s*concurrency\s*:' .github/workflows/prod-cicd.yaml || echo "No concurrency block found"
echo -e "\n=== Checking for trigger configuration ==="
rg -nP '^\s*(pull_request|push|on):' .github/workflows/prod-cicd.yaml
echo -e "\n=== Full workflow file content ==="
cat -n .github/workflows/prod-cicd.yamlRepository: souzip/souzip-api
Length of output: 5432
동시 배포 실행 제어가 누락되었습니다.
push 트리거로 연속 발생 시 deploy 작업이 동시에 실행되어 blue/green 배포와 nginx 설정에서 경합이 발생할 수 있습니다. 배포를 직렬화하기 위해 워크플로우 레벨에 concurrency 설정이 필요합니다.
🔧 제안 수정안
on:
pull_request:
branches:
- main
push:
branches:
- main
+concurrency:
+ group: prod-deploy
+ cancel-in-progress: false🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/prod-cicd.yaml around lines 4 - 9, The workflow is missing
a workflow-level concurrency setting, so multiple pushes can trigger overlapping
runs and cause concurrent execution of the deploy job (risking blue/green and
nginx race conditions); add a top-level concurrency stanza to the workflow
(e.g., concurrency: { group: "deploy-${{ github.ref }}", cancel-in-progress:
true }) to serialize runs for the same branch/ref and ensure the existing deploy
job is executed one at a time.
| REGISTRY="asia-northeast3-docker.pkg.dev/souzip-488211/souzip-prod-repo/souzip-api" | ||
|
|
||
| WORK_DIR="/home/souzip-prod/souzip" | ||
| DEPLOY_DIR="$WORK_DIR/deploy/prod" | ||
|
|
||
| BLUE_COMPOSE="docker-compose.blue.yaml" | ||
| GREEN_COMPOSE="docker-compose.green.yaml" | ||
|
|
||
| BLUE_PROJECT="souzip-blue" | ||
| GREEN_PROJECT="souzip-green" | ||
|
|
||
| NGINX_UPSTREAM_FILE="/etc/nginx/conf.d/upstream-souzip.conf" | ||
|
|
||
| BLUE_PORT=8081 | ||
| GREEN_PORT=8082 | ||
|
|
||
| MAX_RETRY=6 | ||
| RETRY_INTERVAL=10 | ||
|
|
||
| cd "$WORK_DIR" || exit 1 | ||
|
|
||
| echo -e "${YELLOW}[1/7] 최신 이미지 다운로드${NC}" | ||
|
|
||
| docker pull ${REGISTRY}:latest | ||
|
|
||
| NEW_IMAGE=$(docker images ${REGISTRY}:latest -q) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# latest 태그 의존 지점 확인
echo "=== Checking deploy.sh ==="
cat -n deploy/prod/scripts/deploy.sh | sed -n '1,50p'
echo -e "\n=== Searching for :latest tags in deployment files ==="
rg -n ':latest' deploy/prod/ .github/workflows/ 2>/dev/null | head -30Repository: souzip/souzip-api
Length of output: 2102
🏁 Script executed:
#!/bin/bash
# Check how docker-compose files are used and if they reference the pulled image
echo "=== Checking docker-compose usage in deploy.sh ==="
cat -n deploy/prod/scripts/deploy.sh | grep -A 20 -B 5 "docker-compose"
echo -e "\n=== Checking docker-compose.blue.yaml content ==="
head -20 deploy/prod/docker-compose.blue.yaml
echo -e "\n=== Checking how NEW_IMAGE is used after being set ==="
cat -n deploy/prod/scripts/deploy.sh | grep -A 15 "NEW_IMAGE="Repository: souzip/souzip-api
Length of output: 1788
🏁 Script executed:
#!/bin/bash
# Check how docker-compose files are invoked and if NEW_IMAGE is used
echo "=== Searching for docker-compose invocations in deploy.sh ==="
rg -n "docker-compose" deploy/prod/scripts/deploy.sh
echo -e "\n=== Full deploy.sh to see complete flow ==="
wc -l deploy/prod/scripts/deploy.shRepository: souzip/souzip-api
Length of output: 289
🏁 Script executed:
#!/bin/bash
# Get the full deploy.sh to understand the complete deployment flow
cat -n deploy/prod/scripts/deploy.shRepository: souzip/souzip-api
Length of output: 3856
프로덕션 배포에서 :latest 태그 사용으로 인한 재현성 및 롤백 추적성 저하
배포 스크립트(32, 34번 줄)뿐만 아니라 docker-compose 파일들(blue.yaml, green.yaml 5번 줄)에서도 :latest 태그가 하드코딩되어 있어, 동일한 이미지 버전을 보장하지 못합니다. 특히 82-83번 줄의 docker compose pull은 compose 파일의 :latest 정의를 따릅니다.
commit SHA 또는 semantic version 같은 immutable 태그로 고정하되, 다음을 함께 변경해야 합니다:
- deploy.sh에서 IMAGE_TAG 변수화
- docker-compose.blue.yaml, docker-compose.green.yaml에서 image 필드 수정
- 필요시 CI/CD 워크플로우에서 태그를 동적으로 주입
🔧 제안 수정안
--- a/deploy/prod/scripts/deploy.sh
+++ b/deploy/prod/scripts/deploy.sh
@@ -1,6 +1,7 @@
#!/bin/bash
set -e
+IMAGE_TAG="${IMAGE_TAG:-latest}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
@@ -29,11 +30,11 @@ cd "$WORK_DIR" || exit 1
echo -e "${YELLOW}[1/7] 최신 이미지 다운로드${NC}"
-docker pull ${REGISTRY}:latest
+docker pull "${REGISTRY}:${IMAGE_TAG}"
-NEW_IMAGE=$(docker images ${REGISTRY}:latest -q)
+NEW_IMAGE=$(docker images "${REGISTRY}:${IMAGE_TAG}" -q)--- a/deploy/prod/docker-compose.blue.yaml
+++ b/deploy/prod/docker-compose.blue.yaml
@@ -2,7 +2,7 @@ version: "3.8"
services:
backend:
- image: asia-northeast3-docker.pkg.dev/souzip-488211/souzip-prod-repo/souzip-api:latest
+ image: asia-northeast3-docker.pkg.dev/souzip-488211/souzip-prod-repo/souzip-api:${IMAGE_TAG:-latest}
container_name: souzip-api-blue--- a/deploy/prod/docker-compose.green.yaml
+++ b/deploy/prod/docker-compose.green.yaml
@@ -2,7 +2,7 @@ version: "3.8"
services:
backend:
- image: asia-northeast3-docker.pkg.dev/souzip-488211/souzip-prod-repo/souzip-api:latest
+ image: asia-northeast3-docker.pkg.dev/souzip-488211/souzip-prod-repo/souzip-api:${IMAGE_TAG:-latest}
container_name: souzip-api-green🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@deploy/prod/scripts/deploy.sh` around lines 9 - 34, The script currently
hardcodes :latest which breaks reproducible deploys; introduce an IMAGE_TAG
variable (default from env or CI) and replace all uses of :latest so docker pull
${REGISTRY}:${IMAGE_TAG} is used, update NEW_IMAGE to query
${REGISTRY}:${IMAGE_TAG}, and change docker-compose.blue.yaml and
docker-compose.green.yaml image fields to reference the IMAGE_TAG (e.g., use
environment substitution or a template placeholder) so docker compose pull /
docker compose up will use the immutable tag; ensure CI injects the IMAGE_TAG
(commit SHA or semver) and the deploy.sh and any docker compose pull commands
consume that variable (symbols to change: IMAGE_TAG, REGISTRY, NEW_IMAGE, docker
pull invocation, docker-compose.blue.yaml and docker-compose.green.yaml image
fields, and any docker compose pull calls).
| WORK_DIR="/home/souzip-prod/souzip" | ||
| DEPLOY_DIR="$WORK_DIR/deploy/prod" | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, verify the hardcoded WORK_DIR in the deploy script
cat -n deploy/prod/scripts/deploy.sh | head -20Repository: souzip/souzip-api
Length of output: 648
🏁 Script executed:
# Search for workflow files that might use GCP_PROD_USER
find .github -name "*.yaml" -o -name "*.yml" | head -10Repository: souzip/souzip-api
Length of output: 125
🏁 Script executed:
# Look for references to the hardcoded path in other files
rg "souzip-prod" --type sh --type yamlRepository: souzip/souzip-api
Length of output: 497
🏁 Script executed:
cat -n .github/workflows/prod-cicd.yaml | grep -A 5 -B 5 "GCP_PROD_USER\|WORK_DIR\|/home"Repository: souzip/souzip-api
Length of output: 1121
🏁 Script executed:
# Check for any secrets usage in the workflow
cat .github/workflows/prod-cicd.yaml | head -100Repository: souzip/souzip-api
Length of output: 2442
워크플로우 경로와 스크립트 경로 불일치로 배포 실패 위험이 있습니다.
워크플로우는 /home/${{ secrets.GCP_PROD_USER }}/souzip으로 파일을 배포(line 97, 109)하지만, deploy.sh의 WORK_DIR은 /home/souzip-prod/souzip로 고정되어 있습니다(line 11). GCP_PROD_USER 값이 souzip-prod와 다르면 스크립트가 파일을 찾지 못해 배포가 실패합니다.
상대 경로 기반으로 변경하여 스크립트 위치에 따라 동적으로 경로를 결정하는 것을 권장합니다.
🔧 제안 수정안
--- a/deploy/prod/scripts/deploy.sh
+++ b/deploy/prod/scripts/deploy.sh
@@
-WORK_DIR="/home/souzip-prod/souzip"
-DEPLOY_DIR="$WORK_DIR/deploy/prod"
+SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
+DEPLOY_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
+WORK_DIR="$(cd "$DEPLOY_DIR/../.." && pwd)"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@deploy/prod/scripts/deploy.sh` around lines 11 - 13, The hardcoded WORK_DIR
(and DEPLOY_DIR) in deploy.sh causes mismatches with the workflow's /home/${{
secrets.GCP_PROD_USER }}/souzip path; change deploy.sh to compute paths relative
to the script location instead of a fixed user folder by deriving the script
directory (e.g., from $0) and setting WORK_DIR based on that directory, then set
DEPLOY_DIR relative to WORK_DIR so the script works regardless of GCP_PROD_USER
or the home path.
| -- CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA cdb_admin; | ||
|
|
||
|
|
||
| -- | ||
| -- Name: EXTENSION postgis; Type: COMMENT; Schema: -; Owner: | ||
| -- | ||
|
|
||
| COMMENT ON EXTENSION postgis IS 'PostGIS geometry and geography spatial types and functions'; | ||
| -- COMMENT ON EXTENSION postgis IS 'PostGIS geometry and geography spatial types and functions'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the migration file content around lines 32-39
echo "=== Migration file content (lines 25-45) ==="
sed -n '25,45p' src/main/resources/db/migration/V1__init_schema.sql
echo -e "\n=== Check SouvenirRepository for ST_DWithin/ST_Distance usage ==="
rg -n 'ST_DWithin|ST_Distance|ST_SetSRID|ST_MakePoint' src/main/java/com/souzip/domain/souvenir/repository/SouvenirRepository.java
echo -e "\n=== Check all PostGIS extension references in migration files ==="
find src/main/resources/db/migration -name "*.sql" -exec grep -n 'postgis\|PostGIS' {} +
echo -e "\n=== Full SouvenirRepository.java file (checking lines around 21-46) ==="
wc -l src/main/java/com/souzip/domain/souvenir/repository/SouvenirRepository.javaRepository: souzip/souzip-api
Length of output: 1686
🏁 Script executed:
#!/bin/bash
# View the full SouvenirRepository.java to understand the query context
echo "=== Full SouvenirRepository.java content ==="
cat -n src/main/java/com/souzip/domain/souvenir/repository/SouvenirRepository.java
echo -e "\n=== Check if other Java files use PostGIS functions ==="
rg -l 'ST_DWithin|ST_Distance|ST_SetSRID|ST_MakePoint' src/main/java/
echo -e "\n=== Check for any PostGIS setup in other migration files ==="
find src/main/resources/db/migration -name "*.sql" | sortRepository: souzip/souzip-api
Length of output: 3282
PostGIS 확장 생성이 주석 처리되어 있어 런타임 쿼리 실패를 초래합니다.
SouvenirRepository.java의 findNearbySouvenirs() 메서드(37-45줄)가 ST_DWithin, ST_Distance, ST_SetSRID, ST_MakePoint 등 PostGIS 공간 함수를 직접 사용하고 있습니다. 현재 V1__init_schema.sql 32줄과 39줄의 PostGIS 확장 생성 구문이 주석 처리되어 있어, 이 쿼리는 데이터베이스에 해당 확장이 설치되지 않으면 실행 시 실패합니다.
확장 생성 구문을 활성화하거나, 외부 프로비저닝을 사용한다면 마이그레이션에서 존재 여부를 검증해야 합니다.
제안 수정안
--- a/src/main/resources/db/migration/V1__init_schema.sql
+++ b/src/main/resources/db/migration/V1__init_schema.sql
@@ -29,6 +29,6 @@
-- Name: postgis; Type: EXTENSION; Schema: -; Owner: -
--
--- CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA cdb_admin;
+CREATE EXTENSION IF NOT EXISTS postgis;
@@ -36,4 +36,4 @@
-- Name: EXTENSION postgis; Type: COMMENT; Schema: -; Owner:
--
--- COMMENT ON EXTENSION postgis IS 'PostGIS geometry and geography spatial types and functions';
+COMMENT ON EXTENSION postgis IS 'PostGIS geometry and geography spatial types and functions';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/resources/db/migration/V1__init_schema.sql` around lines 32 - 39,
The PostGIS extension creation is commented out in V1__init_schema.sql which
breaks runtime queries used by SouvenirRepository.findNearbySouvenirs (uses
ST_DWithin, ST_Distance, ST_SetSRID, ST_MakePoint). Re-enable the extension
creation (uncomment or add CREATE EXTENSION IF NOT EXISTS postgis) in
V1__init_schema.sql, or alternatively add a migration check that
verifies/creates the extension before any spatial queries run; ensure the
migration uses "CREATE EXTENSION IF NOT EXISTS postgis" so the
findNearbySouvenirs query will succeed.
* build: mysql 의존성 추가 * chore: Docker 개발 환경 설정 * chore: docker-compose 및 초기 테이블 작성 * chore: 이전 PR 적용 * chore: env 예시 파일 수정 * refactor: BaseEntity DateTime 변경 * feat: 국가 Entity 및 외부 API DTO 추가 * refactor: Country 및 외부 API DTO 수정 * feat: Country 리포지토리 추가 * feat: CountryService 구현 - local환경에서만 국가 데이터 저장 - 조회 메서드 구현 - 중복 저장 방지 * refactor: 중복 방지 Set 자료구조로 수정 * refactor: service 레이어 트랜잭션 클래스에 readOnly로 수정 * test: CountryService 테스트 코드 작성 * refactor: region Enum처리로 로직 수정 * refactor: 조건 가독성을 위해 메서드 분리 * refactor: Service에서 ResponseDto 반환하도록 변경 * feat: 컨트롤러 및 API 문서화 * perf: List 응답 구조 개선 * chore: 애노테이션 관련 깊이 순으로 수정 * refactor: List 응답 및 외부 API 호출 로직 분리 * [SOU-2] 환율 데이터 저장 (#29) * 환율 Entity 및 외부 API DTO 추가 * 환율 Entity 및 외부 API DTO 추가 * feat: 스케줄러 활성화를 위한 설정 추가 * feat: ExchangeRate 레포지토리 추가 * feat: 환율 스케줄러 추가 * feat: ExchangeRateService 구현 * refactor: 엔티티 클래스 updatedAt 필드 추가 * refactor: 예외 코드 추가 * chore: 외부 API base URL 추가 * [SOU-15] 데이터베이스 구조 변경 및 서비스 로직 수정 (#31) * refactor: 초기 데이터 구조 변경 * refactor: 나라 api 필드 통화, 언어별 나라이름 추가 * refactor: 테이블 구조 변경으로 인해 entity 수정 * feat: currency Entity 추가 * refactor: 데이터 구조 변경 및 나라 수집 로직 변경 * refactor: 데이터 구조 변경 및 나라 수집 로직 변경 * [SOU-2] 환율 서비스 리팩토링 (#32) * refactor: 환율 서비스 리팩토링 * feat: 단일/여러 나라 환율 조회 및 DTO 응답 구현 * refactor: 환율 DTO 불필요 메소드 제거 * refactor: 외부 API 호출 로직 개선 * chore: 불필요한 import 제거 * chore: 코드 정리 및 불필요한 요소 제거 * [SOU-4] 카카오 로그인 구현 (#33) * build: security, jwt, dotenv 의존성 추가 * fix: user DB 예약어로 되어있어 더블쿼터로 감싸야 테이블 생성됨 * refactor: 불필요한 조건 제거 * refactor: 외부API 메서드 분리 * feat: UserRepository 구현 * feat: RefreshToken Entity 구현 * feat: RefreshTokenRepository 구현 * refactor: RefreshTokenRepositroy 엔티티 수정 * feat: JWT 설정 프로퍼티 클래스 구현 * feat: 공통 yaml에 jwt 유효시간 추가 * chore: 클래스 바로 밑 필드 공백 추가 * feat: JWT 토큰 생성 및 검증 구현 * feat: SecurityConfig 설정 구현 * feat: @require 메타 애노테이션 구현 - 메서드/클래스 레벨에서 인증 필요시 애노테이션 명시 - @RequireAuth 애노테이션으로 권한 체크로 인 해 모든 요청 허가 * feat: OAuthProperties 구현 및 AppConfig로 properties 클래스 중앙 관리 * feat: 로그인 DTO 구현 * feat: 로그인 DTO 구현 * feat: Strategy 패턴 적용 - OAuthClient 인터페이스 추가 - OAuthUserInfo 인터페이스 추가 * feat: OAuthClientFcatory 구현 * feat: 카카오 로그인 구현 * test: 서비스 로직 테스트 코드 작성 * refactor: 서비스 로직 테스트 코드 리팩터링 * test: 컨트롤러 테스트 코드 및 API 문서화 작성 * dosc: index.adoc 에 auth 문서 추가 * [SOU-21] 토큰 재발급 구현 (#36) * refactor: 유저 객체를 저장하는 것이 아니라 id만 저장하도록 수정 * refactor: refreshToken 유효기간 프로퍼티스에서 값가져오도록 수정 * chore: 토큰 유효기간 수정 * feat:토큰 재발급 구현 * test: 재발급 테스트 코드 작성 * refactor: 에러 케이스 추가 및 문서 수정 * [SOU-22] 만료된 refreshToken 삭제 스케줄러 및 로직 추가 (#37) * feat: 만료된 refreshToken 삭제 로직 및 스케줄러 구현 * refactor: 스케줄러 시간대 명시 및 리포지토리 애노테이션 추가 * [SOU-13] 환율 API 및 문서화 (#35) * chore: 테이블명 수정 * fix: 환율 매핑 시 기준/외국 통화 순서 수정 * feat: 국가별 환율 조회 메소드 추가 * feat: 국가별 환율 조회 API 추가 * test: 환율 서비스 테스트 작성 * feat: 환율 API 문서화 * chore: 패키지 경로 수정 * refactor: 수정 * [SOU-8] 로그아웃 구현 (#38) * refactor: security 화이트리스트 적용 * feat: 로그아웃 구현 * refactor: 에러 문서 수정 * [NO-ISSUE] 공통 응답 구조로 변경 (#39) * feat: 로그아웃 구현 # Conflicts: # src/docs/asciidoc/auth.adoc # src/test/java/com/souzip/api/domain/auth/controller/AuthControllerTest.java * refactor: 에러 문서 수정 * refactor: 응답 구조 공통 응답으로 수정 * chore: currencyDto 패키지 분리 * [NO-ISSUE] 서비스 로직과 외부 API 호출 로직 분리 (#40) * refactor: DTO 변환 로직 가독성 개선 * refactor: 환율 서비스 KRW 기준 단순화 * test: 환율 서비스 테스트 코드 수정 * refactor: 외부 API 호출과 서비스 로직 분리 * test: 테스트 코드 수정 * [NO-ISSUE] 환율 응답 구조 개선 (#41) * refactor: 응답 구조 개선하여 List 기반으로 반환 * test: 테스트 코드 수정 * [SOU-9] 회원탈퇴 구현 (#43) * feat: 회원탈퇴 구현 * refactor: 회원탈퇴 유저 정보 수정 및 재가입 로직 수정 * test: 이름 변경 * fix: 환율 저장 누락 문제 해결 (#45) * [SOU-28] 파일 로직 구현 (#46) * config: object storage 설정 * feat: 파일 로직 구현 * feat: 파일 로직 구현 * fix: currencyDto 파일 구조 수정 * [SOU-3] CI/CD 파이프라인 구축 (#42) * ci: 개발 서버용 워크플로우 추가 * ci: Docker & CI/CD 설정 * chore: 테스트용 application.yaml 추가 * chore: DB 호스트명 수정 * ci: 테스트 제외 빌드 테스트 * ci: 테스트 제외 빌드 테스트 * ci: 도커 이미지 태그 추가 * chore: 오타 수정 * ci: dev 프로파일 적용하도록 ENTRYPOINT 수정 * ci: 워크플로우 수정 및 정리 * ci: pull_request로 이벤트 변경 * ci: Gradle 테스트 캐시 무시 적용 * ci: 테스트용 DB 환경변수 추가 * test: 테스트 클래스에 test 프로필 적용 * ci: 인메모리 H2로 테스트 전환 * ci: Docker pull 추가 및 DB 생성 전략 변경 * chore: PostgreSQL 스키마 지정 * chore: dev 환경용 Profile 추가 * chore: Dockerfile 수정 * chore: dev 환경용 Profile 추가 * test: Mockito 기반으로 테스트 코드 수정 * ci: CICD 환경변수 추가 * [SOU-16] 상품 생성 (#44) * feat: 상품 엔티티 추가 * refactor: 상품 엔티티 수정 및 soft delete 적용 * feat: 상품 생성 요청 DTO 추가 * feat: 상품 레포지토리 추가 * refactor: 엔티티 및 ENUM 수정 * refactor: 상품 DTO 수정 * chore: dev 프로필 제거 * feat: 상품 생성 로직 구현 * [SOU-25] NullPointException 으로 인해 컨테이너 죽음 수정 (#47) * fix: nullpoint 발생으로 인해 컨테이너 죽음 수정 * perf: currencyCode 없는 나라 저장 하지 않도록 필터 추가 * refactor: 컴파일 단계에서 경고 수정 * [SOU-17] 상품 수정 (#48) * feat: 상품 수정 DTO 추가 * feat: 업데이트 메소드 추가 * feat: 수정 서비스 로직 구현 * refactor: 존재하지 않는 데이터 예외 처리 적용 * feat: 수정 API 추가 * chore: deleted 필드 기본값 유지 * [SOU-18] 상품 삭제 (#49) * chore: 스케줄러 프로필 수정 * feat: 상품 레포지토리 Soft Delete용 조회 메소드 추가 * feat: 상품 서비스 Soft Delete 추가 * feat: 상품 삭제 API 구현 * feat: 도시 모델 추가 (#50) * [SOU-32] 상품 기능 확장 (#51) * feat: 상품 생성, 수정, 삭제 로직 개선 및 권한 검증 추가 * feat: 상품 생성 시 파일 업로드 처리 * chore: 테스트용 시큐리티 예외 처리 * chore: 수정 * feat: 상품 생성/수정 파일 업로드 처리 및 테스트, REST Docs 추가 * feat: 상품 단건 조회 구현 (#52) * feat: google, apple 로그인 구현 (#54) * [SOU-30] 상점 추가 (#53) * feat: 상점 엔티티 추가 * feat: 정적 팩토리 메서드 추가 * [NO-ISSUE] 상품 파일 업로드 로직 수정 (#55) * fix: 상품 파일 업로드 로직 수정 * fix: 위도/경도 컬럼 타입 오류 수정 * feat: 상품 응답 DTO에서 userId 제거 * test: 테스트 코드 수정 * [SOU-35] 온보딩 구현 (#56) * feat: 온보딩 구현 * feat: 온보딩 구현 * refactor: 기본 필드 false로 적용 (#57) * docs: 문서 수정 (#58) * [SOU-38] 온보딩 이미지 처리 수정 (#60) * refactor: 온보딩 과정 이미지 처리 수정 * test: 프로퍼티 위치 수정 * test: 메서드 static 삭제 * chore: 최대 닉네임 글자수 제한 수정 (#61) * [NO-ISSUE] 문서 단순 수정 (#62) * chore: 최대 닉네임 글자수 제한 수정 * docs: 문서 수정 * [SOU-36] 기념품 조회 시 현지/환율 적용 가격 표시 (#59) * refactor: 도메인 및 패키지/파일명 변경 * chore: DTO 파일명 변경 * refactor: 엔티티 수정사항 반영 및 DTO 수정 * refactor: 컨트롤러 및 서비스 수정 * refactor: 에러 코드 수정 * test: 테스트 코드 수정 * feat: geocoding API 연동 및 DTO 추가 * feat: 기념품 DTO 및 엔티티 수정 * refactor: 기념품 서비스에 환율 적용 로직 반영 * feat: 환율 계산 서비스 및 DTO 추가 * fix: 환율 관련 에러 코드 추가 * chore: Geocoding API 관련 설정 추가 * test: 기념품 컨트롤러 테스트 수정 * fix: restdocs 테스트 실패 문제 해결 * test: 기념품 컨트롤러 테스트 보완 * fix: geocoding API key 누락으로 컨테이너 종료 이슈 수정 (#63) * [SOU-36] 기념품 API 문서화 (#64) * feat: DTO validation 추가 * docs: 기념품 API 문서화 * [SOU-23] 나라, 환율 불필요한 로직 삭제 (#65) * refactor: Country 리팩토링 및 관련 API 문서 정리 * refactor: ExchangeRate 리팩토링 및 관련 API 문서 정리 * test: TODO 주석 추가 * [SOU-39] 통화기호 호출 API (#66) * feat: 통화기호 조회 API 구현 * test: 통화 기호 조회 테스트 추가 * docs: API 문서 추가 * [SOU-40] 사용자 위치기반 기념품 조회 (#68) * feat: 근처 기념품 조회용 DTO 추가 * feat: 사용자 위치 기반 기념품 조회 기능 추가 * test: 테스트 코드 작성 * docs: API 문서 추가 * feat: 기념품 조회 반경 조정 * [SOU-177] 온보딩과정 약관동의 추가 (#69) * build: elasticsearch 구축 * build: elasticsearch 구축 * chore: 불필요한 도커 폴더 삭제 * fix: 서버환경 네트워크 치환 수정 * feat: 검색 구현 # Conflicts: # src/main/java/com/souzip/api/domain/souvenir/repository/SouvenirRepository.java * refactor: docs data 필드 삭제 * chore: 응답 삭제 * refactor: 스코어 필드 삭제 * perf: 오타 및 초성 검색 개선 * test: test * feat: 약관동의 저장 구현 * feat: 닉네임 중복 체크 api 구현 (#70) * [NO-ISSUE] 테스트 케이스 추가 (#71) * test: 테스트 케이스 추가 * chore: 테스트 케이스 삭제 * [SOU-182] 기념품 조회 개선 (#72) * feat: 컨트롤러에 인증 어노테이션 적용 * feat: 기념품 엔티티 수정 * feat: isOwned 필드 추가 및 서비스 매핑 * fix: 데이터 NULL 문제 해결 * refactor: 기념품 관련 로직 개선 * test: 테스트 코드 수정 * feat: 기념품 API 접근 권한 처리 개선 * feat: 근처 기념품 조회 응답 수정 * test: 테스트 코드 수정 * docs: API 문서 추가 * [SOU-184] 기념품 조회 응답 수정 (#73) * feat: 기념품 조회 응답 수정 * feat: 근처 기념품 조회 ListResponse 적용 * test: 테스트 코드 수정 * docs: API 문서 업데이트 * [NO-ISSUE] API 문서 필수값 여부 반영 (#74) * fix: 가격 미입력 시 처리 로직 수정 * feat: 근처 기념품 조회 반경 추가 * test: 테스트 코드 수정 * feat: 마이페이지 구현 (#75) * docs: API 문서 최신화 및 수정 (#76) * chore: 클로바 연동 (#77) * refactor: 나라 위도 경도 수정 (#78) * [SOU-180] 일반 기념품 추천 (#79) * chore: 사용하지 않는 import 제거 * chore: 변수 업데이트 * feat: 일반 추천용 DTO 추가 * feat: 일반 추천용 레포지토리 구현 * feat: 일반 추천 서비스 로직 구현 * feat: 기념품 추천 컨트롤러 추가 * fix: 인증 설정 수정 * test: 테스트 코드 작성 * docs: API 문서 추가 * chore: 코드 정리 및 메소드 분리 * test: 테스트 코드 수정 * docs: 문서 수정 * docs: User API 문서 복구 * docs: API 문서 필수값 여부 추가 (#81) * docs: API 문서 nullable 표시 개선 (#82) * [SOU-181] AI 기념품 추천 (#80) * feat: AI 기념품 추천 로직 구현 * feat: 프롬프트 수정 * feat: 기념품 AI/일반 추천 기능 개선 및 문서 업데이트 * test: 테스트 코드 수정 * docs: 문서 설명 수정 * feat: 엔드포인트 수정 * feat: 최근 업로드 기반 기념품 추천 로직 구현 * fix: API 응답 수정 * fix: 테스트 수정 및 문서 수정 * [SOU-29] 검색 구현 (#67) * feat: 검색 구현 # Conflicts: # src/main/java/com/souzip/api/domain/souvenir/repository/SouvenirRepository.java * chore: 응답 삭제 * refactor: 스코어 필드 삭제 * perf: 오타 및 초성 검색 개선 * feat: 검색 구현 * [NO-ISSUE] 검색 문서 수정 (#83) * chore: 응답 삭제 * refactor: 스코어 필드 삭제 * perf: 오타 및 초성 검색 개선 * feat: 검색 구현 * docs: AI 기념품 추천 API 문서화 (#84) * [SOU-197] 페이지네이션 필드명 변경 (#85) * feat: AI 추천 API 인증 적용 * refactor: 필드명 수정 * docs: 검색 API 문서 수정 * [SOU-198] 검색 API 수정 (#86) * feat: 검색 문서 및 응답에 위도/경도 추가 * test: 검색 API 테스트 코드 수정 * [SOU-199] AI 추천 수정 (#87) * feat: 검색 문서 및 응답에 위도/경도 추가 * test: 검색 API 테스트 코드 수정 * perf: fetchJoin 적용, N+1 방지 * chore: 환경 변수 추가 * perf: 조회 속도 약 70% 개선 (#89) * fix: 페이지네이션 버그 수정 (#90) * [SOU-237] 로그 시스템 구축 (#91) * build: actuator, prometheus 의존성 추가 * chore: management 환경별 설정 * feat: 디바이스타입 추가 * feat: auth 로그 엔티티 추가 * feat: 로그 시스템 구축 * chore: 리프레시 토큰 재발급 로그 삭제 (#92) * [SOU-266] 회원탈퇴 감사 로그 추가 (#93) * feat: 회원탈퇴 로그 수집 * feat: 탈퇴 로그에 userId 기록 추가 * chore: 오타 수정 * feat: 메서드 파라미터 기반 userId 추출 로직 추가 * [SOU-275] 프로필 이미지 포맷 변경에 따른 URL 수정 (#94) * refactor: 프로필 이미지 url 수정 * test: 테스트 코드 수정 * chore: flyway 적용 및 로컬, 개발 디비 분리 (#96) * feat: 기념품 감사 로그 추가 (#95) * chore: actions 스크립트 수정 (#97) * [SOU-282] 온보딩 동의항목 감사 로그 추가 (#100) * feat: 마케팅 동의 로그 추가 * feat: 온보딩 동의항목 감사 로그 추가 * feat: 온보딩 동의 항목 메타데이터에 위치 동의 추가 * chore: 변수 누락 수정 * [SOU-284] IOS 소유권 이전 대응 로직 추가 (#101) * feat: Apple 마이그레이션 설정 추가 * feat: DB 스키마 추가 * feat: 애플 소유권 이전 대응 로직 추가 * [SOU-270] 닉네임 중복 버그 수정 (#102) * fix: 회원가입시 초기 닉네임을 name으로 지정하고 있는 문제를 회원가입시 null 로 지정 * chore: 초기 회원가입시 닉네임 null * chore: 닉네임 낫널 수정 스크립트 작성 * chore: 스크립트 삭제 * refactor: 수정 * feat: 마지막 로그인 시간 저장 기능 추가 (#103) * refactor: 타임존 아시아 적용 (#104) * [NO-ISSUE] 초기 닉네임을 null값이 아닌 빈값으로 수정 (#105) * fix: 로그인 닉네임 수정 * fix: 로그인 닉네임 수정 * refactor: PR과 배포 프로세스 분리 (#106) * [SOU-294] Job1과 Job2는 파일 공유 버그 수정 (#107) * fix: Job1 과 Job2 독립적인 러너이기 때문에 파일 공유가 되지 않아 Artifact 를 사용하여 공유 * chore: artifact 3 지원 중단으로 4로 변경 * refactor: 경로 수정 * fix: 자르 파일 경로 디버깅 및 수정 (#108) * [SOU-295] 도커 이미지 배포 및 롤백 자동화 (#109) * feat: 배포 및 롤백 자동화 구현 * chore: 불필요한 주석 삭제 * refactor: 기존 (#110) gradle-build-action 사용 중단을 권장한다고 안내에 따라 setup-gradle 로 변경 * feat: 도커 컴포즈로 분리 (#111) * feat: 서버관련 디스코드 알림 추가 (#112) * refactor: 경로 수정 및 중복 제거 (#113) * fix: cicd 파일 수정 (#114) * fix: 단순 제거 (#115) * fix: 단순 제거 (#116) * refactor: 폴더 경로 수정 및 알림 수정 (#117) * fix: 검색시 4글자 이상 입력시 검색 안 되는 버그 수정 (#118) * fix: 검색 개선 (#119) * chore: 애플 로그인 로그 추가 (#120) * refactor: 긴급 수정 (#121) * refactor: 수정 (#122) * [SOU-325] 나라별 추천 기념품 선정 기준 변경 (#123) * feat: 국가별 추천 기념품 조회 구조 개편 * 추천 국가 조회 API 테스트 수정 * 추천 국가 API 문서 갱신 * chore: 설명 수정 및 불필요한 주석 제거 * refactor: 애플 로그인 이전 대응 완료 (#124) * refactor: 배포 알림 수정 (#125) * refactor: 배포 알림 수정 (#127) * [SOU-326] 국가별 기념품 등록 수 집계 기준 변경 (#126) * feat: 국가별 기념품 등록 통계 기준을 누적으로 변경 * test: 테스트 코드 수정 * docs: API 문서 수정 * refactor: 배포 알림 수정 (#128) * [NO-ISSUE] 충돌 해결 (#129) * refactor: 애플 로그인 이전 대응 완료 * feat: 국가별 기념품 등록 통계 기준을 누적으로 변경 # Conflicts: # src/main/java/com/souzip/api/domain/recommend/general/repository/GeneralRecommendationRepositoryCustomImpl.java * test: 테스트 코드 수정 * docs: API 문서 수정 * refactor: 배포 알림 수정 (#125) * refactor: 배포 알림 수정 (#127) * refactor: 배포 알림 수정 * test: 수정 * fix: 수정 --------- Co-authored-by: Kimdonghwan <kimdonghwan913@gmail.com> Co-authored-by: monkey <105265603+Develop-KIM@users.noreply.github.com> * [NO-ISSUE] 수정 (#130) * refactor: 애플 로그인 이전 대응 완료 * feat: 국가별 기념품 등록 통계 기준을 누적으로 변경 # Conflicts: # src/main/java/com/souzip/api/domain/recommend/general/repository/GeneralRecommendationRepositoryCustomImpl.java * test: 테스트 코드 수정 * docs: API 문서 수정 * refactor: 배포 알림 수정 (#125) * refactor: 배포 알림 수정 (#127) * refactor: 배포 알림 수정 * test: 수정 * fix: 수정 * chore: 수정 * refactor: 밥좀 먹자 --------- Co-authored-by: bum0w0 <kgy5988@naver.com> * feat: 기념품 등록 수가 가장 많은 국가 Top10 조회 API 추가 (#131) * feat: 기념품 등록 수가 가장 많은 국가 Top10 조회 API 추가 * chore: 자자 * [SOU-354] adoc 빌드 경고 수정 및 URL 한글 디코딩 처리 (#132) * docs: 스니펫 템플릿 섹션 헤더 제거 * docs: REST Docs URL 쿼리 파라미터 한글 디코딩 처리 추가 * docs: REST Docs URL 쿼리 파라미터 한글 디코딩 처리 추가 (#133) * fix: Souvenir files 필드 빌더 기본값 초기화 누락 수정 (#134) * refactor: ClovaStudioClient raw 타입 제거 및 제네릭 타입 적용 (#135) * fix: 감사로그 로그인 시 userId에 oauthAccessToken이 저장되는 버그 수정 (#136) * refactor: userIdParam 기본값 빈값으로 수정 (#137) * chore: 롱타입도 필터되도록 수정 (#138) * fix: 캐스팅 오류 수정 (#139) * refactor: 로그아웃시 userID 에 내부 ID값 저장 되는 부분 수정 (#140) * [NO-ISSUE] 기념품 최다등록 국가 Top 10 조회 API 문서 반영 (#141) * test: 기념품 최다등록 국가 조회 테스트 코드 추가 * docs: API 문서 반영 * [SOU-358] 코드 래빗 PR 리뷰 자동화 (#142) * feat: 코드 래빗 PR 리뷰 자동화 * chore: CodeRabbit poem 리뷰 옵션 테스트 적용 * chore: 파일명 수정 * chore: 옵션 변경 테스트 * [NO-ISSUE] 기념품 최다등록 국가 Top10 및 국가별 기념품 조회 API 추가 (#143) * feat: 기념품 최다등록 국가 Top10 API 추가 * test: 테스트 코드 수정 * docs: API 문서 추가 * chore: 템플릿 삭제 및 설정 파일 수정 * feat: 엔드포인트 수정 * chore: 테스트 및 문서 수정 * fix: api 주소 변경 (#144) * fix: api 주소 변경 (#145) * [SOU-371] CORS 설정 추가 (#146) # Conflicts: # src/main/resources/static/docs/index.html * [SOU-367] 관리자 로그인 API 추가 (#147) * feat: 관리자 엔티티, 역할, 레포지토리 추가 * feat: 어드민 도메인 모델 추가 * feat: 어드민 클래스 추가 및 BaseErrorCode 도입 * test: 어드민 도메인 모델 테스트 추가 * feat: 어드민 인프라 레이어 추가 * refactor: 로그인에 불필요한 레포지토리 메서드 제거 및 테스트 작성 * feat: 어드민 초기화 추가 # Conflicts: # src/main/resources/static/docs/index.html * feat: 어드민 어플리케이션 레이어 추가 * feat: 어드민 프레젠테이션 레이어 추가 * test: 어드민 테스트 코드 개선 및 문서 작성, 테스트 전용 패스워드 엔코더 헬퍼클래스 추가 * test: 어드민 테스트 코드 개선 * [SOU-384] 관리자 로그인 JWT 추가 (#148) * feat: JWT 토큰 생성 및 검증 구현 * feat: 어드민 테이블 Flyway 마이그레이션 추가 * test: 어드민 테스트 코드 토큰 추가 * fix: 어드민 초기 유저네임 및 패스워드 env 추가 (#149) * docs: REST DOCS 공통화 및 수정 (#150) * [SOU-384] 어드민 리프레시 토큰 관리 및 인증 구현 (#151) * refactor: 어드민 엔티티 파일명 수정 * feat: 어드민 리프레시 토큰 인프라 레이어 추가 * test: 어드민 도메인 테스트 추가 * feat: 어드민 리프레시 토큰 인프라 레이어 추가 * feat: 어드민 인증 서비스 로직 추가 * feat: 어드민 리프레시/로그아웃 컨트롤러 추가 - 어드민 JWT 인증 필터 추가 * test: 어드민 컨트롤러 테스트 추가 * feat: 어드민 리프레시 토큰 정리 스케줄러 추가 * feat: 어드민 리프레시 토큰 정리 스케줄러 추가 * feat: 어드민 리프레시 토큰 정리 스케줄러 추가 * docs: index.html 생성 * docs: 로컬에서 API문서 카피본 생기지 않도록 수정 * feat: 어드민 리프레시 토큰 테이블 flyway 마이그레이션 추가 * fix: flyway 파일 수정으로 인한 체크섬 변경으로 flyway 유효성 검사 실패 (#152) * chore: cors 설정 수정 (#153) * fix: 업데이트 시점에 생성일자 필드 수정되는 버그 수정 (#154) * [SOU-372] 관리자 권한에 따른 역할 제어 (#155) * chore: 패키지 구조 변경 * 관리자 역할 기반 접근 제어 애노테이션 추가 * feat: 관리자 인증 토큰에 역할 권한 정보 추가 * feat: 권한 없음 예외 처리 추가 * refactor: SecurityConfig에 명시적인 AccessDeniedHandler 추가 * [SOU-133] 관리자 초대 API 추가 (#156) * feat: 관리자 초대 Command 추가 * feat: 관리자 초대 Request/Response DTO 추가 * feat: 관리자 도메인 예외 클래스 추가 * feat: 관리자 초대 기능 Service 추가 * feat: 관리자 초대 API 추가 * test: 관리자 초대 테스트 코드 추가 * [SOU-133] 관리자 초대 및 조회, 삭제 로직 추가 및 수정 (#157) * refactor: 관리자 계정 잠금 기능 제거 * feat: 관리자 초대 및 삭제 조회 수정 * chore: CORS 추가 (#158) * [NO-ISSUE] Souvenir 엔티티 불필요한 필드 및 메서드 제거 (#159) * refactor: Souvenir 엔티티 불필요한 필드 및 메서드 제거 * chore: flyway 마이그레이션 파일 수정 * chore: souvenir 필드 삭제 (#160) * [SOU-243] 기념품 환율 계산 로직 개선 (#161) * feat: v2 가격 구조를 위한 DB 마이그레이션 추가 * feat: SouvenirRequest 및 값객체 추가 * feat: v2 서비스 로직 추가 및 응답 DTO 추가 * perf: 기념품 가격 환율 로직 개선 * [SOU-243] 서비스 로직 책임 분리 (#162) * feat: v2 서비스 로직 추가 및 응답 DTO 추가 * perf: 기념품 가격 환율 로직 개선 * refactor: 환율/계산 로직 exchange 로 분리하여 책임 분리 * refactor: 환율/계산 로직 exchange 로 분리하여 책임 분리 * fix: 헬스체크 JSON변형 실패 (#163) * [SOU-392] 나라 검색시 도시 우선순위 로직 추가 (#164) * feat: City 엔티티에 priority 필드 추가 * feat: City 엔티티에 priority 필드 추가 * feat: LocationDocument에 priority 필드 추가 * feat: SearchResponse에 priority 필드 추가 * feat: 검색 결과에 도시 우선순위 정렬 적용 * feat: City 엔티티에 updatePriority 메서드 추가 * feat: 도시 우선순위 관리 서비스 추가 * refactor: 우선순위 서버 내부에서 처리하도록 수정 * feat: QueryDSL 도시 커스텀 레포지토리 추가 * feat: 도시 우선순위 변경 시 밀기/당기기 로직 적용 * feat: 도시 우선순위 수정 시 비관적 락 적용 * feat: AdminManagementService reindex 플래그 설정 * test: 관리자 도시 우선순위 관련 테스트 코드 작성 * chore: flyway City 우선순위 필드 마이그레이션 sql 추가 * [SOU-390] 나라 검색시 도시만 응답가도록 필터링 적용 (#165) * refactor: 나라 검색시 도시만 응답가도록 수정 * test: 나라 검색시 도시만 응답가도록 테스트 코드 수정 * [SOU-390] 관리자 페이지 도시 CRD 및 나라 목록 API 추가 (#166) * refactor: 도시 우선순위 변경을 이벤트 방식으로 리팩토링 * feat: 나라/도시 목록 조회 API 추가 * test: 테스트 수정 * feat: 도시 생성 요청 이벤트 추가 * feat: 도시 삭제 요청 이벤트 추가 * feat: 도시 생성/삭제 커맨드 및 서비스 추가 * feat: 도시 생성/삭제 API 추가 * [SOU-390] 나라 목록 페이징 적용 (#167) * refactor: 도시 우선순위 변경을 이벤트 방식으로 리팩토링 # Conflicts: # src/main/java/com/souzip/api/domain/admin/application/AdminManagementService.java # src/test/java/com/souzip/api/domain/admin/application/AdminManagementServiceTest.java * feat: 나라/도시 목록 조회 API 추가 * feat: 도시 생성 요청 이벤트 추가 * feat: 도시 생성/삭제 커맨드 및 서비스 추가 * feat: 도시 생성/삭제 API 추가 * refactor: 어드민은 시티 port 인터페이스만 바라보도록 수정 * refactor: country 도메인 포트 패턴 적용 * refactor: 테스트 코드 수정 * dosc: 나라 목록 페이징 문서 수정 * chore: 중복 메서드 삭제 * test: 테스트 수정 * test: usecase 테스트 삭제 * [SOU-390] 도시 목록 페이징 적용 (#168) * refactor: 도시 우선순위 변경을 이벤트 방식으로 리팩토링 # Conflicts: # src/main/java/com/souzip/api/domain/admin/application/AdminManagementService.java # src/test/java/com/souzip/api/domain/admin/application/AdminManagementServiceTest.java * feat: 나라/도시 목록 조회 API 추가 * feat: 도시 생성 요청 이벤트 추가 * feat: 도시 생성/삭제 커맨드 및 서비스 추가 * feat: 도시 생성/삭제 API 추가 * chore: 중복 메서드 삭제 * test: 테스트 수정 * [SOU-390] 기존 어탭터 삭제 (#169) * refactor: 도시 우선순위 변경을 이벤트 방식으로 리팩토링 # Conflicts: # src/main/java/com/souzip/api/domain/admin/application/AdminManagementService.java # src/test/java/com/souzip/api/domain/admin/application/AdminManagementServiceTest.java * feat: 나라/도시 목록 조회 API 추가 * feat: 도시 생성 요청 이벤트 추가 * feat: 도시 생성/삭제 커맨드 및 서비스 추가 * feat: 도시 생성/삭제 API 추가 * chore: 중복 메서드 삭제 * test: 테스트 수정 * refactor: 기존 어댑터 삭제 * fix: 우선순위 변경 로직 수정 (#170) * [NO-ISSUE] 우선순위 변경 로직 수정 (#171) * fix: 우선순위 변경 로직 수정 # Conflicts: # src/main/java/com/souzip/api/domain/city/repository/CityRepositoryCustom.java # src/main/java/com/souzip/api/domain/city/repository/CityRepositoryImpl.java # src/test/java/com/souzip/api/domain/city/application/command/CityCommandServiceTest.java * fix: 우선순위 변경 로직 수정 * fix: 우선순위 변경 로직 수정 (#172) * [NO-ISSUE] 아키텍처 수정 (#173) * refactor: port/adapter 전환 * refactor: city → search 직접 의존을 도메인 이벤트로 분리 * test: 테스트코드 수정 * refactor: 서비스로직 책임 분리 * refactor: 서비스로직 책임 분리 * refactor: 서비스로직 책임 분리 * [SOU-376] Codex 가이드 파일 추가 (#174) * feat: Codex 가이드 파일 추가 * docs: 리뷰 규칙 추가 * chore: env파일 example 수정 (#175) * feat: 관리자 나라 키워드 검색 구현 (#176) * feat: 도시 이름 수정 구현 (#177) * [SOU-456] 도시 우선순위 기존 우선순위 변경시 중복되는 버그 수정 (#178) * fix: 우선순위 로직 수정 * fix: 커멘드서비스 로직 수정 * test: 로직 수정 * [SOU-456] 우선순위가 있는 도시를 변경시 중복되는 버그 수정 (#179) * fix: 커멘드서비스 로직 수정 * test: 로직 수정 * refactor: 기존 우선순위 가진 도시를 변경시 중복 되는 버그 수정 * refactor: 기존 우선순위 가진 도시를 변경시 중복 되는 버그 수정 (#180) * refactor: 기존 우선순위 가진 도시를 변경시 중복 되는 버그 수정 (#181) * [SOU-423] 개발 서버 DB 컨테이너 구성 (#182) * feat: 개발 환경용 docker-compose에 PostgreSQL 컨테이너 추가 * chore: 배포 및 롤백 스크립트 수정 * feat: 환경별 DB 설정 및 env 구조 정리 * feat: 운영 환경 설정 파일 추가 * chore: 롤백 시 postgres/api 기동 결과를 개별 검증 * chore: 배포 스크립트 DB 기동 실패 처리 보완 * fix: Flyway migration에서 psql 메타 커맨드 주석처리 (#183) * [NO-ISSUE] flyway baseline 설정값 추가 (#184) * fix: Flyway migration에서 psql 메타 커맨드 주석처리 * fix: 수정 * [NO-ISSUE] Flyway V1에서 psql 백슬래시 메타커맨드 제거 (#186) * fix: 수정 * fix: Flyway V1에서 psql 백슬래시 메타커맨드 제거 * feat: v1 스키마 스크립트 수정 * Fix/no issue flyway (#187) * fix: 수정 * fix: Flyway V1에서 psql 백슬래시 메타커맨드 제거 * feat: v1 스키마 스크립트 수정 * chore: flyway 없앰 * [SOU-471] 배포 시스템 분리 (#188) * refactor: 배포 시스템 분리 * refactor: 독스 URL 변수명 수정 * fix: 도커 컴포즈 버전 수정 (#189) * [NO-ISSUE] 로컬 DB 도커 서포트로 변경 (#190) * fix: 도커 컴포즈 버전 수정 * feat: 로컬 DB 도커 컴포즈 서포트로 구축 * fix: 도커 컴포즈 비활성화 (#191) * [SOU-446] 엘라스틱서치 관련 코드 제거 (#192) * refactor: 엘라스틱서치 제거 * docs: 개발 문서 작성 * docs: 개발 문서 작성 * docs: 개발 문서 작성 * fix: 응답에 스코어 하이라이트 추가 (#193) * fix: 응답에 스코어 하이라이트 추가 (#194) * [SOU-446] null 대신 빈값주도록 수정 (#195) * fix: 응답에 스코어 하이라이트 추가 * fix: 응답에 스코어 하이라이트 추가 * feat: 위치 도메인 레이어 구현 (#196) * [SOU-483] location 애플리케이션 구현 (#197) * feat: 위치 애플리케이션 레이어 구현 * feat: location flyway 마이그레이션 파일 추가 * refactor: cityRepository 빈 이름 중복 수정 * refactor: searchService 빈 이름 중복 수정 (#198) * fix: flyway 파일 이름 수정 (#199) * [SOU-426] 지오코딩 구조 변경 및 리팩터링 (#200) * refactor: gecoding 패키지 구조 변경 및 리팩터링 * refactor: 정적 팩토리 메서드 사용하도록 수정 * refactor: env 키 이름 변경 * [SOU-426] 지오코딩 응답 필드명 개선 및 하위 호환성 유지 (#201) * refactor: 응답 필드명 수정 * test: 메서드 이름 수정 * test: 필드명 수정 * docs: 문서 필드명 수정 * refactor: GeocodingResult 필드명을 address로 변경하고 API 응답 하위 호환성 유지 * docs: 문서 작성 * feat: google places api 연동 (#202) * [SOU-486] 검색 확장 및 구조 개선 (#203) * feat: 검색 확장 * refactor: 로케이션 패키지 구조 개선 * docs: 도메인모델 문서 수정 * test: 리버스 지오코딩 서비스 테스트 작성 * docs: 스니펫 템플릿 수정 * chore: 검색 시큐리티 화이트리스트에 추가 * [NO-ISSSUE] 파일 패키지 구조및 불필요한 루트 패키지 api 제거 (#204) * refactor: 파일 구조 수정 * test: 파일 테스트 코드 작성 및 리팩터링 * chore: 불필요한 루트 패키지 삭제: * refator: 파일 타입 필드명 수정 * fix: 잘못 수정된 필드명 수정 * [SOU-143] 공지사항 적용 (#205) * docs: 파일 관련 문서 작성 * feat: 공지사항 도메인 모델 구현 * fix: 좌표 하이버네이트 경고로 인해 클래스로 수정 * fix: 하이버네이트 Dialect 제거 * refactor: 파일 익셉션 위치 수정 * feat: 공지사항 애플리케이션 레이어 구현 * feat: 공지사항 구현 * refactor: file entityType 이넘으로 변경 * feat: flyway 공지사항 마이그레이션 파일 추가 * refactor: 에러 메시지 수정 * refactor: 권한 체크 추가 * test: 테스트 메시지 매칭부분 삭제: * feat: 유효성 검사 추가 * perf: 목록 조회 N+1 해결 * refactor: 사용자 api 활성화 체크 로직 추가 * refactor: 파일 삭제 잠재적 버그 수정 * test: 메서드 수정 * fix: 헬스 체크 퍼블릭 수정 (#206) * [NO-ISSUE] 공지사항 응답 구조 변경 (#207) * refactor: 파일 형식 svg 추가 * refactor: 공지사항 응답 구조 변경 * ci: 프로덕션 CI/CD 파이프라인 추가 (#208) * feat: blue/green docker-compose 구성 추가 (#209) * refactor: 검색 응답 구조 변경 (#210) * [SOU-421] 프로덕션 서버 무중단 배포 구현 (#211) * feat: 프로덕션 서버 배포 스크립트 작성 * ci: 배포 트리거 설정 * fix: compose v2 문법 제거 * chore: 프로덕션 환경에서 도커 컴포즈 비활성화 * chore: docker compose v2 적용 * feat: prod 배포 스크립트 개선 * chore: 롤백 스크립트 삭제 * fix: Flyway schema init idempotency 및 권한 이슈 수정 * fix: Flyway migration에서 postgis extension 생성 구문 제거 * fix: Flyway PostGIS 권한 오류 수정' * fix: CI/CD에 누락된 NCP Object Storage 환경변수 추가 * fix: 블루/그린 배포 시 도커 컴포즈 충돌 문제 수정 * chore: 배포 사용자 souzip-prod로 변경 * ci: 프로덕션 배포 트리거 브랜치를 main으로 변경 --------- Co-authored-by: Kimdonghwan <kimdonghwan913@gmail.com> Co-authored-by: Kimdonghwan <105265603+Develop-KIM@users.noreply.github.com>
Summary by CodeRabbit
릴리스 노트
New Features
Bug Fixes
Chores