Skip to content

feat : 백엔드 core 서버 기본 세팅#8

Merged
i3months merged 19 commits into
devfrom
feature/backend-setup
May 13, 2026
Merged

feat : 백엔드 core 서버 기본 세팅#8
i3months merged 19 commits into
devfrom
feature/backend-setup

Conversation

@pswaao88

Copy link
Copy Markdown
Contributor

변경 사항

  • Gradle 기반 의존성 정리
    • validation, security, amqp, actuator
    • Flyway, PostgreSQL, Springdoc, AWS SDK v2, Nimbus JWT
    • Testcontainers, ArchUnit
  • application.yml / profile 분리
    • local, test 환경 설정 분리
    • @ConfigurationProperties 기반 타입 안전 설정 관리
  • DB 스키마 정리
    • Flyway V1 초기 스키마 추가
    • JPA 엔티티와 DB 구조 정합성 맞춤
    • AnalyzedDocument의 sourceType/sourceId 구조 정리
  • 공통 기반 추가
    • API 에러 코드 / 예외 처리
    • 표준 에러 응답
    • traceId 필터
    • 민감정보 마스킹 유틸
  • 인증/보안 foundation
    • JWT access token 생성/검증
    • SecurityConfig
    • JWT 인증 필터
    • GitHub OAuth / refresh / logout / SSE stream token skeleton
  • SSE / RabbitMQ foundation
    • SSE emitter registry
    • SSE event model / keep-alive scheduler
    • RabbitMQ exchange / routing key / envelope / publisher
  • S3 ObjectStorage abstraction
    • ObjectStorageClient 포트
    • S3ObjectStorageClient 어댑터
    • StoredObject, StorageException
  • system health endpoint
    • /api/system/live
    • /api/system/ready
    • /api/system/health
  • 아키텍처 검증 테스트
    • domain/application/presentation 의존 방향 검증
    • Entity 규칙 검증
    • Transactional 위치 검증

검증

  • 로컬 PostgreSQL / RabbitMQ 컨테이너 기반 실행 확인
  • 앱 기동 및 Flyway/JPA 연결 확인

pswaao88 added 18 commits May 10, 2026 10:35
현재 필요한 의존성 추가
validation, security, amqp, flyway, openapi, s3, jwt, archunit, testcontainer 추가
yml 설정값 common/properties로 관리
docs의 database.md를 통해 flyway V1 추가
핵심 테이블에 대해서 인덱스 반영
user token을 encryptedToken으로 변경
consentType을 enum으로 정렬
시간 필드 Instant로 변경
status enum으로 변경
시간 Instant로 변경
status enum 변경
AnalyzedDocument source 부분 제거 후 FK관계로 정리
status 를 enum으로 변경 및 시간 Instant로 변경
status enum으로 변경 및 제약 조건 반영
HTTP 요청에 x-trace-id 부여
MDC에 저장하는 TraceFilter 추가
응답 헤더 및 어레 응답에 traceID를 포함해 ID로 추적가능
email 등등 로그에 남지 않도록 PilMasker 추가
각 계층별 의존 방향, Entitiy 위치 등 아키텍처 규칙을 ArchUnit으로 검증
JWT access token 생성/검증
Bearer token 인증 필터 추가
API 스켈레톤으로 구성
SSE emitter, event model 등추가
core AI간 비동기 메세지 기반 생성
linve, ready, health 엔드 포인트 추가
S3 및 MinIO 의존하지 않도록 추상화 하여 추가
@vercel

vercel Bot commented May 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stackup Ready Ready Preview, Comment May 12, 2026 4:24pm

long userId,
String githubUsername
) {
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

record 좋네요 코드 간결 굿

public class AuthService {

private static final long SKELETON_USER_ID = 1L;
private static final String SKELETON_GITHUB_USERNAME = "stackup-user";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

이부분은 임시로 작성한거겠죠?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

흐름 테스트를 위해서 임시 값 작성하고 나중에 로직 구현시에 없앨 예정입니다.


@Column(name = "expires_at", nullable = false)
private LocalDateTime expiresAt;
private Instant expiresAt;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[질문] 오 Instant는 어떤 차이가 있나요. 시간대 표현 시 저 방식이 더 효과적일까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

기존 LocalDatetime 자체가 상대적으로 표시가 될 수 있어서
UTC 같은 시간대를 표시한 Instant를 통해 절대적인 시간 계산이 돼서 토큰 관리가 효과적일 거 같습니다.

private final AuthService authService;

public AuthController(AuthService authService) {
this.authService = authService;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

이 부분 보다는 자동 DI 사용하는편이 좋아보입니다.
스프링이 알아서 DI 해줄거에요 저거 안써도

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

오 다른 방법이 있군요 한번 찾아보겠습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

찾아본결과 record클래스로 변경하는거 같아서 controller를 record로 변경했습니다.

ACCESS_DENIED(HttpStatus.FORBIDDEN, "접근 권한이 없습니다."),

SYS_RATE_LIMITED(HttpStatus.TOO_MANY_REQUESTS, "요청이 너무 많습니다."),
SYS_DEPENDENCY_DOWN(HttpStatus.SERVICE_UNAVAILABLE, "필수 외부 의존성이 응답하지 않습니다."),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

에러코드를 ENUM으로 정의하셨군요 좋습니다

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(DomainException.class)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

DomainException이 하위 예외들의 부모라면 여기서 함께 잡히지 않을까 싶네요
GlobalExceptionHandler 에서는 하위 예외들도 모두 정의하는걸까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

각 하위 예외들이 GlobalExceptionHanlder에 잡혀서 도메인에 대한 예외를 처리해 구조를 단순화를 하려고 했고 각 상황에 맞는 ApiErrorCode (enum)으로 응답 형식을 통일하려고 했습니다.

@@ -0,0 +1,105 @@
package com.stackup.stackup.common.log;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

log 하위에 있는 이유는 로깅 시 사용자 개인정보를 제거하기 위해서일까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

맞습니다 로그에 남길시 개인정보를 남기지 않기 위한 마스킹 유틸이고 log과 연관이 깊다고 생각해서 log 하위애 두었습니다.

public class RabbitMessagePublisher {

private static final String VERSION = "v1";
private static final String PUBLISHER = "core-server";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

이부분은 아예 yml 이나 다른 쪽으로 빼는것도 좋아보입니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

해당 변수 yml로 빼도록 하겠습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

해당 변수 뿐만 아니라 RabbitMQ관련 하드코딩된 변수들 전부 applicaion.yml로 옮겨서 properties에 주입해 사용하도록 변경했습니다.


public class StorageException extends RuntimeException {

public StorageException(String message) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

StorageExcpetion은 저장소 관련 오류를 모두 정의하는 듯 하네요.
DomainException과는 어떻게 연관되는지 궁금합니다.

그리고 StorageException 전용 Type도 만들어두면 좋을듯합니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

StorageExcpetion의 경우 저장소 관련 인프라 예외기 때문에DomainException과는 연결이 되어있지 않습니다. 지금 구조에는 Exception.class로 핸들러가 처리하기 때문에 전용 Type 만들도록 하겠습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Storage전용 Type 만들고 GlobalHandler가 StorageExcpetion 잡도록 만들었습니다.

@Table(
name = "analyzed_documents",
indexes = {
@Index(name = "idx_analyzed_docs_source", columnList = "source_type, source_id")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

인덱스는 나중에 한 번에 잡는것도 좋아보입니다.

application: rabbit MQ message관련 정의
apllicaion-local: Rabbit MQ 접속을 위한 값
@i3months i3months merged commit bec9c78 into dev May 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants