diff --git a/Gemfile b/Gemfile index 50c0c25..d3ae856 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem "pg", "~> 1.1" gem "puma", "~> 6.0" # Frontend +gem "propshaft" # asset pipeline leve gem "importmap-rails" gem "turbo-rails" gem "stimulus-rails" diff --git a/README.md b/README.md index fdc9483..e0d5ad1 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,52 @@ docker-compose exec app bundle exec whenever --update-crontab --- + +## 🩺 Correção (11/06): container caía mostrando ajuda do "rails new" + +**Sintoma:** `docker-compose up` subia e o log mostrava o help do `rails new` em loop. +**Causa:** o repositório tinha os arquivos da aplicação (models/controllers/views) mas **não tinha o esqueleto de boot do Rails** — sem `config/application.rb` e `config.ru`, o comando `rails s` não reconhece a pasta como um app Rails e cai no modo "criar app novo". + +**Arquivos adicionados nesta correção:** +``` +config.ru # entrada Rack +config/boot.rb, environment.rb # boot do Rails +config/application.rb # módulo GadeLogistica + timezone SP + pt-BR +config/puma.rb # servidor web +config/environments/{development,production,test}.rb +config/importmap.rb # pins do Stimulus/Turbo +config/initializers/devise.rb # obrigatório para o devise_for das rotas +config/locales/pt-BR.yml # formatos de data brasileiros +bin/rails, bin/rake # executáveis +app/javascript/application.js # bootstrap Turbo + Stimulus +app/javascript/controllers/{application,index}.js +Gemfile # + gem propshaft (servir o JS via importmap) +app/views/layouts/application.html.erb # + javascript_importmap_tags (Stimulus não carregava!) +config/routes.rb # devise_for agora aponta para users/sessions (login PIN) +``` + +### Como subir agora (passo a passo completo) + +```bash +# 1. Criar o .env (você NÃO tem ele ainda — é cópia do exemplo): +cp .env.example .env + +# 2. Gerar a SECRET_KEY_BASE e colar no .env: +openssl rand -hex 64 +nano .env # cole em SECRET_KEY_BASE= e preencha DB_HOST/DB_USER/DB_PASSWORD + +# 3. Rebuild (Gemfile mudou — gem propshaft): +docker-compose build --no-cache +docker-compose up -d + +# 4. Criar banco do sistema + migrar + popular: +docker-compose exec app bundle exec rails db:create db:migrate db:seed + +# 5. Conferir: +docker-compose logs -f app # deve mostrar "Listening on http://0.0.0.0:3000" +# Acesse http://SEU_IP:3000 → admin@gade.com / Gade@2026! +``` + ## 🔐 Segurança - **NUNCA** versione `.env`, `config/master.key` ou qualquer arquivo com senha diff --git a/app/javascript/application.js b/app/javascript/application.js new file mode 100644 index 0000000..0a54717 --- /dev/null +++ b/app/javascript/application.js @@ -0,0 +1,2 @@ +import "@hotwired/turbo-rails" +import "controllers" diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js new file mode 100644 index 0000000..efe3cb0 --- /dev/null +++ b/app/javascript/controllers/application.js @@ -0,0 +1,5 @@ +import { Application } from "@hotwired/stimulus" +const application = Application.start() +application.debug = false +window.Stimulus = application +export { application } diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js new file mode 100644 index 0000000..702b3a6 --- /dev/null +++ b/app/javascript/controllers/index.js @@ -0,0 +1,3 @@ +import { application } from "controllers/application" +import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +eagerLoadControllersFrom("controllers", application) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index efbbbe8..ac28d0d 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -48,6 +48,7 @@ @keyframes spin { to { transform: rotate(360deg); } } + <%= javascript_importmap_tags %> <%= yield :head %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..a9b8655 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..808f5eb --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..9e89791 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. +require_relative "config/environment" +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..1b1fa42 --- /dev/null +++ b/config/application.rb @@ -0,0 +1,27 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) +require "dotenv/load" if defined?(Dotenv) + +module GadeLogistica + class Application < Rails::Application + config.load_defaults 7.1 + + # Timezone e idioma Brasil + config.time_zone = "America/Sao_Paulo" + config.i18n.default_locale = :'pt-BR' + config.i18n.available_locales = [:'pt-BR', :en] + config.i18n.fallbacks = [:en] + + # Autoload de services + config.autoload_paths += %W[#{config.root}/app/services] + + # Não gerar specs/helpers desnecessários + config.generators do |g| + g.test_framework :rspec + g.helper false + g.stylesheets false + end + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..9750d5c --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,2 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) +require "bundler/setup" diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..2ca43fd --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,2 @@ +require_relative "application" +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..0e5a683 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,22 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.enable_reloading = true + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + config.cache_store = :memory_store + config.active_storage.service = :local if defined?(ActiveStorage) + + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.action_mailer.default_url_options = { host: ENV.fetch("APP_HOST", "localhost:3000") } + + config.active_support.deprecation = :log + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true + + config.assets.quiet = true if config.respond_to?(:assets) + config.hosts.clear # aceita qualquer host em dev (Docker/IP local) +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..2e3f268 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,27 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.enable_reloading = false + config.eager_load = true + config.consider_all_requests_local = false + + config.force_ssl = false # mude para true quando tiver HTTPS + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + config.log_tags = [:request_id] + config.logger = ActiveSupport::Logger.new(STDOUT).tap { |l| l.formatter = ::Logger::Formatter.new } + .then { |l| ActiveSupport::TaggedLogging.new(l) } + + config.cache_store = :memory_store + config.active_storage.service = :local if defined?(ActiveStorage) + + config.action_mailer.perform_caching = false + config.action_mailer.default_url_options = { host: ENV.fetch("APP_HOST", "localhost:3000") } + + config.i18n.fallbacks = true + config.active_support.report_deprecations = false + config.active_record.dump_schema_after_migration = false + + # Aceita o host configurado no .env + config.hosts << ENV["APP_HOST"]&.split(":")&.first if ENV["APP_HOST"].present? + config.hosts.clear if ENV["RAILS_ALLOW_ALL_HOSTS"] == "true" +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..4c921b0 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,10 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.enable_reloading = false + config.eager_load = ENV["CI"].present? + config.consider_all_requests_local = true + config.cache_store = :null_store + config.action_mailer.delivery_method = :test + config.active_support.deprecation = :stderr +end diff --git a/config/importmap.rb b/config/importmap.rb new file mode 100644 index 0000000..a657ad1 --- /dev/null +++ b/config/importmap.rb @@ -0,0 +1,6 @@ +# Pin npm packages by running ./bin/importmap +pin "application" +pin "@hotwired/turbo-rails", to: "turbo.min.js" +pin "@hotwired/stimulus", to: "stimulus.min.js" +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" +pin_all_from "app/javascript/controllers", under: "controllers" diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 0000000..3c7f29e --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,16 @@ +Devise.setup do |config| + config.mailer_sender = ENV.fetch('SMTP_USERNAME', 'noreply@gade.com.br') + require 'devise/orm/active_record' + config.case_insensitive_keys = [:email] + config.strip_whitespace_keys = [:email] + config.skip_session_storage = [:http_auth] + config.stretches = Rails.env.test? ? 1 : 12 + config.reconfirmable = true + config.expire_all_remember_me_on_sign_out = true + config.password_length = 6..128 + config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ + config.reset_password_within = 6.hours + config.sign_out_via = :delete + config.responder.error_status = :unprocessable_entity + config.responder.redirect_status = :see_other +end diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml new file mode 100644 index 0000000..1ada311 --- /dev/null +++ b/config/locales/pt-BR.yml @@ -0,0 +1,9 @@ +pt-BR: + date: + formats: + default: "%d/%m/%Y" + short: "%d/%m/%Y" + time: + formats: + default: "%d/%m/%Y %H:%M" + short: "%d/%m %H:%M" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..fa45f9d --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,9 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" +port ENV.fetch("PORT") { 3000 } +environment ENV.fetch("RAILS_ENV") { "development" } +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb index cba2dc2..b39314b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,9 @@ # config/routes.rb Rails.application.routes.draw do # Devise — login padrão para admin/gerente/operador - devise_for :users, path: 'auth', path_names: { + devise_for :users, path: 'auth', + controllers: { sessions: 'users/sessions' }, + path_names: { sign_in: 'login', sign_out: 'logout', password: 'senha' diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..473a0f4 diff --git a/public/.keep b/public/.keep new file mode 100644 index 0000000..473a0f4 diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..473a0f4 diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..473a0f4 diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000..473a0f4