# BuyAbans-Style E-Commerce Platform — Setup & Integration Guide

## 1. What's in this package

```
database/migrations/   5 migration files (users, categories/brands, products/variants/inventory, orders/payments, cart/wishlist)
app/Models/             13 Eloquent models with relationships
app/Http/Controllers/Api/            Public API: Product, Cart, Order, Auth, PaymentWebhook
app/Http/Controllers/Api/Admin/      Admin API: Product, Category, Brand, Inventory, Order, Dashboard
app/Http/Middleware/     Role-check middleware
app/Services/            PaymentGatewayService (PayHere / WebXpay / IPG)
resources/views/invoices/  PDF invoice Blade template
routes/api.php           All routes wired together
```

## 2. Project setup

```bash
composer create-project laravel/laravel buyabans-backend
cd buyabans-backend

# Required packages
composer require laravel/sanctum
composer require barryvdh/laravel-dompdf   # PDF invoices

php artisan install:api   # publishes Sanctum config + adds api.php if not present
```

Copy this package's folders into your fresh Laravel project, overwriting/merging:
- `database/migrations/*` → your `database/migrations/`
- `app/Models/*` → your `app/Models/` (replace the default `User.php`)
- `app/Http/Controllers/Api/*` and `Api/Admin/*` → your `app/Http/Controllers/`
- `app/Http/Middleware/EnsureUserHasRole.php` → your `app/Http/Middleware/`
- `app/Services/PaymentGatewayService.php` → your `app/Services/`
- `resources/views/invoices/order.blade.php` → your `resources/views/invoices/`
- `routes/api.php` → replace your `routes/api.php`

Register the role middleware in `bootstrap/app.php`:

```php
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => \App\Http\Middleware\EnsureUserHasRole::class,
    ]);
})
```

## 3. Environment configuration (`.env`)

```env
APP_URL=https://api.yourdomain.lk
FRONTEND_URL=https://yourdomain.lk

DB_CONNECTION=mysql
DB_DATABASE=buyabans
DB_USERNAME=root
DB_PASSWORD=

SANCTUM_STATEFUL_DOMAINS=yourdomain.lk

# PayHere
PAYHERE_MERCHANT_ID=xxxx
PAYHERE_MERCHANT_SECRET=xxxx
PAYHERE_SANDBOX=true

# WebXpay
WEBXPAY_MERCHANT_ID=xxxx

# Bank IPG
IPG_ENDPOINT=https://ipg.bank.lk/payment
IPG_MERCHANT_ID=xxxx
```

Add to `config/services.php`:

```php
'payhere' => [
    'merchant_id' => env('PAYHERE_MERCHANT_ID'),
    'merchant_secret' => env('PAYHERE_MERCHANT_SECRET'),
    'sandbox' => env('PAYHERE_SANDBOX', true),
],
'webxpay' => ['merchant_id' => env('WEBXPAY_MERCHANT_ID')],
'ipg' => ['endpoint' => env('IPG_ENDPOINT'), 'merchant_id' => env('IPG_MERCHANT_ID')],
```

Add `'frontend_url' => env('FRONTEND_URL')` to `config/app.php`.

## 4. Database & storage

```bash
php artisan migrate
php artisan storage:link      # so product/category images are publicly reachable
```

Seed an initial admin:

```bash
php artisan tinker
>>> App\Models\User::create(['name'=>'Admin','email'=>'admin@buyabans.lk','password'=>bcrypt('changeme'),'role'=>'admin']);
```

## 5. Running it

```bash
php artisan serve   # http://localhost:8000/api/...
```

Test with:
```bash
curl http://localhost:8000/api/products
```

## 6. Connecting the Stitch/Tailwind frontend

Your Stitch export is static HTML/Tailwind. Two integration paths:

**Path A — Decoupled SPA (recommended for scale):** Turn the Stitch pages into React/Vue components and call the Laravel API over Axios/Fetch. Laravel stays a pure JSON API; the frontend is a separate deployable (Vercel/Netlify/Nginx).

**Path B — Blade + Alpine.js (fastest to ship):** Drop the Stitch HTML directly into `resources/views`, keep Tailwind, and sprinkle Alpine.js for interactivity (`x-data`, `@click`) calling the same `/api/...` endpoints via `fetch`.

### Example: product listing page (fetch, works for either path)

```js
async function loadProducts(filters = {}) {
  const params = new URLSearchParams(filters);
  const res = await fetch(`https://api.yourdomain.lk/api/products?${params}`);
  const data = await res.json();
  renderProductGrid(data.data); // data.data = paginated product array
}
```

### Example: add to cart

```js
async function addToCart(productId, variantId, qty = 1) {
  const res = await fetch('https://api.yourdomain.lk/api/cart/items', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Guest-Session': localStorage.getItem('guest_session') ?? crypto.randomUUID(),
      ...(authToken && { Authorization: `Bearer ${authToken}` }),
    },
    body: JSON.stringify({ product_id: productId, product_variant_id: variantId, quantity: qty }),
  });
  return res.json();
}
```

### Auth flow

1. `POST /api/auth/register` or `/api/auth/login` → returns `{ user, token }`.
2. Store `token` (memory or httpOnly-cookie-backed storage — avoid plain localStorage for production).
3. Send `Authorization: Bearer <token>` on every authenticated request (checkout, orders, admin routes).

### Checkout → payment gateway redirect

`POST /api/checkout` returns, for online gateways:
```json
{
  "order": { ... },
  "gateway": {
    "checkout_url": "https://sandbox.payhere.lk/pay/checkout",
    "fields": { "merchant_id": "...", "hash": "...", "...": "..." }
  }
}
```
Frontend auto-submits a hidden form with those `fields` to `checkout_url` to redirect the customer into PayHere's hosted payment page. On completion, PayHere calls your `notify_url` webhook server-to-server (already wired to `PaymentWebhookController`), and redirects the browser to `return_url`/`cancel_url`.

## 7. Admin panel

All `/api/admin/*` routes require `auth:sanctum` + `role:admin,staff`. Build the admin panel as a separate protected SPA section (or Blade views) hitting these same endpoints — dashboard stats, product/category/brand CRUD with image upload (`multipart/form-data`), inventory adjustments, and order status transitions.

## 8. Production hardening checklist

- Rate-limit `/api/auth/*` and `/api/checkout` (`throttle:` middleware).
- Queue heavy work (invoice emails, stock notifications) via Laravel Queues + a worker (Redis recommended).
- Add Laravel policies for fine-grained authorization beyond the role middleware.
- Cache category tree and featured products (Redis) — they change infrequently but are read on every page load.
- Put Laravel behind Nginx + PHP-FPM, MySQL on its own managed instance, and object storage (S3-compatible) for product images at scale instead of local disk.
- Enable HTTPS everywhere; PayHere/WebXpay require HTTPS notify URLs in production.
