4/7 - trakingId

@UuidGenerator
@JdbcTypeCode(Types.VARCHAR)
@Column(length = 36, nullable = false, unique = true)
private UUID trackingId;

4/8 도메인 에러코드 정의 (예제 코드입니다.)

@RequiredArgsConstructor
@Getter
public enum ExampleCode implements BaseError {

  EXAMPLE_CODE1(HttpStatus.BAD_REQUEST, 200, "성공적으로 처리되었습니다."),
  EXAMPLE_CODE2(HttpStatus.BAD_REQUEST, 201, "성공적으로 생성되었습니다."),
  EXAMPLE_CODE3(HttpStatus.BAD_REQUEST, 202, "이미 존재하는 리소스입니다."),

  ;

private final HttpStatus status;
  private final Integer code;
  private final String message;

}

4/8 도메인 익셉션 정의 (권고:필수는아니지만 하는걸 추천함) (예제 코드입니다.)

public class ExampleException extends BaseException {

public ExampleException(ExampleCode exampleCode) {
super(exampleCode);
}
}

4/18 카프카 consumer 처리를 하니 kafka-ui가 뻑나간 사건에 대하여…

아래와 같이 Docker-compose를 구성하면 해결된다

kafka internal, external 설정을 해주어야 인식을 한다.

version: '3.8'

services:
  mysql:
    image: mysql:latest
    container_name: mysql_db_chat
    environment:
      MYSQL_ROOT_PASSWORD: moimserver
      MYSQL_DATABASE: chat
      MYSQL_USER: chat
      MYSQL_PASSWORD: moimserver
    ports:
      - "3313:3306"
    volumes:
      - mysql-data-chat:/var/lib/mysql
    networks:
      - app-network

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: phpmyadmin_chat
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: chat
      PMA_PASSWORD: moimserver
    ports:
      - "18087:80"
    depends_on:
      - mysql
    networks:
      - app-network

  mongodb:
    image: mongo:latest
    container_name: mongodb_chat
    environment:
      MONGO_INITDB_ROOT_USERNAME: chat
      MONGO_INITDB_ROOT_PASSWORD: moimserver
    ports:
      - "27017:27017"
    volumes:
      - mongodb-data-chat:/data/db
    networks:
      - app-network

  mongo-express:
    image: mongo-express:latest
    container_name: mongo_express_chat
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: chat
      ME_CONFIG_MONGODB_ADMINPASSWORD: moimserver
      ME_CONFIG_MONGODB_SERVER: mongodb
      ME_CONFIG_BASICAUTH_USERNAME: admin
      ME_CONFIG_BASICAUTH_PASSWORD: moimserver
    ports:
      - "18081:8081"
    depends_on:
      - mongodb
    networks:
      - app-network

  zookeeper:
    image: bitnami/zookeeper:3.9
    container_name: zookeeper
    ports:
      - "2181:2181"
    volumes:
      - zookeeper-data-chat:/bitnami/zookeeper # ZooKeeper 데이터 지속성을 위해 볼륨 추가
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
    networks:
      - app-network

  kafka:
    image: bitnami/kafka:3.6
    container_name: kafka
    ports:
      - "9092:9092"     # 외부 접근용 (localhost:9092)
      - "29092:29092"   # 내부 접근용 (kafka:29092)
    environment:
      - KAFKA_BROKER_ID=1
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
      # 두 개의 리스너 구성
      - KAFKA_LISTENERS=EXTERNAL://0.0.0.0:9092,INTERNAL://0.0.0.0:29092
      - KAFKA_ADVERTISED_LISTENERS=EXTERNAL://localhost:9092,INTERNAL://kafka:29092
      - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=EXTERNAL:PLAINTEXT,INTERNAL:PLAINTEXT
      - KAFKA_INTER_BROKER_LISTENER_NAME=INTERNAL
      - ALLOW_PLAINTEXT_LISTENER=yes
    volumes:
      - kafka-data-chat:/bitnami/kafka
    depends_on:
      - zookeeper
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "kafka-topics --bootstrap-server localhost:9092 --list || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5

  kafka-ui:
    image: provectuslabs/kafka-ui:v0.7.1
    container_name: kafka-ui
    ports:
      - "19092:8080"
    environment:
      - KAFKA_CLUSTERS_0_NAME=local
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:29092
#      - KAFKA_CLUSTERS_0_ZOOKEEPER=zookeeper:2181
#      - DYNAMIC_CONFIG_ENABLED=true
    depends_on:
      - kafka
#      - zookeeper
    networks:
      - app-network

volumes:
  mysql-data-chat:
  mongodb-data-chat:
  kafka-data-chat:
  zookeeper-data-chat:

networks:
  app-network:
    driver: bridge

Code 인터페이스화 - 제안합니다 (규원)


기존 Code

package com.sparta.moim.common.response;

import java.util.Optional;
import java.util.function.Predicate;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum Code {
  /**
   * 성공
   * 200번대
   */
  SUCCESS(HttpStatus.OK, 200, "성공적으로 처리되었습니다."),
  CREATED(HttpStatus.CREATED, 201, "성공적으로 생성되었습니다."),
  ALREADY_EXISTS(HttpStatus.OK, 202, "이미 존재하는 리소스입니다."),

  /**
   * 500번대
   */
  INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 500, "예기치 못한 서버 오류가 발생했습니다."),
  INTERNAL_SERVER_MINIO_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 500, "Minio 서버 오류가 발생했습니다."),
  ;

  private final HttpStatus status;
  private final Integer code;
  private final String message;

  public String getMessage(Throwable e) {
    return this.getMessage(this.getMessage() + " - " + e.getMessage());
    // 결과 예시 - "Validation error - Reason why it isn't valid"
  }

  public String getMessage(String message) {
    return Optional.ofNullable(message)
        .filter(Predicate.not(String::isBlank))
        .orElse(this.getMessage());
  }

  public String getDetailMessage(String message) {
    return this.getMessage() + " : " + message;
  }
}

변경된 코드