A Strategic Partnership between Tyto Insights, DNS Business, and Team Vigil
Built by: Wilmar Smit, Michael Tomlinson, Johan Coetzer, Marcel Stoltz, & Aidan Dawson
UMTAS automates the full university timetabling lifecycle - from ingesting raw PDF schedules and extracting hard and soft scheduling constraints, through to delivering conflict-free, optimised timetables to up to 20,000 concurrent students.
The system is university-agnostic by design: a Core-and-Adapter architecture cleanly separates the constraint-solving engine from institution-specific data formats. Onboarding a new university requires only a thin adapter - the core solver remains untouched.
|
Traditional timetabling is a multi-week manual process. Administrators juggle hundreds of constraints - venue capacities, lecturer availability, student group conflicts - in spreadsheets. A single room change cascades into hours of rescheduling. |
UMTAS ingests the university's existing PDF calendar, parses all constraints automatically, and invokes a CP-SAT constraint-programming solver to generate an optimal schedule in seconds - not weeks. |
Expand features
|
PyMuPDF-powered extraction parses structured and semi-structured university PDF calendars into machine-readable constraint sets - zero manual data entry. |
Google OR-Tools CP-SAT solver handles hard constraints (no double-booking, room capacity) and soft constraints (lecturer preferences, day-spread) with optimal solutions. |
BullMQ-backed job queue processes re-solve requests asynchronously. Administrators receive conflict alerts and revised schedules without blocking the UI. |
|
A Core-and-Adapter architecture decouples the solver from any single institution's data format. New universities onboard by implementing a thin adapter - the core is never touched. |
Prometheus metrics, Grafana dashboards, and Loki log aggregation are provisioned out-of-the-box. PostHog captures product analytics for continuous UX improvement. |
OAuth 2.0 authentication, role-based access control, Redis-backed session management, and MinIO for isolated document storage. All traffic routed through Traefik with TLS termination. |
Expand technology stack
Frontend & UI
Backend & Core
Solver & AI
Infrastructure & DevOps
Testing & QA
Monitoring
This is a pnpm monorepo managed by Turborepo. All applications, shared packages, and infrastructure live in one repository to enable atomic commits and shared tooling across every workstream.
Expand directory tree
UMTAS/
├── apps/
│ ├── backend/ # NestJS API — controllers, services, DrizzleORM, BullMQ
│ │ └── src/
│ │ ├── auth/ # BetterAuth, JWT, RBAC
│ │ ├── Events/ # Event scheduling domain
│ │ ├── Module/ # Module management
│ │ ├── Timetable/ # Timetable CRUD & generation
│ │ ├── mail/ # Transactional email
│ │ └── db/ # Drizzle schema & migrations
│ ├── frontend/ # Next.js — App Router, Tailwind, Shadcn/UI
│ │ └── src/
│ │ ├── app/ # Route segments
│ │ ├── components/ # Shared UI components
│ │ └── lib/ # Utilities & API client
│ ├── solver/ # FastAPI — OR-Tools CP-SAT constraint solver
│ │ ├── main.py
│ │ └── swagger_ui.py
│ └── e2e/ # Playwright end-to-end tests
├── packages/
│ ├── database/ # Shared Drizzle schema & migration tooling
│ └── shared-types/ # Shared TypeScript types across apps
├── infra/
│ ├── traefik/ # Reverse proxy & TLS termination
│ ├── grafana/ # Dashboards & alerting
│ ├── prometheus/ # Metrics scraping
│ ├── loki/ # Log aggregation
│ └── promtail/ # Log shipping
├── docker-compose.yml # Base service definitions
├── docker-compose.prod.yml # Production overrides
├── turbo.json # Turborepo pipeline config
└── pnpm-workspace.yaml # Workspace package declarations
System architecture diagram
The system follows a Service-Oriented Architecture. The Next.js frontend communicates exclusively with the NestJS API Core, which enforces JWT authentication and RBAC before dispatching long-running work (PDF parsing, constraint solving) to stateless workers via a BullMQ job queue. The FastAPI solver and PDF parser run as independently scalable services. All traffic is routed through Traefik with TLS termination.
Expand branching strategy
All development follows a TDD Git Flow. Feature work is done in short-lived branches and merged into dev via pull request. main only receives merges from dev at release points. Every pull request requires CI to pass and at least one peer review.
gitGraph LR:
commit id: "v0.1.0"
branch dev
checkout dev
commit id: "baseline"
branch feat/pdf-parser
checkout feat/pdf-parser
commit id: "failing tests"
commit id: "implementation"
checkout dev
merge feat/pdf-parser id: "PR #12"
branch fix/auth-token
checkout fix/auth-token
commit id: "fix applied"
checkout dev
merge fix/auth-token id: "PR #15"
checkout main
merge dev id: "v0.2.0"
Team Vigil comprises five University of Pretoria Computer Science students with complementary profiles across full-stack development, system architecture, DevOps, data engineering, and machine learning.
Bootstrap - First Time Setup
pnpm run setupVerifies tool versions, copies .env.example to .env, installs all workspace dependencies, and prepares the Python solver container.
Local Development (Recommended)
# Terminal 1 - infrastructure (Postgres, Redis, MinIO, Solver)
pnpm run dev:infra
# Terminal 2 - application (Next.js + NestJS via Turborepo)
pnpm run devRuns infrastructure in Docker and the application natively for the fastest hot-reload performance.
Full Docker Stack
pnpm run dev:dockerBoots the complete stack - frontend, backend, and all infrastructure - in containers. Use this to verify network flows and environment variables before a merge.
With Monitoring (PLG Stack)
pnpm run dev:monitorAdds Grafana, Prometheus, and Loki to the stack for local observability testing.