Job.java
package edu.ucsb.cs156.jobs.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Transient;
import java.time.ZonedDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* JPA entity for one asynchronous job: who launched it, its status, and a human-readable log that
* grows while the job runs.
*
* <p>The creator is denormalized into {@code createdById}/{@code createdByEmail} (no foreign key)
* so this entity has no dependency on any app's {@code User} entity; values come from the
* app-implemented {@link edu.ucsb.cs156.jobs.services.JobUserProvider}.
*
* <p>{@code scopeType}/{@code scopeId} optionally associate the job with one app-domain object
* (e.g. {@code "course"}/{@code 17}); both are null for unscoped jobs.
*
* <p>Timestamps are maintained with JPA lifecycle callbacks rather than Spring Data auditing, so
* the library works whether or not the consuming app enables {@code @EnableJpaAuditing}.
*/
@Data
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
@Entity(name = "jobs")
public class Job {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "created_by_id")
private Long createdById;
private String createdByEmail;
private String jobName;
private String status;
private String scopeType;
private Long scopeId;
/**
* Not persisted as a column of this row (see {@code job_logs}, a separate append-only table, one
* row per log line, v0.2.0). This field exists purely as a Java-level convenience: {@link
* edu.ucsb.cs156.jobs.services.JobContext}'s null-repository test seam still accumulates into it
* in-memory so {@code job.getLog()} keeps working in existing tests, and the controller populates
* it explicitly (full text or a tail preview, depending on the endpoint) before a {@code Job} is
* serialized to a client.
*/
@Transient private String log;
private ZonedDateTime createdAt;
private ZonedDateTime updatedAt;
@PrePersist
void onCreate() {
createdAt = ZonedDateTime.now();
updatedAt = createdAt;
}
@PreUpdate
void onUpdate() {
updatedAt = ZonedDateTime.now();
}
}