Plano de cuidado
Uma diretriz é o desenho do cuidado: a sequência de consultas, tarefas, questionários e mensagens que a equipe deve executar para acompanhar um paciente. O plano de cuidado é essa diretriz aplicada a um paciente — o par que liga uma pessoa a um roteiro de acompanhamento.
No FHIR, a diretriz é um PlanDefinition e a
aplicação dela é um CarePlan. Esta página cobre a
segunda metade: como colocar um paciente numa diretriz, como acompanhar o que foi gerado para
ele e como encerrar o acompanhamento.
O conteúdo da diretriz — as consultas, tarefas e questionários que ela gera — é montado pela equipe no NiloCare, não por esta API. O que você faz aqui é aplicá-la, e para isso precisa da URL da diretriz, que a busca de diretrizes devolve. O cabeçalho da diretriz (nome, descrição e tipo) esse sim é gravável — veja Diretriz.
Linha de cuidado e protocolo
A plataforma organiza as diretrizes em dois tipos:
O tipo vem na leitura em category[0].text, com os códigos care_line e protocol. Não é
algo que você escolha no payload deste recurso: ele é propriedade da diretriz — veja
Diretriz.
Antes de aplicar
A aplicação de uma diretriz não depende só do plano — depende de como o paciente está cadastrado. Dois requisitos, os dois verificados pela plataforma no momento da aplicação:
- O paciente tem equipe de cuidado. Um paciente sem equipe é recusado.
- A equipe cobre as especialidades que a diretriz exige. Precisa haver ao menos um profissional para cada especialidade pedida — pode ser o mesmo profissional cobrindo mais de uma. Faltando alguma, a aplicação é bloqueada.
Os dois erros vêm da plataforma, não da validação do recurso: saem com expression igual a
CarePlan.? e com o motivo em texto (patient_without_care_team,
todo_without_responsible). CarePlan.? não é FHIRPath válido — não tente resolvê-lo
automaticamente para apontar o campo culpado.
Campos
A coluna No NiloCare traz o rótulo com que o dado aparece para a equipe; são rótulos, não caminhos de navegação.
Campos que a Nilo não usa
A CarePlan canônica traz muito mais do que esta integração lê: basedOn, replaces,
partOf, encounter, careTeam, addresses, goal, contributor, supportingInfo,
instantiatesUri, partOf e contained. Nenhum deles é lido, e por isso nenhum aparece na
referência do recurso.
author é a exceção que morde. Ele não grava nada — nem o profissional que aplicou a
diretriz — mas, ao contrário dos outros, é validado. O type é conferido em toda escrita:
qualquer coisa diferente de Practitioner recusa a chamada. E, nas chamadas que criam ou
recriam o plano, o identificador também é resolvido: um profissional inexistente ou inativo
recusa a escrita inteira. Num encerramento ou cancelamento o identificador nem chega a ser
consultado.
Como não há benefício algum em enviá-lo, não envie. Ele não aparece na referência do recurso justamente por isso; as linhas de erro abaixo existem para quem já o manda hoje.
Encontrar a diretriz
instantiatesCanonical é a URL da diretriz. Você a obtém listando as diretrizes disponíveis
— veja Diretriz:
A URL a enviar é {host}/fhir/resources/PlanDefinition/{id}, com o id do recurso
encontrado — ou a url canônica da diretriz, quando ela tiver uma.
A resolução aceita duas formas: a API tenta primeiro o último segmento da URL como id do
recurso e, não achando, procura uma diretriz cujo campo url seja exatamente o que você
enviou. Nos dois caminhos a diretriz precisa estar com status: active.
A URL embute o host do ambiente. Um payload com a URL de produção enviado para o ambiente
de homologação é recusado antes de qualquer validação de negócio, com a mensagem
Resource has identifier from a Nilo environment that is not the current environment. Ao
promover uma integração entre ambientes, troque o host de todos os instantiatesCanonical.
Aplicar a diretriz
Não há endpoint separado para criar e atualizar: o mesmo POST faz os dois, e o status
enviado é o que decide o que acontece.
Os dois modos de aplicação
A resposta devolve o recurso como ficou gravado, sem envelope:
Guarde o id: é por ele que se faz a leitura direta. Ao lado do seu identifier, a resposta
traz o identificador Nilo do plano, no system
…/NamingSystem/hippocrates-api--patient-care-line.
A aplicação imediata confirma a criação do plano, não a geração dos itens. As tarefas, os agendamentos, os questionários e as mensagens são gerados depois, de forma assíncrona, e a geração pode levar alguns minutos.
O status da resposta repete o que você enviou, não o estado derivado do plano na
plataforma. Uma aplicação imediata responde active mesmo enquanto os itens ainda estão sendo
gerados — nesse intervalo o plano vale como pendente do outro lado, e uma leitura posterior
pode trazê-lo como on-hold, sem activity. O sinal de que a geração terminou é a activity
aparecer numa leitura, não o status da resposta ao POST.
Um plano criado com status: draft não tem identificador Nilo: nada foi criado na
plataforma ainda. O recurso FHIR é o seu próprio payload, sem title, sem category, sem
period e sem activity. Não conte com esses campos antes de a alocação acontecer — e veja
o que isso implica para cancelar um plano ainda na fila.
subject.identifier volta trocado. Você envia o identificador do seu sistema, e a
resposta traz o identificador Nilo do paciente
(…/NamingSystem/hippocrates-api--patient). Não é perda de dado: é a referência que a
plataforma usa internamente. Leituras posteriores do mesmo plano podem trazer o seu
identificador de volta, dependendo da configuração da sua implantação.
Como a API reconhece o plano
Duas chaves, nesta ordem.
Com identifier. A API procura um plano com aquele par system + value, em qualquer
estado. Achando, a chamada é uma atualização daquele plano, e valem as regras de
transição de estado.
Sem identifier, ou com um identifier que não casa com nada. A API procura pelo par
subject + instantiatesCanonical, entre os planos nos estados draft, active, on-hold
e entered-in-error — planos já encerrados ou cancelados não entram nessa busca.
O que acontece então depende de qual das duas situações é a sua:
¹ Um plano já existente não aceita draft nem active de novo: a chamada é recusada com
CarePlan can't be updated to status …. A única exceção é o plano em entered-in-error.
A célula que costuma surpreender é a da última coluna: enviar um identifier novo para um
paciente que já está naquela diretriz não cria plano nenhum e não devolve erro. A
resposta é 200 com o plano que já existia, agora carregando também a sua chave. Se o seu
integrador conta chamadas bem-sucedidas como planos criados, ele vai contar errado. Confira o
identificador Nilo da resposta antes de concluir que aplicou a diretriz — e note que o
status da resposta não ajuda nessa distinção, porque ele repete o que você enviou.
Um paciente tem, no máximo, um plano não terminal por diretriz. Havendo mais de um no
store — estado inconsistente, que não deveria acontecer — a escrita falha com
IntegrityError: has more than one Care Plan for Patient and PlanDefinition, e o caso é de
chamado no Suporte.
Estados e transições
Na leitura, o status do plano vem derivado da situação dele na plataforma:
Na escrita, o status é uma instrução, e nem toda transição é permitida:
¹ Um plano ainda em draft não tem registro na plataforma para atualizar. A tentativa falha
com CarePlan with nilo identifier does not exist.
² Com a mesma ressalva: o plano entered-in-error típico é o que falhou na alocação em massa,
e ele nasceu em draft — então não tem registro na plataforma, e essas três transições falham
pelo mesmo motivo. O que funciona nele é reenviá-lo como active ou como draft.
revoked e completed são terminais. Um plano nesses estados não aceita mais nenhuma
atualização: qualquer POST que o alcance pelo identifier é recusado com
CarePlan with status … can't be updated.
Para aplicar a mesma diretriz de novo ao mesmo paciente, envie um identifier novo.
Isso é deliberado: cada aplicação é uma entrada distinta no histórico do paciente naquela
diretriz, com a data em que entrou e a data em que saiu.
entered-in-error é o único estado não terminal do qual se volta. Um plano que falhou na
alocação em massa pode ser reenviado com status: active, e aí um plano novo é criado — ou
com status: draft, e ele volta para a fila.
Encerrar ou cancelar
Para tirar um paciente de uma diretriz, reenvie o plano trocando só o status:
completed— o acompanhamento chegou ao fim como previsto.revoked— a aplicação foi indevida e está sendo desfeita.
Os dois tiram o paciente do acompanhamento. A diferença é de intenção, e ela fica no histórico do paciente.
entered-in-error tem, na plataforma, o mesmo efeito de revoked. A distinção existe no
recurso FHIR, não no registro.
Não é preciso mandar o identifier para encerrar: sem ele, o plano é localizado pelo par
paciente + diretriz.
Um plano ainda em draft não pode ser cancelado. Ele existe só como recurso FHIR, e o
cancelamento precisa de um registro na plataforma para atualizar — a chamada falha com
CarePlan with nilo identifier does not exist, e o paciente continua na fila.
Duas saídas: esperar a alocação acontecer e cancelar depois, ou aplicar o plano agora
enviando um identifier novo com status: active — é esse caminho, e não o reenvio sem
identifier, que promove um plano da fila. Aplicado, ele passa a aceitar o cancelamento.
Essa mensagem não é exclusiva do draft: ela aparece sempre que o recurso alcançado não
carrega o identificador Nilo do plano. O plano na fila é o caso comum porque nunca teve um —
mas um recurso active que tenha perdido o identificador falha igual.
Itens do plano
activity é o que a diretriz gerou para aquele paciente. É só leitura: os itens não são
criados nem alterados por este recurso. Cada item vem de uma de duas formas.
Com reference e progress, quando o item já tem recurso próprio no store:
Com detail, quando a diretriz prevê uma consulta que ainda não virou agendamento:
detail.kind é sempre Appointment, detail.description traz a especialidade prevista,
detail.scheduledPeriod a janela em que ela deveria acontecer e detail.status o andamento,
com os mesmos valores da consulta agendada.
A janela de scheduledPeriod é fixa em sete dias: o fim é sempre sete dias depois do
início. Ela não reflete um prazo configurado na diretriz.
Tarefas e questionários compartilham o type: Task da referência, e se distinguem pelo
system do identificador. Nos dois casos o item é lido como Tarefa —
o questionário do plano é uma tarefa atribuída ao paciente, não a resposta dele. As respostas
são outro recurso, o Questionário respondido, e não
é para ele que esta referência aponta.
Um item pode vir sem reference, sem progress e sem detail. Acontece quando o item já
tem agendamento, mas o agendamento está num estado que esta integração não representa.
Qual identificador as referências de activity carregam depende da mesma configuração de
implantação que vale para subject: com identificadores externos ligados, vem o identificador
do seu sistema; sem ela, o identificador Nilo. Confira numa resposta real antes de casar as
referências com os seus registros.
Um plano na fila ou ainda em geração (status: on-hold) volta sem activity. A lista
vazia não significa diretriz sem itens: significa que a geração não terminou. Não conclua
nada sobre o conteúdo de um plano até ele estar active.
Buscar
A resposta é sempre um Bundle do tipo searchset, mesmo quando há um único resultado:
Busca sem resultados não é erro: volta 200 com um Bundle cujo entry é uma lista vazia.
Trate a ausência de resultados pela lista vazia, não esperando um 404.
Parâmetros de busca suportados
O par subject.identifier + instantiates-canonical é o que identifica o plano de um
paciente numa diretriz — é a mesma busca que a própria plataforma usa para reconhecer um plano
já existente:
Qual identificador do paciente o subject carrega depende da sua implantação. Na
configuração que usa identificadores externos nas referências, é o identificador do seu
sistema — e o filtro acima funciona como está. Sem ela, o subject traz o identificador Nilo
do paciente (…/NamingSystem/hippocrates-api--patient), e é esse system que você tem de
usar no filtro. Confira numa resposta de leitura qual dos dois está lá antes de montar a
busca em volume.
Vários parâmetros canônicos da CarePlan existem e não encontram nada aqui, porque a Nilo
não preenche o campo correspondente: care-team, condition, goal, encounter,
based-on, replaces, part-of, performer, activity-code e activity-reference.
intent é um caso diferente: ele funciona, e por isso é inútil — o valor é constante, então
intent=order traz todos os planos.
category é um caso à parte: o tipo da diretriz vem apenas como texto em category[0].text,
sem coding. Uma busca por token no category não encontra o plano por care_line nem por
protocol.
A paginação é por _count e _page_token; havendo página seguinte, o Bundle traz a URL
pronta em link.
Ler por ID
Diferente da busca, esta leitura não devolve um Bundle — mas também não devolve o recurso
nu. A resposta é um envelope com fullUrl, search e resource, e o plano está em
resource. Ler status ou activity na raiz da resposta não encontra nada.
A leitura por ID responde 404 quando o id não existe.
Quando a alocação falha
A alocação em massa de uma diretriz pode falhar para um paciente específico — por exemplo,
quando a equipe dele não cobre as especialidades exigidas. Nesse caso o plano passa a
entered-in-error e o motivo da falha vem em note:
É o único caso em que note aparece num plano de cuidado. Um plano com note preenchido é
sempre um plano que falhou.
Valores aceitos
status
Na escrita, draft, active, on-hold, completed, revoked e entered-in-error — com as
restrições de transição descritas acima. unknown só aparece na leitura, num plano sem
situação registrada na plataforma.
intent
O FHIR R4 exige o campo, e nada na integração o lê: ele não escolhe modo de aplicação nem
nível de autoridade. É preenchimento obrigatório sem efeito. Envie order — é o valor que
todas as leituras geradas pela plataforma trazem, e o que o resto da documentação assume.
category
Só resposta, e sem coding: o tipo da diretriz vem em category[0].text como care_line ou
protocol.
Efeitos colaterais
status: active cria o plano na plataforma durante a requisição. É a única escrita desta
página que altera o cadastro do paciente de forma imediata — e o que ela dispara em seguida
(geração de tarefas, agendamentos, questionários e mensagens) acontece de forma assíncrona,
fora do controle da chamada.
revoked e completed tiram o paciente do acompanhamento e são irreversíveis. O plano
deixa de estar em execução e não aceita mais nenhuma atualização. O que acontece com as
tarefas e mensagens ainda não executadas é decidido pela plataforma, fora do alcance desta
chamada — não conte com elas depois de encerrar o plano.
Um identifier novo num paciente já alocado não cria plano. A chamada responde 200 com
o plano existente e a sua chave anexada a ele. Veja a tabela em
Como a API reconhece o plano.
Este endpoint não remove planos: a escrita nunca responde 204. O que existe é o
cancelamento, por revoked — e ele preserva o registro no histórico do paciente.
Erros
Recusa é 400, e o corpo é um OperationOutcome: issue[].expression aponta o campo culpado
e issue[].details.text explica o motivo. O outro código que este endpoint devolve é 429.
Os payloads completos estão na aba Referência, em POST /fhir/resources/CarePlan.
Cinco linhas da tabela trazem expression que não é FHIRPath válido: as duas de
CarePlan.?, que vêm da plataforma, e as três de CarePlan.None. Some-se a elas a linha de
exception, que vem sem expression nenhum. Um integrador que usa o expression para
destacar o campo culpado precisa tratar esses casos à parte.
Limite de escrita
A aplicação imediata (status: active) pode ser limitada por janela de tempo, para todo o seu
ambiente. Atingido o limite, a resposta é 429 com o code throttled e o tempo de espera
na mensagem — aguarde e repita. As demais escritas deste recurso não entram nessa conta.
O limite vigente é definido na implantação, e pode estar desligado. Se você vai fazer uma carga em volume, confirme com o Suporte qual é o teto do seu ambiente antes de dimensionar.

