Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
35250c2
[chore/#528] 서브도메인 명시 (#529)
kanghana1 Mar 7, 2026
645a267
[chore/#531] Nginx 설정 파일 수정 (#532)
Dimo-2562 Mar 8, 2026
764ef6f
[Fix/#521] 채팅 이미지/파일 API 통합 및 테스트 코드 작성 (#526)
dbalsk Mar 8, 2026
3e0ec65
[docs/#534] 이슈 템플릿 추가 (#535)
kanghana1 Mar 9, 2026
d9343e6
[chore/#536] FCM 구현을 위한 firebase 의존성 추가 (#537)
kanghana1 Mar 11, 2026
faba49e
fix: 테스트 이슈 라벨링 파싱 문제 해결
Dimo-2562 Mar 11, 2026
141c4ee
[test/#516] Member 테스트코드 작성 (#533)
kanghana1 Mar 11, 2026
73d71d1
[test/#538] 운동 신청/취소, 게스트 초대/취소 API 테스트 작성 (#539)
Dimo-2562 Mar 11, 2026
4c71961
[feat/#540] FCM 의존성 추가 및 알림 기능 구현 (#541)
kanghana1 Mar 15, 2026
3c6d706
[feat/#540] Firebase 주입방식 변경 (#542)
kanghana1 Mar 15, 2026
46a802a
[feat/#540] firebase 환경변수 주입방식으로 변경, docker-compose파일 수정 (#543)
kanghana1 Mar 15, 2026
a7eeaef
[debug/#544] 모임 추천 조회 (콕플 추천 모드) 검색 기능 누락 해결
dbalsk Mar 17, 2026
fb3729f
[debug/#547] 프로필 이름 변경 시 내 채팅방 목록이 전부 내 이름으로 변경되는 버그 (#548)
Dimo-2562 Mar 22, 2026
5af1ffe
[feat/#546] Flyway 도입을 위한 설정 추가 (#549)
kanghana1 Mar 23, 2026
32460d3
[fix/#552] 모임 채팅방 멤버 누락 데이터 보정 (#553)
Dimo-2562 Mar 24, 2026
c09f030
docs: 오픈코드 사용을 위한 .md 파일 추가 (#555)
Dimo-2562 Mar 24, 2026
7b49c30
[test/#518] Bookmark 테스트코드 작성 (#556)
kanghana1 Mar 27, 2026
7215552
[test/#551] 운동 Query 테스트 코드 작성 (#557)
Dimo-2562 Mar 28, 2026
d3e14f7
[test/#517] Notification 단위테스트 및 통합테스트 코드 작성 (#559)
kanghana1 Apr 1, 2026
e331d3d
[test/#519] 모임 도메인 테스트코드 작성 (#558)
dbalsk Apr 2, 2026
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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/기능-구현.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: 기능 구현
about: '기능 설명 및 구현 '
title: "[FEAT]"
title: "[FEAT] "
labels: "\U0001F6E0️ FEAT"
assignees: ''

Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/기능-수정.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: 기능 수정
about: 리팩토링 목적이 아닌 기능 수정
title: "[FIX} "
title: "[FIX] "
labels: "\U0001F527 FIX"
assignees: ''

Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/기타-수정.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: 기타 수정
about: '작은 부분 수정 '
title: "[CHORE]"
title: "[CHORE] "
labels: "\U0001F3B5 CHORE"
assignees: ''

Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/문서-작업-.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: '문서 작업 '
about: 문서작업 내용
title: ''
title: '[Docs] '
labels: "\U0001F4DC DOC"
assignees: ''

Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/오류수정.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: 오류수정
about: '오류 설명 및 수정 '
title: "[DEBUG]"
title: "[DEBUG] "
labels: "\U0001F577️ BUG"
assignees: ''

Expand Down
12 changes: 12 additions & 0 deletions .github/ISSUE_TEMPLATE/테스트-작성.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: '테스트 작성'
about: 테스트 코드 작성
title: '[Test] '
labels: "🧪 TEST"
assignees: ''

---

## 🔑 테스트 내용

<br>
28 changes: 28 additions & 0 deletions .github/workflows/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# WORKFLOWS GUIDE

Apply root `AGENTS.md` first. This file only applies to `.github/workflows/*` edits.

## OVERVIEW
This directory drives CI on pull requests and CD on pushes to `develop` and `main`.

## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| PR build/test | `ci.yml` | writes `application.yml`, creates Firebase key, runs `./gradlew build` |
| Image build + deploy | `cd.yml` | builds on push, tags by branch, then copies compose/nginx/scripts to server |

## CONVENTIONS
- `develop` and `main` are the only workflow branches here.
- `ci.yml` chooses `APPLICATION` vs `APPLICATION_STAGING` by `github.base_ref`.
- `cd.yml` chooses Docker tag `latest` for `main`, `staging` otherwise.
- Deploy step assumes `/home/ubuntu/cockple` and hands off to `scripts/deploy.sh`.

## ANTI-PATTERNS
- Do not hardcode secrets into workflow YAML.
- Do not change copied deploy assets in `cd.yml` without matching script/compose expectations.
- Do not make `main` and `develop` diverge silently; branch-specific behavior is intentionally small and explicit.

## COMMANDS
```bash
./gradlew.bat build
```
4 changes: 3 additions & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
else
echo "DOCKER_TAG=staging" >> $GITHUB_OUTPUT
fi


- name: Build with Gradle
run: |
Expand Down Expand Up @@ -71,7 +72,7 @@ jobs:
envs: >-
DB_PASSWORD,GCS_BUCKET,
KAKAO_CLIENT_ID,KAKAO_CLIENT_SECRET,KAKAO_REDIRECT_URI_PROD,KAKAO_REDIRECT_URI_STAGING,KAKAO_ADMIN_KEY,
JWT_SECRET_KEY
JWT_SECRET_KEY,FIREBASE_SERVICE_ACCOUNT_KEY
script: |
chmod +x /home/ubuntu/cockple/scripts/deploy.sh
bash /home/ubuntu/cockple/scripts/deploy.sh \
Expand All @@ -86,3 +87,4 @@ jobs:
KAKAO_REDIRECT_URI_STAGING: ${{ secrets.KAKAO_REDIRECT_URI_STAGING }}
KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }}
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
FIREBASE_SERVICE_ACCOUNT_KEY: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY }}
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
echo "${{ secrets.APPLICATION_STAGING }}" > src/main/resources/application.yml
fi

- name: Create Firebase Key File
run: |
mkdir -p src/main/resources/firebase
echo '${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY }}' > src/main/resources/firebase/cockple-1a83e-firebase-adminsdk-fbsvc-212ce01565.json

- name: Grant execute permission for Gradle
run: chmod +x gradlew

Expand Down
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,11 @@ application-dev.yml
terraform/.terraform/
terraform/terraform.tfstate
terraform/terraform.tfstate.backup
terraform/terraform.tfvars
terraform/terraform.tfvars

### firebase ###
src/main/resources/firebase/*.json

### Claude / OMC ###
.claude/
.omc/
84 changes: 84 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# PROJECT KNOWLEDGE BASE

**Generated:** 2026-03-23 20:04 KST
**Commit:** 5af1ffe6
**Branch:** develop

## OVERVIEW
Cockple_BE is a single-module Spring Boot 3.5.9 backend for the Cockple badminton platform. Core stack: Java 17, JPA + QueryDSL, MySQL, Redis, JWT/Kakao OAuth, WebSocket chat, Firebase FCM, Flyway, Docker Compose, and Terraform-managed GCP/Cloudflare infra.

Nearest `AGENTS.md` wins. Read this file first, then the closest child file for the area you are changing.

## STRUCTURE
```text
./
├── .github/workflows/ # CI/CD entrypoint
├── scripts/ # deploy and SSH tunnel helpers
├── terraform/ # GCP + Cloudflare infra
├── nginx/ # reverse proxy for prod/staging apps
├── src/main/java/umc/cockple/demo/domain/ # business slices
├── src/main/java/umc/cockple/demo/global/ # cross-cutting infra
├── src/main/resources/ # Spring profiles + Flyway
├── src/main/generated/ # generated QueryDSL Q-types
└── src/test/java/umc/cockple/demo/ # integration/service tests + fixtures
```

## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| App bootstrap | `src/main/java/umc/cockple/demo/Application.java` | Enables JPA auditing and caching |
| Runtime config | `src/main/resources/application*.yml` | `local` is default; `staging` and `prod` override DB/Redis |
| Security/websocket ingress | `src/main/java/umc/cockple/demo/global/config/` | JWT, CORS, WebSocket handler registration |
| Business APIs | `src/main/java/umc/cockple/demo/domain/` | Vertical slices by feature |
| Exercise hotspot | `src/main/java/umc/cockple/demo/domain/exercise/` | Largest converter/query/test surface |
| Chat hotspot | `src/main/java/umc/cockple/demo/domain/chat/` | REST + WebSocket + cache/event flow |
| Shared infra | `src/main/java/umc/cockple/demo/global/` | response, exception, jwt, oauth2, config |
| Test conventions | `src/test/java/umc/cockple/demo/` | shared fixtures + integration base live here |
| Local stack | `docker-compose.yml`, `nginx/`, `scripts/` | prod/staging services share one compose file |
| CI/CD | `.github/workflows/` | PR builds on `develop`/`main`; push deploys by branch |
| Infra changes | `terraform/` | GCP compute/network/storage + Cloudflare |

## CONVENTIONS
- Domain code is organized as feature slices, not horizontal layers across the repo.
- Controllers usually return `BaseResponse` or `ResponseEntity<BaseResponse<...>>`.
- Error codes are per-domain enums and use a documented `1xx/2xx/3xx/4xx` meaning split.
- `application.yml` enforces `ddl-auto: validate`; schema changes belong in Flyway under `src/main/resources/db/migration/`.
- QueryDSL generated sources are wired through Gradle; handwritten code lives under `src/main/java`, generated code under `src/main/generated` or `build/generated/...`.
- Tests split into integration (`MockMvc` + Testcontainers profile) and service/unit (`MockitoExtension`) styles.

## ANTI-PATTERNS (THIS PROJECT)
- Do not edit generated QueryDSL Q-types.
- Do not widen security whitelist or CORS origins casually; both are explicit in `SecurityConfig` and `WebSocketConfig`.
- Do not rely on JPA auto-DDL for schema work; startup uses validation only.
- Do not scatter test fixtures inside feature test packages; shared fixtures already live under `src/test/java/umc/cockple/demo/support/fixture/`.
- Do not assume everything under `global/` is generic; JWT/OAuth code is coupled to member/auth flows.

## UNIQUE STYLES
- `domain/chat` has extra realtime sublayers: `handler/`, `interceptor/`, `events/`, `service/websocket/`.
- `domain/exercise` is the densest slice: large converter, query service, command internals, and the biggest integration tests.
- `domain/party` and `domain/notification` use events/notification wiring more than simpler slices like `bookmark` or `terms`.

## COMMANDS
```bash
./gradlew.bat build
./gradlew.bat test
./gradlew.bat bootRun
docker compose config --services
bash scripts/tunnel.sh <GCP_IP>
```

## CHILD GUIDES
- `.github/workflows/AGENTS.md`
- `scripts/AGENTS.md`
- `terraform/AGENTS.md`
- `src/main/java/umc/cockple/demo/domain/AGENTS.md`
- `src/main/java/umc/cockple/demo/domain/chat/AGENTS.md`
- `src/main/java/umc/cockple/demo/domain/exercise/AGENTS.md`
- `src/main/java/umc/cockple/demo/global/AGENTS.md`
- `src/main/java/umc/cockple/demo/global/config/AGENTS.md`
- `src/test/java/umc/cockple/demo/AGENTS.md`

## NOTES
- CI writes `src/main/resources/application.yml` from GitHub secrets before building.
- CD copies only `docker-compose.yml`, `init-db.sql`, `nginx/`, and `scripts/` to the server; deploy behavior lives in both workflow and shell script.
- Local profile expects MySQL on `3307` and Redis on `6380`; `scripts/tunnel.sh` exposes those ports through SSH forwarding.
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ dependencies {
// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'io.lettuce:lettuce-core'

// firebase
implementation 'com.google.firebase:firebase-admin:9.7.1'

// flyway
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
}

tasks.named('test') {
Expand Down
8 changes: 5 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ services:
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --innodb-buffer-pool-size=256M
- --innodb-buffer-pool-size=512M
volumes:
- mysql-data:/var/lib/mysql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
Expand All @@ -22,8 +22,8 @@ services:
interval: 10s
timeout: 5s
retries: 5
mem_limit: 512m
memswap_limit: 768m
mem_limit: 1g
memswap_limit: 1536m

redis:
image: redis:7-alpine
Expand Down Expand Up @@ -63,6 +63,7 @@ services:
KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI_PROD}
KAKAO_ADMIN_KEY: ${KAKAO_ADMIN_KEY}
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
FIREBASE_SERVICE_ACCOUNT_KEY: ${FIREBASE_SERVICE_ACCOUNT_KEY}
depends_on:
mysql:
condition: service_healthy
Expand All @@ -85,6 +86,7 @@ services:
KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI_STAGING}
KAKAO_ADMIN_KEY: ${KAKAO_ADMIN_KEY}
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
FIREBASE_SERVICE_ACCOUNT_KEY: ${FIREBASE_SERVICE_ACCOUNT_KEY}
depends_on:
mysql:
condition: service_healthy
Expand Down
7 changes: 5 additions & 2 deletions nginx/conf.d/prod.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ server {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}

location / {
proxy_pass http://cockple-app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
}
}
3 changes: 3 additions & 0 deletions nginx/conf.d/staging.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}

location / {
Expand Down
4 changes: 4 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@ http {
keepalive_timeout 65;
client_max_body_size 30M;

gzip on;
gzip_types application/json application/javascript text/plain text/css;
gzip_min_length 256;

include /etc/nginx/conf.d/*.conf;
}
28 changes: 28 additions & 0 deletions scripts/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# SCRIPTS GUIDE

Apply root `AGENTS.md` first. This file only applies to `scripts/*`.

## OVERVIEW
Shell scripts handle server deployment and local SSH tunneling into the remote stack.

## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Branch-aware deploy | `deploy.sh` | writes `.env`, pulls image tag, restarts one app service |
| Remote DB/Redis access | `tunnel.sh` | forwards MySQL to `3307`, Redis to `6380` |

## CONVENTIONS
- `deploy.sh` treats `main` as `cockple-app:latest`; any other branch path becomes `cockple-app-staging:staging`.
- Deploy always starts `mysql`, `redis`, and `nginx` before replacing the app container.
- Health checks are part of the script, not just Docker Compose.

## ANTI-PATTERNS
- Do not change forwarded local ports without matching `application-local.yml`.
- Do not add new required env vars in scripts without updating workflow `envs` and compose.
- Do not bypass the health-check loop when changing deploy behavior.

## COMMANDS
```bash
bash scripts/deploy.sh <docker_repo> <branch>
bash scripts/tunnel.sh <GCP_IP>
```
2 changes: 2 additions & 0 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ KAKAO_REDIRECT_URI_PROD=${KAKAO_REDIRECT_URI_PROD}
KAKAO_REDIRECT_URI_STAGING=${KAKAO_REDIRECT_URI_STAGING}
KAKAO_ADMIN_KEY=${KAKAO_ADMIN_KEY}
JWT_SECRET_KEY=${JWT_SECRET_KEY}
FIREBASE_SERVICE_ACCOUNT_KEY=${FIREBASE_SERVICE_ACCOUNT_KEY}
EOF
echo "${FIREBASE_SERVICE_ACCOUNT_KEY}" > /home/ubuntu/cockple/firebase-service-account.json

echo "=== 배포 전 상태 ==="
sudo docker ps
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/umc/cockple/demo/domain/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# DOMAIN GUIDE

Apply root `AGENTS.md` first. This file covers feature slices under `domain/`.

## OVERVIEW
Business logic is organized by feature slice, usually with `controller`, `converter`, `domain`, `dto`, `enums`, `exception`, `repository`, and `service` subpackages.

## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Member/account flows | `member/` | auth-adjacent domain code |
| Party lifecycle | `party/` | joins, invitations, roles, events |
| Exercise lifecycle | `exercise/` | largest slice; read child guide |
| Chat realtime flows | `chat/` | read child guide |
| Notifications | `notification/` | FCM-backed notifications |
| Simpler slices | `bookmark/`, `contest/`, `file/`, `terms/` | mostly standard pattern |

## CONVENTIONS
- Domain-specific errors live in each slice’s `exception/*ErrorCode.java`.
- Controllers expose `/api/...` endpoints and use global response wrappers.
- Shared enums/base entities come from `global/`; slice-specific rules stay here.
- `party/` and `chat/` add `events/`; `party/` also has `utils/`.
- QueryDSL generated code mirrors entity packages elsewhere; do not mix handwritten logic into generated folders.

## ANTI-PATTERNS
- Do not move business rules into `global/` just because multiple slices depend on them.
- Do not bypass slice error codes with ad hoc strings or generic exceptions.
- Do not edit generated Q-types to “fix” repository behavior.

## CHILD GUIDES
- `chat/AGENTS.md`
- `exercise/AGENTS.md`
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import umc.cockple.demo.domain.bookmark.dto.GetAllExerciseBookmarksResponseDTO;
import umc.cockple.demo.domain.bookmark.dto.GetAllPartyBookmarkResponseDTO;
import umc.cockple.demo.domain.exercise.domain.Exercise;
import umc.cockple.demo.domain.image.service.ImageService;
import umc.cockple.demo.domain.party.domain.Party;
import umc.cockple.demo.domain.party.domain.PartyLevel;
import umc.cockple.demo.domain.party.enums.ActivityTime;
Expand Down
Loading
Loading