---
# System prepended metadata

title: Untitled

---

## DTO 유효성 검사
- cardId는 카드 엔티티, content 댓글 엔티티
- 엔티티가 서로 다른 요청 필드에 대해 어떻게 유효성 검사를 하는지?
- 어떻게 validateIf를 사용하여야 groups와 같은 효과를 낼 수 있는지?
```javascript=
router.post('/:cardId/comment', async (req, res) => {
    const commentService = CommentService.getInstance();
    const userId = req.user.id;
    const { cardId } = req.params;
    const { content } = req.body;

    if (cardId === undefined || !isNumberString(cardId)) {
        throw new BadRequestError('Wrong params');
    }

    if (content === undefined) {
        throw new BadRequestError('Empty content');
    }

    const responseBody = await commentService.addComment({ userId, cardId, content });

    res.status(201).json(responseBody);
});
```
```javascript=
export class CardDto {
    id;

    @ValidateIf((o) => o.title !== undefined)
    @IsString()
    @IsNotEmpty()
    title;

    @ValidateIf((o) => o.content !== undefined)
    @IsString()
    content;

    @ValidateIf((o) => o.position !== undefined)
    @IsNumber()
    position;

    @ValidateIf((o) => o.dueDate !== undefined)
    @IsISO8601()
    dueDate;

    @ValidateIf((o) => o.listId !== undefined)
    @IsNumber()
    listId;
}
```

## After Insert 이벤트를 통한 활동 기록 관리
- 활동기록을 저장하는 로직은 각 보드, 리스트, 카드 서비스와 분리되어야 하는가?
```javascript=
@Transactional()
async deleteCard({ userId, cardId }) {
    const card = await this.cardRepository
        .createQueryBuilder('card')
        .select('card.list')
        .innerJoinAndSelect('card.list', 'list')
        .where('card.id = :cardId', { cardId })
        .getRawOne();
    if (!card) throw new EntityNotFoundError();

    const namespace = getNamespace('localstorage');
    namespace?.set('userId', userId);
    namespace?.set('boardId', card.list_board_id);

    const boardService = BoardService.getInstance();
    await boardService.checkForbidden(userId, card.list_board_id);
    await this.cardRepository.remove(await this.cardRepository.findOne(cardId));
}
```
```javascript=
async afterRemove(event) {
    const activityService = ActivityService.getInstance();
    const userService = UserService.getInstance();
    const namespace = getNamespace('localstorage');
    const user = await userService.getUserById(namespace.get('userId'));
    await activityService.createActivity(
        namespace.get('boardId'),
        `${user.name}님이 카드 ${event.databaseEntity.title}을 삭제하였습니다.`,
    );
}
```


## Frontend 피드백
- 리스트나 카드의 위치를 숫자를 통해서 옮기는 것은 직관적이지 않음
- 보드 화면에서 메인으로 돌아갈 때 진입점을 확실하게
- 보드 화면 왼쪽 상단에 보드 이름이 있는데, 보드 이름처럼 안 보임
- 오른쪽 사이드바 이름을 활동 기록이라는 직관적인 이름으로 변경
- 확장앱 자체의 기능이 없어서 아쉬움
- 강렬한 배경색을 톤다운하는 것이 좋아 보임
- 확장앱에서 카드 배열을 1열로
- 카드 댓글이 없는 경우 개수를 표시하지 말것
- 콜드 스타터를 위한 UI 진입장벽 개선
- "컬러와 여백"