From b046e01263a342e760d268c9b023bd910e3f807d Mon Sep 17 00:00:00 2001 From: pandoli365 Date: Sun, 3 May 2026 23:01:42 +0900 Subject: [PATCH] =?UTF-8?q?=EC=82=AC=EC=9D=B4=ED=8A=B8=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=95=BD=EA=B4=80=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 43 ++++-- .../bibimbap/config/UploadResourceConfig.java | 4 - .../controller/api/GameAssetController.java | 34 +++-- src/main/resources/application.properties | 23 ++++ .../webapp/WEB-INF/views/game-register.jsp | 2 +- .../webapp/WEB-INF/views/operation-policy.jsp | 122 ++++++++++++++---- src/main/webapp/WEB-INF/views/signup.jsp | 5 +- src/main/webapp/WEB-INF/views/terms.jsp | 115 ++++++++++++----- src/test/db/dev-to-live-update.sql | 105 +++++++++++++++ .../bibimbap/DbUpdateQueryGeneratorTest.java | 19 ++- 10 files changed, 368 insertions(+), 104 deletions(-) create mode 100644 src/main/resources/application.properties create mode 100644 src/test/db/dev-to-live-update.sql diff --git a/pom.xml b/pom.xml index 6525f76..05112c9 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 3.3.1 3.5.5 3.4.0 + dev @@ -117,11 +118,19 @@ org.apache.maven.plugins maven-resources-plugin ${maven-resources-plugin.version} + + ${project.build.sourceEncoding} + org.apache.maven.plugins maven-surefire-plugin ${maven-surefire-plugin.version} + + + **/DbUpdateQueryGeneratorTest.java + + org.apache.maven.plugins @@ -212,22 +221,27 @@ dev + + dev + + + src/main/resources + + application.properties + + true + src/main/resources + application.properties application-*.properties dev/application.properties live/** - - src/main/resources/dev - - application.properties - - @@ -244,22 +258,27 @@ live + + live + + + src/main/resources + + application.properties + + true + src/main/resources + application.properties application-*.properties dev/** live/application.properties - - src/main/resources/live - - application.properties - - diff --git a/src/main/java/com/pandoli365/bibimbap/config/UploadResourceConfig.java b/src/main/java/com/pandoli365/bibimbap/config/UploadResourceConfig.java index dd8c2ff..d6d4e6f 100644 --- a/src/main/java/com/pandoli365/bibimbap/config/UploadResourceConfig.java +++ b/src/main/java/com/pandoli365/bibimbap/config/UploadResourceConfig.java @@ -17,13 +17,9 @@ public class UploadResourceConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { Path uploadPath = Paths.get(gameStoragePath).toAbsolutePath().normalize(); - String uploadLocation = uploadPath.toUri().toString(); String profileLocation = uploadPath.resolve("profile").toUri().toString(); - String gameLocation = uploadPath.resolve("game").toUri().toString(); registry.addResourceHandler("/profile/**") .addResourceLocations(profileLocation); - registry.addResourceHandler("/game/**") - .addResourceLocations(uploadLocation, gameLocation); } } diff --git a/src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java b/src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java index 6415586..b331266 100644 --- a/src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java +++ b/src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java @@ -1,14 +1,11 @@ package com.pandoli365.bibimbap.controller.api; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.http.CacheControl; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -19,7 +16,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.Duration; import java.util.Locale; import java.util.UUID; @@ -30,35 +26,35 @@ public class GameAssetController { private String uploadStoragePath; @GetMapping("/game/{gameUuid}/**") - public ResponseEntity gameAsset( + public void gameAsset( @PathVariable("gameUuid") String gameUuid, - HttpServletRequest request + HttpServletRequest request, + HttpServletResponse response ) throws IOException { String normalizedGameUuid = normalizeGameUuid(gameUuid); if (normalizedGameUuid == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + response.sendError(HttpStatus.NOT_FOUND.value()); + return; } Path gameDir = gameRoot().resolve(normalizedGameUuid).normalize(); Path assetFile = resolveAssetFile(gameDir, normalizedGameUuid, request); if (assetFile == null || !Files.isRegularFile(assetFile)) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + response.sendError(HttpStatus.NOT_FOUND.value()); + return; } - HttpHeaders headers = new HttpHeaders(); String contentEncoding = contentEncoding(assetFile); String contentType = contentType(assetFile); + response.setStatus(HttpStatus.OK.value()); if (contentEncoding != null) { - headers.set(HttpHeaders.CONTENT_ENCODING, contentEncoding); - headers.set(HttpHeaders.VARY, HttpHeaders.ACCEPT_ENCODING); + response.setHeader(HttpHeaders.CONTENT_ENCODING, contentEncoding); + response.setHeader(HttpHeaders.VARY, HttpHeaders.ACCEPT_ENCODING); } - headers.set(HttpHeaders.CONTENT_TYPE, contentType); - headers.setCacheControl(CacheControl.maxAge(Duration.ofHours(1)).cachePublic()); - headers.setContentLength(Files.size(assetFile)); - - return ResponseEntity.ok() - .headers(headers) - .body(new FileSystemResource(assetFile)); + response.setHeader(HttpHeaders.CONTENT_TYPE, contentType); + response.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=3600, public"); + response.setContentLengthLong(Files.size(assetFile)); + Files.copy(assetFile, response.getOutputStream()); } private Path gameRoot() { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..d24dd03 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,23 @@ +spring.profiles.active=@app.profile@ +spring.application.name=bibimbap + +# ViewResolver +spring.mvc.view.prefix=/WEB-INF/views/ +spring.mvc.view.suffix=.jsp + +# common +spring.config.import=classpath:${spring.profiles.active}/db.properties + +# IP +server.address=0.0.0.0 + +# encoding +server.servlet.encoding.force-response=false + +# file upload Max Size +spring.servlet.multipart.max-file-size=100MB +spring.servlet.multipart.max-request-size=100MB + +# log +mybatis.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl +logging.level.org.apache.ibatis=TRACE diff --git a/src/main/webapp/WEB-INF/views/game-register.jsp b/src/main/webapp/WEB-INF/views/game-register.jsp index 87a306d..f4dfa29 100644 --- a/src/main/webapp/WEB-INF/views/game-register.jsp +++ b/src/main/webapp/WEB-INF/views/game-register.jsp @@ -394,7 +394,7 @@ - 등록 요청 + 등록 diff --git a/src/main/webapp/WEB-INF/views/operation-policy.jsp b/src/main/webapp/WEB-INF/views/operation-policy.jsp index 3034672..7074a7e 100644 --- a/src/main/webapp/WEB-INF/views/operation-policy.jsp +++ b/src/main/webapp/WEB-INF/views/operation-policy.jsp @@ -83,10 +83,36 @@ .policy-section p { margin: 0.45rem 0 0; } - .policy-section ul { + .policy-section ul, + .policy-section ol { margin: 0.6rem 0 0; padding-left: 1.2rem; } + .policy-table-wrap { + margin-top: 0.75rem; + overflow-x: auto; + } + .policy-table { + width: 100%; + border-collapse: collapse; + min-width: 36rem; + font-size: 0.875rem; + } + .policy-table th, + .policy-table td { + padding: 0.75rem; + border: 1px solid var(--border); + text-align: left; + vertical-align: top; + line-height: 1.6; + } + .policy-table th { + color: var(--text); + background: var(--surface); + } + .policy-table td { + color: var(--text-muted); + } .policy-section strong { color: var(--text); } @@ -98,48 +124,88 @@

운영정책

-

시행일: 2026년 5월 3일

+

시행일: 2026년 4월 16일

-

1. 기본 원칙

-

bibimbap은 이용자가 직접 만든 게임과 관련 콘텐츠를 안전하고 편안하게 공유하는 공간을 지향합니다. 운영자는 이용자의 창작과 표현을 존중하되, 다른 이용자의 권리와 서비스 안정성을 해치는 행위에는 필요한 조치를 합니다.

+

제1조 (목적)

+

본 운영정책은 이용약관에서 위임한 사항과 서비스 운영에 필요한 구체적인 사항을 규정함을 목적으로 합니다. '비빔밥'(이하 "서비스")을 이용하는 모든 회원은 본 정책을 준수해야 합니다.

-

2. 게임 등록 기준

-
    -
  • 게임 제목, 제작자명, 설명, 이미지, 실행 파일 또는 WebGL 경로는 실제 콘텐츠와 관련 있어야 합니다.
  • -
  • 타인의 저작물을 사용할 경우 필요한 권한을 확보해야 합니다.
  • -
  • 실행 파일, 압축 파일, 스크립트 등에는 악성 코드나 이용자 환경을 훼손하는 동작이 포함되어서는 안 됩니다.
  • -
+

제2조 (이용자의 권리와 의무)

+
    +
  1. 회원은 서비스를 이용하며 발생하는 문제에 대해 이메일(artbiit@naver.com)을 통해 문의하고 개선을 요청할 수 있습니다.
  2. +
  3. 회원은 타인의 권리를 침해해서는 안 되며, 쾌적한 커뮤니티 환경 조성을 위해 협조해야 합니다.
  4. +
-

3. 댓글 및 커뮤니티 이용

-
    -
  • 비방, 괴롭힘, 혐오 표현, 개인정보 노출, 도배성 댓글은 제한될 수 있습니다.
  • -
  • 버그 제보와 피드백은 가능한 한 구체적이고 존중하는 방식으로 작성해 주세요.
  • -
  • 운영자는 분쟁 완화와 서비스 보호를 위해 댓글을 숨김 또는 삭제할 수 있습니다.
  • -
+

제3조 (커뮤니티 이용 규칙)

+

회원은 게시물 작성 및 채팅 시 다음 각호에 해당하는 행위를 해서는 안 됩니다.

+
    +
  1. 타인 비방 및 명예훼손: 특정 개인이나 단체를 비하, 모욕하거나 허위 사실을 유포하는 행위
  2. +
  3. 도배 및 광고: 동일한 내용을 반복적으로 게시하거나 운영자의 승인 없는 상업적 광고 행위
  4. +
  5. 음란물 및 혐오 표현: 선정적인 내용, 잔인한 묘사, 특정 계층에 대한 차별 및 혐오를 조장하는 내용
  6. +
  7. 개인정보 유출: 본인 또는 타인의 연락처, 주소 등 개인정보를 노출하는 행위
  8. +
-

4. 업로드 파일 관리

-

이미지와 게임 파일은 지정된 저장소에 업로드됩니다. 이용자는 업로드한 파일이 본인의 창작물이거나 배포 권한이 있는 자료인지 확인해야 합니다. 운영자는 보안, 용량, 저작권, 정책 위반 문제를 이유로 파일을 삭제하거나 접근을 제한할 수 있습니다.

+

제4조 (게임 및 기술적 서비스 이용 규칙)

+

운영자가 게재한 웹게임 및 서비스 이용 시 다음 행위를 엄격히 금지합니다.

+
    +
  1. 데이터 마이닝 및 리버스 엔지니어링: 서비스의 소스 코드를 무단으로 추출하거나, 비정상적인 방식으로 데이터를 수집하는 행위
  2. +
  3. 비인가 프로그램 사용: 운영자가 제공하지 않은 프로그램을 사용하여 게임의 밸런스를 무너뜨리거나 시스템에 부하를 주는 행위
  4. +
  5. 버그 악용: 시스템 오류를 인지하고도 이를 이득을 취할 목적으로 반복 사용하는 행위
  6. +
-

5. 제재 기준

-
    -
  • 경미한 위반은 안내, 수정 요청, 콘텐츠 숨김으로 처리할 수 있습니다.
  • -
  • 반복 위반 또는 명백한 피해가 있는 경우 콘텐츠 삭제, 업로드 제한, 계정 정지 조치를 할 수 있습니다.
  • -
  • 보안 위협, 불법 콘텐츠, 심각한 권리 침해가 확인된 경우 즉시 접근 차단될 수 있습니다.
  • -
+

제5조 (저작권 보호)

+
    +
  1. 회원은 제3자의 저작권을 포함한 지식재산권을 침해하는 결과물을 게시해서는 안 됩니다.
  2. +
  3. 신고 등을 통해 저작권 침해가 확인된 게시물은 사전 통보 없이 삭제될 수 있으며, 반복될 경우 서비스 이용이 제한됩니다.
  4. +
-

6. 신고 및 문의

-

운영정책 위반 콘텐츠, 권리 침해, 계정 문제는 admin@pandoli365.com으로 문의할 수 있습니다. 신고 시 문제가 되는 URL, 화면 캡처, 사유를 함께 전달하면 처리가 빨라집니다.

+

제6조 (제재 기준 및 단계)

+

운영자는 위반 행위의 경중에 따라 다음과 같이 조치할 수 있습니다.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
제재 단계제재 내용대상 항목
1단계: 주의게시물 삭제 및 주의 쪽지 발송단순 게시판 규칙 위반, 경미한 비방
2단계: 기간 제한3일 ~ 30일 서비스 이용 정지반복적인 도배, 욕설, 타인 비방, 버그 악용
3단계: 영구 제한서비스 이용 권한 영구 박탈데이터 마이닝, 해킹, 심각한 저작권 침해, 상습적인 운영 방해
+
-

7. 정책 변경

-

운영정책은 서비스 상황, 법령, 보안 필요에 따라 변경될 수 있습니다. 중요한 변경이 있는 경우 서비스 내 공지 또는 적절한 방법으로 안내합니다.

+

제7조 (복구 및 신고)

+
    +
  1. 서비스 오류로 인해 발생한 피해는 운영자가 확인 가능한 범위 내에서 복구를 위해 노력합니다.
  2. +
  3. 타인의 부정 행위를 발견한 경우 이메일을 통해 신고할 수 있으며, 운영자는 이를 객관적으로 조사하여 처리합니다.
  4. +
+
+
+

부칙

+

본 운영정책은 2026년 4월 16일부터 시행됩니다.

diff --git a/src/main/webapp/WEB-INF/views/signup.jsp b/src/main/webapp/WEB-INF/views/signup.jsp index 1b92985..d579e31 100644 --- a/src/main/webapp/WEB-INF/views/signup.jsp +++ b/src/main/webapp/WEB-INF/views/signup.jsp @@ -235,7 +235,10 @@ diff --git a/src/main/webapp/WEB-INF/views/terms.jsp b/src/main/webapp/WEB-INF/views/terms.jsp index 02cfd84..80c9bbc 100644 --- a/src/main/webapp/WEB-INF/views/terms.jsp +++ b/src/main/webapp/WEB-INF/views/terms.jsp @@ -83,7 +83,8 @@ .policy-section p { margin: 0.45rem 0 0; } - .policy-section ul { + .policy-section ul, + .policy-section ol { margin: 0.6rem 0 0; padding-left: 1.2rem; } @@ -98,50 +99,94 @@

이용약관

-

시행일: 2026년 5월 3일

+

시행일: 2026년 4월 16일

-

제1조 목적

-

본 약관은 bibimbap이 제공하는 게임 게시, 플레이, 댓글, 좋아요 및 관련 서비스의 이용 조건과 절차, 이용자와 운영자의 권리와 의무를 정합니다.

+

제1조 (목적)

+

본 약관은 개인 개발자(이하 "운영자")가 제공하는 웹 서비스 '비빔밥'(이하 "서비스")의 이용 조건 및 절차, 이용자와 운영자의 권리, 의무 및 책임 사항을 규정함을 목적으로 합니다.

-

제2조 계정 및 로그인

-

이용자는 게스트 계정 또는 외부 로그인 제공자를 통해 서비스를 이용할 수 있습니다. 이용자는 본인의 계정 접근 권한을 안전하게 관리해야 하며, 계정 사용 중 발생한 활동에 대한 책임은 이용자에게 있습니다.

+

제2조 (용어의 정의)

+
    +
  1. "서비스"란 운영자가 개발한 웹게임을 게재하고 이용자들이 소통할 수 있는 커뮤니티 공간을 제공하는 웹사이트를 의미합니다.
  2. +
  3. "이용자"란 본 약관에 따라 운영자가 제공하는 서비스를 이용하는 회원 및 비회원을 말합니다.
  4. +
  5. "회원"이란 서비스에 접속하여 본 약관에 동의하고 계정을 생성하여 서비스를 이용하는 자를 말합니다.
  6. +
-

제3조 서비스 이용

+

제3조 (약관의 게시와 개정)

+
    +
  1. 운영자는 본 약관의 내용을 이용자가 쉽게 알 수 있도록 서비스 초기 화면에 게시합니다.
  2. +
  3. 운영자는 관련 법령을 위배하지 않는 범위에서 본 약관을 개정할 수 있습니다.
  4. +
  5. 약관이 개정될 경우 적용 일자 및 개정 사유를 명시하여 현행 약관과 함께 서비스 내에 공지합니다.
  6. +
+
+
+

제4조 (서비스의 제공 및 변경)

+
    +
  1. 서비스는 웹게임 게재 및 커뮤니티 기능을 기본으로 제공하며, 운영자의 판단에 따라 새로운 기능을 추가하거나 기존 기능을 변경할 수 있습니다.
  2. +
  3. 본 서비스는 이용자에게 무료로 제공됩니다. 다만, 서비스 운영상 필요한 경우 일부 기능을 유료화하거나 광고를 게재할 수 있으며, 이 경우 사전에 공지합니다.
  4. +
+
+
+

제5조 (회원가입 및 계정 관리)

+
    +
  1. 이용자는 운영자가 정한 가입 양식에 따라 회원정보를 기입함으로써 회원가입을 신청합니다.
  2. +
  3. 모든 회원은 반드시 본인의 정보를 제공하여야 하며, 타인의 정보를 도용할 경우 서비스 이용 제한 및 관련 법령에 따른 처벌을 받을 수 있습니다.
  4. +
  5. 회원은 자신의 계정과 비밀번호를 관리할 책임이 있으며, 이를 제3자가 이용하도록 하여서는 안 됩니다.
  6. +
+
+
+

제6조 (이용자의 의무 및 금지 행위)

+

이용자는 서비스 이용 시 다음 각호의 행위를 하여서는 안 됩니다.

+
    +
  1. 서비스의 안정적인 운영을 방해할 목적으로 하는 데이터 마이닝, 크롤링, 또는 비정상적인 접근 행위
  2. +
  3. 타인을 비방하거나 명예를 훼손하는 게시물을 작성하는 행위
  4. +
  5. 타인의 저작권 등 지식재산권을 침해하는 행위 (저작권 침해 게임물이나 게시물 게재 등)
  6. +
  7. 공공질서 및 미풍양속에 반하는 정보를 유포하는 행위
  8. +
  9. 기타 관계 법령 및 운영정책에 위배되는 행위
  10. +
+
+
+

제7조 (게시물의 저작권)

+
    +
  1. 회원이 서비스 내에 게시한 게시물의 저작권은 해당 게시물의 저작자에게 귀속됩니다.
  2. +
  3. 운영자는 서비스의 홍보 및 운영 목적으로 회원의 게시물을 노출하거나 복제, 수정하여 사용할 수 있습니다.
  4. +
  5. 회원은 서비스에 저작권 문제가 있는 게시물을 올려서는 안 되며, 이로 인해 발생하는 법적 책임은 게시자 본인에게 있습니다.
  6. +
+
+
+

제8조 (서비스 이용 제한 및 해지)

+
    +
  1. 회원은 언제든지 서비스 내 설정 메뉴를 통해 회원 탈퇴를 신청할 수 있습니다.
  2. +
  3. 운영자는 회원이 제6조의 금지 행위를 한 경우, 사전 통보 없이 서비스 이용을 일시 정지하거나 계정을 삭제할 수 있습니다.
  4. +
+
+
+

제9조 (책임 제한)

+
    +
  1. 운영자는 천재지변, 서버 점검, 네트워크 장애 등 불가항력적인 사유로 서비스를 제공할 수 없는 경우 책임이 면제됩니다.
  2. +
  3. 운영자는 이용자 간 또는 이용자와 제3자 상호 간에 서비스를 매개로 하여 발생한 분쟁에 대해 개입할 의무가 없으며 이로 인한 손해를 배상할 책임이 없습니다.
  4. +
+
+
+

제10조 (준거법 및 관할법원)

+
    +
  1. 본 약관과 관련하여 발생한 분쟁에 대해서는 대한민국 법을 준거법으로 합니다.
  2. +
  3. 서비스 이용으로 발생한 분쟁에 대해 소송이 제기될 경우 서울중앙지방법원을 전속 관할법원으로 합니다.
  4. +
+
+
+

부칙

+

본 약관은 2026년 4월 16일부터 시행됩니다.

+
+
+

문의처

    -
  • 이용자는 서비스의 목적과 운영정책에 맞게 게임, 이미지, 댓글 등 콘텐츠를 등록해야 합니다.
  • -
  • 운영자는 서비스 품질 유지, 보안, 장애 대응을 위해 필요한 범위에서 서비스 제공 방식을 변경하거나 일시 중단할 수 있습니다.
  • -
  • 서비스 내 기능은 개발 상황에 따라 추가, 변경, 제거될 수 있습니다.
  • +
  • 이메일: artbiit@naver.com
-
-

제4조 콘텐츠 권리

-

이용자가 등록한 콘텐츠의 권리는 원칙적으로 해당 이용자에게 있습니다. 다만 이용자는 서비스 내 노출, 저장, 전송, 소개를 위해 필요한 범위에서 운영자에게 콘텐츠를 사용할 수 있는 권한을 부여합니다.

-
-
-

제5조 금지 행위

-
    -
  • 타인의 권리, 개인정보, 저작권을 침해하는 행위
  • -
  • 악성 코드, 비정상 트래픽, 자동화 도구 등으로 서비스를 방해하는 행위
  • -
  • 불법적이거나 혐오, 괴롭힘, 과도한 폭력성, 음란성을 포함한 콘텐츠를 게시하는 행위
  • -
  • 운영자 또는 다른 이용자를 사칭하거나 허위 정보를 등록하는 행위
  • -
-
-
-

제6조 이용 제한

-

운영자는 약관 또는 운영정책을 위반한 이용자에게 콘텐츠 삭제, 기능 제한, 계정 정지, 접근 차단 등의 조치를 할 수 있습니다. 긴급한 보안 또는 피해 확산 우려가 있는 경우 사전 안내 없이 조치할 수 있습니다.

-
-
-

제7조 책임의 한계

-

운영자는 이용자가 등록한 콘텐츠의 완전성, 정확성, 적법성을 보증하지 않습니다. 또한 천재지변, 외부 서비스 장애, 네트워크 문제 등 운영자의 합리적 통제를 벗어난 사유로 발생한 손해에 대해 책임을 지지 않습니다.

-
-
-

제8조 문의

-

서비스 이용과 관련한 문의는 admin@pandoli365.com으로 보낼 수 있습니다.

-
diff --git a/src/test/db/dev-to-live-update.sql b/src/test/db/dev-to-live-update.sql new file mode 100644 index 0000000..64ca28e --- /dev/null +++ b/src/test/db/dev-to-live-update.sql @@ -0,0 +1,105 @@ +-- select = dev +-- update = live +-- generated SQL only. Review before running. + +-- ONLY IN dev: game_comments +-- ONLY IN dev: game_likes +-- ONLY IN dev: games +-- ONLY IN dev: user_auth_identities +-- ONLY IN dev: users + +-- game_comments table does not exist. +CREATE SEQUENCE IF NOT EXISTS "game_comments_id_seq"; +CREATE TABLE "game_comments" ( + "id" bigint DEFAULT nextval('game_comments_id_seq'::regclass) NOT NULL, + "game_id" bigint NOT NULL, + "nickname" character varying(50) NOT NULL, + "content" text NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "deleted_at" timestamp with time zone, + "is_delete" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); + +-- game_likes table does not exist. +CREATE SEQUENCE IF NOT EXISTS "game_likes_id_seq"; +CREATE TABLE "game_likes" ( + "id" bigint DEFAULT nextval('game_likes_id_seq'::regclass) NOT NULL, + "game_id" bigint NOT NULL, + "user_key" character varying(100) NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + PRIMARY KEY ("id") +); + +-- games table does not exist. +CREATE SEQUENCE IF NOT EXISTS "games_id_seq"; +CREATE TABLE "games" ( + "id" bigint DEFAULT nextval('games_id_seq'::regclass) NOT NULL, + "name" character varying(200) NOT NULL, + "creator" character varying(100) NOT NULL, + "creator_note" text, + "git_url" character varying(500), + "webgl_path" character varying(500), + "thumbnail_url" character varying(500), + "like_count" integer DEFAULT 0 NOT NULL, + "is_visible" boolean DEFAULT true NOT NULL, + "sort_order" integer DEFAULT 0 NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "is_delete" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); + +-- user_auth_identities table does not exist. +CREATE SEQUENCE IF NOT EXISTS "user_auth_identities_id_seq"; +CREATE TABLE "user_auth_identities" ( + "id" bigint DEFAULT nextval('user_auth_identities_id_seq'::regclass) NOT NULL, + "user_id" bigint NOT NULL, + "provider" character varying(30) NOT NULL, + "provider_user_id" character varying(255) NOT NULL, + "email" character varying(255), + "display_name" character varying(80), + "avatar_url" character varying(500), + "last_login_at" timestamp with time zone, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "is_delete" boolean DEFAULT false NOT NULL, + "password_hash" character varying(255), + PRIMARY KEY ("id") +); +COMMENT ON COLUMN "user_auth_identities"."id" IS '로그인 연결 정보 고유 ID'; +COMMENT ON COLUMN "user_auth_identities"."user_id" IS '연결된 서비스 내부 사용자 ID'; +COMMENT ON COLUMN "user_auth_identities"."provider" IS '로그인 제공자. guest, google, email, kakao, naver, github, apple'; +COMMENT ON COLUMN "user_auth_identities"."provider_user_id" IS '로그인 제공자가 내려준 사용자 고유 ID. 게스트는 자체 생성 ID 사용'; +COMMENT ON COLUMN "user_auth_identities"."email" IS '해당 로그인 제공자에서 받은 이메일 주소'; +COMMENT ON COLUMN "user_auth_identities"."display_name" IS '해당 로그인 제공자에서 받은 표시 이름'; +COMMENT ON COLUMN "user_auth_identities"."avatar_url" IS '해당 로그인 제공자에서 받은 프로필 이미지 URL'; +COMMENT ON COLUMN "user_auth_identities"."last_login_at" IS '해당 로그인 방식으로 마지막 로그인한 시각'; +COMMENT ON COLUMN "user_auth_identities"."created_at" IS '로그인 연결 정보 생성 시각'; +COMMENT ON COLUMN "user_auth_identities"."updated_at" IS '로그인 연결 정보 마지막 수정 시각'; + +-- users table does not exist. +CREATE SEQUENCE IF NOT EXISTS "users_id_seq"; +CREATE TABLE "users" ( + "id" bigint DEFAULT nextval('users_id_seq'::regclass) NOT NULL, + "display_name" character varying(80) NOT NULL, + "canonical_email" character varying(255), + "avatar_url" character varying(500), + "role" character varying(30) DEFAULT 'USER'::character varying NOT NULL, + "status" character varying(30) DEFAULT 'ACTIVE'::character varying NOT NULL, + "last_login_at" timestamp with time zone, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "is_delete" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +COMMENT ON COLUMN "users"."id" IS '사용자 고유 ID'; +COMMENT ON COLUMN "users"."display_name" IS '서비스에서 표시할 사용자 이름'; +COMMENT ON COLUMN "users"."canonical_email" IS '대표 이메일 주소. 여러 로그인 제공자 중 기준 이메일로 사용'; +COMMENT ON COLUMN "users"."avatar_url" IS '사용자 프로필 이미지 URL'; +COMMENT ON COLUMN "users"."role" IS '사용자 권한. USER 또는 ADMIN'; +COMMENT ON COLUMN "users"."status" IS '계정 상태. ACTIVE, SUSPENDED, DELETED'; +COMMENT ON COLUMN "users"."last_login_at" IS '마지막 로그인 시각'; +COMMENT ON COLUMN "users"."created_at" IS '사용자 생성 시각'; +COMMENT ON COLUMN "users"."updated_at" IS '사용자 정보 마지막 수정 시각'; + diff --git a/src/test/java/com/pandoli365/bibimbap/DbUpdateQueryGeneratorTest.java b/src/test/java/com/pandoli365/bibimbap/DbUpdateQueryGeneratorTest.java index 59ca9f4..0c74e07 100644 --- a/src/test/java/com/pandoli365/bibimbap/DbUpdateQueryGeneratorTest.java +++ b/src/test/java/com/pandoli365/bibimbap/DbUpdateQueryGeneratorTest.java @@ -396,10 +396,7 @@ class DbUpdateQueryGeneratorTest { private static DbConfig loadDbConfig(String profile) throws IOException { Properties properties = new Properties(); String path = profile + "/db.properties"; - try (InputStream inputStream = DbUpdateQueryGeneratorTest.class.getClassLoader().getResourceAsStream(path)) { - if (inputStream == null) { - throw new IOException("Cannot find " + path); - } + try (InputStream inputStream = openDbConfig(path)) { properties.load(inputStream); } @@ -411,6 +408,20 @@ class DbUpdateQueryGeneratorTest { ); } + private static InputStream openDbConfig(String path) throws IOException { + InputStream inputStream = DbUpdateQueryGeneratorTest.class.getClassLoader().getResourceAsStream(path); + if (inputStream != null) { + return inputStream; + } + + Path sourcePath = Path.of("src", "main", "resources").resolve(path); + if (Files.exists(sourcePath)) { + return Files.newInputStream(sourcePath); + } + + throw new IOException("Cannot find " + path); + } + private static boolean sameValue(Object left, Object right) { if (left instanceof BigDecimal leftDecimal && right instanceof BigDecimal rightDecimal) { return leftDecimal.compareTo(rightDecimal) == 0;