Skip to content

Commit b23ba21

Browse files
committed
Merge remote-tracking branch 'origin/dev' into fix/287
2 parents 6f5596a + 027b46e commit b23ba21

File tree

138 files changed

+922
-509
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+922
-509
lines changed

infra/terraform/main.tf

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,58 @@ resource "aws_security_group" "sg_1" {
174174
}
175175
}
176176

177+
# Coturn 서버 전용 보안 그룹 (Security Group)
178+
resource "aws_security_group" "coturn_sg" {
179+
name = "team5-coturn-server-sg"
180+
description = "Allow WebRTC TURN server traffic"
181+
vpc_id = aws_vpc.vpc_1.id
182+
183+
ingress {
184+
description = "SSH for maintenance"
185+
from_port = 22
186+
to_port = 22
187+
protocol = "tcp"
188+
cidr_blocks = ["0.0.0.0/0"]
189+
}
190+
191+
ingress {
192+
description = "TURN Listening Port (TCP)"
193+
from_port = 3478
194+
to_port = 3478
195+
protocol = "tcp"
196+
cidr_blocks = ["0.0.0.0/0"]
197+
}
198+
199+
ingress {
200+
description = "TURN Listening Port (UDP)"
201+
from_port = 3478
202+
to_port = 3478
203+
protocol = "udp"
204+
cidr_blocks = ["0.0.0.0/0"]
205+
}
206+
207+
ingress {
208+
description = "TURN Media Relay Ports (UDP)"
209+
from_port = 49152
210+
to_port = 65535
211+
protocol = "udp"
212+
cidr_blocks = ["0.0.0.0/0"]
213+
}
214+
215+
egress {
216+
from_port = 0
217+
to_port = 0
218+
protocol = "-1"
219+
cidr_blocks = ["0.0.0.0/0"]
220+
}
221+
222+
tags = {
223+
Key = "TEAM"
224+
Value = "devcos-team05"
225+
Name = "team5-coturn-sg"
226+
}
227+
}
228+
177229
# EC2 역할 생성
178230
resource "aws_iam_role" "ec2_role_1" {
179231
tags = {
@@ -307,6 +359,55 @@ ${local.ec2_user_data_base}
307359
EOF
308360
}
309361

362+
resource "aws_instance" "coturn_server" {
363+
ami = "ami-02835aed2a5cb1d2a" # 서울 리전 Ubuntu 22.04 LTS
364+
instance_type = "t3.micro"
365+
subnet_id = aws_subnet.subnet_1.id
366+
vpc_security_group_ids = [aws_security_group.coturn_sg.id]
367+
associate_public_ip_address = true
368+
369+
tags = {
370+
Key = "TEAM"
371+
Value = "devcos-team05"
372+
Name = "team5-coturn-server"
373+
}
374+
375+
# EC2 부팅 시 Coturn 자동 설치 및 설정 스크립트
376+
user_data = <<-EOF
377+
#!/bin/bash
378+
apt-get update
379+
apt-get install -y coturn
380+
381+
PUBLIC_IP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)
382+
PRIVATE_IP=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)
383+
384+
cat <<EOT > /etc/turnserver.conf
385+
listening-port=3478
386+
external-ip=$PUBLIC_IP/$PRIVATE_IP
387+
388+
# 동적 인증을 위한 비밀키 설정
389+
use-auth-secret
390+
static-auth-secret=${var.turn_shared_secret}
391+
392+
lt-cred-mech
393+
realm=${var.catfe_domain_1}
394+
log-file=/var/log/turnserver.log
395+
verbose
396+
fingerprint
397+
no-multicast-peers
398+
EOT
399+
400+
systemctl restart coturn
401+
systemctl enable coturn
402+
EOF
403+
}
404+
405+
# 3. 결과 출력 (Output - Turn 서버 IP 주소 출력)
406+
output "coturn_server_public_ip" {
407+
description = "The public IP address of the Coturn server."
408+
value = aws_instance.coturn_server.public_ip
409+
}
410+
310411
# RDS용 Security Group
311412
resource "aws_security_group" "rds_sg_1" {
312413
name = "team5-rds-sg-1"
@@ -361,6 +462,8 @@ resource "aws_db_instance" "mysql" {
361462
db_subnet_group_name = aws_db_subnet_group.db_subnet_group.name
362463
vpc_security_group_ids = [aws_security_group.rds_sg_1.id]
363464

465+
# RDS 퍼블릭 액세스 허용
466+
publicly_accessible = true
364467

365468
multi_az = false
366469

src/main/java/com/back/domain/board/comment/entity/Comment.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package com.back.domain.board.comment.entity;
22

33
import com.back.domain.board.post.entity.Post;
4-
import com.back.domain.user.entity.User;
4+
import com.back.domain.user.common.entity.User;
55
import com.back.global.entity.BaseEntity;
66
import jakarta.persistence.*;
77
import lombok.Getter;
88
import lombok.NoArgsConstructor;
99

1010
import java.util.ArrayList;
1111
import java.util.List;
12-
import java.util.Objects;
1312

1413
@Entity
1514
@Getter

src/main/java/com/back/domain/board/comment/entity/CommentLike.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package com.back.domain.board.comment.entity;
22

3-
import com.back.domain.user.entity.User;
3+
import com.back.domain.user.common.entity.User;
44
import com.back.global.entity.BaseEntity;
55
import jakarta.persistence.*;
6-
import lombok.AllArgsConstructor;
76
import lombok.Getter;
87
import lombok.NoArgsConstructor;
98

src/main/java/com/back/domain/board/comment/repository/custom/CommentRepositoryImpl.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
import com.back.domain.board.comment.entity.QComment;
99
import com.back.domain.board.common.dto.QAuthorResponse;
1010
import com.back.domain.board.post.entity.QPost;
11-
import com.back.domain.user.entity.QUser;
12-
import com.back.domain.user.entity.QUserProfile;
13-
import com.querydsl.core.BooleanBuilder;
11+
import com.back.domain.user.common.entity.QUser;
12+
import com.back.domain.user.common.entity.QUserProfile;
1413
import com.querydsl.core.types.Order;
1514
import com.querydsl.core.types.OrderSpecifier;
1615
import com.querydsl.core.types.dsl.BooleanExpression;

src/main/java/com/back/domain/board/comment/service/CommentLikeService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import com.back.domain.board.comment.repository.CommentLikeRepository;
77
import com.back.domain.board.comment.repository.CommentRepository;
88
import com.back.domain.notification.event.community.CommentLikedEvent;
9-
import com.back.domain.user.entity.User;
10-
import com.back.domain.user.repository.UserRepository;
9+
import com.back.domain.user.common.entity.User;
10+
import com.back.domain.user.common.repository.UserRepository;
1111
import com.back.global.exception.CustomException;
1212
import com.back.global.exception.ErrorCode;
1313
import lombok.RequiredArgsConstructor;

src/main/java/com/back/domain/board/comment/service/CommentService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import com.back.domain.board.post.repository.PostRepository;
1313
import com.back.domain.notification.event.community.CommentCreatedEvent;
1414
import com.back.domain.notification.event.community.ReplyCreatedEvent;
15-
import com.back.domain.user.entity.User;
16-
import com.back.domain.user.repository.UserRepository;
15+
import com.back.domain.user.common.entity.User;
16+
import com.back.domain.user.common.repository.UserRepository;
1717
import com.back.global.exception.CustomException;
1818
import com.back.global.exception.ErrorCode;
1919
import lombok.RequiredArgsConstructor;

src/main/java/com/back/domain/board/common/dto/AuthorResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.back.domain.board.common.dto;
22

3-
import com.back.domain.user.entity.User;
3+
import com.back.domain.user.common.entity.User;
44
import com.querydsl.core.annotations.QueryProjection;
55

66
/**

src/main/java/com/back/domain/board/post/controller/docs/PostControllerDocs.java

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public interface PostControllerDocs {
5555
{ "id": 1, "name": "공지사항" },
5656
{ "id": 2, "name": "자유게시판" }
5757
],
58+
"images": [
59+
{ "id": 11, "url": "https://example.com/image1.png" },
60+
{ "id": 12, "url": "https://example.com/image2.png" }
61+
],
5862
"createdAt": "2025-09-22T10:30:00",
5963
"updatedAt": "2025-09-22T10:30:00"
6064
}
@@ -112,7 +116,7 @@ public interface PostControllerDocs {
112116
),
113117
@ApiResponse(
114118
responseCode = "404",
115-
description = "존재하지 않는 사용자 또는 카테고리",
119+
description = "존재하지 않는 리소스 (사용자, 카테고리, 파일)",
116120
content = @Content(
117121
mediaType = "application/json",
118122
examples = {
@@ -131,6 +135,14 @@ public interface PostControllerDocs {
131135
"message": "존재하지 않는 카테고리입니다.",
132136
"data": null
133137
}
138+
"""),
139+
@ExampleObject(name = "존재하지 않는 파일(이미지)", value = """
140+
{
141+
"success": false,
142+
"code": "FILE_004",
143+
"message": "파일 정보를 찾을 수 없습니다.",
144+
"data": null
145+
}
134146
""")
135147
}
136148
)
@@ -252,14 +264,22 @@ ResponseEntity<RsData<PageResponse<PostListResponse>>> getPosts(
252264
"message": "게시글이 조회되었습니다.",
253265
"data": {
254266
"postId": 101,
255-
"author": { "id": 5, "nickname": "홍길동", "profileImageUrl": null },
267+
"author": {
268+
"id": 5,
269+
"nickname": "홍길동",
270+
"profileImageUrl": null
271+
},
256272
"title": "첫 번째 게시글",
257273
"content": "안녕하세요, 첫 글입니다!",
258274
"thumbnailUrl": null,
259275
"categories": [
260276
{ "id": 1, "name": "공지사항" },
261277
{ "id": 2, "name": "자유게시판" }
262278
],
279+
"images": [
280+
{ "id": 11, "url": "https://example.com/image1.png" },
281+
{ "id": 12, "url": "https://example.com/image2.png" }
282+
],
263283
"likeCount": 10,
264284
"bookmarkCount": 2,
265285
"commentCount": 3,
@@ -337,8 +357,12 @@ ResponseEntity<RsData<PostDetailResponse>> getPost(
337357
{ "id": 1, "name": "공지사항" },
338358
{ "id": 2, "name": "자유게시판" }
339359
],
360+
"images": [
361+
{ "id": 11, "url": "https://example.com/image1.png" },
362+
{ "id": 12, "url": "https://example.com/image2.png" }
363+
],
340364
"createdAt": "2025-09-22T10:30:00",
341-
"updatedAt": "2025-09-22T10:30:00"
365+
"updatedAt": "2025-09-22T10:45:00"
342366
}
343367
}
344368
""")
@@ -409,7 +433,7 @@ ResponseEntity<RsData<PostDetailResponse>> getPost(
409433
),
410434
@ApiResponse(
411435
responseCode = "404",
412-
description = "존재하지 않는 사용자/게시글/카테고리",
436+
description = "존재하지 않는 리소스 (사용자, 게시글, 카테고리, 파일)",
413437
content = @Content(
414438
mediaType = "application/json",
415439
examples = {
@@ -436,6 +460,14 @@ ResponseEntity<RsData<PostDetailResponse>> getPost(
436460
"message": "존재하지 않는 카테고리입니다.",
437461
"data": null
438462
}
463+
"""),
464+
@ExampleObject(name = "존재하지 않는 파일(이미지)", value = """
465+
{
466+
"success": false,
467+
"code": "FILE_004",
468+
"message": "파일 정보를 찾을 수 없습니다.",
469+
"data": null
470+
}
439471
""")
440472
}
441473
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.back.domain.board.post.dto;
2+
3+
import com.back.domain.file.entity.FileAttachment;
4+
5+
/**
6+
* 이미지 응답 DTO
7+
*
8+
* @param id 이미지 ID
9+
* @param url 이미지 URL
10+
*/
11+
public record ImageResponse(
12+
Long id,
13+
String url
14+
) {
15+
public static ImageResponse from(FileAttachment fileAttachment) {
16+
return new ImageResponse(
17+
fileAttachment.getId(),
18+
fileAttachment.getPublicURL()
19+
);
20+
}
21+
}

src/main/java/com/back/domain/board/post/dto/PostDetailResponse.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.back.domain.board.common.dto.AuthorResponse;
44
import com.back.domain.board.post.entity.Post;
5+
import com.back.domain.file.entity.FileAttachment;
56

67
import java.time.LocalDateTime;
78
import java.util.List;
@@ -15,6 +16,7 @@
1516
* @param content 게시글 내용
1617
* @param thumbnailUrl 썸네일 URL
1718
* @param categories 게시글 카테고리 목록
19+
* @param images 첨부된 이미지 목록
1820
* @param likeCount 좋아요 수
1921
* @param bookmarkCount 북마크 수
2022
* @param commentCount 댓글 수
@@ -30,6 +32,7 @@ public record PostDetailResponse(
3032
String content,
3133
String thumbnailUrl,
3234
List<CategoryResponse> categories,
35+
List<ImageResponse> images,
3336
long likeCount,
3437
long bookmarkCount,
3538
long commentCount,
@@ -38,11 +41,11 @@ public record PostDetailResponse(
3841
LocalDateTime createdAt,
3942
LocalDateTime updatedAt
4043
) {
41-
public static PostDetailResponse from(Post post) {
42-
return from(post, false, false);
44+
public static PostDetailResponse from(Post post, List<FileAttachment> attachments) {
45+
return from(post, attachments, false, false);
4346
}
4447

45-
public static PostDetailResponse from(Post post, boolean likedByMe, boolean bookmarkedByMe) {
48+
public static PostDetailResponse from(Post post, List<FileAttachment> attachments, boolean likedByMe, boolean bookmarkedByMe) {
4649
return new PostDetailResponse(
4750
post.getId(),
4851
AuthorResponse.from(post.getUser()),
@@ -52,6 +55,9 @@ public static PostDetailResponse from(Post post, boolean likedByMe, boolean book
5255
post.getCategories().stream()
5356
.map(CategoryResponse::from)
5457
.toList(),
58+
attachments.stream()
59+
.map(ImageResponse::from)
60+
.toList(),
5561
post.getPostLikes().size(),
5662
post.getPostBookmarks().size(),
5763
post.getComments().size(),

0 commit comments

Comments
 (0)