CRUD de anotações do cliente para o terapeuta

TLDR: /api/v1/me/clients/:client_id/comments passa de só index para index, create, update e destroy, permitindo ao terapeuta registrar anotações do cliente sem depender de uma sessão e listando apenas as próprias anotações.

Contexto

A aba “Anotações” dos detalhes do cliente (trgclub-web) vai ser reformulada conforme o Figma “Meus Clientes / Anotações” (seção Terapeuta PRO). O ticket pede que o terapeuta consulte, crie, edite e exclua anotações de um cliente a qualquer momento, sem depender de uma sessão em andamento, com formatação de texto preservada.

Hoje:

  • Comment é polimórfico (commentable). Só Meeting e User incluem Commentable.
  • GET /api/v1/me/clients/:client_id/comments (API::V1::ClientsCommentsController#index) devolve os comentários de todas as Meeting do paciente em que o terapeuta participa, sem filtrar por autor: comentários de outro participante (ex.: o paciente, via POST /meetings/:id/comments) aparecem para o terapeuta.
  • Anotações só podem ser criadas por POST /api/v1/meetings/:meeting_id/comments. Um cliente sem sessões nunca pode ter anotação.

A spec do front que consome este contrato fica em trgclub-web/.project/docs/specs/ na branch feat/client-annotations.

Objetivos

  • Permitir criar anotação vinculada à relação terapeuta–cliente (UserClient), sem sessão.
  • Permitir editar e excluir, pela rota do cliente, qualquer anotação do terapeuta para aquele cliente — tanto as do UserClient quanto as criadas em sessões (Meeting).
  • Listar só as anotações cujo autor é o terapeuta logado.
  • Aceitar content em HTML (gerado pelo editor do front), sem alterar como as anotações de sessão são gravadas.

Fora de escopo

  • Busca no backend: a busca por termo é feita no front sobre a lista completa.
  • Paginação do index.
  • Checagem de plano PRO nas rotas: segue o padrão atual de /me/clients, protegido apenas pela posse do cliente (current_clients_query) e pela autoria da anotação.
  • Mudanças em /meetings/:meeting_id/comments, /me/comments e no model Comment.
  • Sanitização de HTML na API: o conteúdo é gravado como recebido e o front sanitiza na exibição (DOMPurify), o que também cobre as anotações antigas.
  • Migrations: nenhuma mudança de schema.

Mudanças

app/models/user_client.rb

  • include Commentable → has_many :comments, as: :commentable, dependent: :destroy.

config/routes.rb

ruby resources :comments, only: [:index, :create, :update, :destroy], controller: "clients_comments", on: :member

E atualização do bloco de rotas comentado no fim do arquivo.

app/controllers/api/v1/clients_comments_controller.rb

  • set_user_client: current_clients_query.find(params[:client_id]); 404 com Alerts::NotFound::Female.call(UserClient) se não existir (comportamento atual).
  • Escopo de anotações do terapeuta para o cliente: Comment.where(commentable: [user_client, *Meeting.by_user(patient).with_participant(current_user)], user: current_user).
  • index: o escopo acima, order(created_at: :desc), render json: (mantém CommentSerializer, com locale_format_display).
  • create: user_client.comments.new(content:, user: current_user). Resposta igual a API::V1::CommentsController#create: 201 com { comment: {...} }, ou 422 com errors.
  • update: busca por pid dentro do escopo; 404 se não encontrar (inclui anotação de outro autor ou de outro cliente). Atualiza só content. Resposta 200 com { comment: {...} }, ou 422.
  • destroy: mesma busca; 200 em sucesso.
  • Parâmetros: params.expect(comment: [:content]), igual ao CommentsController.

Contrato resultante

Método Rota Corpo Sucesso Erros
GET /api/v1/me/clients/:client_id/comments — 200 lista 404 cliente
POST /api/v1/me/clients/:client_id/comments { comment: { content } } 201 { comment } 404 cliente, 422
PATCH /api/v1/me/clients/:client_id/comments/:pid { comment: { content } } 200 { comment } 404 cliente/anotação, 422
DELETE /api/v1/me/clients/:client_id/comments/:pid — 200 404 cliente/anotação

Como verificar

Request specs em spec/requests/api/v1/:

  • clients_comments_index_spec.rb (existente, ajustar):
    • o caso “with meetings and comments” usa comentário do paciente → passa a esperar [];
    • novo caso: comentário do terapeuta em Meeting aparece;
    • novo caso: comentário do terapeuta no UserClient aparece;
    • novo caso: comentário do terapeuta para outro cliente não aparece;
    • ordenação por created_at desc.
  • clients_comments_create_spec.rb: cria no UserClient com autor current_user; cliente inexistente → 404; content vazio → 422.
  • clients_comments_update_spec.rb: atualiza anotação do UserClient e de Meeting; anotação de outro autor → 404; de outro cliente → 404; conteúdo vazio → 422.
  • clients_comments_destroy_spec.rb: exclui anotação do UserClient e de Meeting; outro autor → 404.

Rodar bundle exec rspec nos arquivos acima e bundle exec rubocop.

Documentação

  • Criar .project/docs/rules/clients/client_annotations.md com as regras: anotação vinculada ao UserClient ou à Meeting, listagem só do autor, edição/exclusão só do autor. Registrar como R-006 em .project/docs/RULES.md.
  • Adicionar a spec e a regra ao índice .project/docs/README.md.