오늘은 트렐로 팀 프로젝트 API 명세서 작성, NestJS 기본 디렉터리 구조 구성, 엔티티 파일 구성을 진행하였다.
CLI 명령어(nest g module, nest g controller, nest g service 등)을 활용하여 폴더/파일을 자동생성하였고 src 폴더 내에 기능별로 폴더가 추가될 예정이다.
엔티티 작성
기존 작성한 ERD를 피드백 받은 후 db테이블 구조를 적용하기 위한 엔티티 파일을 작성하였다.
@Entity 데코레이터로 어떤 테이블에 매핑할 지, @PrimaryGeneratedColumn(), @Column()으로 어떤 컬럼을 가질지 지정할 수 있었다.
// trelloProject/src/users/entities/user.entity.ts
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
OneToMany,
} from 'typeorm';
// 다른 엔티티들과의 관계를 설정하기 위해 임포트
import { Member } from 'src/members/entities/member.entity';
import { Board } from 'src/boards/entities/board.entity';
import { JoinMember } from 'src/card-members/entities/card-member.entity';
import { Alarm } from 'src/alarms/entities/alarm.entity';
import { Comment } from 'src/comments/entities/comment.entity';
// 이 클래스가 DB의 User 테이블과 매핑되는 엔티티임을 지정
@Entity({
// 실제 DB에서 사용할 테이블 이름 지정
name: 'User',
})
export class User {
// 기본 키 컬럼, 자동으로 생성되는 ID 설정
@PrimaryGeneratedColumn()
id: number;
@Column('varchar', { nullable: false, unique: true })
email: string;
@Column()
password: string;
@Column()
name: string;
@Column({ unique: true })
phoneNumber: string;
@Column({ default: false })
isVerified: boolean;
@Column()
verifyCode: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
// @OneToMany >> 1:N 관계
@OneToMany(() => Board, (board) => board.user) boards: Board[];
@OneToMany(() => Member, (member) => member.user) members: Member[];
@OneToMany(() => JoinMember, (joinMember) => joinMember.user)
joinMembers: JoinMember[];
@OneToMany(() => Comment, (comment) => comment.user) comments: Comment[];
@OneToMany(() => Alarm, (alarm) => alarm.user) alarms: Alarm[];
}
1:N, N:1 관계처럼 엔티티 간 관계를 설정하는 방법(@OneToMany, @ManyToOne)도 기존 실습 프로젝트 파일을 참고하여 작성하였고, 테이블 관계설정 시 양방향 모두에 관계를 작성하여 서로 다른쪽 테이블을 쉽게 조회할 수 있도록하였다.
하위 테이블에 onDelete: 'CASCADE'를 작성하여 무보 테이블 삭제 시 자식 테이블도 삭제되도록 설정할 수 있는 것을 배웠고 내일 관계를 면밀히 조사한 후에 적용하기로 하였다.
Faker 라이브러리를 활용하여 더미테이더 생성 테스트
추가적으로 이번 프로젝트 도전 기능인 [더미데티어 활용하기]를 위해 faker 라이브러리를 사용하는 방법을 찾아 실습 프로젝트에 적용해보았다.
편의성을 위해 명령어 입력 시 더미데이터가 생성되는 형식으로 진행하였다.
...
├─ src
│ ├─ app.controller.spec.ts
│ ├─ app.controller.ts
│ ├─ app.module.ts
│ ├─ app.service.ts
│ ├─ auth
│ │ ├─ auth.module.ts
│ │ ├─ jwt.strategy.ts
│ │ ├─ roles.decorator.ts
│ │ └─ roles.guard.ts
│ ├─ main.ts
│ ├─ seed // faker 라이브러리 활용을 위해 추가한 폴더
│ │ ├─ seed.module.ts
│ │ ├─ seed.service.ts
│ │ └─ seed.ts
...
src 폴더 내 seed 폴더를 구성 후 faker 라이브러리의 사용법을 참고하여 각각의 파일들을 작성하였다.
1. Faker 설치
npm install @faker-js/faker
# 또는
yarn add @faker-js/faker
2. SeedModule, SeedService, seed.ts(스크립트) 작성
// src/seed/seed.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SeedService } from './seed.service';
// 사용할 엔티티 임포트
import { User } from 'src/user/entities/user.entity';
import { Team } from 'src/team/entities/team.entity';
import { SupportMessage } from 'src/support-message/entities/support-message.entity';
@Module({
imports: [
// 사용할 엔티티를 forFeature로 주입
TypeOrmModule.forFeature([User, Team, SupportMessage]),
],
providers: [SeedService],
exports: [SeedService],
})
export class SeedModule {}
// src/seed/seed.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { faker } from '@faker-js/faker';
import { Repository } from 'typeorm';
import { User } from 'src/user/entities/user.entity';
import { Team } from 'src/team/entities/team.entity';
import { SupportMessage } from 'src/support-message/entities/support-message.entity';
import { Role } from 'src/user/types/userRole.type';
@Injectable()
export class SeedService {
constructor(
@InjectRepository(User)
private readonly userRepo: Repository<User>,
@InjectRepository(Team)
private readonly teamRepo: Repository<Team>,
@InjectRepository(SupportMessage)
private readonly supportMessageRepo: Repository<SupportMessage>,
) {}
// Faker를 활용하여 User, Team, SupportMessage 더미 데이터 생성
async createSeedData() {
// 1) Team 더미 데이터 생성
const teams: Team[] = [];
for (let i = 0; i < 3; i++) {
const team = new Team();
team.name = faker.company.name(); // 롤팀이지만 일단 회사 이름 생성으로 진행
team.description = faker.company.catchPhrase(); // 캐치 프레이즈 적용
teams.push(team);
}
const savedTeams = await this.teamRepo.save(teams);
// 2) User 더미 데이터 생성
const users: User[] = [];
for (let i = 0; i < 5; i++) {
const user = new User();
user.email = faker.internet.email(); // 이메일 생성
user.password = '1234'; // 임시 비밀번호
user.role = faker.helpers.arrayElement([Role.User, Role.Admin]); // 객체에서 랜덤으로 생성
users.push(user);
}
const savedUsers = await this.userRepo.save(users);
// 3) SupportMessage 더미 데이터 생성
// (랜덤하게 user/team 조합)
const messages: SupportMessage[] = [];
for (let i = 0; i < 10; i++) {
const msg = new SupportMessage();
msg.message = faker.lorem.sentence(); // 랜덤 문장
msg.user = faker.helpers.arrayElement(savedUsers); // 객체에서 랜덤으로 생성
msg.team = faker.helpers.arrayElement(savedTeams); // 객체에서 랜덤으로 생성
messages.push(msg);
}
await this.supportMessageRepo.save(messages);
console.log('Seed data created successfully!');
}
}
// src/seed/seed.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from 'src/app.module';
import { SeedService } from './seed.service';
async function bootstrap() {
// 1) Nest 애플리케이션 시작
const app = await NestFactory.create(AppModule);
// 2) SeedService를 가져와서
const seedService = app.get(SeedService);
// 3) 더미데이터 생성
await seedService.createSeedData();
// 4) 종료
await app.close();
}
bootstrap().catch((err) => {
console.error(err);
});
src/seed 디렉토리를 생성한 후 폴더에 위 파일들을 적용하였다.
>> SeedService에서 User, Team 등의 더미 데이터를 Faker를 사용해 생성
>> seed.ts 스크립트가 Nest 애플리케이션을 부트스트랩한 후
>> SeedService를 호출하게 된다.
SeedService에서 더미데이터 생성 로직을 작성하는데, 사용할 수 있는 Faker 라이브러리 주요 함수는 다음과 같다.
주요 함수 이름 관련
faker.name.firstName(): 랜덤한 이름의 첫 번째 부분을 생성
faker.name.lastName(): 랜덤한 성을 생성
faker.name.findName(): 랜덤한 전체 이름을 생성
주소 관련
faker.address.city(): 랜덤한 도시 이름을 생성
faker.address.country(): 랜덤한 국가 이름을 생성
faker.address.streetAddress(): 랜덤한 거리 주소를 생성
전화번호 관련
faker.phone.phoneNumber(): 랜덤한 전화번호를 생성
인터넷 관련
faker.internet.email(): 랜덤한 이메일 주소를 생성
faker.internet.userName(): 랜덤한 사용자 이름을 생성
faker.internet.url(): 랜덤한 URL을 생성
회사 관련
faker.company.companyName(): 랜덤한 회사 이름을 생성
faker.company.catchPhrase(): 랜덤한 회사의 슬로건을 생성
문장 및 텍스트 관련
faker.lorem.sentence(): 랜덤한 문장을 생성
faker.lorem.paragraph(): 랜덤한 단락을 생성
faker.lorem.words(): 랜덤한 단어 목록을 생성합
날짜 및 시간 관련
faker.date.past(): 과거의 랜덤한 날짜를 생성
faker.date.future(): 미래의 랜덤한 날짜를 생성
faker.date.between(startDate, endDate): 지정된 날짜 범위 내의 랜덤한 날짜를 생성
금융 관련
faker.finance.amount(): 랜덤한 금액을 생성
faker.finance.creditCardNumber(): 랜덤한 신용카드 번호를 생성
이후 package.json 스크립트의 명령어 관련 설정 추가 후, npm run seed 명령어를 통해 더미데이터 생성 테스트를 진행해보았다.
로직대로 생성은 잘 되었으나 한글로 생성하려면 추가적인 설정을 통해 진행할 수 있다고 한다. 다만 현재 팀 프로젝트에 적용할지는 확정되지 않아 추후 검토 후 반영할 예정이다.
요약
NestJS 프로젝트 디렉토리 구조 설정 : NestJS는 기능별 폴더 구조가 비교적 깔끔하여 모듈-컨트롤러-서비스 파일이 한폴더에 모여 있어 유지 보수가 쉽다.
엔티티 작성 : 데코레이터를 통해 DB 테이블을 코드로 표현하는 방법과 관계설정을 배웠고, 자식 엔티티에 onDelete: 'CASCADE'를 달아 부모와 함께 삭제될 수 있도록 제어할 수 있다.
Faker 라이브러리 : 더미데이터 적용을 위한 Faker 라이브러리 적용을 실습해 보았고 추후 검토하여 프로젝트에 적용 예정.
오늘 배운 점을 토대로 다른 프로젝트 시작 단계의 설계에 더 익숙해질 수 있었고, 새롭게 적용하는 NestJS 프로젝트의 기본적인 형태, 구조에 대해 팀원과 대화하며 이해도를 올릴 수 있었다.
엔티티 작성 시 관계설정 시 꼼꼼한 조사 후 진행해야겠다고 생각하였다.
'TIL' 카테고리의 다른 글
내일배움캠프 13주차 금요일 TIL (0) | 2025.01.24 |
---|---|
내일배움캠프 13주차 화요일 TIL (1) | 2025.01.21 |
내일배움캠프 12주차 금요일 TIL (0) | 2025.01.17 |
내일배움캠프 12주차 목요일 TIL (0) | 2025.01.16 |
내일배움캠프 12주차 수요일 TIL (0) | 2025.01.15 |