diff --git a/db/migrate/20260415040927_create_captain_lifecycle_tables.rb b/db/migrate/20260415040927_create_captain_lifecycle_tables.rb new file mode 100644 index 000000000..af8cc6cfa --- /dev/null +++ b/db/migrate/20260415040927_create_captain_lifecycle_tables.rb @@ -0,0 +1,80 @@ +class CreateCaptainLifecycleTables < ActiveRecord::Migration[7.1] + def change + create_lifecycle_rules_table + create_lifecycle_deliveries_table + create_lifecycle_configs_table + end + + private + + def create_lifecycle_rules_table + create_table :captain_lifecycle_rules do |t| + t.references :account, null: false, foreign_key: true, index: true + t.string :name, null: false + t.text :description + t.boolean :enabled, null: false, default: true + t.string :event, null: false + t.integer :offset_minutes, null: false, default: 0 + t.jsonb :filters, null: false, default: {} + t.string :message_type, null: false, default: 'text' + t.text :message_body, null: false + t.jsonb :message_payload + t.integer :priority, null: false, default: 50 + t.references :created_by_user, foreign_key: { to_table: :users }, index: true + t.timestamps + end + add_index :captain_lifecycle_rules, %i[account_id enabled event] + end + + def create_lifecycle_deliveries_table # rubocop:disable Metrics/MethodLength + create_table :captain_lifecycle_deliveries do |t| + t.references :account, null: false, foreign_key: true, index: true + t.references :lifecycle_rule, + foreign_key: { to_table: :captain_lifecycle_rules }, + index: { name: 'idx_lifecycle_deliveries_rule' } + t.references :captain_reservation, + null: false, + foreign_key: true, + index: { name: 'idx_lifecycle_deliveries_reservation' } + t.references :conversation, foreign_key: true + t.references :message, foreign_key: true + t.references :inbox, foreign_key: true + t.datetime :fire_at, null: false + t.datetime :sent_at + t.string :status, null: false, default: 'scheduled' + t.string :skip_reason + t.text :failure_reason + t.text :rendered_body + t.string :origin, null: false, default: 'scheduled_lifecycle' + t.timestamps + end + add_delivery_indexes + end + + def add_delivery_indexes + add_index :captain_lifecycle_deliveries, + %i[captain_reservation_id origin status], + name: 'idx_lifecycle_deliveries_cap_check' + add_index :captain_lifecycle_deliveries, + %i[account_id status fire_at], + name: 'idx_lifecycle_deliveries_dashboard' + add_index :captain_lifecycle_deliveries, + :fire_at, + where: "status = 'scheduled'", + name: 'idx_lifecycle_deliveries_scheduled' + end + + def create_lifecycle_configs_table + create_table :captain_lifecycle_configs do |t| + t.references :account, null: false, foreign_key: true, index: { unique: true } + t.boolean :quiet_hours_enabled, null: false, default: false + t.time :quiet_hours_from, null: false, default: '23:00' + t.time :quiet_hours_to, null: false, default: '08:00' + t.integer :min_interval_minutes, null: false, default: 30 + t.boolean :pause_on_customer_reply, null: false, default: false + t.integer :pause_on_customer_reply_within_minutes, null: false, default: 60 + t.references :opt_out_label, foreign_key: { to_table: :labels } + t.timestamps + end + end +end diff --git a/db/migrate/20260415040957_add_concierge_to_captain_units.rb b/db/migrate/20260415040957_add_concierge_to_captain_units.rb new file mode 100644 index 000000000..8ace3e935 --- /dev/null +++ b/db/migrate/20260415040957_add_concierge_to_captain_units.rb @@ -0,0 +1,8 @@ +class AddConciergeToCaptainUnits < ActiveRecord::Migration[7.1] + def change + add_reference :captain_units, :concierge_inbox, + foreign_key: { to_table: :inboxes }, + null: true + add_column :captain_units, :concierge_config, :jsonb, null: false, default: {} + end +end diff --git a/db/schema.rb b/db/schema.rb index 773acbd20..aa5354c80 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2026_03_03_172517) do +ActiveRecord::Schema[7.1].define(version: 2026_04_15_040957) do # These extensions should be enabled to support this database enable_extension "pg_stat_statements" enable_extension "pg_trgm" @@ -534,6 +534,68 @@ ActiveRecord::Schema[7.1].define(version: 2026_03_03_172517) do t.index ["inbox_id"], name: "index_captain_inboxes_on_inbox_id" end + create_table "captain_lifecycle_configs", force: :cascade do |t| + t.bigint "account_id", null: false + t.boolean "quiet_hours_enabled", default: false, null: false + t.time "quiet_hours_from", default: "2000-01-01 23:00:00", null: false + t.time "quiet_hours_to", default: "2000-01-01 08:00:00", null: false + t.integer "min_interval_minutes", default: 30, null: false + t.boolean "pause_on_customer_reply", default: false, null: false + t.integer "pause_on_customer_reply_within_minutes", default: 60, null: false + t.bigint "opt_out_label_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_captain_lifecycle_configs_on_account_id", unique: true + t.index ["opt_out_label_id"], name: "index_captain_lifecycle_configs_on_opt_out_label_id" + end + + create_table "captain_lifecycle_deliveries", force: :cascade do |t| + t.bigint "account_id", null: false + t.bigint "lifecycle_rule_id" + t.bigint "captain_reservation_id", null: false + t.bigint "conversation_id" + t.bigint "message_id" + t.bigint "inbox_id" + t.datetime "fire_at", null: false + t.datetime "sent_at" + t.string "status", default: "scheduled", null: false + t.string "skip_reason" + t.text "failure_reason" + t.text "rendered_body" + t.string "origin", default: "scheduled_lifecycle", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id", "status", "fire_at"], name: "idx_lifecycle_deliveries_dashboard" + t.index ["account_id"], name: "index_captain_lifecycle_deliveries_on_account_id" + t.index ["captain_reservation_id", "origin", "status"], name: "idx_lifecycle_deliveries_cap_check" + t.index ["captain_reservation_id"], name: "idx_lifecycle_deliveries_reservation" + t.index ["conversation_id"], name: "index_captain_lifecycle_deliveries_on_conversation_id" + t.index ["fire_at"], name: "idx_lifecycle_deliveries_scheduled", where: "((status)::text = 'scheduled'::text)" + t.index ["inbox_id"], name: "index_captain_lifecycle_deliveries_on_inbox_id" + t.index ["lifecycle_rule_id"], name: "idx_lifecycle_deliveries_rule" + t.index ["message_id"], name: "index_captain_lifecycle_deliveries_on_message_id" + end + + create_table "captain_lifecycle_rules", force: :cascade do |t| + t.bigint "account_id", null: false + t.string "name", null: false + t.text "description" + t.boolean "enabled", default: true, null: false + t.string "event", null: false + t.integer "offset_minutes", default: 0, null: false + t.jsonb "filters", default: {}, null: false + t.string "message_type", default: "text", null: false + t.text "message_body", null: false + t.jsonb "message_payload" + t.integer "priority", default: 50, null: false + t.bigint "created_by_user_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id", "enabled", "event"], name: "idx_on_account_id_enabled_event_2d8b8a9942" + t.index ["account_id"], name: "index_captain_lifecycle_rules_on_account_id" + t.index ["created_by_user_id"], name: "index_captain_lifecycle_rules_on_created_by_user_id" + end + create_table "captain_notification_templates", force: :cascade do |t| t.string "label", null: false t.text "content", null: false @@ -855,8 +917,11 @@ ActiveRecord::Schema[7.1].define(version: 2026_03_03_172517) do t.text "inter_key_content" t.datetime "webhook_configured_at" t.boolean "proactive_pix_polling_enabled", default: false, null: false + t.bigint "concierge_inbox_id" + t.jsonb "concierge_config", default: {}, null: false t.index ["account_id"], name: "index_captain_units_on_account_id" t.index ["captain_brand_id"], name: "index_captain_units_on_captain_brand_id" + t.index ["concierge_inbox_id"], name: "index_captain_units_on_concierge_inbox_id" t.index ["inbox_id"], name: "index_captain_units_on_inbox_id" end @@ -2022,6 +2087,16 @@ ActiveRecord::Schema[7.1].define(version: 2026_03_03_172517) do add_foreign_key "captain_inbox_reminder_settings", "accounts" add_foreign_key "captain_inbox_reminder_settings", "inboxes" add_foreign_key "captain_inboxes", "captain_units" + add_foreign_key "captain_lifecycle_configs", "accounts" + add_foreign_key "captain_lifecycle_configs", "labels", column: "opt_out_label_id" + add_foreign_key "captain_lifecycle_deliveries", "accounts" + add_foreign_key "captain_lifecycle_deliveries", "captain_lifecycle_rules", column: "lifecycle_rule_id" + add_foreign_key "captain_lifecycle_deliveries", "captain_reservations" + add_foreign_key "captain_lifecycle_deliveries", "conversations" + add_foreign_key "captain_lifecycle_deliveries", "inboxes" + add_foreign_key "captain_lifecycle_deliveries", "messages" + add_foreign_key "captain_lifecycle_rules", "accounts" + add_foreign_key "captain_lifecycle_rules", "users", column: "created_by_user_id" add_foreign_key "captain_notification_templates", "inboxes" add_foreign_key "captain_pix_charges", "captain_reservations", column: "reservation_id" add_foreign_key "captain_pix_charges", "captain_units", column: "unit_id" @@ -2059,6 +2134,7 @@ ActiveRecord::Schema[7.1].define(version: 2026_03_03_172517) do add_foreign_key "captain_units", "accounts" add_foreign_key "captain_units", "captain_brands" add_foreign_key "captain_units", "inboxes" + add_foreign_key "captain_units", "inboxes", column: "concierge_inbox_id" add_foreign_key "conversation_crm_insights", "accounts" add_foreign_key "conversation_crm_insights", "contacts" add_foreign_key "conversation_crm_insights", "conversations"