From 226a24aac45af8f626404ed649c1e0f3cec12691 Mon Sep 17 00:00:00 2001 From: Giorgi Zankaidze Date: Mon, 8 Dec 2025 22:38:17 +0400 Subject: [PATCH 1/7] feat: add implementation guide --- DAY3-4-IMPLEMENTATION-GUIDE.md | 554 +++++++++++++++++++++++++++++++++ 1 file changed, 554 insertions(+) create mode 100644 DAY3-4-IMPLEMENTATION-GUIDE.md diff --git a/DAY3-4-IMPLEMENTATION-GUIDE.md b/DAY3-4-IMPLEMENTATION-GUIDE.md new file mode 100644 index 0000000..b140778 --- /dev/null +++ b/DAY3-4-IMPLEMENTATION-GUIDE.md @@ -0,0 +1,554 @@ +# Day 3-4: Database & Video Entity - Implementation Guide + +## Overview + +This guide provides step-by-step instructions for implementing the database schema and video entity with status tracking for the StreamForge project. + +**Estimated Time**: 4-6 hours +**Prerequisites**: +- Docker and docker-compose installed +- PostgreSQL container running +- TypeORM and related dependencies installed (already done) + +--- + +## Step 1: Verify Prerequisites + +### 1.1 Check Database Container is Running + +```bash +docker-compose up -d postgres +docker ps | grep streamforge-postgres +``` + +Expected output: Container should be running and healthy. + +### 1.2 Verify Dependencies + +Check that these packages are installed in `package.json`: +- `@nestjs/typeorm` (v11.0.0) +- `typeorm` (v0.3.28) +- `pg` (v8.16.3) + +If missing, install them: +```bash +npm install @nestjs/typeorm typeorm pg +``` + +--- + +## Step 2: Configure TypeORM in App Module + +### 2.1 Update `apps/api/src/app/app.module.ts` + +Add TypeORM configuration to connect to PostgreSQL: + +**Current state**: Only has ConfigModule imported. + +**What to add**: +1. Import `TypeOrmModule` from `@nestjs/typeorm` +2. Import `ConfigService` from `@nestjs/config` +3. Add `TypeOrmModule.forRootAsync()` to imports array +4. Use `ConfigService` to inject database configuration from `configuration.ts` + +**Implementation**: + +```typescript +import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; +import configuration from '../config/configuration'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + load: [configuration], + envFilePath: ['.env'], + }), + TypeOrmModule.forRootAsync({ + imports: [ConfigModule], + useFactory: (configService: ConfigService) => ({ + type: 'postgres', + host: configService.get('database.host'), + port: configService.get('database.port'), + username: configService.get('database.username'), + password: configService.get('database.password'), + database: configService.get('database.database'), + synchronize: configService.get('database.synchronize'), + logging: configService.get('database.logging'), + autoLoadEntities: true, // Automatically load entities + }), + inject: [ConfigService], + }), + ], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} +``` + +**Key points**: +- `forRootAsync` allows async configuration using ConfigService +- `autoLoadEntities: true` automatically discovers and loads entity files +- Database config values come from `configuration.ts` which reads from environment variables + +--- + +## Step 3: Create Video Entity + +### 3.1 Create Directory Structure + +```bash +mkdir -p apps/api/src/app/videos/entities +``` + +### 3.2 Create `apps/api/src/app/videos/entities/video.entity.ts` + +Create the Video entity with all required fields and status enum: + +```typescript +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +export enum VideoStatus { + UPLOADING = 'UPLOADING', + UPLOADED = 'UPLOADED', + QUEUED = 'QUEUED', + PROCESSING = 'PROCESSING', + COMPLETED = 'COMPLETED', + FAILED = 'FAILED', +} + +@Entity('videos') +export class Video { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ type: 'varchar', length: 255 }) + originalFilename: string; + + @Column({ type: 'varchar', length: 500 }) + s3Key: string; + + @Column({ + type: 'enum', + enum: VideoStatus, + default: VideoStatus.UPLOADING, + }) + status: VideoStatus; + + @Column({ type: 'varchar', length: 100 }) + mimeType: string; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} +``` + +**Field explanations**: +- `id`: UUID primary key, auto-generated +- `originalFilename`: Original name of uploaded file (max 255 chars) +- `s3Key`: MinIO object key/path where file is stored (max 500 chars) +- `status`: Enum tracking video processing state +- `mimeType`: MIME type of the video file (e.g., 'video/mp4') +- `createdAt`: Auto-generated timestamp on creation +- `updatedAt`: Auto-updated timestamp on modification + +**Status enum flow**: +1. `UPLOADING` - File is being uploaded +2. `UPLOADED` - Upload complete, ready for queue +3. `QUEUED` - Job added to RabbitMQ queue +4. `PROCESSING` - Worker is transcoding +5. `COMPLETED` - Transcoding finished successfully +6. `FAILED` - Error occurred at any stage + +--- + +## Step 4: Create Videos Module + +### 4.1 Create `apps/api/src/app/videos/videos.module.ts` + +```typescript +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Video } from './entities/video.entity'; +import { VideosService } from './videos.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([Video])], + providers: [VideosService], + exports: [VideosService], +}) +export class VideosModule {} +``` + +**Key points**: +- `TypeOrmModule.forFeature([Video])` registers Video repository for this module +- `exports: [VideosService]` makes service available to other modules +- This follows NestJS feature module pattern + +--- + +## Step 5: Create Videos Service + +### 5.1 Create `apps/api/src/app/videos/videos.service.ts` + +Implement basic CRUD operations: + +```typescript +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Video, VideoStatus } from './entities/video.entity'; + +@Injectable() +export class VideosService { + constructor( + @InjectRepository(Video) + private videoRepository: Repository