Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
071fba540d | ||
|
|
04fb328850 | ||
|
|
84da0e57e5 | ||
|
|
ad3708e29e | ||
|
|
8b0cd6028b | ||
|
|
94627ba20e | ||
|
|
a782fdfe53 | ||
|
|
f17a8c8c36 | ||
|
|
adbb2419b7 | ||
|
|
5809291741 | ||
|
|
e263e7f25c | ||
|
|
1fee592ee7 | ||
|
|
ff73aa7c4e | ||
|
|
26f6ddc098 |
@@ -394,10 +394,11 @@ jobs:
|
||||
run: |
|
||||
pnpm store prune
|
||||
pnpm install --no-frozen-lockfile
|
||||
- name: 🌐 Install Chrome & Dependencies
|
||||
run: |
|
||||
apt-get update && apt-get install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 libgbm1 libasound2t64 libpango-1.0-0 libcairo2
|
||||
npx puppeteer browsers install chrome
|
||||
- name: Setup Chrome
|
||||
id: setup-chrome
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
with:
|
||||
install-dependencies: true
|
||||
|
||||
# ── Minimalist Smoke Test ──────────────────────────────────────────
|
||||
- name: 🌐 Smoke Test (Essential Flow)
|
||||
@@ -405,6 +406,7 @@ jobs:
|
||||
env:
|
||||
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }}
|
||||
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }}
|
||||
PUPPETEER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
run: npx tsx scripts/smoke.ts
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -2,10 +2,7 @@ node_modules
|
||||
.next
|
||||
.DS_Store
|
||||
.pnpm-store
|
||||
public/uploads
|
||||
public/media
|
||||
|
||||
# Lighthouse CI
|
||||
# lighthouse CI
|
||||
.lighthouseci/
|
||||
lighthouserc.cjs
|
||||
.lighthouserc.json
|
||||
|
||||
@@ -59,10 +59,10 @@ RUN pnpm build
|
||||
FROM node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Install curl for health checks
|
||||
RUN apk add --no-cache curl
|
||||
# Install dependencies for health checks and system compatibility
|
||||
RUN apk add --no-cache libc6-compat curl
|
||||
|
||||
# Create nextjs user and group (standardized in runtime image but ensuring local ownership)
|
||||
# Create nextjs user and group
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs && \
|
||||
chown -R nextjs:nodejs /app
|
||||
@@ -73,10 +73,10 @@ ENV HOSTNAME="0.0.0.0"
|
||||
ENV PORT=3000
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Copy standalone output and static files
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
# Copy standalone output
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
# Copy public and static files
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/cache ./.next/cache
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -45,6 +45,28 @@ export async function sendContactFormAction(formData: FormData) {
|
||||
email,
|
||||
});
|
||||
|
||||
// 1.5. Simple Fail-Safe Backup to Disk
|
||||
// To ensure leads are never lost if email fails or Gotify is down, we append them to a local JSON Lines file.
|
||||
try {
|
||||
const fs = await import('fs');
|
||||
const path = await import('path');
|
||||
const backupDir = path.join(process.cwd(), '.data');
|
||||
if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
|
||||
|
||||
const backupFile = path.join(backupDir, 'leads-backup.jsonl');
|
||||
const leadData = {
|
||||
timestamp: new Date().toISOString(),
|
||||
name,
|
||||
email,
|
||||
productName,
|
||||
message,
|
||||
};
|
||||
fs.appendFileSync(backupFile, JSON.stringify(leadData) + '\\n');
|
||||
logger.info('Successfully saved lead to local backup file', { backupFile });
|
||||
} catch (backupError) {
|
||||
logger.error('Failed to write to local leads backup', { error: String(backupError) });
|
||||
}
|
||||
|
||||
// 2. Send Emails
|
||||
logger.info('Sending branded emails', { email, productName });
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ services:
|
||||
environment:
|
||||
POSTGRES_URI: postgres://${PAYLOAD_DB_USER:-payload}:${PAYLOAD_DB_PASSWORD:-payload}@klz-db:5432/${PAYLOAD_DB_NAME:-payload}
|
||||
PAYLOAD_SECRET: ${PAYLOAD_SECRET:-fallback-secret-for-production-needs-change}
|
||||
volumes:
|
||||
- klz_media_data:/app/public/media
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# HTTP ⇒ HTTPS redirect
|
||||
|
||||
@@ -20,12 +20,13 @@ export default async function middleware(request: NextRequest) {
|
||||
|
||||
if (
|
||||
isServerAction ||
|
||||
pathname.startsWith('/admin') ||
|
||||
pathname.startsWith('/api') ||
|
||||
pathname.startsWith('/stats') ||
|
||||
pathname.startsWith('/errors') ||
|
||||
pathname.startsWith('/health') ||
|
||||
pathname.startsWith('/uploads') ||
|
||||
pathname.startsWith('/media') ||
|
||||
pathname.startsWith('/_next/image') ||
|
||||
pathname.includes('/api/og') ||
|
||||
pathname.includes('opengraph-image') ||
|
||||
pathname.endsWith('sitemap.xml') ||
|
||||
@@ -61,7 +62,7 @@ export default async function middleware(request: NextRequest) {
|
||||
if (['GET', 'HEAD'].includes(request.method)) {
|
||||
// Clone headers to ensure all Next.js internal headers (like router state) are preserved
|
||||
const clonedHeaders = new Headers(request.headers);
|
||||
|
||||
|
||||
effectiveRequest = new NextRequest(urlObj, {
|
||||
headers: clonedHeaders,
|
||||
method: request.method,
|
||||
|
||||
@@ -402,8 +402,9 @@ const nextConfig = {
|
||||
];
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
formats: ['image/webp'],
|
||||
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
||||
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
"prepare": "husky",
|
||||
"preinstall": "npx only-allow pnpm"
|
||||
},
|
||||
"version": "2.3.22-rc.8",
|
||||
"version": "2.3.22-rc.19",
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"@parcel/watcher",
|
||||
|
||||
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 668 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 278 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 278 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 49 KiB |