first commit

This commit is contained in:
AyrisAI
2026-07-23 16:55:44 +03:00
commit bd543c3bda
61 changed files with 17313 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
enum Role {
ADMIN
USER
}
model User {
id String @id @default(cuid())
name String?
email String @unique
password String?
role Role @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
accounts Account[]
sessions Session[]
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
model Category {
id String @id @default(cuid())
name String @unique
slug String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Lesson {
id String @id @default(cuid())
slug String @unique
title String
youtubeId String
youtubeUrl String
thumbnailUrl String
duration String
publishDate DateTime @default(now())
category String
tags String[]
viewsCount Int @default(0)
downloadCount Int @default(0)
likesCount Int @default(0)
summary String @db.Text
notesMarkdown String[]
isFeatured Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
codeSnippets CodeSnippet[]
downloads ResourceDownload[]
chapters VideoChapter[]
}
model CodeSnippet {
id String @id @default(cuid())
fileName String
language String
code String @db.Text
description String?
lessonId String
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
}
model ResourceDownload {
id String @id @default(cuid())
title String
type String // zip, github, pdf, link
url String
size String?
lessonId String
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
}
model VideoChapter {
id String @id @default(cuid())
time String
seconds Int
title String
lessonId String
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
}
model Cheatsheet {
id String @id @default(cuid())
slug String @unique
title String
category String
description String @db.Text
tags String[]
lastUpdated DateTime @default(now())
createdAt DateTime @default(now())
items CheatsheetItem[]
}
model CheatsheetItem {
id String @id @default(cuid())
command String
description String
example String?
cheatsheetId String
cheatsheet Cheatsheet @relation(fields: [cheatsheetId], references: [id], onDelete: Cascade)
}
model ContactMessage {
id String @id @default(cuid())
name String
email String
subject String
message String @db.Text
isRead Boolean @default(false)
createdAt DateTime @default(now())
}
model Setting {
id String @id @default(cuid())
key String @unique
value String @db.Text
updatedAt DateTime @updatedAt
}
+254
View File
@@ -0,0 +1,254 @@
import { Pool } from 'pg';
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from '@prisma/client';
const connectionString = process.env.DATABASE_URL || 'postgres://postgres:mBTWE2cDKGExtpktguD3HPe8y9Xr9kWFYdxV4WHQKISLLGoBAS4UdtfSCfXwvPpq@65.109.236.58:37298/postgres';
const pool = new Pool({ connectionString });
const adapter = new PrismaPg(pool);
const db = new PrismaClient({ adapter });
async function main() {
console.log('Seeding PostgreSQL database...');
// Clear existing records
await db.videoChapter.deleteMany();
await db.resourceDownload.deleteMany();
await db.codeSnippet.deleteMany();
await db.lesson.deleteMany();
await db.cheatsheetItem.deleteMany();
await db.cheatsheet.deleteMany();
// Create Lessons
await db.lesson.create({
data: {
slug: 'nextjs-16-app-router-full-course',
title: 'Next.js 16 App Router & Server Actions Complete Masterclass (Code & Project)',
youtubeId: 'dQw4w9WgXcQ',
youtubeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
thumbnailUrl: 'https://images.unsplash.com/photo-1618401471353-b98afee0b2eb?w=800&auto=format&fit=crop&q=80',
duration: '42:15',
category: 'Next.js',
tags: ['Next.js 16', 'App Router', 'Server Actions', 'TypeScript', 'Tailwind CSS v4'],
viewsCount: 24500,
downloadCount: 4120,
likesCount: 1890,
isFeatured: true,
summary: 'In this tutorial, we build a full-stack Next.js 16 application from scratch covering App Router architecture, proxy.ts middleware, Server Actions, and PostgreSQL integration.',
notesMarkdown: [
'In Next.js 16, using proxy.ts is recommended over deprecated middleware.ts.',
'Server Actions functions are declared with "use server" directive and can be invoked directly from client components.',
'Data fetching revalidation uses revalidatePath or revalidateTag helpers.',
'Form handling UX is significantly improved using useActionState and useFormStatus hooks.'
],
codeSnippets: {
create: [
{
fileName: 'app/actions.ts',
language: 'typescript',
description: 'Server Action function handling form submission',
code: `'use server'\n\nimport { revalidatePath } from 'next/cache';\n\nexport async function submitProjectIdea(formData: FormData) {\n const title = formData.get('title') as string;\n const description = formData.get('description') as string;\n\n if (!title || title.length < 3) {\n return { success: false, error: 'Title must be at least 3 characters long.' };\n }\n\n // Database insertion simulation\n console.log('Saved Idea:', { title, description });\n\n revalidatePath('/ideas');\n return { success: true, message: 'Your idea was submitted successfully!' };\n}`
},
{
fileName: 'proxy.ts',
language: 'typescript',
description: 'Next.js 16 proxy configuration (middleware alternative)',
code: `import { NextRequest, NextResponse } from 'next/server';\nimport createMiddleware from 'next-intl/middleware';\nimport { routing } from '@/i18n/routing';\n\nconst intlMiddleware = createMiddleware(routing);\n\nexport async function proxy(request: NextRequest) {\n if (request.nextUrl.pathname.includes('/admin')) {\n // Auth check logic\n }\n return intlMiddleware(request);\n}\n\nexport const config = {\n matcher: ['/((?!api|_next|_vercel|.*\\\\..*).*)']\n};`
},
{
fileName: 'components/IdeaForm.tsx',
language: 'tsx',
description: 'Client Form component using useActionState',
code: `'use client';\n\nimport { useActionState } from 'react';\nimport { submitProjectIdea } from '@/app/actions';\n\nexport function IdeaForm() {\n const [state, formAction, isPending] = useActionState(submitProjectIdea, null);\n\n return (\n <form action={formAction} className="space-y-4 max-w-md p-6 bg-slate-900 rounded-xl border border-slate-800">\n <h3 className="text-xl font-bold text-white">Add New Idea</h3>\n \n <div>\n <label className="block text-sm text-slate-400 mb-1">Idea Title</label>\n <input name="title" required className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white" />\n </div>\n\n <button disabled={isPending} className="w-full py-2.5 bg-red-600 hover:bg-red-500 text-white rounded-lg font-medium">\n {isPending ? 'Submitting...' : 'Share Idea'}\n </button>\n\n {state?.error && <p className="text-red-400 text-sm">{state.error}</p>}\n {state?.success && <p className="text-emerald-400 text-sm">{state.message}</p>}\n </form>\n );\n}`
}
]
},
downloads: {
create: [
{
title: 'Full Project Source Code (Starter Pack)',
type: 'zip',
url: 'https://github.com/ayrisdev/nextjs-16-starter/archive/refs/heads/main.zip',
size: '4.2 MB'
},
{
title: 'GitHub Repository',
type: 'github',
url: 'https://github.com/ayrisdev/nextjs-16-starter'
},
{
title: 'Lesson Notes & Architecture (PDF Document)',
type: 'pdf',
url: '#',
size: '1.8 MB'
}
]
},
chapters: {
create: [
{ time: '00:00', seconds: 0, title: 'Introduction & Demo' },
{ time: '04:15', seconds: 255, title: 'Next.js 16 Project Setup & Structure' },
{ time: '11:30', seconds: 690, title: 'Routing & Middleware with proxy.ts' },
{ time: '21:00', seconds: 1260, title: 'Form Handling via Server Actions' },
{ time: '32:45', seconds: 1965, title: 'PostgreSQL & Prisma Integration' },
{ time: '40:00', seconds: 2400, title: 'Deployment & Summary' }
]
}
}
});
await db.lesson.create({
data: {
slug: 'python-ai-agent-automation',
title: 'Building Autonomous AI Agents with Python (CrewAI & Gemini API)',
youtubeId: 'dQw4w9WgXcQ',
youtubeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
thumbnailUrl: 'https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?w=800&auto=format&fit=crop&q=80',
duration: '28:50',
category: 'Python & AI',
tags: ['Python', 'CrewAI', 'Gemini API', 'AI Agents', 'Automation'],
viewsCount: 18200,
downloadCount: 3200,
likesCount: 1450,
summary: 'Build an autonomous AI agent in Python that crawls web data, summarizes tech news, and generates structured reports automatically.',
notesMarkdown: [
'🤖 AI agents are configured with role, goal, and backstory.',
'🤖 Equip agents with real-time web search using Serper API or Tavily.',
'🤖 Gemini 1.5 Flash provides high token throughput with minimal latency.'
],
codeSnippets: {
create: [
{
fileName: 'agent.py',
language: 'python',
description: 'CrewAI Agent Definition',
code: `from crewai import Agent, Task, Crew, Process\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nimport os\n\nllm = ChatGoogleGenerativeAI(\n model="gemini-1.5-flash",\n google_api_key=os.getenv("GEMINI_API_KEY")\n)\n\nresearcher = Agent(\n role='Tech Researcher',\n goal='Discover top AI trends from the past 24 hours',\n backstory='You are an expert technology journalist following AI developments.',\n verbose=True,\n llm=llm\n)\n\ntask1 = Task(\n description='Summarize 2026 AI trends in 5 bullet points.',\n expected_output='A markdown list with 5 key takeaways.',\n agent=researcher\n)\n\ncrew = Crew(\n agents=[researcher],\n tasks=[task1],\n process=Process.sequential\n)\n\nresult = crew.kickoff()\nprint(result)`
}
]
},
downloads: {
create: [
{
title: 'Python AI Agent Project Files',
type: 'zip',
url: '#',
size: '2.1 MB'
},
{
title: 'GitHub Repository',
type: 'github',
url: 'https://github.com/ayrisdev/python-ai-agent'
}
]
},
chapters: {
create: [
{ time: '00:00', seconds: 0, title: 'Introduction & What is an AI Agent?' },
{ time: '05:20', seconds: 320, title: 'Installing Dependencies (CrewAI & Gemini)' },
{ time: '14:10', seconds: 850, title: 'Agent & Task Coding' },
{ time: '24:00', seconds: 1440, title: 'Testing & Output Review' }
]
}
}
});
await db.lesson.create({
data: {
slug: 'tailwind-css-v4-tricks-and-setup',
title: 'Modern UI Design with Tailwind CSS v4: Tricks, Themes & Components',
youtubeId: 'dQw4w9WgXcQ',
youtubeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
thumbnailUrl: 'https://images.unsplash.com/photo-1507238691740-187a5b1d37b8?w=800&auto=format&fit=crop&q=80',
duration: '35:10',
category: 'Tailwind CSS',
tags: ['Tailwind CSS v4', 'OKLCH', 'CSS Grid', 'UI Design', 'Shadcn'],
viewsCount: 31000,
downloadCount: 5400,
likesCount: 2600,
summary: 'Learn CSS-first configuration in Tailwind CSS v4 using @import "tailwindcss";, OKLCH color spaces, and advanced glassmorphism component design.',
notesMarkdown: [
'🎨 In Tailwind v4, @theme directive in globals.css replaces tailwind.config.js.',
'🎨 OKLCH color space ensures consistent perceived contrast across light and dark modes.',
'🎨 @custom-variant dark provides flexible dark mode scoping.'
],
codeSnippets: {
create: [
{
fileName: 'globals.css',
language: 'css',
description: 'Tailwind CSS v4 Theme Configuration',
code: `@import "tailwindcss";\n\n@theme inline {\n --color-primary: oklch(0.65 0.22 260);\n --color-accent: oklch(0.72 0.19 145);\n --radius-lg: 1rem;\n}\n\n:root {\n --background: oklch(0.98 0.01 250);\n --foreground: oklch(0.15 0.02 250);\n}`
}
]
},
downloads: {
create: [
{
title: 'Tailwind v4 UI Starter Pack',
type: 'zip',
url: '#',
size: '1.2 MB'
}
]
},
chapters: {
create: [
{ time: '00:00', seconds: 0, title: "What's New in Tailwind v4" },
{ time: '08:30', seconds: 510, title: 'Defining Color Palettes with @theme' },
{ time: '20:15', seconds: 1215, title: 'Building Glassmorphism Cards' }
]
}
}
});
// Create Cheatsheets
await db.cheatsheet.create({
data: {
slug: 'git-komutlari-hizli-rehber',
title: 'Essential Git & GitHub Commands Cheatsheet',
category: 'DevOps & Tooling',
description: 'Handy reference for daily Git workflow, branching, and conflict resolution commands.',
tags: ['Git', 'GitHub', 'Terminal'],
items: {
create: [
{ command: 'git checkout -b feature/new-feature', description: 'Creates a new branch and switches to it.' },
{ command: 'git status', description: 'Lists modified and untracked files.' },
{ command: 'git commit -m "feat: add new page"', description: 'Saves changes with a descriptive commit message.' },
{ command: 'git push origin feature/new-feature', description: 'Pushes the branch to remote repository.' },
{ command: 'git log --oneline -n 5', description: 'Displays last 5 commits in clean single line format.' }
]
}
}
});
await db.cheatsheet.create({
data: {
slug: 'nextjs-app-router-cheatsheet',
title: 'Next.js App Router File Structure & Route Handlers',
category: 'Next.js',
description: 'Special file conventions (page, layout, loading, error) and their responsibilities.',
tags: ['Next.js', 'App Router', 'React'],
items: {
create: [
{ command: 'app/[locale]/page.tsx', description: 'Main page component for the route.' },
{ command: 'app/layout.tsx', description: 'Root layout component wrapping all pages.' },
{ command: 'app/loading.tsx', description: 'Suspense fallback displayed while page loads.' },
{ command: 'app/error.tsx', description: 'Client-side Error Boundary component.' },
{ command: 'app/api/route.ts', description: 'REST API Endpoint handlers (GET, POST, PUT, DELETE).' }
]
}
}
});
console.log('Seeding completed successfully!');
}
main()
.catch((e) => {
console.error('Seed error:', e);
process.exit(1);
})
.finally(async () => {
await db.$disconnect();
await pool.end();
});