# Sector Module Documentation

## Overview

The Sector module provides a complete CRUD (Create, Read, Update, Delete) system for managing business sectors. Each sector has a name and an optional image. The module includes a service layer for business logic, a controller for handling HTTP requests, and proper route definitions.

## Architecture

### Components

1. **Model**: `app/Models/Sector.php`
   - Handles database interactions
   - Uses soft deletes
   - Includes relationships for tracking who added/updated records

2. **Service**: `app/Services/SectorService.php`
   - Contains all business logic
   - Manages file uploads and deletions
   - Handles create, read, update, delete operations

3. **Controller**: `app/Http/Controllers/SectorController.php`
   - Handles HTTP requests/responses
   - Validates input data
   - Delegates business logic to the service

4. **Routes**: `routes/sectors.php`
   - Defines all API endpoints
   - Separates public (read-only) from protected routes

## Database Schema

```sql
CREATE TABLE sectors (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    image VARCHAR(255) NULL,
    added_by BIGINT UNSIGNED NULL,
    updated_by BIGINT UNSIGNED NULL,
    deleted_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (added_by) REFERENCES users(id),
    FOREIGN KEY (updated_by) REFERENCES users(id)
);
```

### Fields

- `id`: Primary key
- `name`: Sector name (required, max 255 characters)
- `image`: Path to sector image stored in `storage/app/public/sectors/` (optional)
- `added_by`: User ID who created the sector
- `updated_by`: User ID who last updated the sector
- `deleted_at`: Soft delete timestamp
- `created_at`: Record creation timestamp
- `updated_at`: Record last update timestamp

## API Endpoints

### Public Endpoints (No Authentication Required)

#### 1. Get All Sectors
```http
GET /api/sectors
```

**Response:**
```json
[
  {
    "id": 1,
    "name": "Technology",
    "image": "http://localhost:8000/storage/sectors/abc123.jpg",
    "added_by": 1,
    "updated_by": 1,
    "created_at": "2024-01-01T00:00:00.000000Z",
    "updated_at": "2024-01-01T00:00:00.000000Z",
    "added_by": {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com"
    },
    "updated_by": {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com"
    }
  }
]
```

#### 2. Get Sector by ID
```http
GET /api/sectors/{id}
```

**Response:**
```json
{
  "id": 1,
  "name": "Technology",
  "image": "http://localhost:8000/storage/sectors/abc123.jpg",
  "added_by": {...},
  "updated_by": {...}
}
```

**Error Response (404):**
```json
{
  "message": "Sector not found"
}
```

#### 3. Get Sector by Name
```http
GET /api/sectors/name/{name}
```

**Example:**
```http
GET /api/sectors/name/technology
```

### Protected Endpoints (Require Authentication)

All protected endpoints require a Sanctum authentication token:
```http
Authorization: Bearer YOUR_TOKEN_HERE
```

#### 4. Create Sector
```http
POST /api/sectors
Authorization: Bearer {token}
Content-Type: multipart/form-data OR application/json
```

**Request Body (JSON without image):**
```json
{
  "name": "Healthcare"
}
```

**Request Body (Form Data with image):**
```
name: Healthcare
image: [file upload]
```

**Validation Rules:**
- `name`: required, string, max 255 characters, unique
- `image`: optional, must be an image file (jpeg, png, jpg, gif, webp), max 2MB

**Success Response (201):**
```json
{
  "message": "Sector created successfully",
  "sector": {
    "id": 2,
    "name": "Healthcare",
    "image": "http://localhost:8000/storage/sectors/xyz789.jpg",
    ...
  }
}
```

#### 5. Update Sector by ID
```http
POST /api/sectors/{id}
Authorization: Bearer {token}
Content-Type: multipart/form-data OR application/json
```

**Request Body (Optional fields):**
```json
{
  "name": "Advanced Technology"
}
```

**Validation Rules:**
- `name`: sometimes required, string, max 255 characters, unique except for current record
- `image`: optional, must be an image file (jpeg, png, jpg, gif, webp), max 2MB

**Note:** When updating with a new image, the old image will be automatically deleted.

**Success Response (200):**
```json
{
  "message": "Sector updated successfully",
  "sector": {...}
}
```

#### 6. Delete Sector by ID
```http
DELETE /api/sectors/{id}
Authorization: Bearer {token}
```

**Success Response (200):**
```json
{
  "message": "Sector deleted successfully"
}
```

**Note:** Deleting a sector will also delete its associated image file.

#### 7. Upsert Sector by Name
```http
POST /api/sectors/name/{name}
Authorization: Bearer {token}
Content-Type: multipart/form-data
```

Creates a new sector if the name doesn't exist, or updates the existing one.

**Example:**
```http
POST /api/sectors/name/Finance
```

**Success Response (200):**
```json
{
  "message": "Sector saved successfully",
  "sector": {...}
}
```

#### 8. Delete Sector by Name
```http
DELETE /api/sectors/name/{name}
Authorization: Bearer {token}
```

**Example:**
```http
DELETE /api/sectors/name/Technology
```

## Service Methods

### SectorService Methods

```php
// Get all sectors with relationships
listAll(): Collection

// Find sector by ID
findById(int $id): ?Sector

// Find sector by name
findByName(string $name): ?Sector

// Create new sector
create(array $data, ?UploadedFile $image = null): Sector

// Update existing sector
update(int $id, array $data, ?UploadedFile $image = null): ?Sector

// Delete sector by ID
delete(int $id): bool

// Create or update sector by name
upsertByName(string $name, array $data, ?UploadedFile $image = null): Sector

// Delete sector by name
deleteByName(string $name): bool
```

## File Storage

### Image Storage Location
- Images are stored in: `storage/app/public/sectors/`
- Publicly accessible via: `http://localhost:8000/storage/sectors/{filename}`

### Image Processing
- Accepted formats: JPEG, PNG, JPG, GIF, WEBP
- Maximum file size: 2MB
- Files are stored with random 40-character filenames to prevent conflicts
- Old images are automatically deleted when updating or deleting sectors

## Usage Examples

### Example 1: Create Sector with Image using cURL

```bash
curl -X POST http://localhost:8000/api/sectors \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "name=Technology" \
  -F "image=@/path/to/image.jpg"
```

### Example 2: Create Sector without Image

```bash
curl -X POST http://localhost:8000/api/sectors \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Healthcare"}'
```

### Example 3: Update Sector Name

```bash
curl -X POST http://localhost:8000/api/sectors/1 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Advanced Technology"}'
```

### Example 4: Get All Sectors (Public)

```bash
curl -X GET http://localhost:8000/api/sectors
```

### Example 5: Using the Service in Code

```php
use App\Services\SectorService;

class YourController extends Controller
{
    protected $sectorService;
    
    public function __construct(SectorService $sectorService)
    {
        $this->sectorService = $sectorService;
    }
    
    public function example(Request $request)
    {
        // Create a sector
        $sector = $this->sectorService->create(
            ['name' => 'Technology'],
            $request->file('image')
        );
        
        // Get all sectors
        $sectors = $this->sectorService->listAll();
        
        // Find by name
        $sector = $this->sectorService->findByName('Technology');
        
        // Update
        $sector = $this->sectorService->update(
            1,
            ['name' => 'Advanced Tech'],
            $request->file('image')
        );
        
        // Delete
        $this->sectorService->delete(1);
    }
}
```

## Model Features

### Relationships

```php
// Get the user who created the sector
$sector->addedBy; // Returns User model

// Get the user who last updated the sector
$sector->updatedBy; // Returns User model
```

### Image Accessor

The image attribute automatically converts the storage path to a full URL:

```php
// Database: sectors/abc123.jpg
// Accessor returns: http://localhost:8000/storage/sectors/abc123.jpg
$sector->image;
```

### Soft Deletes

Sectors use soft deletes, meaning deleted records are not permanently removed:

```php
// Soft delete
$sector->delete();

// Get trashed sectors
Sector::onlyTrashed()->get();

// Restore a soft-deleted sector
$sector->restore();

// Permanently delete
$sector->forceDelete();
```

## Security Features

1. **Authentication**: All write operations (create, update, delete) require authentication via Laravel Sanctum
2. **Validation**: Input data is validated before processing
3. **File Upload Security**: 
   - Only image files are accepted
   - File size limited to 2MB
   - Files stored with random names to prevent path injection
4. **Soft Deletes**: Accidental deletions can be recovered
5. **Audit Trail**: `added_by` and `updated_by` fields track user actions

## Error Handling

### Common Error Responses

**400 Bad Request - Validation Error:**
```json
{
  "message": "The given data was invalid.",
  "errors": {
    "name": ["The name field is required."],
    "image": ["The image must be an image file."]
  }
}
```

**401 Unauthorized:**
```json
{
  "message": "Unauthenticated."
}
```

**404 Not Found:**
```json
{
  "message": "Sector not found"
}
```

**422 Unprocessable Entity - Duplicate Name:**
```json
{
  "message": "The given data was invalid.",
  "errors": {
    "name": ["The name has already been taken."]
  }
}
```

## Testing

To test the Sector module, you can use:

1. **Postman**: Import the endpoints and test with your local server
2. **REST Client (VS Code)**: Use the `API_EXAMPLES.http` file
3. **PHP Unit Tests**: Create test cases in `tests/Feature/SectorTest.php`

### Example Test Case

```php
public function test_can_create_sector()
{
    $user = User::factory()->create();
    
    $response = $this->actingAs($user)
        ->postJson('/api/sectors', [
            'name' => 'Test Sector'
        ]);
    
    $response->assertStatus(201)
        ->assertJson([
            'message' => 'Sector created successfully'
        ]);
    
    $this->assertDatabaseHas('sectors', [
        'name' => 'Test Sector'
    ]);
}
```

## Best Practices

1. **Always use the Service Layer**: Don't bypass the service and interact directly with the model in controllers
2. **Handle Images Properly**: The service automatically manages image uploads and deletions
3. **Use Eager Loading**: When fetching sectors, use `with(['addedBy', 'updatedBy'])` to avoid N+1 queries
4. **Validate Input**: Always validate user input in the controller before passing to the service
5. **Error Handling**: Check for null returns from service methods that might not find records

## Future Enhancements

Potential improvements for the Sector module:

1. Add description field to sectors
2. Implement sector categories or hierarchies
3. Add sorting and pagination to list endpoints
4. Implement search functionality
5. Add bulk operations (import/export)
6. Add image optimization and thumbnail generation
7. Implement versioning for sectors
8. Add more detailed audit logging

## Troubleshooting

### Images not displaying
- Ensure the storage link is created: `php artisan storage:link`
- Check file permissions on `storage/app/public/sectors/`
- Verify the APP_URL in `.env` is correct

### Upload fails
- Check `php.ini` settings: `upload_max_filesize` and `post_max_size`
- Ensure the `storage/app/public/sectors/` directory exists and is writable
- Verify image file is under 2MB

### Authentication issues
- Ensure Sanctum is properly configured
- Check that the token is included in the Authorization header
- Verify the token is valid and not expired
