Os stubs de lifecycle criados na task anterior estavam em app/controllers/
causando futura colisão de redefinição de classe quando os controllers reais
forem implementados em enterprise/app/controllers/ (tasks 4-6). Move os 3
stubs para o enterprise path onde vivem todos os controllers Captain.
Routing spec: 7 examples, 0 failures
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wires 3 new captain namespace resources (lifecycle_rules, lifecycle_config,
lifecycle_deliveries) and a member action `patch :concierge` on units.
Includes stub controllers (to be expanded in Tasks 4-7) and passing routing spec.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaced broken `association :brand, factory: :captain_brand, account: account`
(FactoryBot cannot evaluate `account` lazily that way) with a transient block
that does `Captain::Brand.find_by(account_id: account.id) || association(...)`,
ensuring the brand always belongs to the same account as the unit.
Adds factory spec (6 examples) confirming standalone create, account override,
and brand reuse all work correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also fixes double-scheduling bug in scheduler_spec and delivery_spec caused by
after_create_commit hook firing while rules already exist — reservation is now
created before rules in setup so the hook finds nothing to schedule.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds concierge.* and reservation.* Liquid variables to agent_instructions
so Sofia's orchestrator_prompt receives unit persona/knowledge/variables
and reservation data resolved from conversation.custom_attributes.current_unit_id.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace no-op stub with full perform body: find delivery by id, skip if
blank, delegate to Captain::Lifecycle::Dispatcher#call. Add retry_on
with polynomially_longer backoff (3 attempts). Spec covers dispatcher
delegation and graceful skip for missing records.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Orchestrates guards → render (Liquid) → send pipeline for one delivery.
Handles skip, reschedule, sent, failed states and re-enqueues on reschedule.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement guards following the same pass/reschedule/too_stale pattern as QuietHours.
Also fix belongs_to :conversation on Delivery to use class_name: '::Conversation' to avoid namespace resolution failure inside Captain::Lifecycle module.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add after_commit callbacks to call Captain::Lifecycle::Scheduler on
create, status change (cancelled/no_show), and check_in_at change.
Each handler wraps in rescue StandardError to preserve existing behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pure function mapping reservation events to timestamps; used by Scheduler (T9) to compute fire_at.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TDD: 16 examples passing. Adds EVENTS constant, active/for_event scopes,
and matches_reservation? with unit_ids/categorias/permanencias filters.
Also adds captain_reservation factory used by the spec.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Plano de 20 tasks em TDD cobrindo: migrations, models (Rule/Delivery/Config),
extensões em Captain::Unit, 3 métodos interativos em Wuzapi::Client,
EventResolver, Scheduler event-driven, hooks em Captain::Reservation,
ContextBuilder, 6 guards (Opção C quiet hours, max-5, opt-out, etc),
Dispatcher pipeline, DispatcherJob, injeção Liquid de concierge.* no
orchestrator prompt e spec de integração end-to-end.
Out of scope: UI (Fase B) será plano separado após backend validado.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Design para a feature de automação de mensagens WhatsApp baseada em
eventos do ciclo de vida de reserva — 4 componentes isolados (rules
engine, scheduler event-driven, dispatcher pipeline, concierge AI
Sofia), multi-tenant desde o dia 1, com guards anti-ban e injeção
dinâmica de knowledge por unidade via Liquid.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Existem 3 mecanismos de vinculo inbox-unit no fork:
1. captain_inboxes.captain_unit_id (fluxo Captain)
2. captain_unit_inboxes (tabela join pura, usada pela UI nova)
3. captain_units.inbox_id (legado direto)
O serializer lia so o #1 e retornava null nas outras, fazendo a UI
mostrar 'Nenhuma unidade vinculada' mesmo quando havia vinculo via
#2 ou #3. Agora o jbuilder cai em cascata nas 3 fontes.
Cobre ambos os caminhos (generate_pix_tool e PublicReservationsController):
toda reserva criada recebe um after_create_commit que posta uma mensagem
privada na conversa com os detalhes (suite, check-in, valores, ID).
Remove a criacao duplicada do PublicReservationsController.
- GeneratePixTool: envia payment_link como mensagem outgoing direta (bypassa
hallucination de [Link do Pix] placeholder pela LLM)
- GeneratePixTool: extrai email das mensagens recentes via regex e persiste
em contact.email
- GenerateReservationLinkTool: mesmo padrao de envio direto do link
- Captain::Reservation: after_create_commit callback atualiza
ultima_suite/permanencia/reserva_em/total_reservas em contact.custom_attributes
(aparece no painel lateral)
- Controller grava cpf/ultima_suite/ultima_permanencia/ultima_reserva_em/total_reservas
em contact.custom_attributes (aparece no painel lateral do Chatwoot)
- GenerateReservationLinkTool exige marca/unidade/categoria/permanencia/checkin_at;
retorna erro se Jasmine chamar sem esses dados
Mirrors CheckPixPaymentTool resolve_conversation helpers. No fallback,
Jasmine so precisa passar categoria/permanencia/checkin_at - a tool
preenche nome/telefone/cpf/email a partir do contato.
Cria Captain::Tools::GenerateReservationLinkTool que constrói URL
pré-preenchida do reserva-1001 com dados coletados em conversa.
Registra entrada generate_reservation_link em tools.yml e documenta
RESERVA_1001_BASE_URL no .env.example.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Smoke test revelou que o inbox do tipo whatsapp valida source_id com
regex ^\d{1,15}\z. Trocar UUID por telefone em digitos (phone_digits)
e normalizar phone_number pra +phone_digits antes de criar o contato.
Plano combinado com 19 tasks bite-sized:
- Parte A: seed de dados de teste em reserva_hotel
- Parte B (Fase 2): controller publico Chatwoot com 2 endpoints,
auth por token, 8 specs RSpec, smoke test via curl
- Parte C (Fase 3): client HTTP, formatadores, catalogoService,
useReservationForm, StayDetailsStep, ImageGallery, PriceSummary,
CustomerForm, PixCheckout com polling, SuccessScreen, ReservationFlow
Usa Captain::Unit id=4 (Hotel 1001 Aguas Lindas, inbox_id=2)
como unidade de teste (ja configurada com credenciais Inter).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Em vez de criar schema novo reserva_1001, reaproveita o schema
reserva_hotel existente no projeto Supabase acdvblhzzaneddlxqyst
(InAudit Hotel). Migration aditiva (3 tabelas + 4 colunas Chatwoot)
ja aplicada via MCP antes do plano iniciar.
Adaptacoes:
- Credenciais reais do projeto em .env.local
- Cliente Supabase com db.schema = reserva_hotel
- Tipos gerados com --schema reserva_hotel
- App.tsx le tabela 'marcas' (pt-br) em vez de 'brands'
- Mock do Vitest atualizado
- Task 5 vira "documenta migration aplicada" (sem db push)
- Task 6 usa supabase link + gen types --schema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Plano detalhado em 13 tasks bite-sized para construir a fundacao
do novo app reserva-1001: Vite + React 19 + TS + Tailwind v4 +
Supabase + shadcn/ui base, com paleta premium aplicada e schema
novo aplicado no banco. Entrega: app rodando com as 4 marcas
vindas do Supabase.
Fases subsequentes (backend Chatwoot, fluxo publico, admin,
polish visual, deploy) viram planos separados.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Novo app publico de reserva (Vite + React + Supabase) separado do
Chatwoot, que reusa toda a tubulacao de PIX (CobService, PixCharge,
webhook Inter, ConfirmationService) via um endpoint novo no Chatwoot.
Cobre: arquitetura, paleta premium, modelo de dados reformado
(corrige bug de preco nos domingos), contrato da API nova, fluxo
do cliente, plano de entrega em 6 fases e riscos.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>