6.
1 Technology Stack
Backend Architecture
TypeScript Implementation
Language Selection Rationale: TypeScript was strategically chosen over JavaScript to enhance
code quality, maintainability, and developer productivity throughout the application lifecycle.
Type Safety Benefits: Implementation of strong static typing enables early error detection during
development rather than runtime, significantly reducing potential production bugs.
Interface-Driven Development: Extensive use of TypeScript interfaces to define clear contracts
between different system components, ensuring consistent data flow.
Advanced TypeScript Features Utilized:
Generic types for creating reusable, type-safe components
Union and intersection types for complex data modeling
Type guards for runtime type checking when interfacing with external APIs
Utility types (Pick, Omit, Partial) for type transformation and composition
TypeScript Error Handling: Implementation of custom type definitions and error handling
for database operations:
typescript
// Example of TypeScript error handling with Prisma
try {
const user = await prisma.user.findUnique({
where: { email: userEmail }
});
if (!user) {
throw new Error('User not found');
}
return user;
} catch (error) {
// Typed error handling
if (error instanceof PrismaClientKnownRequestError) {
// Handle Prisma-specific errors
} else {
// Handle general errors
}
}
Database Architecture
PostgreSQL Implementation
Version and Configuration: PostgreSQL 15.x with custom configuration optimized for application
workload patterns
Database Selection Rationale: PostgreSQL was chosen for its robust support for complex data
relationships, transactional integrity, and advanced querying capabilities critical for healthcare
data management.
Schema Design Philosophy: Normalized schema design with strategic denormalization for
performance-critical queries
Healthcare-Specific Optimizations: Schema optimized for medical data with specialized field
types and constraints
Prisma ORM Integration
Schema Definition: Comprehensive Prisma schema file defines the complete data model for the
healthcare application:
prisma
// Core schema excerpt showing user and role definitions
enum Role {
PATIENT
DOCTOR
ADMIN
}
enum BloodType {
A_POS
A_NEG
B_POS
B_NEG
AB_POS
AB_NEG
O_POS
O_NEG
}
model User {
id String @id @default(uuid())
email String @unique
password String
role Role @default(PATIENT)
Blood String
Height String
Weight String
Heart String
Oxygen String
Temperature String
name String
medicalHistory MedicalHistory[]
bedBookings BedBooking[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Relationship Management: Sophisticated relationship mapping between healthcare entities
:
prisma
// Example of relationship definitions in Prisma schema
model Hospital {
id String @id @default(uuid())
name String
address String
bed_availability Int
rating Float?
image_url String?
location_distance Float?
price_general Int?
price_icu Int?
price_emergency Int?
price_pediatric Int?
doctors Doctor[] // One-to-Many Relationship with Doctors
bedBookings BedBooking[] // New relation
}
model Doctor {
id String @id @default(uuid())
name String
specialty String
email String @unique
phone String
hospitalId String
hospital Hospital @relation(fields: [hospitalId], references: [id])
appointments Appointment[]
availableSlots AppointmentAvailability[]
}
Database Connection: PostgreSQL database connection configured via environment variables for
security and flexibility:
prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Prisma Client Generation: Automated TypeScript client generation ensuring type safety in database
operations:
prisma
generator client {
provider = "prisma-client-js"
}
Data Seeding Implementation
Seed Architecture: Modular seed.ts file organizes data seeding by entity type with
comprehensive error handling:
typescript
// Example of the main seeding function structure
async function main() {
console.log("Cleaning up existing data..."
);
// Clear tables in order to respect foreign key constraints
await prisma.appointment.deleteMany({});
await prisma.medicalHistory.deleteMany({});
await prisma.bedBooking.deleteMany({});
await prisma.patient.deleteMany({});
await prisma.appointmentAvailability.deleteMany({});
await prisma.doctor.deleteMany({});
await prisma.hospital.deleteMany({});
await prisma.user.deleteMany({});
console.log("Cleanup completed.");
// Seeding continues...
}
Data Generation Strategy: Realistic test data generation for healthcare-specific entities
:
typescript
// Example of user data seeding with healthcare parameters
const users = [
{
email: "
[email protected]",
password: hashedPassword,
role: "PATIENT",
Blood: "O_POS",
Height: "175cm",
Weight: "70kg",
Heart: "72 bpm",
Oxygen: "98%",
Temperature: "98.6F",
name: "John Doe",
},
{
email: "
[email protected]"
,
password: hashedPassword,
role: "DOCTOR",
Blood: "B_POS",
Height: "165cm",
Weight: "58kg",
Heart: "70 bpm",
Oxygen: "99%",
Temperature: "98.5F",
name: "Dr. Emily Chen",
},
// Additional users...
];
// Bulk create users
await prisma.user.createMany({ data: users });
Relationship Preservation: Complex relationship seeding with proper referential integrity
:
typescript
// Example of seeding related entities with proper references
const doctors = [
{
name: "Dr. Emily Chen",
specialty: "Pediatrics",
email: "
[email protected]"
,
phone: "555-111-2222",
hospitalId: (await prisma.hospital.findFirst({ where: { name: "City General Hospital" }
},
// Additional doctors...
];
await prisma.doctor.createMany({ data: doctors });
Security Integration: Password hashing incorporated directly in the seeding process
:
typescript
// Password security implementation in seeding
const hashedPassword = await bcrypt.hash("password123", 10);
Healthcare Domain Model
Patient Management
Patient Data Structure: Comprehensive patient data model with vital signs, medical history, and
appointment tracking:
prisma
model Patient {
id String @id @default(uuid())
name String
email String @unique
phone String
appointments Appointment[] // One-to-Many Relationship with Appointments
}
model MedicalHistory {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
pastDiagnoses String? // Past illnesses or diagnoses
medications String? // List of medications the patient is taking
allergies String? // Known allergies
surgeries String? // Previous surgeries
chronicDiseases String? // Chronic conditions like diabetes, hypertension
createdAt DateTime @default(now())
}
Hospital and Resource Management
Hospital Information Model: Detailed hospital data structure with bed availability and
pricing:
prisma
model Hospital {
id String @id @default(uuid())
name String
address String
bed_availability Int
rating Float?
image_url String?
location_distance Float?
price_general Int?
price_icu Int?
price_emergency Int?
price_pediatric Int?
doctors Doctor[]
bedBookings BedBooking[]
}
Bed Management System: Specialized model for tracking hospital bed bookings and availability
:
prisma
model BedBooking {
id String @id @default(uuid())
userId String
hospitalId String
bedType String // general, icu, emergency, pediatric
admissionDate DateTime
reason String
notes String?
status String @default("PENDING") // PENDING, CONFIRMED, CANCELED
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
hospital Hospital @relation(fields: [hospitalId], references: [id])
}
Appointment Scheduling System
Appointment Structure: Comprehensive appointment system with status tracking and
doctorpatient relationships:
prisma
model Appointment {
id String @id @default(uuid())
date DateTime @default(now())
patientId String
doctorId String
status String @default("Pending")
patient Patient @relation(fields: [patientId], references: [id])
doctor Doctor @relation(fields: [doctorId], references: [id])
}
enum AppointmentStatus {
PENDING
CONFIRMED
CANCELED
COMPLETED
}
Availability Management: Sophisticated time slot management for doctor availability
:
prisma
model AppointmentAvailability {
id String @id @default(uuid())
doctorId String
doctor Doctor @relation(fields: [doctorId], references: [id], onDelete: Cascade)
date DateTime
startTime DateTime
endTime DateTime
isBooked Boolean @default(false)
}
Security Implementation
Authentication System
Password Security: Bcrypt implementation for secure password hashing as demonstrated in the
seed file:
typescript
// Password hashing implementation
import bcrypt from "bcrypt";
// Securely hash passwords before storing
const hashedPassword = await bcrypt.hash("password123", 10);
Role-Based Access Control
User Role System: Comprehensive role-based security model:
prisma
enum Role {
PATIENT
DOCTOR
ADMIN
}
model User {
// Other fields...
role Role @default(PATIENT)
// Other fields...
}
Database Performance Optimization
Query Optimization Techniques
Bulk Operations: Implementation of efficient bulk database operations as shown in the seed
file:
typescript
// Example of bulk insert operations
await prisma.user.createMany({ data: users });
await prisma.hospital.createMany({ data: hospitals });
await prisma.patient.createMany({ data: patients });
Transactional Data Management
Data Integrity: Proper order of operations to maintain referential integrity:
typescript
// Example of proper cleanup sequence respecting foreign key constraints
await prisma.appointment.deleteMany({});
await prisma.medicalHistory.deleteMany({});
await prisma.bedBooking.deleteMany({});
await prisma.patient.deleteMany({});
await prisma.appointmentAvailability.deleteMany({});
await prisma.doctor.deleteMany({});
await prisma.hospital.deleteMany({});
await prisma.user.deleteMany({});
Connection Management
Resource Cleanup: Proper connection handling and resource release:
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
Backend Implementation & Code Overview
Backend API Development & Integration
Your backend is built using TypeScript with Prisma as your ORM (Object-Relational Mapping) tool to
interact with PostgreSQL. The API integration layer is particularly well-structured:
Centralized API Service
Type-Safe API
Methods
},
delete: <T = any>(
url: string,
config?: AxiosRequestConfig
): Promise<AxiosResponse<T>> => {
return apiClient.delete(url, config);
},
};
Database Design & Query Optimization
Your Prisma schema creates a well-structured healthcare management system with several
interconnected models:
Schema Design
typescript
// Core user model with role-based access
model User {
id String @id @default(uuid())
email String @unique
password String
role Role @default(PATIENT)
Blood String
Height String
Weight String
Heart String
Oxygen String
Temperature String
name String
medicalHistory MedicalHistory[]
bedBookings BedBooking[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Hospital model with bed capacity and pricing
model Hospital {
id String @id @default(uuid())
name String
address String
bed_availability Int
rating Float?
image_url String?
location_distance Float?
price_general Int?
price_icu Int?
price_emergency Int?
price_pediatric Int?
doctors Doctor[]
bedBookings BedBooking[]
}
Query Optimization Techniques
// Example of optimized queries for appointment lookup
async function getUpcomingAppointments(userId: string) {
return prisma.appointment.findMany({
where: {
patientId: userId,
date: {
gte: new Date() // Only future appointments
},
status: {
not: "CANCELED" // Exclude canceled appointments
}
},
include: {
doctor: {
select: {
name: true,
specialty: true,
hospital: {
select: {
name: true,
address: true
}
}
}
}
},
orderBy: {
date: 'asc' // Sort by nearest appointment first
}
});
}
// Optimized query for hospital bed availability
async function getAvailableHospitals(bedType: string) {
return prisma.hospital.findMany({
where: {
bed_availability: {
gt: 0 // Only hospitals with available beds
}
},
select: {
id: true,
name: true,
bed_availability: true,
[`price_${bedType.toLowerCase()}`]: true, // Dynamic price selection
location_distance: true
},
orderBy: {
location_distance: 'asc' // Sort by proximity
},
take: 10 // Limit results for performance
});
}
Database Indexing
typescript
// Efficient indexing on commonly queried fields
model Doctor {
id String @id @default(uuid())
name String
specialty String // Indexed field for frequent specialty searches
email String @unique
phone String
hospitalId String
hospital Hospital @relation(fields: [hospitalId], references: [id])
appointments Appointment[]
availableSlots AppointmentAvailability[]
@@index([specialty]) // Custom index for performance
}
model AppointmentAvailability {
id String @id @default(uuid())
doctorId String
doctor Doctor @relation(fields: [doctorId], references: [id], onDelete: Cascade)
date DateTime
startTime DateTime
endTime DateTime
isBooked Boolean @default(false)
@@index([doctorId, date]) // Compound index for availability lookups
}
Data Seeding Strategy
Your seed script demonstrates best practices for initializing a database:
typescript
async function main() {
console.log("Cleaning up existing data...");
// Clear tables in order to respect foreign key constraints
await prisma.appointment.deleteMany({});
await prisma.medicalHistory.deleteMany({});
await prisma.bedBooking.deleteMany({});
await prisma.patient.deleteMany({});
await prisma.appointmentAvailability.deleteMany({});
await prisma.doctor.deleteMany({});
await prisma.hospital.deleteMany({});
await prisma.user.deleteMany({});
// Hash passwords for security
const hashedPassword = await bcrypt.hash("password123", 10);
// Seed Users in bulk for performance
const users = [
{
email: "
[email protected]",
password: hashedPassword,
role: "PATIENT",
// Additional user data
},
// More users...
];
// Using createMany for bulk insertion (more efficient)
await prisma.user.createMany({ data: users });
// Additional seeding...
}
Key Implementation Features
Authentication Flow
JWT token storage in localStorage
Automatic token inclusion in request headers
Automatic logout and redirection on token expiration
Type-safe auth endpoints
API Error Handling
Centralized error interceptor for authentication issues
Consistent error rejection pattern
Data Access Layer
Strongly-typed Prisma client for database operations
Secure password hashing with bcrypt
Systematic data seeding for development
Summary
Your implementation demonstrates solid backend engineering principles:
1. Type Safety: Using TypeScript throughout the codebase provides compile-time checks and better
developer experience.
2. Data Modeling: Your Prisma schema effectively models the healthcare domain with proper
relationships and constraints.
3. API Structure: A clean service layer with proper error handling and authentication flow.
4. Testability: The seed script enables repeatable testing scenarios with consistent data.
5. Performance Optimization: Appropriate indexing, selective field queries, and bulk operations for
improved database performance.
The codebase shows a well-structured healthcare management system with proper separation of
concerns between data access, authentication, and API communication. The Prisma ORM provides a
typesafe interface to your PostgreSQL database, while the Axios-based API service ensures consistent
handling of network requests.
Security & Privacy Review for Healthcare Application with
Prisma
Executive Summary
This document provides a comprehensive security assessment of the healthcare application built with
Prisma ORM and Express.js. The application handles sensitive patient data and medical records,
making security and privacy critical concerns.
Overall, the application implements many security best practices but has several areas for
improvement to meet healthcare industry standards like HIPAA compliance.
Strengths
1. Authentication System
JWT-based authentication with proper token expiration
Password hashing using bcrypt with salt
Role-based access control (RBAC)
2. Data Protection
Field-level encryption for sensitive medical data (bloodType, diagnosis, treatment, notes)
Proper storage of initialization vectors alongside encrypted data
UUID usage instead of sequential IDs for database records
3. API Security
CSRF protection for state-changing requests
Rate limiting to prevent brute force and DoS attacks
Helmet.js integration for HTTP security headers
4. Application Security
Secure environment variable management
Content Security Policy implementation
Proper CORS configuration limiting origins
Vulnerabilities & Recommendations
1. Authentication & Authorization
Issues:
No refresh token implementation (only access tokens)
No multi-factor authentication option
No session revocation capability
Recommendations:
Implement refresh token rotation for improved security
Add MFA support for sensitive operations
Create an active session management system with revocation capability
Consider implementing IP-based restrictions for administrative access
typescript
// Add refresh token to the schema
model RefreshToken {
id String @id @default(uuid())
token String @unique
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
expiresAt DateTime
createdAt DateTime @default(now())
@@index([userId])
}
// User model update
model User {
// existing fields...
refreshTokens RefreshToken[]
}
2. Data Protection
Issues:
Encryption key stored in .env file without rotation capability
No data anonymization for reporting/analytics
Lack of audit logging for sensitive data access
Recommendations:
Implement key management service (AWS KMS, HashiCorp Vault)
Add data anonymization pipeline for analytics
Create comprehensive audit logging system:
typescript
// Add to schema.prisma
model AuditLog {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
action String // e.g., "READ", "CREATE", "UPDATE", "DELETE"
resourceType String // e.g., "MedicalRecord", "Patient"
resourceId String
description String
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
@@index([userId])
@@index([resourceType, resourceId])
@@index([createdAt])
}
3. API Security
Issues:
Lack of request validation middleware
No API versioning strategy
Missing JSON payload size limits
Recommendations:
Implement request validation with Zod or Joi
Add API versioning (e.g., /api/v1/...)
Configure Express body-parser limits:
typescript
// In app.ts
app.use(express.json({ limit: '100kb' }));
app.use(express.urlencoded({ extended: false, limit: '100kb' }));
4. Database Security
Issues:
No database connection pooling configuration
Missing automated database backup strategy
No data retention policy implementation
Recommendations:
Configure Prisma connection pooling:
// prisma/index.ts
const prisma = new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL,
},
},
// Connection pooling configuration
connectionPool: {
min: 2,
max: 10,
idleTimeoutMs: 30000,
},
});
Implement automated database backups with encryption
Create data retention policies with automated cleanup processes
5. Compliance Specific Requirements
Issues:
Missing privacy policy notifications
No consent management system
Incomplete breach notification procedures
No documented data export/portability functionality
Recommendations:
Add HIPAA-specific privacy notifications
Implement consent management system:
typescript
// Add to schema.prisma
model Consent {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
consentType String // e.g., "DataSharing", "Marketing", "Research"
granted Boolean
consentVersion String // To track policy versions
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([userId, consentType])
}
Testing Recommendations
1. Penetration Testing
Conduct regular penetration testing focusing on authentication and authorization
Test API endpoints for access control vulnerabilities
Verify encrypted data cannot be accessed without proper authorization
2. Security Scanning
Implement dependency scanning in CI/CD pipeline
Regular static code analysis with security focus
Dynamic application security testing (DAST)
3. Compliance Auditing
Perform regular HIPAA compliance audits
Document all security measures for regulatory requirements
Create incident response plans for security breaches