Skip to content

dandylsj/hatoo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

278 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ  Hatoo โ€” ์ง‘์•ˆ์ผ ๊ณต์œ  & ์•Œ๋ฆผ ํ”Œ๋žซํผ

๊ทธ๋ฃน์œผ๋กœ ์ง‘์•ˆ์ผ์„ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•˜๊ณ , ์•Œ๋ฆผ๊ณผ ์ฃผ๊ฐ„ ํ†ต๊ณ„๋กœ ๊ธฐ์—ฌ๋„๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฐฑ์—”๋“œ API ์„œ๋ฒ„

์Šคํฌ๋ฆฐ์ƒท 2026-04-03 174744
ํ•˜ํˆฌ ์•ฑ์‚ฌ์ง„

๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์ถœ์‹œ

image

https://play.google.com/store/apps/details?id=com.rfive.hatoo&hl=ko


๐Ÿ“Œ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

Hatoo๋Š” ๊ฐ€์กฑ, ๋ฃธ๋ฉ”์ดํŠธ ๋“ฑ ์†Œ๊ทœ๋ชจ ๊ทธ๋ฃน์ด ์ง‘์•ˆ์ผ์„ ํšจ์œจ์ ์œผ๋กœ ๋ถ„๋‹ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ํ• ์ผ ๋“ฑ๋ก ๋ฐ ๋ฐฐ์ •, FCM ํ‘ธ์‹œ ์•Œ๋ฆผ, ์ฃผ๊ฐ„ ๊ธฐ์—ฌ๋„ ํ†ต๊ณ„, ์นด์นด์˜ค/๋„ค์ด๋ฒ„ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ํŒ€ ๊ตฌ์„ฑ

์—ญํ•  ์ธ์› ๋‹ด๋‹น
Backend 1๋ช… (๋ณธ์ธ) API ์„œ๋ฒ„ ์„ค๊ณ„ ๋ฐ ๊ฐœ๋ฐœ, DB ์„ค๊ณ„, ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•
Frontend 1๋ช… Android(๊ฐœ๋ฐœํ…Œ์ŠคํŠธ ์ค‘) / iOS ์•ฑ ๊ฐœ๋ฐœ(์˜ˆ์ •)
Designer 1๋ช… UI/UX ๋””์ž์ธ, ํ™”๋ฉด ์„ค๊ณ„
Project Manager 1๋ช… ์ผ์ • ๊ด€๋ฆฌ, ์š”๊ตฌ์‚ฌํ•ญ ์ •์˜, QA

๐Ÿ›  ๊ธฐ์ˆ  ์Šคํƒ

๋ถ„๋ฅ˜ ๊ธฐ์ˆ 
Language Java 17
Framework Spring Boot 3.4.3
ORM Spring Data JPA / Hibernate
DB MySQL 8
์ธ์ฆ JWT (Access + Refresh Token), Spring Security
์†Œ์…œ ๋กœ๊ทธ์ธ Kakao OAuth2, Naver OAuth2
ํ‘ธ์‹œ ์•Œ๋ฆผ Firebase Cloud Messaging (FCM)
์ด๋ฉ”์ผ Spring Mail (Gmail SMTP)
๋ฌธ์„œํ™” SpringDoc OpenAPI (Swagger UI)
๋นŒ๋“œ Gradle
๋ฐฐํฌ GitHub Actions โ†’ GHCR โ†’ Self-hosted Runner (NAS)

โœจ ์ฃผ์š” ๊ธฐ๋Šฅ

๐Ÿ‘ฅ ๊ทธ๋ฃน ๊ด€๋ฆฌ

  • ๊ทธ๋ฃน ์ƒ์„ฑ / ์ดˆ๋Œ€์ฝ”๋“œ ๋ฐœ๊ธ‰ / ์ฐธ์—ฌ / ํƒˆํ‡ด / ๊ฐ•์ œ ํ‡ด์žฅ
  • ๊ฐœ์ธ ๊ทธ๋ฃน(ํ˜ผ์ž ์‚ฌ์šฉ) / ์ผ๋ฐ˜ ๊ทธ๋ฃน ๊ตฌ๋ถ„
  • ๊ทธ๋ฃน๋ณ„ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์„ ํƒ

โœ… ํ• ์ผ ๊ด€๋ฆฌ

  • ํ• ์ผ ๋“ฑ๋ก / ์ˆ˜์ • / ์‚ญ์ œ / ์™„๋ฃŒ ์ฒ˜๋ฆฌ
  • ๋‹ด๋‹น์ž ๋ฐฐ์ • (๊ทธ๋ฃน์› ์ค‘ 1๋ช…)
  • ๋ฐ˜๋ณต ์ฃผ๊ธฐ ์„ค์ •: ์—†์Œ / ๋งค์‹œ๊ฐ„ / ๋งค์ผ / ๋งค์ฃผ / ๋งค๋‹ฌ
  • ๋งˆ๊ฐ ์•Œ๋ฆผ ์„ค์ •: 10๋ถ„ ์ „ / 30๋ถ„ ์ „ / 1์‹œ๊ฐ„ ์ „ / 1์ผ ์ „ / 1์ฃผ ์ „

๐Ÿ”” ์•Œ๋ฆผ ์‹œ์Šคํ…œ (FCM)

  • ํ• ์ผ ์‹œ์ž‘ ์•Œ๋ฆผ (30์ดˆ ์ฃผ๊ธฐ ์Šค์บ”)
  • ๋งˆ๊ฐ ์ž„๋ฐ• ์•Œ๋ฆผ (30์ดˆ ์ฃผ๊ธฐ ์Šค์บ”)
  • ๋งˆ๊ฐ ์ดˆ๊ณผ ์•Œ๋ฆผ (30์ดˆ ์ฃผ๊ธฐ ์Šค์บ”)
  • ์ƒˆ ์ง‘์•ˆ์ผ ๋“ฑ๋ก ์•Œ๋ฆผ (๊ทธ๋ฃน ์ „์ฒด)
  • ํ• ์ผ ๋ฐฐ์ • ์•Œ๋ฆผ (๋ฐฐ์ •๋ฐ›์€ ๋ณธ์ธ์—๊ฒŒ๋งŒ)
  • ์ƒˆ ๋ฉค๋ฒ„ ํ•ฉ๋ฅ˜ ์•Œ๋ฆผ
  • ์ฃผ๊ฐ„ ํ†ต๊ณ„ ๊ณต๊ฐœ ์•Œ๋ฆผ (๋งค์ฃผ ์›”์š”์ผ ์˜ค์ „ 8์‹œ)
  • ๋น„ํ™œ์„ฑ ๊ทธ๋ฃน ์•Œ๋ฆผ (๋งค์›” 1์ผ)
  • ์•Œ๋ฆผ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์ „์ฒด/๊ฐœ์ธ/๊ทธ๋ฃน๋ณ„๋กœ ์„ธ๋ถ„ํ™”ํ•˜์—ฌ ์„ค์ • ๊ฐ€๋Šฅ

๐Ÿ“Š ์ฃผ๊ฐ„ ํ†ต๊ณ„

  • ๋งค์ฃผ ์›”์š”์ผ ์˜ค์ „ 8์‹œ์— ์ง€๋‚œ ์ฃผ ๊ธฐ์—ฌ๋„ ์ž๋™ ์Šค๋ƒ…์ƒท ์ €์žฅ
  • ๊ทธ๋ฃน์›๋ณ„ ์™„๋ฃŒ์œจ ๋žญํ‚น ์กฐํšŒ (์‹ค์‹œ๊ฐ„)
  • ์ฃผ์ฐจ๋ณ„ ๊ธฐ์—ฌ๋„ ์ด๋ ฅ ์กฐํšŒ

๐Ÿ” ์ธ์ฆ

  • ์ž์ฒด ํšŒ์›๊ฐ€์ž… / ๋กœ๊ทธ์ธ (BCrypt ์•”ํ˜ธํ™”)
  • ์นด์นด์˜ค / ๋„ค์ด๋ฒ„ ์†Œ์…œ ๋กœ๊ทธ์ธ
  • JWT Access Token + Refresh Token
  • ์ด๋ฉ”์ผ ์ธ์ฆ ์ฝ”๋“œ (์•„์ด๋”” ์ฐพ๊ธฐ / ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •)

๐Ÿ— ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜

[Android / iOS ์•ฑ]
        โ”‚  HTTPS
        โ–ผ
[Spring Boot API ์„œ๋ฒ„]
        โ”‚
   โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚                           โ”‚
[MySQL 8]            [Firebase FCM]
                               โ”‚
                     [์‚ฌ์šฉ์ž ๋””๋ฐ”์ด์Šค ํ‘ธ์‹œ]

[GitHub Actions]
   โ””โ”€โ”€ Docker Image Build
       โ””โ”€โ”€ GHCR (Container Registry)
           โ””โ”€โ”€ Self-hosted Runner (NAS)
               โ””โ”€โ”€ Docker Compose ๋ฐฐํฌ

๐Ÿ“‚ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

src/main/java/com/hatoo/
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ auth/          # ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ, JWT ์ธ์ฆ
โ”‚   โ”œโ”€โ”€ user/          # ์œ ์ € ์ •๋ณด, ์•Œ๋ฆผ ์ˆ˜์‹  ๋™์˜
โ”‚   โ”œโ”€โ”€ groups/        # ๊ทธ๋ฃน ์ƒ์„ฑ/์ฐธ์—ฌ/๊ด€๋ฆฌ
โ”‚   โ”œโ”€โ”€ groupMember/   # ๊ทธ๋ฃน ๋ฉค๋ฒ„
โ”‚   โ”œโ”€โ”€ task/          # ํ• ์ผ CRUD, ๋ฐ˜๋ณต ์Šค์ผ€์ค„๋Ÿฌ, ์ฃผ๊ฐ„ ํ†ต๊ณ„
โ”‚   โ”œโ”€โ”€ alarm/         # FCM ์„œ๋น„์Šค, ์•Œ๋ฆผ ์Šค์ผ€์ค„๋Ÿฌ, ์•Œ๋ฆผ ๋‚ด์—ญ
โ”‚   โ”œโ”€โ”€ alarmUserAgree/    # ์ „์ฒด/๊ฐœ์ธ ์•Œ๋ฆผ ์ˆ˜์‹  ์„ค์ •
โ”‚   โ”œโ”€โ”€ groupAlarmSetting/ # ๊ทธ๋ฃน๋ณ„ ์•Œ๋ฆผ ์„ค์ •
โ”‚   โ”œโ”€โ”€ oAuth/         # ์นด์นด์˜ค/๋„ค์ด๋ฒ„ ์†Œ์…œ ๋กœ๊ทธ์ธ
โ”‚   โ”œโ”€โ”€ token/         # Refresh Token ๊ด€๋ฆฌ
โ”‚   โ””โ”€โ”€ weeklyStats/   # ์ฃผ๊ฐ„ ๊ธฐ์—ฌ๋„ ์Šค๋ƒ…์ƒท
โ”œโ”€โ”€ common/
โ”‚   โ”œโ”€โ”€ BaseEntity.java       # createdAt, updatedAt ๊ณตํ†ต
โ”‚   โ”œโ”€โ”€ exception/            # ์ „์—ญ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
โ”‚   โ””โ”€โ”€ util/                 # JWT ์œ ํ‹ธ
โ””โ”€โ”€ config/
    โ”œโ”€โ”€ SecurityConfig.java   # Spring Security, CORS
    โ””โ”€โ”€ FirebaseConfig.java   # FCM ์ดˆ๊ธฐํ™”

๐Ÿ—„ ERD

Hatoo ERD

์ฃผ์š” ํ…Œ์ด๋ธ”:

ํ…Œ์ด๋ธ” ์„ค๋ช…
users ์œ ์ € ์ •๋ณด, FCM ํ† ํฐ, ์†Œ์…œ ๋กœ๊ทธ์ธ ID
groups ๊ทธ๋ฃน ์ •๋ณด, ์ดˆ๋Œ€์ฝ”๋“œ
group_members ์œ ์ €-๊ทธ๋ฃน N:M ๋งคํ•‘
tasks ํ• ์ผ ์ •๋ณด, ๋ฐ˜๋ณต ์ฃผ๊ธฐ, ์•Œ๋ฆผ ๋ฐœ์†ก ์—ฌ๋ถ€
task_assignees ํ• ์ผ-์œ ์ € N:M ๋งคํ•‘
group_tasks ํ• ์ผ-๊ทธ๋ฃน N:M ๋งคํ•‘
notification_history ์•Œ๋ฆผ ์ˆ˜์‹  ๋‚ด์—ญ
alarm_user_agree ์ „์ฒด/๊ฐœ์ธ ์•Œ๋ฆผ ์ˆ˜์‹  ์„ค์ •
group_alarm_settings ๊ทธ๋ฃน๋ณ„ ์•Œ๋ฆผ ์„ธ๋ถ€ ์„ค์ •
weekly_stats ์ฃผ๊ฐ„ ๊ธฐ์—ฌ๋„ ์Šค๋ƒ…์ƒท
refresh_token JWT ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ
email_verification ์ด๋ฉ”์ผ ์ธ์ฆ ์ฝ”๋“œ

๐Ÿ”„ CI/CD ํŒŒ์ดํ”„๋ผ์ธ

์ฝ”๋“œ Push (main ๋ธŒ๋žœ์น˜)
  โ””โ”€โ”€ GitHub Actions ํŠธ๋ฆฌ๊ฑฐ
      โ””โ”€โ”€ Docker Image ๋นŒ๋“œ
          โ””โ”€โ”€ GHCR(GitHub Container Registry)์— Push
              โ””โ”€โ”€ Self-hosted Runner (NAS ์„œ๋ฒ„)์—์„œ Pull
                  โ””โ”€โ”€ Docker Compose๋กœ ๋ฌด์ค‘๋‹จ ์žฌ๋ฐฐํฌ

๐Ÿ’ก ๊ธฐ์ˆ ์  ๊ณ ๋ฏผ

์•Œ๋ฆผ ๋‹ค์ค‘ ์ˆ˜์‹  ๋ฌธ์ œ

๊ทธ๋ฃน ์ „์ฒด์—๊ฒŒ ์•Œ๋ฆผ์„ ๋ฐœ์†กํ•  ๋•Œ ๋ฐฐ์ •๋ฐ›์€ ์‚ฌ๋žŒ์ด "์ƒˆ ํ• ์ผ ๋“ฑ๋ก" + "๋‚˜์—๊ฒŒ ๋ฐฐ์ •" ๋‘ ๊ฐœ์˜ ์•Œ๋ฆผ์„ ๋™์‹œ์— ๋ฐ›๋Š” ์ค‘๋ณต ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. sendTaskCreated ๋ฉ”์„œ๋“œ์— assigneeId๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฐฐ์ •๋ฐ›์€ ์‚ฌ๋žŒ์€ ๊ทธ๋ฃน ์ „์ฒด ์•Œ๋ฆผ์—์„œ ์ŠคํŠธ๋ฆผ ํ•„ํ„ฐ๋กœ ์ œ์™ธํ•˜๊ณ , ๊ฐœ์ธ ๋ฐฐ์ • ์•Œ๋ฆผ๋งŒ ์ˆ˜์‹ ํ•˜๋„๋ก ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์•Œ๋ฆผ ์Šค์ผ€์ค„๋Ÿฌ ๋‚ ์งœ ํŒŒ์‹ฑ ์‹คํŒจ

ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ "2026-04-28 13:55:01.884884" (๋งˆ์ดํฌ๋กœ์ดˆ ํฌํ•จ) ๋˜๋Š” "2026-04-27T01:56:04.689Z" (ISO 8601 UTC) ํ˜•์‹์œผ๋กœ ๋‚ ์งœ๋ฅผ ์ „์†กํ•˜๋Š”๋ฐ, ๋‹จ์ผ ํŒจํ„ด ํŒŒ์‹ฑ์œผ๋กœ๋Š” ์ฒ˜๋ฆฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ–ˆ์Šต๋‹ˆ๋‹ค. Instant.parse() โ†’ KST ๋ณ€ํ™˜, ๋‹ค์ค‘ ํฌ๋งท ์ˆœ์ฐจ ์‹œ๋„, ๋‚ ์งœ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ ์ž์ • ์ฒ˜๋ฆฌ๋กœ ํด๋ฐฑํ•˜๋Š” ๋ฐฉ์–ด ๋กœ์ง์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

N+1 ์ฟผ๋ฆฌ ๋ฌธ์ œ

๊ทธ๋ฃน ๋ฉค๋ฒ„ ๋ชฉ๋ก ์กฐํšŒ ํ›„ forEach์—์„œ gm.getUser()๋ฅผ ์ ‘๊ทผํ•˜๋Š” ๊ณผ์ •์—์„œ @ManyToOne(fetch = LAZY) ๊ด€๊ณ„๋กœ ์ธํ•ด N+1 ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. JOIN FETCH ์ฟผ๋ฆฌ ๋˜๋Š” @EntityGraph๋ฅผ ํ™œ์šฉํ•œ ์ฆ‰์‹œ ๋กœ๋”ฉ์œผ๋กœ ๊ฐœ์„ ์ด ํ•„์š”ํ•œ ์ง€์ ์œผ๋กœ ํŒŒ์•…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ๊ฐ„ ํ†ต๊ณ„ ์Šค๋ƒ…์ƒท ์„ค๊ณ„

์‹ค์‹œ๊ฐ„ ์กฐํšŒ๋Š” DB ๋ถ€ํ•˜๊ฐ€ ํฌ๊ณ  ๊ณผ๊ฑฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์กดํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋งค์ฃผ ์›”์š”์ผ ์˜ค์ „ 8์‹œ์— ์ง€๋‚œ ์ฃผ ํ†ต๊ณ„๋ฅผ ์Šค๋ƒ…์ƒท์œผ๋กœ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์„ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œ ํ›„ ์žฌ์‚ฝ์ž…(delete-first)ํ•˜์—ฌ ์Šค์ผ€์ค„๋Ÿฌ ์žฌ์‹คํ–‰ ์‹œ ์ค‘๋ณต ์ €์žฅ ์—†์ด ํ•ญ์ƒ ์ตœ์‹  ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿš€ ๋กœ์ปฌ ์‹คํ–‰ ๋ฐฉ๋ฒ•

์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ

  • Java 17
  • MySQL 8
  • Firebase ์„œ๋น„์Šค ๊ณ„์ • JSON

1. DB ์ƒ์„ฑ

CREATE DATABASE hatoo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

2. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •

ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— .env ํŒŒ์ผ ์ƒ์„ฑ:

DB_URL=jdbc:mysql://localhost:3306/hatoo
DB_USERNAME=root
DB_PASSWORD=๋น„๋ฐ€๋ฒˆํ˜ธ
JWT_SECRET_KEY=์‹œํฌ๋ฆฟํ‚ค
FIREBASE_PATH=/๊ฒฝ๋กœ/service-account.json

3. ์‹คํ–‰

./gradlew bootRun

4. API ๋ฌธ์„œ ํ™•์ธ

http://localhost:8080/swagger-ui.html

๐Ÿ“ก ์ฃผ์š” API ๋ชฉ๋ก

Method URL ์„ค๋ช…
POST /auth/sign ํšŒ์›๊ฐ€์ž…
POST /auth/login ๋กœ๊ทธ์ธ
POST /auth/reissue ํ† ํฐ ์žฌ๋ฐœ๊ธ‰
GET /groups ๋‚ด ๊ทธ๋ฃน ๋ชฉ๋ก ์กฐํšŒ
POST /groups ๊ทธ๋ฃน ์ƒ์„ฑ
POST /tasks ํ• ์ผ ๋“ฑ๋ก
GET /tasks/group/{groupId} ๊ทธ๋ฃน ํ• ์ผ ๋ชฉ๋ก ์กฐํšŒ
PATCH /tasks/{taskId}/task-status ํ• ์ผ ์™„๋ฃŒ ์ฒ˜๋ฆฌ
GET /tasks/group/{groupId}/ranking ์‹ค์‹œ๊ฐ„ ๋žญํ‚น ์กฐํšŒ
GET /tasks/group/{groupId}/weekly-stats ์ฃผ๊ฐ„ ๊ธฐ์—ฌ๋„ ํ†ต๊ณ„
GET /users/notifications ์•Œ๋ฆผ ๋ชฉ๋ก ์กฐํšŒ
PATCH /users/notifications/read-all ์•Œ๋ฆผ ์ „์ฒด ์ฝ์Œ ์ฒ˜๋ฆฌ

์ „์ฒด API ๋ชฉ๋ก์€ Swagger UI์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors