437 lines
16 KiB
Markdown
437 lines
16 KiB
Markdown
# 🎯 MEMORIA COMPLETA DEL PROYECTO - SaaS PageBuilder
|
|
|
|
**Fecha:** 13 Enero 2025
|
|
**Hash:** `gkachele-template-system-20250114-v1`
|
|
**Última actualización:** 14 Enero 2025 - 08:50
|
|
|
|
## 🎯 OBJETIVOS ACTUALES (Memorizado)
|
|
|
|
1. **Template y Menús Profesionales:**
|
|
- Adaptar al menos un template completo
|
|
- Sistema de menús dinámicos (header, footer, sidebar)
|
|
- Múltiples ubicaciones de menú
|
|
- Estructura modular (header.php, footer.php, sidebar.php)
|
|
- Sistema de widgets/áreas
|
|
|
|
2. **Mejorar Landing:**
|
|
- Diseño más profesional
|
|
- Mejor UX/UI
|
|
- Optimización de conversión
|
|
|
|
3. **Automatización con Gitea:**
|
|
- Integración Gitea para repos por cliente
|
|
- Automatización de despliegues
|
|
- Workflows automáticos
|
|
- Integración con n8n (futuro - para competir en Argentina)
|
|
|
|
## ⚠️ REQUISITOS PRINCIPALES (MEMORIZAR)
|
|
|
|
1. **Sincronización con Hash:** Raspberry y Local deben estar sincronizados con hash
|
|
2. **Modularizado:** Código debe estar modularizado
|
|
3. **PRIMERO copiar funcionalidad similar:** NO inventar, copiar funcionalidad similar primero en Raspberry, luego ver qué sirve y qué no
|
|
4. **Iterar:** Probar → Ver qué sirve → Eliminar lo que no sirve → Mejorar
|
|
|
|
**Ver:** `MEMORIA_SINCRONIZACION.md` para detalles
|
|
|
|
## 📍 CONEXIÓN RASPBERRY PI
|
|
|
|
**Credenciales SSH:**
|
|
- **Host:** `komkida.duckdns.org` o `192.168.1.134`
|
|
- **Puerto:** `2222`
|
|
- **Usuario:** `pi`
|
|
- **Password:** `Gdk1983gdk45@`
|
|
|
|
**Comandos de conexión (CON sshpass):**
|
|
```bash
|
|
# Desde WSL - CONECTAR
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134"
|
|
|
|
# COPIAR ARCHIVOS
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' scp -P 2222 -o StrictHostKeyChecking=no /mnt/c/word/demo/app.py pi@192.168.1.134:/home/pi/gkachele-saas/app.py"
|
|
|
|
# EJECUTAR COMANDO REMOTO
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134 'comando aqui'"
|
|
```
|
|
|
|
## 🏗️ ARQUITECTURA
|
|
|
|
### Stack Tecnológico
|
|
- **Backend:** Flask (Python 3) - NO Docker, directo
|
|
- **Base de datos:** SQLite (main.db + cliente-X.db)
|
|
- **Web Server:** Nginx (reverse proxy)
|
|
- **Dominio:** `gk-saas.komkida.duckdns.org`
|
|
- **Puerto Flask:** 5001
|
|
- **Puerto Nginx:** 80
|
|
|
|
### Estructura en Raspberry Pi
|
|
```
|
|
/home/pi/gkachele-saas/
|
|
├── app.py # Flask backend principal
|
|
├── database/
|
|
│ ├── main.db # DB principal (users, sites, requests, media)
|
|
│ └── sites/ # DBs por cliente
|
|
│ ├── cliente-1.db
|
|
│ └── cliente-2.db
|
|
├── sites/ # Sitios compilados/publicados
|
|
├── themes/ # Templates (como WordPress)
|
|
│ ├── gimnasio-claro/
|
|
│ ├── restaurante-moderno/
|
|
│ └── restaurante-elegante/
|
|
├── static/ # CSS, JS, imágenes
|
|
├── templates/ # HTML templates
|
|
│ ├── landing_real.html # Landing GKACHELE™
|
|
│ ├── register.html
|
|
│ ├── login.html
|
|
│ ├── dashboard.html # Dashboard CLIENTE
|
|
│ ├── customizer.html # Personalizador WordPress-like
|
|
│ ├── admin.html # Dashboard PRINCIPAL (tuyo)
|
|
│ └── client_admin.html # Admin del cliente
|
|
└── uploads/ # Media subida por clientes
|
|
```
|
|
|
|
### Estructura en Local (Desarrollo)
|
|
```
|
|
C:\word\
|
|
├── demo/ # Código del SaaS
|
|
│ ├── app.py
|
|
│ ├── database/
|
|
│ ├── themes/
|
|
│ ├── templates/
|
|
│ └── static/
|
|
├── update-raspberry.sh # Script para actualizar Raspberry
|
|
└── MEMORIA_PROYECTO_COMPLETA.md # Este archivo
|
|
```
|
|
|
|
## 🔄 FLUJO COMPLETO
|
|
|
|
```
|
|
1. Cliente → Landing (gk-saas.komkida.duckdns.org)
|
|
2. Cliente elige plan + rubro → /register?plan=base&rubro=restaurante
|
|
3. Cliente se registra → POST /register
|
|
├── Crea usuario en main.db (tabla users)
|
|
├── Crea sitio automático (tema según rubro) en main.db (tabla sites)
|
|
└── Guarda sesión → Redirige a /dashboard (equivalente a wp-admin)
|
|
4. Dashboard → Cliente ve SUS sitios
|
|
5. Customizer → /customizer/{site_id} (sidebar + preview)
|
|
6. Cliente envía → POST /dashboard/submit/{site_id}
|
|
7. Admin → /admin (solo user_id=1) aprueba
|
|
8. Publicado → /site/{slug}
|
|
```
|
|
|
|
## 🗄️ BASES DE DATOS
|
|
|
|
### main.db (SQLite) - TODO EN UNA SOLA BASE DE DATOS (Multi-tenant como WordPress)
|
|
|
|
**✅ Sistema Multi-tenant:** Todos los clientes en una sola base de datos, cada cliente solo ve SUS datos a través de `/dashboard` (equivalente a wp-admin)
|
|
|
|
**Tabla: users**
|
|
- id, email (UNIQUE), password (hash), plan, rubro, created_at
|
|
- Todos los usuarios/clientes están aquí
|
|
|
|
**Tabla: sites**
|
|
- id, user_id (FK), slug (UNIQUE), theme, status (draft/pending/published), content_json, created_at
|
|
- Todos los sitios, filtrados por user_id (cada cliente solo ve los suyos)
|
|
|
|
**Tabla: requests**
|
|
- id, site_id (FK), user_id (FK), status (pending/approved/rejected), created_at
|
|
- Solicitudes de publicación
|
|
|
|
**Tabla: media**
|
|
- id, user_id (FK), site_id (FK), filename, filepath, file_type, uploaded_at
|
|
- Archivos subidos por clientes, filtrados por user_id
|
|
|
|
**Tabla: content**
|
|
- id, user_id (FK), site_id (FK), section, data_json, updated_at
|
|
- Contenido por sección (futuro uso), filtrado por user_id y site_id
|
|
|
|
**Tabla: settings**
|
|
- id, user_id (FK), site_id, key, value, created_at, updated_at
|
|
- Configuraciones (como wp_options en WordPress), filtrado por user_id y site_id
|
|
|
|
**Tabla: menus**
|
|
- id, user_id (FK), site_id (FK), location (header/footer/sidebar), title, url, order_index, parent_id, created_at
|
|
- Sistema de menús dinámicos por ubicación, filtrado por user_id y site_id
|
|
|
|
**Tabla: widgets**
|
|
- id, user_id (FK), site_id (FK), area (sidebar/footer/etc), type, title, content, order_index, created_at, updated_at
|
|
- Sistema de widgets dinámicos por área, filtrado por user_id y site_id
|
|
|
|
## 🎨 TEMPLATES (Sistema WordPress-like)
|
|
|
|
### Templates Disponibles
|
|
- **gimnasio-claro:** Tema para gimnasios (rojo/negro)
|
|
- **restaurante-moderno:** Tema moderno (rojo/naranja) - 2 variantes
|
|
- **restaurante-elegante:** Tema elegante (marrón/dorado)
|
|
|
|
### Estructura de Template (Sistema Modular GKACHELE™)
|
|
```
|
|
themes/
|
|
├── _gkachele/ # Sistema base modular (como WordPress)
|
|
│ ├── header.php # Header con menús dinámicos
|
|
│ ├── footer.php # Footer con copyright GKACHELE™
|
|
│ └── sidebar.php # Sidebar con widgets dinámicos
|
|
├── {nombre}/ # Temas específicos
|
|
│ ├── config.json # Configuración (colores, tipografía, secciones)
|
|
│ ├── template.html # HTML del template (contenido principal)
|
|
│ └── style.css # CSS (opcional)
|
|
```
|
|
|
|
**Sistema de Renderizado:**
|
|
- `render_gkachele_template()` concatena: `header.php` + `template.html` + `sidebar.php` + `footer.php`
|
|
- Menús y widgets se cargan dinámicamente desde la base de datos
|
|
- Soporte para múltiples ubicaciones de menú (header, footer, sidebar)
|
|
- Widgets por área (sidebar, footer, etc.)
|
|
|
|
### Asignación Automática
|
|
- **restaurante:** Aleatorio entre `restaurante-moderno` y `restaurante-elegante`
|
|
- **gimnasio/gimnasios:** `gimnasio-claro`
|
|
- **Otros:** `default`
|
|
|
|
## 🔧 CONFIGURACIÓN NGINX
|
|
|
|
**Archivo:** `/etc/nginx/sites-available/gk-saas.komkida.duckdns.org.conf`
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name gk-saas.komkida.duckdns.org;
|
|
|
|
location / {
|
|
proxy_pass http://localhost:5001;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
}
|
|
```
|
|
|
|
**Comandos:**
|
|
```bash
|
|
sudo nginx -t # Verificar configuración
|
|
sudo systemctl reload nginx # Recargar
|
|
tail -f /var/log/nginx/gk-saas-error.log # Ver logs
|
|
```
|
|
|
|
## 🔄 SERVICIO SYSTEMD
|
|
|
|
**Archivo:** `/etc/systemd/system/gkachele-saas.service`
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=GKACHELE SaaS Flask App
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=pi
|
|
WorkingDirectory=/home/pi/gkachele-saas
|
|
Environment="PATH=/usr/bin:/usr/local/bin:/home/pi/.local/bin"
|
|
ExecStart=/usr/bin/python3 /home/pi/gkachele-saas/app.py
|
|
Restart=always
|
|
RestartSec=10
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
**Comandos:**
|
|
```bash
|
|
sudo systemctl start gkachele-saas # Iniciar
|
|
sudo systemctl stop gkachele-saas # Detener
|
|
sudo systemctl restart gkachele-saas # Reiniciar
|
|
sudo systemctl status gkachele-saas # Estado
|
|
journalctl -u gkachele-saas -f # Ver logs
|
|
```
|
|
|
|
## 🚀 ACTUALIZAR CÓDIGO EN RASPBERRY
|
|
|
|
### Método Correcto (con sshpass desde WSL):
|
|
```bash
|
|
# 1. Copiar código actualizado
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' scp -P 2222 -o StrictHostKeyChecking=no /mnt/c/word/demo/app.py pi@192.168.1.134:/home/pi/gkachele-saas/app.py"
|
|
|
|
# 2. Reiniciar app (matar proceso y reiniciar)
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134 'pkill -f \"python3 app.py\" && cd ~/gkachele-saas && nohup python3 app.py > /tmp/app.log 2>&1 &'"
|
|
```
|
|
|
|
### Instalar Servicio Systemd (una vez):
|
|
```bash
|
|
# Copiar servicio
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' scp -P 2222 -o StrictHostKeyChecking=no gkachele-saas.service pi@192.168.1.134:/tmp/"
|
|
|
|
# Instalar servicio
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134 'sudo mv /tmp/gkachele-saas.service /etc/systemd/system/ && sudo systemctl daemon-reload && sudo systemctl enable gkachele-saas && sudo systemctl start gkachele-saas'"
|
|
```
|
|
|
|
### Configurar Cron en Raspberry (actualizar automáticamente):
|
|
```bash
|
|
# 1. Crear script de actualización
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' scp -P 2222 -o StrictHostKeyChecking=no update-app-raspberry.sh pi@192.168.1.134:~/scripts/update-app.sh"
|
|
|
|
# 2. Dar permisos
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134 'chmod +x ~/scripts/update-app.sh'"
|
|
|
|
# 3. Agregar a crontab (cada hora) - requiere permisos
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134 'echo \"0 * * * * /home/pi/scripts/update-app.sh\" | crontab -'"
|
|
|
|
# Verificar cron
|
|
wsl bash -c "sshpass -p 'Gdk1983gdk45@' ssh -p 2222 -o StrictHostKeyChecking=no pi@192.168.1.134 'crontab -l'"
|
|
```
|
|
|
|
**NOTA:** El cron actualiza cada hora. Para actualizar manualmente el código, usar el método de SCP arriba.
|
|
|
|
## 📋 RUTAS PRINCIPALES
|
|
|
|
### Públicas
|
|
- `GET /` - Landing page
|
|
- `GET /register` - Formulario registro
|
|
- `POST /register` - Crear usuario (JSON)
|
|
- `GET /login` - Formulario login
|
|
- `POST /login` - Iniciar sesión (JSON)
|
|
- `GET /site/{slug}` - Sitio público publicado
|
|
|
|
### Cliente (requiere sesión)
|
|
- `GET /dashboard` - Dashboard del cliente
|
|
- `GET /customizer/{site_id}` - Personalizador
|
|
- `POST /api/customizer/save` - Guardar cambios
|
|
- `GET /api/customizer/preview-frame/{site_id}` - Preview iframe
|
|
- `POST /dashboard/submit/{site_id}` - Enviar para aprobación
|
|
- `GET /dashboard/admin` - Admin del cliente (media, config)
|
|
|
|
### APIs de Menús y Widgets
|
|
- `GET /api/menus/<site_id>` - Obtener menús del sitio
|
|
- `POST /api/menus/<site_id>` - Guardar/actualizar menús
|
|
- `GET /api/widgets/<site_id>` - Obtener widgets del sitio
|
|
- `POST /api/widgets/<site_id>` - Guardar/actualizar widgets
|
|
|
|
### Admin Principal (solo user_id=1)
|
|
- `GET /admin` - Dashboard principal
|
|
- `POST /admin/approve/{request_id}` - Aprobar solicitud
|
|
- `POST /admin/reject/{request_id}` - Rechazar solicitud
|
|
|
|
## 🔐 SEGURIDAD
|
|
|
|
### Sesiones
|
|
- Flask `session` con `secret_key`
|
|
- Cookie `SESSION_COOKIE_SAMESITE = 'Lax'`
|
|
- Sesión se guarda después de login exitoso
|
|
|
|
### Acceso
|
|
- **Clientes:** Solo ven SUS sitios (filtrado por `user_id` en sesión)
|
|
- **Admin:** Solo `user_id = 1` puede acceder a `/admin`
|
|
- **Passwords:** Hash con `werkzeug.security.generate_password_hash`
|
|
|
|
## 🎯 ESTADO ACTUAL
|
|
|
|
### ✅ Funcionando
|
|
- Landing page (GKACHELE™ original)
|
|
- Registro de clientes → Redirige a `/login` (sin sesión automática)
|
|
- Login de clientes → Redirige a `/dashboard`
|
|
- Dashboard del cliente
|
|
- Customizer básico (sidebar + preview)
|
|
- Templates: gimnasio-claro, restaurante-moderno, restaurante-elegante
|
|
- **Sistema modular de templates (_gkachele/header.php, footer.php, sidebar.php)**
|
|
- **Sistema de menús dinámicos (header, footer, sidebar)**
|
|
- **Sistema de widgets dinámicos (sidebar, footer, etc.)**
|
|
- **Función `render_gkachele_template()` para renderizado completo**
|
|
- **APIs para gestionar menús y widgets**
|
|
- Base de datos SQLite multi-tenant (main.db con tablas menus y widgets)
|
|
- Nginx reverse proxy
|
|
- Systemd service
|
|
- DuckDNS para dominio remoto
|
|
- Scripts de gestión: `ver_usuarios.py`, `limpiar_db.py`
|
|
|
|
### ⚠️ Pendiente
|
|
- Drag & drop de secciones (SortableJS)
|
|
- Edición inline (contenteditable)
|
|
- Gitea para repos por cliente + automatización
|
|
- Dashboard principal para aprobar solicitudes
|
|
- Plugins sencillos (colores, tipografía avanzada)
|
|
- SSL/HTTPS (Let's Encrypt)
|
|
|
|
### 🎯 PRÓXIMOS OBJETIVOS (PRIORITARIOS)
|
|
1. **✅ Template y Menús Profesionales (COMPLETADO):**
|
|
- ✅ Sistema modular (_gkachele/header.php, footer.php, sidebar.php)
|
|
- ✅ Sistema de menús dinámicos (header, footer, sidebar)
|
|
- ✅ Múltiples ubicaciones de menú
|
|
- ✅ Sistema de widgets/áreas
|
|
- ⚠️ **PENDIENTE:** UI completa para gestionar menús desde customizer (actualmente solo placeholder)
|
|
|
|
2. **Mejorar Landing:**
|
|
- Diseño más profesional
|
|
- Mejor UX/UI
|
|
- Optimización de conversión
|
|
|
|
3. **Automatización con Gitea:**
|
|
- Integración Gitea para repos por cliente
|
|
- Automatización de despliegues
|
|
- Workflows automáticos
|
|
- Integración con n8n (futuro)
|
|
|
|
## 📦 DEPENDENCIAS
|
|
|
|
**Python:**
|
|
- Flask
|
|
- Werkzeug (password hashing)
|
|
- SQLite3 (built-in)
|
|
|
|
**Instalación:**
|
|
```bash
|
|
pip3 install Flask Werkzeug
|
|
```
|
|
|
|
## 🌐 DUCKDNS
|
|
|
|
**Dominios:**
|
|
- **komkida.duckdns.org:** Token `9c5cff88-b6d7-4704-9b10-4a69afdff797`
|
|
- **gkachele.duckdns.org:** Token `578331b3-ad7b-4154-835d-e496465257b0`
|
|
|
|
**Actualizar IP:**
|
|
```bash
|
|
python3 update-komkida-duckdns.py
|
|
```
|
|
|
|
## 🚀 MIGRACIÓN A VPS
|
|
|
|
**Pasos:**
|
|
1. Copiar `/home/pi/gkachele-saas/` completo
|
|
2. Instalar Python3, Nginx en VPS
|
|
3. Copiar configuración Nginx
|
|
4. Copiar servicio systemd
|
|
5. Cambiar dominio (DuckDNS o dominio real)
|
|
6. Configurar SSL (Let's Encrypt)
|
|
|
|
**Ventajas:**
|
|
- ✅ Mismo código (sin cambios)
|
|
- ✅ Misma estructura
|
|
- ✅ Más recursos
|
|
- ✅ Mejor rendimiento
|
|
|
|
## 📝 NOTAS IMPORTANTES
|
|
|
|
- **NO usar Docker:** Todo corre directamente (Python + Nginx)
|
|
- **NO usar GitHub:** Todo es independiente en Raspberry
|
|
- **SQLite es suficiente:** Para SaaS pequeño, no necesita MySQL
|
|
- **Raspberry Pi 3:** Recursos limitados, pero suficiente para desarrollo
|
|
- **VPS recomendado:** Para producción con muchos clientes
|
|
|
|
## 📦 BACKUP Y VERSIONADO
|
|
|
|
**Hash Actual:** `gkachele-template-system-20250114-v1`
|
|
|
|
**Estado Verificado:**
|
|
- ✅ Templates _gkachele en Raspberry: header.php, footer.php, sidebar.php
|
|
- ✅ Función render_gkachele_template en app.py
|
|
- ✅ Tablas menus y widgets en main.db
|
|
- ✅ Servicio gkachele-saas activo
|
|
- ✅ Flujo de registro: Registro → Login → Dashboard → Customizer
|
|
|
|
**Scripts de Gestión:**
|
|
- `ver_usuarios.py` - Ver usuarios y sitios registrados
|
|
- `limpiar_db.py` - Limpiar base de datos (con confirmación)
|
|
- `verificar_raspberry.sh` - Verificar estado en Raspberry
|
|
|
|
---
|
|
**Última actualización:** 14 Enero 2025 - 08:50
|