- Create a package
com.endlessuphill.regent.data.model. - Inside this package, create the following Kotlin files:
(Enums - create in a sub-package like com.endlessuphill.regent.data.model.enums)
// Role.kt
package com.endlessuphill.regent.data.model.enums
enum class Role {
ADMIN, USER, VIEWER
}// JobStatus.kt
package com.endlessuphill.regent.data.model.enums
enum class JobStatus {
PENDING, // Initial state upon submission record creation
QUEUED, // Successfully placed in Redis queue
STARTED, // Picked up by a dispatcher
SUCCESS, // Executor completed successfully
FAILURE // Executor failed or error during dispatch
}// ScheduleType.kt
package com.endlessuphill.regent.data.model.enums
enum class ScheduleType {
ONE_OFF, RECURRING
}// LogLevel.kt
package com.endlessuphill.regent.data.model.enums
enum class LogLevel {
INFO, WARN, ERROR
}// RuntimeType.kt
package com.endlessuphill.regent.data.model.enums
// We'll keep this extensible, maybe load from config later, but start with known types
enum class RuntimeType {
HTTP, CELERY // Add DOCKER, KUBERNETES etc. later
}(Entities - in com.endlessuphill.regent.data.model)
// User.kt
package com.endlessuphill.regent.data.model
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("users") // Explicit table name
data class User(
@Id
val id: UUID = UUID.randomUUID(), // Let DB generate or ensure uniqueness if app generates
val username: String, // Should be unique
val hashedPassword: String,
val createdAt: Instant = Instant.now()
)// Project.kt
package com.endlessuphill.regent.data.model
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("projects")
data class Project(
@Id
val id: UUID = UUID.randomUUID(),
val name: String, // Should be unique
val createdAt: Instant = Instant.now()
)// ProjectUserRole.kt
package com.endlessuphill.regent.data.model
import com.endlessuphill.regent.data.model.enums.Role
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.util.UUID
// Using a separate ID might be simpler with R2DBC than composite keys initially
@Table("project_user_roles")
data class ProjectUserRole(
@Id
val id: UUID = UUID.randomUUID(), // Surrogate key
val projectId: UUID,
val userId: UUID,
val role: Role
// Consider adding unique constraint on (projectId, userId) in DB schema
)// Job.kt
package com.endlessuphill.regent.data.model
import com.endlessuphill.regent.data.model.enums.JobStatus
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("jobs")
data class Job(
@Id
val id: UUID = UUID.randomUUID(),
val projectId: UUID,
val workerDefinitionId: UUID,
val submittedByUserId: UUID,
val parametersJson: String, // Input parameters as JSON string
var status: JobStatus = JobStatus.PENDING,
var resultJson: String? = null, // Store result data as JSON string
val createdAt: Instant = Instant.now(),
var startedAt: Instant? = null,
var completedAt: Instant? = null
)
// Consider adding unique constraint on (projectId, workerDefinitionId) in DB schema// JobLog.kt
package com.endlessuphill.regent.data.model
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("job_logs")
data class JobLog(
@Id
val id: UUID = UUID.randomUUID(),
val jobId: UUID,
val timestamp: Instant = Instant.now(),
val message: String
)// Schedule.kt
package com.endlessuphill.regent.data.model
import com.endlessuphill.regent.data.model.enums.ScheduleType
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("schedules")
data class Schedule(
@Id
val id: UUID = UUID.randomUUID(),
val projectId: UUID,
val workerDefinitionId: UUID,
val createdByUserId: UUID,
val type: ScheduleType,
val runAt: Instant? = null, // For ONE_OFF type
val cronExpression: String? = null, // For RECURRING type
val parametersJson: String, // Parameters to use when job is triggered
var isEnabled: Boolean = true,
var lastRunAt: Instant? = null,
var nextRunAt: Instant? = null, // Calculated field for scheduler polling
val createdAt: Instant = Instant.now(),
var updatedAt: Instant = Instant.now()
)
// Consider adding unique constraint on (projectId, workerDefinitionId) in DB schema// RegentLog.kt
package com.endlessuphill.regent.data.model
import com.endlessuphill.regent.data.model.enums.LogLevel
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("regent_logs")
data class RegentLog(
@Id
val id: UUID = UUID.randomUUID(),
val timestamp: Instant = Instant.now(),
val level: LogLevel,
val message: String,
val detailsJson: String? = null // Optional structured details
)// WorkerDefinition.kt
package com.endlessuphill.regent.data.model
import com.endlessuphill.regent.data.model.enums.RuntimeType
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.time.Instant
import java.util.UUID
@Table("worker_definitions")
data class WorkerDefinition(
@Id
val id: UUID = UUID.randomUUID(),
val projectId: UUID,
val name: String, // Unique within a project
val runtimeType: RuntimeType,
val configJson: String, // Store config payload as JSON string
val parameterSchemaJson: String, // Store JSON schema as string
val createdAt: Instant = Instant.now(),
val updatedAt: Instant = Instant.now()
// Consider adding unique constraint on (projectId, name) in DB schema
)
Why always me?