""" Base de datos SQLite — esquema unificado con Persona A. Tablas propias del módulo B: truck_status, notificaciones, ws_sessions. """ import sqlite3 from pathlib import Path DB_PATH = Path("basura.db") def get_connection() -> sqlite3.Connection: conn = sqlite3.connect(DB_PATH, check_same_thread=False) conn.row_factory = sqlite3.Row conn.execute("PRAGMA journal_mode=WAL") conn.execute("PRAGMA foreign_keys=ON") return conn def init_db() -> None: conn = get_connection() conn.executescript(""" -- ── Tablas de Persona A (las creamos aquí para que el módulo B -- pueda leerlas aunque A no haya corrido aún) ────────────── CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, phone TEXT, password_hash TEXT NOT NULL, fcm_token TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS addresses ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, alias TEXT, lat REAL NOT NULL, lng REAL NOT NULL, route_id TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS notification_preferences ( user_id INTEGER PRIMARY KEY, notify_proximity BOOLEAN DEFAULT 1, notify_breakdown BOOLEAN DEFAULT 1, notify_delay BOOLEAN DEFAULT 1, notify_route_start BOOLEAN DEFAULT 1, FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS notification_templates ( id INTEGER PRIMARY KEY, trigger_event TEXT UNIQUE, title TEXT, body TEXT ); -- ── Tablas del módulo B ─────────────────────────────────────── CREATE TABLE IF NOT EXISTS truck_status ( route_id TEXT PRIMARY KEY, current_position_id INTEGER DEFAULT 1, last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP, status TEXT DEFAULT 'EN_RUTA' ); CREATE TABLE IF NOT EXISTS rutas ( id TEXT PRIMARY KEY, nombre TEXT NOT NULL, turno TEXT NOT NULL DEFAULT 'mañana' ); CREATE TABLE IF NOT EXISTS puntos_ruta ( id INTEGER PRIMARY KEY AUTOINCREMENT, ruta_id TEXT NOT NULL REFERENCES rutas(id), orden INTEGER NOT NULL, nombre TEXT NOT NULL, lat REAL NOT NULL, lng REAL NOT NULL, tiempo_estimado_min INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS notificaciones ( id INTEGER PRIMARY KEY AUTOINCREMENT, tipo TEXT NOT NULL, ruta_id TEXT NOT NULL, address_id INTEGER, mensaje TEXT NOT NULL, eta_minutos INTEGER, creada_en TEXT NOT NULL ); """) conn.commit() conn.close() _seed_datos_demo() def _seed_datos_demo() -> None: conn = get_connection() existe = conn.execute("SELECT 1 FROM rutas WHERE id='RUTA-01'").fetchone() if existe: conn.close() return conn.executescript(""" -- Ruta de demo (Celaya, Guanajuato) INSERT INTO rutas VALUES ('RUTA-01', 'Ruta 01 — Sector Centro', 'mañana'); INSERT INTO puntos_ruta (ruta_id, orden, nombre, lat, lng, tiempo_estimado_min) VALUES ('RUTA-01', 1, 'Estación Central', 20.5238, -100.8143, 0), ('RUTA-01', 2, 'Col. Independencia', 20.5255, -100.8090, 8), ('RUTA-01', 3, 'Blvd. A. López Mateos', 20.5271, -100.8021, 18), ('RUTA-01', 4, 'Col. Jardines del Bosque', 20.5290, -100.7965, 28), ('RUTA-01', 5, 'Mercado Hidalgo', 20.5310, -100.7910, 38); INSERT INTO truck_status VALUES ('RUTA-01', 1, CURRENT_TIMESTAMP, 'EN_RUTA'); -- Usuario de demo INSERT INTO users (email, phone, password_hash) VALUES ('demo@basura.app', '4611234567', 'hashed_demo'); -- Domicilio de demo asignado a RUTA-01 INSERT INTO addresses (user_id, alias, lat, lng, route_id) VALUES (1, 'Casa', 20.5285, -100.7980, 'RUTA-01'); -- Preferencias por defecto para usuario demo INSERT INTO notification_preferences VALUES (1, 1, 1, 1, 1); -- Templates de notificación INSERT INTO notification_templates (trigger_event, title, body) VALUES ('ruta_iniciada', 'Ruta iniciada', 'El camión ha comenzado su ruta. Prepárate.'), ('aproximandose', '¡Camión cerca!', 'El camión llega en ~{eta} minutos. Saca tu basura.'), ('falla_mecanica', 'Aviso de servicio', 'El camión reportó una falla. Te notificaremos cuando se reanude.'), ('ruta_tarde', 'Cambio de horario', 'El camión de la mañana pasará en el turno de la tarde.'), ('completado', 'Ruta completada', 'El camión completó su paso por tu zona. ¡Hasta mañana!'); """) conn.commit() conn.close()