Index: ckend/src/main/java/medora/Medora5Application.java
===================================================================
--- backend/src/main/java/medora/Medora5Application.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,13 +1,0 @@
-package medora;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class Medora5Application {
-
-    public static void main(String[] args) {
-        SpringApplication.run(Medora5Application.class, args);
-    }
-
-}
Index: backend/src/main/java/medora/MedoraApplication.java
===================================================================
--- backend/src/main/java/medora/MedoraApplication.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/java/medora/MedoraApplication.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,16 @@
+package medora;
+
+import medora.service.AuthService;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class MedoraApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(MedoraApplication.class, args);
+    }
+
+}
Index: backend/src/main/java/medora/config/AuthorizationInterceptor.java
===================================================================
--- backend/src/main/java/medora/config/AuthorizationInterceptor.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/config/AuthorizationInterceptor.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,9 +1,10 @@
 package medora.config;
+
+import medora.util.SecurityUtil;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
 
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
-import medora.util.SecurityUtil;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.HandlerInterceptor;
 
 /**
@@ -18,8 +19,4 @@
  */
 @Component
-
-
-
-
 public class AuthorizationInterceptor implements HandlerInterceptor {
 
Index: backend/src/main/java/medora/config/SecurityConfig.java
===================================================================
--- backend/src/main/java/medora/config/SecurityConfig.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/config/SecurityConfig.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -14,8 +14,8 @@
     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
         http
-                .csrf(csrf -> csrf.disable())
-                .authorizeHttpRequests(auth -> auth
-                        .anyRequest().permitAll()
-                );
+            .csrf(csrf -> csrf.disable())
+            .authorizeHttpRequests(auth -> auth
+                .anyRequest().permitAll()
+            );
 
         return http.build();
Index: backend/src/main/java/medora/config/WebConfig.java
===================================================================
--- backend/src/main/java/medora/config/WebConfig.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/config/WebConfig.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -32,6 +32,6 @@
         Path uploadPath = Path.of("uploads").toAbsolutePath().normalize();
         registry
-                .addResourceHandler("/uploads/**")
-                .addResourceLocations(uploadPath.toUri().toString() + "/");
+            .addResourceHandler("/uploads/**")
+            .addResourceLocations(uploadPath.toUri().toString() + "/");
     }
 
Index: backend/src/main/java/medora/controller/AuthController.java
===================================================================
--- backend/src/main/java/medora/controller/AuthController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/AuthController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -3,4 +3,5 @@
 import medora.dto.LoginRequest;
 import medora.service.AuthService;
+import medora.util.SecurityUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -8,6 +9,8 @@
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
+import jakarta.servlet.http.HttpServletRequest;
 
 import java.util.Map;
+import java.util.HashMap;
 
 @RestController
@@ -19,7 +22,9 @@
 
     private final AuthService authService;
+    private final SecurityUtil securityUtil;
 
-    public AuthController(AuthService authService) {
+    public AuthController(AuthService authService, SecurityUtil securityUtil) {
         this.authService = authService;
+        this.securityUtil = securityUtil;
     }
 
@@ -69,3 +74,36 @@
         return ResponseEntity.ok(Map.of("status", "healthy"));
     }
+
+    /**
+     * Debug endpoint to test token validation
+     */
+    @GetMapping("/debug/token")
+    public ResponseEntity<?> debugToken(HttpServletRequest httpRequest) {
+        String role = securityUtil.getRoleFromRequest(httpRequest);
+        String username = securityUtil.getUsernameFromRequest(httpRequest);
+        Long userId = securityUtil.getUserIdFromRequest(httpRequest);
+
+        Map<String, Object> debug = new HashMap<>();
+        debug.put("role", role);
+        debug.put("username", username);
+        debug.put("userId", userId);
+        debug.put("isValid", role != null);
+
+        if (role == null) {
+            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(debug);
+        }
+        return ResponseEntity.ok(debug);
+    }
+
+    /**
+     * Test endpoint - no auth required, returns test token
+     */
+    @GetMapping("/test/generate-token")
+    public ResponseEntity<?> generateTestToken() {
+        String testToken = authService.generateTestToken();
+        Map<String, Object> response = new HashMap<>();
+        response.put("token", testToken);
+        response.put("message", "Copy this token and try it");
+        return ResponseEntity.ok(response);
+    }
 }
Index: backend/src/main/java/medora/controller/BillingController.java
===================================================================
--- backend/src/main/java/medora/controller/BillingController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/BillingController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -244,6 +244,6 @@
     @PatchMapping("/{billId}/payment-status")
     public ResponseEntity<?> updatePaymentStatus(@PathVariable Long billId,
-                                                 @RequestBody UpdateBillingRequest request,
-                                                 HttpServletRequest httpRequest) {
+                                                @RequestBody UpdateBillingRequest request,
+                                                HttpServletRequest httpRequest) {
         try {
             String role = securityUtil.getRoleFromRequest(httpRequest);
@@ -344,5 +344,5 @@
         if (billing.getMedicalRecord() != null && billing.getMedicalRecord().getPatient() != null) {
             patientName = billing.getMedicalRecord().getPatient().getFirstName() + " " +
-                    billing.getMedicalRecord().getPatient().getLastName();
+                         billing.getMedicalRecord().getPatient().getLastName();
         }
         return new BillingDTO(
Index: backend/src/main/java/medora/controller/DepartmentController.java
===================================================================
--- backend/src/main/java/medora/controller/DepartmentController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/DepartmentController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -162,6 +162,6 @@
     @PutMapping("/{departmentId}")
     public ResponseEntity<?> updateDepartment(@PathVariable Long departmentId,
-                                              @RequestBody Map<String, String> request,
-                                              HttpServletRequest httpRequest) {
+                                             @RequestBody Map<String, String> request,
+                                             HttpServletRequest httpRequest) {
         try {
             String role = securityUtil.getRoleFromRequest(httpRequest);
Index: backend/src/main/java/medora/controller/DiagnosisController.java
===================================================================
--- backend/src/main/java/medora/controller/DiagnosisController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/DiagnosisController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,6 +1,6 @@
 package medora.controller;
 
+import medora.dto.DiagnosisDTO;
 import medora.dto.CreateDiagnosisRequest;
-import medora.dto.DiagnosisDTO;
 import medora.models.domain.Diagnosis;
 import medora.service.DiagnosisService;
Index: backend/src/main/java/medora/controller/DiagnosticController.java
===================================================================
--- backend/src/main/java/medora/controller/DiagnosticController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/java/medora/controller/DiagnosticController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,136 @@
+package medora.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/diagnostic")
+public class DiagnosticController {
+
+    @Autowired
+    private DataSource dataSource;
+
+    @GetMapping("/referrals-count")
+    public ResponseEntity<?> getReferralsCount() {
+        try (Connection conn = dataSource.getConnection();
+             Statement stmt = conn.createStatement();
+             ResultSet rs = stmt.executeQuery("SELECT COUNT(*) as count FROM referrals")) {
+
+            if (rs.next()) {
+                Map<String, Object> result = new HashMap<>();
+                result.put("total_referrals", rs.getInt("count"));
+                return ResponseEntity.ok(result);
+            }
+        } catch (Exception e) {
+            return ResponseEntity.internalServerError()
+                    .body(Map.of("error", e.getMessage()));
+        }
+        return ResponseEntity.ok(Map.of("total_referrals", 0));
+    }
+
+    @GetMapping("/referrals-recent")
+    public ResponseEntity<?> getRecentReferrals() {
+        List<Map<String, Object>> results = new ArrayList<>();
+        try (Connection conn = dataSource.getConnection();
+             Statement stmt = conn.createStatement();
+             ResultSet rs = stmt.executeQuery(
+                     "SELECT referral_id, reason, referral_date, appointment_date, appointment_time " +
+                     "FROM referrals " +
+                     "ORDER BY referral_id DESC " +
+                     "LIMIT 20")) {
+
+            while (rs.next()) {
+                Map<String, Object> row = new HashMap<>();
+                row.put("referral_id", rs.getLong("referral_id"));
+                row.put("reason", rs.getString("reason"));
+                row.put("referral_date", rs.getDate("referral_date"));
+                row.put("appointment_date", rs.getDate("appointment_date"));
+                row.put("appointment_time", rs.getTime("appointment_time"));
+                results.add(row);
+            }
+        } catch (Exception e) {
+            return ResponseEntity.internalServerError()
+                    .body(Map.of("error", e.getMessage()));
+        }
+        return ResponseEntity.ok(results);
+    }
+
+    @GetMapping("/referrals-128-129-130")
+    public ResponseEntity<?> checkSpecificReferrals() {
+        List<Map<String, Object>> results = new ArrayList<>();
+        try (Connection conn = dataSource.getConnection();
+             Statement stmt = conn.createStatement();
+             ResultSet rs = stmt.executeQuery(
+                     "SELECT referral_id, reason, referral_date, appointment_date, appointment_time " +
+                     "FROM referrals " +
+                     "WHERE referral_id IN (128, 129, 130) " +
+                     "ORDER BY referral_id")) {
+
+            while (rs.next()) {
+                Map<String, Object> row = new HashMap<>();
+                row.put("referral_id", rs.getLong("referral_id"));
+                row.put("reason", rs.getString("reason"));
+                row.put("referral_date", rs.getDate("referral_date"));
+                row.put("appointment_date", rs.getDate("appointment_date"));
+                row.put("appointment_time", rs.getTime("appointment_time"));
+                results.add(row);
+            }
+        } catch (Exception e) {
+            return ResponseEntity.internalServerError()
+                    .body(Map.of("error", e.getMessage()));
+        }
+        return ResponseEntity.ok(results);
+    }
+
+    @GetMapping("/database-info")
+    public ResponseEntity<?> getDatabaseInfo() {
+        Map<String, Object> info = new HashMap<>();
+        try (Connection conn = dataSource.getConnection()) {
+            info.put("database", conn.getCatalog());
+            info.put("url", conn.getMetaData().getURL());
+            info.put("username", conn.getMetaData().getUserName());
+            info.put("driver", conn.getMetaData().getDriverName());
+            info.put("schema", conn.getSchema());
+        } catch (Exception e) {
+            info.put("error", e.getMessage());
+        }
+        return ResponseEntity.ok(info);
+    }
+
+    @GetMapping("/table-columns")
+    public ResponseEntity<?> getTableColumns() {
+        List<Map<String, Object>> columns = new ArrayList<>();
+        try (Connection conn = dataSource.getConnection();
+             Statement stmt = conn.createStatement();
+             ResultSet rs = stmt.executeQuery(
+                     "SELECT column_name, data_type, is_nullable " +
+                     "FROM information_schema.columns " +
+                     "WHERE table_name = 'referrals' " +
+                     "ORDER BY ordinal_position")) {
+
+            while (rs.next()) {
+                Map<String, Object> col = new HashMap<>();
+                col.put("column_name", rs.getString("column_name"));
+                col.put("data_type", rs.getString("data_type"));
+                col.put("is_nullable", rs.getString("is_nullable"));
+                columns.add(col);
+            }
+        } catch (Exception e) {
+            return ResponseEntity.internalServerError()
+                    .body(Map.of("error", e.getMessage()));
+        }
+        return ResponseEntity.ok(columns);
+    }
+}
Index: backend/src/main/java/medora/controller/DoctorController.java
===================================================================
--- backend/src/main/java/medora/controller/DoctorController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/DoctorController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -212,6 +212,6 @@
     @PutMapping("/{doctorId}")
     public ResponseEntity<?> updateDoctor(@PathVariable Long doctorId,
-                                          @RequestBody CreateDoctorRequest request,
-                                          HttpServletRequest httpRequest) {
+                                         @RequestBody CreateDoctorRequest request,
+                                         HttpServletRequest httpRequest) {
         try {
             String role = securityUtil.getRoleFromRequest(httpRequest);
Index: backend/src/main/java/medora/controller/LabController.java
===================================================================
--- backend/src/main/java/medora/controller/LabController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/LabController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -125,5 +125,5 @@
     @PutMapping("/{testId}")
     public ResponseEntity<?> updateLabTest(@PathVariable Long testId,
-                                           @RequestBody CreateLabTestRequest request) {
+                                          @RequestBody CreateLabTestRequest request) {
         try {
             logger.info("Updating lab test with ID: {}", testId);
Index: backend/src/main/java/medora/controller/MedicalRecordController.java
===================================================================
--- backend/src/main/java/medora/controller/MedicalRecordController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/MedicalRecordController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,7 +1,7 @@
 package medora.controller;
 
-import medora.dto.AllergyDTO;
 import medora.dto.ComprehensiveMedicalRecordDTO;
 import medora.dto.MedicalRecordDTO;
+import medora.dto.AllergyDTO;
 import medora.dto.SymptomDTO;
 import medora.models.domain.*;
Index: backend/src/main/java/medora/controller/MedicalReportController.java
===================================================================
--- backend/src/main/java/medora/controller/MedicalReportController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/MedicalReportController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -13,4 +13,5 @@
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController
Index: backend/src/main/java/medora/controller/PatientController.java
===================================================================
--- backend/src/main/java/medora/controller/PatientController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/PatientController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -207,6 +207,6 @@
     @PutMapping("/{patientId}")
     public ResponseEntity<?> updatePatient(@PathVariable Long patientId,
-                                           @RequestBody CreatePatientRequest request,
-                                           HttpServletRequest httpRequest) {
+                                          @RequestBody CreatePatientRequest request,
+                                          HttpServletRequest httpRequest) {
         try {
             String role = securityUtil.getRoleFromRequest(httpRequest);
Index: backend/src/main/java/medora/controller/PrescriptionController.java
===================================================================
--- backend/src/main/java/medora/controller/PrescriptionController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/PrescriptionController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,6 +1,6 @@
 package medora.controller;
 
+import medora.dto.PrescriptionDTO;
 import medora.dto.CreatePrescriptionRequest;
-import medora.dto.PrescriptionDTO;
 import medora.models.domain.PrescriptionMedicalRecord;
 import medora.service.PrescriptionService;
Index: backend/src/main/java/medora/controller/ProcedureController.java
===================================================================
--- backend/src/main/java/medora/controller/ProcedureController.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/controller/ProcedureController.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -334,11 +334,10 @@
     private Map<String, Object> convertResultToDTO(ProcedureResults result) {
         return Map.of(
-                "resultId", result.getResultId(),
-                "procedureId", result.getProcedure().getProcedureId(),
-                "procedureType", result.getProcedure().getProcedureType(),
-                "resultDescription", result.getResultDescription() != null ? result.getResultDescription() : "",
-                "resultDate", result.getResultDate()
+            "resultId", result.getResultId(),
+            "procedureId", result.getProcedure().getProcedureId(),
+            "procedureType", result.getProcedure().getProcedureType(),
+            "resultDescription", result.getResultDescription() != null ? result.getResultDescription() : "",
+            "resultDate", result.getResultDate()
         );
     }
 }
-
Index: backend/src/main/java/medora/dto/BillingDetailDTO.java
===================================================================
--- backend/src/main/java/medora/dto/BillingDetailDTO.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/BillingDetailDTO.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -21,6 +21,6 @@
 
     public BillingDetailDTO(Long billId, Long patientId, String patientName, String patientEmbg, String patientPhone,
-                            BigDecimal totalCost, String paymentStatus, LocalDate paymentDate,
-                            LocalDate billDate, List<BillingItemDTO> procedures, List<BillingItemDTO> labTests) {
+                           BigDecimal totalCost, String paymentStatus, LocalDate paymentDate,
+                           LocalDate billDate, List<BillingItemDTO> procedures, List<BillingItemDTO> labTests) {
         this.billId = billId;
         this.patientId = patientId;
Index: backend/src/main/java/medora/dto/CreateDoctorRequest.java
===================================================================
--- backend/src/main/java/medora/dto/CreateDoctorRequest.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/CreateDoctorRequest.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -10,5 +10,6 @@
 @NoArgsConstructor
 @AllArgsConstructor
-public class CreateDoctorRequest {
+public class
+CreateDoctorRequest {
     private String firstName;
     private String lastName;
Index: backend/src/main/java/medora/dto/LabResultDTO.java
===================================================================
--- backend/src/main/java/medora/dto/LabResultDTO.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/LabResultDTO.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,5 +5,4 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-
 import java.time.LocalDate;
 
Index: backend/src/main/java/medora/dto/MedicalRecordDTO.java
===================================================================
--- backend/src/main/java/medora/dto/MedicalRecordDTO.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/MedicalRecordDTO.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,4 +5,6 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
+
+import java.time.LocalDate;
 
 @Getter
Index: backend/src/main/java/medora/dto/PrescriptionDTO.java
===================================================================
--- backend/src/main/java/medora/dto/PrescriptionDTO.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/PrescriptionDTO.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,4 +5,6 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
+
+import java.time.LocalDate;
 
 @Getter
Index: backend/src/main/java/medora/dto/ProcedureRequestDTO.java
===================================================================
--- backend/src/main/java/medora/dto/ProcedureRequestDTO.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/ProcedureRequestDTO.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,5 +5,4 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-
 import java.time.LocalDate;
 
Index: backend/src/main/java/medora/dto/ProcedureResultDTO.java
===================================================================
--- backend/src/main/java/medora/dto/ProcedureResultDTO.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/ProcedureResultDTO.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,5 +5,4 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-
 import java.time.LocalDate;
 
Index: backend/src/main/java/medora/dto/RequestLabTestRequest.java
===================================================================
--- backend/src/main/java/medora/dto/RequestLabTestRequest.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/RequestLabTestRequest.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,5 +5,4 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-
 import java.time.LocalDate;
 
Index: backend/src/main/java/medora/dto/SubmitLabResultRequest.java
===================================================================
--- backend/src/main/java/medora/dto/SubmitLabResultRequest.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/dto/SubmitLabResultRequest.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -5,5 +5,4 @@
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-
 import java.time.LocalDate;
 
Index: backend/src/main/java/medora/models/domain/Admin.java
===================================================================
--- backend/src/main/java/medora/models/domain/Admin.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/Admin.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,10 +1,5 @@
 package medora.models.domain;
 
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
-import jakarta.validation.constraints.Pattern;
+import jakarta.persistence.*;
 import lombok.Getter;
 import lombok.Setter;
@@ -20,25 +15,22 @@
     private Long adminId;
 
-    @Column(name = "username", nullable = false, unique = true)
-    private String username;
+    @OneToOne(optional = false)
+    @JoinColumn(name = "user_id", nullable = false, unique = true)
+    private User user;
 
-    @Column(name = "name", nullable = false)
-    private String name;
-
-    @Column(name = "lastname", nullable = false)
-    private String lastname;
-
-    @Pattern(regexp = ".*@adminmedora.*")
-    @Column(name = "email", nullable = false, unique = true)
-    private String email;
+    @Column(name = "permissions")
+    private String permissions;
 
     public Admin() {}
 
-    public Admin(Long adminId, String username, String name, String lastname, String email) {
+    public Admin(Long adminId, User user, String permissions) {
         this.adminId = adminId;
-        this.username = username;
-        this.name = name;
-        this.lastname = lastname;
-        this.email = email;
+        this.user = user;
+        this.permissions = permissions;
+    }
+
+    public Admin(Long adminId, User user) {
+        this.adminId = adminId;
+        this.user = user;
     }
 }
Index: backend/src/main/java/medora/models/domain/Billing.java
===================================================================
--- backend/src/main/java/medora/models/domain/Billing.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/Billing.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -4,4 +4,5 @@
 import jakarta.persistence.*;
 import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotBlank;
 import lombok.Getter;
 import lombok.Setter;
@@ -38,6 +39,6 @@
     private MedicalRecord medicalRecord;
 
-    @ManyToOne(optional = false)
-    @JoinColumn(name = "admin_id", nullable = false)
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "admin_id", nullable = true)
     private Admin admin;
 
Index: backend/src/main/java/medora/models/domain/Departments.java
===================================================================
--- backend/src/main/java/medora/models/domain/Departments.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/Departments.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,8 +1,4 @@
 package medora.models.domain;
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
+import jakarta.persistence.*;
 import lombok.Getter;
 import lombok.Setter;
Index: backend/src/main/java/medora/models/domain/DoctorLevel.java
===================================================================
--- backend/src/main/java/medora/models/domain/DoctorLevel.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/DoctorLevel.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,8 +1,4 @@
 package medora.models.domain;
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
+import jakarta.persistence.*;
 import lombok.Getter;
 import lombok.Setter;
Index: backend/src/main/java/medora/models/domain/DoctorSpecialization.java
===================================================================
--- backend/src/main/java/medora/models/domain/DoctorSpecialization.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/DoctorSpecialization.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,8 +1,4 @@
 package medora.models.domain;
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
+import jakarta.persistence.*;
 import lombok.Getter;
 import lombok.Setter;
Index: backend/src/main/java/medora/models/domain/LabTechnician.java
===================================================================
--- backend/src/main/java/medora/models/domain/LabTechnician.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/LabTechnician.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,10 +1,5 @@
 package medora.models.domain;
 
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
-import jakarta.validation.constraints.Pattern;
+import jakarta.persistence.*;
 import lombok.Getter;
 import lombok.Setter;
@@ -20,25 +15,22 @@
     private Long technicianId;
 
-    @Column(name = "username", nullable = false, unique = true)
-    private String username;
+    @OneToOne(optional = false)
+    @JoinColumn(name = "user_id", nullable = false, unique = true)
+    private User user;
 
-    @Column(name = "name", nullable = false)
-    private String name;
-
-    @Column(name = "lastname", nullable = false)
-    private String lastname;
-
-    @Pattern(regexp = ".*@labmedora.*")
-    @Column(name = "email", nullable = false, unique = true)
-    private String email;
+    @Column(name = "certification")
+    private String certification;
 
     public LabTechnician() {}
 
-    public LabTechnician(Long technicianId, String username, String name, String lastname, String email) {
+    public LabTechnician(Long technicianId, User user, String certification) {
         this.technicianId = technicianId;
-        this.username = username;
-        this.name = name;
-        this.lastname = lastname;
-        this.email = email;
+        this.user = user;
+        this.certification = certification;
+    }
+
+    public LabTechnician(Long technicianId, User user) {
+        this.technicianId = technicianId;
+        this.user = user;
     }
 }
Index: backend/src/main/java/medora/models/domain/MedicalRecordSymptoms.java
===================================================================
--- backend/src/main/java/medora/models/domain/MedicalRecordSymptoms.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/MedicalRecordSymptoms.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -20,4 +20,5 @@
     @Id
     @ManyToOne(optional = false, fetch = FetchType.LAZY)
+    @JoinColumn(name = "symptom_id")
     private Symptoms symptom;
 
Index: backend/src/main/java/medora/models/domain/MedicalReport.java
===================================================================
--- backend/src/main/java/medora/models/domain/MedicalReport.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/MedicalReport.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -7,4 +7,6 @@
 
 import java.time.LocalDate;
+import java.util.List;
+import java.util.ArrayList;
 
 @Getter
Index: backend/src/main/java/medora/models/domain/Patient.java
===================================================================
--- backend/src/main/java/medora/models/domain/Patient.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/Patient.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -2,5 +2,4 @@
 
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import jakarta.persistence.*;
 import lombok.Getter;
@@ -8,4 +7,5 @@
 import medora.models.enums.BloodType;
 import medora.models.enums.Gender;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 
 import java.time.LocalDate;
Index: backend/src/main/java/medora/models/domain/PerformedLabTests.java
===================================================================
--- backend/src/main/java/medora/models/domain/PerformedLabTests.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/PerformedLabTests.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -48,10 +48,10 @@
 
     public PerformedLabTests(Long performedTestId,
-                             LabTests labTest,
-                             Patient patient,
-                             Doctors doctor,
-                             LabTechnician technician,
-                             LocalDate testDate,
-                             String notes) {
+                            LabTests labTest,
+                            Patient patient,
+                            Doctors doctor,
+                            LabTechnician technician,
+                            LocalDate testDate,
+                            String notes) {
         this.performedTestId = performedTestId;
         this.labTest = labTest;
Index: backend/src/main/java/medora/models/domain/ProcedureResults.java
===================================================================
--- backend/src/main/java/medora/models/domain/ProcedureResults.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/ProcedureResults.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -3,4 +3,5 @@
 
 import jakarta.persistence.*;
+import jakarta.validation.constraints.NotBlank;
 import lombok.Getter;
 import lombok.Setter;
Index: backend/src/main/java/medora/models/domain/Referrals.java
===================================================================
--- backend/src/main/java/medora/models/domain/Referrals.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/Referrals.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -50,11 +50,11 @@
 
     public Referrals(Long referralId,
-                     String reason,
-                     LocalDate referralDate,
-                     LocalDate appointmentDate,
-                     LocalTime appointmentTime,
-                     MedicalRecord medicalRecord,
-                     Doctors fromDoctor,
-                     Doctors toDoctor) {
+                    String reason,
+                    LocalDate referralDate,
+                    LocalDate appointmentDate,
+                    LocalTime appointmentTime,
+                    MedicalRecord medicalRecord,
+                    Doctors fromDoctor,
+                    Doctors toDoctor) {
 
         this.referralId = referralId;
Index: backend/src/main/java/medora/models/domain/Symptoms.java
===================================================================
--- backend/src/main/java/medora/models/domain/Symptoms.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/Symptoms.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -2,8 +2,5 @@
 
 
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
+import jakarta.persistence.*;
 import jakarta.validation.constraints.NotBlank;
 import lombok.Getter;
Index: backend/src/main/java/medora/models/domain/User.java
===================================================================
--- backend/src/main/java/medora/models/domain/User.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/models/domain/User.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -34,11 +34,11 @@
     private Boolean isActive = true;
 
-    // Foreign key to patient  for PATIENT role
-    @OneToOne(fetch = jakarta.persistence.FetchType.LAZY)
+    // Foreign key to patient (only for PATIENT role)
+    @OneToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "patient_id")
     private Patient patient;
 
-    // Foreign key to doctor for DOCTOR role
-    @OneToOne(fetch = jakarta.persistence.FetchType.LAZY)
+    // Foreign key to doctor (only for DOCTOR role)
+    @OneToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "doctor_id")
     private Doctors doctor;
Index: backend/src/main/java/medora/repository/BillingRepository.java
===================================================================
--- backend/src/main/java/medora/repository/BillingRepository.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/repository/BillingRepository.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -116,5 +116,5 @@
         WHERE bp.bill_id = :billId
     """, nativeQuery = true)
-    java.util.List<Object[]> findProceduresForBilling(@Param("billId") Long billId);
+    List<Object[]> findProceduresForBilling(@Param("billId") Long billId);
 
     // UC020 – Get lab tests for a billing record
@@ -125,5 +125,5 @@
         WHERE blt.bill_id = :billId
     """, nativeQuery = true)
-    java.util.List<Object[]> findLabTestsForBilling(@Param("billId") Long billId);
+    List<Object[]> findLabTestsForBilling(@Param("billId") Long billId);
 
     // Cleanup: Delete test records
Index: backend/src/main/java/medora/repository/ProcedureResultRepository.java
===================================================================
--- backend/src/main/java/medora/repository/ProcedureResultRepository.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/repository/ProcedureResultRepository.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -30,3 +30,13 @@
     """)
     List<ProcedureResults> findLatestResultsByProcedure(@Param("procedureId") Long procedureId);
+
+    @Query("""
+        SELECT pr FROM ProcedureResults pr
+        WHERE pr IN (
+            SELECT mrpr.procedureResult FROM MedicalRecordProcedureResults mrpr
+            WHERE mrpr.medicalRecord.recordId = :recordId
+        )
+        AND pr.procedure.procedureId = :procedureId
+    """)
+    List<ProcedureResults> findByMedicalRecordAndProcedure(@Param("recordId") Long recordId, @Param("procedureId") Long procedureId);
 }
Index: backend/src/main/java/medora/service/AppointmentService.java
===================================================================
--- backend/src/main/java/medora/service/AppointmentService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/AppointmentService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -181,5 +181,7 @@
     }
 
-
+    /**
+     * Mark appointment as completed
+     */
     @Transactional
     public Appointment completeAppointment(Long appointmentId) {
@@ -208,4 +210,7 @@
     }
 
+    /**
+     * Get appointment by ID
+     */
     @Transactional(readOnly = true)
     public Optional<Appointment> getAppointmentById(Long appointmentId) {
@@ -220,5 +225,7 @@
     }
 
-
+    /**
+     * Get appointments for patient
+     */
     @Transactional(readOnly = true)
     public List<Appointment> getAppointmentsForPatient(Long patientId) {
@@ -242,5 +249,7 @@
     }
 
-
+    /**
+     * Get appointments for doctor
+     */
     @Transactional(readOnly = true)
     public List<Appointment> getAppointmentsForDoctor(Long doctorId) {
@@ -264,5 +273,7 @@
     }
 
-
+    /**
+     * Get doctor's schedule for a specific date
+     */
     @Transactional(readOnly = true)
     public List<Appointment> getDoctorSchedule(Long doctorId,
@@ -290,5 +301,7 @@
     }
 
-
+    /**
+     * Get all appointments
+     */
     @Transactional(readOnly = true)
     public List<Appointment> getAllAppointments() {
@@ -299,5 +312,8 @@
     }
 
-
+    /**
+     * Find next available appointment slot for a doctor on a given date
+     * Returns a LocalTime for the next available slot, or null if no slots available
+     */
     public LocalTime findNextAvailableSlot(Long doctorId, LocalDate appointmentDate) {
         LocalTime[] timeSlots = {
Index: backend/src/main/java/medora/service/AuthService.java
===================================================================
--- backend/src/main/java/medora/service/AuthService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/AuthService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -6,8 +6,10 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -20,8 +22,10 @@
     private final UserRepository userRepository;
     private final JwtUtil jwtUtil;
+    private final PasswordEncoder passwordEncoder;
 
-    public AuthService(UserRepository userRepository, JwtUtil jwtUtil) {
+    public AuthService(UserRepository userRepository, JwtUtil jwtUtil, PasswordEncoder passwordEncoder) {
         this.userRepository = userRepository;
         this.jwtUtil = jwtUtil;
+        this.passwordEncoder = passwordEncoder;
     }
 
@@ -48,6 +52,6 @@
         }
 
-        // Simple password check (in production, use BCrypt)
-        if (!user.getPassword().equals(password)) {
+        // Verify password using BCrypt
+        if (!passwordEncoder.matches(password, user.getPassword())) {
             logger.warn("Failed login attempt for user: {}", username);
             throw new RuntimeException("Invalid username or password");
@@ -72,4 +76,8 @@
     }
 
+    public String generateTestToken() {
+        return jwtUtil.generateTokenWithDoctorId("admin", "ADMIN", 1L, null, null);
+    }
+
     @Transactional
     public void createUser(String username, String password, String role, String firstName, String lastName) {
@@ -78,7 +86,39 @@
         }
 
-        User user = new User(username, password, role, firstName, lastName);
+        // Hash password before storing
+        String hashedPassword = passwordEncoder.encode(password);
+        User user = new User(username, hashedPassword, role, firstName, lastName);
         userRepository.save(user);
         logger.info("User created: {} with role: {}", username, role);
     }
+
+    /**
+     * One-time migration: re-hashes any user whose stored password is still
+     * plaintext (i.e. not already a BCrypt hash) into a proper BCrypt hash.
+     * Safe to call more than once — already-hashed users are skipped.
+     *
+     * Intended to be run once via a temporary CommandLineRunner bean, then
+     * the bean should be removed so this doesn't run on every startup.
+     */
+    @Transactional
+    public int migratePlaintextPasswords() {
+        List<User> allUsers = userRepository.findAll();
+        int migratedCount = 0;
+
+        for (User user : allUsers) {
+            String currentPassword = user.getPassword();
+
+            // BCrypt hashes always start with $2a$, $2b$, or $2y$ — anything
+            // else is assumed to still be plaintext and needs migrating
+            if (currentPassword != null && !currentPassword.startsWith("$2")) {
+                user.setPassword(passwordEncoder.encode(currentPassword));
+                userRepository.save(user);
+                migratedCount++;
+                logger.info("Migrated password for user: {}", user.getUsername());
+            }
+        }
+
+        logger.info("Password migration complete: {} of {} users migrated", migratedCount, allUsers.size());
+        return migratedCount;
+    }
 }
Index: backend/src/main/java/medora/service/BillingService.java
===================================================================
--- backend/src/main/java/medora/service/BillingService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/BillingService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -221,5 +221,5 @@
         }
 
-        logger.info("Total billing cost for bill ID {}: procedures={}, lab tests={}",
+        logger.info("Total billing cost for bill ID {}: procedures={}, lab tests={}", 
                 billId, procedureCost, labTestCost);
         return procedureCost.add(labTestCost);
@@ -244,5 +244,5 @@
         // This is a placeholder - adjust based on your actual Procedure entity
         logger.info("Adding procedure {} to billing record {}", procedureId, billId);
-
+        
         return null; // Will be implemented with ProcedureRepository injection
     }
@@ -464,8 +464,8 @@
             billingRepository.deleteAll();
 
-            logger.info(" Deleted {} billing records successfully", billingCount);
+            logger.info("✅ Deleted {} billing records successfully", billingCount);
             return billingCount;
         } catch (Exception e) {
-            logger.error(" Error deleting billing records: {}", e.getMessage());
+            logger.error("❌ Error deleting billing records: {}", e.getMessage());
             e.printStackTrace();
             throw e;
Index: backend/src/main/java/medora/service/DepartmentService.java
===================================================================
--- backend/src/main/java/medora/service/DepartmentService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/DepartmentService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -32,5 +32,8 @@
     }
 
-
+    /**
+     * UC023 – View Departments
+     * Get all departments
+     */
     @Transactional(readOnly = true)
     public List<Departments> getAllDepartments() {
@@ -39,5 +42,7 @@
     }
 
-
+    /**
+     * Get department by ID
+     */
     @Transactional(readOnly = true)
     public Optional<Departments> getDepartmentById(Long departmentId) {
@@ -49,5 +54,7 @@
     }
 
-
+    /**
+     * Get department by name
+     */
     @Transactional(readOnly = true)
     public Optional<Departments> getDepartmentByName(String departmentName) {
@@ -59,5 +66,8 @@
     }
 
-
+    /**
+     * UC024 – View Doctors by Department
+     * Get all doctors in a specific department
+     */
     @Transactional(readOnly = true)
     public List<Doctors> getDoctorsByDepartment(Long departmentId) {
@@ -75,5 +85,7 @@
     }
 
-
+    /**
+     * Create a new department
+     */
     @Transactional
     public Departments createDepartment(Departments department) {
@@ -87,5 +99,7 @@
     }
 
-
+    /**
+     * Update department
+     */
     @Transactional
     public Departments updateDepartment(Long departmentId, Departments departmentDetails) {
Index: backend/src/main/java/medora/service/DiagnosisService.java
===================================================================
--- backend/src/main/java/medora/service/DiagnosisService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/DiagnosisService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -2,9 +2,9 @@
 
 import medora.models.domain.Diagnosis;
+import medora.models.domain.Patient;
 import medora.models.domain.Doctors;
-import medora.models.domain.Patient;
 import medora.repository.DiagnosisRepository;
+import medora.repository.PatientRepository;
 import medora.repository.DoctorRepository;
-import medora.repository.PatientRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,4 +69,7 @@
     }
 
+    /**
+     * Get diagnosis by ID
+     */
     @Transactional(readOnly = true)
     public Optional<Diagnosis> getDiagnosisById(Long diagnosisId) {
@@ -78,5 +81,7 @@
     }
 
-
+    /**
+     * Get diagnoses for patient
+     */
     @Transactional(readOnly = true)
     public List<Diagnosis> getDiagnosesForPatient(Long patientId) {
@@ -91,5 +96,7 @@
     }
 
-
+    /**
+     * Get diagnoses by doctor
+     */
     @Transactional(readOnly = true)
     public List<Diagnosis> getDiagnosesByDoctor(Long doctorId) {
@@ -105,22 +112,3 @@
 
 
-    @Transactional
-    public Diagnosis updateDiagnosis(Long diagnosisId,
-                                     String diagnosisName,
-                                     String description) {
-
-        if (diagnosisId == null || diagnosisId <= 0)
-            throw new IllegalArgumentException("Diagnosis ID must be valid");
-
-        Diagnosis diagnosis = diagnosisRepository.findById(diagnosisId)
-                .orElseThrow(() -> new RuntimeException("Diagnosis not found"));
-
-        if (diagnosisName != null && !diagnosisName.isBlank())
-            diagnosis.setName(diagnosisName);
-
-        if (description != null)
-            diagnosis.setDescription(description);
-
-        return diagnosisRepository.save(diagnosis);
-    }
 }
Index: backend/src/main/java/medora/service/DoctorService.java
===================================================================
--- backend/src/main/java/medora/service/DoctorService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/DoctorService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,8 +1,8 @@
 package medora.service;
 
+import medora.models.domain.Doctors;
 import medora.models.domain.Departments;
-import medora.models.domain.Doctors;
+import medora.repository.DoctorRepository;
 import medora.repository.DepartmentRepository;
-import medora.repository.DoctorRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,5 +46,7 @@
     }
 
-
+    /**
+     * Get doctor by email
+     */
     @Transactional(readOnly = true)
     public Doctors getDoctorByEmail(String emailAddress) {
@@ -59,5 +61,7 @@
     }
 
-
+    /**
+     * UC024 – View Doctors by Department
+     */
     @Transactional(readOnly = true)
     public List<Doctors> getDoctorsByDepartment(Long departmentId) {
@@ -74,5 +78,7 @@
     }
 
-
+    /**
+     * Get doctors by specialization
+     */
     @Transactional(readOnly = true)
     public List<Doctors> getDoctorsBySpecialization(Long specializationId) {
@@ -86,5 +92,7 @@
     }
 
-
+    /**
+     * Get doctors by level
+     */
     @Transactional(readOnly = true)
     public List<Doctors> getDoctorsByLevel(Long levelId) {
@@ -98,5 +106,7 @@
     }
 
-
+    /**
+     * Get all doctors
+     */
     @Transactional(readOnly = true)
     public List<Doctors> getAllDoctors() {
@@ -105,5 +115,7 @@
     }
 
-
+    /**
+     * Create doctor
+     */
     @Transactional
     public Doctors createDoctor(Doctors doctor) {
@@ -146,5 +158,7 @@
     }
 
-
+    /**
+     * Update doctor
+     */
     @Transactional
     public Doctors updateDoctor(Long doctorId, Doctors doctorDetails) {
Index: backend/src/main/java/medora/service/LabService.java
===================================================================
--- backend/src/main/java/medora/service/LabService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/LabService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -223,25 +223,6 @@
     @Transactional(readOnly = true)
     public List<PerformedLabTests> getPendingLabTests() {
-        // Get all performed tests and filter to only those without results
-        List<PerformedLabTests> allTests = performedLabTestRepository.findAll();
-
-        return allTests.stream()
-                .filter(test -> {
-                    // Get the patient's medical record
-                    Optional<MedicalRecord> recordOpt = medicalRecordRepository.findByPatientPatientId(test.getPatient().getPatientId());
-                    if (recordOpt.isEmpty()) {
-                        return true; // No medical record, so no results possible
-                    }
-
-                    MedicalRecord record = recordOpt.get();
-                    // Check if this test has results in this medical record
-                    List<MedicalRecordLabResults> results = medicalRecordLabResultRepository
-                            .findByMedicalRecordRecordId(record.getRecordId());
-
-                    // Filter to only results for this specific test
-                    return results.stream()
-                            .noneMatch(r -> r.getLabResult().getLabTest().getTestId().equals(test.getLabTest().getTestId()));
-                })
-                .toList();
+        logger.info("Fetching all pending lab test requests");
+        return performedLabTestRepository.findAll();
     }
 
Index: backend/src/main/java/medora/service/MedicalObservationsService.java
===================================================================
--- backend/src/main/java/medora/service/MedicalObservationsService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/MedicalObservationsService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -2,6 +2,14 @@
 
 
-import medora.models.domain.*;
-import medora.repository.*;
+import medora.models.domain.MedicalRecordSymptoms;
+import medora.models.domain.MedicalRecordAllergies;
+import medora.models.domain.Symptoms;
+import medora.models.domain.Allergies;
+import medora.models.domain.MedicalRecord;
+import medora.repository.SymptomRepository;
+import medora.repository.AllergyRepository;
+import medora.repository.MedicalRecordSymptomRepository;
+import medora.repository.MedicalRecordAllergyRepository;
+import medora.repository.MedicalRecordRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,5 +69,5 @@
                 .orElseThrow(() -> new RuntimeException("Symptom not found with ID: " + symptomId));
 
-
+        // Check if symptom is already recorded
         if (medicalRecordSymptomRepository.existsByMedicalRecordRecordIdAndSymptomSymptomId(
                 medicalRecordId, symptomId)) {
@@ -93,5 +101,5 @@
 
    
-    // For ALLERGIES
+    // ================= ALLERGIES OPERATIONS =================
 
     /**
@@ -128,5 +136,7 @@
     }
 
-
+    /**
+     * Get all allergies for a patient's medical record
+     */
     @Transactional(readOnly = true)
     public List<MedicalRecordAllergies> getAllergiesForMedicalRecord(Long medicalRecordId) {
@@ -143,5 +153,9 @@
     }
 
+    
 
+    /**
+     * Get all available symptoms
+     */
     @Transactional(readOnly = true)
     public List<Symptoms> getAllSymptoms() {
@@ -150,5 +164,7 @@
     }
 
-
+    /**
+     * Get all available allergies
+     */
     @Transactional(readOnly = true)
     public List<Allergies> getAllAllergies() {
Index: backend/src/main/java/medora/service/MedicalRecordService.java
===================================================================
--- backend/src/main/java/medora/service/MedicalRecordService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/MedicalRecordService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,10 +1,21 @@
 package medora.service;
 
-import medora.models.domain.*;
+import medora.models.domain.Allergies;
+import medora.models.domain.MedicalRecord;
+import medora.models.domain.MedicalRecordAllergies;
+import medora.models.domain.MedicalRecordSymptoms;
+import medora.models.domain.Symptoms;
 import medora.models.domain.id.MedicalRecordAllergyId;
 import medora.models.domain.id.MedicalRecordLabResultId;
 import medora.models.domain.id.MedicalRecordProcedureId;
 import medora.models.domain.id.MedicalRecordSymptomId;
-import medora.repository.*;
+import medora.repository.AllergyRepository;
+import medora.repository.MedicalRecordAllergyRepository;
+import medora.repository.MedicalRecordLabResultRepository;
+import medora.repository.MedicalRecordProcedureRepository;
+import medora.repository.MedicalRecordRepository;
+import medora.repository.MedicalRecordSymptomRepository;
+import medora.repository.PatientRepository;
+import medora.repository.SymptomRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -94,5 +105,5 @@
     }
 
-    // UC015 – Link Medical Data to Medical Record
+    // UC015 – Link Medical Data to Medical Record ⭐ (IMPORTANT FIX)
     @Transactional
     public MedicalRecord linkMedicalData(Long recordId, MedicalRecord updatedData) {
@@ -109,4 +120,8 @@
                 .orElseThrow(() -> new RuntimeException("Medical record not found"));
 
+        // Safely link many-to-many/join-table rows.
+        // The project currently models join-tables as explicit entities (e.g. MedicalRecordProcedures),
+        // but `MedicalRecord` entity in this codebase doesn't expose collection getters yet.
+        // To avoid compile problems and still support DTOs that may contain collections, use reflection:
 
         try {
@@ -126,5 +141,5 @@
                 }
             } catch (NoSuchMethodException ignored) {
-
+                // updatedData has no getProcedures() — nothing to do
             }
 
@@ -144,5 +159,5 @@
                 }
             } catch (NoSuchMethodException ignored) {
-
+                // updatedData has no getLabResults() — nothing to do
             }
 
@@ -157,9 +172,10 @@
                         MedicalRecordAllergyId mraId = new MedicalRecordAllergyId(recordId, allergyId);
                         if (medicalRecordAllergyRepository.findById(mraId).isEmpty()) {
-
+                            // Create allergy join entity manually and save
                             MedicalRecordAllergies allergyJoin =
                                 new MedicalRecordAllergies();
                             allergyJoin.setMedicalRecord(record);
-
+                            // Load allergy entity would require allergyRepo, which we don't have injected yet
+                            // For now, just save the join if it doesn't exist (via repository direct save)
                             logger.debug("Allergy {} linking deferred (missing allergyRepo)", allergyId);
                         }
@@ -167,5 +183,5 @@
                 }
             } catch (NoSuchMethodException ignored) {
-
+                // updatedData has no getAllergies() — nothing to do
             }
 
@@ -185,8 +201,8 @@
                 }
             } catch (NoSuchMethodException ignored) {
-
+                // updatedData has no getSymptoms() — nothing to do
             }
         } catch (ReflectiveOperationException e) {
-
+            // If reflection fails for unexpected reasons, log and rethrow as runtime to avoid silent data loss.
             throw new RuntimeException("Failed to link medical data via reflection", e);
         }
@@ -196,4 +212,5 @@
     }
 
+    // UPDATE medical record
     @Transactional
     public MedicalRecord updateMedicalRecord(Long recordId, MedicalRecord recordDetails) {
@@ -214,4 +231,5 @@
     }
 
+    // helper
     @Transactional(readOnly = true)
     public List<MedicalRecord> getAllMedicalRecords() {
@@ -273,5 +291,5 @@
     }
 
-
+    // Reflection helper: try to extract an id from an object using common getter names
     private Long extractId(Object obj, String... candidateGetters) {
         if (obj == null) return null;
@@ -282,5 +300,5 @@
                 if (val instanceof Number) return ((Number) val).longValue();
             } catch (ReflectiveOperationException ignored) {
-
+                // try next
             }
         }
Index: backend/src/main/java/medora/service/MedicalReportService.java
===================================================================
--- backend/src/main/java/medora/service/MedicalReportService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/MedicalReportService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,6 +1,6 @@
 package medora.service;
 
+import medora.models.domain.*;
 import medora.dto.*;
-import medora.models.domain.*;
 import medora.repository.*;
 import org.slf4j.Logger;
@@ -10,6 +10,8 @@
 
 import java.time.LocalDate;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 
Index: backend/src/main/java/medora/service/PatientService.java
===================================================================
--- backend/src/main/java/medora/service/PatientService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/PatientService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -2,8 +2,8 @@
 
 
+import medora.models.domain.Patient;
 import medora.models.domain.MedicalRecord;
-import medora.models.domain.Patient;
+import medora.repository.PatientRepository;
 import medora.repository.MedicalRecordRepository;
-import medora.repository.PatientRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
Index: backend/src/main/java/medora/service/PrescriptionService.java
===================================================================
--- backend/src/main/java/medora/service/PrescriptionService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/PrescriptionService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,10 +1,10 @@
 package medora.service;
 
+import medora.models.domain.Prescriptions;
+import medora.models.domain.PrescriptionMedicalRecord;
 import medora.models.domain.MedicalRecord;
-import medora.models.domain.PrescriptionMedicalRecord;
-import medora.models.domain.Prescriptions;
+import medora.repository.PrescriptionRepository;
+import medora.repository.PrescriptionMedicalRecordRepository;
 import medora.repository.MedicalRecordRepository;
-import medora.repository.PrescriptionMedicalRecordRepository;
-import medora.repository.PrescriptionRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
Index: backend/src/main/java/medora/service/ProcedureService.java
===================================================================
--- backend/src/main/java/medora/service/ProcedureService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/ProcedureService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -297,17 +297,32 @@
                 .orElseThrow(() -> new RuntimeException("Procedure not found"));
 
-        ProcedureResults result = new ProcedureResults();
-        result.setProcedure(procedure);
-        result.setResultDescription(resultDescription);
-        result.setResultDate(resultDate);
-
-        ProcedureResults savedResult = procedureResultRepository.save(result);
-
-        // Link to medical record
-        MedicalRecordProcedureResults link = new MedicalRecordProcedureResults(record, savedResult);
-        medicalRecordProcedureResultRepository.save(link);
-
-        logger.info("Stored procedure result {} for medical record {}", savedResult.getResultId(), medicalRecordId);
-        return savedResult;
+        // Check if result already exists for this medical record and procedure
+        List<ProcedureResults> existingResults = procedureResultRepository.findByMedicalRecordAndProcedure(medicalRecordId, procedureId);
+
+        ProcedureResults result;
+        if (!existingResults.isEmpty()) {
+            // Update existing result
+            result = existingResults.get(0);
+            result.setResultDescription(resultDescription);
+            result.setResultDate(resultDate);
+            ProcedureResults savedResult = procedureResultRepository.save(result);
+            logger.info("Updated procedure result {} for medical record {}", savedResult.getResultId(), medicalRecordId);
+            return savedResult;
+        } else {
+            // Create new result
+            result = new ProcedureResults();
+            result.setProcedure(procedure);
+            result.setResultDescription(resultDescription);
+            result.setResultDate(resultDate);
+
+            // Save result first to generate ID
+            ProcedureResults savedResult = procedureResultRepository.save(result);
+
+            // Then link to medical record
+            MedicalRecordProcedureResults link = new MedicalRecordProcedureResults(record, savedResult);
+            medicalRecordProcedureResultRepository.save(link);
+            logger.info("Created new procedure result {} for medical record {}", savedResult.getResultId(), medicalRecordId);
+            return savedResult;
+        }
     }
 
Index: backend/src/main/java/medora/service/ReferralService.java
===================================================================
--- backend/src/main/java/medora/service/ReferralService.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/service/ReferralService.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -106,5 +106,7 @@
     }
 
-
+    /**
+     * Get referral by ID
+     */
     @Transactional(readOnly = true)
     public Optional<Referrals> getReferralById(Long referralId) {
@@ -116,5 +118,7 @@
     }
 
-
+    /**
+     * Get referrals for a patient
+     */
     @Transactional(readOnly = true)
     public List<Referrals> getReferralsForPatient(Long patientId) {
@@ -131,5 +135,7 @@
     }
 
-
+    /**
+     * Get referrals made by a doctor
+     */
     @Transactional(readOnly = true)
     public List<Referrals> getReferralsByFromDoctor(Long doctorId) {
@@ -146,4 +152,7 @@
     }
 
+    /**
+     * Get referrals received by a doctor
+     */
     @Transactional(readOnly = true)
     public List<Referrals> getReferralsToDoctor(Long doctorId) {
@@ -160,5 +169,8 @@
     }
 
-
+    /**
+     * Create appointment for referral in a separate transaction
+     * Using REQUIRES_NEW ensures appointment creation failures don't rollback the referral
+     */
     @Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW)
     private void createAppointmentForReferral(Long patientId, Long doctorId, LocalDate appointmentDate, LocalTime appointmentTime) {
Index: backend/src/main/java/medora/util/JwtUtil.java
===================================================================
--- backend/src/main/java/medora/util/JwtUtil.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/java/medora/util/JwtUtil.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -30,5 +30,5 @@
     public void init() {
         logger.info("JwtUtil initialized - JWT Secret length: {}, Expiration: {}ms",
-                jwtSecret != null ? jwtSecret.length() : 0, jwtExpirationMs);
+            jwtSecret != null ? jwtSecret.length() : 0, jwtExpirationMs);
         if (jwtSecret == null || jwtSecret.isEmpty()) {
             logger.error("⚠️ JWT_SECRET is not set or empty!");
@@ -123,5 +123,5 @@
 
             logger.info("🔐 Validating token - secret hash: {}, secret length: {}, token length: {}",
-                    jwtSecret.hashCode(), jwtSecret.length(), token.length());
+                jwtSecret.hashCode(), jwtSecret.length(), token.length());
 
             Jwts.parser()
Index: backend/src/main/resources/application.properties
===================================================================
--- backend/src/main/resources/application.properties	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ backend/src/main/resources/application.properties	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -23,3 +23,2 @@
 spring.jackson.serialization.fail-on-empty-beans=false
 spring.jackson.default-property-inclusion=non_null
-
Index: ckend/src/main/resources/db.migration/R__allergy_prescription_safety_enforcement.sql
===================================================================
--- backend/src/main/resources/db.migration/R__allergy_prescription_safety_enforcement.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,85 +1,0 @@
-CREATE DOMAIN non_negative_currency AS DECIMAL(12,2)
-    CHECK (VALUE >= 0);
-
-CREATE OR REPLACE FUNCTION t1_prescription_allergy_check()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-DECLARE
-    v_patient_id BIGINT;
-    v_conflict_allergy_id BIGINT;
-    v_allergy_name TEXT;
-BEGIN
-    SELECT patient_id INTO v_patient_id
-    FROM medical_records
-    WHERE record_id = NEW.record_id;
-
-    IF v_patient_id IS NULL THEN
-        RAISE EXCEPTION 'Medical record % not found', NEW.record_id;
-    END IF;
-
-    SELECT apr.allergy_id, a.name
-    INTO v_conflict_allergy_id, v_allergy_name
-    FROM prescription_restriction pr_rest
-    JOIN allergy_prescription_restrictions apr ON apr.restriction_id = pr_rest.restriction_id
-    JOIN allergies a ON apr.allergy_id = a.allergy_id
-    JOIN medical_record_allergies mra ON a.allergy_id = mra.allergy_id
-    WHERE pr_rest.prescription_id = NEW.prescription_id
-    AND mra.record_id = NEW.record_id
-    LIMIT 1;
-
-    IF v_conflict_allergy_id IS NOT NULL THEN
-        RAISE EXCEPTION 'PRESCRIPTION_ALLERGY_CONFLICT: Prescription % conflicts with allergy % (%) in patient''s record %',
-            NEW.prescription_id, v_conflict_allergy_id, v_allergy_name, NEW.record_id;
-    END IF;
-
-    RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trg_prescription_allergy_check ON prescription_medical_records;
-CREATE TRIGGER trg_prescription_allergy_check
-    BEFORE INSERT
-    ON prescription_medical_records
-    FOR EACH ROW
-    EXECUTE FUNCTION t1_prescription_allergy_check();
-
-CREATE TABLE IF NOT EXISTS prescription_allergy_conflicts_log (
-    log_id BIGSERIAL PRIMARY KEY,
-    record_id BIGINT NOT NULL REFERENCES medical_records(record_id),
-    prescription_id BIGINT NOT NULL REFERENCES prescriptions(prescription_id),
-    allergy_id BIGINT NOT NULL REFERENCES allergies(allergy_id),
-    conflict_type TEXT CHECK (conflict_type IN ('ACTIVE', 'RESOLVED')),
-    detected_date TIMESTAMP DEFAULT NOW(),
-    resolution_notes TEXT,
-    resolved_date TIMESTAMP
-);
-
-CREATE OR REPLACE VIEW v_prescription_allergy_conflicts AS
-SELECT
-    mr.record_id,
-    p.patient_id,
-    p.first_name,
-    p.last_name,
-    pmr.prescription_id,
-    pr.medication_name,
-    a.allergy_id,
-    a.name AS allergy_name,
-    a.allergy_severity,
-    apr.restriction_id,
-    pr_rest.description AS restriction_description,
-    CASE
-        WHEN mra.record_id IS NOT NULL THEN 'ACTIVE_CONFLICT'
-        ELSE 'ARCHIVED'
-    END AS conflict_status
-FROM prescription_medical_records pmr
-JOIN medical_records mr ON pmr.record_id = mr.record_id
-JOIN patients p ON mr.patient_id = p.patient_id
-JOIN prescriptions pr ON pmr.prescription_id = pr.prescription_id
-JOIN prescription_restriction pr_rest ON pr.prescription_id = pr_rest.prescription_id
-JOIN allergy_prescription_restrictions apr ON pr_rest.restriction_id = apr.restriction_id
-JOIN allergies a ON apr.allergy_id = a.allergy_id
-LEFT JOIN medical_record_allergies mra ON mr.record_id = mra.record_id
-    AND a.allergy_id = mra.allergy_id
-WHERE a.allergy_severity IN ('HIGH', 'CRITICAL')
-ORDER BY p.patient_id, a.allergy_severity DESC;
Index: ckend/src/main/resources/db.migration/R__billing_integrity.sql
===================================================================
--- backend/src/main/resources/db.migration/R__billing_integrity.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,145 +1,0 @@
--- schema addition: billing had no "issued" date, only payment_date (populated only once
--- paid), so there was no way to measure how long a still-PENDING bill has been outstanding.
--- Existing rows will backfill to NOW() at ALTER time, which is not historically accurate —
--- acceptable for this project, but worth noting.
-ALTER TABLE billing ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT NOW();
-
-CREATE TABLE IF NOT EXISTS billing_audit_log (
-                                                 audit_id BIGSERIAL PRIMARY KEY,
-                                                 bill_id BIGINT NOT NULL REFERENCES billing(bill_id),
-    old_amount DECIMAL(12,2),
-    new_amount DECIMAL(12,2),
-    old_status TEXT,
-    new_status TEXT,
-    change_type TEXT CHECK (change_type IN ('INSERT', 'UPDATE', 'LINE_ITEM_ADD', 'LINE_ITEM_REMOVE')),
-    changed_at TIMESTAMP DEFAULT NOW()
-    );
-
--- Note: billing_procedures links to the catalog procedure_id, not to a specific
--- performed_procedures row, so when the same procedure type has been performed on more
--- than one patient there is no reliable way to verify a billed line item belongs to the
--- same patient as the bill. That check is intentionally left out rather than implemented
--- unreliably.
-
-CREATE OR REPLACE FUNCTION recalculate_billing_total(p_bill_id BIGINT, p_change_type TEXT)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
-v_procedure_total DECIMAL;
-    v_lab_total DECIMAL;
-    v_new_total DECIMAL;
-BEGIN
-SELECT COALESCE(SUM(p.cost), 0) INTO v_procedure_total
-FROM billing_procedures bp
-         JOIN procedures p ON p.procedure_id = bp.procedure_id
-WHERE bp.bill_id = p_bill_id;
-
-SELECT COALESCE(SUM(lt.cost), 0) INTO v_lab_total
-FROM billing_lab_tests blt
-         JOIN lab_tests lt ON lt.test_id = blt.test_id
-WHERE blt.bill_id = p_bill_id;
-
-v_new_total := v_procedure_total + v_lab_total;
-
-UPDATE billing SET total_cost = v_new_total WHERE bill_id = p_bill_id;
-
-INSERT INTO billing_audit_log (bill_id, new_amount, change_type)
-VALUES (p_bill_id, v_new_total, p_change_type);
-END;
-$$;
-
--- one shared trigger function, reused for both billing_procedures and billing_lab_tests
--- (both tables have a bill_id column, so NEW.bill_id / OLD.bill_id works either way)
-CREATE OR REPLACE FUNCTION t1_billing_line_item_changed()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-BEGIN
-    IF TG_OP = 'DELETE' THEN
-        PERFORM recalculate_billing_total(OLD.bill_id, 'LINE_ITEM_REMOVE');
-RETURN OLD;
-ELSE
-        PERFORM recalculate_billing_total(NEW.bill_id, 'LINE_ITEM_ADD');
-RETURN NEW;
-END IF;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trg_billing_procedures_update_total ON billing_procedures;
-CREATE TRIGGER trg_billing_procedures_update_total
-    AFTER INSERT OR DELETE ON billing_procedures
-FOR EACH ROW
-EXECUTE FUNCTION t1_billing_line_item_changed();
-
-DROP TRIGGER IF EXISTS trg_billing_lab_tests_update_total ON billing_lab_tests;
-CREATE TRIGGER trg_billing_lab_tests_update_total
-    AFTER INSERT OR DELETE ON billing_lab_tests
-FOR EACH ROW
-EXECUTE FUNCTION t1_billing_line_item_changed();
-
-CREATE OR REPLACE FUNCTION is_valid_billing_transition(p_old TEXT, p_new TEXT)
-RETURNS BOOLEAN
-LANGUAGE sql
-IMMUTABLE
-AS $$
-SELECT CASE
-           WHEN p_old = p_new THEN TRUE
-           WHEN p_old = 'PENDING' AND p_new IN ('PAID', 'CANCELLED') THEN TRUE
-           ELSE FALSE
-           END;
-$$;
-
-CREATE OR REPLACE FUNCTION t2_billing_status_transition()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-BEGIN
-    IF NOT is_valid_billing_transition(OLD.payment_status, NEW.payment_status) THEN
-        RAISE EXCEPTION 'Cannot transition billing status from % to %',
-            OLD.payment_status, NEW.payment_status;
-END IF;
-
-    IF OLD.payment_status <> NEW.payment_status THEN
-        INSERT INTO billing_audit_log (bill_id, old_status, new_status, change_type)
-        VALUES (NEW.bill_id, OLD.payment_status, NEW.payment_status, 'UPDATE');
-END IF;
-
-RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trg_billing_status_transition ON billing;
-CREATE TRIGGER trg_billing_status_transition
-    BEFORE UPDATE ON billing
-    FOR EACH ROW
-    EXECUTE FUNCTION t2_billing_status_transition();
-
-CREATE OR REPLACE VIEW v_overdue_billings AS
-SELECT
-    b.bill_id,
-    p.patient_id, p.first_name, p.last_name,
-    b.total_cost, b.payment_status, b.created_at,
-    CURRENT_DATE - b.created_at::DATE AS days_outstanding,
-        CASE
-            WHEN CURRENT_DATE - b.created_at::DATE > 60 THEN 'CRITICAL'
-        WHEN CURRENT_DATE - b.created_at::DATE > 30 THEN 'OVERDUE'
-        ELSE 'PENDING'
-END AS urgency
-FROM billing b
-JOIN medical_records mr ON b.record_id = mr.record_id
-JOIN patients p ON mr.patient_id = p.patient_id
-WHERE b.payment_status = 'PENDING'
-  AND CURRENT_DATE - b.created_at::DATE >= 30
-ORDER BY days_outstanding DESC;
-
-CREATE OR REPLACE PROCEDURE job_billing_alerts()
-LANGUAGE plpgsql
-AS $$
-DECLARE
-    v_overdue_count INT;
-BEGIN
-    SELECT COUNT(*) INTO v_overdue_count FROM v_overdue_billings WHERE days_outstanding > 30;
-    RAISE NOTICE 'Found % overdue billing records requiring follow-up', v_overdue_count;
-END;
-$$;
Index: ckend/src/main/resources/db.migration/R__custom_domains.sql
===================================================================
--- backend/src/main/resources/db.migration/R__custom_domains.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,14 +1,0 @@
-CREATE DOMAIN embg_format AS TEXT
-    CHECK (VALUE ~ '^\d{13}$');
-
-CREATE DOMAIN email_format AS TEXT
-    CHECK (
-        VALUE ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
-        AND LENGTH(VALUE) <= 254
-    );
-
-CREATE DOMAIN phone_number_format AS TEXT
-    CHECK (VALUE ~ '^\+?[\d\s\-().]{7,20}$');
-
-CREATE DOMAIN non_negative_cost AS DECIMAL(12,2)
-    CHECK (VALUE >= 0);
Index: ckend/src/main/resources/db.migration/R__medical_record_integrity.sql
===================================================================
--- backend/src/main/resources/db.migration/R__medical_record_integrity.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,104 +1,0 @@
-CREATE OR REPLACE FUNCTION t1_diagnosis_record_consistency()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-DECLARE
-    v_record_patient BIGINT;
-    v_diagnosis_patient BIGINT;
-BEGIN
-    SELECT patient_id INTO v_record_patient FROM medical_records WHERE record_id = NEW.record_id;
-    SELECT patient_id INTO v_diagnosis_patient FROM diagnosis WHERE diagnosis_id = NEW.diagnosis_id;
-
-    IF v_record_patient IS NULL THEN
-        RAISE EXCEPTION 'Medical record % not found', NEW.record_id;
-    END IF;
-
-    IF v_diagnosis_patient IS NULL THEN
-        RAISE EXCEPTION 'Diagnosis % not found', NEW.diagnosis_id;
-    END IF;
-
-    IF v_record_patient <> v_diagnosis_patient THEN
-        RAISE EXCEPTION 'Diagnosis % belongs to patient %, but medical record % belongs to patient %',
-            NEW.diagnosis_id, v_diagnosis_patient, NEW.record_id, v_record_patient;
-    END IF;
-
-    RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trg_diagnosis_record_consistency ON diagnosis_medical_records;
-CREATE TRIGGER trg_diagnosis_record_consistency
-    BEFORE INSERT ON diagnosis_medical_records
-    FOR EACH ROW EXECUTE FUNCTION t1_diagnosis_record_consistency();
-
-CREATE OR REPLACE FUNCTION t2_procedure_diagnosis_consistency()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-DECLARE
-    v_diagnosis_patient BIGINT;
-BEGIN
-    IF NEW.diagnosis_id IS NOT NULL THEN
-        SELECT patient_id INTO v_diagnosis_patient FROM diagnosis WHERE diagnosis_id = NEW.diagnosis_id;
-
-        IF v_diagnosis_patient IS NULL THEN
-            RAISE EXCEPTION 'Diagnosis % not found', NEW.diagnosis_id;
-        END IF;
-
-        IF NEW.patient_id <> v_diagnosis_patient THEN
-            RAISE EXCEPTION 'Procedure belongs to patient %, but diagnosis % belongs to patient %',
-                NEW.patient_id, NEW.diagnosis_id, v_diagnosis_patient;
-        END IF;
-    END IF;
-
-    RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trg_procedure_diagnosis_consistency ON performed_procedures;
-CREATE TRIGGER trg_procedure_diagnosis_consistency
-    BEFORE INSERT OR UPDATE ON performed_procedures
-                         FOR EACH ROW EXECUTE FUNCTION t2_procedure_diagnosis_consistency();
-
-CREATE OR REPLACE FUNCTION t3_referral_consistency()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-BEGIN
-    IF NOT EXISTS (SELECT 1 FROM medical_records WHERE record_id = NEW.record_id) THEN
-        RAISE EXCEPTION 'Medical record % not found', NEW.record_id;
-    END IF;
-
-    IF NEW.from_doctor_id = NEW.to_doctor_id THEN
-        RAISE EXCEPTION 'Doctor % cannot refer to themselves', NEW.from_doctor_id;
-    END IF;
-
-    RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trg_referral_consistency ON referrals;
-CREATE TRIGGER trg_referral_consistency
-    BEFORE INSERT ON referrals
-    FOR EACH ROW EXECUTE FUNCTION t3_referral_consistency();
-
-CREATE OR REPLACE VIEW v_medical_record_overview AS
-SELECT
-    mr.record_id,
-    p.patient_id, p.first_name, p.last_name, p.embg,
-    COUNT(DISTINCT dmr.diagnosis_id) AS diagnosis_count,
-    COUNT(DISTINCT CASE WHEN d.patient_id IS NOT NULL AND d.patient_id <> p.patient_id THEN dmr.diagnosis_id END) AS diagnosis_mismatches,
-    COUNT(DISTINCT mrp.procedure_id) AS procedures_count,
-    COUNT(DISTINCT mrl.result_id) AS lab_results_count,
-    COUNT(DISTINCT ref.referral_id) AS referrals_count,
-    COUNT(DISTINCT mra.allergy_id) AS allergies_count,
-    COUNT(DISTINCT CASE WHEN ref.from_doctor_id = ref.to_doctor_id THEN ref.referral_id END) AS self_referrals_detected
-FROM medical_records mr
-    JOIN patients p ON mr.patient_id = p.patient_id
-    LEFT JOIN diagnosis_medical_records dmr ON dmr.record_id = mr.record_id
-    LEFT JOIN diagnosis d ON d.diagnosis_id = dmr.diagnosis_id
-    LEFT JOIN medical_record_procedures mrp ON mrp.record_id = mr.record_id
-    LEFT JOIN medical_record_lab_results mrl ON mrl.record_id = mr.record_id
-    LEFT JOIN referrals ref ON mr.record_id = ref.record_id
-    LEFT JOIN medical_record_allergies mra ON mr.record_id = mra.record_id
-GROUP BY mr.record_id, p.patient_id, p.first_name, p.last_name, p.embg;
Index: ckend/src/main/resources/db.migration/V1.1__Create_Daily_Billing_View.sql
===================================================================
--- backend/src/main/resources/db.migration/V1.1__Create_Daily_Billing_View.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,28 +1,0 @@
--- Create materialized view for daily patient billing totals
-CREATE MATERIALIZED VIEW IF NOT EXISTS daily_patient_billing_totals AS
-SELECT
-    p.patient_id,
-    CAST(pp.procedure_date AS DATE) as service_date,
-    COALESCE(SUM(pr.cost), 0) as procedure_cost,
-    0::decimal as lab_test_cost,
-    COALESCE(SUM(pr.cost), 0) as total_cost
-FROM patients p
-LEFT JOIN performed_procedures pp ON p.patient_id = pp.patient_id
-LEFT JOIN procedures pr ON pp.procedure_id = pr.procedure_id
-GROUP BY p.patient_id, CAST(pp.procedure_date AS DATE)
-
-UNION ALL
-
-SELECT
-    p.patient_id,
-    CAST(plt.test_date AS DATE) as service_date,
-    0::decimal as procedure_cost,
-    COALESCE(SUM(lt.cost), 0) as lab_test_cost,
-    COALESCE(SUM(lt.cost), 0) as total_cost
-FROM patients p
-LEFT JOIN performed_lab_tests plt ON p.patient_id = plt.patient_id
-LEFT JOIN lab_tests lt ON plt.test_id = lt.test_id
-GROUP BY p.patient_id, CAST(plt.test_date AS DATE);
-
--- Create index for better query performance
-CREATE INDEX IF NOT EXISTS idx_daily_billing_patient_date ON daily_patient_billing_totals(patient_id, service_date);
Index: ckend/src/main/resources/db.migration/V1.2__Create_Users_Table.sql
===================================================================
--- backend/src/main/resources/db.migration/V1.2__Create_Users_Table.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,33 +1,0 @@
-user
--- Create users table
-CREATE TABLE IF NOT EXISTS users (
-    user_id SERIAL PRIMARY KEY,
-    username VARCHAR(255) NOT NULL UNIQUE,
-    password VARCHAR(255) NOT NULL,
-    role VARCHAR(50) NOT NULL,
-    first_name VARCHAR(100),
-    last_name VARCHAR(100),
-    patient_id BIGINT,
-    doctor_id BIGINT,
-    is_active BOOLEAN DEFAULT true,
-    FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
-    FOREIGN KEY (doctor_id) REFERENCES doctors(doctor_id)
-);
-
--- Create index for username lookup
-CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
-
--- Insert admin user (password: admin123)
-INSERT INTO users (username, password, role, first_name, last_name, is_active)
-VALUES ('admin', 'admin123', 'ADMIN', 'System', 'Administrator', true)
-ON CONFLICT (username) DO NOTHING;
-
--- Insert sample patient users (password: password123 for all)
--- These will be linked to existing patients by EMBG
-INSERT INTO users (username, password, role, first_name, last_name, patient_id, is_active)
-SELECT p.embg, 'password123', 'PATIENT', p.first_name, p.last_name, p.patient_id, true
-FROM patients p
-WHERE NOT EXISTS (
-    SELECT 1 FROM users u WHERE u.username = p.embg
-)
-LIMIT 39;
Index: ckend/src/main/resources/db.migration/V2__Add_appointment_fields_to_referrals.sql
===================================================================
--- backend/src/main/resources/db.migration/V2__Add_appointment_fields_to_referrals.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,7 +1,0 @@
--- Add appointment_date and appointment_time columns to referrals table
-ALTER TABLE referrals ADD COLUMN IF NOT EXISTS appointment_date DATE;
-ALTER TABLE referrals ADD COLUMN IF NOT EXISTS appointment_time TIME;
-
--- Set default values for existing rows
-UPDATE referrals SET appointment_date = referral_date + INTERVAL '1 day', appointment_time = '10:00:00'
-WHERE appointment_date IS NULL;
Index: ckend/src/main/resources/db.migration/V3__Insert_Doctor_Users.sql
===================================================================
--- backend/src/main/resources/db.migration/V3__Insert_Doctor_Users.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,8 +1,0 @@
--- Insert Doctor users from doctors table
-INSERT INTO users (username, password, role, first_name, last_name, doctor_id, is_active)
-SELECT d.email_address, 'doctor123', 'DOCTOR', d.first_name, d.last_name, d.doctor_id, true
-FROM doctors d
-WHERE NOT EXISTS (
-    SELECT 1 FROM users u WHERE u.username = d.email_address
-)
-ON CONFLICT (username) DO NOTHING;
Index: ckend/src/main/resources/db.migration/V4__Insert_Lab_Technician_Users.sql
===================================================================
--- backend/src/main/resources/db.migration/V4__Insert_Lab_Technician_Users.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,9 +1,0 @@
--- Insert Lab Technician users
-INSERT INTO users (username, password, role, first_name, last_name, is_active)
-VALUES
-  ('lab_darko', 'lab123', 'LAB_TECHNICIAN', 'Darko', 'Milosev', true),
-  ('lab_biljana', 'lab123', 'LAB_TECHNICIAN', 'Biljana', 'Trajkovska', true),
-  ('lab_stefan', 'lab123', 'LAB_TECHNICIAN', 'Stefan', 'Nikolovski', true),
-  ('lab_marina', 'lab123', 'LAB_TECHNICIAN', 'Marina', 'Petreska', true),
-  ('lab_aleksandar', 'lab123', 'LAB_TECHNICIAN', 'Aleksandar', 'Ristovski', true)
-ON CONFLICT (username) DO NOTHING;
Index: ckend/src/main/resources/db.migration/V5__Insert_Billing_Admin_Users.sql
===================================================================
--- backend/src/main/resources/db.migration/V5__Insert_Billing_Admin_Users.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,16 +1,0 @@
--- Insert Billing Admin users
-INSERT INTO users (username, password, role, first_name, last_name, is_active)
-SELECT 'admin_ilija', 'adminmedora123', 'BILLING_ADMIN', 'Ilija', 'Admin', true
-WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin_ilija')
-UNION ALL
-SELECT 'admin_elena', 'adminmedora123', 'BILLING_ADMIN', 'Elena', 'Admin', true
-WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin_elena')
-UNION ALL
-SELECT 'admin_marjan', 'adminmedora123', 'BILLING_ADMIN', 'Marjan', 'Admin', true
-WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin_marjan')
-UNION ALL
-SELECT 'admin_vesna', 'adminmedora123', 'BILLING_ADMIN', 'Vesna', 'Admin', true
-WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin_vesna')
-UNION ALL
-SELECT 'admin_dushanka', 'adminmedora123', 'BILLING_ADMIN', 'Dushanka', 'Admin', true
-WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin_dushanka');
Index: ckend/src/main/resources/db.migration/V6__Insert_Billing_Admin_Users.sql
===================================================================
--- backend/src/main/resources/db.migration/V6__Insert_Billing_Admin_Users.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,28 +1,0 @@
-SELECT
-    plt.performed_test_id,
-    lt.test_name,
-    u_p.first_name AS patient_first_name,
-    u_p.last_name AS patient_last_name,
-    u_d.first_name AS doctor_first_name,
-    u_d.last_name AS doctor_last_name,
-    plt.test_date,
-    plt.notes
-FROM performed_lab_tests plt
-         JOIN lab_tests lt ON plt.test_id = lt.test_id
-         JOIN patients p ON plt.patient_id = p.patient_id
-         JOIN users u_p ON p.patient_id = u_p.patient_id
-         JOIN doctors d ON plt.doctor_id = d.doctor_id
-         JOIN users u_d ON d.doctor_id = u_d.doctor_id;
-
-SELECT
-    lt.test_id,
-    lt.test_name,
-    lt.description,
-    lt.cost,
-    plt.test_date,
-    plt.notes
-FROM lab_tests lt
-         JOIN performed_lab_tests plt ON lt.test_id = plt.test_id
-WHERE plt.patient_id = 4 AND plt.test_date = '2026-06-16';
-
-
Index: ckend/src/main/resources/db.migration/V7__Update_Billing_Admin_Names.sql
===================================================================
--- backend/src/main/resources/db.migration/V7__Update_Billing_Admin_Names.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,1 +1,0 @@
-
Index: ckend/src/main/resources/db.migration/V8__appointment_scheduling_integrity.sql
===================================================================
--- backend/src/main/resources/db.migration/V8__appointment_scheduling_integrity.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,133 +1,0 @@
--- schema change: NO_SHOW must be added to the existing status constraint before
--- anything below can ever set it
-ALTER TABLE appointments DROP CONSTRAINT appointments_status_chk;
-ALTER TABLE appointments ADD CONSTRAINT appointments_status_chk
-    CHECK (status IN ('SCHEDULED','COMPLETED','CANCELLED','IN_PROGRESS','NO_SHOW'));
-
--- No generated column needed - we'll compute the time ranges directly in the triggers
--- This approach is simpler and avoids immutability constraints
-
-CREATE OR REPLACE FUNCTION is_valid_appointment_transition(p_old TEXT, p_new TEXT)
-RETURNS BOOLEAN
-LANGUAGE sql
-IMMUTABLE
-AS $$
-SELECT CASE
-           WHEN p_old = p_new THEN TRUE
-           WHEN p_old = 'SCHEDULED'    AND p_new IN ('IN_PROGRESS', 'COMPLETED', 'CANCELLED') THEN TRUE
-           WHEN p_old = 'IN_PROGRESS'  AND p_new IN ('COMPLETED', 'CANCELLED') THEN TRUE
-           ELSE FALSE
-           END;
-$$;
-
-CREATE OR REPLACE FUNCTION trigger_appointments_enforce()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-DECLARE
-    v_combined_datetime TIMESTAMP;
-BEGIN
-    v_combined_datetime := NEW.appointment_date::TIMESTAMP + NEW.appointment_time;
-
-    IF TG_OP = 'INSERT' AND v_combined_datetime < NOW() THEN
-        RAISE EXCEPTION 'Cannot schedule appointment in the past (appointment_date=%, appointment_time=%)',
-            NEW.appointment_date, NEW.appointment_time;
-    END IF;
-
-    IF TG_OP = 'UPDATE' THEN
-        IF NOT is_valid_appointment_transition(OLD.status, NEW.status) THEN
-            RAISE EXCEPTION 'Appointment status cannot transition from % to %',
-                OLD.status, NEW.status;
-        END IF;
-
-        IF NEW.status = 'COMPLETED' AND v_combined_datetime > NOW() THEN
-            RAISE EXCEPTION 'Cannot mark appointment COMPLETED before its scheduled time (scheduled for %)',
-                v_combined_datetime;
-        END IF;
-    END IF;
-
-    RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trigger_appointments_enforce ON appointments;
-CREATE TRIGGER trigger_appointments_enforce
-    BEFORE INSERT OR UPDATE
-                         ON appointments
-                         FOR EACH ROW
-                         EXECUTE FUNCTION trigger_appointments_enforce();
-
-CREATE OR REPLACE FUNCTION t1_appointments_no_overlap()
-RETURNS TRIGGER
-LANGUAGE plpgsql
-AS $$
-DECLARE
-    v_new_start TIMESTAMP;
-    v_new_end TIMESTAMP;
-BEGIN
-    IF NEW.status NOT IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED') THEN
-        RETURN NEW;
-    END IF;
-
-    v_new_start := NEW.appointment_date::TIMESTAMP + NEW.appointment_time;
-    v_new_end := v_new_start + INTERVAL '30 minutes';
-
-    -- Check for doctor double-booking
-    -- Overlap condition: existing_start < new_end AND new_start < existing_end
-    IF EXISTS (
-        SELECT 1 FROM appointments a
-        WHERE a.doctor_id = NEW.doctor_id
-          AND a.status IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED')
-          AND (a.appointment_date::TIMESTAMP + a.appointment_time) < v_new_end
-          AND v_new_start < (a.appointment_date::TIMESTAMP + a.appointment_time + INTERVAL '30 minutes')
-          AND (TG_OP <> 'UPDATE' OR a.appointment_id <> NEW.appointment_id)
-    ) THEN
-        RAISE EXCEPTION 'Doctor % has overlapping appointment at %', NEW.doctor_id, NEW.appointment_date;
-    END IF;
-
-    -- Check for patient double-booking
-    IF EXISTS (
-        SELECT 1 FROM appointments a
-        WHERE a.patient_id = NEW.patient_id
-          AND a.status IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED')
-          AND (a.appointment_date::TIMESTAMP + a.appointment_time) < v_new_end
-          AND v_new_start < (a.appointment_date::TIMESTAMP + a.appointment_time + INTERVAL '30 minutes')
-          AND (TG_OP <> 'UPDATE' OR a.appointment_id <> NEW.appointment_id)
-    ) THEN
-        RAISE EXCEPTION 'Patient % has overlapping appointment at %', NEW.patient_id, NEW.appointment_date;
-    END IF;
-
-    RETURN NEW;
-END;
-$$;
-
-DROP TRIGGER IF EXISTS trigger_appointments_no_overlap ON appointments;
-CREATE TRIGGER trigger_appointments_no_overlap
-    BEFORE INSERT OR UPDATE
-                         ON appointments
-                         FOR EACH ROW
-                         EXECUTE FUNCTION t1_appointments_no_overlap();
-
-CREATE OR REPLACE PROCEDURE job_mark_no_show()
-LANGUAGE plpgsql
-AS $$
-BEGIN
-    UPDATE appointments
-    SET status = 'NO_SHOW'
-    WHERE status = 'SCHEDULED'
-      AND (appointment_date::TIMESTAMP + appointment_time) < (NOW() - INTERVAL '45 minutes');
-END;
-$$;
-
-CREATE OR REPLACE VIEW v_overdue_appointments AS
-SELECT
-    a.appointment_id, a.patient_id, p.first_name, p.last_name,
-    a.doctor_id, d.first_name AS doctor_first_name, d.last_name AS doctor_last_name,
-    a.appointment_date, a.appointment_time, a.status,
-    NOW() - (a.appointment_date::TIMESTAMP + a.appointment_time) AS time_overdue
-FROM appointments a
-         JOIN patients p ON a.patient_id = p.patient_id
-         JOIN doctors d ON a.doctor_id = d.doctor_id
-WHERE a.status = 'SCHEDULED'
-  AND (a.appointment_date::TIMESTAMP + a.appointment_time) < (NOW() - INTERVAL '45 minutes')
-ORDER BY time_overdue DESC;
Index: ckend/src/main/resources/db.migration/V9__mv_revenue_reporting.sql
===================================================================
--- backend/src/main/resources/db.migration/V9__mv_revenue_reporting.sql	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,60 +1,0 @@
--- Revenue reporting: monthly revenue, split by procedure vs. lab test.
--- Procedure revenue is attributed to a department, since `procedures` carries a
--- doctor_id directly on the catalog row. Lab revenue cannot be attributed to a
--- department: lab_tests has no doctor/department reference at all, and
--- billing_lab_tests links only to the catalog test_id, not to a specific performed
--- instance, so there is no reliable way to know which doctor/department administered
--- a billed test. Lab rows are reported at clinic-wide monthly granularity only
--- (department_id/department_name are NULL for those rows).
-
-CREATE MATERIALIZED VIEW mv_revenue_monthly AS
-SELECT
-    DATE_TRUNC('month', b.payment_date)::DATE AS month,
-    dept.department_id,
-    dept.department_name,
-    'PROCEDURE' AS revenue_type,
-    SUM(p.cost) AS revenue,
-    COUNT(DISTINCT b.bill_id) AS transaction_count
-FROM billing b
-         JOIN billing_procedures bp ON bp.bill_id = b.bill_id
-         JOIN procedures p ON p.procedure_id = bp.procedure_id
-         JOIN doctors doc ON doc.doctor_id = p.doctor_id
-         JOIN departments dept ON dept.department_id = doc.department_id
-WHERE b.payment_status = 'PAID'
-GROUP BY DATE_TRUNC('month', b.payment_date), dept.department_id, dept.department_name
-
-UNION ALL
-
-SELECT
-    DATE_TRUNC('month', b.payment_date)::DATE AS month,
-    NULL AS department_id,
-    NULL AS department_name,
-    'LAB' AS revenue_type,
-    SUM(lt.cost) AS revenue,
-    COUNT(DISTINCT b.bill_id) AS transaction_count
-FROM billing b
-         JOIN billing_lab_tests blt ON blt.bill_id = b.bill_id
-         JOIN lab_tests lt ON lt.test_id = blt.test_id
-WHERE b.payment_status = 'PAID'
-GROUP BY DATE_TRUNC('month', b.payment_date);
-
-CREATE INDEX idx_mv_revenue_monthly_month ON mv_revenue_monthly (month, revenue_type);
-
--- Background job: recomputes the materialized view. Designed to be invoked
--- periodically (nightly) via pg_cron, OS-level cron, or an external scheduler.
--- pg_cron was not available in this hosting environment to test automatic
--- scheduling directly, so this procedure is verified by manual invocation:
---   CALL medora_job_refresh_revenue_view();
-CREATE OR REPLACE PROCEDURE medora_job_refresh_revenue_view()
-    LANGUAGE plpgsql
-AS $$
-BEGIN
-    REFRESH MATERIALIZED VIEW mv_revenue_monthly;
-END;
-$$;
-
-CREATE OR REPLACE VIEW v_current_month_revenue AS
-SELECT month, department_id, department_name, revenue_type, revenue, transaction_count
-FROM mv_revenue_monthly
-WHERE month = DATE_TRUNC('month', CURRENT_DATE)::DATE
-ORDER BY revenue_type, revenue DESC;
Index: backend/src/main/resources/db/migration/R__allergy_prescription_safety_enforcement.sql
===================================================================
--- backend/src/main/resources/db/migration/R__allergy_prescription_safety_enforcement.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/R__allergy_prescription_safety_enforcement.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,85 @@
+CREATE DOMAIN non_negative_currency AS DECIMAL(12,2)
+    CHECK (VALUE >= 0);
+
+CREATE OR REPLACE FUNCTION t1_prescription_allergy_check()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    v_patient_id BIGINT;
+    v_conflict_allergy_id BIGINT;
+    v_allergy_name TEXT;
+BEGIN
+    SELECT patient_id INTO v_patient_id
+    FROM medical_records
+    WHERE record_id = NEW.record_id;
+
+    IF v_patient_id IS NULL THEN
+        RAISE EXCEPTION 'Medical record % not found', NEW.record_id;
+    END IF;
+
+    SELECT apr.allergy_id, a.name
+    INTO v_conflict_allergy_id, v_allergy_name
+    FROM prescription_restriction pr_rest
+    JOIN allergy_prescription_restrictions apr ON apr.restriction_id = pr_rest.restriction_id
+    JOIN allergies a ON apr.allergy_id = a.allergy_id
+    JOIN medical_record_allergies mra ON a.allergy_id = mra.allergy_id
+    WHERE pr_rest.prescription_id = NEW.prescription_id
+    AND mra.record_id = NEW.record_id
+    LIMIT 1;
+
+    IF v_conflict_allergy_id IS NOT NULL THEN
+        RAISE EXCEPTION 'PRESCRIPTION_ALLERGY_CONFLICT: Prescription % conflicts with allergy % (%) in patient''s record %',
+            NEW.prescription_id, v_conflict_allergy_id, v_allergy_name, NEW.record_id;
+    END IF;
+
+    RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trg_prescription_allergy_check ON prescription_medical_records;
+CREATE TRIGGER trg_prescription_allergy_check
+    BEFORE INSERT
+    ON prescription_medical_records
+    FOR EACH ROW
+    EXECUTE FUNCTION t1_prescription_allergy_check();
+
+CREATE TABLE IF NOT EXISTS prescription_allergy_conflicts_log (
+    log_id BIGSERIAL PRIMARY KEY,
+    record_id BIGINT NOT NULL REFERENCES medical_records(record_id),
+    prescription_id BIGINT NOT NULL REFERENCES prescriptions(prescription_id),
+    allergy_id BIGINT NOT NULL REFERENCES allergies(allergy_id),
+    conflict_type TEXT CHECK (conflict_type IN ('ACTIVE', 'RESOLVED')),
+    detected_date TIMESTAMP DEFAULT NOW(),
+    resolution_notes TEXT,
+    resolved_date TIMESTAMP
+);
+
+CREATE OR REPLACE VIEW v_prescription_allergy_conflicts AS
+SELECT
+    mr.record_id,
+    p.patient_id,
+    p.first_name,
+    p.last_name,
+    pmr.prescription_id,
+    pr.medication_name,
+    a.allergy_id,
+    a.name AS allergy_name,
+    a.allergy_severity,
+    apr.restriction_id,
+    pr_rest.description AS restriction_description,
+    CASE
+        WHEN mra.record_id IS NOT NULL THEN 'ACTIVE_CONFLICT'
+        ELSE 'ARCHIVED'
+    END AS conflict_status
+FROM prescription_medical_records pmr
+JOIN medical_records mr ON pmr.record_id = mr.record_id
+JOIN patients p ON mr.patient_id = p.patient_id
+JOIN prescriptions pr ON pmr.prescription_id = pr.prescription_id
+JOIN prescription_restriction pr_rest ON pr.prescription_id = pr_rest.prescription_id
+JOIN allergy_prescription_restrictions apr ON pr_rest.restriction_id = apr.restriction_id
+JOIN allergies a ON apr.allergy_id = a.allergy_id
+LEFT JOIN medical_record_allergies mra ON mr.record_id = mra.record_id
+    AND a.allergy_id = mra.allergy_id
+WHERE a.allergy_severity IN ('HIGH', 'CRITICAL')
+ORDER BY p.patient_id, a.allergy_severity DESC;
Index: backend/src/main/resources/db/migration/R__billing_integrity.sql
===================================================================
--- backend/src/main/resources/db/migration/R__billing_integrity.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/R__billing_integrity.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,145 @@
+-- schema addition: billing had no "issued" date, only payment_date (populated only once
+-- paid), so there was no way to measure how long a still-PENDING bill has been outstanding.
+-- Existing rows will backfill to NOW() at ALTER time, which is not historically accurate —
+-- acceptable for this project, but worth noting.
+ALTER TABLE billing ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT NOW();
+
+CREATE TABLE IF NOT EXISTS billing_audit_log (
+                                                 audit_id BIGSERIAL PRIMARY KEY,
+                                                 bill_id BIGINT NOT NULL REFERENCES billing(bill_id),
+    old_amount DECIMAL(12,2),
+    new_amount DECIMAL(12,2),
+    old_status TEXT,
+    new_status TEXT,
+    change_type TEXT CHECK (change_type IN ('INSERT', 'UPDATE', 'LINE_ITEM_ADD', 'LINE_ITEM_REMOVE')),
+    changed_at TIMESTAMP DEFAULT NOW()
+    );
+
+-- Note: billing_procedures links to the catalog procedure_id, not to a specific
+-- performed_procedures row, so when the same procedure type has been performed on more
+-- than one patient there is no reliable way to verify a billed line item belongs to the
+-- same patient as the bill. That check is intentionally left out rather than implemented
+-- unreliably.
+
+CREATE OR REPLACE FUNCTION recalculate_billing_total(p_bill_id BIGINT, p_change_type TEXT)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+v_procedure_total DECIMAL;
+    v_lab_total DECIMAL;
+    v_new_total DECIMAL;
+BEGIN
+SELECT COALESCE(SUM(p.cost), 0) INTO v_procedure_total
+FROM billing_procedures bp
+         JOIN procedures p ON p.procedure_id = bp.procedure_id
+WHERE bp.bill_id = p_bill_id;
+
+SELECT COALESCE(SUM(lt.cost), 0) INTO v_lab_total
+FROM billing_lab_tests blt
+         JOIN lab_tests lt ON lt.test_id = blt.test_id
+WHERE blt.bill_id = p_bill_id;
+
+v_new_total := v_procedure_total + v_lab_total;
+
+UPDATE billing SET total_cost = v_new_total WHERE bill_id = p_bill_id;
+
+INSERT INTO billing_audit_log (bill_id, new_amount, change_type)
+VALUES (p_bill_id, v_new_total, p_change_type);
+END;
+$$;
+
+-- one shared trigger function, reused for both billing_procedures and billing_lab_tests
+-- (both tables have a bill_id column, so NEW.bill_id / OLD.bill_id works either way)
+CREATE OR REPLACE FUNCTION t1_billing_line_item_changed()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+BEGIN
+    IF TG_OP = 'DELETE' THEN
+        PERFORM recalculate_billing_total(OLD.bill_id, 'LINE_ITEM_REMOVE');
+RETURN OLD;
+ELSE
+        PERFORM recalculate_billing_total(NEW.bill_id, 'LINE_ITEM_ADD');
+RETURN NEW;
+END IF;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trg_billing_procedures_update_total ON billing_procedures;
+CREATE TRIGGER trg_billing_procedures_update_total
+    AFTER INSERT OR DELETE ON billing_procedures
+FOR EACH ROW
+EXECUTE FUNCTION t1_billing_line_item_changed();
+
+DROP TRIGGER IF EXISTS trg_billing_lab_tests_update_total ON billing_lab_tests;
+CREATE TRIGGER trg_billing_lab_tests_update_total
+    AFTER INSERT OR DELETE ON billing_lab_tests
+FOR EACH ROW
+EXECUTE FUNCTION t1_billing_line_item_changed();
+
+CREATE OR REPLACE FUNCTION is_valid_billing_transition(p_old TEXT, p_new TEXT)
+RETURNS BOOLEAN
+LANGUAGE sql
+IMMUTABLE
+AS $$
+SELECT CASE
+           WHEN p_old = p_new THEN TRUE
+           WHEN p_old = 'PENDING' AND p_new IN ('PAID', 'CANCELLED') THEN TRUE
+           ELSE FALSE
+           END;
+$$;
+
+CREATE OR REPLACE FUNCTION t2_billing_status_transition()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+BEGIN
+    IF NOT is_valid_billing_transition(OLD.payment_status, NEW.payment_status) THEN
+        RAISE EXCEPTION 'Cannot transition billing status from % to %',
+            OLD.payment_status, NEW.payment_status;
+END IF;
+
+    IF OLD.payment_status <> NEW.payment_status THEN
+        INSERT INTO billing_audit_log (bill_id, old_status, new_status, change_type)
+        VALUES (NEW.bill_id, OLD.payment_status, NEW.payment_status, 'UPDATE');
+END IF;
+
+RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trg_billing_status_transition ON billing;
+CREATE TRIGGER trg_billing_status_transition
+    BEFORE UPDATE ON billing
+    FOR EACH ROW
+    EXECUTE FUNCTION t2_billing_status_transition();
+
+CREATE OR REPLACE VIEW v_overdue_billings AS
+SELECT
+    b.bill_id,
+    p.patient_id, p.first_name, p.last_name,
+    b.total_cost, b.payment_status, b.created_at,
+    CURRENT_DATE - b.created_at::DATE AS days_outstanding,
+        CASE
+            WHEN CURRENT_DATE - b.created_at::DATE > 60 THEN 'CRITICAL'
+        WHEN CURRENT_DATE - b.created_at::DATE > 30 THEN 'OVERDUE'
+        ELSE 'PENDING'
+END AS urgency
+FROM billing b
+JOIN medical_records mr ON b.record_id = mr.record_id
+JOIN patients p ON mr.patient_id = p.patient_id
+WHERE b.payment_status = 'PENDING'
+  AND CURRENT_DATE - b.created_at::DATE >= 30
+ORDER BY days_outstanding DESC;
+
+CREATE OR REPLACE PROCEDURE job_billing_alerts()
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    v_overdue_count INT;
+BEGIN
+    SELECT COUNT(*) INTO v_overdue_count FROM v_overdue_billings WHERE days_outstanding > 30;
+    RAISE NOTICE 'Found % overdue billing records requiring follow-up', v_overdue_count;
+END;
+$$;
Index: backend/src/main/resources/db/migration/R__create_scoped_app_role.sql
===================================================================
--- backend/src/main/resources/db/migration/R__create_scoped_app_role.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/R__create_scoped_app_role.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,35 @@
+-- Create scoped application role with limited privileges
+-- Run this as the postgres superuser once, then update application.properties
+-- to connect as medora_app instead of postgres
+
+-- Step 1: Create the scoped application user
+-- WARNING: Change the password to something strong and unique before running!
+-- This example uses a placeholder — use: openssl rand -base64 32
+-- DO NOT commit the actual password to source control
+CREATE USER medora_app WITH PASSWORD 'CHANGE_ME_TO_A_STRONG_PASSWORD';
+
+-- Step 2: Grant connection and usage privileges
+GRANT CONNECT ON DATABASE medora TO medora_app;
+GRANT USAGE ON SCHEMA public TO medora_app;
+
+-- Step 3: Grant data manipulation privileges (CRUD only, no DDL)
+GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO medora_app;
+GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO medora_app;
+
+-- Step 4: Ensure future tables (created by migrations) automatically grant permissions
+ALTER DEFAULT PRIVILEGES IN SCHEMA public
+GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO medora_app;
+
+ALTER DEFAULT PRIVILEGES IN SCHEMA public
+GRANT USAGE ON SEQUENCES TO medora_app;
+
+-- Verification queries (run as medora_app to confirm access):
+-- SELECT * FROM patients LIMIT 1;  -- should work
+-- CREATE TABLE test (id INT);       -- should fail (not permitted)
+-- DROP TABLE patients;              -- should fail (not permitted)
+
+-- After confirming this works:
+-- 1. Update application.properties: spring.datasource.username=medora_app
+-- 2. Update application.properties: spring.datasource.password=${DB_PASSWORD}
+-- 3. Set environment variable: export DB_PASSWORD='<the password you chose>'
+-- 4. Restart the application
Index: backend/src/main/resources/db/migration/R__custom_domains.sql
===================================================================
--- backend/src/main/resources/db/migration/R__custom_domains.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/R__custom_domains.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,14 @@
+CREATE DOMAIN embg_format AS TEXT
+    CHECK (VALUE ~ '^\d{13}$');
+
+CREATE DOMAIN email_format AS TEXT
+    CHECK (
+        VALUE ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
+        AND LENGTH(VALUE) <= 254
+    );
+
+CREATE DOMAIN phone_number_format AS TEXT
+    CHECK (VALUE ~ '^\+?[\d\s\-().]{7,20}$');
+
+CREATE DOMAIN non_negative_cost AS DECIMAL(12,2)
+    CHECK (VALUE >= 0);
Index: backend/src/main/resources/db/migration/R__medical_record_integrity.sql
===================================================================
--- backend/src/main/resources/db/migration/R__medical_record_integrity.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/R__medical_record_integrity.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,104 @@
+CREATE OR REPLACE FUNCTION t1_diagnosis_record_consistency()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    v_record_patient BIGINT;
+    v_diagnosis_patient BIGINT;
+BEGIN
+    SELECT patient_id INTO v_record_patient FROM medical_records WHERE record_id = NEW.record_id;
+    SELECT patient_id INTO v_diagnosis_patient FROM diagnosis WHERE diagnosis_id = NEW.diagnosis_id;
+
+    IF v_record_patient IS NULL THEN
+        RAISE EXCEPTION 'Medical record % not found', NEW.record_id;
+    END IF;
+
+    IF v_diagnosis_patient IS NULL THEN
+        RAISE EXCEPTION 'Diagnosis % not found', NEW.diagnosis_id;
+    END IF;
+
+    IF v_record_patient <> v_diagnosis_patient THEN
+        RAISE EXCEPTION 'Diagnosis % belongs to patient %, but medical record % belongs to patient %',
+            NEW.diagnosis_id, v_diagnosis_patient, NEW.record_id, v_record_patient;
+    END IF;
+
+    RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trg_diagnosis_record_consistency ON diagnosis_medical_records;
+CREATE TRIGGER trg_diagnosis_record_consistency
+    BEFORE INSERT ON diagnosis_medical_records
+    FOR EACH ROW EXECUTE FUNCTION t1_diagnosis_record_consistency();
+
+CREATE OR REPLACE FUNCTION t2_procedure_diagnosis_consistency()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    v_diagnosis_patient BIGINT;
+BEGIN
+    IF NEW.diagnosis_id IS NOT NULL THEN
+        SELECT patient_id INTO v_diagnosis_patient FROM diagnosis WHERE diagnosis_id = NEW.diagnosis_id;
+
+        IF v_diagnosis_patient IS NULL THEN
+            RAISE EXCEPTION 'Diagnosis % not found', NEW.diagnosis_id;
+        END IF;
+
+        IF NEW.patient_id <> v_diagnosis_patient THEN
+            RAISE EXCEPTION 'Procedure belongs to patient %, but diagnosis % belongs to patient %',
+                NEW.patient_id, NEW.diagnosis_id, v_diagnosis_patient;
+        END IF;
+    END IF;
+
+    RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trg_procedure_diagnosis_consistency ON performed_procedures;
+CREATE TRIGGER trg_procedure_diagnosis_consistency
+    BEFORE INSERT OR UPDATE ON performed_procedures
+                         FOR EACH ROW EXECUTE FUNCTION t2_procedure_diagnosis_consistency();
+
+CREATE OR REPLACE FUNCTION t3_referral_consistency()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+BEGIN
+    IF NOT EXISTS (SELECT 1 FROM medical_records WHERE record_id = NEW.record_id) THEN
+        RAISE EXCEPTION 'Medical record % not found', NEW.record_id;
+    END IF;
+
+    IF NEW.from_doctor_id = NEW.to_doctor_id THEN
+        RAISE EXCEPTION 'Doctor % cannot refer to themselves', NEW.from_doctor_id;
+    END IF;
+
+    RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trg_referral_consistency ON referrals;
+CREATE TRIGGER trg_referral_consistency
+    BEFORE INSERT ON referrals
+    FOR EACH ROW EXECUTE FUNCTION t3_referral_consistency();
+
+CREATE OR REPLACE VIEW v_medical_record_overview AS
+SELECT
+    mr.record_id,
+    p.patient_id, p.first_name, p.last_name, p.embg,
+    COUNT(DISTINCT dmr.diagnosis_id) AS diagnosis_count,
+    COUNT(DISTINCT CASE WHEN d.patient_id IS NOT NULL AND d.patient_id <> p.patient_id THEN dmr.diagnosis_id END) AS diagnosis_mismatches,
+    COUNT(DISTINCT mrp.procedure_id) AS procedures_count,
+    COUNT(DISTINCT mrl.result_id) AS lab_results_count,
+    COUNT(DISTINCT ref.referral_id) AS referrals_count,
+    COUNT(DISTINCT mra.allergy_id) AS allergies_count,
+    COUNT(DISTINCT CASE WHEN ref.from_doctor_id = ref.to_doctor_id THEN ref.referral_id END) AS self_referrals_detected
+FROM medical_records mr
+    JOIN patients p ON mr.patient_id = p.patient_id
+    LEFT JOIN diagnosis_medical_records dmr ON dmr.record_id = mr.record_id
+    LEFT JOIN diagnosis d ON d.diagnosis_id = dmr.diagnosis_id
+    LEFT JOIN medical_record_procedures mrp ON mrp.record_id = mr.record_id
+    LEFT JOIN medical_record_lab_results mrl ON mrl.record_id = mr.record_id
+    LEFT JOIN referrals ref ON mr.record_id = ref.record_id
+    LEFT JOIN medical_record_allergies mra ON mr.record_id = mra.record_id
+GROUP BY mr.record_id, p.patient_id, p.first_name, p.last_name, p.embg;
Index: backend/src/main/resources/db/migration/V1.1__Create_Daily_Billing_View.sql
===================================================================
--- backend/src/main/resources/db/migration/V1.1__Create_Daily_Billing_View.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V1.1__Create_Daily_Billing_View.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,28 @@
+ -- Create materialized view for daily patient billing totals
+CREATE MATERIALIZED VIEW IF NOT EXISTS daily_patient_billing_totals AS
+SELECT
+    p.patient_id,
+    CAST(pp.procedure_date AS DATE) as service_date,
+    COALESCE(SUM(pr.cost), 0) as procedure_cost,
+    0::decimal as lab_test_cost,
+    COALESCE(SUM(pr.cost), 0) as total_cost
+FROM patients p
+LEFT JOIN performed_procedures pp ON p.patient_id = pp.patient_id
+LEFT JOIN procedures pr ON pp.procedure_id = pr.procedure_id
+GROUP BY p.patient_id, CAST(pp.procedure_date AS DATE)
+
+UNION ALL
+
+SELECT
+    p.patient_id,
+    CAST(plt.test_date AS DATE) as service_date,
+    0::decimal as procedure_cost,
+    COALESCE(SUM(lt.cost), 0) as lab_test_cost,
+    COALESCE(SUM(lt.cost), 0) as total_cost
+FROM patients p
+LEFT JOIN performed_lab_tests plt ON p.patient_id = plt.patient_id
+LEFT JOIN lab_tests lt ON plt.test_id = lt.test_id
+GROUP BY p.patient_id, CAST(plt.test_date AS DATE);
+
+-- Create index for better query performance
+CREATE INDEX IF NOT EXISTS idx_daily_billing_patient_date ON daily_patient_billing_totals(patient_id, service_date);
Index: backend/src/main/resources/db/migration/V1.2__Create_Users_Table.sql
===================================================================
--- backend/src/main/resources/db/migration/V1.2__Create_Users_Table.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V1.2__Create_Users_Table.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,41 @@
+-- Create users table
+CREATE TABLE IF NOT EXISTS users (
+    user_id SERIAL PRIMARY KEY,
+    username VARCHAR(255) NOT NULL UNIQUE,
+    password VARCHAR(255) NOT NULL,
+    role VARCHAR(50) NOT NULL,
+    first_name VARCHAR(100),
+    last_name VARCHAR(100),
+    patient_id BIGINT,
+    doctor_id BIGINT,
+    is_active BOOLEAN DEFAULT true,
+    FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
+    FOREIGN KEY (doctor_id) REFERENCES doctors(doctor_id)
+);
+
+-- Create index for username lookup
+CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
+
+-- Insert admin user (password: admin123)
+INSERT INTO users (username, password, role, first_name, last_name, is_active)
+VALUES ('admin', 'admin123', 'ADMIN', 'System', 'Administrator', true)
+ON CONFLICT (username) DO NOTHING;
+
+-- Insert sample patient users (password: password123 for all)
+-- These will be linked to existing patients by EMBG
+INSERT INTO users (username, password, role, first_name, last_name, patient_id, is_active)
+SELECT p.embg, 'password123', 'PATIENT', p.first_name, p.last_name, p.patient_id, true
+FROM patients p
+WHERE NOT EXISTS (
+    SELECT 1 FROM users u WHERE u.username = p.embg
+)
+LIMIT 39;
+
+-- Insert doctor users (password: doctor123 for all)
+-- These will be linked to existing doctors by email
+INSERT INTO users (username, password, role, first_name, last_name, doctor_id, is_active)
+SELECT d.email_address, 'doctor123', 'DOCTOR', d.first_name, d.last_name, d.doctor_id, true
+FROM doctors d
+WHERE NOT EXISTS (
+    SELECT 1 FROM users u WHERE u.username = d.email_address
+);
Index: backend/src/main/resources/db/migration/V2__Add_appointment_fields_to_referrals.sql
===================================================================
--- backend/src/main/resources/db/migration/V2__Add_appointment_fields_to_referrals.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V2__Add_appointment_fields_to_referrals.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,7 @@
+-- Add appointment_date and appointment_time columns to referrals table
+ALTER TABLE referrals ADD COLUMN IF NOT EXISTS appointment_date DATE;
+ALTER TABLE referrals ADD COLUMN IF NOT EXISTS appointment_time TIME;
+
+-- Set default values for existing rows
+UPDATE referrals SET appointment_date = referral_date + INTERVAL '1 day', appointment_time = '10:00:00'
+WHERE appointment_date IS NULL;
Index: backend/src/main/resources/db/migration/V3__Fix_LabTechnician_Admin_Structure.sql
===================================================================
--- backend/src/main/resources/db/migration/V3__Fix_LabTechnician_Admin_Structure.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V3__Fix_LabTechnician_Admin_Structure.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,63 @@
+-- V3__Fix_LabTechnician_Admin_Structure.sql
+-- Refactor LabTechnician and Admin to use user_id FK instead of duplicating user data
+
+-- Step 1: Drop FK constraints from tables that reference lab_technician and admin
+ALTER TABLE IF EXISTS billing DROP CONSTRAINT IF EXISTS "FKd17oy1jh5wl1m8vgitr17ks5m";
+ALTER TABLE IF EXISTS performed_lab_tests DROP CONSTRAINT IF EXISTS "FK7itndt1cw4ekph05b0kuadfge";
+ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS "FKlsz5c3rwmg8f4p8xfay9wqy4w";
+ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS "FK9lxmsmidme9l8ofsx1xfyamtk";
+
+-- Step 2: Clear admin_id and technician_id from billing and performed_lab_tests tables
+UPDATE billing SET admin_id = NULL WHERE admin_id IS NOT NULL;
+UPDATE performed_lab_tests SET technician_id = NULL WHERE technician_id IS NOT NULL;
+
+-- Step 3: Create new structure for lab_technician table with user_id FK
+CREATE TABLE IF NOT EXISTS lab_technician_new (
+    technician_id BIGINT PRIMARY KEY,
+    user_id BIGINT NOT NULL UNIQUE,
+    certification VARCHAR(255),
+    FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
+);
+
+-- Step 4: Migrate existing lab_technician data
+INSERT INTO lab_technician_new (technician_id, user_id, certification)
+SELECT lt.technician_id, u.user_id, lt.email
+FROM lab_technician lt
+LEFT JOIN users u ON u.username = lt.username
+WHERE u.user_id IS NOT NULL
+ON CONFLICT DO NOTHING;
+
+-- Step 5: Drop the old lab_technician table
+DROP TABLE IF EXISTS lab_technician CASCADE;
+
+-- Step 6: Rename new table to original name
+ALTER TABLE lab_technician_new RENAME TO lab_technician;
+
+-- Step 7: Create new structure for admin table with user_id FK
+CREATE TABLE IF NOT EXISTS admin_new (
+    admin_id BIGINT PRIMARY KEY,
+    user_id BIGINT NOT NULL UNIQUE,
+    permissions VARCHAR(255),
+    FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
+);
+
+-- Step 8: Migrate existing admin data
+INSERT INTO admin_new (admin_id, user_id, permissions)
+SELECT a.admin_id, u.user_id, NULL
+FROM admin a
+LEFT JOIN users u ON u.username = a.username
+WHERE u.user_id IS NOT NULL AND u.role = 'ADMIN'
+ON CONFLICT DO NOTHING;
+
+-- Step 9: Drop the old admin table
+DROP TABLE IF EXISTS admin CASCADE;
+
+-- Step 10: Rename new table to original name
+ALTER TABLE admin_new RENAME TO admin;
+
+-- Step 11: Create indexes for performance
+CREATE INDEX IF NOT EXISTS idx_lab_technician_user_id ON lab_technician(user_id);
+CREATE INDEX IF NOT EXISTS idx_admin_user_id ON admin(user_id);
+
+-- Step 12: Add FK constraints back (now with proper data)
+ALTER TABLE performed_lab_tests ADD CONSTRAINT FK7itndt1cw4ekph05b0kuadfge FOREIGN KEY (technician_id) REFERENCES lab_technician(technician_id) ON DELETE SET NULL;
Index: backend/src/main/resources/db/migration/V6__Insert_Billing_Admin_Users.sql
===================================================================
--- backend/src/main/resources/db/migration/V6__Insert_Billing_Admin_Users.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V6__Insert_Billing_Admin_Users.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,28 @@
+SELECT
+    plt.performed_test_id,
+    lt.test_name,
+    u_p.first_name AS patient_first_name,
+    u_p.last_name AS patient_last_name,
+    u_d.first_name AS doctor_first_name,
+    u_d.last_name AS doctor_last_name,
+    plt.test_date,
+    plt.notes
+FROM performed_lab_tests plt
+         JOIN lab_tests lt ON plt.test_id = lt.test_id
+         JOIN patients p ON plt.patient_id = p.patient_id
+         JOIN users u_p ON p.patient_id = u_p.patient_id
+         JOIN doctors d ON plt.doctor_id = d.doctor_id
+         JOIN users u_d ON d.doctor_id = u_d.doctor_id;
+
+SELECT
+    lt.test_id,
+    lt.test_name,
+    lt.description,
+    lt.cost,
+    plt.test_date,
+    plt.notes
+FROM lab_tests lt
+         JOIN performed_lab_tests plt ON lt.test_id = plt.test_id
+WHERE plt.patient_id = 4 AND plt.test_date = '2026-06-16';
+
+
Index: backend/src/main/resources/db/migration/V7__Update_Billing_Admin_Names.sql
===================================================================
--- backend/src/main/resources/db/migration/V7__Update_Billing_Admin_Names.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V7__Update_Billing_Admin_Names.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,1 @@
+
Index: backend/src/main/resources/db/migration/V8__appointment_scheduling_integrity.sql
===================================================================
--- backend/src/main/resources/db/migration/V8__appointment_scheduling_integrity.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V8__appointment_scheduling_integrity.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,133 @@
+-- schema change: NO_SHOW must be added to the existing status constraint before
+-- anything below can ever set it
+ALTER TABLE appointments DROP CONSTRAINT appointments_status_chk;
+ALTER TABLE appointments ADD CONSTRAINT appointments_status_chk
+    CHECK (status IN ('SCHEDULED','COMPLETED','CANCELLED','IN_PROGRESS','NO_SHOW'));
+
+-- No generated column needed - we'll compute the time ranges directly in the triggers
+-- This approach is simpler and avoids immutability constraints
+
+CREATE OR REPLACE FUNCTION is_valid_appointment_transition(p_old TEXT, p_new TEXT)
+RETURNS BOOLEAN
+LANGUAGE sql
+IMMUTABLE
+AS $$
+SELECT CASE
+           WHEN p_old = p_new THEN TRUE
+           WHEN p_old = 'SCHEDULED'    AND p_new IN ('IN_PROGRESS', 'COMPLETED', 'CANCELLED') THEN TRUE
+           WHEN p_old = 'IN_PROGRESS'  AND p_new IN ('COMPLETED', 'CANCELLED') THEN TRUE
+           ELSE FALSE
+           END;
+$$;
+
+CREATE OR REPLACE FUNCTION trigger_appointments_enforce()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    v_combined_datetime TIMESTAMP;
+BEGIN
+    v_combined_datetime := NEW.appointment_date::TIMESTAMP + NEW.appointment_time;
+
+    IF TG_OP = 'INSERT' AND v_combined_datetime < NOW() THEN
+        RAISE EXCEPTION 'Cannot schedule appointment in the past (appointment_date=%, appointment_time=%)',
+            NEW.appointment_date, NEW.appointment_time;
+    END IF;
+
+    IF TG_OP = 'UPDATE' THEN
+        IF NOT is_valid_appointment_transition(OLD.status, NEW.status) THEN
+            RAISE EXCEPTION 'Appointment status cannot transition from % to %',
+                OLD.status, NEW.status;
+        END IF;
+
+        IF NEW.status = 'COMPLETED' AND v_combined_datetime > NOW() THEN
+            RAISE EXCEPTION 'Cannot mark appointment COMPLETED before its scheduled time (scheduled for %)',
+                v_combined_datetime;
+        END IF;
+    END IF;
+
+    RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trigger_appointments_enforce ON appointments;
+CREATE TRIGGER trigger_appointments_enforce
+    BEFORE INSERT OR UPDATE
+                         ON appointments
+                         FOR EACH ROW
+                         EXECUTE FUNCTION trigger_appointments_enforce();
+
+CREATE OR REPLACE FUNCTION t1_appointments_no_overlap()
+RETURNS TRIGGER
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    v_new_start TIMESTAMP;
+    v_new_end TIMESTAMP;
+BEGIN
+    IF NEW.status NOT IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED') THEN
+        RETURN NEW;
+    END IF;
+
+    v_new_start := NEW.appointment_date::TIMESTAMP + NEW.appointment_time;
+    v_new_end := v_new_start + INTERVAL '30 minutes';
+
+    -- Check for doctor double-booking
+    -- Overlap condition: existing_start < new_end AND new_start < existing_end
+    IF EXISTS (
+        SELECT 1 FROM appointments a
+        WHERE a.doctor_id = NEW.doctor_id
+          AND a.status IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED')
+          AND (a.appointment_date::TIMESTAMP + a.appointment_time) < v_new_end
+          AND v_new_start < (a.appointment_date::TIMESTAMP + a.appointment_time + INTERVAL '30 minutes')
+          AND (TG_OP <> 'UPDATE' OR a.appointment_id <> NEW.appointment_id)
+    ) THEN
+        RAISE EXCEPTION 'Doctor % has overlapping appointment at %', NEW.doctor_id, NEW.appointment_date;
+    END IF;
+
+    -- Check for patient double-booking
+    IF EXISTS (
+        SELECT 1 FROM appointments a
+        WHERE a.patient_id = NEW.patient_id
+          AND a.status IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED')
+          AND (a.appointment_date::TIMESTAMP + a.appointment_time) < v_new_end
+          AND v_new_start < (a.appointment_date::TIMESTAMP + a.appointment_time + INTERVAL '30 minutes')
+          AND (TG_OP <> 'UPDATE' OR a.appointment_id <> NEW.appointment_id)
+    ) THEN
+        RAISE EXCEPTION 'Patient % has overlapping appointment at %', NEW.patient_id, NEW.appointment_date;
+    END IF;
+
+    RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS trigger_appointments_no_overlap ON appointments;
+CREATE TRIGGER trigger_appointments_no_overlap
+    BEFORE INSERT OR UPDATE
+                         ON appointments
+                         FOR EACH ROW
+                         EXECUTE FUNCTION t1_appointments_no_overlap();
+
+CREATE OR REPLACE PROCEDURE job_mark_no_show()
+LANGUAGE plpgsql
+AS $$
+BEGIN
+    UPDATE appointments
+    SET status = 'NO_SHOW'
+    WHERE status = 'SCHEDULED'
+      AND (appointment_date::TIMESTAMP + appointment_time) < (NOW() - INTERVAL '45 minutes');
+END;
+$$;
+
+CREATE OR REPLACE VIEW v_overdue_appointments AS
+SELECT
+    a.appointment_id, a.patient_id, p.first_name, p.last_name,
+    a.doctor_id, d.first_name AS doctor_first_name, d.last_name AS doctor_last_name,
+    a.appointment_date, a.appointment_time, a.status,
+    NOW() - (a.appointment_date::TIMESTAMP + a.appointment_time) AS time_overdue
+FROM appointments a
+         JOIN patients p ON a.patient_id = p.patient_id
+         JOIN doctors d ON a.doctor_id = d.doctor_id
+WHERE a.status = 'SCHEDULED'
+  AND (a.appointment_date::TIMESTAMP + a.appointment_time) < (NOW() - INTERVAL '45 minutes')
+ORDER BY time_overdue DESC;
Index: backend/src/main/resources/db/migration/V9__mv_revenue_reporting.sql
===================================================================
--- backend/src/main/resources/db/migration/V9__mv_revenue_reporting.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/migration/V9__mv_revenue_reporting.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,60 @@
+-- Revenue reporting: monthly revenue, split by procedure vs. lab test.
+-- Procedure revenue is attributed to a department, since `procedures` carries a
+-- doctor_id directly on the catalog row. Lab revenue cannot be attributed to a
+-- department: lab_tests has no doctor/department reference at all, and
+-- billing_lab_tests links only to the catalog test_id, not to a specific performed
+-- instance, so there is no reliable way to know which doctor/department administered
+-- a billed test. Lab rows are reported at clinic-wide monthly granularity only
+-- (department_id/department_name are NULL for those rows).
+
+CREATE MATERIALIZED VIEW mv_revenue_monthly AS
+SELECT
+    DATE_TRUNC('month', b.payment_date)::DATE AS month,
+    dept.department_id,
+    dept.department_name,
+    'PROCEDURE' AS revenue_type,
+    SUM(p.cost) AS revenue,
+    COUNT(DISTINCT b.bill_id) AS transaction_count
+FROM billing b
+         JOIN billing_procedures bp ON bp.bill_id = b.bill_id
+         JOIN procedures p ON p.procedure_id = bp.procedure_id
+         JOIN doctors doc ON doc.doctor_id = p.doctor_id
+         JOIN departments dept ON dept.department_id = doc.department_id
+WHERE b.payment_status = 'PAID'
+GROUP BY DATE_TRUNC('month', b.payment_date), dept.department_id, dept.department_name
+
+UNION ALL
+
+SELECT
+    DATE_TRUNC('month', b.payment_date)::DATE AS month,
+    NULL AS department_id,
+    NULL AS department_name,
+    'LAB' AS revenue_type,
+    SUM(lt.cost) AS revenue,
+    COUNT(DISTINCT b.bill_id) AS transaction_count
+FROM billing b
+         JOIN billing_lab_tests blt ON blt.bill_id = b.bill_id
+         JOIN lab_tests lt ON lt.test_id = blt.test_id
+WHERE b.payment_status = 'PAID'
+GROUP BY DATE_TRUNC('month', b.payment_date);
+
+CREATE INDEX idx_mv_revenue_monthly_month ON mv_revenue_monthly (month, revenue_type);
+
+-- Background job: recomputes the materialized view. Designed to be invoked
+-- periodically (nightly) via pg_cron, OS-level cron, or an external scheduler.
+-- pg_cron was not available in this hosting environment to test automatic
+-- scheduling directly, so this procedure is verified by manual invocation:
+--   CALL medora_job_refresh_revenue_view();
+CREATE OR REPLACE PROCEDURE medora_job_refresh_revenue_view()
+    LANGUAGE plpgsql
+AS $$
+BEGIN
+    REFRESH MATERIALIZED VIEW mv_revenue_monthly;
+END;
+$$;
+
+CREATE OR REPLACE VIEW v_current_month_revenue AS
+SELECT month, department_id, department_name, revenue_type, revenue, transaction_count
+FROM mv_revenue_monthly
+WHERE month = DATE_TRUNC('month', CURRENT_DATE)::DATE
+ORDER BY revenue_type, revenue DESC;
Index: backend/src/main/resources/db/phase7/verify_section2_deployment.sql
===================================================================
--- backend/src/main/resources/db/phase7/verify_section2_deployment.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/db/phase7/verify_section2_deployment.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,130 @@
+-- ============================================================================
+-- Section 2: Appointment Scheduling Integrity - Deployment Verification
+-- ============================================================================
+
+-- 1. Check triggers on appointments table
+-- ============================================================================
+-- === 1. TRIGGERS ON APPOINTMENTS TABLE ===
+SELECT
+    tgname as trigger_name,
+    CASE WHEN tgdisabled = 0 THEN 'ENABLED' ELSE 'DISABLED' END as status
+FROM pg_trigger
+WHERE tgrelid = 'appointments'::regclass
+ORDER BY tgname;
+
+-- 2. Check trigger functions
+-- ============================================================================
+-- === 2. TRIGGER FUNCTIONS ===
+SELECT
+    proname as function_name,
+    pronargs as parameter_count,
+    prokind as kind
+FROM pg_proc
+WHERE proname IN ('trigger_appointments_enforce', 'trigger_appointments_no_overlap', 'is_valid_appointment_transition')
+ORDER BY proname;
+
+-- 3. Check background job procedure
+-- ============================================================================
+-- === 3. BACKGROUND JOB PROCEDURE ===
+SELECT
+    proname as procedure_name,
+    prokind as kind,
+    'PL/pgSQL' as language
+FROM pg_proc
+WHERE proname = 'job_mark_no_show';
+
+-- 4. Check view
+-- ============================================================================
+-- === 4. VIEWS ===
+SELECT
+    viewname as view_name,
+    schemaname as schema_name
+FROM pg_views
+WHERE viewname = 'v_overdue_appointments';
+
+-- 5. Check appointment status constraint
+-- ============================================================================
+-- === 5. STATUS CONSTRAINT (CHECK) ===
+SELECT
+    constraint_name,
+    constraint_type,
+    table_name
+FROM information_schema.table_constraints
+WHERE table_name = 'appointments'
+  AND constraint_type = 'CHECK'
+  AND constraint_name LIKE '%status%';
+
+-- 6. Verify constraint includes NO_SHOW
+-- ============================================================================
+-- === 6. CONSTRAINT DEFINITION ===
+SELECT
+    constraint_name,
+    check_clause
+FROM information_schema.check_constraints
+WHERE constraint_name = 'appointments_status_chk';
+
+-- 7. Test appointment status values
+-- ============================================================================
+-- === 7. VALID APPOINTMENT STATUSES ===
+SELECT 'SCHEDULED' as status
+UNION ALL
+SELECT 'IN_PROGRESS'
+UNION ALL
+SELECT 'COMPLETED'
+UNION ALL
+SELECT 'CANCELLED'
+UNION ALL
+SELECT 'NO_SHOW'
+ORDER BY status;
+
+-- 8. Summary Statistics
+-- ============================================================================
+-- === 8. DEPLOYMENT SUMMARY ===
+SELECT
+    'Triggers' as component,
+    COUNT(*) as count
+FROM pg_trigger
+WHERE tgrelid = 'appointments'::regclass
+UNION ALL
+SELECT
+    'Trigger Functions' as component,
+    COUNT(*) as count
+FROM pg_proc
+WHERE proname IN ('trigger_appointments_enforce', 'trigger_appointments_no_overlap')
+UNION ALL
+SELECT
+    'Validation Functions' as component,
+    COUNT(*) as count
+FROM pg_proc
+WHERE proname = 'is_valid_appointment_transition'
+UNION ALL
+SELECT
+    'Background Procedures' as component,
+    COUNT(*) as count
+FROM pg_proc
+WHERE proname = 'job_mark_no_show'
+UNION ALL
+SELECT
+    'Views' as component,
+    COUNT(*) as count
+FROM pg_views
+WHERE viewname = 'v_overdue_appointments'
+ORDER BY component;
+
+-- 9. Test the transition validation function
+-- ============================================================================
+-- === 9. STATUS TRANSITION VALIDATION TEST ===
+SELECT
+    'SCHEDULED → IN_PROGRESS' as transition,
+    is_valid_appointment_transition('SCHEDULED', 'IN_PROGRESS') as valid
+UNION ALL
+SELECT 'SCHEDULED → COMPLETED', is_valid_appointment_transition('SCHEDULED', 'COMPLETED')
+UNION ALL
+SELECT 'SCHEDULED → CANCELLED', is_valid_appointment_transition('SCHEDULED', 'CANCELLED')
+UNION ALL
+SELECT 'IN_PROGRESS → COMPLETED', is_valid_appointment_transition('IN_PROGRESS', 'COMPLETED')
+UNION ALL
+SELECT 'COMPLETED → SCHEDULED', is_valid_appointment_transition('COMPLETED', 'SCHEDULED')
+UNION ALL
+SELECT 'COMPLETED → COMPLETED', is_valid_appointment_transition('COMPLETED', 'COMPLETED')
+ORDER BY transition;
Index: backend/src/main/resources/import.sql
===================================================================
--- backend/src/main/resources/import.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/main/resources/import.sql	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,3 @@
+-- Add appointment_date and appointment_time columns to referrals table if they don't exist
+ALTER TABLE IF EXISTS referrals ADD COLUMN IF NOT EXISTS appointment_date DATE;
+ALTER TABLE IF EXISTS referrals ADD COLUMN IF NOT EXISTS appointment_time TIME;
Index: backend/src/test/java/medora/Medora4ApplicationTests.java
===================================================================
--- backend/src/test/java/medora/Medora4ApplicationTests.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
+++ backend/src/test/java/medora/Medora4ApplicationTests.java	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -0,0 +1,13 @@
+package medora;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Medora4ApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}
Index: ckend/src/test/java/medora/Medora5ApplicationTests.java
===================================================================
--- backend/src/test/java/medora/Medora5ApplicationTests.java	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ 	(revision )
@@ -1,13 +1,0 @@
-package medora;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class Medora5ApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}
Index: frontend/node_modules/.cache/.eslintcache
===================================================================
--- frontend/node_modules/.cache/.eslintcache	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/.cache/.eslintcache	(revision cdcff72e9765342b84a5e4b5d98ca5cb050a5500)
@@ -1,1 +1,1 @@
-[{"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\index.js":"1","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\App.js":"2","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ProtectedRoute.js":"3","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Navbar.js":"4","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Dashboard.js":"5","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Login.js":"6","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientForm.js":"7","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientList.js":"8","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientDetail.js":"9","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorList.js":"10","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentList.js":"11","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorDetail.js":"12","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorForm.js":"13","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordList.js":"14","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordDetail.js":"15","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentForm.js":"16","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-reports\\MedicalReportList.js":"17","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingDetail.js":"18","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingList.js":"19","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabResultForm.js":"20","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabTestList.js":"21","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\referrals\\ReferralList.js":"22","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentDetail.js":"23","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DoctorsByDepartment.js":"24","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureList.js":"25","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentList.js":"26","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureResultForm.js":"27","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Loading.js":"28","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ErrorAlert.js":"29","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\SuccessAlert.js":"30","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\doctorService.js":"31","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\patientService.js":"32","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\labService.js":"33","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\billingService.js":"34","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalRecordService.js":"35","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\appointmentService.js":"36","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\api.js":"37","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalReportService.js":"38","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\procedureService.js":"39","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\referralService.js":"40","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\departmentService.js":"41"},{"size":291,"mtime":1779565979297,"results":"42","hashOfConfig":"43"},{"size":5962,"mtime":1780088012915,"results":"44","hashOfConfig":"43"},{"size":653,"mtime":1788538010065,"results":"45","hashOfConfig":"43"},{"size":6779,"mtime":1780088042009,"results":"46","hashOfConfig":"43"},{"size":25902,"mtime":1780078208743,"results":"47","hashOfConfig":"43"},{"size":4700,"mtime":1780088027675,"results":"48","hashOfConfig":"43"},{"size":6699,"mtime":1780077637080,"results":"49","hashOfConfig":"43"},{"size":3709,"mtime":1779582158802,"results":"50","hashOfConfig":"43"},{"size":3765,"mtime":1780077620493,"results":"51","hashOfConfig":"43"},{"size":4261,"mtime":1779582164628,"results":"52","hashOfConfig":"43"},{"size":5095,"mtime":1780078254573,"results":"53","hashOfConfig":"43"},{"size":3823,"mtime":1780077436553,"results":"54","hashOfConfig":"43"},{"size":5721,"mtime":1780077473267,"results":"55","hashOfConfig":"43"},{"size":16521,"mtime":1780077672148,"results":"56","hashOfConfig":"43"},{"size":43338,"mtime":1780090442995,"results":"57","hashOfConfig":"43"},{"size":6186,"mtime":1780077345198,"results":"58","hashOfConfig":"43"},{"size":13972,"mtime":1780078259626,"results":"59","hashOfConfig":"43"},{"size":9133,"mtime":1780077407613,"results":"60","hashOfConfig":"43"},{"size":9123,"mtime":1788509611323,"results":"61","hashOfConfig":"43"},{"size":10661,"mtime":1780077262778,"results":"62","hashOfConfig":"43"},{"size":30675,"mtime":1780089659773,"results":"63","hashOfConfig":"43"},{"size":14340,"mtime":1779582099654,"results":"64","hashOfConfig":"43"},{"size":5034,"mtime":1780077516096,"results":"65","hashOfConfig":"43"},{"size":3751,"mtime":1780077549043,"results":"66","hashOfConfig":"43"},{"size":14551,"mtime":1780089651077,"results":"67","hashOfConfig":"43"},{"size":4523,"mtime":1779582169530,"results":"68","hashOfConfig":"43"},{"size":10875,"mtime":1780077282008,"results":"69","hashOfConfig":"43"},{"size":257,"mtime":1779387741074,"results":"70","hashOfConfig":"43"},{"size":413,"mtime":1779387741913,"results":"71","hashOfConfig":"43"},{"size":591,"mtime":1779387742952,"results":"72","hashOfConfig":"43"},{"size":725,"mtime":1779387735947,"results":"73","hashOfConfig":"43"},{"size":508,"mtime":1779387734888,"results":"74","hashOfConfig":"43"},{"size":1563,"mtime":1779710377177,"results":"75","hashOfConfig":"43"},{"size":1175,"mtime":1779538034422,"results":"76","hashOfConfig":"43"},{"size":587,"mtime":1779396119196,"results":"77","hashOfConfig":"43"},{"size":774,"mtime":1779387737244,"results":"78","hashOfConfig":"43"},{"size":891,"mtime":1780078103087,"results":"79","hashOfConfig":"43"},{"size":538,"mtime":1779395072850,"results":"80","hashOfConfig":"43"},{"size":1681,"mtime":1779438193288,"results":"81","hashOfConfig":"43"},{"size":866,"mtime":1779530118651,"results":"82","hashOfConfig":"43"},{"size":500,"mtime":1779539907232,"results":"83","hashOfConfig":"43"},{"filePath":"84","messages":"85","suppressedMessages":"86","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1ipi7i1",{"filePath":"87","messages":"88","suppressedMessages":"89","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"90","messages":"91","suppressedMessages":"92","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"93","messages":"94","suppressedMessages":"95","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"96","messages":"97","suppressedMessages":"98","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"99","messages":"100","suppressedMessages":"101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"102","messages":"103","suppressedMessages":"104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"105","messages":"106","suppressedMessages":"107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"108","messages":"109","suppressedMessages":"110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"111","messages":"112","suppressedMessages":"113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"114","messages":"115","suppressedMessages":"116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"117","messages":"118","suppressedMessages":"119","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"120","messages":"121","suppressedMessages":"122","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"123","messages":"124","suppressedMessages":"125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"126","messages":"127","suppressedMessages":"128","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"129","messages":"130","suppressedMessages":"131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"132","messages":"133","suppressedMessages":"134","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"135","messages":"136","suppressedMessages":"137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"138","messages":"139","suppressedMessages":"140","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"141","messages":"142","suppressedMessages":"143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"144","messages":"145","suppressedMessages":"146","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"147","messages":"148","suppressedMessages":"149","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"150","messages":"151","suppressedMessages":"152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"153","messages":"154","suppressedMessages":"155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"156","messages":"157","suppressedMessages":"158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"159","messages":"160","suppressedMessages":"161","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"162","messages":"163","suppressedMessages":"164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"165","messages":"166","suppressedMessages":"167","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"168","messages":"169","suppressedMessages":"170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"171","messages":"172","suppressedMessages":"173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"174","messages":"175","suppressedMessages":"176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"177","messages":"178","suppressedMessages":"179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"180","messages":"181","suppressedMessages":"182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"183","messages":"184","suppressedMessages":"185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"186","messages":"187","suppressedMessages":"188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"189","messages":"190","suppressedMessages":"191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"192","messages":"193","suppressedMessages":"194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"195","messages":"196","suppressedMessages":"197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"198","messages":"199","suppressedMessages":"200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"201","messages":"202","suppressedMessages":"203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"204","messages":"205","suppressedMessages":"206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\index.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\App.js",["207"],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ProtectedRoute.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Navbar.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Dashboard.js",["208"],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Login.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-reports\\MedicalReportList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabResultForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabTestList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\referrals\\ReferralList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DoctorsByDepartment.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureResultForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Loading.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ErrorAlert.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\SuccessAlert.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\doctorService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\patientService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\labService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\billingService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalRecordService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\appointmentService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\api.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalReportService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\procedureService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\referralService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\departmentService.js",[],[],{"ruleId":"209","severity":1,"message":"210","line":31,"column":19,"nodeType":"211","messageId":"212","endLine":31,"endColumn":29},{"ruleId":"213","severity":1,"message":"214","line":77,"column":6,"nodeType":"215","endLine":77,"endColumn":8,"suggestions":"216"},"no-unused-vars","'setRefresh' is assigned a value but never used.","Identifier","unusedVar","react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'isBillingAdmin', 'isDoctor', 'isLabTechnician', 'isPatient', 'user.doctorId', and 'user.patientId'. Either include them or remove the dependency array.","ArrayExpression",["217"],{"desc":"218","fix":"219"},"Update the dependencies array to be: [isBillingAdmin, isDoctor, isLabTechnician, isPatient, user.doctorId, user.patientId]",{"range":"220","text":"221"},[3196,3198],"[isBillingAdmin, isDoctor, isLabTechnician, isPatient, user.doctorId, user.patientId]"]
+[{"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\index.js":"1","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\App.js":"2","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Dashboard.js":"3","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Login.js":"4","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientList.js":"5","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientDetail.js":"6","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ProtectedRoute.js":"7","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentForm.js":"8","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordList.js":"9","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientForm.js":"10","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordDetail.js":"11","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentList.js":"12","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Navbar.js":"13","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorList.js":"14","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingList.js":"15","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorForm.js":"16","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabTestList.js":"17","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingDetail.js":"18","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorDetail.js":"19","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabResultForm.js":"20","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentList.js":"21","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\referrals\\ReferralList.js":"22","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DoctorsByDepartment.js":"23","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentDetail.js":"24","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-reports\\MedicalReportList.js":"25","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureResultForm.js":"26","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureList.js":"27","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ErrorAlert.js":"28","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\SuccessAlert.js":"29","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Loading.js":"30","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\appointmentService.js":"31","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\labService.js":"32","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\doctorService.js":"33","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\patientService.js":"34","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\procedureService.js":"35","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\billingService.js":"36","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalRecordService.js":"37","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\api.js":"38","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\departmentService.js":"39","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\referralService.js":"40","C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalReportService.js":"41"},{"size":291,"mtime":1779565979297,"results":"42","hashOfConfig":"43"},{"size":5962,"mtime":1780088012915,"results":"44","hashOfConfig":"43"},{"size":25902,"mtime":1780078208743,"results":"45","hashOfConfig":"43"},{"size":4700,"mtime":1780088027675,"results":"46","hashOfConfig":"43"},{"size":3709,"mtime":1779582158802,"results":"47","hashOfConfig":"43"},{"size":3765,"mtime":1780077620493,"results":"48","hashOfConfig":"43"},{"size":653,"mtime":1788538010065,"results":"49","hashOfConfig":"43"},{"size":6186,"mtime":1780077345198,"results":"50","hashOfConfig":"43"},{"size":16521,"mtime":1780077672148,"results":"51","hashOfConfig":"43"},{"size":6699,"mtime":1780077637080,"results":"52","hashOfConfig":"43"},{"size":43338,"mtime":1780090442995,"results":"53","hashOfConfig":"43"},{"size":5095,"mtime":1780078254573,"results":"54","hashOfConfig":"43"},{"size":6779,"mtime":1780088042009,"results":"55","hashOfConfig":"43"},{"size":4261,"mtime":1779582164628,"results":"56","hashOfConfig":"43"},{"size":9123,"mtime":1788509611323,"results":"57","hashOfConfig":"43"},{"size":5721,"mtime":1780077473267,"results":"58","hashOfConfig":"43"},{"size":30675,"mtime":1780089659773,"results":"59","hashOfConfig":"43"},{"size":9133,"mtime":1780077407613,"results":"60","hashOfConfig":"43"},{"size":3823,"mtime":1780077436553,"results":"61","hashOfConfig":"43"},{"size":10661,"mtime":1780077262778,"results":"62","hashOfConfig":"43"},{"size":4523,"mtime":1779582169530,"results":"63","hashOfConfig":"43"},{"size":14340,"mtime":1779582099654,"results":"64","hashOfConfig":"43"},{"size":3751,"mtime":1780077549043,"results":"65","hashOfConfig":"43"},{"size":5034,"mtime":1780077516096,"results":"66","hashOfConfig":"43"},{"size":13972,"mtime":1780078259626,"results":"67","hashOfConfig":"43"},{"size":10875,"mtime":1780077282008,"results":"68","hashOfConfig":"43"},{"size":14551,"mtime":1780089651077,"results":"69","hashOfConfig":"43"},{"size":413,"mtime":1779387741913,"results":"70","hashOfConfig":"43"},{"size":591,"mtime":1779387742952,"results":"71","hashOfConfig":"43"},{"size":257,"mtime":1779387741074,"results":"72","hashOfConfig":"43"},{"size":774,"mtime":1779387737244,"results":"73","hashOfConfig":"43"},{"size":1563,"mtime":1779710377177,"results":"74","hashOfConfig":"43"},{"size":725,"mtime":1779387735947,"results":"75","hashOfConfig":"43"},{"size":508,"mtime":1779387734888,"results":"76","hashOfConfig":"43"},{"size":1681,"mtime":1779438193288,"results":"77","hashOfConfig":"43"},{"size":1175,"mtime":1779538034422,"results":"78","hashOfConfig":"43"},{"size":587,"mtime":1779396119196,"results":"79","hashOfConfig":"43"},{"size":891,"mtime":1780078103087,"results":"80","hashOfConfig":"43"},{"size":500,"mtime":1779539907232,"results":"81","hashOfConfig":"43"},{"size":866,"mtime":1779530118651,"results":"82","hashOfConfig":"43"},{"size":538,"mtime":1779395072850,"results":"83","hashOfConfig":"43"},{"filePath":"84","messages":"85","suppressedMessages":"86","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1ipi7i1",{"filePath":"87","messages":"88","suppressedMessages":"89","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"90","messages":"91","suppressedMessages":"92","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"93","messages":"94","suppressedMessages":"95","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"96","messages":"97","suppressedMessages":"98","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"99","messages":"100","suppressedMessages":"101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"102","messages":"103","suppressedMessages":"104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"105","messages":"106","suppressedMessages":"107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"108","messages":"109","suppressedMessages":"110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"111","messages":"112","suppressedMessages":"113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"114","messages":"115","suppressedMessages":"116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"117","messages":"118","suppressedMessages":"119","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"120","messages":"121","suppressedMessages":"122","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"123","messages":"124","suppressedMessages":"125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"126","messages":"127","suppressedMessages":"128","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"129","messages":"130","suppressedMessages":"131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"132","messages":"133","suppressedMessages":"134","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"135","messages":"136","suppressedMessages":"137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"138","messages":"139","suppressedMessages":"140","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"141","messages":"142","suppressedMessages":"143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"144","messages":"145","suppressedMessages":"146","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"147","messages":"148","suppressedMessages":"149","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"150","messages":"151","suppressedMessages":"152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"153","messages":"154","suppressedMessages":"155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"156","messages":"157","suppressedMessages":"158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"159","messages":"160","suppressedMessages":"161","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"162","messages":"163","suppressedMessages":"164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"165","messages":"166","suppressedMessages":"167","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"168","messages":"169","suppressedMessages":"170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"171","messages":"172","suppressedMessages":"173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"174","messages":"175","suppressedMessages":"176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"177","messages":"178","suppressedMessages":"179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"180","messages":"181","suppressedMessages":"182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"183","messages":"184","suppressedMessages":"185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"186","messages":"187","suppressedMessages":"188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"189","messages":"190","suppressedMessages":"191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"192","messages":"193","suppressedMessages":"194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"195","messages":"196","suppressedMessages":"197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"198","messages":"199","suppressedMessages":"200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"201","messages":"202","suppressedMessages":"203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"204","messages":"205","suppressedMessages":"206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\index.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\App.js",["207"],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Dashboard.js",["208"],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\Login.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ProtectedRoute.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\patients\\PatientForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-records\\MedicalRecordDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\appointments\\AppointmentList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Navbar.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabTestList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\billing\\BillingDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\doctors\\DoctorDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\lab-tests\\LabResultForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\referrals\\ReferralList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DoctorsByDepartment.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\departments\\DepartmentDetail.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\medical-reports\\MedicalReportList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureResultForm.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\pages\\procedures\\ProcedureList.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\ErrorAlert.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\SuccessAlert.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\components\\Loading.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\appointmentService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\labService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\doctorService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\patientService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\procedureService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\billingService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalRecordService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\api.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\departmentService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\referralService.js",[],[],"C:\\Users\\User\\Downloads\\medora5\\frontend\\src\\services\\medicalReportService.js",[],[],{"ruleId":"209","severity":1,"message":"210","line":31,"column":19,"nodeType":"211","messageId":"212","endLine":31,"endColumn":29},{"ruleId":"213","severity":1,"message":"214","line":77,"column":6,"nodeType":"215","endLine":77,"endColumn":8,"suggestions":"216"},"no-unused-vars","'setRefresh' is assigned a value but never used.","Identifier","unusedVar","react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'isBillingAdmin', 'isDoctor', 'isLabTechnician', 'isPatient', 'user.doctorId', and 'user.patientId'. Either include them or remove the dependency array.","ArrayExpression",["217"],{"desc":"218","fix":"219"},"Update the dependencies array to be: [isBillingAdmin, isDoctor, isLabTechnician, isPatient, user.doctorId, user.patientId]",{"range":"220","text":"221"},[3196,3198],"[isBillingAdmin, isDoctor, isLabTechnician, isPatient, user.doctorId, user.patientId]"]
