first commit

This commit is contained in:
2026-02-28 02:44:41 +03:00
commit 97fb289fe7
70 changed files with 11928 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
-- CreateEnum
CREATE TYPE "ScrapeJobStatus" AS ENUM ('pending', 'processing', 'completed', 'failed');
-- CreateTable
CREATE TABLE "content" (
"id" TEXT NOT NULL,
"url" VARCHAR(500) NOT NULL,
"title" VARCHAR(255) NOT NULL,
"year" INTEGER,
"plot" TEXT,
"backdropUrl" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "content_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "genres" (
"id" TEXT NOT NULL,
"name" VARCHAR(100) NOT NULL,
CONSTRAINT "genres_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "content_genres" (
"contentId" TEXT NOT NULL,
"genreId" TEXT NOT NULL,
CONSTRAINT "content_genres_pkey" PRIMARY KEY ("contentId","genreId")
);
-- CreateTable
CREATE TABLE "cast_members" (
"id" TEXT NOT NULL,
"contentId" TEXT NOT NULL,
"name" VARCHAR(255) NOT NULL,
CONSTRAINT "cast_members_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "scrape_jobs" (
"id" TEXT NOT NULL,
"url" VARCHAR(500) NOT NULL,
"status" VARCHAR(20) NOT NULL DEFAULT 'pending',
"progress" INTEGER NOT NULL DEFAULT 0,
"step" VARCHAR(100),
"error" TEXT,
"result" JSONB,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "scrape_jobs_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "content_url_key" ON "content"("url");
-- CreateIndex
CREATE INDEX "content_url_idx" ON "content"("url");
-- CreateIndex
CREATE INDEX "content_title_idx" ON "content"("title");
-- CreateIndex
CREATE INDEX "content_year_idx" ON "content"("year");
-- CreateIndex
CREATE UNIQUE INDEX "genres_name_key" ON "genres"("name");
-- CreateIndex
CREATE INDEX "genres_name_idx" ON "genres"("name");
-- CreateIndex
CREATE INDEX "cast_members_contentId_idx" ON "cast_members"("contentId");
-- CreateIndex
CREATE INDEX "cast_members_name_idx" ON "cast_members"("name");
-- CreateIndex
CREATE INDEX "scrape_jobs_url_idx" ON "scrape_jobs"("url");
-- CreateIndex
CREATE INDEX "scrape_jobs_status_idx" ON "scrape_jobs"("status");
-- AddForeignKey
ALTER TABLE "content_genres" ADD CONSTRAINT "content_genres_contentId_fkey" FOREIGN KEY ("contentId") REFERENCES "content"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "content_genres" ADD CONSTRAINT "content_genres_genreId_fkey" FOREIGN KEY ("genreId") REFERENCES "genres"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "cast_members" ADD CONSTRAINT "cast_members_contentId_fkey" FOREIGN KEY ("contentId") REFERENCES "content"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,2 @@
-- Add ageRating column to content table
ALTER TABLE "content" ADD COLUMN "ageRating" VARCHAR(10);

View File

@@ -0,0 +1,5 @@
-- Add type column to content table
ALTER TABLE "content" ADD COLUMN "type" VARCHAR(10) NOT NULL DEFAULT 'movie';
-- Create index for type field
CREATE INDEX "content_type_idx" ON "content"("type");

View File

@@ -0,0 +1,5 @@
-- Add currentSeason column to content table
ALTER TABLE "content" ADD COLUMN "currentSeason" INTEGER;
-- Create index for currentSeason field
CREATE INDEX "content_current_season_idx" ON "content"("currentSeason");

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"

103
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,103 @@
// Prisma Schema for Netflix Scraper API
// Database: PostgreSQL
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ============================================
// Content Tables
// ============================================
/// Main content table for scraped Netflix data
model Content {
id String @id @default(uuid())
url String @unique @db.VarChar(500)
title String @db.VarChar(255)
year Int?
plot String? @db.Text
backdropUrl String? @db.Text
ageRating String? @db.VarChar(10)
type String @default("movie") @db.VarChar(10) // movie or tvshow
currentSeason Int? // Current season number for TV shows
// Relations
genres ContentGenre[]
castMembers CastMember[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([url])
@@index([title])
@@index([year])
@@index([type])
@@index([currentSeason])
@@map("content")
}
/// Genres lookup table
model Genre {
id String @id @default(uuid())
name String @unique @db.VarChar(100)
// Relations
contents ContentGenre[]
@@index([name])
@@map("genres")
}
/// Content-Genre many-to-many relationship
model ContentGenre {
contentId String
genreId String
content Content @relation(fields: [contentId], references: [id], onDelete: Cascade)
genre Genre @relation(fields: [genreId], references: [id], onDelete: Cascade)
@@id([contentId, genreId])
@@map("content_genres")
}
/// Cast members for content
model CastMember {
id String @id @default(uuid())
contentId String
name String @db.VarChar(255)
content Content @relation(fields: [contentId], references: [id], onDelete: Cascade)
@@index([contentId])
@@index([name])
@@map("cast_members")
}
// ============================================
// Job Queue Table (for async processing)
// ============================================
/// Scrape job queue
model ScrapeJob {
id String @id @default(uuid())
url String @db.VarChar(500)
status String @default("pending") @db.VarChar(20) // pending, processing, completed, failed
progress Int @default(0)
step String? @db.VarChar(100)
error String? @db.Text
// Result stored as JSON when completed
result Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([url])
@@index([status])
@@map("scrape_jobs")
}

49
prisma/seed.ts Normal file
View File

@@ -0,0 +1,49 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
/**
* Seed script for initial data
* Run with: npx tsx prisma/seed.ts
*/
async function main() {
console.log('Seeding database...');
// Seed default genres
const genres = [
'Aksiyon',
'Komedi',
'Dram',
'Korku',
'Romantik',
'Bilim Kurgu',
'Gerilim',
'Belgesel',
'Animasyon',
'Aile',
'18+',
'16+',
'13+',
'7+',
];
for (const genreName of genres) {
await prisma.genre.upsert({
where: { name: genreName },
update: {},
create: { name: genreName },
});
}
console.log(`Seeded ${genres.length} genres`);
console.log('Seed completed successfully!');
}
main()
.catch((e) => {
console.error('Seed failed:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});