Dockerfile modif2

This commit is contained in:
corenthin-lebreton 2026-02-26 22:30:29 +01:00
parent 3548eabf68
commit ed84f37e12
6 changed files with 126 additions and 45 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.env
node_modules/
.next/
supabase/
.gitignore

View File

@ -24,21 +24,22 @@ WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
# Variables publiques nécessaires à la compilation du bundle client. # Les NEXT_PUBLIC_* sont baked dans le bundle client.
# Passer via --build-arg ou docker-compose (voir docker-compose.yml). # → Définir dans Dokploy : Project > Build Variables
# Les valeurs vides sont acceptées : les pages sont dynamiques (cookies), # → Les placeholders ci-dessous empêchent le SDK Supabase de lever une
# donc aucune pré-rendu statique ne les utilise au build. # erreur de validation URL si les build-args ne sont pas fournis.
ARG NEXT_PUBLIC_SUPABASE_URL="" ARG NEXT_PUBLIC_SUPABASE_URL=https://placeholder.supabase.co
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY="" ARG NEXT_PUBLIC_SUPABASE_ANON_KEY=placeholder-anon-key-for-build-only
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \ ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \
NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY \ NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY \
NEXT_TELEMETRY_DISABLED=1 \ NEXT_TELEMETRY_DISABLED=1 \
NODE_ENV=production \ NODE_ENV=production \
# Allouer suffisamment de mémoire pour le build Next.js NODE_OPTIONS="--max-old-space-size=2048"
NODE_OPTIONS="--max-old-space-size=4096"
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 WORKDIR /app
# Utilisateur non-root dédié
RUN addgroup --system --gid 1001 nodejs && \ RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs adduser --system --uid 1001 nextjs
# Fichiers publics (favicon, images statiques…)
COPY --from=builder /app/public ./public 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 ./ 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 COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs 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 \ ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \ NEXT_TELEMETRY_DISABLED=1 \
PORT=3000 \ PORT=3000 \
HOSTNAME="0.0.0.0" 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 EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \

View File

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