Index: iknow-api/Repository/Implementations/ProfRepository.cs
===================================================================
--- iknow-api/Repository/Implementations/ProfRepository.cs	(revision ea405569ef29f56fbfc4d77708b6b3faf9286097)
+++ iknow-api/Repository/Implementations/ProfRepository.cs	(revision ea405569ef29f56fbfc4d77708b6b3faf9286097)
@@ -0,0 +1,77 @@
+using iknow_api.Data;
+using iknow_api.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace iknow_api.Repositories
+{
+    public class ProfRepository : IProfRepository
+    {
+        private readonly AppDbContext _context;
+
+        public ProfRepository(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        /// <summary>
+        /// A professor teaches a subject for a given enrolment, so the students
+        /// are reached through semesters_subjects.professor_id and the student
+        /// through the enrolment - matching the ER model, which does not link
+        /// SemestersSubjects to a student directly.
+        /// </summary>
+        private IQueryable<SemesterSubject> TaughtBy(int professorId) =>
+            _context.SemesterSubjects
+                .Where(ss => ss.ProfessorId == professorId)
+                .Include(ss => ss.Subject)
+                .Include(ss => ss.PassedSubject)
+                .Include(ss => ss.EnrolledSemester!)
+                    .ThenInclude(es => es.User)
+                .Include(ss => ss.EnrolledSemester!)
+                    .ThenInclude(es => es.Semester);
+
+        public async Task<List<SemesterSubject>> GetTaughtSemesterSubjectsAsync(int professorId) =>
+            await TaughtBy(professorId)
+                .AsNoTracking()
+                .AsSplitQuery()
+                .ToListAsync();
+
+        public async Task<SemesterSubject?> FindTaughtSemesterSubjectAsync(
+            int professorId, int studentId, int subjectId)
+        {
+            var candidates = await TaughtBy(professorId)
+                .Where(ss => ss.SubjectId == subjectId
+                          && ss.EnrolledSemester!.UserId == studentId)
+                .AsSplitQuery()
+                .ToListAsync();
+
+            // Most recent enrolment first. Semesters are labelled Year/Year+1
+            // throughout the app, so within one year summer follows winter.
+            return candidates
+                .OrderByDescending(ss => ss.EnrolledSemester!.Semester!.Year)
+                .ThenByDescending(ss => ss.EnrolledSemester!.Semester!.Type == sType.summer)
+                .FirstOrDefault();
+        }
+
+        public async Task<PassedSubject?> GetPassedSubjectAsync(int semesterSubjectId) =>
+            await _context.PassedSubjects
+                .FirstOrDefaultAsync(ps => ps.SemesterSubjectId == semesterSubjectId);
+
+        public async Task AddPassedSubjectAsync(PassedSubject passed)
+        {
+            _context.PassedSubjects.Add(passed);
+            await _context.SaveChangesAsync();
+        }
+
+        public async Task UpdatePassedSubjectAsync(PassedSubject passed)
+        {
+            _context.PassedSubjects.Update(passed);
+            await _context.SaveChangesAsync();
+        }
+
+        public async Task RemovePassedSubjectAsync(PassedSubject passed)
+        {
+            _context.PassedSubjects.Remove(passed);
+            await _context.SaveChangesAsync();
+        }
+    }
+}
Index: iknow-api/Repository/Implementations/RefreshTokenRepository.cs
===================================================================
--- iknow-api/Repository/Implementations/RefreshTokenRepository.cs	(revision 10009b9505124c201c365c19c07a9df40b091035)
+++ iknow-api/Repository/Implementations/RefreshTokenRepository.cs	(revision ea405569ef29f56fbfc4d77708b6b3faf9286097)
@@ -41,5 +41,5 @@
                     rt.Token == refreshTokenDto.token &&
                     rt.IsValid &&
-                    rt.ExpiresAt > DateTime.UtcNow);
+                    rt.ExpiresAt > DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified));
 
             return token != null;
Index: iknow-api/Repository/Implementations/UserRepository.cs
===================================================================
--- iknow-api/Repository/Implementations/UserRepository.cs	(revision 10009b9505124c201c365c19c07a9df40b091035)
+++ iknow-api/Repository/Implementations/UserRepository.cs	(revision ea405569ef29f56fbfc4d77708b6b3faf9286097)
@@ -28,6 +28,12 @@
             return await _context.User
                 .Include(u => u.ContactInfo)
-                .Include(u => u.EnrollmentInfo)
                 .Include(u => u.HighSchool)
+                // The study programme is reached through the enrolment, since
+                // Major hangs off EnrolledSemesters rather than off Users.
+                .Include(u => u.Enrolments!)
+                    .ThenInclude(es => es.Major)
+                .Include(u => u.Enrolments!)
+                    .ThenInclude(es => es.Semester)
+                .AsSplitQuery()
                 .FirstOrDefaultAsync(u => u.Id == id);
         }
@@ -48,9 +54,4 @@
             await _context.SaveChangesAsync();
         }
-        public async Task AddEnrollmentAsync(EnrollmentInfo enrollment)
-        {
-            _context.EnrollmentInfo.Add(enrollment);
-            await _context.SaveChangesAsync();
-        }   
         public async Task AddHighSchoolAsync(HighSchool highSchool)
         {
@@ -89,5 +90,7 @@
                 .Include(ps => ps.SemesterSubject)
                     .ThenInclude(ss => ss.Professor)
-                .Where(ps => ps.SemesterSubject.UserId == id)
+                // The ER model reaches the student through the enrolment,
+                // not through a user_id on semesters_subjects.
+                .Where(ps => ps.SemesterSubject.EnrolledSemester.UserId == id)
                 .ToListAsync();
         }
