-
Notifications
You must be signed in to change notification settings - Fork 0
✨ Feature: rud prompt #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,8 @@ package simplerag.ragback.domain.prompt.controller | |
| import jakarta.validation.Valid | ||
| import org.springframework.http.HttpStatus | ||
| import org.springframework.web.bind.annotation.* | ||
| import simplerag.ragback.domain.prompt.dto.PromptCreateRequest | ||
| import simplerag.ragback.domain.prompt.dto.PromptPreviewResponse | ||
| import simplerag.ragback.domain.index.dto.IndexUpdateRequest | ||
| import simplerag.ragback.domain.prompt.dto.* | ||
| import simplerag.ragback.domain.prompt.service.PromptService | ||
| import simplerag.ragback.global.response.ApiResponse | ||
|
|
||
|
|
@@ -23,4 +23,38 @@ class PromptController( | |
| return ApiResponse.ok(savedPrompt) | ||
| } | ||
|
|
||
| @GetMapping("/{promptId}") | ||
| fun getPrompt( | ||
| @PathVariable promptId: Long, | ||
| ): ApiResponse<PromptDetailResponse> { | ||
| val promptDetail = promptService.getPrompt(promptId) | ||
| return ApiResponse.ok(promptDetail) | ||
| } | ||
|
|
||
| @GetMapping | ||
| fun getPrompts( | ||
| @RequestParam cursor: Long, | ||
| @RequestParam take: Int, | ||
| ): ApiResponse<PromptPreviewResponseList> { | ||
| val promptPreviewResponseList = promptService.getPrompts(cursor, take) | ||
| return ApiResponse.ok(promptPreviewResponseList) | ||
| } | ||
|
|
||
| @PutMapping("/{promptId}") | ||
| fun updatePrompt( | ||
| @RequestBody @Valid promptUpdateRequest: PromptUpdateRequest, | ||
| @PathVariable promptId: Long, | ||
| ): ApiResponse<PromptPreviewResponse> { | ||
| val updatedPrompt = promptService.updatePrompt(promptUpdateRequest, promptId) | ||
| return ApiResponse.ok(updatedPrompt) | ||
| } | ||
|
Comment on lines
+43
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Confirm update rules for non-CUSTOM presets and test them Ensure the service/domain layer:
Add integration tests covering:
I can generate test scaffolding for these scenarios if helpful. |
||
|
|
||
| @DeleteMapping("/{promptId}") | ||
| fun deletePrompt( | ||
| @PathVariable promptId: Long, | ||
| ): ApiResponse<Unit> { | ||
| promptService.deletePrompt(promptId) | ||
| return ApiResponse.ok(null, "프롬프트가 삭제되었습니다.") | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,5 +9,13 @@ data class PromptCreateRequest( | |
| val name: String, | ||
| val preSet: PreSet, | ||
| @field:Size(max = 20000) | ||
| val systemPrompt: String, | ||
| val systemPrompt: String?, | ||
| ) | ||
|
|
||
| data class PromptUpdateRequest( | ||
| @field:Size(max = 100) | ||
| val name: String, | ||
| val preSet: PreSet, | ||
| @field:Size(max = 20000) | ||
| val systemPrompt: String?, | ||
| ) | ||
|
Comment on lines
+15
to
21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainHarden request validation and keep DB length aligned
Apply this diff to enforce non-blank names on update: - @field:Size(max = 100)
- val name: String,
+ @field:NotBlank
+ @field:Size(max = 100)
+ val name: String,Add the missing import (outside the selected range): import jakarta.validation.constraints.NotBlankVerify DB mapping length matches: Also consider applying @notblank to PromptCreateRequest.name for parity with update. 🏁 Script executed: #!/bin/bash
# Find the Prompt entity and check 'systemPrompt' column length mapping
rg -nP --type=kt -C3 '\bclass\s+Prompt\b|@Column|\bsystemPrompt\b' src/main/kotlinLength of output: 111 I’ll re-run the validation search with a glob-based grep to catch all Kotlin files: This will confirm whether the DB column mapping for 🏁 Script executed: #!/bin/bash
# Search for Prompt entity definition
rg -n -C3 -g '*.kt' 'class Prompt' src/main/kotlin
# Look for the systemPrompt field in Prompt
rg -n -C3 -g '*.kt' 'systemPrompt' src/main/kotlin
# Check any @Column annotations specifying length
rg -n -C3 -g '*.kt' '@Column.*length' src/main/kotlinLength of output: 18126 Enforce non-blank names on both create/update and clarify systemPrompt storage
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,15 +1,49 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package simplerag.ragback.domain.prompt.dto | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.entity.Prompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.entity.enums.PreSet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data class PromptPreviewResponseList( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val promptPreviewResponseList: List<PromptPreviewResponse>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val cursor: Long?, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val hasNext: Boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun from(prompts: List<Prompt>, cursor: Long?, hasNext: Boolean): PromptPreviewResponseList = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PromptPreviewResponseList( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptPreviewResponseList = prompts.map { prompt -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PromptPreviewResponse.from(prompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor = cursor, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hasNext = hasNext, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+6
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Prefer explicit nextCursor naming and simpler list field; also simplify mapping. "cursor" here represents the next cursor the client should use, not the current one. Rename it to nextCursor to avoid API ambiguity. Also, "promptPreviewResponseList" is verbose—"items" reads better. Lastly, the mapping can be simplified. This is an API surface change; confirm consumers before applying. data class PromptPreviewResponseList(
- val promptPreviewResponseList: List<PromptPreviewResponse>,
- val cursor: Long?,
+ val items: List<PromptPreviewResponse>,
+ val nextCursor: Long?,
val hasNext: Boolean
) {
companion object {
- fun from(prompts: List<Prompt>, cursor: Long?, hasNext: Boolean): PromptPreviewResponseList =
+ fun from(prompts: List<Prompt>, nextCursor: Long?, hasNext: Boolean): PromptPreviewResponseList =
PromptPreviewResponseList(
- promptPreviewResponseList = prompts.map { prompt ->
- PromptPreviewResponse.from(prompt)
- },
- cursor = cursor,
+ items = prompts.map(PromptPreviewResponse::from),
+ nextCursor = nextCursor,
hasNext = hasNext,
)
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data class PromptPreviewResponse( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val id: Long, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val name: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun from( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prompt: Prompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): PromptPreviewResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptPreviewResponse(prompt.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptPreviewResponse(prompt.id, prompt.name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
23
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Use expression body for compact mapping. Minor readability nit: expression body is concise and idiomatic. companion object {
- fun from(
- prompt: Prompt
- ): PromptPreviewResponse {
- return PromptPreviewResponse(prompt.id, prompt.name)
- }
+ fun from(prompt: Prompt): PromptPreviewResponse =
+ PromptPreviewResponse(prompt.id, prompt.name)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data class PromptDetailResponse( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val id: Long, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val name: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val preSet: PreSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val systemPrompt: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun from( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prompt: Prompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): PromptDetailResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptDetailResponse(prompt.id, prompt.name, prompt.preSet, prompt.systemPrompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,48 +3,67 @@ package simplerag.ragback.domain.prompt.entity | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.entity.enums.PreSet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.persistence.* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.dto.PromptCreateRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.dto.PromptUpdateRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.global.entity.BaseEntity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.global.error.ErrorCode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.global.error.PromptException | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Entity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Table(name = "prompts") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class Prompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Column(name = "name", length = 100, nullable = false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val name: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var name: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Enumerated(EnumType.STRING) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Column(name = "pre_set", nullable = false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val preSet: PreSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var preSet: PreSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Column(name = "system_prompt", nullable = false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Lob | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val systemPrompt: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var systemPrompt: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) : BaseEntity() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Column(name = "prompts_id") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val id: Long = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun from( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest: PromptCreateRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Prompt { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val prompt = if (promptCreateRequest.preSet == PreSet.CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Prompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.preSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.systemPrompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Prompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun from(promptCreateRequest: PromptCreateRequest): Prompt = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when (promptCreateRequest.preSet) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PreSet.CUSTOM -> Prompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.preSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.preSet.defaultSystemPrompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.systemPrompt ?: "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!promptCreateRequest.systemPrompt.isNullOrBlank()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw PromptException(ErrorCode.CUSTOM_SYSTEM_PROMPT) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Prompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.preSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptCreateRequest.preSet.defaultSystemPrompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+32
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) DRY the preset rules between create and update. The same conditional rules appear in both from(...) and update(...). Extract a shared helper to reduce duplication and future drift. If you want, I can open a follow-up PR to apply this refactor across service/controller tests. Example helper (outside the shown ranges): // Inside Prompt (private) or companion
private fun resolveSystemPrompt(preSet: PreSet, candidate: String?): String {
if (preSet == PreSet.CUSTOM) return candidate?.trim().orEmpty()
if (!candidate.isNullOrBlank()) throw PromptException(ErrorCode.CUSTOM_SYSTEM_PROMPT)
return preSet.defaultSystemPrompt
}Then within the changed sections:
Also applies to: 52-66 🤖 Prompt for AI Agents🧹 Nitpick (assertive) Normalize systemPrompt on create (trim/empty) to avoid storing whitespace noise. For CUSTOM, you currently persist raw input or empty when null. Trimming avoids accidental leading/trailing whitespace. PreSet.CUSTOM -> Prompt(
promptCreateRequest.name,
promptCreateRequest.preSet,
- promptCreateRequest.systemPrompt ?: ""
+ promptCreateRequest.systemPrompt?.trim().orEmpty()
)🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return prompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun update(promptUpdateRequest: PromptUpdateRequest) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when (promptUpdateRequest.preSet) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PreSet.CUSTOM -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.name = promptUpdateRequest.name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.systemPrompt = promptUpdateRequest.systemPrompt ?: "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.preSet = promptUpdateRequest.preSet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!promptUpdateRequest.systemPrompt.isNullOrBlank()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw PromptException(ErrorCode.CUSTOM_SYSTEM_PROMPT) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.name = promptUpdateRequest.name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.systemPrompt = promptUpdateRequest.preSet.defaultSystemPrompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.preSet = promptUpdateRequest.preSet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+52
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Normalize inputs on update; enforce same rules with trimmed values.
PreSet.CUSTOM -> {
- this.name = promptUpdateRequest.name
- this.systemPrompt = promptUpdateRequest.systemPrompt ?: ""
+ this.name = promptUpdateRequest.name.trim()
+ this.systemPrompt = promptUpdateRequest.systemPrompt?.trim().orEmpty()
this.preSet = promptUpdateRequest.preSet
}
else -> {
if(!promptUpdateRequest.systemPrompt.isNullOrBlank()) {
throw PromptException(ErrorCode.CUSTOM_SYSTEM_PROMPT)
}
- this.name = promptUpdateRequest.name
+ this.name = promptUpdateRequest.name.trim()
this.systemPrompt = promptUpdateRequest.preSet.defaultSystemPrompt
this.preSet = promptUpdateRequest.preSet
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,10 @@ | ||
| package simplerag.ragback.domain.prompt.repository | ||
|
|
||
| import org.springframework.data.domain.Pageable | ||
| import org.springframework.data.domain.Slice | ||
| import org.springframework.data.jpa.repository.JpaRepository | ||
| import simplerag.ragback.domain.prompt.entity.Prompt | ||
|
|
||
| interface PromptRepository: JpaRepository<Prompt, Long> | ||
| interface PromptRepository: JpaRepository<Prompt, Long> { | ||
| fun findByIdGreaterThanOrderById(cursor: Long, pageable: Pageable): Slice<Prompt> | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| package simplerag.ragback.domain.prompt.service | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.domain.PageRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.repository.findByIdOrNull | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Service | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.transaction.annotation.Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.dto.PromptCreateRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.dto.PromptPreviewResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.document.dto.DataFileDetailResponseList | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.document.dto.TagDTO | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.dto.* | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.entity.Prompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.domain.prompt.repository.PromptRepository | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.global.error.ErrorCode | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import simplerag.ragback.global.error.PromptException | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Service | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional(readOnly = true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -21,4 +26,36 @@ class PromptService( | |||||||||||||||||||||||||||||||||||||||||||||||||||
| val savedPrompt = promptRepository.save(prompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptPreviewResponse.from(savedPrompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun getPrompt(promptId: Long): PromptDetailResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptDetailResponse.from(prompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun getPrompts( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor: Long, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| take: Int | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): PromptPreviewResponseList { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| val prompts = promptRepository.findByIdGreaterThanOrderById(cursor, PageRequest.of(0, take)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| val nextCursor = prompts.content.lastOrNull()?.id | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptPreviewResponseList.from(prompts.content, nextCursor, prompts.hasNext()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+35
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Harden paging inputs: clamp take and prevent negative cursors. Avoid accidental large page sizes and negative cursors that could stress DB or yield confusing results. Also aligns with cursor semantics used in the DTO (nextCursor). fun getPrompts(
cursor: Long,
take: Int
): PromptPreviewResponseList {
- val prompts = promptRepository.findByIdGreaterThanOrderById(cursor, PageRequest.of(0, take))
+ val safeTake = take.coerceIn(1, 100)
+ val safeCursor = cursor.coerceAtLeast(0L)
+ val prompts = promptRepository.findByIdGreaterThanOrderById(
+ safeCursor,
+ PageRequest.of(0, safeTake)
+ )
val nextCursor = prompts.content.lastOrNull()?.id
return PromptPreviewResponseList.from(prompts.content, nextCursor, prompts.hasNext())
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun updatePrompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptUpdateRequest: PromptUpdateRequest, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptId: Long | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): PromptPreviewResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| prompt.update(promptUpdateRequest) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return PromptPreviewResponse.from(prompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Reduce repetition: extract a find-or-throw helper. You repeat the NOT_FOUND lookup pattern. Centralize it for clarity and consistency. - val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND)
+ val prompt = findPromptOrThrow(promptId)
prompt.update(promptUpdateRequest)
return PromptPreviewResponse.from(prompt)Add this helper (outside the shown ranges): private fun findPromptOrThrow(id: Long): Prompt =
promptRepository.findByIdOrNull(id) ?: throw PromptException(ErrorCode.NOT_FOUND)🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun deletePrompt(promptId: Long) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptRepository.delete(prompt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+56
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Decide on DELETE semantics: strict 404 vs idempotent delete. Current behavior throws NOT_FOUND if the prompt doesn't exist. Many APIs choose idempotent deletes (204 even if absent) to reduce information leakage and simplify clients. If you prefer idempotency, consider no-op on missing id. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,5 +25,8 @@ enum class ErrorCode( | |||||||||||||||||
| S3_UNSUPPORTED_CONTENT_TYPE(HttpStatus.BAD_REQUEST, "S3_007", "지원하지 않는 Content-Type 입니다."), | ||||||||||||||||||
|
|
||||||||||||||||||
| // index | ||||||||||||||||||
| OVERLAP_OVERFLOW(HttpStatus.BAD_REQUEST, "INDEX_001", "overlap 크기는 chunking 크기를 넘을 수 없습니다.") | ||||||||||||||||||
| OVERLAP_OVERFLOW(HttpStatus.BAD_REQUEST, "INDEX_001", "overlap 크기는 chunking 크기를 넘을 수 없습니다."), | ||||||||||||||||||
|
|
||||||||||||||||||
| // prompt | ||||||||||||||||||
| CUSTOM_SYSTEM_PROMPT(HttpStatus.BAD_REQUEST, "PROMPT_001", "preset이 Custom이 아닐 때 systemPrompt의 조작이 불가능합니다.") | ||||||||||||||||||
|
Comment on lines
+28
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Nit: Keep preset name casing consistent with enum value Use “CUSTOM” (enum name) instead of “Custom” in the message for consistency and easier grep/search. Apply this diff: - CUSTOM_SYSTEM_PROMPT(HttpStatus.BAD_REQUEST, "PROMPT_001", "preset이 Custom이 아닐 때 systemPrompt의 조작이 불가능합니다.")
+ CUSTOM_SYSTEM_PROMPT(HttpStatus.BAD_REQUEST, "PROMPT_001", "preset이 CUSTOM이 아닐 때 systemPrompt의 조작이 불가능합니다.")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
| } | ||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add sane defaults and validation for cursor/take; enable @validated
Without defaults, the list endpoint 400s unless both params are provided. Also guard against negative cursor and unbounded take. You’ll need @validated on the controller class for @Min/@max on @RequestParam to take effect.
Apply this diff to the parameter annotations:
Add @validated on the controller (outside selected range) so the @RequestParam constraints are enforced: