Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
root = true

[*.{kt,kts}]
max_line_length=130
insert_final_newline = true

ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ij_kotlin_packages_to_use_import_on_demand = unset

ktlint_code_style = INTELLIJ_IDEA
ktlint_standard_package-name = disabled
ktlint_standard_function-signature = disabled
ktlint_standard_import-ordering = disabled
ktlint_standard_indent = disabled

[*Test.kt]
max_line_length = off
22 changes: 11 additions & 11 deletions .github/workflows/dev-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,34 @@ jobs:

- name: Create application-dev.yml
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.PROPERTIES_DEV }}" > ./src/main/resources/application-dev.yml
mkdir -p ./apps/juinjang-api/src/main/resources
echo "${{ secrets.PROPERTIES_DEV }}" > ./apps/juinjang-api/src/main/resources/application-dev.yml
shell: bash

- name: Create .p8
run: |
echo "${{ secrets.APPLE_AUTH }}" > ./src/main/resources/AUTHKEY_JUINJAG.p8
echo "${{ secrets.APPLE_AUTH }}" > ./apps/juinjang-api/src/main/resources/AUTHKEY_JUINJAG.p8
shell: bash

# APPLE IN_APP 결제 관련 프로세스 시작
- name: Create certs and keys directories
run: |
mkdir -p ./src/main/resources/keys
mkdir -p ./apps/juinjang-api/src/main/resources/keys

- name: Create IAP .p8 Key
run: |
echo "${{ secrets.APPLE_IAP_KEY }}" > ./src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8
echo "${{ secrets.APPLE_IAP_KEY }}" > ./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8

# 키 파일 크기 확인 (내용은 로그에 출력하지 않음)
if [ -s "./src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8" ]; then
echo "✅ IAP key file created: $(wc -c < ./src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8) bytes"
if [ -s "./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8" ]; then
echo "✅ IAP key file created: $(wc -c < ./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8) bytes"
else
echo "❌ IAP key file is empty!"
exit 1
fi

# PEM 형식 확인
if grep -q "BEGIN PRIVATE KEY" ./src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8; then
if grep -q "BEGIN PRIVATE KEY" ./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_Q5646J7W54.p8; then
echo "✅ IAP key file appears to be in PEM format"
else
echo "⚠️ IAP key file may not be in PEM format"
Expand All @@ -72,7 +72,7 @@ jobs:
# APPLE IN_APP 결제 관련 프로세스 끝

- name: Build With Gradle
run: ./gradlew build -x test
run: ./gradlew :apps:juinjang-api:build -x test

- name: Login to Docker Hub
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/dev-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ jobs:

- name: Create application-dev.yml
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.PROPERTIES_DEV }}" > ./src/main/resources/application-dev.yml
mkdir -p ./apps/juinjang-api/src/main/resources
echo "${{ secrets.PROPERTIES_DEV }}" > ./apps/juinjang-api/src/main/resources/application-dev.yml
shell: bash

- name: Build With Gradle
run: ./gradlew build -x test
run: ./gradlew :apps:juinjang-api:build -x test
18 changes: 9 additions & 9 deletions .github/workflows/prod-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,34 @@ jobs:

- name: Create application-prod.yml
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.PROPERTIES_PROD }}" > ./src/main/resources/application-prod.yml
mkdir -p ./apps/juinjang-api/src/main/resources
echo "${{ secrets.PROPERTIES_PROD }}" > ./apps/juinjang-api/src/main/resources/application-prod.yml
shell: bash

- name: Create .p8
run: |
echo "${{ secrets.APPLE_AUTH }}" > ./src/main/resources/AUTHKEY_JUINJAG.p8
echo "${{ secrets.APPLE_AUTH }}" > ./apps/juinjang-api/src/main/resources/AUTHKEY_JUINJAG.p8
shell: bash

# APPLE IN_APP 결제 관련 프로세스 시작
- name: Create certs and keys directories
run: |
mkdir -p ./src/main/resources/keys
mkdir -p ./apps/juinjang-api/src/main/resources/keys

- name: Create IAP .p8 Key
run: |
echo "${{ secrets.APPLE_IAP_KEY_PROD }}" > ./src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8
echo "${{ secrets.APPLE_IAP_KEY_PROD }}" > ./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8

# 키 파일 크기 확인 (내용은 로그에 출력하지 않음)
if [ -s "./src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8" ]; then
echo "✅ IAP key file created: $(wc -c < ./src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8) bytes"
if [ -s "./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8" ]; then
echo "✅ IAP key file created: $(wc -c < ./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8) bytes"
else
echo "❌ IAP key file is empty!"
exit 1
fi

# PEM 형식 확인
if grep -q "BEGIN PRIVATE KEY" ./src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8; then
if grep -q "BEGIN PRIVATE KEY" ./apps/juinjang-api/src/main/resources/keys/SubscriptionKey_62QGYSCKW2.p8; then
echo "✅ IAP key file appears to be in PEM format"
else
echo "⚠️ IAP key file may not be in PEM format"
Expand All @@ -72,7 +72,7 @@ jobs:
# APPLE IN_APP 결제 관련 프로세스 끝

- name: Build With Gradle
run: ./gradlew build -x test
run: ./gradlew :apps:juinjang-api:build -x test

- name: Login to Docker Hub
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prod-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ jobs:
run: chmod +x gradlew

- name: Build With Gradle
run: ./gradlew build -x test
run: ./gradlew :apps:juinjang-api:build -x test
6 changes: 1 addition & 5 deletions Dockerfile-dev
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
FROM eclipse-temurin:17-jdk

ARG JAR_FILE=./build/libs/juinjang-0.0.1-SNAPSHOT.jar
ARG JAR_FILE=./apps/juinjang-api/build/libs/juinjang-api-0.0.1-SNAPSHOT.jar
ENV GOOGLE_APPLICATION_CREDENTIALS=/app/config/service-account-key.json
COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/var/heapdumps/juinjang", "-Dspring.profiles.active=dev", "-jar", "/app.jar"]




5 changes: 1 addition & 4 deletions Dockerfile-prod
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
FROM eclipse-temurin:17-jdk

ARG JAR_FILE=./build/libs/juinjang-0.0.1-SNAPSHOT.jar
ARG JAR_FILE=./apps/juinjang-api/build/libs/juinjang-api-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/var/heapdumps/juinjang", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]



55 changes: 55 additions & 0 deletions apps/juinjang-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
plugins {
id("org.springframework.boot")
kotlin("jvm")
kotlin("plugin.spring")
kotlin("plugin.jpa")
id("org.jlleitschuh.gradle.ktlint")
}

tasks.named<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") {
archiveBaseName.set("juinjang-api")
}

tasks.named<Jar>("jar") { enabled = false }

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}

dependencies {
// Kotlin
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

// Spring Boot
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-aop")

// Spring Cloud
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")

// Spring Retry
implementation("org.springframework.retry:spring-retry")

// Redis
implementation("org.springframework.boot:spring-boot-starter-data-redis")

// Documentation
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")

// Database
runtimeOnly("com.mysql:mysql-connector-j")
runtimeOnly("com.h2database:h2")

// Test
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("com.ninja-squad:springmockk:4.0.2")
testImplementation("org.mockito:mockito-core:5.14.0")
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
testImplementation("org.instancio:instancio-junit:5.0.2")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package umc.th.juinjang.config.AppConfig.model;

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;


/**
* QAppConfig is a Querydsl query type for AppConfig
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QAppConfig extends EntityPathBase<AppConfig> {

private static final long serialVersionUID = 473934270L;

public static final QAppConfig appConfig = new QAppConfig("appConfig");

public final StringPath configKey = createString("configKey");

public final StringPath configValue = createString("configValue");

public final StringPath description = createString("description");

public final DateTimePath<java.time.LocalDateTime> updatedAt = createDateTime("updatedAt", java.time.LocalDateTime.class);

public QAppConfig(String variable) {
super(AppConfig.class, forVariable(variable));
}

public QAppConfig(Path<? extends AppConfig> path) {
super(path.getType(), path.getMetadata());
}

public QAppConfig(PathMetadata metadata) {
super(AppConfig.class, metadata);
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package umc.th.juinjang.domain.checklist.model;

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;


/**
* QChecklistAnswer is a Querydsl query type for ChecklistAnswer
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QChecklistAnswer extends EntityPathBase<ChecklistAnswer> {

private static final long serialVersionUID = -1311778812L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QChecklistAnswer checklistAnswer = new QChecklistAnswer("checklistAnswer");

public final umc.th.juinjang.domain.common.QBaseEntity _super = new umc.th.juinjang.domain.common.QBaseEntity(this);

public final StringPath answer = createString("answer");

public final NumberPath<Long> answerId = createNumber("answerId", Long.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> createdAt = _super.createdAt;

public final umc.th.juinjang.domain.limjang.model.QLimjang limjangId;

public final QChecklistQuestionShort questionId;

//inherited
public final DateTimePath<java.time.LocalDateTime> updatedAt = _super.updatedAt;

public QChecklistAnswer(String variable) {
this(ChecklistAnswer.class, forVariable(variable), INITS);
}

public QChecklistAnswer(Path<? extends ChecklistAnswer> path) {
this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS));
}

public QChecklistAnswer(PathMetadata metadata) {
this(metadata, PathInits.getFor(metadata, INITS));
}

public QChecklistAnswer(PathMetadata metadata, PathInits inits) {
this(ChecklistAnswer.class, metadata, inits);
}

public QChecklistAnswer(Class<? extends ChecklistAnswer> type, PathMetadata metadata, PathInits inits) {
super(type, metadata, inits);
this.limjangId = inits.isInitialized("limjangId") ? new umc.th.juinjang.domain.limjang.model.QLimjang(forProperty("limjangId"), inits.get("limjangId")) : null;
this.questionId = inits.isInitialized("questionId") ? new QChecklistQuestionShort(forProperty("questionId")) : null;
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package umc.th.juinjang.domain.checklist.model;

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;


/**
* QChecklistQuestionShort is a Querydsl query type for ChecklistQuestionShort
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QChecklistQuestionShort extends EntityPathBase<ChecklistQuestionShort> {

private static final long serialVersionUID = -159808208L;

public static final QChecklistQuestionShort checklistQuestionShort = new QChecklistQuestionShort("checklistQuestionShort");

public final umc.th.juinjang.domain.common.QBaseEntity _super = new umc.th.juinjang.domain.common.QBaseEntity(this);

public final ListPath<ChecklistAnswer, QChecklistAnswer> answerList = this.<ChecklistAnswer, QChecklistAnswer>createList("answerList", ChecklistAnswer.class, QChecklistAnswer.class, PathInits.DIRECT2);

public final EnumPath<ChecklistQuestionType> answerType = createEnum("answerType", ChecklistQuestionType.class);

public final EnumPath<ChecklistQuestionCategory> category = createEnum("category", ChecklistQuestionCategory.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> createdAt = _super.createdAt;

public final NumberPath<Long> questionId = createNumber("questionId", Long.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> updatedAt = _super.updatedAt;

public QChecklistQuestionShort(String variable) {
super(ChecklistQuestionShort.class, forVariable(variable));
}

public QChecklistQuestionShort(Path<? extends ChecklistQuestionShort> path) {
super(path.getType(), path.getMetadata());
}

public QChecklistQuestionShort(PathMetadata metadata) {
super(ChecklistQuestionShort.class, metadata);
}

}

Loading
Loading