Skip to content
Merged
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
61 changes: 50 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

**적(積)** — 랜덤 미션 기반 디지털 디톡스 서비스. 제8회 코커톤.

매일 설정한 디톡스 시간에 랜덤 미션을 수행하고 인증사진을 올려 습관을 쌓는다.
**로그인이 없다.** 앱이 생성한 `deviceId` 로 사용자를 식별한다.
매일 설정한 디톡스 시간에 랜덤 미션을 수행하고 인증사진을 올려 벽돌을 쌓는다.
**로그인이 없다.** 앱이 생성한 `deviceId` 로 사용자를 식별하고, 대부분의 API 는
`X-Device-Id` 헤더로 사용자를 구분한다.

Spring Boot 4.1.0 / Java 21 / PostgreSQL.
Spring Boot 4.1.0 / Java 21 / PostgreSQL / AWS(EC2, RDS, S3).

## 빠른 실행

Expand All @@ -14,7 +15,7 @@ docker compose up -d # Postgres 기동 (호스트 5433)
./gradlew bootRun
```

`.env` 는 **필요 없다.** `application.yml` 과 `docker-compose.yml` 의 기본값이 서로 맞춰져 있어
`.env` 는 필요 없다. `application.yml` 과 `docker-compose.yml` 의 기본값이 서로 맞춰져 있어
클론하고 위 두 줄만 치면 바로 뜬다.

호스트 포트가 5433인 이유: 로컬에 PostgreSQL 이 이미 설치돼 있어도 5432 와 충돌하지 않게 하기 위함.
Expand All @@ -27,19 +28,43 @@ docker compose up -d # Postgres 기동 (호스트 5433)

```
domain/
user/ 사용자 (deviceId, 닉네임, 디톡스 시간)
team/ 팀 생성 / 초대코드 참여
mission/ 랜덤 미션, 인증
image/ S3 Presigned URL 발급
user/ 온보딩, 디톡스 시간, 홈 화면, 벽돌 정산, 팀 전환, 알림 설정
team/ 팀 생성 / 초대코드 참여 / 팀 조회 (N:M, 한 사용자가 여러 팀에 속할 수 있음)
mission/ 오늘의 미션, 10분 타이머, 사진 인증
detox/ 디톡스 진행 화면 (겹치는 팀원 조회)
image/ S3 업로드 (미션 인증 사진)
global/
config/ WebConfig(CORS), SwaggerConfig
response/ ApiResponse, ErrorResponse
exception/ ErrorCode, BusinessException, GlobalExceptionHandler
```

## API 요약

인증 없이 `X-Device-Id` 헤더로 사용자를 식별한다. 상세 스펙은 Swagger UI 참고.

| 도메인 | Method | Path | 설명 |
|---|---|---|---|
| User | POST | `/api/users` | 온보딩 (사용자 생성/로그인) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== README.md context =="
git ls-files README.md
wc -l README.md
sed -n '1,120p' README.md | cat -n

echo
echo "== Search for /api/users and deviceId =="
rg -n "/api/users|deviceId|onboarding|로그인|사용자 생성" -S .

echo
echo "== Candidate backend files =="
git ls-files | rg '^(src|app|server|pages|api|backend|lib|routes)/'

Repository: 8th-COKERTHON/server-team1

Length of output: 27403


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== UserController =="
sed -n '1,120p' src/main/java/com/example/hackathon/domain/user/controller/UserController.java | cat -n

echo
echo "== UserService =="
sed -n '1,140p' src/main/java/com/example/hackathon/domain/user/service/UserService.java | cat -n

echo
echo "== UserCreateResponse =="
sed -n '1,120p' src/main/java/com/example/hackathon/domain/user/dto/response/UserCreateResponse.java | cat -n

Repository: 8th-COKERTHON/server-team1

Length of output: 13080


POST /api/users 설명을 온보딩 기준으로 통일해 주세요.

현재 구현은 deviceId로 기존 사용자를 찾고, 없으면 생성하며 있으면 LOGIN을 반환합니다. 로그인이라고 쓰기보다 온보딩(기존 사용자 식별/신규 생성)처럼 실제 동작에 맞춰 정리하는 편이 덜 헷갈립니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 48, README의 POST /api/users 설명을 실제 동작에 맞게 “온보딩(기존 사용자
식별/신규 생성)”으로 수정하고, 기존의 “온보딩 (사용자 생성/로그인)” 표현을 해당 문구로 통일하세요.

| User | GET/POST/PATCH | `/api/users/detox-time` | 디톡스 시간 조회/설정/수정 |
| User | PATCH | `/api/users/{userId}/active-team` | 선택된 팀 전환 |
| User | PATCH | `/api/users/{userId}/email` | 이메일 등록/수정 (정보 수집만, 발송 없음) |
| User | PATCH | `/api/users/{userId}/notification` | 알림 허용 여부 토글 |
| User | GET | `/api/users/{userId}` | 유저 정보 조회 |
| User | GET | `/api/users/{userId}/home` | 홈 화면 (벽돌/인증 현황/정산) |
| Team | POST | `/api/teams` | 팀 생성 + 초대코드 발급 |
| Team | POST | `/api/teams/join` | 초대코드로 참여 |
| Team | GET | `/api/users/{userId}/teams` | 내 팀 목록 |
| Team | GET | `/api/teams/{teamId}` | 팀 상세 |
| Mission | GET | `/api/missions/today`, `/today/status` | 오늘의 미션 조회 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Mission 상태 API의 전체 경로를 명시하세요.

현재 /today/status만 상대 경로로 표기되어 다른 API 경로 형식과 일관되지 않습니다.

수정 예시
-| Mission | GET | `/api/missions/today`, `/today/status` | 오늘의 미션 조회 |
+| Mission | GET | `/api/missions/today`, `/api/missions/today/status` | 오늘의 미션 조회 |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| Mission | GET | `/api/missions/today`, `/today/status` | 오늘의 미션 조회 |
| Mission | GET | `/api/missions/today`, `/api/missions/today/status` | 오늘의 미션 조회 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 59, README.md의 Mission API 표에서 `/today/status`를 전체 경로인
`/api/missions/today/status`로 수정하여 다른 엔드포인트 표기 형식과 일치시키세요.

| Mission | POST | `/api/missions/today/popup` | 팝업 표시 시각 기록 |
| Mission | POST | `/api/missions/today/confirm` | 미션 확인 |
| Mission | POST/PATCH | `/api/missions/today/certification` | 사진 인증 / 재인증 (multipart) |
| Detox | GET | `/api/detox/progress` | 디톡스 진행 상태, 겹치는 팀원 |

## 공통 응답 형식

모든 API 는 아래 형식으로 응답한다. 컨트롤러는 `ApiResponse.ok(...)` / `ApiResponse.created(...)` 를 반환한다.
컨트롤러는 `ApiResponse.ok(...)` / `ApiResponse.created(...)` 를 반환한다.

성공
```json
Expand All @@ -56,12 +81,26 @@ global/

에러를 내려면 `ErrorCode` 에 상수를 추가하고 서비스에서 `throw new BusinessException(ErrorCode.XXX)` 한다.
`GlobalExceptionHandler` 가 공통 포맷으로 변환한다. `code` 는 enum 이름을 그대로 쓴다.
`reasons` 는 `@Valid` 검증 실패나 필수 헤더 누락 시 `{ "필드명": "메시지" }` 로 채워진다.

## 이미지 업로드

`reasons` 는 `@Valid` 검증 실패 시 `{ "필드명": "메시지" }` 로 채워진다.
미션 인증 사진은 presigned URL 방식이 아니라 **백엔드로 파일을 직접 업로드**한다.

```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

요청 예시 코드 블록에 언어 식별자를 추가하세요.

정적 분석에서 MD040 경고가 발생합니다. text 또는 적절한 언어 식별자를 지정해 주세요.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 90, README.md의 요청 예시 코드 블록에 언어 식별자가 누락되어 MD040 경고가 발생합니다.
해당 fenced code block의 여는 백틱 뒤에 내용에 맞는 언어 식별자(예: text)를 추가하세요.

Source: Linters/SAST tools

POST /api/missions/today/certification (multipart/form-data)
헤더: X-Device-Id
바디: image 파트에 이미지 파일 (jpg/png, 10MB 이하)
Comment on lines +91 to +93

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

허용 이미지 형식에 WebP를 반영하세요.

S3StorageService.validate는 JPEG, PNG, WebP를 허용하지만 README는 jpg/png만 안내합니다. 실제 계약과 맞도록 MIME 타입 기준으로 image/jpeg, image/png, image/webp를 문서화해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 91 - 93, Update the README documentation for POST
/api/missions/today/certification to list the accepted image MIME types as
image/jpeg, image/png, and image/webp, while retaining the 10MB size limit.

```

백엔드가 S3 업로드와 DB 기록(`image_url`, `status=SUCCESS`)을 함께 처리한다.

## 환경변수

로컬은 기본값으로 동작한다. 배포(prod 프로파일)는 `DB_URL / DB_USERNAME / DB_PASSWORD` 를 환경변수로 주입한다.
로컬은 기본값으로 동작한다. 배포(prod 프로파일)는 아래를 환경변수로 주입한다.

- `DB_URL` / `DB_USERNAME` / `DB_PASSWORD` — RDS 접속
- `AWS_REGION` / `AWS_S3_BUCKET` / `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` — S3 업로드

## 배포

Expand Down
Loading