OR_Training / ARQUITECTURA.md
rogarces85's picture
Upload 13 files
9f87fac verified

πŸ—οΈ ARQUITECTURA DEL SISTEMA - Osorno Runners

πŸ“ Diagrama de Arquitectura

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    HUGGINGFACE SPACES                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                                                             β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚  β”‚
β”‚  β”‚  β”‚   Gradio    │◄─────────   app.py     β”‚                β”‚  β”‚
β”‚  β”‚  β”‚  Framework  β”‚         β”‚   (Python)   β”‚                β”‚  β”‚
β”‚  β”‚  β”‚             β”‚         β”‚              β”‚                β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”  β”‚         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                β”‚  β”‚
β”‚  β”‚  β”‚  β”‚Server β”‚  β”‚         β”‚  β”‚ APIs   β”‚  β”‚                β”‚  β”‚
β”‚  β”‚  β”‚  β”‚Port   β”‚  β”‚         β”‚  β”‚ REST   β”‚  β”‚                β”‚  β”‚
β”‚  β”‚  β”‚  β”‚ 7860  β”‚  β”‚         β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β”‚         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚  β”‚
β”‚  β”‚        β”‚        β”‚                β”‚                        β”‚  β”‚
β”‚  β”‚        β–Ό        β”‚                β–Ό                        β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚  β”‚
β”‚  β”‚  β”‚         index.html (Frontend)             β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  HTML5 + CSS3 + JavaScript           β”‚ β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - Login Form                        β”‚ β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - Dashboard                         β”‚ β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - Training Plan Creator             β”‚ β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - Plan List                         β”‚ β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - PDF Export (jsPDF)                β”‚ β”‚           β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚           β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚  β”‚
β”‚  β”‚                        β”‚                                  β”‚  β”‚
β”‚  β”‚                        β–Ό                                  β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚  β”‚
β”‚  β”‚  β”‚      SQLite Database (Persistent)       β”‚             β”‚  β”‚
β”‚  β”‚  β”‚                                           β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  Tabla: users  β”‚  β”‚ Tabla: planes  β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - username    β”‚  β”‚ - id           β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - password    β”‚  β”‚ - plan_data    β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - role        β”‚  β”‚ - created_at   β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  - name        β”‚  β”‚ - created_by   β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ - athlete_name β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚                      β”‚ - distance     β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚                      β”‚ - race_date    β”‚ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚             β”‚  β”‚
β”‚  β”‚  β”‚                                           β”‚             β”‚  β”‚
β”‚  β”‚  β”‚  Archivo: osorno_runners.db              β”‚             β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚  β”‚
β”‚  β”‚                                                             β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                                  β”‚
β”‚  URL: https://huggingface.co/spaces/USUARIO/osorno-runners     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                            β”‚ HTTPS
                            β–Ό
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚   NAVEGADOR      β”‚
                   β”‚   DEL USUARIO    β”‚
                   β”‚                  β”‚
                   β”‚  Chrome/Firefox  β”‚
                   β”‚  Safari/Edge     β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”„ Flujo de Datos

1️⃣ Login

Usuario ingresa credenciales
       β”‚
       β–Ό
index.html (Frontend)
       β”‚
       β”‚ POST /api/login
       β–Ό
app.py (Backend)
       β”‚
       β”‚ authenticate_user()
       β–Ό
SQLite (users table)
       β”‚
       β”‚ Return user data
       β–Ό
Frontend muestra dashboard

2️⃣ Crear Plan

Usuario completa formulario
       β”‚
       β–Ό
index.html valida datos
       β”‚
       β”‚ Genera plan con algoritmos JS
       β–Ό
CΓ‘lculos de:
  - DuraciΓ³n (calculateWeeks)
  - Kilometraje (getBaseKm)
  - Zonas FC (calculateHRZones)
  - Sesiones (generateWeekSessions)
       β”‚
       β”‚ POST /api/save_plan
       β–Ό
app.py (Backend)
       β”‚
       β”‚ save_plan_to_db()
       β–Ό
SQLite (planes table)
       β”‚
       β”‚ Return plan ID
       β–Ό
Frontend muestra confirmaciΓ³n

3️⃣ Ver Planes

Usuario navega a "Ver Planes"
       β”‚
       β”‚ GET /api/get_plans
       β–Ό
app.py (Backend)
       β”‚
       β”‚ get_all_plans(username, role)
       β–Ό
SQLite query segΓΊn permisos:
  - User: WHERE created_by = username
  - Admin: SELECT * FROM planes
       β”‚
       β”‚ Return JSON con planes
       β–Ό
Frontend renderiza lista de planes

4️⃣ Exportar PDF

Usuario click en "Exportar PDF"
       β”‚
       β–Ό
Frontend (jsPDF library)
       β”‚
       β”‚ Lee datos del plan
       β”‚ Genera PDF en el navegador
       β–Ό
Descarga automΓ‘tica del PDF
(No involucra backend)

5️⃣ Eliminar Plan (Solo Admin)

Admin click en "Eliminar"
       β”‚
       β”‚ ConfirmaciΓ³n
       β–Ό
index.html
       β”‚
       β”‚ DELETE /api/delete_plan
       β–Ό
app.py (Backend)
       β”‚
       β”‚ delete_plan_from_db(plan_id)
       β–Ό
SQLite elimina registro
       β”‚
       β”‚ Return success
       β–Ό
Frontend recarga lista de planes

πŸ” Sistema de AutenticaciΓ³n

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         authenticate_user()            β”‚
β”‚                                        β”‚
β”‚  Input: username, password             β”‚
β”‚         β”‚                              β”‚
β”‚         β–Ό                              β”‚
β”‚  Query: SELECT role, name              β”‚
β”‚         FROM users                     β”‚
β”‚         WHERE username = ? AND         β”‚
β”‚               password = ?             β”‚
β”‚         β”‚                              β”‚
β”‚         β–Ό                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ Found?  β”‚          β”‚               β”‚
β”‚  β–Ό YES     β–Ό NO       β”‚               β”‚
β”‚  Return:   Return:    β”‚               β”‚
β”‚  {         None       β”‚               β”‚
β”‚    username,          β”‚               β”‚
β”‚    role,              β”‚               β”‚
β”‚    name               β”‚               β”‚
β”‚  }                    β”‚               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’Ύ Modelo de Datos

Tabla: users

CREATE TABLE users (
    username TEXT PRIMARY KEY,  -- 'USER', 'ADMIN'
    password TEXT NOT NULL,     -- '123' (cambiar en prod)
    role TEXT NOT NULL,         -- 'user', 'admin'
    name TEXT NOT NULL          -- 'Usuario', 'Administrador'
);

Ejemplo de datos:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ username β”‚ password β”‚ role  β”‚ name            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ USER     β”‚ 123      β”‚ user  β”‚ Usuario         β”‚
β”‚ ADMIN    β”‚ 123      β”‚ admin β”‚ Administrador   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Tabla: planes

CREATE TABLE planes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    plan_data TEXT NOT NULL,           -- JSON del plan completo
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_by TEXT NOT NULL,          -- Username del creador
    athlete_name TEXT NOT NULL,        -- Nombre del atleta
    distance TEXT NOT NULL,            -- '5K', '10K', '21K', '42K'
    race_date TEXT NOT NULL            -- Fecha de la carrera
);

Ejemplo de plan_data (JSON):

{
  "id": 1,
  "userData": {
    "name": "Rodrigo GarcΓ©s",
    "age": 40,
    "experience": "intermedio",
    "weight": 75,
    "height": 175,
    "imc": 24.5,
    "hrMax": 180,
    "hrRest": 60,
    "vo2max": 45,
    "distance": "42K",
    "targetPace": "4:30",
    "raceDate": "2025-04-20",
    "trainingDays": ["lunes", "miΓ©rcoles", "viernes", "domingo"]
  },
  "totalWeeks": 20,
  "weeklyPlans": [
    {
      "week": 1,
      "period": "basico",
      "sessions": [...],
      "totalKm": 35
    },
    ...
  ]
}

πŸ”„ Ciclo de Vida de un Plan

1. CREACIΓ“N
   β”œβ”€ Usuario completa formulario
   β”œβ”€ JS valida datos
   β”œβ”€ Algoritmos generan plan
   β”œβ”€ POST a /api/save_plan
   └─ Guarda en SQLite

2. ALMACENAMIENTO
   β”œβ”€ plan_data como JSON TEXT
   β”œβ”€ Metadata en columnas separadas
   └─ Timestamp automΓ‘tico

3. RECUPERACIΓ“N
   β”œβ”€ GET a /api/get_plans
   β”œβ”€ Query segΓΊn role
   β”œβ”€ Parse JSON
   └─ Return array de planes

4. VISUALIZACIΓ“N
   β”œβ”€ Frontend recibe JSON
   β”œβ”€ Renderiza HTML dinΓ‘mico
   └─ Muestra detalles

5. EXPORTACIΓ“N
   β”œβ”€ jsPDF en cliente
   β”œβ”€ Sin backend
   └─ PDF descargado

6. ELIMINACIΓ“N (Admin)
   β”œβ”€ DELETE a /api/delete_plan
   β”œβ”€ Remove de SQLite
   └─ Refresh lista

🌐 Endpoints de la API

POST /api/login

Request:  {"username": "USER", "password": "123"}
Response: {"success": true, "user": {...}}

POST /api/save_plan

Request:  {"plan": "{...}", "username": "ADMIN"}
Response: {"success": true, "id": 1}

GET /api/get_plans

Request:  {"username": "USER", "role": "user"}
Response: {"success": true, "plans": [...]}

DELETE /api/delete_plan

Request:  {"plan_id": 1}
Response: {"success": true}

πŸ”§ Stack TecnolΓ³gico

Frontend

  • HTML5
  • CSS3 (Variables CSS, Flexbox, Grid)
  • JavaScript (ES6+)
  • jsPDF 2.5.1
  • Font Awesome 6.4.0

Backend

  • Python 3.8+
  • Gradio 4.44.0
  • SQLite3 (Built-in)

Infraestructura

  • HuggingFace Spaces
  • CPU basic (2 vCPU, 16 GB RAM)
  • 50 GB Storage
  • HTTPS automΓ‘tico

πŸ“Š MΓ©tricas de Rendimiento

TamaΓ±o de archivos:
β”œβ”€ app.py:           7.3 KB
β”œβ”€ index.html:      17.0 KB
β”œβ”€ requirements.txt: 0.015 KB
└─ Total:          ~24.3 KB

Base de datos:
β”œβ”€ VacΓ­a:            ~20 KB
β”œβ”€ 10 planes:       ~100 KB
β”œβ”€ 100 planes:        ~1 MB
└─ LΓ­mite HF:        50 GB

Tiempos de respuesta:
β”œβ”€ Login:           ~100 ms
β”œβ”€ Crear plan:      ~200 ms
β”œβ”€ Cargar planes:   ~150 ms
└─ Exportar PDF:     ~1-2 seg (cliente)

πŸ›‘οΈ Seguridad

Implementado βœ…

  • AutenticaciΓ³n de usuarios
  • ValidaciΓ³n de formularios
  • Manejo de errores
  • Logs de actividad
  • SeparaciΓ³n de permisos

Por Implementar πŸ”’

  • Hashing de contraseΓ±as (bcrypt)
  • Tokens de sesiΓ³n (JWT)
  • Rate limiting
  • SanitizaciΓ³n de inputs
  • HTTPS forzado (HF lo hace)

πŸ“ˆ Escalabilidad

LΓ­mites Actuales

  • SQLite: ~140 TB teΓ³rico (prΓ‘ctico: GB)
  • HuggingFace: 50 GB storage
  • Concurrent users: ~100
  • Request/min: Ilimitado en HF

Para Escalar

  1. Migrar a PostgreSQL
  2. Implementar Redis para cache
  3. CDN para assets
  4. Load balancing
  5. Microservicios

Esta arquitectura es ideal para:

  • βœ… Prototipo rΓ‘pido
  • βœ… MVP (Minimum Viable Product)
  • βœ… Equipos pequeΓ±os (< 50 usuarios)
  • βœ… Presupuesto cero

Para producciΓ³n enterprise, considerar:

  • Migrar a AWS/GCP/Azure
  • Base de datos dedicada
  • Backups automΓ‘ticos
  • Monitoreo 24/7
  • CI/CD pipeline