Dernière activité 1761878715

D a révisé ce gist 1761878715. Aller à la révision

1 file changed, 224 insertions

nti설계.md(fichier créé)

@@ -0,0 +1,224 @@
1 + 지금 구조는 **1:N 관계 (알림 1건 ↔ 처리내역 여러 건)** 이므로,
2 + 이건 단순 “속성”이 아니라 **하위 리소스(sub-resource)** 로 취급해야 합니다.
3 +
4 + 즉, “NTI(알림)”가 상위 도메인, “처리내역”은 NTI 하위에 종속된 도메인으로 보아야 합니다.
5 + 아래는 **REST 설계, DTO 분리, 서비스 구조** 모두를 기준으로 한 권장 설계안입니다.
6 +
7 + ---
8 +
9 + ## 1. 도메인 관계 요약
10 +
11 + | 개체 | 설명 | 관계 |
12 + | ------------ | ----------- | ------ |
13 + | `Nti` | 알림 (상위 도메인) | 1 |
14 + | `NtiProcess` | 알림의 처리내역 | N (하위) |
15 +
16 + 예시:
17 +
18 + ```
19 + Nti(id=100, title="재난 문자")
20 + ├── NtiProcess(id=1, status="발송대기", updatedAt="2025-10-31")
21 + ├── NtiProcess(id=2, status="발송완료", updatedAt="2025-10-31")
22 + └── ...
23 + ```
24 +
25 + ---
26 +
27 + ## 2. REST API 설계
28 +
29 + ### (1) 상위 도메인: 알림
30 +
31 + | 기능 | Method | URI | 설명 |
32 + | -------- | ------ | --------------------- | -------- |
33 + | 알림 목록 조회 | `GET` | `/api/v1/nti` | 알림 전체 목록 |
34 + | 알림 상세 조회 | `GET` | `/api/v1/nti/{ntiId}` | 알림 단건 조회 |
35 + | 알림 생성 | `POST` | `/api/v1/nti` | 새 알림 생성 |
36 +
37 + ### (2) 하위 리소스: 알림의 처리내역
38 +
39 + | 기능 | Method | URI | 설명 |
40 + | ----------------- | ------ | ------------------------------------------- | --------------- |
41 + | 특정 알림의 처리내역 목록 조회 | `GET` | `/api/v1/nti/{ntiId}/processes` | 특정 알림의 처리내역 리스트 |
42 + | 특정 처리내역 조회 | `GET` | `/api/v1/nti/{ntiId}/processes/{processId}` | 특정 내역 상세 |
43 + | 처리내역 추가 | `POST` | `/api/v1/nti/{ntiId}/processes` | 해당 알림에 내역 추가 |
44 +
45 + ---
46 +
47 + ## 3. Controller 구조
48 +
49 + ```java
50 + @RestController
51 + @RequestMapping("/api/v1/nti")
52 + @RequiredArgsConstructor
53 + @Slf4j
54 + public class NtiController {
55 +
56 + private final NtiService ntiService;
57 +
58 + @GetMapping
59 + public ResponseEntity<List<NtiListResponse>> getAllNti() {
60 + return ResponseEntity.ok(ntiService.getAll());
61 + }
62 +
63 + @GetMapping("/{ntiId}")
64 + public ResponseEntity<NtiDetailDto> getNti(@PathVariable Long ntiId) {
65 + return ResponseEntity.ok(ntiService.getById(ntiId));
66 + }
67 + }
68 + ```
69 +
70 + ```java
71 + @RestController
72 + @RequestMapping("/api/v1/nti/{ntiId}/processes")
73 + @RequiredArgsConstructor
74 + @Slf4j
75 + public class NtiProcessController {
76 +
77 + private final NtiProcessService ntiProcessService;
78 +
79 + @GetMapping
80 + public ResponseEntity<List<NtiProcessDto>> getProcesses(@PathVariable Long ntiId) {
81 + return ResponseEntity.ok(ntiProcessService.getProcessesByNtiId(ntiId));
82 + }
83 +
84 + @GetMapping("/{processId}")
85 + public ResponseEntity<NtiProcessDto> getProcess(
86 + @PathVariable Long ntiId,
87 + @PathVariable Long processId
88 + ) {
89 + return ResponseEntity.ok(ntiProcessService.getProcessDetail(ntiId, processId));
90 + }
91 +
92 + @PostMapping
93 + public ResponseEntity<Void> addProcess(
94 + @PathVariable Long ntiId,
95 + @RequestBody NtiProcessRequest request
96 + ) {
97 + ntiProcessService.addProcess(ntiId, request);
98 + return ResponseEntity.status(HttpStatus.CREATED).build();
99 + }
100 + }
101 + ```
102 +
103 + ---
104 +
105 + ## 4. DTO 구조
106 +
107 + ### Nti (상위)
108 +
109 + ```java
110 + public class NtiDetailDto {
111 + private Long id;
112 + private String title;
113 + private String classification;
114 + private LocalDateTime createdAt;
115 + private List<NtiProcessDto> processes; // 옵션: 포함 조회용
116 + }
117 + ```
118 +
119 + ### NtiProcess (하위)
120 +
121 + ```java
122 + public class NtiProcessDto {
123 + private Long id;
124 + private String status;
125 + private String handler;
126 + private String comment;
127 + private LocalDateTime updatedAt;
128 + }
129 + ```
130 +
131 + 요청용 DTO
132 +
133 + ```java
134 + public class NtiProcessRequest {
135 + private String status;
136 + private String handler;
137 + private String comment;
138 + }
139 + ```
140 +
141 + ---
142 +
143 + ## 5. 서비스 및 패키지 구조
144 +
145 + ```
146 + com.example.nti
147 + ├── controller
148 + │ ├── NtiController.java
149 + │ └── NtiProcessController.java
150 + ├── service
151 + │ ├── NtiService.java
152 + │ └── NtiProcessService.java
153 + ├── dto
154 + │ ├── NtiListResponse.java
155 + │ ├── NtiDetailDto.java
156 + │ ├── NtiProcessDto.java
157 + │ └── NtiProcessRequest.java
158 + ├── repository
159 + │ ├── NtiRepository.java
160 + │ └── NtiProcessRepository.java
161 + └── entity
162 + ├── Nti.java
163 + └── NtiProcess.java
164 + ```
165 +
166 + ---
167 +
168 + ## 6. 데이터 모델 예시 (JPA)
169 +
170 + ```java
171 + @Entity
172 + public class Nti {
173 + @Id @GeneratedValue
174 + private Long id;
175 +
176 + private String title;
177 + private String classification;
178 +
179 + @OneToMany(mappedBy = "nti", cascade = CascadeType.ALL, orphanRemoval = true)
180 + private List<NtiProcess> processes = new ArrayList<>();
181 + }
182 + ```
183 +
184 + ```java
185 + @Entity
186 + public class NtiProcess {
187 + @Id @GeneratedValue
188 + private Long id;
189 +
190 + @ManyToOne(fetch = FetchType.LAZY)
191 + @JoinColumn(name = "nti_id")
192 + private Nti nti;
193 +
194 + private String status;
195 + private String handler;
196 + private String comment;
197 + private LocalDateTime updatedAt;
198 + }
199 + ```
200 +
201 + ---
202 +
203 + ## 7. 설계 요약
204 +
205 + | 구분 | 설계 방식 | URI 예시 |
206 + | ---------- | ------------------------------------ | ------------------------------------------- |
207 + | 상위 리소스 | NTI (알림) | `/api/v1/nti/{ntiId}` |
208 + | 하위 리소스 | 처리내역 | `/api/v1/nti/{ntiId}/processes` |
209 + | 단건 처리내역 조회 | ID 기반 | `/api/v1/nti/{ntiId}/processes/{processId}` |
210 + | DTO | `NtiProcessDto`, `NtiProcessRequest` | 속성 분리 |
211 +
212 + ---
213 +
214 + ## 8. 핵심 요약 문장
215 +
216 + > 알림 하위의 처리내역은 `Nti`의 속성이 아니라 `NtiProcess`라는 독립된 **하위 리소스(Sub-resource)** 로 분리해야 하며,
217 + > `/api/v1/nti/{ntiId}/processes` 형태로 접근하도록 설계하는 것이 RESTful하고 확장성에 유리합니다.
218 +
219 + ---
220 +
221 + 원하신다면
222 + “처리내역이 단순 로그 형태인지, 상태 전이(예: 진행중→완료)인지” 알려주시면
223 + 그 흐름에 맞는 **상태 기반 도메인 설계(state transition model)** 까지 구체화해드릴 수 있습니다.
224 + 그 부분 포함해서 볼까요?
Plus récent Plus ancien