서론

스냅샷 구조는 주로 데이터베이스나 애플리케이션에서 특정 시점의 데이터를 기록하고 보관하는 방식입니다. 이 구조는 데이터 변경 이력을 추적하거나, 복구를 위한 백업을 만들 때 유용하게 사용됩니다.

주요 특징

적용

면시 프로젝트에는 캐릭터와 경력 정보에 스냅샷 구조가 적용되어 있습니다. (팀원들간의 논의하에, 변경점을 기록해야할 필요성이 높은 개념에 적용하였습니다.)

/// 멤버가 생성한 캐릭터.
/// 멤버는 면접 대상자를 등록하여 면접을 예행연습할 수 있다.
/// @namespace Character
model Character {
  id         String    @id @db.Uuid /// PK
  member_id  String    @db.Uuid /// 캐릭터 생성자 아이디
  is_public  Boolean /// 캐릭터 활성화 여부. true인 경우에는 'public', 그렇지 않은 경우는 'private'이다.
  created_at DateTime  @db.Timestamptz /// 캐릭터가 생성된 시점
  deleted_at DateTime? @db.Timestamptz /// 캐릭터가 삭제된 시점

  creator                Member                  @relation(fields: [member_id], references: [id]) // 캐릭터 생성자
  rooms                  Room[] /// 캐릭터를 기준으로 생성된 채팅방
  chats                  Chat[] /// 캐릭터와 대화한 기록
  sources                Source[] /// 캐릭터 생성에 사용된 소스
  character_personalites Character_Personality[] /// 캐릭터 생성에 사용된 성격

  /// 스냅샷들
  snapshots     Character_Snapshot[]
  last_snapshot Character_Last_Snapshot?
}

/// 캐릭터 스냅샷
/// @namespace Character
model Character_Snapshot {
  id           String   @id @db.Uuid /// PK
  character_id String   @db.Uuid /// 스냅샷이 참조하는 캐릭터 ID
  nickname     String /// 캐릭터의 이름, 사용자 본명을 사용하는 것이 권장되나 강제성은 없다.
  email        String? /// 캐릭터에 저장할 이메일 정보. 연락하기 기능에 사용될 이메일을 입력한다.
  phone        String? /// 캐릭터에 저장할 전화번호 정보. 연락하기 기능에 사용될 전화번호을 입력한다.
  image        String? /// 캐릭터 프로필 이미지. s3 url을 저장한다.
  description  String? /// 추가 설명 및 사용자 프롬프트. 캐릭터에게 추가로 학습 시키고 싶은것들이 있다면 입력한다.
  created_at   DateTime @db.Timestamptz /// 스냅샷 생성 시점

  character     Character                @relation(fields: [character_id], references: [id])
  last_snapshot Character_Last_Snapshot?

  character_snapshot_experiences Character_Snapshot_Experience[]
  character_snapshot_positions   Character_Snapshot_Position[]
  character_snapshot_skills      Character_Snapshot_Skill[]
}

/// 캐릭터의 마지막 스냅샷
/// @namespace Character
model Character_Last_Snapshot {
  character_id          String @id @db.Uuid /// Character FK
  character_snapshot_id String @db.Uuid /// Character_Snapshot FK

  character Character          @relation(fields: [character_id], references: [id])
  snapshot  Character_Snapshot @relation(fields: [character_snapshot_id], references: [id])

  @@unique([character_snapshot_id])
}


  /**
   * 특정 캐릭터를 상세조회한다.
   *
   * @param id 조회할 캐릭터의 아이디
   * @param option 조회 옵셔널 파라미터들이다.
   * -  isPublic: 공개 캐릭터만 조회하고 싶을 경우 true로 설정한다.
   */
  async get(
    id: string,
    option?: {
      isPublic?: true;
    },
  ): Promise<Character.GetResponse> {
    const whereInput: Prisma.CharacterWhereUniqueInput = { id: id, is_public: option?.isPublic ? true : undefined };

    const character = await this.prisma.character.findUnique({
      select: {
        id: true,
        member_id: true,
        is_public: true,
        created_at: true,
        last_snapshot: {
          select: {
            snapshot: {
              select: {
                nickname: true,
                email: true,
                phone: true,
                image: true,
                description: true,
						. . . 
      },
      where: whereInput,
    });

    const snapshot = character?.last_snapshot?.snapshot;

    if (!snapshot) {
      throw new NotFoundException('캐릭터 조회 실패. 삭제되었거나 비공개 된 캐릭터 입니다.');
    }
    
    . . .