2 Commits

Author SHA1 Message Date
16916654c0 feat: add database backup script and npm command
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Failing after 1m17s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Failing after 3m31s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-03-11 12:36:34 +01:00
6daf5c66a8 refactor: remove all legacy directus environment variables and standardize on postgres
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 5m14s
Build & Deploy / 🏗️ Build (push) Successful in 7m26s
Build & Deploy / 🚀 Deploy (push) Failing after 32s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-03-11 12:22:57 +01:00
9 changed files with 151 additions and 16 deletions

View File

@@ -225,9 +225,9 @@ jobs:
# 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.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 }}
DIRECTUS_DB_NAME: ${{ secrets.DIRECTUS_DB_NAME || vars.DIRECTUS_DB_NAME || 'directus' }}
DIRECTUS_DB_USER: ${{ secrets.DIRECTUS_DB_USER || vars.DIRECTUS_DB_USER || 'directus' }}
DIRECTUS_DB_PASSWORD: ${{ (needs.prepare.outputs.target == 'testing' && secrets.TESTING_DIRECTUS_DB_PASSWORD) || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_DB_PASSWORD) || secrets.DIRECTUS_DB_PASSWORD || vars.DIRECTUS_DB_PASSWORD || 'directus' }}
POSTGRES_DB: ${{ secrets.POSTGRES_DB || vars.POSTGRES_DB || 'payload' }}
POSTGRES_USER: ${{ secrets.POSTGRES_USER || vars.POSTGRES_USER || 'postgres' }}
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 || 'postgres' }}
# Secrets mapping (Mail)
@@ -285,11 +285,11 @@ jobs:
LOG_LEVEL=$LOG_LEVEL
# Database & Payload
DATABASE_URI=\${DATABASE_URI:-postgresql://$DIRECTUS_DB_USER:$DIRECTUS_DB_PASSWORD@mb-grid-db:5432/$DIRECTUS_DB_NAME}
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}
DIRECTUS_DB_NAME=$DIRECTUS_DB_NAME
DIRECTUS_DB_USER=$DIRECTUS_DB_USER
DIRECTUS_DB_PASSWORD=$DIRECTUS_DB_PASSWORD
POSTGRES_DB=$POSTGRES_DB
POSTGRES_USER=$POSTGRES_USER
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
# Mail
MAIL_HOST=$MAIL_HOST

View File

@@ -8,7 +8,7 @@ services:
- .:/app
environment:
NODE_ENV: development
DATABASE_URI: postgresql://directus:directus@mb-grid-db:5432/directus
DATABASE_URI: postgresql://postgres:postgres@mb-grid-db:5432/payload
# Build / dependency installation
NPM_TOKEN: ${NPM_TOKEN}
CI: 'true'

View File

@@ -89,9 +89,9 @@ services:
env_file:
- ${ENV_FILE:-.env}
environment:
POSTGRES_DB: ${DIRECTUS_DB_NAME:-directus}
POSTGRES_USER: ${DIRECTUS_DB_USER:-directus}
POSTGRES_PASSWORD: ${DIRECTUS_DB_PASSWORD:-directus}
POSTGRES_DB: ${POSTGRES_DB:-payload}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
volumes:
- mb-grid-db-data:/var/lib/postgresql/data

View File

@@ -17,9 +17,6 @@ import {
const envExtension = {
// Project specific overrides or additions
AUTH_COOKIE_NAME: z.string().default("mb_gatekeeper_session"),
INFRA_DIRECTUS_URL: z.string().url().optional(),
INFRA_DIRECTUS_TOKEN: z.string().optional(),
};
/**

View File

@@ -16,7 +16,8 @@
"pagespeed:test": "mintel pagespeed test",
"check:http": "tsx ./scripts/check-http.ts",
"check:apis": "tsx ./scripts/check-apis.ts",
"check:locale": "tsx ./scripts/check-locale.ts"
"check:locale": "tsx ./scripts/check-locale.ts",
"backup:db": "bash ./scripts/backup-db.sh"
},
"keywords": [],
"author": "",
@@ -35,6 +36,8 @@
"@payloadcms/ui": "^3.77.0",
"@react-email/components": "^1.0.8",
"@sentry/nextjs": "^10.38.0",
"bcrypt": "^6.0.0",
"bcryptjs": "^3.0.3",
"framer-motion": "^12.29.2",
"graphql": "^16.13.0",
"lucide-react": "^0.562.0",

33
pnpm-lock.yaml generated
View File

@@ -44,6 +44,12 @@ importers:
'@sentry/nextjs':
specifier: ^10.38.0
version: 10.38.0(@opentelemetry/context-async-hooks@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(react@19.2.4)(webpack@5.104.1(esbuild@0.25.12))
bcrypt:
specifier: ^6.0.0
version: 6.0.0
bcryptjs:
specifier: ^3.0.3
version: 3.0.3
framer-motion:
specifier: ^12.29.2
version: 12.30.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -3482,6 +3488,14 @@ packages:
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
hasBin: true
bcrypt@6.0.0:
resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==}
engines: {node: '>= 18'}
bcryptjs@3.0.3:
resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==}
hasBin: true
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
@@ -5453,6 +5467,10 @@ packages:
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
node-addon-api@8.6.0:
resolution: {integrity: sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==}
engines: {node: ^18 || ^20 || >= 21}
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@@ -5462,6 +5480,10 @@ packages:
encoding:
optional: true
node-gyp-build@4.8.4:
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
hasBin: true
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
@@ -10757,6 +10779,13 @@ snapshots:
baseline-browser-mapping@2.9.19: {}
bcrypt@6.0.0:
dependencies:
node-addon-api: 8.6.0
node-gyp-build: 4.8.4
bcryptjs@3.0.3: {}
bidi-js@1.0.3:
dependencies:
require-from-string: 2.0.2
@@ -12986,10 +13015,14 @@ snapshots:
node-addon-api@7.1.1: {}
node-addon-api@8.6.0: {}
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
node-gyp-build@4.8.4: {}
node-releases@2.0.27: {}
nodemailer@7.0.12: {}

53
scripts/backup-db.sh Normal file
View File

@@ -0,0 +1,53 @@
#!/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 ")"}'

49
scripts/create-admin.ts Normal file
View File

@@ -0,0 +1,49 @@
import { getPayload } from "payload";
import config from "./src/payload/payload.config";
const createAdmin = async () => {
const payload = await getPayload({ config });
const email = "marc@mintel.me";
const password = "Tim300493.";
console.log(`Creating/Updating admin: ${email}`);
try {
// Check if user exists
const users = await payload.find({
collection: "users",
where: {
email: {
equals: email,
},
},
});
if (users.totalDocs > 0) {
console.log("User already exists. Updating password.");
await payload.update({
collection: "users",
id: users.docs[0].id,
data: {
password,
},
});
} else {
await payload.create({
collection: "users",
data: {
email,
password,
},
});
console.log("Admin user created successfully.");
}
} catch (error) {
console.error("Error creating admin:", error);
process.exit(1);
}
process.exit(0);
};
createAdmin();

View File

@@ -46,7 +46,7 @@ export default buildConfig({
connectionString:
process.env.DATABASE_URI ||
process.env.POSTGRES_URI ||
`postgresql://${process.env.DIRECTUS_DB_USER || "directus"}:${process.env.DIRECTUS_DB_PASSWORD || "directus"}@127.0.0.1:5432/${process.env.DIRECTUS_DB_NAME || "directus"}`,
`postgresql://${process.env.POSTGRES_USER || "postgres"}:${process.env.POSTGRES_PASSWORD || "postgres"}@127.0.0.1:5432/${process.env.POSTGRES_DB || "payload"}`,
},
prodMigrations: migrations,
}),