Prototype illustrative role assignments project

This commit is contained in:
ivan-pelly
2026-02-19 07:19:50 -08:00
parent 9d9a416d1c
commit f178add2be
34 changed files with 2118 additions and 0 deletions
@@ -0,0 +1,39 @@
// =============================================================================
// AssignmentType.cs
// =============================================================================
// This enum represents the RELATIONSHIP between a user and a student.
//
// Think of it this way: a user's ROLE (Teacher, Paraeducator, Supervisor) tells
// you WHAT they are. Their ASSIGNMENT TYPE tells you HOW they're connected to a
// specific student.
//
// For example, a Teacher might be the "PrimaryTeacher" for Student A, but have
// "TemporaryCoverage" for Student B (e.g., covering for a colleague on leave).
//
// This is stored in the `student_assignments` table in the database —
// each row says "User X is connected to Student Y as [this type]."
// =============================================================================
namespace RolesAssignments.Models;
public enum AssignmentType
{
// The main teacher responsible for this student.
// Has full read/write access to goals, entries, sensitive notes, etc.
PrimaryTeacher,
// A paraeducator (teaching assistant) assigned to help with this student.
// Can view the student and add progress entries, but can only edit/delete
// their OWN entries — not entries made by someone else.
Paraeducator,
// A supervisor (admin/principal) overseeing this student.
// Has read-only access: can view everything and generate reports,
// but cannot create, edit, or delete anything.
Supervisor,
// A teacher temporarily covering for the primary teacher (e.g., sick leave).
// In this prototype, treated similarly to PrimaryTeacher for simplicity,
// but in a real system you might limit what they can do.
TemporaryCoverage
}
+28
View File
@@ -0,0 +1,28 @@
// =============================================================================
// Goal.cs
// =============================================================================
// Represents a learning goal that belongs to a specific student.
// For example: "Student will read 20 words per minute by end of semester."
//
// Only a PrimaryTeacher (or TemporaryCoverage) can create or edit goals.
// Everyone else assigned to the student can VIEW them, but not change them.
// =============================================================================
namespace RolesAssignments.Models;
public class Goal
{
public int Id { get; set; }
// The student this goal belongs to.
// This is the foreign key back to the students table.
public int StudentId { get; set; }
// The text of the goal itself
public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
// Who created this goal and when
public int CreatedByUserId { get; set; }
public DateTime CreatedAt { get; set; }
}
@@ -0,0 +1,41 @@
// =============================================================================
// ProgressEntry.cs
// =============================================================================
// Represents a single log entry tracking a student's progress toward a goal.
// For example: "Feb 19 — Student read 15 words per minute today."
//
// This is the entity that demonstrates the TWO-LAYER authorization check:
//
// Layer 1 (Student-level): "Is this user assigned to the student at all?"
// Layer 2 (Entry-level): "Does this user own THIS specific entry?"
//
// Teachers can edit/delete ANY entry for their assigned students.
// Paraeducators can only edit/delete entries THEY created.
// Supervisors cannot edit/delete anything.
//
// The key field for Layer 2 is `CreatedByUserId` — it tells us who wrote
// this entry, which determines ownership.
// =============================================================================
namespace RolesAssignments.Models;
public class ProgressEntry
{
public int Id { get; set; }
// Which student this entry is about
public int StudentId { get; set; }
// The content of the progress note
public string Notes { get; set; } = string.Empty;
// WHO created this entry — this is the field used for ownership checks.
// When a paraeducator tries to edit an entry, we compare this field
// against the current user's ID to decide if they're allowed.
public int CreatedByUserId { get; set; }
public DateTime CreatedAt { get; set; }
// Soft-delete: mark as deleted instead of actually removing the row
public bool IsDeleted { get; set; }
}
@@ -0,0 +1,41 @@
// =============================================================================
// Requests.cs
// =============================================================================
// These are the "request" DTOs — the shapes of data that the API expects to
// RECEIVE from the caller when creating or updating resources.
//
// They're intentionally simple: just the fields the caller controls.
// Things like Id, CreatedByUserId, and CreatedAt are set by the server,
// not by the caller.
//
// In a real app, you'd add validation attributes here (e.g., [Required],
// [MaxLength(500)]) to enforce rules before the data reaches your logic.
// =============================================================================
namespace RolesAssignments.Models;
// --- Goal Requests ---
public class CreateGoalRequest
{
public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
public class UpdateGoalRequest
{
public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
// --- Progress Entry Requests ---
public class CreateEntryRequest
{
public string Notes { get; set; } = string.Empty;
}
public class UpdateEntryRequest
{
public string Notes { get; set; } = string.Empty;
}
@@ -0,0 +1,30 @@
// =============================================================================
// Student.cs
// =============================================================================
// A simple student entity. In a real app this would map to the `students` table.
//
// Note: students don't "belong" to a teacher directly. Instead, the connection
// is made through the `student_assignments` table (see StudentAssignment.cs).
// This keeps the data model flexible — a student can have multiple adults
// working with them, each with a different level of access.
// =============================================================================
namespace RolesAssignments.Models;
public class Student
{
public int Id { get; set; }
// A human-readable label like "Student A" or an internal identifier.
// In a real system this might be a school-issued ID number.
public string Identifier { get; set; } = string.Empty;
// e.g., "2025-2026"
public string ProgramYear { get; set; } = string.Empty;
public int Age { get; set; }
// Soft-delete flag. Instead of removing rows from the database,
// we mark them as deleted so we can still reference historical data.
public bool IsDeleted { get; set; }
}
@@ -0,0 +1,49 @@
// =============================================================================
// StudentAssignment.cs
// =============================================================================
// This class represents a single row from the `student_assignments` table.
//
// It is THE MOST IMPORTANT piece of data in the entire authorization system.
// Every permission decision boils down to: "Does this user have an active
// assignment to this student, and if so, what type is it?"
//
// The corresponding database table looks like this:
//
// CREATE TABLE student_assignments (
// id INT PRIMARY KEY AUTO_INCREMENT,
// user_id INT NOT NULL,
// student_id INT NOT NULL,
// assignment_type ENUM('PrimaryTeacher','Paraeducator','Supervisor','TemporaryCoverage') NOT NULL,
// start_date DATE NOT NULL,
// end_date DATE NULL, -- NULL means "no end date" (ongoing)
// is_active BOOLEAN NOT NULL DEFAULT TRUE,
// FOREIGN KEY (user_id) REFERENCES users(id),
// FOREIGN KEY (student_id) REFERENCES students(id)
// );
// =============================================================================
namespace RolesAssignments.Models;
public class StudentAssignment
{
public int Id { get; set; }
// Which user is assigned
public int UserId { get; set; }
// Which student they're assigned to
public int StudentId { get; set; }
// What kind of assignment this is (see AssignmentType.cs for details)
public AssignmentType AssignmentType { get; set; }
// When this assignment started (e.g., the beginning of the school year)
public DateTime StartDate { get; set; }
// When this assignment ends. NULL means it's ongoing with no planned end date.
public DateTime? EndDate { get; set; }
// A quick on/off switch. If a student transfers classes, you can set this
// to false instead of deleting the row — preserving the history.
public bool IsActive { get; set; }
}
@@ -0,0 +1,27 @@
// =============================================================================
// StudentSummaryDto.cs
// =============================================================================
// A "DTO" (Data Transfer Object) is a lightweight object designed specifically
// for sending data over the wire (in API responses). It contains only the
// fields the caller needs — no internal details, no navigation properties.
//
// This DTO is returned by the "Get My Students" list endpoint. It includes
// the student's basic info plus the assignment type, so the frontend knows
// what kind of access the current user has.
// =============================================================================
namespace RolesAssignments.Models;
public class StudentSummaryDto
{
public int Id { get; set; }
public string Identifier { get; set; } = string.Empty;
public string ProgramYear { get; set; } = string.Empty;
public int Age { get; set; }
// This tells the frontend what the current user's relationship to this
// student is. For supervisors who see all students, this might be null
// for students they don't have a direct assignment to (though in this
// prototype, supervisors always have Supervisor-type assignments).
public string? AssignmentType { get; set; }
}