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.
Overview
The Results Gallery provides a public-facing view of evaluated projects, displaying historical rankings organized by semester, year, and category. This transparent system showcases the top-performing engineering projects from UNIPAZ’s academic programs.
Public Results Display
What’s Publicly Visible
The Results Gallery displays:
Top 5 Rankings Best-performing projects per category and period
Project Names Full titles of evaluated projects
Team Members Names of student authors
Final Scores Average evaluation scores (1.0-5.0)
Data Privacy
What’s NOT Displayed Publicly:
Individual criterion scores
Evaluator feedback and observations
Incomplete/pending evaluations
Projects with status other than “Evaluado”
Evaluator names
Only projects with estado = 'Evaluado' appear in the public rankings, ensuring only completed assessments are visible.
Filtering System
Available Filters
Users can filter results using three dimensions:
< select id = "filter-year" >
< option value = "2026" > 2026 </ option >
< option value = "2025" > 2025 </ option >
< option value = "2024" > 2024 </ option >
< option value = "2023" > 2023 </ option >
</ select >
View results from different academic years (2023-2026 shown, expandable). < select id = "filter-semester" >
< option value = "1" > 1 (Primer Semestre) </ option >
< option value = "2" > 2 (Segundo Semestre) </ option >
</ select >
Choose between first or second semester results. < select id = "filter-category" >
< option value = "Desarrollo" > Desarrollo </ option >
< option value = "Propuesta" > Propuesta </ option >
< option value = "Aplicación" > Aplicación </ option >
</ select >
Filter by project category:
Desarrollo : Software development projects
Propuesta : Research proposals
Aplicación : Applied technology projects
Filter Interaction
const year = document . getElementById ( 'filter-year' )?. value || new Date (). getFullYear (). toString ();
const semester = document . getElementById ( 'filter-semester' )?. value || '1' ;
const category = document . getElementById ( 'filter-category' )?. value || 'Desarrollo' ;
When users click the “Filtrar” button, the system:
Reads all three filter values
Queries the database for matching projects
Calculates rankings
Updates the display
Ranking Calculation
Query Logic
The system loads evaluated projects with their scores:
const { data : proyectos , error : pErr } = await supabaseClient
. from ( 'proyectos' )
. select ( `
id, nombre, categoria, semestre, anio, estado,
evaluaciones ( puntaje_final ),
proyecto_estudiantes (
perfiles ( nombre )
)
` )
. eq ( 'estado' , 'Evaluado' )
. eq ( 'anio' , year )
. eq ( 'semestre' , semester )
. eq ( 'categoria' , category );
Score Averaging
For projects with multiple evaluators, scores are averaged:
let rankedProjects = proyectos . map ( p => {
let avgScore = 0 ;
if ( p . evaluaciones && p . evaluaciones . length > 0 ) {
const totalScore = p . evaluaciones . reduce (( acc , curr ) => acc + parseFloat ( curr . puntaje_final || 0 ), 0 );
avgScore = parseFloat (( totalScore / p . evaluaciones . length ). toFixed ( 1 ));
}
let studentsText = 'Anónimo' ;
if ( p . proyecto_estudiantes && p . proyecto_estudiantes . length > 0 ) {
studentsText = p . proyecto_estudiantes . map ( pe => pe . perfiles ?. nombre ). join ( ', ' );
}
return {
id: p . id ,
nombre: escapeHTML ( p . nombre ),
students: escapeHTML ( studentsText ),
score: avgScore
};
});
Averaging Formula:
Project Score = ∑ i = 1 n Evaluator i Score n \text{Project Score} = \frac{\sum_{i=1}^{n} \text{Evaluator}_i\text{Score}}{n} Project Score = n ∑ i = 1 n Evaluator i Score
Where n n n is the number of evaluators who submitted evaluations.
Ranking Sort
rankedProjects . sort (( a , b ) => b . score - a . score );
const top5 = rankedProjects . slice ( 0 , 5 );
Projects are sorted by average score (descending) and limited to Top 5 for display.
Display Components
< div style = "text-align: center; margin-bottom: 3rem;" >
< h1 > Resultados Históricos </ h1 >
< p > Consulta el ranking de los mejores proyectos por año, semestre y categoría. </ p >
</ div >
Provides context about the purpose of the page.
Ranking Table
Results are displayed in a structured table:
let tableRowsHtml = top5 . map (( p , index ) => {
const rankClass = index === 0 ? 'rank-1' : ( index === 1 ? 'rank-2' : ( index === 2 ? 'rank-3' : '' ));
return `
<tr>
<td>
<div class="rank-badge ${ rankClass } "> ${ index + 1 } </div>
</td>
<td><strong> ${ p . nombre } </strong></td>
<td> ${ p . students } </td>
<td style="text-align: right; font-weight: 700; color: var(--primary-color); font-size: 1.2rem;">
${ p . score . toFixed ( 1 ) }
</td>
</tr>
` ;
}). join ( '' );
Table Columns:
Column Description Format Rank Position (1-5) Badge with special styling for top 3 Nombre del Proyecto Project title Bold text Integrantes Student names Comma-separated list Puntaje Final Average score 1 decimal place (e.g., 4.5)
Rank Badges
The top 3 positions receive special visual treatment:
Rank 1 : rank-1 class (typically gold/yellow styling)
Rank 2 : rank-2 class (typically silver/gray styling)
Rank 3 : rank-3 class (typically bronze/brown styling)
Ranks 4-5 : Default badge styling
Empty States
No Results Found
if ( top5 . length === 0 ) {
container . innerHTML = `
<div class="card">
<i class="fa-solid fa-ranking-star" style="font-size: 3rem; color: #cbd5e1;"></i>
<h3>No hay proyectos evaluados</h3>
<p>Aún no existen proyectos evaluados para <strong> ${ category } </strong> en el periodo <strong> ${ year } - ${ semester } </strong>.</p>
</div>
` ;
return ;
}
When no projects match the filter criteria, a friendly empty state appears with:
Icon indicating no results
Clear message explaining why
The specific category and period searched
Loading State
container . innerHTML = `
<div class="card">
<i class="fa-solid fa-circle-notch fa-spin" style="font-size: 2rem; color: var(--primary-color);"></i>
<p>Cargando ranking histórico...</p>
</div>
` ;
While data is loading, users see a spinning icon with a loading message.
Historical Gallery
Photo Gallery Component
The galeriaView.js file provides a visual complement to the results:
function renderGaleriaView () {
return `
<div style="max-width: 1200px; margin: 3rem auto; padding: 0 1rem;">
<div style="text-align: center; margin-bottom: 3rem;">
<h1>Galería de Proyectos</h1>
<p>Recuerdos visuales de las ediciones pasadas de la Rueda de Proyectos.</p>
</div>
` ;
}
Gallery Organization
Photos are organized by academic period:
< section >
< h2 > Año 2026 / Semestre 1 </ h2 >
< div class = "gallery-grid" >
< div class = "gallery-item" >
< i class = "fa-solid fa-code" ></ i >
< div > Stand Innovación </ div >
</ div >
< div class = "gallery-item" >
< i class = "fa-solid fa-microchip" ></ i >
< div > Prototipo IoT </ div >
</ div >
<!-- More items -->
</ div >
</ section >
Most recent semester with placeholder icons for:
Innovation stands
IoT prototypes
Winning teams
Live evaluations
< section >
< h2 > Año 2025 / Semestre 2 </ h2 >
< div class = "gallery-grid" >
< div class = "gallery-item" >
< i class = "fa-solid fa-robot" ></ i >
< div > Robótica Avanzada </ div >
</ div >
<!-- More items -->
</ div >
</ section >
Previous semester showing:
Advanced robotics
Mobile apps
Award ceremonies
Earlier period with data center and analytics projects
The gallery currently uses FontAwesome icons as placeholders. In production, these would be replaced with actual project photos uploaded during the event.
Public vs Authenticated Views
Access Levels
Public View
Student View
Docente View
Admin View
Anyone can see:
Top 5 rankings per category/period
Project names
Student names (for attribution)
Final averaged scores
Cannot see:
Individual evaluator scores
Evaluation observations
Pending projects
Admin controls
Students can see:
All public information
Their own project details
Their project’s full evaluation data (on their dashboard)
Cannot see:
Other students’ detailed evaluations
Evaluator identities
Docentes can see:
All public information
Projects they’re assigned to evaluate
Their own submitted evaluations
Cannot see:
Other evaluators’ scores before submission
Admins can see:
Everything
Full evaluation details
Evaluator assignments
All project data regardless of status
Search and Discovery
Filter Combinations
Users can combine filters to find specific results:
Example: Find Best Development Projects in 2025-1
Set Year: 2025
Set Semester: 1
Set Category: Desarrollo
Click “Filtrar”
Result: Top 5 software development projects from first semester 2025
Example: View All Proposals from Current Year
Set Year: 2026 (current)
Set Semester: 1 or 2 (current)
Set Category: Propuesta
Click “Filtrar”
Result: Top 5 research proposals from current semester
Example: Compare Across Semesters
Users can manually switch between semesters to compare:
Which semester had higher scores?
How many projects were evaluated?
Quality trends over time
Data Integrity
Score Precision
avgScore = parseFloat (( totalScore / p . evaluaciones . length ). toFixed ( 1 ));
Scores are displayed with 1 decimal place precision for consistency with the evaluation interface.
HTML Sanitization
nombre : escapeHTML ( p . nombre ),
students : escapeHTML ( studentsText ),
All user-generated content (project names, student names) is sanitized using the escapeHTML() function to prevent XSS attacks.
Error Handling
catch ( e ) {
console . error ( "loadHistoricalRankings Error:" , e );
if ( container ) {
container . innerHTML = `
<div class="card">
<i class="fa-solid fa-triangle-exclamation"></i>
<p>Ocurrió un error al cargar el ranking histórico.</p>
</div>
` ;
}
}
If database queries fail, users see a friendly error message while errors are logged for debugging.
Query Optimization
The system uses Supabase’s query expansion to reduce round trips:
. select ( `
id, nombre, categoria, semestre, anio, estado,
evaluaciones ( puntaje_final ),
proyecto_estudiantes (
perfiles ( nombre )
)
` )
This single query fetches:
Project data
All related evaluations
Student profile information
By joining related tables in the query, we avoid the N+1 query problem and load all necessary data in one database round trip.
Automatic Updates
The results page automatically refreshes when:
Users change filter selections
The page is loaded/reloaded
No manual refresh needed - the system always shows current data from the database.
Evaluation System Understand how scores are generated and averaged
Project Management Learn how projects are created and tracked through their lifecycle