# Laravel Enterprise Coding Standard & Architecture Rules

This coding standard is mandatory for Laravel backend development in ERPFlow.

---

# 1. Core Architecture

Use Service Repository Architecture as the primary application architecture.

For major domains/modules, prefer:

```text
Controller
Form Request
Service Interface
Service Implementation
Repository Interface
Repository Implementation
Model
Resource / Transformer
DTO when required
```

The exact structure may be adapted for genuinely simple cases, but the
architecture must not be bypassed without a valid reason.

---

# 2. Service Interface

Every application Service MUST have an interface.

Example:

```php
interface TaskServiceInterface
{
    public function create(array $data): Task;
}
```

Controllers depend on Service Interfaces.

Services must not depend directly on concrete repositories.

---

# 3. Repository Interface

Every Repository MUST have an interface.

Example:

```php
interface TaskRepositoryInterface
{
    public function create(array $data): Task;
}
```

Bind interfaces through the appropriate Service Provider.

```php
$this->app->bind(
    TaskServiceInterface::class,
    TaskService::class
);

$this->app->bind(
    TaskRepositoryInterface::class,
    TaskRepository::class
);
```

---

# 4. Controller Responsibility

Controllers MUST remain thin.

Controllers may:

- Receive validated request
- Call Service
- Return response
- Handle application-level exceptions according to project convention

Controllers MUST NOT contain:

- Business logic
- Query logic
- Complex calculations
- Approval decisions
- Workflow decisions
- Permission business rules
- Multi-step database operations

---


# 5. Controller Exception Handling

Every controller method MUST use try/catch according to project convention.

```php
public function store(StoreTaskRequest $request)
{
    try {
        $task = $this->taskService->create($request->validated());

        return $this->successResponse($task, 'Task created successfully');
    } catch (Throwable $e) {
        report($e);

        return $this->errorResponse('Failed to create task', 500);
    }
}
```

Never expose raw exception messages to users in production.

---

# 6. Controller Request Handling

Do not pass raw Request objects into Services.

Wrong:

```php
$this->taskService->create($request);
```

Correct:

```php
$this->taskService->create($request->validated());
```

Or:

```php
$this->taskService->create(
    CreateTaskData::fromRequest($request)
);
```

---

# 7. Form Request

Create/Update operations MUST use Form Requests.

Examples:

```text
StoreTaskRequest
UpdateTaskRequest
ApproveTaskRequest
AssignRoleRequest
CreateWorkflowRequest
```

Validation belongs in Form Requests.

Do not duplicate validation rules inside controllers unless a genuinely dynamic
business validation is required.

---

# 8. Service Layer

Business logic MUST reside in Services.

Examples:

- Approval rules
- Permission decisions related to business state
- Status transitions
- Calculations
- Workflow orchestration
- Contract assignment
- Commission calculation
- Business validations
- Notification decisions
- Data transformation before persistence

Services may coordinate repositories, events, jobs, and domain operations.

Any Service method that performs a database write MUST run inside
`DB::transaction`. Controllers that trigger those writes MUST use try/catch
(see Controller Exception Handling).

---

# 9. Repository Layer

Repositories are responsible for database access.

Repositories may contain:

- create
- update
- delete
- find
- findById
- findBySlug
- filtering
- pagination
- relationship loading
- simple database queries

Repositories MUST NOT contain:

- Business decisions
- Approval logic
- Permission decisions
- Workflow decisions
- Notifications
- Complex business calculations

Repositories MUST inject the Eloquent model in the constructor and access it
only through `$this->model`.

Do NOT call the model class directly inside repositories.

Required pattern:

```php
protected $model;

public function __construct(BareboneModelDescription $model)
{
    $this->model = $model;
}

public function store($data)
{
    return $this->model->updateOrCreate(
        [
            'id' => $data['id'] ?? null,
        ],
        $data
    );
}

public function query()
{
    return $this->model->query();
}
```

Wrong:

```php
BareboneModelDescription::create($data);
BareboneModelDescription::where('id', $id)->first();
BareboneModelDescription::query()->paginate();
```

Correct:

```php
$this->model->create($data);
$this->model->where('id', $id)->first();
$this->model->query()->paginate();
```

---

# 10. Transactions

Any database write operation MUST run inside a database transaction in the
Service layer.

This includes single-record and multi-step writes:

- Create
- Update
- Delete
- Approval
- Workflow transition
- Role assignment
- Permission changes
- Contract assignment
- Status changes
- Financial operations
- Multi-table writes

Transactions MUST be controlled by the Service layer.

Repositories MUST NOT open transactions.

Controllers that trigger write operations MUST use try/catch (see Controller
Exception Handling).

Wrong:

```php
public function create(array $data): Task
{
    return $this->taskRepository->create($data);
}
```

Correct:

```php
public function create(array $data): Task
{
    return DB::transaction(function () use ($data) {
        return $this->taskRepository->create($data);
    });
}
```

---

# 11. API Response

All APIs MUST follow the project's standardized response format.

Success:

```json
{
  "success": true,
  "message": "Operation successful",
  "data": {}
}
```

Error:

```json
{
  "success": false,
  "message": "Something went wrong",
  "errors": {}
}
```

Use the project's reusable response helper/trait.

---

# 12. API Resources

Do not return raw Eloquent models directly from API controllers.

Use API Resources.

```php
return $this->successResponse(
    new TaskResource($task),
    'Task fetched successfully'
);
```

For collections:

```php
return TaskResource::collection($tasks);
```

---

# 13. DTO

Use DTOs when payloads are:

- Complex
- Reused
- Passed across multiple layers
- Difficult to understand as raw arrays

Examples:

```text
CreateTaskData
UpdateEmployeeData
ApprovalRequestData
```

Do not create DTOs for every trivial one-field operation.

---

# 14. Events and Listeners

Use Events and Listeners for side effects where appropriate.

Examples:

- Notifications
- Activity logs
- Email
- External integration
- Secondary processing

Example:

```php
event(new TaskCreated($task));
```

Do not put unrelated side effects directly into controllers.

---

# 15. Jobs

Use queued Jobs for heavy or asynchronous processing.

Examples:

- Email
- Report generation
- Import
- Export
- Large file processing
- Large notifications
- Long-running integrations

Do not block HTTP requests unnecessarily.

---

# 16. Authorization

Authorization must use:

- Policies
- Gates
- Permission middleware
- Permission services

Do not repeatedly implement authorization logic manually in controllers.

---

# 17. Models

Models may contain:

- Relationships
- Casts
- Accessors
- Mutators
- Scopes
- Small helper methods

Models MUST NOT contain large business workflows.

Avoid fat models.

---

# 18. Naming

Use consistent names.

```text
TaskController
TaskServiceInterface
TaskService
TaskRepositoryInterface
TaskRepository
StoreTaskRequest
TaskResource
CreateTaskData
TaskCreated
GenerateTaskReportJob
```

---

# 19. Method Naming

Prefer explicit names.

Repository:

```text
findById()
findBySlug()
getPaginated()
create()
update()
delete()
```

Service:

```text
createTask()
updateTask()
deleteTask()
approveTask()
assignTask()
changeStatus()
```

Avoid vague names:

```text
process()
handle()
manage()
doWork()
```

unless the class/context genuinely makes the meaning clear.

---

# 20. No Direct Database Query in Controller

Never use:

```php
Model::where(...)
DB::table(...)
DB::transaction(...)
```

inside Controllers.

Controllers call Services.

---

# 21. Logging

Use appropriate logging:

```php
report($e);

Log::info(...);
Log::warning(...);
Log::error(...);
```

Never expose raw exception messages to users in production.

---

# 22. Exceptions

Use domain/application exceptions when business rules require them.

Examples:

```text
ApprovalRequiredException
PermissionDeniedException
WorkflowNotFoundException
InvalidStatusTransitionException
```

Services may throw domain exceptions.

---

# 23. Status Management

Use Enum or constants for controlled statuses.

Example:

```php
enum ApprovalStatus: string
{
    case Pending = 'pending';
    case Approved = 'approved';
    case Rejected = 'rejected';
}
```

Do not scatter arbitrary status strings throughout the application.

---

# 24. Configuration-Driven Design

Keep configurable concerns configurable where appropriate.

Examples:

- Modules
- Actions
- Permissions
- Roles
- Menus
- Approval workflows
- Notification templates
- Settings

Do not hardcode framework-level business configuration unnecessarily.

---

# 25. Avoid Unnecessary Abstraction

The architecture requires Interfaces, but that does NOT mean every piece of
code should receive additional abstractions.

Do not introduce:

- Generic repositories
- Generic CRUD services
- Unnecessary base classes
- Unnecessary factories
- Unnecessary wrappers
- Unnecessary event buses

unless the project has a real architectural requirement.

---

# 26. Layer Separation

Maintain:

```text
Controller
    ↓
Service Interface
    ↓
Service
    ↓
Repository Interface
    ↓
Repository
    ↓
Model / Database
```

Cross-cutting concerns such as authorization, events, jobs, and resources should
be introduced at their appropriate boundaries.

---

# 27. Final Architecture Checklist

Before completing a Laravel backend implementation:

- [ ] Correct module identified
- [ ] Controller is thin
- [ ] Controller try/catch present
- [ ] Write path covered by try/catch
- [ ] Form Request used
- [ ] Service Interface exists
- [ ] Service implementation exists
- [ ] Repository Interface exists
- [ ] Repository implementation exists
- [ ] Repository uses `$this->model` (no direct `Model::` usage)
- [ ] Database logic remains in Repository
- [ ] Business logic remains in Service
- [ ] DB write wrapped in `DB::transaction` (Service)
- [ ] Resource used for API response
- [ ] DTO added if genuinely needed
- [ ] Authorization handled appropriately
- [ ] Events/Jobs used where appropriate
- [ ] Existing conventions preserved
