diff --git a/attached_assets/Pasted--status-500-message-connect-ECONNREFUSED-172-20-0-10-443-error-ErrorEvent--1754925087618_1754925087618.txt b/attached_assets/Pasted--status-500-message-connect-ECONNREFUSED-172-20-0-10-443-error-ErrorEvent--1754925087618_1754925087618.txt new file mode 100644 index 0000000..975f022 --- /dev/null +++ b/attached_assets/Pasted--status-500-message-connect-ECONNREFUSED-172-20-0-10-443-error-ErrorEvent--1754925087618_1754925087618.txt @@ -0,0 +1,199 @@ + status: 500, + + message: 'connect ECONNREFUSED 172.20.0.10:443', + + error: ErrorEvent { + + [Symbol(kTarget)]: WebSocket { + + _events: [Object: null prototype], + + _eventsCount: 4, + + _maxListeners: undefined, + + _binaryType: 'arraybuffer', + + _closeCode: 1006, + + _closeFrameReceived: false, + + _closeFrameSent: false, + + _closeMessage: , + + _closeTimer: null, + + _errorEmitted: true, + + _extensions: {}, + + _paused: false, + + _protocol: '', + + _readyState: 3, + + _receiver: null, + + _sender: null, + + _socket: null, + + _bufferedAmount: 0, + + _isServer: false, + + _redirects: 0, + + _autoPong: true, + + _url: 'wss://logiflow-db/v2', + + _req: null, + + [Symbol(shapeMode)]: false, + + [Symbol(kCapture)]: false + + }, + + [Symbol(kType)]: 'error', + + [Symbol(kError)]: Error: connect ECONNREFUSED 172.20.0.10:443 + + at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1611:16) { + + errno: -111, + + code: 'ECONNREFUSED', + + syscall: 'connect', + + address: '172.20.0.10', + + port: 443 + + }, + + [Symbol(kMessage)]: 'connect ECONNREFUSED 172.20.0.10:443' + + } + +} + +POST /api/login 500 in 9ms + +Error: connect ECONNREFUSED 172.20.0.10:443 + + at file:///app/node_modules/@neondatabase/serverless/index.mjs:1345:74 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async NeonPreparedQuery.execute (file:///app/node_modules/drizzle-orm/neon-serverless/session.js:76:20) + + at async DatabaseStorage.getUserByUsername (file:///app/dist/index.js:893:20) + + at async Strategy._verify (file:///app/dist/index.js:2461:24) + +Server error: { + + status: 500, + + message: 'connect ECONNREFUSED 172.20.0.10:443', + + error: ErrorEvent { + + [Symbol(kTarget)]: WebSocket { + + _events: [Object: null prototype], + + _eventsCount: 4, + + _maxListeners: undefined, + + _binaryType: 'arraybuffer', + + _closeCode: 1006, + + _closeFrameReceived: false, + + _closeFrameSent: false, + + _closeMessage: , + + _closeTimer: null, + + _errorEmitted: true, + + _extensions: {}, + + _paused: false, + + _protocol: '', + + _readyState: 3, + + _receiver: null, + + _sender: null, + + _socket: null, + + _bufferedAmount: 0, + + _isServer: false, + + _redirects: 0, + + _autoPong: true, + + _url: 'wss://logiflow-db/v2', + + _req: null, + + [Symbol(shapeMode)]: false, + + [Symbol(kCapture)]: false + + }, + + [Symbol(kType)]: 'error', + + [Symbol(kError)]: Error: connect ECONNREFUSED 172.20.0.10:443 + + at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1611:16) { + + errno: -111, + + code: 'ECONNREFUSED', + + syscall: 'connect', + + address: '172.20.0.10', + + port: 443 + + }, + + [Symbol(kMessage)]: 'connect ECONNREFUSED 172.20.0.10:443' + + } + +} + +POST /api/login 500 in 23ms + +Error: connect ECONNREFUSED 172.20.0.10:443 + + at file:///app/node_modules/@neondatabase/serverless/index.mjs:1345:74 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async NeonPreparedQuery.execute (file:///app/node_modules/drizzle-orm/neon-serverless/session.js:76:20) + + at async DatabaseStorage.getUserByUsername (file:///app/dist/index.js:893:20) + + at async Strategy._verify (file:///app/dist/index.js:2461:24) + +HEAD /api/health 200 in 1ms \ No newline at end of file diff --git a/attached_assets/{6B8A9306-D258-4800-A65A-86DC1D0A236C}_1754924926047.png b/attached_assets/{6B8A9306-D258-4800-A65A-86DC1D0A236C}_1754924926047.png new file mode 100644 index 0000000..ed0066a Binary files /dev/null and b/attached_assets/{6B8A9306-D258-4800-A65A-86DC1D0A236C}_1754924926047.png differ diff --git a/server/db.production.ts b/server/db.production.ts new file mode 100644 index 0000000..accea2f --- /dev/null +++ b/server/db.production.ts @@ -0,0 +1,39 @@ +import { Pool } from 'pg'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import * as schema from "@shared/schema"; + +console.log('🐳 PRODUCTION: Configuring standard PostgreSQL database'); + +if (!process.env.DATABASE_URL) { + throw new Error("DATABASE_URL must be set for production"); +} + +// Log connection details (without password) +const dbUrl = new URL(process.env.DATABASE_URL); +console.log('🐳 Database connection:', { + host: dbUrl.hostname, + port: dbUrl.port, + database: dbUrl.pathname.slice(1), + user: dbUrl.username +}); + +export const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + ssl: false, // No SSL for local Docker + max: 20, + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 10000, +}); + +export const db = drizzle({ client: pool, schema }); + +// Test connection +pool.on('connect', () => { + console.log('✅ PostgreSQL connection established'); +}); + +pool.on('error', (err) => { + console.error('❌ PostgreSQL connection error:', err); +}); + +console.log('✅ Production PostgreSQL database configured'); \ No newline at end of file diff --git a/server/db.ts b/server/db.ts index 7ca3d56..0071107 100644 --- a/server/db.ts +++ b/server/db.ts @@ -1,15 +1,62 @@ -import { Pool, neonConfig } from '@neondatabase/serverless'; -import { drizzle } from 'drizzle-orm/neon-serverless'; -import ws from "ws"; import * as schema from "@shared/schema"; -neonConfig.webSocketConstructor = ws; +// Simple environment detection +const isProduction = process.env.NODE_ENV === 'production'; +const dbUrl = process.env.DATABASE_URL; -if (!process.env.DATABASE_URL) { - throw new Error( - "DATABASE_URL must be set. Did you forget to provision a database?", - ); +console.log('🔗 Database initialization:', { + NODE_ENV: process.env.NODE_ENV, + isProduction, + hasDbUrl: !!dbUrl, + dbHost: dbUrl ? new URL(dbUrl).hostname : 'none' +}); + +let db: any; +let pool: any; + +if (isProduction && dbUrl && (dbUrl.includes('logiflow-db') || dbUrl.includes('localhost') || dbUrl.includes('127.0.0.1'))) { + // Standard PostgreSQL for production Docker + console.log('🐳 PRODUCTION: Using standard PostgreSQL'); + const { Pool } = await import('pg'); + const { drizzle } = await import('drizzle-orm/node-postgres'); + + pool = new Pool({ + connectionString: dbUrl, + ssl: false, + max: 10, + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 5000, + }); + + db = drizzle({ client: pool, schema }); + + // Test connection + try { + await pool.connect().then(client => { + console.log('✅ PostgreSQL connection test successful'); + client.release(); + }); + } catch (error) { + console.error('❌ PostgreSQL connection test failed:', error); + } +} else { + // Fallback: use Neon for development (but will be overridden by MemStorage) + console.log('🔧 DEV: Using Neon (fallback, will use MemStorage)'); + const { Pool, neonConfig } = await import('@neondatabase/serverless'); + const { drizzle } = await import('drizzle-orm/neon-serverless'); + const ws = await import('ws'); + + neonConfig.webSocketConstructor = ws.default; + + if (dbUrl) { + pool = new Pool({ connectionString: dbUrl }); + db = drizzle({ client: pool, schema }); + } else { + // Create dummy instances for development + pool = null; + db = null; + console.log('🔧 DEV: No DATABASE_URL, using MemStorage'); + } } -export const pool = new Pool({ connectionString: process.env.DATABASE_URL }); -export const db = drizzle({ client: pool, schema }); \ No newline at end of file +export { db, pool }; \ No newline at end of file diff --git a/server/index.production.ts b/server/index.production.ts index 9020385..8e5743a 100644 --- a/server/index.production.ts +++ b/server/index.production.ts @@ -1,10 +1,12 @@ import express, { type Request, Response, NextFunction } from "express"; import { createServer, type Server } from "http"; -import { storage } from "./storage.js"; -import { setupLocalAuth, requireAuth } from "./localAuth.production.js"; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; +// Database will be configured in storage.js +import { storage } from "./storage.js"; +import { setupLocalAuth, requireAuth } from "./localAuth.production.js"; + // Get directory paths const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/server/storage.ts b/server/storage.ts index 32b4fce..f341168 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -1963,6 +1963,9 @@ class MemStorage implements IStorage { } // Use MemStorage in development, DatabaseStorage in production -const isProduction = process.env.NODE_ENV === 'production' && process.env.DATABASE_URL; -export const storage = isProduction ? new DatabaseStorage() : new MemStorage(); -console.log(isProduction ? '🐳 PRODUCTION: Using PostgreSQL storage' : '🔧 DEV: Using in-memory storage'); +const isProduction = process.env.NODE_ENV === 'production'; +const dbUrl = process.env.DATABASE_URL; +const isProductionDocker = isProduction && dbUrl && (dbUrl.includes('logiflow-db') || dbUrl.includes('localhost')); + +export const storage = isProductionDocker ? new DatabaseStorage() : new MemStorage(); +console.log(isProductionDocker ? '🐳 PRODUCTION: Using PostgreSQL storage' : '🔧 DEV: Using in-memory storage');