# 🛒 E-Commerce REST API

<div align="center">

[![Laravel](https://img.shields.io/badge/Laravel-11.x-FF2D20?style=for-the-badge&logo=laravel)](https://laravel.com)
[![PHP](https://img.shields.io/badge/PHP-8.2+-777BB4?style=for-the-badge&logo=php)](https://php.net)
[![Sanctum](https://img.shields.io/badge/Auth-Sanctum_Multi--Guard-4CAF50?style=for-the-badge)](https://laravel.com/docs/sanctum)
[![Redis](https://img.shields.io/badge/Cache-Redis-DC382D?style=for-the-badge&logo=redis)](https://redis.io)
[![Tests](https://img.shields.io/badge/Tests-PHPUnit_11-366488?style=for-the-badge&logo=php)](https://phpunit.de)

A **production-ready**, modular e-commerce REST API built with **Laravel 11** following clean architecture principles — featuring dual-guard authentication, Redis caching, real-time broadcasting, and a comprehensive test suite.

**Base URL (production):** `https://codosoft.site/api/v1`

</div>

---

## ✨ Features

| Feature | Details |
|---|---|
| **Multi-Guard Auth** | Separate `users` + `admins` tables; Sanctum tokens are provider-scoped |
| **Clean Architecture** | Controllers → Actions → Services → DTOs (thin controllers) |
| **RBAC** | Admin roles: `super_admin`, `admin`, `moderator` with role hierarchy |
| **State Machine** | Order status transitions validated server-side |
| **Redis Caching** | Product listings & details cached 10 min; auto-invalidated on mutation |
| **Queue System** | Welcome OTP emails dispatched via queued jobs |
| **Real-time Events** | `OrderStatusUpdated` broadcast via Pusher/Soketi |
| **Favorites** | Toggle / check / list user favorites |
| **Reviews** | Write-protected (must have a delivered order for the product) |
| **Rate Limiting** | Auth endpoints: 5/min · Orders: 10/min · Global: 60/min |
| **Test Suite** | 50+ tests: unit, integration, security, authorization |

---

## 🏗️ Architecture

```
app/
├── Actions/          # Single-responsibility use-cases (CreateOrderAction)
├── DTOs/             # Data Transfer Objects (type-safe input contracts)
├── Events/           # Domain events (OrderStatusUpdated)
├── Exceptions/       # Custom business exceptions
├── Http/
│   ├── Controllers/
│   │   └── Api/V1/
│   │       ├── Admin/          # Admin-only controllers (auth:admin guard)
│   │       └── ...             # User controllers (auth:sanctum guard)
│   ├── Requests/     # Form requests with validation rules
│   └── Resources/    # API response transformers
├── Listeners/        # Event listeners
├── Mail/             # Mailable classes
├── Models/           # Eloquent models (User + Admin — separate tables)
├── Policies/         # Authorization policies
├── Services/         # Business logic layer
└── Traits/           # Shared traits (ApiResponse)
```

---

## 🔐 Multi-Guard Authentication

This API uses **two completely separate authentication guards**:

| Guard | Token Source | Model | Table |
|---|---|---|---|
| `auth:sanctum` | User login | `App\Models\User` | `users` |
| `auth:admin` | Admin login | `App\Models\Admin` | `admins` |

> **Security:** A user token **cannot** pass the `auth:admin` guard and vice-versa. Sanctum resolves tokens against their provider's model — cross-guard access is physically impossible.

---

## 📋 API Reference

### 🔓 Public Endpoints

| Method | Endpoint | Description |
|---|---|---|
| `POST` | `/api/v1/register` | Register new user |
| `POST` | `/api/v1/login` | User login (returns token) |
| `POST` | `/api/v1/admin/login` | Admin login (returns admin token) |
| `GET` | `/api/v1/products` | List products (search, filter, sort, paginate) |
| `GET` | `/api/v1/products/{id}` | Get single product |
| `GET` | `/api/v1/categories` | List categories |
| `GET` | `/api/v1/brands` | List brands |
| `GET` | `/api/v1/products/{id}/reviews` | Get product reviews (public) |

### 👤 User Endpoints (`Authorization: Bearer <user_token>`)

| Method | Endpoint | Description |
|---|---|---|
| `POST` | `/api/v1/logout` | Logout (revoke token) |
| `GET` | `/api/v1/profile` | Get profile |
| `GET` | `/api/v1/cart` | View cart |
| `POST` | `/api/v1/cart/items` | Add item to cart |
| `PUT` | `/api/v1/cart/items/{id}` | Update cart item quantity |
| `DELETE` | `/api/v1/cart/items/{id}` | Remove cart item |
| `POST` | `/api/v1/cart/coupon` | Apply coupon |
| `DELETE` | `/api/v1/cart/coupon` | Remove coupon |
| `DELETE` | `/api/v1/cart` | Clear cart |
| `GET` | `/api/v1/orders` | List my orders |
| `POST` | `/api/v1/orders` | Create order from cart |
| `GET` | `/api/v1/orders/{id}` | View my order |
| `GET` | `/api/v1/favorites` | List my favorites |
| `POST` | `/api/v1/favorites/{productId}/toggle` | Add/remove favorite |
| `GET` | `/api/v1/favorites/{productId}/check` | Check if favorited |
| `DELETE` | `/api/v1/favorites/{productId}` | Remove favorite |
| `POST` | `/api/v1/products/{id}/reviews` | Submit review *(requires delivered order)* |
| `PUT` | `/api/v1/products/{id}/reviews/{reviewId}` | Update own review |
| `DELETE` | `/api/v1/products/{id}/reviews/{reviewId}` | Delete own review |

### 🔑 Admin Endpoints (`Authorization: Bearer <admin_token>`)

| Method | Endpoint | Description |
|---|---|---|
| `POST` | `/api/v1/admin/logout` | Admin logout |
| `GET` | `/api/v1/admin/profile` | Admin profile |
| `POST` | `/api/v1/admin/products` | Create product |
| `PUT` | `/api/v1/admin/products/{id}` | Update product |
| `DELETE` | `/api/v1/admin/products/{id}` | Delete product |
| `GET` | `/api/v1/admin/orders` | List ALL orders |
| `GET` | `/api/v1/admin/orders/{id}` | View any order |
| `PATCH` | `/api/v1/admin/orders/{id}/status` | Update order status |

---

## 🗄️ Order Status Flow

```
pending → confirmed → processing → shipped → delivered
                                           ↘
                              cancelled ←── (any state)
                              refunded  ←── delivered
```

---

## 🚀 Quick Start

### 1. Clone & Install

```bash
git clone https://github.com/Ana-Mezo/e-commerce.git
cd e-commerce
composer install
cp .env.example .env
php artisan key:generate
```

### 2. Configure Environment

Edit `.env` — minimum required:
```env
DB_DATABASE=your_database
DB_USERNAME=your_user
DB_PASSWORD=your_password

# For local dev, use sync queue & log mail (no Redis needed):
QUEUE_CONNECTION=sync
MAIL_MAILER=log
CACHE_STORE=file
```

### 3. Migrate & Seed

```bash
php artisan migrate
php artisan db:seed
```

**Test Credentials (after seeding):**

| Role | Email | Password |
|---|---|---|
| Super Admin | superadmin@ecommerce.com | password |
| Admin | admin@ecommerce.com | password |
| Moderator | moderator@ecommerce.com | password |
| User | user@ecommerce.com | password |
| User 2 | user2@ecommerce.com | password |

### 4. Run

```bash
# Development (runs server + queue + logs):
composer run dev

# Or manually:
php artisan serve
php artisan queue:listen --tries=3
```

---

## 🧪 Testing

```bash
# Run all tests
php artisan test

# Run specific suites
php artisan test --filter SecurityTest       # Authorization & security
php artisan test --filter FavoriteApiTest    # Favorites
php artisan test --filter ReviewApiTest      # Reviews
php artisan test --filter ProductApiTest     # Products
php artisan test --filter OrderApiTest       # Orders
php artisan test --filter AuthApiTest        # Authentication

# With coverage (requires Xdebug or PCOV)
php artisan test --coverage
```

**Test coverage areas:**
- ✅ Unauthenticated access → `401`  
- ✅ Regular user cannot create/edit/delete products → `401`  
- ✅ User cannot view/modify another user's order → `404`  
- ✅ User token rejected by admin guard → `401`  
- ✅ Admin token rejected by user guard → `401`  
- ✅ Review requires delivered order → `403`  
- ✅ Duplicate review prevention → `422`  
- ✅ Invalid status transitions → `422`  
- ✅ Validation failure cases  

---

## ⚙️ Production Checklist

```bash
# 1. Set environment
APP_ENV=production
APP_DEBUG=false
BCRYPT_ROUNDS=14

# 2. Optimize
php artisan config:cache
php artisan route:cache
php artisan view:cache
composer install --optimize-autoloader --no-dev

# 3. Queue worker (use Supervisor)
php artisan queue:work redis --tries=3 --timeout=90

# 4. Schedule (add to cron)
* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1

# 5. Migrate in production
php artisan migrate --force
```

---

## 🔄 Caching Strategy

| Data | Cache Key | TTL | Invalidation |
|---|---|---|---|
| Product listing | `products:{filter_hash}` | 10 min | On any product CRUD |
| Single product | `product:{id}` | 10 min | On update/delete |

> **Production note:** With Redis tags enabled, use `Cache::tags(['products'])->flush()` for more granular invalidation instead of full flush.

---

## 📡 Real-Time Events

`OrderStatusUpdated` is broadcast on the `orders.{userId}` channel when an admin updates an order status.

**Frontend subscribe example:**
```javascript
Echo.private(`orders.${userId}`)
    .listen('OrderStatusUpdated', (e) => {
        console.log('Order status changed:', e.order.status);
    });
```

---

## 📦 Tech Stack

| Layer | Technology |
|---|---|
| Framework | Laravel 11 |
| Auth | Laravel Sanctum (multi-guard) |
| Database | MySQL 8+ |
| Cache / Queue | Redis |
| Broadcasting | Pusher / Soketi |
| Mail | SMTP (Mailtrap for dev) |
| Testing | PHPUnit 11 |
| Code Style | Laravel Pint |

---

## 🤝 Contributing

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Run tests: `php artisan test`
4. Submit a pull request

---

<div align="center">
  Built with ❤️ using Laravel 11 · <a href="https://codosoft.site">codosoft.site</a>
</div>
