From aeceba9095a5d86e1522bd2f2e817ecc026f33b5 Mon Sep 17 00:00:00 2001 From: Ricardo Monla Date: Wed, 8 Apr 2026 23:39:24 -0300 Subject: [PATCH] =?UTF-8?q?Init:=20MVP=20de=20Gesti=C3=B3n=20de=20Pagos=20?= =?UTF-8?q?(Stitch=20UI=20+=20SQLite/PHP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plan/00_PLAN.md | 48 ++++++++ pagos/add.html | 186 +++++++++++++++++++++++++++++ pagos/api/auth.php | 14 +++ pagos/api/db.php | 31 +++++ pagos/api/movimientos.php | 80 +++++++++++++ pagos/css/style.css | 7 ++ pagos/db/.gitignore | 2 + pagos/db/schema.sql | 26 ++++ pagos/index.html | 235 +++++++++++++++++++++++++++++++++++++ pagos/js/add.js | 94 +++++++++++++++ pagos/js/dashboard.js | 80 +++++++++++++ pagos/js/tailwind-theme.js | 67 +++++++++++ 12 files changed, 870 insertions(+) create mode 100644 docs/plan/00_PLAN.md create mode 100644 pagos/add.html create mode 100644 pagos/api/auth.php create mode 100644 pagos/api/db.php create mode 100644 pagos/api/movimientos.php create mode 100644 pagos/css/style.css create mode 100644 pagos/db/.gitignore create mode 100644 pagos/db/schema.sql create mode 100644 pagos/index.html create mode 100644 pagos/js/add.js create mode 100644 pagos/js/dashboard.js create mode 100644 pagos/js/tailwind-theme.js diff --git a/docs/plan/00_PLAN.md b/docs/plan/00_PLAN.md new file mode 100644 index 0000000..3b6fdf8 --- /dev/null +++ b/docs/plan/00_PLAN.md @@ -0,0 +1,48 @@ +# Plan de Desarrollo: Sistema de Gestión de Gastos y Pagos (rm-PAGOs) + +## Contexto y Arquitectura +- **Frontend**: Diseños generados por Stitch (HTML, CSS Vainilla, JS). Diseño moderno "Quiet Wealth / Financial Sanctuary". +- **Backend**: PHP 8.2 (procesamiento ligero, para máxima compatibilidad con el servidor de destino). +- **Base de Datos**: SQLite3 (liviana, portátil y soportada nativamente por PHP, sin necesidad de un servidor de BD separado). +- **Despliegue**: Servidor Proxmox LXC `srvv-nginx-rm` (Debian 12, NGINX 1.22.1, HTTPS activo). + +--- + +## Fases de Ejecución + +### Fase 1: Estructuración y Maquetación (Frontend Static) +**Objetivo:** Tener todo el diseño web unificado y navegable estáticamente. +1. Crear la estructura de la aplicación DENTRO de la carpeta `pagos/` (que es la que se usará para el despliegue). `pagos/index.html`, `pagos/css/`, `pagos/api/`, `pagos/db/`. +2. Exportar las pantallas generadas en Stitch (Dashboard, Nuevo Gasto, Historial) y acomodarlas como plantillas base (HTML). +3. Configurar el archivo CSS general con las variables del sistema de diseño (Lumina Finance). +4. Enlazar la navegación básica con Javascript o anclas entre pantallas. + +### Fase 2: Motor de Base de Datos y Backend (PHP/SQLite) +**Objetivo:** Persistir la información y crear la lógica detrás de las pantallas. +1. Diseñar el esquema de base de datos SQLite (tablas básicas como `movimientos` y `categorias`). +2. Crear un archivo clase base en PHP (`db.php`) para conexión y operaciones CRUD. +3. Crear los endpoints/controladores PHP (`api/movimientos.php`) que manejen operaciones GET, POST, PUT y DELETE. +4. Ajustar los scripts de inicialización de la BD. + +### Fase 3: Integración Frontend ↔ Backend (Dinámica) +**Objetivo:** Darle vida a las pantallas usando Javascript interactuando con PHP. +1. **Nuevo Movimiento**: Enlazar el formulario "Agregar" usando Fetch/AJAX (Vanilla JS) para enviarle los datos al backend de forma transparente sin refrescar. +2. **Dashboard**: + - Calcular saldo dinámico, sumatorias de gastos del mes, etc., usando SQL. + - Enlazar librería de gráficos (por ejemplo Chart.js) para pintar la dona de categorías leyendo desde la base de datos. +3. **Historial**: Renderizar la lista de últimos movimientos desde SQLite y añadir sistema de borrado. + +### Fase 4: Despliegue Configurado (Producción) +**Objetivo:** Llevar el sistema al servidor `srvv-nginx-rm` para uso real. +1. **Seguridad Básica:** Añadir una pantalla de Login o protección sencilla (ya que son datos financieros personales) utilizando las sesiones nativas de PHP o Basic Auth en NGINX. +2. **Configuración del Servidor:** + - Crear un subdirectorio o alias en NGINX (ejemplo `rmonla.duckdns.org/pagos`). + - Clonar o actualizar por deploy key en `/var/www/pagos`. + - Asegurar permisos de escritura a la carpeta `db/` para que PHP (usuario `www-data`) pueda modifciar el archivo `.sqlite`. +3. Pruebas End-to-End directas desde el teléfono. + +--- + +## Roadmap de Próximos Pasos (De Inmediato) +1. Iniciar con la **Fase 1**, configurando estructura base (`index.html`, `style.css`) volcando el HTML de Stitch en un index. +2. Crear un script rápido de inicialización de SQLite. diff --git a/pagos/add.html b/pagos/add.html new file mode 100644 index 0000000..7049dd5 --- /dev/null +++ b/pagos/add.html @@ -0,0 +1,186 @@ + + + + + +Nuevo Movimiento - Sanctuary + + + + + + + + + + +
+
+ +

Nuevo Movimiento

+
+
+
+
+ +
+ + +
+ +
+ +
+$ +0 +
+
+ +
+ +
+ + +
+ +
+
+ +
+calendar_today + +
+
+
+ +
+edit_note + +
+
+
+
+ +
+ + + + + + + + + + + + +
+
+ +
+ +
+ +
+Calm plant leaves + + \ No newline at end of file diff --git a/pagos/api/auth.php b/pagos/api/auth.php new file mode 100644 index 0000000..f6cdf07 --- /dev/null +++ b/pagos/api/auth.php @@ -0,0 +1,14 @@ + diff --git a/pagos/api/db.php b/pagos/api/db.php new file mode 100644 index 0000000..c593d37 --- /dev/null +++ b/pagos/api/db.php @@ -0,0 +1,31 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Si no existía, crear la BD desde schema y establecer permisos + if ($is_new && file_exists($schema_file)) { + $schema = file_get_contents($schema_file); + $pdo->exec($schema); + // Intentar dar permisos para www-data en el servidor + @chmod($db_file, 0666); + @chmod(dirname($db_file), 0777); + } + + return $pdo; + } catch (PDOException $e) { + http_response_code(500); + die(json_encode(['error' => 'Connection failed: ' . $e->getMessage()])); + } +} +?> diff --git a/pagos/api/movimientos.php b/pagos/api/movimientos.php new file mode 100644 index 0000000..bc77435 --- /dev/null +++ b/pagos/api/movimientos.php @@ -0,0 +1,80 @@ +query("SELECT + SUM(CASE WHEN tipo = 'ingreso' THEN monto ELSE -monto END) as balance + FROM movimientos"); + $balance = $stmtBalance->fetch(PDO::FETCH_ASSOC)['balance'] ?? 0; + + // 2. Últimos movimientos + $stmtMovi = $pdo->query("SELECT m.*, c.nombre as categoria_nombre, c.icono as categoria_icono + FROM movimientos m + LEFT JOIN categorias c ON m.id_categoria = c.id + ORDER BY m.fecha DESC, m.id DESC LIMIT 5"); + $movimientos = $stmtMovi->fetchAll(PDO::FETCH_ASSOC); + + // 3. Agrupación por categoría para gráfico donut (sólo gastos de este mes/año) + // Por simplicidad traemos todos los gastos + $stmtGraph = $pdo->query("SELECT c.nombre, c.color_hex, SUM(m.monto) as total + FROM movimientos m + JOIN categorias c ON m.id_categoria = c.id + WHERE m.tipo = 'gasto' + GROUP BY c.id + ORDER BY total DESC"); + $grafico = $stmtGraph->fetchAll(PDO::FETCH_ASSOC); + + // 4. Categorías para el modal de nuevo registro + $stmtCat = $pdo->query("SELECT * FROM categorias"); + $categorias = $stmtCat->fetchAll(PDO::FETCH_ASSOC); + + echo json_encode([ + 'status' => 'success', + 'balance' => (float)$balance, + 'movimientos' => $movimientos, + 'grafico' => $grafico, + 'categorias' => $categorias + ]); + } catch (Exception $e) { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); + } + +} elseif ($method === 'POST') { + // Insertar nuevo movimiento + $data = json_decode(file_get_contents('php://input'), true); + + // Validación mínima + if (!isset($data['tipo'], $data['monto'], $data['id_categoria'], $data['fecha'])) { + http_response_code(400); + die(json_encode(['status' => 'error', 'message' => 'Faltan campos obligatorios'])); + } + + try { + $stmt = $pdo->prepare("INSERT INTO movimientos (tipo, monto, fecha, notas, id_categoria) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([ + $data['tipo'], + (float) $data['monto'], + $data['fecha'], + $data['notas'] ?? '', + (int) $data['id_categoria'] + ]); + echo json_encode(['status' => 'success', 'id' => $pdo->lastInsertId()]); + } catch (Exception $e) { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); + } +} else { + http_response_code(405); + echo json_encode(['status' => 'error', 'message' => 'Método no permitido']); +} +?> diff --git a/pagos/css/style.css b/pagos/css/style.css new file mode 100644 index 0000000..68c9808 --- /dev/null +++ b/pagos/css/style.css @@ -0,0 +1,7 @@ +.material-symbols-outlined { + font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; +} +body { + font-family: 'Manrope', sans-serif; + min-height: max(884px, 100dvh); +} diff --git a/pagos/db/.gitignore b/pagos/db/.gitignore new file mode 100644 index 0000000..4928ca6 --- /dev/null +++ b/pagos/db/.gitignore @@ -0,0 +1,2 @@ +*.sqlite +*.sqlite-* diff --git a/pagos/db/schema.sql b/pagos/db/schema.sql new file mode 100644 index 0000000..d865e9d --- /dev/null +++ b/pagos/db/schema.sql @@ -0,0 +1,26 @@ +CREATE TABLE IF NOT EXISTS categorias ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + nombre TEXT NOT NULL, + icono TEXT NOT NULL, + color_hex TEXT DEFAULT '#005050' +); + +CREATE TABLE IF NOT EXISTS movimientos ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + tipo TEXT CHECK( tipo IN ('gasto','ingreso') ) NOT NULL, + monto REAL NOT NULL, + fecha TEXT NOT NULL, + notas TEXT, + id_categoria INTEGER, + fecha_creacion DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(id_categoria) REFERENCES categorias(id) +); + +-- Insertar algunas categorías por defecto +INSERT INTO categorias (nombre, icono, color_hex) VALUES +('Comida', 'restaurant', '#005050'), +('Vivienda', 'home', '#4d6357'), +('Transporte', 'directions_car', '#264b5c'), +('Servicios', 'bolt', '#3e4948'), +('Entretenimiento', 'movie', '#006a6a'), +('Salario / Ingresos', 'payments', '#006a6a'); diff --git a/pagos/index.html b/pagos/index.html new file mode 100644 index 0000000..27a9644 --- /dev/null +++ b/pagos/index.html @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + +
+
+
+account_balance_wallet +

Quiet Wealth

+
+
+ +
+
+
+
+ +
+

Resumen

+

Octubre 2023

+
+ +
+ +
+
+
+

Balance Total

+

$0.00

+
+trending_up ++12.4% este mes +
+
+
+ +
+

Distribución de Gastos

+
+ +
+ + + + + + + + +
+$2,840 +Gastado +
+
+ +
+
+
+
+Comida +
+45% +
+
+
+
+Vivienda +
+30% +
+
+
+
+Transporte +
+15% +
+
+
+
+ +
+
+

Movimientos Recientes

+ +
+
+ +
+
+
+restaurant +
+
+

Restaurante La Paz

+

24 Oct 2023

+
+
+

-$45.50

+
+ +
+
+
+shopping_bag +
+
+

Tienda Moderna

+

22 Oct 2023

+
+
+

-$120.00

+
+ +
+
+
+payments +
+
+

Depósito de Nómina

+

20 Oct 2023

+
+
+

+$2,100.00

+
+
+
+
+ +