# REST API Architecture

## Base URL
All endpoints (example): `http://localhost/<your-app-folder>/api/v1/` when Apache/nginx rewrites `/api/*` to `public/index.php`, or `http://localhost/<your-app-folder>/public/api/v1/` if the server exposes `public/` directly.

### Base path configuration
The app can be mounted under a subfolder (example `/<your-app-folder>`). The system must not hardcode that folder name.

- **Backend**: `helpers/AppUrls.php` resolves the base path automatically (or uses env `LINKPROX_BASE_PATH`). `LINKPROX_BASE_PATH` must be a path segment (e.g. `/my-app` or `/`), not a hostname.
- **Frontend**: `views/layouts/header.php` and `views/auth/login.php` inject `window.LINKPROX_API_BASE_V1` (canonical `/<base>/api/v1`). `resources/js/api.js` normalizes the Axios `baseURL` (absolute path, safe fallbacks) so relative resolution against `/views/...` does not produce broken URLs.

## Authentication
All protected endpoints require a JWT token:
```
Authorization: Bearer <token>
```
Tokens are issued by `POST /api/v1/auth/login`. They are validated by `AuthMiddleware::protect()` in every controller method.

**Login rules:** Email and password must match a row in `users` with status `active` or `pending_verification` and a non-empty `password_hash` verified with `password_verify()`. There is no alternate “demo” password path.

## Standard Response Format
```json
{
  "status": "success",
  "message": "Human-readable message",
  "data": {},
  "errors": null
}
```
Error response:
```json
{
  "status": "error",
  "message": "Validation failed",
  "data": null,
  "errors": "Detailed error string or object"
}
```

---

## All Registered API Endpoints

### Auth
| Method | Endpoint | Description |
|---|---|---|
| POST | `/api/v1/auth/login` | Email + password login (bcrypt `password_hash` only) |
| PUT | `/api/v1/auth/password` | Change password (authenticated; requires current password) |
| POST | `/api/v1/auth/logout-all` | Bump `token_version` — invalidates all JWTs for the user |
| POST | `/api/v1/auth/send-otp` | Generate OTP (response may include `otp_debug` in dev — remove or gate for production) |
| POST | `/api/v1/auth/login-otp` | Login with OTP |
| POST | `/api/v1/auth/forgot-password` | Start password reset flow |
| POST | `/api/v1/auth/reset-password` | Reset with token |

### Company Profile
| Method | Endpoint | Description |
|---|---|---|
| GET/PUT | `/api/v1/company/profile` | Get or update company profile |
| PUT | `/api/v1/company/profile/legal` | Update legal information |
| POST | `/api/v1/company/profile/upload_logo` | Upload company logo |
| POST | `/api/v1/company/profile/upload_document` | Upload a document |
| DELETE | `/api/v1/company/profile/document` | Delete a document |

### Company Catalog (Products)
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/company/catalog` | List products |
| GET | `/api/v1/company/catalog/details?id=` | Single product |
| POST | `/api/v1/company/catalog` | Create product |
| PUT | `/api/v1/company/catalog` | Update product |
| DELETE | `/api/v1/company/catalog` | Delete product |
| POST | `/api/v1/company/catalog/upload` | Upload catalog product media |

### Company Dashboard
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/company/dashboard/stats` | Aggregated KPI / funnel stats for company dashboard |
| GET | `/api/v1/company/dashboard/activity` | Recent activity feed |
| GET | `/api/v1/company/dashboard/widgets` | Batched widgets (requests needing response, recent requests, active contracts, system activity) |

### Company Services
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/company/services` | List services |
| GET | `/api/v1/company/services/details?id=` | Single service |
| POST | `/api/v1/company/services` | Create service |
| PUT | `/api/v1/company/services` | Update service |
| POST | `/api/v1/company/services/upload` | Upload service media |

### Requests (Company-side)
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/requests` | List requests for company |
| GET | `/api/v1/requests/count` | Count of unread/new requests |
| POST | `/api/v1/requests/update-status` | Update request status |

### Quotations (Company-side)
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/company/quotations` | List quotations |
| POST | `/api/v1/company/quotations` | Create quotation |
| GET | `/api/v1/company/quotations/details?id=` | Single quotation |
| GET | `/api/v1/company/quotations/request?request_id=` | Quotation for a request |
| POST | `/api/v1/company/quotations/upload` | Upload quotation PDF |

### Contracts (Company-side)
| Method | Endpoint | Description |
|---|---|---|
| POST | `/api/v1/company/contracts` | Generate new contract from quotation |
| GET | `/api/v1/company/contracts` | List all contracts |
| GET | `/api/v1/company/contracts/init?quotation_id=` | Init data for contract generation |
| GET | `/api/v1/company/contracts/roles?contract_id=` | Get assigned staff roles |
| POST | `/api/v1/company/contracts/roles?contract_id=` | Save staff roles |
| GET | `/api/v1/company/contracts/review?contract_id=&is_revision=` | Full printable contract payload + `timeline`; includes `version_status` (latest `contract_versions.review_status`). Timeline may end with `type: "termination"` when status is `termination_pending`, `terminated`, or `cancelled`. |
| GET | `/api/v1/company/contracts/details?contract_id=` | Contract header / meta for details UI |
| GET | `/api/v1/company/contracts/timeline?contract_id=` | `{ "timeline": [...] }` — same event rules as embedded review `timeline` (including termination rows) |
| GET | `/api/v1/company/contracts/messages?contract_id=` | Request-scoped messages for the contract’s `request_id` |
| GET | `/api/v1/company/contracts/edit?contract_id=&is_revision=` | Editable contract data |
| POST | `/api/v1/company/contracts/upload` | Upload contract document (multipart) |
| POST | `/api/v1/company/contracts/send?contract_id=` | Send latest **draft** version to client (`review_status` → `sent_for_review`) |
| POST | `/api/v1/company/contracts/sign?contract_id=` | Sign contract via UAE PASS (simulated) |
| POST | `/api/v1/company/contracts/start-revision?contract_id=` | Start a new revision |
| POST | `/api/v1/company/contracts/cancel-revision?contract_id=` | Discard draft revision |
| GET | `/api/v1/company/contracts/milestones?contract_id=` | List payment milestones for company view |
| GET | `/api/v1/company/contracts/milestones/details?milestone_id=` | Single milestone detail |
| POST | `/api/v1/company/contracts/milestones/request-payment` | Request payment for a milestone |
| POST | `/api/v1/company/contracts/milestones/send-reminder` | Send reminder |
| POST | `/api/v1/company/contracts/milestones/review` | Review / approve milestone evidence (company flow) |
| GET | `/api/v1/company/contracts/termination/settlement?contract_id=` | Termination financial snapshot + settlement scenarios |
| POST | `/api/v1/company/contracts/termination/approve` | Approve termination with `system_scenario`; sets contract `termination_pending` |
| POST | `/api/v1/company/contracts/termination/reject` | Reject pending termination request (JSON `contract_id`) |
| GET | `/api/v1/company/contracts/termination/reconciliation?contract_id=` | Settlement reconciliation payload (`termination_pending`) |
| POST | `/api/v1/company/contracts/termination/confirm-settlement` | Confirm settlement complete; sets `terminated` + `terminated_at` (JSON `contract_id`) |

### Contract execution (stages; company, customer, site_engineer, admin)
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/contracts/execution?contract_id=` | Stages + overall progress % |
| GET | `/api/v1/contracts/execution/stages/details?stage_id=` | Stage detail; includes `pending_extension_request` |
| POST | `/api/v1/contracts/execution/stages/update` | Submit stage evidence/update (multipart: `stage_id`, `notes`, `files[]`) |
| POST | `/api/v1/contracts/execution/stages/save` | Save internal progress (multipart: includes `delay_expected` / `notify_customer`) |
| POST | `/api/v1/contracts/execution/stages/mark-complete` | Request customer review/completion (JSON: `stage_id`) |
| POST | `/api/v1/contracts/execution/stages/review` | Customer/Admin review: JSON `{stage_id, action: 'approve'|'reject', notes}` |
| POST | `/api/v1/contracts/execution/stages/remind` | Send reminder to customer to review (JSON: `stage_id`) |
| POST | `/api/v1/contracts/execution/stages` | [Owner] Create new stage (JSON: `contract_id`, `title`, `description`, `sequence_no`) |
| PUT | `/api/v1/contracts/execution/stages` | [Owner] Update stage meta (JSON: `stage_id`, `title`, `description`) |
| DELETE | `/api/v1/contracts/execution/stages?stage_id=` | [Owner] Delete empty stage |
| POST | `/api/v1/contracts/execution/stages/reorder` | [Owner] Reorder stages (JSON: `contract_id`, `stages: [{id, sequence_no}, ...]`) |
| POST | `/api/v1/contracts/execution/stages/extension-request` | **Request deadline extension** (multipart: `contract_id`, `stage_id`, `proposed_deadline`, `reason_code`, `explanation`; `files[]`) |
| GET | `/api/v1/contracts/execution/stages/extension-requests?contract_id=` | List extension requests + attachments |
| POST | `/api/v1/contracts/execution/stages/extension-request/review` | Approve/reject extension: JSON `{request_id, action: 'approve'|'reject', customer_note}` |

### Chat
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/chat/history?request_id=` | Get chat messages for a request |
| POST | `/api/v1/chat/send` | Send a message `{request_id, message}` |

### Notifications (Company)
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/notifications` | List notifications |
| POST | `/api/v1/notifications/read` | Mark as read |
| GET | `/api/v1/notifications/settings` | Get notification prefs |
| PUT | `/api/v1/notifications/settings` | Update notification prefs |
| GET | `/api/v1/customer/help` | List customer help requests |
| POST | `/api/v1/customer/help` | Submit a help request |
| GET | `/api/v1/customer/help/categories` | List available help categories |
| GET | `/api/v1/customer/support/info` | Get general support contact info |
| GET | `/api/v1/customer/faqs` | List FAQs |
| GET | `/api/v1/customer/notifications` | List customer notifications |
| POST | `/api/v1/customer/notifications/read` | Mark as read (JSON `{id}` or `{all:true}`) |
| GET | `/api/v1/customer/activity` | Get activity feed (supports `types`, `statuses`, `date_from`, `date_to`, `q`) |

### Settings (Company)
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/settings` | Get account settings |
| PUT | `/api/v1/settings` | Update account settings |
| POST | `/api/v1/company/deactivate-request` | Request account deactivation |

### 4. Admin Management (Admin-only)

#### Manage Banners
- **GET** `/api/v1/admin/banners`: List all banners.
- **POST** `/api/v1/admin/banners`: Create a new banner.
- **PUT** `/api/v1/admin/banners`: Update a banner.
- **DELETE** `/api/v1/admin/banners`: Delete a banner.

#### Manage Catalog Features
- **POST** `/api/v1/admin/catalog/feature`: Toggle featured status for a service or product.
    - Payload: `{"id": 1, "type": "service", "is_featured": 1}`
- **GET** `/api/v1/admin/catalog/moderation`: List all catalog items for moderation.

### Admin
| Method | Endpoint | Description |
|---|---|---|
| GET | `/api/v1/admin/companies` | List all companies |
| POST | `/api/v1/admin/companies/approve` | Approve a company |
| POST | `/api/v1/admin/companies/suspend` | Suspend a company |
| GET | `/api/v1/admin/companies/details?id=` | Company detail |
| POST | `/api/v1/admin/companies/update-status` | Generic status update |
| POST | `/api/v1/admin/companies/verify` | Mark company as verified |

### Customer (Mobile App API)
| Method | Endpoint | Description |
|---|---|---|
| GET/PUT | `/api/v1/customer/profile` | Customer profile |
| GET/POST/DELETE | `/api/v1/customer/addresses` | Customer addresses |
| GET/PUT | `/api/v1/customer/settings` | Settings |
| GET | `/api/v1/customer/dashboard` | Customer dashboard (stats, sliders, latest uploads, service/product categories, partners) |
| GET | `/api/v1/customer/companies` | Browse companies (Filters: `search`, `emirate_id`, `area_id`, `offering_type`) |
| GET | `/api/v1/customer/companies/details?id=` | Company detail (profile) |
| GET/POST | `/api/v1/customer/requests` | Customer requests |
| GET | `/api/v1/customer/quotations` | Quotation list |
| GET | `/api/v1/customer/quotations/details?id=` | Quotation detail |
| POST | `/api/v1/customer/quotations/respond` | Accept/reject quotation |
| GET | `/api/v1/customer/contracts` | Contract list |
| GET | `/api/v1/customer/contracts/details?id=` | Contract detail |
| GET | `/api/v1/customer/browse/services` | Browse services (Filters: `company_id`, `category_id`, `search`, `execution_mode`) |
| GET | `/api/v1/customer/browse/products` | Browse products (Filters: `company_id`, `category_id`, `search`, `min_price`, `max_price`) |
| GET | `/api/v1/customer/browse/categories` | Browse categories (Filters: `company_id`, `type`) |
| GET | `/api/v1/customer/browse/all` | Browse both products & services (Filters: `company_id`, `category_id`, `search`) |
| GET/POST | `/api/v1/customer/conversations` | Conversations |
| POST | `/api/v1/customer/conversations/start` | Start a conversation |
| GET/POST | `/api/v1/customer/payments` | Payments |
| POST | `/api/v1/customer/payments/submit` | Submit milestone payment |

---

## How to Add a New Endpoint
1. Add an `if` block in `public/index.php`
2. Create or extend the relevant controller method
3. Add the JS wrapper in `resources/js/api.js`
4. Update `API_COLLECTION.json` (Postman collection; optional helper `scratch/update_postman.php` if maintained)
5. Update `API_STRUCTURE.md` (and `README.md` / `COMPANY_MODULES.md` / `IMPLEMENTATION_PLAN.md` when the feature is user-visible or architectural)
