Skip to content
Merged
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
9 changes: 7 additions & 2 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ jobs:
JWT_LOGIN_FAILURE_REDIRECT_URI: ${{ secrets.JWT_LOGIN_FAILURE_REDIRECT_URI }}
JWT_LOGIN_FAILURE_REDIRECT_URI_DEV: ${{ secrets.JWT_LOGIN_FAILURE_REDIRECT_URI_DEV }}
SERVER_DOMAIN: ${{ secrets.SERVER_DOMAIN }}
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED: ${{ secrets.CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED }}
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL: ${{ secrets.CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL }}
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV: ${{ secrets.CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV }}

steps:
- name: Checkout code
Expand Down Expand Up @@ -114,8 +117,10 @@ jobs:
DISCORD_WEBHOOK_URL,ANTHROPIC_API_KEY,OPENAI_API_KEY,
KAKAO_REST_API_KEY,KAKAO_CLIENT_SECRET,
APPLE_TEAM_ID,APPLE_KEY_ID,APPLE_CLIENT_ID,
JWT_SECRET,JWT_REDIRECT_URI,JWT_REDIRECT_URI_DEV,JWT_LOGIN_FAILURE_REDIRECT_URI,JWT_LOGIN_FAILURE_REDIRECT_URI_DEV,SERVER_DOMAIN
JWT_SECRET,JWT_REDIRECT_URI,JWT_REDIRECT_URI_DEV,JWT_LOGIN_FAILURE_REDIRECT_URI,JWT_LOGIN_FAILURE_REDIRECT_URI_DEV,SERVER_DOMAIN,
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED,CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL,
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV,CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV
script: |
cd ~/deploy
chmod +x scripts/deploy.sh
./scripts/deploy.sh
./scripts/deploy.sh
12 changes: 7 additions & 5 deletions docker/docker-compose.blue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ services:
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
- JWT_SECRET=${JWT_SECRET}
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI}
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI}
- SERVER_DOMAIN=${SERVER_DOMAIN}
ports:
- "8080:8080"
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI}
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI}
- SERVER_DOMAIN=${SERVER_DOMAIN}
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED}
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL}
ports:
- "8080:8080"
volumes:
- ~/keys:/app/keys:ro
networks:
Expand Down
2 changes: 2 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ services:
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI_DEV}
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI_DEV}
- SERVER_DOMAIN=${SERVER_DOMAIN}
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV}
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV}
volumes:
- ~/keys:/app/keys:ro
networks:
Expand Down
12 changes: 7 additions & 5 deletions docker/docker-compose.green.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ services:
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
- JWT_SECRET=${JWT_SECRET}
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI}
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI}
- SERVER_DOMAIN=${SERVER_DOMAIN}
ports:
- "8081:8080"
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI}
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI}
- SERVER_DOMAIN=${SERVER_DOMAIN}
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED}
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL}
ports:
- "8081:8080"
volumes:
- ~/keys:/app/keys:ro
networks:
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ trap cleanup EXIT

# Generate .env from SSH-injected environment variables
log "Writing .env file..."
env | grep -E '^(DOCKER_IMAGE|BRANCH|SPRING_PROFILES_ACTIVE|DB_|REDIS_|ANTHROPIC_|OPENAI_|DISCORD_|KAKAO_|APPLE_TEAM_ID|APPLE_KEY_ID|APPLE_CLIENT_ID|JWT_|SERVER_)' > "${DOCKER_DIR}/.env"
env | grep -E '^(DOCKER_IMAGE|BRANCH|SPRING_PROFILES_ACTIVE|DB_|REDIS_|ANTHROPIC_|OPENAI_|DISCORD_|KAKAO_|APPLE_TEAM_ID|APPLE_KEY_ID|APPLE_CLIENT_ID|JWT_|SERVER_|CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED|CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL|CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV|CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV)' > "${DOCKER_DIR}/.env"
chmod 600 "${DOCKER_DIR}/.env"

# Step 1: Ensure Docker network exists
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import com.techfork.domain.activity.repository.ScrabPostRepository;
import com.techfork.domain.post.entity.PostKeyword;
import com.techfork.domain.post.repository.PostKeywordRepository;
import com.techfork.domain.user.entity.User;
import com.techfork.domain.user.exception.UserErrorCode;
import com.techfork.domain.user.repository.UserRepository;
import com.techfork.global.exception.GeneralException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.techfork.domain.user.entity.User;
import com.techfork.domain.user.exception.UserErrorCode;
import com.techfork.domain.user.repository.UserRepository;
import com.techfork.global.exception.GeneralException;
import com.techfork.global.util.CloudflareThirdPartyThumbnailOptimizer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -31,9 +32,10 @@ public class ActivityQueryService {

private final UserRepository userRepository;
private final ScrabPostRepository scrabPostRepository;
private final PostKeywordRepository postKeywordRepository;
private final ReadPostRepository readPostRepository;
private final ActivityConverter activityConverter;
private final PostKeywordRepository postKeywordRepository;
private final ReadPostRepository readPostRepository;
private final ActivityConverter activityConverter;
private final CloudflareThirdPartyThumbnailOptimizer thumbnailOptimizer;

public BookmarkListResponse getBookmarks(Long userId, Long lastBookmarkId, int size) {
User user = userRepository.findById(userId)
Expand Down Expand Up @@ -78,13 +80,13 @@ private List<BookmarkDto> attachKeywordsToPostInfoList(List<BookmarkDto> bookmar
.title(post.title())
.shortSummary(post.shortSummary())
.url(post.url())
.companyName(post.companyName())
.logoUrl(post.logoUrl())
.publishedAt(post.publishedAt())
.thumbnailUrl(post.thumbnailUrl())
.viewCount(post.viewCount())
.keywords(keywordMap.getOrDefault(post.postId(), List.of()))
.isBookmarked(post.isBookmarked())
.companyName(post.companyName())
.logoUrl(post.logoUrl())
.publishedAt(post.publishedAt())
.thumbnailUrl(thumbnailOptimizer.optimize(post.thumbnailUrl()))
.viewCount(post.viewCount())
.keywords(keywordMap.getOrDefault(post.postId(), List.of()))
.isBookmarked(post.isBookmarked())
.build())
.toList();
}
Expand Down Expand Up @@ -112,13 +114,13 @@ private List<ReadPostDto> attachKeywordsToReadPosts(List<ReadPostDto> readPosts)
.title(readPost.title())
.shortSummary(readPost.shortSummary())
.url(readPost.url())
.companyName(readPost.companyName())
.logoUrl(readPost.logoUrl())
.publishedAt(readPost.publishedAt())
.thumbnailUrl(readPost.thumbnailUrl())
.viewCount(readPost.viewCount())
.keywords(keywordMap.getOrDefault(readPost.postId(), List.of()))
.isBookmarked(null)
.companyName(readPost.companyName())
.logoUrl(readPost.logoUrl())
.publishedAt(readPost.publishedAt())
.thumbnailUrl(thumbnailOptimizer.optimize(readPost.thumbnailUrl()))
.viewCount(readPost.viewCount())
.keywords(keywordMap.getOrDefault(readPost.postId(), List.of()))
.isBookmarked(null)
.readAt(readPost.readAt())
.build())
.toList();
Expand All @@ -142,13 +144,13 @@ private List<ReadPostDto> attachBookmarksToReadPosts(List<ReadPostDto> readPosts
.title(readPost.title())
.shortSummary(readPost.shortSummary())
.url(readPost.url())
.companyName(readPost.companyName())
.logoUrl(readPost.logoUrl())
.publishedAt(readPost.publishedAt())
.thumbnailUrl(readPost.thumbnailUrl())
.viewCount(readPost.viewCount())
.keywords(readPost.keywords())
.isBookmarked(bookmarkedPostIds.contains(readPost.postId()))
.companyName(readPost.companyName())
.logoUrl(readPost.logoUrl())
.publishedAt(readPost.publishedAt())
.thumbnailUrl(thumbnailOptimizer.optimize(readPost.thumbnailUrl()))
.viewCount(readPost.viewCount())
.keywords(readPost.keywords())
.isBookmarked(bookmarkedPostIds.contains(readPost.postId()))
.readAt(readPost.readAt())
.build())
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
import com.techfork.domain.post.dto.*;
import com.techfork.domain.post.entity.PostKeyword;
import com.techfork.domain.post.enums.EPostSortType;
import com.techfork.domain.post.repository.PostKeywordRepository;
import com.techfork.domain.post.repository.PostRepository;
import com.techfork.global.exception.CommonErrorCode;
import com.techfork.global.exception.GeneralException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.techfork.domain.post.repository.PostKeywordRepository;
import com.techfork.domain.post.repository.PostRepository;
import com.techfork.global.exception.CommonErrorCode;
import com.techfork.global.exception.GeneralException;
import com.techfork.global.util.CloudflareThirdPartyThumbnailOptimizer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -28,9 +29,10 @@
public class PostQueryService {

private final PostRepository postRepository;
private final PostKeywordRepository postKeywordRepository;
private final ScrabPostRepository scrabPostRepository;
private final PostConverter postConverter;
private final PostKeywordRepository postKeywordRepository;
private final ScrabPostRepository scrabPostRepository;
private final PostConverter postConverter;
private final CloudflareThirdPartyThumbnailOptimizer thumbnailOptimizer;

public CompanyListResponse getCompanies() {
List<String> companies = postRepository.findDistinctCompanies();
Expand Down Expand Up @@ -142,13 +144,13 @@ private List<PostInfoDto> attachKeywordsToPostInfoList(List<PostInfoDto> posts)
.id(post.id())
.title(post.title())
.shortSummary(post.shortSummary())
.company(post.company())
.url(post.url())
.logoUrl(post.logoUrl())
.thumbnailUrl(post.thumbnailUrl())
.publishedAt(post.publishedAt())
.viewCount(post.viewCount())
.keywords(keywordMap.getOrDefault(post.id(), List.of()))
.company(post.company())
.url(post.url())
.logoUrl(post.logoUrl())
.thumbnailUrl(thumbnailOptimizer.optimize(post.thumbnailUrl()))
.publishedAt(post.publishedAt())
.viewCount(post.viewCount())
.keywords(keywordMap.getOrDefault(post.id(), List.of()))
.isBookmarked(null)
.build())
.toList();
Expand All @@ -172,13 +174,13 @@ private List<PostInfoDto> attachBookmarksToPostInfoList(List<PostInfoDto> posts,
.id(post.id())
.title(post.title())
.shortSummary(post.shortSummary())
.company(post.company())
.url(post.url())
.logoUrl(post.logoUrl())
.thumbnailUrl(post.thumbnailUrl())
.publishedAt(post.publishedAt())
.viewCount(post.viewCount())
.keywords(post.keywords())
.company(post.company())
.url(post.url())
.logoUrl(post.logoUrl())
.thumbnailUrl(thumbnailOptimizer.optimize(post.thumbnailUrl()))
.publishedAt(post.publishedAt())
.viewCount(post.viewCount())
.keywords(post.keywords())
.isBookmarked(bookmarkedPostIds.contains(post.id()))
.build())
.toList();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.techfork.domain.recommendation.converter;

import com.techfork.domain.post.entity.Post;
import com.techfork.domain.post.entity.PostKeyword;
import com.techfork.domain.recommendation.dto.RecommendationListResponse;
import com.techfork.domain.recommendation.dto.RecommendedPostDto;
import com.techfork.domain.recommendation.entity.RecommendedPost;
import org.springframework.stereotype.Component;
import com.techfork.domain.post.entity.Post;
import com.techfork.domain.post.entity.PostKeyword;
import com.techfork.domain.recommendation.dto.RecommendationListResponse;
import com.techfork.domain.recommendation.dto.RecommendedPostDto;
import com.techfork.domain.recommendation.entity.RecommendedPost;
import com.techfork.global.util.CloudflareThirdPartyThumbnailOptimizer;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class RecommendationConverter {

public RecommendationListResponse toRecommendationListResponse(List<RecommendedPost> recommendedPosts) {
@Component
@RequiredArgsConstructor
public class RecommendationConverter {

private final CloudflareThirdPartyThumbnailOptimizer thumbnailOptimizer;

public RecommendationListResponse toRecommendationListResponse(List<RecommendedPost> recommendedPosts) {
List<RecommendedPostDto> dtos = recommendedPosts.stream()
.map(this::toRecommendedPostDto)
.toList();
Expand All @@ -34,14 +39,14 @@ public RecommendedPostDto toRecommendedPostDto(RecommendedPost recommendedPost)
.id(recommendedPost.getId())
.postId(post.getId())
.title(post.getTitle())
.shortSummary(post.getShortSummary())
.company(post.getCompany())
.url(post.getUrl())
.logoUrl(post.getTechBlog().getLogoUrl())
.thumbnailUrl(post.getThumbnailUrl())
.viewCount(post.getViewCount())
.isBookmarked(null) // Will be set later in service layer
.publishedAt(post.getPublishedAt())
.shortSummary(post.getShortSummary())
.company(post.getCompany())
.url(post.getUrl())
.logoUrl(post.getTechBlog().getLogoUrl())
.thumbnailUrl(thumbnailOptimizer.optimize(post.getThumbnailUrl()))
.viewCount(post.getViewCount())
.isBookmarked(null) // Will be set later in service layer
.publishedAt(post.getPublishedAt())
.keywords(keywords)
.similarityScore(recommendedPost.getSimilarityScore())
.mmrScore(recommendedPost.getMmrScore())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.techfork.domain.user.document.UserProfileDocument;
import com.techfork.domain.user.repository.UserProfileDocumentRepository;
import com.techfork.global.llm.EmbeddingClient;
import com.techfork.global.util.CloudflareThirdPartyThumbnailOptimizer;
import com.techfork.global.util.RrfScorer;
import com.techfork.global.util.VectorUtil;
import java.io.IOException;
Expand Down Expand Up @@ -55,6 +56,7 @@ public class SearchServiceImpl implements SearchService {
private final PostRepository postRepository;
private final ScrabPostRepository scrabPostRepository;
private final Executor searchAsyncExecutor;
private final CloudflareThirdPartyThumbnailOptimizer thumbnailOptimizer;

@Override
public List<SearchResult> searchOnlyBm25(String query) {
Expand Down Expand Up @@ -325,7 +327,7 @@ private SearchResult mapToSearchResult(Hit<PostDocument> hit) {
.companyName(doc.getCompany())
.url(doc.getUrl())
.logoUrl(doc.getLogoUrl())
.thumbnailUrl(doc.getThumbnailUrl())
.thumbnailUrl(thumbnailOptimizer.optimize(doc.getThumbnailUrl()))
.publishedAt(doc.getPublishedAt())
.hybridScore(score)
.finalScore(score)
Expand Down Expand Up @@ -400,4 +402,4 @@ private List<SearchResult> attachPostMetadata(List<SearchResult> results, Long u
.build())
.collect(Collectors.toList());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.techfork.global.config;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Getter
@Setter
@Component
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "cloudflare.third-party-thumbnail-optimization")
public class CloudflareThirdPartyThumbnailOptimizationProperties {

private boolean enabled = false;

private String deliveryBaseUrl = "";

private Integer width = 480;

private Integer quality = 75;

private String fit = "scale-down";

private String format = "auto";
}
Loading