Plan Done, Dockerization and cleanup
Build & Push Docker Images / test-backend (push) Successful in 55s
Build & Push Docker Images / test-frontend (push) Successful in 43s
Run Tests / test-backend (push) Successful in 48s
Run Tests / test-frontend (push) Successful in 42s
Build & Push Docker Images / build-backend (push) Failing after 4m7s
Build & Push Docker Images / build-frontend (push) Failing after 32s

This commit is contained in:
Antoni Nuñez Romeu
2026-05-19 18:16:28 +02:00
parent 93ec8e6a6c
commit cc9a24d6d6
18 changed files with 666 additions and 101 deletions
+30 -55
View File
@@ -5,7 +5,9 @@ import { promisify } from 'util';
import path from 'path';
import { fileURLToPath } from 'url';
import session from 'express-session';
import connectSqlite3 from 'connect-sqlite3';
import bcrypt from 'bcrypt';
import rateLimit from 'express-rate-limit';
import { searchMedicines, getMedicineDetails } from './cima-service.js';
import { runFarmaciaWebhookImport, DEFAULT_FARMACIAS_WEBHOOK, importPharmaciesFromRows } from './farmacias-webhook-import.js';
import { fetchPharmaciesExternal } from '../API/index.js';
@@ -18,25 +20,36 @@ const PORT = process.env.PORT || 3001;
// Configure CORS with credentials
app.use(cors({
origin: 'http://localhost:3000',
origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
credentials: true
}));
app.use(express.json());
// Configure session
app.use(session({
const SQLiteStore = connectSqlite3(session);
const sessionConfig = {
secret: process.env.SESSION_SECRET || 'farma-finder-secret-key-change-in-production',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // Set to true in production with HTTPS
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
}));
};
if (process.env.NODE_ENV !== 'test') {
sessionConfig.store = new SQLiteStore({ db: 'sessions.sqlite', dir: __dirname });
}
// Configure session
app.use(session(sessionConfig));
const searchLimiter = rateLimit({ windowMs: 60_000, max: 30, standardHeaders: true, legacyHeaders: false });
const loginLimiter = rateLimit({ windowMs: 60_000, max: 5, standardHeaders: true, legacyHeaders: false });
// Database setup
const dbPath = path.join(__dirname, 'database.sqlite');
const dbPath = process.env.DATABASE_PATH || path.join(__dirname, 'database.sqlite');
const db = new sqlite3.Database(dbPath);
// Custom wrapper to get lastID from db.run
@@ -67,17 +80,6 @@ async function initDatabase() {
)
`);
// Create medicines table
await dbRun(`
CREATE TABLE IF NOT EXISTS medicines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
active_ingredient TEXT,
dosage TEXT,
form TEXT
)
`);
// Create junction table for pharmacy-medicine relationships
// Ahora usa nregistro (número de registro de CIMA) en lugar de medicine_id local
await dbRun(`
@@ -93,8 +95,6 @@ async function initDatabase() {
)
`);
// Create indexes for better search performance
await dbRun(`CREATE INDEX IF NOT EXISTS idx_medicine_name ON medicines(name)`);
await dbRun(`CREATE INDEX IF NOT EXISTS idx_pharmacy_medicine ON pharmacy_medicines(medicine_nregistro)`);
// Create users table for authentication
@@ -116,7 +116,7 @@ async function initDatabase() {
// API Routes
// Search medicines using CIMA API with Redis cache
app.get('/api/medicines/search', async (req, res) => {
app.get('/api/medicines/search', searchLimiter, async (req, res) => {
try {
const query = req.query.q || '';
@@ -206,7 +206,7 @@ const requireAuth = (req, res, next) => {
// ========== AUTHENTICATION ROUTES ==========
// Login endpoint
app.post('/api/auth/login', async (req, res) => {
app.post('/api/auth/login', loginLimiter, async (req, res) => {
try {
const { username, password } = req.body;
@@ -584,34 +584,6 @@ app.get('/api/admin/medicines', requireAuth, async (req, res) => {
}
});
// NOTA: Ya no necesitamos endpoints para crear/editar medicamentos localmente
// porque ahora usamos la API de CIMA como fuente de verdad
// Add a new medicine (DEPRECATED - mantenido solo para compatibilidad)
app.post('/api/admin/medicines', requireAuth, async (req, res) => {
try {
// Ya no se agregan medicamentos localmente, se obtienen de CIMA
return res.status(400).json({
error: 'Medicine management has been moved to CIMA API. Use the search feature to find medicines.'
});
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Update a medicine (DEPRECATED - mantenido solo para compatibilidad)
app.put('/api/admin/medicines/:id', requireAuth, async (req, res) => {
try {
return res.status(400).json({
error: 'Medicine management has been moved to CIMA API.'
});
} catch (error) {
console.error('Error updating medicine:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get medicines for a specific pharmacy (usando nregistro)
app.get('/api/admin/pharmacies/:pharmacyId/medicines', requireAuth, async (req, res) => {
try {
@@ -718,10 +690,13 @@ app.delete('/api/admin/pharmacy-medicines/:id', requireAuth, async (req, res) =>
}
});
// Start server
initDatabase().then(() => {
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
});
export { app, initDatabase, db };
if (process.env.NODE_ENV !== 'test') {
initDatabase().then(() => {
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
});
}