# Arquitetura

## Modelo SaaS

A aplicação é um monólito modular. Todos os clientes utilizam a mesma aplicação e base de dados, mas cada registo operacional contém `tenant_id`. O middleware `ResolveTenant` valida a associação do utilizador à organização e inicializa `TenantContext`. Os modelos que usam `BelongsToTenant` aplicam um global scope e preenchem automaticamente o `tenant_id`.

## Camadas

1. **Identidade:** utilizadores, organizações e memberships.
2. **Licença:** planos, módulos, subscrições Stripe e overrides por organização.
3. **Core documental:** dossiês, pastas, documentos, armazenamento e auditoria.
4. **Módulos horizontais:** workflow, PDF, importação, personalização.
5. **Verticais:** Educação, RH, Imobiliário, Associados e Serviços Profissionais.
6. **Infraestrutura:** filas, scheduler, PostgreSQL, Redis, S3 e email.

## Estratégia de tenancy

Para a primeira versão comercial recomenda-se uma base de dados partilhada com `tenant_id`, porque simplifica atualizações, métricas e suporte. Para clientes enterprise pode ser adicionada uma edição com base de dados dedicada, mantendo os mesmos contratos de serviço.

## Ficheiros

O binário nunca é público. A base de dados guarda apenas metadados e o caminho interno. Downloads autenticados e partilhas públicas passam sempre por controladores. O token público é guardado apenas como hash SHA-256.

## Billing

A entidade faturada é `Tenant`, não `User`. A organização pode ter vários utilizadores, mas apenas uma subscrição principal. O `SubscriptionReconciler` associa o Price ID recebido da Stripe a um plano e sincroniza os módulos da licença.

## Evolução recomendada

Manter a aplicação como monólito modular até existirem motivos reais para separar serviços. Filas de email, PDF e importação podem crescer de forma independente sem transformar prematuramente o produto em microserviços.

## Editor de modelos PDF

O módulo `pdf_forms` separa quatro responsabilidades:

- `pdf_templates`: metadados, estado, PDF privado e controlo de concorrência;
- `pdf_template_regions`: campos e coordenadas normalizadas por página;
- `pdf_template_assets`: imagens privadas associadas ao modelo;
- `pdf_template_revisions`: snapshots JSON imutáveis para publicação e restauro.

O browser usa PDF.js apenas para renderização e autoria visual. O backend continua a ser a autoridade para permissões, validação, tenancy, persistência, versões e armazenamento. A gravação usa `lock_version` e bloqueio de linha para impedir que duas sessões substituam silenciosamente o trabalho uma da outra.


## Geração imutável de PDFs

A autoria e a execução estão separadas. Quando o utilizador pede uma geração, a aplicação cria uma cópia imutável do PDF publicado, guarda snapshots das regiões e valores e envia apenas o ID da geração para a fila `pdf`. O worker recompõe o documento página a página, escreve o resultado num ficheiro temporário, envia-o por stream para o armazenamento privado e cria um `Document` no dossiê. Este desenho evita condições de corrida com edições posteriores e reduz o consumo de memória em PDFs grandes.
