⚠️ Achado principal: o spec original parte de uma premissa errada

O spec pasted assume que hoje existe só o widget de Agenda, e que o card de contato precisa ser construído do zero. Isso não é verdade.

Os dois componentes já existem e já convivem no mesmo container:

  • TerapistContact.tsx (src/containers/PublicProfile/components/) — card “Informações de Contato” completo: telefone, localização, e-mail, botão WhatsApp (wa.me/:number).
  • ProfileScheduler.tsx (mesma pasta) — o widget “Agenda” (calendário), título literal "Agenda", usa TRGScheduleCalendar.

A escolha entre os dois não é por tipo de profissional/plano (o spec já suspeitava disso e pediu verificação — a suspeita tinha fundamento, só que a variável real é outra). É por quem está vendo a página:

```ruby # trgclub-api/app/models/therapist_sections_manager.rb SECTIONS = { therapist: [“personal_contact”], patient: [“scheduling”] }.freeze

def sections return SECTIONS[:therapist] if user_logged? && user.is_therapist? SECTIONS[:patient] end ```

Chamado em Api::V1::TherapistsController com current_user = o visitante, não o dono do perfil. Ou seja: hoje, um terapeuta logado vendo qualquer perfil público vê o card de contato; um visitante anônimo ou paciente vê a Agenda — independente de quem seja o profissional.

No frontend isso é consumido em PublicProfile.tsx (showTerapistContact / showSchedulling), com um fallback controlado pela feature flag Flag.COST_REDUCTION_PHASE_ONE: se a flag estiver desligada, sempre mostra Agenda, ignorando a lógica de seções.

As duas telas de referência (Vilson e Maria) muito provavelmente diferem pela sessão de quem tirou o print (terapeuta logado vs. não), não por serem profissionais de tiers diferentes. O badge “Master CITRG” é outra lógica, completamente desacoplada (user_has_valid_master_certificate? em user_profile.rb, só afeta o selo no header, não a sidebar).

Consequência prática: esta não é uma história de “criar componente novo”. É uma história de generalizar uma migração que já está em andamento — terminar de ligar a flag pra 100% dos usuários e simplificar TherapistSectionsManager pra sempre retornar contato, removendo a Agenda desta tela pra qualquer visitante.

Situação das outras 3 histórias do spec original

História Spec original assumia Realidade no código
2 — Vídeo Feature nova Já implementada por completo: campo video_url em UserProfile, upload via UserVideo.tsx, renderização com link “Assista meu vídeo” + modal em TerapeutaCardHeader.tsx. Provavelmente não precisa de código novo — só confirmar que está ativa pra todos os perfis.
3 — Truncamento de bio Componente novo Componente reutilizável já existe: src/components/ui/TrucatedText/index.tsx (Typography com line-clamp + prop lines). O trabalho real é aplicar esse componente no campo de bio do perfil público, não construir um novo.
4 — Bandeiras de idioma Componente novo Confirmado como novo de fato. Não existe mapa idioma→bandeira em nenhum lugar do frontend. Hoje idiomas são só texto (languages: string[] em TerapeutaCard.tsx).

Outros pontos de atenção encontrados

  • Nomenclatura: o use case sugerido no spec, exibir_informacoes_contato.rb, viola a convenção do projeto (CLAUDE.md exige inglês; módulos seguem padrão Namespace::Action, ex.: Invitations::AcceptFlow, UserProfiles::Update). Nome correto seria algo como TherapistContacts::Show.
  • Agenda é reaproveitada em outro lugar (confirma a hipótese do próprio spec): Availability, AvailabilityTool::*, Availabilities::FindByUser/DestroyByUser e TherapistAvailableTimes::UpdateByProfile são usados no fluxo de agendamento de reuniões e na configuração de disponibilidade do terapeuta (onboarding). Não dá pra depreciar o backend — a história é só “esconder/substituir componente nessa view”, exatamente como o spec previu como plano B.
  • Não existe campo whatsapp dedicado — o link é derivado do campo phone (+ phone_country). Vale confirmar que todo phone salvo tem o formato certo (DDI + DDD + número, sem formatação) antes de virar link wa.me, senão o botão pode gerar link quebrado pra números antigos sem DDI.
  • Não existe utilitário compartilhado pra montar link do WhatsApp — está duplicado em pelo menos 3 lugares (TerapistContact.tsx, Menu/constants.ts, Footer/constants.ts). Boa oportunidade de extrair, mas fora do escopo se quiser manter o PR pequeno.

User Story (revisada): Card de contato sempre visível no perfil do profissional

Como visitante da página de perfil de qualquer profissional (seja terapeuta logado, paciente logado ou anônimo) Quero ver sempre o card “Informações de contato” (telefone, localização, e-mail, WhatsApp) na sidebar Para conseguir avaliar e falar com o profissional diretamente, sem depender do widget de agendamento automático, independente de quem estou logado como

Necessidade

Hoje o card de contato só aparece para um subconjunto de visitantes (terapeutas logados); todo o resto vê a Agenda. Isso limita o alcance da necessidade original: permitir que qualquer visitante avalie e contate o profissional sem depender do agendamento automático.

Output (definição de pronto)

  1. TherapistSectionsManager#sections deixa de depender de current_user (visitante) — sempre retorna ["personal_contact"], para qualquer tipo de visitante (anônimo, paciente, terapeuta).
  2. Renomear/ajustar o método e a classe se o nome TherapistSectionsManager/SECTIONS deixar de fazer sentido sem a branch de paciente (evitar código morto — remover a chave :patient e a lógica de scheduling se não for usada em mais nenhum lugar).
  3. Frontend: remover o fallback controlado por Flag.COST_REDUCTION_PHASE_ONE em PublicProfile.tsx — a flag deixa de ser condição para mostrar contato; vira comportamento único.
  4. ProfileScheduler.tsx deixa de ser importado/renderizado em PublicProfile.tsx (mas o componente e toda a stack de Availability/AvailabilityTool::* permanecem intactos — são usados no fluxo de agendamento de reuniões e na configuração de disponibilidade do terapeuta).
  5. Testes: request spec cobrindo os 3 papéis de visitante (anônimo, paciente, terapeuta) recebendo personal_contact em todos os casos.
  6. QA manual: validar formato do link wa.me para telefones salvos sem DDI (dado legado).
  7. Sem use case novo necessário do lado de “montar dados do card” — TerapistContact.tsx já consome os dados existentes de UserProfile/User/UserAddress. O trabalho é majoritariamente remoção/simplificação de condicional, não criação.

Cenários Gherkin

```gherkin Cenário: Visitante anônimo vê o card de contato Dado que não estou autenticado Quando acesso a página de perfil de qualquer profissional Então devo ver o card “Informações de contato” na lateral direita E não devo ver o widget de “Agenda” com calendário

Cenário: Paciente logado vê o card de contato Dado que estou autenticado como paciente Quando acesso a página de perfil de qualquer profissional Então devo ver o card “Informações de contato” na lateral direita E não devo ver o widget de “Agenda” com calendário

Cenário: Terapeuta logado vê o card de contato (comportamento já existente, mantido) Dado que estou autenticado como terapeuta Quando acesso a página de perfil de qualquer profissional Então devo ver o card “Informações de contato” na lateral direita

Cenário: Botão de WhatsApp Dado que estou no card de informações de contato Quando clico no botão “WhatsApp” Então devo ser redirecionado para o WhatsApp com o número do profissional já preenchido, incluindo o DDI

Cenário: Feature flag de rollout não altera mais o resultado Dado que a flag “COST_REDUCTION_PHASE_ONE” está desligada para o meu usuário Quando acesso a página de perfil de qualquer profissional Então devo ver o card “Informações de contato” da mesma forma que veria com a flag ligada ```


Histórias 2, 3 e 4 — status revisado (sem necessidade de reescrever o spec original)

Os cenários Gherkin das Histórias 2, 3 e 4 do spec original continuam válidos como critério de aceite — a diferença é o tamanho do trabalho, não o comportamento esperado:

  • História 2 (vídeo): tratar como verificação, não implementação. Rodar os cenários já escritos no spec original contra o ambiente atual antes de abrir qualquer PR; é provável que já passem.
  • História 3 (truncamento de bio): o “Output” muda de “criar <TruncatedText />” para “importar TrucatedText de src/components/ui/TrucatedText e aplicá-lo ao campo de bio em PublicProfile”. Vale corrigir o typo da pasta (Trucated → Truncated) no mesmo PR ou abrir um ticket separado de cleanup.
  • História 4 (bandeiras): único item do spec original que é 100% trabalho novo, como descrito. Mantém o use case/componente sugerido (<LanguageTag idioma="pt-BR" /> + mapa centralizado idioma→bandeira).