diff --git a/apps/sample-website/.env.example b/apps/sample-website/.env.example new file mode 100644 index 0000000..2e74407 --- /dev/null +++ b/apps/sample-website/.env.example @@ -0,0 +1,31 @@ +# Project +PROJECT_NAME=sample-website +PROJECT_COLOR=#82ed20 + +# Authentication +GATEKEEPER_PASSWORD=mintel +AUTH_COOKIE_NAME=mintel_gatekeeper_session + +# Host Config (Local) +TRAEFIK_HOST=sample-website.localhost +DIRECTUS_HOST=cms.sample-website.localhost + +# Next.js +NEXT_PUBLIC_BASE_URL=http://sample-website.localhost + +# Directus +DIRECTUS_URL=http://localhost:8055 +DIRECTUS_KEY=sample-key-123 +DIRECTUS_SECRET=sample-secret-123 +DIRECTUS_ADMIN_EMAIL=admin@mintel.me +DIRECTUS_ADMIN_PASSWORD=mintel-admin-pass +DIRECTUS_DB_NAME=directus +DIRECTUS_DB_USER=directus +DIRECTUS_DB_PASSWORD=mintel-db-pass + +# Sentry / Glitchtip +SENTRY_DSN= + +# Analytics (Umami) +NEXT_PUBLIC_UMAMI_WEBSITE_ID= +NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js diff --git a/apps/sample-website/Dockerfile b/apps/sample-website/Dockerfile new file mode 100644 index 0000000..31fe010 --- /dev/null +++ b/apps/sample-website/Dockerfile @@ -0,0 +1,69 @@ +FROM node:20-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +RUN apk add --no-cache libc6-compat curl +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json package-lock.json* pnpm-lock.yaml* ./ +RUN corepack enable pnpm && \ + pnpm config set store-dir /root/.local/share/pnpm/store/v3 && \ + pnpm i --frozen-lockfile + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. +ENV NEXT_TELEMETRY_DISABLED=1 + +# Build-time environment variables for Next.js +ARG NEXT_PUBLIC_BASE_URL +ARG NEXT_PUBLIC_UMAMI_WEBSITE_ID +ARG NEXT_PUBLIC_UMAMI_SCRIPT_URL +ARG NEXT_PUBLIC_TARGET +ARG DIRECTUS_URL + +ENV NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL +ENV NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID +ENV NEXT_PUBLIC_UMAMI_SCRIPT_URL=$NEXT_PUBLIC_UMAMI_SCRIPT_URL +ENV NEXT_PUBLIC_TARGET=$NEXT_PUBLIC_TARGET +ENV DIRECTUS_URL=$DIRECTUS_URL + +# Build the application +RUN corepack enable pnpm && pnpm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +# Install curl for health checks +RUN apk add --no-cache curl + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Set the correct permission for prerender cache +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["node", "server.js"] diff --git a/apps/sample-website/directus/extensions/.gitkeep b/apps/sample-website/directus/extensions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/sample-website/directus/uploads/.gitkeep b/apps/sample-website/directus/uploads/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/sample-website/docker-compose.yml b/apps/sample-website/docker-compose.yml new file mode 100644 index 0000000..5e2a9de --- /dev/null +++ b/apps/sample-website/docker-compose.yml @@ -0,0 +1,75 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + args: + NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL:-http://localhost:3000} + NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${NEXT_PUBLIC_UMAMI_WEBSITE_ID} + NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${NEXT_PUBLIC_UMAMI_SCRIPT_URL} + NEXT_PUBLIC_TARGET: ${TARGET:-development} + DIRECTUS_URL: ${DIRECTUS_URL:-http://directus:8055} + image: sample-website:latest + container_name: sample-website-app + restart: always + networks: + - infra + env_file: + - .env + ports: + - "3000:3000" + labels: + - "traefik.enable=true" + - "traefik.http.routers.sample-website.rule=Host(`${TRAEFIK_HOST:-sample-website.localhost}`)" + - "traefik.http.services.sample-website.loadbalancer.server.port=3000" + + directus: + image: directus/directus:11 + container_name: sample-website-directus + restart: always + networks: + - infra + env_file: + - .env + environment: + KEY: ${DIRECTUS_KEY:-mintel-key} + SECRET: ${DIRECTUS_SECRET:-mintel-secret} + ADMIN_EMAIL: ${DIRECTUS_ADMIN_EMAIL:-admin@mintel.me} + ADMIN_PASSWORD: ${DIRECTUS_ADMIN_PASSWORD:-mintel-admin} + DB_CLIENT: 'pg' + DB_HOST: 'directus-db' + DB_PORT: '5432' + DB_DATABASE: ${DIRECTUS_DB_NAME:-directus} + DB_USER: ${DIRECTUS_DB_USER:-directus} + DB_PASSWORD: ${DIRECTUS_DB_PASSWORD:-mintel-db-pass} + WEBSOCKETS_ENABLED: 'true' + PUBLIC_URL: ${DIRECTUS_URL:-http://localhost:8055} + ports: + - "8055:8055" + volumes: + - ./directus/uploads:/directus/uploads + - ./directus/extensions:/directus/extensions + labels: + - "traefik.enable=true" + - "traefik.http.routers.sample-website-directus.rule=Host(`${DIRECTUS_HOST:-cms.sample-website.localhost}`)" + - "traefik.http.services.sample-website-directus.loadbalancer.server.port=8055" + + directus-db: + image: postgres:15-alpine + container_name: sample-website-db + restart: always + networks: + - infra + environment: + POSTGRES_DB: ${DIRECTUS_DB_NAME:-directus} + POSTGRES_USER: ${DIRECTUS_DB_USER:-directus} + POSTGRES_PASSWORD: ${DIRECTUS_DB_PASSWORD:-mintel-db-pass} + volumes: + - directus-db-data:/var/lib/postgresql/data + +networks: + infra: + external: true + +volumes: + directus-db-data: diff --git a/apps/sample-website/package.json b/apps/sample-website/package.json index 182dd4d..e31fcdf 100644 --- a/apps/sample-website/package.json +++ b/apps/sample-website/package.json @@ -11,13 +11,13 @@ "lint": "next lint", "typecheck": "tsc --noEmit", "test": "vitest run --passWithNoTests", - "directus:bootstrap": "mintel directus bootstrap", - "directus:push:testing": "mintel directus sync push testing", - "directus:pull:testing": "mintel directus sync pull testing", - "directus:push:staging": "mintel directus sync push staging", - "directus:pull:staging": "mintel directus sync pull staging", - "directus:push:prod": "mintel directus sync push production", - "directus:pull:prod": "mintel directus sync pull production", + "cms:bootstrap": "mintel directus bootstrap", + "cms:push:testing": "mintel directus sync push testing", + "cms:pull:testing": "mintel directus sync pull testing", + "cms:push:staging": "mintel directus sync push staging", + "cms:pull:staging": "mintel directus sync pull staging", + "cms:push:prod": "mintel directus sync push production", + "cms:pull:prod": "mintel directus sync pull production", "pagespeed:test": "mintel pagespeed" }, "dependencies": { diff --git a/packages/infra/docker/Dockerfile.nextjs b/packages/infra/docker/Dockerfile.nextjs index 5684ebf..76fcadf 100644 --- a/packages/infra/docker/Dockerfile.nextjs +++ b/packages/infra/docker/Dockerfile.nextjs @@ -7,9 +7,15 @@ WORKDIR /app # Install dependencies based on the preferred package manager COPY package.json package-lock.json* pnpm-lock.yaml* ./ -RUN if [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ - elif [ -f package-lock.json ]; then npm ci; \ - else npm i; fi +RUN if [ -f pnpm-lock.yaml ]; then \ + corepack enable pnpm && \ + pnpm config set store-dir /root/.local/share/pnpm/store/v3 && \ + pnpm i --frozen-lockfile; \ + elif [ -f package-lock.json ]; then \ + npm ci; \ + else \ + npm i; \ + fi # Rebuild the source code only when needed FROM base AS builder @@ -24,14 +30,22 @@ ENV NEXT_TELEMETRY_DISABLED=1 ARG NEXT_PUBLIC_BASE_URL ARG NEXT_PUBLIC_UMAMI_WEBSITE_ID ARG NEXT_PUBLIC_UMAMI_SCRIPT_URL +ARG NEXT_PUBLIC_TARGET +ARG DIRECTUS_URL ENV NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL ENV NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID ENV NEXT_PUBLIC_UMAMI_SCRIPT_URL=$NEXT_PUBLIC_UMAMI_SCRIPT_URL +ENV NEXT_PUBLIC_TARGET=$NEXT_PUBLIC_TARGET +ENV DIRECTUS_URL=$DIRECTUS_URL # Build the application -RUN if [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ - else npm run build; fi +RUN if [ -f pnpm-lock.yaml ]; then \ + corepack enable pnpm && \ + pnpm run build; \ + else \ + npm run build; \ + fi # Production image, copy all the files and run next FROM base AS runner