diff --git a/docs/api-specs/attendance-api.md b/docs/api-specs/attendance-api.md index a7ceb84c..e28347cc 100644 --- a/docs/api-specs/attendance-api.md +++ b/docs/api-specs/attendance-api.md @@ -4,11 +4,11 @@ - 출석체크 API는 `snake_case` 필드명을 기준으로 합니다. - 출석 주기는 **월요일 기준 1주일(월~일)**로 초기화됩니다. -- 매일 1회 출석 체크 시 `+5P`를 지급하고, 7일 연속 출석 달성 시 추가로 `+7P`를 지급합니다. -- 7일 연속 출석 실패 시 다음 주 월요일에 연속 출석 카운트가 초기화됩니다. +- 매일 1회 출석 체크 시 `+5P`를 지급합니다. 단, 월~토 6일을 모두 출석한 뒤 맞이하는 일요일에는 `+5P` 대신 `+7P`를 **대체 지급**합니다(가산이 아님). +- 전날 출석 없이 출석 시 연속 출석 카운트가 1로 리셋됩니다. - 인증이 필요한 모든 API는 `Authorization: Bearer {access_token}` 헤더를 요구합니다. - 외부 응답에서는 내부 PK인 `user_id`를 노출하지 않고 `user_tag`를 사용합니다. -- 포인트 단위는 `P(포인트)`이며, 지급 내역은 별도 이력 테이블에 저장합니다. +- 포인트 단위는 `P(포인트)`이며, 지급 내역은 `credit_histories` 테이블에 저장됩니다. 출석체크 전용 이력 조회 API는 없고, 크레딧 적립/소비 통합 이력은 `GET /api/v1/me/credits/history`로 조회합니다. ### 1.1 출석 상태 정의 @@ -22,14 +22,15 @@ | 조건 | 지급 포인트 | |------|-------------| -| 매일 출석 체크 | `+5P` | -| 7일 연속 출석 달성 (일요일) | 추가 `+7P` | +| 평일(월~토) 출석 체크 | `+5P` | +| 일요일 출석 체크 (월~토 개근 시) | `+5P` 대신 `+7P` **대체 지급** | +| 일요일 출석 체크 (월~토 중 결석 있음) | `+5P` (평일과 동일) | -### 1.3 연속 출석 초기화 정책 +### 1.3 연속 출석(streak) 정책 -- 연속 출석 카운트는 **매주 월요일 00:00**에 초기화됩니다. -- 한 주(월~일) 내에 출석하지 않은 날이 있어도, 해당 주 일요일까지는 연속 출석 달성이 가능합니다. -- 단, 전날 출석 없이 오늘 출석 시 연속 카운트는 1로 리셋됩니다. +- 연속 출석 카운트(`consecutive_days`)는 통계·화면 표시용이며, 포인트 지급 여부는 **요일(일요일 여부)과 그 주 월~토 개근 여부**로만 결정됩니다. streak 값 자체가 포인트에 가산되지 않습니다. +- 전날 출석 기록이 없는 상태에서 오늘 출석하면 연속 카운트는 1로 리셋됩니다. +- 주간 통계는 매주 월요일 기준으로 초기화됩니다. --- @@ -40,8 +41,8 @@ 오늘의 출석을 체크하고 포인트를 지급합니다. - 하루에 1회만 출석 가능합니다. 중복 출석 시 `409`를 반환합니다. -- 출석 성공 시 `+5P`를 즉시 지급합니다. -- 7일 연속 출석 달성 시 `+5P`에 추가로 `+7P`를 지급합니다. +- 평일(월~토) 출석 성공 시 `+5P`를 즉시 지급합니다. +- 일요일 출석 시, 그 주 월~토를 모두 출석했다면 `+5P` 대신 `+7P`를 대체 지급합니다. 요청 헤더: @@ -65,7 +66,7 @@ } ``` -7일 연속 출석 달성 시 응답: +일요일에 월~토 개근 보너스가 대체 지급된 응답 (이 날은 `points_earned`가 5가 아니라 7로 대체되며, `streak_bonus_points`는 이 대체된 값과 동일합니다): ```json { @@ -73,7 +74,7 @@ "data": { "user_tag": "pique-5010f67e", "attended_at": "2025-07-13T09:00:00Z", - "points_earned": 5, + "points_earned": 7, "streak_bonus_earned": true, "streak_bonus_points": 7, "consecutive_days": 7, @@ -152,62 +153,12 @@ --- -### 2.4 `GET /api/v1/attendance/points/history` - -출석 포인트 지급 이력을 조회합니다. - -- 최신순으로 반환하며, 페이지네이션을 지원합니다. - -요청 헤더: - -- `Authorization: Bearer {access_token}` - -쿼리 파라미터: - -| 파라미터 | 타입 | 필수 | 설명 | -|----------|------|------|------| -| `page` | `integer` | N | 페이지 번호 (기본값: `1`) | -| `size` | `integer` | N | 페이지 크기 (기본값: `20`, 최대: `50`) | - -응답: - -```json -{ - "statusCode": 200, - "data": { - "total_count": 32, - "page": 1, - "size": 20, - "items": [ - { - "rewarded_at": "2025-07-10T09:00:00Z", - "points": 5, - "reason": "DAILY_ATTENDANCE", - "consecutive_days": 4 - }, - { - "rewarded_at": "2025-07-06T08:30:00Z", - "points": 7, - "reason": "STREAK_BONUS", - "consecutive_days": 7 - } - ] - }, - "error": null -} -``` - -가능한 `reason` 값: - -- `DAILY_ATTENDANCE` — 일일 출석 보상 (`+5P`) -- `STREAK_BONUS` — 7일 연속 출석 달성 보상 (`+7P`) - ---- +> 출석 포인트만 별도로 필터링해 조회하는 API는 없습니다. 크레딧 적립/소비 통합 이력은 `GET /api/v1/me/credits/history`(마이페이지 도메인)로 조회하며, 출석 보상은 `credit_type: TODAY_CREDIT`(평일 5P) 또는 `ATTENDANCE_STREAK`(일요일 대체 7P)로 구분됩니다. ## 3. 어드민 API - 어드민 전용 API는 `Authorization: Bearer {access_token}` 헤더와 함께 어드민 권한이 있는 계정만 호출 가능합니다. -- 어드민 권한이 없는 계정이 호출 시 `403`과 `FORBIDDEN`을 반환합니다. +- 어드민 권한이 없는 계정이 호출 시 `403`과 `AUTH_FORBIDDEN`을 반환합니다. ### 3.1 `GET /api/v1/admin/attendance/stats` @@ -352,7 +303,7 @@ | `400` | `COMMON_INVALID_PARAMETER` | 요청 파라미터가 잘못되었습니다. | | `401` | `AUTH_ACCESS_TOKEN_EXPIRED` | Access Token 만료 — Refresh 필요 | | `401` | `AUTH_REFRESH_TOKEN_EXPIRED` | Refresh Token 만료 — 재로그인 필요 | -| `403` | `FORBIDDEN` | 어드민 권한이 없는 사용자 | +| `403` | `AUTH_FORBIDDEN` | 어드민 권한이 없는 사용자 | | `403` | `USER_BANNED` | 영구 제재된 사용자 | | `403` | `USER_SUSPENDED` | 일정 기간 이용 정지된 사용자 | | `404` | `USER_NOT_FOUND` | 존재하지 않는 `user_tag` | diff --git a/docs/api-specs/notification-api.md b/docs/api-specs/notification-api.md index ae82f976..0d6069b8 100644 --- a/docs/api-specs/notification-api.md +++ b/docs/api-specs/notification-api.md @@ -158,7 +158,35 @@ --- -### 3.2 `GET /api/v1/notifications/{notificationId}` +### 3.2 `GET /api/v1/notifications/unread` + +알림함 벨 아이콘 배지 표시용으로, 미읽음 알림 존재 여부만 가볍게 확인합니다. 목록 조회와 달리 페이지네이션 없이 boolean 하나만 반환합니다. + +요청 헤더: + +- `Authorization: Bearer {access_token}` + +쿼리 파라미터: + +| 파라미터 | 타입 | 필수 | 설명 | +|---|---|---|---| +| `category` | `string` | N | `ALL` \| `CONTENT` \| `NOTICE` \| `EVENT` (생략 시 전체 기준) | + +성공 응답 `200 OK`: + +```json +{ + "statusCode": 200, + "data": { + "hasUnread": true + }, + "error": null +} +``` + +--- + +### 3.3 `GET /api/v1/notifications/{notificationId}` 알림 상세를 조회합니다. (목록과 동일한 필드 + `readAt`) @@ -202,7 +230,7 @@ --- -### 3.3 `PATCH /api/v1/notifications/{notificationId}/read` +### 3.4 `PATCH /api/v1/notifications/{notificationId}/read` 알림 1건을 읽음 처리합니다. @@ -222,7 +250,7 @@ --- -### 3.4 `PATCH /api/v1/notifications/read-all` +### 3.5 `PATCH /api/v1/notifications/read-all` 알림함의 모든 알림을 읽음 처리합니다. @@ -230,12 +258,14 @@ - `Authorization: Bearer {access_token}` -성공 응답 `200 OK`: +성공 응답 `200 OK`: 처리 직후 미읽음 알림 존재 여부(`hasUnread`)를 함께 내려줍니다. 모든 알림을 읽었다면 `hasUnread`는 `false`입니다. ```json { "statusCode": 200, - "data": null, + "data": { + "hasUnread": false + }, "error": null } ``` diff --git a/hs_err_pid172944.log b/hs_err_pid172944.log deleted file mode 100644 index 8707abc3..00000000 --- a/hs_err_pid172944.log +++ /dev/null @@ -1,281 +0,0 @@ -# -# There is insufficient memory for the Java Runtime Environment to continue. -# Native memory allocation (mmap) failed to map 532676608 bytes. Error detail: G1 virtual space -# Possible reasons: -# The system is out of physical RAM or swap space -# This process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap -# Possible solutions: -# Reduce memory load on the system -# Increase physical memory or swap space -# Check if swap backing store is full -# Decrease Java heap size (-Xmx/-Xms) -# Decrease number of Java threads -# Decrease Java thread stack sizes (-Xss) -# Set larger code cache with -XX:ReservedCodeCacheSize= -# JVM is running with Zero Based Compressed Oops mode in which the Java heap is -# placed in the first 32GB address space. The Java Heap base address is the -# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress -# to set the Java Heap base and to place the Java Heap above 32GB virtual address. -# This output file may be truncated or incomplete. -# -# Out of Memory Error (os_windows.cpp:3714), pid=172944, tid=186552 -# -# JRE version: (21.0.10+7) (build ) -# Java VM: OpenJDK 64-Bit Server VM (21.0.10+7-LTS, mixed mode, emulated-client, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64) -# No core dump will be written. Minidumps are not enabled by default on client versions of Windows -# - ---------------- S U M M A R Y ------------ - -Command Line: -XX:TieredStopAtLevel=1 -Dspring.profiles.active=local -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar=51664 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 com.swyp.picke.PickeApplication - -Host: Intel(R) Core(TM) Ultra 5 125H, 18 cores, 31G, Windows 11 , 64 bit Build 26100 (10.0.26100.7920) -Time: Mon Mar 30 22:58:11 2026 elapsed time: 1.695367 seconds (0d 0h 0m 1s) - ---------------- T H R E A D --------------- - -Current thread (0x0000024510954d30): JavaThread "Unknown thread" [_thread_in_vm, id=186552, stack(0x0000007972f00000,0x0000007973000000) (1024K)] - -Stack: [0x0000007972f00000,0x0000007973000000] -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -V [jvm.dll+0x6df2b9] -V [jvm.dll+0x8bbdeb] -V [jvm.dll+0x8be37a] -V [jvm.dll+0x8bea53] -V [jvm.dll+0x28a7a6] -V [jvm.dll+0x6dbc15] -V [jvm.dll+0x6cfbca] -V [jvm.dll+0x364f6e] -V [jvm.dll+0x36ce3b] -V [jvm.dll+0x3be8d9] -V [jvm.dll+0x3beb7b] -V [jvm.dll+0x339137] -V [jvm.dll+0x339c7b] -V [jvm.dll+0x88634e] -V [jvm.dll+0x3cb831] -V [jvm.dll+0x86f25c] -V [jvm.dll+0x45e901] -V [jvm.dll+0x460541] -C [jli.dll+0x52f0] -C [ucrtbase.dll+0x37b0] -C [KERNEL32.DLL+0x2e8d7] -C [ntdll.dll+0x8c48c] - - ---------------- P R O C E S S --------------- - -Threads class SMR info: -_java_thread_list=0x00007ffa227e2208, length=0, elements={ -} - -Java Threads: ( => current thread ) -Total: 0 - -Other Threads: - 0x00000245266f03f0 WorkerThread "GC Thread#0" [id=134476, stack(0x0000007973000000,0x0000007973100000) (1024K)] - 0x00000245109ce130 ConcurrentGCThread "G1 Main Marker" [id=195520, stack(0x0000007973100000,0x0000007973200000) (1024K)] - 0x00000245109d0570 WorkerThread "G1 Conc#0" [id=133400, stack(0x0000007973200000,0x0000007973300000) (1024K)] - -[error occurred during error reporting (printing all threads), id 0xc0000005, EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffa21edbbb7] -VM state: not at safepoint (not fully initialized) - -VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event]) -[0x00007ffa228566b0] Heap_lock - owner thread: 0x0000024510954d30 - -Heap address: 0x0000000606800000, size: 8088 MB, Compressed Oops mode: Zero based, Oop shift amount: 3 - -CDS archive(s) mapped at: [0x0000000000000000-0x0000000000000000-0x0000000000000000), size 0, SharedBaseAddress: 0x0000000800000000, ArchiveRelocationMode: 1. -Narrow klass base: 0x0000000000000000, Narrow klass shift: 0, Narrow klass range: 0x0 - -GC Precious Log: - CardTable entry size: 512 - Card Set container configuration: InlinePtr #cards 4 size 8 Array Of Cards #cards 32 size 80 Howl #buckets 8 coarsen threshold 7372 Howl Bitmap #cards 1024 size 144 coarsen threshold 921 Card regions per heap region 1 cards per card region 8192 - -Heap: - garbage-first heap total 0K, used 0K [0x0000000606800000, 0x0000000800000000) - region size 4096K, 0 young (0K), 0 survivors (0K) - -[error occurred during error reporting (printing heap information), id 0xc0000005, EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffa222c9019] -GC Heap History (0 events): -No events - -Dll operation events (1 events): -Event: 0.007 Loaded shared library D:\application\.jdk\bin\java.dll - -Deoptimization events (0 events): -No events - -Classes loaded (0 events): -No events - -Classes unloaded (0 events): -No events - -Classes redefined (0 events): -No events - -Internal exceptions (0 events): -No events - -ZGC Phase Switch (0 events): -No events - -VM Operations (0 events): -No events - -Memory protections (0 events): -No events - -Nmethod flushes (0 events): -No events - -Events (0 events): -No events - - -Dynamic libraries: -0x00007ff7fbf60000 - 0x00007ff7fbf6e000 D:\application\.jdk\bin\java.exe -0x00007ffb03b00000 - 0x00007ffb03d67000 C:\WINDOWS\SYSTEM32\ntdll.dll -0x00007ffb02ce0000 - 0x00007ffb02da9000 C:\WINDOWS\System32\KERNEL32.DLL -0x00007ffb00fa0000 - 0x00007ffb01391000 C:\WINDOWS\System32\KERNELBASE.dll -0x00007ffb003e0000 - 0x00007ffb0052b000 C:\WINDOWS\System32\ucrtbase.dll -0x00007ffaeab10000 - 0x00007ffaeab2e000 D:\application\.jdk\bin\VCRUNTIME140.dll -0x00007ffae63b0000 - 0x00007ffae63c8000 D:\application\.jdk\bin\jli.dll -0x00007ffb02db0000 - 0x00007ffb02f75000 C:\WINDOWS\System32\USER32.dll -0x00007ffae7290000 - 0x00007ffae7523000 C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8037_none_3e092faae333b53b\COMCTL32.dll -0x00007ffb031a0000 - 0x00007ffb03249000 C:\WINDOWS\System32\msvcrt.dll -0x00007ffb015c0000 - 0x00007ffb015e7000 C:\WINDOWS\System32\win32u.dll -0x00007ffb02780000 - 0x00007ffb027ab000 C:\WINDOWS\System32\GDI32.dll -0x00007ffb01770000 - 0x00007ffb0189b000 C:\WINDOWS\System32\gdi32full.dll -0x00007ffb005f0000 - 0x00007ffb00693000 C:\WINDOWS\System32\msvcp_win.dll -0x00007ffb03160000 - 0x00007ffb03191000 C:\WINDOWS\System32\IMM32.DLL -0x00007ffaecfa0000 - 0x00007ffaecfac000 D:\application\.jdk\bin\vcruntime140_1.dll -0x00007ffad39c0000 - 0x00007ffad3a49000 D:\application\.jdk\bin\msvcp140.dll -0x00007ffa21b90000 - 0x00007ffa22938000 D:\application\.jdk\bin\server\jvm.dll -0x00007ffb01d30000 - 0x00007ffb01deb000 C:\WINDOWS\System32\ADVAPI32.dll -0x00007ffb03250000 - 0x00007ffb032f7000 C:\WINDOWS\System32\sechost.dll -0x00007ffb024a0000 - 0x00007ffb025b8000 C:\WINDOWS\System32\RPCRT4.dll -0x00007ffb029a0000 - 0x00007ffb02a14000 C:\WINDOWS\System32\WS2_32.dll -0x00007ffb00240000 - 0x00007ffb0029e000 C:\WINDOWS\SYSTEM32\POWRPROF.dll -0x00007ffaec6c0000 - 0x00007ffaec6f5000 C:\WINDOWS\SYSTEM32\WINMM.dll -0x00007ffae7a30000 - 0x00007ffae7a3b000 C:\WINDOWS\SYSTEM32\VERSION.dll -0x00007ffb00220000 - 0x00007ffb00234000 C:\WINDOWS\SYSTEM32\UMPDC.dll -0x00007ffaff170000 - 0x00007ffaff18b000 C:\WINDOWS\SYSTEM32\kernel.appcore.dll -0x00007ffaea260000 - 0x00007ffaea26a000 D:\application\.jdk\bin\jimage.dll -0x00007ffafe4f0000 - 0x00007ffafe732000 C:\WINDOWS\SYSTEM32\DBGHELP.DLL -0x00007ffb01e50000 - 0x00007ffb021d2000 C:\WINDOWS\System32\combase.dll -0x00007ffb02f80000 - 0x00007ffb03057000 C:\WINDOWS\System32\OLEAUT32.dll -0x00007ffada3d0000 - 0x00007ffada40b000 C:\WINDOWS\SYSTEM32\dbgcore.DLL -0x00007ffb013a0000 - 0x00007ffb01445000 C:\WINDOWS\System32\bcryptPrimitives.dll -0x00007ffae63a0000 - 0x00007ffae63b0000 D:\application\.jdk\bin\instrument.dll -0x00007ffae6310000 - 0x00007ffae6331000 D:\application\.jdk\bin\java.dll - -JVMTI agents: -C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar path:none, loaded, not initialized, instrumentlib options:51664 - -dbghelp: loaded successfully - version: 4.0.5 - missing functions: none -symbol engine: initialized successfully - sym options: 0x614 - pdb path: .;D:\application\.jdk\bin;C:\WINDOWS\SYSTEM32;C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8037_none_3e092faae333b53b;D:\application\.jdk\bin\server - -VM Arguments: -jvm_args: -XX:TieredStopAtLevel=1 -Dspring.profiles.active=local -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar=51664 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -java_command: com.swyp.picke.PickeApplication -java_class_path (initial): D:\Desktop\project\Server\build\classes\java\main;D:\Desktop\project\Server\build\resources\main;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.42\8365263844ebb62398e0dc33057ba10ba472d3b8\lombok-1.18.42.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-web\3.5.11\68fde4c94249e92526105a93ac7c22bd89b6945e\spring-boot-starter-web-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-webmvc-ui\2.8.16\61c68f705d3f17e8318fb18b2904fa6368af251c\springdoc-openapi-starter-webmvc-ui-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-validation\3.5.11\903eefb6eab302617b0f01cc6d65664343bff2a7\spring-boot-starter-validation-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-data-jpa\3.5.11\f176e5c643720818ec7910e1dd2ccb402411cc5d\spring-boot-starter-data-jpa-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-security\3.5.11\db8b6b7951883dea3ce7404f20d6816104cedd4e\spring-boot-starter-security-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-api\0.12.6\478886a888f6add04937baf0361144504a024967\jjwt-api-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-webflux\3.5.11\1461f9a6b6b8397ad71a98c9bbf4278159fb9624\spring-boot-starter-webflux-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.crypto.tink\apps-rewardedads\1.9.1\cbaf11457b36fe57d90a5cb16a76833906486503\apps-rewardedads-1.9.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.cloud\google-cloud-texttospeech\2.58.0\9be37bd3c81c14c72c9cbcfa2dfaf6dad7a35075\google-cloud-texttospeech-2.58.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-starter-s3\3.3.0\fa9790f990ab540814aafdbf2e97c8cd53b5b1a6\spring-cloud-aws-starter-s3-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-thymeleaf\3.5.11\d997aa0df579cf43507d425057940e2712e44808\spring-boot-starter-thymeleaf-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-json\3.5.11\4cdcd68dcddf0a4c645166e39c3fe448fe2b8e98\spring-boot-starter-json-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\3.5.11\10ce971300fd56d6be5f1cfe7d27ddfb1ed7158d\spring-boot-starter-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-tomcat\3.5.11\fb7b96cb61e5fd5700aed96194562e32d166b5ef\spring-boot-starter-tomcat-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webmvc\6.2.16\ff2db80406f1459fddd14a8d06d57e0e3ab69465\spring-webmvc-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-web\6.2.16\2c4355f1f7e5b8969f696cbc90f25cc22f0f2164\spring-web-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-webmvc-api\2.8.16\6e41988d84978e529c01a4cc052b761cd27d5b90\springdoc-openapi-starter-webmvc-api-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.webjars\swagger-ui\5.32.0\d04c7e3e5b8616813136fa36382a548751775528\swagger-ui-5.32.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.webjars\webjars-locator-lite\1.1.3\217ce590453251b39b72c4a9af3986998f6fdbd9\webjars-locator-lite-1.1.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-el\10.1.52\cd94ce17c5a9937eca365eb494711efa10d49b86\tomcat-embed-el-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.validator\hibernate-validator\8.0.3.Final\4425f554297a1c5ba03a3f30e559a9fd91048cf8\hibernate-validator-8.0.3.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-jdbc\3.5.11\3ce801963caadf6eb29abd68f5a0fe50c9bfe211\spring-boot-starter-jdbc-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.orm\hibernate-core\6.6.42.Final\996e3df4a6c67941b582e4493cb9a39c83198f1e\hibernate-core-6.6.42.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.data\spring-data-jpa\3.5.9\56081dde4f663db74ba000c1f8ab30673058c363\spring-data-jpa-3.5.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aspects\6.2.16\763140a66821c494985533f29280a3b4132cf055\spring-aspects-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-web\6.5.8\3db7bf41191d5b23493cca6252595405b5112b34\spring-security-web-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-config\6.5.8\302d32eba89131c0ffd15ba0a1e465051336d42f\spring-security-config-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\6.2.16\59250efa248420a114fe23b4ccf2fea46b804186\spring-aop-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webflux\6.2.16\699ef8bc182893f9ed43206d372f20c4f9aa3231\spring-webflux-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-reactor-netty\3.5.11\f98bd3e3019078679dec4f21fb63152aa2e059a7\spring-boot-starter-reactor-netty-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.crypto.tink\tink\1.10.0\84771b1a4bb5726f73fb8490fadb23f1d2aacd38\tink-1.10.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.13.2\48b8230771e573b54ce6e867a9001e75977fe78e\gson-2.13.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.http-client\google-http-client\1.45.3\dde98b597081b98514867c9cefa551fcdea3a28c\google-http-client-1.45.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.41.0\4381275efdef6ddfae38f002c31e84cd001c97f0\error_prone_annotations-2.41.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.opencensus\opencensus-contrib-http-util\0.31.1\3c13fc5715231fadb16a9b74a44d9d59c460cfa8\opencensus-contrib-http-util-0.31.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\33.4.0-jre\3fcc0a259f724c7de54a6a55ea7e26d3d5c0cac\guava-33.4.0-jre.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-api\1.69.0\965c2c7f708cd6e6ddbf1eb175c3e87e96e41297\grpc-api-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-stub\1.69.0\9e7dc30a9c2df70e25ef4b941f46187e6e178e7a\grpc-stub-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-protobuf\1.69.0\2990b4948357d4fe46aaecb47290cff102079f1e\grpc-protobuf-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\api-common\2.43.0\963d97d95e9bf7275cc26f0b6b72e2aa5b92c6fd\api-common-2.43.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auto.value\auto-value-annotations\1.11.0\f0d047931d07cfbc6fa4079854f181ff62891d6f\auto-value-annotations-1.11.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\javax.annotation\javax.annotation-api\1.3.2\934c04d3cfef185a8008e7bf34331b79730a9d43\javax.annotation-api-1.3.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\3.0.0\7399e65dd7e9ff3404f4535b2f017093bdb134c7\j2objc-annotations-3.0.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protobuf-java\3.25.5\5ae5c9ec39930ae9b5a61b32b93288818ec05ec1\protobuf-java-3.25.5.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-common-protos\2.51.0\ead75a32e6fd65740b6a69feb658254aeab3fef0\proto-google-common-protos-2.51.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-cloud-texttospeech-v1\2.58.0\42f1f29876ddfa2523ebcc41dae801195fd8b3ce\proto-google-cloud-texttospeech-v1-2.58.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-cloud-texttospeech-v1beta1\0.147.0\576df432a2c1181deabf21a54fdecc1a32f69f4e\proto-google-cloud-texttospeech-v1beta1-0.147.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\failureaccess\1.0.2\c4a06a64e650562f30b7bf9aaec1bfed43aca12b\failureaccess-1.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\b421526c5f297295adef1c886e5246c39d4ac629\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.48.4\6b5d69a61012211d581e68699baf3beb1fd382da\checker-qual-3.48.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax\2.60.0\2d277e0795cb69bc14e03be068aa002539e3ef49\gax-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auth\google-auth-library-credentials\1.31.0\b9cd5346d3a683d9a8d9786453f2419cc832a97f\google-auth-library-credentials-1.31.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.opencensus\opencensus-api\0.31.1\66a60c7201c2b8b20ce495f0295b32bb0ccbbc57\opencensus-api-0.31.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-context\1.69.0\cea23878872f76418dcd6df0c6eef0bf27463537\grpc-context-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auth\google-auth-library-oauth2-http\1.31.0\df5be46d21b983aab8d0250f19b585a94bdedcde\google-auth-library-oauth2-http-1.31.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax-grpc\2.60.0\ca4d7dc8c2a85fbdba25ff3449726852e2359ae9\gax-grpc-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-inprocess\1.69.0\8ac4d2e13b48bed9624b8bc485c90f3d28820c93\grpc-inprocess-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-core\1.69.0\7dad3419dfb91a77788afcdf79e0477172784910\grpc-core-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-alts\1.69.0\6d1eac6726fd6fd177666c10fd154823b82272eb\grpc-alts-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-grpclb\1.69.0\d2c9c066693ce94805a503bc47f5b1e76f51541c\grpc-grpclb-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.conscrypt\conscrypt-openjdk-uber\2.5.2\d858f142ea189c62771c505a6548d8606ac098fe\conscrypt-openjdk-uber-2.5.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-auth\1.69.0\a75e19b20bb732364bdcc0979e9d7c9baa4e408e\grpc-auth-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-netty-shaded\1.69.0\99aa9789172695a4b09fe2af5f5bd0ab1be4ae85\grpc-netty-shaded-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax-httpjson\2.60.0\131d9283925337406e35561ec17bf326a9ecec1a\gax-httpjson-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpclient\4.5.14\1194890e6f56ec29177673f2f12d0b8e627dec98\httpclient-4.5.14.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\commons-codec\commons-codec\1.18.0\ee45d1cf6ec2cc2b809ff04b4dc7aec858e0df8f\commons-codec-1.18.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpcore\4.4.16\51cf043c87253c9f58b539c9f7e44c8894223850\httpcore-4.4.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.http-client\google-http-client-gson\1.45.3\29eba40245c4a4e5466f8764bd894d6a97c6694f\google-http-client-gson-1.45.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protobuf-java-util\3.25.5\38cc5ce479603e36466feda2a9f1dfdb2210ef00\protobuf-java-util-3.25.5.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.threeten\threetenbp\1.7.0\8703e893440e550295aa358281db468625bc9a05\threetenbp-1.7.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-starter\3.3.0\7d82d320cb1851beca3005eab2e484a38bd58a08\spring-cloud-aws-starter-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-s3\3.3.0\661e2914e3ad6555e20ffa262a9987c15bcc1712\spring-cloud-aws-s3-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\2.0.17\d9e58ac9c7779ba3bf8142aff6c830617a7fe60f\slf4j-api-2.0.17.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.thymeleaf\thymeleaf-spring6\3.1.3.RELEASE\4b276ea2bd536a18e44b40ff1d9f4848965ff59c\thymeleaf-spring6-3.1.3.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jdk8\2.19.4\90d304bcdb1a4bacb6f4347be625d75300973c60\jackson-datatype-jdk8-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jsr310\2.19.4\3cbcf2e636a6b062772299bf19a347536e58c4df\jackson-datatype-jsr310-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.module\jackson-module-parameter-names\2.19.4\502dfea4c83502f444837b3d040a51e8475f15f2\jackson-module-parameter-names-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.19.4\7a39bf9257b726b90b80f27fa3f5174bc75162a5\jackson-databind-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\3.5.11\3c7d2ec2ac3c301e95814e37fed1c86c19927fc4\spring-boot-autoconfigure-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\3.5.11\8b7f6df00bfbe74d370e1d05d985a127884d2a9c\spring-boot-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\3.5.11\62b692ed7aee31a5670796be8b07732b6b836f4e\spring-boot-starter-logging-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.annotation\jakarta.annotation-api\2.1.1\48b9bda22b091b1f48b13af03fe36db3be6e1ae3\jakarta.annotation-api-2.1.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\6.2.16\a73937f20a303e057add523915b48eb7901e1848\spring-core-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\2.4\e0666b825b796f85521f02360e77f4c92c5a7a07\snakeyaml-2.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-websocket\10.1.52\9d32b801fb474306349013fcdd8317c8cb4d739e\tomcat-embed-websocket-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-core\10.1.52\f512bef2796b51299f4752f95918982c3003131d\tomcat-embed-core-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\6.2.16\caeae6bd50832d6ab28f707aa740e957401a5c20\spring-context-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\6.2.16\990289064c810be71630fca9da8e2b6fe8f897b5\spring-beans-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\6.2.16\e293ab797b1698084e56ae1f2362b315148683f6\spring-expression-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-observation\1.15.9\edf37b25cdfac0704d6fefa4543edb3ed1817eb0\micrometer-observation-1.15.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-common\2.8.16\5b702cb484981b42cfb455bd80b6ce7f49d34210\springdoc-openapi-starter-common-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.jspecify\jspecify\1.0.0\7425a601c1c7ec76645a78d22b8c6a627edee507\jspecify-1.0.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.validation\jakarta.validation-api\3.0.2\92b6631659ba35ca09e44874d3eb936edfeee532\jakarta.validation-api-3.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.jboss.logging\jboss-logging\3.6.2.Final\3e0a139d7a74cc13b5e01daa8aaa7f71dccd577e\jboss-logging-3.6.2.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml\classmate\1.7.3\f61c7e7b81e9249b0f6a05914eff9d54fb09f4a0\classmate-1.7.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.zaxxer\HikariCP\6.3.3\7c5aec1e47a97ff40977e0193018865304ea9585\HikariCP-6.3.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jdbc\6.2.16\addfdde7b3212f34c95d791c37bb04ba4b08a1b7\spring-jdbc-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.persistence\jakarta.persistence-api\3.1.0\66901fa1c373c6aff65c13791cc11da72060a8d6\jakarta.persistence-api-3.1.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.transaction\jakarta.transaction-api\2.0.1\51a520e3fae406abb84e2e1148e6746ce3f80a1a\jakarta.transaction-api-2.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.data\spring-data-commons\3.5.9\6b577c71f563e78a7da984a3d572fde8a4df8103\spring-data-commons-3.5.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-orm\6.2.16\44b3cfb2c046440f83729641c929c405dc7f2c89\spring-orm-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-tx\6.2.16\5f9d6e78b76530e6258de8a0dff991fb1ad4b9b0\spring-tx-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4-runtime\4.13.0\5a02e48521624faaf5ff4d99afc88b01686af655\antlr4-runtime-4.13.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.aspectj\aspectjweaver\1.9.25.1\a713c790da4d794c7dfb542b550d4e44898d5e23\aspectjweaver-1.9.25.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-core\6.5.8\d052dca52e49d95d2b03f81ae4b6762eeb4c78d0\spring-security-core-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor\reactor-core\3.7.16\dc7f2ba3c4fbc69678937dfe1ad45264d8a1c7be\reactor-core-3.7.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor.netty\reactor-netty-http\1.2.15\b20bb13c95b44f1d0c148bdf1197b7d4a7e0f278\reactor-netty-http-1.2.15.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-autoconfigure\3.3.0\b5a0b27e91ee997f8c86e4b0c521858fdcb9dc9b\spring-cloud-aws-autoconfigure-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-core\3.3.0\3c501426267d8ccbaaebc9796bd5de5bc5d0702e\spring-cloud-aws-core-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\s3\2.29.52\db65bc6177b0c4514be1f9775cb2094e29e85d3c\s3-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.thymeleaf\thymeleaf\3.1.3.RELEASE\51474f2a90b282ee97dabcd159c7faf24790f373\thymeleaf-3.1.3.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.19.4\a720ca9b800742699e041c3890f3731fe516085e\jackson-core-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.19.4\bbb09b1e7f7f5108890270eb701cb3ddef991c05\jackson-annotations-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.5.32\2b1042c50f508f2eb402bd4d22ccbdf94cc37d2e\logback-classic-1.5.32.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.24.3\da1143e2a2531ee1c2d90baa98eb50a28a39d5a7\log4j-to-slf4j-2.24.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\2.0.17\524cb6ccc2b68a57604750e1ab8b13b5a786a6aa\jul-to-slf4j-2.0.17.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\6.2.16\8af6546d28815be574f384dceb93d248e9934f90\spring-jcl-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-commons\1.15.9\5a38f43cdc79a309a458c8ce130fff30a2a7f59\micrometer-commons-1.15.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-core-jakarta\2.2.43\500566364be54e3556bcec28922a41ca5fcc7dcd\swagger-core-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-crypto\6.5.8\aec1a6f6c0e06be9dff08b11e8e1f457afca44b2\spring-security-crypto-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.reactivestreams\reactive-streams\1.0.4\3864a1320d97d7b045f729a326e1e077661f31b7\reactive-streams-1.0.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor.netty\reactor-netty-core\1.2.15\94b2ca82f310c1bf31d3038060e4572eeca1d4b2\reactor-netty-core-1.2.15.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-http2\4.1.131.Final\2e4c47131c60e0bbbca067c891597b466f7033ba\netty-codec-http2-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-http\4.1.131.Final\253d80637ed689ed309ca62371e5fb97746b165\netty-codec-http-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns-native-macos\4.1.131.Final\9e4a908c073e56caa4127f54d946e3e9a5208506\netty-resolver-dns-native-macos-4.1.131.Final-osx-x86_64.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns\4.1.131.Final\7714c0babe26712ccfdbc158aa64898ab909e7d8\netty-resolver-dns-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-epoll\4.1.131.Final\10b7a905019c1ad5c37e8cf63d7229fb00668c1d\netty-transport-native-epoll-4.1.131.Final-linux-x86_64.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-core\2.29.52\dcfa86ac727b5d4e0abad1e8b025ac2febb6382e\aws-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\auth\2.29.52\76f9b22a99b0de0fd31447db22a5cba4ed4b172e\auth-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\regions\2.29.52\270b31c8695739d495452d380d036c72698e623\regions-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-xml-protocol\2.29.52\e7290d4528affec022bd2f3739853f774a955ac2\aws-xml-protocol-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\protocol-core\2.29.52\1a0e4a114c0943142ca395000a949ee840890fea\protocol-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\sdk-core\2.29.52\3f058b489fac3d091417339e02b165e72c637f61\sdk-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\arns\2.29.52\879712423589b58434b8831b9b75304a16983178\arns-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\profiles\2.29.52\59dd1368bff2d242d84515ec7ea8fe63bb472c4e\profiles-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\crt-core\2.29.52\6a16e04be0e8bb8a1767e0644c631dadddfdd764\crt-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth\2.29.52\aa4ce3ff7bcd8dcf131a4f5445455b3eb4926dcf\http-auth-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-aws\2.29.52\1d0dbfa072bc46207066ffa498ad4ed65c52ac6d\http-auth-aws-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-spi\2.29.52\4a64e68a88e3eef0b51819f742931f3607cdd996\http-auth-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\identity-spi\2.29.52\d18449651e8798398cadab6c4b5d8594bb0281c\identity-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\checksums\2.29.52\90631313060ff8ef1ab7745bb1e9740913bdcefc\checksums-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\retries-spi\2.29.52\7e2c7ad44106799491de8cced5925b6473d62e4b\retries-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-client-spi\2.29.52\a8da4f289736c702ec6664836761412e7e1e54a2\http-client-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\metrics-spi\2.29.52\92c3797208d24b2b25ab9b6d1bbab624c3af1b9c\metrics-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\json-utils\2.29.52\d88c6c03061b9f3fcd17dc8456365dab67cc1597\json-utils-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\utils\2.29.52\bde94a15cd79b0240bfa10230970e2f0e4c51eba\utils-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\checksums-spi\2.29.52\537363296f035a935b7d3b50a5bef90014d38010\checksums-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\endpoints-spi\2.29.52\bd702a44ad440628af93afa1ec1d7cdc56baec67\endpoints-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\annotations\2.29.52\9fa958ce528b57d90db01c5015daaf7bd373e57f\annotations-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.attoparser\attoparser\2.0.7.RELEASE\e5d0e988d9124139d645bb5872b24dfa23e283cc\attoparser-2.0.7.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.unbescape\unbescape\1.1.6.RELEASE\7b90360afb2b860e09e8347112800d12c12b2a13\unbescape-1.1.6.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.5.32\fdfb3ff9a842303d4a95207294a6c6bc64e2605d\logback-core-1.5.32.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.24.3\b02c125db8b6d295adf72ae6e71af5d83bce2370\log4j-api-2.24.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-models-jakarta\2.2.43\a68f7470eb763609878460272000f260eabc24dc\swagger-models-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.dataformat\jackson-dataformat-yaml\2.19.4\500956daea0869bf753b94fdaa77e5dc99847d79\jackson-dataformat-yaml-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-lang3\3.17.0\b17d2136f0460dcc0d2016ceefca8723bdf4ee70\commons-lang3-3.17.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-annotations-jakarta\2.2.43\dbd40253251deabb7a628a54b4550dc4fb492f4\swagger-annotations-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.xml.bind\jakarta.xml.bind-api\4.0.4\d6d2327f3817d9a33a3b6b8f2e15a96bc2e7afdc\jakarta.xml.bind-api-4.0.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler-proxy\4.1.131.Final\5ff9e74613a9dd3ca078f06880a16c8cdc046de0\netty-handler-proxy-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler\4.1.131.Final\5ca67999f41c0a68f0b66485ceb990683a0b0694\netty-handler-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec\4.1.131.Final\1874341f7b29879c6833c17e7305272f0cdc2cb6\netty-codec-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport\4.1.131.Final\474862e0855d7a9828fab06a9c73c05387604ee3\netty-transport-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-buffer\4.1.131.Final\f97b636ecd9b81ae3fd1d039b69c4fd3959ecf\netty-buffer-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-common\4.1.131.Final\cdc659109da226b698a74b543a5b97dd0f7e6959\netty-common-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns-classes-macos\4.1.131.Final\b9d57038cc4144e36aee5898085b7f1f018d2c9f\netty-resolver-dns-classes-macos-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-dns\4.1.131.Final\cd23e12e5c3448a1b12c8a4b8deeb4faeb5e483e\netty-codec-dns-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver\4.1.131.Final\9db1bfd7c57b9b6aa9b5cfc61fc3304594bb6b39\netty-resolver-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-classes-epoll\4.1.131.Final\4d7848ac709491fb14f8bce2796fc3eff4a04fd6\netty-transport-classes-epoll-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-unix-common\4.1.131.Final\fa975e4751b23d50c0a60569829f31944d11d292\netty-transport-native-unix-common-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\retries\2.29.52\48cb57817dd88977ec71e63550673c5ce010a191\retries-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.eventstream\eventstream\1.0.1\6ff8649dffc5190366ada897ba8525a836297784\eventstream-1.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-aws-eventstream\2.29.52\e8b723c48008bcac96e2cc34c7415bd8b581c601\http-auth-aws-eventstream-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-query-protocol\2.29.52\672d7a2df481414d02eedf3a9eff45fb87f1b8a\aws-query-protocol-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\third-party-jackson-core\2.29.52\82ff600d837e83130502775a1555c45d7a3e2e1\third-party-jackson-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.activation\jakarta.activation-api\2.1.4\9e5c2a0d75dde71a0bedc4dbdbe47b78a5dc50f8\jakarta.activation-api-2.1.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-socks\4.1.131.Final\614eacc17f44d8abaeaea81f210b4980c3568262\netty-codec-socks-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-devtools\3.5.11\fe7dfcaf3153d049909a618a7ba7df288e80f090\spring-boot-devtools-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-impl\0.12.6\ac23673a84b6089e0369fb8ab2c69edd91cd6eb0\jjwt-impl-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-jackson\0.12.6\f141e0c1136ba17f2632858238a31ae05642dbf8\jjwt-jackson-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.postgresql\postgresql\42.7.10\35100a3f0899551e27af8fed4a3414619a4663b3\postgresql-42.7.10.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.h2database\h2\2.3.232\4fcc05d966ccdb2812ae8b9a718f69226c0cf4e2\h2-2.3.232.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-protobuf-lite\1.69.0\91711f27421babf868e424a64426fccb9e8bf6ec\grpc-protobuf-lite-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.52.0\9c17f496846ab1fca8975c6a50ceac0b3bbe63f0\checker-qual-3.52.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.android\annotations\4.1.1.4\a1678ba907bf92691d879fef34e1a187038f9259\annotations-4.1.1.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.codehaus.mojo\animal-sniffer-annotations\1.24\aa9ba58d30e0aad7f1808fce9c541ea3760678d8\animal-sniffer-annotations-1.24.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-util\1.69.0\1929ab12fce0c610d9d7229b8767f6abb09ebd51\grpc-util-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.perfmark\perfmark-api\0.27.0\f86f575a41b091786a4b027cd9c0c1d2e3fc1c01\perfmark-api-0.27.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-googleapis\1.69.0\1c11a033d96689a4bf3c92fe89b35f5edaef10c2\grpc-googleapis-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-xds\1.69.0\fa1d282a8ba3ae2a5dc0205d2f6a18b5606b5b62\grpc-xds-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-services\1.69.0\bcd917dad2380ee7cf4728da33816ffb9fad6b8b\grpc-services-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.re2j\re2j\1.7\2949632c1b4acce0d7784f28e3152e9cf3c2ec7a\re2j-1.7.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.common\hibernate-commons-annotations\7.0.3.Final\e183c4be8bb41d12e9f19b374e00c34a0a85f439\hibernate-commons-annotations-7.0.3.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.smallrye\jandex\3.2.0\f17ad860f62a08487b9edabde608f8ac55c62fa7\jandex-3.2.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy\1.17.8\af5735f63d00ca47a9375fae5c7471a36331c6ed\byte-buddy-1.17.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-runtime\4.0.6\fb95ebb62564657b2fedfe165b859789ef3a8711\jaxb-runtime-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.inject\jakarta.inject-api\2.0.1\4c28afe1991a941d7702fe1362c365f0a8641d1e\jakarta.inject-api-2.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-core\4.0.6\8e61282303777fc98a00cc3affd0560d68748a75\jaxb-core-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\apache-client\2.29.52\b7ce213c946d69ab1807b3f7ecac1ce29ed60485\apache-client-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\netty-nio-client\2.29.52\20fa79ba82d3b290b12cd10ca49f0ff7608a6107\netty-nio-client-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.eclipse.angus\angus-activation\2.0.3\7f80607ea5014fef0b1779e6c33d63a88a45a563\angus-activation-2.0.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\txw2\4.0.6\4f4cd53b5ff9a2c5aa1211f15ed2569c57dfb044\txw2-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.sun.istack\istack-commons-runtime\4.1.2\18ec117c85f3ba0ac65409136afa8e42bc74e739\istack-commons-runtime-4.1.2.jar -Launcher Type: SUN_STANDARD - -[Global flags] - intx CICompilerCount = 12 {product} {ergonomic} - uint ConcGCThreads = 4 {product} {ergonomic} - uint G1ConcRefinementThreads = 14 {product} {ergonomic} - size_t G1HeapRegionSize = 4194304 {product} {ergonomic} - uintx GCDrainStackTargetSize = 64 {product} {ergonomic} - size_t InitialHeapSize = 532676608 {product} {ergonomic} - bool ManagementServer = true {product} {command line} - size_t MarkStackSize = 4194304 {product} {ergonomic} - size_t MaxHeapSize = 8480882688 {product} {ergonomic} - size_t MinHeapDeltaBytes = 4194304 {product} {ergonomic} - size_t MinHeapSize = 8388608 {product} {ergonomic} - uintx NonNMethodCodeHeapSize = 4096 {pd product} {ergonomic} - uintx NonProfiledCodeHeapSize = 0 {pd product} {ergonomic} - bool ProfileInterpreter = false {pd product} {command line} - uintx ProfiledCodeHeapSize = 0 {pd product} {ergonomic} - size_t SoftMaxHeapSize = 8480882688 {manageable} {ergonomic} - intx TieredStopAtLevel = 1 {product} {command line} - bool UseCompressedOops = true {product lp64_product} {ergonomic} - bool UseG1GC = true {product} {ergonomic} - bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} - -Logging: -Log output configuration: - #0: stdout all=warning uptime,level,tags foldmultilines=false - #1: stderr all=off uptime,level,tags foldmultilines=false - -Release file: - -Environment Variables: -JAVA_HOME=C:\Users\guswn\.jdks\corretto-19.0.2 -CLASSPATH=%JAVA_HOME%\lib -PATH=%JAVA_HOME%\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;D:\application\Git\cmd;C:\Program Files\Docker\Docker\resources\bin;D:\application\putty\;C:\Program Files\dotnet\;C:\Program Files\Bandizip\;D:\application\nodejs\;C:\Users\guswn\AppData\Local\Programs\Python\Python312\Scripts\;C:\Users\guswn\AppData\Local\Programs\Python\Python312\;C:\Users\guswn\AppData\Local\Programs\Python\Launcher\;C:\Users\guswn\AppData\Local\Microsoft\WindowsApps;D:\application\Microsoft VS Code\bin;C:\Users\guswn\AppData\Local\JetBrains\Toolbox\scripts;C:\Users\guswn\.local\bin;D:\application\IntelliJ IDEA 2025.3.2\bin;D:\application\JetBrains Gateway 2025.3.2\bin;C:\Users\guswn\AppData\Roaming\npm -USERNAME=guswn -OS=Windows_NT -PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 170 Stepping 4, GenuineIntel -TMP=C:\Users\guswn\AppData\Local\Temp -TEMP=C:\Users\guswn\AppData\Local\Temp - - - - -Periodic native trim disabled - ---------------- S Y S T E M --------------- - -OS: - Windows 11 , 64 bit Build 26100 (10.0.26100.7920) -OS uptime: 16 days 18:33 hours -Hyper-V role detected - -CPU: total 18 (initial active 18) (9 cores per cpu, 2 threads per core) family 6 model 170 stepping 4 microcode 0x1f, cx8, cmov, fxsr, ht, mmx, 3dnowpref, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, lzcnt, tsc, tscinvbit, avx, avx2, aes, erms, clmul, bmi1, bmi2, adx, sha, fma, vzeroupper, clflush, clflushopt, clwb, hv, serialize, rdtscp, rdpid, fsrm, f16c, cet_ibt, cet_ss -Processor Information for processor 0 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 1 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 2 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 3 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 4 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 5 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 6 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 7 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 8 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 9 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 10 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 11 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 12 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 13 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 14 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 15 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 16 - Max Mhz: 2500, Current Mhz: 700, Mhz Limit: 700 -Processor Information for processor 17 - Max Mhz: 2500, Current Mhz: 700, Mhz Limit: 700 - -Memory: 4k page, system-wide physical 32346M (3876M free) -TotalPageFile size 61970M (AvailPageFile size 336M) -current process WorkingSet (physical memory assigned to process): 13M, peak: 13M -current process commit charge ("private bytes"): 68M, peak: 576M - -vm_info: OpenJDK 64-Bit Server VM (21.0.10+7-LTS) for windows-amd64 JRE (21.0.10+7-LTS), built on 2026-01-15T22:13:46Z by "Administrator" with MS VC++ 17.14 (VS2022) - -END. diff --git a/hs_err_pid189152.log b/hs_err_pid189152.log deleted file mode 100644 index 12c25b95..00000000 --- a/hs_err_pid189152.log +++ /dev/null @@ -1,281 +0,0 @@ -# -# There is insufficient memory for the Java Runtime Environment to continue. -# Native memory allocation (mmap) failed to map 532676608 bytes. Error detail: G1 virtual space -# Possible reasons: -# The system is out of physical RAM or swap space -# This process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap -# Possible solutions: -# Reduce memory load on the system -# Increase physical memory or swap space -# Check if swap backing store is full -# Decrease Java heap size (-Xmx/-Xms) -# Decrease number of Java threads -# Decrease Java thread stack sizes (-Xss) -# Set larger code cache with -XX:ReservedCodeCacheSize= -# JVM is running with Zero Based Compressed Oops mode in which the Java heap is -# placed in the first 32GB address space. The Java Heap base address is the -# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress -# to set the Java Heap base and to place the Java Heap above 32GB virtual address. -# This output file may be truncated or incomplete. -# -# Out of Memory Error (os_windows.cpp:3714), pid=189152, tid=195204 -# -# JRE version: (21.0.10+7) (build ) -# Java VM: OpenJDK 64-Bit Server VM (21.0.10+7-LTS, mixed mode, emulated-client, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64) -# No core dump will be written. Minidumps are not enabled by default on client versions of Windows -# - ---------------- S U M M A R Y ------------ - -Command Line: -XX:TieredStopAtLevel=1 -Dspring.profiles.active=local -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar=55101 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 com.swyp.picke.PickeApplication - -Host: Intel(R) Core(TM) Ultra 5 125H, 18 cores, 31G, Windows 11 , 64 bit Build 26100 (10.0.26100.7920) -Time: Mon Mar 30 22:58:27 2026 elapsed time: 2.032925 seconds (0d 0h 0m 2s) - ---------------- T H R E A D --------------- - -Current thread (0x0000027bde915cc0): JavaThread "Unknown thread" [_thread_in_vm, id=195204, stack(0x00000086bb400000,0x00000086bb500000) (1024K)] - -Stack: [0x00000086bb400000,0x00000086bb500000] -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -V [jvm.dll+0x6df2b9] -V [jvm.dll+0x8bbdeb] -V [jvm.dll+0x8be37a] -V [jvm.dll+0x8bea53] -V [jvm.dll+0x28a7a6] -V [jvm.dll+0x6dbc15] -V [jvm.dll+0x6cfbca] -V [jvm.dll+0x364f6e] -V [jvm.dll+0x36ce3b] -V [jvm.dll+0x3be8d9] -V [jvm.dll+0x3beb7b] -V [jvm.dll+0x339137] -V [jvm.dll+0x339c7b] -V [jvm.dll+0x88634e] -V [jvm.dll+0x3cb831] -V [jvm.dll+0x86f25c] -V [jvm.dll+0x45e901] -V [jvm.dll+0x460541] -C [jli.dll+0x52f0] -C [ucrtbase.dll+0x37b0] -C [KERNEL32.DLL+0x2e8d7] -C [ntdll.dll+0x8c48c] - - ---------------- P R O C E S S --------------- - -Threads class SMR info: -_java_thread_list=0x00007ffa227e2208, length=0, elements={ -} - -Java Threads: ( => current thread ) -Total: 0 - -Other Threads: - 0x0000027bf46a03f0 WorkerThread "GC Thread#0" [id=7472, stack(0x00000086bb500000,0x00000086bb600000) (1024K)] - 0x0000027bde990120 ConcurrentGCThread "G1 Main Marker" [id=163140, stack(0x00000086bb600000,0x00000086bb700000) (1024K)] - 0x0000027bde991760 WorkerThread "G1 Conc#0" [id=152476, stack(0x00000086bb700000,0x00000086bb800000) (1024K)] - -[error occurred during error reporting (printing all threads), id 0xc0000005, EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffa21edbbb7] -VM state: not at safepoint (not fully initialized) - -VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event]) -[0x00007ffa228566b0] Heap_lock - owner thread: 0x0000027bde915cc0 - -Heap address: 0x0000000606800000, size: 8088 MB, Compressed Oops mode: Zero based, Oop shift amount: 3 - -CDS archive(s) mapped at: [0x0000000000000000-0x0000000000000000-0x0000000000000000), size 0, SharedBaseAddress: 0x0000000800000000, ArchiveRelocationMode: 1. -Narrow klass base: 0x0000000000000000, Narrow klass shift: 0, Narrow klass range: 0x0 - -GC Precious Log: - CardTable entry size: 512 - Card Set container configuration: InlinePtr #cards 4 size 8 Array Of Cards #cards 32 size 80 Howl #buckets 8 coarsen threshold 7372 Howl Bitmap #cards 1024 size 144 coarsen threshold 921 Card regions per heap region 1 cards per card region 8192 - -Heap: - garbage-first heap total 0K, used 0K [0x0000000606800000, 0x0000000800000000) - region size 4096K, 0 young (0K), 0 survivors (0K) - -[error occurred during error reporting (printing heap information), id 0xc0000005, EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffa222c9019] -GC Heap History (0 events): -No events - -Dll operation events (1 events): -Event: 0.005 Loaded shared library D:\application\.jdk\bin\java.dll - -Deoptimization events (0 events): -No events - -Classes loaded (0 events): -No events - -Classes unloaded (0 events): -No events - -Classes redefined (0 events): -No events - -Internal exceptions (0 events): -No events - -ZGC Phase Switch (0 events): -No events - -VM Operations (0 events): -No events - -Memory protections (0 events): -No events - -Nmethod flushes (0 events): -No events - -Events (0 events): -No events - - -Dynamic libraries: -0x00007ff7fbf60000 - 0x00007ff7fbf6e000 D:\application\.jdk\bin\java.exe -0x00007ffb03b00000 - 0x00007ffb03d67000 C:\WINDOWS\SYSTEM32\ntdll.dll -0x00007ffb02ce0000 - 0x00007ffb02da9000 C:\WINDOWS\System32\KERNEL32.DLL -0x00007ffb00fa0000 - 0x00007ffb01391000 C:\WINDOWS\System32\KERNELBASE.dll -0x00007ffb003e0000 - 0x00007ffb0052b000 C:\WINDOWS\System32\ucrtbase.dll -0x00007ffae63b0000 - 0x00007ffae63c8000 D:\application\.jdk\bin\jli.dll -0x00007ffb02db0000 - 0x00007ffb02f75000 C:\WINDOWS\System32\USER32.dll -0x00007ffb015c0000 - 0x00007ffb015e7000 C:\WINDOWS\System32\win32u.dll -0x00007ffb02780000 - 0x00007ffb027ab000 C:\WINDOWS\System32\GDI32.dll -0x00007ffae7290000 - 0x00007ffae7523000 C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8037_none_3e092faae333b53b\COMCTL32.dll -0x00007ffb031a0000 - 0x00007ffb03249000 C:\WINDOWS\System32\msvcrt.dll -0x00007ffb01770000 - 0x00007ffb0189b000 C:\WINDOWS\System32\gdi32full.dll -0x00007ffaeab10000 - 0x00007ffaeab2e000 D:\application\.jdk\bin\VCRUNTIME140.dll -0x00007ffb005f0000 - 0x00007ffb00693000 C:\WINDOWS\System32\msvcp_win.dll -0x00007ffb03160000 - 0x00007ffb03191000 C:\WINDOWS\System32\IMM32.DLL -0x00007ffaecfa0000 - 0x00007ffaecfac000 D:\application\.jdk\bin\vcruntime140_1.dll -0x00007ffad39c0000 - 0x00007ffad3a49000 D:\application\.jdk\bin\msvcp140.dll -0x00007ffa21b90000 - 0x00007ffa22938000 D:\application\.jdk\bin\server\jvm.dll -0x00007ffb01d30000 - 0x00007ffb01deb000 C:\WINDOWS\System32\ADVAPI32.dll -0x00007ffb03250000 - 0x00007ffb032f7000 C:\WINDOWS\System32\sechost.dll -0x00007ffb024a0000 - 0x00007ffb025b8000 C:\WINDOWS\System32\RPCRT4.dll -0x00007ffb029a0000 - 0x00007ffb02a14000 C:\WINDOWS\System32\WS2_32.dll -0x00007ffb00240000 - 0x00007ffb0029e000 C:\WINDOWS\SYSTEM32\POWRPROF.dll -0x00007ffaec6c0000 - 0x00007ffaec6f5000 C:\WINDOWS\SYSTEM32\WINMM.dll -0x00007ffae7a30000 - 0x00007ffae7a3b000 C:\WINDOWS\SYSTEM32\VERSION.dll -0x00007ffb00220000 - 0x00007ffb00234000 C:\WINDOWS\SYSTEM32\UMPDC.dll -0x00007ffaff170000 - 0x00007ffaff18b000 C:\WINDOWS\SYSTEM32\kernel.appcore.dll -0x00007ffaea260000 - 0x00007ffaea26a000 D:\application\.jdk\bin\jimage.dll -0x00007ffafe4f0000 - 0x00007ffafe732000 C:\WINDOWS\SYSTEM32\DBGHELP.DLL -0x00007ffb01e50000 - 0x00007ffb021d2000 C:\WINDOWS\System32\combase.dll -0x00007ffb02f80000 - 0x00007ffb03057000 C:\WINDOWS\System32\OLEAUT32.dll -0x00007ffada3d0000 - 0x00007ffada40b000 C:\WINDOWS\SYSTEM32\dbgcore.DLL -0x00007ffb013a0000 - 0x00007ffb01445000 C:\WINDOWS\System32\bcryptPrimitives.dll -0x00007ffae63a0000 - 0x00007ffae63b0000 D:\application\.jdk\bin\instrument.dll -0x00007ffae6310000 - 0x00007ffae6331000 D:\application\.jdk\bin\java.dll - -JVMTI agents: -C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar path:none, loaded, not initialized, instrumentlib options:55101 - -dbghelp: loaded successfully - version: 4.0.5 - missing functions: none -symbol engine: initialized successfully - sym options: 0x614 - pdb path: .;D:\application\.jdk\bin;C:\WINDOWS\SYSTEM32;C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8037_none_3e092faae333b53b;D:\application\.jdk\bin\server - -VM Arguments: -jvm_args: -XX:TieredStopAtLevel=1 -Dspring.profiles.active=local -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar=55101 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -java_command: com.swyp.picke.PickeApplication -java_class_path (initial): D:\Desktop\project\Server\build\classes\java\main;D:\Desktop\project\Server\build\resources\main;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.42\8365263844ebb62398e0dc33057ba10ba472d3b8\lombok-1.18.42.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-web\3.5.11\68fde4c94249e92526105a93ac7c22bd89b6945e\spring-boot-starter-web-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-webmvc-ui\2.8.16\61c68f705d3f17e8318fb18b2904fa6368af251c\springdoc-openapi-starter-webmvc-ui-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-validation\3.5.11\903eefb6eab302617b0f01cc6d65664343bff2a7\spring-boot-starter-validation-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-data-jpa\3.5.11\f176e5c643720818ec7910e1dd2ccb402411cc5d\spring-boot-starter-data-jpa-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-security\3.5.11\db8b6b7951883dea3ce7404f20d6816104cedd4e\spring-boot-starter-security-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-api\0.12.6\478886a888f6add04937baf0361144504a024967\jjwt-api-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-webflux\3.5.11\1461f9a6b6b8397ad71a98c9bbf4278159fb9624\spring-boot-starter-webflux-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.crypto.tink\apps-rewardedads\1.9.1\cbaf11457b36fe57d90a5cb16a76833906486503\apps-rewardedads-1.9.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.cloud\google-cloud-texttospeech\2.58.0\9be37bd3c81c14c72c9cbcfa2dfaf6dad7a35075\google-cloud-texttospeech-2.58.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-starter-s3\3.3.0\fa9790f990ab540814aafdbf2e97c8cd53b5b1a6\spring-cloud-aws-starter-s3-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-thymeleaf\3.5.11\d997aa0df579cf43507d425057940e2712e44808\spring-boot-starter-thymeleaf-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-json\3.5.11\4cdcd68dcddf0a4c645166e39c3fe448fe2b8e98\spring-boot-starter-json-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\3.5.11\10ce971300fd56d6be5f1cfe7d27ddfb1ed7158d\spring-boot-starter-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-tomcat\3.5.11\fb7b96cb61e5fd5700aed96194562e32d166b5ef\spring-boot-starter-tomcat-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webmvc\6.2.16\ff2db80406f1459fddd14a8d06d57e0e3ab69465\spring-webmvc-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-web\6.2.16\2c4355f1f7e5b8969f696cbc90f25cc22f0f2164\spring-web-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-webmvc-api\2.8.16\6e41988d84978e529c01a4cc052b761cd27d5b90\springdoc-openapi-starter-webmvc-api-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.webjars\swagger-ui\5.32.0\d04c7e3e5b8616813136fa36382a548751775528\swagger-ui-5.32.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.webjars\webjars-locator-lite\1.1.3\217ce590453251b39b72c4a9af3986998f6fdbd9\webjars-locator-lite-1.1.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-el\10.1.52\cd94ce17c5a9937eca365eb494711efa10d49b86\tomcat-embed-el-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.validator\hibernate-validator\8.0.3.Final\4425f554297a1c5ba03a3f30e559a9fd91048cf8\hibernate-validator-8.0.3.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-jdbc\3.5.11\3ce801963caadf6eb29abd68f5a0fe50c9bfe211\spring-boot-starter-jdbc-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.orm\hibernate-core\6.6.42.Final\996e3df4a6c67941b582e4493cb9a39c83198f1e\hibernate-core-6.6.42.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.data\spring-data-jpa\3.5.9\56081dde4f663db74ba000c1f8ab30673058c363\spring-data-jpa-3.5.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aspects\6.2.16\763140a66821c494985533f29280a3b4132cf055\spring-aspects-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-web\6.5.8\3db7bf41191d5b23493cca6252595405b5112b34\spring-security-web-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-config\6.5.8\302d32eba89131c0ffd15ba0a1e465051336d42f\spring-security-config-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\6.2.16\59250efa248420a114fe23b4ccf2fea46b804186\spring-aop-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webflux\6.2.16\699ef8bc182893f9ed43206d372f20c4f9aa3231\spring-webflux-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-reactor-netty\3.5.11\f98bd3e3019078679dec4f21fb63152aa2e059a7\spring-boot-starter-reactor-netty-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.crypto.tink\tink\1.10.0\84771b1a4bb5726f73fb8490fadb23f1d2aacd38\tink-1.10.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.13.2\48b8230771e573b54ce6e867a9001e75977fe78e\gson-2.13.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.http-client\google-http-client\1.45.3\dde98b597081b98514867c9cefa551fcdea3a28c\google-http-client-1.45.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.41.0\4381275efdef6ddfae38f002c31e84cd001c97f0\error_prone_annotations-2.41.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.opencensus\opencensus-contrib-http-util\0.31.1\3c13fc5715231fadb16a9b74a44d9d59c460cfa8\opencensus-contrib-http-util-0.31.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\33.4.0-jre\3fcc0a259f724c7de54a6a55ea7e26d3d5c0cac\guava-33.4.0-jre.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-api\1.69.0\965c2c7f708cd6e6ddbf1eb175c3e87e96e41297\grpc-api-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-stub\1.69.0\9e7dc30a9c2df70e25ef4b941f46187e6e178e7a\grpc-stub-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-protobuf\1.69.0\2990b4948357d4fe46aaecb47290cff102079f1e\grpc-protobuf-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\api-common\2.43.0\963d97d95e9bf7275cc26f0b6b72e2aa5b92c6fd\api-common-2.43.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auto.value\auto-value-annotations\1.11.0\f0d047931d07cfbc6fa4079854f181ff62891d6f\auto-value-annotations-1.11.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\javax.annotation\javax.annotation-api\1.3.2\934c04d3cfef185a8008e7bf34331b79730a9d43\javax.annotation-api-1.3.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\3.0.0\7399e65dd7e9ff3404f4535b2f017093bdb134c7\j2objc-annotations-3.0.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protobuf-java\3.25.5\5ae5c9ec39930ae9b5a61b32b93288818ec05ec1\protobuf-java-3.25.5.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-common-protos\2.51.0\ead75a32e6fd65740b6a69feb658254aeab3fef0\proto-google-common-protos-2.51.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-cloud-texttospeech-v1\2.58.0\42f1f29876ddfa2523ebcc41dae801195fd8b3ce\proto-google-cloud-texttospeech-v1-2.58.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-cloud-texttospeech-v1beta1\0.147.0\576df432a2c1181deabf21a54fdecc1a32f69f4e\proto-google-cloud-texttospeech-v1beta1-0.147.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\failureaccess\1.0.2\c4a06a64e650562f30b7bf9aaec1bfed43aca12b\failureaccess-1.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\b421526c5f297295adef1c886e5246c39d4ac629\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.48.4\6b5d69a61012211d581e68699baf3beb1fd382da\checker-qual-3.48.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax\2.60.0\2d277e0795cb69bc14e03be068aa002539e3ef49\gax-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auth\google-auth-library-credentials\1.31.0\b9cd5346d3a683d9a8d9786453f2419cc832a97f\google-auth-library-credentials-1.31.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.opencensus\opencensus-api\0.31.1\66a60c7201c2b8b20ce495f0295b32bb0ccbbc57\opencensus-api-0.31.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-context\1.69.0\cea23878872f76418dcd6df0c6eef0bf27463537\grpc-context-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auth\google-auth-library-oauth2-http\1.31.0\df5be46d21b983aab8d0250f19b585a94bdedcde\google-auth-library-oauth2-http-1.31.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax-grpc\2.60.0\ca4d7dc8c2a85fbdba25ff3449726852e2359ae9\gax-grpc-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-inprocess\1.69.0\8ac4d2e13b48bed9624b8bc485c90f3d28820c93\grpc-inprocess-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-core\1.69.0\7dad3419dfb91a77788afcdf79e0477172784910\grpc-core-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-alts\1.69.0\6d1eac6726fd6fd177666c10fd154823b82272eb\grpc-alts-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-grpclb\1.69.0\d2c9c066693ce94805a503bc47f5b1e76f51541c\grpc-grpclb-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.conscrypt\conscrypt-openjdk-uber\2.5.2\d858f142ea189c62771c505a6548d8606ac098fe\conscrypt-openjdk-uber-2.5.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-auth\1.69.0\a75e19b20bb732364bdcc0979e9d7c9baa4e408e\grpc-auth-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-netty-shaded\1.69.0\99aa9789172695a4b09fe2af5f5bd0ab1be4ae85\grpc-netty-shaded-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax-httpjson\2.60.0\131d9283925337406e35561ec17bf326a9ecec1a\gax-httpjson-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpclient\4.5.14\1194890e6f56ec29177673f2f12d0b8e627dec98\httpclient-4.5.14.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\commons-codec\commons-codec\1.18.0\ee45d1cf6ec2cc2b809ff04b4dc7aec858e0df8f\commons-codec-1.18.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpcore\4.4.16\51cf043c87253c9f58b539c9f7e44c8894223850\httpcore-4.4.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.http-client\google-http-client-gson\1.45.3\29eba40245c4a4e5466f8764bd894d6a97c6694f\google-http-client-gson-1.45.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protobuf-java-util\3.25.5\38cc5ce479603e36466feda2a9f1dfdb2210ef00\protobuf-java-util-3.25.5.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.threeten\threetenbp\1.7.0\8703e893440e550295aa358281db468625bc9a05\threetenbp-1.7.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-starter\3.3.0\7d82d320cb1851beca3005eab2e484a38bd58a08\spring-cloud-aws-starter-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-s3\3.3.0\661e2914e3ad6555e20ffa262a9987c15bcc1712\spring-cloud-aws-s3-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\2.0.17\d9e58ac9c7779ba3bf8142aff6c830617a7fe60f\slf4j-api-2.0.17.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.thymeleaf\thymeleaf-spring6\3.1.3.RELEASE\4b276ea2bd536a18e44b40ff1d9f4848965ff59c\thymeleaf-spring6-3.1.3.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jdk8\2.19.4\90d304bcdb1a4bacb6f4347be625d75300973c60\jackson-datatype-jdk8-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jsr310\2.19.4\3cbcf2e636a6b062772299bf19a347536e58c4df\jackson-datatype-jsr310-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.module\jackson-module-parameter-names\2.19.4\502dfea4c83502f444837b3d040a51e8475f15f2\jackson-module-parameter-names-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.19.4\7a39bf9257b726b90b80f27fa3f5174bc75162a5\jackson-databind-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\3.5.11\3c7d2ec2ac3c301e95814e37fed1c86c19927fc4\spring-boot-autoconfigure-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\3.5.11\8b7f6df00bfbe74d370e1d05d985a127884d2a9c\spring-boot-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\3.5.11\62b692ed7aee31a5670796be8b07732b6b836f4e\spring-boot-starter-logging-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.annotation\jakarta.annotation-api\2.1.1\48b9bda22b091b1f48b13af03fe36db3be6e1ae3\jakarta.annotation-api-2.1.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\6.2.16\a73937f20a303e057add523915b48eb7901e1848\spring-core-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\2.4\e0666b825b796f85521f02360e77f4c92c5a7a07\snakeyaml-2.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-websocket\10.1.52\9d32b801fb474306349013fcdd8317c8cb4d739e\tomcat-embed-websocket-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-core\10.1.52\f512bef2796b51299f4752f95918982c3003131d\tomcat-embed-core-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\6.2.16\caeae6bd50832d6ab28f707aa740e957401a5c20\spring-context-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\6.2.16\990289064c810be71630fca9da8e2b6fe8f897b5\spring-beans-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\6.2.16\e293ab797b1698084e56ae1f2362b315148683f6\spring-expression-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-observation\1.15.9\edf37b25cdfac0704d6fefa4543edb3ed1817eb0\micrometer-observation-1.15.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-common\2.8.16\5b702cb484981b42cfb455bd80b6ce7f49d34210\springdoc-openapi-starter-common-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.jspecify\jspecify\1.0.0\7425a601c1c7ec76645a78d22b8c6a627edee507\jspecify-1.0.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.validation\jakarta.validation-api\3.0.2\92b6631659ba35ca09e44874d3eb936edfeee532\jakarta.validation-api-3.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.jboss.logging\jboss-logging\3.6.2.Final\3e0a139d7a74cc13b5e01daa8aaa7f71dccd577e\jboss-logging-3.6.2.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml\classmate\1.7.3\f61c7e7b81e9249b0f6a05914eff9d54fb09f4a0\classmate-1.7.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.zaxxer\HikariCP\6.3.3\7c5aec1e47a97ff40977e0193018865304ea9585\HikariCP-6.3.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jdbc\6.2.16\addfdde7b3212f34c95d791c37bb04ba4b08a1b7\spring-jdbc-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.persistence\jakarta.persistence-api\3.1.0\66901fa1c373c6aff65c13791cc11da72060a8d6\jakarta.persistence-api-3.1.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.transaction\jakarta.transaction-api\2.0.1\51a520e3fae406abb84e2e1148e6746ce3f80a1a\jakarta.transaction-api-2.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.data\spring-data-commons\3.5.9\6b577c71f563e78a7da984a3d572fde8a4df8103\spring-data-commons-3.5.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-orm\6.2.16\44b3cfb2c046440f83729641c929c405dc7f2c89\spring-orm-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-tx\6.2.16\5f9d6e78b76530e6258de8a0dff991fb1ad4b9b0\spring-tx-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4-runtime\4.13.0\5a02e48521624faaf5ff4d99afc88b01686af655\antlr4-runtime-4.13.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.aspectj\aspectjweaver\1.9.25.1\a713c790da4d794c7dfb542b550d4e44898d5e23\aspectjweaver-1.9.25.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-core\6.5.8\d052dca52e49d95d2b03f81ae4b6762eeb4c78d0\spring-security-core-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor\reactor-core\3.7.16\dc7f2ba3c4fbc69678937dfe1ad45264d8a1c7be\reactor-core-3.7.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor.netty\reactor-netty-http\1.2.15\b20bb13c95b44f1d0c148bdf1197b7d4a7e0f278\reactor-netty-http-1.2.15.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-autoconfigure\3.3.0\b5a0b27e91ee997f8c86e4b0c521858fdcb9dc9b\spring-cloud-aws-autoconfigure-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-core\3.3.0\3c501426267d8ccbaaebc9796bd5de5bc5d0702e\spring-cloud-aws-core-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\s3\2.29.52\db65bc6177b0c4514be1f9775cb2094e29e85d3c\s3-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.thymeleaf\thymeleaf\3.1.3.RELEASE\51474f2a90b282ee97dabcd159c7faf24790f373\thymeleaf-3.1.3.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.19.4\a720ca9b800742699e041c3890f3731fe516085e\jackson-core-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.19.4\bbb09b1e7f7f5108890270eb701cb3ddef991c05\jackson-annotations-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.5.32\2b1042c50f508f2eb402bd4d22ccbdf94cc37d2e\logback-classic-1.5.32.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.24.3\da1143e2a2531ee1c2d90baa98eb50a28a39d5a7\log4j-to-slf4j-2.24.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\2.0.17\524cb6ccc2b68a57604750e1ab8b13b5a786a6aa\jul-to-slf4j-2.0.17.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\6.2.16\8af6546d28815be574f384dceb93d248e9934f90\spring-jcl-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-commons\1.15.9\5a38f43cdc79a309a458c8ce130fff30a2a7f59\micrometer-commons-1.15.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-core-jakarta\2.2.43\500566364be54e3556bcec28922a41ca5fcc7dcd\swagger-core-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-crypto\6.5.8\aec1a6f6c0e06be9dff08b11e8e1f457afca44b2\spring-security-crypto-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.reactivestreams\reactive-streams\1.0.4\3864a1320d97d7b045f729a326e1e077661f31b7\reactive-streams-1.0.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor.netty\reactor-netty-core\1.2.15\94b2ca82f310c1bf31d3038060e4572eeca1d4b2\reactor-netty-core-1.2.15.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-http2\4.1.131.Final\2e4c47131c60e0bbbca067c891597b466f7033ba\netty-codec-http2-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-http\4.1.131.Final\253d80637ed689ed309ca62371e5fb97746b165\netty-codec-http-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns-native-macos\4.1.131.Final\9e4a908c073e56caa4127f54d946e3e9a5208506\netty-resolver-dns-native-macos-4.1.131.Final-osx-x86_64.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns\4.1.131.Final\7714c0babe26712ccfdbc158aa64898ab909e7d8\netty-resolver-dns-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-epoll\4.1.131.Final\10b7a905019c1ad5c37e8cf63d7229fb00668c1d\netty-transport-native-epoll-4.1.131.Final-linux-x86_64.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-core\2.29.52\dcfa86ac727b5d4e0abad1e8b025ac2febb6382e\aws-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\auth\2.29.52\76f9b22a99b0de0fd31447db22a5cba4ed4b172e\auth-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\regions\2.29.52\270b31c8695739d495452d380d036c72698e623\regions-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-xml-protocol\2.29.52\e7290d4528affec022bd2f3739853f774a955ac2\aws-xml-protocol-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\protocol-core\2.29.52\1a0e4a114c0943142ca395000a949ee840890fea\protocol-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\sdk-core\2.29.52\3f058b489fac3d091417339e02b165e72c637f61\sdk-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\arns\2.29.52\879712423589b58434b8831b9b75304a16983178\arns-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\profiles\2.29.52\59dd1368bff2d242d84515ec7ea8fe63bb472c4e\profiles-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\crt-core\2.29.52\6a16e04be0e8bb8a1767e0644c631dadddfdd764\crt-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth\2.29.52\aa4ce3ff7bcd8dcf131a4f5445455b3eb4926dcf\http-auth-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-aws\2.29.52\1d0dbfa072bc46207066ffa498ad4ed65c52ac6d\http-auth-aws-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-spi\2.29.52\4a64e68a88e3eef0b51819f742931f3607cdd996\http-auth-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\identity-spi\2.29.52\d18449651e8798398cadab6c4b5d8594bb0281c\identity-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\checksums\2.29.52\90631313060ff8ef1ab7745bb1e9740913bdcefc\checksums-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\retries-spi\2.29.52\7e2c7ad44106799491de8cced5925b6473d62e4b\retries-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-client-spi\2.29.52\a8da4f289736c702ec6664836761412e7e1e54a2\http-client-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\metrics-spi\2.29.52\92c3797208d24b2b25ab9b6d1bbab624c3af1b9c\metrics-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\json-utils\2.29.52\d88c6c03061b9f3fcd17dc8456365dab67cc1597\json-utils-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\utils\2.29.52\bde94a15cd79b0240bfa10230970e2f0e4c51eba\utils-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\checksums-spi\2.29.52\537363296f035a935b7d3b50a5bef90014d38010\checksums-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\endpoints-spi\2.29.52\bd702a44ad440628af93afa1ec1d7cdc56baec67\endpoints-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\annotations\2.29.52\9fa958ce528b57d90db01c5015daaf7bd373e57f\annotations-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.attoparser\attoparser\2.0.7.RELEASE\e5d0e988d9124139d645bb5872b24dfa23e283cc\attoparser-2.0.7.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.unbescape\unbescape\1.1.6.RELEASE\7b90360afb2b860e09e8347112800d12c12b2a13\unbescape-1.1.6.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.5.32\fdfb3ff9a842303d4a95207294a6c6bc64e2605d\logback-core-1.5.32.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.24.3\b02c125db8b6d295adf72ae6e71af5d83bce2370\log4j-api-2.24.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-models-jakarta\2.2.43\a68f7470eb763609878460272000f260eabc24dc\swagger-models-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.dataformat\jackson-dataformat-yaml\2.19.4\500956daea0869bf753b94fdaa77e5dc99847d79\jackson-dataformat-yaml-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-lang3\3.17.0\b17d2136f0460dcc0d2016ceefca8723bdf4ee70\commons-lang3-3.17.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-annotations-jakarta\2.2.43\dbd40253251deabb7a628a54b4550dc4fb492f4\swagger-annotations-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.xml.bind\jakarta.xml.bind-api\4.0.4\d6d2327f3817d9a33a3b6b8f2e15a96bc2e7afdc\jakarta.xml.bind-api-4.0.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler-proxy\4.1.131.Final\5ff9e74613a9dd3ca078f06880a16c8cdc046de0\netty-handler-proxy-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler\4.1.131.Final\5ca67999f41c0a68f0b66485ceb990683a0b0694\netty-handler-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec\4.1.131.Final\1874341f7b29879c6833c17e7305272f0cdc2cb6\netty-codec-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport\4.1.131.Final\474862e0855d7a9828fab06a9c73c05387604ee3\netty-transport-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-buffer\4.1.131.Final\f97b636ecd9b81ae3fd1d039b69c4fd3959ecf\netty-buffer-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-common\4.1.131.Final\cdc659109da226b698a74b543a5b97dd0f7e6959\netty-common-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns-classes-macos\4.1.131.Final\b9d57038cc4144e36aee5898085b7f1f018d2c9f\netty-resolver-dns-classes-macos-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-dns\4.1.131.Final\cd23e12e5c3448a1b12c8a4b8deeb4faeb5e483e\netty-codec-dns-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver\4.1.131.Final\9db1bfd7c57b9b6aa9b5cfc61fc3304594bb6b39\netty-resolver-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-classes-epoll\4.1.131.Final\4d7848ac709491fb14f8bce2796fc3eff4a04fd6\netty-transport-classes-epoll-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-unix-common\4.1.131.Final\fa975e4751b23d50c0a60569829f31944d11d292\netty-transport-native-unix-common-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\retries\2.29.52\48cb57817dd88977ec71e63550673c5ce010a191\retries-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.eventstream\eventstream\1.0.1\6ff8649dffc5190366ada897ba8525a836297784\eventstream-1.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-aws-eventstream\2.29.52\e8b723c48008bcac96e2cc34c7415bd8b581c601\http-auth-aws-eventstream-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-query-protocol\2.29.52\672d7a2df481414d02eedf3a9eff45fb87f1b8a\aws-query-protocol-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\third-party-jackson-core\2.29.52\82ff600d837e83130502775a1555c45d7a3e2e1\third-party-jackson-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.activation\jakarta.activation-api\2.1.4\9e5c2a0d75dde71a0bedc4dbdbe47b78a5dc50f8\jakarta.activation-api-2.1.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-socks\4.1.131.Final\614eacc17f44d8abaeaea81f210b4980c3568262\netty-codec-socks-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-devtools\3.5.11\fe7dfcaf3153d049909a618a7ba7df288e80f090\spring-boot-devtools-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-impl\0.12.6\ac23673a84b6089e0369fb8ab2c69edd91cd6eb0\jjwt-impl-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-jackson\0.12.6\f141e0c1136ba17f2632858238a31ae05642dbf8\jjwt-jackson-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.postgresql\postgresql\42.7.10\35100a3f0899551e27af8fed4a3414619a4663b3\postgresql-42.7.10.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.h2database\h2\2.3.232\4fcc05d966ccdb2812ae8b9a718f69226c0cf4e2\h2-2.3.232.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-protobuf-lite\1.69.0\91711f27421babf868e424a64426fccb9e8bf6ec\grpc-protobuf-lite-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.52.0\9c17f496846ab1fca8975c6a50ceac0b3bbe63f0\checker-qual-3.52.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.android\annotations\4.1.1.4\a1678ba907bf92691d879fef34e1a187038f9259\annotations-4.1.1.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.codehaus.mojo\animal-sniffer-annotations\1.24\aa9ba58d30e0aad7f1808fce9c541ea3760678d8\animal-sniffer-annotations-1.24.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-util\1.69.0\1929ab12fce0c610d9d7229b8767f6abb09ebd51\grpc-util-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.perfmark\perfmark-api\0.27.0\f86f575a41b091786a4b027cd9c0c1d2e3fc1c01\perfmark-api-0.27.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-googleapis\1.69.0\1c11a033d96689a4bf3c92fe89b35f5edaef10c2\grpc-googleapis-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-xds\1.69.0\fa1d282a8ba3ae2a5dc0205d2f6a18b5606b5b62\grpc-xds-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-services\1.69.0\bcd917dad2380ee7cf4728da33816ffb9fad6b8b\grpc-services-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.re2j\re2j\1.7\2949632c1b4acce0d7784f28e3152e9cf3c2ec7a\re2j-1.7.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.common\hibernate-commons-annotations\7.0.3.Final\e183c4be8bb41d12e9f19b374e00c34a0a85f439\hibernate-commons-annotations-7.0.3.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.smallrye\jandex\3.2.0\f17ad860f62a08487b9edabde608f8ac55c62fa7\jandex-3.2.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy\1.17.8\af5735f63d00ca47a9375fae5c7471a36331c6ed\byte-buddy-1.17.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-runtime\4.0.6\fb95ebb62564657b2fedfe165b859789ef3a8711\jaxb-runtime-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.inject\jakarta.inject-api\2.0.1\4c28afe1991a941d7702fe1362c365f0a8641d1e\jakarta.inject-api-2.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-core\4.0.6\8e61282303777fc98a00cc3affd0560d68748a75\jaxb-core-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\apache-client\2.29.52\b7ce213c946d69ab1807b3f7ecac1ce29ed60485\apache-client-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\netty-nio-client\2.29.52\20fa79ba82d3b290b12cd10ca49f0ff7608a6107\netty-nio-client-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.eclipse.angus\angus-activation\2.0.3\7f80607ea5014fef0b1779e6c33d63a88a45a563\angus-activation-2.0.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\txw2\4.0.6\4f4cd53b5ff9a2c5aa1211f15ed2569c57dfb044\txw2-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.sun.istack\istack-commons-runtime\4.1.2\18ec117c85f3ba0ac65409136afa8e42bc74e739\istack-commons-runtime-4.1.2.jar -Launcher Type: SUN_STANDARD - -[Global flags] - intx CICompilerCount = 12 {product} {ergonomic} - uint ConcGCThreads = 4 {product} {ergonomic} - uint G1ConcRefinementThreads = 14 {product} {ergonomic} - size_t G1HeapRegionSize = 4194304 {product} {ergonomic} - uintx GCDrainStackTargetSize = 64 {product} {ergonomic} - size_t InitialHeapSize = 532676608 {product} {ergonomic} - bool ManagementServer = true {product} {command line} - size_t MarkStackSize = 4194304 {product} {ergonomic} - size_t MaxHeapSize = 8480882688 {product} {ergonomic} - size_t MinHeapDeltaBytes = 4194304 {product} {ergonomic} - size_t MinHeapSize = 8388608 {product} {ergonomic} - uintx NonNMethodCodeHeapSize = 4096 {pd product} {ergonomic} - uintx NonProfiledCodeHeapSize = 0 {pd product} {ergonomic} - bool ProfileInterpreter = false {pd product} {command line} - uintx ProfiledCodeHeapSize = 0 {pd product} {ergonomic} - size_t SoftMaxHeapSize = 8480882688 {manageable} {ergonomic} - intx TieredStopAtLevel = 1 {product} {command line} - bool UseCompressedOops = true {product lp64_product} {ergonomic} - bool UseG1GC = true {product} {ergonomic} - bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} - -Logging: -Log output configuration: - #0: stdout all=warning uptime,level,tags foldmultilines=false - #1: stderr all=off uptime,level,tags foldmultilines=false - -Release file: - -Environment Variables: -JAVA_HOME=C:\Users\guswn\.jdks\corretto-19.0.2 -CLASSPATH=%JAVA_HOME%\lib -PATH=%JAVA_HOME%\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;D:\application\Git\cmd;C:\Program Files\Docker\Docker\resources\bin;D:\application\putty\;C:\Program Files\dotnet\;C:\Program Files\Bandizip\;D:\application\nodejs\;C:\Users\guswn\AppData\Local\Programs\Python\Python312\Scripts\;C:\Users\guswn\AppData\Local\Programs\Python\Python312\;C:\Users\guswn\AppData\Local\Programs\Python\Launcher\;C:\Users\guswn\AppData\Local\Microsoft\WindowsApps;D:\application\Microsoft VS Code\bin;C:\Users\guswn\AppData\Local\JetBrains\Toolbox\scripts;C:\Users\guswn\.local\bin;D:\application\IntelliJ IDEA 2025.3.2\bin;D:\application\JetBrains Gateway 2025.3.2\bin;C:\Users\guswn\AppData\Roaming\npm -USERNAME=guswn -OS=Windows_NT -PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 170 Stepping 4, GenuineIntel -TMP=C:\Users\guswn\AppData\Local\Temp -TEMP=C:\Users\guswn\AppData\Local\Temp - - - - -Periodic native trim disabled - ---------------- S Y S T E M --------------- - -OS: - Windows 11 , 64 bit Build 26100 (10.0.26100.7920) -OS uptime: 16 days 18:33 hours -Hyper-V role detected - -CPU: total 18 (initial active 18) (9 cores per cpu, 2 threads per core) family 6 model 170 stepping 4 microcode 0x1f, cx8, cmov, fxsr, ht, mmx, 3dnowpref, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, lzcnt, tsc, tscinvbit, avx, avx2, aes, erms, clmul, bmi1, bmi2, adx, sha, fma, vzeroupper, clflush, clflushopt, clwb, hv, serialize, rdtscp, rdpid, fsrm, f16c, cet_ibt, cet_ss -Processor Information for processor 0 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 1 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 2 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 3 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 4 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 5 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 6 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 7 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 8 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 9 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 10 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 11 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 12 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 13 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 14 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 15 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 16 - Max Mhz: 2500, Current Mhz: 700, Mhz Limit: 700 -Processor Information for processor 17 - Max Mhz: 2500, Current Mhz: 700, Mhz Limit: 700 - -Memory: 4k page, system-wide physical 32346M (3826M free) -TotalPageFile size 61970M (AvailPageFile size 310M) -current process WorkingSet (physical memory assigned to process): 13M, peak: 13M -current process commit charge ("private bytes"): 68M, peak: 576M - -vm_info: OpenJDK 64-Bit Server VM (21.0.10+7-LTS) for windows-amd64 JRE (21.0.10+7-LTS), built on 2026-01-15T22:13:46Z by "Administrator" with MS VC++ 17.14 (VS2022) - -END. diff --git a/hs_err_pid192028.log b/hs_err_pid192028.log deleted file mode 100644 index cd8d3a59..00000000 --- a/hs_err_pid192028.log +++ /dev/null @@ -1,281 +0,0 @@ -# -# There is insufficient memory for the Java Runtime Environment to continue. -# Native memory allocation (mmap) failed to map 532676608 bytes. Error detail: G1 virtual space -# Possible reasons: -# The system is out of physical RAM or swap space -# This process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap -# Possible solutions: -# Reduce memory load on the system -# Increase physical memory or swap space -# Check if swap backing store is full -# Decrease Java heap size (-Xmx/-Xms) -# Decrease number of Java threads -# Decrease Java thread stack sizes (-Xss) -# Set larger code cache with -XX:ReservedCodeCacheSize= -# JVM is running with Zero Based Compressed Oops mode in which the Java heap is -# placed in the first 32GB address space. The Java Heap base address is the -# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress -# to set the Java Heap base and to place the Java Heap above 32GB virtual address. -# This output file may be truncated or incomplete. -# -# Out of Memory Error (os_windows.cpp:3714), pid=192028, tid=189352 -# -# JRE version: (21.0.10+7) (build ) -# Java VM: OpenJDK 64-Bit Server VM (21.0.10+7-LTS, mixed mode, emulated-client, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64) -# No core dump will be written. Minidumps are not enabled by default on client versions of Windows -# - ---------------- S U M M A R Y ------------ - -Command Line: -XX:TieredStopAtLevel=1 -Dspring.profiles.active=local -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar=55095 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 com.swyp.picke.PickeApplication - -Host: Intel(R) Core(TM) Ultra 5 125H, 18 cores, 31G, Windows 11 , 64 bit Build 26100 (10.0.26100.7920) -Time: Mon Mar 30 22:58:20 2026 elapsed time: 2.059801 seconds (0d 0h 0m 2s) - ---------------- T H R E A D --------------- - -Current thread (0x0000012fb4ed3030): JavaThread "Unknown thread" [_thread_in_vm, id=189352, stack(0x00000005f8500000,0x00000005f8600000) (1024K)] - -Stack: [0x00000005f8500000,0x00000005f8600000] -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -V [jvm.dll+0x6df2b9] -V [jvm.dll+0x8bbdeb] -V [jvm.dll+0x8be37a] -V [jvm.dll+0x8bea53] -V [jvm.dll+0x28a7a6] -V [jvm.dll+0x6dbc15] -V [jvm.dll+0x6cfbca] -V [jvm.dll+0x364f6e] -V [jvm.dll+0x36ce3b] -V [jvm.dll+0x3be8d9] -V [jvm.dll+0x3beb7b] -V [jvm.dll+0x339137] -V [jvm.dll+0x339c7b] -V [jvm.dll+0x88634e] -V [jvm.dll+0x3cb831] -V [jvm.dll+0x86f25c] -V [jvm.dll+0x45e901] -V [jvm.dll+0x460541] -C [jli.dll+0x52f0] -C [ucrtbase.dll+0x37b0] -C [KERNEL32.DLL+0x2e8d7] -C [ntdll.dll+0x8c48c] - - ---------------- P R O C E S S --------------- - -Threads class SMR info: -_java_thread_list=0x00007ffa227e2208, length=0, elements={ -} - -Java Threads: ( => current thread ) -Total: 0 - -Other Threads: - 0x0000012fcd0203f0 WorkerThread "GC Thread#0" [id=193216, stack(0x00000005f8600000,0x00000005f8700000) (1024K)] - 0x0000012fb7315ca0 ConcurrentGCThread "G1 Main Marker" [id=154308, stack(0x00000005f8700000,0x00000005f8800000) (1024K)] - 0x0000012fb73180e0 WorkerThread "G1 Conc#0" [id=191576, stack(0x00000005f8800000,0x00000005f8900000) (1024K)] - -[error occurred during error reporting (printing all threads), id 0xc0000005, EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffa21edbbb7] -VM state: not at safepoint (not fully initialized) - -VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event]) -[0x00007ffa228566b0] Heap_lock - owner thread: 0x0000012fb4ed3030 - -Heap address: 0x0000000606800000, size: 8088 MB, Compressed Oops mode: Zero based, Oop shift amount: 3 - -CDS archive(s) mapped at: [0x0000000000000000-0x0000000000000000-0x0000000000000000), size 0, SharedBaseAddress: 0x0000000800000000, ArchiveRelocationMode: 1. -Narrow klass base: 0x0000000000000000, Narrow klass shift: 0, Narrow klass range: 0x0 - -GC Precious Log: - CardTable entry size: 512 - Card Set container configuration: InlinePtr #cards 4 size 8 Array Of Cards #cards 32 size 80 Howl #buckets 8 coarsen threshold 7372 Howl Bitmap #cards 1024 size 144 coarsen threshold 921 Card regions per heap region 1 cards per card region 8192 - -Heap: - garbage-first heap total 0K, used 0K [0x0000000606800000, 0x0000000800000000) - region size 4096K, 0 young (0K), 0 survivors (0K) - -[error occurred during error reporting (printing heap information), id 0xc0000005, EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffa222c9019] -GC Heap History (0 events): -No events - -Dll operation events (1 events): -Event: 0.044 Loaded shared library D:\application\.jdk\bin\java.dll - -Deoptimization events (0 events): -No events - -Classes loaded (0 events): -No events - -Classes unloaded (0 events): -No events - -Classes redefined (0 events): -No events - -Internal exceptions (0 events): -No events - -ZGC Phase Switch (0 events): -No events - -VM Operations (0 events): -No events - -Memory protections (0 events): -No events - -Nmethod flushes (0 events): -No events - -Events (0 events): -No events - - -Dynamic libraries: -0x00007ff7fbf60000 - 0x00007ff7fbf6e000 D:\application\.jdk\bin\java.exe -0x00007ffb03b00000 - 0x00007ffb03d67000 C:\WINDOWS\SYSTEM32\ntdll.dll -0x00007ffb02ce0000 - 0x00007ffb02da9000 C:\WINDOWS\System32\KERNEL32.DLL -0x00007ffb00fa0000 - 0x00007ffb01391000 C:\WINDOWS\System32\KERNELBASE.dll -0x00007ffb003e0000 - 0x00007ffb0052b000 C:\WINDOWS\System32\ucrtbase.dll -0x00007ffaeab10000 - 0x00007ffaeab2e000 D:\application\.jdk\bin\VCRUNTIME140.dll -0x00007ffae63b0000 - 0x00007ffae63c8000 D:\application\.jdk\bin\jli.dll -0x00007ffb02db0000 - 0x00007ffb02f75000 C:\WINDOWS\System32\USER32.dll -0x00007ffae7290000 - 0x00007ffae7523000 C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8037_none_3e092faae333b53b\COMCTL32.dll -0x00007ffb015c0000 - 0x00007ffb015e7000 C:\WINDOWS\System32\win32u.dll -0x00007ffb031a0000 - 0x00007ffb03249000 C:\WINDOWS\System32\msvcrt.dll -0x00007ffb02780000 - 0x00007ffb027ab000 C:\WINDOWS\System32\GDI32.dll -0x00007ffb01770000 - 0x00007ffb0189b000 C:\WINDOWS\System32\gdi32full.dll -0x00007ffb005f0000 - 0x00007ffb00693000 C:\WINDOWS\System32\msvcp_win.dll -0x00007ffb03160000 - 0x00007ffb03191000 C:\WINDOWS\System32\IMM32.DLL -0x00007ffaecfa0000 - 0x00007ffaecfac000 D:\application\.jdk\bin\vcruntime140_1.dll -0x00007ffad39c0000 - 0x00007ffad3a49000 D:\application\.jdk\bin\msvcp140.dll -0x00007ffa21b90000 - 0x00007ffa22938000 D:\application\.jdk\bin\server\jvm.dll -0x00007ffb01d30000 - 0x00007ffb01deb000 C:\WINDOWS\System32\ADVAPI32.dll -0x00007ffb03250000 - 0x00007ffb032f7000 C:\WINDOWS\System32\sechost.dll -0x00007ffb024a0000 - 0x00007ffb025b8000 C:\WINDOWS\System32\RPCRT4.dll -0x00007ffb029a0000 - 0x00007ffb02a14000 C:\WINDOWS\System32\WS2_32.dll -0x00007ffb00240000 - 0x00007ffb0029e000 C:\WINDOWS\SYSTEM32\POWRPROF.dll -0x00007ffaec6c0000 - 0x00007ffaec6f5000 C:\WINDOWS\SYSTEM32\WINMM.dll -0x00007ffae7a30000 - 0x00007ffae7a3b000 C:\WINDOWS\SYSTEM32\VERSION.dll -0x00007ffb00220000 - 0x00007ffb00234000 C:\WINDOWS\SYSTEM32\UMPDC.dll -0x00007ffaff170000 - 0x00007ffaff18b000 C:\WINDOWS\SYSTEM32\kernel.appcore.dll -0x00007ffaea260000 - 0x00007ffaea26a000 D:\application\.jdk\bin\jimage.dll -0x00007ffafe4f0000 - 0x00007ffafe732000 C:\WINDOWS\SYSTEM32\DBGHELP.DLL -0x00007ffb01e50000 - 0x00007ffb021d2000 C:\WINDOWS\System32\combase.dll -0x00007ffb02f80000 - 0x00007ffb03057000 C:\WINDOWS\System32\OLEAUT32.dll -0x00007ffada3d0000 - 0x00007ffada40b000 C:\WINDOWS\SYSTEM32\dbgcore.DLL -0x00007ffb013a0000 - 0x00007ffb01445000 C:\WINDOWS\System32\bcryptPrimitives.dll -0x00007ffae63a0000 - 0x00007ffae63b0000 D:\application\.jdk\bin\instrument.dll -0x00007ffae6310000 - 0x00007ffae6331000 D:\application\.jdk\bin\java.dll - -JVMTI agents: -C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar path:none, loaded, not initialized, instrumentlib options:55095 - -dbghelp: loaded successfully - version: 4.0.5 - missing functions: none -symbol engine: initialized successfully - sym options: 0x614 - pdb path: .;D:\application\.jdk\bin;C:\WINDOWS\SYSTEM32;C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8037_none_3e092faae333b53b;D:\application\.jdk\bin\server - -VM Arguments: -jvm_args: -XX:TieredStopAtLevel=1 -Dspring.profiles.active=local -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\guswn\AppData\Local\Programs\IntelliJ IDEA\lib\idea_rt.jar=55095 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -java_command: com.swyp.picke.PickeApplication -java_class_path (initial): D:\Desktop\project\Server\build\classes\java\main;D:\Desktop\project\Server\build\resources\main;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.42\8365263844ebb62398e0dc33057ba10ba472d3b8\lombok-1.18.42.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-web\3.5.11\68fde4c94249e92526105a93ac7c22bd89b6945e\spring-boot-starter-web-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-webmvc-ui\2.8.16\61c68f705d3f17e8318fb18b2904fa6368af251c\springdoc-openapi-starter-webmvc-ui-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-validation\3.5.11\903eefb6eab302617b0f01cc6d65664343bff2a7\spring-boot-starter-validation-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-data-jpa\3.5.11\f176e5c643720818ec7910e1dd2ccb402411cc5d\spring-boot-starter-data-jpa-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-security\3.5.11\db8b6b7951883dea3ce7404f20d6816104cedd4e\spring-boot-starter-security-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-api\0.12.6\478886a888f6add04937baf0361144504a024967\jjwt-api-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-webflux\3.5.11\1461f9a6b6b8397ad71a98c9bbf4278159fb9624\spring-boot-starter-webflux-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.crypto.tink\apps-rewardedads\1.9.1\cbaf11457b36fe57d90a5cb16a76833906486503\apps-rewardedads-1.9.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.cloud\google-cloud-texttospeech\2.58.0\9be37bd3c81c14c72c9cbcfa2dfaf6dad7a35075\google-cloud-texttospeech-2.58.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-starter-s3\3.3.0\fa9790f990ab540814aafdbf2e97c8cd53b5b1a6\spring-cloud-aws-starter-s3-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-thymeleaf\3.5.11\d997aa0df579cf43507d425057940e2712e44808\spring-boot-starter-thymeleaf-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-json\3.5.11\4cdcd68dcddf0a4c645166e39c3fe448fe2b8e98\spring-boot-starter-json-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\3.5.11\10ce971300fd56d6be5f1cfe7d27ddfb1ed7158d\spring-boot-starter-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-tomcat\3.5.11\fb7b96cb61e5fd5700aed96194562e32d166b5ef\spring-boot-starter-tomcat-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webmvc\6.2.16\ff2db80406f1459fddd14a8d06d57e0e3ab69465\spring-webmvc-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-web\6.2.16\2c4355f1f7e5b8969f696cbc90f25cc22f0f2164\spring-web-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-webmvc-api\2.8.16\6e41988d84978e529c01a4cc052b761cd27d5b90\springdoc-openapi-starter-webmvc-api-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.webjars\swagger-ui\5.32.0\d04c7e3e5b8616813136fa36382a548751775528\swagger-ui-5.32.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.webjars\webjars-locator-lite\1.1.3\217ce590453251b39b72c4a9af3986998f6fdbd9\webjars-locator-lite-1.1.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-el\10.1.52\cd94ce17c5a9937eca365eb494711efa10d49b86\tomcat-embed-el-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.validator\hibernate-validator\8.0.3.Final\4425f554297a1c5ba03a3f30e559a9fd91048cf8\hibernate-validator-8.0.3.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-jdbc\3.5.11\3ce801963caadf6eb29abd68f5a0fe50c9bfe211\spring-boot-starter-jdbc-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.orm\hibernate-core\6.6.42.Final\996e3df4a6c67941b582e4493cb9a39c83198f1e\hibernate-core-6.6.42.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.data\spring-data-jpa\3.5.9\56081dde4f663db74ba000c1f8ab30673058c363\spring-data-jpa-3.5.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aspects\6.2.16\763140a66821c494985533f29280a3b4132cf055\spring-aspects-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-web\6.5.8\3db7bf41191d5b23493cca6252595405b5112b34\spring-security-web-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-config\6.5.8\302d32eba89131c0ffd15ba0a1e465051336d42f\spring-security-config-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\6.2.16\59250efa248420a114fe23b4ccf2fea46b804186\spring-aop-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webflux\6.2.16\699ef8bc182893f9ed43206d372f20c4f9aa3231\spring-webflux-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-reactor-netty\3.5.11\f98bd3e3019078679dec4f21fb63152aa2e059a7\spring-boot-starter-reactor-netty-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.crypto.tink\tink\1.10.0\84771b1a4bb5726f73fb8490fadb23f1d2aacd38\tink-1.10.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.13.2\48b8230771e573b54ce6e867a9001e75977fe78e\gson-2.13.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.http-client\google-http-client\1.45.3\dde98b597081b98514867c9cefa551fcdea3a28c\google-http-client-1.45.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.41.0\4381275efdef6ddfae38f002c31e84cd001c97f0\error_prone_annotations-2.41.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.opencensus\opencensus-contrib-http-util\0.31.1\3c13fc5715231fadb16a9b74a44d9d59c460cfa8\opencensus-contrib-http-util-0.31.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\33.4.0-jre\3fcc0a259f724c7de54a6a55ea7e26d3d5c0cac\guava-33.4.0-jre.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-api\1.69.0\965c2c7f708cd6e6ddbf1eb175c3e87e96e41297\grpc-api-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-stub\1.69.0\9e7dc30a9c2df70e25ef4b941f46187e6e178e7a\grpc-stub-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-protobuf\1.69.0\2990b4948357d4fe46aaecb47290cff102079f1e\grpc-protobuf-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\api-common\2.43.0\963d97d95e9bf7275cc26f0b6b72e2aa5b92c6fd\api-common-2.43.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auto.value\auto-value-annotations\1.11.0\f0d047931d07cfbc6fa4079854f181ff62891d6f\auto-value-annotations-1.11.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\javax.annotation\javax.annotation-api\1.3.2\934c04d3cfef185a8008e7bf34331b79730a9d43\javax.annotation-api-1.3.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\3.0.0\7399e65dd7e9ff3404f4535b2f017093bdb134c7\j2objc-annotations-3.0.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protobuf-java\3.25.5\5ae5c9ec39930ae9b5a61b32b93288818ec05ec1\protobuf-java-3.25.5.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-common-protos\2.51.0\ead75a32e6fd65740b6a69feb658254aeab3fef0\proto-google-common-protos-2.51.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-cloud-texttospeech-v1\2.58.0\42f1f29876ddfa2523ebcc41dae801195fd8b3ce\proto-google-cloud-texttospeech-v1-2.58.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api.grpc\proto-google-cloud-texttospeech-v1beta1\0.147.0\576df432a2c1181deabf21a54fdecc1a32f69f4e\proto-google-cloud-texttospeech-v1beta1-0.147.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\failureaccess\1.0.2\c4a06a64e650562f30b7bf9aaec1bfed43aca12b\failureaccess-1.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\b421526c5f297295adef1c886e5246c39d4ac629\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.48.4\6b5d69a61012211d581e68699baf3beb1fd382da\checker-qual-3.48.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax\2.60.0\2d277e0795cb69bc14e03be068aa002539e3ef49\gax-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auth\google-auth-library-credentials\1.31.0\b9cd5346d3a683d9a8d9786453f2419cc832a97f\google-auth-library-credentials-1.31.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.opencensus\opencensus-api\0.31.1\66a60c7201c2b8b20ce495f0295b32bb0ccbbc57\opencensus-api-0.31.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-context\1.69.0\cea23878872f76418dcd6df0c6eef0bf27463537\grpc-context-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.auth\google-auth-library-oauth2-http\1.31.0\df5be46d21b983aab8d0250f19b585a94bdedcde\google-auth-library-oauth2-http-1.31.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax-grpc\2.60.0\ca4d7dc8c2a85fbdba25ff3449726852e2359ae9\gax-grpc-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-inprocess\1.69.0\8ac4d2e13b48bed9624b8bc485c90f3d28820c93\grpc-inprocess-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-core\1.69.0\7dad3419dfb91a77788afcdf79e0477172784910\grpc-core-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-alts\1.69.0\6d1eac6726fd6fd177666c10fd154823b82272eb\grpc-alts-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-grpclb\1.69.0\d2c9c066693ce94805a503bc47f5b1e76f51541c\grpc-grpclb-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.conscrypt\conscrypt-openjdk-uber\2.5.2\d858f142ea189c62771c505a6548d8606ac098fe\conscrypt-openjdk-uber-2.5.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-auth\1.69.0\a75e19b20bb732364bdcc0979e9d7c9baa4e408e\grpc-auth-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-netty-shaded\1.69.0\99aa9789172695a4b09fe2af5f5bd0ab1be4ae85\grpc-netty-shaded-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.api\gax-httpjson\2.60.0\131d9283925337406e35561ec17bf326a9ecec1a\gax-httpjson-2.60.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpclient\4.5.14\1194890e6f56ec29177673f2f12d0b8e627dec98\httpclient-4.5.14.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\commons-codec\commons-codec\1.18.0\ee45d1cf6ec2cc2b809ff04b4dc7aec858e0df8f\commons-codec-1.18.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpcore\4.4.16\51cf043c87253c9f58b539c9f7e44c8894223850\httpcore-4.4.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.http-client\google-http-client-gson\1.45.3\29eba40245c4a4e5466f8764bd894d6a97c6694f\google-http-client-gson-1.45.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protobuf-java-util\3.25.5\38cc5ce479603e36466feda2a9f1dfdb2210ef00\protobuf-java-util-3.25.5.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.threeten\threetenbp\1.7.0\8703e893440e550295aa358281db468625bc9a05\threetenbp-1.7.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-starter\3.3.0\7d82d320cb1851beca3005eab2e484a38bd58a08\spring-cloud-aws-starter-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-s3\3.3.0\661e2914e3ad6555e20ffa262a9987c15bcc1712\spring-cloud-aws-s3-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\2.0.17\d9e58ac9c7779ba3bf8142aff6c830617a7fe60f\slf4j-api-2.0.17.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.thymeleaf\thymeleaf-spring6\3.1.3.RELEASE\4b276ea2bd536a18e44b40ff1d9f4848965ff59c\thymeleaf-spring6-3.1.3.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jdk8\2.19.4\90d304bcdb1a4bacb6f4347be625d75300973c60\jackson-datatype-jdk8-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jsr310\2.19.4\3cbcf2e636a6b062772299bf19a347536e58c4df\jackson-datatype-jsr310-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.module\jackson-module-parameter-names\2.19.4\502dfea4c83502f444837b3d040a51e8475f15f2\jackson-module-parameter-names-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.19.4\7a39bf9257b726b90b80f27fa3f5174bc75162a5\jackson-databind-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\3.5.11\3c7d2ec2ac3c301e95814e37fed1c86c19927fc4\spring-boot-autoconfigure-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\3.5.11\8b7f6df00bfbe74d370e1d05d985a127884d2a9c\spring-boot-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\3.5.11\62b692ed7aee31a5670796be8b07732b6b836f4e\spring-boot-starter-logging-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.annotation\jakarta.annotation-api\2.1.1\48b9bda22b091b1f48b13af03fe36db3be6e1ae3\jakarta.annotation-api-2.1.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\6.2.16\a73937f20a303e057add523915b48eb7901e1848\spring-core-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\2.4\e0666b825b796f85521f02360e77f4c92c5a7a07\snakeyaml-2.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-websocket\10.1.52\9d32b801fb474306349013fcdd8317c8cb4d739e\tomcat-embed-websocket-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-core\10.1.52\f512bef2796b51299f4752f95918982c3003131d\tomcat-embed-core-10.1.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\6.2.16\caeae6bd50832d6ab28f707aa740e957401a5c20\spring-context-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\6.2.16\990289064c810be71630fca9da8e2b6fe8f897b5\spring-beans-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\6.2.16\e293ab797b1698084e56ae1f2362b315148683f6\spring-expression-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-observation\1.15.9\edf37b25cdfac0704d6fefa4543edb3ed1817eb0\micrometer-observation-1.15.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springdoc\springdoc-openapi-starter-common\2.8.16\5b702cb484981b42cfb455bd80b6ce7f49d34210\springdoc-openapi-starter-common-2.8.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.jspecify\jspecify\1.0.0\7425a601c1c7ec76645a78d22b8c6a627edee507\jspecify-1.0.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.validation\jakarta.validation-api\3.0.2\92b6631659ba35ca09e44874d3eb936edfeee532\jakarta.validation-api-3.0.2.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.jboss.logging\jboss-logging\3.6.2.Final\3e0a139d7a74cc13b5e01daa8aaa7f71dccd577e\jboss-logging-3.6.2.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml\classmate\1.7.3\f61c7e7b81e9249b0f6a05914eff9d54fb09f4a0\classmate-1.7.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.zaxxer\HikariCP\6.3.3\7c5aec1e47a97ff40977e0193018865304ea9585\HikariCP-6.3.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jdbc\6.2.16\addfdde7b3212f34c95d791c37bb04ba4b08a1b7\spring-jdbc-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.persistence\jakarta.persistence-api\3.1.0\66901fa1c373c6aff65c13791cc11da72060a8d6\jakarta.persistence-api-3.1.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.transaction\jakarta.transaction-api\2.0.1\51a520e3fae406abb84e2e1148e6746ce3f80a1a\jakarta.transaction-api-2.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.data\spring-data-commons\3.5.9\6b577c71f563e78a7da984a3d572fde8a4df8103\spring-data-commons-3.5.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-orm\6.2.16\44b3cfb2c046440f83729641c929c405dc7f2c89\spring-orm-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-tx\6.2.16\5f9d6e78b76530e6258de8a0dff991fb1ad4b9b0\spring-tx-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4-runtime\4.13.0\5a02e48521624faaf5ff4d99afc88b01686af655\antlr4-runtime-4.13.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.aspectj\aspectjweaver\1.9.25.1\a713c790da4d794c7dfb542b550d4e44898d5e23\aspectjweaver-1.9.25.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-core\6.5.8\d052dca52e49d95d2b03f81ae4b6762eeb4c78d0\spring-security-core-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor\reactor-core\3.7.16\dc7f2ba3c4fbc69678937dfe1ad45264d8a1c7be\reactor-core-3.7.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor.netty\reactor-netty-http\1.2.15\b20bb13c95b44f1d0c148bdf1197b7d4a7e0f278\reactor-netty-http-1.2.15.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-autoconfigure\3.3.0\b5a0b27e91ee997f8c86e4b0c521858fdcb9dc9b\spring-cloud-aws-autoconfigure-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.awspring.cloud\spring-cloud-aws-core\3.3.0\3c501426267d8ccbaaebc9796bd5de5bc5d0702e\spring-cloud-aws-core-3.3.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\s3\2.29.52\db65bc6177b0c4514be1f9775cb2094e29e85d3c\s3-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.thymeleaf\thymeleaf\3.1.3.RELEASE\51474f2a90b282ee97dabcd159c7faf24790f373\thymeleaf-3.1.3.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.19.4\a720ca9b800742699e041c3890f3731fe516085e\jackson-core-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.19.4\bbb09b1e7f7f5108890270eb701cb3ddef991c05\jackson-annotations-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.5.32\2b1042c50f508f2eb402bd4d22ccbdf94cc37d2e\logback-classic-1.5.32.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.24.3\da1143e2a2531ee1c2d90baa98eb50a28a39d5a7\log4j-to-slf4j-2.24.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\2.0.17\524cb6ccc2b68a57604750e1ab8b13b5a786a6aa\jul-to-slf4j-2.0.17.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\6.2.16\8af6546d28815be574f384dceb93d248e9934f90\spring-jcl-6.2.16.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-commons\1.15.9\5a38f43cdc79a309a458c8ce130fff30a2a7f59\micrometer-commons-1.15.9.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-core-jakarta\2.2.43\500566364be54e3556bcec28922a41ca5fcc7dcd\swagger-core-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.security\spring-security-crypto\6.5.8\aec1a6f6c0e06be9dff08b11e8e1f457afca44b2\spring-security-crypto-6.5.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.reactivestreams\reactive-streams\1.0.4\3864a1320d97d7b045f729a326e1e077661f31b7\reactive-streams-1.0.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.projectreactor.netty\reactor-netty-core\1.2.15\94b2ca82f310c1bf31d3038060e4572eeca1d4b2\reactor-netty-core-1.2.15.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-http2\4.1.131.Final\2e4c47131c60e0bbbca067c891597b466f7033ba\netty-codec-http2-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-http\4.1.131.Final\253d80637ed689ed309ca62371e5fb97746b165\netty-codec-http-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns-native-macos\4.1.131.Final\9e4a908c073e56caa4127f54d946e3e9a5208506\netty-resolver-dns-native-macos-4.1.131.Final-osx-x86_64.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns\4.1.131.Final\7714c0babe26712ccfdbc158aa64898ab909e7d8\netty-resolver-dns-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-epoll\4.1.131.Final\10b7a905019c1ad5c37e8cf63d7229fb00668c1d\netty-transport-native-epoll-4.1.131.Final-linux-x86_64.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-core\2.29.52\dcfa86ac727b5d4e0abad1e8b025ac2febb6382e\aws-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\auth\2.29.52\76f9b22a99b0de0fd31447db22a5cba4ed4b172e\auth-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\regions\2.29.52\270b31c8695739d495452d380d036c72698e623\regions-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-xml-protocol\2.29.52\e7290d4528affec022bd2f3739853f774a955ac2\aws-xml-protocol-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\protocol-core\2.29.52\1a0e4a114c0943142ca395000a949ee840890fea\protocol-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\sdk-core\2.29.52\3f058b489fac3d091417339e02b165e72c637f61\sdk-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\arns\2.29.52\879712423589b58434b8831b9b75304a16983178\arns-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\profiles\2.29.52\59dd1368bff2d242d84515ec7ea8fe63bb472c4e\profiles-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\crt-core\2.29.52\6a16e04be0e8bb8a1767e0644c631dadddfdd764\crt-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth\2.29.52\aa4ce3ff7bcd8dcf131a4f5445455b3eb4926dcf\http-auth-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-aws\2.29.52\1d0dbfa072bc46207066ffa498ad4ed65c52ac6d\http-auth-aws-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-spi\2.29.52\4a64e68a88e3eef0b51819f742931f3607cdd996\http-auth-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\identity-spi\2.29.52\d18449651e8798398cadab6c4b5d8594bb0281c\identity-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\checksums\2.29.52\90631313060ff8ef1ab7745bb1e9740913bdcefc\checksums-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\retries-spi\2.29.52\7e2c7ad44106799491de8cced5925b6473d62e4b\retries-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-client-spi\2.29.52\a8da4f289736c702ec6664836761412e7e1e54a2\http-client-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\metrics-spi\2.29.52\92c3797208d24b2b25ab9b6d1bbab624c3af1b9c\metrics-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\json-utils\2.29.52\d88c6c03061b9f3fcd17dc8456365dab67cc1597\json-utils-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\utils\2.29.52\bde94a15cd79b0240bfa10230970e2f0e4c51eba\utils-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\checksums-spi\2.29.52\537363296f035a935b7d3b50a5bef90014d38010\checksums-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\endpoints-spi\2.29.52\bd702a44ad440628af93afa1ec1d7cdc56baec67\endpoints-spi-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\annotations\2.29.52\9fa958ce528b57d90db01c5015daaf7bd373e57f\annotations-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.attoparser\attoparser\2.0.7.RELEASE\e5d0e988d9124139d645bb5872b24dfa23e283cc\attoparser-2.0.7.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.unbescape\unbescape\1.1.6.RELEASE\7b90360afb2b860e09e8347112800d12c12b2a13\unbescape-1.1.6.RELEASE.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.5.32\fdfb3ff9a842303d4a95207294a6c6bc64e2605d\logback-core-1.5.32.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.24.3\b02c125db8b6d295adf72ae6e71af5d83bce2370\log4j-api-2.24.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-models-jakarta\2.2.43\a68f7470eb763609878460272000f260eabc24dc\swagger-models-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.dataformat\jackson-dataformat-yaml\2.19.4\500956daea0869bf753b94fdaa77e5dc99847d79\jackson-dataformat-yaml-2.19.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-lang3\3.17.0\b17d2136f0460dcc0d2016ceefca8723bdf4ee70\commons-lang3-3.17.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.swagger.core.v3\swagger-annotations-jakarta\2.2.43\dbd40253251deabb7a628a54b4550dc4fb492f4\swagger-annotations-jakarta-2.2.43.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.xml.bind\jakarta.xml.bind-api\4.0.4\d6d2327f3817d9a33a3b6b8f2e15a96bc2e7afdc\jakarta.xml.bind-api-4.0.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler-proxy\4.1.131.Final\5ff9e74613a9dd3ca078f06880a16c8cdc046de0\netty-handler-proxy-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler\4.1.131.Final\5ca67999f41c0a68f0b66485ceb990683a0b0694\netty-handler-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec\4.1.131.Final\1874341f7b29879c6833c17e7305272f0cdc2cb6\netty-codec-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport\4.1.131.Final\474862e0855d7a9828fab06a9c73c05387604ee3\netty-transport-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-buffer\4.1.131.Final\f97b636ecd9b81ae3fd1d039b69c4fd3959ecf\netty-buffer-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-common\4.1.131.Final\cdc659109da226b698a74b543a5b97dd0f7e6959\netty-common-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver-dns-classes-macos\4.1.131.Final\b9d57038cc4144e36aee5898085b7f1f018d2c9f\netty-resolver-dns-classes-macos-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-dns\4.1.131.Final\cd23e12e5c3448a1b12c8a4b8deeb4faeb5e483e\netty-codec-dns-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver\4.1.131.Final\9db1bfd7c57b9b6aa9b5cfc61fc3304594bb6b39\netty-resolver-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-classes-epoll\4.1.131.Final\4d7848ac709491fb14f8bce2796fc3eff4a04fd6\netty-transport-classes-epoll-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-unix-common\4.1.131.Final\fa975e4751b23d50c0a60569829f31944d11d292\netty-transport-native-unix-common-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\retries\2.29.52\48cb57817dd88977ec71e63550673c5ce010a191\retries-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.eventstream\eventstream\1.0.1\6ff8649dffc5190366ada897ba8525a836297784\eventstream-1.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\http-auth-aws-eventstream\2.29.52\e8b723c48008bcac96e2cc34c7415bd8b581c601\http-auth-aws-eventstream-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\aws-query-protocol\2.29.52\672d7a2df481414d02eedf3a9eff45fb87f1b8a\aws-query-protocol-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\third-party-jackson-core\2.29.52\82ff600d837e83130502775a1555c45d7a3e2e1\third-party-jackson-core-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.activation\jakarta.activation-api\2.1.4\9e5c2a0d75dde71a0bedc4dbdbe47b78a5dc50f8\jakarta.activation-api-2.1.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec-socks\4.1.131.Final\614eacc17f44d8abaeaea81f210b4980c3568262\netty-codec-socks-4.1.131.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-devtools\3.5.11\fe7dfcaf3153d049909a618a7ba7df288e80f090\spring-boot-devtools-3.5.11.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-impl\0.12.6\ac23673a84b6089e0369fb8ab2c69edd91cd6eb0\jjwt-impl-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.jsonwebtoken\jjwt-jackson\0.12.6\f141e0c1136ba17f2632858238a31ae05642dbf8\jjwt-jackson-0.12.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.postgresql\postgresql\42.7.10\35100a3f0899551e27af8fed4a3414619a4663b3\postgresql-42.7.10.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.h2database\h2\2.3.232\4fcc05d966ccdb2812ae8b9a718f69226c0cf4e2\h2-2.3.232.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-protobuf-lite\1.69.0\91711f27421babf868e424a64426fccb9e8bf6ec\grpc-protobuf-lite-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.52.0\9c17f496846ab1fca8975c6a50ceac0b3bbe63f0\checker-qual-3.52.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.android\annotations\4.1.1.4\a1678ba907bf92691d879fef34e1a187038f9259\annotations-4.1.1.4.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.codehaus.mojo\animal-sniffer-annotations\1.24\aa9ba58d30e0aad7f1808fce9c541ea3760678d8\animal-sniffer-annotations-1.24.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-util\1.69.0\1929ab12fce0c610d9d7229b8767f6abb09ebd51\grpc-util-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.perfmark\perfmark-api\0.27.0\f86f575a41b091786a4b027cd9c0c1d2e3fc1c01\perfmark-api-0.27.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-googleapis\1.69.0\1c11a033d96689a4bf3c92fe89b35f5edaef10c2\grpc-googleapis-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-xds\1.69.0\fa1d282a8ba3ae2a5dc0205d2f6a18b5606b5b62\grpc-xds-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.grpc\grpc-services\1.69.0\bcd917dad2380ee7cf4728da33816ffb9fad6b8b\grpc-services-1.69.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.google.re2j\re2j\1.7\2949632c1b4acce0d7784f28e3152e9cf3c2ec7a\re2j-1.7.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.hibernate.common\hibernate-commons-annotations\7.0.3.Final\e183c4be8bb41d12e9f19b374e00c34a0a85f439\hibernate-commons-annotations-7.0.3.Final.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\io.smallrye\jandex\3.2.0\f17ad860f62a08487b9edabde608f8ac55c62fa7\jandex-3.2.0.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy\1.17.8\af5735f63d00ca47a9375fae5c7471a36331c6ed\byte-buddy-1.17.8.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-runtime\4.0.6\fb95ebb62564657b2fedfe165b859789ef3a8711\jaxb-runtime-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\jakarta.inject\jakarta.inject-api\2.0.1\4c28afe1991a941d7702fe1362c365f0a8641d1e\jakarta.inject-api-2.0.1.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-core\4.0.6\8e61282303777fc98a00cc3affd0560d68748a75\jaxb-core-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\apache-client\2.29.52\b7ce213c946d69ab1807b3f7ecac1ce29ed60485\apache-client-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\software.amazon.awssdk\netty-nio-client\2.29.52\20fa79ba82d3b290b12cd10ca49f0ff7608a6107\netty-nio-client-2.29.52.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.eclipse.angus\angus-activation\2.0.3\7f80607ea5014fef0b1779e6c33d63a88a45a563\angus-activation-2.0.3.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\txw2\4.0.6\4f4cd53b5ff9a2c5aa1211f15ed2569c57dfb044\txw2-4.0.6.jar;C:\Users\guswn\.gradle\caches\modules-2\files-2.1\com.sun.istack\istack-commons-runtime\4.1.2\18ec117c85f3ba0ac65409136afa8e42bc74e739\istack-commons-runtime-4.1.2.jar -Launcher Type: SUN_STANDARD - -[Global flags] - intx CICompilerCount = 12 {product} {ergonomic} - uint ConcGCThreads = 4 {product} {ergonomic} - uint G1ConcRefinementThreads = 14 {product} {ergonomic} - size_t G1HeapRegionSize = 4194304 {product} {ergonomic} - uintx GCDrainStackTargetSize = 64 {product} {ergonomic} - size_t InitialHeapSize = 532676608 {product} {ergonomic} - bool ManagementServer = true {product} {command line} - size_t MarkStackSize = 4194304 {product} {ergonomic} - size_t MaxHeapSize = 8480882688 {product} {ergonomic} - size_t MinHeapDeltaBytes = 4194304 {product} {ergonomic} - size_t MinHeapSize = 8388608 {product} {ergonomic} - uintx NonNMethodCodeHeapSize = 4096 {pd product} {ergonomic} - uintx NonProfiledCodeHeapSize = 0 {pd product} {ergonomic} - bool ProfileInterpreter = false {pd product} {command line} - uintx ProfiledCodeHeapSize = 0 {pd product} {ergonomic} - size_t SoftMaxHeapSize = 8480882688 {manageable} {ergonomic} - intx TieredStopAtLevel = 1 {product} {command line} - bool UseCompressedOops = true {product lp64_product} {ergonomic} - bool UseG1GC = true {product} {ergonomic} - bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} - -Logging: -Log output configuration: - #0: stdout all=warning uptime,level,tags foldmultilines=false - #1: stderr all=off uptime,level,tags foldmultilines=false - -Release file: - -Environment Variables: -JAVA_HOME=C:\Users\guswn\.jdks\corretto-19.0.2 -CLASSPATH=%JAVA_HOME%\lib -PATH=%JAVA_HOME%\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;D:\application\Git\cmd;C:\Program Files\Docker\Docker\resources\bin;D:\application\putty\;C:\Program Files\dotnet\;C:\Program Files\Bandizip\;D:\application\nodejs\;C:\Users\guswn\AppData\Local\Programs\Python\Python312\Scripts\;C:\Users\guswn\AppData\Local\Programs\Python\Python312\;C:\Users\guswn\AppData\Local\Programs\Python\Launcher\;C:\Users\guswn\AppData\Local\Microsoft\WindowsApps;D:\application\Microsoft VS Code\bin;C:\Users\guswn\AppData\Local\JetBrains\Toolbox\scripts;C:\Users\guswn\.local\bin;D:\application\IntelliJ IDEA 2025.3.2\bin;D:\application\JetBrains Gateway 2025.3.2\bin;C:\Users\guswn\AppData\Roaming\npm -USERNAME=guswn -OS=Windows_NT -PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 170 Stepping 4, GenuineIntel -TMP=C:\Users\guswn\AppData\Local\Temp -TEMP=C:\Users\guswn\AppData\Local\Temp - - - - -Periodic native trim disabled - ---------------- S Y S T E M --------------- - -OS: - Windows 11 , 64 bit Build 26100 (10.0.26100.7920) -OS uptime: 16 days 18:33 hours -Hyper-V role detected - -CPU: total 18 (initial active 18) (9 cores per cpu, 2 threads per core) family 6 model 170 stepping 4 microcode 0x1f, cx8, cmov, fxsr, ht, mmx, 3dnowpref, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, lzcnt, tsc, tscinvbit, avx, avx2, aes, erms, clmul, bmi1, bmi2, adx, sha, fma, vzeroupper, clflush, clflushopt, clwb, hv, serialize, rdtscp, rdpid, fsrm, f16c, cet_ibt, cet_ss -Processor Information for processor 0 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 1 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 2 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 3 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 4 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 5 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 6 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 7 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 8 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 9 - Max Mhz: 3600, Current Mhz: 700, Mhz Limit: 684 -Processor Information for processor 10 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 11 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 12 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 13 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 14 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 15 - Max Mhz: 1200, Current Mhz: 1200, Mhz Limit: 1200 -Processor Information for processor 16 - Max Mhz: 2500, Current Mhz: 700, Mhz Limit: 700 -Processor Information for processor 17 - Max Mhz: 2500, Current Mhz: 700, Mhz Limit: 700 - -Memory: 4k page, system-wide physical 32346M (3866M free) -TotalPageFile size 61970M (AvailPageFile size 362M) -current process WorkingSet (physical memory assigned to process): 13M, peak: 13M -current process commit charge ("private bytes"): 68M, peak: 576M - -vm_info: OpenJDK 64-Bit Server VM (21.0.10+7-LTS) for windows-amd64 JRE (21.0.10+7-LTS), built on 2026-01-15T22:13:46Z by "Administrator" with MS VC++ 17.14 (VS2022) - -END. diff --git a/railpack.json b/railpack.json new file mode 100644 index 00000000..a875b64b --- /dev/null +++ b/railpack.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://schema.railpack.com", + "buildAptPackages": ["ffmpeg"], + "deploy": { + "aptPackages": ["ffmpeg"] + } +} diff --git a/src/main/java/com/swyp/picke/domain/admin/controller/AdminPickeController.java b/src/main/java/com/swyp/picke/domain/admin/controller/AdminPickeController.java index e190d6a7..4fcf4e53 100644 --- a/src/main/java/com/swyp/picke/domain/admin/controller/AdminPickeController.java +++ b/src/main/java/com/swyp/picke/domain/admin/controller/AdminPickeController.java @@ -1,52 +1,52 @@ package com.swyp.picke.domain.admin.controller; import io.swagger.v3.oas.annotations.Hidden; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +/** + * 관리자 페이지는 별도 Next.js 앱(admin-web)으로 이관되었다. + * 기존 admin 경로(picke.store/api/v1/admin/**)는 새 앱으로 리다이렉트한다. + * OAuth 콜백(?code=...)은 쿼리스트링을 보존해 새 앱 로그인 페이지로 전달한다. + */ @Hidden @Controller @RequestMapping("/api/v1/admin") public class AdminPickeController { - @Value("${oauth.kakao.client-id}") - private String kakaoClientId; + @Value("${admin.web.url:https://picke.up.railway.app}") + private String adminWebUrl; - @Value("${oauth.google.client-id}") - private String googleClientId; - - @Value("${picke.baseUrl}") - private String baseUrl; + private String redirect(String path, HttpServletRequest request) { + String qs = request.getQueryString(); + return "redirect:" + adminWebUrl + path + (qs != null ? "?" + qs : ""); + } @GetMapping({"", "/"}) - public String index() { - return "redirect:/api/v1/admin/login"; + public String index(HttpServletRequest request) { + return redirect("/login", request); } @GetMapping("/login") - public String adminLoginPage(Model model) { - model.addAttribute("kakaoClientId", kakaoClientId); - model.addAttribute("googleClientId", googleClientId); - model.addAttribute("redirectUri", baseUrl + "/api/v1/admin/login"); - - return "admin/admin-login"; + public String adminLoginPage(HttpServletRequest request) { + return redirect("/login", request); } @GetMapping("/picke/list") - public String pickeListPage() { - return "admin/picke-list"; + public String pickeListPage(HttpServletRequest request) { + return redirect("/picke/list", request); } @GetMapping("/picke") - public String pickeCreatePage() { - return "admin/picke-create"; + public String pickeCreatePage(HttpServletRequest request) { + return redirect("/picke/create", request); } @GetMapping("/picke/notice") - public String noticePage() { - return "admin/admin-notice"; + public String noticePage(HttpServletRequest request) { + return redirect("/notice", request); } -} \ No newline at end of file +} diff --git a/src/main/java/com/swyp/picke/domain/admin/controller/AdminTestAccountController.java b/src/main/java/com/swyp/picke/domain/admin/controller/AdminTestAccountController.java new file mode 100644 index 00000000..786b97d5 --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/admin/controller/AdminTestAccountController.java @@ -0,0 +1,31 @@ +package com.swyp.picke.domain.admin.controller; + +import com.swyp.picke.domain.admin.dto.testaccount.request.CreateTestAccountRequest; +import com.swyp.picke.domain.admin.dto.testaccount.response.TestAccountResponse; +import com.swyp.picke.domain.oauth.service.AuthService; +import com.swyp.picke.global.common.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "관리자 테스트 계정 API", description = "QA/외부 테스터용 로컬 로그인 계정 발급") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/admin/test-accounts") +@PreAuthorize("hasRole('ADMIN')") +public class AdminTestAccountController { + + private final AuthService authService; + + @Operation(summary = "테스트 계정 생성") + @PostMapping + public ApiResponse createTestAccount(@Valid @RequestBody CreateTestAccountRequest request) { + return ApiResponse.onSuccess(authService.createLocalTestAccount(request)); + } +} diff --git a/src/main/java/com/swyp/picke/domain/admin/dto/testaccount/request/CreateTestAccountRequest.java b/src/main/java/com/swyp/picke/domain/admin/dto/testaccount/request/CreateTestAccountRequest.java new file mode 100644 index 00000000..6f24b258 --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/admin/dto/testaccount/request/CreateTestAccountRequest.java @@ -0,0 +1,20 @@ +package com.swyp.picke.domain.admin.dto.testaccount.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@Schema(description = "테스트 계정 생성 요청 객체") +public class CreateTestAccountRequest { + + @NotBlank + @Schema(description = "테스트 계정 아이디", example = "qa-tester01") + private String username; + + @NotBlank + @Schema(description = "테스트 계정 비밀번호", example = "P@ssw0rd!") + private String password; +} diff --git a/src/main/java/com/swyp/picke/domain/admin/dto/testaccount/response/TestAccountResponse.java b/src/main/java/com/swyp/picke/domain/admin/dto/testaccount/response/TestAccountResponse.java new file mode 100644 index 00000000..3532f285 --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/admin/dto/testaccount/response/TestAccountResponse.java @@ -0,0 +1,11 @@ +package com.swyp.picke.domain.admin.dto.testaccount.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class TestAccountResponse { + private String username; + private String userTag; +} diff --git a/src/main/java/com/swyp/picke/domain/attendance/service/AttendanceService.java b/src/main/java/com/swyp/picke/domain/attendance/service/AttendanceService.java index 32f46a55..f2532280 100644 --- a/src/main/java/com/swyp/picke/domain/attendance/service/AttendanceService.java +++ b/src/main/java/com/swyp/picke/domain/attendance/service/AttendanceService.java @@ -36,7 +36,6 @@ public class AttendanceService { private static final ZoneId SEOUL_ZONE = ZoneId.of("Asia/Seoul"); - private static final int STREAK_BONUS_THRESHOLD = 7; private static final int STREAK_REWARD_POINTS = CreditType.ATTENDANCE_STREAK.getDefaultAmount(); private final AttendanceRecordRepository attendanceRecordRepository; @@ -54,7 +53,11 @@ public CheckResponse check() { throw new CustomException(ErrorCode.ATTENDANCE_ALREADY_CHECKED); } - int dailyPoints = CreditType.TODAY_CREDIT.getDefaultAmount(); + // 월~토 개근 후 맞는 일요일에는 5P 대신 7P를 지급(대체), 그 외에는 매일 5P + boolean perfectWeekBonus = isSundayWithFullWeekAttendance(user.getId(), today); + CreditType creditType = perfectWeekBonus ? CreditType.ATTENDANCE_STREAK : CreditType.TODAY_CREDIT; + int dailyPoints = creditType.getDefaultAmount(); + AttendanceRecord record = AttendanceRecord.builder() .user(user) .attendedDate(today) @@ -63,19 +66,19 @@ public CheckResponse check() { attendanceRecordRepository.save(record); Long referenceId = toDateLong(today); - creditService.addCredit(user.getId(), CreditType.TODAY_CREDIT, referenceId); + creditService.addCredit(user.getId(), creditType, referenceId); AttendanceStreak streak = getOrCreateStreak(user, today); - boolean streakBonusEarned = updateStreak(streak, today, user.getId()); + updateStreak(streak, today); - int streakBonusPoints = streakBonusEarned ? STREAK_REWARD_POINTS : 0; + int streakBonusPoints = perfectWeekBonus ? dailyPoints : 0; int totalPoints = creditService.getTotalPoints(user.getId()); return new CheckResponse( user.getUserTag(), LocalDateTime.now(SEOUL_ZONE), dailyPoints, - streakBonusEarned, + perfectWeekBonus, streakBonusPoints, streak.getCurrentStreak(), totalPoints @@ -174,10 +177,10 @@ private AttendanceStreak getOrCreateStreak(User user, LocalDate today) { }); } - private boolean updateStreak(AttendanceStreak streak, LocalDate today, Long userId) { + private void updateStreak(AttendanceStreak streak, LocalDate today) { LocalDate yesterday = today.minusDays(1); boolean continuedStreak = attendanceRecordRepository - .existsByUserIdAndAttendedDate(userId, yesterday); + .existsByUserIdAndAttendedDate(streak.getUserId(), yesterday); if (continuedStreak || streak.getCurrentStreak() == 0) { streak.attend(today); @@ -185,17 +188,17 @@ private boolean updateStreak(AttendanceStreak streak, LocalDate today, Long user LocalDate weekStart = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); streak.resetStreak(weekStart); } + } - boolean justAchieved = streak.getCurrentStreak() >= STREAK_BONUS_THRESHOLD - && streak.isStreakAchieved() - && !creditService.existsHistory(userId, CreditType.ATTENDANCE_STREAK, toDateLong(streak.getStreakWeekStart()) + 7L); - - if (justAchieved) { - Long streakReferenceId = toDateLong(streak.getStreakWeekStart()) + 7L; - creditService.addCredit(userId, CreditType.ATTENDANCE_STREAK, streakReferenceId); + private boolean isSundayWithFullWeekAttendance(Long userId, LocalDate today) { + if (today.getDayOfWeek() != DayOfWeek.SUNDAY) { + return false; } - - return justAchieved; + LocalDate monday = today.minusDays(6); + LocalDate saturday = today.minusDays(1); + List monToSatRecords = + attendanceRecordRepository.findByUserIdAndAttendedDateBetween(userId, monday, saturday); + return monToSatRecords.size() == 6; } private Long toDateLong(LocalDate date) { diff --git a/src/main/java/com/swyp/picke/domain/battle/service/BattleAutoSeedService.java b/src/main/java/com/swyp/picke/domain/battle/service/BattleAutoSeedService.java index 406c1ba2..97d7b102 100644 --- a/src/main/java/com/swyp/picke/domain/battle/service/BattleAutoSeedService.java +++ b/src/main/java/com/swyp/picke/domain/battle/service/BattleAutoSeedService.java @@ -6,11 +6,9 @@ import com.swyp.picke.domain.perspective.repository.PerspectiveRepository; import com.swyp.picke.domain.perspective.service.GptPerspectiveGenerationService; import com.swyp.picke.domain.user.entity.User; -import com.swyp.picke.domain.user.enums.CreditType; import com.swyp.picke.domain.user.enums.UserBattleStep; import com.swyp.picke.domain.user.enums.UserRole; import com.swyp.picke.domain.user.repository.UserRepository; -import com.swyp.picke.domain.user.service.CreditService; import com.swyp.picke.domain.user.service.UserBattleService; import com.swyp.picke.domain.vote.entity.BattleVote; import com.swyp.picke.domain.vote.repository.BattleVoteRepository; @@ -32,7 +30,6 @@ public class BattleAutoSeedService { private final UserRepository userRepository; private final BattleVoteRepository battleVoteRepository; private final UserBattleService userBattleService; - private final CreditService creditService; private final PerspectiveRepository perspectiveRepository; private final GptPerspectiveGenerationService gptPerspectiveGenerationService; @@ -78,8 +75,6 @@ public void seed(Battle battle, List options, int botCount) { .build(); battleVoteRepository.save(vote); - creditService.addCredit(bot.getId(), CreditType.BATTLE_VOTE, vote.getId()); - userBattleService.upsertStep(bot, battle, UserBattleStep.COMPLETED); battle.addParticipant(); diff --git a/src/main/java/com/swyp/picke/domain/notification/controller/NotificationController.java b/src/main/java/com/swyp/picke/domain/notification/controller/NotificationController.java index 2cb20dfa..c176a171 100644 --- a/src/main/java/com/swyp/picke/domain/notification/controller/NotificationController.java +++ b/src/main/java/com/swyp/picke/domain/notification/controller/NotificationController.java @@ -2,6 +2,7 @@ import com.swyp.picke.domain.notification.dto.response.NotificationDetailResponse; import com.swyp.picke.domain.notification.dto.response.NotificationListResponse; +import com.swyp.picke.domain.notification.dto.response.NotificationUnreadResponse; import com.swyp.picke.domain.notification.enums.NotificationCategory; import com.swyp.picke.domain.notification.service.NotificationService; import com.swyp.picke.global.common.response.ApiResponse; @@ -35,6 +36,15 @@ public ApiResponse getNotifications( return ApiResponse.onSuccess(notificationService.getNotifications(userId, category, page, size)); } + @Operation(summary = "알림 미읽음 여부 확인 (배지용)") + @GetMapping("/unread") + public ApiResponse hasUnread( + @AuthenticationPrincipal Long userId, + @RequestParam(required = false) NotificationCategory category + ) { + return ApiResponse.onSuccess(notificationService.hasUnread(userId, category)); + } + @Operation(summary = "알림 상세 조회") @GetMapping("/{notificationId}") public ApiResponse getNotificationDetail( @@ -56,8 +66,8 @@ public ApiResponse markAsRead( @Operation(summary = "알림 전체 읽음 처리") @PatchMapping("/read-all") - public ApiResponse markAllAsRead(@AuthenticationPrincipal Long userId) { + public ApiResponse markAllAsRead(@AuthenticationPrincipal Long userId) { notificationService.markAllAsRead(userId); - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess(notificationService.hasUnread(userId, NotificationCategory.ALL)); } } diff --git a/src/main/java/com/swyp/picke/domain/notification/controller/NotificationTestController.java b/src/main/java/com/swyp/picke/domain/notification/controller/NotificationTestController.java new file mode 100644 index 00000000..78f2ed77 --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/notification/controller/NotificationTestController.java @@ -0,0 +1,33 @@ +package com.swyp.picke.domain.notification.controller; + +import com.swyp.picke.domain.notification.enums.NotificationDetailCode; +import com.swyp.picke.domain.notification.service.NotificationService; +import com.swyp.picke.global.common.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "[Test] Notification", description = "인앱 알림 테스트 API") +@RestController +@RequestMapping("/api/test/notifications") +@RequiredArgsConstructor +public class NotificationTestController { + + private final NotificationService notificationService; + + @Operation(summary = "인앱 알림 즉시 생성", description = "실제 푸시 발송 없이 지정한 유저에게 인앱 알림을 즉시 생성합니다.") + @PostMapping + public ApiResponse createTestNotification( + @RequestParam Long userId, + @RequestParam NotificationDetailCode detailCode, + @RequestParam String body, + @RequestParam Long referenceId + ) { + notificationService.createNotification(userId, detailCode, body, referenceId); + return ApiResponse.onSuccess("userId=" + userId + " 알림 생성 완료 (detailCode=" + detailCode + ")"); + } +} diff --git a/src/main/java/com/swyp/picke/domain/notification/dto/response/NotificationUnreadResponse.java b/src/main/java/com/swyp/picke/domain/notification/dto/response/NotificationUnreadResponse.java new file mode 100644 index 00000000..4b6938b0 --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/notification/dto/response/NotificationUnreadResponse.java @@ -0,0 +1,5 @@ +package com.swyp.picke.domain.notification.dto.response; + +public record NotificationUnreadResponse( + boolean hasUnread +) {} diff --git a/src/main/java/com/swyp/picke/domain/notification/repository/NotificationRepository.java b/src/main/java/com/swyp/picke/domain/notification/repository/NotificationRepository.java index 7ab6759e..14bf3bd1 100644 --- a/src/main/java/com/swyp/picke/domain/notification/repository/NotificationRepository.java +++ b/src/main/java/com/swyp/picke/domain/notification/repository/NotificationRepository.java @@ -38,6 +38,20 @@ AND NOT EXISTS ( """) boolean hasUnreadBroadcast(@Param("userId") Long userId, @Param("category") NotificationCategory category); + @Query(""" + SELECT CASE WHEN COUNT(n) > 0 THEN true ELSE false END + FROM Notification n + WHERE (:category IS NULL OR n.category = :category) + AND ( + (n.user.id = :userId AND n.read = false) + OR (n.user IS NULL AND NOT EXISTS ( + SELECT 1 FROM NotificationRead nr + WHERE nr.notification = n AND nr.userId = :userId + )) + ) + """) + boolean existsUnread(@Param("userId") Long userId, @Param("category") NotificationCategory category); + @Modifying @Query(""" UPDATE Notification n SET n.read = true, n.readAt = CURRENT_TIMESTAMP diff --git a/src/main/java/com/swyp/picke/domain/notification/service/NotificationService.java b/src/main/java/com/swyp/picke/domain/notification/service/NotificationService.java index 1d5be4b5..ea749435 100644 --- a/src/main/java/com/swyp/picke/domain/notification/service/NotificationService.java +++ b/src/main/java/com/swyp/picke/domain/notification/service/NotificationService.java @@ -3,6 +3,7 @@ import com.swyp.picke.domain.notification.dto.response.NotificationDetailResponse; import com.swyp.picke.domain.notification.dto.response.NotificationListResponse; import com.swyp.picke.domain.notification.dto.response.NotificationSummaryResponse; +import com.swyp.picke.domain.notification.dto.response.NotificationUnreadResponse; import com.swyp.picke.domain.notification.entity.Notification; import com.swyp.picke.domain.notification.entity.NotificationRead; import com.swyp.picke.domain.notification.enums.NotificationCategory; @@ -146,6 +147,11 @@ public boolean hasNewBroadcast(Long userId, NotificationCategory category) { return notificationRepository.hasUnreadBroadcast(userId, category); } + public NotificationUnreadResponse hasUnread(Long userId, NotificationCategory category) { + NotificationCategory filterCategory = (category == null || category == NotificationCategory.ALL) ? null : category; + return new NotificationUnreadResponse(notificationRepository.existsUnread(userId, filterCategory)); + } + private Notification getAccessibleNotification(Long userId, Long notificationId) { Notification notification = notificationRepository.findById(notificationId) .orElseThrow(() -> new CustomException(ErrorCode.NOTIFICATION_NOT_FOUND)); diff --git a/src/main/java/com/swyp/picke/domain/oauth/controller/AuthController.java b/src/main/java/com/swyp/picke/domain/oauth/controller/AuthController.java index 0ac93e0a..8946f324 100644 --- a/src/main/java/com/swyp/picke/domain/oauth/controller/AuthController.java +++ b/src/main/java/com/swyp/picke/domain/oauth/controller/AuthController.java @@ -1,5 +1,6 @@ package com.swyp.picke.domain.oauth.controller; +import com.swyp.picke.domain.oauth.dto.LocalLoginRequest; import com.swyp.picke.domain.oauth.dto.LoginRequest; import com.swyp.picke.domain.oauth.dto.LoginResponse; import com.swyp.picke.domain.oauth.dto.LogoutResponse; @@ -31,6 +32,14 @@ public ApiResponse login( return ApiResponse.onSuccess(authService.login(provider, request)); } + @Operation(summary = "로컬(테스트 계정) 로그인") + @PostMapping("/auth/login/local") + public ApiResponse loginLocal( + @Valid @RequestBody LocalLoginRequest request + ) { + return ApiResponse.onSuccess(authService.loginLocal(request)); + } + @Operation(summary = "Access Token 재발급") @PostMapping("/auth/refresh") public ApiResponse refresh( diff --git a/src/main/java/com/swyp/picke/domain/oauth/dto/LocalLoginRequest.java b/src/main/java/com/swyp/picke/domain/oauth/dto/LocalLoginRequest.java new file mode 100644 index 00000000..90b3ceeb --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/oauth/dto/LocalLoginRequest.java @@ -0,0 +1,20 @@ +package com.swyp.picke.domain.oauth.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@Schema(description = "로컬(테스트 계정) 로그인 요청 객체") +public class LocalLoginRequest { + + @NotBlank + @Schema(description = "관리자가 발급한 테스트 계정 아이디", example = "qa-tester01") + private String username; + + @NotBlank + @Schema(description = "테스트 계정 비밀번호", example = "P@ssw0rd!") + private String password; +} diff --git a/src/main/java/com/swyp/picke/domain/oauth/entity/UserLocalAccount.java b/src/main/java/com/swyp/picke/domain/oauth/entity/UserLocalAccount.java new file mode 100644 index 00000000..92a11a17 --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/oauth/entity/UserLocalAccount.java @@ -0,0 +1,32 @@ +package com.swyp.picke.domain.oauth.entity; + +import com.swyp.picke.domain.user.entity.User; +import com.swyp.picke.global.common.BaseEntity; +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Entity +@Table(name = "user_local_accounts") +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@EntityListeners(AuditingEntityListener.class) +public class UserLocalAccount extends BaseEntity { + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false, unique = true) + private User user; + + @Column(nullable = false, unique = true, length = 50) + private String username; + + @Column(name = "password_hash", nullable = false) + private String passwordHash; + + @Builder + public UserLocalAccount(User user, String username, String passwordHash) { + this.user = user; + this.username = username; + this.passwordHash = passwordHash; + } +} diff --git a/src/main/java/com/swyp/picke/domain/oauth/jwt/JwtFilter.java b/src/main/java/com/swyp/picke/domain/oauth/jwt/JwtFilter.java index f4c0b76a..42c11fc2 100644 --- a/src/main/java/com/swyp/picke/domain/oauth/jwt/JwtFilter.java +++ b/src/main/java/com/swyp/picke/domain/oauth/jwt/JwtFilter.java @@ -34,7 +34,8 @@ public class JwtFilter extends OncePerRequestFilter { "/css", "/images", "/favicon.ico", - "/api/v1/auth", + "/api/v1/auth/login", + "/api/v1/auth/refresh", "/swagger-ui", "/v3/api-docs", "/api/v1/home", @@ -47,6 +48,8 @@ public class JwtFilter extends OncePerRequestFilter { "/.well-known", "/api/v1/resources", "/app-ads.txt", + "/terms", + "/privacy-policy", "/robots.txt" ); diff --git a/src/main/java/com/swyp/picke/domain/oauth/repository/UserLocalAccountRepository.java b/src/main/java/com/swyp/picke/domain/oauth/repository/UserLocalAccountRepository.java new file mode 100644 index 00000000..094d4b8b --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/oauth/repository/UserLocalAccountRepository.java @@ -0,0 +1,13 @@ +package com.swyp.picke.domain.oauth.repository; + +import com.swyp.picke.domain.oauth.entity.UserLocalAccount; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserLocalAccountRepository extends JpaRepository { + + Optional findByUsername(String username); + + boolean existsByUsername(String username); +} diff --git a/src/main/java/com/swyp/picke/domain/oauth/service/AuthService.java b/src/main/java/com/swyp/picke/domain/oauth/service/AuthService.java index 4dc534d5..75d68024 100644 --- a/src/main/java/com/swyp/picke/domain/oauth/service/AuthService.java +++ b/src/main/java/com/swyp/picke/domain/oauth/service/AuthService.java @@ -3,14 +3,19 @@ import com.swyp.picke.domain.oauth.client.AppleOAuthClient; import com.swyp.picke.domain.oauth.client.GoogleOAuthClient; import com.swyp.picke.domain.oauth.client.KakaoOAuthClient; +import com.swyp.picke.domain.admin.dto.testaccount.request.CreateTestAccountRequest; +import com.swyp.picke.domain.admin.dto.testaccount.response.TestAccountResponse; +import com.swyp.picke.domain.oauth.dto.LocalLoginRequest; import com.swyp.picke.domain.oauth.dto.LoginRequest; import com.swyp.picke.domain.oauth.dto.LoginResponse; import com.swyp.picke.domain.oauth.dto.OAuthUserInfo; import com.swyp.picke.domain.oauth.dto.WithdrawRequest; import com.swyp.picke.domain.oauth.entity.AuthRefreshToken; +import com.swyp.picke.domain.oauth.entity.UserLocalAccount; import com.swyp.picke.domain.oauth.entity.UserSocialAccount; import com.swyp.picke.domain.oauth.jwt.JwtProvider; import com.swyp.picke.domain.oauth.repository.AuthRefreshTokenRepository; +import com.swyp.picke.domain.oauth.repository.UserLocalAccountRepository; import com.swyp.picke.domain.oauth.repository.UserSocialAccountRepository; import com.swyp.picke.domain.user.enums.CharacterType; import com.swyp.picke.domain.user.enums.CreditType; @@ -30,6 +35,7 @@ import com.swyp.picke.global.common.exception.CustomException; import com.swyp.picke.global.common.exception.ErrorCode; import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -82,6 +88,7 @@ public class AuthService { private final AppleOAuthClient appleOAuthClient; private final UserRepository userRepository; private final UserSocialAccountRepository socialAccountRepository; + private final UserLocalAccountRepository localAccountRepository; private final AuthRefreshTokenRepository refreshTokenRepository; private final UserProfileRepository userProfileRepository; private final UserSettingsRepository userSettingsRepository; @@ -89,6 +96,7 @@ public class AuthService { private final UserWithdrawalRepository userWithdrawalRepository; private final JwtProvider jwtProvider; private final CreditService creditService; + private final PasswordEncoder passwordEncoder; public LoginResponse login(String provider, LoginRequest request) { @@ -146,6 +154,45 @@ public LoginResponse login(String provider, LoginRequest request) { } } + return issueTokensAndBuildResponse(user, isNewUser); + } + + public LoginResponse loginLocal(LocalLoginRequest request) { + UserLocalAccount localAccount = localAccountRepository.findByUsername(request.getUsername()) + .orElseThrow(() -> new CustomException(ErrorCode.AUTH_INVALID_CREDENTIALS)); + + if (!passwordEncoder.matches(request.getPassword(), localAccount.getPasswordHash())) { + throw new CustomException(ErrorCode.AUTH_INVALID_CREDENTIALS); + } + + return issueTokensAndBuildResponse(localAccount.getUser(), false); + } + + public TestAccountResponse createLocalTestAccount(CreateTestAccountRequest request) { + if (localAccountRepository.existsByUsername(request.getUsername())) { + throw new CustomException(ErrorCode.LOCAL_ACCOUNT_USERNAME_DUPLICATED); + } + + User user = User.builder() + .userTag(generateUserTag()) + .role(UserRole.USER) + .status(UserStatus.ACTIVE) + .build(); + userRepository.save(user); + initializeUserDomain(user); + + localAccountRepository.save(UserLocalAccount.builder() + .user(user) + .username(request.getUsername()) + .passwordHash(passwordEncoder.encode(request.getPassword())) + .build()); + + creditService.addCredit(user.getId(), CreditType.DEFAULT_CREDIT, user.getId()); + + return new TestAccountResponse(request.getUsername(), user.getUserTag()); + } + + private LoginResponse issueTokensAndBuildResponse(User user, boolean isNewUser) { // 제재 유저 체크 if (user.getStatus() == UserStatus.BANNED) { throw new CustomException(ErrorCode.USER_BANNED); diff --git a/src/main/java/com/swyp/picke/domain/perspective/controller/BestCommentSchedulerTestController.java b/src/main/java/com/swyp/picke/domain/perspective/controller/BestCommentSchedulerTestController.java deleted file mode 100644 index 552c30c5..00000000 --- a/src/main/java/com/swyp/picke/domain/perspective/controller/BestCommentSchedulerTestController.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.swyp.picke.domain.perspective.controller; - -import com.swyp.picke.domain.perspective.scheduler.BestCommentScheduler; -import com.swyp.picke.global.common.response.ApiResponse; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Tag(name = "[Test] BestCommentScheduler", description = "스케줄러 테스트 API") -@RestController -@RequestMapping("/api/test/scheduler") -@RequiredArgsConstructor -public class BestCommentSchedulerTestController { - - private final BestCommentScheduler bestCommentScheduler; - - @Operation(summary = "베스트 댓글 정산 전체 실행", description = "PUBLISHED 상태 배틀 전체를 대상으로 베스트 댓글 포인트 정산을 즉시 실행합니다.") - @PostMapping("/best-comment") - public ApiResponse runAll() { - bestCommentScheduler.awardBestComments(); - return ApiResponse.onSuccess("베스트 댓글 정산 완료"); - } - - @Operation(summary = "베스트 댓글 정산 단건 실행", description = "특정 battleId에 대해서만 베스트 댓글 포인트 정산을 즉시 실행합니다.") - @PostMapping("/best-comment/battles/{battleId}") - public ApiResponse runByBattle(@PathVariable Long battleId) { - bestCommentScheduler.processBattle(battleId); - return ApiResponse.onSuccess("battleId=" + battleId + " 베스트 댓글 정산 완료"); - } -} diff --git a/src/main/java/com/swyp/picke/domain/perspective/controller/PerspectiveController.java b/src/main/java/com/swyp/picke/domain/perspective/controller/PerspectiveController.java index 9aaf97b4..842cc265 100644 --- a/src/main/java/com/swyp/picke/domain/perspective/controller/PerspectiveController.java +++ b/src/main/java/com/swyp/picke/domain/perspective/controller/PerspectiveController.java @@ -24,6 +24,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @Tag(name = "관점 API", description = "관점 생성, 조회, 수정, 삭제") @RestController @RequestMapping("/api/v1") @@ -63,9 +65,9 @@ public ApiResponse getPerspectives( return ApiResponse.onSuccess(perspectiveService.getPerspectives(battleId, userId, cursor, size, optionId, sort)); } - @Operation(summary = "내 관점 조회", description = "해당 배틀에서 본인이 작성한 관점을 조회합니다.") + @Operation(summary = "내 관점 조회", description = "해당 배틀에서 본인이 작성한 관점 목록을 조회합니다.") @GetMapping("/battles/{battleId}/perspectives/me") - public ApiResponse getMyPerspective( + public ApiResponse> getMyPerspective( @PathVariable Long battleId, @AuthenticationPrincipal Long userId) { return ApiResponse.onSuccess(perspectiveService.getMyPerspective(battleId, userId)); diff --git a/src/main/java/com/swyp/picke/domain/perspective/entity/Perspective.java b/src/main/java/com/swyp/picke/domain/perspective/entity/Perspective.java index 4456b0ae..7ccefa46 100644 --- a/src/main/java/com/swyp/picke/domain/perspective/entity/Perspective.java +++ b/src/main/java/com/swyp/picke/domain/perspective/entity/Perspective.java @@ -13,7 +13,6 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -21,10 +20,7 @@ @Getter @Entity -@Table( - name = "perspectives", - uniqueConstraints = @UniqueConstraint(columnNames = {"battle_id", "user_id"}) -) +@Table(name = "perspectives") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Perspective extends BaseEntity { diff --git a/src/main/java/com/swyp/picke/domain/perspective/repository/PerspectiveRepository.java b/src/main/java/com/swyp/picke/domain/perspective/repository/PerspectiveRepository.java index c2a683ef..c95f04f6 100644 --- a/src/main/java/com/swyp/picke/domain/perspective/repository/PerspectiveRepository.java +++ b/src/main/java/com/swyp/picke/domain/perspective/repository/PerspectiveRepository.java @@ -7,13 +7,10 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.Optional; public interface PerspectiveRepository extends JpaRepository { - boolean existsByBattleIdAndUserId(Long battleId, Long userId); - - Optional findByBattleIdAndUserId(Long battleId, Long userId); + List findByBattleIdAndUserIdOrderByCreatedAtDesc(Long battleId, Long userId); List findByBattleIdAndStatusOrderByCreatedAtDesc(Long battleId, PerspectiveStatus status, Pageable pageable); diff --git a/src/main/java/com/swyp/picke/domain/perspective/scheduler/BestCommentScheduler.java b/src/main/java/com/swyp/picke/domain/perspective/scheduler/BestCommentScheduler.java deleted file mode 100644 index ab7ff943..00000000 --- a/src/main/java/com/swyp/picke/domain/perspective/scheduler/BestCommentScheduler.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.swyp.picke.domain.perspective.scheduler; - -import com.swyp.picke.domain.battle.entity.Battle; -import com.swyp.picke.domain.battle.enums.BattleStatus; -import com.swyp.picke.domain.battle.repository.BattleRepository; -import com.swyp.picke.domain.perspective.entity.PerspectiveComment; -import com.swyp.picke.domain.perspective.repository.PerspectiveCommentRepository; -import com.swyp.picke.domain.user.enums.CreditType; -import com.swyp.picke.domain.user.service.CreditService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.PageRequest; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; - -@Slf4j -@Component -@RequiredArgsConstructor -public class BestCommentScheduler { - - private static final int MIN_LIKE_COUNT = 10; - private static final int TOP_N = 3; - - private final BattleRepository battleRepository; - private final PerspectiveCommentRepository perspectiveCommentRepository; - private final CreditService creditService; - - @Scheduled(cron = "0 0 0 * * MON") - public void awardBestComments() { - log.info("[BestCommentScheduler] 베스트 댓글 포인트 정산 시작"); - - List battles = battleRepository.findByStatusAndDeletedAtIsNull(BattleStatus.PUBLISHED); - - for (Battle battle : battles) { - try { - processBattle(battle.getId()); - } catch (Exception e) { - log.error("[BestCommentScheduler] battleId={} 처리 중 오류 발생: {}", battle.getId(), e.getMessage()); - } - } - - log.info("[BestCommentScheduler] 베스트 댓글 포인트 정산 완료"); - } - - @Transactional - public void processBattle(Long battleId) { - List topComments = perspectiveCommentRepository.findTopCommentsByBattleId( - battleId, - MIN_LIKE_COUNT, - PageRequest.of(0, TOP_N) - ); - - if (topComments.isEmpty()) { - return; - } - - for (PerspectiveComment comment : topComments) { - Long userId = comment.getUser().getId(); - Long commentId = comment.getId(); - - creditService.addCredit(userId, CreditType.BEST_COMMENT, commentId); - log.info("[BestCommentScheduler] 포인트 지급 - battleId={}, commentId={}, userId={}", battleId, commentId, userId); - } - } -} diff --git a/src/main/java/com/swyp/picke/domain/perspective/service/PerspectiveService.java b/src/main/java/com/swyp/picke/domain/perspective/service/PerspectiveService.java index d987e521..1688d09b 100644 --- a/src/main/java/com/swyp/picke/domain/perspective/service/PerspectiveService.java +++ b/src/main/java/com/swyp/picke/domain/perspective/service/PerspectiveService.java @@ -85,10 +85,6 @@ public CreatePerspectiveResponse createPerspective(Long battleId, Long userId, C User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - if (perspectiveRepository.existsByBattleIdAndUserId(battleId, userId)) { - throw new CustomException(ErrorCode.PERSPECTIVE_ALREADY_EXISTS); - } - Long postVoteOptionId = BattleVoteService.findPostVoteOptionId(battleId, userId); BattleOption option = battleService.findOptionById(postVoteOptionId); @@ -181,27 +177,30 @@ public UpdatePerspectiveResponse updatePerspective(Long perspectiveId, Long user return new UpdatePerspectiveResponse(perspective.getId(), perspective.getContent(), perspective.getUpdatedAt()); } - public MyPerspectiveResponse getMyPerspective(Long battleId, Long userId) { + public List getMyPerspective(Long battleId, Long userId) { battleService.findById(battleId); - Perspective perspective = perspectiveRepository.findByBattleIdAndUserId(battleId, userId) - .orElseThrow(() -> new CustomException(ErrorCode.PERSPECTIVE_NOT_FOUND)); + List perspectives = perspectiveRepository.findByBattleIdAndUserIdOrderByCreatedAtDesc(battleId, userId); UserSummary user = userQueryService.findSummaryById(userId); String characterImageUrl = resolveCharacterImageUrl(user.characterType()); - BattleOption option = perspective.getOption(); - boolean isLiked = perspectiveLikeRepository.existsByPerspectiveAndUserId(perspective, userId); - return new MyPerspectiveResponse( - perspective.getId(), - new MyPerspectiveResponse.UserSummary(user.userTag(), user.nickname(), user.characterType(), characterImageUrl), - new MyPerspectiveResponse.OptionSummary(option.getId(), BattleOptionDisplay.opinion(option), option.getTitle(), option.getStance()), - perspective.getContent(), - perspective.getLikeCount(), - perspective.getCommentCount(), - isLiked, - perspective.getStatus(), - perspective.getCreatedAt() - ); + return perspectives.stream() + .map(perspective -> { + BattleOption option = perspective.getOption(); + boolean isLiked = perspectiveLikeRepository.existsByPerspectiveAndUserId(perspective, userId); + return new MyPerspectiveResponse( + perspective.getId(), + new MyPerspectiveResponse.UserSummary(user.userTag(), user.nickname(), user.characterType(), characterImageUrl), + new MyPerspectiveResponse.OptionSummary(option.getId(), BattleOptionDisplay.opinion(option), option.getTitle(), option.getStance()), + perspective.getContent(), + perspective.getLikeCount(), + perspective.getCommentCount(), + isLiked, + perspective.getStatus(), + perspective.getCreatedAt() + ); + }) + .toList(); } @Transactional diff --git a/src/main/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceImpl.java b/src/main/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceImpl.java index ce1ebd63..61e576e2 100644 --- a/src/main/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceImpl.java +++ b/src/main/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceImpl.java @@ -69,9 +69,10 @@ public String processReward(AdMobRewardRequest request) { log.info("[AdMob] 보상 이력 저장 완료: historyId={}", history.getId()); // 6. 크레딧 적립 (history.getId()를 referenceId로 사용해 unique 충돌 방지) - creditService.addCredit(user.getId(), CreditType.FREE_CHARGE, request.reward_amount(), history.getId()); + // AdMob이 보낸 reward_amount는 콘솔 설정에 따라 달라질 수 있어 신뢰하지 않고, 정책상 고정값(FREE_CHARGE)만 지급한다 + creditService.addCredit(user.getId(), CreditType.FREE_CHARGE, CreditType.FREE_CHARGE.getDefaultAmount(), history.getId()); log.info("[AdMob] 포인트 적립 완료: userId={}, amount={}, historyId={}", - user.getId(), request.reward_amount(), history.getId()); + user.getId(), CreditType.FREE_CHARGE.getDefaultAmount(), history.getId()); return "OK"; } diff --git a/src/main/java/com/swyp/picke/domain/user/enums/CreditType.java b/src/main/java/com/swyp/picke/domain/user/enums/CreditType.java index 03519c34..a9cd46c0 100644 --- a/src/main/java/com/swyp/picke/domain/user/enums/CreditType.java +++ b/src/main/java/com/swyp/picke/domain/user/enums/CreditType.java @@ -5,13 +5,11 @@ @Getter public enum CreditType { TODAY_CREDIT(5), // 출석체크: 하루 1회 - ATTENDANCE_STREAK(7), // 7일 연속 출석 보너스 + ATTENDANCE_STREAK(7), // 월~토 개근 후 일요일 출석체크 (TODAY_CREDIT 대신 지급) DEFAULT_CREDIT(30), // 기본 크레딧: 회원가입 시 기본 지급 - BATTLE_VOTE(5), // 배틀 참여 보상: 사후 투표 완료 시 즉시 지급 BATTLE_ENTRY(-5), // 지난 배틀 이용 비용: 사전 투표 최초 진입 시 차감 - MAJORITY_WIN(10), // 다수결 보상: 월요일 배치, 2주 전 배틀 TOP≥10 대상 + MAJORITY_WIN(5), // 다수결 보상: 월요일 배치, 2주 전 배틀 TOP≥10 대상 BEST_COMMENT(15), // 베댓 보상: 월요일 배치, 2주 전 배틀 좋아요 1위 - WEEKLY_CHARGE(40), // 주간 자동 충전: 매주 월요일 00:00 활성 사용자 전체 FREE_CHARGE(20), // 광고/자유 충전: 가변 금액 TOPIC_SUGGEST(100), // 주제 제안 TOPIC_ADOPTED(120); // 주제 채택 diff --git a/src/main/java/com/swyp/picke/domain/user/service/CreditService.java b/src/main/java/com/swyp/picke/domain/user/service/CreditService.java index 82c8359c..7f5dce8b 100644 --- a/src/main/java/com/swyp/picke/domain/user/service/CreditService.java +++ b/src/main/java/com/swyp/picke/domain/user/service/CreditService.java @@ -33,7 +33,7 @@ public class CreditService { /** * 현재 로그인한 유저에게 크레딧 적립 (기본 포인트). * 일반적인 유저 액션(투표, 관점 작성, 좋아요 등)에서 사용. - * 예: creditService.addCredit(CreditType.BATTLE_VOTE, voteId); + * 예: creditService.addCredit(CreditType.BATTLE_ENTRY, battleId); */ @Transactional public void addCredit(CreditType creditType, Long referenceId) { diff --git a/src/main/java/com/swyp/picke/domain/user/service/batch/CreditWeeklyBatchScheduler.java b/src/main/java/com/swyp/picke/domain/user/service/batch/CreditWeeklyBatchScheduler.java index 83e18bec..5203f84c 100644 --- a/src/main/java/com/swyp/picke/domain/user/service/batch/CreditWeeklyBatchScheduler.java +++ b/src/main/java/com/swyp/picke/domain/user/service/batch/CreditWeeklyBatchScheduler.java @@ -9,14 +9,13 @@ /** * 매주 월요일 00:00 (KST) 에 크레딧 주간 배치를 실행한다. * - * 세 잡을 순차로 돌린다: - * 1) 다수결 보상 (+10P) — 2주 전 배틀, 총 투표수 ≥ 10 인 건의 승수 옵션 투표자 전원 - * 2) 베댓 보상 (+50P) — 2주 전 배틀의 Perspective 좋아요 1위 작성자 - * 3) 주간 자동 충전 (+40P) — 활성 사용자 전체 + * 다수결 보상 (+5P) — 2주 전 배틀, 총 투표수 ≥ 10 인 건의 승수 옵션 투표자 전원 * - * 다수결/베댓은 동일 스냅샷 윈도우(14~20일 전 targetDate)를 공유한다. - * 각 잡의 referenceId 가 결정적(배틀ID / perspectiveID / 주차코드)이므로 - * CreditHistory 유니크 제약으로 중복 실행 시에도 추가 적립은 발생하지 않는다. + * 잡의 referenceId 가 결정적(배틀ID)이므로 CreditHistory 유니크 제약으로 + * 중복 실행 시에도 추가 적립은 발생하지 않는다. + * + * 베댓 보상(BestCommentRewardJob, +15P)은 정책표상 "미구현 보류" 항목이라 비활성화했다. + * 재활성화 시 runSafely("BestCommentRewardJob", () -> bestCommentRewardJob.run(runDate)) 호출을 복원하면 된다. */ @Slf4j @Component @@ -24,8 +23,6 @@ public class CreditWeeklyBatchScheduler { private final MajorityWinRewardJob majorityWinRewardJob; - private final BestCommentRewardJob bestCommentRewardJob; - private final WeeklyChargeJob weeklyChargeJob; @Scheduled(cron = "0 0 0 ? * MON", zone = "Asia/Seoul") public void runWeeklyBatch() { @@ -33,8 +30,6 @@ public void runWeeklyBatch() { log.info("[CreditWeeklyBatch] start runDate={}", runDate); runSafely("MajorityWinRewardJob", () -> majorityWinRewardJob.run(runDate)); - runSafely("BestCommentRewardJob", () -> bestCommentRewardJob.run(runDate)); - runSafely("WeeklyChargeJob", () -> weeklyChargeJob.run(runDate)); log.info("[CreditWeeklyBatch] end runDate={}", runDate); } diff --git a/src/main/java/com/swyp/picke/domain/user/service/batch/MajorityWinRewardJob.java b/src/main/java/com/swyp/picke/domain/user/service/batch/MajorityWinRewardJob.java index e687062f..3ed65123 100644 --- a/src/main/java/com/swyp/picke/domain/user/service/batch/MajorityWinRewardJob.java +++ b/src/main/java/com/swyp/picke/domain/user/service/batch/MajorityWinRewardJob.java @@ -21,7 +21,7 @@ * 다수결 보상 배치. * runDate(월요일) 기준 targetDate ∈ [runDate-20, runDate-14] 범위의 배틀 중 * 최다 득표 옵션(= 다수결 승자 옵션)을 선정하고, - * 그 옵션을 사전 투표한 사용자 전원에게 +10P (CreditType.MAJORITY_WIN) 를 지급한다. + * 그 옵션을 사전 투표한 사용자 전원에게 +5P (CreditType.MAJORITY_WIN) 를 지급한다. * * referenceId = battleId. CreditHistory 유니크 제약으로 같은 배틀 재실행 시 중복 지급 없음. */ diff --git a/src/main/java/com/swyp/picke/domain/user/service/batch/WeeklyChargeJob.java b/src/main/java/com/swyp/picke/domain/user/service/batch/WeeklyChargeJob.java deleted file mode 100644 index 38e7f3ba..00000000 --- a/src/main/java/com/swyp/picke/domain/user/service/batch/WeeklyChargeJob.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.swyp.picke.domain.user.service.batch; - -import com.swyp.picke.domain.user.entity.User; -import com.swyp.picke.domain.user.enums.CreditType; -import com.swyp.picke.domain.user.enums.UserStatus; -import com.swyp.picke.domain.user.repository.UserRepository; -import com.swyp.picke.domain.user.service.CreditService; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -/** - * 주간 자동 충전 배치. - * 활성 사용자(UserStatus.ACTIVE) 전원에게 +40P (CreditType.WEEKLY_CHARGE) 지급. - * - * referenceId = 배치 실행 월요일의 yyyyMMdd 정수. 같은 주차 재실행 시 중복 지급 없음. - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class WeeklyChargeJob { - - private static final DateTimeFormatter KEY_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd"); - - private final UserRepository userRepository; - private final CreditService creditService; - - @Transactional - public void run(LocalDate runDate) { - Long weekKey = Long.parseLong(runDate.format(KEY_FORMAT)); - List activeUsers = userRepository.findAllByStatus(UserStatus.ACTIVE); - - log.info("[WeeklyChargeJob] runDate={} activeUsers={}", runDate, activeUsers.size()); - - for (User user : activeUsers) { - creditService.addCredit(user.getId(), CreditType.WEEKLY_CHARGE, weekKey); - } - } -} diff --git a/src/main/java/com/swyp/picke/domain/vote/repository/BattleVoteRepository.java b/src/main/java/com/swyp/picke/domain/vote/repository/BattleVoteRepository.java index 07bbf0bb..f3c5e504 100644 --- a/src/main/java/com/swyp/picke/domain/vote/repository/BattleVoteRepository.java +++ b/src/main/java/com/swyp/picke/domain/vote/repository/BattleVoteRepository.java @@ -9,6 +9,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.time.LocalDate; import java.util.List; import java.util.Optional; @@ -49,6 +50,9 @@ List findByUserIdAndPreVoteOptionDisplayOrderNotOrderByCreatedAtDesc long countByUserId(Long userId); + // 오늘의 배틀 무료 참여(일 1회) 제한 체크용: 유저가 오늘 날짜인 배틀에 이미 참여했는지 확인 + boolean existsByUserIdAndBattle_TargetDate(Long userId, LocalDate targetDate); + @Query("SELECT COUNT(v) FROM BattleVote v WHERE v.user.id = :userId AND v.preVoteOption.displayOrder = :displayOrder") long countByUserIdAndPreVoteOptionDisplayOrder(@Param("userId") Long userId, @Param("displayOrder") Integer displayOrder); diff --git a/src/main/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImpl.java b/src/main/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImpl.java index d4461436..8497d6b8 100644 --- a/src/main/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImpl.java +++ b/src/main/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImpl.java @@ -129,7 +129,7 @@ public VoteResultResponse preVote(Long battleId, Long userId, VoteRequest reques vote = existingVote.get(); vote.updatePreVote(option); } else { - if (shouldChargeBattleEntryCredit(battle)) { + if (shouldChargeBattleEntryCredit(battle, user)) { creditService.addCredit(user.getId(), CreditType.BATTLE_ENTRY, battle.getId()); } vote = BattleVote.createPreVote(user, battle, option); @@ -169,9 +169,6 @@ public VoteResultResponse postVote(Long battleId, Long userId, VoteRequest reque userBattleService.upsertStep(user, battle, UserBattleStep.COMPLETED); eventPublisher.publishEvent(new VoteUpdatedEvent(battleId)); - // 사후 투표 완료 보상 +5P. referenceId=voteId 로 (user, BATTLE_VOTE, voteId) 유니크 제약에 의해 중복 지급 방지. - creditService.addCredit(user.getId(), CreditType.BATTLE_VOTE, vote.getId()); - return new VoteResultResponse(vote.getId(), UserBattleStep.COMPLETED); } @@ -202,8 +199,13 @@ public void completeTts(Long battleId, Long userId) { userBattleService.upsertStep(user, battle, UserBattleStep.POST_VOTE); } - private boolean shouldChargeBattleEntryCredit(Battle battle) { + // 오늘의 배틀(targetDate == 오늘)은 하루 1회에 한해 무료 진입, 그 외 진입 또는 이미 오늘 무료 진입을 사용한 경우 -5P 차감 + private boolean shouldChargeBattleEntryCredit(Battle battle, User user) { LocalDate today = LocalDate.now(KST); - return battle.getTargetDate() == null || !battle.getTargetDate().isEqual(today); + boolean isTodayBattle = battle.getTargetDate() != null && battle.getTargetDate().isEqual(today); + if (!isTodayBattle) { + return true; + } + return battleVoteRepository.existsByUserIdAndBattle_TargetDate(user.getId(), today); } } diff --git a/src/main/java/com/swyp/picke/global/common/exception/ErrorCode.java b/src/main/java/com/swyp/picke/global/common/exception/ErrorCode.java index 046d7070..c0b5dedd 100644 --- a/src/main/java/com/swyp/picke/global/common/exception/ErrorCode.java +++ b/src/main/java/com/swyp/picke/global/common/exception/ErrorCode.java @@ -26,6 +26,8 @@ public enum ErrorCode { AUTH_ACCESS_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "AUTH_401_ACCESS", "Access Token이 만료되었습니다."), AUTH_REFRESH_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "AUTH_401_REFRESH", "Refresh Token이 만료되었습니다. 다시 로그인이 필요합니다."), AUTH_FORBIDDEN(HttpStatus.FORBIDDEN, "AUTH_403", "해당 API 접근 권한(관리자 권한)이 없습니다."), + AUTH_INVALID_CREDENTIALS(HttpStatus.UNAUTHORIZED, "AUTH_401_CRED", "아이디 또는 비밀번호가 올바르지 않습니다."), + LOCAL_ACCOUNT_USERNAME_DUPLICATED(HttpStatus.CONFLICT, "AUTH_409_USERNAME", "이미 사용 중인 아이디입니다."), // User USER_BANNED(HttpStatus.FORBIDDEN, "USER_403_BAN", "영구 제재된 사용자입니다."), @@ -78,7 +80,6 @@ public enum ErrorCode { // Perspective PERSPECTIVE_NOT_FOUND(HttpStatus.NOT_FOUND, "PERSPECTIVE_404", "존재하지 않는 관점입니다."), - PERSPECTIVE_ALREADY_EXISTS(HttpStatus.CONFLICT, "PERSPECTIVE_409", "이미 관점을 작성한 배틀입니다."), PERSPECTIVE_FORBIDDEN(HttpStatus.FORBIDDEN, "PERSPECTIVE_403", "본인 관점만 수정/삭제할 수 있습니다."), PERSPECTIVE_POST_VOTE_REQUIRED(HttpStatus.CONFLICT, "PERSPECTIVE_VOTE_409", "사후 투표가 완료되지 않았습니다."), PERSPECTIVE_MODERATION_NOT_FAILED(HttpStatus.BAD_REQUEST, "PERSPECTIVE_400", "검수 실패 상태의 관점이 아닙니다."), diff --git a/src/main/java/com/swyp/picke/global/config/SecurityConfig.java b/src/main/java/com/swyp/picke/global/config/SecurityConfig.java index 9f36b37a..73ca62b7 100644 --- a/src/main/java/com/swyp/picke/global/config/SecurityConfig.java +++ b/src/main/java/com/swyp/picke/global/config/SecurityConfig.java @@ -13,6 +13,8 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; @@ -51,7 +53,9 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/battle/**", "/.well-known/**", "/app-ads.txt", - "/robots.txt" + "/robots.txt", + "/terms", + "/privacy-policy" ).permitAll() // 2. 관리자 HTML 화면 렌더링 요청 @@ -72,6 +76,11 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http.build(); } + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); diff --git a/src/main/java/com/swyp/picke/global/infra/media/service/FFmpegService.java b/src/main/java/com/swyp/picke/global/infra/media/service/FFmpegService.java index 6cbd1af5..ac3bc632 100644 --- a/src/main/java/com/swyp/picke/global/infra/media/service/FFmpegService.java +++ b/src/main/java/com/swyp/picke/global/infra/media/service/FFmpegService.java @@ -17,9 +17,49 @@ public class FFmpegService implements AudioProcessor { @Value("${media.ffprobe.path:ffprobe}") private String ffprobePath; + private String resolveExecutable(String configuredPath, String fallback) { + if (configuredPath == null || configuredPath.isBlank()) { + return resolveFallbackExecutable(fallback); + } + + File candidate = new File(configuredPath); + if (isAbsolutePath(configuredPath) && !candidate.exists()) { + log.warn("[FFmpeg] 설정된 실행 파일을 찾지 못해 PATH 명령어로 대체합니다: {}", configuredPath); + return resolveFallbackExecutable(fallback); + } + + return configuredPath; + } + + private boolean isAbsolutePath(String path) { + return new File(path).isAbsolute() || path.startsWith("/") || path.startsWith("\\"); + } + + private String resolveFallbackExecutable(String fallback) { + if (File.separatorChar != '\\') { + return fallback; + } + + try { + Process process = new ProcessBuilder("where.exe", fallback).start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String resolved = reader.readLine(); + process.waitFor(); + if (resolved != null && !resolved.isBlank()) { + return resolved.trim(); + } + } + } catch (Exception e) { + log.debug("[FFmpeg] 대체 실행 파일 탐색 실패: {}, 원인={}", fallback, e.getMessage()); + } + + return fallback; + } + public Integer getAudioDurationMs(File audioFile) throws Exception { + String resolvedFfprobePath = resolveExecutable(ffprobePath, "ffprobe"); String[] cmd = { - ffprobePath, "-v", "error", "-show_entries", "format=duration", + resolvedFfprobePath, "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", audioFile.getAbsolutePath() }; Process process = new ProcessBuilder(cmd).start(); @@ -31,11 +71,12 @@ public Integer getAudioDurationMs(File audioFile) throws Exception { } public File createSilenceFile(int durationMs) throws Exception { + String resolvedFfmpegPath = resolveExecutable(ffmpegPath, "ffmpeg"); File output = File.createTempFile("silence_", ".mp3"); double seconds = durationMs / 1000.0; String[] cmd = { - ffmpegPath, "-y", "-f", "lavfi", "-i", "anullsrc=r=44100:cl=mono", + resolvedFfmpegPath, "-y", "-f", "lavfi", "-i", "anullsrc=r=44100:cl=mono", "-t", String.valueOf(seconds), "-acodec", "libmp3lame", output.getAbsolutePath() }; @@ -44,15 +85,13 @@ public File createSilenceFile(int durationMs) throws Exception { } public File mergeAudioFiles(List audioFiles) throws Exception { - if (audioFiles == null || audioFiles.isEmpty()) throw new IllegalArgumentException("병합할 파일이 없습니다."); + if (audioFiles == null || audioFiles.isEmpty()) throw new IllegalArgumentException("merged audio file list is empty."); + String resolvedFfmpegPath = resolveExecutable(ffmpegPath, "ffmpeg"); - // FFmpeg에 전달할 리스트 파일 생성 (UTF-8 인코딩) File listFile = File.createTempFile("ffmpeg_list_", ".txt"); try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(listFile), "UTF-8"))) { for (File file : audioFiles) { - // 윈도우의 'C:\temp\file.mp3'를 'C:/temp/file.mp3'로 변환 String safePath = file.getAbsolutePath().replace("\\", "/"); - // FFmpeg 문법에 맞춰 file '경로' 형태로 기록 writer.write("file '" + safePath + "'"); writer.newLine(); } @@ -60,9 +99,8 @@ public File mergeAudioFiles(List audioFiles) throws Exception { File output = File.createTempFile("merged_full_", ".mp3"); - // 병합 명령어 구성 String[] cmd = { - ffmpegPath, "-y", "-f", "concat", "-safe", "0", + resolvedFfmpegPath, "-y", "-f", "concat", "-safe", "0", "-i", listFile.getAbsolutePath(), "-acodec", "libmp3lame", "-q:a", "2", output.getAbsolutePath() @@ -74,24 +112,22 @@ public File mergeAudioFiles(List audioFiles) throws Exception { } private void executeCommand(String[] cmd) throws Exception { - log.info("[FFmpeg] 명령어 실행: {}", String.join(" ", cmd)); + log.info("[FFmpeg] 명령 실행: {}", String.join(" ", cmd)); ProcessBuilder pb = new ProcessBuilder(cmd); - pb.redirectErrorStream(true); // 에러와 출력을 합침 + pb.redirectErrorStream(true); Process process = pb.start(); - // 실시간 로그 출력 (에러 원인 파악용) try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"))) { String line; while ((line = reader.readLine()) != null) { - log.info("[FFmpeg Output] {}", line); // 문제 발생 시 로그에서 바로 확인 가능 + log.info("[FFmpeg 출력] {}", line); } } int exitCode = process.waitFor(); - if (exitCode != 0) { - log.error("[FFmpeg] 프로세스 오류 발생! Exit Code: {}", exitCode); + log.error("[FFmpeg] 프로세스 오류 발생. Exit Code: {}", exitCode); throw new RuntimeException("FFmpeg 프로세스 오류 발생. Exit Code: " + exitCode); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/swyp/picke/global/web/controller/StaticTextFileController.java b/src/main/java/com/swyp/picke/global/web/controller/StaticTextFileController.java new file mode 100644 index 00000000..2b2a6925 --- /dev/null +++ b/src/main/java/com/swyp/picke/global/web/controller/StaticTextFileController.java @@ -0,0 +1,67 @@ +package com.swyp.picke.global.web.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.io.IOException; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * app-ads.txt, robots.txt는 크롤러(AdMob, 검색엔진)가 Content-Type: text/plain을 기대하므로, + * 정적 리소스 핸들러의 MIME 추론에 맡기지 않고 명시적으로 text/plain으로 응답한다. + * 이용약관/개인정보처리방침은 노션 공유 링크가 로그인 리다이렉트 루프에 걸려 외부(AdMob 심사 등)에서 + * 접근 불가능해서, 인증 없이 접근 가능한 정적 HTML로 직접 서빙한다. + */ +@Tag(name = "정적 텍스트 파일", description = "app-ads.txt, robots.txt, 약관/정책 페이지 서빙") +@RestController +public class StaticTextFileController { + + private static final MediaType TEXT_PLAIN_UTF8 = new MediaType("text", "plain", java.nio.charset.StandardCharsets.UTF_8); + + @Operation(summary = "app-ads.txt 조회") + @GetMapping("/app-ads.txt") + public ResponseEntity getAppAdsTxt() throws IOException { + return textResponse("static/app-ads.txt"); + } + + @Operation(summary = "robots.txt 조회") + @GetMapping("/robots.txt") + public ResponseEntity getRobotsTxt() throws IOException { + return textResponse("static/robots.txt"); + } + + @Operation(summary = "서비스 이용약관 조회") + @GetMapping("/terms") + public ResponseEntity getTerms() throws IOException { + return htmlResponse("static/terms.html"); + } + + @Operation(summary = "개인정보 처리방침 조회") + @GetMapping("/privacy-policy") + public ResponseEntity getPrivacyPolicy() throws IOException { + return htmlResponse("static/privacy-policy.html"); + } + + private ResponseEntity textResponse(String classpathLocation) throws IOException { + Resource resource = new ClassPathResource(classpathLocation); + return ResponseEntity.ok() + .contentType(TEXT_PLAIN_UTF8) + .contentLength(resource.contentLength()) + .header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600") + .body(resource); + } + + private ResponseEntity htmlResponse(String classpathLocation) throws IOException { + Resource resource = new ClassPathResource(classpathLocation); + return ResponseEntity.ok() + .contentType(MediaType.TEXT_HTML) + .contentLength(resource.contentLength()) + .header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600") + .body(resource); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e2671442..60c036c8 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -124,6 +124,10 @@ jwt: access-token-expiration: 3600000 refresh-token-expiration: 1209600000 +admin: + web: + url: ${ADMIN_WEB_URL:https://picke.up.railway.app} + picke: baseUrl: ${PICKE_BASE_URL:https://picke.store} s3: diff --git a/src/main/resources/db/migration/V20260724_01__create_user_local_accounts.sql b/src/main/resources/db/migration/V20260724_01__create_user_local_accounts.sql new file mode 100644 index 00000000..7a81529e --- /dev/null +++ b/src/main/resources/db/migration/V20260724_01__create_user_local_accounts.sql @@ -0,0 +1,12 @@ +-- 관리자가 발급하는 테스트 계정(username/password) 로컬 로그인을 위한 테이블 +CREATE TABLE IF NOT EXISTS user_local_accounts ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + user_id BIGINT NOT NULL, + username VARCHAR(50) NOT NULL, + password_hash VARCHAR(255) NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP, + CONSTRAINT uk_user_local_accounts_username UNIQUE (username), + CONSTRAINT uk_user_local_accounts_user_id UNIQUE (user_id), + CONSTRAINT fk_user_local_accounts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); diff --git a/src/main/resources/db/migration/V20260724_02__drop_perspectives_unique_constraint.sql b/src/main/resources/db/migration/V20260724_02__drop_perspectives_unique_constraint.sql new file mode 100644 index 00000000..70990822 --- /dev/null +++ b/src/main/resources/db/migration/V20260724_02__drop_perspectives_unique_constraint.sql @@ -0,0 +1,20 @@ +-- 1인 1관점 제한 해제: perspectives(battle_id, user_id) 유니크 제약 제거 +-- Hibernate가 이름을 자동 생성해 환경마다 다를 수 있으므로 이름에 의존하지 않고 동적으로 찾아 드롭한다. +DO $$ +DECLARE + found_constraint_name text; +BEGIN + SELECT tc.constraint_name INTO found_constraint_name + FROM information_schema.table_constraints tc + JOIN information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_name = kcu.table_name + WHERE tc.table_name = 'perspectives' + AND tc.constraint_type = 'UNIQUE' + GROUP BY tc.constraint_name + HAVING array_agg(kcu.column_name ORDER BY kcu.column_name) = ARRAY['battle_id', 'user_id']; + + IF found_constraint_name IS NOT NULL THEN + EXECUTE format('ALTER TABLE perspectives DROP CONSTRAINT %I', found_constraint_name); + END IF; +END $$; diff --git a/src/main/resources/static/privacy-policy.html b/src/main/resources/static/privacy-policy.html new file mode 100644 index 00000000..393228a6 --- /dev/null +++ b/src/main/resources/static/privacy-policy.html @@ -0,0 +1,77 @@ + + + + + +PicKé 개인정보 처리방침 + + + + +

PicKé 개인정보 처리방침

+ +

제1조 (개인정보의 처리 목적)

+

회사는 다음의 목적을 위해 개인정보를 처리하며, 목적 외 용도로는 이용하지 않습니다.

+
    +
  1. 서비스 제공: 이용자의 투표 및 선택 데이터 기반 가치관 성향 분석 리포트 생성, 콘텐츠 추천.
  2. +
  3. 회원 관리: 회원제 서비스 이용에 따른 본인 식별, 부정 이용 방지, 각종 고지 전달.
  4. +
  5. 서비스 개선: 접속 빈도 파악 및 서비스 이용 통계 분석을 통한 서비스 고도화.
  6. +
+ +

제2조 (처리하는 개인정보 항목)

+

회사는 서비스 제공을 위해 아래의 항목을 수집합니다.

+
    +
  1. 회원 가입 및 소셜 로그인: 이메일, 닉네임, 프로필 이미지.
  2. +
  3. 서비스 이용 과정 중 자동 수집: +
      +
    • 서비스 내 콘텐츠 클릭 및 선택 기록(배틀 참여, 투표 등)
    • +
    • 의사결정 고민 시간(Latency) 및 콘텐츠 재생 구간 체류 기록
    • +
    • 기기정보(OS, 모델명), 접속 로그, IP 주소, 쿠키.
    • +
    • 광고 식별자(ADID/IDFA): 맞춤형 광고 제공 및 광고 효과 분석 목적.
    • +
    +
  4. +
+ +

제3조 (개인정보의 처리 및 보유 기간)

+
    +
  1. 회원 정보: 회원 탈퇴 시까지 보유.
  2. +
  3. 서비스 이용 기록: 서비스 이용 종료 시까지 또는 관련 법령(통신비밀보호법 등)에 따른 보존 기간(3개월) 동안 보관.
  4. +
+ +

제4조 (개인정보처리의 위탁)

+

회사는 서비스 분석 및 인프라 운영을 위해 다음과 같이 개인정보 처리 업무를 위탁하고 있습니다.

+
    +
  1. 서버 운영: Google Cloud Platform (데이터 저장 및 관리)
  2. +
  3. 사용자 행동 분석: Mixpanel, Inc. (서비스 이용 통계 및 행동 데이터 분석)
  4. +
  5. 광고 플랫폼: Google AdMob (맞춤형 광고 노출 제어)
  6. +
+ +

제5조 (정보주체의 권리·의무 및 행사방법)

+

이용자는 언제든지 자신의 개인정보 열람, 정정, 삭제, 처리 정지를 요구할 수 있습니다. 서비스 내 설정 메뉴를 통해 직접 처리하거나 고객센터를 통해 요청하실 수 있습니다.

+ +

제6조 (개인정보 자동 수집 장치의 설치·운영 및 거부)

+
    +
  1. 회사는 이용자에게 최적화된 서비스를 제공하기 위해 '쿠키(Cookie)' 및 '광고 식별자'를 사용합니다.
  2. +
  3. 이용자는 브라우저 설정 또는 모바일 기기 설정을 통해 쿠키 허용 거부 및 광고 추적 제한을 설정할 수 있습니다. 단, 거부 시 일부 맞춤형 서비스 이용이 어려울 수 있습니다.
  4. +
+ +

제7조 (개인정보의 안전성 확보조치)

+

회사는 개인정보 보호를 위해 접근 권한 관리, 데이터 암호화, 보안 프로그램 설치 등 기술적/관리적 조치를 다하고 있습니다.

+ +

제8조 (개인정보 보호책임자)

+
    +
  • 성명: 천다올 (대표자)
  • +
  • 담당부서: 서비스 운영팀
  • +
  • 연락처: picke.project@gmail.com
  • +
+ +

부칙
본 개인정보 처리방침은 2026년 4월 5일부터 시행됩니다.

+ + + diff --git a/src/main/resources/static/terms.html b/src/main/resources/static/terms.html new file mode 100644 index 00000000..494bcdab --- /dev/null +++ b/src/main/resources/static/terms.html @@ -0,0 +1,74 @@ + + + + + +PICKé 서비스 이용약관 + + + + +

PICKé 서비스 이용약관

+ +

제1조 (목적)

+

본 약관은 PICKé(이하 "회사")가 제공하는 지식 콘텐츠 큐레이션 및 가치관 분석 서비스(이하 "서비스")의 이용과 관련하여 회사와 이용자 간의 권리, 의무 및 책임사항, 서비스 이용조건 및 절차 등을 규정함을 목적으로 합니다.

+ +

제2조 (정의)

+
    +
  1. "서비스"란 회사가 운영하는 애플리케이션 및 웹을 통해 제공되는 지식 콘텐츠 시청, 투표 참여, 가치관 분석 리포트 등을 의미합니다.
  2. +
  3. "콘텐츠"란 회사가 생성한 텍스트, 오디오(TTS 포함), 이미지, 인터랙티브 분기형 대본 등을 말합니다.
  4. +
  5. "내공(포인트)"이란 서비스 내 활동에 따라 부여되는 무상의 가상 데이터로, 등급 상승 및 특정 기능 이용에 사용됩니다. 이는 현금으로 환급되지 않으며 제3자에게 유료로 양도할 수 없습니다.
  6. +
+ +

제3조 (서비스의 특징 및 기술적 제한)

+
    +
  1. 회사는 AI 및 TTS(Text-to-Speech) 기술을 활용하여 콘텐츠를 제공하며, 기술적 특성상 일시적인 음성-텍스트 싱크 불일치나 기계적 오류가 발생할 수 있습니다.
  2. +
  3. 회사가 제공하는 성향 분석 결과는 이용자의 유희와 자아 성찰을 돕기 위한 참고 자료일 뿐, 의학적·법률적·윤리적 판단의 절대적 기준이 될 수 없습니다.
  4. +
+ +

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

+
    +
  1. 이용자는 소셜 로그인 등을 통해 약관 동의 후 서비스를 이용할 수 있습니다.
  2. +
  3. 회원은 자신의 계정 및 식별코드 관리에 대한 책임을 지며, 타인의 정보 도용 시 서비스 이용이 영구 제한될 수 있습니다.
  4. +
+ +

제5조 (서비스 이용 및 제한)

+
    +
  1. 회사는 다음의 경우 이용을 제한하거나 게시물을 삭제할 수 있습니다. +
      +
    • 자동화된 수단(매크로, 봇 등)을 이용하여 부정한 방법으로 투표하거나 내공을 쌓는 행위
    • +
    • 서비스 내에서 타인에게 불쾌감을 주는 욕설, 비하, 특정 사상 강요 등의 행위
    • +
    +
  2. +
  3. 일일 투표 참여 한도를 초과한 경우, 광고 시청 등을 통해 추가 참여권을 획득해야 합니다.
  4. +
+ +

제6조 (저작권 및 데이터 활용)

+
    +
  1. 서비스 내 모든 콘텐츠와 성향 분석 리포트의 디자인/알고리즘에 대한 저작권은 회사에 귀속됩니다.
  2. +
  3. 회원은 자신의 분석 결과를 비영리적인 목적으로 소셜 미디어 등에 자유롭게 공유할 수 있습니다.
  4. +
  5. 회사는 서비스 고도화를 위해 이용자의 투표 데이터를 익명화하여 통계 및 분석 자료로 활용할 수 있습니다.
  6. +
+ +

제7조 (책임제한)

+
    +
  1. 회사는 천재지변, 기간통신사업자의 장애 등 불가항력으로 인한 서비스 중단에 책임을 지지 않습니다.
  2. +
  3. 회사는 콘텐츠가 담고 있는 철학적 견해의 객관적 타당성을 보장하지 않으며, 이용자의 선택에 따른 심리적 변화나 결과에 대해 책임을 지지 않습니다.
  4. +
+ +

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

+
    +
  1. 본 약관의 해석 및 회사와 이용자 간의 분쟁에는 대한민국 법률을 적용합니다.
  2. +
  3. 서비스 이용과 관련하여 발생한 분쟁은 회사의 본사 소재지 관할 법원을 제1심 합의관할 법원으로 합니다.
  4. +
+ +

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

+ + + diff --git a/src/test/java/com/swyp/picke/domain/notification/controller/NotificationTestControllerTest.java b/src/test/java/com/swyp/picke/domain/notification/controller/NotificationTestControllerTest.java new file mode 100644 index 00000000..7f48771f --- /dev/null +++ b/src/test/java/com/swyp/picke/domain/notification/controller/NotificationTestControllerTest.java @@ -0,0 +1,30 @@ +package com.swyp.picke.domain.notification.controller; + +import com.swyp.picke.domain.notification.enums.NotificationDetailCode; +import com.swyp.picke.domain.notification.service.NotificationService; +import org.junit.jupiter.api.Test; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class NotificationTestControllerTest { + + private final NotificationService notificationService = mock(NotificationService.class); + private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new NotificationTestController(notificationService)).build(); + + @Test + void createTestNotification_callsServiceWithGivenParams() throws Exception { + mockMvc.perform(post("/api/test/notifications") + .param("userId", "1") + .param("detailCode", "NEW_BATTLE") + .param("body", "테스트 알림 본문") + .param("referenceId", "100")) + .andExpect(status().isOk()); + + verify(notificationService).createNotification(1L, NotificationDetailCode.NEW_BATTLE, "테스트 알림 본문", 100L); + } +} diff --git a/src/test/java/com/swyp/picke/domain/notification/service/NotificationServiceTest.java b/src/test/java/com/swyp/picke/domain/notification/service/NotificationServiceTest.java index 69aea51d..0afe16f3 100644 --- a/src/test/java/com/swyp/picke/domain/notification/service/NotificationServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/notification/service/NotificationServiceTest.java @@ -283,6 +283,30 @@ void markAllAsRead_calls_repository() { verify(notificationReadRepository).markAllBroadcastAsRead(userId); } + @Test + @DisplayName("ALL 카테고리로 미읽음 여부를 확인하면 카테고리 필터 없이 조회한다") + void hasUnread_withAllCategory_queriesWithoutCategoryFilter() { + Long userId = 1L; + when(notificationRepository.existsUnread(userId, null)).thenReturn(true); + + var response = notificationService.hasUnread(userId, NotificationCategory.ALL); + + assertThat(response.hasUnread()).isTrue(); + verify(notificationRepository).existsUnread(userId, null); + } + + @Test + @DisplayName("카테고리를 지정하면 해당 카테고리로 미읽음 여부를 확인한다") + void hasUnread_withSpecificCategory_queriesWithCategoryFilter() { + Long userId = 1L; + when(notificationRepository.existsUnread(userId, NotificationCategory.CONTENT)).thenReturn(false); + + var response = notificationService.hasUnread(userId, NotificationCategory.CONTENT); + + assertThat(response.hasUnread()).isFalse(); + verify(notificationRepository).existsUnread(userId, NotificationCategory.CONTENT); + } + private User createMockUser() { return User.builder() .userTag("test-user-tag") diff --git a/src/test/java/com/swyp/picke/domain/oauth/service/OAuthServiceTest.java b/src/test/java/com/swyp/picke/domain/oauth/service/OAuthServiceTest.java index 4e44a078..eba3aaa6 100644 --- a/src/test/java/com/swyp/picke/domain/oauth/service/OAuthServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/oauth/service/OAuthServiceTest.java @@ -3,13 +3,19 @@ import com.swyp.picke.domain.oauth.client.GoogleOAuthClient; import com.swyp.picke.domain.oauth.client.KakaoOAuthClient; import com.swyp.picke.domain.oauth.client.AppleOAuthClient; +import com.swyp.picke.domain.admin.dto.testaccount.request.CreateTestAccountRequest; +import com.swyp.picke.domain.admin.dto.testaccount.response.TestAccountResponse; +import com.swyp.picke.domain.oauth.dto.LocalLoginRequest; import com.swyp.picke.domain.oauth.dto.LoginRequest; import com.swyp.picke.domain.oauth.dto.LoginResponse; import com.swyp.picke.domain.oauth.dto.OAuthUserInfo; import com.swyp.picke.domain.oauth.dto.WithdrawRequest; +import com.swyp.picke.domain.oauth.entity.UserLocalAccount; import com.swyp.picke.domain.oauth.entity.UserSocialAccount; +import com.swyp.picke.global.common.exception.CustomException; import com.swyp.picke.domain.oauth.jwt.JwtProvider; import com.swyp.picke.domain.oauth.repository.AuthRefreshTokenRepository; +import com.swyp.picke.domain.oauth.repository.UserLocalAccountRepository; import com.swyp.picke.domain.oauth.repository.UserSocialAccountRepository; import com.swyp.picke.domain.user.enums.CharacterType; import com.swyp.picke.domain.user.entity.User; @@ -30,10 +36,12 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.crypto.password.PasswordEncoder; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @@ -46,6 +54,7 @@ class OAuthServiceTest { @Mock private AppleOAuthClient appleOAuthClient; @Mock private UserRepository userRepository; @Mock private UserSocialAccountRepository socialAccountRepository; + @Mock private UserLocalAccountRepository localAccountRepository; @Mock private AuthRefreshTokenRepository refreshTokenRepository; @Mock private UserProfileRepository userProfileRepository; @Mock private UserSettingsRepository userSettingsRepository; @@ -53,6 +62,7 @@ class OAuthServiceTest { @Mock private UserWithdrawalRepository userWithdrawalRepository; @Mock private JwtProvider jwtProvider; @Mock private CreditService creditService; + @Mock private PasswordEncoder passwordEncoder; private AuthService authService; @@ -61,10 +71,10 @@ void setUp() { // 수동 주입으로 안정성 확보 authService = new AuthService( kakaoOAuthClient, googleOAuthClient, appleOAuthClient, userRepository, - socialAccountRepository, refreshTokenRepository, + socialAccountRepository, localAccountRepository, refreshTokenRepository, userProfileRepository, userSettingsRepository, userTendencyScoreRepository, userWithdrawalRepository, - jwtProvider, creditService + jwtProvider, creditService, passwordEncoder ); } @@ -211,6 +221,105 @@ void setUp() { verify(socialAccountRepository).save(socialAccount); } + @Test + void loginLocal_존재하는_계정과_올바른_비밀번호면_로그인_성공() { + User user = User.builder() + .userTag("pique-local") + .role(UserRole.USER) + .status(UserStatus.ACTIVE) + .build(); + + UserLocalAccount localAccount = UserLocalAccount.builder() + .user(user) + .username("qa-tester01") + .passwordHash("hashed-pw") + .build(); + + when(localAccountRepository.findByUsername("qa-tester01")).thenReturn(Optional.of(localAccount)); + when(passwordEncoder.matches("plain-pw", "hashed-pw")).thenReturn(true); + when(jwtProvider.createAccessToken(any(), anyString())).thenReturn("jwt-access"); + when(jwtProvider.createRefreshToken()).thenReturn("jwt-refresh"); + + LoginResponse response = authService.loginLocal(new LocalLoginRequest("qa-tester01", "plain-pw")); + + assertThat(response.getAccessToken()).isEqualTo("jwt-access"); + assertThat(response.isNewUser()).isFalse(); + verify(refreshTokenRepository).save(any()); + } + + @Test + void loginLocal_존재하지_않는_아이디면_인증오류를_던진다() { + when(localAccountRepository.findByUsername("no-such-user")).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> authService.loginLocal(new LocalLoginRequest("no-such-user", "plain-pw"))) + .isInstanceOf(CustomException.class); + + verify(jwtProvider, never()).createAccessToken(any(), anyString()); + } + + @Test + void loginLocal_비밀번호가_틀리면_인증오류를_던진다() { + User user = User.builder() + .userTag("pique-local") + .role(UserRole.USER) + .status(UserStatus.ACTIVE) + .build(); + + UserLocalAccount localAccount = UserLocalAccount.builder() + .user(user) + .username("qa-tester01") + .passwordHash("hashed-pw") + .build(); + + when(localAccountRepository.findByUsername("qa-tester01")).thenReturn(Optional.of(localAccount)); + when(passwordEncoder.matches("wrong-pw", "hashed-pw")).thenReturn(false); + + assertThatThrownBy(() -> authService.loginLocal(new LocalLoginRequest("qa-tester01", "wrong-pw"))) + .isInstanceOf(CustomException.class); + + verify(jwtProvider, never()).createAccessToken(any(), anyString()); + } + + @Test + void createLocalTestAccount_신규_유저와_로컬계정을_생성한다() { + CreateTestAccountRequest request = new CreateTestAccountRequest("qa-tester02", "plain-pw"); + + User savedUser = User.builder() + .userTag("pique-test") + .role(UserRole.USER) + .status(UserStatus.ACTIVE) + .build(); + + when(localAccountRepository.existsByUsername("qa-tester02")).thenReturn(false); + when(passwordEncoder.encode("plain-pw")).thenReturn("hashed-pw"); + + ArgumentCaptor userCaptor = ArgumentCaptor.forClass(User.class); + when(userRepository.save(userCaptor.capture())).thenReturn(savedUser); + + TestAccountResponse response = authService.createLocalTestAccount(request); + + assertThat(response.getUsername()).isEqualTo("qa-tester02"); + assertThat(response.getUserTag()).isEqualTo(userCaptor.getValue().getUserTag()); + + ArgumentCaptor localAccountCaptor = ArgumentCaptor.forClass(UserLocalAccount.class); + verify(localAccountRepository).save(localAccountCaptor.capture()); + assertThat(localAccountCaptor.getValue().getPasswordHash()).isEqualTo("hashed-pw"); + + verify(userProfileRepository).save(any()); + verify(userSettingsRepository).save(any()); + verify(userTendencyScoreRepository).save(any()); + } + + @Test + void createLocalTestAccount_이미_존재하는_아이디면_예외를_던진다() { + when(localAccountRepository.existsByUsername("dup-user")).thenReturn(true); + + assertThatThrownBy(() -> authService.createLocalTestAccount(new CreateTestAccountRequest("dup-user", "plain-pw"))) + .isInstanceOf(CustomException.class); + + verify(userRepository, never()).save(any()); + } + @Test void withdraw_탈퇴사유를_저장하고_사용자를_삭제처리한다() { User user = User.builder() diff --git a/src/test/java/com/swyp/picke/domain/perspective/service/PerspectiveServiceTest.java b/src/test/java/com/swyp/picke/domain/perspective/service/PerspectiveServiceTest.java index 8f36e2c4..43697a0e 100644 --- a/src/test/java/com/swyp/picke/domain/perspective/service/PerspectiveServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/perspective/service/PerspectiveServiceTest.java @@ -5,6 +5,9 @@ import com.swyp.picke.domain.battle.enums.BattleOptionLabel; import com.swyp.picke.domain.battle.enums.BattleStatus; import com.swyp.picke.domain.battle.service.BattleService; +import com.swyp.picke.domain.perspective.dto.request.CreatePerspectiveRequest; +import com.swyp.picke.domain.perspective.dto.response.CreatePerspectiveResponse; +import com.swyp.picke.domain.perspective.dto.response.MyPerspectiveResponse; import com.swyp.picke.domain.perspective.dto.response.PerspectiveDetailResponse; import com.swyp.picke.domain.perspective.entity.Perspective; import com.swyp.picke.domain.perspective.repository.PerspectiveCommentRepository; @@ -19,6 +22,7 @@ import com.swyp.picke.domain.vote.service.BattleVoteService; import com.swyp.picke.global.infra.s3.service.S3PresignedUrlService; import java.time.LocalDate; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -90,6 +94,54 @@ void getPerspectiveDetail_returns_option_opinion_as_label() { assertThat(response.option().title()).isEqualTo("예술이 아니다"); } + @Test + @DisplayName("이미 관점을 남긴 배틀에도 새 관점을 추가로 등록할 수 있다") + void createPerspective_allows_multiple_perspectives_for_same_user_and_battle() { + Battle battle = battle(100L); + User user = user(1L); + BattleOption option = option(10L, battle, BattleOptionLabel.A, "예술이다"); + + when(battleService.findById(100L)).thenReturn(battle); + when(userRepository.findById(1L)).thenReturn(Optional.of(user)); + when(battleVoteService.findPostVoteOptionId(100L, 1L)).thenReturn(10L); + when(battleService.findOptionById(10L)).thenReturn(option); + when(perspectiveRepository.save(org.mockito.ArgumentMatchers.any(Perspective.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + CreatePerspectiveResponse response = perspectiveService.createPerspective( + 100L, 1L, new CreatePerspectiveRequest("두 번째 관점")); + + assertThat(response).isNotNull(); + org.mockito.Mockito.verify(perspectiveRepository).save(org.mockito.ArgumentMatchers.any(Perspective.class)); + } + + @Test + @DisplayName("내 관점 조회는 한 배틀에 남긴 여러 관점을 목록으로 반환한다") + void getMyPerspective_returns_multiple_perspectives_as_list() { + Battle battle = battle(100L); + User user = user(1L); + BattleOption option = option(10L, battle, BattleOptionLabel.A, "예술이다"); + + Perspective first = Perspective.builder().battle(battle).user(user).option(option).content("첫 번째").build(); + first.publish(); + ReflectionTestUtils.setField(first, "id", 1L); + + Perspective second = Perspective.builder().battle(battle).user(user).option(option).content("두 번째").build(); + second.publish(); + ReflectionTestUtils.setField(second, "id", 2L); + + when(battleService.findById(100L)).thenReturn(battle); + when(perspectiveRepository.findByBattleIdAndUserIdOrderByCreatedAtDesc(100L, 1L)) + .thenReturn(List.of(second, first)); + when(userQueryService.findSummaryById(1L)).thenReturn(new UserSummary("user-1", "nick", "OWL")); + when(s3PresignedUrlService.generatePresignedUrl(anyString())).thenReturn("character-url"); + + List responses = perspectiveService.getMyPerspective(100L, 1L); + + assertThat(responses).hasSize(2); + assertThat(responses).extracting(MyPerspectiveResponse::perspectiveId).containsExactly(2L, 1L); + } + private Battle battle(Long id) { Battle battle = Battle.builder() .title("battle") diff --git a/src/test/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceTest.java b/src/test/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceTest.java index 016a5024..ca0bf39c 100644 --- a/src/test/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/reward/service/AdMobRewardServiceTest.java @@ -97,7 +97,7 @@ void processReward_Success() throws Exception { assertThat(result).isEqualTo("OK"); // // 4. 호출 검증 - verify(creditService, times(1)).addCredit(eq(1L), eq(CreditType.FREE_CHARGE), eq(100), anyLong()); + verify(creditService, times(1)).addCredit(eq(1L), eq(CreditType.FREE_CHARGE), eq(CreditType.FREE_CHARGE.getDefaultAmount()), anyLong()); verify(adRewardHistoryRepository, times(1)).saveAndFlush(any(AdRewardHistory.class)); verify(userService, times(1)).findByUserTag("pique-1cc4a030"); } diff --git a/src/test/java/com/swyp/picke/domain/scenario/service/ScenarioAudioPipelineServiceTest.java b/src/test/java/com/swyp/picke/domain/scenario/service/ScenarioAudioPipelineServiceTest.java new file mode 100644 index 00000000..6e0515e9 --- /dev/null +++ b/src/test/java/com/swyp/picke/domain/scenario/service/ScenarioAudioPipelineServiceTest.java @@ -0,0 +1,157 @@ +package com.swyp.picke.domain.scenario.service; + +import com.swyp.picke.domain.battle.entity.Battle; +import com.swyp.picke.domain.battle.enums.BattleCreatorType; +import com.swyp.picke.domain.battle.enums.BattleStatus; +import com.swyp.picke.domain.battle.repository.BattleRepository; +import com.swyp.picke.domain.scenario.entity.Scenario; +import com.swyp.picke.domain.scenario.entity.ScenarioNode; +import com.swyp.picke.domain.scenario.entity.Script; +import com.swyp.picke.domain.scenario.enums.AudioPathType; +import com.swyp.picke.domain.scenario.enums.CreatorType; +import com.swyp.picke.domain.scenario.enums.ScenarioStatus; +import com.swyp.picke.domain.scenario.enums.SpeakerType; +import com.swyp.picke.domain.scenario.repository.ScenarioRepository; +import com.swyp.picke.global.infra.media.service.FFmpegService; +import com.swyp.picke.global.infra.s3.service.S3UploadService; +import com.swyp.picke.global.infra.tts.service.TtsService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.io.File; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ScenarioAudioPipelineServiceTest { + + @Mock + private ScenarioRepository scenarioRepository; + + @Mock + private TtsService ttsService; + + @Mock + private S3UploadService s3UploadService; + + @Mock + private BattleRepository battleRepository; + + private FFmpegService ffmpegService; + private ScenarioAudioPipelineService scenarioAudioPipelineService; + private final List uploadedFiles = new ArrayList<>(); + + @BeforeEach + void setUp() { + ffmpegService = new FFmpegService(); + ReflectionTestUtils.setField(ffmpegService, "ffmpegPath", "/usr/bin/ffmpeg"); + ReflectionTestUtils.setField(ffmpegService, "ffprobePath", "/usr/bin/ffprobe"); + + scenarioAudioPipelineService = new ScenarioAudioPipelineService( + scenarioRepository, + ttsService, + ffmpegService, + s3UploadService, + battleRepository + ); + } + + @AfterEach + void tearDown() { + for (File file : uploadedFiles) { + if (file != null && file.exists()) { + file.delete(); + } + } + } + + @Test + void generateAndMergeAudioAsync_usesFallbackExecutableAndCompletesUploadFlow() throws Exception { + Battle battle = Battle.builder() + .title("scenario battle") + .summary("summary") + .description("description") + .targetDate(LocalDate.now()) + .audioDuration(0) + .status(BattleStatus.PENDING) + .creatorType(BattleCreatorType.ADMIN) + .build(); + + Scenario scenario = Scenario.builder() + .battle(battle) + .isInteractive(false) + .status(ScenarioStatus.PENDING) + .creatorType(CreatorType.ADMIN) + .build(); + + ScenarioNode node = ScenarioNode.builder() + .nodeName("START") + .isStartNode(true) + .audioDuration(0) + .build(); + + Script firstScript = Script.builder() + .speakerType(SpeakerType.NARRATOR) + .speakerName("Narrator") + .text("First line") + .build(); + Script secondScript = Script.builder() + .speakerType(SpeakerType.NARRATOR) + .speakerName("Narrator") + .text("Second line") + .build(); + + node.addScript(firstScript); + node.addScript(secondScript); + scenario.addNode(node); + scenario.replaceVoiceSettings(Map.of(SpeakerType.NARRATOR, "voice-narrator")); + + when(scenarioRepository.findById(1L)).thenReturn(Optional.of(scenario)); + when(ttsService.generateTtsWithSsml(eq("First line"), eq(SpeakerType.NARRATOR), eq("voice-narrator"))) + .thenReturn(ffmpegService.createSilenceFile(1000)); + when(ttsService.generateTtsWithSsml(eq("Second line"), eq(SpeakerType.NARRATOR), eq("voice-narrator"))) + .thenReturn(ffmpegService.createSilenceFile(1000)); + + AtomicInteger chunkIndex = new AtomicInteger(); + when(s3UploadService.uploadFile(anyString(), any(File.class))).thenAnswer(invocation -> { + File file = invocation.getArgument(1, File.class); + uploadedFiles.add(file); + + String key = invocation.getArgument(0, String.class); + if (key.contains("/chunks/")) { + return "s3://scenario/chunks/" + chunkIndex.incrementAndGet() + ".mp3"; + } + return "s3://scenario/merged/common.mp3"; + }); + + scenarioAudioPipelineService.generateAndMergeAudioAsync(1L); + + assertThat(scenario.getStatus()).isEqualTo(ScenarioStatus.PUBLISHED); + assertThat(firstScript.getAudioUrl()).isEqualTo("s3://scenario/chunks/1.mp3"); + assertThat(secondScript.getAudioUrl()).isEqualTo("s3://scenario/chunks/2.mp3"); + assertThat(scenario.getAudios()).containsEntry(AudioPathType.COMMON, "s3://scenario/merged/common.mp3"); + assertThat(battle.getAudioDuration()).isNotNull().isGreaterThan(0); + + verify(ttsService, times(2)).generateTtsWithSsml(anyString(), eq(SpeakerType.NARRATOR), eq("voice-narrator")); + verify(s3UploadService, times(3)).uploadFile(anyString(), any(File.class)); + verify(battleRepository).save(battle); + verify(scenarioRepository).saveAndFlush(scenario); + } +} diff --git a/src/test/java/com/swyp/picke/domain/user/service/CreditServiceTest.java b/src/test/java/com/swyp/picke/domain/user/service/CreditServiceTest.java index 5cac8027..bd207d58 100644 --- a/src/test/java/com/swyp/picke/domain/user/service/CreditServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/user/service/CreditServiceTest.java @@ -64,25 +64,25 @@ void addCredit_forCurrentUser_savesDefaultAmount() { User user = newUser(1L, 0); when(userService.findCurrentUser()).thenReturn(user); when(userRepository.findById(1L)).thenReturn(Optional.of(user)); - when(userRepository.incrementCredit(1L, CreditType.BATTLE_VOTE.getDefaultAmount())).thenReturn(1); + when(userRepository.incrementCredit(1L, CreditType.BEST_COMMENT.getDefaultAmount())).thenReturn(1); - creditService.addCredit(CreditType.BATTLE_VOTE, 10L); + creditService.addCredit(CreditType.BEST_COMMENT, 10L); ArgumentCaptor captor = ArgumentCaptor.forClass(CreditHistory.class); verify(creditHistoryRepository).saveAndFlush(captor.capture()); CreditHistory saved = captor.getValue(); assertThat(saved.getUser().getId()).isEqualTo(1L); - assertThat(saved.getCreditType()).isEqualTo(CreditType.BATTLE_VOTE); - assertThat(saved.getAmount()).isEqualTo(CreditType.BATTLE_VOTE.getDefaultAmount()); + assertThat(saved.getCreditType()).isEqualTo(CreditType.BEST_COMMENT); + assertThat(saved.getAmount()).isEqualTo(CreditType.BEST_COMMENT.getDefaultAmount()); assertThat(saved.getReferenceId()).isEqualTo(10L); - verify(userRepository).incrementCredit(1L, CreditType.BATTLE_VOTE.getDefaultAmount()); + verify(userRepository).incrementCredit(1L, CreditType.BEST_COMMENT.getDefaultAmount()); } @Test @DisplayName("referenceId가 없으면 적립을 거부한다") void addCredit_withoutReferenceId_throwsException() { - assertThatThrownBy(() -> creditService.addCredit(1L, CreditType.BATTLE_VOTE, 10, null)) + assertThatThrownBy(() -> creditService.addCredit(1L, CreditType.BEST_COMMENT, 10, null)) .isInstanceOf(CustomException.class) .extracting("errorCode") .isEqualTo(ErrorCode.CREDIT_REFERENCE_REQUIRED); @@ -97,12 +97,12 @@ void addCredit_duplicateInsert_ignoresConflict() { when(userRepository.findById(1L)).thenReturn(Optional.of(user)); when(creditHistoryRepository.saveAndFlush(any(CreditHistory.class))) .thenThrow(new DataIntegrityViolationException("duplicate")); - when(creditHistoryRepository.existsByUserIdAndCreditTypeAndReferenceId(1L, CreditType.BATTLE_VOTE, 10L)) + when(creditHistoryRepository.existsByUserIdAndCreditTypeAndReferenceId(1L, CreditType.BEST_COMMENT, 10L)) .thenReturn(true); - creditService.addCredit(1L, CreditType.BATTLE_VOTE, 5, 10L); + creditService.addCredit(1L, CreditType.BEST_COMMENT, 5, 10L); - verify(creditHistoryRepository).existsByUserIdAndCreditTypeAndReferenceId(1L, CreditType.BATTLE_VOTE, 10L); + verify(creditHistoryRepository).existsByUserIdAndCreditTypeAndReferenceId(1L, CreditType.BEST_COMMENT, 10L); verify(userRepository, never()).incrementCredit(1L, 5); } @@ -142,10 +142,10 @@ void addCredit_nonDuplicateIntegrityFailure_rethrows() { when(userRepository.findById(1L)).thenReturn(Optional.of(user)); when(creditHistoryRepository.saveAndFlush(any(CreditHistory.class))) .thenThrow(new DataIntegrityViolationException("broken")); - when(creditHistoryRepository.existsByUserIdAndCreditTypeAndReferenceId(1L, CreditType.BATTLE_VOTE, 10L)) + when(creditHistoryRepository.existsByUserIdAndCreditTypeAndReferenceId(1L, CreditType.BEST_COMMENT, 10L)) .thenReturn(false); - assertThatThrownBy(() -> creditService.addCredit(1L, CreditType.BATTLE_VOTE, 10, 10L)) + assertThatThrownBy(() -> creditService.addCredit(1L, CreditType.BEST_COMMENT, 10, 10L)) .isInstanceOf(CustomException.class) .extracting("errorCode") .isEqualTo(ErrorCode.CREDIT_SAVE_FAILED); diff --git a/src/test/java/com/swyp/picke/domain/user/service/MypageServiceTest.java b/src/test/java/com/swyp/picke/domain/user/service/MypageServiceTest.java index 7e546280..0854dae4 100644 --- a/src/test/java/com/swyp/picke/domain/user/service/MypageServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/user/service/MypageServiceTest.java @@ -303,7 +303,7 @@ void getContentActivities_returns_likes() { void getCreditHistory_returns_paginated_history() { User user = createUser(1L, "tag"); CreditHistory latest = creditHistory(301L, user, CreditType.BEST_COMMENT, 50, 91L, LocalDateTime.now()); - CreditHistory older = creditHistory(300L, user, CreditType.BATTLE_VOTE, 5, 90L, LocalDateTime.now().minusDays(1)); + CreditHistory older = creditHistory(300L, user, CreditType.MAJORITY_WIN, 5, 90L, LocalDateTime.now().minusDays(1)); when(userService.findCurrentUser()).thenReturn(user); when(creditService.getHistory(1L, PageRequest.of(0, 2))) diff --git a/src/test/java/com/swyp/picke/domain/user/service/batch/WeeklyChargeJobTest.java b/src/test/java/com/swyp/picke/domain/user/service/batch/WeeklyChargeJobTest.java deleted file mode 100644 index 0b675986..00000000 --- a/src/test/java/com/swyp/picke/domain/user/service/batch/WeeklyChargeJobTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.swyp.picke.domain.user.service.batch; - -import com.swyp.picke.domain.user.entity.User; -import com.swyp.picke.domain.user.enums.CreditType; -import com.swyp.picke.domain.user.enums.UserRole; -import com.swyp.picke.domain.user.enums.UserStatus; -import com.swyp.picke.domain.user.repository.UserRepository; -import com.swyp.picke.domain.user.service.CreditService; -import java.time.LocalDate; -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class WeeklyChargeJobTest { - - @Mock - private UserRepository userRepository; - - @Mock - private CreditService creditService; - - @InjectMocks - private WeeklyChargeJob job; - - @Test - @DisplayName("활성 사용자에게만 WEEKLY_CHARGE 를 지급한다") - void run_rewardsOnlyActiveUsers() { - User activeUser1 = user(1L); - User activeUser2 = user(2L); - LocalDate runDate = LocalDate.of(2026, 4, 13); - - when(userRepository.findAllByStatus(UserStatus.ACTIVE)).thenReturn(List.of(activeUser1, activeUser2)); - - job.run(runDate); - - verify(creditService).addCredit(1L, CreditType.WEEKLY_CHARGE, 20260413L); - verify(creditService).addCredit(2L, CreditType.WEEKLY_CHARGE, 20260413L); - } - - private User user(Long id) { - User user = User.builder() - .userTag("user-" + id) - .nickname("nick") - .role(UserRole.USER) - .status(UserStatus.ACTIVE) - .build(); - ReflectionTestUtils.setField(user, "id", id); - return user; - } -} diff --git a/src/test/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImplTest.java b/src/test/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImplTest.java index 6135445a..07cd98eb 100644 --- a/src/test/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImplTest.java +++ b/src/test/java/com/swyp/picke/domain/vote/service/BattleVoteServiceImplTest.java @@ -103,6 +103,27 @@ void preVote_doesNotChargeBattleEntryCreditForTodayBattle() { verify(creditService, never()).addCredit(10L, CreditType.BATTLE_ENTRY, 100L); } + @Test + @DisplayName("오늘의 배틀이라도 오늘 이미 무료 진입을 사용했다면 크레딧을 차감한다") + void preVote_chargesBattleEntryCreditWhenFreeEntryAlreadyUsedToday() { + Battle battle = battle(100L, LocalDate.now()); + User user = user(10L); + BattleOption option = option(201L, battle, BattleOptionLabel.A); + + when(battleService.findById(100L)).thenReturn(battle); + when(userRepository.findById(10L)).thenReturn(Optional.of(user)); + when(battleOptionRepository.findById(201L)).thenReturn(Optional.of(option)); + when(battleVoteRepository.findByBattleAndUser(battle, user)).thenReturn(Optional.empty()); + when(battleVoteRepository.existsByUserIdAndBattle_TargetDate(10L, LocalDate.now())).thenReturn(true); + when(userBattleService.getUserBattleStatus(user, battle)) + .thenReturn(new UserBattleStatusResponse(100L, UserBattleStep.NONE)); + + VoteResultResponse response = battleVoteService.preVote(100L, 10L, new VoteRequest(201L)); + + assertThat(response.status()).isEqualTo(UserBattleStep.PRE_VOTE); + verify(creditService).addCredit(10L, CreditType.BATTLE_ENTRY, 100L); + } + @Test @DisplayName("이미 사전 투표한 배틀이면 옵션 변경 시 추가 차감하지 않는다") void preVote_doesNotChargeAgainWhenVoteAlreadyExists() { @@ -131,8 +152,8 @@ void preVote_doesNotChargeAgainWhenVoteAlreadyExists() { } @Test - @DisplayName("사후 투표 완료 시 참여 보상 크레딧을 지급한다") - void postVote_rewardsBattleParticipationCredit() { + @DisplayName("사후 투표 완료 시 스텝을 완료 상태로 전환한다") + void postVote_completesUserBattleStep() { Battle battle = battle(100L, null); User user = user(10L); BattleOption preOption = option(201L, battle, BattleOptionLabel.A); @@ -157,7 +178,6 @@ void postVote_rewardsBattleParticipationCredit() { assertThat(response.voteId()).isEqualTo(300L); assertThat(response.status()).isEqualTo(UserBattleStep.COMPLETED); verify(userBattleService).upsertStep(user, battle, UserBattleStep.COMPLETED); - verify(creditService).addCredit(10L, CreditType.BATTLE_VOTE, 300L); } private Battle battle(Long id, LocalDate targetDate) { diff --git a/src/test/java/com/swyp/picke/global/web/controller/StaticTextFileControllerTest.java b/src/test/java/com/swyp/picke/global/web/controller/StaticTextFileControllerTest.java new file mode 100644 index 00000000..a9a2e854 --- /dev/null +++ b/src/test/java/com/swyp/picke/global/web/controller/StaticTextFileControllerTest.java @@ -0,0 +1,28 @@ +package com.swyp.picke.global.web.controller; + +import org.junit.jupiter.api.Test; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class StaticTextFileControllerTest { + + private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new StaticTextFileController()).build(); + + @Test + void appAdsTxt_isServedAsTextPlain() throws Exception { + mockMvc.perform(get("/app-ads.txt")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("text/plain")); + } + + @Test + void robotsTxt_isServedAsTextPlain() throws Exception { + mockMvc.perform(get("/robots.txt")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("text/plain")); + } +}