ai 'chat' is helping now
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m9s
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m9s
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
server {
|
server {
|
||||||
# Listen on port 80 for incoming HTTP requests.
|
# Listen on port 80 for incoming HTTP requests.
|
||||||
|
|
||||||
|
# Allow large file uploads (e.g., for flyers). This must be set here to prevent Nginx from rejecting large requests before they reach the Node.js backend.
|
||||||
|
client_max_body_size 100M;
|
||||||
|
|
||||||
# The root directory where your built application files are located.
|
# The root directory where your built application files are located.
|
||||||
# This matches the destination in your rsync command.
|
# This matches the destination in your rsync command.
|
||||||
root /var/www/flyer-crawler.projectium.com;
|
root /var/www/flyer-crawler.projectium.com;
|
||||||
@@ -11,6 +14,12 @@ server {
|
|||||||
# The domain name this configuration applies to.
|
# The domain name this configuration applies to.
|
||||||
server_name flyer-crawler.projectium.com;
|
server_name flyer-crawler.projectium.com;
|
||||||
|
|
||||||
|
# Deny access to all dotfiles
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
# This is the crucial part for a Single-Page Application (SPA).
|
# This is the crucial part for a Single-Page Application (SPA).
|
||||||
# 1. It first tries to serve the requested file ($uri).
|
# 1. It first tries to serve the requested file ($uri).
|
||||||
@@ -24,6 +33,13 @@ server {
|
|||||||
# It tells Nginx that any request starting with /api/ should be
|
# It tells Nginx that any request starting with /api/ should be
|
||||||
# forwarded to your Node.js server running on port 3001.
|
# forwarded to your Node.js server running on port 3001.
|
||||||
location /api/ {
|
location /api/ {
|
||||||
|
# Increase timeouts for long-running API requests, like AI processing.
|
||||||
|
# The default is 60s, which is often too short for AI image analysis.
|
||||||
|
# We'll set it to 300s (5 minutes) to be safe.
|
||||||
|
proxy_connect_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
|
||||||
# The trailing slash on the proxy_pass URL is crucial.
|
# The trailing slash on the proxy_pass URL is crucial.
|
||||||
# It tells Nginx to strip the `/api/` prefix from the request URI
|
# It tells Nginx to strip the `/api/` prefix from the request URI
|
||||||
# before passing it to the backend server.
|
# before passing it to the backend server.
|
||||||
@@ -55,8 +71,8 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/flyer-crawler.projectium.com/privkey.pem; # managed by Certbot
|
ssl_certificate_key /etc/letsencrypt/live/flyer-crawler.projectium.com/privkey.pem; # managed by Certbot
|
||||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
server {
|
server {
|
||||||
if ($host = flyer-crawler.projectium.com) {
|
if ($host = flyer-crawler.projectium.com) {
|
||||||
return 301 https://$host$request_uri;
|
return 301 https://$host$request_uri;
|
||||||
@@ -67,4 +83,6 @@ server {
|
|||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name flyer-crawler.projectium.com;
|
server_name flyer-crawler.projectium.com;
|
||||||
return 404; # managed by Certbot
|
return 404; # managed by Certbot
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { Router, Request, Response, NextFunction } from 'express';
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
import multer from 'multer';
|
import multer from 'multer';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
import passport from './passport';
|
import passport from './passport';
|
||||||
import { optionalAuth } from './passport';
|
import { optionalAuth } from './passport';
|
||||||
import * as db from '../services/db';
|
import * as db from '../services/db';
|
||||||
@@ -14,6 +15,14 @@ const router = Router();
|
|||||||
|
|
||||||
// --- Multer Configuration for File Uploads ---
|
// --- Multer Configuration for File Uploads ---
|
||||||
const storagePath = process.env.STORAGE_PATH || '/var/www/flyer-crawler.projectium.com/assets';
|
const storagePath = process.env.STORAGE_PATH || '/var/www/flyer-crawler.projectium.com/assets';
|
||||||
|
|
||||||
|
// Ensure the storage path exists at startup so multer can write files there.
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(storagePath, { recursive: true });
|
||||||
|
logger.debug(`AI upload storage path ready: ${storagePath}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`Failed to create storage path (${storagePath}). File uploads may fail.`, { error: err });
|
||||||
|
}
|
||||||
const diskStorage = multer.diskStorage({
|
const diskStorage = multer.diskStorage({
|
||||||
destination: function (req, file, cb) {
|
destination: function (req, file, cb) {
|
||||||
cb(null, storagePath);
|
cb(null, storagePath);
|
||||||
@@ -27,7 +36,19 @@ const diskStorage = multer.diskStorage({
|
|||||||
const memoryStorage = multer.memoryStorage();
|
const memoryStorage = multer.memoryStorage();
|
||||||
|
|
||||||
const uploadToDisk = multer({ storage: diskStorage });
|
const uploadToDisk = multer({ storage: diskStorage });
|
||||||
const uploadToMemory = multer({ storage: memoryStorage });
|
|
||||||
|
// Diagnostic middleware: log incoming AI route requests (headers and sizes)
|
||||||
|
router.use((req: Request, res: Response, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const contentType = req.headers['content-type'] || '';
|
||||||
|
const contentLength = req.headers['content-length'] || 'unknown';
|
||||||
|
const authPresent = !!req.headers['authorization'];
|
||||||
|
logger.debug('[API /ai] Incoming request', { method: req.method, url: req.originalUrl, contentType, contentLength, authPresent });
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Failed to log incoming AI request headers', { error: e });
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This endpoint processes a flyer using AI. It uses `optionalAuth` middleware to allow
|
* This endpoint processes a flyer using AI. It uses `optionalAuth` middleware to allow
|
||||||
|
|||||||
Reference in New Issue
Block a user