# Guia: Como Adicionar uma Nova Funcionalidade

Este guia descreve o passo a passo para implementar uma nova funcionalidade seguindo a arquitetura já usada no projeto: Controllers finos, Requests para validação, DTOs para transporte de dados, Services para regra de negócio, Repositories para acesso a dados, e Resources para a resposta da API.

## 1. Visão geral do fluxo

Toda requisição autenticada de tenant passa pelo seguinte fluxo, na ordem:

```
Rota (routes/api.php)
  → Middleware identify.tenant / ensure.tenant.db
    → FormRequest (valida a entrada)
      → DTO (empacota os dados validados)
        → Controller (orquestra, sem lógica de negócio)
          → Service (Contract + implementação — regra de negócio)
            → Repository (Contract + implementação — acesso ao Model/DB)
              → Model (Central ou Tenant)
        ← Resource (formata a resposta)
```

Cada camada só conhece a interface (`Contract`) da camada seguinte, nunca a implementação concreta. O binding entre interface e implementação é feito em `app/Providers/AppServiceProvider.php`.

## 2. Onde cada arquivo entra

| Camada | Pasta | Exemplo existente |
|---|---|---|
| Rotas | `routes/api.php` | grupo `v1`, middleware `identify.tenant` |
| Middleware | `app/Http/Middleware/` | `IdentifyTenant.php`, `EnsureTenantDatabase.php` |
| Validação | `app/Http/Requests/` | `LoginRequest.php` |
| DTO | `app/DTOs/` | `AuthLoginDTO.php` |
| Controller | `app/Http/Controllers/Api/V1/` | `AuthController.php` |
| Contrato de Service | `app/Services/Contracts/` | `AuthServiceContract.php` |
| Service | `app/Services/` | `AuthService.php` |
| Contrato de Repository | `app/Repositories/Contracts/` | `UserRepositoryInterface.php` |
| Repository | `app/Repositories/` | `EloquentUserRepository.php` |
| Model | `app/Models/Central/` ou `app/Models/Tenant/` | `Tenant.php`, `User.php` |
| Resource | `app/Http/Resources/` | `UserResource.php` |
| Migration | `database/central/migrations/` ou `database/tenant/migrations/` | `create_usuarios_table.php` |
| Binding | `app/Providers/AppServiceProvider.php` | `register()` |

**Central vs Tenant:** dados que valem para todos os clientes (ex.: cadastro de tenants) ficam na conexão `central`. Dados específicos de cada cliente (ex.: usuários, dados de negócio) ficam na conexão `tenant`, que é trocada dinamicamente pelo middleware `IdentifyTenant` a cada requisição.

## 3. Passo a passo com exemplo

Exemplo prático: adicionar um endpoint `GET /api/v1/me` que retorna os dados do usuário autenticado.

### 3.1. Repository (se precisar de uma nova consulta)

Se a consulta necessária já existe no contrato (ex.: `findByLogin`), pule esta etapa. Caso contrário, adicione o método ao contrato e implemente-o:

```php
// app/Repositories/Contracts/UserRepositoryInterface.php
public function findById(int $id): ?User;
```

```php
// app/Repositories/EloquentUserRepository.php
public function findById(int $id): ?User
{
    return User::find($id);
}
```

Nunca chame `App\Models\...` diretamente de um Controller ou Service — sempre passe pelo Repository.

### 3.2. DTO (quando há dados de entrada)

Endpoints somente de leitura, sem payload, geralmente não precisam de DTO (o exemplo `/me` não precisa). Quando o endpoint recebe dados (ex.: atualizar perfil), crie um DTO imutável:

```php
// app/DTOs/UpdateProfileDTO.php
namespace App\DTOs;

readonly class UpdateProfileDTO
{
    public function __construct(
        public string $nome,
        public string $email,
    ) {}

    public static function fromRequest($request): self
    {
        return new self(
            nome: $request->input('nome'),
            email: $request->input('email'),
        );
    }
}
```

### 3.3. FormRequest (validação)

```php
// app/Http/Requests/UpdateProfileRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UpdateProfileRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // a autorização de tenant já ocorreu no middleware
    }

    public function rules(): array
    {
        return [
            'nome' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email'],
        ];
    }
}
```

### 3.4. Contrato de Service + Service (regra de negócio)

```php
// app/Services/Contracts/UserServiceContract.php
namespace App\Services\Contracts;

use App\Models\Tenant\User;

interface UserServiceContract
{
    public function getAuthenticatedUser(User $user): User;
}
```

```php
// app/Services/UserService.php
namespace App\Services;

use App\Models\Tenant\User;
use App\Services\Contracts\UserServiceContract;

class UserService implements UserServiceContract
{
    public function getAuthenticatedUser(User $user): User
    {
        return $user;
    }
}
```

Toda regra de negócio (validações de domínio, cálculos, orquestração de múltiplos repositories) vive aqui — nunca no Controller.

### 3.5. Registrar o binding

```php
// app/Providers/AppServiceProvider.php
public function register(): void
{
    $this->app->bind(UserRepositoryInterface::class, EloquentUserRepository::class);
    $this->app->bind(AuthServiceContract::class, AuthService::class);
    $this->app->bind(UserServiceContract::class, UserService::class); // nova linha
}
```

Sem esse binding, o Laravel não sabe qual implementação injetar quando o Controller pedir o `Contract` no construtor.

### 3.6. Resource (formato da resposta)

Reaproveite `UserResource` se os campos já servirem; caso contrário, crie um novo em `app/Http/Resources/`.

### 3.7. Controller

```php
// app/Http/Controllers/Api/V1/UserController.php
namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use App\Services\Contracts\UserServiceContract;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;

class UserController extends Controller
{
    public function __construct(
        protected UserServiceContract $userService
    ) {}

    public function me(Request $request): JsonResponse
    {
        $user = $this->userService->getAuthenticatedUser($request->user());

        return response()->json(new UserResource($user));
    }
}
```

O Controller apenas: recebe a requisição já validada, monta o DTO (quando houver), chama o Service, e devolve a resposta via Resource. Nenhuma regra de negócio ou query deve aparecer aqui.

### 3.8. Rota

```php
// routes/api.php
use App\Http\Controllers\Api\V1\UserController;

Route::prefix('v1')->group(function () {
    Route::middleware(['identify.tenant'])->group(function () {
        Route::post('/login', [AuthController::class, 'login']);
        Route::post('/password/forgot', [PasswordResetController::class, 'forgot']);
        Route::post('/password/reset', [PasswordResetController::class, 'reset']);

        // Rotas autenticadas usam também o guard do Sanctum
        Route::middleware(['auth:sanctum'])->group(function () {
            Route::get('/me', [UserController::class, 'me']);
        });
    });
});
```

Toda rota de tenant precisa do middleware `identify.tenant` (identifica o cliente pelo header `X-Tenant-ID` ou query `?tenant=`). Rotas que exigem login autenticado também precisam de `auth:sanctum`.

## 4. Funcionalidades que criam uma tabela nova

1. Decida se a tabela é central (compartilhada) ou de tenant (por cliente).
2. Crie a migration na pasta correta:
   - `database/central/migrations/` → rode com `php artisan make:migration nome --path=database/central/migrations`
   - `database/tenant/migrations/` → rode com `php artisan make:migration nome --path=database/tenant/migrations`
3. Rode a migration:
   - Central: `php artisan migrate --database=central --path=database/central/migrations`
   - Tenant (banco template do `.env`): `php artisan migrate --database=tenant --path=database/tenant/migrations`
   - Tenant (todos os clientes cadastrados): `php artisan tenants:migrate`
4. Crie o Model em `app/Models/Central/` ou `app/Models/Tenant/`, definindo explicitamente `$connection` e `$table` (o projeto usa nomes de tabela legados, ex.: `configuracoes.db_usuarios`).

## 5. Convenções do projeto

- Nomes de classes em inglês (`Controller`, `Service`, `Repository`, `Request`, `Resource`), mensagens de erro voltadas ao usuário em português.
- DTOs são `readonly class` com método estático `fromRequest()`.
- Erros de validação de negócio (ex.: credenciais inválidas, usuário inativo) usam `ValidationException::withMessages([...])` dentro do Service — o Laravel já converte isso em resposta HTTP 422.
- Nunca acesse `DB::` ou `Model::` direto de um Controller.
- Toda nova interface precisa do binding correspondente em `AppServiceProvider`, senão a injeção de dependência falha com `BindingResolutionException`.
- Ao adicionar um endpoint sob `v1`, sempre inclua o middleware `identify.tenant` (a menos que o endpoint seja explicitamente público/central, como um health check).

## 6. Checklist antes de abrir o PR

- [ ] Migration criada na pasta certa (central ou tenant) e testada com `php artisan migrate`
- [ ] Contrato + implementação de Repository (se houve nova consulta)
- [ ] Contrato + implementação de Service (regra de negócio)
- [ ] Binding adicionado em `AppServiceProvider`
- [ ] FormRequest com as regras de validação
- [ ] DTO (se o endpoint recebe payload)
- [ ] Controller enxuto, sem lógica de negócio
- [ ] Resource para formatar a resposta
- [ ] Rota registrada em `routes/api.php` com os middlewares corretos
- [ ] Testes em `tests/` cobrindo o caminho feliz e os erros esperados
- [ ] `composer run test` passando
