| name | nexus-pharma-manager |
| description | Sistema completo de gestão farmacêutica do Ecossistema NEXUS Clinical. Use este skill SEMPRE que o usuário mencionar: estoque, farmácia, lotes, validade, Stock-First, insumos, pharma, compostos disponíveis, ordem de compra, fornecedor, inventário, dispensação, movimentação de estoque, entrada de medicamento, saída de medicamento, ajuste de inventário, lote vencido, ou qualquer tarefa relacionada a gestão de medicamentos, vitaminas, suplementos e compostos no NEXUS. Este skill é a plataforma de farmácia do NEXUS — se o usuário menciona qualquer operação de estoque, prescrição baseada em disponibilidade, ou administração de insumos clínicos, use-o imediatamente.
|
NEXUS Pharma Manager — Sistema Stock-First
Sistema integrado de gestão de estoque farmacêutico do Ecossistema NEXUS.
O Pharma Manager garante que toda prescrição seja validada contra estoque real em tempo real
antes de ser ofertada ao paciente. Integra-se ao Protocol Engine, LabPro e iMeddis.
Filosofia Stock-First
Princípio Central: Não prescrever o que não temos em estoque.
Quando o Protocol Engine gera uma prescrição, o Pharma Manager intercepta
e verifica disponibilidade. Se indisponível:
- Busca bioequivalentes em estoque
- Propõe substitutos com evidência científica
- Oferece opções ao médico (aguardar estoque, trocar por alternativa, cancelar)
- Nunca força prescrição impossível
Quando Este Skill É Ativado
Operações de Estoque
- Entrada (ENTRADA): Recebimento de ordem de compra, criação de lote, atualização de quantidade
- Saída (SAÍDA): Dispensação de composto, consumo de estoque, depleção de lote
- Ajuste (AJUSTE): Inventário físico, correção de discrepância, quarentena de lote
- Movimentações: Registrar, historiar, reconciliar movimentações
Gestão de Lotes (Batches)
- Criar/atualizar lotes com número, validade, fabricante, fornecedor
- Rastreabilidade FIFO (First In, First Out) para dispensação
- Alertas automáticos para lotes vencendo/vencidos
- Quarentena de lotes com problemas
Fornecedores & Compras
- Cadastro e gestão de fornecedores (CNPJ, contato, endereço)
- Histórico de performance (rating, tempo de entrega, valor total)
- Ordens de compra: workflow PENDING → APPROVED → ORDERED → RECEIVED → CANCELLED
- Recebimento com criação automática de batches
Integração com Protocolos
- Validação Stock-First: antes de prescrever, consultar estoque
- Sugestão de substitutos bioequivalentes
- Reserva de estoque quando protocolo é gerado
- Liberação de reserva se protocolo é cancelado
- Consumo de estoque quando protocolo é executado
Alertas & Relatórios
- Estoque baixo: alertar quando quantidade < minLevel
- Itens esgotados: OUT OF STOCK
- Lotes vencendo: 30 dias, 15 dias, 7 dias antes da validade
- Relatórios de movimentação por período
- Reconciliação de inventário (esperado vs. real)
Arquitetura de Dados
6 Coleções Firestore (Multi-tenant por clinicId)
| Coleção | Documentos | Função |
|---|
| pharma_stock | PharmaItem (id: compoundId) | Estoque consolidado por composto |
| pharma_batches | Batch | Rastreabilidade por lote + FIFO |
| pharma_movements | Movement | Auditoria imutável de movimentações |
| pharma_suppliers | Supplier | Cadastro de fornecedores |
| pharma_purchase_orders | PurchaseOrder | Workflow de compras |
| stock_reservations | StockReservation | Reservas ligadas a protocolos |
PharmaItem (pharma_stock)
{
id: string;
compoundId: string;
name: string;
category: PharmaCategory;
quantityAvailable: number;
quantityReserved: number;
unit: string;
minStockLevel: number;
maxStockLevel?: number;
status: StockStatus;
createdAt: Date;
updatedAt: Date;
lastStockUpdate?: Date;
notes?: string;
}
Batch (pharma_batches)
{
id: string;
compoundId: string;
compoundName: string;
batchNumber: string;
quantity: number;
quantityRemaining: number;
expiryDate: Date;
manufacturingDate: Date;
supplierId: string;
supplierName: string;
costPerUnit: number;
status: BatchStatus;
purchaseOrderId?: string;
createdAt: Date;
updatedAt: Date;
}
Movement (pharma_movements)
{
id: string;
type: MovementType;
compoundId: string;
compoundName: string;
batchId?: string;
batchNumber?: string;
quantity: number;
date: Date;
userId: string;
userName: string;
notes: string;
protocolId?: string;
patientId?: string;
patientNexusId?: string;
auditHash: string;
createdAt: Date;
}
PurchaseOrder (pharma_purchase_orders)
{
id: string;
orderNumber: string;
supplierId: string;
supplierName: string;
items: PurchaseOrderItem[];
status: PurchaseOrderStatus;
totalValue: number;
createdAt: Date;
createdBy: string;
updatedAt: Date;
receivedAt?: Date;
notes?: string;
}
Fluxos Operacionais
1. Entrada de Estoque (Recebimento de Ordem de Compra)
1. [Admin/Doctor] Cria PurchaseOrder com itens e fornecedor
→ Status: PENDING
2. [Admin] Aprova ordem
→ Status: APPROVED
3. [Admin] Marca como enviada ao fornecedor
→ Status: SENT
4. [Admin/Doctor] Recebe estoque
→ receivePurchaseOrder() é chamado
→ Para cada item:
- Cria Batch (com batchNumber, validade, quantidade, custo)
- Atualiza quantityAvailable em pharma_stock
- Registra Movement type='IN'
→ Status: RECEIVED
Serviço: addStockWithBatch() em pharmaStock.service.ts
2. Saída de Estoque (Dispensação)
1. [Doctor] Gera protocolo com compostos
→ Pharma Manager verifica Stock-First
→ reserveStock() para cada composto com quantidade necessária
→ Status da reserva: 'active'
2. [Paciente/Staff] Retira estoque (dispensa)
→ consumeStockFromBatch() é chamado
→ getBatch FIFO + decrementQuantity do batch
→ Atualiza quantityAvailable em pharma_stock
→ Registra Movement type='OUT'
→ Update na reserva: status 'consumed'
Serviço: consumeStockFromBatch() em pharmaStock.service.ts
3. Ajuste de Inventário
1. [Admin/Doctor] Realiza contagem física
→ Diferença descoberta (ex: -5 unidades)
2. Registra ajuste via recordMovement()
→ type='ADJUSTMENT'
→ notes='Contagem física: -5 unidades'
3. reconcileInventory() valida:
→ Quantidade esperada (soma de movimentos)
vs. Quantidade real (física)
Serviço: reconcileInventory() em pharmaMovements.service.ts
4. Integrações com Protocolos (Stock-First)
ANTES DE PRESCREVER:
1. Protocol Engine chama checkAvailability(compounds)
→ Retorna StockCheckResult[] com status de cada composto
2. Se canFulfill=false:
→ Busca substituto via findSubstitute()
→ Oferece ao médico com evidência bioequivalência
3. Se aceita prescrição:
→ reserveStock(compoundId, quantity, protocolId, patientId)
→ Cria StockReservation com expiração em 7 dias
→ Incrementa quantityReserved em pharma_stock
NO DISPENSA:
5. Consome estoque via consumeStockFromBatch()
→ Decrementa quantityReserved
SE PROTOCOLO CANCELADO:
6. releaseReservation(reservationId)
→ Libera quantityReserved
Serviço: checkAvailability(), reserveStock(), releaseReservation()
em pharmaStock.service.ts
Regras de Acesso (RBAC)
Firestore Rules (firestore.rules):
match /pharma_stock/{itemId} {
allow read: if isDoctor(); // Leitura: Doctor+
allow write: if isDoctor(); // Escrita: Doctor+ (cria/atualiza estoque)
}
match /pharma_batches/{batchId} {
allow read: if isDoctor();
allow write: if isDoctor();
}
match /pharma_movements/{movementId} {
allow read: if isDoctor();
allow create: if isDoctor();
allow update: if false; // IMUTÁVEL (auditoria)
allow delete: if false; // IMUTÁVEL (auditoria)
}
match /pharma_suppliers/{supplierId} {
allow read: if isDoctor();
allow write: if isAdmin(); // Apenas Admin pode gerenciar fornecedores
}
match /pharma_purchase_orders/{orderId} {
allow read: if isDoctor();
allow create: if isDoctor(); // Doctor cria O.C.
allow update: if isDoctor(); // Doctor aprova/recebe
allow delete: if isAdmin(); // Admin deleta
}
match /stock_reservations/{reservationId} {
allow read: if isDoctor();
allow write: if isDoctor();
}
Tipos de Movimento
| Tipo | Origem | Significado |
|---|
| IN | Entrada | Recebimento de O.C., aumento de estoque |
| OUT | Saída | Dispensação, diminuição de estoque |
| ADJUSTMENT | Ajuste | Inventário físico, correção |
| EXPIRED | Expiração | Lote venceu, removido de uso |
| RESERVED | Reserva | Composto reservado por protocolo (não efetivo) |
| CONSUMED | Consumo | Composto foi efetivamente usado/dispensado |
Busca de Bioequivalentes
Substitutos conhecidos para Stock-First (em pharmaStock.service.ts):
cipionato-testosterona → [enantato-testosterona, undecanoato-testosterona]
enantato-testosterona → [cipionato-testosterona, undecanoato-testosterona]
estradiol-valerato → [estradiol-benzoato, estradiol-cypionato]
vitamina-d3 → [vitamina-d2, calcitriol]
b12-cianocobalamina → [b12-metilcobalamina, b12-hidroxocobalamina]
Quando composto não tem estoque, o sistema busca automaticamente substituto
com bioequivalência comprovada, oferecendo ao médico com base em evidência.
Alertas & Status
StockStatus (pharma_stock)
- OK: Quantidade ≥ minStockLevel, não expirado
- LOW: minStockLevel > quantidade > 0
- OUT: Quantidade = 0
- EXPIRED: Data expiração < hoje
- RESERVED: Bloqueado por reserva de protocolo
BatchStatus (pharma_batches)
- ACTIVE: quantityRemaining > 0, expiryDate > hoje
- EXPIRED: expiryDate ≤ hoje
- DEPLETED: quantityRemaining = 0
- QUARANTINE: Isolado por qualidade/problema
Multi-tenant (Isolamento por Clinica)
Cada documento em pharma_* pode ter clinicId:
{
compoundId: "cipionato-testosterona",
name: "Cipionato de Testosterona",
quantityAvailable: 50,
clinicId: "clinic-001" // Isolamento de dados
}
Firestore queries usam where('clinicId', '==', userClinicId) para garantir
que estoque de uma clínica não é visível em outra.
Integrações Externas
Protocol Engine
- Consulta estoque via
checkAvailability()
- Reserva via
reserveStock()
- Libera via
releaseReservation()
- Consome via
consumeStockFromBatch()
PharmaStore (Zustand)
Dividido em 4 sub-stores (não é mais um "God Store"):
- usePharmaSharedStore: Alertas, stats, loading
- usePharmaInventoryStore: Estoque, low-stock, reservas
- usePharmaOperationsStore: Fornecedores, batches, movimentações
- usePharmaOrdersStore: Ordens de compra
Leia references/stock-first-philosophy.md para entender a integração.
Operações Frequentes
Verificar Disponibilidade Antes de Prescrever
const results = await checkAvailability([
{ compoundId: 'cipionato-testosterona', quantity: 100 },
{ compoundId: 'estradiol-valerato', quantity: 2 }
]);
results[0] = {
compoundId: 'cipionato-testosterona',
available: 45, // Menos que solicitado!
canFulfill: false,
substitute: {
compoundId: 'enantato-testosterona', // Alternativa
available: 30
}
}
Receber Ordem de Compra
await receivePurchaseOrder(orderId, [
{
itemId: 'item-001',
batchNumber: 'BATCH-2024-001',
receivedQuantity: 50,
expiryDate: new Date('2026-03-15'),
manufacturingDate: new Date('2023-01-15')
}
]);
// Automático:
// 1. Cria Batch
// 2. Atualiza pharma_stock.quantityAvailable
// 3. Registra Movement type='IN'
Dispensar Composto
await consumeStockFromBatch(
compoundId: 'cipionato-testosterona',
quantity: 100,
userId: 'user-001',
userName: 'Dr. João Silva',
notes: 'Dispensação protocolo PRO-001'
);
// Automático:
// 1. Busca lote FIFO mais antigo
// 2. Decrementa quantityRemaining do batch
// 3. Atualiza pharma_stock.quantityAvailable
// 4. Registra Movement type='OUT' com auditHash
Reconciliar Inventário
const reconciliation = await reconcileInventory(
compoundId: 'vitamina-d3',
actualQuantity: 95 // Contagem física
);
// Retorna:
// {
// expectedQuantity: 100,
// actualQuantity: 95,
// difference: -5,
// movements: [...]
// }
// Se diferença, registrar ajuste:
await recordMovement({
type: 'ADJUSTMENT',
compoundId: 'vitamina-d3',
quantity: -5,
notes: 'Contagem física realizada em 2024-03-07'
});
Estrutura de Referências
Leia os arquivos em references/ para detalhes:
- stock-first-philosophy.md: Conceito fundamental, diagrama de fluxo
- inventory-management.md: CRUD de estoque, batch tracking, alertas
- pharma-collections.md: Schema completo, índices, queries
- purchase-orders.md: Workflow O.C., recebimento, gestão de custos
- integration-protocol-ai.md: Como Pharma se integra ao Protocol Engine
- operational-workflows.md: Day-to-day pharmacy operations
Troubleshooting
"Stock não suficiente"
→ Verificar checkAvailability(), consultar findSubstitute(), oferecer alternativa
"Lote vencendo"
→ Query getExpiringItems(daysAhead), alertar e isolar em QUARANTINE
"Discrepância de inventário"
→ reconcileInventory(), registrar ADJUSTMENT, auditar movimentações
"Reserva não liberada"
→ releaseReservation() ao cancelar protocolo
Próximos Passos (Roadmap)