Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: "DEV - CI/CD"

on:
push:
branches:
- develop
- main
pull_request:
types: [opened, synchronize, reopened]
branches:
- develop
- main

jobs:
# 1️⃣ Build & tests
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Generate Prisma Client
run: pnpm prisma generate

- name: Skip tests (no test script defined)
run: echo "⚠️ Aucun test défini, étape ignorée."

- name: Build app
run: pnpm build

# 2️⃣ Build & push Docker image
docker-build-push:
runs-on: ubuntu-latest
needs: build-and-test
permissions:
contents: read
packages: write

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=dev-latest
type=sha,format=long

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
NEXT_PUBLIC_ENV=develop

# 3️⃣ Deploy DEV
deploy-dev:
runs-on: self-hosted
needs: docker-build-push

steps:
- name: Clean workspace
run: rm -rf *

- name: Checkout code
uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pull new image + restart DEV stack
run: |
echo "🔧 Deploying on DEV..."
cd /home/baptiste/Dev/WPT/dev
docker-compose pull
docker rm -f wpt-dev_website || true
docker-compose up -d --remove-orphans
echo "🚀 Deployed in DEV!"
110 changes: 110 additions & 0 deletions .github/workflows/prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: "PROD - CI/CD"

on:
push:
tags:
- 'v*.*.*' # Se déclenche sur les tags de version (ex: v1.0.0, v2.1.3)

jobs:
# 1️⃣ Build & tests
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Generate Prisma Client
run: pnpm prisma generate

- name: Skip tests (no test script defined)
run: echo "⚠️ Aucun test défini, étape ignorée."

- name: Build app
run: pnpm build

# 2️⃣ Build & push Docker image
docker-build-push:
runs-on: ubuntu-latest
needs: build-and-test
permissions:
contents: read
packages: write

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,format=long

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
NEXT_PUBLIC_ENV=production

# 3️⃣ Deploy PROD
deploy-prod:
runs-on: self-hosted
needs: docker-build-push

steps:
- name: Clean workspace
run: rm -rf *

- name: Checkout code
uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pull new image + restart PROD stack
run: |
echo "🔧 Deploying on PROD..."
cd /home/baptiste/Dev/WPT/prod
docker-compose pull
docker rm -f wpt_website || true
docker-compose up -d --remove-orphans
echo "🚀 Deployed in PROD!"
80 changes: 65 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,74 @@
# Étape 1 : build
FROM node:22-alpine AS builder
FROM node:22-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat openssl
WORKDIR /app
RUN npm install -g pnpm

# Install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate

# Install dependencies based on pnpm
COPY package.json pnpm-lock.yaml ./
COPY .env .env
RUN pnpm install
RUN pnpm install --frozen-lockfile

FROM base AS dev
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN apk add --no-cache openssl
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Generates prisma files
RUN pnpm prisma generate

# Enables Hot Reloading Check https://github.com/vercel/next.js/issues/36774 for more information
ENV CHOKIDAR_USEPOLLING=true
ENV WATCHPACK_POLLING=true

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN apk add --no-cache openssl
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1

# Generates prisma files for production build
RUN pnpm prisma generate
RUN pnpm build

# Étape 2 : image finale propre
FROM node:22-alpine
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
RUN npm install -g pnpm
COPY --from=builder /app/package.json /app/pnpm-lock.yaml ./
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/next.config.ts ./
COPY --from=builder /app/tsconfig.json ./

RUN pnpm install --prod
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

RUN apk add --no-cache openssl
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Install pnpm in runner
RUN corepack enable && corepack prepare pnpm@latest --activate

# Copier les fichiers nécessaires
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./
COPY --from=builder --chown=nextjs:nodejs /app/pnpm-lock.yaml ./
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
COPY --from=builder --chown=nextjs:nodejs /app/next.config.ts ./

USER nextjs

EXPOSE 3000
CMD ["pnpm", "start"]
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"

# Prisma generate + db push + start
CMD sh -c "pnpm prisma generate && pnpm prisma db push --accept-data-loss && pnpm start"
22 changes: 10 additions & 12 deletions app/[locale]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@ import type React from 'react'

import { useState, useEffect, useRef } from 'react'
import { DocumentationSection } from '@/components/pages/(auth)/landing/DocumentationSection'
import { TestimonialsSection } from '@/components/pages/(auth)/landing/TestimonialSection'
import { PricingSection } from '@/components/pages/(auth)/landing/PrincingSection'
import { FAQSection } from '@/components/pages/(auth)/landing/FaqSection'
import { CTASection } from '@/components/pages/(auth)/landing/CtaSection'
import { FooterSection } from '@/components/pages/(auth)/landing/FooterSection'
import NumbersThatSpeak from '@/components/pages/(auth)/landing/NumbersThatSpeak'
import EffortlessIntegration from '@/components/pages/(auth)/landing/EffortlessIntegration'
import YourWorkInSync from '@/components/pages/(auth)/landing/YourWorkInSync'
import SmartSimpleBrilliant from '@/components/pages/(auth)/landing/SmartSimpleBrilliant'
import { SITENAME } from '@/constants/globals'
import { LANDING_PAGE_LINKS, ROUTES } from '@/constants/routes'
import { Link } from '@/lib/i18n/navigation'
import { useTranslations } from 'next-intl'
import Image from 'next/image'

function Badge({ icon, text }: { icon: React.ReactNode; text: string }) {
return (
Expand Down Expand Up @@ -143,15 +139,18 @@ export default function LandingPage() {
<div className="w-full max-w-[497px] lg:w-[497px] flex flex-col justify-center items-center gap-6 sm:gap-8 md:gap-10 lg:gap-12 relative z-10 mt-6 sm:mt-8 md:mt-10 lg:mt-12">
<div className="backdrop-blur-[8.25px] flex justify-start items-center gap-4">
<div className="h-10 sm:h-11 md:h-12 px-6 sm:px-8 md:px-10 lg:px-12 py-2 sm:py-[6px] relative bg-primary hover:bg-primary/90 transition-colors shadow-[0px_0px_0px_2.5px_rgba(255,255,255,0.1)_inset] overflow-hidden rounded-full flex justify-center items-center cursor-pointer">
<Link href={ROUTES.SIGN_IN} className="flex flex-col justify-center text-primary-foreground text-sm sm:text-base md:text-[15px] font-semibold leading-5 font-sans">
<Link
href={ROUTES.SIGN_IN}
className="flex flex-col justify-center text-primary-foreground text-sm sm:text-base md:text-[15px] font-semibold leading-5 font-sans"
>
{t('Buttons.CTA')}
</Link>
</div>
</div>
</div>

<div className="absolute top-[232px] sm:top-[248px] md:top-[264px] lg:top-[320px] left-1/2 transform -translate-x-1/2 z-0 pointer-events-none">
<img
<Image
src="/mask-group-pattern.svg"
alt=""
className="w-[936px] sm:w-[1404px] md:w-[2106px] lg:w-[2808px] h-auto opacity-30 sm:opacity-40 md:opacity-50 mix-blend-multiply"
Expand Down Expand Up @@ -351,7 +350,6 @@ export default function LandingPage() {
<div className="self-stretch px-4 sm:px-6 md:px-24 py-8 sm:py-12 md:py-16 border-b border-border flex justify-center items-center gap-6">
<div className="w-full max-w-[586px] px-4 sm:px-6 py-4 sm:py-5 overflow-hidden rounded-lg flex flex-col justify-start items-center gap-3 sm:gap-4">
<Badge

icon={
<svg
width="12"
Expand All @@ -368,14 +366,14 @@ export default function LandingPage() {
/>
</svg>
}
text={t("Trusted.Badge")}
text={t('Trusted.Badge')}
/>

<div className="w-full max-w-[472.55px] text-center flex justify-center flex-col text-foreground text-xl sm:text-2xl md:text-3xl lg:text-5xl font-bold leading-tight md:leading-[60px] font-sans tracking-tight">
{t("Trusted.Title")}
{t('Trusted.Title')}
</div>
<div className="self-stretch text-center text-muted-foreground text-sm sm:text-base font-normal leading-6 sm:leading-7 font-sans">
{t("Trusted.Description")}
{t('Trusted.Description')}
</div>
</div>
</div>
Expand Down Expand Up @@ -421,7 +419,7 @@ export default function LandingPage() {
`}
>
<div className="w-6 h-6 xs:w-7 xs:h-7 sm:w-8 sm:h-8 md:w-9 md:h-9 lg:w-10 lg:h-10 relative shadow-[0px_-4px_8px_rgba(255,255,255,0.64)_inset] overflow-hidden rounded-full">
<img
<Image
src="/horizon-icon.svg"
alt="Horizon"
className="w-full h-full object-contain"
Expand Down
Loading
Loading