# PHARVION - Laravel Backend API

A production-ready Laravel REST API for pharma bulk product and vendor information management.

## Features

- ✅ RESTful API with proper HTTP conventions
- ✅ Laravel Sanctum authentication
- ✅ Admin Dashboard with Filament
- ✅ MySQL database with optimized queries
- ✅ Comprehensive API validation
- ✅ Error handling and logging
- ✅ API pagination and filtering
- ✅ Full-text search capabilities
- ✅ CORS configuration
- ✅ Rate limiting

## Project Structure

```
backend/
├── app/
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── Api/
│   │   │   │   ├── ProductController.php
│   │   │   │   ├── VendorController.php
│   │   │   │   ├── EventController.php
│   │   │   │   ├── InquiryController.php
│   │   │   │   └── AuthController.php
│   │   │   └── Admin/
│   │   ├── Requests/
│   │   │   ├── StoreProductRequest.php
│   │   │   ├── UpdateProductRequest.php
│   │   │   └── ...
│   │   └── Resources/
│   │       ├── ProductResource.php
│   │       ├── VendorResource.php
│   │       └── ...
│   ├── Models/
│   │   ├── Product.php
│   │   ├── Vendor.php
│   │   ├── Event.php
│   │   ├── Inquiry.php
│   │   ├── Category.php
│   │   └── User.php
│   ├── Filament/
│   │   └── Resources/
│   │       ├── ProductResource.php
│   │       ├── VendorResource.php
│   │       └── ...
│   ├── Repositories/
│   │   ├── ProductRepository.php
│   │   ├── VendorRepository.php
│   │   └── ...
│   ├── Services/
│   │   ├── SearchService.php
│   │   └── InquiryService.php
│   ├── Traits/
│   │   ├── ApiResponse.php
│   │   └── FilterQueryBuilder.php
│   └── Exceptions/
│       └── Handler.php
│
├── database/
│   ├── migrations/     # Database schema files
│   ├── seeders/        # Sample data
│   └── factories/      # Model factories for testing
│
├── routes/
│   ├── api.php         # API routes
│   ├── web.php         # Web routes
│   └── channels.php    # Broadcast channels
│
├── config/
│   ├── app.php
│   ├── database.php
│   ├── cache.php
│   ├── cors.php
│   └── sanctum.php
│
├── tests/              # Unit & feature tests
├── .env.example        # Environment template
├── artisan             # Artisan CLI
└── composer.json       # Dependencies
```

## Getting Started

### Prerequisites

- PHP 8.2+
- MySQL 8.0+
- Composer
- Laravel 11+

### Installation

1. **Navigate to backend directory**:
```bash
cd backend
```

2. **Copy environment file**:
```bash
cp .env.example .env
```

3. **Install dependencies**:
```bash
composer install
```

4. **Generate application key**:
```bash
php artisan key:generate
```

5. **Configure database**:
Edit `.env` and set your database credentials:
```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=pharvion
DB_USERNAME=root
DB_PASSWORD=
```

6. **Create database**:
```bash
mysql -u root -p -e "CREATE DATABASE pharvion;"
```

7. **Run migrations**:
```bash
php artisan migrate
```

8. **Seed sample data** (optional):
```bash
php artisan db:seed
```

9. **Start the server**:
```bash
php artisan serve
```

The API will be available at `http://localhost:8000/api`

## API Documentation

Complete API documentation is in `/documentation/API_DOCUMENTATION.md`

### API Endpoints Summary

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/products` | List products with pagination |
| GET | `/api/products/{id}` | Get single product |
| POST | `/api/admin/products` | Create product (admin) |
| PUT | `/api/admin/products/{id}` | Update product (admin) |
| DELETE | `/api/admin/products/{id}` | Delete product (admin) |
| GET | `/api/vendors` | List vendors |
| GET | `/api/vendors/{id}` | Get single vendor |
| GET | `/api/events` | List events |
| GET | `/api/categories` | List categories |
| POST | `/api/inquiries` | Create inquiry |
| GET | `/api/search` | Global search |

## Authentication

### Sanctum Setup

Sanctum is already configured in `config/sanctum.php`.

### Admin Login

```bash
POST /api/auth/login

{
  "email": "admin@pharvion.com",
  "password": "password123"
}

Response:
{
  "success": true,
  "data": {
    "user": {...},
    "token": "abc123def456..."
  }
}
```

### Using Tokens

Add token to request headers:
```
Authorization: Bearer {token}
```

## Database Schema

Refer to `/documentation/DATABASE_SCHEMA.md` for complete schema documentation.

### Key Tables

- **categories**: Product categories
- **vendors**: Vendor information
- **products**: Pharmaceutical products
- **events**: Industry events
- **inquiries**: Customer inquiries
- **users**: Admin users
- **personal_access_tokens**: Sanctum tokens

## Eloquent Models

### Product Model

```php
class Product extends Model
{
    protected $fillable = ['product_name', 'generic_name', 'category_id', ...];
    
    public function category()
    {
        return $this->belongsTo(Category::class);
    }
    
    public function vendor()
    {
        return $this->belongsTo(Vendor::class);
    }
    
    public function inquiries()
    {
        return $this->hasMany(Inquiry::class);
    }
}
```

### Vendor Model

```php
class Vendor extends Model
{
    protected $fillable = ['company_name', 'phone', 'email', ...];
    
    public function products()
    {
        return $this->hasMany(Product::class);
    }
}
```

### Event Model

```php
class Event extends Model
{
    protected $fillable = ['title', 'description', 'location', ...];
    protected $casts = [
        'start_date' => 'datetime',
        'end_date' => 'datetime',
        'is_featured' => 'boolean',
    ];
}
```

### Inquiry Model

```php
class Inquiry extends Model
{
    protected $fillable = ['product_id', 'name', 'company', ...];
    
    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}
```

## Repository Pattern

Repositories encapsulate data access logic:

```php
class ProductRepository
{
    public function getAll($page = 1, $perPage = 20, $filters = [])
    {
        return Product::with(['category', 'vendor'])
            ->when($filters['category_id'] ?? null, fn($q) => 
                $q->where('category_id', $filters['category_id']))
            ->when($filters['search'] ?? null, fn($q) => 
                $q->whereFullText(['product_name', 'generic_name'], $filters['search']))
            ->paginate($perPage, ['*'], 'page', $page);
    }
}
```

## API Resources

Resources transform models into consistent JSON responses:

```php
class ProductResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'product_name' => $this->product_name,
            'generic_name' => $this->generic_name,
            'category' => new CategoryResource($this->whenLoaded('category')),
            'vendor' => new VendorResource($this->whenLoaded('vendor')),
            'cas_number' => $this->cas_number,
            'purity' => $this->purity,
            'moq' => $this->moq,
            'moq_unit' => $this->moq_unit,
            'created_at' => $this->created_at->toIso8601String(),
        ];
    }
}
```

## Form Requests

Validation is handled in Form Request classes:

```php
class StoreProductRequest extends FormRequest
{
    public function authorize(): bool
    {
        return auth()->check() && auth()->user()->role === 'admin';
    }

    public function rules(): array
    {
        return [
            'product_name' => 'required|string|max:255|unique:products',
            'category_id' => 'required|exists:categories,id',
            'vendor_id' => 'required|exists:vendors,id',
            'purity' => 'nullable|regex:/^(100|[1-9]?[0-9])\.?[0-9]*%?$/',
            'moq' => 'nullable|integer|min:1',
        ];
    }
}
```

## Admin Panel (Filament)

Access the admin panel at:
```
http://localhost:8000/admin
```

### Features

- Manage products, vendors, events, and categories
- View and respond to inquiries
- User management
- Analytics dashboard

### Creating a Filament Resource

```php
class ProductResource extends Resource
{
    protected static ?string $model = Product::class;

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                TextInput::make('product_name')
                    ->required()
                    ->maxLength(255),
                Select::make('category_id')
                    ->relationship('category', 'name')
                    ->required(),
                // ... more fields
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                TextColumn::make('product_name'),
                TextColumn::make('vendor.company_name'),
                TextColumn::make('category.name'),
            ]);
    }
}
```

## Middleware

Custom middleware for API requests:

```php
// app/Http/Middleware/ApiResponse.php
class ApiResponse
{
    public function handle(Request $request, Closure $next)
    {
        // Add JSON response wrapper
        $response = $next($request);
        
        if ($request->wantsJson()) {
            return $this->wrapResponse($response);
        }
        
        return $response;
    }
}
```

## Traits

Reusable traits for common functionality:

```php
// app/Traits/ApiResponse.php
trait ApiResponse
{
    protected function success($data = null, $message = 'Success', $status = 200)
    {
        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => $data,
        ], $status);
    }

    protected function error($message = 'Error', $errors = null, $status = 400)
    {
        return response()->json([
            'success' => false,
            'message' => $message,
            'errors' => $errors,
        ], $status);
    }
}
```

## Caching

Implement query caching for performance:

```php
public function getPopularProducts($limit = 10)
{
    return Cache::remember('popular_products', 3600, function () use ($limit) {
        return Product::popular()->limit($limit)->get();
    });
}
```

## Full-Text Search

MySQL full-text search implementation:

```php
Product::whereFullText(['product_name', 'generic_name', 'description'], $query)
    ->get();
```

## API Response Format

All API responses follow this structure:

```json
{
  "success": true,
  "message": "Operation successful",
  "data": {
    "items": [],
    "pagination": {
      "total": 100,
      "per_page": 20,
      "current_page": 1,
      "last_page": 5
    }
  }
}
```

## Error Handling

Centralized error handling in exception handler:

```php
// app/Exceptions/Handler.php
public function render($request, Throwable $exception)
{
    if ($exception instanceof ModelNotFoundException) {
        return response()->json([
            'success' => false,
            'message' => 'Resource not found',
        ], 404);
    }

    return parent::render($request, $exception);
}
```

## Testing

Run tests with Pest:

```bash
# All tests
php artisan test

# Specific test file
php artisan test tests/Feature/ProductControllerTest.php

# With coverage
php artisan test --coverage
```

### Example Test

```php
test('can retrieve products', function () {
    $products = Product::factory(10)->create();
    
    $response = $this->getJson('/api/products');
    
    $response->assertStatus(200)
        ->assertJsonCount(10, 'data.items');
});
```

## Performance Optimization

### Database Queries

```php
// Use eager loading to prevent N+1
Product::with(['category', 'vendor'])->get();

// Select specific columns
Product::select(['id', 'product_name', 'category_id'])->get();

// Use pagination
Product::paginate(20);
```

### Caching

```php
// Cache frequently accessed data
Cache::remember('categories', 3600, function () {
    return Category::with('products')->get();
});
```

### Indexing

All tables have proper indexes defined in migrations for:
- Foreign keys
- Frequently searched columns
- Frequently filtered columns
- Full-text search fields

## Rate Limiting

Configure in `.env`:
```
API_RATE_LIMIT=100        # Requests
API_RATE_LIMIT_WINDOW=60  # Seconds
```

Apply to routes:
```php
Route::middleware('throttle:100,60')->group(function () {
    // API routes
});
```

## Logging

Configure logging in `config/logging.php`:

```php
\Log::info('Product retrieved', ['product_id' => $id]);
\Log::error('API error', ['error' => $exception->getMessage()]);
```

View logs:
```bash
tail -f storage/logs/laravel.log
```

## Deployment

### Production Checklist

- [ ] Set `APP_DEBUG=false` in `.env`
- [ ] Generate JWT secret: `php artisan jwt:generate`
- [ ] Run migrations: `php artisan migrate --force`
- [ ] Optimize for production:
  ```bash
  php artisan config:cache
  php artisan route:cache
  php artisan view:cache
  php artisan optimize
  ```
- [ ] Set up SSL/HTTPS
- [ ] Configure CORS properly
- [ ] Set up proper logging
- [ ] Configure error reporting (Sentry, etc.)

### Deployment to DigitalOcean

```bash
# SSH into server
ssh root@your_server_ip

# Clone repository
git clone your_repo.git
cd backend

# Install dependencies
composer install --no-dev

# Setup environment
cp .env.example .env
php artisan key:generate
php artisan jwt:secret

# Database
php artisan migrate --force

# Optimize
php artisan config:cache
php artisan route:cache

# Start server (use supervisor for long-running)
php artisan serve --host=0.0.0.0 --port=8000
```

## Resources

- [Laravel Documentation](https://laravel.com/docs)
- [Sanctum Documentation](https://laravel.com/docs/sanctum)
- [Filament Documentation](https://filamentphp.com)
- [Eloquent ORM](https://laravel.com/docs/eloquent)
- [API Best Practices](https://restfulapi.net/)

## License

Proprietary - PHARVION Platform

## Support

For development issues, refer to the main project `/documentation/SETUP_GUIDE.md`
