feat(backend): persist tasks and generated message history

- add EntityTask domain and CRUD API backed by PostgreSQL

- relate generated messages directly to tasks and delete on task removal

- move preview generation to backend Llama endpoint

- migrate frontend task APIs from localStorage to backend endpoints

- update tests and CLAUDE rules for backend-owned LLM/persistence
This commit is contained in:
2026-03-27 02:46:56 -03:00
parent f2a16b5cf6
commit ebcea643c4
20 changed files with 1181 additions and 244 deletions

View File

@@ -0,0 +1,53 @@
package com.condado.newsletter.model
import jakarta.persistence.CascadeType
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.FetchType
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.OneToMany
import jakarta.persistence.Table
import org.hibernate.annotations.CreationTimestamp
import java.time.LocalDateTime
import java.util.UUID
/**
* Represents a configurable task belonging to a virtual entity.
*/
@Entity
@Table(name = "entity_tasks")
class EntityTask(
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "entity_id", nullable = false)
val virtualEntity: VirtualEntity,
@Column(nullable = false)
val name: String,
@Column(columnDefinition = "TEXT", nullable = false)
val prompt: String,
@Column(name = "schedule_cron", nullable = false)
val scheduleCron: String,
@Column(name = "email_lookback", nullable = false)
val emailLookback: String,
@Column(nullable = false)
val active: Boolean = true,
@CreationTimestamp
@Column(name = "created_at", updatable = false, nullable = false)
val createdAt: LocalDateTime? = null
) {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
var id: UUID? = null
@OneToMany(mappedBy = "task", cascade = [CascadeType.ALL], orphanRemoval = true)
val generatedMessages: MutableList<GeneratedMessageHistory> = mutableListOf()
}

View File

@@ -0,0 +1,37 @@
package com.condado.newsletter.model
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.FetchType
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import java.time.LocalDateTime
import java.util.UUID
/**
* Stores generated test messages for a task, so the history survives page reloads and restarts.
*/
@Entity
@Table(name = "generated_message_history")
class GeneratedMessageHistory(
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "task_id", nullable = false)
val task: EntityTask,
@Column(nullable = false)
val label: String,
@Column(columnDefinition = "TEXT", nullable = false)
val content: String,
@Column(name = "created_at", nullable = false)
val createdAt: LocalDateTime = LocalDateTime.now()
) {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
var id: UUID? = null
}