Documentation Index Fetch the complete documentation index at: https://mintlify.com/danielpose1996-stack/ruedadeproyectos/llms.txt
Use this file to discover all available pages before exploring further.
Introduction
RuedaPro UNIPAZ is a client-side web application built with vanilla JavaScript and Supabase as the backend-as-a-service. The platform manages engineering project evaluations for UNIPAZ’s Computer Engineering program.
System Architecture
High-Level Architecture
The application follows a simple but effective architecture:
┌─────────────────────────────────────────────────────────┐
│ Browser Client │
│ ┌────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ HTML/CSS │ │ JavaScript │ │ Supabase SDK │ │
│ │ Views │←→│ Router │←→│ Client │ │
│ └────────────┘ └─────────────┘ └─────────────────┘ │
└──────────────────────────────────────────┬──────────────┘
│
│ HTTPS/WebSocket
│
┌────────────▼──────────────┐
│ Supabase Backend │
│ ┌─────────────────────┐ │
│ │ PostgreSQL DB │ │
│ │ (with RLS) │ │
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │
│ │ Auth Service │ │
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │
│ │ Storage Service │ │
│ └─────────────────────┘ │
└───────────────────────────┘
Core Components
1. Frontend Structure
The application is organized into logical modules:
Configuration (js/config.js) - Supabase client initialization
Authentication (js/auth.js) - Session management and login/logout
Router (js/router.js) - Client-side routing and navigation
Views (js/views/*) - UI rendering functions
Main (js/main.js) - Application initialization
2. Supabase Client Initialization
The Supabase client is initialized at application startup in js/config.js:
const SUPABASE_URL = 'https://gbjmulgwdjxqehhlrqjy.supabase.co' ;
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' ;
let supabaseClient = null ;
if ( window . supabase ) {
supabaseClient = window . supabase . createClient ( SUPABASE_URL , SUPABASE_ANON_KEY );
}
The supabaseClient global variable is available throughout the application for database operations and authentication.
Data Flow
1. Application Lifecycle
1. Page Load
↓
2. DOMContentLoaded Event
↓
3. Initialize Theme Toggle
↓
4. Initialize Router
↓
5. Navigate to 'home' route
↓
6. Restore Session (async)
↓
7. Update Global Header
2. Authentication Flow
User Login Request
↓
handleLogin(event, role)
↓
supabaseClient.auth.signInWithPassword()
↓
Extract user_metadata (role, nombre)
↓
Verify role matches login type
↓
Update currentUser & currentProfile
↓
Navigate to role-specific dashboard
↓
updateGlobalHeader()
3. Data Query Flow
The application uses Supabase’s query builder to interact with the PostgreSQL database:
// Example: Fetch student projects with evaluations
const { data : assignments , error } = await supabaseClient
. from ( 'proyecto_estudiantes' )
. select ( `
proyecto_id,
proyectos (
id, nombre, categoria, semestre, anio, estado,
evaluaciones (
puntaje_final,
observaciones,
perfiles (nombre)
)
)
` )
. eq ( 'estudiante_id' , currentProfile . id );
View Rendering System
Render Pattern
All views follow a consistent pattern:
View Function - Returns HTML string
Loader Function - Fetches data and updates DOM
Event Handlers - Attached via inline handlers or after render
Example:
// 1. Render function returns HTML
function renderEstudianteDashboard () {
setTimeout (() => {
loadEstudianteDashboard (); // Call loader
}, 100 );
return `<div id="estudiante-data-container">...</div>` ;
}
// 2. Loader fetches data
async function loadEstudianteDashboard () {
const { data , error } = await supabaseClient
. from ( 'proyecto_estudiantes' )
. select ( '...' )
. eq ( 'estudiante_id' , currentProfile . id );
// Update DOM
container . innerHTML = generateHTML ( data );
}
Routing Mechanism
The application uses a simple client-side router implemented in js/router.js:
Route Registration
Navigation links use data-route attributes:
< a href = "#" data-route = "home" > Inicio </ a >
< a href = "#" data-route = "dashboard-docente" > Dashboard </ a >
Navigation Function
function navigateTo ( route , data = null ) {
const appContent = document . getElementById ( 'app-content' );
switch ( route ) {
case 'home' :
appContent . innerHTML = renderHomeView ();
break ;
case 'dashboard-docente' :
if ( currentProfile ?. rol === 'docente' ) {
appContent . innerHTML = renderDocenteDashboard ();
} else {
navigateTo ( 'home' ); // Redirect if unauthorized
}
break ;
// ... more routes
}
window . scrollTo ( 0 , 0 );
}
Route Protection
Routes are protected by checking currentProfile.rol before rendering protected views.
State Management
The application maintains global state using two key variables:
Current User State
let currentUser = null ; // Supabase auth user object
let currentProfile = null ; // Application profile object
Profile Structure
currentProfile = {
id: 'uuid' , // User UUID from Supabase Auth
nombre: 'John Doe' , // User's full name
rol: 'docente' , // Role: 'estudiante', 'docente', or 'admin'
avatar_url: 'url' // Optional avatar URL
};
State Updates
State is updated in three scenarios:
Login - handleLogin() sets user and profile
Session Restore - restoreSession() restores from Supabase session
Logout - handleLogout() clears state
Database Interaction Patterns
1. Simple Query
const { data , error } = await supabaseClient
. from ( 'proyectos' )
. select ( '*' )
. eq ( 'estado' , 'Activo' );
2. Nested Relationships
const { data , error } = await supabaseClient
. from ( 'proyecto_evaluadores' )
. select ( `
proyecto_id,
proyectos (
id,
nombre,
evaluaciones (puntaje_final)
)
` )
. eq ( 'evaluador_id' , currentProfile . id );
3. Insert Operation
const { data , error } = await supabaseClient
. from ( 'evaluaciones' )
. insert ({
proyecto_id: projectId ,
evaluador_id: currentProfile . id ,
puntaje_final: score ,
observaciones: comments
});
4. Update Operation
const { data , error } = await supabaseClient
. from ( 'proyectos' )
. update ({ estado: 'Evaluado' })
. eq ( 'id' , projectId );
Security Features
XSS Protection
All user input is sanitized using the escapeHTML() helper:
function escapeHTML ( str ) {
if ( typeof str !== 'string' ) return str ;
return str
. replace ( /&/ g , '&' )
. replace ( /</ g , '<' )
. replace ( />/ g , '>' )
. replace ( /"/ g , '"' )
. replace ( /'/ g , ''' );
}
Usage:
htmlContent += `<h2> ${ escapeHTML ( p . nombre ) } </h2>` ;
Row-Level Security (RLS)
Supabase enforces Row-Level Security policies at the database level to ensure users can only access authorized data.
Role-Based Access Control
Routes and functionality are protected by role checks:
if ( currentProfile ?. rol === 'docente' ) {
// Render docente view
} else {
navigateTo ( 'home' ); // Redirect unauthorized users
}
API Sections
Explore detailed documentation for specific API areas:
Authentication API User login, logout, and session management
Database Schema Database tables, relationships, and constraints
Views API View rendering functions and patterns
Router API Client-side routing and navigation
Best Practices
1. Error Handling
Always handle errors from Supabase operations:
try {
const { data , error } = await supabaseClient
. from ( 'proyectos' )
. select ( '*' );
if ( error ) throw error ;
// Process data
} catch ( e ) {
console . error ( "Error:" , e );
// Show user-friendly error message
}
2. Loading States
Provide feedback during async operations:
submitBtn . disabled = true ;
submitBtn . textContent = 'Cargando...' ;
// Perform operation
submitBtn . disabled = false ;
submitBtn . textContent = 'Enviar' ;
3. Data Validation
Validate data before database operations:
if ( ! email || ! password ) {
errorDiv . textContent = 'Por favor completa todos los campos' ;
return ;
}
Lazy Loading - Views fetch data only when rendered
Eager Loading - Use nested selects to reduce round trips
Client-side Caching - User session cached in browser
Minimal Dependencies - Vanilla JS with single external dependency (Supabase)
Next Steps