Migrate to PostgreSQL and add DragonflyDB support

This commit is contained in:
VPS 4 Builder
2026-05-26 03:50:14 +02:00
parent bda5adf070
commit 13175f93aa
5 changed files with 197 additions and 369 deletions
+131 -360
View File
@@ -1,248 +1,109 @@
const mysql = require('mysql2/promise');
const fs = require('fs').promises;
const path = require('path');
const { Pool } = require('pg');
let pool = null;
let sqliteDb = null;
const isSqlite = process.env.DB_TYPE === 'sqlite';
// Helper to rewrite MySQL-specific syntax to SQLite
function rewriteQuery(sql) {
if (!isSqlite) return sql;
let query = sql;
// Replace NOW() with datetime('now')
query = query.replace(/\bNOW\(\)/gi, "datetime('now')");
// Rewrite ON DUPLICATE KEY UPDATE for users
if (query.includes('ON DUPLICATE KEY UPDATE')) {
query = `INSERT INTO users (username, email, password_hash, created_at)
VALUES (?, ?, ?, datetime('now'))
ON CONFLICT(username) DO UPDATE SET
email = excluded.email,
password_hash = excluded.password_hash`;
}
return query;
}
// ================================================================
// INICIALIZAR BANCO DE DADOS
// FUNÇÕES AUXILIARES DE COMPATIBILIDADE (MYSQL -> POSTGRES)
// ================================================================
async function initSQLite() {
const { DatabaseSync } = require('node:sqlite');
const dbPath = process.env.DB_PATH || path.join(__dirname, 'dental_images.db');
function rewriteToPostgres(sql) {
let rewritten = sql;
sqliteDb = new DatabaseSync(dbPath);
console.log(`✅ Banco de dados SQLite criado/inicializado em: ${dbPath}`);
// 1. Converter MySQL NOW() para Postgres CURRENT_TIMESTAMP
rewritten = rewritten.replace(/\bNOW\(\)/gi, 'CURRENT_TIMESTAMP');
// Criar tabelas para SQLite
sqliteDb.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
clinic_name TEXT,
pc_name TEXT,
is_admin INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`);
// 2. Converter parâmetros de ? para $1, $2, etc.
let paramIndex = 1;
rewritten = rewritten.replace(/\?/g, () => `$${paramIndex++}`);
sqliteDb.exec(`
CREATE TABLE IF NOT EXISTS images (
id INTEGER PRIMARY KEY AUTOINCREMENT,
image_guid TEXT NOT NULL,
patient_name TEXT,
client_name TEXT,
original_filename TEXT,
filename TEXT NOT NULL,
enabled INTEGER DEFAULT 1,
tooth_number TEXT,
tooth_side TEXT,
patient_name_resumed TEXT,
original_image_id INTEGER,
rotation INTEGER DEFAULT 0,
flip_horizontal INTEGER DEFAULT 0,
flip_vertical INTEGER DEFAULT 0,
doctor TEXT,
remark TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`);
sqliteDb.exec(`
CREATE TABLE IF NOT EXISTS gtos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
gto_number TEXT NOT NULL,
patient_name TEXT NOT NULL,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`);
sqliteDb.exec(`
CREATE TABLE IF NOT EXISTS gto_images (
id INTEGER PRIMARY KEY AUTOINCREMENT,
gto_id INTEGER NOT NULL,
image_id INTEGER NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(gto_id) REFERENCES gtos(id),
FOREIGN KEY(image_id) REFERENCES images(id)
);
`);
// Migrações para adicionar colunas se o banco já existia
try {
sqliteDb.exec("ALTER TABLE images ADD COLUMN doctor TEXT");
} catch (e) {
// Coluna já existe
}
try {
sqliteDb.exec("ALTER TABLE images ADD COLUMN remark TEXT");
} catch (e) {
// Coluna já existe
}
console.log('✅ Tabelas SQLite users e images criadas/verificadas');
// Migrações para adicionar colunas em users se o banco já existia
try { sqliteDb.exec("ALTER TABLE users ADD COLUMN clinic_name TEXT"); } catch (e) {}
try { sqliteDb.exec("ALTER TABLE users ADD COLUMN pc_name TEXT"); } catch (e) {}
try { sqliteDb.exec("ALTER TABLE users ADD COLUMN is_admin INTEGER DEFAULT 0"); } catch (e) {}
// Criar administrador padrão se não houver usuários
try {
const stmtCount = sqliteDb.prepare('SELECT COUNT(*) as count FROM users');
const userCount = stmtCount.get().count;
if (userCount === 0) {
console.log('⚠️ Nenhum usuário encontrado no SQLite. Criando admin padrão (admin / admin1234)...');
const bcrypt = require('bcrypt');
const passwordHash = bcrypt.hashSync('admin1234', 10);
const stmtInsert = sqliteDb.prepare(`
INSERT INTO users (username, email, password_hash, clinic_name, pc_name, is_admin)
VALUES (?, ?, ?, ?, ?, 1)
`);
stmtInsert.run('admin', 'admin@dental.local', passwordHash, 'Admin Clinic', 'Admin PC');
console.log('✅ Usuário admin padrão criado com sucesso!');
// 3. Adicionar RETURNING id nas inserções se não houver
if (rewritten.trim().toUpperCase().startsWith('INSERT INTO')) {
if (!rewritten.toUpperCase().includes('RETURNING')) {
rewritten += ' RETURNING id';
}
} catch (error) {
console.error('⚠️ Erro ao criar admin padrão:', error.message);
}
// 4. Reescrever ON DUPLICATE KEY UPDATE do MySQL
if (rewritten.includes('ON DUPLICATE KEY UPDATE')) {
// Isso é específico para a query de inserção de usuário default
rewritten = `INSERT INTO users (username, email, password_hash, created_at)
VALUES ($1, $2, $3, CURRENT_TIMESTAMP)
ON CONFLICT (username) DO UPDATE SET
email = EXCLUDED.email,
password_hash = EXCLUDED.password_hash
RETURNING id`;
}
return rewritten;
}
// ================================================================
// INICIALIZAR BANCO DE DADOS POSTGRESQL
// ================================================================
async function initDatabase() {
if (isSqlite) {
await initSQLite();
return;
const dbConfig = {
host: process.env.DB_HOST || '10.99.0.3',
port: process.env.DB_PORT || 5432,
user: process.env.DB_USER || 'postgres',
database: process.env.DB_NAME || 'dental_images',
max: 20, // Max number of clients in the pool
idleTimeoutMillis: 30000,
};
if (process.env.DB_PASSWORD) {
dbConfig.password = process.env.DB_PASSWORD;
}
try {
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
};
const dbName = process.env.DB_NAME || 'dental_images';
pool = new Pool(dbConfig);
// Criar pool temporário SEM database para poder criar o banco
const tempPool = mysql.createPool({
...dbConfig,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// Testa a conexão
const client = await pool.connect();
console.log(`✅ Conectado ao PostgreSQL (Host: ${dbConfig.host}, DB: ${dbConfig.database})`);
client.release();
console.log('✅ Pool de conexões MySQL criado');
// Verificar se banco existe, se não criar
try {
const [databases] = await tempPool.query(
`SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?`,
[dbName]
);
if (databases.length === 0) {
console.log(`⚠️ Banco ${dbName} não encontrado. Criando...`);
await tempPool.query(`CREATE DATABASE ${dbName} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
console.log(`✅ Banco ${dbName} criado!`);
} else {
console.log(`✅ Banco ${dbName} já existe`);
}
} catch (error) {
console.error('❌ Erro ao verificar/criar banco:', error);
throw error;
}
// Fechar pool temporário
await tempPool.end();
// Criar pool definitivo COM database
pool = mysql.createPool({
...dbConfig,
database: dbName,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
enableKeepAlive: true,
keepAliveInitialDelay: 0
});
// Testar conexão
const connection = await pool.getConnection();
console.log('✅ Conectado ao MySQL');
connection.release();
// Criar tabelas
// Criar as tabelas
await createTables();
} catch (error) {
console.error('❌ Erro ao conectar ao MySQL:', error.message);
console.error('Verifique:');
console.error('1. MySQL está rodando? (sudo systemctl status mysql)');
console.error('2. Credenciais corretas no .env?');
console.error('3. Usuário tem permissão para criar databases?');
console.error('❌ Erro ao conectar ao PostgreSQL:', error.message);
throw error;
}
}
// ================================================================
// CRIAR TABELAS MYSQL
// CRIAR TABELAS POSTGRESQL
// ================================================================
async function createTables() {
const connection = await pool.getConnection();
const client = await pool.connect();
try {
// Tabela de usuários
await connection.query(`
await client.query(`
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
clinic_name VARCHAR(100) NULL,
pc_name VARCHAR(50) NULL,
is_admin TINYINT(1) DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
clinic_name VARCHAR(100),
pc_name VARCHAR(50),
is_admin BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✅ Tabela users criada/verificada');
console.log('✅ Tabela users criada/verificada no PostgreSQL');
// Tabela de imagens
await connection.query(`
await client.query(`
CREATE TABLE IF NOT EXISTS images (
id INT AUTO_INCREMENT PRIMARY KEY,
id SERIAL PRIMARY KEY,
image_guid VARCHAR(255) NOT NULL,
patient_name TEXT,
client_name VARCHAR(100),
original_filename TEXT,
filename TEXT NOT NULL,
enabled TINYINT(1) DEFAULT 1,
enabled BOOLEAN DEFAULT true,
tooth_number VARCHAR(10),
tooth_side VARCHAR(10),
patient_name_resumed VARCHAR(50),
@@ -250,167 +111,99 @@ async function createTables() {
rotation INT DEFAULT 0,
flip_horizontal INT DEFAULT 0,
flip_vertical INT DEFAULT 0,
doctor VARCHAR(255) NULL,
remark TEXT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_images_enabled (enabled),
INDEX idx_images_original (original_image_id),
INDEX idx_patient_name (patient_name(100)),
INDEX idx_image_guid (image_guid),
INDEX idx_client_name (client_name),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
doctor VARCHAR(255),
remark TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✅ Tabela images criada/verificada');
// Criação de índices no PostgreSQL
await client.query('CREATE INDEX IF NOT EXISTS idx_images_enabled ON images(enabled)');
await client.query('CREATE INDEX IF NOT EXISTS idx_images_original ON images(original_image_id)');
await client.query('CREATE INDEX IF NOT EXISTS idx_image_guid ON images(image_guid)');
await client.query('CREATE INDEX IF NOT EXISTS idx_client_name ON images(client_name)');
await client.query('CREATE INDEX IF NOT EXISTS idx_created_at ON images(created_at)');
console.log('✅ Tabela images criada/verificada no PostgreSQL');
// Tabela GTOs
await connection.query(`
await client.query(`
CREATE TABLE IF NOT EXISTS gtos (
id INT AUTO_INCREMENT PRIMARY KEY,
id SERIAL PRIMARY KEY,
gto_number VARCHAR(100) NOT NULL,
patient_name VARCHAR(255) NOT NULL,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_gtos_patient (patient_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✅ Tabela gtos criada/verificada');
await client.query('CREATE INDEX IF NOT EXISTS idx_gtos_patient ON gtos(patient_name)');
console.log('✅ Tabela gtos criada/verificada no PostgreSQL');
// Tabela de vínculo GTO-Images
await connection.query(`
await client.query(`
CREATE TABLE IF NOT EXISTS gto_images (
id INT AUTO_INCREMENT PRIMARY KEY,
gto_id INT NOT NULL,
image_id INT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (gto_id) REFERENCES gtos(id) ON DELETE CASCADE,
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
UNIQUE INDEX idx_gto_image (gto_id, image_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
id SERIAL PRIMARY KEY,
gto_id INT NOT NULL REFERENCES gtos(id) ON DELETE CASCADE,
image_id INT NOT NULL REFERENCES images(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(gto_id, image_id)
)
`);
console.log('✅ Tabela gto_images criada/verificada');
console.log('✅ Tabela gto_images criada/verificada no PostgreSQL');
// Verificar e adicionar colunas se não existirem (migração)
// Verificar colunas faltantes em users (migração)
try {
const columns = await connection.query(`
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'images'
AND COLUMN_NAME = 'client_name'
const res = await client.query(`
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'clinic_name'
`);
if (columns[0].length === 0) {
console.log('⚠️ Coluna client_name não encontrada. Adicionando...');
await connection.query(`
ALTER TABLE images
ADD COLUMN client_name VARCHAR(100) NULL
AFTER patient_name
`);
await connection.query(`
ALTER TABLE images
ADD INDEX idx_client_name (client_name)
`);
console.log('✅ Coluna client_name adicionada');
}
} catch (error) {
console.warn('⚠️ Erro ao verificar/adicionar coluna client_name:', error.message);
}
// Migração para coluna doctor
try {
const columnsDoctor = await connection.query(`
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'images'
AND COLUMN_NAME = 'doctor'
`);
if (columnsDoctor[0].length === 0) {
console.log('⚠️ Coluna doctor não encontrada. Adicionando...');
await connection.query(`
ALTER TABLE images
ADD COLUMN doctor VARCHAR(255) NULL
AFTER client_name
if (res.rows.length === 0) {
console.log('⚠️ Adicionando novas colunas na tabela users...');
await client.query(`
ALTER TABLE users
ADD COLUMN clinic_name VARCHAR(100),
ADD COLUMN pc_name VARCHAR(50),
ADD COLUMN is_admin BOOLEAN DEFAULT false
`);
}
} catch (error) {
console.warn('⚠️ Erro ao verificar/adicionar coluna doctor:', error.message);
} catch (e) {
console.warn('⚠️ Erro ao migrar tabela users:', e.message);
}
// Migração para coluna remark
// Criar administrador padrão se não houver usuários
try {
const columnsRemark = await connection.query(`
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'images'
AND COLUMN_NAME = 'remark'
`);
if (columnsRemark[0].length === 0) {
console.log('⚠️ Coluna remark não encontrada. Adicionando...');
await connection.query(`
ALTER TABLE images
ADD COLUMN remark TEXT NULL
AFTER doctor
`);
const res = await client.query('SELECT COUNT(*) as count FROM users');
if (parseInt(res.rows[0].count) === 0) {
console.log('⚠️ Nenhum usuário encontrado. Criando admin padrão (admin / admin1234)...');
const bcrypt = require('bcrypt');
const passwordHash = bcrypt.hashSync('admin1234', 10);
await client.query(`
INSERT INTO users (username, email, password_hash, clinic_name, pc_name, is_admin)
VALUES ($1, $2, $3, $4, $5, true)
`, ['admin', 'admin@dental.local', passwordHash, 'Admin Clinic', 'Admin PC']);
console.log('✅ Usuário admin padrão criado com sucesso!');
}
} catch (error) {
console.warn('⚠️ Erro ao verificar/adicionar coluna remark:', error.message);
}
// Migração para colunas da tabela users (clinic_name, pc_name, is_admin)
try {
const columnsUsers = await connection.query(`
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'users'
AND COLUMN_NAME = 'clinic_name'
`);
if (columnsUsers[0].length === 0) {
console.log('⚠️ Colunas de clínica em users não encontradas. Adicionando...');
await connection.query(`
ALTER TABLE users
ADD COLUMN clinic_name VARCHAR(100) NULL AFTER password_hash,
ADD COLUMN pc_name VARCHAR(50) NULL AFTER clinic_name,
ADD COLUMN is_admin TINYINT(1) DEFAULT 0 AFTER pc_name
`);
// O primeiro usuário (admin padrão) deve virar admin se já existe
await connection.query(`UPDATE users SET is_admin = 1 ORDER BY id ASC LIMIT 1`);
}
} catch (error) {
console.warn('⚠️ Erro ao verificar/adicionar colunas de clínica em users:', error.message);
console.error('⚠️ Erro ao criar admin padrão:', error.message);
}
} catch (error) {
console.error('Erro ao criar tabelas:', error);
console.error('Erro ao criar tabelas no PostgreSQL:', error);
} finally {
connection.release();
client.release();
}
}
// ================================================================
// FUNÇÕES DE CONSULTA
// FUNÇÕES DE CONSULTA (ENVOLVENDO O POOL DO PG)
// ================================================================
function get(query, params = []) {
if (isSqlite) {
return new Promise((resolve, reject) => {
try {
const stmt = sqliteDb.prepare(rewriteQuery(query));
const row = stmt.get(...params);
resolve(row || null);
} catch (error) {
reject(error);
}
});
}
return new Promise(async (resolve, reject) => {
try {
const [rows] = await pool.query(query, params);
resolve(rows[0] || null);
const res = await pool.query(rewriteToPostgres(query), params);
resolve(res.rows[0] || null);
} catch (error) {
reject(error);
}
@@ -418,22 +211,10 @@ function get(query, params = []) {
}
function all(query, params = []) {
if (isSqlite) {
return new Promise((resolve, reject) => {
try {
const stmt = sqliteDb.prepare(rewriteQuery(query));
const rows = stmt.all(...params);
resolve(rows);
} catch (error) {
reject(error);
}
});
}
return new Promise(async (resolve, reject) => {
try {
const [rows] = await pool.query(query, params);
resolve(rows);
const res = await pool.query(rewriteToPostgres(query), params);
resolve(res.rows || []);
} catch (error) {
reject(error);
}
@@ -441,27 +222,17 @@ function all(query, params = []) {
}
function run(query, params = []) {
if (isSqlite) {
return new Promise((resolve, reject) => {
try {
const stmt = sqliteDb.prepare(rewriteQuery(query));
const result = stmt.run(...params);
resolve({
lastID: result.lastInsertRowid,
changes: result.changes
});
} catch (error) {
reject(error);
}
});
}
return new Promise(async (resolve, reject) => {
try {
const [result] = await pool.query(query, params);
const rewritten = rewriteToPostgres(query);
const res = await pool.query(rewritten, params);
// No PostgreSQL, se adicionamos RETURNING id, o id estará no res.rows[0]
const insertedId = (res.rows && res.rows[0] && res.rows[0].id) ? res.rows[0].id : null;
resolve({
lastID: result.insertId,
changes: result.affectedRows
lastID: insertedId,
changes: res.rowCount
});
} catch (error) {
reject(error);
@@ -478,5 +249,5 @@ module.exports = {
get,
all,
run,
get db() { return isSqlite ? sqliteDb : pool; }
get db() { return pool; }
};
+9 -8
View File
@@ -16,16 +16,17 @@
"author": "Rcesar",
"license": "MIT",
"dependencies": {
"socket.io": "^4.7.2",
"express": "^4.18.2",
"sharp": "^0.32.6",
"mysql2": "^3.6.0",
"dotenv": "^16.3.1",
"cors": "^2.8.5",
"bcrypt": "^5.1.1",
"jsonwebtoken": "^9.0.2",
"cookie-parser": "^1.4.6",
"express-session": "^1.17.3"
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-session": "^1.17.3",
"ioredis": "^5.10.1",
"jsonwebtoken": "^9.0.2",
"pg": "^8.21.0",
"sharp": "^0.32.6",
"socket.io": "^4.7.2"
},
"engines": {
"node": ">=16.0.0",
+40
View File
@@ -0,0 +1,40 @@
const Redis = require('ioredis');
let redisClient = null;
function initRedis() {
const host = process.env.REDIS_HOST || '10.99.0.3';
const port = process.env.REDIS_PORT || 6379;
const password = process.env.REDIS_PASSWORD || '';
redisClient = new Redis({
host,
port,
password,
retryStrategy: (times) => {
// Reconecta exponencialmente com limite de 3 segundos
const delay = Math.min(times * 50, 3000);
return delay;
}
});
redisClient.on('connect', () => {
console.log(`✅ Conectado ao DragonflyDB/Redis em ${host}:${port}`);
});
redisClient.on('error', (err) => {
console.error('❌ Erro de conexão no DragonflyDB/Redis:', err.message);
});
}
function getClient() {
if (!redisClient) {
initRedis();
}
return redisClient;
}
module.exports = {
initRedis,
getClient
};
+16
View File
@@ -18,6 +18,7 @@ const patientsRouter = require('./routes/patients');
const gtosRouter = require('./routes/gtos');
const systemRoutes = require('./routes/system');
const { checkInstallation } = require('./installer/check-installation');
const redis = require('./redis');
// ================================================================
// CONFIGURAÇÃO DO SERVIDOR
@@ -72,6 +73,18 @@ app.get('/status', (req, res) => {
});
});
// DragonflyDB Ping check
app.get('/api/redis/ping', async (req, res) => {
try {
const client = redis.getClient();
await client.set('ping_test', 'pong', 'EX', 10);
const value = await client.get('ping_test');
res.json({ success: true, dragonfly_db: 'connected', test_value: value });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Verificar se o nome do computador/cliente já existe
app.get('/api/clients/check-name', async (req, res) => {
try {
@@ -911,6 +924,9 @@ async function start() {
console.log('⚠️ Banco de dados não configurado. Execute a instalação em /install');
}
// Inicializar cliente DragonflyDB/Redis
redis.initRedis();
// Iniciar servidor
server.listen(PORT, () => {
console.log('═══════════════════════════════════════════════════════');
+1 -1
View File
@@ -12,7 +12,7 @@ services:
environment:
- NODE_ENV=production
- PORT=3000
- DB_TYPE=sqlite
- DB_TYPE=postgres\n - DB_HOST=10.99.0.3\n - REDIS_HOST=10.99.0.3\n - REDIS_PORT=6379\n - REDIS_PASSWORD=clube67_db_pass_9903
- DB_PATH=/app/data/dental_images.db
- DB_PORT=5432
- DB_USER=clube67