← All work
Higher education · internal toolsSole developerDelivered

Course Governance Platform

Semester course approval for a university, from department head to Student Affairs

Next.js 15
React 19
TypeScript
PostgreSQL / Prisma
Approval workflows
RBAC
Excel import/export
Reporting
The faculty-wide course pool with per-department roll-ups and bulk approve/return.
The faculty-wide course pool with per-department roll-ups and bulk approve/return.

A role-based course management platform that moves every course from a department head's draft through dean and rector approval to Student Affairs, with authorization enforced per role, per scope, and per form field.

Client context

A private university in Istanbul with a multi-faculty structure, where each department chair builds that department's course catalogue every semester.

Turkish universities run this cycle under a strict hierarchy. A course is not simply "created" — it is proposed by a department, reviewed at faculty level by the dean, approved at university level by the rector, and only then handed to Student Affairs for entry into the OBS student information system. Each step carries different authority over different parts of the same record.

The operational challenge

Semester planning of this shape breaks down in spreadsheets and email for reasons that have little to do with data volume:

Product strategy and approach

The guiding decision was to treat the approval hierarchy as the product's core domain model rather than a permissions afterthought. Two consequences followed.

First, approval state is a first-class lifecycle, not a status label — seven distinct states including separate dean-return and rector-return states, so a returned course holds a real position in the workflow with its own permitted transitions.

Second, each role gets its own operating surface rather than one screen with buttons hidden. Signing in routes each role to the workspace matching its job: department head to their catalogue, dean to the faculty-wide pool, rector to the university-wide pool, Student Affairs to the OBS panel. Navigation is filtered by role — Student Affairs sees a two-item menu where an administrator sees the full management tree.

The core solution

Course authoring with structural depth. A course record carries roughly forty planning attributes — credits, ECTS, theoretical and practical hours, language, delivery mode, classroom type, in- and out-of-department quotas, and shared-department configuration.

Multi-branch sections with instructor-per-branch. Each course splits into 1–10 branches, each with its own instructor and weekly hours, enforced by a uniqueness constraint on (course, branch number). Assignment happens through a dialog showing each candidate's confirmed hours, pending hours, minimum load, and expertise areas — so load balancing is decided with the data in view.

Shared courses as structured data. A shared course stores explicit department-plus-class-level combinations, validated and de-duplicated on save, re-validated before approval, and editable only at dean and rector level.

Approval with authority checked at the moment of writing. Approving or returning runs inside a database transaction that re-reads both actor and course, confirms the actor is still active and the course is still in the state the request assumed, re-checks authority, then writes the new state, the approval record, and the notifications together. A course whose state moved under a reviewer's feet fails with "the course status has changed, the operation was cancelled" rather than silently overwriting someone else's decision.

Governed hand-off to Student Affairs. Fully approved courses appear in a dedicated OBS panel with completion metrics, per-course and bulk "processed" marking that records who processed it and when, and an Excel export shaped for OBS entry.

Operational reporting and bulk onboarding. Faculty, university, department, and activity reports run off the same records — approval rate, average approval duration, per-department comparison — plus a rector-only report on instructor workload. Academic staff import from Excel through a four-step wizard against a documented ten-column contract, with institutional emails generated automatically and records committed in batches of 25 so a large import cannot exceed request limits.

Primary workflows

  1. Plan → submit: department head drafts courses, sets branch count, assigns an instructor per branch against live load, submits for dean approval.
  2. Review → approve or return: dean works the faculty pool, approving or returning with a reason, individually or in bulk; returns route back to the department with the reason attached.
  3. Final approval → hand-off: rector approves across the university-wide pool; Student Affairs then works the approved-only queue, marks courses OBS-processed, and exports the workbook.
  4. Throughout: in-app and email notifications reach the next actor at each transition, and every field edit and state change is written to an audit log.

My role

Sole developer. Repository history records 92 commits by a single author over roughly six weeks, covering the data model, approval engine, authorization layer, all four role workspaces, the reporting suite, the notification and email subsystem, and the Excel tooling.

Technical approach

Next.js 15, React 19, TypeScript, PostgreSQL via Prisma, NextAuth, Tailwind, Nodemailer, SheetJS. Decisions a buyer should care about:

Outcomes and evidence

Verified by exercising the running application across all four roles against a seeded database, plus source review:

No usage, adoption, time-saved, or cost figures are claimed: this analysis had no access to production data. No AI capability is claimed either — the forecasting in the performance report is simple arithmetic extrapolation, and is described as such.

Confidentiality

The institution is not named, and all screenshots come from a local development instance running synthetic seed data. No real staff, student, or course records were accessed.


Need a similar product or workflow? If your approvals run on spreadsheets and email — authority differing by role and by field, work returned as often as approved, a downstream team needing a clean hand-off — this is the shape of system that fixes it.

Screens

Instructor assignment per branch, decided against that instructor's confirmed hours, pending hours, minimum load and expertise areas.
Instructor assignment per branch, decided against that instructor's confirmed hours, pending hours, minimum load and expertise areas.
Student Affairs sees fully approved courses only, marks them OBS-processed and exports an OBS-ready workbook.
Student Affairs sees fully approved courses only, marks them OBS-processed and exports an OBS-ready workbook.
A shared course with its explicit department-plus-class-level combinations and the full approval history attached.
A shared course with its explicit department-plus-class-level combinations and the full approval history attached.
The dean's approval queue — approve or return with a reason, individually or in bulk.
The dean's approval queue — approve or return with a reason, individually or in bulk.
The rector's university-wide pool, the last gate before hand-off.
The rector's university-wide pool, the last gate before hand-off.
Faculty report — approval rate, average approval duration and per-department comparison, computed from live records.
Faculty report — approval rate, average approval duration and per-department comparison, computed from live records.
A department's catalogue; each course carries roughly forty planning attributes.
A department's catalogue; each course carries roughly forty planning attributes.
The department head's dashboard — approval-state distribution for their own catalogue.
The department head's dashboard — approval-state distribution for their own catalogue.
The dean's dashboard across the faculty pipeline.
The dean's dashboard across the faculty pipeline.
System administration — roles, scopes and the shared authorization layer's configuration.
System administration — roles, scopes and the shared authorization layer's configuration.
Academic-staff import through a four-step wizard against a documented ten-column contract, committed in batches.
Academic-staff import through a four-step wizard against a documented ten-column contract, committed in batches.

Captured from a local development instance running synthetic seed data — no real staff, student or course records appear. The institution's mark is pixelated in every frame.

Architecture

System contextscroll to explore
Course lifecycle, draft to OBSscroll to explore
← Back to all work