프로젝트·파일 데이터 모델
프로젝트와 파일·폴더 엔티티를 정의하고 소유 관계와 계층 구조를 구성합니다.
프로젝트 및 파일 관리 API 구현
DATABASE SCHEMA · INVARIANTS
Project membership과 Entry adjacency를 제약으로 보장한다
File·Folder 경로 모델을 남기지 않는다. Entry의 parentId, siblingKey, kind, revision과 복합 외래 키가 트리 구조와 편집 순서를 지킨다.
- User
email은 유일하고 passwordHash는 기본 조회에서 제외합니다.
- Project
ownerId는 사용자에 대한 외래 키입니다.
- Project Member
(projectId, userId)가 역할 하나를 가집니다.
- Entry adjacency
parentId는 같은 projectId의 Entry만 가리킵니다.
- Entry revision
형제 이름은 유일하고 파일 편집마다 revision이 증가합니다.
화살표는 신뢰 또는 상태가 다음 경계로 이동하는 방향을 뜻합니다.
이제 사용자 인증이 완료된 후 접근할 수 있는 프로젝트 및 파일 관리 API를 구현합니다.
Project Entity
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, CreateDateColumn, UpdateDateColumn } from 'typeorm';
import { User } from '../../auth/entities/user.entity'; // User 엔티티 임포트
import { File } from '../../file/entities/file.entity'; // File 엔티티 임포트 (미리 정의했다고 가정)
import { Folder } from '../../folder/entities/folder.entity'; // Folder 엔티티 임포트 (미리 정의했다고 가정)
@Entity()
export class Project {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ nullable: false })
name: string;
@Column({ nullable: false })
ownerId: string; // 소유자 ID
@ManyToOne(() => User, user => user.projects)
owner: User; // User 엔티티와의 관계
@OneToMany(() => File, file => file.project)
files: File[];
@OneToMany(() => Folder, folder => folder.project)
folders: Folder[];
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}File & Folder Entities
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from 'typeorm';
import { Project } from '../../project/entities/project.entity';
@Entity()
export class File {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ nullable: false })
name: string;
@Column({ nullable: false })
path: string; // 예: '/src/main.ts'
@Column({ type: 'text', nullable: true })
content: string; // 파일 내용 (TEXT 타입)
@Column({ nullable: true })
type: string; // 파일 타입 (예: 'javascript', 'python')
@Column({ nullable: false })
projectId: string;
@ManyToOne(() => Project, project => project.files, { onDelete: 'CASCADE' }) // 프로젝트 삭제 시 파일도 삭제
project: Project;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from 'typeorm';
import { Project } from '../../project/entities/project.entity';
@Entity()
export class Folder {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ nullable: false })
name: string;
@Column({ nullable: false })
path: string; // 예: '/src'
@Column({ nullable: false })
projectId: string;
@ManyToOne(() => Project, project => project.folders, { onDelete: 'CASCADE' }) // 프로젝트 삭제 시 폴더도 삭제
project: Project;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}