feat: establish reservation portal foundation
This commit is contained in:
68
docs/ARCHITECTURE.md
Normal file
68
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 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.
|
||||
|
||||
```text
|
||||
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 e concorrência de aprovação (a criar).
|
||||
- `app/Domain/Handovers`: entrega, devolução e incidentes (a criar).
|
||||
- `app/Domain/Audit`: logs imutáveis pela interface.
|
||||
- `app/Integrations/SnipeIt`: único ponto de comunicação com Snipe-IT (a criar).
|
||||
|
||||
## 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:
|
||||
|
||||
1. `AvailabilityService` produz erros de negócio legíveis;
|
||||
2. PostgreSQL mantém a garantia final com uma restrição `EXCLUDE USING gist` nos 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.
|
||||
|
||||
## Fluxo de dados Snipe-IT
|
||||
|
||||
1. Um job consulta a API paginada com token de leitura.
|
||||
2. Um mapper reduz a resposta aos campos documentados.
|
||||
3. `AssetSyncService` faz upsert por `snipe_asset_id` e calcula `content_hash`.
|
||||
4. Ativos ausentes numa sincronização completa ficam `active = false`; não são apagados para preservar histórico.
|
||||
5. Antes de aprovação ou entrega, o ativo é validado novamente.
|
||||
6. Checkout/check-in usam um token operacional separado e guardam apenas a resposta necessária para auditoria.
|
||||
|
||||
## 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.
|
||||
Reference in New Issue
Block a user