책을 검색하고, 해당 책에 대한 독서 기록을 남길 수 있습니다.
저장한 책의 정보와 나만의 기록을 사람들과 쉽게 공유해보세요!
24.09.20 ~ 진행 중
-
현재
feature/aws
브랜치에서 AWS EC2와 RDS를 사용하여 배포 환경을 구축 중이며, 추후 CI/CD 파이프라인을 구성할 예정입니다.진행 상황
-
로컬 환경 개발 완료
- 카카오 소셜 회원가입/로그인 기능 (REST)
- 책 검색 및 저장 기능 (REST)
- 좋아요 기능 (GraphQL)
- 저장한 책 정보 외부 공유 기능 (REST)
- 노트 CRUD 기능 (GraphQL)
-
Jest 테스트 코드 작성 중
-
CI/CD 배포 파이프라인 구축
-
git clone https://github.com/joosomi/bookpecker.git
프로젝트 루트 디렉토리에 .env
파일을 생성하고, 다음과 같은 환경 변수를 설정하세요:
# 애플리케이션 포트 설정
APP_PORT=
# PostgreSQL 데이터베이스 설정
POSTGRES_USER= # PostgreSQL 사용자 이름
POSTGRES_PASSWORD= # PostgreSQL 사용자 비밀번호
POSTGRES_DB= # 사용할 데이터베이스 이름
POSTGRES_HOST= # 데이터베이스 호스트 (개발환경 : localhost)
POSTGRES_PORT= # PostgreSQL 데이터베이스 포트
# Prisma
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?schema=public"
#KAKAO
KAKAO_CLIENT_ID=
KAKAO_REDIRECT_URI=
#JWT secret key
JWT_SECRET=
JWT_SHARE_SECRET=
#NAVER
NAVER_CLIENT_ID=
NAVER_CLIENT_SECRET=
프로젝트의 데이터베이스 및 필요한 서비스를 Docker로 실행하려면, 아래 단계를 따르세요.
루트 디렉토리에 있는 docker-compose.dev.yml
파일을 확인하고, .env
파일이 제대로 설정되었는지 확인하세요.
아래 명령어를 사용하여 Docker 컨테이너를 백그라운드에서 실행합니다:
docker-compose -f docker-compose.dev.yml up -d
-
app
- 개발 환경에서 애플리케이션을 실행하는 서비스입니다. 코드 수정 시 바로 반영되도록 volumes 설정을 통해 실시간으로 변경 사항을 적용합니다.
app 서비스는 DB 서비스인 db_dev에 의존하여, DB가 실행된 후에 애플리케이션이 실행됩니다.
- 개발 환경에서 애플리케이션을 실행하는 서비스입니다. 코드 수정 시 바로 반영되도록 volumes 설정을 통해 실시간으로 변경 사항을 적용합니다.
-
db_dev
- image:
postgres:15.7
버전의 PostgreSQL을 사용합니다. db-init.sh
스크립트: PostgreSQL 컨테이너가 처음 실행될 때 자동으로 실행됩니다. 데이터베이스를 생성하고, 환경변수로 설정한 이름, 비밀번호의 사용자를 생성하고 해당 DB에 대한 권한을 부여합니다.
- image:
Docker 컨테이너가 실행된 후, 프로젝트의 모든 의존성을 설치해야 합니다.
npm install
서버 실행
npm run start
개발 모드 실행
npm run start:dev
- User:
- 카카오 소셜 로그인을 통해 받아온 사용자 정보 저장
- kakaoId, 이메일, 사용자가 설정한 이름 등 기본 정보 관리
- Book:
- Naver 책 검색 API를 통해 검색된 책 정보 저장
- ISBN을 unique 식별자로 사용하여 중복 방지 (0으로 시작할 수 있기 때문에 문자열로 저장)
- UserBook:
- 사용자-책 정보 관리 (좋아요 기능)
- Note:
- 사용자의 책 관련 노트 저장
- 특정 책에 대한 사용자의 생각, 리뷰 등 기록
로컬에서 프로젝트를 실행한 후, 다음 URL을 통해 Swagger 문서에 접근할 수 있습니다:
http://localhost:<APP_PORT>/api-docs
참고: `<APP_PORT>`는 `.env` 파일에서 설정한 포트 번호입니다.
Swagger를 통해 API 요청을 테스트하고, 각 엔드포인트의 상세 정보를 확인할 수 있습니다.
🔍 디렉토리 구조
...
├── docker
│ ├── Dockerfile.dev
│ └── db-init.sh
├── docker-compose.dev.yml
├── nest-cli.json
├── package-lock.json
├── package.json
├── prisma
│ ├── migrations
│ └── schema.prisma
├── src
│ ├── app.module.ts
│ ├── feature
│ │ ├── auth
│ │ │ ├── auth.module.ts
│ │ │ ├── decorators
│ │ │ │ └── public.decorator.ts
│ │ │ ├── guards
│ │ │ │ └── jwt-auth.guard.ts
│ │ │ ├── strategies
│ │ │ │ └── jwt-auth.strategy.ts
│ │ │ └── types
│ │ │ └── jwt.type.ts
│ │ ├── common
│ │ │ └── book-search
│ │ │ ├── book-search.controller.spec.ts
│ │ │ ├── book-search.controller.ts
│ │ │ ├── book-search.module.ts
│ │ │ ├── book-search.service.spec.ts
│ │ │ ├── book-search.service.ts
│ │ │ ├── dto
│ │ │ │ └── book-search.dto.ts
│ │ │ └── types
│ │ │ └── naver-api.types.ts
│ │ ├── graphql
│ │ │ ├── book
│ │ │ │ ├── book.graphql
│ │ │ │ ├── book.module.ts
│ │ │ │ ├── book.resolver.ts
│ │ │ │ ├── book.service.spec.ts
│ │ │ │ ├── book.service.ts
│ │ │ │ └── dto
│ │ │ │ ├── save-book.input.ts
│ │ │ │ └── toggle-like.input.ts
│ │ │ ├── note
│ │ │ │ ├── dto
│ │ │ │ │ ├── create-note-dto.ts
│ │ │ │ │ └── update-note-dto.ts
│ │ │ │ ├── note.graphql
│ │ │ │ ├── note.module.ts
│ │ │ │ ├── note.resolver.ts
│ │ │ │ ├── note.service.spec.ts
│ │ │ │ └── note.service.ts
│ │ │ └── scalar
│ │ │ └── date-scalar.ts
│ │ └── rest
│ │ ├── oauth
│ │ │ ├── oauth.controller.spec.ts
│ │ │ ├── oauth.controller.ts
│ │ │ ├── oauth.module.ts
│ │ │ ├── oauth.service.spec.ts
│ │ │ ├── oauth.service.ts
│ │ │ └── strategies
│ │ │ └── kakao.strategy.ts
│ │ └── share-book
│ │ ├── dto
│ │ │ └── create-book-share-token.dto.ts
│ │ ├── share-book.controller.spec.ts
│ │ ├── share-book.controller.ts
│ │ ├── share-book.module.ts
│ │ ├── share-book.service.spec.ts
│ │ ├── share-book.service.ts
│ │ └── types
│ │ └── shared-book-response.type.ts
│ ├── filter
│ │ └── global-exception.filter.ts
│ ├── graphql.ts
│ ├── logging
│ │ └── logger.ts
│ ├── main.ts
│ └── prisma
│ ├── prisma.module.ts
│ ├── prisma.service.spec.ts
│ └── prisma.service.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
효율적인 프로젝트 관리를 위해 Issue와 PR에 대한 템플릿을 설정하여 프로젝트를 진행하였습니다.
일관된 코드 스타일을 유지하기 위해 ESLint와 Prettier를 사용하였습니다.
-
주요 ESLint 설정:
- 함수 반환 타입 명시 설정으로 타입 안정성 강화
any
타입 사용시 경고하여 타입 명확성 유지
새로운 기술들을 사용해보게 되어서 구현하는 데에 생각보다 개발에 시간이 많이 걸렸지만, GraphQL과 OAuth, Prisma를 활용해볼 수 있어서 유익했습니다.
먼저 kakao passport를 활용하여 쉽게 카카오 인증을 구현할 수 있다는 것을 배웠습니다. 처음에는 Passport 라이브러리 사용 없이 Auth 서비스 단에서 인증 로직을 처리하였으나, 코드가 길고 비효율적이라고 느껴져서 kakao passport를 적용하였고, guard로 쉽게 인증 처리를 할 수 있다는 것을 알게 되었습니다.
처음에는 graphql code-first 방식으로 구현을 했으나 요구 사항을 다시 검토하여 schema-first로 구현했어야 하는 것을 알게되어 리팩토링하였습니다. 스키마 파일 정의를 통한 리졸버 구현 방식을 배울 수 있어서 좋았습니다. 독립적으로 스키마 파일이 관리되어서 개발 중 변경 사항이 있을 때 쉽게 수정할 수 있었습니다.
Prisma를 처음 사용해보았는데 장점을 알게 되어 좋았습니다. 특히 DB 마이그레이션을 관리할 수 있어 변경 사항을 쉽게 파악할 수 있었습니다. 또한 prisma studio로 쉽게 데이터 확인이 가능하니까 개발 과정에서도 편리했습니다.
외부 공유 기능에서는 JWT 토큰을 활용해 만료 시간을 설정하여 구현했습니다. 처음에는 막연히 Guard로 처리해야하나 생각했었는데, 비로그인 사용자도 접근할 수 있는 엔드포인트이고, 단순히 제한 시간만 필요한 상황이기 때문에, Custom Guard를 별도로 구현하기보다는 서비스 단에서 토큰을 검증하는 방식이 더 단순하고 효율적이라고 판단했습니다. 추후 여러 종류의 공유 토큰이 생기거나, 공유 관련 엔드포인트가 더 필요하게 된다면, Custom Guard를 도입하는 것도 고려해볼 수 있겠지만, 현재는 엔드포인트가 하나뿐이므로 서비스 레벨에서 공유 토큰을 검증하였습니다.