Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

104 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Referral Management & Specialist Coordination Hub

A full-stack healthcare application for managing the lifecycle of patient referrals — from the moment a specialist raises a referral request, through coordinator routing to an in-network facility, to appointment scheduling and completion.

The core problem it addresses is referral leakage: patients who get referred out of a hospital network never complete their appointment, or end up seen at an out-of-network facility. Leakage means lost continuity of care for the patient and lost revenue for the network. This system keeps the referral inside a tracked, auditable workflow and gives administrators the analytics to see where patients are dropping off.

Built as a capstone project during an internship training program.


Table of Contents


The Problem It Solves

In a hospital network, a specialist often needs to send a patient to another specialty (e.g. a cardiologist refers a patient to endocrinology). In many systems this handoff happens over phone, fax, or a loose EMR note, and nobody owns the follow-through. The referral "leaks":

  • The patient is never scheduled.
  • The patient is scheduled at an out-of-network facility, so revenue leaves the system.
  • The referral sits in an ambiguous state with no aging or accountability.

This platform makes the handoff a first-class, tracked entity:

  • Every referral has an explicit status and an owning coordinator.
  • Coordinators route referrals to the nearest in-network facility that actually staffs the requested specialty.
  • Specialist matching is specialty-aware, so a referral only goes to a provider who can treat it.
  • Every state transition is written to an audit log.
  • An admin analytics layer surfaces leakage rate, referral aging, specialty load, and appointment throughput so the network can act on the drop-off points.

Roles & Workflow

The system is built around four roles, each with its own dashboard and a strictly scoped set of permissions:

Role What they do
Specialist Looks up patients by MRN, raises referral requests to another specialty, manages their assigned referrals, and runs their daily appointment schedule (viewing slots, completing appointments).
Referral Coordinator The routing engine of the system. Reviews incoming referral requests, picks a destination facility from a distance-ranked, specialty-filtered list, assigns a matching specialist, rejects invalid requests, and can fan a single request out to multiple facilities at once.
Patient Tracks their own referrals and appointments, sees referral status history, and maintains their profile.
Admin Manages users and consumes the analytics layer — leakage, aging, specialty load, appointment analytics, top specialists, daily/monthly referral trends.

Referral Lifecycle

A referral moves through an explicit state machine (backed by the ReferralStatus table):

Requested → Submitted → Accepted → Scheduled → Completed → Closed
                     └→ Rejected
  • Requested — a specialist raises the referral (patient + target specialty + urgency + reason).
  • Submitted — the coordinator has routed it to a destination facility.
  • Accepted / Rejected — the destination side takes ownership, or the coordinator rejects it.
  • Scheduled — an appointment is booked into a specialist's shift block.
  • Completed / Closed — the visit happened and the referral is closed out.

Urgency is a first-class dimension (Routine, Urgent, Emergency) and drives prioritisation and aging analytics.

A subtle but important business rule lives in the referral detail logic: which facility is shown as the "primary" facility depends on status. Before a referral is Accepted it reflects the origin facility; once accepted it flips to the destination facility — so the UI always shows the party currently responsible for the patient.

Multi-facility routing

When a coordinator isn't sure which facility will accept, they can route one referral request to several facilities in a single action. The backend stamps all the resulting referrals with a shared ReferralGroupId (a Guid), so the sibling referrals can be tracked and reconciled as one logical request.

Architecture

┌────────────────────────┐        HTTPS / JWT         ┌────────────────────────────┐
│  Vue 3 SPA (Vite)      │  ───────────────────────►  │  ASP.NET Core Web API      │
│                        │                            │                            │
│  • Role-based router   │                            │  Controllers               │
│  • Axios API layer     │  ◄───────────────────────  │    → Services (business)   │
│  • Tailwind UI         │        JSON DTOs           │      → EF Core → SQL Server │
└────────────────────────┘                            └────────────────────────────┘

The backend follows a conventional layered design:

  • Controllers are thin — they authorize, bind DTOs, and delegate.
  • Services hold all business logic (routing, specialist matching, referral state transitions, analytics aggregation) and are wired through constructor DI, registered centrally in Extensions/ServiceRegistration.cs.
  • EF Core (AppDbContext) handles persistence against SQL Server, with a set of database views (vw_Coordinator_RequestedReferrals, vw_Specialist_AssignedPatients, vw_AppointmentDetails) mapped as keyless entities to push heavy read-side joins into the database.
  • A global exception middleware translates typed exceptions (NotFoundException, BadRequestException, ForbiddenException, UnauthorizedException) into consistent HTTP error responses, so services can throw domain errors instead of hand-rolling status codes.
  • Serilog writes rolling daily log files (7-day retention).

The frontend mirrors the backend's role split: pages under pages/{admin,specialist,referral-coordinator,patient}, a typed API client per domain under src/api, and a route guard that enforces role access before a page ever loads.

Tech Stack

Backend

  • ASP.NET Core 8 Web API (C#, nullable + implicit usings enabled)
  • Entity Framework Core 8 (SQL Server provider)
  • JWT bearer authentication (Microsoft.AspNetCore.Authentication.JwtBearer)
  • BCrypt.Net for password hashing
  • Serilog (file sink) for structured logging
  • Swashbuckle / Swagger for API documentation

Frontend

  • Vue 3 (Composition API, <script setup>) + TypeScript
  • Vite build tooling
  • Vue Router 5 with role-based navigation guards
  • Tailwind CSS 4
  • Axios with a shared interceptor layer; jwt-decode for client-side claims

Database

  • SQL Server — schema, seed data, views, and indexes managed as raw SQL scripts under Database/Scripts

Data Model

Core tables (see Database/Scripts/CreateTable.sql):

  • Identity & rolesUser, Role, and role-specific profile tables (Admin, Specialist, ReferralCoordinator, Patient).
  • Network topologyGlobalNetworkHospitalFacility, with Latitude/Longitude on facilities to power distance-based routing.
  • Clinical taxonomySpecialty (Cardiology, Dermatology, Oncology, …) and the SpecialistSpecialities link table so one specialist can hold multiple specialties.
  • Referral flowReferral, ReferralAssignment, ReferralStatus, UrgencyLevel.
  • SchedulingAppointment, AppointmentStatus, and ShiftBlock (three 8-hour blocks covering a 24-hour day).
  • ComplianceAuditLog for a trail of referral state changes.

Read-heavy screens are served through SQL views and supported by 15 indexes (indexes.sql) on the hot query paths (referral lookups, coordinator queues, appointment detail joins).

API Surface

All endpoints are under /api and are role-gated with [Authorize(Roles = ...)]. Highlights:

Area Endpoints (examples)
Auth POST /api/auth/register, POST /api/auth/login, GET /api/auth/me
Specialist GET /api/patient/lookup/{mrn}, POST /api/specialist/referral-intake, GET /api/specialist/specialities, GET /api/referral/my-referrals
Coordinator GET /api/referral/requested, GET /api/referral/specialists/{referralId}, GET /api/referral/{referralId}/facilities-dropdown, POST /api/referral/route, POST /api/referral/{referralId}/reject
Appointments GET /api/appointments/available-slots/{specialistId}/{date}, POST /api/appointments, GET /api/appointments/schedule/{date}, PUT /api/appointments/{id}/complete
Patient GET /api/patient/dashboard, GET /api/patient/referrals, GET /api/patient/appointments/upcoming
Admin analytics GET /api/admin/dashboard, GET /api/admin/analytics/referral-leakage, /facility-leakage, /specialty-load, /referral-aging, /scheduled-delays, /top-specialists, /daily-referrals

Interactive docs (with a Bearer auth flow) are available at /swagger when running in Development.

Security

  • Authentication — stateless JWT bearer tokens. On login the API issues a signed token carrying the user's id and role claims; tokens expire after the configured Jwt:ExpiryMinutes.
  • Authorization — every controller action is decorated with role requirements, so the API is the source of truth for access control; the Vue router guard is a UX convenience layered on top, not the security boundary.
  • Password storage — passwords are hashed with BCrypt; plaintext is never persisted.
  • Registration integrity — user + role-profile creation runs inside a database transaction, so a half-created account can never leak through.
  • CORS — locked to the Vite dev origin via the named VuePolicy.
  • Transport — HTTPS redirection is enforced in the pipeline.
  • Auditability — referral state changes are recorded in AuditLog, which matters in a healthcare context where who-changed-what-and-when is a compliance concern.

Project Structure

Referral-Management/
├── Backend/
│   └── Referral-Management.Api/
│       └── Referral-Management.Api/
│           ├── Controllers/      # thin HTTP endpoints, role-gated
│           ├── Services/         # business logic (routing, matching, analytics)
│           ├── Models/           # EF Core entities + AppDbContext + views
│           ├── DTOs/             # request/response contracts
│           ├── Migrations/       # EF Core migrations
│           ├── Middleware/       # global exception handling
│           ├── Exceptions/       # typed domain exceptions
│           ├── Extensions/       # DI / service registration
│           └── Program.cs
├── Frontend/
│   ├── src/
│   │   ├── pages/                # per-role screens
│   │   ├── components/           # per-role UI components
│   │   ├── api/                  # typed Axios clients
│   │   ├── router/               # role-based route guards
│   │   ├── types/                # shared TypeScript contracts
│   │   └── utils/                # auth, dates, error handling
│   └── package.json
└── Database/
    └── Scripts/
        ├── CreateTable.sql       # schema
        ├── SeedData.sql          # reference + demo data
        ├── Views.sql             # read-side views
        └── indexes.sql           # performance indexes

Getting Started

Prerequisites

  • .NET 8 SDK
  • Node.js 18+ (for Vite / Vue 3)
  • SQL Server (local instance or container)

1. Database

Run the scripts in Database/Scripts against your SQL Server instance, in order:

CreateTable.sql  →  Views.sql  →  indexes.sql  →  SeedData.sql

This creates the schema, read-side views, indexes, and seeds reference data (roles, specialties, statuses, urgency levels, shift blocks) plus demo records.

2. Backend

cd Backend/Referral-Management.Api/Referral-Management.Api
dotnet restore
dotnet run

The API starts with Swagger UI at /swagger. If you prefer EF migrations over the raw scripts, dotnet ef database update applies the baseline migration instead.

3. Frontend

cd Frontend
npm install
npm run dev

The SPA runs on http://localhost:5173 (the origin whitelisted in the backend CORS policy).

Configuration

Backend settings live in appsettings.json. Secrets should be kept out of source control — set them via .NET user-secrets or environment variables for anything beyond local development:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=Referral-Management;Trusted_Connection=True;TrustServerCertificate=True;"
  },
  "Jwt": {
    "Issuer": "ReferralManagementAPI",
    "Audience": "ReferralManagementClient",
    "ExpiryMinutes": 360
    // "Key": "<signing key — supply via secrets/env, not committed>"
  }
}

The frontend reads the API base URL from its Axios configuration in src/api/axios.ts.

About

Full-stack healthcare app for tracking patient referrals end-to-end — specialist intake, coordinator routing to in-network facilities, appointment scheduling, and admin leakage analytics. ASP.NET Core 8 · Vue 3 · SQL Server.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages