se agrega .md de tailscale para hacer gitea https

This commit is contained in:
George committed 2026-10-20 11:18:08 -05:00
1 parent f915802fb4
commit 920a4a2d56
10 files changed
+2081 -2066

No files matched your search

+33 -12
View File
@@ -4,11 +4,11 @@
"type": "split",
"children": [
{
"id": "7eb63950e584c8c8",
"id": "74bf841407436ba6",
"type": "tabs",
"children": [
{
"id": "52972da0bc9d4ad0",
"id": "0519cc60f14f90b9",
"type": "leaf",
"state": {
"type": "markdown",
@@ -41,7 +41,9 @@
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
"autoReveal": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-folder-closed",
"title": "Files"
@@ -183,16 +185,38 @@
"bases:Create new base": false
}
},
"active": "52972da0bc9d4ad0",
"active": "0519cc60f14f90b9",
"lastOpenFiles": [
"005-Learn/Instructivo Git Gitea.md",
"005-Learn/Instructivo Entornos Virtuales Python.md",
"005-Learn/Instructivo Git Branches.md",
"005-Learn/Instructivo Git Gitea.md",
"005-Learn/Planificación desarrollo agente ia.md",
"005-Learn/Obsidian WorkingCopy Manual.md",
"005-Learn/Proyecto SAP B1 - FastAPI - React - Next.js.md",
"005-Learn/Roadmap Next.js.md",
"005-Learn/Instructivo launchd iOS.md",
"005-Learn/Guia_Entornos_Virtuales_Python.md",
"005-Learn/Stack Tecnológico Recomendado.md",
"005-Learn/Roadmap Next.js.md",
"005-Learn/Proyecto SAP B1 - FastAPI - React - Next.js.md",
"006-Proyecto-Bingo/07 UI Components.md",
"006-Proyecto-Bingo/06 Estados (Zustand).md",
"006-Proyecto-Bingo/04 Motor lógico de Bingo.md",
"006-Proyecto-Bingo/02 Diagrama.md",
"006-Proyecto-Bingo/01 Markdown del proyecto.md",
"006-Proyecto-Bingo/00 App Bingo.md",
"006-Proyecto-Bingo/03 SQLite.md",
"006-Proyecto-Bingo/05 Navegación.md",
"005-Learn/Instructivo_launchd_SAP_B1_SUNAT.md",
"006-Proyecto-Bingo/sqlite_erd_flat_design.png",
"006-Proyecto-Bingo/mockup-bingo.png",
"006-Proyectos/01 Proyecto App Bingo.md",
"006-Proyectos/07 Modelo de datos Isar.md",
"006-Proyectos/02 Arquitectura técnica.md",
"006-Proyectos/03 Entorno de desarrollo.md",
"006-Proyectos/06 Mockups base.md",
"006-Proyectos/04 Estructura de carpetas.md",
"006-Proyectos/05 Mockups iniciales.md",
"006-Proyecto-Bingo",
"005-Learn/roadmap_nextjs_erp.html",
"Instructivo Git Gitea.md",
"005-Learn",
"004-SDK-SAP",
"003-Hana",
@@ -200,9 +224,6 @@
"001-Linux",
"Untitled.canvas",
"Untitled.base",
"Roadmap-nextjs-erp.md",
"roadmap_nextjs_erp.html",
"2026-05-18.md",
"Welcome.md"
"roadmap_nextjs_erp.html"
]
}
@@ -0,0 +1,84 @@
# Creación de entornos virtuales en Python
## Requisitos
- Tener Python instalado.
- Verificar:
``` bash
python --version
```
## Crear el entorno
``` bash
python -m venv .venv
```
## Activar
### macOS / Linux
``` bash
source .venv/bin/activate
```
### Windows CMD
``` cmd
.venv\Scripts\activate.bat
```
### Windows PowerShell
``` powershell
.venv\Scripts\Activate.ps1
```
## Instalar dependencias
``` bash
pip install -r requirements.txt
```
o
``` bash
pip install requests fastapi uvicorn
```
## Guardar dependencias
``` bash
pip freeze > requirements.txt
```
## Desactivar
``` bash
deactivate
```
## Verificar el intérprete
``` bash
python -c "import sys; print(sys.executable)"
```
## .gitignore recomendado
``` gitignore
.venv/
__pycache__/
*.py[cod]
.vscode/
.idea/
.env
.pytest_cache/
.mypy_cache/
.ruff_cache/
*.sqlite3
*.db
.DS_Store
Thumbs.db
```
+624 -61
View File
@@ -1,192 +1,755 @@
# 🌿 Guía Completa para Crear y Manejar un Branch en Git
Porque romper `main` directamente es una tradición demasiado popular en desarrollo de software.
Git existe precisamente para evitar ese tipo de tragedias humanas.
Romper `main` directamente sigue siendo una tradición muy popular en desarrollo de software.
Git existe precisamente para evitar ese tipo de tragedias.
En esta guía usaremos un caso real como hilo conductor: una agencia que lleva un **proyecto por cada cliente**, y necesita crear una rama nueva cada vez que empieza a trabajar en la funcionalidad de un cliente específico (por ejemplo, `cliente-acme`).
```mermaid
gitGraph
commit id: "inicio"
commit id: "version estable"
branch cliente-acme
checkout cliente-acme
commit id: "dashboard acme"
commit id: "ajustes acme"
checkout main
merge cliente-acme id: "merge acme a main"
branch cliente-globex
checkout cliente-globex
commit id: "reporte globex"
checkout main
merge cliente-globex id: "merge globex a main"
```
---
# 1️⃣ Verifica el estado actual del proyecto
## 🗺️ Flujo general del proceso
```mermaid
flowchart TD
A[git status] --> B{Hay cambios sin guardar?}
B -- Si --> C[git add . + git commit]
B -- No --> D
C --> D[git checkout main]
D --> E[git pull]
E --> F["git checkout -b cliente-acme"]
F --> G[git branch para confirmar]
G --> H[Trabajar y hacer commits]
H --> I[git checkout main]
I --> J["git merge cliente-acme"]
J --> K[git push]
K --> L["git branch -d cliente-acme"]
```bash
git status
```
Esto te mostrará:
---
## 1️⃣ Verifica el estado actual del proyecto
```bash
git status
```
Esto te muestra:
- Archivos modificados
- Archivos en stage
- Archivos sin seguimiento
---
# 2️⃣ Guarda tus cambios importantes
Si tienes cambios importantes, crea un commit antes de crear el branch.
## 2️⃣ Guarda tus cambios importantes
Si tienes cambios importantes, crea un commit antes de crear el branch:
```bash
git add .
git commit -m "Version estable antes de nueva funcionalidad"
```
✅ Esto crea un punto seguro al cual regresar.
---
## 📦 Alternativa: usar stash
### 📦 Alternativa: usar stash
Si todavía no quieres hacer commit:
```bash
git stash
```
Luego podrás recuperarlos con:
```bash
git stash pop
```
---
# 3️⃣ Ve a la rama principal
## 3️⃣ Ve a la rama principal
```bash
git checkout main
```
---
# 4️⃣ Descarga lo último del repositorio
## 4️⃣ Descarga lo último del repositorio
```bash
git pull
```
Esto sincroniza tu proyecto local con el remoto.
---
# 5️⃣ Crea la nueva rama
```bash
git checkout -b nueva-funcionalidad
```
## 📌 Ejemplo real
```bash
git checkout -b agregar-dashboard-powerbi
```
---
# 6️⃣ Verifica que estás en la nueva rama
## 5️⃣ Crea la nueva rama
```bash
git checkout -b nombre-de-la-rama
```
### 📌 Ejemplo con proyecto por cliente
Supongamos que la agencia empieza a trabajar en el dashboard del cliente **Acme**:
```bash
git checkout -b cliente-acme
```
Si más adelante empieza otro proyecto, para el cliente **Globex**:
```bash
git checkout -b cliente-globex
```
De esta forma cada cliente tiene su propio espacio de trabajo aislado, sin afectar el código de los demás.
```mermaid
gitGraph
commit id: "main estable"
branch cliente-acme
branch cliente-globex
```
---
## 6️⃣ Verifica que estás en la nueva rama
```bash
git branch
```
La rama actual aparecerá con un `*`
## 📌 Ejemplo
La rama actual aparecerá marcada con un `*`.
### 📌 Ejemplo
```text
main
* agregar-dashboard-powerbi
* cliente-acme
cliente-globex
```
---
# 7️⃣ Trabaja normalmente y guarda cambios
## 7️⃣ Trabaja normalmente y guarda cambios
```bash
git add .
git commit -m "Agrega nueva funcionalidad"
git commit -m "Agrega dashboard de ventas para Acme"
```
Puedes repetir este paso tantas veces como necesites mientras avanzas en el proyecto del cliente:
```bash
git add .
git commit -m "Ajusta colores y logo segun manual de marca de Acme"
```
```mermaid
gitGraph
commit id: "main estable"
branch cliente-acme
checkout cliente-acme
commit id: "dashboard ventas"
commit id: "ajustes de marca"
```
---
# 8️⃣ Regresa a main cuando todo funcione
## 8️⃣ Regresa a main cuando todo funcione
```bash
git checkout main
```
---
# 9️⃣ Une la nueva funcionalidad a main
## 9️⃣ Une la nueva funcionalidad a main
```bash
git merge nueva-funcionalidad
git merge cliente-acme
```
### 📌 Ejemplo del resultado
```mermaid
gitGraph
commit id: "main estable"
branch cliente-acme
checkout cliente-acme
commit id: "dashboard ventas"
commit id: "ajustes de marca"
checkout main
merge cliente-acme id: "entrega a Acme lista"
```
---
# 🔟 Sube los cambios al repositorio remoto
## 🔟 Sube los cambios al repositorio remoto
```bash
git push
```
---
# 1️⃣1️⃣ Elimina la rama si ya no la necesitas
## 1️⃣1️⃣ Elimina la rama si ya no la necesitas
Una vez que el trabajo del cliente ya fue entregado y fusionado a `main`, puedes borrar la rama para mantener el repositorio limpio:
```bash
git branch -d nueva-funcionalidad
git branch -d cliente-acme
```
---
# 🧠 Recomendaciones importantes
Si Git no te deja borrarla porque detecta cambios sin fusionar, y estás seguro de que quieres eliminarla de todos modos:
✅ Nunca trabajes directamente sobre `main`
✅ Haz commits pequeños y claros
✅ Usa nombres descriptivos para tus branches
✅ Verifica siempre con `git status`
---
# 🚨 Comandos útiles extra
## Ver historial de commits
```bash
git branch -D cliente-acme
```
---
## 🧠 Recomendaciones importantes
✅ Nunca trabajes directamente sobre `main`
✅ Haz commits pequeños y claros
✅ Usa nombres descriptivos para tus branches (por ejemplo, `cliente-acme`, no `rama1`)
✅ Verifica siempre con `git status` antes de cambiar de rama
✅ Si manejas varios clientes a la vez, mantén una rama por cliente para evitar mezclar entregas
```mermaid
gitGraph
commit id: "main"
branch cliente-acme
branch cliente-globex
branch cliente-initech
checkout cliente-acme
commit id: "avance acme"
checkout cliente-globex
commit id: "avance globex"
checkout cliente-initech
commit id: "avance initech"
```
---
## ❓ ¿Siempre hay que hacer merge a main?
No. El `merge` a `main` solo tiene sentido si `main` representa algo que **todos los clientes comparten**. Si los cambios son exclusivos de un cliente y no deben mezclarse con nada más, tienes otras opciones.
### Opción 1: La rama del cliente vive sola (sin merge a main)
Trabajas y subes esa rama directamente, sin tocar `main`:
```bash
git checkout -b cliente-acme
# ... trabajas y haces commits ...
git push origin cliente-acme
```
`main` se queda intacto, y `cliente-acme` existe como una línea de desarrollo independiente para siempre (o hasta que ya no la necesites).
```mermaid
gitGraph
commit id: "main estable"
branch cliente-acme
checkout cliente-acme
commit id: "dashboard acme"
commit id: "ajustes acme"
```
Aquí `cliente-acme` nunca se vuelve a juntar con `main`.
### Opción 2: main es solo una plantilla base
Si cada cliente parte de una base común (por ejemplo, la plantilla del proyecto), tiene sentido traer cambios **de main hacia el cliente** cuando la plantilla mejora, pero no al revés:
```bash
git checkout cliente-acme
git merge main
```
Esto trae las mejoras de la plantilla al proyecto del cliente. Es al revés del flujo normal: en vez de `cliente-acme → main`, es `main → cliente-acme`.
```mermaid
gitGraph
commit id: "plantilla v1"
branch cliente-acme
checkout main
commit id: "plantilla v2 mejorada"
checkout cliente-acme
commit id: "avance acme"
merge main id: "trae mejoras de plantilla"
```
### Opción 3: Cada cliente es su propio repositorio o deploy
Si el código de cada cliente es tan distinto que ni siquiera comparte historial útil con los demás, muchas agencias usan directamente **una rama por cliente que se despliega tal cual**, sin merges entre ellas. En este caso `main` queda solo como referencia general, o incluso no se usa en ese repo.
```mermaid
gitGraph
commit id: "main (referencia)"
branch cliente-acme
branch cliente-globex
checkout cliente-acme
commit id: "deploy acme"
checkout cliente-globex
commit id: "deploy globex"
```
> 💡 Elige la opción según qué tan relacionado esté el trabajo entre clientes: si comparten código base, usa la Opción 2; si son totalmente independientes, la Opción 1 o la Opción 3.
---
## 🚨 Comandos útiles extra
### Ver historial de commits
```bash
git log --oneline
```
---
## Ver diferencias de archivos
### Ver diferencias de archivos
```bash
git diff
```
---
## Salir del visor de git diff
### Salir del visor de git diff / git log
Presiona:
```text
q
```
Porque claramente mostrar texto simple en terminal era demasiado fácil para Unix.
### Ver todas las ramas, incluidas las remotas
```bash
git branch -a
```
### Cambiar de una rama de cliente a otra rápidamente
```bash
git checkout cliente-globex
```
---
# 🎯 Resultado esperado
Tu flujo ideal debería verse así:
## 🎯 Resultado esperado
Tu flujo ideal, aplicado al caso de proyectos por cliente, debería verse así:
```text
main
└── nueva-funcionalidad
└── commits
└── merge a main
├── cliente-acme
│ └── commits del proyecto Acme
│ └── merge a main
├── cliente-globex
│ └── commits del proyecto Globex
│ └── merge a main
└── cliente-initech
└── commits del proyecto Initech
└── merge a main
```
Un proceso ordenado.
Casi sospechosamente profesional para estándares normales de desarrollo.
Un proceso ordenado, con una rama independiente por cada cliente, y `main` siempre reflejando el estado estable y entregado del trabajo.
+111 -67
View File
@@ -1,17 +1,30 @@
# 🚀 Subir proyecto local a Gitea (Mac + Tailscale)
## 1. Crear `.gitignore`
> Guía ordenada por **flujo normal de trabajo**. Si algo falla, sigue las marcas ⚠️ que apuntan a su resolución al final del documento.
---
## PARTE A — FLUJO NORMAL (paso a paso)
### 1. Crear repositorio en Gitea
- Nombre: `descarga_adjuntos_correos_cpe`
- Sin README
- Sin opciones automáticas
> Guarda la URL del repositorio para usarla después.
### 2. Crear `.gitignore`
```bash
cd /Users/george/descarga_adjuntos_correos_cpe
touch .gitignore
```
## 2. Editar `.gitignore`
### 3. Editar `.gitignore`
```bash
nano .gitignore
```
### Contenido recomendado
#### Contenido recomendado
```bash
__pycache__/
*.pyc
@@ -23,100 +36,131 @@ secrets.yaml
.idea/
```
## 3. Si ya hiciste `git add` antes del `.gitignore`
```bash
git rm -r --cached .
git add .
git commit -m "aplicar gitignore correctamente"
```
> ⚠️ ¿Ya habías hecho `git add` antes de crear el `.gitignore`? → [[#Resolución: archivos que debían ignorarse siguen apareciendo]]
## 4. Inicializar repositorio Git
### 4. Inicializar repositorio Git
```bash
cd /Users/george/descarga_adjuntos_correos_cpe
git init
```
## 5. Agregar archivos
### 5. Agregar archivos
```bash
git add .
```
## 6. Primer commit
> ⚠️ ¿Agregaste errores o archivos incorrectos? → [[#Resolución: quitar archivos del staging (deshacer git add)]]
### 6. Primer commit
```bash
git commit -m "primer commit"
```
## 6.1 Commit de un proyecto dentro de una Solución
> ⚠️ ¿El commit quedó mal y aún no hice push? → [[#Resolución: deshacer un commit antes de subirlo]]
### 7. Conectar repo local con Gitea
```bash
git remote add origin http://100.68.242.27:30000/george/descarga_adjuntos_correos_cpe.git
```
> ⚠️ ¿El remote ya existe o está mal configurado? → [[#Resolución: problemas con el remote]]
### 8. Subir código por primera vez
```bash
git branch -M main
git push -u origin main
```
> ⚠️ ¿El push falla por conexión o autenticación? → [[#Resolución: no puedo subir (push)]]
---
## PARTE B — VARIANTES DE COMMIT
Estos pasos van **después** del commit básico según lo que necesites.
### Commit de un proyecto dentro de una Solución
```bash
git add ProyectoA/
git status
git commit -m "mensaje commit para los archivos modificados del proyecto"
```
## 6.2 Commit de un archivo específico dentro de un proyecto
### Commit de un archivo específico dentro de un proyecto
```bash
git add ProyectoA/FacturaNegociable.cs
git status
git commit -m "mensaje commit para el archivo especifico del proyecto"
```
## 6. 3 Git reset , quita todos los archivos del staging area que coloco git add, reversa el git add antes del git commit
```bash
git reset
```
---
## 6. 4 Git reset , si ya hice commit, pero aún no hice push
```bash
git reset --soft HEAD~1
git reset
```
## PARTE C — FLUJO DIARIO
## 7. Crear repositorio en Gitea
- Nombre: descarga_adjuntos_correos_cpe
- Sin README
- Sin opciones automáticas
## 8. URL del repositorio
```bash
http://100.68.242.27:30000/george/descarga_adjuntos_correos_cpe.git
```
## 9. Conectar repo local con Gitea
```bash
git remote add origin http://100.68.242.27:30000/george/descarga_adjuntos_correos_cpe.git
```
## 10. Subir código por primera vez
```bash
git branch -M main
git push -u origin main
```
## 11. Cambiar URL del repositorio
```bash
git remote set-url origin http://100.x.x.x:3000/george/descarga_adjuntos_correos_cpe.git
git remote -v
```
## 12. Eliminar y volver a configurar remote
```bash
git remote remove origin
git remote add origin http://100.68.242.27:3000/george/descarga_adjuntos_correos_cpe.git
```
## 13. Validar conexión
```bash
curl http://100.68.242.27:30000
```
## 14. Acceso a Gitea
[URL de Gitea en NAS](http://100.68.242.27:30000)
## 15. Flujo diario
```bash
git add .
git commit -m "mensaje claro"
git push
```
---
## PARTE D — CLONAR / REUTILIZAR
### Clonar repositorio
```bash
git clone http://100.68.242.27:3000/george/descarga_adjuntos_correos_cpe.git
```
### Validar conexión con Gitea
```bash
curl http://100.68.242.27:30000
```
---
## PARTE E — ACCESO
- [URL de Gitea en NAS](http://100.68.242.27:30000)
---
# 🔧 RESOLUCIÓN DE PROBLEMAS
## Resolución: archivos que debían ignorarse siguen apareciendo
Si ya hiciste `git add` antes del `.gitignore`, quitalos del índice:
```bash
git rm -r --cached .
git add .
git commit -m "aplicar gitignore correctamente"
```
## Resolución: quitar archivos del staging (deshacer git add)
Si agregaste archivos que no deberían ir, reversa el `git add` **antes** de commitear:
```bash
git reset
```
## Resolución: deshacer un commit antes de subirlo
Si ya hiciste commit pero **aún no** hiciste push:
```bash
git reset --soft HEAD~1
git reset
```
## Resolución: no puedo subir (push)
- Verifica la conexión con el NAS: `curl http://100.68.242.27:30000`
- Revisa si el remote está bien configurado: `git remote -v`
## Resolución: problemas con el remote (URL incorrecta o antigua)
### Cambiar la URL del repositorio
```bash
git remote set-url origin http://100.x.x.x:3000/george/descarga_adjuntos_correos_cpe.git
git remote -v
```
### Eliminar y volver a configurar el remote
```bash
git remote remove origin
git remote add origin http://100.68.242.27:3000/george/descarga_adjuntos_correos_cpe.git
```
+171
View File
@@ -0,0 +1,171 @@
# Instructivo: Ejecutar un servicio Python con launchd en macOS
## Objetivo
Ejecutar un servicio de Python de forma automática utilizando `launchd`.
## Estructura sugerida
``` text
/Users/george/services/sap_sunat/
.venv/
main.py
config.ini
logs/
stdout.log
stderr.log
```
## Verificar el entorno virtual
Activar:
``` bash
source .venv/bin/activate
```
Obtener el intérprete:
``` bash
which python
```
Usar esa ruta en `ProgramArguments`.
## Archivo .plist
Ubicación recomendada para un usuario:
``` text
~/Library/LaunchAgents/com.george.sap.sunat.plist
```
Claves habituales:
- `Label`
- `ProgramArguments`
- `WorkingDirectory`
- `RunAtLoad`
- `KeepAlive`
- `StandardOutPath`
- `StandardErrorPath`
## Comentarios
Se permiten comentarios XML:
``` xml
<!-- Comentario -->
```
También se pueden comentar bloques completos de claves.
## Cargar el servicio
``` bash
launchctl load ~/Library/LaunchAgents/com.george.sap.sunat.plist
```
En versiones recientes también:
``` bash
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.george.sap.sunat.plist
```
## Verificar
``` bash
launchctl list | grep sap
```
Información detallada:
``` bash
launchctl print gui/$(id -u)/com.george.sap.sunat
```
## Detener
``` bash
launchctl unload ~/Library/LaunchAgents/com.george.sap.sunat.plist
```
o
``` bash
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.george.sap.sunat.plist
```
## Monitorización
Monitor de Actividad: - Buscar `python` o `python3`.
Terminal:
``` bash
ps -ef | grep python
```
Consumo:
``` bash
ps -o pid,rss,vsz,%cpu,command -p <PID>
```
Ver logs:
``` bash
tail -f logs/stdout.log
tail -f logs/stderr.log
```
## Recomendaciones
- Usar `logging` con rotación.
- Manejar reconexión a SAP HANA.
- Implementar reintentos para SUNAT.
- Mantener configuración en `config.ini` o `.env`.
- Capturar `SIGTERM` para cerrar conexiones correctamente.
- Si el servicio es permanente, controlar internamente la frecuencia
de ejecución (cada 10 s entre 06:00 y 13:15; cada 30 min entre 13:15
y 14:00).
## Ejemplo de archivo .plist
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.george.sap.sunat</string>
<key>ProgramArguments</key>
<array>
<string>/Users/george/services/sap_sunat/.venv/bin/python</string>
<string>/Users/george/services/sap_sunat/main.py</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/george/services/sap_sunat</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/george/services/sap_sunat/logs/stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/george/services/sap_sunat/logs/stderr.log</string>
</dict>
</plist>
```
@@ -0,0 +1,674 @@
# Agente IA para SAP Business One + HANA
## Objetivo
Construir progresivamente un agente de IA tipo chat para la empresa, conectado a SAP Business One sobre HANA, usando modelos locales mediante Ollama.
La evolución prevista es:
- Consultas de negocio en lenguaje natural.
- KPIs.
- Análisis de datos.
- Gráficos y cuadros resumen.
- Reportes PDF y Excel.
- Resúmenes gerenciales.
- Alertas y análisis automáticos.
La estrategia es comenzar pequeño y agregar capacidades mediante herramientas independientes.
## Arquitectura
```text
USUARIO
|
v
+-------------+
| Chat Web UI |
| React/Vite |
+------+------+
|
v
+-------------+
| FastAPI |
| Backend |
+------+------+
|
+---------+---------+
| |
v v
+-----------+ +--------------+
| Ollama | | Tool / Skill |
| Local LLM | | Engine |
+-----------+ +-------+------+
|
+--------+--------+
| |
v v
SAP HANA SAP Service Layer
```
### Principio fundamental
El modelo de IA no debe tener acceso directo e irrestricto a SAP.
El LLM debe solicitar herramientas (`tools`) que ejecuten consultas controladas.
Ejemplo:
```text
Usuario: ¿Cuánto vendimos este mes?
|
v
Ollama
|
v
ventas_mes()
|
v
Python / FastAPI
|
v
SAP HANA
|
v
Resultado
|
v
Ollama
|
v
Respuesta al usuario
```
Esto permite controlar permisos, consultas y calidad de los resultados.
## Tecnologías
### Frontend
- React
- Vite
- Interfaz tipo ChatGPT
- Tablas
- Gráficos
- Dashboards
### Backend
- Python
- FastAPI
- Herramientas / Skills
- Control de acceso
- Gestión de conversaciones
- Generación de reportes
### IA
- Ollama
- Modelos locales
- Candidatos iniciales: Qwen 3 8B, Qwen 3 14B, Mistral Small y Gemma 3 12B.
- La elección final dependerá del hardware y de pruebas reales.
### Datos e integración
- SAP Business One
- SAP HANA
- Vistas HANA
- SQL controlado
- SAP Service Layer para operaciones que necesiten la lógica de SAP
### Visualización y documentos
- Plotly para gráficos interactivos
- Matplotlib para imágenes/gráficos destinados a documentos
- ReportLab para PDF
- OpenPyXL para Excel
# Fase 1: herramientas básicas
Crear inicialmente un conjunto pequeño de funciones Python:
```text
ventas_hoy()
ventas_mes()
top_clientes()
productos_mas_vendidos()
facturas_pendientes()
compras_mes()
stock_critico()
cuentas_por_cobrar()
cuentas_por_pagar()
utilidad_mes()
```
Cada herramienta ejecutará internamente una consulta SQL o utilizará una vista HANA.
El usuario pregunta:
```text
¿Cuánto vendimos este mes?
```
El agente determina:
```text
tool = ventas_mes()
```
Obtiene el resultado y genera una respuesta en lenguaje natural.
## Fase 2: herramientas con parámetros
Agregar parámetros:
```text
ventas_por_cliente(cliente)
ventas_por_fecha(desde, hasta)
compras_por_proveedor(proveedor, desde, hasta)
stock_almacen(almacen)
articulo(codigo)
```
Ejemplo:
```text
¿Cuánto le hemos vendido a Alicorp este año?
```
Puede interpretarse como:
```text
ventas_cliente(
cliente="ALICORP",
año=2026
)
```
## Fase 3: capa semántica empresarial
En lugar de hacer que el modelo conozca todas las tablas de SAP Business One, crear vistas orientadas al negocio:
```text
VW_VENTAS
VW_COMPRAS
VW_STOCK
VW_CXC
VW_CXP
VW_CLIENTES
VW_PRODUCTOS
VW_VENDEDORES
VW_KPI_VENTAS
VW_KPI_COBRANZAS
```
Las vistas deben presentar información clara y consistente, por ejemplo:
```text
Cliente
RUC
Vendedor
Línea
Ciudad
Total
Margen
Cantidad
Fecha
```
## Fase 4: SQL generado por IA
Cuando el sistema básico sea estable, se puede permitir que el modelo genere SQL, pero únicamente sobre vistas analíticas autorizadas.
Ejemplo:
```text
Vista: VW_VENTAS
Campos:
Fecha
Cliente
Ciudad
Total
Margen
Cantidad
Vendedor
```
Pregunta:
```text
¿Cuánto vendimos por ciudad?
```
Consulta posible:
```sql
SELECT
Ciudad,
SUM(Total) AS TotalVentas
FROM VW_VENTAS
GROUP BY Ciudad;
```
El backend debe validar el SQL antes de ejecutarlo.
## Fase 5: conversación con contexto
El agente debe mantener el contexto:
```text
Usuario: Muéstrame las ventas de marzo.
Agente: ...
Usuario: Ahora solo Lima.
Agente: ...
Usuario: Compáralo con febrero.
Agente: ...
Usuario: Haz un gráfico.
Agente: ...
```
## Fase 6: gráficos
El agente podrá generar visualizaciones como:
- Ventas por vendedor
- Ventas por ciudad
- Ventas mensuales
- Margen por línea
- Top 10 productos
- Top 10 clientes
- Evolución de cobranza
- Stock por almacén
Flujo:
```text
Pregunta -> Tool -> HANA -> Datos -> Motor de gráficos -> Gráfico -> Chat
```
## Fase 7: KPIs
Crear un catálogo de indicadores.
### Ventas
- Ventas del mes
- Ventas acumuladas
- Cumplimiento de meta
- Crecimiento vs. período anterior
- Ticket promedio
- Ventas por vendedor
- Ventas por cliente
- Ventas por producto
### Rentabilidad
- Margen bruto
- Margen por producto
- Margen por línea
- Margen por vendedor
### Inventario
- Stock disponible
- Stock crítico
- Rotación
- Productos sin movimiento
- Productos próximos a agotarse
### Finanzas
- Cuentas por cobrar
- Cuentas por pagar
- Vencimientos
- Cobranza
- Antigüedad de saldos
## Fase 8: reportes
El usuario podrá solicitar:
```text
Genera un resumen gerencial de junio.
```
El sistema:
1. Consulta los datos.
2. Calcula KPIs.
3. Genera gráficos.
4. Utiliza el LLM para interpretar los resultados.
5. Genera conclusiones.
6. Crea un PDF.
7. Puede crear un Excel.
Estructura posible:
```text
REPORTE GERENCIAL
Resumen ejecutivo
Ventas
Rentabilidad
Inventario
Cuentas por cobrar
Principales variaciones
Principales clientes
Principales productos
Conclusiones
```
## Fase 9: alertas automáticas
Ejemplo de resumen diario:
```text
Ventas: S/ 124,500
Meta: 95%
Margen: 28%
Top vendedor: Carlos
Productos sin stock: 14
Clientes con deuda: 18
```
El agente también podría detectar anomalías:
```text
- Las ventas de Arequipa disminuyeron 15%.
- El producto X cayó 20% respecto al promedio.
- Las cobranzas aumentaron 12%.
- Tres clientes concentran una parte importante de la deuda vencida.
```
La IA debe aportar principalmente interpretación de datos reales, no inventar respuestas plausibles.
## Seguridad
Principios desde el inicio:
- El LLM no debe tener credenciales directas de HANA.
- Las herramientas deben estar controladas por el backend.
- Separar consultas de lectura de operaciones de escritura.
- No permitir SQL arbitrario inicialmente.
- Validar parámetros.
- Registrar las consultas ejecutadas.
- Registrar usuario, herramienta y fecha.
- Controlar qué herramientas puede utilizar cada usuario.
- Utilizar Service Layer para operaciones que modifiquen SAP.
- No permitir que una pregunta de lenguaje natural ejecute operaciones destructivas.
Arquitectura de lectura:
```text
Usuario -> LLM -> Tool controlada -> Vista/Query HANA -> Resultado
```
Arquitectura de operaciones:
```text
Usuario -> LLM -> Tool controlada -> Validación -> Service Layer -> SAP Business One
```
# Capa semántica empresarial
Uno de los componentes más importantes será un catálogo que explique al agente qué significa cada dato.
Ejemplo:
```text
VW_VENTAS
Descripción:
Información consolidada de documentos de venta.
Campos:
Fecha
Fecha del documento.
Cliente
Código del cliente.
NombreCliente
Nombre comercial.
Vendedor
Vendedor responsable.
Total
Importe total del documento.
Margen
Margen bruto calculado.
Cantidad
Cantidad vendida.
```
También se deben documentar reglas de negocio, por ejemplo:
```text
"Ventas" significa documentos de venta contabilizados.
"No considerar documentos cancelados."
"Margen" se calcula utilizando el costo correspondiente.
"Ventas del mes" utiliza DocDate salvo que se indique otra fecha.
```
Esto será más importante que intentar meter miles de tablas SAP en el contexto del LLM.
# Estructura inicial del proyecto
```text
agente_sap/
|
+-- app/
| +-- main.py
| +-- api/
| | +-- chat.py
| | +-- reports.py
| +-- agent/
| | +-- agent.py
| | +-- prompts.py
| | +-- tools.py
| +-- tools/
| | +-- ventas.py
| | +-- compras.py
| | +-- stock.py
| | +-- clientes.py
| | +-- finanzas.py
| +-- database/
| | +-- hana.py
| +-- sap/
| | +-- service_layer.py
| +-- reports/
| | +-- pdf.py
| | +-- excel.py
| +-- charts/
| +-- charts.py
|
+-- frontend/
| +-- ...
|
+-- sql/
| +-- views/
| +-- queries/
|
+-- docs/
| +-- semantic_layer/
|
+-- tests/
|
+-- .env
+-- requirements.txt
+-- README.md
```
# Primera versión recomendada
No empezar con dashboards, agentes autónomos ni SQL generado por IA.
La primera versión debería hacer solamente:
```text
Chat
|
v
Ollama
|
v
Tools Python
|
v
HANA
|
v
Resultado
|
v
Ollama
|
v
Respuesta
```
Con cinco herramientas iniciales:
```text
ventas_hoy()
ventas_mes()
top_clientes()
stock_critico()
cuentas_por_cobrar()
```
Y una interfaz web sencilla.
# Evolución recomendada
```text
FASE 1
Chat + Ollama + 5 tools
|
v
FASE 2
Tools con parámetros
|
v
FASE 3
Vistas HANA / capa semántica
|
v
FASE 4
SQL controlado sobre vistas
|
v
FASE 5
Contexto conversacional
|
v
FASE 6
Gráficos
|
v
FASE 7
KPIs
|
v
FASE 8
PDF / Excel
|
v
FASE 9
Dashboards
|
v
FASE 10
Alertas y análisis automáticos
```
# Objetivo final
El asistente podrá responder preguntas como:
```text
¿Cuánto vendimos este mes?
¿Cuáles son nuestros 10 mejores clientes?
¿Qué productos están cayendo en ventas?
¿Qué vendedores no están alcanzando su meta?
¿Cuánto tenemos pendiente de cobrar?
¿Qué clientes tienen mayor deuda vencida?
¿Cómo se comportaron las ventas frente al mes anterior?
¿Cuál es nuestro margen promedio?
Genera un reporte gerencial del mes.
Genera un Excel con las ventas por vendedor.
Muéstrame un gráfico de ventas de los últimos 12 meses.
¿Qué problemas ves en los datos de este mes?
```
Posteriormente:
```text
Analiza la situación comercial de la empresa
y dame las principales conclusiones.
```
Las conclusiones deben basarse en datos reales obtenidos de SAP, no en respuestas inventadas por el modelo.
# Principio de diseño
La arquitectura debe ser modular.
Cada nueva capacidad debe incorporarse como una nueva herramienta:
```text
Nueva necesidad
|
v
Nueva Tool
|
v
Consulta / Vista HANA
|
v
Documentación semántica
|
v
Disponible para el agente
```
Esto permite crecer sin rehacer toda la aplicación.
# Conclusión
La estrategia recomendada es construir primero un **asistente de consulta sobre SAP Business One**, no un sistema autónomo.
La combinación:
```text
React
+
FastAPI
+
Ollama
+
Tools Python
+
SAP HANA
+
Service Layer
```
es suficiente para construir una primera versión sólida.
La pieza más importante no será el modelo de IA, sino la **capa de herramientas y conocimiento empresarial** que conectará el lenguaje natural con los datos reales de SAP.
El modelo puede cambiarse posteriormente. Las herramientas, vistas, reglas de negocio y capa semántica serán el verdadero activo del proyecto.
@@ -1,587 +0,0 @@
# Proyecto ERP Web Empresarial Integrado con SAP Business One Service Layer
# Objetivo General
Desarrollar una aplicación web empresarial para mantenimiento de datos maestros de Socios de Negocio similar al formulario estándar de SAP Business One.
La solución utilizará:
- Frontend:
- React.js
- Next.js
- TypeScript
- Backend:
- Python
- FastAPI
- Integración:
- SAP Business One Service Layer
---
# Filosofía de Arquitectura
La solución debe:
- Ser escalable
- Ser desacoplada
- Tener arquitectura por capas
- Tener código mantenible
- Tener funciones pequeñas y reutilizables
- Aplicar principios SOLID
- Tener separación de responsabilidades
- Tener documentación técnica
---
# Arquitectura General
```mermaid
flowchart TD
A[Frontend Next.js] --> B[Backend FastAPI]
B --> C[SAP Business One Service Layer]
C --> D[SAP Business One Database]
```
---
# Tecnologías
# Frontend
- React.js
- Next.js
- TypeScript
- React Hook Form
- Zod
- Axios
- Zustand
- TailwindCSS
- Shadcn UI
---
# Backend
- Python
- FastAPI
- Pydantic
- SQLAlchemy
- httpx
- passlib[bcrypt]
- JWT Authentication
---
# Integración SAP
- SAP Business One Service Layer
- Session Management
- B1SESSION
- ROUTEID
---
# Estrategia de Desarrollo por Etapas
# IMPORTANTE
NO desarrollar frontend y backend simultáneamente.
El proyecto debe ejecutarse por etapas para:
- minimizar errores
- facilitar pruebas
- mantener arquitectura limpia
- evitar acoplamiento prematuro
---
# ETAPA 1 - Diseño de Arquitectura
## Objetivo
Definir completamente la arquitectura antes de programar.
---
## Tareas
### 1. Crear diagramas Mermaid
Crear:
- arquitectura general
- flujo login
- flujo CRUD
- flujo Service Layer
- arquitectura backend
- arquitectura frontend
---
## Diagramas recomendados
### Flujo Login
```mermaid
sequenceDiagram
Frontend->>Backend: Login usuario
Backend->>SAP Service Layer: Login técnico SAP
SAP Service Layer-->>Backend: B1SESSION
Backend->>SAP Service Layer: Consultar EmployeesInfo
SAP Service Layer-->>Backend: Datos usuario
Backend-->>Frontend: JWT
```
---
### Arquitectura Backend
```mermaid
flowchart TD
A[Routes] --> B[Services]
B --> C[Repositories]
C --> D[SAP Integration]
D --> E[Service Layer]
```
---
# Resultado esperado ETAPA 1
- Diagramas completos
- Arquitectura definida
- Carpetas definidas
- Responsabilidades definidas
---
# ETAPA 2 - Backend Base
# IMPORTANTE
Primero construir backend.
Razones:
- frontend depende APIs
- frontend depende autenticación
- frontend depende estructura JSON
- frontend depende validaciones
---
# Objetivos ETAPA 2
Construir:
- estructura FastAPI
- autenticación
- integración SAP
- manejo sesiones
- JWT
- logging
- manejo errores
---
# Estructura Backend
```text
/app
/api
/services
/repositories
/schemas
/models
/validators
/middlewares
/core
/integrations
/sap
/utils
/queries
```
---
# Funcionalidades Backend Iniciales
## 1. Login SAP técnico
Endpoint:
```text
POST /auth/login
```
---
## 2. Session Manager SAP
Implementar:
- login automático
- refresh automático
- manejo cookies
- timeout
- retry policy
---
## 3. JWT propio
Implementar:
- access token
- refresh token
- expiración
- middleware autenticación
---
## 4. Integración OHEM
Usar:
```text
EmployeesInfo
```
del Service Layer.
---
# Usuarios
Los usuarios funcionales estarán en:
```text
OHEM
```
mediante Service Layer.
---
# UDFs requeridos
| Campo | Uso |
|---|---|
| U_APP_USERNAME | Usuario |
| U_APP_PASSWORD | Password hash |
| U_APP_ROLE | Rol |
| U_APP_ACTIVE | Estado |
---
# Seguridad Passwords
Usar:
```text
bcrypt
```
Nunca guardar passwords en texto plano.
---
# Resultado esperado ETAPA 2
- Backend funcionando
- Login funcionando
- JWT funcionando
- Integración SAP funcionando
---
# ETAPA 3 - CRUD Socios de Negocio
# Objetivo
Implementar CRUD Business Partners.
---
# Entidad principal
```text
BusinessPartners
```
---
# Campos OCRD
| Campo | Uso |
|---|---|
| CardCode | Código |
| CardName | Nombre |
| CardType | Tipo |
| LicTradNum | Documento |
| Phone1 | Teléfono |
| E_Mail | Correo |
| Currency | Moneda |
| GroupCode | Grupo |
---
# Campos CRD1
| Campo | Uso |
|---|---|
| Address | Dirección |
| Country | País |
| Street | Calle |
| ZipCode | Código Postal |
| AdresType | Tipo |
---
# Reglas de negocio
## LicTradNum
Debe:
- tener 8 caracteres
- ser numérico
---
## CardCode
Debe autogenerarse:
```text
CardType + LicTradNum
```
Ejemplo:
```text
C12345678
```
---
# Operaciones CRUD
| Operación | Método |
|---|---|
| Listar | GET |
| Obtener | GET |
| Crear | POST |
| Actualizar | PATCH |
| Eliminar | DELETE/PATCH |
---
# Resultado esperado ETAPA 3
- CRUD completo
- Validaciones
- Integración real SAP
---
# ETAPA 4 - Queries Optimizados
# Objetivo
Mejorar performance.
---
# IMPORTANTE
NO usar entidades completas SAP para listados masivos.
---
# Estrategia
## Escrituras
Usar:
- Service Layer estándar
---
## Lecturas masivas
Usar:
- SQLQueries
- queries optimizados
- paginación
---
# Resultado esperado ETAPA 4
- Listados rápidos
- Filtros
- Paginación
---
# ETAPA 5 - Frontend Base
# Objetivo
Construir frontend luego de estabilizar backend.
---
# Estructura Frontend
```text
/src
/app
/components
/services
/hooks
/layouts
/store
/validators
/types
/utils
```
---
# Pantallas Iniciales
## Login
Campos:
- usuario
- password
- company db
---
## Master Layout
- sidebar
- header
- content
---
## Socio de Negocio
- formulario OCRD
- grid CRD1
- CRUD
- validaciones
---
# Resultado esperado ETAPA 5
- Login UI
- navegación
- consumo APIs
---
# ETAPA 6 - Frontend Empresarial
# Objetivo
Mejorar experiencia usuario.
---
# Funcionalidades
- loading states
- toast notifications
- manejo errores
- tablas
- búsqueda
- debounce
- paginación
- responsive
---
# ETAPA 7 - Seguridad y Performance
# Objetivo
Preparar entorno productivo.
---
# Implementar
- cache
- retry policy
- correlation ID
- logs
- auditoría
- middleware seguridad
- rate limiting
- circuit breaker
---
# ETAPA 8 - DevOps y Despliegue
# Backend
- Docker
- Variables entorno
- Gunicorn/Uvicorn
---
# Frontend
- Build Next.js
- Reverse proxy
---
# Infraestructura
- HTTPS
- NGINX
- SSL
- monitoreo
---
# Recomendaciones Arquitectónicas
## NO hacer
- acceso SQL directo escritura SAP
- passwords en texto plano
- lógica SAP en frontend
- consultas gigantes Service Layer
---
# SI hacer
- backend desacoplado
- funciones pequeñas
- validaciones separadas
- logs centralizados
- manejo global errores
---
# Objetivo Final
Construir una plataforma empresarial:
- mantenible
- escalable
- desacoplada
- compatible con SAP Business One
- optimizada para crecimiento futuro
-746
View File
@@ -1,746 +0,0 @@
# Hoja de Ruta: Desarrollo de Aplicaciones Operacionales para SAP Business One con Next.js
> Duración estimada: 4 a 5 meses
> Objetivo: Construir aplicaciones web operacionales simples, rápidas y mantenibles conectadas a SAP Business One mediante Service Layer.
---
# Objetivo real del proyecto
El objetivo NO es crear un ERP completo como SAP Business One.
El objetivo es desarrollar:
- formularios operacionales específicos
- módulos independientes
- validaciones empresariales
- procesos rápidos para usuarios internos
Cada módulo tendrá:
- una funcionalidad específica
- su propia lógica
- su propio formulario
- integración con SAP Business One
---
# Filosofía del sistema
SAP Business One seguirá siendo:
```text
Sistema maestro ERP
```
La aplicación web será:
```text
Frontend operacional especializado
↓
Validaciones empresariales
↓
Integración con SAP Service Layer
```
---
# Ejemplos reales de módulos
## Almacén
- Recepción de Orden de Compra
- Transferencias de almacén
- Validación de lotes
- Conteo de inventario
---
## Compras
- Factura de gastos
- Factura de productos
- Distribución por centros de costo
- Validación SUNAT
---
## Ventas
- Validación de pedidos
- Aprobaciones
- Seguimiento comercial
---
# Arquitectura recomendada
```text
Frontend
- Next.js
- TypeScript
- React Hook Form
- TanStack Table
Backend Integración
- FastAPI
ERP
- SAP Business One Service Layer
```
---
# Flujo típico de trabajo
```text
1. Consultar información desde SAP
2. Mostrar información al usuario
3. Validar reglas operacionales
4. Permitir edición controlada
5. Enviar información final a SAP
```
---
# Principios de diseño UI
## El sistema debe ser:
- rápido
- minimalista
- estable
- predecible
- orientado a productividad
---
## Evitar
- animaciones
- dashboards innecesarios
- exceso de colores
- imágenes decorativas
- diseño tipo startup
---
## Priorizar
- velocidad
- teclado
- tabulación
- búsqueda rápida
- formularios densos
- tablas operacionales
---
# Fase 1 — Fundamentos web modernos
Duración: ~3 semanas
---
# JavaScript moderno
## Aprender
- let / const
- funciones
- arrays
- objetos
- async / await
- fetch API
- módulos
---
## Objetivo ERP
Consumir APIs y transformar datos empresariales.
Ejemplos:
- obtener OC
- obtener proveedores
- listar artículos
- validar estados
---
# HTML y CSS
## Aprender
- formularios
- tablas
- inputs
- layouts
- Flexbox
- CSS Grid
- responsive básico
---
## Objetivo ERP
Construir:
- formularios operacionales
- tablas densas
- layouts empresariales
---
# TypeScript
## Aprender
- interfaces
- types
- arrays tipados
- objetos anidados
- generics
- Partial
- Pick
- Omit
---
## Objetivo ERP
Modelar:
- documentos
- líneas
- almacenes
- lotes
- centros de costo
---
# Fase 2 — React para sistemas empresariales
Duración: ~3 semanas
---
# Componentes
## Aprender
- componentes reutilizables
- props
- composición
---
## Objetivo ERP
Crear:
- inputs
- tablas
- formularios
- modales
---
# Hooks React
## Aprender
- useState
- useEffect
- useMemo
- useCallback
---
## Objetivo ERP
Controlar:
- formularios
- búsquedas
- filtros
- cálculos
---
# Formularios controlados
## Aprender
- eventos
- validaciones
- manejo errores
---
## Objetivo ERP
Validar:
- cantidades
- RUC
- fechas
- almacenes
- centros de costo
---
# Fase 3 — Formularios empresariales modernos
Duración: ~2 semanas
> Esta es una de las fases MÁS importantes.
---
# React Hook Form
## Aprender
- useForm
- Controller
- FormProvider
- useFieldArray
---
## Objetivo ERP
Manejar:
- formularios grandes
- líneas dinámicas
- validaciones rápidas
---
# Zod
## Aprender
- schemas
- validaciones
- refinements
---
## Objetivo ERP
Centralizar reglas empresariales.
Ejemplos:
- cantidad > 0
- RUC válido
- lote obligatorio
- centro de costo requerido
---
# Fase 4 — Next.js moderno
Duración: ~4 semanas
---
# App Router
## Aprender
- app/
- layouts
- rutas dinámicas
---
## Ejemplos
```text
/recepcion-oc
/factura-gastos
/factura-productos
/transferencias
```
---
# Server Components y Client Components
## Aprender
- use client
- separación cliente/servidor
---
## Objetivo ERP
Separar:
- carga datos
- UI
- validaciones
---
# API Routes
## Aprender
- GET
- POST
- PATCH
---
## Objetivo ERP
Comunicación:
- frontend
- FastAPI
- SAP
---
# Autenticación
## Aprender
- sesiones
- middleware
- protección rutas
---
## Escenario real
Usuario:
- existe en OHEM
- usa login corporativo
- trabaja con usuario SAP indirecto
---
# Fase 5 — Estado servidor y tablas
Duración: ~2 semanas
---
# TanStack Query
## Aprender
- fetching
- cache
- invalidaciones
- mutations
---
## Objetivo ERP
Optimizar:
- búsquedas
- consultas SAP
- refresco de datos
---
# TanStack Table
## Aprender
- filtros
- sorting
- paginación
- selección filas
---
## Objetivo ERP
Construir:
- líneas documento
- búsquedas
- listados operacionales
---
# Fase 6 — Componentes ERP reutilizables
Duración: ~2 semanas
> Esta fase define la calidad del sistema completo.
---
# Componentes clave
## ERPDataTable
Tabla reutilizable:
- filtros
- búsqueda
- selección
- teclado
---
# SearchModal
Modal reutilizable para:
- artículos
- proveedores
- clientes
- órdenes
- almacenes
---
# Inputs inteligentes
Crear componentes:
- InputRUC
- InputCurrency
- InputDate
- InputQuantity
- InputWarehouse
---
# Layouts reutilizables
## Crear
- FormLayout
- FilterLayout
- ModalLayout
---
# Fase 7 — Backend integración FastAPI
Duración: ~2 semanas
---
# FastAPI
## Aprender
- endpoints
- modelos Pydantic
- autenticación
- manejo errores
---
# Objetivo ERP
Centralizar:
- login SAP
- sesión Service Layer
- validaciones
- logs
- auditoría
---
# Arquitectura recomendada
```text
Next.js
↓
FastAPI
↓
SAP Service Layer
```
---
# Fase 8 — Integración SAP Business One
Duración: ~2 semanas
---
# Aprender
- login Service Layer
- cookies sesión
- GET
- POST
- PATCH
---
# Escenarios reales
## Recepción OC
```text
1. Buscar OC
2. Mostrar pendientes
3. Registrar cantidades
4. Crear Entrada Mercancía
```
---
## Factura proveedor
```text
1. Traer Entrada Mercancía
2. Completar datos contables
3. Distribuir gastos
4. Crear Factura Proveedor
```
---
# Validaciones reales
## Manejar
- sesión expirada
- errores SAP
- timeouts
- validaciones SUNAT
- concurrencia
---
# Fase 9 — Seguridad y despliegue
Duración: ~1 semana
---
# Seguridad
## Aprender
- HTTPS
- CORS
- middleware
- protección APIs
---
# Deploy
## Aprender
- Docker
- Nginx
- Linux
- variables entorno
---
# Estructura recomendada
```text
/apps
/recepcion-oc
/factura-gastos
/factura-productos
/transferencias
/shared-ui
/shared-api
/shared-types
```
---
# Filosofía modular
Cada módulo:
- independiente
- simple
- mantenible
- desplegable
---
# Proyecto inicial recomendado
## Recepción de Orden de Compra
Porque incluye:
- filtros
- tablas
- modales
- líneas
- validaciones
- SAP Service Layer
---
# Stack recomendado
## Frontend
- Next.js
- TypeScript
- Tailwind CSS
- shadcn/ui
---
## Formularios
- React Hook Form
- Zod
---
## Tablas
- TanStack Table
---
## Estado servidor
- TanStack Query
---
## Backend
- FastAPI
---
# Recursos recomendados
| Tema | Recurso |
|---|---|
| JavaScript | https://javascript.info |
| TypeScript | https://www.typescriptlang.org/docs |
| React | https://react.dev |
| Next.js | https://nextjs.org/learn |
| Tailwind CSS | https://tailwindcss.com |
| React Hook Form | https://react-hook-form.com |
| Zod | https://zod.dev |
| TanStack Query | https://tanstack.com/query |
| TanStack Table | https://tanstack.com/table |
| FastAPI | https://fastapi.tiangolo.com |
---
# Resumen total
| Fase | Tema | Semanas |
|---|---|---|
| 1 | Fundamentos web | 3 |
| 2 | React empresarial | 3 |
| 3 | Formularios modernos | 2 |
| 4 | Next.js | 4 |
| 5 | Estado y tablas | 2 |
| 6 | Componentes ERP reutilizables | 2 |
| 7 | FastAPI integración | 2 |
| 8 | SAP Business One | 2 |
| 9 | Seguridad y deploy | 1 |
| Total | | ~21 semanas |
---
# Meta final
Construir aplicaciones operacionales empresariales:
- rápidas
- simples
- mantenibles
- desacopladas
- conectadas a SAP Business One
Sin intentar reinventar un ERP completo. La humanidad ya ha sufrido suficiente con eso.
-593
View File
@@ -1,593 +0,0 @@
## Aplicaciones Operacionales para SAP Business One
> Objetivo: construir aplicaciones web empresariales simples, rápidas, mantenibles y desacopladas para procesos específicos conectados a SAP Business One mediante Service Layer.
---
# Filosofía tecnológica
El objetivo NO es crear:
- una plataforma compleja
- microservicios innecesarios
- interfaces visualmente exageradas
El objetivo es construir:
- formularios operacionales rápidos
- tablas empresariales eficientes
- validaciones sólidas
- integración estable con SAP Business One
---
# Arquitectura general recomendada
```text
Frontend (Next.js)
↓
Backend Integración (FastAPI)
↓
SAP Business One Service Layer
```
---
# Lenguajes recomendados
# 1. TypeScript
## Uso principal
Frontend empresarial.
---
## Se utilizará en:
- Next.js
- React
- Formularios
- Tablas
- Validaciones
- Componentes reutilizables
---
## ¿Por qué usar TypeScript?
Porque los sistemas ERP manejan:
- muchos datos
- documentos complejos
- estructuras anidadas
- validaciones empresariales
TypeScript ayuda a:
- reducir errores
- mantener consistencia
- mejorar mantenimiento
- detectar problemas temprano
---
## Ejemplo típico ERP
```ts
interface PurchaseOrderLine {
itemCode: string
description: string
quantity: number
warehouseCode: string
}
```
---
# 2. Python
## Uso principal
Backend de integración.
---
## Se utilizará en:
- FastAPI
- integración SAP
- validaciones empresariales
- integración SUNAT
- logs
- auditoría
- automatizaciones
- procesos auxiliares
---
## ¿Por qué Python?
Porque:
- es rápido de desarrollar
- excelente para APIs
- ideal para integración empresarial
- muy compatible con automatización
- excelente ecosistema
---
# IDE recomendado
# Antigravity
## IDE principal
Antigravity puede ser muy útil para este proyecto debido a:
- generación acelerada de código
- asistencia IA
- productividad
- soporte moderno TypeScript y React
---
# Uso recomendado de Antigravity
## Excelente para generar:
- formularios
- CRUDs
- tablas
- hooks
- componentes
- validaciones
- clientes API
- schemas Zod
---
## NO depender completamente de IA para:
- arquitectura
- seguridad
- lógica SAP
- reglas contables
- autorizaciones
- estructura del sistema
---
# Filosofía correcta con IA
```text
Arquitectura y lógica:
Manual
Implementación repetitiva:
Asistida por IA
```
---
# Recomendación importante
La IA debe:
- acelerar desarrollo
- reducir boilerplate
- mejorar productividad
La IA NO debe:
- tomar decisiones arquitectónicas
- definir reglas empresariales
- controlar diseño de integración SAP
---
# VS Code como respaldo
## Recomendado instalar también:
Visual Studio Code.
---
## Motivos
- estabilidad
- debugging excelente
- ecosistema enorme
- respaldo confiable
- herramientas empresariales
---
# Extensiones recomendadas
## Frontend
- ES7+ React snippets
- Tailwind CSS IntelliSense
- ESLint
- Prettier
- Error Lens
---
## Python
- Python
- Pylance
- Ruff
- Black Formatter
---
# Librerías Frontend
# Next.js
## Framework principal
Se utilizará para:
- páginas
- layouts
- formularios
- módulos operacionales
- autenticación
- API routes
---
## ¿Por qué Next.js?
Porque:
- estructura moderna
- excelente soporte TypeScript
- arquitectura ordenada
- ideal para aplicaciones empresariales
---
# React
## Base UI
React será utilizado para:
- componentes
- formularios
- tablas
- modales
- interacción usuario
---
# Tailwind CSS
## Framework CSS recomendado
Ideal para:
- sistemas empresariales
- diseño minimalista
- formularios densos
- layouts rápidos
---
## Ventajas
- rápido
- consistente
- fácil mantenimiento
- poco CSS manual
---
# shadcn/ui
## Librería UI recomendada
Ideal para:
- modales
- dialogs
- tablas
- formularios
- selects
- popovers
---
## Ventaja principal
Los componentes:
- son modificables
- quedan dentro del proyecto
- no dependen de librerías cerradas
---
# Formularios
# React Hook Form
## Librería MÁS importante del frontend
Se utilizará para:
- formularios complejos
- validaciones
- líneas dinámicas
- formularios ERP
---
## Casos reales
- facturas
- entradas mercancía
- transferencias
- gastos
- validaciones tributarias
---
# Zod
## Validaciones empresariales
Se utilizará para:
- validar formularios
- validar payloads
- centralizar reglas
---
## Ejemplos
- RUC válido
- cantidad > 0
- centro costo obligatorio
- lote requerido
---
# Manejo de datos
# TanStack Query
## Manejo de estado servidor
Se utilizará para:
- consultas SAP
- cache
- refresh
- sincronización datos
---
## Ventajas
- evita consultas repetidas
- mejora performance
- simplifica fetching
---
# Tablas ERP
# TanStack Table
## Librería crítica ERP
Se utilizará para:
- líneas documento
- listados
- filtros
- selección
- edición
---
## Funcionalidades importantes
- filtros
- sorting
- búsqueda
- navegación teclado
- paginación
---
# Backend recomendado
# FastAPI
## Backend principal
FastAPI será utilizado para:
- integración SAP
- autenticación
- validaciones
- logs
- auditoría
- APIs internas
---
# Arquitectura recomendada
```text
Next.js
↓
FastAPI
↓
SAP Service Layer
```
---
# ¿Por qué usar FastAPI?
Porque:
- rápido
- limpio
- tipado
- excelente documentación
- ideal para APIs empresariales
---
# SAP Business One
## SAP seguirá siendo:
```text
Sistema maestro ERP
```
La aplicación web:
- NO reemplaza SAP
- NO replica SAP completo
La aplicación:
- simplifica procesos específicos
- mejora experiencia operacional
- agrega validaciones
- acelera tareas
---
# Herramientas adicionales
# Postman o Insomnia
## Para pruebas API
Utilizados para probar:
- SAP Service Layer
- FastAPI
- APIs SUNAT
---
# Obsidian
## Documentación técnica
Ideal para:
- arquitectura
- flujos
- snippets
- documentación SAP
---
# Git
## Control versiones
Recomendado:
- Git
- GitHub
- Gitea
---
# Docker
## Deploy empresarial
Aprender:
- Docker
- Docker Compose
- Nginx
---
# Organización recomendada
```text
/apps
/recepcion-oc
/factura-gastos
/factura-productos
/transferencias
/shared-ui
/shared-api
/shared-types
/shared-validations
```
---
# Filosofía modular
Cada módulo debe ser:
- independiente
- simple
- mantenible
- desacoplado
---
# Componentes reutilizables críticos
## SearchModal
Modal reutilizable para:
- artículos
- proveedores
- clientes
- órdenes compra
---
# ERPDataTable
Tabla reutilizable:
- filtros
- búsqueda
- selección
- teclado
---
# Inputs inteligentes
Crear:
- InputRUC
- InputCurrency
- InputDate
- InputQuantity
- InputWarehouse
---
# Prioridades reales de aprendizaje
# Prioridad máxima
1. TypeScript
2. React Hook Form
3. TanStack Table
4. FastAPI
5. SAP Service Layer
---
# Prioridad media
6. Next.js
7. TanStack Query
8. Zod
9. Docker
---
# Prioridad baja
- Redux
- animaciones
- dashboards complejos
- SEO
- diseño visual avanzado
---
# Objetivo final
Construir aplicaciones empresariales:
- rápidas
- operacionales
- mantenibles
- desacopladas
- integradas con SAP Business One
Sin intentar reinventar un ERP completo. La industria ya tiene suficientes cicatrices por eso.
+384
View File
@@ -0,0 +1,384 @@
# Gitea público con Tailscale Funnel en NAS UGREEN
Guía para exponer Gitea (en Docker, NAS UGREEN con UGOS) por HTTPS a internet usando **Tailscale Funnel**, de modo que funcione desde cualquier equipo **sin instalar Tailscale**, en casa y fuera, con una sola URL.
## Datos de esta instalación
| Elemento | Valor |
|---|---|
| URL pública final | `https://unasgeorge.vaquita-hadar.ts.net` |
| Tailnet | `vaquita-hadar.ts.net` |
| Nombre del NAS en Tailscale | `unasgeorge` |
| IP Tailscale del NAS (contenedor) | `100.68.242.27` |
| IP local del NAS | `192.168.1.145` |
| Puerto de Gitea en el NAS (host) | `30000` (interno del contenedor: `3000`) |
| Puerta de enlace Docker (bridge) | `172.17.0.1` |
| Destino del proxy de Funnel | `http://172.17.0.1:30000` |
| Usuario Gitea | `george` |
### Esquema
```
Cualquier equipo (con o sin Tailscale)
│
▼
https://unasgeorge.vaquita-hadar.ts.net (puerto 443, HTTPS, Let's Encrypt)
│
▼ Tailscale Funnel (contenedor Tailscale en el NAS)
http://172.17.0.1:30000 (interno, nadie lo usa directamente)
│
▼
Gitea
```
---
## 1. Preparar Tailscale (panel web)
### 1.1 Activar certificados HTTPS
1. Entrar a <https://login.tailscale.com/admin/dns>.
2. En **HTTPS Certificates**, pulsar **Enable HTTPS**.
### 1.2 Permitir Funnel en la política de acceso
1. Entrar a <https://login.tailscale.com/admin/acls>.
2. Verificar que exista este bloque (añadirlo si no está, respetando las comas):
```json
"nodeAttrs": [
{
"target": ["autogroup:member"],
"attr": ["funnel"]
}
]
```
3. Guardar (**Save**).
> Alternativa: la primera vez que se ejecuta `tailscale funnel`, el comando muestra un enlace (`https://login.tailscale.com/f/funnel?node=...`) que añade este permiso automáticamente.
**Validación:** después del paso 2, en <https://login.tailscale.com/admin/machines> debe aparecer la etiqueta **Funnel** junto a `unasgeorge`.
---
## 2. Configurar Funnel en el contenedor de Tailscale
### 2.1 Abrir la terminal del contenedor
1. Entrar al panel del NAS (UGOS) → app **Docker** → **Contenedores**.
2. Abrir el contenedor de **Tailscale** → **Terminal** → añadir terminal.
3. En *Command* usar **`/bin/sh`** (la imagen de Tailscale no trae bash).
> Si algún comando da *failed to connect to local tailscaled*, anteponer el socket:
> `tailscale --socket=/tmp/tailscaled.sock <comando>`
### 2.2 Comprobar que Tailscale está conectado
```sh
tailscale status
tailscale version
```
Debe aparecer `unasgeorge` con IP `100.68.242.27`. Versión recomendada: 1.50 o superior.
### 2.3 Encontrar por dónde ve el contenedor a Gitea
El contenedor de Tailscale está en la red bridge de Docker: **no** llega a Gitea por la IP local del NAS ni por `127.0.0.1`. Hay que usar la puerta de enlace de Docker.
```sh
ip route | head -1
# Resultado esperado: default via 172.17.0.1 dev eth0
wget -qO- -T 5 http://172.17.0.1:30000 | head -c 200
# Debe devolver HTML que empieza con <!DOCTYPE html>
```
Referencia de lo que **no** funciona en esta instalación:
```sh
wget -qO- -T 5 http://192.168.1.145:30000 | head -c 200 # download timed out
wget -qO- -T 5 http://127.0.0.1:30000 | head -c 200 # Connection refused
```
### 2.4 Activar Funnel
```sh
tailscale serve reset
tailscale funnel --bg http://172.17.0.1:30000
```
Salida esperada:
```
Available on the internet:
https://unasgeorge.vaquita-hadar.ts.net/
|-- proxy http://172.17.0.1:30000
Funnel started and running in the background.
```
### 2.5 Validar
```sh
tailscale funnel status
```
Debe mostrar **un solo** destino:
```
https://unasgeorge.vaquita-hadar.ts.net (Funnel on)
|-- / proxy http://172.17.0.1:30000
```
> `--bg` deja Funnel activo en segundo plano y sobrevive a reinicios del contenedor. Si el contenedor se **recrea** (no solo se reinicia) y su estado no está en un volumen, hay que repetir el paso 2.4.
>
> Para desactivar Funnel: `tailscale funnel --https=443 off`
---
## 3. Configurar Gitea
### 3.1 Variables de entorno del contenedor (prioritario)
Las variables `GITEA__seccion__CLAVE` **tienen prioridad sobre `app.ini`** y lo reescriben en cada arranque. En esta instalación existía `GITEA__server__ROOT_URL = http://100.68.242.27:30000/`, que era la causa de que el botón *Clone* mostrara la URL antigua.
1. App **Docker** de UGOS → contenedor de **Gitea** → **Detener**.
2. **Editar → Variables de entorno**.
3. Dejar los valores así (cambiar o añadir):
```
GITEA__server__ROOT_URL = https://unasgeorge.vaquita-hadar.ts.net/
GITEA__server__DOMAIN = unasgeorge.vaquita-hadar.ts.net
GITEA__server__SSH_DOMAIN = 192.168.1.145
GITEA__server__PUBLIC_URL_DETECTION = never
GITEA__service__DISABLE_REGISTRATION = true
```
4. Guardar e **Iniciar** el contenedor. Los repositorios no se pierden: están en el volumen.
### 3.2 `app.ini` (si no se usan variables)
Ruta habitual dentro del volumen: `.../gitea/gitea/conf/app.ini` (en el contenedor: `/data/gitea/conf/app.ini`). Se puede editar desde el **Gestor de archivos** de UGOS.
```ini
[server]
DOMAIN = unasgeorge.vaquita-hadar.ts.net
ROOT_URL = https://unasgeorge.vaquita-hadar.ts.net/
SSH_DOMAIN = 192.168.1.145
PUBLIC_URL_DETECTION = never
[service]
DISABLE_REGISTRATION = true
```
Reiniciar el contenedor de Gitea tras editar.
> `PUBLIC_URL_DETECTION = never` hace que Gitea use siempre `ROOT_URL` para los enlaces, aunque se entre por otra dirección (IP de Tailscale, `ugdocker.link`, etc.).
> `SSH_DOMAIN` apunta a la IP local: SSH **no** pasa por Funnel, solo funciona en la red de casa.
### 3.3 Validar
- **Administración del sitio → Configuración → URL de la aplicación** debe ser `https://unasgeorge.vaquita-hadar.ts.net/`.
- En cualquier repo, el botón **Clone (HTTPS)** debe mostrar:
`https://unasgeorge.vaquita-hadar.ts.net/george/<repo>.git`
- Al cerrar sesión **no** debe aparecer la opción *Registrarse*.
> El aviso *"The detected web site URL is ... unlikely matching the site config"* solo aparece cuando se entra por una dirección distinta de `ROOT_URL`. Desaparece al entrar por `https://unasgeorge.vaquita-hadar.ts.net`.
### 3.4 Crear un token de acceso
Git por HTTPS usa el token como contraseña.
1. Gitea → avatar → **Configuración → Aplicaciones** → *Administrar tokens de acceso*.
2. Nombre: uno por equipo (ej. `macbook-air`, `serfactpro`).
3. Permisos: **repository → Read and Write** (y **user → Read** si lo pide).
4. **Generar token** y copiarlo (solo se muestra una vez).
> No usar **Manage SSH Keys** para esto: las claves SSH no funcionan a través de Funnel.
---
## 4. Validaciones de acceso
### 4.1 Desde un equipo con Tailscale encendido
```bash
curl -I https://unasgeorge.vaquita-hadar.ts.net
```
Esperado:
```
HTTP/2 200
```
Si se queda colgado después de `Request completely sent off`, Funnel no llega a Gitea: revisar el paso 2.3 y el destino del proxy.
### 4.2 DNS público (sin Tailscale)
```bash
dig +short unasgeorge.vaquita-hadar.ts.net A @1.1.1.1
dig +short unasgeorge.vaquita-hadar.ts.net A @8.8.8.8
```
Esperado (IPs de los servidores de entrada de Funnel, pueden variar):
```
209.177.145.97
209.177.145.192
```
> Si sale vacío o `No answer`, el registro DNS público aún no se ha creado. Puede tardar desde 10 minutos hasta unas horas. No hay que cambiar nada, solo esperar.
### 4.3 Desde un equipo o servidor **sin Tailscale**
En el Mac: apagar Tailscale (icono de la barra de menú) y limpiar caché DNS:
```bash
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
```
En Linux (si usa systemd-resolved):
```bash
sudo resolvectl flush-caches
```
En Windows (PowerShell):
```powershell
ipconfig /flushdns
```
Comprobaciones (válidas en macOS, Linux y Windows con curl/git):
```bash
# 1. Resuelve por DNS público
nslookup unasgeorge.vaquita-hadar.ts.net 8.8.8.8
# 2. Responde por HTTPS
curl -I https://unasgeorge.vaquita-hadar.ts.net
# Esperado: HTTP/2 200
# 3. Git llega al repositorio (pedirá usuario y token si es privado)
git ls-remote https://unasgeorge.vaquita-hadar.ts.net/george/sap-legacy-webhook-emulator.git
```
### 4.4 Prueba desde una red totalmente externa
En el iPhone (o cualquier móvil): desactivar Wi-Fi, desactivar Tailscale y abrir en el navegador:
```
https://unasgeorge.vaquita-hadar.ts.net
```
Debe cargar la página de Gitea.
### 4.5 URLs de comprobación
| Qué | URL |
|---|---|
| Gitea (pública) | <https://unasgeorge.vaquita-hadar.ts.net> |
| Repo de ejemplo | <https://unasgeorge.vaquita-hadar.ts.net/george/sap-legacy-webhook-emulator> |
| Máquinas Tailscale (etiqueta Funnel) | <https://login.tailscale.com/admin/machines> |
| Política de acceso (nodeAttrs funnel) | <https://login.tailscale.com/admin/acls> |
| DNS / certificados HTTPS | <https://login.tailscale.com/admin/dns> |
---
## 5. Cambiar el `origin` de los proyectos
### 5.1 Un proyecto
```bash
cd ruta/al/proyecto
# Ver el remoto actual
git remote -v
# Cambiarlo
git remote set-url origin https://unasgeorge.vaquita-hadar.ts.net/george/<repo>.git
# Verificar
git remote -v
git ls-remote origin
git push
```
Credenciales en el primer `push`:
- **Username:** `george`
- **Password:** el **token** (al pegarlo no se ve nada, es normal)
### 5.2 Varios proyectos a la vez (macOS / Linux)
Desde la carpeta que contiene todos los proyectos. Sustituye cualquiera de las URLs antiguas (IP Tailscale, IP local o `ugdocker.link`) por la nueva:
```bash
for d in */; do
[ -d "$d/.git" ] || continue
old=$(git -C "$d" remote get-url origin 2>/dev/null) || continue
new=$(echo "$old" | sed -E 's#^https?://(100\.68\.242\.27|192\.168\.1\.145|app-30000-unasgeorge\.us15\.ugdocker\.link)(:30000)?#https://unasgeorge.vaquita-hadar.ts.net#')
if [ "$old" != "$new" ]; then
git -C "$d" remote set-url origin "$new"
echo "$d $old -> $new"
fi
done
```
### 5.3 Varios proyectos a la vez (Windows PowerShell)
```powershell
Get-ChildItem -Directory | ForEach-Object {
if (Test-Path "$($_.FullName)\.git") {
$old = git -C $_.FullName remote get-url origin 2>$null
if ($old) {
$new = $old -replace '^https?://(100\.68\.242\.27|192\.168\.1\.145|app-30000-unasgeorge\.us15\.ugdocker\.link)(:30000)?', 'https://unasgeorge.vaquita-hadar.ts.net'
if ($old -ne $new) {
git -C $_.FullName remote set-url origin $new
Write-Host "$($_.Name) $old -> $new"
}
}
}
}
```
### 5.4 Guardar el token para no escribirlo cada vez
| Sistema | Comando / comportamiento |
|---|---|
| macOS | Se guarda solo en el Llavero (`git config --global credential.helper osxkeychain`) |
| Windows | Git Credential Manager lo guarda automáticamente |
| Linux | `git config --global credential.helper store` (guarda en texto plano en `~/.git-credentials`) |
### 5.5 Clonar en un equipo nuevo
```bash
git clone https://unasgeorge.vaquita-hadar.ts.net/george/<repo>.git
```
---
## 6. Seguridad (Gitea queda público en internet)
- [ ] Registro desactivado (`DISABLE_REGISTRATION = true`, verificado en variables de entorno **y** `app.ini`).
- [ ] 2FA activado: **Configuración → Seguridad**.
- [ ] Repositorios privados marcados como **privados**.
- [ ] Un token por equipo; revocar el de un equipo perdido en **Configuración → Aplicaciones**.
- [ ] Revisar que no exista otra variable `GITEA__...` que anule estos ajustes.
---
## 7. Problemas encontrados y solución
| Síntoma | Causa | Solución |
|---|---|---|
| `ssh` y `ping` a `100.68.242.27` hacen timeout | Esa IP es del contenedor de Tailscale, no del sistema del NAS | Usar la terminal del contenedor desde la app Docker de UGOS |
| `Funnel is not enabled on your tailnet` | Falta permiso Funnel | Abrir el enlace que muestra el comando y aceptar |
| `port 443 is not allowed for funnel` | El nodo aún no tiene el atributo `funnel` | Revisar `nodeAttrs` (paso 1.2) y reiniciar el contenedor de Tailscale |
| HTTPS conecta pero no responde (`Request completely sent off` y nada más) | Funnel apuntaba a un destino inalcanzable (`:3000` o `192.168.1.145:30000`) | `tailscale serve reset` y Funnel a `http://172.17.0.1:30000` |
| `Could not resolve host` sin Tailscale / `dig` vacío | DNS público de Funnel aún no publicado | Esperar (minutos a horas) y repetir `dig` |
| Clone muestra `http://100.68.242.27:30000/...` o `ugdocker.link` | Variable `GITEA__server__ROOT_URL` antigua anulaba `app.ini` | Cambiar la variable y añadir `PUBLIC_URL_DETECTION = never` |
| Aviso *detected web site URL ... unlikely matching* | Se entra por una dirección distinta de `ROOT_URL` | Informativo; entrar por la URL pública |