Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -75,4 +75,15 @@ public ResponseEntity<List<BaseLineDto>> getMyBaseLines(
List<BaseLineDto> list = nodeService.getMyBaseLines(me.getId());
return ResponseEntity.ok(list);
}

// 한줄 요약: 소유자 검증 후 베이스라인과 모든 연관 데이터 일괄 삭제
@DeleteMapping("/{baseLineId}")
public ResponseEntity<Void> deleteBaseLine(
@AuthenticationPrincipal CustomUserDetails me,
@PathVariable Long baseLineId
) {
if (me == null) throw new ApiException(ErrorCode.HANDLE_ACCESS_DENIED, "login required");
nodeService.deleteBaseLineDeep(me.getId(), baseLineId); // 가장 많이 사용하는 호출: 파사드에 위임
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import com.back.domain.node.entity.FollowPolicy;
import com.back.domain.node.entity.NodeCategory;

import java.util.List;

public record DecNodeDto(
Expand Down Expand Up @@ -46,11 +45,14 @@ public record DecNodeDto(
Boolean root, // 라인 헤더면 true
Long pivotLinkBaseNodeId, // 베이스 분기 슬롯에서 올라온 첫 노드면 해당 BaseNode id
Integer pivotSlotIndex, // 0/1 (분기 슬롯 인덱스), 아니면 null
Long pivotLinkDecisionNodeId,

// 단일 패스 렌더용 최소 힌트
Integer renderPhase, // 1=from-base 라인, 2..N=fork 깊이(부모 라인 +1)
Long incomingFromId, // 이 노드로 "들어오는" 에지의 from 노드 id(루트면 포크 원본, 아니면 parentId)
String incomingEdgeType // "normal" | "fork"
String incomingEdgeType, // "root","prelude","from-base","fork","normal"
// 포크 원본 라인 id(디버깅/렌더 보조용)
Long incomingFromLineId
) {
// === 호환 오버로드(기존 서비스 호출 유지) ===
public DecNodeDto(
Expand All @@ -70,6 +72,6 @@ public DecNodeDto(
followPolicy, pinnedCommitId, virtual, effectiveCategory, effectiveSituation,
effectiveDecision, effectiveOptions, effectiveDescription,
null, null, null, null,
null, null, null); // 새 필드는 null 기본값
null, null, null, null,null); // 새 필드는 null 기본값
}
}
5 changes: 5 additions & 0 deletions back/src/main/java/com/back/domain/node/entity/BaseLine.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.back.domain.node.entity;

import com.back.domain.scenario.entity.Scenario;
import com.back.domain.user.entity.User;
import com.back.global.baseentity.BaseEntity;
import jakarta.persistence.*;
Expand Down Expand Up @@ -35,6 +36,10 @@ public class BaseLine extends BaseEntity {
@Builder.Default
private List<BaseNode> baseNodes = new ArrayList<>();

@OneToMany(mappedBy = "baseLine", cascade = CascadeType.ALL, orphanRemoval = true)
@Builder.Default
private List<Scenario> scenarios = new ArrayList<>();

//중간 피벗 나이 목록 반환(헤더/꼬리 제외, 중복 제거, 오름차순)
public List<Integer> pivotAges() {
List<BaseNode> nodes = this.baseNodes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package com.back.domain.node.entity;

import com.back.domain.scenario.entity.Scenario;
import com.back.domain.user.entity.User;
import com.back.global.baseentity.BaseEntity;
import jakarta.persistence.*;
Expand Down Expand Up @@ -34,6 +35,9 @@ public class DecisionLine extends BaseEntity {
@Column(nullable = false)
private DecisionLineStatus status;

@Column(name = "parent_line_id")
private Long parentLineId;

@OneToMany(mappedBy = "decisionLine", cascade = CascadeType.ALL, orphanRemoval = true)
private List<DecisionNode> decisionNodes = new ArrayList<>();

Expand All @@ -46,6 +50,10 @@ public class DecisionLine extends BaseEntity {
@JoinColumn(name = "pinned_commit_id")
private BaselineCommit pinnedCommit;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "scenario_id")
private Scenario scenario;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OneToOne(mappedBy = "decisionLine", fetch = FetchType.LAZㅛ)
private Scenario scenario;

시나리오 쪽에서 OneToOne 설정이 되어 있어서 이 방향으로 고민해봐주실 수 있을까요?

추가적으로 sql 구문은 추가할 필요 없을 것 같습니다! 감사합니다!!

// 라인 취소 상태 전이
public void cancel() {
if (this.status == DecisionLineStatus.COMPLETED) {
Expand Down
11 changes: 11 additions & 0 deletions back/src/main/java/com/back/domain/node/entity/DecisionNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public class DecisionNode extends BaseEntity {
@JoinColumn(name = "override_version_id")
private NodeAtomVersion overrideVersion;

@Column(name = "ai_next_situation", columnDefinition = "TEXT")
private String aiNextSituation;

@Column(name = "ai_next_recommended_option", columnDefinition = "TEXT")
private String aiNextRecommendedOption;

// 다음 나이 검증
public void guardNextAgeValid(int nextAge) {
if (nextAge <= this.getAgeYear()) {
Expand All @@ -94,4 +100,9 @@ public void setOverride(NodeAtomVersion version) {
this.followPolicy = FollowPolicy.OVERRIDE;
this.overrideVersion = version;
}

public void setAiHint(String nextSituation, String nextRecommended) {
this.aiNextSituation = nextSituation;
this.aiNextRecommendedOption = nextRecommended;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ public NodeMappers(VersionResolver resolver,
e.getSelectedIndex(),
e.getParentOptionIndex(),
e.getDescription(),
null,
null,
e.getAiNextSituation(),
e.getAiNextRecommendedOption(),
e.getFollowPolicy(),
pinnedCommitId,
null, // virtual 투영은 상위 레이어에서 주입
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@ public interface BaseLineRepository extends JpaRepository<BaseLine, Long> {
// 사용자별 베이스라인 목록 조회 (페이징 및 N+1 방지)
@Query("SELECT DISTINCT bl FROM BaseLine bl LEFT JOIN FETCH bl.baseNodes bn WHERE bl.user.id = :userId ORDER BY bl.createdDate DESC")
Page<BaseLine> findAllByUserIdWithBaseNodes(@Param("userId") Long userId, Pageable pageable);

boolean existsByIdAndUser_Id(Long baseLineId, Long userId);

void deleteByIdAndUser_Id(Long baseLineId, Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ public interface BaseNodeRepository extends JpaRepository<BaseNode, Long> {
@Query("update BaseNode b set b.altOpt2TargetDecisionId = null " +
"where b.id = :id and b.altOpt2TargetDecisionId = :targetId")
int unlinkAlt2IfMatches(@Param("id") Long id, @Param("targetId") Long targetId);

void deleteByBaseLine_Id(Long baseLineId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import com.back.domain.node.entity.BaselineBranch;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
Expand All @@ -20,4 +23,10 @@ public interface BaselineBranchRepository extends JpaRepository<BaselineBranch,

// BaseLine 기준 브랜치 목록 조회
List<BaselineBranch> findByBaseLine_Id(Long baseLineId);

void deleteByBaseLine_Id(Long baseLineId);

@Modifying
@Query("update BaselineBranch b set b.headCommit = null where b.baseLine.id = :baseLineId")
void clearHeadByBaseLineId(@Param("baseLineId") Long baseLineId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ public interface BaselineCommitRepository extends JpaRepository<BaselineCommit,
// N+1 방지용: 부모 커밋 즉시 로딩
@EntityGraph(attributePaths = {"parentCommit"})
List<BaselineCommit> findAll();

void deleteByBranch_BaseLine_Id(Long baseLineId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public interface BaselinePatchRepository extends JpaRepository<BaselinePatch, Lo

// 커밋 집합과 ageYear로 필터링하여 최신 우선 정렬
List<BaselinePatch> findByCommit_IdInAndAgeYearOrderByIdDesc(Collection<Long> commitIds, Integer ageYear);

void deleteByCommit_Branch_BaseLine_Id(Long baseLineId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ public interface DecisionLineRepository extends JpaRepository<DecisionLine, Long
@EntityGraph(attributePaths = {"user"})
Optional<DecisionLine> findWithUserById(Long id);

void deleteByBaseLine_Id(Long baseLineId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ public interface DecisionNodeRepository extends JpaRepository<DecisionNode, Long

// 같은 베이스라인에 속한 "헤드(부모 없음)" 결정 노드들만 조회
List<DecisionNode> findByDecisionLine_BaseLine_IdAndParentIsNull(Long baseLineId);

void deleteByDecisionLine_BaseLine_Id(Long baseLineId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,24 @@
import com.back.domain.node.entity.*;
import com.back.domain.node.mapper.NodeMappers;
import com.back.domain.node.repository.*;
import com.back.domain.scenario.repository.ScenarioRepository;
import com.back.domain.scenario.repository.SceneCompareRepository;
import com.back.domain.scenario.repository.SceneTypeRepository;
import com.back.domain.user.entity.Role;
import com.back.domain.user.entity.User;
import com.back.domain.user.repository.UserRepository;
import com.back.global.exception.ApiException;
import com.back.global.exception.ErrorCode;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
Expand All @@ -31,15 +38,21 @@ class BaseLineService {

private final BaseLineRepository baseLineRepository;
private final BaseNodeRepository baseNodeRepository;
private final DecisionLineRepository decisionLineRepository;
private final DecisionNodeRepository decisionNodeRepository;
private final UserRepository userRepository;
private final NodeDomainSupport support;
private final ScenarioRepository scenarioRepository;
private final SceneTypeRepository sceneTypeRepository;
private final SceneCompareRepository sceneCompareRepository;

// 하이브리드 초기화용
private final NodeAtomRepository atomRepo;
private final NodeAtomVersionRepository versionRepo;
private final BaselineBranchRepository branchRepo;
private final BaselineCommitRepository commitRepo;
private final BaselinePatchRepository patchRepo; // ← 추가
private final BaselinePatchRepository patchRepo;
private final EntityManager em;

private final NodeMappers mappers;

Expand Down Expand Up @@ -131,4 +144,48 @@ public PivotListDto getPivotBaseNodes(Long baseLineId) {
}
return new PivotListDto(baseLineId, list);
}

@Transactional
public void deleteBaseLineDeep(Long userId, Long baseLineId) {
// 가장 많이 사용하는 호출: 소유자/존재 여부 검증
boolean owned = baseLineRepository.existsByIdAndUser_Id(baseLineId, userId);
if (!owned) throw new ApiException(ErrorCode.BASE_LINE_NOT_FOUND, "baseline not found or not owned");

// 가장 많이 사용하는 호출: 결정노드 → 결정라인
decisionNodeRepository.deleteByDecisionLine_BaseLine_Id(baseLineId);
decisionLineRepository.deleteByBaseLine_Id(baseLineId);

// 가장 많이 사용하는 호출: DVCS 역순(Patch→Commit→Branch)
patchRepo.deleteByCommit_Branch_BaseLine_Id(baseLineId);
branchRepo.clearHeadByBaseLineId(baseLineId);
commitRepo.deleteByBranch_BaseLine_Id(baseLineId);
branchRepo.deleteByBaseLine_Id(baseLineId);

// (중간 플러시) 위 벌크 삭제 쿼리 확실히 반영
em.flush();
em.clear();

// 시나리오 삭제(자식 → 부모 순서)
List<Long> scenarioIds = scenarioRepository.findIdsByBaseLine_Id(baseLineId);
if (scenarioIds != null && !scenarioIds.isEmpty()) {
// 가장 많이 사용하는 호출: 시나리오 비교/타입(자식 테이블) 선삭제
sceneCompareRepository.deleteByScenario_IdIn(scenarioIds);
sceneTypeRepository.deleteByScenario_IdIn(scenarioIds);

// (중간 플러시) 자식이 먼저 사라진 것을 보장
em.flush();
em.clear();

// 부모(Scenario) 벌크 삭제
scenarioRepository.deleteByIdIn(scenarioIds);
}

// (중간 플러시) 시나리오 트리 정리 완료 보장
em.flush();
em.clear();

// 가장 많이 사용하는 호출: 베이스노드 → 베이스라인
baseNodeRepository.deleteByBaseLine_Id(baseLineId);
baseLineRepository.deleteByIdAndUser_Id(baseLineId, userId);
}
}
Loading