Skip to content

add isAbstract to templates and do validation on update/create#164

Merged
nk-coding merged 2 commits intomainfrom
feature/abstract_templates
Jan 23, 2026
Merged

add isAbstract to templates and do validation on update/create#164
nk-coding merged 2 commits intomainfrom
feature/abstract_templates

Conversation

@nk-coding
Copy link
Contributor

@nk-coding nk-coding commented Jan 23, 2026

Summary by CodeRabbit

  • New Features
    • Templates can now be marked as abstract.
    • Template creation endpoints accept an abstract flag.
  • Behavior Changes
    • Creation and update operations validate and prevent using abstract (or deprecated) templates.
    • Sync/import flows now skip abstract templates when selecting defaults.

✏️ Tip: You can customize this high-level summary in your review settings.

@nk-coding nk-coding requested a review from spethso January 23, 2026 07:54
@nk-coding nk-coding self-assigned this Jan 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Adds an isAbstract boolean to Template and subclasses, threads the flag through template creation paths and sync code, and introduces TemplateService.validateTemplateUsage(...) which services call to reject abstract or deprecated templates before assignment.

Changes

Cohort / File(s) Summary
Template Model Updates (isAbstract Property)
core/src/main/kotlin/gropius/model/template/Template.kt, core/src/main/kotlin/gropius/model/template/ArtefactTemplate.kt, core/src/main/kotlin/gropius/model/template/ComponentTemplate.kt, core/src/main/kotlin/gropius/model/template/IMSTemplate.kt, core/src/main/kotlin/gropius/model/template/InterfaceSpecificationTemplate.kt, core/src/main/kotlin/gropius/model/template/IssueTemplate.kt, core/src/main/kotlin/gropius/model/template/RelationPartnerTemplate.kt, core/src/main/kotlin/gropius/model/template/RelationTemplate.kt
Added isAbstract: Boolean to Template constructor and propagated parameter through all subclass constructors; updated annotations on the base property.
DTO Input Updates
core/src/main/kotlin/gropius/dto/input/template/CreateTemplateInput.kt
Added isAbstract: Boolean property (GraphQLDescription) to input DTO.
TemplateService Validation
core/src/main/kotlin/gropius/service/template/TemplateService.kt
Added suspend fun validateTemplateUsage(template: Template<*, *>) which throws if template is abstract or deprecated.
Services: Validation Injection (Architecture & Issue/Artefact)
core/src/main/kotlin/gropius/service/architecture/ComponentService.kt, core/src/main/kotlin/gropius/service/architecture/IMSService.kt, core/src/main/kotlin/gropius/service/architecture/InterfaceSpecificationService.kt, core/src/main/kotlin/gropius/service/architecture/RelationService.kt, core/src/main/kotlin/gropius/service/issue/ArtefactService.kt, core/src/main/kotlin/gropius/service/issue/IssueService.kt
Added TemplateService dependency to constructors and call validateTemplateUsage(...) during create/update flows before assigning templates.
Template Creation Services
core/src/main/kotlin/gropius/service/template/ArtefactTemplateService.kt, core/src/main/kotlin/gropius/service/template/ComponentTemplateService.kt, core/src/main/kotlin/gropius/service/template/InterfaceSpecificationTemplateService.kt, core/src/main/kotlin/gropius/service/template/IssueTemplateService.kt, core/src/main/kotlin/gropius/service/template/RelationTemplateService.kt
Pass input.isAbstract into template constructors when creating templates; adjusted argument ordering where applicable.
Sync Module Updates
sync-github/src/main/kotlin/gropius/sync/github/GithubDataService.kt, sync-github/src/main/kotlin/gropius/sync/github/config/IMSConfigManager.kt, sync-jira/src/main/kotlin/gropius/sync/jira/JiraDataService.kt, sync-jira/src/main/kotlin/gropius/sync/jira/config/IMSConfigManager.kt
Updated default/fallback template instantiations and filters to include isAbstract handling; exclude abstract templates in selection filters.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Service
    participant TemplateService
    participant Repository

    Client->>Service: createEntity(request with templateId)
    Service->>Repository: loadTemplate(templateId)
    Repository-->>Service: template
    Service->>TemplateService: validateTemplateUsage(template)
    alt template is abstract or deprecated
        TemplateService-->>Service: throw IllegalStateException
        Service-->>Client: error response
    else valid template
        TemplateService-->>Service: validation ok
        Service->>Repository: save entity with template
        Repository-->>Service: success
        Service-->>Client: success response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • chriku

Poem

🐰 I hop and check each template's face,
No abstract hopers in the usage race,
Services call, I guard the door,
Deprecated bunnies bounce no more,
Hooray — clean templates, a tidy space!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main objectives of the PR: adding an isAbstract property to template classes and implementing validation logic during template creation and updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
sync-github/src/main/kotlin/gropius/sync/github/config/IMSConfigManager.kt (1)

152-182: Exclude abstract templates from selection sets.

findTemplates() only filters !isDeprecated; with the new isAbstract flag, an abstract template can satisfy the “identical” check and block creation of a usable template, or be returned for use and later rejected by validation. Filter out isAbstract in both template queries.

🔧 Suggested fix
-        val acceptableTemplates = neoOperations.findAll<IMSTemplate>().filter {
-            (!it.isDeprecated) && isContentCompatible(
+        val acceptableTemplates = neoOperations.findAll<IMSTemplate>().filter {
+            (!it.isDeprecated) && (!it.isAbstract) && isContentCompatible(
                 it, IMSConfig.IMS_TEMPLATE_NAME, IMSConfig.IMS_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsProjectTemplate().value,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_NAME,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsIssueTemplate().value, IMS_ISSUE_TEMPLATE_NAME, IMS_ISSUE_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsUserTemplate().value, IMS_USER_TEMPLATE_NAME, IMS_USER_TEMPLATE_FIELDS
             )
         }.toSet().toMutableSet()
         val identicalTemplates = neoOperations.findAll<IMSTemplate>().filter {
-            (!it.isDeprecated) && isContentIdentical(
+            (!it.isDeprecated) && (!it.isAbstract) && isContentIdentical(
                 it, IMSConfig.IMS_TEMPLATE_NAME, IMSConfig.IMS_TEMPLATE_FIELDS
             ) && isContentIdentical(
                 it.imsProjectTemplate().value,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_NAME,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_FIELDS
             ) && isContentIdentical(
                 it.imsIssueTemplate().value, IMS_ISSUE_TEMPLATE_NAME, IMS_ISSUE_TEMPLATE_FIELDS
             ) && isContentIdentical(
                 it.imsUserTemplate().value, IMS_USER_TEMPLATE_NAME, IMS_USER_TEMPLATE_FIELDS
             )
         }.toSet().toMutableSet()
sync-jira/src/main/kotlin/gropius/sync/jira/config/IMSConfigManager.kt (1)

112-128: Exclude abstract templates from the acceptable set.

With the new isAbstract flag, findTemplates() can currently accept abstract templates, which will later be rejected by validateTemplateUsage and break sync flows.

🔧 Proposed fix
-        val acceptableTemplates = neoOperations.findAll<IMSTemplate>().filter {
-            (!it.isDeprecated) && isContentCompatible(
+        val acceptableTemplates = neoOperations.findAll<IMSTemplate>().filter {
+            (!it.isDeprecated) && (!it.isAbstract) && isContentCompatible(
                 it, IMSConfig.IMS_TEMPLATE_NAME, IMSConfig.IMS_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsProjectTemplate().value,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_NAME,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsIssueTemplate().value, IMS_ISSUE_TEMPLATE_NAME, IMS_ISSUE_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsUserTemplate().value, IMS_USER_TEMPLATE_NAME, IMS_USER_TEMPLATE_FIELDS
             )
         }.toSet().toMutableSet()
🧹 Nitpick comments (4)
core/src/main/kotlin/gropius/service/template/TemplateService.kt (1)

28-35: Consider enhancing error messages with template identification.

The error messages are generic and don't identify which template failed validation. Including the template's name or ID would improve debuggability.

♻️ Suggested improvement
     suspend fun validateTemplateUsage(template: Template<*, *>) {
         if (template.isAbstract) {
-            throw IllegalStateException("Cannot use abstract template")
+            throw IllegalStateException("Cannot use abstract template: ${template.name}")
         }
         if (template.isDeprecated) {
-            throw IllegalStateException("Cannot use deprecated template")
+            throw IllegalStateException("Cannot use deprecated template: ${template.name}")
         }
     }
core/src/main/kotlin/gropius/service/architecture/InterfaceSpecificationService.kt (1)

86-91: Consider validating template usage earlier for fail-fast behavior.

The template validation at line 90 occurs after validateInitialTemplatedFields (line 88) and after creating the InterfaceSpecification object (line 89). If the template is abstract or deprecated, this work is wasted. Moving validation immediately after fetching the template would fail faster.

♻️ Suggested reordering
     suspend fun createInterfaceSpecification(
         component: Component, input: InterfaceSpecificationInput
     ): InterfaceSpecification {
         input.validate()
         val template = interfaceSpecificationTemplateRepository.findById(input.template)
+        templateService.validateTemplateUsage(template)
         val templatedFields = templatedNodeService.validateInitialTemplatedFields(template, input)
         val interfaceSpecification = InterfaceSpecification(input.name, input.description, templatedFields)
-        templateService.validateTemplateUsage(template)
         interfaceSpecification.template().value = template
sync-jira/src/main/kotlin/gropius/sync/jira/JiraDataService.kt (1)

106-108: Consider using named arguments for Boolean parameters to improve readability.

With multiple consecutive Boolean arguments, the code becomes harder to read and maintain. Named arguments would clarify the intent.

♻️ Suggested improvement
         return neoOperations.findAll(IssueTemplate::class.java).awaitFirstOrNull() ?: neoOperations.save(
-            IssueTemplate("noissue", "", mutableMapOf(), false, false)
+            IssueTemplate(
+                name = "noissue",
+                description = "",
+                templateFieldSpecifications = mutableMapOf(),
+                isDeprecated = false,
+                isAbstract = false
+            )
         ).awaitSingle()
core/src/main/kotlin/gropius/service/architecture/IMSService.kt (1)

56-60: Consider validating template usage earlier for fail-fast behavior.

Similar to the pattern in InterfaceSpecificationService, the template validation occurs after creating the IMS object and validating templated fields. Moving validation immediately after fetching the template would avoid unnecessary work if the template is invalid.

♻️ Suggested reordering
         val template = imsTemplateRepository.findById(input.template)
+        templateService.validateTemplateUsage(template)
         val templatedFields = templatedNodeService.validateInitialTemplatedFields(template, input)
         val ims = IMS(input.name, input.description, templatedFields)
-        templateService.validateTemplateUsage(template)
         ims.template().value = template

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sync-github/src/main/kotlin/gropius/sync/github/config/IMSConfigManager.kt (1)

153-178: Also exclude abstract/deprecated sub-templates.

Line 153 and Line 167 only filter IMSTemplate itself. If any of the nested IMSProjectTemplate, IMSIssueTemplate, or IMSUserTemplate are abstract/deprecated, they can still be selected and assigned, which undermines the new validation intent.

💡 Suggested fix
-        val acceptableTemplates = neoOperations.findAll<IMSTemplate>().filter {
-            (!it.isDeprecated && !it.isAbstract) && isContentCompatible(
+        val acceptableTemplates = neoOperations.findAll<IMSTemplate>().filter {
+            (!it.isDeprecated && !it.isAbstract)
+            && (!it.imsProjectTemplate().value.isDeprecated && !it.imsProjectTemplate().value.isAbstract)
+            && (!it.imsIssueTemplate().value.isDeprecated && !it.imsIssueTemplate().value.isAbstract)
+            && (!it.imsUserTemplate().value.isDeprecated && !it.imsUserTemplate().value.isAbstract)
+            && isContentCompatible(
                 it, IMSConfig.IMS_TEMPLATE_NAME, IMSConfig.IMS_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsProjectTemplate().value,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_NAME,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsIssueTemplate().value, IMS_ISSUE_TEMPLATE_NAME, IMS_ISSUE_TEMPLATE_FIELDS
             ) && isContentCompatible(
                 it.imsUserTemplate().value, IMS_USER_TEMPLATE_NAME, IMS_USER_TEMPLATE_FIELDS
             )
         }.toSet().toMutableSet()
         val identicalTemplates = neoOperations.findAll<IMSTemplate>().filter {
-            (!it.isDeprecated && !it.isAbstract) && isContentIdentical(
+            (!it.isDeprecated && !it.isAbstract)
+            && (!it.imsProjectTemplate().value.isDeprecated && !it.imsProjectTemplate().value.isAbstract)
+            && (!it.imsIssueTemplate().value.isDeprecated && !it.imsIssueTemplate().value.isAbstract)
+            && (!it.imsUserTemplate().value.isDeprecated && !it.imsUserTemplate().value.isAbstract)
+            && isContentIdentical(
                 it, IMSConfig.IMS_TEMPLATE_NAME, IMSConfig.IMS_TEMPLATE_FIELDS
             ) && isContentIdentical(
                 it.imsProjectTemplate().value,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_NAME,
                 IMSProjectConfig.IMS_PROJECT_TEMPLATE_FIELDS
             ) && isContentIdentical(
                 it.imsIssueTemplate().value, IMS_ISSUE_TEMPLATE_NAME, IMS_ISSUE_TEMPLATE_FIELDS
             ) && isContentIdentical(
                 it.imsUserTemplate().value, IMS_USER_TEMPLATE_NAME, IMS_USER_TEMPLATE_FIELDS
             )
         }.toSet().toMutableSet()

@nk-coding nk-coding merged commit dbf6c88 into main Jan 23, 2026
2 checks passed
@nk-coding nk-coding deleted the feature/abstract_templates branch January 23, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant