Unitru Academic provides two complementary schedule features. The Weekly Schedule reconstructs your current timetable from real attendance data — no manual input needed — and displays it as a Monday-to-Friday grid with course name, group, teacher, and classroom for each block. The Schedule Optimizer operates independently: given a list of course names from the official catalog, it finds the top-5 conflict-free section combinations ranked by a scoring function that penalizes idle gaps, excess campus days, and extreme-hour sessions.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Andr21Da16/UNITRU-ACADEMIC/llms.txt
Use this file to discover all available pages before exploring further.
Weekly Schedule
How It Is Built
The weekly schedule is derived entirely from attendance session records extracted from the SUV. The builder lives inbackend/src/domain/services/schedule_builder.py and follows this process:
Identify the student's real turn
The SUV often embeds sessions from multiple groups inside the same attendance tracker. The builder detects the student’s actual turn by looking for the
(day, start_time, end_time) blocks where at least one session has a non-absent status (P, PRESENTE, A, J, JUSTIFICADO, JU). Blocks belonging to other groups (all statuses S/A) are discarded. If no block shows any attendance yet — for example in the first week of the cycle — all blocks are kept so that no course disappears from the grid.Deduplicate slots
Sessions are collapsed by a
(day_name, start_time, end_time, course_name) key. Only the first occurrence of each unique combination becomes a ScheduleSlot — cancelled sessions are always skipped.Enrich from the enrollment record
When enrollment data is available, each slot is cross-referenced against enrolled courses by normalized course name (uppercased, whitespace-collapsed). The enrollment record supplies
group and teacher when they are present.ScheduleSlot Fields
Grid Layout
The frontend (schedule_grid.tsx) renders only the days that have at least one slot. Multiple courses that share the same time block (e.g., theory and practice) are stacked vertically inside the same cell rather than overwriting each other. Enrolled courses with no confirmed attendance yet are surfaced as a warning banner at the top of the grid so the student does not lose track of them.
Schedule Optimizer
The optimizer is implemented inbackend/src/domain/services/schedule_optimizer.py. It is used to plan the next enrollment cycle by finding the best conflict-free combination of sections from the official course catalog.
Optimizer Weights
Scoring uses aOptimizerWeights dataclass — lower score = better schedule:
| Field | Default | Description |
|---|---|---|
gap_per_hour | 1.0 | Penalty per hour of idle time between classes on the same day |
per_day | 3.0 | Penalty per campus day |
per_extreme | 2.0 | Penalty per session starting before 08:00 or ending after 19:00 |
early_before_min | 480 (08:00) | Sessions starting before this minute-of-day count as extreme |
late_after_min | 1140 (19:00) | Sessions ending after this minute-of-day count as extreme |
OptimizedSchedule Fields
Each candidate schedule returned by the optimizer exposes:| Field | Type | Description |
|---|---|---|
score | float | Total penalty score (lower = better) |
days | int | Number of distinct campus days |
gap_minutes | int | Total idle minutes between classes across all days |
extreme_sessions | int | Number of sessions in extreme hours |
selections | list[CourseSelection] | One section/subgroup choice per course |
sessions | list[CatalogSession] | Flattened list of all individual sessions (property) |
How the Algorithm Works
Build candidate selections per course
For each requested course name the optimizer queries the catalog using normalized matching (Unicode-stripped, lowercased, whitespace-normalized). Sections are grouped by
(cycle, section). Within a section, sessions without a subgroup (theory/practice shared by all) are always included; each distinct subgroup label (lab groups G1/G2/…) produces one CourseSelection candidate, each bundling the shared fixed sessions with that subgroup’s own sessions.Backtracking with conflict detection
A recursive backtracking function walks through the course list. For each candidate selection it checks every session against all already-committed sessions for overlap:
a.day == b.day AND a.start_min < b.end_min AND b.start_min < a.end_min. Any overlapping candidate is skipped entirely.Score and sort
Every complete combination of one selection per course is scored and appended to the results list. After all combinations are exhausted, the list is sorted ascending by
score.optimize() Signature
Missing Courses
If a requested course name is not found in the catalog (after normalization), it is appended to themissing list and excluded from optimization. The remaining courses are still optimized normally.
UI Presentation
The optimizer view (optimizer_view.tsx) renders each candidate schedule as an expandable panel labeled Opción 1 · recomendada (lowest score) through Opción 5. Each panel shows:
- A chip row listing the selected section (and lab subgroup when applicable) for each course.
- A summary line: number of campus days, total idle time, and extreme-session count.
- A full schedule grid reusing the same
ScheduleGridcomponent as the weekly schedule.