Updated: 2026-01-19
Files:
src/main/kotlin/com/tistory/shanepark/dutypark/member/repository/MemberRepository.ktsrc/main/kotlin/com/tistory/shanepark/dutypark/member/repository/FriendRelationRepository.ktsrc/main/kotlin/com/tistory/shanepark/dutypark/duty/repository/DutyRepository.ktsrc/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.ktsrc/main/kotlin/com/tistory/shanepark/dutypark/duty/service/DutyService.kt
Problem: getOtherDuties() performs individual queries for each friend, causing N+1 pattern and poor performance when user has many friends.
Impact: Dashboard load time scales linearly with friend count. Users with 10+ friends experience noticeable delay.
Recommendation:
-
MemberRepository.kt: Add batch member lookup with team using@EntityGraph -
FriendRelationRepository.kt: Add method to query relations for memberId + multiple friendIds -
DutyRepository.kt: Add batch duty query for multiple members + date range with@EntityGraph -
FriendService.kt: Add batch visibility filter method forgetOtherDuties() -
DutyService.kt: RefactorgetOtherDuties()to use batch loading while preserving visibility rules and lazy init
File: src/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.kt
Problem: FriendService (345 lines) contains mixed responsibilities: friend relationship management and friend request handling with significant code duplication.
Impact: Hard to test, harder to maintain. Request-related logic is tangled with relationship queries.
Recommendation:
- Extract
FriendRequestServicewith:sendRequest(),acceptRequest(),rejectRequest(),cancelRequest(),getPendingRequests() - Keep
FriendServicefocused on:findAllFriends(),searchPossibleFriends(), visibility checks
Files:
src/main/kotlin/com/tistory/shanepark/dutypark/duty/controller/DutyBatchController.ktsrc/main/kotlin/com/tistory/shanepark/dutypark/team/controller/TeamManageController.kt
Problem: Duty batch import logic is duplicated between controllers. Both handle Excel parsing, validation, and batch creation.
Impact: Bug fixes must be applied in two places. Risk of behavior divergence.
Recommendation:
- Create
DutyBatchServiceFactoryto centralize batch import logic - Share validation rules and error handling between both controllers
File: frontend/src/types/index.ts
Problem: DutyType, Friend, DDay types are defined locally in multiple views instead of using shared types.
Affected Files:
DayDetailModal.vue(lines 29-56): Local Schedule, DutyTypeScheduleViewModal.vue(lines 19-50): Local Schedule, DutyTypeTodoDetailModal.vue(lines 27-36): Local TodoTodoOverviewModal.vue(lines 24-43): Local Todo, attachment
Impact: Type drift between components. Changes must be made in multiple places.
Recommendation:
- Remove local interface definitions from modal components
- Import all types from
@/types/index.ts - Add any missing types to shared types file
Problem: WEEK_DAYS_KO array and formatTime() logic are duplicated across components.
Recommendation:
- Create
frontend/src/utils/date.ts - Export
WEEK_DAYS_KO: ['일', '월', '화', '수', '목', '금', '토'] - Export
formatTime(hour: number, minute: number): string
Problem: size: 10 or size: 20 hardcoded across 6+ API files.
| File | Line | Value |
|---|---|---|
src/api/schedule.ts |
115 | size: 10 |
src/api/admin.ts |
32, 50 | size: 10 |
src/api/team.ts |
147 | size: 10 |
src/api/member.ts |
110 | size: 10 |
src/api/notification.ts |
8 | size: 20 |
Recommendation:
- Create
frontend/src/constants/pagination.ts - Export
SEARCH_SIZE = 10,NOTIFICATIONS_SIZE = 20,ADMIN_PAGE_SIZE = 10 - Update all API modules to use constants
Problem: makeSchedule() defined in 2 separate test files with different implementations:
ScheduleServiceIntegrationTest.kt(line 742) - UsesscheduleService.createSchedule()ScheduleTimeParsingQueueManagerTest.kt(line 73) - Creates Schedule directly
Impact: Inconsistent test setup. Harder to maintain factory methods.
Recommendation:
- Create
src/test/kotlin/com/tistory/shanepark/dutypark/TestFixtures.kt - Extract
makeSchedule(),makeMember(),makeTeam(),makeDuty()factories - Standardize on consistent factory patterns
Problem: Fixed dates/times repeated across test files.
Recommendation:
- Create
src/test/kotlin/com/tistory/shanepark/dutypark/TestConstants.kt - Export
FIXED_DATE = LocalDate.of(2025, 1, 15) - Export
FIXED_DATE_TIME = LocalDateTime.of(2025, 1, 15, 10, 0) - Export
FAR_FUTURE_DATE = LocalDate.of(2099, 12, 31)
Problem: Mixed usage of:
.orElseThrow()(no message) - 116 instances.orElseThrow { exception }(with message)
Files:
SchedulePermissionService.kt(lines 31, 36)FriendService.kt(12+ instances)ScheduleService.kt(8+ instances)AttachmentService.kt(lines 98, 116 - inconsistent within same file)MemberService.kt(10+ instances)
Impact: Generic NoSuchElementException without context makes debugging difficult.
Recommendation: Create utility extension and standardize exception types:
fun <T> Optional<T>.orThrow(errorMessage: String): T =
orElseThrow { IllegalArgumentException(errorMessage) }File: src/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.kt
Lines: 235-244
Problem: searchPossibleFriends() loads ALL friends and pending requests into memory, then filters:
val friends = findAllFriends(login).map { it.id } // Loads ALL friends
val pendingRequestsFrom = getPendingRequestsFrom(member).map { it.toMember.id } // Loads ALL pending
val excludeIds = friends + pendingRequestsFrom + member.idImpact: Memory and performance issues scale with user's social graph size.
Recommendation: Replace with repository query using JPA subqueries for pagination efficiency.
| Service | Lines | Status | Recommendation |
|---|---|---|---|
AttachmentService.kt |
454 | Extract AttachmentSessionService, AttachmentFileService |
|
FriendService.kt |
345 | MEDIUM | Extract FriendRequestService |
TodoService.kt |
313 | ACCEPTABLE | Current structure is reasonable |
Status: ✅ RESOLVED - Queries are properly optimized with JOIN FETCH and @EntityGraph:
ScheduleRepository.kt: UsesJOIN FETCHfor member, tags, and tag.memberFriendRelationRepository.kt: Uses@EntityGraphfor friend and friend.team
File: FriendRelationRepository.kt (line 13)
Problem: findByMemberAndFriend() lacks @EntityGraph, may cause lazy loading issues.
Recommendation: Add @EntityGraph(attributePaths = ["friend", "friend.team"]).
File: FriendService.kt (line 247)
Problem: loginMemberToMember() called 12+ times in same service, each querying DB.
Recommendation: Cache result or pass as parameter.
Problem: Multiple components define local Schedule, Duty, Todo interfaces instead of using @/types.
| File | Local Interfaces | Should Use |
|---|---|---|
DayDetailModal.vue (lines 29-56) |
Schedule, DutyType | @/types |
ScheduleViewModal.vue (lines 19-50) |
Schedule, DutyType | @/types |
TodoDetailModal.vue (lines 27-36) |
Todo | @/types |
TodoOverviewModal.vue (lines 24-43) |
Todo, attachment | @/types |
Recommendation: Remove local definitions and import from @/types/index.ts.
| Component | Lines | Severity | Recommendation |
|---|---|---|---|
DutyView.vue |
2,168 | CRITICAL | Extract: DutyCalendar, DutyToolbar, TodoSection, DDaySection |
DayDetailModal.vue |
993 | LARGE | Split read-only view from create/edit form |
TodoDetailModal.vue |
529 | ACCEPTABLE | Within reasonable bounds |
File: src/types/index.ts
Problem: Confusing naming across attachment types:
Attachment(lines 71-75): Minimal propertiesAttachmentDto(lines 80-92): Full backend DTONormalizedAttachment(lines 106-120): UI representation
Recommendation: Rename for clarity:
export interface ScheduleAttachmentSummary { ... } // Simple reference
export interface AttachmentDto { ... } // Backend DTO
export interface NormalizedAttachment { ... } // UI-readyProblem: size: 10 or size: 20 scattered across API files.
| File | Line | Value |
|---|---|---|
src/api/schedule.ts |
115 | size: 10 |
src/api/admin.ts |
32, 50 | size: 10 |
src/api/team.ts |
147 | size: 10 |
src/api/member.ts |
110 | size: 10 |
src/api/notification.ts |
8 | size: 20 |
Recommendation: Create src/config/pagination.ts:
export const PAGINATION_DEFAULTS = {
SEARCH_SIZE: 10,
NOTIFICATIONS_SIZE: 20,
ADMIN_PAGE_SIZE: 10,
}Status: Partially centralized via Pinia stores, but still scattered in DutyView.vue.
Centralized (Good):
auth.tsstore: User data, impersonationtheme.tsstore: Theme preference
Scattered (Needs Refactoring):
DutyView.vue: Todo filter settings, D-Day selection, session highlighting
Recommendation: Create src/composables/useLocalStorage.ts for unified storage access.
Problem: Three different export patterns in use:
| Pattern | Files | Example |
|---|---|---|
| Named export only | schedule, notification, auth, todo, duty, etc. | export const scheduleApi = { ... } |
| Named + default export | admin, team | export const adminApi = { ... }; export default adminApi |
| Multiple named + default | member | Multiple exports + default object |
Recommendation: Standardize to named exports only.
File: build.gradle.kts (line 27)
Problem: Using springAiVersion = "2.0.0-M1" (pre-release milestone)
Risk: Milestone versions may have breaking changes and are not production-ready.
Recommendation: Upgrade to stable 1.x release or wait for 2.0.0 GA.
File: src/main/resources/application.yml (line 29)
Problem: Documentation (CLAUDE.md) states "Gemini 2.0 Flash Lite" but code uses gemma-4-31b-it.
Recommendation: Update documentation or configuration to be consistent.
File: src/main/resources/application.yml (lines 23-31)
Problem:
spring:
ai:
openai: # Misleading namespace name
api-key: "${GEMINI_API_KEY:EMPTY}"
chat:
base-url: "https://generativelanguage.googleapis.com/v1beta/openai/"Impact: Confusing configuration; uses OpenAI-compatible protocol for Gemini.
Recommendation: Add clarifying comments explaining the OpenAI-compatible endpoint pattern.
Status: ✅ CORRECTLY CONFIGURED
File: build.gradle.kts (line 50)
io.netty:netty-resolver-dns-native-macos:4.1.93.Final:osx-aarch_64 is properly configured for Apple Silicon development.
File: frontend/package.json
@types/node: Check for latest version
npm update @types/nodeControllers without tests:
DutyBatchControllerTeamScheduleController
Note: Test coverage significantly improved - 22 of 24 controllers now have tests.
Status: ✅ RESOLVED - All test files now use fixed dates instead of LocalDateTime.now().
Fixed files: All 18+ test files updated to use:
- Fixed date constants (
fixedDate,fixedDateTime) - Far future/past dates for time comparison tests (e.g.,
2099-12-31for "always after now") - Current date only where the service explicitly requires it (e.g., Dashboard endpoint returns "today's" data)
Exceptions (intentionally use current date):
DashboardControllerTest.kt: Dashboard endpoint returns data for "today" internallyCalendarDayServiceTest.kt: DDayDto calculatesdaysLeftusingLocalDate.now()internallyAuthServiceTest.kt: Token validity checked against current time
Problem: makeSchedule() defined in 2 separate test files with different implementations:
ScheduleServiceIntegrationTest.kt(line 742) - UsesscheduleService.createSchedule()ScheduleTimeParsingQueueManagerTest.kt(line 73) - Creates Schedule directly
Recommendation: Extract to shared TestFixtures.kt.
Current: TestUtils.kt exists but only provides jsr310JsonMapper() helper.
Missing:
- Entity factory methods (makeSchedule, makeMember, etc.)
- Fixture builders
- Test constants
Recommendation: Expand TestUtils.kt or create separate TestFixtures.kt:
src/test/kotlin/.../util/
├── TestFixtures.kt (factory methods)
├── TestClock.kt (fixed clock provider)
└── AssertionHelpers.kt
- Spring AI stable version migration
- Fix documentation/config mismatch for AI model
- Batch dashboard schedule loading (5 repository/service changes)
- FriendRequest service extraction
- DutyBatchServiceFactory extraction
-
Extract(DONE)TodoService.toTodoResponse()helper -
Split(DONE)AttachmentService.finalizeSession()into helper methods -
Remove duplicate file deletion logic in(DONE)AttachmentService -
Resolve N+1 query patterns(DONE - properly optimized)
- Consolidate frontend types in
types/index.ts - Remove duplicate local interfaces from modals
- Create date utilities (
WEEK_DAYS_KO,formatTime()) - Pagination constants extraction
- Fix
FriendService.searchPossibleFriends()performance - Extract test fixtures and constants
- Split large components (
DutyView.vue- 2,168 lines) - Split
AttachmentServiceinto focused services - Add missing controller tests (DutyBatchController, TeamScheduleController)
- Standardize error handling patterns (116 instances)
- Extract frontend constants and storage utilities
- Standardize API client export patterns
| Area | HIGH | MEDIUM | LOW | RESOLVED |
|---|---|---|---|---|
| Backend | 2 | 4 | 0 | 1 |
| Frontend | 3 | 3 | 0 | 0 |
| Config | 2 | 1 | 1 | 1 |
| Tests | 1 | 2 | 0 | 1 |
| Total | 8 | 10 | 1 | 3 |
- Dashboard Schedule Loading: Refactored to batch loading for improved performance
- Team Manage / Day Detail UI: Split into focused components
- Time-Dependent Tests: Fixed all 18+ test files that used
LocalDateTime.now()orLocalDate.now()directly- Replaced with fixed date constants (
fixedDate = LocalDate.of(2025, 1, 15)) - Used far future/past dates for time comparison tests
- Documented exceptions where current date is intentionally required (Dashboard, DDayDto, token validity)
- Replaced with fixed date constants (
- TodoService: Extracted
toResponse()helper method, eliminating 52 lines of duplication - AttachmentService:
- Extracted
moveAttachmentToFinalLocation(),updateAttachmentOrdering(),deleteTempAttachment()helpers finalizeSession()reduced from 125 lines to 71 linesdiscardSession()now reusesdeleteAttachment()method
- Extracted
- N+1 Query Patterns: Verified resolved - queries properly use
JOIN FETCHand@EntityGraph - macOS Netty Dependency: Verified correctly configured for Apple Silicon
- REST Docs coverage improved to 22/24 controllers documented
- Unit + integration test variants added for major services (Friend, Duty, Team, Member, Schedule)
- Total service test files: 36 (excellent coverage)