Compare commits
7 Commits
5fb73d57dd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 037794c4b7 | |||
| 06147dade4 | |||
| 08e16ce754 | |||
| df37f23270 | |||
| 503676dab5 | |||
| 52480b4f55 | |||
| 77d87e7be9 |
@@ -29,8 +29,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
rm -rf .next .turbo node_modules || true
|
rm -rf .next .turbo node_modules || true
|
||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
- name: 🧪 Parallel Checks
|
- name: 🧪 QA Checks
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||||
run: |
|
run: |
|
||||||
pnpm lint &
|
pnpm lint
|
||||||
pnpm build &
|
pnpm build
|
||||||
wait
|
|
||||||
|
|||||||
@@ -93,6 +93,15 @@ jobs:
|
|||||||
echo "short_sha=$SHORT_SHA"
|
echo "short_sha=$SHORT_SHA"
|
||||||
} >> "$GITHUB_OUTPUT"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
echo "--- DEBUG ---"
|
||||||
|
echo "TARGET: $TARGET"
|
||||||
|
echo "IMAGE_TAG: $IMAGE_TAG"
|
||||||
|
echo "ENV_FILE: $ENV_FILE"
|
||||||
|
echo "PRIMARY_HOST: $PRIMARY_HOST"
|
||||||
|
echo "TRAEFIK_RULE: $TRAEFIK_RULE"
|
||||||
|
echo "PROJECT_NAME: $PRJ-$TARGET"
|
||||||
|
echo "--- END DEBUG ---"
|
||||||
|
|
||||||
# ⏳ Wait for Upstream Packages/Images if Tagged
|
# ⏳ Wait for Upstream Packages/Images if Tagged
|
||||||
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
||||||
echo "🔎 Checking for @mintel dependencies in package.json..."
|
echo "🔎 Checking for @mintel dependencies in package.json..."
|
||||||
@@ -167,12 +176,16 @@ jobs:
|
|||||||
pnpm install --no-frozen-lockfile
|
pnpm install --no-frozen-lockfile
|
||||||
- name: 🧪 QA Checks
|
- name: 🧪 QA Checks
|
||||||
if: github.event.inputs.skip_checks != 'true'
|
if: github.event.inputs.skip_checks != 'true'
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||||
run: |
|
run: |
|
||||||
pnpm lint
|
pnpm lint
|
||||||
pnpm exec tsc --noEmit
|
pnpm exec tsc --noEmit
|
||||||
pnpm test run
|
pnpm test run
|
||||||
- name: 🏗️ Build Test
|
- name: 🏗️ Build Test
|
||||||
if: github.event.inputs.skip_checks != 'true'
|
if: github.event.inputs.skip_checks != 'true'
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||||
run: pnpm build
|
run: pnpm build
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
@@ -231,14 +244,7 @@ jobs:
|
|||||||
IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }}
|
IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }}
|
||||||
PROJECT_NAME: ${{ needs.prepare.outputs.project_name }}
|
PROJECT_NAME: ${{ needs.prepare.outputs.project_name }}
|
||||||
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }}
|
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }}
|
||||||
|
MINTEL_PRIVATE_TOKEN: ${{ secrets.MINTEL_PRIVATE_TOKEN }}
|
||||||
# Secrets mapping (Database & CMS)
|
|
||||||
PAYLOAD_SECRET: ${{ (needs.prepare.outputs.target == 'testing' && secrets.TESTING_PAYLOAD_SECRET) || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_PAYLOAD_SECRET) || secrets.PAYLOAD_SECRET || secrets.MINTEL_PRIVATE_TOKEN || secrets.DIRECTUS_SECRET || vars.PAYLOAD_SECRET || 'you-need-to-set-a-payload-secret' }}
|
|
||||||
DATABASE_URI: ${{ (needs.prepare.outputs.target == 'testing' && secrets.TESTING_DATABASE_URI) || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DATABASE_URI) || secrets.DATABASE_URI || vars.DATABASE_URI }}
|
|
||||||
POSTGRES_DB: ${{ secrets.POSTGRES_DB || vars.POSTGRES_DB || 'payload' }}
|
|
||||||
POSTGRES_USER: ${{ secrets.POSTGRES_USER || vars.POSTGRES_USER || 'directus' }}
|
|
||||||
POSTGRES_PASSWORD: ${{ (needs.prepare.outputs.target == 'testing' && secrets.TESTING_POSTGRES_PASSWORD) || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_POSTGRES_PASSWORD) || secrets.POSTGRES_PASSWORD || vars.POSTGRES_PASSWORD || 'directus' }}
|
|
||||||
|
|
||||||
|
|
||||||
# Secrets mapping (Mail)
|
# Secrets mapping (Mail)
|
||||||
MAIL_HOST: ${{ secrets.SMTP_HOST || vars.SMTP_HOST }}
|
MAIL_HOST: ${{ secrets.SMTP_HOST || vars.SMTP_HOST }}
|
||||||
@@ -296,13 +302,6 @@ jobs:
|
|||||||
PROJECT_COLOR=$PROJECT_COLOR
|
PROJECT_COLOR=$PROJECT_COLOR
|
||||||
LOG_LEVEL=$LOG_LEVEL
|
LOG_LEVEL=$LOG_LEVEL
|
||||||
|
|
||||||
# Database & Payload
|
|
||||||
DATABASE_URI=\${DATABASE_URI:-postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@mb-grid-db:5432/$POSTGRES_DB}
|
|
||||||
PAYLOAD_SECRET=${PAYLOAD_SECRET:-you-need-to-set-a-payload-secret}
|
|
||||||
POSTGRES_DB=$POSTGRES_DB
|
|
||||||
POSTGRES_USER=$POSTGRES_USER
|
|
||||||
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
|
|
||||||
|
|
||||||
# Mail
|
# Mail
|
||||||
MAIL_HOST=$MAIL_HOST
|
MAIL_HOST=$MAIL_HOST
|
||||||
MAIL_PORT=$MAIL_PORT
|
MAIL_PORT=$MAIL_PORT
|
||||||
@@ -351,28 +350,6 @@ jobs:
|
|||||||
ssh root@alpha.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' pull"
|
ssh root@alpha.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' pull"
|
||||||
ssh root@alpha.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' up -d --remove-orphans"
|
ssh root@alpha.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' up -d --remove-orphans"
|
||||||
|
|
||||||
# Apply Payload Migrations using the target app container's programmatic endpoint
|
|
||||||
ssh root@alpha.mintel.me "cd $SITE_DIR && echo '→ Waiting for DB and Running Payload Migrations...' && \
|
|
||||||
for i in {1..15}; do \
|
|
||||||
echo \"Attempt \$i...\"; \
|
|
||||||
docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' exec -T mb-grid-app sh -c 'curl -s -i -X POST -H \"Authorization: Bearer \$PAYLOAD_SECRET\" http://localhost:3000/api/payload/migrate' > /tmp/migrate_res 2>&1; \
|
|
||||||
if grep -q \"200 OK\" /tmp/migrate_res; then \
|
|
||||||
echo \"✅ Migrations successful!\"; \
|
|
||||||
cat /tmp/migrate_res; \
|
|
||||||
break; \
|
|
||||||
else \
|
|
||||||
echo \"❌ Attempt \$i failed. Response:\"; \
|
|
||||||
cat /tmp/migrate_res; \
|
|
||||||
if [ \$i -eq 15 ]; then \
|
|
||||||
echo \"❌ Migration failed after 15 attempts! Dumping app logs...\"; \
|
|
||||||
docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' logs --tail 100 mb-grid-app; \
|
|
||||||
exit 1; \
|
|
||||||
fi; \
|
|
||||||
echo \"⏳ Retrying in 5s...\"; \
|
|
||||||
sleep 5; \
|
|
||||||
fi; \
|
|
||||||
done"
|
|
||||||
|
|
||||||
ssh root@alpha.mintel.me "docker system prune -f --filter 'until=24h'"
|
ssh root@alpha.mintel.me "docker system prune -f --filter 'until=24h'"
|
||||||
|
|
||||||
- name: 🧹 Post-Deploy Cleanup (Runner)
|
- name: 🧹 Post-Deploy Cleanup (Runner)
|
||||||
@@ -409,41 +386,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pnpm store prune
|
pnpm store prune
|
||||||
pnpm install --no-frozen-lockfile
|
pnpm install --no-frozen-lockfile
|
||||||
- name: 📦 Cache APT Packages
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: /var/cache/apt/archives
|
|
||||||
key: apt-cache-${{ runner.os }}-${{ runner.arch }}-chromium
|
|
||||||
|
|
||||||
- name: 💾 Cache Chromium
|
|
||||||
id: cache-chromium
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: /usr/bin/chromium
|
|
||||||
key: ${{ runner.os }}-chromium-native-${{ hashFiles('package.json') }}
|
|
||||||
|
|
||||||
- name: 🔍 Install Chromium (Native & ARM64)
|
|
||||||
if: steps.cache-chromium.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
rm -f /etc/apt/apt.conf.d/docker-clean
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y gnupg wget ca-certificates
|
|
||||||
OS_ID=$(. /etc/os-release && echo $ID)
|
|
||||||
CODENAME=$(. /etc/os-release && echo $VERSION_CODENAME)
|
|
||||||
if [ "$OS_ID" = "debian" ]; then
|
|
||||||
apt-get install -y chromium
|
|
||||||
else
|
|
||||||
mkdir -p /etc/apt/keyrings
|
|
||||||
KEY_ID="82BB6851C64F6880"
|
|
||||||
wget -qO- "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x$KEY_ID" | gpg --dearmor > /etc/apt/keyrings/xtradeb.gpg
|
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/xtradeb.gpg] http://ppa.launchpad.net/xtradeb/apps/ubuntu $CODENAME main" > /etc/apt/sources.list.d/xtradeb-ppa.list
|
|
||||||
printf "Package: *\nPin: release o=LP-PPA-xtradeb-apps\nPin-Priority: 1001\n" > /etc/apt/preferences.d/xtradeb
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y --allow-downgrades chromium
|
|
||||||
fi
|
|
||||||
[ -f /usr/bin/chromium ] && ln -sf /usr/bin/chromium /usr/bin/google-chrome
|
|
||||||
[ -f /usr/bin/chromium ] && ln -sf /usr/bin/chromium /usr/bin/chromium-browser
|
|
||||||
|
|
||||||
# ── Critical Smoke Tests (MUST pass) ──────────────────────────────────
|
# ── Critical Smoke Tests (MUST pass) ──────────────────────────────────
|
||||||
- name: 🏥 CMS Deep Health Check
|
- name: 🏥 CMS Deep Health Check
|
||||||
env:
|
env:
|
||||||
@@ -465,14 +407,6 @@ jobs:
|
|||||||
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN }}
|
||||||
|
|
||||||
- name: 📝 E2E Form Submission Test
|
|
||||||
if: always() && steps.deps.outcome == 'success'
|
|
||||||
env:
|
|
||||||
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }}
|
|
||||||
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || vars.GATEKEEPER_PASSWORD }}
|
|
||||||
PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium
|
|
||||||
run: pnpm test run
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
# JOB 6: Notifications
|
# JOB 6: Notifications
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ ENV UMAMI_API_ENDPOINT=$UMAMI_API_ENDPOINT
|
|||||||
ENV NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID
|
ENV NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID
|
||||||
ENV SKIP_RUNTIME_ENV_VALIDATION=true
|
ENV SKIP_RUNTIME_ENV_VALIDATION=true
|
||||||
ENV CI=true
|
ENV CI=true
|
||||||
|
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
|
|
||||||
# Enable pnpm
|
# Enable pnpm
|
||||||
RUN corepack enable && corepack prepare pnpm@10.3.0 --activate
|
RUN corepack enable && corepack prepare pnpm@10.3.0 --activate
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default async function Page({ params }: PageProps) {
|
|||||||
try {
|
try {
|
||||||
const mdx = await import(`@/content/${locale}/avb.mdx`);
|
const mdx = await import(`@/content/${locale}/avb.mdx`);
|
||||||
Content = mdx.default;
|
Content = mdx.default;
|
||||||
} catch (e) {
|
} catch {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default async function Page({ params }: PageProps) {
|
|||||||
try {
|
try {
|
||||||
const mdx = await import(`@/content/${locale}/datenschutz.mdx`);
|
const mdx = await import(`@/content/${locale}/datenschutz.mdx`);
|
||||||
Content = mdx.default;
|
Content = mdx.default;
|
||||||
} catch (e) {
|
} catch {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default async function Page({ params }: PageProps) {
|
|||||||
try {
|
try {
|
||||||
const mdx = await import(`@/content/${locale}/impressum.mdx`);
|
const mdx = await import(`@/content/${locale}/impressum.mdx`);
|
||||||
Content = mdx.default;
|
Content = mdx.default;
|
||||||
} catch (e) {
|
} catch {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
import HomeContent from "@/components/HomeContent";
|
import HomeContent from "@/components/HomeContent";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -21,7 +21,7 @@ export default async function Page({ params }: PageProps) {
|
|||||||
try {
|
try {
|
||||||
const mdx = await import(`@/content/${locale}/index.mdx`);
|
const mdx = await import(`@/content/${locale}/index.mdx`);
|
||||||
Content = mdx.default;
|
Content = mdx.default;
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Fallback if MDX is not yet created for this locale
|
// Fallback if MDX is not yet created for this locale
|
||||||
return <HomeContent />;
|
return <HomeContent />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default async function Page({ params }: PageProps) {
|
|||||||
try {
|
try {
|
||||||
const mdx = await import(`@/content/${locale}/about.mdx`);
|
const mdx = await import(`@/content/${locale}/about.mdx`);
|
||||||
Content = mdx.default;
|
Content = mdx.default;
|
||||||
} catch (e) {
|
} catch {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,11 @@ export default function Contact() {
|
|||||||
<div className="absolute inset-0 border-2 border-accent/0 group-hover:border-accent/20 transition-all duration-500 z-10 pointer-events-none rounded-[2.5rem]" />
|
<div className="absolute inset-0 border-2 border-accent/0 group-hover:border-accent/20 transition-all duration-500 z-10 pointer-events-none rounded-[2.5rem]" />
|
||||||
<iframe
|
<iframe
|
||||||
className="w-full h-full border-0"
|
className="w-full h-full border-0"
|
||||||
title={t("info.mapTitle") || "Location Map"}
|
title={
|
||||||
|
t.has("info.mapTitle")
|
||||||
|
? t("info.mapTitle")
|
||||||
|
: "Location Map"
|
||||||
|
}
|
||||||
src="https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552"
|
src="https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
10
lib/env.ts
10
lib/env.ts
@@ -24,14 +24,20 @@ const envExtension = {
|
|||||||
/**
|
/**
|
||||||
* Full schema including Mintel base and refinements
|
* Full schema including Mintel base and refinements
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
export const envSchema = withMintelRefinements(
|
export const envSchema = withMintelRefinements(
|
||||||
z.object(mintelEnvSchema).extend(envExtension),
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(z as any).object(mintelEnvSchema).extend(envExtension) as any,
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validated environment object.
|
* Validated environment object.
|
||||||
*/
|
*/
|
||||||
export const env = validateMintelEnv(envExtension);
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export const env = validateMintelEnv(envExtension) as any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For legacy compatibility with existing code.
|
* For legacy compatibility with existing code.
|
||||||
|
|||||||
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/dev/types/routes.d.ts";
|
import "./.next/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mb-grid-solutions.com",
|
"name": "mb-grid-solutions.com",
|
||||||
"version": "1.3.22",
|
"version": "1.4.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@10.18.3",
|
"packageManager": "pnpm@10.18.3",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# ────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Payload CMS Database Backup
|
|
||||||
# Creates a timestamped pg_dump of the Payload Postgres database.
|
|
||||||
# Usage: npm run backup:db
|
|
||||||
# ────────────────────────────────────────────────────────────────────────────
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Load environment variables
|
|
||||||
if [ -f .env ]; then
|
|
||||||
set -a; source .env; set +a
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Fallback for local development if not in .env
|
|
||||||
DB_NAME="${POSTGRES_DB:-payload}"
|
|
||||||
DB_USER="${POSTGRES_USER:-postgres}"
|
|
||||||
# For production, we need the container name.
|
|
||||||
# We'll use the PROJECT_NAME to find it if possible, otherwise use a default.
|
|
||||||
PROJECT_NAME="${PROJECT_NAME:-mb-grid-solutions-production}"
|
|
||||||
DB_CONTAINER="${DB_CONTAINER:-${PROJECT_NAME}-mb-grid-db-1}"
|
|
||||||
BACKUP_DIR="./backups"
|
|
||||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
|
||||||
BACKUP_FILE="${BACKUP_DIR}/payload_${TIMESTAMP}.sql.gz"
|
|
||||||
|
|
||||||
# Ensure backup directory exists
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
|
|
||||||
# Check if container is running
|
|
||||||
if ! docker ps --format '{{.Names}}' | grep -q "$DB_CONTAINER"; then
|
|
||||||
echo "❌ Database container '$DB_CONTAINER' is not running."
|
|
||||||
echo " Check your docker-compose status."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "📦 Backing up Payload database..."
|
|
||||||
echo " Container: $DB_CONTAINER"
|
|
||||||
echo " Database: $DB_NAME"
|
|
||||||
echo " Output: $BACKUP_FILE"
|
|
||||||
|
|
||||||
# Run pg_dump inside the container and compress
|
|
||||||
# We use directus as user for now if we haven't fully switched to postgres user in all environments
|
|
||||||
# But the script should be consistent with the environment.
|
|
||||||
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$DB_NAME" --clean --if-exists | gzip > "$BACKUP_FILE"
|
|
||||||
|
|
||||||
# Show result
|
|
||||||
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
|
||||||
echo ""
|
|
||||||
echo "✅ Backup complete: $BACKUP_FILE ($SIZE)"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Show existing backups
|
|
||||||
echo "📋 Available backups:"
|
|
||||||
ls -lh "$BACKUP_DIR"/*.sql.gz 2>/dev/null | awk '{print " " $NF " (" $5 ")"}'
|
|
||||||
Reference in New Issue
Block a user