Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
@Document(collection = "tickets")
@CompoundIndexes({
@CompoundIndex(name = "tenant_ticketNumber_idx", def = "{'tenantId':1,'ticketNumber':1}", unique = true),
// TODO(lifecycle-rollout): drop legacy status_order index after `status` field removal
@CompoundIndex(name = "status_order", def = "{'status': 1, 'order': 1}"),
@CompoundIndex(name = "status_kind", def = "{'statusKind': 1}"),
@CompoundIndex(name = "status_id_order", def = "{'statusId': 1, 'order': 1}")
})
Expand All @@ -38,8 +36,6 @@ public class Ticket implements TenantScoped {
private Integer ticketNumber;
private String title;
private String description;
// TODO(lifecycle-rollout): drop legacy status field once all reads/writes use statusKind/statusId
private TicketStatus status;
private String statusId;
private TicketStatusKind statusKind;
private TicketCreationSource creationSource;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.openframe.data.document.ticket.filter;

import com.openframe.data.document.ticket.TicketStatus;
import com.openframe.data.document.ticket.TicketStatusKind;
import com.openframe.data.document.ticket.TicketCreationSource;
import lombok.AllArgsConstructor;
Expand All @@ -20,15 +19,9 @@
@NoArgsConstructor
@AllArgsConstructor
public class TicketQueryFilter {
// TODO(lifecycle-rollout): drop legacy `statuses` field after rollout
// ===== Legacy (lifecycle feature flag OFF) =====
private List<TicketStatus> statuses;

// ===== Lifecycle feature (lifecycle feature flag ON) =====
private List<String> statusIds;
private List<TicketStatusKind> statusKinds;

// ===== Shared =====
private List<String> organizationIds;
private List<String> assigneeIds;
private List<String> labelIds;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.openframe.data.repository.ticket;

import com.openframe.data.document.ticket.Ticket;
import com.openframe.data.document.ticket.TicketStatus;
import com.openframe.data.document.ticket.TicketStatusKind;
import com.openframe.data.document.ticket.filter.TicketQueryFilter;
import org.springframework.data.mongodb.core.query.Query;
Expand All @@ -24,8 +23,6 @@ List<Ticket> findTicketsWithCursor(Query query, String cursor, int limit,

long countTickets(Query query);

Map<TicketStatus, Long> countTicketsByStatus();

Map<TicketStatusKind, Long> countTicketsByStatusKind();

Map<String, Long> countTicketsByStatusId();
Expand All @@ -34,8 +31,6 @@ List<Ticket> findTicketsWithCursor(Query query, String cursor, int limit,

Optional<Long> getAverageResolutionTimeMs();

int updateStatusBulk(TicketStatus fromStatus, TicketStatus toStatus);

int reassignTicketsToStatus(String fromStatusId, String toStatusId, TicketStatusKind toKind);

void updateTitle(String ticketId, String title);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.openframe.data.repository.ticket;

import com.openframe.data.document.ticket.Ticket;
import com.openframe.data.document.ticket.TicketStatus;
import com.openframe.data.document.ticket.TicketStatusKind;
import com.openframe.data.document.ticket.filter.TicketQueryFilter;
import com.openframe.data.mongo.TenantAwareMongoTemplate;
Expand Down Expand Up @@ -32,7 +31,6 @@ public class CustomTicketRepositoryImpl extends TenantAwareRepositorySupport imp
private static final String ID_FIELD = "_id";
private static final String DEFAULT_SORT_FIELD = "_id";

private static final String FIELD_STATUS = "status";
private static final String FIELD_STATUS_ID = "statusId";
private static final String FIELD_STATUS_KIND = "statusKind";
private static final String FIELD_TICKET_NUMBER = "ticketNumber";
Expand All @@ -57,7 +55,6 @@ public class CustomTicketRepositoryImpl extends TenantAwareRepositorySupport imp
private static final List<String> SORTABLE_FIELDS = List.of(
ID_FIELD,
FIELD_TICKET_NUMBER,
FIELD_STATUS,
FIELD_STATUS_KIND,
FIELD_ORGANIZATION_NAME,
FIELD_ASSIGNED_NAME,
Expand All @@ -78,7 +75,6 @@ public Query buildTicketQuery(TicketQueryFilter filter, String search,
Query query = new Query();

if (filter != null) {
addCriteriaIfNotEmpty(query, FIELD_STATUS, filter.getStatuses());
addCriteriaIfNotEmpty(query, FIELD_STATUS_ID, filter.getStatusIds());
addCriteriaIfNotEmpty(query, FIELD_STATUS_KIND, filter.getStatusKinds());
addCriteriaIfNotEmpty(query, FIELD_ORGANIZATION_ID, filter.getOrganizationIds());
Expand Down Expand Up @@ -206,7 +202,6 @@ private Criteria buildIdCriteria(ObjectId cursorId, boolean isDesc) {
private Object getSortFieldValue(Ticket ticket, String sortField) {
return switch (sortField) {
case FIELD_TICKET_NUMBER -> ticket.getTicketNumber();
case FIELD_STATUS -> ticket.getStatus() != null ? ticket.getStatus().name() : null;
case FIELD_STATUS_KIND -> ticket.getStatusKind() != null ? ticket.getStatusKind().name() : null;
case FIELD_ORGANIZATION_NAME -> ticket.getOrganizationName();
case FIELD_ASSIGNED_NAME -> ticket.getAssignedName();
Expand All @@ -224,33 +219,6 @@ public long countTickets(Query query) {
return mongoTemplate.count(query, Ticket.class);
}

@Override
public Map<TicketStatus, Long> countTicketsByStatus() {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(tenantCriteria()),
Aggregation.group(FIELD_STATUS).count().as(AGG_COUNT),
Aggregation.project(AGG_COUNT).and(ID_FIELD).as(FIELD_STATUS)
);

AggregationResults<Document> results = mongoTemplate.aggregate(
aggregation, Ticket.class, Document.class);

Map<TicketStatus, Long> statusCounts = new EnumMap<>(TicketStatus.class);
for (Document doc : results.getMappedResults()) {
String statusStr = doc.getString(FIELD_STATUS);
if (statusStr != null) {
try {
TicketStatus status = TicketStatus.valueOf(statusStr);
statusCounts.put(status, doc.getInteger(AGG_COUNT).longValue());
} catch (IllegalArgumentException e) {
log.warn("Unknown ticket status: {}", statusStr);
}
}
}

return statusCounts;
}

@Override
public Map<TicketStatusKind, Long> countTicketsByStatusKind() {
Aggregation aggregation = Aggregation.newAggregation(
Expand Down Expand Up @@ -328,19 +296,6 @@ public Optional<Long> getAverageResolutionTimeMs() {
return Optional.empty();
}

@Override
public int updateStatusBulk(TicketStatus fromStatus, TicketStatus toStatus) {
Query query = new Query(Criteria.where(FIELD_STATUS).is(fromStatus));
Update update = new Update()
.set(FIELD_STATUS, toStatus)
.set(FIELD_UPDATED_AT, Instant.now());

long modifiedCount = mongoTemplate.updateMulti(query, update, Ticket.class).getModifiedCount();
log.debug("Bulk status update: {} -> {}, modified: {}", fromStatus, toStatus, modifiedCount);

return (int) modifiedCount;
}

@Override
public int reassignTicketsToStatus(String fromStatusId, String toStatusId, TicketStatusKind toKind) {
Query query = new Query(Criteria.where(FIELD_STATUS_ID).is(fromStatusId));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.openframe.data.repository.ticket;

import com.openframe.data.document.ticket.Ticket;
import com.openframe.data.document.ticket.TicketStatus;
import com.openframe.data.repository.TenantAwareRepository;
import org.springframework.data.mongodb.repository.Aggregation;
import org.springframework.data.mongodb.repository.MongoRepository;
Expand All @@ -15,13 +14,8 @@
@TenantAwareRepository
public interface TicketRepository extends MongoRepository<Ticket, String>, CustomTicketRepository {

// TODO(lifecycle-rollout): drop legacy methods (by enum TicketStatus) after rollout
// ===== Legacy (used when lifecycle feature flag is OFF) =====

Optional<Ticket> findByTicketNumber(Integer ticketNumber);

List<Ticket> findByStatus(TicketStatus status);

List<Ticket> findByOrganizationId(String organizationId);

List<Ticket> findByAssignedTo(String assignedTo);
Expand All @@ -33,36 +27,6 @@ public interface TicketRepository extends MongoRepository<Ticket, String>, Custo
@Query("{ '_id': ?0, 'owner.machineId': ?1 }")
Optional<Ticket> findByIdAndOwnerMachineId(String id, String machineId);

@Aggregation(pipeline = {
"{ $match: { 'tenantId': ?1, 'status': ?0, 'order': { $ne: null } } }",
"{ $sort: { 'order': 1 } }",
"{ $limit: 1 }"
})
Optional<Ticket> findFirstInColumn(TicketStatus status, String tenantId);

@Aggregation(pipeline = {
"{ $match: { 'tenantId': ?1, 'status': ?0, 'order': { $ne: null } } }",
"{ $sort: { 'order': -1 } }",
"{ $limit: 1 }"
})
Optional<Ticket> findLastInColumn(TicketStatus status, String tenantId);

@Aggregation(pipeline = {
"{ $match: { 'tenantId': ?2, 'status': ?0, 'order': { $gt: ?1 } } }",
"{ $sort: { 'order': 1 } }",
"{ $limit: 1 }"
})
Optional<Ticket> findFirstAfter(TicketStatus status, String order, String tenantId);

@Aggregation(pipeline = {
"{ $match: { 'tenantId': ?2, 'status': ?0, 'order': { $lt: ?1 } } }",
"{ $sort: { 'order': -1 } }",
"{ $limit: 1 }"
})
Optional<Ticket> findFirstBefore(TicketStatus status, String order, String tenantId);

// ===== Lifecycle feature (used when lifecycle feature flag is ON) =====

long countByStatusId(String statusId);

@Aggregation(pipeline = {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import io.mongock.api.annotations.RollbackExecution;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.core.env.Environment;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
Expand All @@ -28,8 +27,10 @@
import static org.springframework.util.StringUtils.hasText;

@Slf4j
// TODO(lifecycle-rollout): drop runAlways=true after flag is permanently on — body becomes a normal one-shot migration
@ChangeUnit(id = "migrate-ticket-status-model", order = "003", author = "openframe", runAlways = true)
// One-shot migration of any remaining legacy enum-status tickets to the custom-status model
// (statusId/statusKind). Reads the raw `status` field via bson Document, so it stays valid after
// the legacy field/enum are removed from the Ticket POJO.
@ChangeUnit(id = "migrate-ticket-status-model", order = "003", author = "openframe")
public class MigrateTicketStatusesChangeUnit {

private static final String FIELD_ID = "_id";
Expand All @@ -40,7 +41,6 @@ public class MigrateTicketStatusesChangeUnit {
private static final String FIELD_LEGACY_STATUS = "status";
private static final String FIELD_UPDATED_AT = "updatedAt";
private static final String COLLECTION_TICKETS = "tickets";
private static final String LIFECYCLE_FLAG = "openframe.features.tickets.lifecycle.enabled";

private static final String LEGACY_ON_HOLD = "ON_HOLD";

Expand All @@ -52,12 +52,7 @@ public class MigrateTicketStatusesChangeUnit {
);

@Execution
public void execution(MongoTemplate mongoTemplate, Environment environment, TenantIdProvider tenantIdProvider) {
// TODO(lifecycle-rollout): remove flag guard + drop Environment param after rollout
if (!environment.getProperty(LIFECYCLE_FLAG, Boolean.class, false)) {
log.info("Migrate ticket statuses: lifecycle feature disabled; skipping");
return;
}
public void execution(MongoTemplate mongoTemplate, TenantIdProvider tenantIdProvider) {
log.info("Migrate ticket statuses: starting");

String tenantId = tenantIdProvider.getTenantId();
Expand Down
Loading