# Autorização e Acesso ao Portal (revisto)

> ⚠️ Este documento substitui o antigo "04-MULTI-TENANCY-E-RBAC.md" (SaaS
> multi-org). Ver `07-ADDENDUM-PIVOT-REQUISITOS.md` para o porquê da
> mudança. Já não existe `organization_id` nem `TenantScope` — o sistema é
> single-tenant por instalação.

## 1. Dois tipos de utilizador

```
User.client_id === null   → utilizador INTERNO (equipa da empresa gestora)
User.client_id === X      → utilizador de PORTAL, ligado ao Client X
```

Não há middleware de "tenant activo" — a autorização depende de **quem é
o utilizador** e, se for de portal, **a que `client_id` pertence**.

## 2. Utilizadores internos — RBAC clássico

`spatie/laravel-permission` (sem "teams" — já não é necessário, é uma só
instalação). Roles seedados conforme a secção 8 da spec original: Admin,
Property Manager, Maintenance Manager, Approver, Finance, Technician.

Permissões granulares tal como a secção 9 (`properties.view`,
`work_orders.assign`, etc.), verificadas sempre via **Policy**, nunca só
`hasRole()` num controller.

## 3. Utilizadores de portal — acesso por `client_id`

Um utilizador de portal:
- Tem sempre role fixo `Requester` (ou `PortalUser`).
- **Nunca** passa pelas mesmas rotas `/api/v1/*` da equipa interna — usa um
  conjunto de rotas dedicado `/api/v1/portal/*`, cada uma com o seu próprio
  Controller e Policy, que filtram **sempre** por `client_id` do
  utilizador autenticado.
- O `client_id` nunca vem do payload/request — vem sempre de
  `$request->user()->client_id`.

```php
// Exemplo: PortalMaintenanceRequestController@index
public function index(Request $request)
{
    $clientId = $request->user()->client_id; // nunca do payload

    return MaintenanceRequest::where('client_id', $clientId)
        ->latest()
        ->paginate();
}
```

Um pedido só fica associado a um `client_id` quando é criado — resolvido
automaticamente a partir da `property_relationship` activa do utilizador
(ex: ele é `TENANT` do imóvel X) ou, se for pedido interno, fica `null`.

## 4. Camadas de verificação (equivalente à secção 31 original)

Para `GET /api/v1/portal/maintenance-requests/{id}`:

1. `auth:sanctum` → autenticado?
2. É mesmo um utilizador de portal (`client_id` não nulo)? Se não, 403.
3. Policy: `$maintenanceRequest->client_id === $user->client_id`? Se não,
   **404** (nunca 403 — não revela existência do pedido de outro cliente).
4. Só depois devolve os dados.

Para as rotas internas (`/api/v1/*`), a verificação é: autenticado +
`isInternal()` + Policy com a permissão certa.

## 5. Porque é que isto ainda vale a pena testar como "isolamento"

Mesmo sem multi-tenancy SaaS, o portal do cliente continua a ser a mesma
categoria de risco: um inquilino nunca pode ver dados de outro inquilino.
Os testes de `docs/06-ESTRATEGIA-TESTES.md` mantêm-se — só mudam de
"cross-tenant" para "cross-client" (ver
`tests/Feature/PortalClientIsolationExampleTest.php`).

## 6. Branding / White-label

Nada de "AMIMAK" (ou qualquer outro nome de cliente) hardcoded em texto,
lógica ou testes. Tudo o que for específico da empresa gestora que usa a
instalação vive em:

- `.env` — nome legal, NUIT, moeda por omissão, timezone
- `config/company.php` — lê do `.env`, expõe via `config('company.name')`
- tabela `settings` (key/value) — para o que o Admin deve poder editar em
  runtime sem precisar de deploy (ex: logótipo, cores, prefixo de
  numeração de Work Orders)

Uma venda futura a outra imobiliária = nova instalação com o seu próprio
`.env`/BD — nunca um segundo tenant na mesma base de dados.
