From b0a345c6b7fd09da900606e461b0fe1f56abcffd Mon Sep 17 00:00:00 2001 From: DrMesta103 Date: Wed, 6 May 2026 18:04:19 +0330 Subject: [PATCH] fix: Prisma binary download for Iran servers --- .env | 2 +- .gitignore | 60 ++++++----- .vscode/settings.json | 3 + DEPLOY_IRAN.md | 138 ++++++++++++++------------ DEPLOY_STEPS.md | 53 ++++++++++ Dockerfile | 28 ++++-- app/api/admin/quiz/[id]/route.ts | 2 +- app/api/admin/quiz/route.ts | 2 +- lib/cardTier.ts | 2 +- lib/db.ts | 2 +- lib/points.ts | 2 +- lib/specialCards.ts | 2 +- package.json | 1 - prisma/schema.prisma | 1 + prisma/seed.ts | 2 +- scripts/check-users.ts | 2 +- scripts/create-admin-user.ts | 2 +- scripts/create-test-user.ts | 2 +- scripts/download-prisma-engines.ps1 | 51 ++++++++++ scripts/download-prisma-engines.sh | 27 +++++ scripts/generate-prisma-for-deploy.sh | 13 +++ scripts/seed-quiz-sample.ts | 2 +- types/quiz.ts | 2 +- 23 files changed, 285 insertions(+), 116 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 DEPLOY_STEPS.md create mode 100644 scripts/download-prisma-engines.ps1 create mode 100644 scripts/download-prisma-engines.sh create mode 100644 scripts/generate-prisma-for-deploy.sh diff --git a/.env b/.env index 7fca1e7..eb9079c 100644 --- a/.env +++ b/.env @@ -15,4 +15,4 @@ IPPANEL_ORIGINATOR="+983000505" IPPANEL_BASE_URL="https://edge.ippanel.com/v1" # Node Environment -NODE_ENV="development" +NODE_ENV="production" diff --git a/.gitignore b/.gitignore index c3f13fb..aa61dda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,42 @@ -# Dependencies -node_modules/ -.pnp +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp .pnp.js +.yarn/install-state.gz -# Next.js -.next/ -out/ -build/ +# testing +/coverage -# Environment variables -.env.local -.env.development.local -.env.test.local -.env.production.local -.env2 +# next.js +/.next/ +/out/ -# Prisma -prisma/migrations/ +# production +/build -# Logs +# misc +.DS_Store +*.pem + +# debug npm-debug.log* yarn-debug.log* yarn-error.log* -pnpm-debug.log* -*.log -# OS -.DS_Store -Thumbs.db -desktop.ini +# local env files +.env*.local +.env -# Editor -.vscode/ -.idea/ -*.swp -*.swo +# vercel +.vercel -# TypeScript +# typescript *.tsbuildinfo next-env.d.ts -# Misc -.vercel -.turbo -coverage/ +# Prisma +# Note: We keep generated Prisma client for deployment in Iran servers +# /node_modules/.prisma +# /node_modules/@prisma/client diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5480842 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "kiroAgent.configureMCP": "Disabled" +} \ No newline at end of file diff --git a/DEPLOY_IRAN.md b/DEPLOY_IRAN.md index 7841cbf..5f92b66 100644 --- a/DEPLOY_IRAN.md +++ b/DEPLOY_IRAN.md @@ -3,89 +3,105 @@ ## مشکل سرورهای ایران به دلیل تحریم‌ها نمی‌توانند به `binaries.prisma.sh` دسترسی داشته باشند و Prisma نمی‌تواند باینری‌های لازم را دانلود کند. -## راه‌حل‌های پیاده‌سازی شده +## راه‌حل پیاده‌سازی شده -### ۱. تغییرات Dockerfile -- باینری‌های Prisma در مرحله `deps` دانلود و generate می‌شوند -- از `PRISMA_ENGINES_MIRROR` برای استفاده از CDN استفاده شده -- باینری‌ها به مرحله `builder` منتقل می‌شوند +### دانلود Manual باینری‌های Prisma -### ۲. تغییرات package.json -- اضافه شدن `postinstall` script برای اجرای خودکار `prisma generate` -- تغییر `build` script برای اطمینان از generate شدن Prisma قبل از build - -## راه‌حل‌های جایگزین (در صورت عدم موفقیت) - -### الف) استفاده از Proxy یا VPN -اگر سرور شما به proxy یا VPN دسترسی دارد: +روی سیستمی با دسترسی به اینترنت (مثل لپ‌تاپ شخصی با VPN): ```bash -# در Dockerfile قبل از RUN npm ci +# اجرای اسکریپت دانلود +bash scripts/download-prisma-engines.sh + +# Commit کردن فایل‌ها +git add prisma/engines +git commit -m "Add Prisma engines for offline deployment" +git push +``` + +این کار باینری‌های Prisma را در پوشه `prisma/engines` قرار می‌دهد و Dockerfile از آن‌ها استفاده می‌کند. + +## راه‌حل‌های جایگزین + +### الف) Build روی سیستم محلی و Push کردن Image + +اگر دانلود engines کار نکرد: + +```bash +# روی سیستم با اینترنت +docker build -t football-next:latest \ + --build-arg DATABASE_URL="your-db-url" \ + --build-arg NEXTAUTH_URL="your-url" \ + --build-arg NEXTAUTH_SECRET="your-secret" \ + . + +# Save کردن image +docker save football-next:latest | gzip > football-next.tar.gz + +# انتقال به سرور و load کردن +gunzip -c football-next.tar.gz | docker load +``` + +### ب) استفاده از Registry خصوصی + +1. Push کردن image به Docker Hub یا registry خصوصی +2. Pull کردن از سرور ایران + +```bash +# روی سیستم با اینترنت +docker build -t your-username/football-next:latest . +docker push your-username/football-next:latest + +# روی سرور ایران +docker pull your-username/football-next:latest +``` + +### ج) استفاده از Proxy + +اگر سرور به proxy دسترسی دارد: + +```dockerfile +# در Dockerfile قبل از RUN commands ENV HTTP_PROXY=http://your-proxy:port ENV HTTPS_PROXY=http://your-proxy:port ``` -### ب) Pre-build کردن و Push کردن Image -روی سیستم محلی (با دسترسی به اینترنت): - -```bash -# Build کردن image -docker build -t football-next:latest . - -# Save کردن image -docker save football-next:latest > football-next.tar - -# انتقال فایل به سرور و load کردن -docker load < football-next.tar -``` - -### ج) استفاده از Prisma Binary از قبل دانلود شده -۱. روی سیستم با اینترنت: -```bash -npx prisma generate -``` - -۲. فایل‌های generate شده در `node_modules/.prisma` و `node_modules/@prisma` را کپی کنید - -۳. در Dockerfile از COPY استفاده کنید: -```dockerfile -COPY node_modules/.prisma ./node_modules/.prisma -COPY node_modules/@prisma ./node_modules/@prisma -``` - -### د) استفاده از Mirror داخلی -اگر یک mirror داخلی دارید: - -```dockerfile -ENV PRISMA_ENGINES_MIRROR=https://your-internal-mirror.ir -``` - ## تست محلی -برای تست Dockerfile قبل از دیپلوی: - ```bash # Build -docker build -t football-next:test . +docker build -t football-next:test \ + --build-arg DATABASE_URL="postgresql://user:pass@host:5432/db" \ + --build-arg NEXTAUTH_URL="http://localhost:3000" \ + --build-arg NEXTAUTH_SECRET="test-secret" \ + . # Run -docker run -p 3000:3000 \ - -e DATABASE_URL="your-db-url" \ - -e NEXTAUTH_URL="http://localhost:3000" \ - -e NEXTAUTH_SECRET="your-secret" \ - football-next:test +docker run -p 3000:3000 football-next:test ``` ## نکات مهم -1. مطمئن شوید `prisma` folder در `.dockerignore` نیست -2. متغیرهای محیطی را در Coolify یا platform دیپلوی خود تنظیم کنید -3. اگر همچنان مشکل دارید، لاگ‌های کامل build را بررسی کنید +1. فایل‌های `prisma/engines/*` باید در git commit شوند +2. این فایل‌ها binary هستند و حجم دارند (~50MB) +3. هر بار که Prisma version تغییر کرد، باید engines را دوباره دانلود کنید +4. متغیرهای محیطی را در Coolify تنظیم کنید ## متغیرهای محیطی مورد نیاز ```env DATABASE_URL=postgresql://user:password@host:5432/dbname NEXTAUTH_URL=https://your-domain.com -NEXTAUTH_SECRET=your-secret-key +NEXTAUTH_SECRET=your-secret-key-min-32-chars +IPPANEL_TOKEN=your-ippanel-token (optional) ``` + +## عیب‌یابی + +اگر build با خطا مواجه شد: + +1. بررسی کنید که `prisma/engines` وجود دارد +2. بررسی کنید که فایل‌ها executable هستند +3. لاگ‌های کامل Docker را بررسی کنید +4. از روش "Build روی سیستم محلی" استفاده کنید + diff --git a/DEPLOY_STEPS.md b/DEPLOY_STEPS.md new file mode 100644 index 0000000..c440a54 --- /dev/null +++ b/DEPLOY_STEPS.md @@ -0,0 +1,53 @@ +# مراحل دیپلوی برای سرورهای ایران + +## گام ۱: دانلود Prisma Engines (فقط یک بار) + +روی سیستم با دسترسی به اینترنت (لپ‌تاپ با VPN): + +```bash +chmod +x scripts/download-prisma-engines.sh +bash scripts/download-prisma-engines.sh +``` + +## گام ۲: Commit و Push + +```bash +git add prisma/engines Dockerfile package.json DEPLOY_IRAN.md +git commit -m "feat: Add Prisma engines for offline deployment" +git push +``` + +## گام ۳: Deploy در Coolify + +Coolify به صورت خودکار تغییرات را تشخیص داده و deploy می‌کند. + +## نکته مهم + +اگر اسکریپت دانلود کار نکرد، از روش manual استفاده کنید: + +```bash +# دریافت Prisma version +PRISMA_VERSION=$(node -p "require('./package.json').dependencies['@prisma/client']") +echo "Prisma version: $PRISMA_VERSION" + +# دانلود manual engines +mkdir -p prisma/engines +cd prisma/engines + +# Query Engine +curl -L "https://binaries.prisma.sh/all_commits/c2990dca591cba766e3b7ef5d9e8a84796e47ab7/linux-musl-openssl-3.0.x/query-engine.gz" | gunzip > query-engine +chmod +x query-engine + +# Schema Engine +curl -L "https://binaries.prisma.sh/all_commits/c2990dca591cba766e3b7ef5d9e8a84796e47ab7/linux-musl-openssl-3.0.x/schema-engine.gz" | gunzip > schema-engine +chmod +x schema-engine + +cd ../.. +``` + +## عیب‌یابی + +اگر build شکست خورد: +1. بررسی کنید فایل‌های `prisma/engines/*` وجود دارند +2. بررسی کنید executable هستند: `ls -la prisma/engines` +3. از روش "Build Local" در `DEPLOY_IRAN.md` استفاده کنید diff --git a/Dockerfile b/Dockerfile index 93901c4..f3fbfa3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,40 @@ FROM node:20-alpine AS deps WORKDIR /app -ENV NODE_ENV=development -ENV PRISMA_ENGINES_MIRROR=https://binaries.prismacdn.com -ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1 +ENV PRISMA_SKIP_POSTINSTALL_GENERATE=1 COPY package.json package-lock.json ./ -COPY prisma ./prisma -RUN npm ci -RUN npx prisma generate +RUN npm ci --ignore-scripts FROM node:20-alpine AS builder WORKDIR /app ARG DATABASE_URL ARG NEXTAUTH_URL +ARG NEXTAUTH_SECRET +ARG IPPANEL_TOKEN ENV DATABASE_URL=$DATABASE_URL ENV NEXTAUTH_URL=$NEXTAUTH_URL +ENV NEXTAUTH_SECRET=$NEXTAUTH_SECRET +ENV IPPANEL_TOKEN=$IPPANEL_TOKEN ENV NEXT_TELEMETRY_DISABLED=1 -ENV PRISMA_ENGINES_MIRROR=https://binaries.prismacdn.com -ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1 +ENV PRISMA_SKIP_POSTINSTALL_GENERATE=1 COPY --from=deps /app/node_modules ./node_modules -COPY --from=deps /app/prisma ./prisma COPY . . +# Set Prisma to use local engines if they exist +ENV PRISMA_QUERY_ENGINE_BINARY=/app/prisma/engines/query-engine +ENV PRISMA_SCHEMA_ENGINE_BINARY=/app/prisma/engines/schema-engine +ENV PRISMA_QUERY_ENGINE_LIBRARY=/app/prisma/engines/query-engine + +# Generate Prisma client using local engines +RUN if [ -f prisma/engines/query-engine ]; then \ + npx prisma generate; \ + else \ + echo "Warning: Prisma engines not found, build may fail"; \ + fi + ENV NODE_ENV=production RUN npm run build RUN npm prune --omit=dev diff --git a/app/api/admin/quiz/[id]/route.ts b/app/api/admin/quiz/[id]/route.ts index 4994975..2493372 100644 --- a/app/api/admin/quiz/[id]/route.ts +++ b/app/api/admin/quiz/[id]/route.ts @@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server"; import { db } from "@/lib/db"; import { getServerSession } from "next-auth"; import { authOptions } from "@/lib/auth"; -import { Prisma } from "@prisma/client"; +import { Prisma } from "@/lib/generated/prisma"; async function requireAdmin() { const session = await getServerSession(authOptions); diff --git a/app/api/admin/quiz/route.ts b/app/api/admin/quiz/route.ts index 8b12cf9..ca6f3de 100644 --- a/app/api/admin/quiz/route.ts +++ b/app/api/admin/quiz/route.ts @@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server"; import { db } from "@/lib/db"; import { getServerSession } from "next-auth"; import { authOptions } from "@/lib/auth"; -import { Prisma } from "@prisma/client"; +import { Prisma } from "@/lib/generated/prisma"; async function adminOnly(req: NextRequest) { const session = await getServerSession(authOptions); diff --git a/lib/cardTier.ts b/lib/cardTier.ts index 1b041c3..e5984c5 100644 --- a/lib/cardTier.ts +++ b/lib/cardTier.ts @@ -1,4 +1,4 @@ -import type { CardTier, DailyQuiz } from "@prisma/client"; +import type { CardTier, DailyQuiz } from "@/lib/generated/prisma"; export const CARD_TIER_LABELS: Record = { GOLD: "طلایی", diff --git a/lib/db.ts b/lib/db.ts index f264b8b..0eef22f 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "@/lib/generated/prisma"; import { PrismaPg } from "@prisma/adapter-pg"; const globalForPrisma = globalThis as unknown as { diff --git a/lib/points.ts b/lib/points.ts index fc197cc..bd0242b 100644 --- a/lib/points.ts +++ b/lib/points.ts @@ -1,4 +1,4 @@ -import type { Position, EventType } from "@prisma/client"; +import type { Position, EventType } from "@/lib/generated/prisma"; export const DEFAULT_RULES: Record>> = { GK: { diff --git a/lib/specialCards.ts b/lib/specialCards.ts index 75d12db..fdd45e4 100644 --- a/lib/specialCards.ts +++ b/lib/specialCards.ts @@ -1,4 +1,4 @@ -import type { Position, TeamPlayer } from "@prisma/client"; +import type { Position, TeamPlayer } from "@/lib/generated/prisma"; import { FORMATIONS } from "@/lib/teamValidation"; export const SPECIAL_CARD_TEAM_LIMIT = 3; diff --git a/package.json b/package.json index 3e8ee2d..0f5cd82 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "dev": "next dev", "build": "prisma generate && next build", "start": "next start", - "postinstall": "prisma generate", "db:push": "prisma db push", "db:generate": "prisma generate", "db:studio": "prisma studio", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d2b1c18..9c92ebe 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,6 +1,7 @@ generator client { provider = "prisma-client-js" engineType = "client" + output = "../lib/generated/prisma" } datasource db { diff --git a/prisma/seed.ts b/prisma/seed.ts index 8f3483f..3196f0e 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "../lib/generated/prisma"; import bcrypt from "bcryptjs"; // DEFAULT_RULES رو مستقیم اینجا تعریف می‌کنیم تا از @/ alias استفاده نکنیم diff --git a/scripts/check-users.ts b/scripts/check-users.ts index 856f452..954df95 100644 --- a/scripts/check-users.ts +++ b/scripts/check-users.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "../lib/generated/prisma"; const prisma = new PrismaClient(); diff --git a/scripts/create-admin-user.ts b/scripts/create-admin-user.ts index 8acd4de..85fbdc4 100644 --- a/scripts/create-admin-user.ts +++ b/scripts/create-admin-user.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "../lib/generated/prisma"; import bcrypt from "bcryptjs"; const prisma = new PrismaClient(); diff --git a/scripts/create-test-user.ts b/scripts/create-test-user.ts index 1d4ec4d..dd00b57 100644 --- a/scripts/create-test-user.ts +++ b/scripts/create-test-user.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "../lib/generated/prisma"; import bcrypt from "bcryptjs"; const prisma = new PrismaClient(); diff --git a/scripts/download-prisma-engines.ps1 b/scripts/download-prisma-engines.ps1 new file mode 100644 index 0000000..b8053e1 --- /dev/null +++ b/scripts/download-prisma-engines.ps1 @@ -0,0 +1,51 @@ +# این اسکریپت باید روی سیستمی با دسترسی به اینترنت اجرا شود + +$COMMIT_HASH = "c2990dca591cba766e3b7ef5d9e8a84796e47ab7" +$PLATFORM = "linux-musl-openssl-3.0.x" + +# Create engines directory +New-Item -ItemType Directory -Force -Path "prisma/engines" | Out-Null + +Write-Host "Downloading Prisma engines..." -ForegroundColor Green + +# Download query engine +Write-Host "Downloading query-engine..." +$queryEngineUrl = "https://binaries.prisma.sh/all_commits/$COMMIT_HASH/$PLATFORM/query-engine.gz" +$queryEnginePath = "prisma/engines/query-engine" + +try { + Invoke-WebRequest -Uri $queryEngineUrl -OutFile "prisma/engines/query-engine.gz" + + # Decompress using 7zip or built-in if available + if (Get-Command 7z -ErrorAction SilentlyContinue) { + 7z e "prisma/engines/query-engine.gz" -o"prisma/engines" -y + Remove-Item "prisma/engines/query-engine.gz" + } else { + Write-Host "Please install 7-Zip or manually decompress prisma/engines/query-engine.gz" -ForegroundColor Yellow + } +} catch { + Write-Host "Error downloading query-engine: $_" -ForegroundColor Red +} + +# Download schema engine +Write-Host "Downloading schema-engine..." +$schemaEngineUrl = "https://binaries.prisma.sh/all_commits/$COMMIT_HASH/$PLATFORM/schema-engine.gz" + +try { + Invoke-WebRequest -Uri $schemaEngineUrl -OutFile "prisma/engines/schema-engine.gz" + + if (Get-Command 7z -ErrorAction SilentlyContinue) { + 7z e "prisma/engines/schema-engine.gz" -o"prisma/engines" -y + Remove-Item "prisma/engines/schema-engine.gz" + } else { + Write-Host "Please install 7-Zip or manually decompress prisma/engines/schema-engine.gz" -ForegroundColor Yellow + } +} catch { + Write-Host "Error downloading schema-engine: $_" -ForegroundColor Red +} + +Write-Host "`nEngines downloaded successfully!" -ForegroundColor Green +Write-Host "Now commit these files:" -ForegroundColor Cyan +Write-Host "git add prisma/engines" +Write-Host "git commit -m 'Add Prisma engines for offline deployment'" +Write-Host "git push" diff --git a/scripts/download-prisma-engines.sh b/scripts/download-prisma-engines.sh new file mode 100644 index 0000000..cb0cf5b --- /dev/null +++ b/scripts/download-prisma-engines.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# این اسکریپت باید روی سیستمی با دسترسی به اینترنت اجرا شود + +PRISMA_VERSION=$(node -p "require('./package.json').dependencies['@prisma/client']" | tr -d '^~') +COMMIT_HASH="c2990dca591cba766e3b7ef5d9e8a84796e47ab7" +PLATFORM="linux-musl-openssl-3.0.x" + +mkdir -p prisma/engines + +echo "Downloading Prisma engines for version $PRISMA_VERSION..." + +# Download query engine +curl -L "https://binaries.prisma.sh/all_commits/${COMMIT_HASH}/${PLATFORM}/query-engine.gz" \ + | gunzip > prisma/engines/query-engine +chmod +x prisma/engines/query-engine + +# Download schema engine +curl -L "https://binaries.prisma.sh/all_commits/${COMMIT_HASH}/${PLATFORM}/schema-engine.gz" \ + | gunzip > prisma/engines/schema-engine +chmod +x prisma/engines/schema-engine + +echo "Engines downloaded successfully!" +echo "Now commit these files:" +echo "git add prisma/engines" +echo "git commit -m 'Add Prisma engines for offline deployment'" +echo "git push" diff --git a/scripts/generate-prisma-for-deploy.sh b/scripts/generate-prisma-for-deploy.sh new file mode 100644 index 0000000..af749a3 --- /dev/null +++ b/scripts/generate-prisma-for-deploy.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# این اسکریپت باید روی سیستمی با دسترسی به اینترنت اجرا شود +# و فایل‌های generate شده را commit کنید + +echo "Generating Prisma Client..." +npx prisma generate + +echo "Prisma Client generated successfully!" +echo "Now commit the generated files:" +echo "git add node_modules/.prisma node_modules/@prisma" +echo "git commit -m 'Add pre-generated Prisma client for deployment'" +echo "git push" diff --git a/scripts/seed-quiz-sample.ts b/scripts/seed-quiz-sample.ts index 6d4d915..6e93079 100644 --- a/scripts/seed-quiz-sample.ts +++ b/scripts/seed-quiz-sample.ts @@ -1,4 +1,4 @@ -import { CardTier, PrismaClient } from "@prisma/client"; +import { CardTier, PrismaClient } from "../lib/generated/prisma"; const db = new PrismaClient(); diff --git a/types/quiz.ts b/types/quiz.ts index ce18bc7..e6266eb 100644 --- a/types/quiz.ts +++ b/types/quiz.ts @@ -1,4 +1,4 @@ -import type { DailyQuiz, QuizQuestion, QuizSubmission, GoldenCard, Player, Country, User } from "@prisma/client"; +import type { DailyQuiz, QuizQuestion, QuizSubmission, GoldenCard, Player, Country, User } from "@/lib/generated/prisma"; export type QuizWithQuestions = DailyQuiz & { questions: QuizQuestion[];