FlipNote μλΉμ€μ μ μ λλ©μΈ λ°±μλ λ ν¬μ§ν 리μ λλ€.
- Java 21 μ΄μ
- Gradle 8 μ΄μ
- MySQL 8 μ΄μ
- Redis 6 μ΄μ
- Google OAuth2 ν΄λΌμ΄μΈνΈ μμ± λ° API ν€ λ°κΈ
- Resend κ³μ μμ± λ° API ν€ λ°κΈ
# μμ‘΄μ± μ€μΉ λ° λΉλ
./gradlew build -x testapplication.ymlμμ μ°Έμ‘°νλ νκ²½ λ³μ λͺ©λ‘μ
λλ€. λ‘컬 μ€ν μ .env λλ IDE μ€ν ꡬμ±μ μλ λ³μλ₯Ό μ€μ ν©λλ€.
# βββ Database βββββββββββββββββββββββββββββββββββββββββββ
DB_URL=jdbc:mysql://localhost:3306/flipnote_user
DB_USERNAME=
DB_PASSWORD=
# βββ Redis ββββββββββββββββββββββββββββββββββββββββββββββ
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# βββ JPA ββββββββββββββββββββββββββββββββββββββββββββββββ
# create | create-drop | update | validate | none
DDL_AUTO=update
# βββ gRPC βββββββββββββββββββββββββββββββββββββββββββββββ
GRPC_PORT=9092
# βββ JWT ββββββββββββββββββββββββββββββββββββββββββββββββ
JWT_SECRET=
# μ‘μΈμ€ ν ν° λ§λ£ μκ° (ms), κΈ°λ³Έκ° 900000 (15λΆ)
JWT_ACCESS_EXPIRATION=900000
# 리νλ μ ν ν° λ§λ£ μκ° (ms), κΈ°λ³Έκ° 604800000 (7μΌ)
JWT_REFRESH_EXPIRATION=604800000
# βββ Email (Resend) βββββββββββββββββββββββββββββββββββββ
APP_RESEND_API_KEY=
# βββ Client βββββββββββββββββββββββββββββββββββββββββββββ
# νλ‘ νΈμλ URL (CORS, 리λ€μ΄λ νΈμ μ¬μ©)
APP_CLIENT_URL=http://localhost:3000
# βββ Google OAuth2 ββββββββββββββββββββββββββββββββββββββ
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
β οΈ μ£Όμ: νκ²½ λ³μ νμΌμ μ λ gitμ 컀λ°νμ§ λ§μΈμ..gitignoreμ ν¬ν¨λμ΄ μλμ§ λ°λμ νμΈνμΈμ.
./gradlew bootRunκΈ°λ³Έμ μΌλ‘ http://localhost:8081μμ μ€νλ©λλ€.
Swagger UIλ http://localhost:8081/users/swagger-ui.htmlμμ νμΈν μ μμ΅λλ€.
./gradlew bootJarbuild/libs/user-0.0.1-SNAPSHOT.jar νμΌμ΄ μμ±λ©λλ€.
./gradlew test# μ΄λ―Έμ§ λΉλ
docker build -t flipnote-user .
# 컨ν
μ΄λ μ€ν
docker run -p 8081:8081 \
-e DB_URL=... \
-e JWT_SECRET=... \
flipnote-usermain λΈλμΉμ push μ GitHub Actionsκ° μλμΌλ‘ μλ κ³Όμ μ μ€νν©λλ€.
CI (push / pull_request β main)
- JDK 21 μ€μΉ
./gradlew build -x testβ λΉλ κ²μ¦./gradlew testβ ν μ€νΈ μ€ν- Dependency-Check β μ·¨μ½μ λΆμ 리ν¬νΈ μμ±
CD (push β main)
- GitHub Container Registry(GHCR) λ‘κ·ΈμΈ
- Docker μ΄λ―Έμ§ λΉλ
ghcr.io/dungbik/flipnote-userμ΄λ―Έμ§ Push
λ°°ν¬μ νμν μν¬λ¦Ώ(
ORG_PAT)μ GitHub Repository β Settings β Secrets and variables β Actionsμ λ±λ‘ν΄μΌ ν©λλ€.
-
κ°λ΅ν λ²μ
src/main/java/flipnote/user/ βββ domain/ # λλ©μΈ λ μ΄μ΄ (μν°ν°, λ ν¬μ§ν 리, μλ¬μ½λ, μ΄λ²€νΈ) βββ application/ # μ ν리μΌμ΄μ λ μ΄μ΄ (μλΉμ€, 컀맨λ, κ²°κ³Ό κ°μ²΄) βββ infrastructure/ # μΈνλΌ λ μ΄μ΄ (JWT, Redis, λ©μΌ, OAuth, μ€μ ) βββ interfaces/ # μΈν°νμ΄μ€ λ μ΄μ΄ (HTTP, gRPC μ§μ μ )
FlipNote-User/
βββ src/
β βββ main/
β β βββ java/flipnote/user/
β β β βββ UserApplication.java
β β β β
β β β βββ domain/ # λλ©μΈ λ μ΄μ΄
β β β β βββ common/ # λλ©μΈ 곡ν΅
β β β β β βββ ErrorCode.java
β β β β β βββ BizException.java
β β β β β βββ EmailSendException.java
β β β β βββ entity/ # JPA μν°ν°
β β β β β βββ User.java
β β β β β βββ OAuthLink.java
β β β β β βββ BaseEntity.java
β β β β βββ repository/ # λ ν¬μ§ν 리 μΈν°νμ΄μ€
β β β β β βββ UserRepository.java
β β β β β βββ OAuthLinkRepository.java
β β β β βββ event/ # λλ©μΈ μ΄λ²€νΈ
β β β β β βββ EmailVerificationSendEvent.java
β β β β β βββ PasswordResetCreateEvent.java
β β β β βββ AuthErrorCode.java
β β β β βββ UserErrorCode.java
β β β β βββ ImageErrorCode.java
β β β β βββ TokenClaims.java
β β β β βββ TokenPair.java
β β β β βββ PasswordResetConstants.java
β β β β βββ VerificationConstants.java
β β β β
β β β βββ application/ # μ ν리μΌμ΄μ
λ μ΄μ΄
β β β β βββ command/ # μλΉμ€ μ
λ ₯ 컀맨λ (κ²μ¦ μ΄λ
Έν
μ΄μ
μμ)
β β β β β βββ SignupCommand.java
β β β β β βββ LoginCommand.java
β β β β β βββ ChangePasswordCommand.java
β β β β β βββ UpdateProfileCommand.java
β β β β βββ result/ # μλΉμ€ μΆλ ₯ κ²°κ³Ό κ°μ²΄ (νλ‘ν μ½ λ¬΄κ΄)
β β β β β βββ UserResult.java
β β β β β βββ UserRegisterResult.java
β β β β β βββ MyInfoResult.java
β β β β β βββ UserInfoResult.java
β β β β β βββ UserUpdateResult.java
β β β β β βββ TokenValidateResult.java
β β β β β βββ SocialLinkResult.java
β β β β β βββ SocialLinksResult.java
β β β β βββ AuthService.java
β β β β βββ OAuthService.java
β β β β βββ UserService.java
β β β β
β β β βββ infrastructure/ # μΈνλΌ λ μ΄μ΄
β β β β βββ config/ # λ²μ© μ€μ (App, JPA, Swagger, gRPC ν΄λΌμ΄μΈνΈ)
β β β β βββ jwt/ # JWT λ°κΈ/κ²μ¦ + μ€μ
β β β β βββ mail/ # λ©μΌ λ°μ‘ μλΉμ€ + μ€μ + μ½λ μμ±
β β β β βββ oauth/ # Google OAuth2 ν΄λΌμ΄μΈνΈ + μ€μ
β β β β βββ redis/ # Redis μ μ₯μ (ν ν°, μΈμ¦μ½λ λ±)
β β β β βββ listener/ # λλ©μΈ μ΄λ²€νΈ 리μ€λ
β β β β
β β β βββ interfaces/ # μΈν°νμ΄μ€ λ μ΄μ΄
β β β βββ http/ # HTTP μ§μ
μ
β β β β βββ AuthController.java # μΈμ¦ (νμκ°μ
, λ‘κ·ΈμΈ, λΉλ°λ²νΈ λ±)
β β β β βββ OAuthController.java # μμ
λ‘κ·ΈμΈ (Google OAuth2)
β β β β βββ UserController.java # μ μ μ 보 μ‘°ν/μμ
β β β β βββ dto/request/ # HTTP Request DTO (@Valid ν¬ν¨)
β β β β βββ common/ # ApiResponse, μμΈ μ²λ¦¬, μΏ ν€ μ νΈ
β β β βββ grpc/ # gRPC μ§μ
μ
β β β βββ GrpcUserQueryService.java # μ μ μ‘°ν gRPC μλΉμ€
β β β βββ GrpcExceptionHandlerImpl.java # gRPC μ μ μμΈ μ²λ¦¬
β β β
β β βββ proto/ # gRPC proto νμΌ
β β β βββ user_query.proto
β β β βββ image.proto
β β β
β β βββ resources/
β β βββ application.yml
β β βββ templates/email/ # μ΄λ©μΌ HTML ν
νλ¦Ώ (Thymeleaf)
β β βββ email-verification.html
β β βββ password-reset.html
β β
β βββ test/
β βββ java/flipnote/user/
β
βββ Dockerfile
βββ build.gradle.kts
βββ settings.gradle.kts