diff --git a/.claude/rules/checklist.md b/.claude/rules/checklist.md index 412b2dd..21c2ea3 100644 --- a/.claude/rules/checklist.md +++ b/.claude/rules/checklist.md @@ -14,6 +14,7 @@ - [ ] 프로젝트 식별 값 교체 (`PROJECT_NAME` 등 루트 env 키) - [ ] 의존성 설치: `cd backend && npm ci`, `cd frontend && npm ci`, `cd flutter && flutter pub get` - [ ] Docker 개발 환경 기동으로 동작 확인 ([[docker]]) + (Redis 는 기본 비활성이다 — 필요하면 루트 `.env` 에 `COMPOSE_PROFILES=redis`) ## 2. 커밋 전 공통 점검 (매 작업) diff --git a/.claude/skills/docker/SKILL.md b/.claude/skills/docker/SKILL.md index de7accf..76d24f5 100644 --- a/.claude/skills/docker/SKILL.md +++ b/.claude/skills/docker/SKILL.md @@ -76,6 +76,28 @@ dc exec redis redis-cli -a --- +## 선택적 서비스 (Redis) + +**Redis 는 기본적으로 기동하지 않는다.** 단일 인스턴스에서는 in-memory 캐시로 충분하고, +쓰지 않는 컨테이너는 메모리만 차지하며 혼란을 준다. + +```bash +# 켜기 — 루트 .env.{APP_ENV} 한 줄 수정 (이후 평소 명령 그대로) +COMPOSE_PROFILES=redis + +# 또는 일회성 +dc --profile redis up -d +``` + +- compose `profiles: ["redis"]` 로 숨겨져 있고, backend 의 의존성은 `required: false` 라 + Redis 가 없어도 정상 기동한다. +- 데이터 볼륨(`${REDIS_DATA_DIR}`)과 `REDIS_*` 환경변수는 그대로 유지되므로, + 켜면 이전 데이터와 설정이 그대로 이어진다. +- **애플리케이션 코드는 아직 Redis 를 사용하지 않는다.** 실제 연결 절차는 [[nestjs]] 참조. +- 끝까지 쓰지 않을 프로젝트라면 compose 에서 redis 서비스와 관련 env 를 지우는 편이 낫다. + +--- + ## 규칙 - **빌드 최소화**: 의존성(package.json / pubspec 등) 변경이 없으면 `--build` 없이 기동한다. diff --git a/.claude/skills/nestjs/SKILL.md b/.claude/skills/nestjs/SKILL.md index 83a7226..4e08c82 100644 --- a/.claude/skills/nestjs/SKILL.md +++ b/.claude/skills/nestjs/SKILL.md @@ -202,16 +202,17 @@ SwaggerModule.setup('api-docs', app, document); ## 성능 & 최신 트렌드 추가 규칙 - **캐싱**: `@nestjs/cache-manager` 가 전역 등록되어 있으나 **현재 저장소는 in-memory** 다. - > 📐 **Redis 는 확장 지점이다.** compose 에 redis 컨테이너가 뜨고 `REDIS_HOST`/`REDIS_PORT`/`REDIS_PASSWORD` 가 - > 백엔드로 주입되지만, **아직 이를 사용하는 코드는 없다.** 단일 인스턴스에서는 in-memory 로 충분하다. + > 📐 **Redis 는 확장 지점이다.** compose 에서 **기본 비활성**(profile)이며 애플리케이션도 사용하지 않는다. + > 단일 인스턴스에서는 in-memory 로 충분하다. > > Redis 가 실제로 필요해지는 시점(다중 인스턴스 운영, 세션·캐시 공유, 분산 락)에 연결한다: + > 0. 컨테이너 활성화 — 루트 `.env` 에 `COMPOSE_PROFILES=redis` ([[docker]]) > 1. Redis store 패키지 설치 (**컨테이너 안에서** — 위 의존성 주의 항목 참조) > 2. `app.module.ts` 의 `CacheModule.register` 를 `registerAsync` + Redis store 로 교체 > 3. `modules/health` 에 Redis 인디케이터 추가 (지금은 DB 만 검사한다) > 4. 연결 실패 시 앱이 죽지 않도록 폴백 전략을 정한다 > - > 끝까지 쓰지 않을 프로젝트라면 compose 에서 redis 서비스를 빼는 편이 낫다 — 쓰지 않는 컨테이너는 혼란만 준다. + > 끝까지 쓰지 않을 프로젝트라면 compose 에서 redis 서비스와 관련 env 를 지우는 편이 낫다. - **Rate Limiting**: `@nestjs/throttler` 로 일원화 (`app.module.ts` 의 `APP_GUARD`). 초과 시 429 → `REQ_001`. 라우트 단위 조정은 `@Throttle({ default: { ttl, limit } })`, 제외는 `@SkipThrottle()` (헬스체크에 적용되어 있다). **rate limiter 를 중복으로 추가하지 말 것** ([[security]]) diff --git a/.env.development.example b/.env.development.example index 22890f3..3a7a2f5 100644 --- a/.env.development.example +++ b/.env.development.example @@ -53,3 +53,13 @@ THROTTLE_LIMIT=100 # (운영 환경에서는 이 값과 무관하게 항상 비활성화된다) # ========================================== DB_SYNCHRONIZE=false + +# ========================================== +# 선택적 서비스 (Compose profiles) +# +# 기본값(비어 있음) = redis 를 기동하지 않는다. +# 캐시·세션 공유가 필요해지면 아래를 redis 로 바꾸면 컨테이너가 함께 뜬다. +# COMPOSE_PROFILES=redis +# 일회성으로 켜려면: docker compose --profile redis ... up -d +# ========================================== +COMPOSE_PROFILES= diff --git a/.env.production.example b/.env.production.example index 92ead9e..70920c7 100644 --- a/.env.production.example +++ b/.env.production.example @@ -53,3 +53,13 @@ THROTTLE_LIMIT=100 # (운영 환경에서는 이 값과 무관하게 항상 비활성화된다) # ========================================== DB_SYNCHRONIZE=false + +# ========================================== +# 선택적 서비스 (Compose profiles) +# +# 기본값(비어 있음) = redis 를 기동하지 않는다. +# 캐시·세션 공유가 필요해지면 아래를 redis 로 바꾸면 컨테이너가 함께 뜬다. +# COMPOSE_PROFILES=redis +# 일회성으로 켜려면: docker compose --profile redis ... up -d +# ========================================== +COMPOSE_PROFILES= diff --git a/README.md b/README.md index 159735c..5ce1086 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ NestJS(백엔드) · Vue 3(웹) · Flutter(모바일)를 하나의 저장소에 | `frontend/` | Vue 3 + Vite | 웹 프론트엔드 | 5173 | | `flutter/` | Flutter + Riverpod | 모바일 앱 | - | | `db` | PostgreSQL | 데이터베이스 | 5432 | -| `redis` | Redis | 캐시 / 세션 | 6379 | +| `redis` | Redis | 캐시 / 세션 (**기본 비활성**) | 6379 | ## 사전 요구사항 @@ -41,6 +41,8 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.d - API: - Swagger 문서: +> Redis 는 기본적으로 뜨지 않습니다. 필요해지면 루트 `.env.{env}` 에 `COMPOSE_PROFILES=redis` 를 설정하세요. + 전체 실행/배포 명령어는 [`.claude/skills/docker/SKILL.md`](./.claude/skills/docker/SKILL.md) 참조. ## 모바일 앱 실행 (Flutter) diff --git a/docker-compose.yml b/docker-compose.yml index 7e8de0a..6e4082c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -73,8 +73,10 @@ services: depends_on: db: condition: service_healthy + # redis 는 profile 로 비활성화될 수 있으므로 선택적 의존으로 둔다 redis: condition: service_healthy + required: false healthcheck: # localhost 는 컨테이너 안에서 ::1 로 먼저 해석되는데 Node 는 0.0.0.0(IPv4) 바인딩이므로 127.0.0.1 을 명시한다 test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:${BACKEND_PORT}/ || exit 1"] @@ -120,9 +122,14 @@ services: - "com.centurylinklabs.watchtower.enable=true" # ---------------------------------------- - # 4. Redis — 내부 네트워크 전용 + # 4. Redis — 내부 네트워크 전용 · 기본 비활성 + # + # 기본적으로 기동하지 않는다. 캐시/세션 공유가 실제로 필요해질 때 켠다. + # 루트 .env.{APP_ENV} 에서 COMPOSE_PROFILES=redis + # 또는 일회성으로 docker compose --profile redis up -d # ---------------------------------------- redis: + profiles: ["redis"] container_name: ${PROJECT_NAME}-redis image: ${REDIS_IMAGE} command: redis-server --requirepass ${REDIS_PASSWORD}