feat(#21): Replaced chat comment component with proper cursor-based commenting

This commit is contained in:
2025-12-25 18:03:31 +01:00
parent 7f7852a66a
commit e472a5715d
27 changed files with 968 additions and 244 deletions

View File

@@ -90,8 +90,8 @@ task generate_legalconsenthub_server(type: org.openapitools.generator.gradle.plu
enumPropertyNaming: 'original',
interfaceOnly : 'true',
useSpringBoot3 : 'true']
typeMappings = [DateTime: "LocalDateTime"]
importMappings = [LocalDateTime: "java.time.LocalDateTime"]
typeMappings = [DateTime: "Instant"]
importMappings = [Instant: "java.time.Instant"]
}
compileKotlin.dependsOn(tasks.generate_legalconsenthub_server)

View File

@@ -18,7 +18,7 @@ import jakarta.persistence.OneToMany
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import java.time.Instant
import java.util.UUID
@Entity
@@ -47,8 +47,8 @@ class ApplicationForm(
var lastModifiedBy: User,
@CreatedDate
@Column(nullable = false)
var createdAt: LocalDateTime? = null,
var createdAt: Instant? = null,
@LastModifiedDate
@Column(nullable = false)
var modifiedAt: LocalDateTime? = null,
var modifiedAt: Instant? = null,
)

View File

@@ -33,9 +33,12 @@ class ApplicationFormController(
)
override fun getAllApplicationForms(organizationId: String?): ResponseEntity<PagedApplicationFormDto> =
ResponseEntity.ok(
pagedApplicationFormMapper.toPagedApplicationFormDto(
applicationFormService.getApplicationForms(organizationId),
),
applicationFormService.getApplicationFormsWithCommentCounts(organizationId).let { result ->
pagedApplicationFormMapper.toPagedApplicationFormDto(
result.page,
result.commentCountByApplicationFormId,
)
},
)
@PreAuthorize(

View File

@@ -19,8 +19,9 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSubSectionSna
import org.springframework.stereotype.Service
import org.thymeleaf.TemplateEngine
import org.thymeleaf.context.Context
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.UUID
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionOperator as VisibilityConditionOperatorDto
@@ -39,7 +40,7 @@ class ApplicationFormFormatService(
fun generatePdf(
snapshot: ApplicationFormSnapshotDto,
createdAt: LocalDateTime?,
createdAt: Instant?,
): ByteArray {
val latexContent = generateLatex(snapshot, createdAt)
return pdfRenderer.render(latexContent)
@@ -58,7 +59,7 @@ class ApplicationFormFormatService(
fun generateLatex(
snapshot: ApplicationFormSnapshotDto,
createdAt: LocalDateTime?,
createdAt: Instant?,
): String {
val filteredSnapshot = filterVisibleElements(snapshot)
val exportModel = buildLatexExportModel(filteredSnapshot, createdAt)
@@ -88,7 +89,7 @@ class ApplicationFormFormatService(
organizationId = LatexEscaper.escape(applicationForm.organizationId),
employer = LatexEscaper.escape("Arbeitgeber der Organisation ${applicationForm.organizationId}"),
worksCouncil = LatexEscaper.escape("Betriebsrat der Organisation ${applicationForm.organizationId}"),
createdAt = applicationForm.createdAt?.format(dateFormatter) ?: "",
createdAt = applicationForm.createdAt?.atZone(ZoneId.of("Europe/Berlin"))?.format(dateFormatter) ?: "",
sections =
applicationForm.formElementSections.map { section ->
LatexSection(
@@ -116,7 +117,7 @@ class ApplicationFormFormatService(
private fun buildLatexExportModel(
snapshot: ApplicationFormSnapshotDto,
createdAt: LocalDateTime?,
createdAt: Instant?,
): LatexExportModel {
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
@@ -126,7 +127,7 @@ class ApplicationFormFormatService(
organizationId = LatexEscaper.escape(snapshot.organizationId),
employer = LatexEscaper.escape("Arbeitgeber der Organisation ${snapshot.organizationId}"),
worksCouncil = LatexEscaper.escape("Betriebsrat der Organisation ${snapshot.organizationId}"),
createdAt = createdAt?.format(dateFormatter) ?: "",
createdAt = createdAt?.atZone(ZoneId.of("Europe/Berlin"))?.format(dateFormatter) ?: "",
sections =
snapshot.sections.map { section ->
LatexSection(

View File

@@ -6,7 +6,7 @@ import com.betriebsratkanzlei.legalconsenthub.user.UserMapper
import com.betriebsratkanzlei.legalconsenthub.user.UserService
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import org.springframework.stereotype.Component
import java.time.LocalDateTime
import java.time.Instant
import java.util.UUID
@Component
@@ -16,6 +16,12 @@ class ApplicationFormMapper(
private val userService: UserService,
) {
fun toApplicationFormDto(applicationForm: ApplicationForm): ApplicationFormDto =
toApplicationFormDto(applicationForm, null)
fun toApplicationFormDto(
applicationForm: ApplicationForm,
commentCount: Long?,
): ApplicationFormDto =
ApplicationFormDto(
id = applicationForm.id,
name = applicationForm.name,
@@ -30,9 +36,10 @@ class ApplicationFormMapper(
organizationId = applicationForm.organizationId,
createdBy = userMapper.toUserDto(applicationForm.createdBy),
lastModifiedBy = userMapper.toUserDto(applicationForm.lastModifiedBy),
createdAt = applicationForm.createdAt ?: LocalDateTime.now(),
modifiedAt = applicationForm.modifiedAt ?: LocalDateTime.now(),
createdAt = applicationForm.createdAt ?: Instant.now(),
modifiedAt = applicationForm.modifiedAt ?: Instant.now(),
status = applicationForm.status,
commentCount = commentCount,
)
fun toNewApplicationForm(applicationFormDto: ApplicationFormDto): ApplicationForm {

View File

@@ -1,6 +1,7 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.application_form_version.ApplicationFormVersionService
import com.betriebsratkanzlei.legalconsenthub.comment.CommentRepository
import com.betriebsratkanzlei.legalconsenthub.email.ApplicationFormCreatedEvent
import com.betriebsratkanzlei.legalconsenthub.email.ApplicationFormSubmittedEvent
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormInvalidStateException
@@ -22,6 +23,11 @@ import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import java.util.UUID
data class ApplicationFormPageWithCommentCounts(
val page: Page<ApplicationForm>,
val commentCountByApplicationFormId: Map<UUID, Long>,
)
@Service
class ApplicationFormService(
private val applicationFormRepository: ApplicationFormRepository,
@@ -31,6 +37,7 @@ class ApplicationFormService(
private val versionService: ApplicationFormVersionService,
private val userService: UserService,
private val eventPublisher: ApplicationEventPublisher,
private val commentRepository: CommentRepository,
) {
fun createApplicationForm(applicationFormDto: ApplicationFormDto): ApplicationForm {
val applicationForm = applicationFormMapper.toNewApplicationForm(applicationFormDto)
@@ -62,10 +69,26 @@ class ApplicationFormService(
}
fun getApplicationForms(organizationId: String?): Page<ApplicationForm> {
val pageable = PageRequest.of(0, 10)
val pageable = PageRequest.of(0, 100)
return applicationFormRepository.findAllByIsTemplateFalseAndOrganizationId(organizationId, pageable)
}
fun getApplicationFormsWithCommentCounts(organizationId: String?): ApplicationFormPageWithCommentCounts {
val page = getApplicationForms(organizationId)
val applicationFormIds = page.content.mapNotNull { it.id }
if (applicationFormIds.isEmpty()) {
return ApplicationFormPageWithCommentCounts(page, emptyMap())
}
val counts =
commentRepository.countByApplicationFormIds(applicationFormIds).associate { projection ->
projection.applicationFormId to projection.commentCount
}
return ApplicationFormPageWithCommentCounts(page, counts)
}
fun updateApplicationForm(
id: UUID,
applicationFormDto: ApplicationFormDto,

View File

@@ -3,14 +3,25 @@ package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedApplicationFormDto
import org.springframework.data.domain.Page
import org.springframework.stereotype.Component
import java.util.UUID
@Component
class PagedApplicationFormMapper(
private val applicationFormMapper: ApplicationFormMapper,
) {
fun toPagedApplicationFormDto(pagedApplicationForm: Page<ApplicationForm>): PagedApplicationFormDto =
toPagedApplicationFormDto(pagedApplicationForm, emptyMap())
fun toPagedApplicationFormDto(
pagedApplicationForm: Page<ApplicationForm>,
commentCountByApplicationFormId: Map<UUID, Long>,
): PagedApplicationFormDto =
PagedApplicationFormDto(
content = pagedApplicationForm.content.map { applicationFormMapper.toApplicationFormDto(it) },
content =
pagedApplicationForm.content.map { applicationForm ->
val count = applicationForm.id?.let { commentCountByApplicationFormId[it] } ?: 0L
applicationFormMapper.toApplicationFormDto(applicationForm, count)
},
number = pagedApplicationForm.number,
propertySize = pagedApplicationForm.size,
numberOfElements = pagedApplicationForm.numberOfElements,

View File

@@ -16,7 +16,7 @@ import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import java.time.Instant
import java.util.UUID
@Entity
@@ -45,5 +45,5 @@ class ApplicationFormVersion(
var createdBy: User,
@CreatedDate
@Column(nullable = false)
var createdAt: LocalDateTime? = null,
var createdAt: Instant? = null,
)

View File

@@ -13,7 +13,7 @@ import jakarta.persistence.ManyToOne
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import java.time.Instant
import java.util.UUID
@Entity
@@ -22,17 +22,17 @@ class Comment(
@Id
@GeneratedValue
var id: UUID? = null,
@Column(nullable = false)
@Column(nullable = false, columnDefinition = "TEXT")
var message: String = "",
@ManyToOne
@JoinColumn(name = "created_by_id", nullable = false)
var createdBy: User,
@CreatedDate
@Column(nullable = false)
var createdAt: LocalDateTime? = null,
var createdAt: Instant? = null,
@LastModifiedDate
@Column(nullable = false)
var modifiedAt: LocalDateTime? = null,
var modifiedAt: Instant? = null,
@ManyToOne
@JoinColumn(name = "application_form_id", nullable = false)
var applicationForm: ApplicationForm? = null,

View File

@@ -1,19 +1,20 @@
package com.betriebsratkanzlei.legalconsenthub.comment
import com.betriebsratkanzlei.legalconsenthub_api.api.CommentApi
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormCommentCountsDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CursorPagedCommentDto
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.RestController
import java.time.Instant
import java.util.UUID
@RestController
class CommentController(
val commentService: CommentService,
val commentMapper: CommentMapper,
val pagedCommentMapper: PagedCommentMapper,
) : CommentApi {
@PreAuthorize(
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
@@ -32,12 +33,36 @@ class CommentController(
@PreAuthorize(
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
)
override fun getCommentsByApplicationFormId(applicationFormId: UUID): ResponseEntity<PagedCommentDto> =
ResponseEntity.ok(
pagedCommentMapper.toPagedCommentDto(
commentService.getComments(applicationFormId),
override fun getGroupedCommentCountByApplicationFromId(
applicationFormId: UUID,
): ResponseEntity<ApplicationFormCommentCountsDto> {
val counts = commentService.getGroupedCommentCountByApplicationFromId(applicationFormId)
return ResponseEntity.ok(
ApplicationFormCommentCountsDto(
counts = counts.mapKeys { it.key.toString() },
),
)
}
@PreAuthorize(
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
)
override fun getCommentsByApplicationFormId(
applicationFormId: UUID,
formElementId: UUID?,
cursorCreatedAt: Instant?,
limit: Int,
): ResponseEntity<CursorPagedCommentDto> {
val page = commentService.getComments(applicationFormId, formElementId, cursorCreatedAt, limit)
return ResponseEntity.ok(
CursorPagedCommentDto(
content = page.comments.map { commentMapper.toCommentDto(it) },
nextCursorCreatedAt = page.nextCursorCreatedAt,
hasMore = page.hasMore,
),
)
}
@PreAuthorize(
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
@@ -48,7 +73,7 @@ class CommentController(
): ResponseEntity<CommentDto> =
ResponseEntity.ok(
commentMapper.toCommentDto(
commentService.updateComment(commentDto),
commentService.updateComment(id, commentDto),
),
)

View File

@@ -9,7 +9,7 @@ import com.betriebsratkanzlei.legalconsenthub.user.UserService
import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto
import org.springframework.stereotype.Component
import java.time.LocalDateTime
import java.time.Instant
import java.util.UUID
@Component
@@ -23,8 +23,8 @@ class CommentMapper(
CommentDto(
id = comment.id ?: throw IllegalStateException("Comment ID must not be null!"),
message = comment.message,
createdAt = comment.createdAt ?: LocalDateTime.now(),
modifiedAt = comment.modifiedAt ?: LocalDateTime.now(),
createdAt = comment.createdAt ?: Instant.now(),
modifiedAt = comment.modifiedAt ?: Instant.now(),
createdBy = userMapper.toUserDto(comment.createdBy),
applicationFormId =
comment.applicationForm?.id
@@ -56,6 +56,14 @@ class CommentMapper(
)
}
fun applyUpdate(
existing: Comment,
commentDto: CommentDto,
): Comment {
existing.message = commentDto.message
return existing
}
fun toComment(
applicationFormId: UUID,
formElementId: UUID,

View File

@@ -4,13 +4,68 @@ import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.Repository
import java.time.Instant
import java.util.UUID
interface ApplicationFormCommentCountProjection {
val applicationFormId: UUID
val commentCount: Long
}
interface FormElementCommentCountProjection {
val formElementId: UUID
val commentCount: Long
}
@Repository
interface CommentRepository : JpaRepository<Comment, UUID> {
fun findAllByApplicationForm(
applicationForm: ApplicationForm,
pageable: Pageable,
): Page<Comment>
@Query(
"""
select c.applicationForm.id as applicationFormId, count(c.id) as commentCount
from Comment c
where c.applicationForm.id in :applicationFormIds
group by c.applicationForm.id
""",
)
fun countByApplicationFormIds(
@Param("applicationFormIds") applicationFormIds: Collection<UUID>,
): List<ApplicationFormCommentCountProjection>
@Query(
"""
select c.*
from comment c
where c.application_form_id = :applicationFormId
and (cast(:formElementId as uuid) is null or c.form_element_id = :formElementId)
and (cast(:cursorCreatedAt as timestamp) is null or c.created_at < :cursorCreatedAt)
order by c.created_at desc, c.id desc
""",
nativeQuery = true,
)
fun findNextByApplicationFormId(
@Param("applicationFormId") applicationFormId: UUID,
@Param("formElementId") formElementId: UUID?,
@Param("cursorCreatedAt") cursorCreatedAt: Instant?,
pageable: Pageable,
): List<Comment>
@Query(
"""
select c.formElement.id as formElementId, count(c.id) as commentCount
from Comment c
where c.applicationForm.id = :applicationFormId
group by c.formElement.id
""",
)
fun countByApplicationFormIdGroupByFormElementId(
@Param("applicationFormId") applicationFormId: UUID,
): List<FormElementCommentCountProjection>
}

View File

@@ -7,11 +7,17 @@ import com.betriebsratkanzlei.legalconsenthub.error.CommentNotFoundException
import com.betriebsratkanzlei.legalconsenthub.error.CommentNotUpdatedException
import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import java.time.Instant
import java.util.UUID
data class CursorCommentPage(
val comments: List<Comment>,
val nextCursorCreatedAt: Instant?,
val hasMore: Boolean,
)
@Service
class CommentService(
private val commentRepository: CommentRepository,
@@ -36,25 +42,55 @@ class CommentService(
fun getCommentById(id: UUID): Comment = commentRepository.findById(id).orElseThrow { CommentNotFoundException(id) }
fun getComments(applicationFormId: UUID): Page<Comment> {
val applicationForm =
applicationFormRepository.findById(applicationFormId).orElse(null)
val pageable = PageRequest.of(0, 10)
return commentRepository.findAllByApplicationForm(applicationForm, pageable)
fun getComments(
applicationFormId: UUID,
formElementId: UUID?,
cursorCreatedAt: Instant?,
limit: Int,
): CursorCommentPage {
applicationFormRepository.findById(applicationFormId).orElse(null)
val pageSize = limit.coerceIn(1, 50)
val fetchSize = pageSize + 1
val comments =
commentRepository.findNextByApplicationFormId(
applicationFormId = applicationFormId,
formElementId = formElementId,
cursorCreatedAt = cursorCreatedAt,
pageable = PageRequest.of(0, fetchSize),
)
val hasMore = comments.size > pageSize
val pageItems = if (hasMore) comments.take(pageSize) else comments
val nextCursor = if (hasMore) pageItems.lastOrNull()?.createdAt else null
return CursorCommentPage(
comments = pageItems,
nextCursorCreatedAt = nextCursor,
hasMore = hasMore,
)
}
fun updateComment(commentDto: CommentDto): Comment {
// TODO find statt mappen?
val comment = commentMapper.toComment(commentDto)
val updatedComment: Comment
fun getGroupedCommentCountByApplicationFromId(applicationFormId: UUID): Map<UUID, Long> {
applicationFormRepository.findById(applicationFormId).orElse(null)
try {
updatedComment = commentRepository.save(comment)
return commentRepository
.countByApplicationFormIdGroupByFormElementId(applicationFormId)
.associate { it.formElementId to it.commentCount }
}
fun updateComment(
id: UUID,
commentDto: CommentDto,
): Comment {
val existing = getCommentById(id)
val updated = commentMapper.applyUpdate(existing, commentDto)
return try {
commentRepository.save(updated)
} catch (e: Exception) {
throw CommentNotUpdatedException(e, commentDto.id)
throw CommentNotUpdatedException(e, id)
}
return updatedComment
}
fun deleteCommentByID(id: UUID) {

View File

@@ -1,23 +0,0 @@
package com.betriebsratkanzlei.legalconsenthub.comment
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto
import org.springframework.data.domain.Page
import org.springframework.stereotype.Component
@Component
class PagedCommentMapper(
private val commentMapper: CommentMapper,
) {
fun toPagedCommentDto(pagedComment: Page<Comment>): PagedCommentDto =
PagedCommentDto(
content = pagedComment.content.map { commentMapper.toCommentDto(it) },
number = pagedComment.number,
propertySize = pagedComment.size,
numberOfElements = pagedComment.numberOfElements,
last = pagedComment.isLast,
totalPages = pagedComment.totalPages,
totalElements = pagedComment.totalElements,
empty = pagedComment.isEmpty,
first = pagedComment.isFirst,
)
}

View File

@@ -13,7 +13,7 @@ import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import java.time.Instant
import java.util.UUID
@Entity
@@ -42,5 +42,5 @@ class Notification(
var organizationId: String = "",
@CreatedDate
@Column(nullable = false)
var createdAt: LocalDateTime? = null,
var createdAt: Instant? = null,
)

View File

@@ -8,7 +8,7 @@ import jakarta.persistence.Table
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import java.time.Instant
@Entity
@EntityListeners(AuditingEntityListener::class)
@@ -29,8 +29,8 @@ class User(
var emailOnFormSubmitted: Boolean = true,
@CreatedDate
@Column(nullable = false)
var createdAt: LocalDateTime? = null,
var createdAt: Instant? = null,
@LastModifiedDate
@Column(nullable = false)
var modifiedAt: LocalDateTime? = null,
var modifiedAt: Instant? = null,
)

View File

@@ -1,53 +1,53 @@
create table app_user
(
email_on_form_created boolean not null,
email_on_form_submitted boolean not null,
created_at timestamp(6) not null,
modified_at timestamp(6) not null,
email_on_form_created boolean not null,
email_on_form_submitted boolean not null,
created_at timestamp(6) with time zone not null,
modified_at timestamp(6) with time zone not null,
email varchar(255),
keycloak_id varchar(255) not null,
name varchar(255) not null,
keycloak_id varchar(255) not null,
name varchar(255) not null,
organization_id varchar(255),
primary key (keycloak_id)
);
create table application_form
(
is_template boolean not null,
created_at timestamp(6) not null,
modified_at timestamp(6) not null,
id uuid not null,
created_by_id varchar(255) not null,
last_modified_by_id varchar(255) not null,
name varchar(255) not null,
is_template boolean not null,
created_at timestamp(6) with time zone not null,
modified_at timestamp(6) with time zone not null,
id uuid not null,
created_by_id varchar(255) not null,
last_modified_by_id varchar(255) not null,
name varchar(255) not null,
organization_id varchar(255),
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
primary key (id)
);
create table application_form_version
(
version_number integer not null,
created_at timestamp(6) not null,
application_form_id uuid not null,
id uuid not null,
created_by_id varchar(255) not null,
name varchar(255) not null,
organization_id varchar(255) not null,
snapshot_data TEXT not null,
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
version_number integer not null,
created_at timestamp(6) with time zone not null,
application_form_id uuid not null,
id uuid not null,
created_by_id varchar(255) not null,
name varchar(255) not null,
organization_id varchar(255) not null,
snapshot_data TEXT not null,
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
primary key (id)
);
create table comment
(
created_at timestamp(6) not null,
modified_at timestamp(6) not null,
application_form_id uuid not null,
form_element_id uuid not null,
id uuid not null,
created_by_id varchar(255) not null,
message varchar(255) not null,
created_at timestamp(6) with time zone not null,
modified_at timestamp(6) with time zone not null,
application_form_id uuid not null,
form_element_id uuid not null,
id uuid not null,
created_by_id varchar(255) not null,
message TEXT not null,
primary key (id)
);
@@ -109,16 +109,16 @@ create table form_element_sub_section
create table notification
(
is_read boolean not null,
created_at timestamp(6) not null,
id uuid not null,
click_target varchar(255) not null,
message TEXT not null,
organization_id varchar(255) not null,
is_read boolean not null,
created_at timestamp(6) with time zone not null,
id uuid not null,
click_target varchar(255) not null,
message TEXT not null,
organization_id varchar(255) not null,
recipient_id varchar(255),
target_roles TEXT,
title varchar(255) not null,
type varchar(255) not null check (type in ('INFO', 'WARNING', 'ERROR')),
title varchar(255) not null,
type varchar(255) not null check (type in ('INFO', 'WARNING', 'ERROR')),
primary key (id)
);
@@ -136,9 +136,7 @@ alter table if exists application_form_version
add constraint FKpfri4lhy9wqfsp8esabedkq6c
foreign key (application_form_id)
references application_form
on
delete
cascade;
on delete cascade;
alter table if exists application_form_version
add constraint FKl6fbcrvh439gbwgcvvfyxaggi