# RamionMarketplace Project Analysis & Conventions

## 1. Project Modules
Your project follows a modular architecture. Under `app/Http/Controllers`, there is a separate directory for each major feature/module. The current modules in the system are:
- **Auth**: Handles registration, login, logout, and authenticated user profile retrieval.
- **User**: Manages user records, including creation, listing, updating, and deletion.
- **Role**: Manages roles inside the system.
- **Permission**: Manages system permissions.
- **SmtpConfig**: Handles mail/SMTP configuration details.
- **Media**: Handles file uploads, storage, deletion, and streaming of files.

## 2. Authentication System (Auth & Guards)
The authentication system is custom-built using **JWT (JSON Web Tokens)** rather than standard Laravel Session or Sanctum guards.
- **Guard (`JwtGuard.php`)**: Implements Laravel's `Guard` interface. It retrieves the token from the request. It primarily checks an HTTP-only Cookie (`accessToken`), falling back to the `Authorization` bearer header or a query parameter `token`.
- **Service (`JwtService.php`)**: Handles actual token generation, decoding, and validation, resolving the corresponding User ID from the payload.
- **Login Flow (`AuthController.php`)**: When a user logs in, the system validates the email and password hash. It then generates a JWT token and returns it inside a **Secure, HTTP-only Cookie** named `accessToken`. This ensures the token is automatically sent on succeeding requests while keeping it safe from XSS attacks.

## 3. CRUD Architecture (Model, Repository, Controller, Resource)
The project is built on top of the **Repository Pattern**, decoupling data access from business logic:
- **BaseRepository**: A generic repository class (`BaseRepository.php`) providing common database operations like `all()`, `find()`, `create()`, `update()`, `delete()`, `paginated()`, and `count()`.
- **Controller**: Every controller extends a base `Controller` class and injects its respective repository via Dependency Injection. The base `Controller` provides helper methods `successResponse()` and `errorResponse()` to guarantee uniform JSON response shapes across the API.
- **Traits**: The models utilize several traits (`HasFilter`, `HasSearch`, `HasSort`, `HasPagination`) to automatically handle searching, filtering, and pagination within the query builder pipeline of the `BaseRepository`.
- **Resource**: Formats API responses uniformly using Laravel Resources.
- **Requests**: Form-requests (e.g., `StoreUserRequest`) are used to decouple and encapsulate validation logic.

## 4. Models, Migrations & Routes
- **Migration**: String-based UUID primary keys (50 characters) are used instead of auto-incrementing integer IDs. Timestamps are also stored in camelCase format (`createdAt`, `updatedAt`) instead of standard snake_case.
- **Routes**: Instead of declaring all routes inside a single `routes/api.php` file, each module has its own `routes.php` file (e.g., `app/Http/Controllers/User/routes.php`). These are registered inside `routes/api.php` via `require` statements wrapped inside route prefixes.

## 5. File Upload (Media Module)
File uploads are handled by the `MediaController`:
- Files are saved on the `public` storage disk under the `media/{year}/{month}/` directory structure.
- The controller handles both single and multiple file uploads.
- Metadata (file name, original name, MIME type, file size, storage path) is persisted in the database via the `MediaRepository`.
- For private files, security is enforced using a `stream` method in the controller that checks whether the authenticated user has permission (ownership or admin role) before returning the file content as an inline stream.

---

## 6. How to Add a New Module (Step-by-Step Convention)

If you need to introduce a new module (e.g., `Product`), you should follow the structure outlined below to maintain codebase consistency:

### Step 1: Create Migration & Model
Ensure the migration specifies `id` as a 50-character primary string, and uses camelCase timestamps:
```php
$table->string('id', 50)->primary();
// ... your columns
$table->timestamp('createdAt');
$table->timestamp('updatedAt');
```
In your Model, register the required traits and override the default timestamp column names:
```php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Traits\HasCustomUuid;
use App\Traits\HasSearch;
use App\Traits\HasFilter;

class Product extends Model {
    use HasCustomUuid, HasSearch, HasFilter;

    const CREATED_AT = 'createdAt';
    const UPDATED_AT = 'updatedAt';
    
    protected $fillable = [
        // fillable properties
    ];
}
```

### Step 2: Create Validation Requests
Create `StoreProductRequest.php` and `UpdateProductRequest.php` inside `app/Http/Requests/Product/` to handle input validation.

### Step 3: Create Resource
Create `app/Http/Resources/ProductResource.php` to define the output format of the resource.

### Step 4: Create Repository
Create `app/Http/Controllers/Product/ProductRepository.php` extending the `BaseRepository`:
```php
namespace App\Http\Controllers\Product;

use App\Http\Controllers\BaseRepository;
use App\Models\Product;

class ProductRepository extends BaseRepository {
    public function __construct(Product $model) {
        parent::__construct($model);
    }
}
```

### Step 5: Create Controller
Create `app/Http/Controllers/Product/ProductController.php` extending `Controller` and inject `ProductRepository`:
```php
namespace App\Http\Controllers\Product;

use App\Http\Controllers\Controller;
use App\Http\Requests\Product\StoreProductRequest;
use App\Http\Requests\Product\UpdateProductRequest;
use App\Http\Resources\ProductResource;
use Illuminate\Http\JsonResponse;

class ProductController extends Controller {
    protected ProductRepository $repository;
    
    public function __construct(ProductRepository $repository) {
        $this->repository = $repository;
    }
    
    public function list(): JsonResponse {
        $products = $this->repository->paginated();
        $total = $this->repository->count();
        return $this->successResponse('Products retrieved successfully', ProductResource::collection($products), $total);
    }
    
    public function create(StoreProductRequest $request): JsonResponse {
        $validated = $request->validated();
        $product = $this->repository->create($validated);
        return $this->successResponse('Product created successfully', new ProductResource($product), null, 201);
    }

    public function single($id): JsonResponse {
        $product = $this->repository->find($id);
        if (!$product) {
            $this->notFound('Product not found');
        }
        return $this->successResponse('Product retrieved successfully', new ProductResource($product));
    }

    public function update(UpdateProductRequest $request, $id): JsonResponse {
        $validated = $request->validated();
        $product = $this->repository->update($id, $validated);
        if (!$product) {
            $this->notFound('Product not found');
        }
        return $this->successResponse('Product updated successfully', new ProductResource($product));
    }

    public function delete($id): JsonResponse {
        $product = $this->repository->find($id);
        if (!$product) {
            $this->notFound('Product not found');
        }
        $this->repository->delete($id);
        return $this->successResponse('Product deleted successfully');
    }
}
```

### Step 6: Create Routes
Create a `routes.php` file inside the module directory `app/Http/Controllers/Product/routes.php`:
```php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Product\ProductController;

Route::middleware('auth')->group(function () {
    Route::get('/', [ProductController::class, 'list']);
    Route::post('/', [ProductController::class, 'create']);
    Route::get('/{id}', [ProductController::class, 'single']);
    Route::put('/{id}', [ProductController::class, 'update']);
    Route::delete('/{id}', [ProductController::class, 'delete']);
});
```

### Step 7: Register Routes in `api.php`
Register your module routes inside `routes/api.php`:
```php
Route::prefix('product')->group(function () {
    require __DIR__ . '/../app/Http/Controllers/Product/routes.php';
});
```
