Skip to content

Commit 8ec5147

Browse files
EpicFnEpicFn
andauthored
[Feat/OPS-326] 대시보드 데이터 저장 체계 구축 (#85)
* refactor : graph 도메인을 dashboard 도메인으로 수정, dashboard 엔티티 생성 * feat : 스페이스 단건 조회 시 대시보드 id도 함께 반환 * refactor : API 명 변경 * dashboard 기반으로 저장/조회 되도록 변경 * refactor : 테스트 코드 수정 * fix : 반환 메세지 수정 * feat : 서명 검증 로직 구현 * refactor : signature 서비스 분리 * fix : 오타 수정 * fix : CI 파이프라인 수정 --------- Co-authored-by: EpicFn <[email protected]>
1 parent 2b90a90 commit 8ec5147

File tree

29 files changed

+695
-227
lines changed

29 files changed

+695
-227
lines changed

.github/workflows/test-server-ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ jobs:
6161
echo "spring.cloud.aws.s3.bucket: ${{ secrets.AWS_S3_BUCKET_NAME }}" >> src/main/resources/application-secrets.yml
6262
echo "spring.cloud.aws.stack.auto: false" >> src/main/resources/application-secrets.yml
6363
64+
echo "liveblocks.secret-key: ${{ secrets.LIVEBLOCKS_SECRET_KEY }}" >> src/main/resources/application-secrets.yml
65+
6466
# 6. application-secrets-server.yml 생성
6567
- name: Generate application-secrets-server.yml
6668
run: |

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ dependencies {
9898
// Playwright for Java
9999
implementation 'com.microsoft.playwright:playwright:1.54.0'
100100

101+
// Apache Commons Codec
102+
implementation"commons-codec:commons-codec:1.19.0"
101103
}
102104

103105
dependencyManagement {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.tuna.zoopzoop.backend.domain.dashboard.controller;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.tags.Tag;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
9+
import org.springframework.web.bind.annotation.*;
10+
import org.tuna.zoopzoop.backend.domain.dashboard.dto.BodyForReactFlow;
11+
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Graph;
12+
import org.tuna.zoopzoop.backend.domain.dashboard.service.DashboardService;
13+
import org.tuna.zoopzoop.backend.domain.dashboard.service.GraphService;
14+
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
15+
import org.tuna.zoopzoop.backend.global.rsData.RsData;
16+
import org.tuna.zoopzoop.backend.global.security.jwt.CustomUserDetails;
17+
18+
import java.nio.file.AccessDeniedException;
19+
20+
@RestController
21+
@RequiredArgsConstructor
22+
@RequestMapping("api/v1/dashboard")
23+
@Tag(name = "ApiV1GraphController", description = "React-flow 데이터 컨트롤러")
24+
public class ApiV1DashboardController {
25+
private final DashboardService dashboardService;
26+
27+
/**
28+
* React-flow 데이터 저장(갱신) API
29+
* @param dashboardId React-flow 데이터의 dashboard 식별 id
30+
* @param requestBody React-flow 에서 보내주는 body 전체
31+
* @param signature Liveblocks-Signature 헤더 값
32+
* @return ResponseEntity<RsData<Void>>
33+
*/
34+
@PutMapping("/{dashboardId}/graph")
35+
@Operation(summary = "React-flow 데이터 저장(갱신)")
36+
public ResponseEntity<RsData<Void>> updateGraph(
37+
@PathVariable Integer dashboardId,
38+
@RequestBody String requestBody,
39+
@RequestHeader("Liveblocks-Signature") String signature
40+
) {
41+
dashboardService.verifyAndUpdateGraph(dashboardId, requestBody, signature);
42+
43+
return ResponseEntity
44+
.status(HttpStatus.OK)
45+
.body(new RsData<>(
46+
"200",
47+
"React-flow 데이터를 저장했습니다.",
48+
null
49+
));
50+
}
51+
52+
/**
53+
* React-flow 데이터 조회 API
54+
* @param dashboardId React-flow 데이터의 dashboard 식별 id
55+
*/
56+
@GetMapping("/{dashboardId}/graph")
57+
@Operation(summary = "React-flow 데이터 조회")
58+
public ResponseEntity<RsData<BodyForReactFlow>> getGraph(
59+
@PathVariable Integer dashboardId,
60+
@AuthenticationPrincipal CustomUserDetails userDetails
61+
) throws AccessDeniedException {
62+
// TODO : 권한 체크 로직 추가
63+
Member member = userDetails.getMember();
64+
dashboardService.verifyAccessPermission(member, dashboardId);
65+
66+
Graph graph = dashboardService.getGraphByDashboardId(dashboardId);
67+
return ResponseEntity
68+
.status(HttpStatus.OK)
69+
.body(new RsData<>(
70+
"200",
71+
"ID: " + dashboardId + " 의 React-flow 데이터를 조회했습니다.",
72+
BodyForReactFlow.from(graph)
73+
));
74+
75+
}
76+
}

src/main/java/org/tuna/zoopzoop/backend/domain/graph/dto/BodyForReactFlow.java renamed to src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/dto/BodyForReactFlow.java

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
package org.tuna.zoopzoop.backend.domain.graph.dto;
1+
package org.tuna.zoopzoop.backend.domain.dashboard.dto;
22

33
import com.fasterxml.jackson.annotation.JsonProperty;
4-
import org.tuna.zoopzoop.backend.domain.graph.entity.Edge;
5-
import org.tuna.zoopzoop.backend.domain.graph.entity.Graph;
6-
import org.tuna.zoopzoop.backend.domain.graph.entity.Node;
7-
import org.tuna.zoopzoop.backend.domain.graph.enums.EdgeType;
8-
import org.tuna.zoopzoop.backend.domain.graph.enums.NodeType;
4+
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Edge;
5+
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Graph;
6+
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Node;
7+
import org.tuna.zoopzoop.backend.domain.dashboard.enums.EdgeType;
8+
import org.tuna.zoopzoop.backend.domain.dashboard.enums.NodeType;
99

1010
import java.util.List;
1111
import java.util.Map;
@@ -15,6 +15,7 @@ public record BodyForReactFlow(
1515
List<NodeDto> nodes,
1616
List<EdgeDto> edges
1717
) {
18+
1819
public record NodeDto(
1920
@JsonProperty("id") String nodeKey,
2021
@JsonProperty("type") String nodeType,
@@ -105,4 +106,40 @@ public static BodyForReactFlow from(Graph graph) {
105106

106107
return new BodyForReactFlow(nodeDtos, edgeDtos);
107108
}
109+
110+
public List<Node> toNodeEntities(Graph graph) {
111+
return this.nodes().stream()
112+
.map(dto -> {
113+
Node node = new Node();
114+
node.setNodeKey(dto.nodeKey());
115+
node.setNodeType(NodeType.valueOf(dto.nodeType().toUpperCase()));
116+
node.setData(dto.data());
117+
node.setPositonX(dto.positionDto().x());
118+
node.setPositonY(dto.positionDto().y());
119+
node.setGraph(graph); // 연관관계 설정
120+
return node;
121+
})
122+
.toList();
123+
}
124+
125+
public List<Edge> toEdgeEntities(Graph graph) {
126+
return this.edges().stream()
127+
.map(dto -> {
128+
Edge edge = new Edge();
129+
edge.setEdgeKey(dto.edgeKey());
130+
edge.setSourceNodeKey(dto.sourceNodeKey());
131+
edge.setTargetNodeKey(dto.targetNodeKey());
132+
edge.setEdgeType(EdgeType.valueOf(dto.edgeType().toUpperCase()));
133+
edge.setAnimated(dto.isAnimated());
134+
if (dto.styleDto() != null) {
135+
edge.setStroke(dto.styleDto().stroke());
136+
edge.setStrokeWidth(dto.styleDto().strokeWidth());
137+
}
138+
edge.setGraph(graph); // 연관관계 설정
139+
return edge;
140+
})
141+
.toList();
142+
}
143+
144+
108145
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.tuna.zoopzoop.backend.domain.dashboard.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
import org.tuna.zoopzoop.backend.domain.space.space.entity.Space;
7+
import org.tuna.zoopzoop.backend.global.jpa.entity.BaseEntity;
8+
9+
@Entity
10+
@Getter
11+
@Setter
12+
public class Dashboard extends BaseEntity {
13+
// 대시보드의 이름
14+
@Column(nullable = false)
15+
private String name;
16+
17+
// 이 대시보드가 속한 스페이스
18+
@OneToOne(fetch = FetchType.LAZY)
19+
@JoinColumn(name = "space_id")
20+
private Space space;
21+
22+
// 이 대시보드가 담고 있는 그래프 콘텐츠 (1:1 관계)
23+
// Cascade 설정을 통해 Dashboard 저장 시 Graph도 함께 저장되도록 함
24+
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
25+
@JoinColumn(name = "graph_id")
26+
private Graph graph;
27+
28+
// Dashboard 생성 시 비어있는 Graph를 함께 생성하는 편의 메서드
29+
public static Dashboard create(String name, Space space) {
30+
Dashboard dashboard = new Dashboard();
31+
dashboard.setName(name);
32+
dashboard.setSpace(space);
33+
dashboard.setGraph(new Graph()); // 비어있는 Graph 생성 및 연결
34+
return dashboard;
35+
}
36+
}

src/main/java/org/tuna/zoopzoop/backend/domain/graph/entity/Edge.java renamed to src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/entity/Edge.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package org.tuna.zoopzoop.backend.domain.graph.entity;
1+
package org.tuna.zoopzoop.backend.domain.dashboard.entity;
22

33
import jakarta.persistence.*;
44
import lombok.Getter;
55
import lombok.Setter;
6-
import org.tuna.zoopzoop.backend.domain.graph.enums.EdgeType;
6+
import org.tuna.zoopzoop.backend.domain.dashboard.enums.EdgeType;
77
import org.tuna.zoopzoop.backend.global.jpa.entity.BaseEntity;
88

99
@Getter

src/main/java/org/tuna/zoopzoop/backend/domain/graph/entity/Graph.java renamed to src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/entity/Graph.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.tuna.zoopzoop.backend.domain.graph.entity;
1+
package org.tuna.zoopzoop.backend.domain.dashboard.entity;
22

33
import jakarta.persistence.CascadeType;
44
import jakarta.persistence.Entity;

src/main/java/org/tuna/zoopzoop/backend/domain/graph/entity/Node.java renamed to src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/entity/Node.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package org.tuna.zoopzoop.backend.domain.graph.entity;
1+
package org.tuna.zoopzoop.backend.domain.dashboard.entity;
22

33
import jakarta.persistence.*;
44
import lombok.Getter;
55
import lombok.Setter;
6-
import org.tuna.zoopzoop.backend.domain.graph.enums.NodeType;
6+
import org.tuna.zoopzoop.backend.domain.dashboard.enums.NodeType;
77
import org.tuna.zoopzoop.backend.global.jpa.entity.BaseEntity;
88

99
import java.util.HashMap;

src/main/java/org/tuna/zoopzoop/backend/domain/graph/enums/EdgeType.java renamed to src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/enums/EdgeType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.tuna.zoopzoop.backend.domain.graph.enums;
1+
package org.tuna.zoopzoop.backend.domain.dashboard.enums;
22

33
public enum EdgeType {
44
DEFAULT,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.tuna.zoopzoop.backend.domain.dashboard.enums;
2+
3+
public enum NodeType {
4+
CUSTOM
5+
}

0 commit comments

Comments
 (0)