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
9 changes: 4 additions & 5 deletions .claude/skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ GitHub 이슈를 대상 repo에 생성한다. **반드시 사용자 승인을

| 구분 | repo |
|------|------|
| frontend | `how-about-us/frontend-server` |
| backend | `how-about-us/backend-server` |
| ai | `how-about-us/ai-server` |
| frontend | `uttae/frontend-server` |
| backend | `uttae/backend-server` |
| ai | `uttae/ai-server` |

## Workflow

Expand Down Expand Up @@ -79,7 +79,7 @@ GitHub 이슈를 대상 repo에 생성한다. **반드시 사용자 승인을
```
이슈 초안입니다. 확인해주세요.

- Repo: how-about-us/xxx
- Repo: uttae/xxx
- 라벨: enhancement, bug (해당하는 라벨 나열)
- 제목: ...
- 본문:
Expand Down Expand Up @@ -116,4 +116,3 @@ EOF
- 사용자가 "이슈 올려"라고 하면 바로 생성 → **초안 먼저**
- repo를 추측해서 잘못된 곳에 생성 → **모호하면 물어보기**
- 템플릿 없이 자유 형식으로 작성 → **항상 템플릿 사용**

28 changes: 26 additions & 2 deletions .claude/skills/review-code-against-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,36 @@ description: Use when the user asks to create, open, prepare, or publish a PR/pu

## Checklist

### Step 0. diff 수집
### Step 0. 기준 브랜치 결정 및 diff 수집

먼저 `CONTRIBUTING.md`의 Branch Strategy를 확인하고 PR 기준 브랜치를 결정한다.

기준 브랜치 우선순위:

1. 사용자가 PR 대상 브랜치를 명시했으면 그 값을 사용한다.
2. 이미 열린 PR이 있으면 `gh pr view --json baseRefName`의 `baseRefName`을 사용한다.
3. 현재 브랜치가 `feature/*`이면 `dev`를 사용한다.
4. 현재 브랜치가 `hotfix/*`이면 `main`을 사용한다.
5. 현재 브랜치가 `dev`이면 `main`을 사용한다.
6. 현재 브랜치가 `main`이면 `dev`를 사용한다. 이 경우는 hotfix 반영 후 `main` → `dev` 백머지 PR이다.
7. 판단할 수 없으면 사용자에게 PR 대상 브랜치를 확인한다.

브랜치 전략:

| 현재 브랜치 | PR 대상 |
|------|------|
| `feature/*` | `dev` |
| `hotfix/*` | `main` |
| `dev` | `main` |
| `main` | `dev` 백머지 |

```bash
git diff main --name-only
git fetch origin <base-branch> --quiet
git diff --name-only origin/<base-branch>...HEAD
```

보고서에는 기준 브랜치, 현재 브랜치, diff 범위를 먼저 적는다.

변경된 `.java` 파일 목록을 추출한다. 변경 파일이 없으면 "변경 없음"으로 종료한다.

변경된 파일을 두 그룹으로 분류한다:
Expand Down
11 changes: 8 additions & 3 deletions .env.db.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# PostgreSQL
DB_NAME=howaboutus
# PostgreSQL (AWS Lightsail Managed DB)
DB_HOST=change-this-lightsail-db-endpoint
DB_NAME=uttae
DB_USER=prod
DB_PASSWORD=change-this-db-password

# MongoDB
MONGO_USER=prod
MONGO_PASSWORD=change-this-mongo-password
MONGO_DB=howaboutus
MONGO_DB=uttae

# Redis
REDIS_PASSWORD=change-this-redis-password
REDIS_MAXMEMORY=384mb

# Private network bindings
DB_PRIVATE_IP=10.0.0.13
Expand Down
4 changes: 2 additions & 2 deletions .env.dev.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# PostgreSQL
DB_NAME=howaboutus
DB_NAME=uttae
DB_USER=dev
DB_PASSWORD=dev

# MongoDB
MONGO_USER=dev
MONGO_PASSWORD=dev
MONGO_DB=howaboutus
MONGO_DB=uttae

# JWT (32자 이상의 랜덤 문자열)
JWT_SECRET=local-dev-secret-please-change-this-to-something-random
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/deploy-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ concurrency:

env:
DEPLOY_PATH: /opt/how-about-us-backend
APP_IMAGE_REPOSITORY: ghcr.io/${{ github.repository_owner }}/backend-server
APP_IMAGE_REPOSITORY: ghcr.io/${{ github.repository }}
APP_WAIT_TIMEOUT_SECONDS: 180

jobs:
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
- hbu-api
environment: production-api
env:
APP_IMAGE: ghcr.io/${{ github.repository_owner }}/backend-server:${{ github.sha }}
APP_IMAGE: ghcr.io/${{ github.repository }}:${{ github.sha }}

steps:
- name: Check out source
Expand Down Expand Up @@ -108,6 +108,7 @@ jobs:
grep '^APP_IMAGE=' "$DEPLOY_PATH/.env.prod"
grep '^API_PRIVATE_IP=' "$DEPLOY_PATH/.env.prod"
grep '^LOKI_PUSH_URL=' "$DEPLOY_PATH/.env.prod"
grep '^REDIS_PASSWORD=.' "$DEPLOY_PATH/.env.prod"
docker compose --env-file "$DEPLOY_PATH/.env.prod" -f "$DEPLOY_PATH/compose.app.prod.yaml" config >/dev/null

- name: Detect runtime config changes
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/deploy-db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,23 @@ jobs:
grep '^POSTGRES_EXPORTER_PORT=' .env.db
grep '^REDIS_EXPORTER_PORT=' .env.db
grep '^MONGODB_EXPORTER_PORT=' .env.db
grep '^REDIS_PASSWORD=.' .env.db

docker compose --env-file .env.db -f compose.db.prod.yaml config >/dev/null

- name: Deploy DB services and exporters
run: |
cd "$DEPLOY_PATH"
docker compose --env-file .env.db -f compose.db.prod.yaml pull postgres redis mongodb postgres-exporter redis-exporter mongodb-exporter node-exporter
docker compose --env-file .env.db -f compose.db.prod.yaml up -d --wait --wait-timeout "$DB_WAIT_TIMEOUT_SECONDS" postgres redis mongodb postgres-exporter redis-exporter mongodb-exporter node-exporter
docker compose --env-file .env.db -f compose.db.prod.yaml pull postgres-exporter redis mongodb redis-exporter mongodb-exporter node-exporter
docker compose --env-file .env.db -f compose.db.prod.yaml up -d --wait --wait-timeout "$DB_WAIT_TIMEOUT_SECONDS" postgres-exporter redis mongodb redis-exporter mongodb-exporter node-exporter
docker compose --env-file .env.db -f compose.db.prod.yaml ps

- name: Print DB logs on deploy failure
if: failure()
run: |
cd "$DEPLOY_PATH"
docker compose --env-file .env.db -f compose.db.prod.yaml ps
docker compose --env-file .env.db -f compose.db.prod.yaml logs postgres redis mongodb postgres-exporter redis-exporter mongodb-exporter node-exporter --tail=200
docker compose --env-file .env.db -f compose.db.prod.yaml logs postgres-exporter redis mongodb redis-exporter mongodb-exporter node-exporter --tail=200

- name: Prune unused Docker images
if: always()
Expand Down
2 changes: 1 addition & 1 deletion .serena/memories/project_overview.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Project Overview\n- `how-about-us-backend` is a Spring Boot backend for room-based place exploration/bookmark features with authentication and external Google API integration.\n- Main domains currently visible in the codebase: `auth`, `bookmarks`, `places`, `rooms`, plus `common` for shared config/error/integration code.\n- Source of truth for AI work is `AGENTS.md`; domain details live under `docs/ai/` such as `docs/ai/features.md` and `docs/ai/erd.md`.\n- Key stack from project docs and build config: Spring Boot 4.0.5, Java 21, Gradle, Spring Data JPA, PostgreSQL/PostGIS, Redis, MongoDB, Spring Security, WebSocket/STOMP, Lombok, springdoc OpenAPI, Testcontainers, Jib.\n- Runtime profiles: `dev` for local development with Docker Compose support, `prod` for AWS Lightsail deployment.\n- Package structure follows `com.howaboutus.backend.<domain>` with `common/` for shared concerns and domain packages for controller/service/repository/entity separation.
# Project Overview\n- `uttae-backend` is a Spring Boot backend for room-based place exploration/bookmark features with authentication and external Google API integration.\n- Main domains currently visible in the codebase: `auth`, `bookmarks`, `places`, `rooms`, plus `common` for shared config/error/integration code.\n- Source of truth for AI work is `AGENTS.md`; domain details live under `docs/ai/` such as `docs/ai/features.md` and `docs/ai/erd.md`.\n- Key stack from project docs and build config: Spring Boot 4.0.5, Java 21, Gradle, Spring Data JPA, PostgreSQL/PostGIS, Redis, MongoDB, Spring Security, WebSocket/STOMP, Lombok, springdoc OpenAPI, Testcontainers, Jib.\n- Runtime profiles: `dev` for local development with Docker Compose support, `prod` for AWS Lightsail deployment.\n- Package structure follows `com.howaboutus.backend.<domain>` with `common/` for shared concerns and domain packages for controller/service/repository/entity separation.
2 changes: 1 addition & 1 deletion .serena/project.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# the name by which the project can be referenced within Serena
project_name: "how-about-us-backend"
project_name: "uttae-backend"


# list of languages for which language servers are started; choose from:
Expand Down
11 changes: 6 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
## Tech Stack

- **Framework**: Spring Boot 4.0.5, Java 21
- **Database**: PostgreSQL 17 + PostGIS 3.5, MongoDB 8
- **Database**: PostgreSQL 17.10, MongoDB 8.0.21
- **Cache**: Redis 8
- **Auth**: Spring Security
- **Realtime**: WebSocket + STOMP
- **Build**: Gradle
- **기타**: Lombok, Spring Data JPA, Spring Data MongoDB, `hibernate-spatial`
- **기타**: Lombok, Spring Data JPA, Spring Data MongoDB

## Commands

Expand Down Expand Up @@ -78,9 +78,10 @@ src/main/resources/

## Gotchas

- PostgreSQL 이미지는 `postgis/postgis:17-3.5`를 사용한다.
- MongoDB 이미지는 `mongo:8`을 사용하며 채팅 메시지 저장소로 사용한다.
- 공간 데이터 엔티티에는 `hibernate-spatial` 타입을 사용한다.
- PostgreSQL 이미지는 `postgres:17.10`을 사용한다.
- MongoDB 이미지는 `mongo:8.0.21`을 사용하며 채팅 메시지 저장소로 사용한다.
- PostgreSQL 스키마 변경은 Flyway SQL 마이그레이션으로 관리한다.
- MongoDB 컬렉션/인덱스 변경은 Mongock ChangeUnit으로 관리한다. 변경 클래스는 `common/migration/mongo/` 아래에 두고, Spring Data 자동 인덱스 생성에 의존하지 않는다.
- dev 환경의 PostgreSQL 포트는 `5433`이다.
- `spring.jpa.open-in-view=false`가 설정되어 있다.
- WebSocket + STOMP 사용 시 Spring Security 설정에서 WebSocket 엔드포인트를 별도 허용해야 한다.
Expand Down
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ feature/<topic> → dev → main
- `main`에 직접 push하지 않는다.
- `feature/*` 브랜치는 `dev`에서 분기하고 `dev`로 머지한다.
- 브랜치는 작업 단위로 짧게 유지한다.
- `feature/*` 브랜치의 PR 대상은 `dev`다.
- `dev` 브랜치의 릴리스 PR 대상은 `main`이다.

### Hotfix 흐름

Expand All @@ -28,8 +30,9 @@ hotfix/<topic> → main → dev (백머지)
```

- `hotfix/*` 브랜치는 `main`에서 직접 분기한다.
- `hotfix/*` 브랜치의 PR 대상은 `main`이다.
- 수정 완료 후 `main`에 머지한다.
- 머지 후 동일 변경사항을 반드시 `dev`에도 백머지하여 이후 릴리스에서 누락되지 않도록 한다.
- 머지 후 `main`에서 `dev`로 백머지 PR을 올려 동일 변경사항이 이후 릴리스에서 누락되지 않도록 한다.

## Commit Convention

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2026 우리어때
Copyright (c) 2026 우때

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# How About Us Backend
# Uttae Backend

협업형 여행 계획 플랫폼 **우리어때**의 백엔드 서버입니다.
협업형 여행 계획 플랫폼 **우때**의 백엔드 서버입니다.
## Demo
[![시연 영상](https://img.youtube.com/vi/T6Qd0sUiB48/maxresdefault.jpg)](https://www.youtube.com/watch?v=T6Qd0sUiB48)

Expand All @@ -13,7 +13,7 @@

- **Language**: Java 21
- **Framework**: Spring Boot 4.0.5
- **Database**: PostgreSQL 17 + PostGIS 3.5, MongoDB 8
- **Database**: PostgreSQL 17.10, MongoDB 8.0.21
- **Cache**: Redis 8
- **Auth**: Spring Security + JWT
- **Realtime**: WebSocket + STOMP
Expand All @@ -29,7 +29,7 @@ src/main/java/com/howaboutus/backend/
├── auth/ ← 인증/인가
├── bookmarks/ ← 북마크
├── messages/ ← 채팅 메시지 (MongoDB)
├── places/ ← 장소 (PostGIS 공간 데이터)
├── places/ ← 장소 (Google Places API 연동)
├── realtime/ ← WebSocket 실시간 통신
├── rooms/ ← 채팅방
├── schedules/ ← 일정
Expand Down
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {

group = 'com.howaboutus'
version = '0.0.1-SNAPSHOT'
description = 'how-about-us-backend'
description = 'uttae-backend'

java {
toolchain {
Expand All @@ -34,10 +34,11 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.hibernate.orm:hibernate-spatial'
runtimeOnly 'org.postgresql:postgresql'
implementation 'org.springframework.boot:spring-boot-starter-flyway'
runtimeOnly 'org.flywaydb:flyway-database-postgresql'
implementation 'io.mongock:mongock-standalone:5.5.1'
implementation 'io.mongock:mongodb-sync-v4-driver:5.5.1'

implementation 'org.springframework.boot:spring-boot-starter-security'

Expand Down
6 changes: 5 additions & 1 deletion compose.app.dev.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
name: uttae

services:
app:
api-server:
build: .
env_file:
- ./.env.dev
Expand All @@ -24,3 +26,5 @@ services:
timeout: 5s
retries: 12
start_period: 30s


4 changes: 2 additions & 2 deletions compose.app.prod.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: how-about-us-app
name: uttae-api

services:
app:
Expand Down Expand Up @@ -66,7 +66,7 @@ services:
max-file: "3"

caddy:
image: how-about-us-caddy:2.11-ratelimit
image: uttae-caddy:2.11-ratelimit
build:
context: .
dockerfile: infra/caddy/Dockerfile
Expand Down
11 changes: 7 additions & 4 deletions compose.db.dev.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#file: noinspection SpellCheckingInspection
name: uttae

services:
postgres:
image: 'postgis/postgis:17-3.5'
platform: linux/amd64
image: 'postgres:17.10'
env_file:
- ./.env.dev
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
test: ["CMD-SHELL", "pg_isready -h localhost -p 5432 -U $${DB_USER} -d $${DB_NAME}"]
interval: 10s
timeout: 5s
retries: 10
Expand All @@ -33,7 +34,7 @@ services:
- redis-data:/data

mongodb:
image: 'mongo:8'
image: 'mongo:8.0.21'
env_file:
- ./.env.dev
environment:
Expand All @@ -54,3 +55,5 @@ volumes:
postgres-data:
redis-data:
mongodb-data:


Loading