{"id":27048708,"url":"https://github.com/dawwson/chagok-be","last_synced_at":"2026-04-07T18:33:21.159Z","repository":{"id":206672726,"uuid":"716407795","full_name":"dawwson/chagok-be","owner":"dawwson","description":"[차곡 BE] 개인용 가계부 서비스 - REST API 서버","archived":false,"fork":false,"pushed_at":"2025-04-01T09:59:37.000Z","size":516,"stargazers_count":0,"open_issues_count":5,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-03T16:21:04.253Z","etag":null,"topics":["aws-ec2","aws-rds","docker","jest","jwt","nestjs","nodejs","postgresql","typeorm","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/dawwson.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-09T04:20:32.000Z","updated_at":"2025-04-01T09:59:41.000Z","dependencies_parsed_at":"2024-08-12T09:11:17.401Z","dependency_job_id":"6f349f87-0ffa-4c9f-abde-774c378c57dd","html_url":"https://github.com/dawwson/chagok-be","commit_stats":null,"previous_names":["dawwson/budget-keeper-be","dawwson/chagok-be"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dawwson/chagok-be","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dawwson%2Fchagok-be","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dawwson%2Fchagok-be/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dawwson%2Fchagok-be/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dawwson%2Fchagok-be/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dawwson","download_url":"https://codeload.github.com/dawwson/chagok-be/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dawwson%2Fchagok-be/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31524525,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["aws-ec2","aws-rds","docker","jest","jwt","nestjs","nodejs","postgresql","typeorm","typescript"],"created_at":"2025-04-05T07:15:50.403Z","updated_at":"2026-04-07T18:33:21.094Z","avatar_url":"https://github.com/dawwson.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eBudget Keeper\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/dawwson/budget-keeper-be/assets/45624238/ba7ab27e-f40b-4d24-9ea5-00b8590536b0\" width=\"100%\" height=\"300\" /\u003e\n\u003c/p\u003e\n\n\u003ch2 align=\"center\"\u003eIntroduction\u003c/h2\u003e\n\u003cp align=\"center\"\u003e\n    \u003ccode\u003eBudget Keeper\u003c/code\u003e는 사용자들이 개인 재무를 관리하고 지출을 추적하는 데 도움을 주는 서비스입니다.\u003cbr\u003e월별로 예산을 설정하고 카테고리별로 지출 내역을 관리함으로써 사용자들의 재무 목표를 달성할 수 있습니다.\n    \u003cbr\u003e\n    \u003cbr\u003e\n    \u003cimg src=\"https://img.shields.io/badge/E2E Test-Passing-2ade16?style=flat-square\"\u003e\n    \u003cbr\u003e\n    \u003cbr\u003e\n\u003c/p\u003e\n\n\u003ch2 align=\"center\"\u003eSkills\u003c/h2\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge\u0026logo=typescript\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Node.js-339933?style=for-the-badge\u0026logo=node.js\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Nest.js-E0234E?style=for-the-badge\u0026logo=nestjs\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/TypeORM-fcad03?style=for-the-badge\"\u003e\n    \u003cbr\u003e\n    \u003cimg src=\"https://img.shields.io/badge/PostgreSQL-00758F?style=for-the-badge\u0026logo=postgresql\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Jest-C21325?style=for-the-badge\u0026logo=jest\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/jwt-000000?style=for-the-badge\u0026logo=jsonwebtokens\u0026logoColor=white\"\u003e\n    \u003cbr\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Docker-2496ED?style=for-the-badge\u0026logo=docker\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/aws ec2-FF9900?style=for-the-badge\u0026logo=amazon-ec2\u0026logoColor=white\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/aws rds-527FFF?style=for-the-badge\u0026logo=amazon-rds\u0026logoColor=white\"\u003e\n\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n## Table of Contents\n- [Installation](#installation)\n- [Directory](#directory)\n- [ERD](#erd)\n- [REST API](#rest-api)\n- [Convention](#convention)\n- [Architecture](#architecture)\n- [Deployment Structure](#deployment-structure)\n- [TIL \u0026 Retrospective](#til--retrospective)\n- [Test Result](#test-result)\n\n\u003cbr\u003e\n\n## Installation\n```bash!\n\u003e npm install        # 패키지 설치\n\u003e npm run start:db   # 도커로 데이터베이스 실행\n\u003e npm run start:dev  # 개발버전 앱 실행\n\u003e npm run seed:dev   # 카테고리 데이터 생성\n```\n\n\u003cbr\u003e\n\n## Directory\n\u003cdetails\u003e\n    \u003csummary\u003e폴더 구조 보기\u003c/summary\u003e\n    \u003cpre\u003e\n        \u003ccode\u003e\nsrc\n├── api                # API 요청이 들어오는 Controller가 포함된 모듈\n│   ├── auth           # 인증 모듈(/auth)\n│   │   ├── dto\n│   │   ├── service\n│   │   └── strategy\n│   ├── budget         # 예산 모듈(/budgets)\n│   │   ├── dto\n│   │   └── service\n│   ├── category       # 카테고리 모듈(/categories)\n│   │   ├── dto\n│   │   └── service\n│   └── expense        # 지출 모듈(/expenses)\n│       ├── dto\n│       ├── enum\n│       ├── guard\n│       └── service\n├── config             # 환경 변수 설정 관련\n├── database\n│   └── seeding        # DB seeding 관련\n├── entity\n└── shared             # 여러 모듈에 걸쳐서 쓰이는 파일\n    ├── enum\n    ├── guard\n    └── interface\ntest\n├── e2e                # e2e 테스트 파일\n├── in-memory-testing  # 인 메모리 DB 테스트 관련 파일\n└── jest-e2e.json\n        \u003c/code\u003e\n    \u003c/pre\u003e\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## ERD\n![budget-keeper erd](https://github.com/dawwson/budget-keeper-be/assets/45624238/755f0bc3-fdac-469c-b748-15518095318c)\n\n\u003cdetails\u003e\n    \u003csummary\u003e테이블 설계 의도 보기\u003c/summary\u003e\n    \u003cbr\u003e\n    \u003cb\u003e사용자, 예산, 카테고리의 관계\u003c/b\u003e\n        \u003cul\u003e\n            \u003cli\u003e사용자는 여러 예산을 설정할 수 있습니다.\u003c/li\u003e\n            \u003cli\u003e한 번 예산을 설정할 때 카테고리별 예산을 지정할 수 있으므로 예산과 카테고리는 다대다 관계입니다.\u003c/li\u003e\n            \u003cli\u003e다대다 관계는 확장성과 유지보수 문제로 일반적으로 잘 사용하지 않으므로 중간 테이블\u003ccode\u003ebudget_category\u003c/code\u003e을 두어 일대다, 다대일로 풀어냈습니다.\u003c/li\u003e\n            \u003cul\u003e\n                \u003cli\u003e사용자 : 예산 = \u003ccode\u003e1:N\u003c/code\u003e\u003c/li\u003e\n                \u003cli\u003e예산 : 예산-카테고리 = \u003ccode\u003e1:N\u003c/code\u003e\u003c/li\u003e\n                \u003cli\u003e예산-카테고리 : 카테고리 = \u003ccode\u003eN:1\u003c/code\u003e\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/ul\u003e\n    \u003cb\u003e사용자, 지출, 카테고리의 관계\u003c/b\u003e\n        \u003cul\u003e\n            \u003cli\u003e사용자는 여러 지출을 등록할 수 있으므로 일대다 관계입니다.\u003c/li\u003e\n            \u003cli\u003e한 번 지출을 등록할 때 한 개의 카테고리를 지정할 수 있으므로 다대일 관계입니다.\u003c/li\u003e\n            \u003cul\u003e\n                \u003cli\u003e사용자 : 지출 = \u003ccode\u003e1:N\u003c/code\u003e\u003c/li\u003e\n                \u003cli\u003e지출 : 카테고리 = \u003ccode\u003eN:1\u003c/code\u003e\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/ul\u003e\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## REST API\n[자세한 내용은 GitHub Wiki로 이동! 🏃🏻‍♀️💨](https://github.com/dawwson/budget-keeper-be/wiki/1%EF%B8%8F%E2%83%A3-REST-API-%EB%AC%B8%EC%84%9C)\n\n| Method | URL | Description | Authorization | Completed |\n| :---: | --- | --- | :---: | :---: |\n| `POST` | `/auth/sign-up` | 회원가입 | X | ✅ |\n| `POST` | `/auth/sign-in` | 로그인 | X | ✅ |\n| `GET` | `/categories` | 카테고리 목록 조회 | O | ✅ |\n| `PUT` | `/budgets/{year}/{month}` | 월별 예산 설정 | O | ✅ |\n| `GET` | `/budgets/{year}/{month}/recommendation` | 월별 예산 추천 | O | ✅ |\n| `POST` | `/expenses` | 지출 생성 | O | ✅ |\n| `PATCH` | `/expenses/{id}` | 지출 수정 | O | ✅ |\n| `GET` | `/expenses/{id}` | 지출 상세 조회 | O | ✅ |\n| `GET` | `/expenses` | 지출 목록 조회 | O | ✅ |\n| `DELETE` | `/expenses/{id}` | 지출 삭제 | O | ✅ |\n| `GET` | `/expenses/statistics` | 지출 통계 | O | ✅ |\n\n\u003cbr\u003e\n\n## Convention\n[자세한 내용은 GitHub Wiki로 이동! 🏃🏻‍♀️💨](https://github.com/dawwson/budget-keeper-be/wiki/2%EF%B8%8F%E2%83%A3-%EC%BB%A8%EB%B2%A4%EC%85%98)\n\n\u003cbr\u003e\n\n## Architecture\n\u003cdetails\u003e\n    \u003csummary\u003e아키텍쳐 설계 의도 보기\u003c/summary\u003e\n    \u003cbr\u003e\n    \u003cb\u003e1. Custom Repository를 사용하지 않습니다.\u003c/b\u003e\n    \u003cul\u003e\n        \u003cli\u003e\u003ccode\u003eTypeORM\u003c/code\u003e 0.3 버전부터 \u003ccode\u003e@EntityRepository()\u003c/code\u003e 데코레이터가 \u003ccode\u003edeprecated\u003c/code\u003e됨에 따라 여러 기술 블로그에서 \u003ccode\u003eCustom Repository\u003c/code\u003e 만드는 방법을 소개하고 있습니다. 하지만 따라서 적용하지 않은 이유는 다음과 같습니다. \u003c/li\u003e\n            \u003cul\u003e\n                \u003cli\u003e이미 \u003ccode\u003eORM\u003c/code\u003e에서 제공하는 메서드를 한 번 더 추상화하게 되어, 요구사항이 늘어날수록 유지보수가 어려워진다고 느꼈습니다.\u003c/li\u003e\n                \u003cli\u003e향후 \u003ccode\u003eORM\u003c/code\u003e의 교체를 고려하여 서비스 레이어에서의 \u003ccode\u003eORM\u003c/code\u003e에 대한 의존성을 줄이기 위해 분리한다 하더라도, 현실적으로 한 번 정해진 \u003ccode\u003eORM\u003c/code\u003e시스템을 교체하기는 어렵다고 생각했습니다. \u003ccode\u003eORM\u003c/code\u003e마다 모델링 방법부터도 매우 다르기 때문입니다.\u003c/li\u003e\n                \u003cli\u003e\u003ccode\u003eCustom Repository\u003c/code\u003e의 단위 테스트가 어려워집니다. \u003ccode\u003eRepository\u003c/code\u003e를 분리하게 되면 테스트의 목적은 \u003ccode\u003eTypeORM\u003c/code\u003e의 메소드가 잘 동작하는지 확인하는 것에 그치게 됩니다.\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003cli\u003e대신 \u003ccode\u003eNestJS\u003c/code\u003e에서 제공하는 \u003ccode\u003e@InjectRepository()\u003c/code\u003e를 사용하여 \u003ccode\u003eRepository Pattern\u003c/code\u003e을 사용합니다.\u003c/li\u003e\n        \u003cli\u003e참고 자료\u003c/li\u003e\n        \u003cul\u003e\n            \u003cli link\u003e\u003ca href=\"https://youtu.be/6Tnq_e2MmVE?si=bdO-3-BLSGGnrc7Y\"\u003eEF Core에서 Repository 패턴은 쓰지 말 것\u003c/a\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/ul\u003e\n    \u003cb\u003e2. Service 계층 규칙\u003c/b\u003e\n    \u003cul\u003e\n        \u003cli\u003e\u003ccode\u003eService\u003c/code\u003e 계층에서는 여러 \u003ccode\u003eRepository\u003c/code\u003e를 주입받을 수 있습니다.\u003c/li\u003e\n        \u003cli\u003e\u003ccode\u003eRepository\u003c/code\u003e는 \u003ccode\u003eService\u003c/code\u003e에만 주입될 수 있습니다.\u003c/li\u003e\n        \u003cli\u003e\u003ccode\u003eService\u003c/code\u003e가 아닌 다른 \u003ccode\u003eProvider\u003c/code\u003e에서 데이터베이스 접근이 필요할 경우, \u003ccode\u003eRepository\u003c/code\u003e를 주입받아서 외부로 노출하는 \u003ccode\u003eProvider\u003c/code\u003e를 생성합니다.(함께 팀 프로젝트를 했던 \u003ca href=\"https://github.com/kangssu\"\u003e@kangssu\u003c/a\u003e님의 아이디어를 좀 더 구체화시켰습니다 👍)\n            \u003cul\u003e\n                \u003cli\u003e해당 \u003ccode\u003eProvider\u003c/code\u003e의 클래스명은 \u003ccode\u003e{자원명}Lib\u003c/code\u003e로 지정합니다.\u003c/li\u003e\n                \u003cli\u003e핵심 비즈니스 로직이 담긴 \u003ccode\u003eService\u003c/code\u003e와 코드를 분리하고, 상위 레벨로 만들어서 데이터베이스 커넥션을 추상화하기 위함입니다.\u003c/li\u003e\n            \u003c/ul\u003e\n\u003c/li\u003e\n    \u003c/ul\u003e\n    \u003cb\u003e3. DTO는 어디서 변환하는가?\u003c/b\u003e\n    \u003cul\u003e\n        \u003cli\u003e\u003ccode\u003eclas-transformer\u003c/code\u003e에서 제공하는 객체 매핑 데코레이터 및 함수를 활용합니다.\u003c/li\u003e\n        \u003cli\u003e\u003ccode\u003eController\u003c/code\u003e ➡️ \u003ccode\u003eService\u003c/code\u003e\u003c/li\u003e\n            \u003cul\u003e\n                \u003cli\u003e요청 \u003ccode\u003eDTO\u003c/code\u003e 클래스의 함수에서 변환합니다\u003c/li\u003e\n                \u003cli\u003e함수명은 \u003ccode\u003eto{서비스_DTO_이름}()\u003c/code\u003e으로 지정합니다.\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003cli\u003e\u003ccode\u003eEntity\u003c/code\u003e ➡️ \u003ccode\u003eResponse\u003c/code\u003e\u003c/li\u003e\n            \u003cul\u003e\n                \u003cli\u003e응답 \u003ccode\u003eDTO\u003c/code\u003e 클래스의 \u003ccode\u003estatic\u003c/code\u003e 함수에서 변환합니다\u003c/li\u003e\n                \u003cli\u003e함수명은 \u003ccode\u003eof()\u003c/code\u003e로 지정합니다.\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003cli\u003e참고 자료\u003c/li\u003e\n        \u003cul\u003e\n            \u003ca href=\"https://jojoldu.tistory.com/617\"\u003eTypeScript 환경에서 class-transformer 적극적으로 사용하기\u003c/a\u003e\n        \u003c/ul\u003e\n    \u003c/ul\u003e\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## Deployment Structure\n\u003cimg width=\"1082\" alt=\"image\" src=\"https://github.com/dawwson/budget-keeper-be/assets/45624238/28afc544-793d-40bd-8e04-4758ad12f91e\"\u003e\n\n- 로컬 개발 환경에서 프로덕션 환경변수를 설정하여 `Docker`기반으로 빌드합니다.\n- `Docker Hub`에 빌드한 이미지를 업로드합니다.\n- `EC2`에서 이미지를 내려받아서 실행합니다.\n- `EC2`와 `RDS`는 동일한 `VPC` 내에서 다른 보안 그룹으로 설정하여 통신합니다.\n\n\u003cbr\u003e\n\n## TIL \u0026 Retrospective\n[자세한 내용은 GitHub Wiki로 이동! 🏃🏻‍♀️💨](https://github.com/dawwson/budget-keeper-be/wiki/3%EF%B8%8F%E2%83%A3-%08TIL-\u0026-Retrospective)\n\n- [[NestJS] in-memory 데이터베이스로 테스트 코드 작성하기(with pg-mem)](https://github.com/dawwson/budget-keeper-be/wiki/3%EF%B8%8F%E2%83%A3-%08TIL-\u0026-Retrospective#-in-memory-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EB%A1%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0with-pg-mem)\n- [[Docker] 빌드 스테이지와 실행 스테이지 나누기](https://github.com/dawwson/budget-keeper-be/wiki/3%EF%B8%8F%E2%83%A3-%08TIL-\u0026-Retrospective#-%EB%B9%8C%EB%93%9C-%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%A7%80%EC%99%80-%EC%8B%A4%ED%96%89-%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%A7%80-%EB%82%98%EB%88%84%EA%B8%B0)\n- [[AWS] EC2 \u0026 RDS 환경 설정 방법](https://github.com/dawwson/budget-keeper-be/wiki/3%EF%B8%8F%E2%83%A3-%08TIL-\u0026-Retrospective#1-6-aws)\n\n\u003cbr\u003e\n\n## Test Result\n- E2E 테스트 결과\n\u003cimg width=\"316\" alt=\"image\" src=\"https://github.com/user-attachments/assets/3de8c899-ac35-43b1-a4c9-88e697905368\"\u003e\n\n\n\u003cbr\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdawwson%2Fchagok-be","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdawwson%2Fchagok-be","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdawwson%2Fchagok-be/lists"}