diff --git a/CLAUDE.md b/CLAUDE.md index 3bd5311..9d8f360 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -99,7 +99,6 @@ - **새 설정값은 루트 `.env.{APP_ENV}` 에 먼저 추가**하고, 필요한 서비스에 `docker-compose.yml` 의 `environment` / `args` 로 전달한다. - 서비스 자체 env 파일에는 **루트에서 내려주지 않는 고유 값만** 작성한다. (예: 백엔드 `JWT_SECRET`) - `docker-compose.yml` 의 `env_file` 지시자 때문에 `backend/.env.{APP_ENV}` 파일은 비어 있어도 **존재해야 한다.** -- **단독 실행(non-Docker)** 시에는 주입이 없으므로, 각 서비스 `.env.{APP_ENV}` 의 주석 처리된 예시 값을 활성화해 사용한다. - **Flutter 는 예외** — docker-compose 대상이 아니므로 `flutter/.env` 에서 `API_URL` 을 독립적으로 관리한다. - 모든 env 파일은 커밋 금지, `*.example` 만 커밋한다. (`.gitignore` 의 `!*.example` 재포함 규칙) diff --git a/README.md b/README.md index 3524d4a..2af0879 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ NestJS(백엔드) · Vue 3(웹) · Flutter(모바일)를 하나의 저장소에 ## 사전 요구사항 -- Docker / Docker Compose (권장 구동 방식) -- 단독 실행 시: Node.js `^20.19 || >=22.12`, Flutter SDK `^3.11` +- Docker / Docker Compose +- 모바일 앱(선택): Flutter SDK `^3.11` ## 빠른 시작 (Docker) @@ -26,7 +26,6 @@ NestJS(백엔드) · Vue 3(웹) · Flutter(모바일)를 하나의 저장소에 # backend/frontend 는 docker-compose 가 값을 주입하므로 예제만 복사하면 된다. cp .env.development.example .env.development # ← 여기에만 값 입력 cp backend/.env.development.example backend/.env.development # (존재만 필요, 내용 최소) -cp frontend/.env.development.example frontend/.env.development # (단독 실행 시에만 사용) # 2) 개발 환경 기동 (코드만 수정 시) docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.development up -d @@ -43,21 +42,8 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.d 전체 실행/배포 명령어는 [`command.md`](./command.md) 참조. -## 단독 실행 (Docker 미사용) - -```bash -# 백엔드 -cd backend && npm install && npm run start:dev - -# 프론트엔드 -cd frontend && npm install && npm run dev - -# 모바일 -cd flutter && cp .env.example .env && flutter pub get && flutter run -``` - -> 단독 실행 시 백엔드 `.env.development` 의 `DB_HOST`/`REDIS_HOST` 를 `localhost` 로 두고, -> PostgreSQL·Redis 를 별도로 띄워야 합니다. +> 모바일 앱은 docker-compose 대상이 아니므로 별도로 실행합니다: +> `cd flutter && cp .env.example .env && flutter pub get && flutter run` ## 환경변수 @@ -70,7 +56,7 @@ cd flutter && cp .env.example .env && flutter pub get && flutter run | ----------------------------- | ---------------------------------------- | --------------------- | | `.env.{env}.example` | 루트 — 모든 설정의 SSOT (compose 주입) | ✅ 여기에 작성 | | `backend/.env.{env}.example` | 백엔드 — 고유 시크릿(JWT 등)만 | 최소 (존재 필수) | -| `frontend/.env.{env}.example` | 프론트 — 단독 실행용 `VITE_API_BASE_URL` | 단독 실행 시에만 | +| `frontend/.env.{env}.example` | 프론트 — 값 없음(compose 가 build arg 주입) | 작성 불필요 | | `flutter/.env.example` | 모바일 — `API_URL` (compose 비대상) | ✅ 독립 관리 | `{env}` = `development` | `production` diff --git a/docs/integration-progress.md b/docs/integration-progress.md index 22ea01f..f641bf8 100644 --- a/docs/integration-progress.md +++ b/docs/integration-progress.md @@ -254,7 +254,7 @@ **스택**: `@nestjs/cache-manager@3` + `cache-manager@6`(Keyv 기반) → Redis 연결은 신규 의존성 **`@keyv/redis`**. docker-compose 가 이미 redis 컨테이너 + `REDIS_HOST/PORT/PASSWORD` 주입. **백엔드** -- **CacheModule → Redis 전환**(`app.module.ts` `registerAsync`): `REDIS_HOST` 있으면 `createKeyv(redis://…)` 스토어, **없으면 인메모리 폴백**(단독 실행/테스트). keyv `error` 이벤트를 흡수해 Redis 장애가 프로세스를 죽이지 않음(캐시 미스→DB 폴백). 기본 TTL 60초. +- **CacheModule → Redis 전환**(`app.module.ts` `registerAsync`): `REDIS_HOST` 있으면 `createKeyv(redis://…)` 스토어, **없으면 인메모리 폴백**(REDIS_HOST 미설정 시). keyv `error` 이벤트를 흡수해 Redis 장애가 프로세스를 죽이지 않음(캐시 미스→DB 폴백). 기본 TTL 60초. - **저장소 목록 캐싱**(`GET /repos`): 신규 `RepoCacheService`(repo 모듈) — **버전 네임스페이스 무효화**. 키 `repos:list:v{ver}:p{page}:s{size}`, 변경 시 `repos:list:ver` 증가로 기존 키 일괄 폐기(keyv 와일드카드 삭제 미지원 회피). 모든 캐시 접근은 try/catch 로 실패 시 DB 조회 폴백. - **무효화 지점**: RepoService 생성/수정/삭제 + RepoSyncService 동기화 + **MemberService 초대/제거**(목록 카드 멤버 수·아바타 반영, 역할 변경은 목록 불변이라 제외 — *2026-06-19 보강*). `RepoCacheService` 공유. - **보강(2026-06-19, 검토 [`redis-cache-review.md`](./redis-cache-review.md))**: ① C1 멤버 변경 무효화, ② 기동 시 캐시 모드 로그(Redis/인메모리 가시화), ③ `main.ts` `enableShutdownHooks()` — 종료 시 알림 Redis pub/sub 연결 graceful close(이전엔 훅 미설정으로 `onModuleDestroy` 가 死코드였음). diff --git a/frontend/.env.development.example b/frontend/.env.development.example index 245193e..3199cce 100644 --- a/frontend/.env.development.example +++ b/frontend/.env.development.example @@ -3,8 +3,5 @@ # VITE_ 변수는 docker-compose 가 루트 .env.development 값을 build arg 로 주입한다: # VITE_API_BASE_URL ← BACKEND_API_URL # VITE_AI_TIMEOUT_MS ← AI_TIMEOUT_MS -# 따라서 Docker 로 띄울 땐 이 파일에 작성할 필요가 없다. -# 단독 실행(non-Docker)으로 vite dev 를 띄울 때만 아래 주석을 풀어 사용한다. +# 따라서 이 파일에 별도로 작성할 값은 없다. # ========================================== -# VITE_API_BASE_URL=http://localhost:3100/api -# VITE_AI_TIMEOUT_MS=60000 diff --git a/frontend/.env.production.example b/frontend/.env.production.example index 5d8d33f..1a11326 100644 --- a/frontend/.env.production.example +++ b/frontend/.env.production.example @@ -3,8 +3,5 @@ # VITE_ 변수는 docker-compose 가 루트 .env.production 값을 build arg 로 주입한다: # VITE_API_BASE_URL ← BACKEND_API_URL # VITE_AI_TIMEOUT_MS ← AI_TIMEOUT_MS -# 따라서 Docker 로 빌드할 땐 이 파일에 작성할 필요가 없다. -# 단독 빌드(non-Docker)로 vite build 할 때만 아래 주석을 풀어 운영 도메인으로 사용한다. +# 따라서 이 파일에 별도로 작성할 값은 없다. # ========================================== -# VITE_API_BASE_URL=https://your-domain.com/api -# VITE_AI_TIMEOUT_MS=60000