# IHMS CMS Backend — Frontend Integration & cPanel Deployment Guide

## 1. Purpose

This document gives the frontend developer the exact API endpoints and data formats required to connect all CMS modules to the new PHP backend. It also gives step-by-step instructions to deploy the backend to cPanel.

> **Important:** No frontend types or data shapes have been changed. The API responses mirror the existing mock service objects (`IBlogPost`, `INewsPost`, `ICsr`, `IFaq`, `IPartner`, `IAdmin`, etc.), so switching from mock to live API should require only a URL change.

---

## 2. Environment Variable for Frontend

In the Next.js frontend project root, create or update `.env.local`:

```env
# Local development
NEXT_PUBLIC_APP_API_URL=http://localhost:4000

# Production / cPanel deployment
NEXT_PUBLIC_APP_API_URL=https://api.ihms.com
```

No other frontend config is required. `src/services/apiService.ts` already reads `NEXT_PUBLIC_APP_API_URL`.

---

## 3. cPanel Deployment Checklist

### Step A — Database

1. Log in to cPanel → **MySQL® Databases** or **phpMyAdmin**.
2. Create a database, e.g. `ihms_cms`.
3. Create a database user and add it to the database with **ALL PRIVILEGES**.
4. Open **phpMyAdmin**, select the database, open the **SQL** tab.
5. Copy the entire contents of `backend/database/migration.sql` and run it.
6. This creates all tables and inserts two default users:

| Email | Password | Role |
|-------|----------|------|
| `admin@ihms.com` | `admin123` | `super_admin` |
| `editor@ihms.com` | `admin123` | `editor` |

> Change these passwords after first login.

---

### Step B — Upload Backend Files

Recommended folder layout on cPanel:

```
public_html/
└── backend/
    ├── .env
    ├── composer.json
    ├── config/
    ├── database/
    ├── public/       ← Document Root must point here
    ├── src/
    ├── uploads/
    └── vendor/
```

**Option 1 — SSH / cPanel File Manager**

1. Zip the `backend/` folder locally.
2. Upload via **File Manager** or FTP/SFTP and extract.
3. Create `.env` from `.env.example` and fill in values.

> **No Composer step is required.** This backend uses a built-in autoloader and no external Composer packages, so you can upload the files directly.

---

### Step C — Configure `.env`

```env
APP_NAME="IHMS CMS API"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://api.ihms.com

DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=your_cpanel_db_name
DB_USERNAME=your_cpanel_db_user
DB_PASSWORD=your_cpanel_db_password

JWT_SECRET=replace-this-with-a-long-random-string-min-64-chars
JWT_ISSUER=ihms-cms-api
JWT_EXPIRY=3600

CORS_ALLOWED_ORIGINS=https://ihms.com,https://admin.ihms.com

UPLOAD_MAX_SIZE=5242880
UPLOAD_ALLOWED_TYPES=jpg,jpeg,png,gif,webp,svg,pdf,doc,docx
UPLOAD_PATH=uploads
```

---

### Step D — Set Document Root

1. In cPanel, go to **Domains** → **Create A New Domain** or **Subdomains**.
2. Create a subdomain, e.g. `api.ihms.com`.
3. Set the **Document Root** to: `public_html/backend/public`
4. This makes all API routes available at `https://api.ihms.com/api/...`

The `public/.htaccess` file handles URL rewriting and security.

---

### Step E — Set Permissions

| Path | Permission |
|------|------------|
| `backend/public/` | 755 |
| `backend/uploads/` | 755 (writable) |
| `backend/.env` | 644 |
| `backend/vendor/` | 755 |

---

### Step F — Test

Open in browser:

```
https://api.ihms.com/api/health
```

Expected response:

```json
{
  "status": "success",
  "data": {
    "status": "ok",
    "timestamp": "2026-07-23T09:00:00+01:00",
    "version": "1.0.0"
  }
}
```

Test login:

```bash
curl -X POST https://api.ihms.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@ihms.com","password":"admin123"}'
```

---

## 4. Security Notes for cPanel

- Set `APP_DEBUG=false` in production.
- Use a strong, random `JWT_SECRET` (at least 64 characters).
- Ensure SSL/HTTPS is enabled for the subdomain.
- The `.htaccess` file already blocks access to `.env`, `composer.json`, and `composer.lock`.
- Never commit `.env` to Git.

---

## 5. API Endpoint Reference for Frontend

Base URL: `{NEXT_PUBLIC_APP_API_URL}/api`

All protected routes require:

```http
Authorization: Bearer <token>
```

### Response Wrapper

All endpoints return:

```json
{
  "status": "success" | "error",
  "message": "...",
  "data": { ... }
}
```

Paginated lists return:

```json
{
  "status": "success",
  "data": [ ... ],
  "meta": {
    "total": 50,
    "page": 1,
    "limit": 10,
    "totalPages": 5,
    "hasNext": true,
    "hasPrev": false
  }
}
```

---

### Authentication

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `POST` | `/auth/login` | No | Login and receive JWT + admin info |
| `GET` | `/auth/me` | Yes | Get current admin profile |

**Login request:**

```json
{
  "email": "admin@ihms.com",
  "password": "admin123"
}
```

**Login response:**

```json
{
  "status": "success",
  "message": "Login successful",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "admin": {
      "id": "uuid",
      "name": "Super Admin",
      "email": "admin@ihms.com",
      "role": "super_admin"
    }
  }
}
```

---

### Blog Posts

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/blogs?page=1&limit=10&status=active` | Yes | List blog posts |
| `GET` | `/blogs/{id}` | Yes | Get single blog post |
| `POST` | `/blogs` | Yes | Create blog post |
| `PUT` | `/blogs/{id}` | Yes | Update blog post |
| `PATCH` | `/blogs/{id}/toggle-status` | Yes | Toggle active/draft |
| `DELETE` | `/blogs/{id}` | Yes | Delete blog post |

**Create blog post request:**

```json
{
  "title": "Understanding Health Insurance",
  "description": "A comprehensive guide...",
  "cover_image_url": "https://api.ihms.com/uploads/uuid.jpg",
  "content_blocks": [
    {
      "id": "block-1",
      "type": "heading_text",
      "data": { "text": "Introduction" }
    },
    {
      "id": "block-2",
      "type": "text_box",
      "data": { "text": "Content here..." }
    }
  ],
  "status": "active",
  "seo_title": "Understanding Health Insurance",
  "seo_description": "...",
  "seo_keywords": "health, insurance, nigeria"
}
```

**Returned object** matches `IBlogPost` exactly, including `id`, `date`, and `status`.

---

### News Posts

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/news?page=1&limit=10&tag_id=xxx&status=active` | Yes | List news posts |
| `GET` | `/news/{id}` | Yes | Get single news post |
| `POST` | `/news` | Yes | Create news post |
| `PUT` | `/news/{id}` | Yes | Update news post |
| `PATCH` | `/news/{id}/toggle-status` | Yes | Toggle active/inactive |
| `DELETE` | `/news/{id}` | Yes | Delete news post |

**Create news post request:**

```json
{
  "title": "New Partnership Announcement",
  "content": "Full news content...",
  "cover_image_url": "https://api.ihms.com/uploads/uuid.jpg",
  "category": "Company News",
  "tag_id": "uuid-of-tag",
  "socials": {
    "facebook": "https://facebook.com/...",
    "twitter": "https://twitter.com/...",
    "instagram": "https://instagram.com/...",
    "linkedin": "https://linkedin.com/...",
    "youtube": "https://youtube.com/..."
  },
  "source_link": "https://source.com/article",
  "cta_plan": "optional-plan-id",
  "status": "active"
}
```

**Returned object** matches `INewsPost` exactly.

---

### CSR Campaigns

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/csr?page=1&limit=10&status=active` | Yes | List CSR campaigns |
| `GET` | `/csr/{id}` | Yes | Get single CSR campaign |
| `POST` | `/csr` | Yes | Create CSR campaign |
| `PUT` | `/csr/{id}` | Yes | Update CSR campaign |
| `PATCH` | `/csr/{id}/toggle-status` | Yes | Toggle active/inactive |
| `DELETE` | `/csr/{id}` | Yes | Delete CSR campaign |

**Create CSR campaign request:**

```json
{
  "title": "Community Health Outreach",
  "description": "Campaign description...",
  "cover_image_url": "https://api.ihms.com/uploads/uuid.jpg",
  "short_desc_one": "Short description one",
  "short_desc_two": "Short description two",
  "content_blocks": [ ... ],
  "status": "active",
  "seo_title": "...",
  "seo_description": "...",
  "seo_keywords": "..."
}
```

**Returned object** matches `ICsr` exactly.

---

### FAQs

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/faqs?category=general` | Yes | List FAQs |
| `GET` | `/faqs/{id}` | Yes | Get single FAQ |
| `POST` | `/faqs` | Yes | Create FAQ |
| `PUT` | `/faqs/{id}` | Yes | Update FAQ |
| `DELETE` | `/faqs/{id}` | Yes | Delete FAQ |

**Create FAQ request:**

```json
{
  "category": "general",
  "question": "What is IHMS?",
  "answer": "IHMS stands for International Health Management Services..."
}
```

**Returned object** matches `IFaq` exactly.

---

### Partners

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/partners?status=active` | Yes | List partners |
| `POST` | `/partners` | Yes | Create partner |
| `PUT` | `/partners/{id}` | Yes | Update partner |
| `DELETE` | `/partners/{id}` | Yes | Delete partner |

**Create partner request:**

```json
{
  "name": "Partner Name",
  "logoUrl": "https://api.ihms.com/uploads/uuid.png",
  "status": "active"
}
```

The backend also accepts `logo_url` as an alias for `logoUrl`.

---

### Tags (News Categories)

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/tags` | Yes | List all tags |
| `POST` | `/tags` | Yes | Create tag |
| `PUT` | `/tags/{id}` | Yes | Update tag |
| `DELETE` | `/tags/{id}` | Yes | Delete tag |

**Returned object** matches `ITag`:

```json
{
  "id": "uuid",
  "name": "Company News"
}
```

---

### Media / File Uploads

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `POST` | `/media/upload` | Yes | Upload image/file |
| `GET` | `/media?page=1&limit=20` | Yes | List uploaded files |
| `DELETE` | `/media/{id}` | Yes | Delete uploaded file |

**Upload request:** `multipart/form-data` with field `file`.

**Upload response:**

```json
{
  "status": "success",
  "message": "File uploaded successfully",
  "data": {
    "id": "uuid",
    "filename": "uuid.jpg",
    "original_name": "photo.jpg",
    "mime_type": "image/jpeg",
    "size": 123456,
    "url": "https://api.ihms.com/uploads/uuid.jpg",
    "created_at": "2026-07-23 09:00:00"
  }
}
```

Use the `url` field directly in `cover_image_url` or `logoUrl`.

---

### Health Check

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `GET` | `/health` | No | Server health check |

---

## 6. Frontend Migration from Mock to Live API

No types or components need to change. The only migration step is replacing the mock service files with real API calls using the existing `apiService` instance.

For example, in `src/features/dashboard/blogs/blog.api.ts`, replace mock calls:

```ts
import { apiService } from "@/services/apiService";
import { BlogFormData, IBlogPost } from "./blog.types";

export const BlogService = {
  getBlogs: () => apiService.getPaginated<IBlogPost>("/blogs"),
  getBlogById: (id: string) => apiService.get<IBlogPost>(`/blogs/${id}`),
  createBlog: (data: BlogFormData) => apiService.post<IBlogPost>("/blogs", data),
  updateBlog: (id: string, data: Partial<IBlogPost>) => apiService.put<IBlogPost>(`/blogs/${id}`, data),
  deleteBlog: (id: string) => apiService.delete<void>(`/blogs/${id}`),
  toggleStatus: (id: string) => apiService.patch<IBlogPost>(`/blogs/${id}/toggle-status`),
};
```

Apply the same pattern to `news.api.ts`, `csr.api.ts`, `faq.api.ts`, and `partner.api.ts`.

---

## 7. Key Data Compatibility Guarantees

| Frontend Type | Backend Response Shape | Notes |
|---------------|------------------------|-------|
| `IAdmin` | `{ id, name, email, role }` | Identical |
| `IBlogPost` | Includes `id`, `title`, `description`, `cover_image_url`, `content_blocks`, `status`, `date` | `date` = `created_at` |
| `INewsPost` | Includes `id`, `title`, `category`, `content`, `cover_image_url`, `socials`, `source_link`, `status`, `date`, `cta_plan` | `category` can be tag ID or name |
| `ICsr` | Includes `id`, `title`, `description`, `cover_image_url`, `short_desc_one`, `short_desc_two`, `content_blocks`, `status`, `date` | Identical |
| `IFaq` | `{ id, category, question, answer }` | Identical |
| `IPartner` | `{ id, name, logoUrl, status }` | Backend accepts both `logoUrl` and `logo_url` |
| `ITag` | `{ id, name }` | Identical |

---

## 8. Common Issues & Fixes

| Issue | Cause | Fix |
|-------|-------|-----|
| `401 Unauthorized` | Token missing or expired | Re-login via `/auth/login` |
| `CORS error` | Frontend domain not allowed | Add frontend URL to `CORS_ALLOWED_ORIGINS` in `.env` |
| `404 Not Found` | `mod_rewrite` disabled or wrong document root | Ensure document root is `backend/public` and `.htaccess` exists |
| `500 Internal Server Error` | DB connection failed or missing `.env` | Check `.env` values, set `APP_DEBUG=true` temporarily |
| Upload fails | `uploads/` folder not writable | Set permission to `755` and check PHP upload limits in cPanel |

---

## 9. Summary for Frontend Developer

1. Set `NEXT_PUBLIC_APP_API_URL` in `.env.local`.
2. Replace mock service files with `apiService` calls using the endpoints above.
3. Use the returned `url` from `/media/upload` for images.
4. All existing TypeScript interfaces remain valid — no type changes needed.
5. Handle `401` globally; the existing `apiService` interceptor already redirects to login.

---

## 10. Cleanup Note for Project Owner

There appear to be duplicate folders at the project root (`config/`, `database/`, `uploads/`, `src/Controllers/`, `src/Core/`, `src/Helpers/`, `src/Middleware/`, `src/Models/`). These are not part of the Next.js frontend and are likely accidental copies. The correct backend code is inside `backend/`. You can safely delete the duplicate root-level folders to avoid confusion.