feat: payload cms
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 1m13s
Build & Deploy / 🏗️ Build (push) Failing after 5m53s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Smoke Test (push) Has been skipped
Build & Deploy / ⚡ Lighthouse (push) Has been skipped
Build & Deploy / ♿ WCAG (push) Has been skipped
Build & Deploy / 🛡️ Quality Gates (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s

This commit is contained in:
2026-02-24 02:28:48 +01:00
parent 41cfe19cbf
commit a5d77fc69b
89 changed files with 25282 additions and 1903 deletions

View File

@@ -1,12 +1,6 @@
services:
klz-app:
build:
context: .
dockerfile: Dockerfile
args:
NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL}
DIRECTUS_URL: "${DIRECTUS_URL}"
image: registry.infra.mintel.me/mintel/klz-cables.com:${IMAGE_TAG:-latest}
image: registry.infra.mintel.me/mintel/klz-2026:${IMAGE_TAG:-latest}
restart: unless-stopped
networks:
default:
@@ -15,8 +9,6 @@ services:
- klz.localhost
env_file:
- ${ENV_FILE:-.env}
environment:
IMGPROXY_URL: ${IMGPROXY_URL:-http://klz-imgproxy:8080}
labels:
- "traefik.enable=true"
# HTTP ⇒ HTTPS redirect
@@ -31,43 +23,23 @@ services:
- "traefik.http.routers.${PROJECT_NAME:-klz}.service=${PROJECT_NAME:-klz}-app-svc"
- "traefik.http.routers.${PROJECT_NAME:-klz}.middlewares=${AUTH_MIDDLEWARE:-klz-ratelimit,klz-forward,klz-compress}"
# Public Router (Whitelist for OG Images, Sitemaps, Health)
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-klz-cables.com}`)}) && (PathPrefix(`/health`) || PathPrefix(`/sitemap.xml`) || PathPrefix(`/robots.txt`) || PathPrefix(`/manifest.webmanifest`) || PathPrefix(`/api/og`) || PathPrefix(`/de/api/og`) || PathPrefix(`/en/api/og`) || PathPrefix(`/logo-white.svg`) || PathPrefix(`/icon-white.svg`) || PathPrefix(`/opengraph-image`) || PathPrefix(`/de/opengraph-image`) || PathPrefix(`/en/opengraph-image`) || PathPrefix(`/blog/opengraph-image`) || PathPrefix(`/de/blog/opengraph-image`) || PathPrefix(`/en/blog/opengraph-image`) || PathRegexp(`^/sitemap(-[0-9]+)?\\.xml$`) || PathRegexp(`.*\\.(svg|png|jpg|jpeg|gif|webp|ico|webm|mp4|map)$`))"
# Public Router (Whitelist)
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-klz-cables.com}`)}) && (PathPrefix(`/health`) || PathPrefix(`/sitemap.xml`) || PathPrefix(`/robots.txt`) || PathPrefix(`/manifest.webmanifest`) || PathPrefix(`/api/og`) || PathRegexp(`.*opengraph-image.*`) || PathRegexp(`^/sitemap(-[0-9]+)?\\.xml$`))"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls=${TRAEFIK_TLS:-false}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.service=${PROJECT_NAME:-klz}-app-svc"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.middlewares=${AUTH_MIDDLEWARE_UNPROTECTED:-klz-ratelimit,klz-forward,klz-compress}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.priority=2000"
- "traefik.http.services.${PROJECT_NAME:-klz}-app-svc.loadbalancer.server.scheme=http"
- "traefik.http.services.${PROJECT_NAME:-klz}-app-svc.loadbalancer.server.port=3000"
- "traefik.docker.network=infra"
- "caddy=http://${TRAEFIK_HOST:-klz.localhost}"
- "caddy.reverse_proxy={{upstreams 3000}}"
# Middleware Definitions
# Middlewares
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-compress.compress=true"
# Forwarded Headers
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-forward.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-forward.headers.customrequestheaders.X-Forwarded-Ssl=on"
# Authentication Middleware (ForwardAuth)
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-auth.forwardauth.address=http://${PROJECT_NAME:-klz}-gatekeeper:3000/gatekeeper/api/verify"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-auth.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-auth.forwardauth.authRequestHeaders=X-Forwarded-Host,X-Forwarded-Proto,X-Forwarded-For,Cookie"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-auth.forwardauth.authResponseHeaders=X-Auth-User"
# Rate Limit Middleware
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-ratelimit.ratelimit.burst=50"
healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:3000/health" ]
interval: 15s
timeout: 10s
retries: 3
start_period: 45s
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-forward.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-forward.headers.customrequestheaders.X-Forwarded-Ssl=on"
klz-gatekeeper:
profiles: [ "gatekeeper" ]
@@ -81,125 +53,26 @@ services:
- ${ENV_FILE:-.env}
environment:
PORT: 3000
PROJECT_NAME: ${PROJECT_NAME:-KLZ Cables}
PROJECT_COLOR: "#82ed20"
COOKIE_DOMAIN: ${COOKIE_DOMAIN}
AUTH_COOKIE_NAME: ${AUTH_COOKIE_NAME:-klz_gatekeeper_session}
GATEKEEPER_PASSWORD: ${GATEKEEPER_PASSWORD}
NEXT_PUBLIC_BASE_URL: ${GATEKEEPER_ORIGIN}
labels:
- "traefik.enable=true"
- "traefik.docker.network=infra"
- "traefik.http.routers.${PROJECT_NAME:-klz}-gatekeeper.rule=(Host(`${TRAEFIK_HOST:-testing.klz-cables.com}`) && PathPrefix(`/gatekeeper`))"
- "traefik.http.routers.${PROJECT_NAME:-klz}-gatekeeper.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-gatekeeper.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-gatekeeper.tls=${TRAEFIK_TLS:-false}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-gatekeeper.service=${PROJECT_NAME:-klz}-gatekeeper-svc"
- "traefik.http.services.${PROJECT_NAME:-klz}-gatekeeper-svc.loadbalancer.server.port=3000"
- "traefik.docker.network=infra"
klz-cms:
image: registry.infra.mintel.me/mintel/directus:latest
restart: unless-stopped
command: [ "node", "cli.js", "start" ]
env_file:
- ${ENV_FILE:-.env}
environment:
KEY: ${DIRECTUS_KEY}
SECRET: ${DIRECTUS_SECRET}
ADMIN_EMAIL: ${DIRECTUS_ADMIN_EMAIL}
ADMIN_PASSWORD: ${DIRECTUS_ADMIN_PASSWORD}
DB_CLIENT: 'pg'
DB_HOST: 'klz-db'
DB_PORT: '5432'
DB_DATABASE: ${DIRECTUS_DB_NAME:-directus}
DB_USER: ${DIRECTUS_DB_USER:-directus}
DB_PASSWORD: ${DIRECTUS_DB_PASSWORD:-120in09oenaoinsd9iaidon}
WEBSOCKETS_ENABLED: 'true'
PUBLIC_URL: ${DIRECTUS_URL:-https://cms.klz-cables.com}
HOST: '0.0.0.0'
networks:
- default
- infra
volumes:
- ./directus/uploads:/directus/uploads
- ./directus/extensions:/directus/extensions
- ./directus/schema:/directus/schema
- ./directus/migrations:/directus/migrations
healthcheck:
disable: true
labels:
- "traefik.enable=true"
- "traefik.http.routers.${PROJECT_NAME:-klz}-cms.rule=Host(`${DIRECTUS_HOST:-cms.klz-cables.com}`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-cms.entrypoints=websecure"
- "traefik.http.routers.${PROJECT_NAME:-klz}-cms.priority=5000"
- "traefik.http.routers.${PROJECT_NAME:-klz}-cms.tls=true"
- "traefik.http.routers.${PROJECT_NAME:-klz}-cms.tls.certresolver=le"
- "traefik.http.routers.${PROJECT_NAME:-klz}-cms.service=${PROJECT_NAME:-klz}-cms-svc"
- "traefik.http.services.${PROJECT_NAME:-klz}-cms-svc.loadbalancer.server.port=8055"
- "traefik.docker.network=infra"
- "caddy=http://${DIRECTUS_HOST:-cms.klz-cables.com}"
- "caddy.reverse_proxy={{upstreams 8055}}"
klz-db:
image: postgres:15-alpine
restart: unless-stopped
env_file:
- ${ENV_FILE:-.env}
environment:
POSTGRES_DB: ${DIRECTUS_DB_NAME:-directus}
POSTGRES_USER: ${DIRECTUS_DB_USER:-directus}
POSTGRES_DB: ${DIRECTUS_DB_NAME:-payload}
POSTGRES_USER: ${DIRECTUS_DB_USER:-payload}
POSTGRES_PASSWORD: ${DIRECTUS_DB_PASSWORD:-120in09oenaoinsd9iaidon}
volumes:
- directus-db-data:/var/lib/postgresql/data
- klz_db_data:/var/lib/postgresql/data
networks:
- default
klz-imgproxy:
build:
context: ../at-mintel
dockerfile: apps/image-service/Dockerfile
restart: unless-stopped
networks:
- default
- infra
extra_hosts:
- "klz.localhost:host-gateway"
- "cms.klz.localhost:host-gateway"
- "host.docker.internal:host-gateway"
environment:
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY}
# explicitly map localhost, production and staging to bypass gatekeeper
IMGPROXY_URL_MAPPING: "https://staging.klz-cables.com:http://klz-app:3000,https://klz-cables.com:http://klz-app:3000,https://${TRAEFIK_HOST:-klz.localhost}:http://klz-app:3000,${DIRECTUS_URL}:http://klz-cms:8055,https://cms.klz-cables.com:http://klz-cms:8055"
IMGPROXY_LOG_LEVEL: debug
labels:
- "traefik.enable=true"
# Existing Local HTTP Router
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy.rule=Host(`img.${TRAEFIK_HOST:-klz.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy.entrypoints=web"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy.service=${PROJECT_NAME:-klz}-imgproxy-svc"
# NEW: Direct Public Staging Router for /_img (Bypasses Next.js rewrites)
# This fixes the Next.js URL-decoding bug on dynamic image proxy paths
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.rule=(Host(`${TRAEFIK_HOST:-klz.localhost}`) || Host(`staging.klz-cables.com`) || Host(`testing.klz-cables.com`)) && PathPrefix(`/_img`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.priority=99999"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.tls=${TRAEFIK_TLS:-false}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.service=${PROJECT_NAME:-klz}-imgproxy-svc"
- "traefik.http.services.${PROJECT_NAME:-klz}-imgproxy-svc.loadbalancer.server.port=8080"
- "traefik.http.routers.${PROJECT_NAME:-klz}-img.middlewares=${PROJECT_NAME:-klz}-img-strip"
- "traefik.http.middlewares.${PROJECT_NAME:-klz}-img-strip.stripprefix.prefixes=/_img"
# HTTPS router (staging/prod)
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.rule=Host(`img.${TRAEFIK_HOST:-klz.localhost}`)"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.tls=${TRAEFIK_TLS:-false}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
- "traefik.http.routers.${PROJECT_NAME:-klz}-imgproxy-secure.service=${PROJECT_NAME:-klz}-imgproxy-svc"
- "traefik.http.services.${PROJECT_NAME:-klz}-imgproxy-svc.loadbalancer.server.port=8080"
- "traefik.docker.network=infra"
- "caddy=http://img.${TRAEFIK_HOST:-klz.localhost}"
- "caddy.reverse_proxy={{upstreams 8080}}"
ports:
- "54322:5432"
networks:
default:
@@ -208,6 +81,5 @@ networks:
external: true
volumes:
directus-db-data:
external: true
name: klz-cablescom_directus-db-data
klz_db_data:
external: false