-
+const {
+ DATABASE_URL,
+ JWT_SECRET,
+ EVOLUTION_BASE_URL,
+ EVOLUTION_API_KEY,
+ EVOLUTION_INSTANCE,
+} = process.env;
- - Configuración Avanzada -
+app.use(cors()); +app.use(express.json()); - -
+if (!DATABASE_URL || !JWT_SECRET) {
+ console.error("❌ ERROR FATAL: Faltan variables de entorno");
+ process.exit(1);
+}
-
-
-
-
-
+const pool = new Pool({
+ connectionString: DATABASE_URL,
+ ssl: false
+});
-
+// ==========================================
+// 🧠 AUTO-ACTUALIZACIÓN DB
+// ==========================================
+async function autoUpdateDB() {
+ const client = await pool.connect();
+ try {
+ console.log("🔄 Verificando estructura DB...");
-
+ await client.query(`
+ CREATE TABLE IF NOT EXISTS users (
+ id SERIAL PRIMARY KEY,
+ full_name TEXT NOT NULL,
+ phone TEXT NOT NULL,
+ email TEXT NOT NULL,
+ dni TEXT,
+ address TEXT,
+ password_hash TEXT NOT NULL,
+ is_verified BOOLEAN DEFAULT FALSE,
+ owner_id INT,
+ role TEXT DEFAULT 'operario',
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+ CREATE TABLE IF NOT EXISTS login_codes (
+ id SERIAL PRIMARY KEY,
+ user_id INT REFERENCES users(id) ON DELETE CASCADE,
+ phone TEXT NOT NULL,
+ code_hash TEXT NOT NULL,
+ purpose TEXT DEFAULT 'register_verify',
+ consumed_at TIMESTAMP,
+ expires_at TIMESTAMP NOT NULL,
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+ CREATE TABLE IF NOT EXISTS guilds (
+ id SERIAL PRIMARY KEY,
+ owner_id INT REFERENCES users(id) ON DELETE CASCADE,
+ name TEXT NOT NULL,
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+ CREATE TABLE IF NOT EXISTS user_guilds (
+ user_id INT REFERENCES users(id) ON DELETE CASCADE,
+ guild_id INT REFERENCES guilds(id) ON DELETE CASCADE,
+ PRIMARY KEY (user_id, guild_id)
+ );
+ CREATE TABLE IF NOT EXISTS companies (
+ id SERIAL PRIMARY KEY,
+ owner_id INT REFERENCES users(id) ON DELETE CASCADE,
+ name TEXT NOT NULL,
+ cif TEXT,
+ email TEXT,
+ phone TEXT,
+ address TEXT,
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+ CREATE TABLE IF NOT EXISTS clients (
+ id SERIAL PRIMARY KEY,
+ owner_id INT REFERENCES users(id) ON DELETE CASCADE,
+ full_name TEXT NOT NULL,
+ phone TEXT NOT NULL,
+ email TEXT,
+ addresses JSONB DEFAULT '[]',
+ notes TEXT,
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+ CREATE TABLE IF NOT EXISTS service_statuses (
+ id SERIAL PRIMARY KEY,
+ owner_id INT REFERENCES users(id) ON DELETE CASCADE,
+ name TEXT NOT NULL,
+ color TEXT DEFAULT 'gray',
+ is_default BOOLEAN DEFAULT FALSE,
+ is_final BOOLEAN DEFAULT FALSE,
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+
+ -- Tablas de Zonas (Simplificadas)
+ CREATE TABLE IF NOT EXISTS zones (
+ id SERIAL PRIMARY KEY,
+ name TEXT NOT NULL,
+ owner_id INT,
+ created_at TIMESTAMP DEFAULT NOW()
+ );
+ CREATE TABLE IF NOT EXISTS user_zones (
+ user_id INT REFERENCES users(id) ON DELETE CASCADE,
+ zone_id INT REFERENCES zones(id) ON DELETE CASCADE,
+ PRIMARY KEY (user_id, zone_id)
+ );
-
+// HELPERS
+function normalizePhone(phone) { let p = String(phone || "").trim().replace(/\s+/g, "").replace(/-/g, ""); if (!p) return ""; if (!p.startsWith("+") && /^[6789]\d{8}$/.test(p)) return "+34" + p; return p; }
+function genCode6() { return String(Math.floor(100000 + Math.random() * 900000)); }
+function signToken(user) { const accountId = user.owner_id || user.id; return jwt.sign({ sub: user.id, email: user.email, phone: user.phone, role: user.role || 'operario', accountId }, JWT_SECRET, { expiresIn: "30d" }); }
+function authMiddleware(req, res, next) { const h = req.headers.authorization || ""; const token = h.startsWith("Bearer ") ? h.slice(7) : ""; if (!token) return res.status(401).json({ ok: false, error: "No token" }); try { req.user = jwt.verify(token, JWT_SECRET); next(); } catch { return res.status(401).json({ ok: false, error: "Token inválido" }); } }
+async function sendWhatsAppCode(phone, code) { if (!EVOLUTION_BASE_URL || !EVOLUTION_API_KEY) return; const url = `${EVOLUTION_BASE_URL.replace(/\/$/, "")}/message/sendText/${EVOLUTION_INSTANCE}`; await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", "apikey": EVOLUTION_API_KEY }, body: JSON.stringify({ number: phone.replace("+", ""), text: `🔐 Código: *${code}*` }) }).catch(console.error); }
-
-
-
- Gestor de Plantillas
-Próximamente podrás editar tus textos aquí.
-