-
Notifications
You must be signed in to change notification settings - Fork 0
✨ Feature: create prompt #22
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
Conversation
WalkthroughAdds prompt creation functionality: new POST /api/v1/prompts controller, request/response DTOs, service with transactional create/save flow, JPA repository, Prompt factory method from request, and an expanded PreSet enum with multiple presets and default system prompts. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Controller as PromptController
participant Service as PromptService
participant Repo as PromptRepository
participant Entity as Prompt
Client->>Controller: POST /api/v1/prompts (PromptCreateRequest)
Controller->>Service: createPrompt(request)
Service->>Entity: Prompt.from(request)
Service->>Repo: save(prompt)
Repo-->>Service: savedPrompt
Service-->>Controller: PromptPreviewResponse.from(savedPrompt)
Controller-->>Client: ApiResponse<PromptPreviewResponse> (201)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt (1)
19-21: Consider setting an explicit TEXT type for portability
@LobwithoutcolumnDefinitioncan become a BLOB on some dialects. If you target PostgreSQL/MySQL and intend a large text column, prefer an explicit type (e.g.,TEXT).Add (outside this hunk):
@Column(name = "system_prompt", nullable = false, columnDefinition = "TEXT") @Lob val systemPrompt: String,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt(1 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt(1 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt(1 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt(2 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/entity/enums/PreSet.kt(1 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt(1 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt (2)
src/main/kotlin/simplerag/ragback/domain/index/controller/IndexController.kt (2)
indexService(11-59)HttpStatus(18-25)src/main/kotlin/simplerag/ragback/domain/document/controller/DataFileController.kt (1)
dataFileService(20-64)
src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt (2)
src/main/kotlin/simplerag/ragback/domain/prompt/entity/FewShot.kt (1)
name(6-29)src/main/kotlin/simplerag/ragback/domain/chat/entity/Model.kt (1)
name(8-29)
src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt (2)
src/main/kotlin/simplerag/ragback/domain/document/dto/DataFileResponseDTO.kt (4)
id(14-25)id(44-65)from(19-23)id(68-78)src/main/kotlin/simplerag/ragback/domain/index/dto/IndexResponseDTO.kt (2)
indexId(20-32)toIndexPreviewResponse(25-30)
🔇 Additional comments (2)
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt (1)
3-11: I’ve added scripts to print the first 200 lines of bothPromptController.ktandIndexController.ktso we can verify if the suggested annotations and imports are used or missing. Once we have the outputs, we can confirm whether to add@ResponseStatus,HttpStatus,@Validated, and@Valid(orjavax.validation.Valid) imports.src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt (1)
10-12: Transactional boundaries and mapping look solidService is correctly read-only by default with a write method for creation. Mapping via the entity factory and returning a preview DTO is clean.
Also applies to: 16-23
| @RestController | ||
| @RequestMapping("/api/v1/prompts") | ||
| class PromptController( | ||
| private val promptService: PromptService | ||
| ) { |
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.
💡 Verification agent
🧩 Analysis chain
Return HTTP 201 for creation and enable bean validation on the request
Consistent with your Index/DataFile controllers, mark the POST as 201 Created and enable validation.
@RestController
@RequestMapping("/api/v1/prompts")
-class PromptController(
+@Validated
+class PromptController(
private val promptService: PromptService
) {
@PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
fun createPrompt(
- @RequestBody promptCreateRequest: PromptCreateRequest
+ @RequestBody @Valid promptCreateRequest: PromptCreateRequest
): ApiResponse<PromptPreviewResponse> {
val savedPrompt = promptService.createPrompt(promptCreateRequest)
return ApiResponse.ok(savedPrompt)
}To confirm consistency across controllers, you can run:
Also applies to: 18-23
🏁 Script executed:
#!/bin/bash
# Show POST endpoints and whether they declare 201
rg -nP --type=kt -C2 '@PostMapping' src/main/kotlin/simplerag/ragback/domain/.+?/controller/.+?Controller\.kt \
| sed -n '1,200p'Length of output: 153
To ensure we correctly mirror the behavior of your existing controllers, let’s re-scan all controller classes for @PostMapping and check whether they already declare @ResponseStatus(HttpStatus.CREATED) and @Valid. Please run:
🏁 Script executed:
#!/bin/bash
# Find all @PostMapping in controller classes and show surrounding lines
rg -n '@PostMapping' -C2 src/main/kotlin/simplerag/ragback/domain/*/controller/*Controller.ktLength of output: 1791
To confirm the exact annotations on your existing POST endpoints, let’s extract the relevant snippets from both controllers:
🏁 Script executed:
#!/bin/bash
echo "=== IndexController.createIndex ==="
rg -nP -C3 'fun createIndex' src/main/kotlin/simplerag/ragback/domain/index/controller/IndexController.kt || true
rg -nP '@RequestBody' -C3 src/main/kotlin/simplerag/ragback/domain/index/controller/IndexController.kt || true
rg -nP '@Valid' -C3 src/main/kotlin/simplerag/ragback/domain/index/controller/IndexController.kt || true
rg -nP '@ResponseStatus' -C3 src/main/kotlin/simplerag/ragback/domain/index/controller/IndexController.kt || true
echo
echo "=== DataFileController POST ==="
rg -nP -C5 '@PostMapping' src/main/kotlin/simplerag/ragback/domain/document/controller/DataFileController.kt || true
rg -nP '@ResponseStatus' -C3 src/main/kotlin/simplerag/ragback/domain/document/controller/DataFileController.kt || true
rg -nP '@Validated' -C3 src/main/kotlin/simplerag/ragback/domain/document/controller/DataFileController.kt || trueLength of output: 3599
PromptController: mark POST create as 201 Created and enable bean validation
To stay consistent with your other controllers, please update PromptController as follows:
• File: src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt
• Add @Validated at the class level
• Annotate the createPrompt method with @ResponseStatus(HttpStatus.CREATED)
• Add @Valid to the @RequestBody parameter
@RestController
@RequestMapping("/api/v1/prompts")
-@Validated
-class PromptController(
+@Validated
+class PromptController(
private val promptService: PromptService
) {
@PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
fun createPrompt(
- @RequestBody promptCreateRequest: PromptCreateRequest
+ @RequestBody @Valid promptCreateRequest: PromptCreateRequest
): ApiResponse<PromptPreviewResponse> {
val savedPrompt = promptService.createPrompt(promptCreateRequest)
return ApiResponse.ok(savedPrompt)
}📝 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.
| @RestController | |
| @RequestMapping("/api/v1/prompts") | |
| class PromptController( | |
| private val promptService: PromptService | |
| ) { | |
| @RestController | |
| @RequestMapping("/api/v1/prompts") | |
| @Validated | |
| class PromptController( | |
| private val promptService: PromptService | |
| ) { | |
| @PostMapping | |
| @ResponseStatus(HttpStatus.CREATED) | |
| fun createPrompt( | |
| @RequestBody @Valid promptCreateRequest: PromptCreateRequest | |
| ): ApiResponse<PromptPreviewResponse> { | |
| val savedPrompt = promptService.createPrompt(promptCreateRequest) | |
| return ApiResponse.ok(savedPrompt) | |
| } | |
| } |
🤖 Prompt for AI Agents
In
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt
around lines 12–16, the controller should enable bean validation and return the
correct status for POST: add the @Validated annotation at the class level,
annotate the createPrompt handler with @ResponseStatus(HttpStatus.CREATED), and
add @Valid to the @RequestBody parameter; also add the necessary imports
(org.springframework.validation.annotation.Validated,
org.springframework.web.bind.annotation.ResponseStatus,
org.springframework.http.HttpStatus and javax/ jakarta.validation.Valid
depending on your setup).
| data class PromptCreateRequest( | ||
| val name: String, | ||
| val preSet: PreSet, | ||
| val systemPrompt: String, | ||
| ) No newline at end of file |
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 bean validation and make systemPrompt optional for non-CUSTOM presets
Right now any request must provide a systemPrompt even when a preset will override it, and there’s no validation aligned with your DB constraints (name length = 100). Enforce invariants at the edge and improve DX by making systemPrompt optional unless preSet == CUSTOM.
Apply this diff to the DTO:
data class PromptCreateRequest(
- val name: String,
- val preSet: PreSet,
- val systemPrompt: String,
+ @field:jakarta.validation.constraints.NotBlank
+ @field:jakarta.validation.constraints.Size(max = 100)
+ val name: String,
+ val preSet: PreSet,
+ @field:jakarta.validation.constraints.Size(max = 20000)
+ val systemPrompt: String? = null,
)And ensure the controller method is annotated with @Validated so these constraints are enforced.
Additionally add the missing imports (outside the changed hunk):
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.Size🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt
around lines 6 to 10, add bean validation to align with DB constraints and make
systemPrompt optional unless preSet == CUSTOM: annotate the name field with
@field:NotBlank and @field:Size(max = 100) to enforce non-empty and max length
100; keep preSet required; change systemPrompt to nullable (String?) and remove
unconditional @NotBlank, then implement conditional validation by adding a
custom validator or a @AssertTrue boolean function on the DTO that returns true
when preSet != PreSet.CUSTOM or (preSet == PreSet.CUSTOM &&
!systemPrompt.isNullOrBlank()), and annotate that method with
@AssertTrue(message = "systemPrompt is required for CUSTOM preset"); add the
missing imports (jakarta.validation.constraints.NotBlank,
jakarta.validation.constraints.Size and
jakarta.validation.constraints.AssertTrue) and ensure the controller handling
this DTO is annotated with @Validated so the constraints are enforced.
|
|
||
| data class PromptCreateRequest( | ||
| val name: String, | ||
| val preSet: PreSet, |
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.
🧹 Nitpick (assertive)
Consider renaming preSet → preset for consistent, idiomatic naming
The mixed-case “PreSet” leaks into the API as preSet. Kotlin/Java community typically uses “preset”. Renaming early avoids long-term churn across DB column names, JSON, and code.
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt
around line 8, the property name `preSet: PreSet` leaks non-idiomatic
mixed-casing into the API; rename the property to `preset: PreSet` and update
all references accordingly (constructor usages, JSON serialization names, DTO
mapping, database/ORM column mappings, tests and any callers) ensuring
serialization annotations (e.g., @JsonProperty) or column mappings are adjusted
if you must preserve an external contract during rollout; run and update
unit/integration tests and compile-time references to finish the rename.
| @@ -0,0 +1,15 @@ | |||
| package simplerag.ragback.domain.prompt.dto | |||
|
|
|||
| import simplerag.ragback.domain.prompt.entity.Prompt | |||
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.
🧹 Nitpick (assertive)
Import PreSet if exposing it in the response
If you include preset in the preview, add the missing import.
Apply this diff if you adopt the response changes below:
-import simplerag.ragback.domain.prompt.entity.Prompt
+import simplerag.ragback.domain.prompt.entity.Prompt
+import simplerag.ragback.domain.prompt.entity.enums.PreSet📝 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.
| import simplerag.ragback.domain.prompt.entity.Prompt | |
| // src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt | |
| import simplerag.ragback.domain.prompt.entity.Prompt | |
| import simplerag.ragback.domain.prompt.entity.enums.PreSet | |
| // …rest of file… |
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt
around line 3, the DTO now exposes the PreSet type but the corresponding import
is missing; add an import for simplerag.ragback.domain.prompt.entity.PreSet
(i.e. import simplerag.ragback.domain.prompt.entity.PreSet) alongside the
existing Prompt import so the file compiles and the response can reference
PreSet.
| data class PromptPreviewResponse( | ||
| val id: Long, | ||
| ) { | ||
| companion object { | ||
| fun from( | ||
| prompt: Prompt | ||
| ): PromptPreviewResponse { | ||
| return PromptPreviewResponse(prompt.id) | ||
| } | ||
| } |
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.
🧹 Nitpick (assertive)
Return minimally useful metadata in the preview (id, name, preset)
Returning only id creates an immediate follow-up GET to show what was created. Mirror the pattern from other “PreviewResponse” types and include name and preSet.
Apply this diff:
-data class PromptPreviewResponse(
- val id: Long,
-) {
- companion object {
- fun from(
- prompt: Prompt
- ): PromptPreviewResponse {
- return PromptPreviewResponse(prompt.id)
- }
- }
-}
+data class PromptPreviewResponse(
+ val id: Long,
+ val name: String,
+ val preSet: PreSet,
+) {
+ companion object {
+ fun from(prompt: Prompt): PromptPreviewResponse =
+ PromptPreviewResponse(
+ id = prompt.id,
+ name = prompt.name,
+ preSet = prompt.preSet,
+ )
+ }
+}📝 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.
| data class PromptPreviewResponse( | |
| val id: Long, | |
| ) { | |
| companion object { | |
| fun from( | |
| prompt: Prompt | |
| ): PromptPreviewResponse { | |
| return PromptPreviewResponse(prompt.id) | |
| } | |
| } | |
| data class PromptPreviewResponse( | |
| val id: Long, | |
| val name: String, | |
| val preSet: PreSet, | |
| ) { | |
| companion object { | |
| fun from(prompt: Prompt): PromptPreviewResponse = | |
| PromptPreviewResponse( | |
| id = prompt.id, | |
| name = prompt.name, | |
| preSet = prompt.preSet, | |
| ) | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt
around lines 5 to 14, the PromptPreviewResponse currently only returns id;
update the data class to include val name: String and val preSet: Boolean (or
the actual type used on Prompt) and modify the companion from(prompt: Prompt) to
populate those fields from prompt.name and prompt.preSet so the preview contains
id, name and preSet to avoid an extra GET.
| CUSTOM( | ||
| "User-defined custom prompt", | ||
| "TODO: custom system prompt here" | ||
| ), | ||
|
|
||
| // Retrieval / Q&A | ||
| RAG_QA( | ||
| "Question Answering with retrieved context", | ||
| "TODO: system prompt for RAG_QA" | ||
| ), | ||
| RAG_SUMMARIZER( | ||
| "Summarize documents retrieved via RAG", | ||
| "TODO: system prompt for RAG_SUMMARIZER" | ||
| ), | ||
|
|
||
| // Code related | ||
| CODE_REVIEW_BACKEND( | ||
| "Backend code review (Java/Kotlin/Spring)", | ||
| "TODO: system prompt for CODE_REVIEW_BACKEND" | ||
| ), | ||
| CODE_REVIEW_GENERAL( | ||
| "General code review and best practices", | ||
| "TODO: system prompt for CODE_REVIEW_GENERAL" | ||
| ), | ||
|
|
||
| // Language tasks | ||
| TRANSLATION_EN_KO( | ||
| "English ↔ Korean translation", | ||
| "TODO: system prompt for TRANSLATION_EN_KO" | ||
| ), | ||
| TRANSLATION_MULTI( | ||
| "Multi-language translation", | ||
| "TODO: system prompt for TRANSLATION_MULTI" | ||
| ), | ||
| PROOFREAD_KR( | ||
| "Korean proofreading / grammar correction", | ||
| "TODO: system prompt for PROOFREAD_KR" | ||
| ), | ||
|
|
||
| // Content tasks | ||
| TEXT_SUMMARIZER( | ||
| "General text summarization", | ||
| "TODO: system prompt for TEXT_SUMMARIZER" | ||
| ), | ||
| DATA_CLEANER( | ||
| "Text cleaning and preprocessing", | ||
| "TODO: system prompt for DATA_CLEANER" | ||
| ), | ||
| EMAIL_WRITER( | ||
| "Email / message generation", | ||
| "TODO: system prompt for EMAIL_WRITER" | ||
| ), | ||
|
|
||
| // Safety / Guardrails | ||
| SAFETY_FILTERED( | ||
| "Safe response (avoid harmful or unsafe outputs)", | ||
| "TODO: system prompt for SAFETY_FILTERED" | ||
| ) |
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.
🧹 Nitpick (assertive)
Do not ship with “TODO” default prompts — this violates requirements and will persist placeholders
Per PR objectives (“Add OpenSource Prompt Set”), every non-CUSTOM preset currently writes “TODO …” into the database via defaultSystemPrompt. That’s a correctness and product issue.
Pick one of the following immediately:
- Minimal fix now: replace TODOs with sane, short defaults.
- Safer guard: block non-CUSTOM creation until defaults exist.
- Better architecture: store template keys here and load full prompt text from external resources (files/DB), enabling iteration without redeploys.
Minimal, immediate fix (replace only the string literals below):
@@
CUSTOM(
"User-defined custom prompt",
- "TODO: custom system prompt here"
+ "" // Not used — CUSTOM comes from request
),
@@
RAG_QA(
"Question Answering with retrieved context",
- "TODO: system prompt for RAG_QA"
+ "You are a grounded QA assistant. Use ONLY the provided CONTEXT to answer. If the answer is not in CONTEXT, say \"I don't know\". Cite sources by title or id."
),
RAG_SUMMARIZER(
"Summarize documents retrieved via RAG",
- "TODO: system prompt for RAG_SUMMARIZER"
+ "Summarize the provided CONTEXT for a busy reader. Use bullet points, keep facts verifiable, avoid speculation, and include key entities, dates, and numbers."
),
@@
CODE_REVIEW_BACKEND(
"Backend code review (Java/Kotlin/Spring)",
- "TODO: system prompt for CODE_REVIEW_BACKEND"
+ "Review backend code (Kotlin/Java/Spring). Focus on correctness, concurrency, security, input validation, performance, error handling, transactions, and testability. Output concise action items with code snippets."
),
CODE_REVIEW_GENERAL(
"General code review and best practices",
- "TODO: system prompt for CODE_REVIEW_GENERAL"
+ "Perform a pragmatic code review. Identify bugs, edge cases, readability issues, dead code, and missing tests. Propose minimal diffs to fix critical issues."
),
@@
TRANSLATION_EN_KO(
"English ↔ Korean translation",
- "TODO: system prompt for TRANSLATION_EN_KO"
+ "Translate between English and Korean. Preserve meaning, tone, and formatting. Provide only the translation without additional commentary."
),
TRANSLATION_MULTI(
"Multi-language translation",
- "TODO: system prompt for TRANSLATION_MULTI"
+ "Translate between the user’s source and target languages. Maintain tone and formatting. Do not add explanations unless asked."
),
PROOFREAD_KR(
"Korean proofreading / grammar correction",
- "TODO: system prompt for PROOFREAD_KR"
+ "Proofread Korean text. Fix grammar, spacing, and style while preserving meaning. Output only the corrected text."
),
@@
TEXT_SUMMARIZER(
"General text summarization",
- "TODO: system prompt for TEXT_SUMMARIZER"
+ "Summarize the text in 5–7 bullet points. Be faithful, concise, and include critical facts (who/what/when/where/why)."
),
DATA_CLEANER(
"Text cleaning and preprocessing",
- "TODO: system prompt for DATA_CLEANER"
+ "Normalize whitespace, remove boilerplate, fix common encoding issues, and standardize quotes and dashes. Preserve semantic content."
),
EMAIL_WRITER(
"Email / message generation",
- "TODO: system prompt for EMAIL_WRITER"
+ "Draft a clear, polite email given purpose, audience, and key points. Include subject and body. Keep it concise and actionable."
),
@@
SAFETY_FILTERED(
"Safe response (avoid harmful or unsafe outputs)",
- "TODO: system prompt for SAFETY_FILTERED"
+ "Follow safety best practices. Refuse requests involving illegal, harmful, or sensitive content. Offer safe alternatives when declining."
)Longer-term architecture (recommended):
- Replace
defaultSystemPrompt: StringwithtemplateKey: Stringand look up prompt text from a registry (JSON/YAML in resources or DB), enabling A/B tests and localization without code changes.
| @Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| @Column(name = "prompts_id") | ||
| val id: Long = 0 |
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.
💡 Verification agent
🧩 Analysis chain
Verify your Kotlin JPA configuration if keeping val id: Long = 0
Hibernate must set this generated id on a val field via reflection/bytecode enhancement. Ensure the Kotlin JPA/all-open plugins are applied. Alternatively, prefer val id: Long? = null to reduce surprises (will require adapting DTO mapping).
Run this quick check:
🏁 Script executed:
#!/bin/bash
# Verify Kotlin JPA/all-open is enabled
rg -nP 'kotlin\("plugin\.jpa"\)|allOpen|kotlin-jpa' -g 'build.gradle*' -C2 || trueLength of output: 267
🏁 Script executed:
#!/bin/bash
# Display the first 50 lines of build.gradle* to inspect plugin declarations
head -n 50 build.gradle build.gradle.kts || trueLength of output: 1683
Verify Kotlin JPA compiler plugin setup – confirms ID handling
Your Gradle configuration already applies the necessary Kotlin compiler plugins to support JPA entities:
- The
org.jetbrains.kotlin.plugin.jpacompiler plugin is declared in thepluginsblock, which wraps both the no-arg and all-open plugins for JPA support, automatically generating a no-argument constructor and opening classes annotated with@Entity,@Embeddable, and@MappedSuperclass(kotlinlang.org). - An explicit
allOpenblock listsjakarta.persistence.Entityandjakarta.persistence.MappedSuperclass, ensuring these classes aren’t final so Hibernate can proxy them (kotlinlang.org).
Given this setup, Hibernate will correctly set the generated id on your val id: Long = 0 field via reflection/bytecode enhancement.
As an optional refactoring for clearer “unsaved” semantics, you may choose to change the declaration to:
val id: Long? = nulland update any DTO mappings accordingly to use null as the sentinel for new entities.
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt around lines
24-26, confirm the Kotlin JPA compiler plugins are enabled in Gradle
(org.jetbrains.kotlin.plugin.jpa / no-arg and all-open configured for
jakarta.persistence annotations) so Hibernate can set the @Id @GeneratedValue
val id: Long = 0 via reflection; optionally refactor the entity id to a nullable
sentinel by changing it to val id: Long? = null and update any DTO/mapping code
that assumes 0 to use null for unsaved entities.
| companion object { | ||
| fun from( | ||
| promptCreateRequest: PromptCreateRequest | ||
| ): Prompt { | ||
|
|
||
| val prompt = if (promptCreateRequest.preSet == PreSet.CUSTOM) { | ||
| Prompt( | ||
| promptCreateRequest.name, | ||
| promptCreateRequest.preSet, | ||
| promptCreateRequest.systemPrompt | ||
| ) | ||
| } else { | ||
| Prompt( | ||
| promptCreateRequest.name, | ||
| promptCreateRequest.preSet, | ||
| promptCreateRequest.preSet.defaultSystemPrompt | ||
| ) | ||
| } | ||
|
|
||
| return prompt | ||
| } | ||
| } |
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
Normalize inputs, enforce invariants, and fail fast if presets are not configured
- Trim and validate
nameagainst blank input. - Make
systemPromptresolution explicit with awhenand validate non-blank. - Guard against accidentally persisting TODO defaults.
- Reduce duplication in the factory.
Apply this diff within the factory:
companion object {
fun from(
promptCreateRequest: PromptCreateRequest
): Prompt {
-
- val prompt = if (promptCreateRequest.preSet == PreSet.CUSTOM) {
- Prompt(
- promptCreateRequest.name,
- promptCreateRequest.preSet,
- promptCreateRequest.systemPrompt
- )
- } else {
- Prompt(
- promptCreateRequest.name,
- promptCreateRequest.preSet,
- promptCreateRequest.preSet.defaultSystemPrompt
- )
- }
-
- return prompt
+ val name = promptCreateRequest.name.trim()
+ require(name.isNotBlank()) { "Prompt name must not be blank." }
+
+ val resolvedSystemPrompt = when (promptCreateRequest.preSet) {
+ PreSet.CUSTOM -> (promptCreateRequest.systemPrompt ?: "").trim()
+ else -> promptCreateRequest.preSet.defaultSystemPrompt.trim()
+ }
+
+ require(resolvedSystemPrompt.isNotBlank()) {
+ "systemPrompt must not be blank. For non-CUSTOM presets, defaultSystemPrompt must be configured."
+ }
+ if (promptCreateRequest.preSet != PreSet.CUSTOM &&
+ resolvedSystemPrompt.startsWith("TODO", ignoreCase = true)
+ ) {
+ throw IllegalStateException("Preset ${promptCreateRequest.preSet} defaultSystemPrompt is not configured.")
+ }
+
+ return Prompt(
+ name = name,
+ preSet = promptCreateRequest.preSet,
+ systemPrompt = resolvedSystemPrompt,
+ )
}
}📝 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.
| companion object { | |
| fun from( | |
| promptCreateRequest: PromptCreateRequest | |
| ): Prompt { | |
| val prompt = if (promptCreateRequest.preSet == PreSet.CUSTOM) { | |
| Prompt( | |
| promptCreateRequest.name, | |
| promptCreateRequest.preSet, | |
| promptCreateRequest.systemPrompt | |
| ) | |
| } else { | |
| Prompt( | |
| promptCreateRequest.name, | |
| promptCreateRequest.preSet, | |
| promptCreateRequest.preSet.defaultSystemPrompt | |
| ) | |
| } | |
| return prompt | |
| } | |
| } | |
| companion object { | |
| fun from( | |
| promptCreateRequest: PromptCreateRequest | |
| ): Prompt { | |
| val name = promptCreateRequest.name.trim() | |
| require(name.isNotBlank()) { "Prompt name must not be blank." } | |
| val resolvedSystemPrompt = when (promptCreateRequest.preSet) { | |
| PreSet.CUSTOM -> (promptCreateRequest.systemPrompt ?: "").trim() | |
| else -> promptCreateRequest.preSet.defaultSystemPrompt.trim() | |
| } | |
| require(resolvedSystemPrompt.isNotBlank()) { | |
| "systemPrompt must not be blank. For non-CUSTOM presets, defaultSystemPrompt must be configured." | |
| } | |
| if (promptCreateRequest.preSet != PreSet.CUSTOM && | |
| resolvedSystemPrompt.startsWith("TODO", ignoreCase = true) | |
| ) { | |
| throw IllegalStateException("Preset ${promptCreateRequest.preSet} defaultSystemPrompt is not configured.") | |
| } | |
| return Prompt( | |
| name = name, | |
| preSet = promptCreateRequest.preSet, | |
| systemPrompt = resolvedSystemPrompt, | |
| ) | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt around lines
28 to 49, the factory does not normalize or validate inputs and duplicates
construction logic; change it to trim and validate the incoming name (reject
blank after trim), resolve the systemPrompt with an explicit when on preSet (use
promptCreateRequest.systemPrompt for PreSet.CUSTOM, otherwise use
preSet.defaultSystemPrompt), validate the resolved systemPrompt is non-blank and
fail fast if it is blank or matches any TODO/default sentinel, and then
construct and return a single Prompt instance (reduce duplication by building
the resolvedName and resolvedSystemPrompt first and reuse them for
construction).
| import org.springframework.data.jpa.repository.JpaRepository | ||
| import simplerag.ragback.domain.prompt.entity.Prompt | ||
|
|
||
| interface PromptRepository: JpaRepository<Prompt, Long> No newline at end of file |
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.
🧹 Nitpick (assertive)
Style nit + add helper to prevent duplicate names
- Kotlin style: add a space before the colon.
- Expose
existsByNameto preempt duplicates at the service layer (pair with a DB unique constraint).
Apply this diff:
-interface PromptRepository: JpaRepository<Prompt, Long>
+interface PromptRepository : JpaRepository<Prompt, Long> {
+ fun existsByName(name: String): Boolean
+}And add a unique constraint on prompts.name (outside this hunk):
@Table(
name = "prompts",
uniqueConstraints = [UniqueConstraint(name = "uk_prompts_name", columnNames = ["name"])]
)🤖 Prompt for AI Agents
In
src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt
around line 6, the interface declaration needs Kotlin style spacing and an
existence helper: change "interface PromptRepository: JpaRepository<Prompt,
Long>" to use a space before the colon and add a method signature fun
existsByName(name: String): Boolean so services can check duplicates; also add a
unique constraint on the prompts table in the Prompt entity with @Table(name =
"prompts", uniqueConstraints = [UniqueConstraint(name = "uk_prompts_name",
columnNames = ["name"])]) to enforce uniqueness at the DB level.
| @Transactional | ||
| fun createPrompt( | ||
| promptCreateRequest: PromptCreateRequest | ||
| ): PromptPreviewResponse { | ||
| val prompt = Prompt.from(promptCreateRequest) | ||
| val savedPrompt = promptRepository.save(prompt) | ||
| return PromptPreviewResponse.from(savedPrompt) | ||
| } |
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.
🧹 Nitpick (assertive)
Consider guarding against duplicate names and clarifying default system prompt behavior
- If prompt names must be unique, add a repository existence check (or handle unique index violations) to return a domain-friendly error rather than surfacing a DB exception.
- Ensure Prompt.from applies a sensible default: when preSet != CUSTOM and systemPrompt is null/blank, use the preset’s defaultSystemPrompt. If that logic isn’t in the factory yet, move it there to centralize invariants.
Example (outside this file):
// PromptRepository.kt
interface PromptRepository : JpaRepository<Prompt, Long> {
fun existsByName(name: String): Boolean
}// PromptService.kt (inside createPrompt)
if (promptRepository.existsByName(promptCreateRequest.name)) {
// throw your domain exception, e.g., DuplicateResourceException("Prompt name already exists")
}If a DB-level guarantee is desired, also add a unique constraint on the name column and translate DataIntegrityViolationException.
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt
around lines 16-23, guard against duplicate prompt names and centralize default
system-prompt logic: before saving, call
promptRepository.existsByName(promptCreateRequest.name) and throw a
domain-friendly DuplicateResourceException (or similar) if true; also
catch/translate DataIntegrityViolationException from the repository save to the
same domain exception if you prefer DB-level uniqueness. Move or augment
Prompt.from to ensure that when promptCreateRequest.preSet != PreSet.CUSTOM and
systemPrompt is null/blank it sets systemPrompt to the preset’s
defaultSystemPrompt so the factory enforces that invariant rather than relying
on service code.
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.
Actionable comments posted: 2
♻️ Duplicate comments (3)
src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt (2)
10-10: Rename preSet → preset for idiomatic, stable API naming (keep backward compatibility with aliases)Adopt “preset” consistently; accept legacy “preSet” via @JsonAlias to avoid breaking clients.
The diff above includes this rename plus
@JsonAlias("preSet")to keep old payloads working. I can sweep usages across the codebase if you’d like.
8-12: Harden validation at the edge; make systemPrompt optional and conditionally required (CUSTOM only)Enforce invariants consistent with DB constraints and UX. Name should be non-blank and ≤100. systemPrompt shouldn’t be mandatory when a preset supplies the default; require it only for user-defined/custom presets.
Apply this diff:
package simplerag.ragback.domain.prompt.dto -import jakarta.validation.constraints.Size +import com.fasterxml.jackson.annotation.JsonAlias +import com.fasterxml.jackson.annotation.JsonProperty +import jakarta.validation.constraints.AssertTrue +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.Size import simplerag.ragback.domain.prompt.entity.enums.PreSet data class PromptCreateRequest( - @field:Size(max = 100) - val name: String, - val preSet: PreSet, - @field:Size(max = 20000) - val systemPrompt: String, + @field:NotBlank + @field:Size(max = 100) + val name: String, + @JsonProperty("preset") + @JsonAlias("preSet") + val preset: PreSet, + @field:Size(max = 20000) + val systemPrompt: String? = null, ) +{ + @AssertTrue(message = "systemPrompt is required when preset is CUSTOM") + fun isSystemPromptValid(): Boolean = + preset != PreSet.CUSTOM || !systemPrompt.isNullOrBlank() +}Follow-ups:
- Update mapping code (e.g., Prompt.from(request)) to use
request.presetinstead ofrequest.preSet.- Ensure controller is annotated with
@Validatedso these constraints are enforced (see controller comment).I can push a follow-up patch touching the mapper/service and add tests for both CUSTOM and non-CUSTOM paths.
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt (1)
11-15: Enable bean validation at the controller levelAdd
@Validatedto ensure the DTO constraints trigger on this endpoint, consistent with IndexController.@RestController @RequestMapping("/api/v1/prompts") -class PromptController( +@org.springframework.validation.annotation.Validated +class PromptController( private val promptService: PromptService ) {Alternatively, add the import and short annotation:
+import org.springframework.validation.annotation.Validated @@ -@RequestMapping("/api/v1/prompts") -class PromptController( +@RequestMapping("/api/v1/prompts") +@Validated +class PromptController(
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt(1 hunks)src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt (2)
src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt (1)
name(7-26)src/main/kotlin/simplerag/ragback/domain/prompt/entity/enums/PreSet.kt (1)
NONE(3-5)
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt (1)
src/main/kotlin/simplerag/ragback/domain/index/controller/IndexController.kt (2)
indexService(11-59)HttpStatus(18-25)
🔇 Additional comments (2)
src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt (1)
1-13: Confirm PreSet enum includes CUSTOM and verify DTO-to-entity mappingI’ve checked the
PreSetenum insrc/main/kotlin/simplerag/ragback/domain/prompt/entity/enums/PreSet.ktand it does define aCUSTOMconstant, so the conditional validation predicate can safely refer to it. However, I didn’t find any factory or conversion function that mapsPromptCreateRequest(insrc/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptCreateRequest.kt) into your domainPromptentity. Please verify:
- That a mapping (e.g.
from(request: PromptCreateRequest)) exists and is actually invoked when creating aPrompt.- That your mapping logic applies
defaultSystemPromptfor all presets exceptCUSTOM, and enforcessystemPromptwhenpreSet == CUSTOM.- If no such factory exists yet, either implement it or adjust your validation logic to ensure
systemPromptremains required for non-CUSTOM presets (or update the predicate to match your desired behavior).src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt (1)
17-24: POST semantics and validation look goodUsing @ResponseStatus(HttpStatus.CREATED) and @Valid on the request aligns with your other controllers.
| @PostMapping | ||
| @ResponseStatus(HttpStatus.CREATED) | ||
| fun createPrompt( | ||
| @RequestBody @Valid promptCreateRequest: PromptCreateRequest | ||
| ): ApiResponse<PromptPreviewResponse> { | ||
| val savedPrompt = promptService.createPrompt(promptCreateRequest) | ||
| return ApiResponse.ok(savedPrompt) | ||
| } |
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.
🧹 Nitpick (assertive)
Optional: set Location header for the created resource
If PromptPreviewResponse exposes the new prompt’s ID, consider returning ResponseEntity with a Location header for better REST semantics.
Example (illustrative):
-import org.springframework.http.HttpStatus
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.http.HttpHeaders
+import org.springframework.web.util.UriComponentsBuilder
@@
- @ResponseStatus(HttpStatus.CREATED)
- fun createPrompt(
+ fun createPrompt(
@RequestBody @Valid promptCreateRequest: PromptCreateRequest
- ): ApiResponse<PromptPreviewResponse> {
- val savedPrompt = promptService.createPrompt(promptCreateRequest)
- return ApiResponse.ok(savedPrompt)
+ ): ResponseEntity<ApiResponse<PromptPreviewResponse>> {
+ val savedPrompt = promptService.createPrompt(promptCreateRequest)
+ val location = UriComponentsBuilder.fromPath("/api/v1/prompts/{id}")
+ .buildAndExpand(savedPrompt.id)
+ .toUri()
+ return ResponseEntity
+ .status(HttpStatus.CREATED)
+ .header(HttpHeaders.LOCATION, location.toString())
+ .body(ApiResponse.ok(savedPrompt))
}📝 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.
| @PostMapping | |
| @ResponseStatus(HttpStatus.CREATED) | |
| fun createPrompt( | |
| @RequestBody @Valid promptCreateRequest: PromptCreateRequest | |
| ): ApiResponse<PromptPreviewResponse> { | |
| val savedPrompt = promptService.createPrompt(promptCreateRequest) | |
| return ApiResponse.ok(savedPrompt) | |
| } | |
| // Add these imports (in addition to the existing HttpStatus import) | |
| import org.springframework.http.ResponseEntity | |
| import org.springframework.http.HttpHeaders | |
| import org.springframework.web.util.UriComponentsBuilder | |
| @PostMapping | |
| fun createPrompt( | |
| @RequestBody @Valid promptCreateRequest: PromptCreateRequest | |
| ): ResponseEntity<ApiResponse<PromptPreviewResponse>> { | |
| val savedPrompt = promptService.createPrompt(promptCreateRequest) | |
| val location = UriComponentsBuilder | |
| .fromPath("/api/v1/prompts/{id}") | |
| .buildAndExpand(savedPrompt.id) | |
| .toUri() | |
| return ResponseEntity | |
| .status(HttpStatus.CREATED) | |
| .header(HttpHeaders.LOCATION, location.toString()) | |
| .body(ApiResponse.ok(savedPrompt)) | |
| } |
🤖 Prompt for AI Agents
In
src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt
around lines 17 to 24, update the createPrompt method to return a ResponseEntity
and set a Location header pointing to the newly created prompt resource: after
saving, extract the new prompt ID from PromptPreviewResponse (if it does not
contain an ID, add it to the DTO or return an object that includes the ID),
build the resource URI (e.g. using
ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri()),
and return ResponseEntity.created(location).body(savedPrompt) so the response
status is 201 and the Location header is set.
| @field:Size(max = 100) | ||
| val name: String, |
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.
🧹 Nitpick (assertive)
Align DTO with DB non-null constraint for name; add @notblank
The DB declares name NOT NULL with length 100. Add @notblank in addition to @SiZe to block all-whitespace names.
Apply the @NotBlank addition from the main diff above.
🤖 Prompt for AI Agents
In src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt
around lines 8 to 9, the DTO field 'name' only has @Size(max = 100) but the DB
column is NOT NULL and should reject blank/whitespace-only values; add the
@NotBlank annotation alongside @Size to enforce non-blank input and update
imports to include javax.validation.constraints.NotBlank (or the project's
validation package) so the validator will reject empty/whitespace names to match
the DB constraint.
📌 Overview
create prompt
🔍 Related Issues
✨ Changes
✨ Feature: create prompt
✨ Feature: add prompt detail
📸 Screenshots / Test Results (Optional)
Attach images or videos if necessary.
✅ Checklist
🗒️ Additional Notes
Add any other context or information here.
Summary by CodeRabbit