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
28 changes: 14 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@
| 분류 | 기술 | 버전 |
|---------------|-----------------------------------------------------------------------|----------------|
| 언어 | Java | 21 |
| 프레임워크 | Spring Boot | 3.5.8 |
| AI | Spring AI (Google Gemini via Vertex AI) | 1.1.2 |
| 프레임워크 | Spring Boot | 4.1.0 |
| AI | Spring AI (Google Gemini via Vertex AI) | 2.0.0 |
| ORM | Spring Data JPA + Hibernate | (Boot BOM) |
| DB | MySQL | - |
| 인증 | JWT (Auth0 java-jwt 4.5.0) + OAuth2 Client | - |
| 클라우드 | OCI Java SDK (Object Storage) + Cloudflare CDN + Google Cloud Storage | 3.90.0 |
| 문서변환 | JODConverter (LibreOffice) | 4.4.9 |
| PDF 처리 | Apache PDFBox | 3.0.3 |
| 문서변환 | JODConverter (LibreOffice) | 4.4.11 |
| PDF 처리 | Apache PDFBox | 3.0.7 |
| 모니터링 | Micrometer + Prometheus + Actuator | (Boot BOM) |
| 장애격리 | Resilience4j (Circuit Breaker) | 2.3.0 |
| 장애격리 | Resilience4j (Circuit Breaker) | 2.4.0 |
| Rate Limiting | Bucket4j + Caffeine | 8.19.0 |
| API 문서 | SpringDoc OpenAPI (Swagger UI) | 2.8.17 |
| API 문서 | SpringDoc OpenAPI (Swagger UI) | 3.0.3 |
| 암호화 | Jasypt | 3.0.5 |
| ID 난독화 | Hashids | 1.0.3 |
| 빌드 | Gradle (Groovy DSL) | 8.14.3 |
| 컨테이너 | Jib (Docker) | 3.4.0 |
| 컨테이너 | Jib (Docker) | 3.5.3 |
| 포맷터 | Spotless + Google Java Format | 7.0.4 / 1.25.2 |
| DB 마이그레이션 | Flyway | (Boot BOM) |
| 테스트 | JUnit 5 | (Boot BOM) |
Expand Down Expand Up @@ -80,7 +80,7 @@ q-asker/api/
│ ├── resilience.yml # Circuit Breaker
│ └── spring-doc.yml # Swagger/OpenAPI
├── modules/
│ ├── global/ # 공통 (BaseEntity, ApiResponse, GlobalExceptionHandler)
│ ├── global/ # 공통 (BaseEntity, ApiResponse, GlobalExceptionHandler, Boot4CompatConfig)
│ ├── auth/ (api + impl) # 인증 (JWT, OAuth2, RateLimitFilter)
│ ├── oci/ (api + impl) # OCI Object Storage 파일 업로드
│ ├── board/ (api + impl) # 게시판
Expand All @@ -94,11 +94,9 @@ q-asker/api/
│ ├── monitoring/ # Grafana Alloy 설정
│ ├── mysql/ # MySQL Docker 설정
│ ├── base-image/ # Docker 베이스 이미지
│ ├── scripts/
│ │ └── oci-mysql-backup/ # OCI MySQL 백업/복구/헬스체크 스크립트 (backup.sh, restore.sh, healthcheck.sh, systemd)
│ └── terraform/
│ ├── gcp/ # GCP 인프라 (GCS, IAM, Vertex AI)
│ └── oci/ # OCI 인프라 (NSG Cloudflare 인바운드, MySQL HeatWave 백업/PITR)
│ ├── blue-green/ # Blue-Green 무중단 배포 (Nginx 트래픽 스위칭, docker-compose, deploy.sh)
│ └── scripts/
│ └── oci-mysql-backup/ # OCI MySQL 백업/복구/헬스체크 스크립트 (backup.sh, restore.sh, healthcheck.sh, deploy.sh, env.example, healthcheck.baseline.yml, lib/, systemd/, RESTORE.md) — 리눅스·macOS 호환 (gzip -dc, sha256sum↔shasum 폴백)
├── docs/ # 문서, 분석 자료
├── gradle/
│ ├── libs.versions.toml # Version Catalog: 모든 의존성/플러그인 버전 SSOT
Expand Down Expand Up @@ -161,5 +159,7 @@ q-asker/api/

<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
shell commands, and other important information, read the current plan
shell commands, and other important information, read the current plan:
`specs/001-quiz-read-optimization/plan.md` (research.md, data-model.md,
contracts/, quickstart.md in the same directory)
<!-- SPECKIT END -->
6 changes: 6 additions & 0 deletions app/src/main/resources/config/app-common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ q-asker:
allowed-extensions: application/pdf,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-powerpoint
max-file-size: 52_428_800

# 관리자 이미지 업로드 검증 (문서 업로드와 규칙이 달라 분리)
admin:
image-upload:
max-size: 5_242_880 # 5MB
allowed-types: image/jpeg,image/png,image/gif,image/webp

server:
shutdown: graceful

Expand Down
11 changes: 9 additions & 2 deletions infra/scripts/oci-mysql-backup/backup.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,15 @@ fail() {
exit "$code"
}

# sha256sum(GNU/coreutils) 또는 shasum -a 256(macOS/BSD) 이식성 래퍼.
# 둘 다 "<hash> <path>" 형식으로 출력하므로 downstream awk '{print $1}' 호환.
sha256() {
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$@"
else shasum -a 256 "$@"; fi
}

# ─── 사전 검증 ───
for cmd in flock mysqldump mysql sha256sum jq oci; do
for cmd in flock mysqldump mysql jq oci; do
command -v "$cmd" >/dev/null || { log "[ERR] $cmd 미설치"; exit 1; }
done
for var in MYSQL_HOST MYSQL_USER MYSQL_PASSWORD MYSQL_DATABASE; do
Expand Down Expand Up @@ -124,7 +131,7 @@ log "[step 1/5] dump complete ($DUMP_SIZE bytes)"

# ─── Step 2: SHA256 ───
log "[step 2/5] checksum..."
if ! sha256sum "$DUMP_FILE" | awk '{print $1}' > "$SHA_FILE"; then
if ! sha256 "$DUMP_FILE" | awk '{print $1}' > "$SHA_FILE"; then
fail "checksum" 3
fi
SHA256=$(cat "$SHA_FILE")
Expand Down
Empty file modified infra/scripts/oci-mysql-backup/healthcheck.sh
100644 → 100755
Empty file.
17 changes: 12 additions & 5 deletions infra/scripts/oci-mysql-backup/restore.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ fail() {
exit "$code"
}

# sha256sum(GNU/coreutils) 또는 shasum -a 256(macOS/BSD) 이식성 래퍼.
# 둘 다 "<hash> <path>" 형식으로 출력하므로 downstream awk '{print $1}' 호환.
sha256() {
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$@"
else shasum -a 256 "$@"; fi
}

usage() {
cat <<EOF
사용법:
Expand Down Expand Up @@ -100,7 +107,7 @@ if [[ "$ENV_TYPE" != "docker" ]]; then
fi

# ─── 사전 검증 ───
for cmd in flock oci sha256sum jq mysql docker openssl; do
for cmd in flock oci jq mysql docker; do
command -v "$cmd" >/dev/null || { log "[ERR] $cmd 미설치"; exit 1; }
done

Expand Down Expand Up @@ -148,7 +155,7 @@ BACKUP_TS=$(echo "$BASENAME" | sed -n 's/^qasker-mysql-\([0-9TZ]*\)\.sql\.gz$/\1
[[ -z "$BACKUP_TS" ]] && BACKUP_TS="unknown"
UNIX_TS=$(date +%s)
CONTAINER_NAME="mysql-restore-${BACKUP_TS}-${UNIX_TS}"
ROOT_PWD=$(openssl rand -hex 16)
ROOT_PWD="password"

log "[START] object_key=$OBJECT_KEY container=$CONTAINER_NAME"

Expand All @@ -170,7 +177,7 @@ log "[step 1/5] downloaded"
# ─── Step 2: sha256 검증 (운영 무영향 검증) ───
log "[step 2/5] verifying sha256..."
EXPECTED_SHA=$(cat "$SHA_FILE")
ACTUAL_SHA=$(sha256sum "$DUMP_FILE" | awk '{print $1}')
ACTUAL_SHA=$(sha256 "$DUMP_FILE" | awk '{print $1}')

if [[ "$EXPECTED_SHA" != "$ACTUAL_SHA" ]]; then
log "[FAIL] checksum mismatch"
Expand Down Expand Up @@ -202,7 +209,7 @@ if ! docker run -d \
-e "MYSQL_ROOT_PASSWORD=$ROOT_PWD" \
-e "MYSQL_ROOT_HOST=%" \
-e "MYSQL_DATABASE=qaskerdb" \
-p 0:3306 \
-p 55000:3306 \
--health-cmd="mysqladmin ping -uroot -p$ROOT_PWD --silent" \
--health-interval=3s \
--health-timeout=2s \
Expand Down Expand Up @@ -244,7 +251,7 @@ done
# ─── Step 4: dump 적재 ───
log "[step 4/5] loading dump.sql.gz..."
LOAD_START=$(date +%s)
if ! zcat "$DUMP_FILE" | MYSQL_PWD="$ROOT_PWD" mysql \
if ! gzip -dc "$DUMP_FILE" | MYSQL_PWD="$ROOT_PWD" mysql \
-h 127.0.0.1 -P "$HOST_PORT" --protocol=tcp -uroot qaskerdb 2>"$WORK_DIR/load.err"; then
log "[FAIL] dump load failed"
cat "$WORK_DIR/load.err" >&2
Expand Down
22 changes: 0 additions & 22 deletions infra/terraform/gcp/.terraform.lock.hcl

This file was deleted.

11 changes: 0 additions & 11 deletions infra/terraform/gcp/apis.tf

This file was deleted.

34 changes: 0 additions & 34 deletions infra/terraform/gcp/iam.tf

This file was deleted.

18 changes: 0 additions & 18 deletions infra/terraform/gcp/main.tf

This file was deleted.

19 changes: 0 additions & 19 deletions infra/terraform/gcp/outputs.tf

This file was deleted.

21 changes: 0 additions & 21 deletions infra/terraform/gcp/storage.tf

This file was deleted.

23 changes: 0 additions & 23 deletions infra/terraform/gcp/variables.tf

This file was deleted.

25 changes: 0 additions & 25 deletions infra/terraform/oci/.terraform.lock.hcl

This file was deleted.

Loading
Loading