feat(db): 로컬 DDL 즉시적용 스크립트 + 셋업 절차 문서화
마이그레이션 도구(flyway/liquibase) 부재. db/schema.sql 은 컨테이너 최초 기동 시 1회만 자동 주입되어, 이후 docs/*-ddl.sql 변경은 실행 DB 에 미반영. - db/apply-local-ddl.sh: docs/*-ddl.sql 을 실행 컨테이너 dev 스키마에 멱등 적용(search_path 강제, ON_ERROR_STOP=1, .env 접속정보 로드, 컨테이너 가드). - docs/usage/local-setup.md §4.1: 신규/변경 DDL 즉시 적용 절차 + 작성자 규약 (DDL 파일 / 실행 DB / db/schema.sql 세 곳 동기화). 검증: game-reviews-ddl.sql 적용 후 game_review_axes·game_review_stats· game_comments.updated_at·game_reviews.is_rating_manual 생성 확인, 스크립트 전체 멱등 재실행 성공. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
375a2de0ff
commit
3593c82d78
|
|
@ -0,0 +1,66 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# db/apply-local-ddl.sh
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 권위 DDL(docs/*-ddl.sql)을 실행 중인 로컬 DB 컨테이너에 즉시 적용한다.
|
||||||
|
#
|
||||||
|
# 배경: 이 프로젝트는 flyway/liquibase 가 없다(docs/usage/local-setup.md §4).
|
||||||
|
# db/schema.sql 은 컨테이너 *최초* 기동 시 docker-entrypoint-initdb.d 로 1회만
|
||||||
|
# 자동 주입되므로, 그 이후 docs/*-ddl.sql 로 추가된 스키마 변경은 실행 DB 에
|
||||||
|
# 자동 반영되지 않는다. 데이터를 잃는 `docker compose down -v` 대신, 이 스크립트로
|
||||||
|
# 변경분을 실행 DB 에 비파괴 적용해 곧바로 로컬 테스트할 수 있다.
|
||||||
|
#
|
||||||
|
# 안전성: 모든 docs/*-ddl.sql 은 멱등(IF NOT EXISTS / DO $$ guard / CREATE OR
|
||||||
|
# REPLACE)하게 작성한다. 따라서 전체를 몇 번 재실행해도 기존 객체는 NOTICE 후
|
||||||
|
# skip 되고 누락분만 생성된다. ON_ERROR_STOP=1 로 첫 에러에서 즉시 중단한다.
|
||||||
|
#
|
||||||
|
# 사용:
|
||||||
|
# db/apply-local-ddl.sh # docs/*-ddl.sql 전체 적용(기본)
|
||||||
|
# db/apply-local-ddl.sh docs/game-reviews-ddl.sql # 특정 파일만 적용
|
||||||
|
#
|
||||||
|
# 환경변수 override(기본값은 .env 에서 로드):
|
||||||
|
# DB_CONTAINER (기본 bibimbap-db) / PG_USER / PG_DB / PG_SCHEMA(기본 dev)
|
||||||
|
# =============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
# .env 에서 기본 접속 정보 로드(있으면). 없으면 컨테이너 기본값 사용.
|
||||||
|
if [ -f .env ]; then
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. ./.env
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONTAINER="${DB_CONTAINER:-bibimbap-db}"
|
||||||
|
PGUSER_="${PG_USER:-${POSTGRES_USER:-bibimbap}}"
|
||||||
|
PGDB_="${PG_DB:-${POSTGRES_DB:-bibimbap}}"
|
||||||
|
SCHEMA="${PG_SCHEMA:-${APP_SCHEMA:-dev}}"
|
||||||
|
|
||||||
|
# 적용 대상: 인자가 있으면 그 파일들, 없으면 docs/*-ddl.sql 전체.
|
||||||
|
if [ "$#" -gt 0 ]; then
|
||||||
|
files=("$@")
|
||||||
|
else
|
||||||
|
files=(docs/*-ddl.sql)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 컨테이너 가동 확인.
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -qx "$CONTAINER"; then
|
||||||
|
echo "✗ DB 컨테이너 '$CONTAINER' 가 떠 있지 않다. 먼저: docker compose up -d db" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "▶ 대상 컨테이너=$CONTAINER db=$PGDB_ schema=$SCHEMA"
|
||||||
|
for f in "${files[@]}"; do
|
||||||
|
if [ ! -f "$f" ]; then
|
||||||
|
echo "✗ 파일 없음: $f" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "▶ 적용: $f"
|
||||||
|
# docs/*-ddl.sql 은 unqualified 테이블명을 쓰므로 search_path 로 스키마를 강제한다.
|
||||||
|
docker exec -e PGOPTIONS="-c search_path=$SCHEMA" -i "$CONTAINER" \
|
||||||
|
psql -U "$PGUSER_" -d "$PGDB_" -v ON_ERROR_STOP=1 -f - < "$f"
|
||||||
|
done
|
||||||
|
echo "✓ 완료 — docs/*-ddl.sql → '$SCHEMA' 스키마 적용됨"
|
||||||
|
|
@ -151,6 +151,35 @@ $ ./mvnw -P dev spring-boot:run
|
||||||
|
|
||||||
> 경고: `db/schema.sql` 의 5개 비권위 테이블(users / games / game_comments / game_likes 및 user_auth_identities 의 추론 부분)은 운영 DB `pg_dump` 와 대조하기 전까지 타입을 신뢰하지 말 것. §7 미해결 항목 참조.
|
> 경고: `db/schema.sql` 의 5개 비권위 테이블(users / games / game_comments / game_likes 및 user_auth_identities 의 추론 부분)은 운영 DB `pg_dump` 와 대조하기 전까지 타입을 신뢰하지 말 것. §7 미해결 항목 참조.
|
||||||
|
|
||||||
|
### 4.1 신규/변경 DDL 을 실행 중 로컬 DB 에 즉시 적용
|
||||||
|
|
||||||
|
**핵심 사실**: `db/schema.sql` 은 컨테이너 **최초 기동 시 1회만** `docker-entrypoint-initdb.d` 로 자동 주입된다. 그 이후 `docs/*-ddl.sql` 로 추가된 스키마 변경은 **실행 중인 DB 에 자동 반영되지 않는다.** flyway/liquibase 가 없으므로(§4) 변경분을 수동으로 적용해야 한다.
|
||||||
|
|
||||||
|
`docker compose down -v` 재기동은 스키마를 다시 주입하지만 **로컬 데이터가 전부 소실**된다. 데이터를 보존하면서 변경분만 비파괴 적용하려면 다음 헬퍼를 쓴다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 권위 DDL(docs/*-ddl.sql) 전체를 실행 컨테이너의 dev 스키마에 멱등 적용.
|
||||||
|
# 모든 docs/*-ddl.sql 은 IF NOT EXISTS / DO $$ / CREATE OR REPLACE 로 작성되어
|
||||||
|
# 몇 번 재실행해도 기존 객체는 skip 되고 누락분만 생성된다.
|
||||||
|
db/apply-local-ddl.sh # 전체 적용(기본)
|
||||||
|
db/apply-local-ddl.sh docs/game-reviews-ddl.sql # 특정 파일만
|
||||||
|
|
||||||
|
# 접속 정보는 .env(POSTGRES_USER / POSTGRES_DB / APP_SCHEMA)에서 읽고,
|
||||||
|
# DB_CONTAINER / PG_USER / PG_DB / PG_SCHEMA 환경변수로 override 할 수 있다.
|
||||||
|
```
|
||||||
|
|
||||||
|
> 내부적으로 `docker exec -e PGOPTIONS="-c search_path=dev" bibimbap-db psql -U <user> -d <db> -v ON_ERROR_STOP=1 -f -` 로 적용한다. `docs/*-ddl.sql` 은 unqualified 테이블명을 쓰므로 `search_path` 로 스키마를 강제하는 것이 필수다.
|
||||||
|
|
||||||
|
#### 새 DDL 을 추가할 때의 규약 (작성자 의무)
|
||||||
|
|
||||||
|
`docs/<기능>-ddl.sql` 을 새로 추가하거나 변경하면 **세 곳을 함께 맞춘다.** 하나라도 빠지면 환경 간 스키마가 어긋난다.
|
||||||
|
|
||||||
|
1. **`docs/<기능>-ddl.sql`** — 권위 DDL. 모든 문장을 멱등(IF NOT EXISTS / DO `$$` 가드 / CREATE OR REPLACE)으로 작성한다.
|
||||||
|
2. **실행 중 로컬 DB** — `db/apply-local-ddl.sh` 를 실행해 즉시 적용한다. → 곧바로 로컬 테스트 가능.
|
||||||
|
3. **`db/schema.sql`** — 동일 변경을 반영(`SET search_path TO dev;` 블록 안)해, 신규 환경의 컨테이너 최초 기동 init 에도 포함되게 한다.
|
||||||
|
|
||||||
|
> 검증: 적용 후 `docker exec bibimbap-db psql -U bibimbap -d bibimbap -c "\d dev.<테이블>"` 로 컬럼·제약·인덱스를 확인한다.
|
||||||
|
|
||||||
## 5. 검증 체크리스트
|
## 5. 검증 체크리스트
|
||||||
|
|
||||||
실제 통과한 항목은 `[x]` 다.
|
실제 통과한 항목은 `[x]` 다.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue