Regra de pagamento: - Entrega.pagas agora exige status='completed' E checkout preenchido (antes era checkin). Afeta dashboard, painel do motorista, job 1h e elegibilidade das consolidações de forma consistente. Veículo no lugar de rota na consolidação: - migration troca consolidacoes.route_ids por vehicle_ids (jsonb + gin) - Entrega: da_veiculo/veiculos_unicos; contar_pagas usa vehicle - new.html.erb: filtro "Veículos" (multi-select por vehicle) - validar.html.erb: mostra o veículo em vez do código da rota - filtros/elegibilidade do controller passam a usar vehicle_ids Docs/diagnóstico atualizados. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project overview
Reem Logística is a Rails 7 web application for controlling delivery costs for Gade Hospitalar (account_id: 95907). It manages consolidations of driver payments across delivery routes (UBS SUL, UBS LESTE, EMAD, STS, SAD, etc.).
Commands
All commands run inside Docker. The PostgreSQL database lives externally (not in docker-compose).
# Start
docker-compose up -d
# Rails console
docker-compose exec app bundle exec rails console
# Run migrations
docker-compose exec app bundle exec rails db:migrate
# Seed (creates admin + test drivers)
docker-compose exec app bundle exec rails db:seed
# Logs
docker-compose logs -f app
# Tests (RSpec)
docker-compose exec app bundle exec rspec
docker-compose exec app bundle exec rspec spec/models/consolidacao_spec.rb # single file
# Rake task (runs manually what the cron job runs hourly)
docker-compose exec app bundle exec rake historico:atualizar
# Activate the hourly cron job on the server
docker-compose exec app bundle exec whenever --update-crontab
Setup from scratch
cp .env.example .env
# Edit .env: set DB_HOST, DB_PASSWORD, and generate SECRET_KEY_BASE with:
# openssl rand -hex 64
docker-compose build --no-cache
docker-compose up -d
docker-compose exec app bundle exec rails db:create db:migrate db:seed
Default credentials (change in production): admin@gade.com / Gade@2026!
Critical constraint: read-only external table
The table public.db_reem_simplerout_2026 is owned by an external system (SimpleRoute) that updates it every hour. NEVER create migrations for it, and never run INSERT/UPDATE/DELETE/DROP/TRUNCATE on it.
Entrega (app/models/entrega.rb) maps to this table and enforces readonly? = true. All queries go through its scopes — the most important being .pagas (status='completed' AND checkout IS NOT NULL), which defines payment eligibility. Consolidations filter eligible deliveries by vehicle (vehicle column → Consolidacao#vehicle_ids), not by route.
Architecture
Data flow
- External system writes to
db_reem_simplerout_2026hourly Atualizar HistoricoEstimadoJob(triggered by Whenever cron every hour) counts paid deliveries per driver and writes tohistorico_estimados- Admins/managers create Consolidações (payment batches) covering a date range + list of drivers
- A 3-step wizard classifies each delivery per driver (Normal/Retirada/Bônus/Desconto toggles)
- Finalizing a consolidation sends WhatsApp (Twilio) and email notifications to drivers
- Drivers view their own panel at
/motoristausing a 4-digit PIN or QR code from their printed payslip
Key models
| Model | Table | Notes |
|---|---|---|
Entrega |
db_reem_simplerout_2026 |
Read-only. External data. |
Consolidacao |
consolidacoes |
Payment batch. Enum status: rascunho/finalizada/arquivada. Soft-delete via deleted_at. |
ConsolidacaoMotorista |
consolidacao_motoristas |
Join: which drivers are in a consolidation. |
ConsolidacaoEntrega |
consolidacao_entregas |
Each classified delivery. Enum tipo: normal/retirada/bonus/desconto. |
HistoricoEstimado |
historico_estimados |
Snapshot of hourly estimated values per driver. |
Configuracao |
configuracoes |
Key-value store for prices and feature flags. Access via Configuracao.valor('chave'). |
AuditoriaLog |
auditoria_logs |
Audit trail. Controllers include Auditavel concern and call auditar!(:acao, registro). |
User |
users |
Devise auth. Roles: admin/gerente/operador/motorista. Drivers may have no email — they log in via pin_code (4 digits, unique per driver) or login_token (QR). |
Authorization
Pundit policies in app/policies/. ApplicationController includes Pundit::Authorization and calls authenticate_user! on every action. The motorista panel (/motorista/**) uses a separate session mechanism (motorista/sessoes_controller.rb) — drivers are NOT authenticated via Devise.
Two login flows for drivers
/auth/login(Devise, Fase 2) — PIN tab on the standard login page/motorista/login(Fase 8) — dedicated numeric keypad, used by QR codes printed on payslips. Prefer this for mobile. Both usepin_code.
PDF generation
app/services/pdf/ contains three classes:
BasePdf— shared black/orange header and footer layoutRelatorioMotoristaPdf— detailed delivery table per driverHoleritePdf— payslip style + embedded QR code (viarqrcode/chunky_png) linking to/motorista/acesso/:token
The consolidation wizard
/consolidacoes/:id/wizard → /consolidacao_entregas/validar → /consolidacao_entregas/revisar
- Passo 1 (wizard): pick a driver. Shows progress per driver.
- Passo 2 (validar): color-coded toggle buttons per delivery (orange=Normal, dark orange=Retirada, white=Bônus, black=Desconto). Toggle individual or mass-classify. Stimulus controller (
validacao_controller.js) handles real-time totals and progress. - Passo 3 (revisar): summary for the selected driver, then move to the next driver or save as draft.
Finalizing is blocked (server-side + UI) until all drivers have all eligible deliveries classified.
Notifications (NotificacaoService)
Controlled by Configuracao flags notificacao_whatsapp and notificacao_email. Failures are rescued and logged — they never abort the finalization. WhatsApp requires Twilio ENV vars + driver telefone field in +5511999998888 format.
Design system
Dark theme (default). Colors: background #0a0a0a, cards #1a1a1a, accent/buttons #f97316 (orange), text #ffffff, success #22c55e, error #ef4444. Minimum font 16px desktop / 18px mobile. Touch targets minimum 48px height.
Environment variables
All config comes from .env (never hardcoded). Key variables:
DB_HOST/DB_NAME/DB_USER/DB_PASSWORD— PostgreSQL connectionDB_EXISTING_ACCOUNT_ID— filtersdb_reem_simplerout_2026to Gade's account (default: 95907)SECRET_KEY_BASE— generate withopenssl rand -hex 64APP_HOST— used in QR code URLs and notification linksTWILIO_*— WhatsApp notifications (optional)SMTP_*— Email notifications (optional, only activates ifSMTP_USERNAMEis set)