Skip to content

Comment: comment 모듈 추가 및 application, api 작성 #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8653bd8
feat(comment): add comment-service build gradle file
seonghooni May 3, 2025
fe8311f
fix(board): add flyway to board.database-local.yml
seonghooni May 3, 2025
11a0274
feat(comment/reply): create domain, exception, read-model to api module
seonghooni May 3, 2025
6a8053d
feat(comment/reply): create port to application module
seonghooni May 3, 2025
95edb7d
feat(comment/reply): create entity to driven/entity module
seonghooni May 3, 2025
e41ab5b
build(comment/reply): create yml, postgresql script to entity module
seonghooni May 3, 2025
223fd5d
build(comment/reply): build comment module configurations (settings.g…
seonghooni May 3, 2025
7efcd78
fix: merge conflict resolved in build.gradle.kts
seonghooni May 11, 2025
22bb9f3
fix(comment/reply): rename postgresql files
seonghooni May 11, 2025
734e71c
fix(comment/reply): fix typo/syntax in entity
seonghooni May 11, 2025
caf146d
build(comment/reply): modify build.gradle.kts, settings.gradle.kts
seonghooni May 11, 2025
de2beaa
feat(comment/reply): add EntityStatusConverter
seonghooni May 11, 2025
2a2af19
fix(comment/reply): modify comment/driven/rdb/build.gradle.kts
seonghooni May 11, 2025
746daea
fix(comment/reply): resolve conflict monolith/main-runner/build.gradl…
seonghooni May 11, 2025
970cfc4
refactor(comment/reply): add builder method to entity
seonghooni May 18, 2025
8bb4c97
refactor(comment/reply): add fk to domain
seonghooni May 18, 2025
c8814aa
feat(comment/reply): add RDB adapter(command,query)
seonghooni May 18, 2025
c4c602f
refactor(comment/reply): remove getter annotation from entity
seonghooni May 18, 2025
5b77667
refactor(comment/reply): modify function, parameter of port and adapter
seonghooni May 19, 2025
0488fb9
feat(comment/reply): add QueryService, CommandService, UseCase
seonghooni May 19, 2025
f0d73b2
refactor(comment/reply): modify readModels, port, adapter
seonghooni May 19, 2025
7097736
feat(comment/reply): add command service, query service
seonghooni May 19, 2025
a990533
feat(comment/reply): add command api, query api, dto to web-mvc module
seonghooni May 19, 2025
d0062f7
refactor(comment/reply): modify base-package according to #86
seonghooni May 19, 2025
b007832
refactor(comment/reply): add boardId field to CommentDetail
seonghooni May 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/01. main-issue.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Main Issue
description: Describe the task list.
title: "[MAIN] "
title: "☀️ "
#labels: []
#projects: []
#assignees:
Expand All @@ -9,7 +9,7 @@ body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Thanks for taking the time to fill out this issue!
# - type: input
# id: contact
# attributes:
Expand Down
93 changes: 93 additions & 0 deletions .github/ISSUE_TEMPLATE/03. bug-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Bug Report
description: Describe the bug you encountered.
title: "🐞 "
labels: ["type: bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: dropdown
id: bug-type
attributes:
label: 🐞 Bug Types (Multiple)
description: |
어떤 종류의 문제인가요?

- 🐞 오류 (에러, 예외 발생, 논리적 오류 등)
- 🏗 컨벤션·리팩터링 (코드 스타일, 아키텍처 등)
- ⚡️ 성능 (지연, 과도한 자원, 병목 현상 등)
- ✏️ 오타·설명 오류 (문서, 문자열, 주석, 식별자 등)
- 🔧 기타 (빌드, 환경변수 등)

**❗️ 보안 취약점은 pkw19961027@gmail.com으로 메일 부탁드립니다.**

<br />\* 다중 선택
multiple: true
options:
- 🐞 오류
- 🏗 컨벤션·리팩터링
- ⚡️ 성능
- ✏️ 오타·설명 오류
- 🔧 기타
default: 0
validations:
required: true
- type: input
id: summary
attributes:
label: <br /> 💬 Summary of the Bug
description: 버그를 한 문장 정도로 요약해 주세요.
placeholder: ex. 로그인 후 화면이 멈춥니다.
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: <br /> 🔁 오류 재현 (Reproduction Steps)
description: 버그를 재현하기 위한 구체적인 단계들을 순서대로 적어 주세요.
placeholder: |
1.
2.
3.

validations:
required: false
- type: textarea
id: logs
attributes:
label: <br /> 📝 관련 로그 (Logs)
description: 에러 메시지나 로그가 있다면 복사해서 붙여 주세요.
placeholder: |
Error: Cannot read property 'foo' of undefined
at …
render: console
validations:
required: false
- type: textarea
id: expected-behavior
attributes:
label: <br /> 🎯 기대 동작 (Expected Behavior)
description: 정상적으로 동작했을 때 어떤 결과가 나와야 하는지 설명해 주세요.
placeholder: ex. 로그인 후 대시보드 페이지가 보여야 합니다.
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: <br /> 🔍 실제 동작 (Actual Behavior)
description: 어떤 동작이 나타나는지 설명해 주세요.
placeholder: ex. 로그인 후 버튼이 반응하지 않습니다.
validations:
required: true
- type: textarea
id: additional-note
attributes:
label: <br /> 부연 설명 (Additional Notes)
description: 관련 브랜치나 커밋, Active profile, 환경변수 등 기타 참고할 만한 정보가 있으면 적어 주세요.
placeholder: Tell us any other details you think will help us fix this!
value: |
<!-- main 브랜치를 대상으로 하지 않을 경우, 관련 브랜치나 커밋을 명시해 주세요. -->
<!-- Active profiles, 테스트용 환경변수(공개 가능한 범위만) 등 필요한 정보를 입력해 주세요. -->
validations:
required: false
18 changes: 15 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Pull Request

## Issues

- Resolves #0
Expand All @@ -11,12 +9,26 @@
- 주요 변경 사항에 대한 간단한 설명을 작성해 주세요.
- 관련 이슈 번호를 포함해 주세요 (예: `#123`).

<br />

## Review Points

<!-- 리뷰어가 중점적으로 확인해야 할 항목을 작성해 주세요. -->
<!-- (Ex: 구현 로직, API 스펙, 테스트 케이스 등) -->

- 상세한 리뷰를 원하는 영역은 작업 의도와 함께 설명해 주세요.

<br />

## How Has This Been Tested?

- 변경 사항을 테스트하는 방법에 대해 설명해 주세요.
- 어떤 환경에서 테스트가 이루어졌는지 명시해 주세요.

<!-- 테스트를 생략하거나 육안으로 실행만 확인했다고 쓸 수도 있습니다. -->

<br />

## Additional Notes

- 이 PR과 관련된 추가적인 정보가 있다면 여기에 기재해 주세요.

14 changes: 11 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ plugins {
}

allprojects {
group = "me.nettee"
version = "1.0-SNAPSHOT"

repositories {
mavenCentral()
}
Expand All @@ -34,7 +31,18 @@ subprojects {
}
}

configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
configureEach {
exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
}
}

dependencies {
// FIXME determine the placement of logging library later
implementation("org.springframework.boot:spring-boot-starter-log4j2")
if(project.name != "common") {
api(project(":common"))
}
Expand Down
8 changes: 6 additions & 2 deletions core/core.settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ include(
":jpa-core",
":exception-handler-core",
":cors-api",
":cors-webmvc"
":cors-webmvc",
":snowflake-id-api",
":snowflake-id-hibernate",
)

project(":jpa-core").projectDir = core["jpa-core"]!!
project(":exception-handler-core").projectDir = core["exception-handler-core"]!!
project(":cors-webmvc").projectDir = core["nettee-cors-webmvc"]!!
project(":cors-api").projectDir = core["nettee-cors-api"]!!
project(":cors-api").projectDir = core["nettee-cors-api"]!!
project(":snowflake-id-api").projectDir = core["nettee-snowflake-id-api"]!!
project(":snowflake-id-hibernate").projectDir = core["nettee-snowflake-id-hibernate"]!!
3 changes: 2 additions & 1 deletion core/jpa-core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
api(project(":snowflake-id-hibernate"))
api("org.springframework.boot:spring-boot-starter-data-jpa")

// querydsl
implementation("com.querydsl:querydsl-jpa:${dependencyManagement.importedProperties["querydsl.version"]}:jakarta")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package nettee.jpa.support;

import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import nettee.hibenate.annotation.SnowflakeGenerated;

import java.io.Serializable;

@Getter
@MappedSuperclass
public abstract class SnowflakeBaseEntity implements Serializable {
@Id
@SnowflakeGenerated
private Long id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package nettee.jpa.support;

import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.Instant;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class SnowflakeBaseTimeEntity extends SnowflakeBaseEntity {
@CreatedDate
private Instant createdAt;

@LastModifiedDate
private Instant updatedAt;
}
3 changes: 3 additions & 0 deletions core/snowflake/nettee-snowflake-id-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies {
compileOnly("org.springframework.boot:spring-boot-autoconfigure:3.4.3")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package nettee.snowflake.constants;

public final class SnowflakeConstants {
// 한국 시간(KST): 2025-03-26 23:40:00 기준점
public static final long NETTEE_EPOCH = 1_743_000_000_000L;
public static final String PREFIX = "nettee.persistence.snowflake";

private SnowflakeConstants() {}

public static final class SnowflakeDefault {
public static final int WORKER_ID_BIT_SIZE = 5;
public static final int DATACENTER_ID_BIT_SIZE = 5;
public static final int SEQUENCE_BIT_SIZE = 12;

public static final int WORKER_ID_SHIFT = SEQUENCE_BIT_SIZE;
public static final int DATACENTER_ID_SHIFT = SEQUENCE_BIT_SIZE + WORKER_ID_BIT_SIZE;
public static final int TIMESTAMP_LEFT_SHIFT = SEQUENCE_BIT_SIZE + WORKER_ID_BIT_SIZE + DATACENTER_ID_BIT_SIZE;

public static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BIT_SIZE);
public static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BIT_SIZE);
public static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BIT_SIZE);

private SnowflakeDefault() {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nettee.snowflake.exception;

import static nettee.snowflake.constants.SnowflakeConstants.SnowflakeDefault.MAX_DATACENTER_ID;

public class InvalidDatacenterIdException extends RuntimeException {

private final long datacenterId;

public InvalidDatacenterIdException(long datacenterId) {
super("Datacenter ID can't be greater than %d or less than 0. Input: %d"
.formatted(MAX_DATACENTER_ID, datacenterId));
this.datacenterId = datacenterId;
}

public long getDatacenterId() {
return datacenterId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nettee.snowflake.exception;

import static nettee.snowflake.constants.SnowflakeConstants.SnowflakeDefault.MAX_WORKER_ID;

public class InvalidWorkerIdException extends RuntimeException{

private final long workerId;

public InvalidWorkerIdException(final long workerId) {
super("Worker ID can't be greater than %d or less than 0. Input: %d"
.formatted(MAX_WORKER_ID, workerId));
this.workerId = workerId;
}

public long getWorkerId() {
return workerId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package nettee.snowflake.persistence.id;

import nettee.snowflake.properties.SnowflakeProperties;
import nettee.snowflake.validator.SnowflakeConstructingValidator;

import static nettee.snowflake.constants.SnowflakeConstants.NETTEE_EPOCH;
import static nettee.snowflake.constants.SnowflakeConstants.SnowflakeDefault.*;

public class Snowflake {
private final long datacenterId;
private final long workerId;
private final long epoch;

private long sequence = 0L;
private long lastTimestamp = -1L;

public Snowflake(SnowflakeProperties properties) {
this(properties.datacenterId(), properties.workerId(), properties.epoch());
}

public Snowflake(long datacenterId, long workerId, long epoch) {
SnowflakeConstructingValidator.validateDatacenterId(datacenterId);
SnowflakeConstructingValidator.validateWorkerId(workerId);

this.workerId = workerId;
this.datacenterId = datacenterId;
this.epoch = epoch >= 0 ? epoch : NETTEE_EPOCH;
}

public synchronized long nextId() {
long timestamp = timeGen();

if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp
));
}

if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}

lastTimestamp = timestamp;
return ((timestamp - epoch) << TIMESTAMP_LEFT_SHIFT) |
(datacenterId << DATACENTER_ID_SHIFT) |
(workerId << WORKER_ID_SHIFT) |
sequence;
}

private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}

private long timeGen() {
return System.currentTimeMillis();
}
}
Loading