# Hospital Management Information System (HMIS) — Production Installation & Deployment Guide

This document provides complete, step-by-step instructions for deploying and installing the **Hospital Management Information System (HMIS)** onto any online hosting environment.

Both installation workflows are fully documented:
* **Method A: Zero-Terminal Web-Based Installation Wizard (Recommended for cPanel, Plesk, DirectAdmin, and Shared Hosting)** — 100% browser-based GUI, zero command line/SSH required.
* **Method B: Cloud VPS / Dedicated Server Deployment (Ubuntu 22.04/24.04 LTS + Nginx + MySQL 8 + Wildcard SSL)** — Automated production setup for high-concurrency multi-tenant operations.

---

## 📋 Table of Contents
1. [System Prerequisites & Server Sizing](#-system-prerequisites--server-sizing)
2. [Required PHP 8.2 Extensions](#-required-php-82-extensions)
3. [Method A: Zero-Terminal Web Installation (Browser GUI)](#-method-a-zero-terminal-web-installation-browser-gui)
   * [Step 1: Prepare the Complete Release Package](#step-1-prepare-the-complete-release-package)
   * [Step 2: Upload & Extract via cPanel / Plesk File Manager](#step-2-upload--extract-via-cpanel--plesk-file-manager)
   * [Step 3: Point Document Root to public/](#step-3-point-document-root-to-public)
   * [Step 4: Create MySQL Database via Hosting GUI](#step-4-create-mysql-database-via-hosting-gui)
   * [Step 5: Run the 3-Step Web Installation Wizard](#step-5-run-the-3-step-web-installation-wizard)
   * [Step 6: Setup Cron Job via cPanel GUI](#step-6-setup-cron-job-via-cpanel-gui)
4. [Method B: Linux VPS Deployment (Ubuntu + Nginx + MySQL)](#-method-b-linux-vps-deployment-ubuntu--nginx--mysql)
   * [Step 1: Domain & Wildcard DNS Records](#step-1-domain--wildcard-dns-records)
   * [Step 2: Install PHP 8.2, Nginx, and MySQL 8](#step-2-install-php-82-nginx-and-mysql-8)
   * [Step 3: Database & User Provisioning](#step-3-database--user-provisioning)
   * [Step 4: Deploy Files & File Permissions](#step-4-deploy-files--file-permissions)
   * [Step 5: Configure Nginx Virtual Host with Subdomains](#step-5-configure-nginx-virtual-host-with-subdomains)
   * [Step 6: SSL TLS 1.3 Certificate (Let's Encrypt / Certbot)](#step-6-ssl-tls-13-certificate-lets-encrypt--certbot)
5. [Multi-Tenant Subdomain Configuration](#-multi-tenant-subdomain-configuration)
6. [Troubleshooting & Verification](#-troubleshooting--verification)

---

## 🖥️ System Prerequisites & Server Sizing

| Sizing Tier | Facilities / Concurrency | Recommended Hardware | Hosting Options |
|---|---|---|---|
| **Entry / Single Facility** | 1 Hospital, up to 100 OPD/day | 2 vCPUs, 4 GB RAM, 40 GB NVMe | cPanel Shared Hosting, Cloudways, DigitalOcean Basic |
| **Mid-Tier Multi-Tenant** | 2–10 Hospitals, active IPD & Pharmacy POS | 4 vCPUs, 8 GB RAM, 80 GB NVMe | Dedicated VPS (AWS EC2, Hetzner, Linode) |
| **Enterprise SaaS Tier** | 10–100+ Hospitals, High IOPS Diagnostics | 8+ vCPUs, 16–32 GB ECC RAM, RAID-1 NVMe | Managed Cluster / AWS RDS + Multi-AZ EC2 |

---

## 📦 Required PHP 8.2 Extensions

Ensure your hosting environment or `php.ini` has the following extensions enabled:

```ini
extension=pdo
extension=pdo_mysql
extension=gd
extension=intl
extension=mbstring
extension=curl
extension=fileinfo
extension=xml
extension=zip
extension=bcmath
extension=opcache
```

> [!NOTE]
> All standard commercial web hosts (cPanel with EA-PHP 8.2 or Alt-PHP, Hostinger, Cloudways, Namecheap, Bluehost, GoDaddy) provide these extensions selectable via the **Select PHP Version / PHP Extensions** control panel.

---

## 🌐 Method A: Zero-Terminal Web Installation (Browser GUI)

This method requires **no terminal, no SSH keys, and no Composer CLI on the server**.

### Step 1: Prepare the Complete Release Package
To install without a terminal, the package must contain the pre-built `vendor/` directory so Composer does not need to be executed on the server.
1. On your computer, verify all dependencies are installed:
   ```bash
   composer install --no-dev --optimize-autoloader
   ```
2. Compress the root application folder into a `.zip` archive (e.g., `hospital_release.zip`).
   * **Include:** `app`, `bootstrap`, `config`, `database`, `public`, `resources`, `routes`, `storage`, `vendor`, `.env.example`, `artisan`, `composer.json`.
   * **Exclude:** `.git`, `.github`, `tests`, `node_modules`, `.env`, `storage/installed` (if present).
   > [!IMPORTANT]
   > Ensure `storage/installed` does NOT exist in your zip file or server before running the wizard. If `storage/installed` exists, the system assumes it is already configured and redirects all requests to `/login` instead of `/install`.

### Step 2: Upload & Extract via cPanel / Plesk File Manager
1. Log in to your hosting control panel (**cPanel**, **Plesk**, **CyberPanel**, or **DirectAdmin**).
2. Open **File Manager**.
3. Create a dedicated folder outside the public web root (e.g. `/home/your_username/hospital_app`) or upload directly into `public_html`.
4. Click **Upload**, select your `hospital_release.zip`, and wait for the upload to reach 100%.
5. Right-click the uploaded `.zip` file and click **Extract**.

### Step 3: Point Document Root to public/
Laravel requires the web server's Document Root to point to the `public/` directory for security:
* **In cPanel:**
  1. Go to **Domains** or **Subdomains**.
  2. For your domain (e.g. `his.yourhospital.com`), change the **Document Root** field to:
     ```
     /home/your_username/hospital_app/public
     ```
  3. Click **Save**.
* **Folder Permissions:**
  Ensure the following folders have write permissions (`775` or `755` in cPanel File Manager):
  * `storage/` (and all subfolders)
  * `bootstrap/cache/`

### Step 4: Create MySQL Database via Hosting GUI
1. In cPanel, navigate to **Databases** &rarr; **MySQL Database Wizard**.
2. **Step 1: Create A Database** — e.g. `youruser_hmis`. Click *Next Step*.
3. **Step 2: Create Database Users** — e.g. `youruser_dbuser` and a strong password. Click *Create User*.
4. **Step 3: Add User to Database** — Check **ALL PRIVILEGES**. Click *Make Changes*.
5. Note down your Database Name, Username, and Password.

### Step 5: Run the 3-Step Web Installation Wizard
Open your web browser and navigate to your website URL:
```
https://his.yourhospital.com
```
The application will automatically detect that it has not been configured and redirect you to the **Installation Wizard** (`/install`):

> [!NOTE]
> **Troubleshooting: Not Redirecting to `/install`?**
> - **Redirecting to `/login` instead?** The installation lock file `storage/installed` exists on your server. Delete `storage/installed` via cPanel File Manager or SSH (`rm storage/installed`) to unlock the installer.
> - **404 Not Found on `/install`?** Ensure `public/.htaccess` exists on your server and Apache `mod_rewrite` is enabled. Without `.htaccess`, server routing will not reach Laravel.
> - **Showing directory index or 403 Forbidden?** Verify your domain's Document Root points to `/public` (e.g. `/home/username/hospital_app/public`).
> - **500 Server Error?** Ensure `storage/` and `bootstrap/cache/` are writable (`chmod -R 775 storage bootstrap/cache`) and required PHP 8.2 extensions are enabled in cPanel &rarr; Select PHP Version.

```mermaid
sequenceDiagram
    autonumber
    actor User as Hospital Admin / Installer
    participant Browser as Web Browser
    participant Wizard as /install Web Wizard
    participant DB as MySQL Database Server

    User->>Browser: Open https://yourdomain.com
    Browser->>Wizard: Auto-redirects to /install
    Wizard->>Browser: Displays Step 1: System & Permissions Checklist
    User->>Wizard: Clicks "Configure Database"
    Wizard->>Browser: Displays Step 2: Database Connection Form
    User->>Wizard: Enters DB details & clicks "Test Connection"
    Wizard->>DB: Handshake test via PDO
    DB-->>Wizard: Connection Verified
    Wizard-->>Browser: Green confirmation badge
    User->>Wizard: Enters Hospital Name, Code, and Super Admin Credentials
    User->>Wizard: Clicks "1-Click Install Now"
    Wizard->>DB: Auto-runs all 21 migrations & seeds clinical masters
    Wizard->>Wizard: Writes APP_KEY, .env, and storage/installed lock file
    Wizard-->>Browser: Step 4: Installation Complete Screen
    User->>Browser: Clicks "Launch Hospital System" -> Logs into Dashboard
```

#### Step 5.1: Requirements & Permissions Check (`/install`)
* The wizard inspects PHP version compatibility ($\ge$ 8.2.0) and all required extensions (`pdo_mysql`, `gd`, `intl`, `mbstring`, `curl`, `fileinfo`, `xml`, `zip`, `bcmath`).
* Verifies directory write access.
* Click **Configure Database**.

#### Step 5.2: Database Connection (`/install/database`)
* **Application URL:** `https://his.yourhospital.com`
* **Database Host:** `localhost` or `127.0.0.1`
* **Port:** `3306`
* **Database Name:** The database created in Step 4
* **Database Username:** The MySQL user created in Step 4
* **Database Password:** The MySQL password
* Click **Test Connection**: A live badge confirms connection before saving.
* Click **Save & Continue**.

#### Step 5.3: Hospital Profile & Super Admin Account (`/install/setup`)
* **Hospital Profile:** Hospital Name (e.g. *Swapnapuri Nursing Home*), Hospital Code (e.g. *SNH*), Official Email, Phone, and Address.
* **Super Admin Account:** Full Name, Email, Username, Password ($\ge$ 8 chars).
* Click **1-Click Install Now**.

The application executes background migrations, clinical master seeding, generates the application key, creates your Super Administrator account, locks the installer (`storage/installed`), and presents the login link!

### Step 6: Setup Cron Job via cPanel GUI
Laravel requires a cron job running every minute for background appointments, patient reminders, and bed matrix auditing:
1. In cPanel, click **Cron Jobs** under the *Advanced* section.
2. Under **Add New Cron Job**, select **Once Per Minute** (`* * * * *`).
3. In the **Command** field, enter:
   ```bash
   /usr/local/bin/php /home/your_username/hospital_app/artisan schedule:run >> /dev/null 2>&1
   ```
4. Click **Add New Cron Job**.

---

## 🛠️ Method B: Linux VPS Deployment (Ubuntu + Nginx + MySQL)

For dedicated servers and Cloud VPS instances (AWS EC2, DigitalOcean, Hetzner, Linode, Vultr):

### Step 1: Domain & Wildcard DNS Records
In your DNS management console (Cloudflare, GoDaddy, Route53), configure:
* **A Record:** `@` &rarr; `YOUR_SERVER_PUBLIC_IP`
* **A Record:** `*` &rarr; `YOUR_SERVER_PUBLIC_IP` *(Allows all tenant subdomains: `hospital1.domain.com`)*

### Step 2: Install PHP 8.2, Nginx, and MySQL 8
Connect to your server via SSH:
```bash
ssh root@YOUR_SERVER_IP
```
Execute system updates and install components:
```bash
sudo apt update && sudo apt upgrade -y
sudo apt install -y software-properties-common curl git zip unzip ufw supervisor

# Add PHP 8.2 Repository
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Install PHP 8.2-FPM and modules
sudo apt install -y php8.2 php8.2-fpm php8.2-mysql php8.2-gd php8.2-intl \
    php8.2-mbstring php8.2-curl php8.2-xml php8.2-zip php8.2-bcmath \
    php8.2-opcache

# Install Web Server and Database
sudo apt install -y nginx mysql-server

# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer
```

### Step 3: Database & User Provisioning
```bash
sudo mysql
```
Run within MySQL:
```sql
CREATE DATABASE hospital_saas CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'hospital_user'@'localhost' IDENTIFIED BY 'StrongHealthcarePass2026#';
GRANT ALL PRIVILEGES ON hospital_saas.* TO 'hospital_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
```

### Step 4: Deploy Files & File Permissions
```bash
sudo mkdir -p /var/www/hospital-system
cd /var/www/hospital-system

# Clone or extract repository
git clone <YOUR_GIT_REPOSITORY_URL> .

# Setup ownership and folder permissions
sudo chown -R www-data:www-data /var/www/hospital-system
sudo find /var/www/hospital-system -type f -exec chmod 644 {} \;
sudo find /var/www/hospital-system -type d -exec chmod 755 {} \;
sudo chmod -R 775 /var/www/hospital-system/storage /var/www/hospital-system/bootstrap/cache
```

Now you can either **navigate to your domain in your browser to run the Web Installer**, or run the CLI commands:
```bash
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data cp .env.example .env
sudo -u www-data php artisan key:generate --force
# Update DB settings in .env, then:
sudo -u www-data php artisan migrate --seed --force
sudo -u www-data php artisan storage:link
sudo -u www-data php artisan config:cache
sudo -u www-data php artisan route:cache
sudo -u www-data php artisan view:cache
```

### Step 5: Configure Nginx Virtual Host with Subdomains
Create `/etc/nginx/sites-available/hospital.conf`:
```nginx
server {
    listen 80;
    server_name yourdomain.com *.yourdomain.com;
    root /var/www/hospital-system/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    add_header X-XSS-Protection "1; mode=block";

    index index.php index.html;
    charset utf-8;

    # Allow up to 50MB for radiology scans, DICOM, and patient document uploads
    client_max_body_size 50M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
```

Enable site and restart Nginx:
```bash
sudo ln -s /etc/nginx/sites-available/hospital.conf /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx
```

### Step 6: SSL TLS 1.3 Certificate (Let's Encrypt / Certbot)
```bash
sudo apt install -y certbot python3-certbot-nginx

# For standard single/multi domain
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# For wildcard subdomains (*.yourdomain.com):
sudo certbot certonly --manual --preferred-challenges=dns -d "yourdomain.com" -d "*.yourdomain.com"
```

Configure System Scheduler:
```bash
sudo crontab -u www-data -e
```
Add:
```cron
* * * * * cd /var/www/hospital-system && php artisan schedule:run >> /dev/null 2>&1
```

---

## 🏢 Multi-Tenant Subdomain Configuration

To route tenants dynamically via subdomains:
1. Ensure your DNS has a Wildcard `*` A Record pointing to your server IP.
2. In `.env`, set:
   ```env
   SAAS_APP_DOMAIN="yourdomain.com"
   ```
3. When creating a tenant in Super Admin:
   * Hospital 1: Subdomain `snh` &rarr; `https://snh.yourdomain.com`
   * Hospital 2: Subdomain `citycare` &rarr; `https://citycare.yourdomain.com`
   * Super Admin Portal: Root domain `https://yourdomain.com/admin`

---

## 🔍 Troubleshooting & Verification

### 1. Verification Health Check
Visit the public health endpoint:
```bash
curl -i https://yourdomain.com/health
```
Expected HTTP 200 response:
```json
{
  "status": "operational",
  "hospital": "Swapnapuri Nursing Home",
  "timestamp": "2026-09-30T..."
}
```

### 2. Common Issues & Solutions

* **Issue: "500 Internal Server Error" on fresh install**
  * *Cause:* Writable folder permissions missing or `APP_KEY` empty.
  * *Solution:* In cPanel File Manager, ensure `storage/` and `bootstrap/cache/` are `chmod 775`. Run the `/install` wizard or check `storage/logs/laravel.log`.
* **Issue: "403 Forbidden" or redirection loop to `/install`**
  * *Cause:* The installer lock file `storage/installed` does not exist or has invalid permissions.
  * *Solution:* Complete the web installer at `https://yourdomain.com/install` or create `storage/installed` manually.
* **Issue: "Access Denied for user 'root'@'localhost'"**
  * *Cause:* Incorrect database credentials provided.
  * *Solution:* Re-check MySQL database name, user, and password in cPanel MySQL Database Wizard.

---

## 🔒 Security Best Practices
1. **Never commit `.env` or production credentials** to Git.
2. **Installation Lock:** Always verify that `storage/installed` exists after setup so no third party can re-run `/install`.
3. **Database Security:** MySQL should strictly bind to `127.0.0.1` and never accept incoming connections from public ports (3306 blocked on firewall).
4. **Automated Database Backups:** Setup a daily backup schedule in cPanel Backup Wizard or via bash cron.
