Skip to content
$ ash_
All work
2022/Full-Stack Developer/archived

Education Management Portal

3 distinct user roles in one coherent application

A multi-role web application for managing courses, enrolments, and student data, built with Python and Flask.

Stack

PythonFlaskHTMLCSSSQL

Problem

Building a platform with multiple user roles sounds straightforward until you hit the edge cases: what can an instructor see that a student can't? What happens if someone tries to access a URL they don't have permission for? This project was a deliberate study in building role-based access control from scratch rather than relying on a framework's defaults.

My Contribution

Built the full application — backend architecture, RBAC implementation, database schema, and frontend templates. The key design decisions were mine:

  • Modular Flask blueprints — one blueprint per user role (Admin, Instructor, Student) so each stays focused and independent
  • Route-level RBAC enforcement — permissions checked server-side on every request, not hidden in templates
  • SQL schema designed around the multi-role relationship model — clean joins between users, courses, and enrolments

Architecture

Flask backend with three blueprint modules. Admin has full platform access. Instructor scope is limited to their own courses. Student scope covers available courses and their own enrolments.

The critical architectural decision was enforcing access control at the route level, not the template level. Hiding elements in the UI isn't security — a direct URL request bypasses all of it. Every protected endpoint validates the session role before doing anything else.

SQL schema uses a standard relational model: users table with a role field, courses, enrolments as a junction table. Kept the queries simple and readable rather than clever.

Outcomes

Three fully functional user flows — each role sees exactly what it should and nothing it shouldn't. Direct URL attacks on restricted routes return 403s, not redirected views. The codebase stayed readable as features grew because each blueprint owns its own territory.

Learnings

RBAC edge cases are where the complexity hides. The happy path is trivial. The interesting questions are: what happens when a student tries to enrol in a course that's full? What if an instructor tries to view another instructor's student list? Working through those cases here made me much more deliberate about permission design in later projects.