Arquitetura
Componentes, sequências e jobs assíncronos.
Visão de componentes
+---------------------------------------------------------------+
| CLIENTES |
| +------------------+ +----------------+ +-------+ |
| | PWA (tablet) | | Leitor 1D/2D | | Zebra | |
| | React + Vite |<---->| HID Keyboard | | ZD220 | |
| +--------+---------+ +----------------+ +---+---+ |
| | HTTPS ^ |
| v | |
| Cloudflare CDN/WAF ZPL raw |
| | (window.print)
+-----------+---------------------------------------------+-----+
v
+---------------------------------------------------------------+
| CLOUDFLARE WORKERS (Hono) |
| +--------------+ +-----------+ +----------+ +--------------+ |
| | Rotas REST | | Auth (JWT)| | FSM core | | Idempotency | |
| | /v1/* | | PBKDF2 | | lifecycle| | KV / D1 | |
| +------+-------+ +-----------+ +----------+ +--------------+ |
| | |
| v |
| +--------------+ +--------+ +-----------+ +---------+ |
| | D1 (SQLite) | | R2 | | Queues | | KV | |
| | multi-tenant | | photos | | jobs/dlq | | cache | |
| +--------------+ +--------+ +-----------+ +---------+ |
| | |
| v |
| +------------------+ |
| | Queue consumer | |
| | REPORT / RECALL | |
| | ERP_WEBHOOK ... | |
| +--------+---------+ |
+---------------------------------------+----------------------+
|
v HTTPS + HMAC
+----------------+
| ERP / CCIH |
| (externo) |
+----------------+
Sequência: lifecycle scan
Único ponto de entrada para qualquer leitura de código de barras/QR no chão operacional.
PWA Worker (Hono) D1 FSM
| POST /v1/lifecycle/scan | |
| { barcode, target_phase, context } | |
|---------------->| | |
| | requireAuth + idempotency | |
| |---------- SELECT ------> | |
| | (item, kit, equipamento, batch corrente) |
| |<--------- rows --------- | |
| | transition(entity, currentStatus, event) |
| |---------------------------------------------->|
| |<--- newStatus | Error (regra térmica/peso/quarentena/recall)
| | INSERT ict_lifecycle_events |
| |---------- INSERT ------> | |
| | audit('lifecycle.scan') |
| |---------- INSERT ------> | |
| 200 { ok: true, new_status } | |
|<----------------| | |
Sequência: recall biológico em cascata
Supervisor Worker Queue ERP
| POST /v1/recall (botão pânico, 2x confirmação)
|--------------------->|
| | INSERT ict_recall_events (OPEN)
| | enqueue { type: 'RECALL_CASCADE', recall_id }
| |-------------------------->|
| 200 { id } | |
|<---------------------| |
v
+------------------+
| Queue consumer |
| expandBatch() |
| batch -> kits |
| kits -> cirurgias
| cir. -> pacientes
+--------+---------+
|
v
UPDATE kit_instances
SET is_quarantined = 1
UPDATE ict_recall_events
SET status = 'IN_PROGRESS'
|
v enqueue ERP_WEBHOOK
+------------------+
| Webhook delivery |
| HMAC-SHA256 |
+--------+---------+
|
v POST + retry exp.
ERP / CCIH
|
v 2xx
UPDATE ict_recall_events
SET status = 'CLOSED'
Sequência: troca de organização (matriz → filial)
PWA Worker D1
| GET /v1/auth/accessible-orgs
|--------------------->|
| | SELECT orgs WHERE id = home OR parent_org_id = home
| | (ADMIN ve todas; demais apenas concedidas via ict_user_org_access)
| { items: [...] } |
|<---------------------|
| usuário escolhe filial X
| POST /v1/auth/switch-org { target_org_id: X }
|--------------------->|
| | valida X.parent_org_id = home OR role = ADMIN
| | re-assina JWT com org_id = X, home_org_id = home
| { token, org: X } |
|<---------------------|
| reseta TanStack Query e refetch /v1/me
Crons
| Schedule (UTC) | Job | Efeito |
|---|---|---|
0 4 * * * | Bowie-Dick diário | Marca autoclaves vapor como BLOCKED_BOWIE_DICK; RT precisa liberar. |
30 */6 * * * | BI ready | Varre indicadores biológicos com incubação finalizada; gera alerta. |
45 */6 * * * | Manutenção preventiva | Itens cujo cycles_count ≥ vida_util_estimada entram em passivação obrigatória. |
Tipos de job na fila
REPORT_GENERATE— gera PDF de batch (worker leve).MAINTENANCE_ALERT— webhook ao ERP + audit log.RECALL_CASCADE— expande batch → kits → cirurgias → pacientes.ERP_WEBHOOK_DELIVERY— entrega outbound com retry exponencial; DLQ após 3 falhas.
Hierarquia matriz/filial em D1
ict_organizations
+----+--------+----------+-----------+---------------+
| id | slug | legal_ | org_type | parent_org_id |
| | | name | | |
+----+--------+----------+-----------+---------------+
| HQ | matriz | "Rede X" | HQ | NULL |
| B1 | sp-1 | "Filial" | BRANCH | HQ |
| B2 | rj-1 | "Filial" | BRANCH | HQ |
+----+--------+----------+-----------+---------------+
ict_user_org_access (concessões cruzadas)
+----+---------+--------------+-----------------+--------+
| id | user_id | home_org_id | target_org_id | role |
+----+---------+--------------+-----------------+--------+
| .. | U1 | HQ | B1 | NURSE |
| .. | U1 | HQ | B2 | NURSE |
+----+---------+--------------+-----------------+--------+
JWT após switch-org:
{
sub: U1, role: NURSE,
org_id: B1, org_slug: "sp-1",
home_org_id: HQ, home_org_slug: "matriz"
}