122 lines
9.4 KiB
Markdown
122 lines
9.4 KiB
Markdown
# Registo de decisões técnicas
|
|
|
|
## ADR-001 — Monólito modular Laravel/Inertia
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Usar Laravel 13 com React/TypeScript através de Inertia no mesmo projeto. Mantém autenticação, autorização, filas e transações numa única unidade operacional, sem impedir separação por domínio.
|
|
|
|
## ADR-002 — PostgreSQL como garantia de conflitos
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Usar PostgreSQL e períodos semiabertos `[início, fim)`. A lógica aplicacional melhora a mensagem ao utilizador; uma restrição de exclusão GiST garante que concorrência ou um erro aplicacional não cria sobreposição bloqueante.
|
|
|
|
## ADR-003 — Cache local, sem replicação total do Snipe-IT
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Guardar apenas os campos de ativos necessários ao catálogo e reservas. A sincronização desativa registos ausentes em vez de os apagar. A base de dados do Snipe-IT nunca é acedida diretamente.
|
|
|
|
## ADR-004 — Registo público desativado
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Contas são criadas por administrador, convite ou identidade institucional verificada. Mantêm-se recuperação de palavra-passe, verificação de email, 2FA e passkeys do starter kit.
|
|
|
|
## ADR-005 — Ambiente reproduzível em Docker Compose
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Desenvolvimento e primeira instalação utilizam serviços separados para Nginx, PHP-FPM, PostgreSQL, Redis, Vite, filas, scheduler e Mailpit. Produção deve usar imagens imutáveis, HTTPS e gestão externa de segredos, mantendo a mesma topologia lógica.
|
|
|
|
## ADR-006 — Português de Portugal na interface
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Textos funcionais são escritos em português europeu. Nomes de código, eventos e tabelas permanecem em inglês para consistência técnica.
|
|
|
|
## ADR-007 — Sincronização Snipe-IT convergente por execução
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Consumir `/api/v1/hardware` por `offset`/`limit`, com páginas configuráveis até ao máximo oficial de 500 registos. Cada ativo visto recebe o ID da execução em `last_seen_sync_run_id`; a desativação de ausentes só ocorre depois de todas as páginas terminarem com sucesso. Upserts de páginas já válidas podem permanecer após uma falha, permitindo convergência na execução seguinte sem manter uma transação aberta durante chamadas HTTP. Repetir apenas falhas de ligação, HTTP 429 e HTTP 5xx. Usar lock distribuído, job único e token exclusivo de leitura.
|
|
|
|
## ADR-008 — Pré-reserva bloqueante com expiração auditada
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Uma requisição submetida cria itens em `held` e bloqueia o período durante 48 horas, até decisão, cancelamento ou expiração. O próprio requisitante pode cancelar apenas enquanto a máquina de estados admite a transição. Um job único executado a cada cinco minutos expira pedidos `pending_approval` ou `awaiting_information` com prazo vencido. Cancelamento e expiração usam bloqueio transacional da requisição, libertam todos os itens bloqueantes e produzem eventos de auditoria; intervalos que se tocam continuam permitidos pela semântica `[início, fim)`.
|
|
|
|
## ADR-009 — Decisões com revalidação sob bloqueio
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
A autorização HTTP e a verificação no serviço exigem perfil de aprovador ou administrador ativo. Antes de aprovar, o serviço bloqueia a requisição e os ativos por ordem estável, ignora apenas os itens da própria pré-reserva e volta a validar estado, atribuição, bloqueios e conflitos externos. A decisão altera requisição e itens na mesma transação e escreve tanto `approval_actions` como `audit_logs`. Rejeição liberta os itens; um pedido de esclarecimentos mantém a pré-reserva e renova o prazo por 48 horas.
|
|
|
|
## ADR-010 — Notificações após commit e substituição equivalente
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Notificações funcionais são colocadas na fila apenas depois da confirmação da transação e enviadas por email e caixa interna. A submissão e uma resposta a esclarecimentos notificam aprovadores ativos; decisões e substituições notificam o requisitante. Uma substituição não altera automaticamente a decisão: exige justificação, equipamento livre da mesma categoria, bloqueio de ambas as linhas, novo item `held` e preservação do item original como `cancelled` para auditoria.
|
|
|
|
## ADR-011 — Escritas Snipe-IT sem retry e reconciliação explícita
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Checkout e check-in usam um token operacional distinto do token de leitura e nunca escrevem diretamente na base de dados do Snipe-IT. Cada equipamento é movimentado remotamente antes de o respetivo `reservation_item` e `handover_record` serem confirmados localmente. Escritas não têm retry automático: uma falha de ligação ou HTTP 5xx pode ser posterior à execução remota e a repetição cega não é segura. Numa operação com vários itens, sucessos confirmados são preservados e uma falha posterior coloca a requisição em `incident`, com IDs concluídos, item falhado e erro em auditoria. O operador reconcilia o ativo no Snipe-IT e repete apenas o movimento ainda pendente.
|
|
|
|
O checkout é dirigido a `checkout_to_type=user`; o ID remoto confirmado pelo operador é guardado em `users.snipe_user_id`. O check-in usa o estado e a localização habitual provenientes da última sincronização. Esta opção segue os contratos oficiais de [checkout](https://snipe-it.readme.io/reference/hardware-checkout), [check-in](https://snipe-it.readme.io/reference/hardware-checkin) e o comportamento documentado de [erros em HTTP 200](https://snipe-it.readme.io/reference/api-overview).
|
|
|
|
## ADR-012 — Políticas persistentes e buffers temporais imutáveis
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Guardar parâmetros funcionais em `portal_settings`, mantendo defaults seguros no código. Antecedência, duração, prazo e limite de itens aplicam-se a novos pedidos. A margem é materializada em cada item através de `buffer_starts_at`/`buffer_ends_at` e protegida pela restrição de exclusão PostgreSQL. Alterar a política não recalcula reservas existentes: o período bloqueante aceite no momento da submissão permanece estável e auditável.
|
|
|
|
## ADR-013 — Supervisão de leitura e exportações seguras
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Separar Gates para calendário global, relatórios e auditoria. Administradores têm acesso integral; auditores consultam relatórios/auditoria sem mutações; aprovadores e operadores consultam o calendário global. Relatórios são limitados a 366 dias, exportados por streaming e neutralizam possíveis fórmulas em CSV. Modelos de notificação são conteúdo funcional persistente, mas credenciais SMTP e tokens continuam exclusivamente no ambiente.
|
|
|
|
## ADR-014 — Entra ID de tenant único com associação explícita
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Implementar diretamente o Authorization Code Flow OIDC com PKCE, usando descoberta específica do tenant e `firebase/php-jwt` 7 para validação criptográfica RS256. Validar `state`, `nonce`, expiração, emissor, audiência e `tid`; nunca persistir tokens. A versão 6 da biblioteca foi rejeitada por existir um aviso de segurança ativo e não foi adicionada à lista de exceções do Composer.
|
|
|
|
Por defeito, uma identidade Microsoft só pode ser associada a partir de uma conta local autenticada e depois de confirmação recente da palavra-passe. Não existe associação ou provisionamento automático por email. Esta escolha evita apropriação de conta por claims mutáveis ou endereços reutilizados. O login local permanece como recuperação controlada e o tenant institucional é obrigatório e expresso por GUID.
|
|
|
|
## ADR-015 — Health checks mínimos e restauro verificável
|
|
|
|
**Data:** 2026-08-04
|
|
**Estado:** aceite
|
|
|
|
Separar liveness, que prova apenas resposta do processo, de readiness, que confirma PostgreSQL e cache. As respostas públicas contêm apenas o estado agregado. O Nginx usa readiness no Docker Compose.
|
|
|
|
Disponibilizar scripts independentes para `pg_dump` custom e restauro numa base temporária validada. Os scripts usam nomes resolvidos do contentor, restringem os identificadores aceites, geram checksum e nunca substituem a base principal. Encriptação, armazenamento externo, retenção e alertas permanecem responsabilidades explícitas da plataforma de produção.
|
|
|
|
## ADR-016 — Snipe-IT de produção imutável salvo movimentos controlados
|
|
|
|
**Data:** 2026-08-05
|
|
**Estado:** aceite
|
|
|
|
A instância Snipe-IT configurada é de produção. Ficam proibidas, tanto na aplicação como em diagnóstico, operações de criação, edição ou eliminação de ativos, modelos, produtos e restantes dados mestres. Os únicos pedidos remotos de escrita admitidos são checkout e check-in resultantes de uma ação operacional legítima no portal; testes de conectividade e sincronizações são exclusivamente de leitura.
|
|
|
|
Cada checkout faz primeiro uma leitura atual de `hardware/{id}` e é recusado sem qualquer escrita se o ativo estiver atribuído. Cada check-in exige um `HandoverRecord` de checkout criado pelo portal para o mesmo requisitante e uma leitura atual que confirme a atribuição ao respetivo `snipe_user_id`. Uma divergência é tratada como incidente para reconciliação manual. Mantém-se a decisão de não repetir escritas automaticamente e de nunca expor tokens, URL privada ou respostas com dados de inventário em documentação, logs de diagnóstico ou mensagens de agentes.
|