From abb0c6a9f7b8be602991fba6fc279763ad8e3e0e Mon Sep 17 00:00:00 2001 From: sb Date: Sun, 12 Jul 2026 00:03:32 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EB=B0=B1=EC=97=94=EB=93=9C=20README=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(=EC=8A=A4=ED=83=9D=C2=B7=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=C2=B7=EC=98=A4=EB=8A=98=20=EC=A7=84=ED=96=89=20?= =?UTF-8?q?=EB=82=B4=EC=97=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e18ff1b --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# 산책갈개 · dognation_BT (Backend) + +우리 강아지 성향에 맞는 동네 산책 메이트를 안전하게 찾는 서비스의 백엔드 API. + +## 스택 +- **Spring Boot 3.3 / Java 17 / Gradle** +- **PostgreSQL + PostGIS** (운영/개발) · **H2** (로컬) +- **Flyway** (스키마 마이그레이션, `validate`) +- **Redis** (Lettuce) — 체크인 활성 메이트(24h TTL), 논리 DB로 dev/prod 격리 +- **STOMP over WebSocket** — 실시간 알림/채팅 +- **Gemini API** (`gemini-flash-latest`) — AI 궁합 추천 + +## 프로파일 · 포트 +| 프로파일 | DB | Flyway | 포트 | Redis DB | +|---|---|---|---|---| +| `local` | H2(create-drop) | 비활성 | 8080 | 3 | +| `dev` | Postgres | validate+migrate | **9091** | 3 | +| `prod` | Postgres | validate+migrate | **9090** | 4 | + +```bash +# 로컬 실행 (H2 + 시드 + dev 로그인 토큰) +SPRING_PROFILES_ACTIVE=local GEMINI_API_KEY=... ./gradlew bootRun +``` + +## 도메인 구조 (`domain/`) +- `auth` — 소셜 로그인(Apple 네이티브, aud=번들ID) · 세션 토큰 +- `user` — 회원 · 구독 티어(FREE / AD_FREE / PREMIUM) +- `dog` — 강아지 프로필 · 성향 태그(댕비티아이) · 중성화 여부 +- `spot` — 산책 스팟 · 체크인(Redis+Postgres) · 한줄평 · '자주 오는 견종' 통계 · AI 궁합 추천 +- `matching` — 매칭 신청/수락/거절 · 쿼터 · 20분 자동만료 · 피드백 알림 +- `chat` — 매칭 1:1 채팅방 +- `affinity` — 찰떡지수(우리 1:1 / 동네 1:N) · 산책 후 피드백 +- `billing` — 구독 · `report` — 신고/블랙리스트 + +## 배포 +- **CI = Gitea Actions** (`.gitea/workflows/`, GitHub Actions 문법) +- dev: `dev` push → 빌드 → jar를 SSH(cat)로 전송 → 컨테이너 재기동(경로 자가치유) +- prod: `main` push → 동일 방식으로 `api` 컨테이너 배포 +- 컨테이너는 JRE 이미지에 `app.jar`를 볼륨 마운트, 호스트 Redis는 `host.docker.internal` + +--- + +## 오늘 진행 내역 (2026-07-11 ~ 07-12) + +### 인증 +- **Apple 로그인**(네이티브 `@capacitor-community/apple-sign-in`) 백엔드 검증 — aud=번들ID `kr.sblog.dognation` + +### 스팟 · 체크인 · 통계 +- 체크인 → **Redis(24h TTL, 활성 메이트)** + **Postgres(통계용)** 동시 저장 +- 스팟 활성 메이트 조회(본인 강아지 제외) +- **'이 시간대 자주 오는 견종'** 통계 API — 접속 요일·시간대 기준 체크인 집계 + +### AI 궁합 추천 (Gemini) +- 스팟 활성 강아지 중 내 강아지와 사이좋게 지낼 메이트를 궁합점수·이유와 함께 추천 +- 크기/성향 충돌(대형견 무서움 등) 고려, 후보 밖 dogId(환각) 방지 +- **중성화 조건 필터**(상관없음/완료/안함), 추천 사유 **친근한 말투**(~해요/~예요) +- **찰떡지수 반영** — 프롬프트에 `pastAffinity`(우리 호감도)·`neighborhood`(동네 사교성) 주입 + +### 매칭 플로우 +- 신청 시 **무료 쿼터 차감**(FREE/AD_FREE 하루 3회, PREMIUM 무제한), 중복 신청 방지 +- 진행중 상태 · 상대에게 **STOMP 실시간 알림**(`/topic/users/{id}`) +- 수락 → **1:1 채팅방 생성 + 결과 메시지**, 거절 → 불발 알림 +- **20분 미수락 자동 만료** 스케줄러 + +### 찰떡지수 피드백 (신규) +- 산책 후 피드백(잘 놀았어요/안 맞았어요) → **우리 찰떡지수(1:1)** GOOD +1 / BAD -2, **동네 찰떡지수(1:N)** GOOD +0.5 / BAD -1 (0 미만 차감 없음) +- BAD 사유 수집(성향/간식·장난감/입질·공격성/보호자 매너 + 추가입력) +- **우리 찰떡지수**는 매칭 이력 쌍 + **유료회원만 노출**(무료는 "유료회원 전용") +- 수락 2시간 후 **피드백 요청 알림**(`FEEDBACK_REQUEST`) 스케줄러 +- 마이그레이션 `V9__affinity.sql` (V8 리포트와 버전 충돌 → V9로 조정) + +### 운영 · 인프라 +- 신고(피신고자 관리) + 블랙리스트 + Redis 내성 (`V8__reports_blacklist.sql`) +- 프로파일 분리(local/dev/prod), 포트 dev=9091 / prod=9090 +- **Redis 논리 DB 격리**(dev=3, prod=4) +- Dockerfile + `.dockerignore`, **Gitea Actions jar 자동배포**(dev/prod), 배포 경로 자가치유 +- dev 프로파일 테스트 데이터 시더 + +> 프론트엔드: [dognation_PT](https://gitlab.sblog.kr/sb/dognation_PT) · 관리자: dognation_AT \ No newline at end of file