4.8 KiB
Arquitetura
Contexto
O portal é uma aplicação independente e complementar ao Snipe-IT. Usa um monólito modular para reduzir custo operacional, mas separa os domínios internamente para evitar acoplamento entre inventário, reservas, aprovações e operações.
Browser
│ HTTPS
▼
Nginx ──► Laravel + Inertia/React
├── PostgreSQL (estado do portal)
├── Redis (cache, filas, locks)
├── SMTP/Mailpit
└── Snipe-IT REST API
Responsabilidade dos sistemas
| Informação/operação | Sistema oficial |
|---|---|
| Etiqueta, série, modelo, categoria e localização habitual | Snipe-IT |
| Estado operacional e atribuição física atual | Snipe-IT |
| Checkout e check-in efetivos | Snipe-IT via API |
| Pedidos futuros e calendário | Portal |
| Aprovação, rejeição, cancelamento e conflitos | Portal |
| Entrega/devolução e evidência operacional | Portal, sincronizada com Snipe-IT |
| Auditoria do fluxo de requisição | Portal |
Módulos
app/Domain/Identity: perfis, permissões e identidades externas.app/Domain/Inventory: cache local de ativos e consultas do catálogo.app/Domain/Reservations: disponibilidade, estados, regras e requisições.app/Domain/Approvals: decisões, histórico e concorrência de aprovação.app/Domain/Handovers: entrega, devolução e incidentes (a criar).app/Domain/Audit: logs imutáveis pela interface.app/Integrations/SnipeIt: cliente HTTP, DTOs, mapper e exceções da API Snipe-IT.
Consistência temporal
Os períodos usam [starts_at, ends_at): uma reserva que termina às 11:00 não entra em conflito com outra que começa às 11:00.
A defesa ocorre em duas camadas:
AvailabilityServiceproduz erros de negócio legíveis;- PostgreSQL mantém a garantia final com uma restrição
EXCLUDE USING gistnos estados bloqueantes.
Uma criação ou aprovação deve bloquear as linhas dos ativos, voltar a validar dentro da transação e tolerar corrida através da restrição da base de dados.
AvailabilityService::availableAssets() aplica as mesmas condições em SQL para alimentar catálogo e formulário sem carregar todo o inventário em memória. O período consultado é propagado até à criação da requisição; a validação transacional continua a ser a garantia aplicacional final.
Pré-reservas ficam bloqueantes em held enquanto aguardam decisão. ReservationService centraliza criação, cancelamento e expiração: todas as transições bloqueiam a requisição, atualizam os itens bloqueantes e criam um AuditLog. Um job único procura prazos vencidos a cada cinco minutos. A restrição GiST continua a proteger contra corridas entre estes ciclos de vida.
ApprovalService bloqueia a requisição e os ativos antes de aprovar ou substituir, revalida a disponibilidade e regista cada passo em approval_actions e audit_logs. Uma substituição cancela o item original e cria um novo held, apenas na mesma categoria. Pedidos e respostas de esclarecimento conservam o histórico e renovam explicitamente o prazo.
Notificações implementam ShouldQueue, usam afterCommit e seguem dois canais: email e tabela notifications. A caixa interna consulta exclusivamente a relação polimórfica do utilizador autenticado, evitando acesso horizontal a notificações de terceiros.
Fluxo de dados Snipe-IT
- Um job consulta a API paginada com token de leitura.
- Um mapper reduz a resposta aos campos documentados.
AssetSyncServicefaz upsert porsnipe_asset_id, calculacontent_hashe marca cada ativo comlast_seen_sync_run_id.- Apenas após todas as páginas serem recebidas com sucesso, ativos cujo marcador não corresponde à execução atual ficam
active = false; não são apagados para preservar histórico. - Antes de aprovação ou entrega, o ativo é validado novamente.
- Checkout/check-in usam um token operacional separado e guardam apenas a resposta necessária para auditoria.
Uma falha intermédia pode deixar upserts válidos das páginas anteriores, mas nunca executa a desativação global. A sincronização seguinte converge o cache. Um lock distribuído e um job único impedem duas sincronizações simultâneas.
Referências oficiais usadas para o contrato: autenticação da API, listagem de hardware e limites/paginação.
Segurança
- Sem registo público.
- Cookies seguros e HTTPS em produção.
- Policies em cada ação de domínio.
- Tokens e segredos apenas no ambiente.
- Dois tokens Snipe-IT com menor privilégio.
- MFA obrigatório a definir para perfis privilegiados antes do piloto.
- Logs de auditoria não expostos a operações de update/delete.