← All work
Personal project Full-Stack Development 2025

AxisPT

A full-stack practice-management system for a physical therapy program: separate student and admin portals for scheduling, session logging, and progress tracking, built end to end with React, Express, and PostgreSQL.

Role
Full-Stack Development, Database Design, Authentication, UI Design
Discipline
Full-Stack Development
Year
2025
Headline
2 Role-based portals on one shared schema

Context

AxisPT started as a way to give physical therapy students and the staff supervising them a shared system instead of paper logs and spreadsheets. Students need to record sessions, treatment plans, and patient progress as they happen; supervisors need to see all of that across every student at once, approve it, and report on it. I built the whole thing solo: schema, API, auth, and both front ends, as a way to learn what a real stack actually demands once authentication, roles, and data relationships are all live at the same time.

The problem

The two portals needed to feel like different products while sharing one database and one API. A student should only ever see their own patients and sessions; an admin needs to see everyone's, filter by date or therapist, and export summaries for review. That meant the access-control logic had to live in the API itself, not just be hidden in the UI, and the data model had to support both a narrow per-student view and a wide cross-student report from the same tables. On top of that, progress data (visit counts, pain scores, range of motion over time) only means anything as a trend, so it had to be queried and charted, not just listed.

Process

  1. 01

    Modeled the schema around roles first

    Before writing any UI I mapped out the PostgreSQL schema: users with a role column, patients, sessions, and treatment plans, with foreign keys tying sessions back to both a student and a patient. Getting the relationships right up front meant the same tables could answer "show me my patients" and "show me every student's patients this week" without duplicating data.

  2. 02

    Built the API and locked it down with JWT

    The Express API issues a JWT on login and checks it on every protected route, with middleware that reads the user's role and scopes queries accordingly: a student's token can only pull their own records, an admin's can pull anyone's. Centralizing that in middleware meant the access rule was enforced once, at the API, rather than re-checked (and possibly forgotten) in every screen.

  3. 03

    Built the student portal around the session log

    The student-facing React app centers on a session log: pick a patient, record what was done, note pain scores and range of motion, and see that patient's history at a glance. Forms validate before they hit the API, and the recent-sessions view doubles as a quick way to pick up where the last visit left off.

  4. 04

    Built the admin portal around oversight and reporting

    The admin portal reuses the same component library but is built for breadth: a calendar of every scheduled session, a searchable table of every student's patients, and progress charts built with Chart.js that plot a patient's metrics over time. A print view, built with react-to-print, formats a patient's history into a clean page an admin can hand off or file.

Outcome

AxisPT ended up as a complete, working slice of a real practice-management product: two portals, one schema, role-based access enforced at the API, and reporting that turns raw session data into something a supervisor can actually read. It is the project I point to when someone asks what I can build end to end, from the database up through a deployed UI.

  • 2 Portals (student, admin) on one schema
  • JWT Role-based auth, enforced at the API
  • Chart.js Progress visualized over time, not just listed
  • React + Express + PostgreSQL Full stack, deployed end to end

A live demo is up at axis-pt.vercel.app (the backend may take a moment to wake up on first load).