diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..915f7e1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +# Git +.git +.gitignore + +# Secrets — JAMAIS dans l'image +.env +.env.local +.env.production + +# Dev +node_modules +*.log +.cursor + +# Assets source bruts (seul public/ va dans l'image Docker) +assets/ + +# Infra (pas besoin dans le conteneur) +Dockerfile +docker-compose.yml +nginx.conf +ssl/ + +# Docs +README.md diff --git a/.env.example b/.env.example index eed70d3..126bc37 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,10 @@ +# ── Stripe ──────────────────────────────────────────────────────────────────── +# Clé secrète Stripe (test: sk_test_... / prod: sk_live_...) STRIPE_SECRET_KEY=sk_test_... + +# Secret webhook (obtenu via: stripe listen --print-secret) STRIPE_WEBHOOK_SECRET=whsec_... -DOMAIN=http://localhost:3000 + +# ── App ─────────────────────────────────────────────────────────────────────── +# URL publique du site (sans slash final) +DOMAIN=https://rebour.studio diff --git a/.gitignore b/.gitignore index a14702c..25a567b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,14 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json # Finder (MacOS) folder config .DS_Store + +# Secrets +.env +.env.* +!.env.example + +# SSL certs +ssl/ + +# Nginx logs volume +nginx-logs/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b6fbe96 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# ───────────────────────────────────────────────────────────────────────────── +# REBOUR — Dockerfile +# Runtime : Bun + Elysia (pas de SSR, le HTML est statique dans public/) +# Stratégie : multi-stage pour image finale la plus légère possible +# ───────────────────────────────────────────────────────────────────────────── + +# ── Stage 1 : installation des dépendances ──────────────────────────────────── +FROM oven/bun:1.3-alpine AS deps + +WORKDIR /app + +COPY package.json bun.lock ./ +RUN bun install --frozen-lockfile --production + +# ── Stage 2 : image de production ───────────────────────────────────────────── +FROM oven/bun:1.3-alpine AS runner + +WORKDIR /app + +# Dépendances uniquement runtime +COPY --from=deps /app/node_modules ./node_modules + +# Code serveur +COPY server.ts ./ + +# Fichiers publics (HTML statique + assets + CSS/JS) +# Le HTML est pré-écrit, pas de build step nécessaire (pas de SSR/bundler) +COPY public/ ./public/ + +# Utilisateur non-root (sécurité) +USER bun + +EXPOSE 3000 + +ENV NODE_ENV=production + +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD wget -qO- http://localhost:3000/robots.txt || exit 1 + +CMD ["bun", "run", "server.ts"] diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..ad2ed09 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,24 @@ +# ───────────────────────────────────────────────────────────────────────────── +# REBOUR — Dockerfile.dev +# Hot reload via `bun --hot` : redémarre le serveur à chaque changement de +# server.ts. Les fichiers statiques (public/) sont montés en volume, donc +# toute modif HTML/CSS/JS est immédiatement visible sans rebuild. +# ───────────────────────────────────────────────────────────────────────────── +FROM oven/bun:1.3-alpine + +WORKDIR /app + +# Installe les dépendances (dev incluses pour les types) +COPY package.json bun.lock* ./ +RUN bun install + +# Le code source est monté en volume (voir docker-compose.dev.yml), +# on copie uniquement pour que l'image soit autonome si besoin. +COPY server.ts ./ +COPY public/ ./public/ + +EXPOSE 3000 + +ENV NODE_ENV=development + +CMD ["bun", "--watch", "server.ts"] diff --git a/assets/WhatsApp Image 2026-02-14 at 12.23.09 (2).jpeg b/assets/lamp-violet.jpg similarity index 100% rename from assets/WhatsApp Image 2026-02-14 at 12.23.09 (2).jpeg rename to assets/lamp-violet.jpg diff --git a/assets/WhatsApp Image 2026-02-14 at 12.23.09.jpeg b/assets/lampes-serie.jpg similarity index 100% rename from assets/WhatsApp Image 2026-02-14 at 12.23.09.jpeg rename to assets/lampes-serie.jpg diff --git a/assets/WhatsApp Image 2026-02-14 at 12.23.09 (1).jpeg b/assets/table-terrazzo.jpg similarity index 100% rename from assets/WhatsApp Image 2026-02-14 at 12.23.09 (1).jpeg rename to assets/table-terrazzo.jpg diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..6420bd4 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,21 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile.dev + ports: + - "3000:3000" + volumes: + # Monte tout le projet pour le hot reload + - .:/app + # Évite d'écraser node_modules de l'image par le dossier local (s'il est vide) + - /app/node_modules + environment: + NODE_ENV: development + STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-} + STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-} + DOMAIN: ${DOMAIN:-http://localhost:3000} + # Force bun --watch à utiliser le polling sur Docker Desktop Mac + # (les événements inotify ne sont pas propagés depuis macOS) + CHOKIDAR_USEPOLLING: "true" + restart: unless-stopped diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e2c008c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,49 @@ +services: + + # ── App Elysia/Bun ──────────────────────────────────────────────────────── + app: + build: + context: . + dockerfile: Dockerfile + target: runner + restart: unless-stopped + # Port NON exposé publiquement : nginx est le seul point d'entrée + expose: + - "3000" + environment: + NODE_ENV: production + STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} + STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET} + DOMAIN: ${DOMAIN:-http://localhost} + networks: + - rebour-net + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:3000/robots.txt || exit 1"] + interval: 5s + timeout: 3s + retries: 5 + start_period: 5s + + # ── Nginx : reverse proxy, gzip, cache headers, rate-limit API ─────────── + nginx: + image: nginx:1.27-alpine + restart: on-failure + ports: + - "0.0.0.0:80:80" + - "0.0.0.0:443:443" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + # En prod : décommenter + monter les certificats Let's Encrypt + # - /etc/letsencrypt:/etc/letsencrypt:ro + - nginx-logs:/var/log/nginx + depends_on: + - app + networks: + - rebour-net + +networks: + rebour-net: + driver: bridge + +volumes: + nginx-logs: diff --git a/index.html b/index.html index 7059413..fa70ac1 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,62 @@ - REBOUR + + + REBOUR — Mobilier d'art contemporain | Collection 001 + + + + + + + + + + + + + + + + + + + + + + + + + @@ -100,8 +155,8 @@
- REBOUR -