Skip to content

Feat/180 domain user minsu#26

Merged
Misu0616 merged 3 commits into
feat/180-domainfrom
feat/180-domain-user-minsu
Feb 23, 2026
Merged

Feat/180 domain user minsu#26
Misu0616 merged 3 commits into
feat/180-domainfrom
feat/180-domain-user-minsu

Conversation

@ms-0o0
Copy link
Copy Markdown
Contributor

@ms-0o0 ms-0o0 commented Feb 23, 2026

개요

User 엔티티 추가

관련 BackLog

Resolves: 180

PR 유형

  • 새로운 기능 추가
  • 버그 수정
  • CSS 등 사용자 UI 디자인 변경
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

PR Checklist

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

Summary by CodeRabbit

Release Notes

  • New Features

    • API documentation and interactive testing interface now available at /swagger-ui.html
    • New endpoints for managing applications, data transfers, family shared pools, notifications, permissions, and policies
    • Enhanced support for question submission and tracking
    • Individual and family-level threshold management
  • Configuration

    • Security configuration implemented with API documentation access
  • Chores

    • Database schema initialized with full table structure and relationships

@ms-0o0 ms-0o0 self-assigned this Feb 23, 2026
@ms-0o0 ms-0o0 added the feature 새 기능 개발 label Feb 23, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 23, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR establishes the foundational API infrastructure for a mobile data management backend. It introduces OpenAPI/Swagger documentation support, 14 REST controllers spanning apps, data, family, lines, notifications, permissions, policies, and questions domains, corresponding request/response DTOs with OpenAPI annotations, Spring Security configuration, application properties, database schema initialization with migration scripts, and domain entities.

Changes

Cohort / File(s) Summary
Project Configuration
.gitignore, build.gradle, src/main/resources/application.yaml
Added .metadata STS entry to .gitignore, new springdoc-openapi-starter-webmvc-ui dependency, and comprehensive Spring Boot YAML configuration with DataSource, Flyway, MyBatis, security, and Swagger settings.
OpenAPI & Security Setup
src/main/java/com/pooli/common/config/OpenApiConfig.java, src/main/java/com/pooli/common/config/SecurityConfig.java
Created OpenAPI bean configuration with metadata (title, description, contact) and SecurityFilterChain bean disabling CSRF with permissive access to Swagger endpoints and public API routes.
Application Management
src/main/java/com/pooli/application/controller/AppController.java, src/main/java/com/pooli/application/domain/dto/response/AppResDto.java
New AppController with GET /api/apps endpoint returning empty AppResDto list; defined AppResDto with appId, appName, createdAt, and policy-related flags via Lombok and OpenAPI annotations.
Data Usage Management
src/main/java/com/pooli/data/controller/DataController.java, src/main/java/com/pooli/data/domain/dto/request/DataTransferReqDto.java, src/main/java/com/pooli/data/domain/dto/response/*
Created DataController with POST transfer, GET monthly/app/balance usage endpoints returning placeholder DTOs; defined request/response DTOs (DataTransferReqDto, MonthlyDataUsageResDto, AppDataUsageResDto, DataBalancesResDto) with nested structures and Lombok boilerplate.
Family Management
src/main/java/com/pooli/family/controller/FamilyController.java, src/main/java/com/pooli/family/controller/FamilySharedPoolsController.java, src/main/java/com/pooli/family/domain/enums/FamilyRole.java, src/main/java/com/pooli/family/domain/dto/request/*, src/main/java/com/pooli/family/domain/dto/response/*
Introduced FamilyController and FamilySharedPoolsController with 9 endpoints for member queries and shared pool operations; defined FamilyRole enum (OWNER, MEMBER) and 10 DTOs for requests/responses with OpenAPI schemas and Lombok support.
Line Management
src/main/java/com/pooli/line/controller/LineController.java, src/main/java/com/pooli/line/domain/dto/request/UpdateIndividualThresholdReqDto.java, src/main/java/com/pooli/line/domain/dto/response/*
Created LineController with GET lines and threshold endpoints, PATCH update; defined request/response DTOs (LineSimpleResDto, IndividualThresholdResDto, UpdateIndividualThresholdReqDto) for line and threshold management.
Notification Management
src/main/java/com/pooli/notification/controller/AlarmSettingController.java, src/main/java/com/pooli/notification/controller/NotiReadController.java, src/main/java/com/pooli/notification/controller/NotiSendController.java, src/main/java/com/pooli/notification/domain/enums/AlarmCode.java, src/main/java/com/pooli/notification/domain/dto/request/*, src/main/java/com/pooli/notification/domain/dto/response/*
Introduced three notification controllers with 10 endpoints for alarm settings, notification CRUD, and read status; defined AlarmCode enum and 5 DTOs (AlarmSettingReqDto, NotiSendReqDto/ResDto, UnreadCountsResDto) with OpenAPI annotations.
Permission Management
src/main/java/com/pooli/permission/controller/MemberPermissionController.java, src/main/java/com/pooli/permission/controller/PermissionController.java, src/main/java/com/pooli/permission/controller/RoleController.java, src/main/java/com/pooli/permission/domain/dto/request/*, src/main/java/com/pooli/permission/domain/dto/response/*
Created three permission controllers with 8 endpoints for member permissions, permission CRUD, and role transfer; defined 9 DTOs for requests/responses (including MemberPermissionResDto, PermissionReqDto/ResDto, RepresentativeRoleTransferResDto, SimpleMessageResDto).
Policy Management
src/main/java/com/pooli/policy/controller/AdminPolicyController.java, src/main/java/com/pooli/policy/controller/UserPolicyController.java, src/main/java/com/pooli/policy/domain/dto/request/*, src/main/java/com/pooli/policy/domain/dto/response/*
Introduced AdminPolicyController (4 endpoints) and UserPolicyController (12 endpoints) for policy operations; defined 11 request and response DTOs covering block, limit, app, and family policies with OpenAPI schemas.
Question Management
src/main/java/com/pooli/question/controller/QuestionController.java, src/main/java/com/pooli/question/domain/dto/QuestionAttachmentDto.java, src/main/java/com/pooli/question/domain/dto/request/QuestionCreateReqDto.java, src/main/java/com/pooli/question/domain/dto/response/*
Created QuestionController with 5 endpoints for question CRUD and category queries; defined 5 DTOs (QuestionAttachmentDto, QuestionCreateReqDto, QuestionListResDto, QuestionResDto, QuestionCategoryResDto/ListResDto) for question operations.
Common Utilities
src/main/java/com/pooli/common/dto/PagingResDto.java
Introduced generic PagingResDto<T> for paginated responses with content, page, size, totalElements, totalPages fields via Lombok and OpenAPI annotations.
Domain Entities
src/main/java/com/pooli/user/domain/entity/User.java, src/main/java/com/pooli/user/domain/entity/Role.java, src/main/java/com/pooli/user/domain/entity/UserRole.java
Created three JPA entity classes (User, Role, UserRole) with Lombok boilerplate for getters, builders, and controlled constructors.
Database Schema
src/main/resources/db/migration/V1__init.sql, src/main/resources/db/migration/V2602231343__convert_timestamp_to_datetime6.sql
Defined comprehensive database schema with 24 tables including USERS, ROLE, FAMILY, LINE, POLICY, QUESTION, PERMISSION, and related entities with primary keys, foreign keys, and constraints; added migration to convert TIMESTAMP to DATETIME(6) columns.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Feat/225 swagger permission seunghyun #18: Introduces identical OpenAPI/Springdoc configuration and .metadata .gitignore entry; contains overlapping permission and role controller implementations with similar DTO structures.

Suggested reviewers

  • Misu0616

Poem

🐰 A thousand DTOs hop through the API land,
With Swagger annotations neat and grand,
Controllers spring forth, like carrots in rows,
Data flows freely as the schema grows! 🌱

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Feat/180 domain user minsu' is vague and uses a branch naming convention rather than a clear changeset description, making it unclear to future readers. Consider renaming the title to something more descriptive like 'Add User entity and domain layer structure' to clearly communicate the main changes at a glance.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/180-domain-user-minsu

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (11)
src/main/resources/db/migration/V2602231343__convert_timestamp_to_datetime6.sql-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Remove the UTF-8 BOM from the first line of this file.

The file starts with a UTF-8 BOM (byte sequence efbbbf), which can cause Flyway and some SQL parsers to misinterpret the opening comment. Save the file as UTF-8 without BOM.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/resources/db/migration/V2602231343__convert_timestamp_to_datetime6.sql`
at line 1, The first line of the migration file begins with a UTF-8 BOM (byte
sequence efbbbf) which can break Flyway/SQL parsing; open the file containing
the comment "-- Convert TIMESTAMP columns created in V1__init.sql to
DATETIME(6)." and re-save it as UTF-8 without BOM (remove the BOM bytes from the
start of the file) so the opening comment is plain ASCII/UTF-8 and no BOM
remains.
src/main/java/com/pooli/data/domain/dto/response/MonthlyDataUsageResDto.java-27-38 (1)

27-38: ⚠️ Potential issue | 🟡 Minor

Add missing Lombok annotations to nested DTO.

MonthlyUsageDto has @Builder but is missing @AllArgsConstructor and @NoArgsConstructor annotations. Without these, JSON deserialization with Jackson may fail. The outer class and similar nested DTOs (e.g., AppUsageDto in AppDataUsageResDto) include these annotations.

🛠️ Proposed fix
     `@Builder`
     `@Getter`
+    `@AllArgsConstructor`(access = AccessLevel.PRIVATE)
+    `@NoArgsConstructor`(access = AccessLevel.PRIVATE)
     `@Schema`(description = "월별 사용량 DTO")
     public static class MonthlyUsageDto {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/domain/dto/response/MonthlyDataUsageResDto.java`
around lines 27 - 38, The nested DTO MonthlyUsageDto currently only has `@Builder`
and `@Getter` which can break Jackson deserialization; add Lombok annotations
`@AllArgsConstructor` and `@NoArgsConstructor` to the MonthlyUsageDto declaration
(alongside the existing `@Builder` and `@Getter`) so Jackson can instantiate it,
matching the pattern used for other nested DTOs like AppUsageDto in
AppDataUsageResDto.
build.gradle-31-31 (1)

31-31: ⚠️ Potential issue | 🟡 Minor

Update springdoc-openapi to the latest stable version.

The dependency is compatible with Spring Boot 3.5.10, but version 2.8.5 is outdated. Update to 2.8.15 (the latest stable in the 2.8.x line for Spring Boot 3.x, released Jan 1, 2026) unless there's a specific compatibility reason to pin to 2.8.5 (e.g., Spring AI integration).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@build.gradle` at line 31, Update the springdoc-openapi dependency version
from 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5' to
'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.15' in the build.gradle
dependency block; ensure no other code relies on the older version (e.g., Spring
AI integrations) before changing and run a quick build/test to confirm
compatibility.
src/main/java/com/pooli/line/domain/dto/response/IndividualThresholdResDto.java-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Typo in schema description: "bite" should be "byte".

The unit description has a spelling error that will appear in the API documentation.

📝 Suggested fix
-    `@Schema`(description = "개인 데이터 임계치(bite)", example = "3000")
+    `@Schema`(description = "개인 데이터 임계치(byte)", example = "3000")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/line/domain/dto/response/IndividualThresholdResDto.java`
at line 12, The Schema description for the individual data threshold contains a
typo ("bite"); update the `@Schema` description in IndividualThresholdResDto (the
annotation on the field/property annotated with `@Schema`(description = "개인 데이터
임계치(bite)", example = "3000")) to use the correct unit string "byte" so the API
docs read "개인 데이터 임계치(byte)".
src/main/java/com/pooli/family/domain/dto/response/FamilySharedPoolResDto.java-12-23 (1)

12-23: ⚠️ Potential issue | 🟡 Minor

Resolve TODO comments about units and type choices before release.

Line 12 and Line 23 read like unresolved questions. Please decide the unit (MB/KB/byte) and numeric type, then update the @Schema descriptions and remove the TODOs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/family/domain/dto/response/FamilySharedPoolResDto.java`
around lines 12 - 23, Decide on units and numeric types: use MB as the canonical
unit and keep all three fields as Long (poolTotalData, poolRemainingData,
pool_base_data); update each `@Schema` description to mention "(MB)" and change
the example values to MB-appropriate numbers (e.g., 20, 8.5) or integer MB
values as needed, then remove the TODO comments; ensure the field types remain
Long in the DTO so no downstream type changes are required.
src/main/java/com/pooli/question/domain/dto/response/QuestionResDto.java-3-38 (1)

3-38: ⚠️ Potential issue | 🟡 Minor

Change createdAt from LocalDate to LocalDateTime.

The field is declared as LocalDate but the schema example includes a time component (2026-02-23T14:30:00). Additionally, all other createdAt fields across the codebase (User, UserRole, PermissionResDto, NotiSendResDto, AppResDto, etc.) use LocalDateTime. Align this field with the codebase pattern and the example format.

Suggested fix
-import java.time.LocalDate;
+import java.time.LocalDateTime;
@@
-    `@Schema`(description = "문의사항 생성 시점", example = "2026-02-23T14:30:00")
-    private LocalDate createdAt;
+    `@Schema`(description = "문의사항 생성 시점", example = "2026-02-23T14:30:00")
+    private LocalDateTime createdAt;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/question/domain/dto/response/QuestionResDto.java`
around lines 3 - 38, The createdAt field in QuestionResDto is typed as LocalDate
but its schema example includes a time and other DTOs use LocalDateTime; update
the field type in QuestionResDto from java.time.LocalDate to
java.time.LocalDateTime and adjust the import accordingly (replace LocalDate
import with LocalDateTime) so the field signature (private LocalDateTime
createdAt) and schema example align with the rest of the codebase (class
QuestionResDto, field createdAt).
src/main/java/com/pooli/policy/domain/dto/request/AppPolicyUpdateReqDto.java-11-15 (1)

11-15: ⚠️ Potential issue | 🟡 Minor

Align AppPolicyUpdateReqDto fields with update DTO pattern or explicitly document partial update support.

Lines 11 and 14 lack requiredMode, while similar update DTOs (BlockPolicyUpdateReqDto, LimitPolicyUpdateReqDto) mark their fields as requiredMode = Schema.RequiredMode.REQUIRED. The controller's null-checking logic (applying Boolean.FALSE and 0 defaults) suggests this DTO intentionally supports partial updates, but this should be either:

  • Explicitly documented in the class or field descriptions, OR
  • Aligned with other update DTOs by adding requiredMode = Schema.RequiredMode.REQUIRED if full updates are expected
✏️ Option 1: Align with other update DTOs
-    `@Schema`(description = "앱 정책 활성화 여부", example = "true")
+    `@Schema`(description = "앱 정책 활성화 여부", example = "true", requiredMode = Schema.RequiredMode.REQUIRED)
     private Boolean enabled;

-    `@Schema`(description = "일일 제한량(MB)", example = "500")
+    `@Schema`(description = "일일 제한량(MB)", example = "500", requiredMode = Schema.RequiredMode.REQUIRED)
     private Integer dailyLimitMb;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/policy/domain/dto/request/AppPolicyUpdateReqDto.java`
around lines 11 - 15, AppPolicyUpdateReqDto currently leaves the fields enabled
and dailyLimitMb without Schema.requiredMode while similar update DTOs
(BlockPolicyUpdateReqDto, LimitPolicyUpdateReqDto) mark fields as required;
update this DTO to either (a) mark both fields with `@Schema`(requiredMode =
Schema.RequiredMode.REQUIRED) to match the other update DTOs if full updates are
expected, or (b) explicitly document partial-update semantics on the class or
these field Schemas (e.g., note that null means “no change”) to match the
controller’s null-checking logic that applies defaults; locate
AppPolicyUpdateReqDto and edit the annotations or Javadoc for enabled and
dailyLimitMb accordingly.
src/main/java/com/pooli/data/domain/dto/response/AppDataUsageResDto.java-15-15 (1)

15-15: ⚠️ Potential issue | 🟡 Minor

Typo: "bite" should be "byte".

The schema description says "bite" but should be "byte". This typo also appears in related DTOs (DataBalancesResDto, MonthlyDataUsageResDto).

🔧 Fix typo
-    `@Schema`(description = "총 사용 데이터량(bite)", example = "5200")
+    `@Schema`(description = "총 사용 데이터량(byte)", example = "5200")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/domain/dto/response/AppDataUsageResDto.java` at
line 15, Fix the typo in the `@Schema` description texts: change "총 사용 데이터량(bite)"
to "총 사용 데이터량(byte)" in AppDataUsageResDto (class name) and make the same
correction in the related DTOs DataBalancesResDto and MonthlyDataUsageResDto so
their `@Schema` descriptions/examples use "byte" instead of "bite".
src/main/java/com/pooli/notification/domain/dto/request/AlarmSettingReqDto.java-12-28 (1)

12-28: ⚠️ Potential issue | 🟡 Minor

Make DTO fields private for encapsulation.

Line 12-28 declare package-private fields. Standard DTO practice is private fields with Lombok accessors to avoid unintended access across packages.

🔒 Proposed fix
-    Boolean familyAlarm;
+    private Boolean familyAlarm;
...
-    Boolean questionAlarm;
+    private Boolean questionAlarm;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/notification/domain/dto/request/AlarmSettingReqDto.java`
around lines 12 - 28, The DTO AlarmSettingReqDto exposes package-private Boolean
fields (familyAlarm, userAlarm, policyChangeAlarm, policyLimitAlarm,
permissionAlarm, questionAlarm); change each field to private and rely on
existing Lombok accessors (or add `@Getter/`@Setter) so fields are encapsulated,
update any direct field accesses to use getters/setters if present elsewhere,
and ensure serialization frameworks still see the fields (e.g., keep Lombok
annotations or add `@JsonProperty` if needed).
src/main/java/com/pooli/data/domain/dto/response/DataBalancesResDto.java-16-20 (1)

16-20: ⚠️ Potential issue | 🟡 Minor

Fix unit typo in schema description (“bite” → “byte”).

This is user-facing Swagger text.

✏️ Proposed fix
-    `@Schema`(description = "가족 공유 데이터 잔량(bite)", example = "5000")
+    `@Schema`(description = "가족 공유 데이터 잔량(byte)", example = "5000")
     private Long sharedDataRemaining;

-    `@Schema`(description = "개인 데이터 잔량(bite)", example = "2000")
+    `@Schema`(description = "개인 데이터 잔량(byte)", example = "2000")
     private Long personalDataRemaining;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/domain/dto/response/DataBalancesResDto.java`
around lines 16 - 20, The `@Schema` descriptions on DataBalancesResDto currently
use the typo "bite"; update the user-facing Swagger text for the fields
sharedDataRemaining and personalDataRemaining to use "byte" instead of "bite" so
the descriptions read e.g. "가족 공유 데이터 잔량(byte)" and "개인 데이터 잔량(byte)". Ensure
both `@Schema` annotations on the sharedDataRemaining and personalDataRemaining
fields are corrected.
src/main/java/com/pooli/data/controller/DataController.java-49-80 (1)

49-80: ⚠️ Potential issue | 🟡 Minor

Use the month param (or validate it) to avoid misleading responses.

The handler always returns 3 months regardless of the request, which conflicts with the API description.

💡 One way to apply the parameter
-        List<MonthlyDataUsageResDto.MonthlyUsageDto> usages = List.of(
+        List<MonthlyDataUsageResDto.MonthlyUsageDto> allUsages = List.of(
                 MonthlyDataUsageResDto.MonthlyUsageDto.builder()
                         .yearMonth("2026-01")
                         .usedAmount(1000L)
                         .build(),
                 MonthlyDataUsageResDto.MonthlyUsageDto.builder()
                         .yearMonth("2026-02")
                         .usedAmount(1500L)
                         .build(),
                 MonthlyDataUsageResDto.MonthlyUsageDto.builder()
                         .yearMonth("2026-03")
                         .usedAmount(1100L)
                         .build()
         );
 
-        Long average = usages.stream()
-                .mapToLong(MonthlyDataUsageResDto.MonthlyUsageDto::getUsedAmount)
-                .sum() / usages.size();
+        int count = Math.min(Math.max(month, 0), allUsages.size());
+        List<MonthlyDataUsageResDto.MonthlyUsageDto> usages = allUsages.subList(0, count);
+
+        Long average = usages.isEmpty() ? 0L : usages.stream()
+                .mapToLong(MonthlyDataUsageResDto.MonthlyUsageDto::getUsedAmount)
+                .sum() / usages.size();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/controller/DataController.java` around lines 49
- 80, getMonthlyDataUsage currently ignores the request param month and always
returns three hard-coded MonthlyUsageDto entries; update the method to
use/validate the month param (e.g., ensure month > 0 and within a sensible max)
and generate the usages list dynamically for the requested number of months (or
return 400 if invalid). Locate getMonthlyDataUsage in DataController and replace
the hard-coded List.of(...) construction with logic that builds
MonthlyDataUsageResDto.MonthlyUsageDto items based on the month parameter (using
YearMonth or similar to compute yearMonth strings) and recompute averageAmount
from that generated list.
🧹 Nitpick comments (29)
src/main/resources/application.yaml (2)

17-17: Ensure baseline-on-migrate is disabled in production.

Setting baseline-on-migrate: true on an existing database will create a baseline and may skip pending migrations. Ensure this is set to false in production environments to avoid accidental data migration issues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/application.yaml` at line 17, The Flyway setting
baseline-on-migrate is currently controlled by ${FLYWAY_BASELINE_ON_MIGRATE} in
application.yaml; ensure this is disabled in production by setting the
FLYWAY_BASELINE_ON_MIGRATE environment variable to "false" (or hardcode
baseline-on-migrate: false in the production profile), and verify that any
deployment/config map or prod Spring profile does not override it to true so
migrations will not be baselined accidentally.

11-13: Consider adding HikariCP pool settings for production readiness.

The HikariCP configuration only includes initialization-fail-timeout. For production environments, consider configuring additional pool settings such as maximum-pool-size, minimum-idle, connection-timeout, and idle-timeout to prevent resource exhaustion under load.

Example HikariCP settings
   hikari:
     # Do not fail app startup immediately when DB is unavailable
     initialization-fail-timeout: ${DB_INIT_FAIL_TIMEOUT}
+    maximum-pool-size: ${DB_POOL_MAX_SIZE:10}
+    minimum-idle: ${DB_POOL_MIN_IDLE:5}
+    connection-timeout: ${DB_CONNECTION_TIMEOUT:30000}
+    idle-timeout: ${DB_IDLE_TIMEOUT:600000}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/application.yaml` around lines 11 - 13, Add
production-ready HikariCP properties alongside the existing
hikari.initialization-fail-timeout: configure hikari.maximum-pool-size,
hikari.minimum-idle, hikari.connection-timeout, and hikari.idle-timeout with
sensible defaults or environment variables; update application.yaml to read
these values (e.g., ${DB_MAX_POOL_SIZE}, ${DB_MIN_IDLE}, ${DB_CONN_TIMEOUT},
${DB_IDLE_TIMEOUT}) so the pool sizing and timeouts are controllable in
different environments and prevent resource exhaustion under load.
src/main/resources/db/migration/V2602231343__convert_timestamp_to_datetime6.sql (1)

4-74: Plan for DDL locking/rebuild impact.
A long sequence of ALTER TABLE ... MODIFY COLUMN can lock or rebuild large tables in MySQL. If this is a production migration, consider an online schema change strategy or a maintenance window.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/resources/db/migration/V2602231343__convert_timestamp_to_datetime6.sql`
around lines 4 - 74, This migration runs many blocking ALTER TABLE ... MODIFY
COLUMN statements (e.g., ALTER TABLE `DAILY_APP_TOTAL_DATA` MODIFY COLUMN
`created_at`..., ALTER TABLE `USERS` MODIFY COLUMN `updated_at`..., ALTER TABLE
`ANSWER` MODIFY COLUMN `deleted_at`...), which can lock/rebuild large tables;
resolve by converting this single-file migration into a safe deployment plan:
either run the changes during a maintenance window, or perform non-blocking
online schema changes using tools like pt-online-schema-change or gh-ost per
table (or implement a staged deploy that adds new DATETIME(6) columns,
backfills, swaps names, drops old columns), and update the migration file /
runbook to reflect the chosen approach and include the tool/command or
maintenance-window schedule for each of the listed tables.
src/main/java/com/pooli/policy/domain/dto/request/PolicyActivationReqDto.java (1)

11-16: Consider adding @NotNull validation for runtime enforcement.

The @Schema(requiredMode = REQUIRED) annotation only documents the field as required in OpenAPI specs but doesn't enforce it at runtime. Consider adding Bean Validation annotations to ensure the constraint is enforced when the request is processed.

💡 Proposed fix to add validation
 package com.pooli.policy.domain.dto.request;
 
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
 import lombok.Getter;
 import lombok.Setter;
 
 `@Getter`
 `@Setter`
 `@Schema`(description = "정책 활성화 요청 바디")
 public class PolicyActivationReqDto {
+        `@NotNull`(message = "policyId는 필수입니다")
         `@Schema`(
                 description = "활성화할 정책 식별자",
                 example = "1003",
                 requiredMode = Schema.RequiredMode.REQUIRED
         )
         private Long policyId;
 }

Note: Ensure the controller method parameter is annotated with @Valid to trigger validation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/policy/domain/dto/request/PolicyActivationReqDto.java`
around lines 11 - 16, The PolicyActivationReqDto class has policyId annotated
with `@Schema`(requiredMode = REQUIRED) which only documents the requirement; add
javax.validation.constraints.NotNull (or jakarta.validation.constraints.NotNull)
to the policyId field in PolicyActivationReqDto to enforce runtime validation,
and ensure any controller method receiving PolicyActivationReqDto is annotated
with `@Valid` on the parameter so bean validation is triggered at request binding.
src/main/java/com/pooli/policy/domain/dto/request/LimitPolicyUpdateReqDto.java (1)

11-12: Consider adding @NotNull validation for runtime enforcement.

Similar to PolicyActivationReqDto, the @Schema(requiredMode = REQUIRED) only affects API documentation. Add @NotNull to enforce the requirement at runtime.

💡 Proposed fix
+import jakarta.validation.constraints.NotNull;
+
 `@Getter`
 `@Setter`
 `@Schema`(description = "제한 정책 단건 수정 요청")
 public class LimitPolicyUpdateReqDto {
+    `@NotNull`(message = "policyValue는 필수입니다")
     `@Schema`(description = "수정할 정책 값", example = "1024", requiredMode = Schema.RequiredMode.REQUIRED)
     private Integer policyValue;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/policy/domain/dto/request/LimitPolicyUpdateReqDto.java`
around lines 11 - 12, Add javax.validation.constraints.NotNull to enforce
runtime validation on the policyValue field in LimitPolicyUpdateReqDto: annotate
the field policyValue with `@NotNull` (in addition to the existing `@Schema`) so the
validation framework will reject nulls at runtime; ensure the import for NotNull
is added and that this DTO is validated where used (e.g., controller methods
annotated with `@Valid`).
src/main/java/com/pooli/family/domain/dto/request/CreateSharedPoolContributionReqDto.java (2)

12-16: Inconsistent ID types across DTOs.

The identifier types differ between DTOs: this DTO uses Integer for familyId and lineId, while FamilyMembersSimpleResDto uses Long for lineId and userId. Consider standardizing on Long for all entity identifiers to avoid potential mapping issues and to accommodate future growth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/family/domain/dto/request/CreateSharedPoolContributionReqDto.java`
around lines 12 - 16, The DTO CreateSharedPoolContributionReqDto currently
declares familyId and lineId as Integer; change both fields to Long to match
FamilyMembersSimpleResDto (which uses Long for lineId and userId), update any
corresponding getters/setters or Lombok annotations, and adjust `@Schema` example
values (e.g., "1" -> "1") and any validation or mapping code that assumes
Integer so the identifier types are consistent across DTOs and mappings.

12-19: Add validation annotations for request fields.

This request DTO lacks validation annotations. For a contribution request, consider:

  • familyId and lineId should be non-null
  • amount should be non-null and positive (users shouldn't contribute zero or negative data)
💡 Proposed fix to add validation
 package com.pooli.family.domain.dto.request;
 
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
 import lombok.Getter;
 import lombok.Setter;
 
 `@Getter`
 `@Setter`
 `@Schema`(description = "공유풀 데이터 담기 요청 DTO")
 public class CreateSharedPoolContributionReqDto {
 
+    `@NotNull`
     `@Schema`(description = "가족 식별자", example = "1")
     private Integer familyId;
 
+    `@NotNull`
     `@Schema`(description = "회선 식별자", example = "10")
     private Integer lineId;
 
+    `@NotNull`
+    `@Positive`
     `@Schema`(description = "공유풀에 담을 데이터량(MB)", example = "500")
     private Long amount;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/family/domain/dto/request/CreateSharedPoolContributionReqDto.java`
around lines 12 - 19, Add bean validation annotations to the
CreateSharedPoolContributionReqDto: mark familyId and lineId with `@NotNull`, and
mark amount with `@NotNull` plus a positivity constraint (e.g., `@Positive` or
`@Min`(1)) so contributions cannot be zero/negative; update imports to use the
proper validation package (javax.validation.constraints.* or
jakarta.validation.constraints.*) and ensure the DTO class is validated where
requests are bound (e.g., controller methods expecting
CreateSharedPoolContributionReqDto).
src/main/java/com/pooli/data/domain/dto/response/MonthlyDataUsageResDto.java (1)

23-25: Mutable setter breaks immutability pattern.

The updateAverageAmount method introduces mutability, which is inconsistent with other response DTOs in the codebase that use immutable patterns (private constructors + builder). Consider computing averageAmount during construction instead, or if post-construction mutation is required, document why this exception is necessary.

💡 Alternative: compute average in a static factory
public static MonthlyDataUsageResDto of(List<MonthlyUsageDto> usages) {
    Long average = usages.isEmpty() ? 0L : 
        usages.stream()
              .mapToLong(MonthlyUsageDto::getUsedAmount)
              .average()
              .orElse(0.0).longValue();
    return MonthlyDataUsageResDto.builder()
            .usages(usages)
            .averageAmount(average)
            .build();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/domain/dto/response/MonthlyDataUsageResDto.java`
around lines 23 - 25, The updateAverageAmount method in MonthlyDataUsageResDto
introduces post-construction mutability; remove or deprecate this setter and
compute averageAmount at creation instead by adding a static factory (e.g.,
MonthlyDataUsageResDto.of(List<MonthlyUsageDto> usages)) that computes the
average (handle empty lists by returning 0L), then build the DTO via the
existing builder with usages and averageAmount set; if mutation truly is
required, make updateAverageAmount private and add a comment explaining the
exceptional need instead of a public setter.
src/main/java/com/pooli/permission/domain/dto/request/PermissionReqDto.java (2)

11-12: Consider specifying requiredMode for API clarity.

Other request DTOs in this PR (e.g., BlockPolicyUpdateReqDto) specify requiredMode = Schema.RequiredMode.REQUIRED for mandatory fields. If permissionTitle is required for permission creation/update, add this for consistent API documentation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/permission/domain/dto/request/PermissionReqDto.java`
around lines 11 - 12, The `@Schema` on permissionTitle in PermissionReqDto should
mark the field as required for consistent API docs; update the annotation to
include requiredMode = Schema.RequiredMode.REQUIRED (e.g., `@Schema`(description =
"권한 이름", example = "데이터 차단", requiredMode = Schema.RequiredMode.REQUIRED)) so
the field appears required like other DTOs such as BlockPolicyUpdateReqDto and
ensure any necessary import for Schema.RequiredMode is present.

4-4: Prefer explicit imports over wildcard.

The wildcard import lombok.* is used but only @Getter and @Setter are needed. Related DTOs in this codebase use explicit imports for consistency.

♻️ Suggested fix
-import lombok.*;
+import lombok.Getter;
+import lombok.Setter;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/permission/domain/dto/request/PermissionReqDto.java`
at line 4, Replace the wildcard Lombok import with explicit imports: remove
"import lombok.*;" and add only the annotations used in PermissionReqDto (e.g.,
"import lombok.Getter;" and "import lombok.Setter;") so the class uses explicit
imports consistent with the codebase; update the import statement near the
PermissionReqDto class accordingly.
src/main/java/com/pooli/policy/domain/dto/response/PolicyActivationResDto.java (1)

18-19: Consider using a typed date/time representation.

Using String for activatedAt works but loses compile-time type safety and relies on consistent formatting. Consider LocalDateTime or OffsetDateTime with a @JsonFormat annotation for stricter typing, though the current approach is consistent with PolicyDeactivationResDto.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/policy/domain/dto/response/PolicyActivationResDto.java`
around lines 18 - 19, Change the activatedAt field in PolicyActivationResDto
from String to a typed temporal type (e.g., java.time.OffsetDateTime or
java.time.LocalDateTime) to gain compile-time safety; update the field
declaration activatedAt accordingly, add the appropriate `@JsonFormat`(pattern =
"...", timezone = "...") (and/or `@JsonSerialize/`@JsonDeserialize if needed) and
adjust the `@Schema` example to match the chosen format, and ensure imports are
added; mirror the same approach used in PolicyDeactivationResDto (or update that
DTO for consistency) so serialization/deserialization behavior is consistent
across both DTOs.
src/main/java/com/pooli/policy/domain/dto/response/AdminPolicyResDto.java (1)

24-25: Consider using LocalDateTime for the timestamp field.

The updatedAt field is typed as String, while other response DTOs in this codebase (e.g., SimpleMessageResDto, PermissionResDto, MemberPermissionResDto) use LocalDateTime for timestamp fields. Using a consistent type improves type safety and ensures uniform serialization behavior across the API.

♻️ Suggested change
+import java.time.LocalDateTime;
+
 `@Schema`(description = "최종 수정 시각", example = "2026-02-20T10:10:00")
-    private String updatedAt;
+    private LocalDateTime updatedAt;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/policy/domain/dto/response/AdminPolicyResDto.java`
around lines 24 - 25, The updatedAt field in AdminPolicyResDto is a String but
should be LocalDateTime to match other DTOs and ensure consistent serialization;
change the type of the updatedAt field in class AdminPolicyResDto from String to
java.time.LocalDateTime, add the necessary import, and update the `@Schema`
example/format if needed (e.g., ensure example uses an ISO-8601 datetime) so
Jackson/DateTime serializers for LocalDateTime are applied consistently across
SimpleMessageResDto, PermissionResDto, and MemberPermissionResDto.
src/main/java/com/pooli/notification/domain/dto/request/NotiSendReqDto.java (1)

17-18: Field name should be plural to match the List type.

The field is declared as List<Long> but named userId (singular). This can be confusing for API consumers. Additionally, the @Schema example shows "1" which doesn't represent a list value.

♻️ Suggested fix
-	`@Schema`(description = "알림 보낼 사용자 ID", example = "1")
-	private List<Long> userId; // 여러명한테 보낼걸 대비해 List 형태
+	`@Schema`(description = "알림 보낼 사용자 ID 목록", example = "[1, 2, 3]")
+	private List<Long> userIds;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/notification/domain/dto/request/NotiSendReqDto.java`
around lines 17 - 18, Rename the field userId in NotiSendReqDto to a plural form
(e.g., userIds) and update its `@Schema` to reflect a list type (change
description to "알림 보낼 사용자 ID 목록" and example to a JSON array like "[1]" or
"[1,2]"); also update all references (getters/setters, constructors, builders,
DTO mappings, and any code that accesses NotiSendReqDto.userId) to use the new
field name to avoid compile errors and keep the API contract consistent.
src/main/java/com/pooli/permission/controller/RoleController.java (1)

29-39: Stub implementation lacks validation and business logic.

The endpoint currently echoes input parameters without performing actual role transfer. While this appears to be intentional scaffolding for API documentation, consider adding:

  1. Validation to ensure currentUserId and changeUserId are different
  2. Service layer injection when implementing actual business logic
♻️ Example validation
     public ResponseEntity<RepresentativeRoleTransferResDto> transferRepresentativeRole(
             `@Parameter`(description = "현재 대표 사용자 ID", example = "101")
             `@RequestParam` Long currentUserId,
             `@Parameter`(description = "변경 대상 사용자 ID", example = "202")
             `@RequestParam` Long changeUserId) {
+        if (currentUserId.equals(changeUserId)) {
+            throw new IllegalArgumentException("현재 대표와 변경 대상이 동일할 수 없습니다.");
+        }
+        // TODO: Inject and call service layer for actual role transfer
         RepresentativeRoleTransferResDto representativeRoleTransferResDto = RepresentativeRoleTransferResDto.builder()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/permission/controller/RoleController.java` around
lines 29 - 39, The transferRepresentativeRole controller method currently just
echoes inputs and lacks validation and service call; update
transferRepresentativeRole to validate that currentUserId and changeUserId are
not null and are different (return 400/throw a validation exception if invalid),
inject and call a RoleService (e.g.,
roleService.transferRepresentative(currentUserId, changeUserId)) to perform
business logic, and build RepresentativeRoleTransferResDto from the service
result instead of blindly returning the request values; ensure the method
signature and DTO usage remain, and add appropriate exception handling to
translate service errors into HTTP responses.
src/main/java/com/pooli/family/domain/dto/response/FamilySharedPoolResDto.java (1)

20-21: Rename pool_base_data to poolBaseData for consistency with Java conventions and other fields in this DTO.

All other fields in FamilySharedPoolResDto use camelCase (poolTotalData, poolRemainingData, monthlyUsageAmount, monthlyContributionAmount), and all DTOs across the codebase follow the same convention. The snake_case field stands out as an inconsistency.

Suggested rename
-    `@Schema`(description = "공유풀 기본 제공량(bite)", example = "8500")
-    private Long pool_base_data;
+    `@Schema`(description = "공유풀 기본 제공량(bite)", example = "8500")
+    private Long poolBaseData;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/family/domain/dto/response/FamilySharedPoolResDto.java`
around lines 20 - 21, Rename the snake_case field pool_base_data in
FamilySharedPoolResDto to camelCase poolBaseData to match the DTO convention;
update the field declaration and any corresponding getter/setter and usages
(e.g., getPool_base_data / setPool_base_data) to getPoolBaseData /
setPoolBaseData, and adjust any JSON annotations if present (e.g.,
`@JsonProperty`) or mapping code that references "pool_base_data" so
serialization/deserialization and all references compile and remain consistent
with the other fields like poolTotalData and poolRemainingData.
src/main/java/com/pooli/question/domain/dto/QuestionAttachmentDto.java (1)

20-21: Align fileSize with codebase pattern by using Long instead of primitive int.

All other numeric fields in DTOs throughout the codebase use boxed types (Long, Integer). Using Long for fileSize maintains consistency, supports potential null values in DTOs, and avoids the ~2GB cap of primitive int.

♻️ Suggested change
-    private int fileSize;
+    private Long fileSize;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/question/domain/dto/QuestionAttachmentDto.java`
around lines 20 - 21, Change the QuestionAttachmentDto.field fileSize from
primitive int to boxed Long to match DTO numeric patterns and allow nulls;
update the field type in class QuestionAttachmentDto (and any corresponding
getter/setter or builder/constructor references) and ensure the `@Schema`
annotation remains, adjusting example if needed to a long literal (e.g.,
"204800")—also update any serialization/deserialization usages or tests that
assume an int to accept Long.
src/main/java/com/pooli/family/domain/dto/request/UpdateSharedDataThresholdReqDto.java (1)

10-12: Consider adding validation for the threshold value.

The newFamilyThreshold field lacks validation. Negative or null values could cause issues. Also, the example value of "1500" bytes (~1.5KB) seems unusually small for a data usage threshold—consider if this should be in MB or if the example should be larger (e.g., "1073741824" for 1GB).

💡 Proposed validation
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+
 `@Getter`
 `@Setter`
 `@Schema`(description = "가족 공유 데이터 사용량 임계치 수정 요청 DTO")
 public class UpdateSharedDataThresholdReqDto {
+    `@NotNull`
+    `@Positive`
-    `@Schema`(description = "새로운 임계치 값(단위: Byte)", example = "1500")
+    `@Schema`(description = "새로운 임계치 값(단위: Byte)", example = "1073741824")
     private Long newFamilyThreshold;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/family/domain/dto/request/UpdateSharedDataThresholdReqDto.java`
around lines 10 - 12, The UpdateSharedDataThresholdReqDto.newFamilyThreshold
field lacks validation and has a misleading small example; add javax/hibernate
validation annotations (e.g., `@NotNull` and `@Positive` or `@Min`(1)) to
newFamilyThreshold in class UpdateSharedDataThresholdReqDto and update the
`@Schema` example to a realistic value (e.g., "1073741824" for 1GB) and a clear
unit description, and ensure callers (controllers) validate incoming DTOs with
`@Valid` so the annotations are enforced.
src/main/java/com/pooli/data/domain/dto/response/AppDataUsageResDto.java (1)

21-31: Nested AppUsageDto is missing @NoArgsConstructor.

The nested AppUsageDto class lacks @NoArgsConstructor, which may cause issues with Jackson deserialization or certain frameworks that require a no-args constructor. Other nested DTOs in the codebase (e.g., MonthlyUsageDto) also follow this pattern, but it's worth ensuring consistency with the outer class annotations.

Also, the "bite" typo on line 29 should be "byte".

💡 Proposed fix
     `@Getter`
     `@Builder`
+    `@NoArgsConstructor`(access = AccessLevel.PRIVATE)
+    `@AllArgsConstructor`(access = AccessLevel.PRIVATE)
     `@Schema`(description = "앱별 사용량 DTO")
     public static class AppUsageDto {

         `@Schema`(description = "애플리케이션 이름", example = "YouTube")
         private String appName;

-        `@Schema`(description = "사용량(bite)", example = "2000")
+        `@Schema`(description = "사용량(byte)", example = "2000")
         private Long usedAmount;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/domain/dto/response/AppDataUsageResDto.java`
around lines 21 - 31, Add a no-args constructor annotation to the nested DTO and
fix the typo in the Schema description: annotate the nested class AppUsageDto
with Lombok's `@NoArgsConstructor` (in addition to the existing `@Getter/`@Builder)
so Jackson/other frameworks can instantiate it, and change the `@Schema`
description for usedAmount from "사용량(bite)" to "사용량(byte)". Ensure imports for
lombok.NoArgsConstructor are present if missing.
src/main/java/com/pooli/application/controller/AppController.java (2)

28-28: Reconsider 404 response for list endpoint.

A "list all" endpoint typically returns 200 with an empty list when no items exist, rather than 404. The 404 status is more appropriate for single-resource lookups (e.g., /api/apps/{id}). This is consistent with other controllers in the codebase (e.g., NotiReadController), but worth reconsidering for semantic correctness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/application/controller/AppController.java` at line
28, The list endpoint in AppController currently declares a 404 ApiResponse
which is inappropriate for a collection resource; update the API responses on
the list method (e.g., the method in AppController that returns the app list) to
remove the 404 response and ensure it documents a 200 response that can return
an empty list (match behavior used in NotiReadController); adjust the
`@ApiResponse` annotations accordingly so the method only documents successful 200
responses (and any relevant error codes like 500) rather than 404 for "no
items".

22-35: Fix inconsistent indentation.

The method body has extra leading spaces compared to the class-level indentation. This affects code readability.

🔧 Proposed fix for indentation
-	  `@Operation`(
-          summary = "애플리케이션 목록 조회",
-          description = "애플리케이션 ID 기준 등록된 애플리케이션 목록을 모두 조회한다."
-      )
-      `@ApiResponses`({
-          `@ApiResponse`(responseCode = "200", description = "조회 성공"),
-          `@ApiResponse`(responseCode = "404", description = "앱 정보가 존재하지 않음"),
-          `@ApiResponse`(responseCode = "500", description = "서버 오류"),
-            
-      })
-      `@GetMapping`
-      public ResponseEntity<List<AppResDto>> getApps(){
-          return ResponseEntity.ok(List.of());
-      }
+    `@Operation`(
+        summary = "애플리케이션 목록 조회",
+        description = "애플리케이션 ID 기준 등록된 애플리케이션 목록을 모두 조회한다."
+    )
+    `@ApiResponses`({
+        `@ApiResponse`(responseCode = "200", description = "조회 성공"),
+        `@ApiResponse`(responseCode = "404", description = "앱 정보가 존재하지 않음"),
+        `@ApiResponse`(responseCode = "500", description = "서버 오류"),
+    })
+    `@GetMapping`
+    public ResponseEntity<List<AppResDto>> getApps() {
+        return ResponseEntity.ok(List.of());
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/application/controller/AppController.java` around
lines 22 - 35, The getApps method in AppController has inconsistent indentation
in its body; align the method signature and body with the class-level
indentation by removing the extra leading spaces before the annotations and the
method block so that `@Operation`, `@ApiResponses`, `@GetMapping` and the method
declaration public ResponseEntity<List<AppResDto>> getApps() and its body use
the same indentation level as other class members in AppController; ensure
opening and closing braces and the return statement are indented consistently
with the surrounding methods.
src/main/java/com/pooli/permission/domain/dto/request/MemberPermissionUpsertReqDto.java (1)

12-17: Consider adding validation annotations for required fields.

The DTO lacks @NotNull or other Bean Validation annotations. If permissionId and isEnable are required for the upsert operation, adding validation would prevent invalid requests from reaching the service layer.

💡 Optional: Add validation annotations
+import jakarta.validation.constraints.NotNull;
+
 `@Getter`
 `@Setter`
 `@Schema`(description = "구성원 권한 부여 변경 요청 DTO")
 public class MemberPermissionUpsertReqDto {

+    `@NotNull`
     `@Schema`(description = "권한 ID", example = "1")
     private Integer permissionId;

+    `@NotNull`
     `@JsonProperty`("is_enable")
     `@Schema`(description = "권한 활성화 여부", example = "true")
     private Boolean isEnable;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/permission/domain/dto/request/MemberPermissionUpsertReqDto.java`
around lines 12 - 17, Add Bean Validation to the DTO by annotating
MemberPermissionUpsertReqDto's fields that are required: add `@NotNull` to the
permissionId and isEnable fields (retain the existing `@JsonProperty`("is_enable")
on isEnable), and ensure javax.validation.constraints.NotNull is imported; after
this change, make sure any controllers that accept MemberPermissionUpsertReqDto
are validating input (e.g., `@Valid` on the controller parameter) so the
validation takes effect.
src/main/java/com/pooli/common/config/SecurityConfig.java (1)

15-15: CSRF disabled - document the rationale.

CSRF protection is disabled, which is common for stateless REST APIs using token-based authentication. However, if the API will use session-based auth or cookies, CSRF protection should be re-enabled. Consider adding a comment explaining why CSRF is disabled.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/common/config/SecurityConfig.java` at line 15, CSRF
is being explicitly disabled in SecurityConfig via the .csrf(csrf ->
csrf.disable()) call; add a concise comment next to that expression explaining
the rationale (e.g., this is a stateless REST API using token-based auth so CSRF
is unnecessary) and note the conditions under which it must be re-enabled (e.g.,
if session/cookie-based auth is introduced). Ensure the comment references
SecurityConfig and the .csrf(...) line so future reviewers know why CSRF was
turned off and when to revert the change.
src/main/java/com/pooli/family/domain/dto/response/FamilyMembersSimpleResDto.java (1)

15-19: Type consistency with existing family DTOs.

Line 15-19 use Long for lineId/userId, but FamilyMembersResDto (src/main/java/com/pooli/family/domain/dto/response/FamilyMembersResDto.java, lines 28-38) uses Integer. Aligning types across DTOs will prevent client-side parsing inconsistencies.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/family/domain/dto/response/FamilyMembersSimpleResDto.java`
around lines 15 - 19, The DTO FamilyMembersSimpleResDto currently declares
fields lineId and userId as Long; change both to Integer to match the existing
FamilyMembersResDto and ensure type consistency across DTOs (update the field
types in FamilyMembersSimpleResDto and adjust any related
getters/setters/constructors or usages that reference lineId/userId to use
Integer as well, and keep or update the `@Schema` examples to valid Integer
examples if needed).
src/main/java/com/pooli/notification/controller/NotiSendController.java (1)

35-37: Return created resources (or adjust status).

Line 35-37 always return 201 with an empty list. Consider returning the created notifications (or a Location header), or switch to a status that matches the empty body to avoid ambiguous client behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/notification/controller/NotiSendController.java`
around lines 35 - 37, The sendAlarm method in NotiSendController currently
responds with 201 Created and an empty body which is misleading; update
sendAlarm to return the actual created notifications (map service result to
List<NotiSendResDto>) and respond with
ResponseEntity.created(URI).body(createdList) or, if you don’t have a single
resource URI, include a Location header (or return 200/204 to match an empty
body). Locate sendAlarm and the request/response DTOs (NotiSendReqDto,
NotiSendResDto) and either call the notification creation service, map results
into NotiSendResDto and return a 201 with body and Location, or change the
status to 200/204 when intentionally returning no content.
src/main/java/com/pooli/data/domain/dto/request/DataTransferReqDto.java (1)

12-19: Validate required/positive transfer fields.

Line 12-19 accept null/negative values as-is. Consider enforcing non-null and positive checks at the DTO or controller/service validation layer so invalid transfers are rejected early.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/data/domain/dto/request/DataTransferReqDto.java`
around lines 12 - 19, The DTO fields fromLineId, toLineId and amount in
DataTransferReqDto allow null/negative values; add validation annotations to
enforce non-null and positive values (e.g., `@NotNull` on fromLineId and toLineId
and `@NotNull/`@Positive on amount or `@PositiveOrZero` if zero allowed) and ensure
the consuming controller method accepts `@Valid` DataTransferReqDto so validation
is triggered; update any service-level checks if additional business rules (like
fromLineId != toLineId) are required and include descriptive validation
messages.
src/main/java/com/pooli/policy/domain/dto/response/FamilyPolicyChangeResDto.java (1)

18-22: Use a typed timestamp for processedAt.

Line 21-22 define processedAt as String even though the example is ISO-8601. For consistency and type-safety, consider switching to LocalDateTime (or apply a fixed format annotation) to avoid format drift.

♻️ Proposed refactor
-    `@Schema`(description = "처리 시각", example = "2026-02-20T10:10:00")
-    private String processedAt;
+    `@Schema`(description = "처리 시각", example = "2026-02-20T10:10:00")
+    private LocalDateTime processedAt;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/policy/domain/dto/response/FamilyPolicyChangeResDto.java`
around lines 18 - 22, Change the processedAt field in FamilyPolicyChangeResDto
from String to java.time.LocalDateTime and add a Jackson serialization format so
the ISO-8601 example is preserved: update the field type to LocalDateTime (add
import), annotate processedAt with `@JsonFormat`(shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ss") (and keep or adjust the `@Schema` example if
desired) so serialization/deserialization is consistent and type-safe; ensure
necessary imports (java.time.LocalDateTime and
com.fasterxml.jackson.annotation.JsonFormat) are added and update any
constructors/getters/setters or mappers referencing processedAt accordingly.
src/main/java/com/pooli/family/controller/FamilyController.java (1)

42-47: Use Long for familyId/lineId to align with BIGINT IDs.

Integer can overflow or reject valid values once IDs grow. Consider switching to Long here (and mirror the change in /members-simple) for consistency with schema/DTOs.

♻️ Proposed change
-    public ResponseEntity<FamilyMembersResDto> getFamilyMembers(
-            `@Parameter`(description = "가족 ID", example = "1")
-            `@RequestParam` Integer familyId,
-
-            `@Parameter`(description = "회선 ID", example = "10")
-            `@RequestParam` Integer lineId
+    public ResponseEntity<FamilyMembersResDto> getFamilyMembers(
+            `@Parameter`(description = "가족 ID", example = "1")
+            `@RequestParam` Long familyId,
+
+            `@Parameter`(description = "회선 ID", example = "10")
+            `@RequestParam` Long lineId
     ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/family/controller/FamilyController.java` around lines
42 - 47, The request parameters in FamilyController.getFamilyMembers use Integer
for familyId and lineId but your DB and DTOs use BIGINT; change the parameter
types from Integer to Long (for both `@RequestParam` familyId and lineId) to avoid
overflow and type mismatch, and make the same change for the analogous endpoint
(/members-simple) so controller signatures align with your DTOs/entities/DTO
classes that expect Long IDs; update any usages within these methods to use
long/Long accordingly.
src/main/resources/db/migration/V1__init.sql (1)

353-415: Add UNIQUE constraints where “UK” is indicated in comments.

Columns like QUESTION_CATEGORY.question_category_name, LINE.phone, and USERS.email are marked as unique but not enforced, which can allow duplicates.

➕ Example UNIQUE constraints
+ALTER TABLE `QUESTION_CATEGORY`
+    ADD CONSTRAINT `UK_QUESTION_CATEGORY_NAME` UNIQUE (`question_category_name`);
+
+ALTER TABLE `LINE`
+    ADD CONSTRAINT `UK_LINE_PHONE` UNIQUE (`phone`);
+
+ALTER TABLE `USERS`
+    ADD CONSTRAINT `UK_USERS_EMAIL` UNIQUE (`email`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/db/migration/V1__init.sql` around lines 353 - 415, Add
UNIQUE constraints for every column marked "UK" in the migration by adding ALTER
TABLE ... ADD CONSTRAINT UK_<TABLE>_<COLUMN> UNIQUE(<column>) statements;
specifically ensure QUESTION_CATEGORY.question_category_name, LINE.phone, and
USERS.email are made unique (use constraint names like
UK_QUESTION_CATEGORY_question_category_name, UK_LINE_phone, UK_USERS_email) and
add similar UK constraints for any other columns noted as UK in the file so
duplicates cannot be inserted.
src/main/java/com/pooli/line/controller/LineController.java (1)

57-61: Prefer Long for lineId to match DTO/schema types.

Aligning the request param with BIGINT/Long avoids range issues and keeps types consistent across layers.

♻️ Proposed change
-    public ResponseEntity<IndividualThresholdResDto> getIndividualThreshold(
-            `@Parameter`(description = "회선 ID", example = "1")
-            `@RequestParam` Integer lineId
+    public ResponseEntity<IndividualThresholdResDto> getIndividualThreshold(
+            `@Parameter`(description = "회선 ID", example = "1")
+            `@RequestParam` Long lineId
     ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/line/controller/LineController.java` around lines 57
- 61, The request parameter type for lineId in the controller method
getIndividualThreshold should be changed from Integer to Long to match
BIGINT/Long types used in DTOs and schema; update the method signature parameter
(`@RequestParam` Long lineId) and any internal uses or calls (e.g., service method
invocations that accept lineId) to accept Long so types remain consistent with
IndividualThresholdResDto and downstream layers. Ensure any parsing/validation
still works and adjust unit tests or method overloads that referenced Integer
lineId to use Long.

Comment on lines +14 to +24
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs/**")
.permitAll()
.anyRequest()
.permitAll())
.httpBasic(Customizer.withDefaults());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security configuration permits all requests without authentication.

The current configuration allows all requests without authentication (.anyRequest().permitAll()). While this may be intentional for early development/API scaffolding, ensure this is locked down before production deployment. The .httpBasic(Customizer.withDefaults()) has no effect since all requests are already permitted.

Consider adding a TODO or documentation to track this:

// TODO: Restrict endpoints before production deployment
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/common/config/SecurityConfig.java` around lines 14 -
24, SecurityConfig currently permits all requests via the
http.authorizeHttpRequests(...) chain (notably anyRequest().permitAll()),
rendering httpBasic(...) ineffective; update the authorizeHttpRequests
configuration to enforce authentication for non-public endpoints (e.g., change
anyRequest().permitAll() to anyRequest().authenticated() or restrict by roles)
and add a clear TODO comment in SecurityConfig near the
http.authorizeHttpRequests block to remind developers to tighten rules before
production (e.g., reference http, authorizeHttpRequests, anyRequest, httpBasic
to locate the change).

Comment on lines +19 to +67
@Schema(description = "가족 식별자", example = "1")
private Integer familyId;

@Schema(description = "가족 공유풀 총량", example = "10000000")
private Long sharedPoolTotalData;

@Schema(description = "가족 구성원 목록")
private List<FamilyMemberDto> members;


@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Schema(description = "가족 구성원 DTO")
public static class FamilyMemberDto {

@Schema(description = "회원 식별자", example = "100")
private Integer userId;

@Schema(description = "회선 식별자", example = "10")
private Integer lineId;

@Schema(description = "요금제 식별자", example = "3")
private Integer planId;

@Schema(description = "회원 이름", example = "홍길동")
private String userName;

@Schema(description = "전화번호", example = "010-1234-5678")
private String phone;

@Schema(description = "요금제명", example = "5G 프리미엄")
private String planName;

@Schema(description = "기본 제공 데이터 잔량(bite)", example = "5000")
private Long remainingData;

@Schema(description = "기본 제공 데이터량(MB)", example = "10000")
private Long basicDataAmount;

@Schema(description = "가족 역할 (OWNER / MEMBER)", example = "OWNER")
private FamilyRole role;

@Schema(description = "사용 가능한 공유풀 데이터 총량(bite)", example = "120")
private Long sharedPoolTotalAmount;

@Schema(description = "사용 가능한 공유풀 데이터 잔량(bite)", example = "12000")
private Long sharedPoolRemainingAmount;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for identifier types across family/line/user DTOs and entities
rg -n -C2 '\b(Long|Integer)\s+(familyId|lineId|userId|planId)\b' src/main/java/com/pooli -g '*.java'

Repository: pooli-dev/pooli-be

Length of output: 28683


🏁 Script executed:

#!/bin/bash
# Search for Family-related entity definitions to check actual DB types
find src/main/java/com/pooli -name "*.java" -path "*/entity/*" | xargs grep -l "Family\|family" | head -10

Repository: pooli-dev/pooli-be

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Also check for specific identifier definitions in entity classes
rg -n '@Id|@Column|private.*family|private.*user|private.*line|private.*plan' src/main/java/com/pooli/family/domain/entity -A1 -B1

Repository: pooli-dev/pooli-be

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Find all entity files in the family module
find src/main/java/com/pooli/family -name "*.java" -type f

Repository: pooli-dev/pooli-be

Length of output: 993


🏁 Script executed:

#!/bin/bash
# Also search for `@Entity` annotation to find all entity classes
rg -l '@Entity' src/main/java/com/pooli --type java

Repository: pooli-dev/pooli-be

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Check overall directory structure to understand the codebase organization
ls -la src/main/java/com/pooli/

Repository: pooli-dev/pooli-be

Length of output: 814


🏁 Script executed:

#!/bin/bash
# Search more broadly for `@Entity` across the entire codebase
find src -name "*.java" -type f | xargs grep -l "@Entity" | head -20

Repository: pooli-dev/pooli-be

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Let's check if there's an entity directory or package structure
find src -type d -name entity

Repository: pooli-dev/pooli-be

Length of output: 192


🏁 Script executed:

#!/bin/bash
# Search for classes with `@Getter` and `@Entity` patterns that might be entities
rg -n "class.*\{" src/main/java/com/pooli/user/domain -A5 | head -30

Repository: pooli-dev/pooli-be

Length of output: 1346


🏁 Script executed:

#!/bin/bash
# Let's check the User entity we saw earlier
cat -n src/main/java/com/pooli/user/domain/entity/User.java | head -40

Repository: pooli-dev/pooli-be

Length of output: 692


🏁 Script executed:

#!/bin/bash
# Check the Family entity
cat -n src/main/java/com/pooli/family/domain/entity/Family.java 2>/dev/null || echo "Family.java not found"

Repository: pooli-dev/pooli-be

Length of output: 83


🏁 Script executed:

#!/bin/bash
# List all files in family entity directory
ls -la src/main/java/com/pooli/family/domain/entity/

Repository: pooli-dev/pooli-be

Length of output: 227


🏁 Script executed:

#!/bin/bash
# Check Line entity
cat -n src/main/java/com/pooli/line/domain/entity/Line.java 2>/dev/null | head -50

Repository: pooli-dev/pooli-be

Length of output: 44


🏁 Script executed:

#!/bin/bash
# List all files in line entity directory
ls -la src/main/java/com/pooli/line/domain/entity/

Repository: pooli-dev/pooli-be

Length of output: 227


🏁 Script executed:

#!/bin/bash
# Search for any schema or database configuration files
find src -name "*.sql" -o -name "schema.sql" -o -name "*.properties" | head -20

Repository: pooli-dev/pooli-be

Length of output: 186


🏁 Script executed:

#!/bin/bash
# Check if there's any JPA annotation or column type definitions in the DTOs themselves
rg -n "@Column|@GeneratedValue" src/main/java/com/pooli/family/domain/dto -A2

Repository: pooli-dev/pooli-be

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Check the database schema for ID column definitions
cat src/main/resources/db/migration/V1__init.sql | grep -i -E "family|user|line|plan" | head -50

Repository: pooli-dev/pooli-be

Length of output: 1645


🏁 Script executed:

#!/bin/bash
# Look for specific table definitions with their column types
rg -n "CREATE TABLE|INT|BIGINT|family_id|user_id|line_id|plan_id" src/main/resources/db/migration/V1__init.sql

Repository: pooli-dev/pooli-be

Length of output: 10501


Align identifier types to avoid truncation and API inconsistency.

familyId, userId, and lineId are Integer but the database defines them as BIGINT, which risks truncation and client model conflicts. FamilyMembersSimpleResDto correctly uses Long for these fields. Standardize to Long for consistency and to match the actual database schema (note: planId is correctly Integer since the PLAN table uses INT).

🛠️ Proposed alignment
-    private Integer familyId;
+    private Long familyId;
-        private Integer userId;
+        private Long userId;
-        private Integer lineId;
+        private Long lineId;

(Keep planId as Integer as it correctly matches the database INT column)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/family/domain/dto/response/FamilyMembersResDto.java`
around lines 19 - 67, Change the identifier types to match the DB BIGINT
columns: update FamilyMembersResDto.familyId and the nested
FamilyMemberDto.userId and FamilyMemberDto.lineId from Integer to Long (leave
FamilyMemberDto.planId as Integer); ensure getters/builders/annotations remain
valid for the new Long types so the DTO aligns with FamilyMembersSimpleResDto
and avoids truncation/inconsistency.

Comment on lines +12 to +16
@Schema(description = "회선 ID", example = "1")
private Integer lineId;

@Schema(description = "개인 데이터 임계치(MB)", example = "3000")
private Integer individualThreshold;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align threshold type/unit with response DTO.

Line 15-16 use Integer and MB, but IndividualThresholdResDto (src/main/java/com/pooli/line/domain/dto/response/IndividualThresholdResDto.java, lines 5-16) uses Long and “bite” (bytes). This mismatch can lead to incorrect thresholds or client confusion. Please align type + unit on both request/response.

🔧 Example alignment (if MB is the canonical unit)
-    `@Schema`(description = "개인 데이터 임계치(MB)", example = "3000")
-    private Integer individualThreshold;
+    `@Schema`(description = "개인 데이터 임계치(MB)", example = "3000")
+    private Long individualThreshold;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Schema(description = "회선 ID", example = "1")
private Integer lineId;
@Schema(description = "개인 데이터 임계치(MB)", example = "3000")
private Integer individualThreshold;
`@Schema`(description = "회선 ID", example = "1")
private Integer lineId;
`@Schema`(description = "개인 데이터 임계치(MB)", example = "3000")
private Long individualThreshold;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/line/domain/dto/request/UpdateIndividualThresholdReqDto.java`
around lines 12 - 16, The request DTO currently declares individualThreshold as
Integer with unit MB which mismatches IndividualThresholdResDto that uses Long
and bytes; update UpdateIndividualThresholdReqDto by changing the field type
individualThreshold from Integer to Long and adjust the `@Schema`
description/example to indicate bytes (or the same unit/text used in
IndividualThresholdResDto) so both DTOs share the same type and unit semantics
(reference class names: UpdateIndividualThresholdReqDto and
IndividualThresholdResDto).

@Schema(description = "개인 데이터 임계치 조회 응답 DTO")
public class IndividualThresholdResDto {
@Schema(description = "개인 데이터 임계치(bite)", example = "3000")
private Long individualThreshold;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's see all occurrences of individualThreshold with context
rg -n "individualThreshold" --type java -B 2 -A 2

Repository: pooli-dev/pooli-be

Length of output: 1795


🏁 Script executed:

#!/bin/bash
# Find and read the request DTO file
fd "UpdateIndividualThresholdReqDto.java" --type f

Repository: pooli-dev/pooli-be

Length of output: 146


🏁 Script executed:

#!/bin/bash
# Find and read the response DTO file  
fd "IndividualThresholdResDto.java" --type f

Repository: pooli-dev/pooli-be

Length of output: 141


Align type consistency and clarify unit semantics between request and response DTOs.

IndividualThresholdResDto.individualThreshold is typed as Long, but UpdateIndividualThresholdReqDto.individualThreshold is typed as Integer. Additionally, the schema descriptions use different units—the request DTO specifies "MB" while the response DTO specifies "bite"—which compounds the confusion. These inconsistencies suggest either a missing conversion between units or a documentation error. Align both the types and unit semantics to represent the same domain concept consistently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/pooli/line/domain/dto/response/IndividualThresholdResDto.java`
at line 13, The response DTO field IndividualThresholdResDto.individualThreshold
is Long while the request DTO
UpdateIndividualThresholdReqDto.individualThreshold is Integer and their schema
descriptions use different units ("MB" vs "bite"); make both DTOs use the same
numeric type (choose Integer or Long consistently) and update both `@Schema`
descriptions to the same unit (e.g., "MB" or "bytes"); if the domain stores a
different base unit, perform explicit conversion in your mapping layer (the
mapper/converter that maps UpdateIndividualThresholdReqDto ↔
IndividualThresholdResDto) so the DTOs represent the same semantic value.

Comment on lines +20 to +39
@Operation(
summary = "가족 데이터 알림 설정 변경",
description = "가족 데이터 알림 설정의 ON/OFF를 변경한다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "알람 정보가 존재하지 않음"),
@ApiResponse(responseCode = "500", description = "서버 오류"),
})
@PatchMapping("/family-alarm")
public ResponseEntity<AlarmSettingReqDto> updateFamilyAlarm(){

// @AuthenticationPrincipal LoginUser loginUser

AlarmSettingReqDto response = AlarmSettingReqDto.builder()
.familyAlarm(false)
.build();

return ResponseEntity.ok(response);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

PATCH endpoint cannot update state (hardcoded false).
The handler doesn’t accept any input and always returns familyAlarm(false), so clients can’t actually toggle the setting.

🔧 Suggested fix (example)
-@PatchMapping("/family-alarm")
-public ResponseEntity<AlarmSettingReqDto> updateFamilyAlarm(){
+@PatchMapping("/family-alarm")
+public ResponseEntity<AlarmSettingReqDto> updateFamilyAlarm(
+        `@RequestBody` AlarmSettingReqDto request){
 
-    AlarmSettingReqDto response = AlarmSettingReqDto.builder()
-                .familyAlarm(false)
-                .build();
+    AlarmSettingReqDto response = AlarmSettingReqDto.builder()
+                .familyAlarm(request.getFamilyAlarm())
+                .build();
 
     return ResponseEntity.ok(response);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/notification/controller/AlarmSettingController.java`
around lines 20 - 39, The updateFamilyAlarm handler in AlarmSettingController
currently ignores input and always returns
AlarmSettingReqDto.builder().familyAlarm(false), so change updateFamilyAlarm to
accept the desired state and user context (e.g., add parameters like
`@RequestBody` AlarmSettingReqDto request and `@AuthenticationPrincipal` LoginUser
loginUser), call a domain/service method (e.g.,
alarmSettingService.updateFamilyAlarm(loginUser.getId(),
request.isFamilyAlarm())) to persist the change, and return the updated
AlarmSettingReqDto from that service; ensure input validation and appropriate
responses for not-found or error cases instead of the hardcoded false.

Comment on lines +61 to +79
@Operation(
summary = "전체 알림 상태 읽음으로 변경",
description = "사용자가 읽지 않은 알림의 상태를 모두 읽음으로 변경한다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "알람 정보가 존재하지 않음"),
@ApiResponse(responseCode = "500", description = "서버 오류"),
})
@PatchMapping("/read-all")
public ResponseEntity<UnreadCountsResDto> allRead(){
Long lineId = 2L; // 일단 임의로 회선 id 변경함
UnreadCountsResDto response = UnreadCountsResDto.builder()
.lineId(lineId)
.unreadCount(0L)
.build();

return ResponseEntity.ok(response);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hardcoded lineId breaks per-user correctness.
Using a fixed lineId means this endpoint can return or mutate data for the wrong user. Use the authenticated principal or a validated request parameter instead.

🔧 Suggested fix (example)
-@PatchMapping("/read-all")
-public ResponseEntity<UnreadCountsResDto> allRead(){
-    Long lineId = 2L; // 일단 임의로 회선 id 변경함
+@PatchMapping("/read-all")
+public ResponseEntity<UnreadCountsResDto> allRead(
+        `@RequestParam` Long lineId){
     UnreadCountsResDto response = UnreadCountsResDto.builder()
                 .lineId(lineId)
                 .unreadCount(0L)
                 .build();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Operation(
summary = "전체 알림 상태 읽음으로 변경",
description = "사용자가 읽지 않은 알림의 상태를 모두 읽음으로 변경한다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "알람 정보가 존재하지 않음"),
@ApiResponse(responseCode = "500", description = "서버 오류"),
})
@PatchMapping("/read-all")
public ResponseEntity<UnreadCountsResDto> allRead(){
Long lineId = 2L; // 일단 임의로 회선 id 변경함
UnreadCountsResDto response = UnreadCountsResDto.builder()
.lineId(lineId)
.unreadCount(0L)
.build();
return ResponseEntity.ok(response);
}
`@Operation`(
summary = "전체 알림 상태 읽음으로 변경",
description = "사용자가 읽지 않은 알림의 상태를 모두 읽음으로 변경한다."
)
`@ApiResponses`({
`@ApiResponse`(responseCode = "200", description = "조회 성공"),
`@ApiResponse`(responseCode = "404", description = "알람 정보가 존재하지 않음"),
`@ApiResponse`(responseCode = "500", description = "서버 오류"),
})
`@PatchMapping`("/read-all")
public ResponseEntity<UnreadCountsResDto> allRead(
`@RequestParam` Long lineId){
UnreadCountsResDto response = UnreadCountsResDto.builder()
.lineId(lineId)
.unreadCount(0L)
.build();
return ResponseEntity.ok(response);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/notification/controller/NotiReadController.java`
around lines 61 - 79, The allRead() method in NotiReadController currently uses
a hardcoded Long lineId = 2L which breaks per-user behavior; replace this by
extracting the authenticated user or a validated request parameter and using
that to determine lineId, call the service (e.g., NotiReadService.markAllRead or
a similar method) to perform the update and retrieve the actual unread count,
then build UnreadCountsResDto with the real lineId and unreadCount instead of
the hardcoded values; remove the hardcoded lineId, validate authorization, and
ensure the method signature accepts either `@AuthenticationPrincipal` / Principal
or a `@RequestParam/`@PathVariable as appropriate.

Comment on lines +222 to +247
@Operation(
summary = "특정 구성원 정책 정보 수정",
description = "사용자 권한 필요. 앱 정책 PK 기준으로 1건만 수정하고 PK와 값을 응답합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "요청 성공"),
@ApiResponse(responseCode = "404", description = "리소스를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
@PatchMapping("/policies/lines/apps")
public ResponseEntity<AppPolicyResDto> updateAppPolicy(
@Parameter(description = "회선 식별자", example = "101")
@RequestParam Long lineId,
@Parameter(description = "앱 정책 PK", example = "7301")
@RequestParam Long appPolicyId,
@RequestBody AppPolicyUpdateReqDto request
) {
AppPolicyResDto response = AppPolicyResDto.builder()
.appPolicyId(appPolicyId)
.appId(resolveAppId(appPolicyId))
.appName(resolveAppName(appPolicyId))
.enabled(request.getEnabled() != null ? request.getEnabled() : Boolean.FALSE)
.dailyLimitMb(request.getDailyLimitMb() != null ? request.getDailyLimitMb() : 0)
.build();
return ResponseEntity.ok(response);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Unknown appPolicyId is silently mapped to 0/Unknown.
Returning 0/Unknown hides invalid input and can mislead clients. Prefer a 404/400 response when the ID isn’t recognized.

🔧 Suggested fix (example)
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.http.HttpStatus;
...
     private Long resolveAppId(Long appPolicyId) {
         if (Long.valueOf(7301L).equals(appPolicyId)) {
             return 301L;
         }
         if (Long.valueOf(7302L).equals(appPolicyId)) {
             return 302L;
         }
         if (Long.valueOf(7303L).equals(appPolicyId)) {
             return 401L;
         }
-        return 0L;
+        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Unknown appPolicyId");
     }

     private String resolveAppName(Long appPolicyId) {
         if (Long.valueOf(7301L).equals(appPolicyId)) {
             return "YouTube";
         }
         if (Long.valueOf(7302L).equals(appPolicyId)) {
             return "Instagram";
         }
         if (Long.valueOf(7303L).equals(appPolicyId)) {
             return "GameX";
         }
-        return "Unknown";
+        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Unknown appPolicyId");
     }

Also applies to: 368-392

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/policy/controller/UserPolicyController.java` around
lines 222 - 247, The updateAppPolicy method currently maps unknown appPolicyId
to 0/"Unknown" via resolveAppId/resolveAppName which hides invalid input; change
updateAppPolicy (and the analogous handler around lines 368-392) to validate the
appPolicyId up front by querying the domain/service (e.g.,
AppPolicyService.findById(appPolicyId)) or checking whether
resolveAppId/resolveAppName return a real value, and if not return a 404
(ResponseEntity.notFound() or throw new
ResponseStatusException(HttpStatus.NOT_FOUND, "...")) or a 400 for bad IDs; only
build and return AppPolicyResDto when the policy exists, and include a clear
error message referencing appPolicyId in the response/exception.

Comment on lines +31 to +44
@Operation(
summary = "문의사항 생성 요청",
description = "새로운 문의사항을 생성한다"
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "문의사항 생성 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청"),
@ApiResponse(responseCode = "500", description = "서버 오류"),

})
@PostMapping
public ResponseEntity<List<QuestionCreateReqDto>> createQuestion(@RequestBody QuestionCreateReqDto request) {
return ResponseEntity.status(HttpStatus.CREATED).body(List.of());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Create endpoint returns request DTO list + empty body.
POST /api/questions should return a created resource or no body, not a list of request DTOs.

🔧 Suggested fix (minimal)
-@PostMapping
-public ResponseEntity<List<QuestionCreateReqDto>> createQuestion(`@RequestBody` QuestionCreateReqDto request) {
-    return ResponseEntity.status(HttpStatus.CREATED).body(List.of());
-}
+@PostMapping
+public ResponseEntity<Void> createQuestion(`@RequestBody` QuestionCreateReqDto request) {
+    return ResponseEntity.status(HttpStatus.CREATED).build();
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Operation(
summary = "문의사항 생성 요청",
description = "새로운 문의사항을 생성한다"
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "문의사항 생성 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청"),
@ApiResponse(responseCode = "500", description = "서버 오류"),
})
@PostMapping
public ResponseEntity<List<QuestionCreateReqDto>> createQuestion(@RequestBody QuestionCreateReqDto request) {
return ResponseEntity.status(HttpStatus.CREATED).body(List.of());
}
`@Operation`(
summary = "문의사항 생성 요청",
description = "새로운 문의사항을 생성한다"
)
`@ApiResponses`({
`@ApiResponse`(responseCode = "201", description = "문의사항 생성 성공"),
`@ApiResponse`(responseCode = "400", description = "잘못된 요청"),
`@ApiResponse`(responseCode = "500", description = "서버 오류"),
})
`@PostMapping`
public ResponseEntity<Void> createQuestion(`@RequestBody` QuestionCreateReqDto request) {
return ResponseEntity.status(HttpStatus.CREATED).build();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/question/controller/QuestionController.java` around
lines 31 - 44, The createQuestion method currently returns a
List<QuestionCreateReqDto> and an empty list body; change the contract to either
return the created resource (e.g., a QuestionResponse DTO) or no body. Minimal
fix: update the method signature of createQuestion to return
ResponseEntity<Void> (replace List<QuestionCreateReqDto>), and return
ResponseEntity.status(HttpStatus.CREATED).build(); alternatively, if you want to
return the created resource, create a QuestionResponse DTO, return
ResponseEntity.created(location).body(createdDto) using createQuestion and
QuestionCreateReqDto to build the response and set the Location header (via
ServletUriComponentsBuilder or similar).

private Long userId;
private String userName;
private String email;
private String password;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security concern: Password field handling.

Storing password as a plain String field with a Lombok @Getter exposes it to accidental serialization (e.g., JSON responses, logs). Consider:

  1. Hash the password before storing (use BCrypt or Argon2 via Spring Security's PasswordEncoder).
  2. Exclude from serialization by adding @JsonIgnore or @ToString.Exclude to prevent accidental exposure.
  3. Alternatively, consider removing password from the domain entity and handling credentials in a separate, security-focused class.
🛡️ Suggested annotation to reduce exposure risk
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.ToString;
+
 `@Getter`
 `@Builder`
+@ToString(exclude = "password")
 `@AllArgsConstructor`(access = AccessLevel.PRIVATE)
 `@NoArgsConstructor`(access = AccessLevel.PROTECTED)
 public class User {

     private Long userId;
     private String userName;
     private String email;
+    `@JsonIgnore`
     private String password;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/pooli/user/domain/entity/User.java` at line 16, The User
entity currently declares a plain String password field (private String
password) which is exposed via Lombok-generated accessors; update the handling
by (1) marking the field to be excluded from accidental
serialization/diagnostics (add annotations such as `@JsonIgnore` and
`@ToString.Exclude` on the password field in User) and (2) ensure passwords are
stored hashed by hashing input before setting the field (use a PasswordEncoder
from Spring Security when creating/updating users, e.g., call
encoder.encode(rawPassword) in the service that sets User::setPassword) or move
credentials into a dedicated credential/DTO class instead of the domain entity.

Comment on lines +199 to +209
DROP TABLE IF EXISTS `ALRAM_HISTORY`;

CREATE TABLE `ALRAM_HISTORY` (
`alarm_history_id` BIGINT NOT NULL,
`user_id` BIGINT NOT NULL,
`alarm_code` ENUM('LIMIT','POLICY', 'PERMISSION','QUESTION') NOT NULL COMMENT 'enum',
`value` TEXT NULL COMMENT 'json',
`created_at` TIMESTAMP NOT NULL,
`deleted_at` TIMESTAMP NULL,
`read_at` TIMESTAMP NULL
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix typo ALRAM_HISTORYALARM_HISTORY to avoid mismatched table names.

The typo propagates to PK/FK names and can break ORM mappings or queries expecting ALARM_HISTORY.

🛠️ Proposed fix
-DROP TABLE IF EXISTS `ALRAM_HISTORY`;
+DROP TABLE IF EXISTS `ALARM_HISTORY`;

-CREATE TABLE `ALRAM_HISTORY` (
+CREATE TABLE `ALARM_HISTORY` (
     `alarm_history_id` BIGINT NOT NULL,
     `user_id` BIGINT NOT NULL,
     `alarm_code` ENUM('LIMIT','POLICY', 'PERMISSION','QUESTION') NOT NULL COMMENT 'enum',
     `value` TEXT NULL COMMENT 'json',
     `created_at` TIMESTAMP NOT NULL,
     `deleted_at` TIMESTAMP NULL,
     `read_at` TIMESTAMP NULL
 );
 
-ALTER TABLE `ALRAM_HISTORY` ADD CONSTRAINT `PK_ALRAM_HISTORY` PRIMARY KEY (
+ALTER TABLE `ALARM_HISTORY` ADD CONSTRAINT `PK_ALARM_HISTORY` PRIMARY KEY (
     `alarm_history_id`
 );
 
-ALTER TABLE `ALRAM_HISTORY` ADD CONSTRAINT `FK_USERS_TO_ALRAM_HISTORY_1` FOREIGN KEY (
+ALTER TABLE `ALARM_HISTORY` ADD CONSTRAINT `FK_USERS_TO_ALARM_HISTORY_1` FOREIGN KEY (
     `user_id`
 )
-REFERENCES `USERS` (
+REFERENCES `USERS` (
     `user_id`
 );

Also applies to: 422-608

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/db/migration/V1__init.sql` around lines 199 - 209, Rename
the misspelled table and all related identifiers from ALRAM_HISTORY to
ALARM_HISTORY in this migration: update the DROP TABLE and CREATE TABLE
statements to use ALARM_HISTORY, ensure the primary key/constraint and any index
names reference ALARM_HISTORY (and the column alarm_history_id remains
unchanged), and update any FK definitions or references elsewhere in this file
(including the regions noted around lines 422-608) that point to ALRAM_HISTORY
so they point to ALARM_HISTORY instead.

@ms-0o0 ms-0o0 changed the base branch from main to feat/180-domain February 23, 2026 06:44
Copy link
Copy Markdown
Contributor

@Misu0616 Misu0616 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

erd 기반 확인 완료

@Misu0616 Misu0616 merged commit 6750531 into feat/180-domain Feb 23, 2026
1 check passed
@ms-0o0 ms-0o0 deleted the feat/180-domain-user-minsu branch February 23, 2026 08:06
@coderabbitai coderabbitai Bot mentioned this pull request Mar 4, 2026
13 tasks
This was referenced Mar 11, 2026
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature 새 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants