fix: Prisma binary download for Iran servers

This commit is contained in:
2026-05-06 18:04:19 +03:30
parent ea6e67b4e8
commit b0a345c6b7
23 changed files with 285 additions and 116 deletions

2
.env
View File

@@ -15,4 +15,4 @@ IPPANEL_ORIGINATOR="+983000505"
IPPANEL_BASE_URL="https://edge.ippanel.com/v1"
# Node Environment
NODE_ENV="development"
NODE_ENV="production"

60
.gitignore vendored
View File

@@ -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

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"kiroAgent.configureMCP": "Disabled"
}

View File

@@ -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 روی سیستم محلی" استفاده کنید

53
DEPLOY_STEPS.md Normal file
View File

@@ -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` استفاده کنید

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<CardTier, string> = {
GOLD: "طلایی",

View File

@@ -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 {

View File

@@ -1,4 +1,4 @@
import type { Position, EventType } from "@prisma/client";
import type { Position, EventType } from "@/lib/generated/prisma";
export const DEFAULT_RULES: Record<string, Partial<Record<string, number>>> = {
GK: {

View File

@@ -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;

View File

@@ -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",

View File

@@ -1,6 +1,7 @@
generator client {
provider = "prisma-client-js"
engineType = "client"
output = "../lib/generated/prisma"
}
datasource db {

View File

@@ -1,4 +1,4 @@
import { PrismaClient } from "@prisma/client";
import { PrismaClient } from "../lib/generated/prisma";
import bcrypt from "bcryptjs";
// DEFAULT_RULES رو مستقیم اینجا تعریف می‌کنیم تا از @/ alias استفاده نکنیم

View File

@@ -1,4 +1,4 @@
import { PrismaClient } from "@prisma/client";
import { PrismaClient } from "../lib/generated/prisma";
const prisma = new PrismaClient();

View File

@@ -1,4 +1,4 @@
import { PrismaClient } from "@prisma/client";
import { PrismaClient } from "../lib/generated/prisma";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();

View File

@@ -1,4 +1,4 @@
import { PrismaClient } from "@prisma/client";
import { PrismaClient } from "../lib/generated/prisma";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -1,4 +1,4 @@
import { CardTier, PrismaClient } from "@prisma/client";
import { CardTier, PrismaClient } from "../lib/generated/prisma";
const db = new PrismaClient();

View File

@@ -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[];