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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ WhyLog 모노레포에서 개발자와 AI 에이전트가 따라야 하는 공

- [Architecture](docs/architecture.md): AI·Server·Web 연결 구조와 서비스 흐름
- [Domain](docs/domain.md): 공통 용어와 비즈니스 규칙
- [Decisions](docs/decisions/README.md): 월별 회의 결정 기록 인덱스
- [Decisions](docs/decisions/README.md): 회의에서 확정된 결정 사항, `YYYY-MM.md`로 월별 관리
- [PR Reviews](docs/pr-reviews/README.md): PR별 CI 리뷰 기록 형식과 조회 규칙

## 저장소 구조
Expand All @@ -32,7 +32,7 @@ WhyLog 모노레포에서 개발자와 AI 에이전트가 따라야 하는 공
- 각 파트에 문서를 추가하거나 경로를 변경하면 해당 파트의 문서 목차도 함께 갱신합니다.
- 파트 문서 구성이 변경되면 루트의 파트별 문서 인덱스도 함께 갱신합니다.
- 파트 목차와 루트 인덱스 중 하나만 누락된 경우 기록성 수정으로 보고 바로 PR로 반영합니다.
- 회의에서 확정된 결정은 `docs/decisions/YYYY/MM/decisions.md`에 월 단위로 기록합니다. 해당 월 파일이 없을 때만 새로 만들고 `docs/decisions/README.md` 인덱스를 갱신합니다.
- 회의에서 확정된 결정은 `docs/decisions/YYYY-MM.md`에 월 단위로 기록합니다. 해당 월 파일이 없을 때만 새로 만들고 `docs/decisions/README.md` 인덱스를 갱신합니다.
- `docs/pr-reviews/`는 규칙이 아닌 실행 기록입니다. 에이전트는 현재 작업과 관련된 PR 문서만 선택해서 읽습니다.
- AI가 회의 녹음에서 뽑은 초안은 그대로 머지하지 않습니다. 기록 담당이 결정만 남기고 서술·요약·배경 설명을 걷어낸 뒤 PR을 올립니다. 월별 `decisions.md`에는 결정 한 줄과 날짜만 들어갑니다.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Decisions

회의에서 확정된 주요 결정 사항과 변경 이유를 기록합니다.
# Decisions 2026-07

## 2026-07-29

Expand Down
17 changes: 17 additions & 0 deletions docs/decisions/2026-08.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Decisions 2026-08

## 2026-08-09

- 기본 브랜치를 `develop`으로 사용한다. `main`은 추후 배포 브랜치로 둔다.
- 작업 단위는 이슈 생성을 강제하지 않고, 브랜치 생성 → PR 생성 → 작업 → 중간 Push → CI/AI 리뷰 → Merge 흐름을 유지한다.
- 커밋 메시지는 `<type>(<scope>): <설명>` 형식을 쓴다. type은 `feat` `fix` `refactor` `docs` `chore` `ci` `style` `test`, scope는 `ai` `server` `web` `docs` `root`이며, 여러 파트를 동시에 바꾸면 scope를 생략한다.
- PR 템플릿에 예상 소요시간과 실제 소요시간을 함께 기록해 평가 지표로 쓴다.
- AI 코드 리뷰는 PR마다 GitHub Actions로 실행하고 PR 코멘트로 확인하며, 리뷰 결과는 `docs`에 PR 단위로도 저장한다.
- AI 리뷰 모델은 우선 무료 모델을 쓰고, 품질이 떨어지면 유료·다른 모델 교체를 다시 논의한다.
- 팀 커뮤니케이션은 슬랙 대신 디스코드를 사용한다.
- 서버는 당장 별도 배포하지 않는다. 로컬 환경에서 진행하고, 필요하면 ngrok으로 임시 공개한다.
- 기획·디자인은 파트 통합하지 않는다. 기존 UI로 처리되는 작은 기능은 AI가 기존 코드·디자인을 참고해 바로 구현하고, 새 페이지나 새 UX가 필요한 큰 기능만 별도로 기획·디자인한다. 디자인 토큰 문서는 보류한다.
- 이번 사이클 기능 고도화 범위를 로그인/마이페이지, 실시간 회의, 결정사항·적용사항 대시보드, 팀+알림 4가지로 정한다. 검색 기능은 보류한다.
- 실시간 회의는 LiveKit 대신 RTC를 직접 구현한다.
- 담당을 상완(로그인/마이페이지), 혜성(실시간 회의), 준용(결정사항·적용사항 대시보드), 윤지(팀+알림)로 배정한다.
- 다음 회의는 2026년 8월 13일(목)로 조율하며, 확정은 카카오톡으로 한다.
3 changes: 2 additions & 1 deletion docs/decisions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

## 2026

- [2026-07](2026/07/decisions.md)
- [2026-07](2026-07.md)
- [2026-08](2026-08.md)
35 changes: 35 additions & 0 deletions docs/pr-reviews/PR-10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# PR-10 AI 리뷰 기록

- PR: https://github.com/WhyLog-App/WhyLog/pull/10
- 제목: Docs/decisions
- 브랜치: `develop` ← `docs/decisions`
- HEAD: `e8ce08c947891eba660d20b8aa950a04219637ed`
- 입력 digest: `89db636a51cd53ba5e00ecebd19b353586b6336516010b821f88fe57476cf16d`
- 모델: Google `gemini-3.6-flash`
- 상태: **PASS**
- 생성 시각(UTC): 2026-08-09T16:43:35+00:00

## 요약

회의 결정 기록 문서의 경로 구조 정리(YYYY-MM.md) 및 2026-08 결정 사항 반영, 서버 로컬 개발을 위한 Docker Compose 및 환경변수 검사 스크립트 추가 변경입니다. 주요 규칙 위반이나 차단 요소는 없습니다.

## 이번 실행에서 새로 발견됨

없음

## 이전 실행부터 계속 남아있음

없음

## 현재까지 사라짐(자동 추정)

없음

## 실행 이력

|HEAD|상태|모델|전체|신규|계속|해결|시각|
|---|---|---|---:|---:|---:|---:|---|
|e8ce08c94789|PASS|Google gemini-3.6-flash|||||2026-08-09T16:43:35+00:00|

<!-- whylog-ai-pr-review-state {"findings":[],"head_sha":"e8ce08c947891eba660d20b8aa950a04219637ed","history":[{"generated_at":"2026-08-09T16:43:35+00:00","head_sha":"e8ce08c947891eba660d20b8aa950a04219637ed","model":"gemini-3.6-flash","new":0,"ongoing":0,"provider":"Google","resolved":0,"status":"PASS","total":0}],"model":"gemini-3.6-flash","pr":{"author":"ggamnunq","base":"develop","head":"docs/decisions","number":10,"title":"Docs/decisions","url":"https://github.com/WhyLog-App/WhyLog/pull/10"},"provider":"Google","resolved":[],"review_input_digest":"89db636a51cd53ba5e00ecebd19b353586b6336516010b821f88fe57476cf16d","schema":1,"status":"PASS","summary":"회의 결정 기록 문서의 경로 구조 정리(YYYY-MM.md) 및 2026-08 결정 사항 반영, 서버 로컬 개발을 위한 Docker Compose 및 환경변수 검사 스크립트 추가 변경입니다. 주요 규칙 위반이나 차단 요소는 없습니다."} -->
<!-- whylog-ai-pr-review-signature 8a671d7b33807b96c59072863094b55ec004cd74dad6c411538973af4b8827fc -->
44 changes: 44 additions & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# docker-compose.yml이 읽는 값 (MySQL/Redis 컨테이너 자체 설정)
MYSQL_DATABASE=whylog
MYSQL_USER=whylog
MYSQL_PASSWORD=whylog
MYSQL_ROOT_PASSWORD=whylog
MYSQL_PORT=3306
REDIS_PORT=6379

# 아래부터는 서버 앱(application.yaml)이 읽는 값
# docker-compose로 띄운 MySQL/Redis에 맞춘 기본값
DEV_DB_URL=jdbc:mysql://localhost:3306/whylog
DEV_DB_USERNAME=whylog
DEV_DB_PASSWORD=whylog

DEV_REDIS_HOST=localhost
DEV_REDIS_PORT=6379
DEV_REDIS_PASSWORD=

CORS_ALLOWED_ORIGINS=http://localhost:3000

# 32자 이상 임의 문자열이면 로컬 구동에는 충분
JWT_SECRET=local-dev-jwt-secret-please-change-32chars
JWT_ACCESS_TOKEN_EXPIRE_TIME=3600000
JWT_REFRESH_TOKEN_EXPIRE_TIME=1209600000

# LiveKit 기능을 실제로 쓰지 않으면 기본값(application.yaml)으로 대체됨
LIVEKIT_URL=wss://example.livekit.invalid
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=01234567890123456789012345678901

# 32바이트(AES-256) 키. 로컬 구동용 예시이며 실제 값은 담당자에게 문의
GITHUB_TOKEN_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef

# S3 업로드 기능을 실제로 쓰지 않으면 더미값으로도 앱은 기동됨
AWS_S3_BUCKET=whylog-dev-bucket
AWS_REGION=ap-northeast-2
AWS_S3_ACCESS_KEY=dummy
AWS_S3_SECRET_KEY=dummy

# Ubuntu/WSL: /usr/bin/ffprobe, macOS(Homebrew): /opt/homebrew/bin/ffprobe
AUDIO_FFPROBE_COMMAND=/opt/homebrew/bin/ffprobe

# AI 서버(FastAPI) 주소. 로컬에서 ai/ 서비스를 함께 띄운 경우의 주소
FAST_API_BASE_URL=http://localhost:8000
59 changes: 58 additions & 1 deletion server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
- API Docs: Swagger (springdoc-openapi)
- Logging: Log4j2
- Build Tool: Gradle
- Deploy: AWS <!-- Docker · GitHub Actions 사용 시 추가 -->
- Deploy: AWS
- Local Dev: Docker Compose (MySQL, Redis)


## 서버 아키텍처
Expand All @@ -48,6 +49,62 @@
- Swagger UI: `/swagger-ui/index.html` (springdoc-openapi)


## 실행 방법

두 방법 모두 서버 앱 자체는 로컬에서 `./gradlew bootRun`으로 실행합니다. 차이는 MySQL/Redis를 어떻게 붙이느냐입니다.

```bash
cp .env.example .env
# .env를 열어 값 채우기 (JWT_SECRET, GITHUB_TOKEN_ENCRYPTION_KEY, AWS_*, FAST_API_BASE_URL 등)
# 실제 기능(S3 업로드·GitHub 연동·LiveKit)을 안 쓸 거면 .env.example의 더미값 그대로 둬도 서버는 기동됩니다.
```

### 1) Docker Compose로 실행

로컬에 MySQL/Redis를 직접 설치하지 않고 컨테이너로 띄웁니다.

```bash
./scripts/dev.sh
```

`dev.sh`는 먼저 `.env`의 필수 값이 채워졌는지 검사하고(`scripts/check-env.sh`), 통과하면 `docker compose up -d`로 MySQL(3306)·Redis(6379)를 기동한 뒤 `.env` 값을 환경변수로 로드해 `./gradlew bootRun`을 실행합니다. 필수 값이 비어 있으면 어떤 변수인지 출력하고 종료합니다. 각 단계를 직접 실행하려면:

```bash
docker compose up -d --wait # MySQL(3306), Redis(6379) 기동 후 healthy가 될 때까지 대기
set -a; source .env; set +a # .env 값을 환경변수로 로드 (zsh/bash)
./gradlew bootRun
```

- 종료: `docker compose down` (데이터를 지우려면 `docker compose down -v`)
- `.env.example`의 `DEV_DB_URL`, `DEV_REDIS_HOST` 등은 이 compose 설정에 맞춰져 있어 그대로 쓰면 됩니다.

### 2) Docker 없이 실행

로컬에 MySQL 8, Redis를 직접 설치해 기동하거나(예: `brew install mysql redis`), 팀이 공유하는 개발용 DB/Redis에 접속합니다.

```bash
# 예: 로컬 설치 시
brew install mysql redis ffmpeg # ffprobe는 오디오 길이 분석에 필요
brew services start mysql
brew services start redis
```

- `.env`의 `DEV_DB_URL`, `DEV_DB_USERNAME`, `DEV_DB_PASSWORD`, `DEV_REDIS_HOST`, `DEV_REDIS_PORT`, `DEV_REDIS_PASSWORD`를 실제 접속 정보로 맞춥니다.
- `AUDIO_FFPROBE_COMMAND`를 로컬 ffprobe 경로로 맞춥니다 (macOS Homebrew 기준 기본값은 `/opt/homebrew/bin/ffprobe`).

```bash
./scripts/check-env.sh # 필수 값이 채워졌는지 검사
set -a; source .env; set +a
./gradlew bootRun
```

IntelliJ를 쓴다면 터미널 대신 아래처럼 실행해도 됩니다.

1. `Run` → `Edit Configurations` → `ServerApplication`의 `Environment variables`에서 값을 채웁니다.
- 직접 하나씩 입력하거나, 옆의 폴더 아이콘(`Paste`/`파일 아이콘`)으로 `.env` 파일을 그대로 불러와도 됩니다.
2. `ServerApplication.java`를 열고 상단(또는 좌측) 실행 버튼을 누르면 됩니다.


## 프로젝트 구조
#### 도메인형
- 각 도메인 패키지는 엔티티, DTO, 컨트롤러, 서비스, 리포지토리 등 하위 패키지를 포함
Expand Down
37 changes: 37 additions & 0 deletions server/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: whylog-server

services:
mysql:
image: mysql:8.0
container_name: whylog-mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE:-whylog}
MYSQL_USER: ${MYSQL_USER:-whylog}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-whylog}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-whylog}
TZ: Asia/Seoul
ports:
- "${MYSQL_PORT:-3306}:3306"
volumes:
- whylog-mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10

redis:
image: redis:7
container_name: whylog-redis
restart: unless-stopped
ports:
- "${REDIS_PORT:-6379}:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10

volumes:
whylog-mysql-data:
48 changes: 48 additions & 0 deletions server/scripts/check-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# .env에 필수 값이 채워졌는지 검사합니다. dev.sh가 자동으로 호출하며, 단독 실행도 가능합니다.
set -euo pipefail
cd "$(dirname "$0")/.."

if [ ! -f .env ]; then
echo ".env가 없습니다. cp .env.example .env 로 만든 뒤 값을 채워주세요." >&2
exit 1
fi

set -a
source .env
set +a

# application.yaml에서 기본값(:) 없이 필수로 요구하는 값만 검사합니다.
# DEV_REDIS_PASSWORD는 필수지만 로컬 Redis에 비밀번호가 없으면 빈 값이 정상이라 제외합니다.
REQUIRED_VARS=(
DEV_DB_URL
DEV_DB_USERNAME
DEV_DB_PASSWORD
DEV_REDIS_HOST
DEV_REDIS_PORT
CORS_ALLOWED_ORIGINS
JWT_SECRET
GITHUB_TOKEN_ENCRYPTION_KEY
AWS_S3_BUCKET
AWS_S3_ACCESS_KEY
AWS_S3_SECRET_KEY
FAST_API_BASE_URL
)

missing=()
for name in "${REQUIRED_VARS[@]}"; do
value="${!name:-}"
if [ -z "$value" ]; then
missing+=("$name")
fi
done

if [ "${#missing[@]}" -gt 0 ]; then
echo ".env에 아래 필수 값이 비어 있습니다:" >&2
for name in "${missing[@]}"; do
echo " - $name" >&2
done
exit 1
fi

echo "필수 환경변수 확인 완료."
14 changes: 14 additions & 0 deletions server/scripts/dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Docker Compose로 MySQL/Redis를 띄우고 .env를 로드한 뒤 서버를 실행합니다.
set -euo pipefail
cd "$(dirname "$0")/.."

./scripts/check-env.sh

docker compose up -d --wait

set -a
source .env
set +a

exec ./gradlew bootRun