{"id":29422143,"url":"https://github.com/setung/photogram","last_synced_at":"2025-07-12T04:02:55.390Z","repository":{"id":288294855,"uuid":"958590903","full_name":"setung/photogram","owner":"setung","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-16T16:15:17.000Z","size":223,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-04-17T00:13:11.972Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/setung.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-01T12:55:51.000Z","updated_at":"2025-04-16T16:15:20.000Z","dependencies_parsed_at":"2025-04-20T06:31:11.882Z","dependency_job_id":null,"html_url":"https://github.com/setung/photogram","commit_stats":null,"previous_names":["setung/photogram"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/setung/photogram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setung%2Fphotogram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setung%2Fphotogram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setung%2Fphotogram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setung%2Fphotogram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/setung","download_url":"https://codeload.github.com/setung/photogram/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setung%2Fphotogram/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264935293,"owners_count":23685493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-12T04:02:53.060Z","updated_at":"2025-07-12T04:02:55.115Z","avatar_url":"https://github.com/setung.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# photogram\n\nInstagram을 모티브로 한 MSA 기반의 SNS 프로젝트입니다.  \n대규모 트래픽 처리와 이벤트 기반 아키텍처 설계를 목표로 구현되었습니다.\n\n---\n\n## 프로젝트 목표\n\n- MSA 구조 설계 및 구현\n- Kafka 기반 이벤트 처리 경험\n- ElasticSearch를 활용한 태그 기반 검색\n- 대규모 시스템 설계 및 트래픽 처리 구조 학습\n\n---\n\n## 시스템 아키텍처\n\u003cimg width=\"630\" alt=\"스크린샷 2025-04-14 오후 2 43 50\" src=\"https://github.com/user-attachments/assets/977574e6-2a84-47cd-a34b-0c1ba7ffec1b\" /\u003e\n\n- **Gateway**: 진입점, JWT 인증 및 라우팅\n- **Discovery**: 마이크로서비스 등록 및 위치 탐색\n- **Config**: 설정 중앙관리\n- **User-service**: 회원가입, 로그인, 유저/팔로우 관리\n- **Post-service**: 게시글, 이미지 업로드, 좋아요, 댓글\n- **Feed-service**: 팔로우 기반 피드 구성\n- **Post-Search-service**: 태그 기반 게시글 검색\n\n---\n\n## 기술 스택\n\n| 분류             | 기술                                                         |\n|------------------|--------------------------------------------------------------|\n| Backend          | Spring Boot (Kotlin), Spring Cloud                           |\n| DB               | MySQL, Redis                                                 |\n| 메시징           | Kafka                                                        |\n| 검색             | ElasticSearch                                                |\n| 스토리지         | AWS S3                                                       |\n| 이메일           | AWS SES                                                      |\n| 인프라           | Config Server, Discovery(Eureka), Gateway                    |\n| 모니터링         | Micrometer, Grafana, Prometheus                              |\n| 분산 추적        | Sleuth, Zipkin                                               |\n| 장애 대응        | Resilience4j                                                 |\n\n---\n\n## 실행 방법\n```bash\n./gradlew build\ndocker-compose up\n```\n\n---\n\n## [마이크로서비스간 장애 전파 막기](https://dev-setung.tistory.com/58) (Resilience4j + Redis)\n\u003cimg width=\"611\" alt=\"스크린샷 2025-04-23 오후 12 58 25\" src=\"https://github.com/user-attachments/assets/52d62db4-cb02-48d8-ad7f-2417bb12b60b\" /\u003e\n\n**문제점**\n - Post-service에서 게시글 조회 시, 작성자 정보를 User-service에 의존함 → User-service 장애 시 Post-service도 함께 실패하는 장애 전파 문제 발생\n\n**해결방안**\n - Redis 캐싱: User-service 응답을 Redis에 저장, 이후 요청 시 캐시 우선 조회\n - Resilience4j CircuitBreaker + Fallback: 캐시 미스 + User-service 장애 시, Fallback으로 비공개 사용자 정보 반환\n\n---\n\n## [태그 기반 게시글 검색](https://dev-setung.tistory.com/56) (ElasticSearch + Kafka)\n\u003cimg width=\"580\" alt=\"스크린샷 2025-04-14 오후 2 56 32\" src=\"https://github.com/user-attachments/assets/fe1e21b4-e185-42a7-b6d5-58dc90ed978f\" /\u003e\n\n- 게시글 저장 시 Kafka를 통해 게시글 정보를 `post-search-service`로 전송\n- `post-search-service`는 해당 데이터를 ElasticSearch에 인덱싱\n- 검색 요청 시 ES에서 `multi_match` 쿼리로 태그 기반 게시글 검색 수행\n- 태그 자동 완성 또는 관련성 높은 검색 기능 확장 가능\n\n---\n\n## [Push 기반 피드 구현](https://dev-setung.tistory.com/57)\n\u003cimg width=\"915\" alt=\"스크린샷 2025-04-14 오후 8 09 02\" src=\"https://github.com/user-attachments/assets/340b90d1-7ccd-4805-b2cc-89de7fe21998\" /\u003e\n\n- 클라이언트가 게시글 업로드 요청을 보낸다.\n- post-service는 게시글을 DB에 저장한 뒤, 게시글 업로드 이벤트를 Kafka로 발행한다.\n  event_payload : { postId, writerId }\n- feed-service는 Kafka에서 해당 업로드 이벤트를 pull(구독) 한다.\n- 이벤트를 가져온 feed-service는 writerId를 기반으로 user-service에 팔로워 목록을 요청한다.\n- 받아온 팔로워 목록을 순회하며, 각 유저의 피드 정보(Redis, Sorted Set)에 업로드된 게시글 ID를 저장한다.\n- 사용자가 피드를 조회할 때, Redis에 저장된 게시글 ID를 통해 빠르게 가져올 수 있게 된다.\n\n---\n\n## [인증 시스템](https://dev-setung.tistory.com/55) (JWT + Gateway 인증 필터)\n\u003cimg width=\"656\" alt=\"스크린샷 2025-04-14 오후 2 56 01\" src=\"https://github.com/user-attachments/assets/5295d268-7fe9-4982-8f9f-a9bf48ec48f5\" /\u003e\n\n- 로그인 시 `user-service`에서 JWT를 생성하고 클라이언트에 전달\n- 모든 요청은 `Gateway`에서 JWT를 검증 후 `user-id`를 헤더로 추가해 마이크로서비스로 전달\n- 각 서비스에서는 `user-id`를 통해 인증된 사용자 정보를 활용\n- 익명 사용자 요청도 지원 (JWT 미포함 시 `user-id: -1`로 간주)\n- 인증이 필요한 API와 아닌 API를 구분할 수 있는 설정 제공 (`allowAnonymous`)\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsetung%2Fphotogram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsetung%2Fphotogram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsetung%2Fphotogram/lists"}