init 1.0.0

This commit is contained in:
2026-06-19 00:42:00 +02:00
commit 5ca960746b
67 changed files with 3261 additions and 0 deletions
@@ -0,0 +1,87 @@
using LehrerApp.Core.Models;
namespace LehrerApp.Core.Interfaces;
public interface IStudentRepository
{
Student? GetById(Guid id);
List<Student> GetAll(bool includeInactive = false);
List<Student> GetByGroup(Guid groupId, string schoolYear);
void Save(Student student);
void Delete(Guid id);
}
public interface IGroupRepository
{
LearningGroup? GetById(Guid id);
List<LearningGroup> GetAll();
List<LearningGroup> GetBySchoolYear(string schoolYear);
void Save(LearningGroup group);
void Delete(Guid id);
}
public interface IEnrollmentRepository
{
List<Enrollment> GetByStudent(Guid studentId);
List<Enrollment> GetByGroup(Guid groupId);
List<Enrollment> GetByGroupAndYear(Guid groupId, string schoolYear);
void Save(Enrollment enrollment);
void Delete(Guid id);
}
public interface IExamRepository
{
Exam? GetById(Guid id);
List<Exam> GetByGroup(Guid groupId);
void Save(Exam exam);
void Delete(Guid id);
}
public interface IExamResultRepository
{
List<ExamResult> GetByExam(Guid examId);
List<ExamResult> GetByStudent(Guid studentId);
ExamResult? GetByExamAndStudent(Guid examId, Guid studentId);
void Save(ExamResult result);
void SaveMany(List<ExamResult> results);
}
public interface IGradeRepository
{
List<Grade> GetByStudentAndGroup(Guid studentId, Guid groupId);
List<Grade> GetByGroup(Guid groupId);
void Save(Grade grade);
void Delete(Guid id);
}
public interface IUnitRepository
{
Unit? GetById(Guid id);
List<Unit> GetByGroup(Guid groupId);
void Save(Unit unit);
void Delete(Guid id);
}
public interface ILessonRepository
{
List<Lesson> GetByUnit(Guid unitId);
List<Lesson> GetByGroupAndDate(Guid groupId, DateOnly date);
List<Lesson> GetByGroupAndRange(Guid groupId, DateOnly from, DateOnly to);
void Save(Lesson lesson);
void Delete(Guid id);
}
public interface IDocumentationRepository
{
List<Documentation> GetByStudent(Guid studentId);
List<Documentation> GetByStudentAndType(Guid studentId, DocumentationType type);
void Save(Documentation doc);
void Delete(Guid id);
}
public interface IWorkTaskRepository
{
List<WorkTask> GetByStatus(WorkTaskStatus status);
List<WorkTask> GetAll();
void Save(WorkTask task);
void Delete(Guid id);
}
public interface ITimeEntryRepository
{
List<TimeEntry> GetByDate(DateOnly date);
List<TimeEntry> GetByDateRange(DateOnly from, DateOnly to);
List<TimeEntry> GetByTask(Guid taskId);
void Save(TimeEntry entry);
void Delete(Guid id);
}
+5
View File
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project>
+42
View File
@@ -0,0 +1,42 @@
namespace LehrerApp.Core.Models;
public class Exam
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid GroupId { get; set; }
public string Title { get; set; } = "";
public DateOnly Date { get; set; }
public string Subject { get; set; } = "";
public int? ExamNumber { get; set; }
public List<ExamTask> Tasks { get; set; } = [];
public List<GradingKeyEntry> GradingKey { get; set; } = [];
public ExamStatus Status { get; set; } = ExamStatus.Planned;
public string? Notes { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class ExamTask
{
public int Nr { get; set; }
public string? Title { get; set; }
public double MaxPoints { get; set; }
public double Weight { get; set; } = 1.0;
}
public class GradingKeyEntry
{
public string Grade { get; set; } = "";
public double MinPercent { get; set; }
}
public class ExamResult
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid ExamId { get; set; }
public Guid StudentId { get; set; }
public List<double> Points { get; set; } = [];
public double TotalPoints { get; set; }
public string? Grade { get; set; }
public bool Absent { get; set; }
public string? Comment { get; set; }
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public enum ExamStatus { Planned, Conducted, Graded, Returned }
+26
View File
@@ -0,0 +1,26 @@
namespace LehrerApp.Core.Models;
public class LearningGroup
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
public GroupType Type { get; set; }
public string? Subject { get; set; }
public string SchoolYear { get; set; } = "";
public int GradeLevel { get; set; }
public GradingSystem GradingSystem { get; set; }
public int? HoursPerWeek { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class Enrollment
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid StudentId { get; set; }
public Guid GroupId { get; set; }
public string SchoolYear { get; set; } = "";
public DateOnly EnrolledAt { get; set; } = DateOnly.FromDateTime(DateTime.Today);
public DateOnly? LeftAt { get; set; }
}
public enum GroupType { Class, Course }
public enum GradingSystem { Grades1To6, Points0To15 }
+50
View File
@@ -0,0 +1,50 @@
namespace LehrerApp.Core.Models;
public class Grade
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid StudentId { get; set; }
public Guid GroupId { get; set; }
public string SchoolYear { get; set; } = "";
public GradeCategory Category { get; set; }
public string Value { get; set; } = "";
public DateOnly Date { get; set; }
public double Weight { get; set; } = 1.0;
public string? Note { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
public enum GradeCategory { Oral, Homework, Participation, Project, Other }
public class Unit
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid GroupId { get; set; }
public string Title { get; set; } = "";
public string Subject { get; set; } = "";
public string SchoolYear { get; set; } = "";
public DateOnly? StartDate { get; set; }
public DateOnly? EndDate { get; set; }
public List<string> Competencies { get; set; } = [];
public UnitStatus Status { get; set; } = UnitStatus.Planned;
public string? Notes { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class Lesson
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid UnitId { get; set; }
public Guid GroupId { get; set; }
public DateOnly Date { get; set; }
public int? LessonNumber { get; set; }
public string Topic { get; set; } = "";
public string? Phase { get; set; }
public List<string> Methods { get; set; } = [];
public List<string> Materials { get; set; } = [];
public string? Homework { get; set; }
public string? Reflection { get; set; }
public LessonStatus Status { get; set; } = LessonStatus.Planned;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public enum UnitStatus { Planned, Active, Completed }
public enum LessonStatus { Planned, Conducted }
+24
View File
@@ -0,0 +1,24 @@
namespace LehrerApp.Core.Models;
public class Student
{
public Guid Id { get; set; } = Guid.NewGuid();
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public string FullName => $"{LastName}, {FirstName}";
public DateOnly? DateOfBirth { get; set; }
public Gender? Gender { get; set; }
public List<Contact> Contacts { get; set; } = [];
public string? Notes { get; set; }
public bool IsActive { get; set; } = true;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class Contact
{
public string Name { get; set; } = "";
public string Relation { get; set; } = "";
public string? Phone { get; set; }
public string? Email { get; set; }
}
public enum Gender { M, W, D }
+61
View File
@@ -0,0 +1,61 @@
namespace LehrerApp.Core.Models;
public class Documentation
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid StudentId { get; set; }
public Guid? GroupId { get; set; }
public DocumentationType Type { get; set; }
public DateOnly Date { get; set; }
public string Title { get; set; } = "";
public string Content { get; set; } = "";
public List<string> Participants { get; set; } = [];
public AbsenceData? AbsenceData { get; set; }
public SupportData? SupportData { get; set; }
public bool IsConfidential { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class AbsenceData
{
public int LessonCount { get; set; }
public bool Excused { get; set; }
public string? Reason { get; set; }
}
public class SupportData
{
public List<string> Measures { get; set; } = [];
public DateOnly? ReviewDate { get; set; }
public SupportStatus Status { get; set; } = SupportStatus.Active;
}
public enum DocumentationType { Conversation, Incident, SupportPlan, Absence }
public enum SupportStatus { Active, Completed, Paused }
public class WorkTask
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Title { get; set; } = "";
public TaskCategory Category { get; set; }
public Guid? GroupId { get; set; }
public DateOnly? DueDate { get; set; }
public int? EstimatedMinutes { get; set; }
public WorkTaskStatus Status { get; set; } = WorkTaskStatus.Open;
public string? Notes { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class TimeEntry
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid? TaskId { get; set; }
public string Category { get; set; } = "";
public Guid? GroupId { get; set; }
public DateOnly Date { get; set; }
public TimeOnly? StartTime { get; set; }
public TimeOnly? EndTime { get; set; }
public int DurationMinutes { get; set; }
public string? Description { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
public enum TaskCategory { Correction, Preparation, Admin, Meeting, Other }
public enum WorkTaskStatus { Open, InProgress, Done }
+52
View File
@@ -0,0 +1,52 @@
using LehrerApp.Core.Models;
namespace LehrerApp.Core.Services;
public class GradingService
{
public string CalculateGrade(double achieved, double maximum, List<GradingKeyEntry> key)
{
if (maximum <= 0) return "-";
var percent = achieved / maximum * 100.0;
return key.OrderByDescending(k => k.MinPercent)
.FirstOrDefault(k => percent >= k.MinPercent)
?.Grade ?? key.OrderBy(k => k.MinPercent).First().Grade;
}
public static List<GradingKeyEntry> DefaultKey1To6() =>
[
new() { Grade = "1", MinPercent = 87.5 },
new() { Grade = "2", MinPercent = 75.0 },
new() { Grade = "3", MinPercent = 62.5 },
new() { Grade = "4", MinPercent = 50.0 },
new() { Grade = "5", MinPercent = 25.0 },
new() { Grade = "6", MinPercent = 0.0 },
];
public static List<GradingKeyEntry> DefaultKey0To15() =>
[
new() { Grade = "15", MinPercent = 95.0 },
new() { Grade = "14", MinPercent = 90.0 },
new() { Grade = "13", MinPercent = 85.0 },
new() { Grade = "12", MinPercent = 80.0 },
new() { Grade = "11", MinPercent = 75.0 },
new() { Grade = "10", MinPercent = 70.0 },
new() { Grade = "9", MinPercent = 65.0 },
new() { Grade = "8", MinPercent = 60.0 },
new() { Grade = "7", MinPercent = 55.0 },
new() { Grade = "6", MinPercent = 50.0 },
new() { Grade = "5", MinPercent = 45.0 },
new() { Grade = "4", MinPercent = 40.0 },
new() { Grade = "3", MinPercent = 33.0 },
new() { Grade = "2", MinPercent = 27.0 },
new() { Grade = "1", MinPercent = 20.0 },
new() { Grade = "0", MinPercent = 0.0 },
];
public double WeightedAverage(List<(string Grade, double Weight)> grades)
{
var numeric = grades
.Select(g => (Value: int.TryParse(g.Grade, out var n) ? (int?)n : null, g.Weight))
.Where(g => g.Value.HasValue).ToList();
if (numeric.Count == 0) return 0;
var total = numeric.Sum(g => g.Weight);
return total == 0 ? 0 : numeric.Sum(g => g.Value!.Value * g.Weight) / total;
}
}
@@ -0,0 +1,22 @@
namespace LehrerApp.Core.Services;
public class SchoolYearService
{
public string CurrentSchoolYear()
{
var now = DateTime.Today;
return FormatSchoolYear(now.Month >= 8 ? now.Year : now.Year - 1);
}
public string FormatSchoolYear(int startYear) =>
$"{startYear}/{(startYear + 1) % 100:D2}";
public DateOnly SchoolYearStart(string sy) =>
new(int.Parse(sy.Split('/')[0]), 8, 1);
public DateOnly SchoolYearEnd(string sy) =>
new(int.Parse(sy.Split('/')[0]) + 1, 7, 31);
public List<string> RecentSchoolYears(int count = 5)
{
var now = DateTime.Today;
var cur = now.Month >= 8 ? now.Year : now.Year - 1;
return Enumerable.Range(0, count).Select(i => FormatSchoolYear(cur - i)).ToList();
}
}