-
Notifications
You must be signed in to change notification settings - Fork 0
Chore: 패키지 설정 #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough프로젝트 전역 에디터/줄바꿈 설정(.editorconfig, .gitattributes) 추가로 LF 고정. package.json에 Swagger·Yjs·WebSocket 관련 런타임 의존성 추가. TypeORM 설정을 명시적 엔티티 등록( Cardset, CardsetManager, Card )과 synchronize=false로 변경. Swagger UI(/api-docs) 도입. Cardset, CardsetManager, Card 도메인의 모듈/서비스/컨트롤러/엔티티 및 기본 스펙 테스트 추가. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Node as Node.js
participant Nest as NestFactory
participant App as AppModule
participant TypeORM as TypeORM
participant Swagger as SwaggerModule
participant HTTP as HTTP Server
rect rgb(248,250,255)
Note over Nest,App: 애플리케이션 부트스트랩(변경)
Node->>Nest: create(AppModule)
Nest->>App: 모듈 초기화(imports: CardsetModule, CardsetManagerModule, CardModule)
App->>TypeORM: initialize(entities=[Cardset, CardsetManager, Card], synchronize=false)
end
rect rgb(240,255,240)
Note over Swagger,HTTP: API 문서 설정(신규)
Nest->>Swagger: build 문서(DocumentBuilder: Flip Note API, BearerAuth)
Swagger-->>HTTP: /api-docs 라우트 등록
end
Nest-->>HTTP: listen(PORT)
sequenceDiagram
autonumber
participant Client
participant Controller
participant Service
Note over Controller,Service: 도메인 스켈레톤 흐름(신규)
Client->>Controller: HTTP 요청 (향후 엔드포인트)
Controller->>Service: 서비스 호출
Service-->>Controller: 결과 반환
Controller-->>Client: 응답
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
package.json (1)
55-55: Jest@^30 ↔ ts-jest@^29 호환성 불일치 — 버전 정렬 필요 (package.json: lines 55, 59)웹 확인 결과: 최신 ts-jest는 Jest 메이저 29만 지원합니다.
옵션 A (권장): Jest를 29로 낮춤
- "jest": "^30.0.0", + "jest": "^29.7.0",옵션 B: ts-jest가 v30으로 릴리스되어 Jest 30을 지원하면 ts-jest를 30으로 올림
- "ts-jest": "^29.2.5", + "ts-jest": "^30.0.0",
🧹 Nitpick comments (23)
.editorconfig (1)
1-10: 기본 설정은 적절합니다. Markdown 줄바꿈/불필요 공백 처리와 Makefile 탭 들여쓰기 예외를 추가하세요.
전역 LF, 2칸 스페이스, UTF-8 모두 👍. 실사용에서 흔한 불편을 줄이기 위해 아래 보완을 권장합니다.
- 전역 트레일링 공백 제거 + Markdown만 보존
- Makefile은 탭 들여쓰기 강제
- YAML 명시(현재 전역 2칸이지만 가독성 위해 섹션 분리 추천)
적용 예시(diff):
[*] end_of_line = lf insert_final_newline = true charset = utf-8 indent_style = space indent_size = 2 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab + +[*.yml] +indent_size = 2 + +[*.yaml] +indent_size = 2.gitattributes (1)
1-6: LF 강제는 좋습니다. lockfile, 스크립트, 바이너리 파일 규칙을 보완해 주세요.
체크아웃 시 일관된 개행을 확보했지만, 다음을 추가하면 협업 시 충돌/노이즈가 더 줄어듭니다.
- lockfile: 큰 diff 억제(-diff) 및 LF 고정
- 쉘 스크립트: LF 강제
- 바이너리 자산: binary 처리(개행/변환 방지)
추가 예시(diff):
* text=auto eol=lf *.ts text eol=lf *.js text eol=lf *.json text eol=lf *.md text eol=lf + +# scripts +*.sh text eol=lf + +# lockfiles +package-lock.json text eol=lf -diff +yarn.lock text eol=lf -diff +pnpm-lock.yaml text eol=lf -diff + +# assets +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +# SVG는 텍스트이므로 LF 고정 +*.svg text eol=lfpackage.json (2)
34-34: swagger-ui-express 의존성 필요성 재검토Nest의
SwaggerModule.setup()만 사용한다면swagger-ui-express는 불필요할 수 있습니다. 실제 사용 여부 확인 후 미사용이면 제거 권장.- "swagger-ui-express": "^5.0.1",
36-38: 미사용 실시간 협업 패키지는 단계적 도입 권장
ws,y-websocket,yjs가 아직 코드에 사용되지 않았다면 PR 스코프를 좁히고 필요 시 별도 PR로 추가하는 것이 보안·공급망·리뷰 용이성 측면에서 유리합니다.src/cardset/cardset.service.spec.ts (1)
15-17: 스모크 테스트 외에 최소 동작 테스트 추가 권장현재는 정의 여부만 검증합니다. 서비스 메서드가 생기면 성공/에러 경로에 대한 단위 테스트를 바로 추가해 주세요.
원하시면 기본 테스트 템플릿을 생성해 드립니다.
src/cardset-manager/entities/cardset-manager.entity.ts (1)
5-6: 중복(비효율) 인덱스 정리
@Unique(['userId','cardSetId'])는 (userId, cardSetId) 복합 유니크 인덱스를 생성합니다. 이때userId단일 조건은 복합 인덱스의 좌측 프리픽스로 활용 가능하므로 별도의@Index(['userId'])는 중복일 수 있습니다. 반면cardSetId단일 조건은 프리픽스가 아니므로 단일 인덱스 유지 가치가 있습니다.다음과 같이 정리하세요:
@Entity('card_set_managers') -@Unique(['userId', 'cardSetId']) -@Index('idx_card_set_manager_user', ['userId']) +@Unique('uq_card_set_manager_user_cardset', ['userId', 'cardSetId']) @Index('idx_card_set_manager_cardset', ['cardSetId']) export class CardsetManager {추가 제안(선택): 읽기 모델 명확화를 위해 Cardset 연관을 노출하되, 현재 정책과 맞춰 FK 제약은 끈 상태로 유지 가능.
import { ManyToOne, JoinColumn } from 'typeorm'; import { Cardset } from '../../cardset/entities/cardset.entity'; @ManyToOne(() => Cardset, { createForeignKeyConstraints: false }) @JoinColumn({ name: 'card_set_id' }) cardset?: Cardset;src/cardset/entities/cardset.entity.ts (2)
14-21: 프로퍼티 네이밍 일관성(가독성)불리언은
isXxx/hasXxx형태가 일반적입니다. 선택적으로 리네이밍을 고려해 주세요.- publicVisible!: boolean; + isPublic!: boolean;(컬럼명은 그대로
is_public유지)
11-12: 조회 패턴 대비 인덱스 고려
group_id,category로 자주 조회/필터한다면 보조 인덱스 추가를 검토하세요. 데이터량이 커지면 효과적입니다.Also applies to: 22-23
src/cardset-manager/cardset-manager.controller.spec.ts (1)
17-19: 스모크 테스트 OK — 향후 동작 테스트 확장현재 정의 여부만 검증합니다. 실제 라우트 핸들러 추가 시 성공/에러 케이스 테스트를 보강해 주세요.
src/card/card.module.ts (1)
5-9: 서비스 외부 사용 계획 시 exports 추가다른 모듈에서
CardService를 주입해 사용한다면exports에 노출해야 합니다. (추후 TypeORM Repository 주입 예정이면TypeOrmModule.forFeature([Card])도imports에 추가 필요)@Module({ - controllers: [CardController], - providers: [CardService], + controllers: [CardController], + providers: [CardService], + exports: [CardService], }) export class CardModule {}src/card/card.controller.spec.ts (1)
1-20: 단위 테스트에서 Service 목으로 대체 권장컨트롤러는 현재 로직을 호출하지 않으므로 실제
CardService대신 빈 목을 주입하면 테스트가 가볍고 의존성에 덜 민감합니다.- providers: [CardService], + providers: [ + { provide: CardService, useValue: {} }, + ],src/cardset/cardset.module.ts (1)
5-9: 다른 모듈에서 CardsetService 사용 계획 점검추후 타 모듈에서 주입한다면
exports에 올려두는 것이 편합니다. 현재 필요 없다면 생략해도 무방합니다.@Module({ controllers: [CardsetController], providers: [CardsetService], + exports: [CardsetService], })src/cardset-manager/cardset-manager.service.spec.ts (1)
1-18: 의존성 없는 서비스는 직접 인스턴스화로 간소화 가능Nest TestingModule 없이도 테스트가 가능합니다. 실행 시간이 줄고 간결해집니다.
-import { Test, TestingModule } from '@nestjs/testing'; +// Nest testing utilities 불필요 (직접 인스턴스화) import { CardsetManagerService } from './cardset-manager.service'; describe('CardsetManagerService', () => { let service: CardsetManagerService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [CardsetManagerService], - }).compile(); - - service = module.get<CardsetManagerService>(CardsetManagerService); - }); + beforeEach(() => { + service = new CardsetManagerService(); + }); it('should be defined', () => { expect(service).toBeDefined(); }); });src/cardset/cardset.controller.ts (1)
1-7: Swagger 그룹 태깅으로 문서 가독성 향상컨트롤러에
@ApiTags를 추가하면 문서 섹션이 정리됩니다.-import { Controller } from '@nestjs/common'; +import { Controller } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; @@ -@Controller('cardset') +@ApiTags('cardset') +@Controller('cardset') export class CardsetController { constructor(private readonly cardsetService: CardsetService) {} }src/card/card.controller.ts (1)
1-7: Swagger 그룹 태깅 추가 제안카드 도메인 엔드포인트를 별도 섹션으로 구분합니다.
-import { Controller } from '@nestjs/common'; +import { Controller } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; @@ -@Controller('card') +@ApiTags('card') +@Controller('card') export class CardController { constructor(private readonly cardService: CardService) {} }src/card/card.service.spec.ts (1)
1-18: 의존성 없는 서비스 테스트 간소화 가능
CardService가 외부 의존성이 없으므로 직접 생성 방식으로 단순화할 수 있습니다.-import { Test, TestingModule } from '@nestjs/testing'; +// Nest testing utilities 불필요 (직접 인스턴스화) import { CardService } from './card.service'; describe('CardService', () => { let service: CardService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [CardService], - }).compile(); - - service = module.get<CardService>(CardService); - }); + beforeEach(() => { + service = new CardService(); + }); it('should be defined', () => { expect(service).toBeDefined(); }); });src/cardset-manager/cardset-manager.module.ts (1)
1-8: Repository 주입 대비: TypeOrmModule.forFeature 연결 권장향후
CardsetManagerService에서Repository<CardsetManager>를 주입할 예정이라면, 모듈에TypeOrmModule.forFeature를 미리 연결해 주세요.아래 패치를 제안합니다:
import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CardsetManager } from './entities/cardset-manager.entity'; import { CardsetManagerService } from './cardset-manager.service'; import { CardsetManagerController } from './cardset-manager.controller'; @Module({ + imports: [TypeOrmModule.forFeature([CardsetManager])], controllers: [CardsetManagerController], providers: [CardsetManagerService], }) export class CardsetManagerModule {}src/cardset/cardset.controller.spec.ts (2)
9-12: 서비스 의존성 목킹으로 스펙 안정화
CardsetService가 리포지토리 등 외부 의존성을 가지면 현재 스펙이 실패할 수 있습니다. 간단한 목으로 대체해 스펙을 안정화하세요.- providers: [CardsetService], + providers: [ + { provide: CardsetService, useValue: {} }, + ],
17-19: 스모크 테스트를 넘어 최소 동작 검증 추가 제안현재는 존재 여부만 확인합니다. 컨트롤러에 메서드가 생기면 하나의 happy-path 단위테스트를 추가해 주세요.
src/cardset-manager/cardset-manager.controller.ts (2)
4-4: REST 경로 네이밍(복수형) 정렬리소스 경로를 관례적으로 복수형(
cardset-managers)으로 권장합니다.-@Controller('cardset-manager') +@Controller('cardset-managers')
1-7: Swagger 태그 추가로 문서 탐색성 향상프로젝트에 Swagger를 도입했다면 태그를 붙여 그룹화하세요.
-import { Controller } from '@nestjs/common'; +import { Controller } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; @@ -@Controller('cardset-managers') +@ApiTags('cardset-managers') +@Controller('cardset-managers') export class CardsetManagerController {src/app.module.ts (1)
18-18: DB_PORT 파싱 가드 추가
process.env.DB_PORT가 비어있으면Number(undefined)는NaN이 됩니다. 기본값을 두거나 확실한 파싱을 권장합니다.- port: Number(process.env.DB_PORT), + port: parseInt(process.env.DB_PORT ?? '3306', 10),추가로
ConfigModule에 환경변수 스키마 검증(Joi 등) 도입을 고려해 주세요.src/card/entities/card.entity.ts (1)
1-3: 조회 성능을 위한 인덱스 추가 제안
card_set_id조인/필터가 잦다면 인덱스를 추가하세요.-import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, JoinColumn } from 'typeorm'; +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, JoinColumn, Index } from 'typeorm'; @@ - @Column({ name: 'card_set_id', type: 'int', nullable: false }) + @Index('idx_card_card_set_id') + @Column({ name: 'card_set_id', type: 'int', nullable: false }) cardSetId!: number;Also applies to: 9-11
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (23)
.editorconfig(1 hunks).gitattributes(1 hunks)package.json(1 hunks)src/app.module.ts(2 hunks)src/card/card.controller.spec.ts(1 hunks)src/card/card.controller.ts(1 hunks)src/card/card.module.ts(1 hunks)src/card/card.service.spec.ts(1 hunks)src/card/card.service.ts(1 hunks)src/card/entities/card.entity.ts(1 hunks)src/cardset-manager/cardset-manager.controller.spec.ts(1 hunks)src/cardset-manager/cardset-manager.controller.ts(1 hunks)src/cardset-manager/cardset-manager.module.ts(1 hunks)src/cardset-manager/cardset-manager.service.spec.ts(1 hunks)src/cardset-manager/cardset-manager.service.ts(1 hunks)src/cardset-manager/entities/cardset-manager.entity.ts(1 hunks)src/cardset/cardset.controller.spec.ts(1 hunks)src/cardset/cardset.controller.ts(1 hunks)src/cardset/cardset.module.ts(1 hunks)src/cardset/cardset.service.spec.ts(1 hunks)src/cardset/cardset.service.ts(1 hunks)src/cardset/entities/cardset.entity.ts(1 hunks)src/main.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
src/cardset/cardset.service.ts (2)
src/card/card.service.ts (1)
Injectable(3-5)src/cardset-manager/cardset-manager.service.ts (1)
Injectable(3-6)
src/cardset/cardset.module.ts (3)
src/app.module.ts (1)
Module(11-32)src/card/card.module.ts (1)
Module(5-9)src/cardset-manager/cardset-manager.module.ts (1)
Module(5-9)
src/cardset-manager/cardset-manager.module.ts (3)
src/app.module.ts (1)
Module(11-32)src/card/card.module.ts (1)
Module(5-9)src/cardset/cardset.module.ts (1)
Module(5-9)
src/cardset-manager/cardset-manager.service.ts (2)
src/card/card.service.ts (1)
Injectable(3-5)src/cardset/cardset.service.ts (1)
Injectable(3-6)
src/cardset/entities/cardset.entity.ts (2)
src/card/entities/card.entity.ts (1)
Entity(4-18)src/cardset-manager/entities/cardset-manager.entity.ts (1)
Entity(3-16)
src/card/card.service.ts (2)
src/cardset-manager/cardset-manager.service.ts (1)
Injectable(3-6)src/cardset/cardset.service.ts (1)
Injectable(3-6)
src/card/card.controller.ts (2)
src/cardset-manager/cardset-manager.controller.ts (1)
Controller(4-7)src/cardset/cardset.controller.ts (1)
Controller(4-7)
src/cardset-manager/entities/cardset-manager.entity.ts (2)
src/card/entities/card.entity.ts (1)
Entity(4-18)src/cardset/entities/cardset.entity.ts (1)
Entity(3-30)
src/cardset/cardset.controller.ts (2)
src/card/card.controller.ts (1)
Controller(4-7)src/cardset-manager/cardset-manager.controller.ts (1)
Controller(4-7)
src/cardset-manager/cardset-manager.controller.ts (2)
src/card/card.controller.ts (1)
Controller(4-7)src/cardset/cardset.controller.ts (1)
Controller(4-7)
src/card/entities/card.entity.ts (1)
src/cardset/entities/cardset.entity.ts (1)
Entity(3-30)
src/card/card.module.ts (3)
src/app.module.ts (1)
Module(11-32)src/cardset-manager/cardset-manager.module.ts (1)
Module(5-9)src/cardset/cardset.module.ts (1)
Module(5-9)
🔇 Additional comments (5)
src/cardset/cardset.service.ts (1)
3-6: 스켈레톤 서비스 OK초기 스캐폴딩으로 적절합니다. 이후 비즈니스 로직 추가 시 DTO/에러 처리 정책을 함께 정의해 주세요.
package.json (1)
46-46: @types/express@^5 사용 여부 확인Nest 11 기본 어댑터/타입 호환성(Express 4 vs 5)을 확인해 주세요. Express 5 타입은 서드파티 미들웨어 타입들과 충돌할 수 있습니다.
src/cardset-manager/cardset-manager.service.ts (1)
3-6: 스켈레톤 서비스 OK모듈·컨트롤러와의 의존성 연결이 정상입니다. 구현 추가 시 인터페이스/예외 정책 정합성만 확인해 주세요.
src/card/card.service.ts (1)
1-5: 스켈레톤 서비스 추가 OK현재 단계에선 충분합니다. CardModule에 정상 등록되어 있는지 정도만 확인해 주세요.
src/card/entities/card.entity.ts (1)
12-14: 외래키 제약 비활성화 — 의도 확인 및 FK 활성화 권고createForeignKeyConstraints: false는 DB에 외래키 제약을 생성하지 않아 고아 레코드와 데이터 무결성 위험이 큽니다. 특별한 이유가 없다면 외래키를 생성하도록 변경하고 삭제 규칙(onDelete)을 명시하세요.
파일: src/card/entities/card.entity.ts (라인 12–14)
권장 예시:
@manytoone(() => Cardset, { onDelete: 'CASCADE' })
@joincolumn({ name: 'card_set_id' })
cardset?: Cardset;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/main.ts (1)
8-15: Swagger는 운영(prod)에서 기본 비활성화해야 합니다. 환경변수로 게이트하십시오.현재 모든 환경에서 /api-docs가 노출됩니다. 운영 정보 노출 리스크가 큽니다. 이전 코멘트와 동일 이슈로 미해결입니다.
아래처럼 게이트해 주세요.
- const config = new DocumentBuilder() - .setTitle('Flip Note API') - .setDescription('API documentation') - .setVersion('1.0.0') - .addBearerAuth() - .build(); - const document = SwaggerModule.createDocument(app, config); - SwaggerModule.setup('api-docs', app, document); + if (process.env.SWAGGER_ENABLED === 'true' || process.env.NODE_ENV !== 'production') { + const config = new DocumentBuilder() + .setTitle('Flip Note API') + .setDescription('API documentation') + .setVersion('1.0.0') + .addBearerAuth() + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api-docs', app, document); + }
🧹 Nitpick comments (3)
src/main.ts (3)
12-13: Bearer 스키마를 명시하고 글로벌 보안 요구사항을 추가하세요.Swagger UI와 클라이언트 툴의 상호운용성을 위해 스키마를 구체화하고 전역 보안 요구를 선언하는 편이 좋습니다.
- .addBearerAuth() + .addBearerAuth( + { type: 'http', scheme: 'bearer', bearerFormat: 'JWT', description: 'JWT access token' }, + 'bearer' + ) + .addSecurityRequirements('bearer')
15-15: /api-docs 경로와 토큰 유지 옵션을 환경화하세요.경로 충돌을 피하고 개발 편의를 위해 persistAuthorization을 켜두는 것을 권장합니다(운영 비활성화 전제).
- SwaggerModule.setup('api-docs', app, document); + SwaggerModule.setup(process.env.SWAGGER_PATH ?? 'api-docs', app, document, { + swaggerOptions: { persistAuthorization: true }, + });
16-26: 주석 처리된 대체 코드 블록은 제거하세요.실제 로직으로 대체되었으므로 주석 블록은 소음입니다. 유지 시 오해를 유발합니다.
- // swagger 운영 환경에서 비활성화 - // if (process.env.SWAGGER_ENABLED === 'true' || process.env.NODE_ENV !== 'production') { - // const config = new DocumentBuilder() - // .setTitle('Flip Note API') - // .setDescription('API documentation') - // .setVersion('1.0.0') - // .addBearerAuth() - // .build(); - // const document = SwaggerModule.createDocument(app, config); - // SwaggerModule.setup('api-docs', app, document); - // }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
package.json(1 hunks)src/app.module.ts(2 hunks)src/card/entities/card.entity.ts(1 hunks)src/main.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/card/entities/card.entity.ts
- package.json
- src/app.module.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (1)
src/main.ts (1)
3-3: Swagger 의존성 임포트 자체는 무난합니다.임포트는 적절합니다. 아래 게이팅 적용만 병행하세요.
📝 변경 내용
✅ 체크리스트
💬 기타 참고 사항
Summary by CodeRabbit
신기능
테스트
작업(Chores)