Dockerfile modif2
This commit is contained in:
parent
3548eabf68
commit
ed84f37e12
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.env
|
||||
node_modules/
|
||||
.next/
|
||||
supabase/
|
||||
.gitignore
|
||||
34
Dockerfile
34
Dockerfile
@ -24,21 +24,22 @@ WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Variables publiques nécessaires à la compilation du bundle client.
|
||||
# Passer via --build-arg ou docker-compose (voir docker-compose.yml).
|
||||
# Les valeurs vides sont acceptées : les pages sont dynamiques (cookies),
|
||||
# donc aucune pré-rendu statique ne les utilise au build.
|
||||
ARG NEXT_PUBLIC_SUPABASE_URL=""
|
||||
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY=""
|
||||
# Les NEXT_PUBLIC_* sont baked dans le bundle client.
|
||||
# → Définir dans Dokploy : Project > Build Variables
|
||||
# → Les placeholders ci-dessous empêchent le SDK Supabase de lever une
|
||||
# erreur de validation URL si les build-args ne sont pas fournis.
|
||||
ARG NEXT_PUBLIC_SUPABASE_URL=https://placeholder.supabase.co
|
||||
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY=placeholder-anon-key-for-build-only
|
||||
|
||||
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY \
|
||||
NEXT_TELEMETRY_DISABLED=1 \
|
||||
NODE_ENV=production \
|
||||
# Allouer suffisamment de mémoire pour le build Next.js
|
||||
NODE_OPTIONS="--max-old-space-size=4096"
|
||||
NODE_OPTIONS="--max-old-space-size=2048"
|
||||
|
||||
RUN npm run build
|
||||
# Affiche les vars actives et expose la sortie complète du build
|
||||
RUN echo "→ NEXT_PUBLIC_SUPABASE_URL = $NEXT_PUBLIC_SUPABASE_URL" && \
|
||||
npm run build
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
@ -50,31 +51,26 @@ RUN apk update && apk upgrade --no-cache
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Utilisateur non-root dédié
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs
|
||||
|
||||
# Fichiers publics (favicon, images statiques…)
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Serveur Next.js standalone (bundle minimal, sans node_modules complets)
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
|
||||
# Assets statiques compilés (_next/static)
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
# Secrets et vars publiques injectés au runtime par Dokploy
|
||||
# (Project > Environment Variables) :
|
||||
# NEXT_PUBLIC_SUPABASE_URL
|
||||
# NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
# SUPABASE_SERVICE_ROLE_KEY
|
||||
ENV NODE_ENV=production \
|
||||
NEXT_TELEMETRY_DISABLED=1 \
|
||||
PORT=3000 \
|
||||
HOSTNAME="0.0.0.0"
|
||||
|
||||
# Secrets injectés au runtime uniquement (jamais baked dans l'image) :
|
||||
# NEXT_PUBLIC_SUPABASE_URL
|
||||
# NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
# SUPABASE_SERVICE_ROLE_KEY
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
services:
|
||||
solyquiz:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
# Les variables NEXT_PUBLIC_* sont lues depuis le fichier .env
|
||||
# grâce à env_file, puis transmises comme build args
|
||||
args:
|
||||
NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL}
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY}
|
||||
image: solyquiz:latest
|
||||
container_name: solyquiz
|
||||
ports:
|
||||
- "3000:3000"
|
||||
# Secrets injectés uniquement au runtime (non présents dans l'image)
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
restart: unless-stopped
|
||||
# Limite les ressources pour éviter les abus
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512m
|
||||
cpus: "1.0"
|
||||
8
lib/supabase/client.ts
Normal file
8
lib/supabase/client.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { createBrowserClient } from '@supabase/ssr'
|
||||
|
||||
export function createClient() {
|
||||
return createBrowserClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||
)
|
||||
}
|
||||
62
lib/supabase/server.ts
Normal file
62
lib/supabase/server.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { createServerClient, type CookieOptions } from '@supabase/ssr'
|
||||
import { createClient as createSupabaseClient } from '@supabase/supabase-js'
|
||||
import { cookies } from 'next/headers'
|
||||
|
||||
export async function createClient() {
|
||||
const cookieStore = await cookies()
|
||||
|
||||
return createServerClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
getAll() {
|
||||
return cookieStore.getAll()
|
||||
},
|
||||
setAll(cookiesToSet: { name: string; value: string; options?: CookieOptions }[]) {
|
||||
try {
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
cookieStore.set(name, value, options)
|
||||
)
|
||||
} catch {
|
||||
// setAll appelé depuis un Server Component
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/** Client admin avec service_role — bypass RLS + accès auth.admin.* */
|
||||
export function createAdminClient() {
|
||||
return createSupabaseClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||||
{ auth: { autoRefreshToken: false, persistSession: false } }
|
||||
)
|
||||
}
|
||||
|
||||
export async function createServiceClient() {
|
||||
const cookieStore = await cookies()
|
||||
|
||||
return createServerClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
getAll() {
|
||||
return cookieStore.getAll()
|
||||
},
|
||||
setAll(cookiesToSet: { name: string; value: string; options?: CookieOptions }[]) {
|
||||
try {
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
cookieStore.set(name, value, options)
|
||||
)
|
||||
} catch {
|
||||
// ignoré
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
36
lib/supabase/typed.ts
Normal file
36
lib/supabase/typed.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Ce fichier fournit des wrappers typés pour les opérations Supabase courantes.
|
||||
* Les types sont définis manuellement en attendant la génération via `supabase gen types`.
|
||||
* Note: Connecter votre projet Supabase et lancer `npx supabase gen types typescript`
|
||||
* pour obtenir des types auto-générés qui remplaceront ce fichier.
|
||||
*/
|
||||
|
||||
import type {
|
||||
Profile,
|
||||
Category,
|
||||
Subchapter,
|
||||
Quiz,
|
||||
Question,
|
||||
Answer,
|
||||
Session,
|
||||
StudentParticipation,
|
||||
StudentAnswer,
|
||||
} from '@/lib/types/database'
|
||||
|
||||
export type {
|
||||
Profile,
|
||||
Category,
|
||||
Subchapter,
|
||||
Quiz,
|
||||
Question,
|
||||
Answer,
|
||||
Session,
|
||||
StudentParticipation,
|
||||
StudentAnswer,
|
||||
}
|
||||
|
||||
// Types pour les retours de requêtes
|
||||
export type SupabaseResponse<T> = {
|
||||
data: T | null
|
||||
error: { message: string; code?: string } | null
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user