-
-
Setup Your Better Together Community Platform
-
Fill out the platform details below to set up your platform.
+
+
+
+
+
+ A strong community starts with a solid foundation. Let’s begin by filling in
+ a few details about your platform. Before you know it, you’ll have a home base
+ where everyone can gather and collaborate.
+
<% if @form.errors.any? %>
@@ -19,48 +53,63 @@
<%= form_for @form, url: setup_wizard_step_create_host_platform_path, method: :post, class: 'needs-validation', novalidate: true do |f| %>
- <%= f.label :name, class: 'form-label' %>
- <%= f.text_field :name, autofocus: true, class: "form-control#{' is-invalid' if @form.errors[:name].any?}", required: true %>
+ <%= f.label :name, 'What should we call your platform?', class: 'form-label' %>
+ <%= f.text_field :name, autofocus: true, placeholder: 'Example: The Community Hall', class: "form-control#{' is-invalid' if @form.errors[:name].any?}", required: true %>
+
+ This name will appear at the top of your platform and welcome everyone who arrives.
+
- <%= f.label :description, class: 'form-label' %>
- <%= f.text_area :description, class: "form-control#{' is-invalid' if @form.errors[:description].any?}", rows: 3, required: true %>
+ <%= f.label :description, 'How would you describe your community space?', class: 'form-label' %>
+ <%= f.text_area :description, placeholder: 'A place where neighbors and friends support each other.', class: "form-control#{' is-invalid' if @form.errors[:description].any?}", rows: 3, required: true %>
+
+ This helps visitors understand what your community is all about.
+
- <%= f.label :url, class: 'form-label' %>
- <%= f.text_field :url, class: "form-control#{' is-invalid' if @form.errors[:url].any?}", required: true %>
+ <%= f.label :url, 'Where can people find you online?', class: 'form-label' %>
+ <%= f.text_field :url, placeholder: 'https://yourplatform.com', class: "form-control#{' is-invalid' if @form.errors[:url].any?}", required: true %>
+
+ This will be your platform’s web address — its front door on the internet.
+
- <%= f.label :privacy, class: 'form-label' %>
+ <%= f.label :privacy, 'Who can visit your space?', class: 'form-label' %>
<%= f.select :privacy, BetterTogether::Platform.privacies.keys.map { |privacy| [privacy.humanize, privacy] }, {}, { class: 'form-select', required: true } %>
+
+ Choose whether your space is open to the public or invitation-only.
+
-
- <%= f.label :time_zone, class: 'form-label' %>
- <%= f.time_zone_select :time_zone, ActiveSupport::TimeZone.all, {}, { class: 'form-select', id: 'time_zone_select', required: true } %>
+
+
+ <%= f.label :time_zone, 'Which time zone should we use?', class: 'form-label' %>
+ <%= f.time_zone_select :time_zone, ActiveSupport::TimeZone.all, {},
+ {
+ class: 'form-select',
+ data: { 'better-together--time-zone-target': 'select' },
+ id: 'time_zone_select',
+ required: true
+ }
+ %>
+
+ This helps keep events and notifications in sync for everyone.
+
- <%= f.submit 'Next Step', class: 'btn btn-primary' %>
+
+ <%= f.submit 'Next Step', class: 'btn btn-primary w-100' %>
+
<% end %>
+
+
-
-
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb
index ec56bb2a3..67b1d1eea 100644
--- a/app/views/devise/shared/_links.html.erb
+++ b/app/views/devise/shared/_links.html.erb
@@ -16,16 +16,10 @@
<%= link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name), class: 'devise-link' %>
<% end %>
- <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
- <%# this should be moved to omniautho block. unlock translation key incorrect. %>
- <%=
- link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), new_unlock_path(resource_name), class: 'devise-link' %>
- <% end %>
-
- <%- if devise_mapping.omniauthable? %>
- <%- resource_class.omniauth_providers.each do |provider| %>
- <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: 'devise-link' %>
- <% end %>
+<%- if devise_mapping.omniauthable? && params[:oauth_login].present? %>
+ <%- resource_class.omniauth_providers.each do |provider| %>
+ <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
<% end %>
+<% end %>
diff --git a/app/views/layouts/better_together/_locale_switcher.html.erb b/app/views/layouts/better_together/_locale_switcher.html.erb
index 505762279..765744bd6 100644
--- a/app/views/layouts/better_together/_locale_switcher.html.erb
+++ b/app/views/layouts/better_together/_locale_switcher.html.erb
@@ -6,8 +6,8 @@
diff --git a/better_together.gemspec b/better_together.gemspec
index 1311fa52d..94e4050ab 100644
--- a/better_together.gemspec
+++ b/better_together.gemspec
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'activerecord-postgis-adapter'
spec.add_dependency 'active_storage_svg_sanitizer'
spec.add_dependency 'active_storage_validations'
+ spec.add_dependency 'acts_as_tenant'
spec.add_dependency 'bootstrap', '~> 5.3.2'
spec.add_dependency 'dartsass-sprockets', '~> 3.1'
spec.add_dependency 'devise'
@@ -54,6 +55,10 @@ Gem::Specification.new do |spec|
spec.add_dependency 'mobility', '>= 1.0.1', '< 2.0'
spec.add_dependency 'mobility-actiontext', '~> 1.1'
spec.add_dependency 'noticed'
+ spec.add_dependency 'octokit'
+ spec.add_dependency 'omniauth'
+ spec.add_dependency 'omniauth-github', '~> 2.0.0'
+ spec.add_dependency 'omniauth-rails_csrf_protection'
spec.add_dependency 'premailer-rails'
spec.add_dependency 'public_activity'
spec.add_dependency 'pundit', '>= 2.1', '< 2.6'
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 4153c5126..cf772aff6 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -273,7 +273,8 @@
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
- # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
+ config.omniauth :github, ENV.fetch('GITHUB_CLIENT_ID', nil), ENV.fetch('GITHUB_CLIENT_SECRET', nil),
+ scope: 'user,public_repo'
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
diff --git a/config/routes.rb b/config/routes.rb
index e21f52788..f921f064d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -3,6 +3,11 @@
require 'sidekiq/web'
BetterTogether::Engine.routes.draw do # rubocop:todo Metrics/BlockLength
+ devise_for :users,
+ class_name: BetterTogether.user_class.to_s,
+ only: :omniauth_callbacks,
+ controllers: { omniauth_callbacks: 'better_together/users/omniauth_callbacks' }
+
scope ':locale', # rubocop:todo Metrics/BlockLength
locale: /#{I18n.available_locales.join('|')}/ do
# bt base path
@@ -14,7 +19,6 @@
class_name: BetterTogether.user_class.to_s,
controllers: {
confirmations: 'better_together/users/confirmations',
- # omniauth_callbacks: 'better_together/users/omniauth_callbacks',
passwords: 'better_together/users/passwords',
registrations: 'better_together/users/registrations',
sessions: 'better_together/users/sessions'
@@ -31,6 +35,7 @@
defaults: { format: :html, locale: I18n.locale }
get 'search', to: 'search#search'
+
# Avoid clobbering admin users_path helper; keep redirect but rename helper
get 'users', to: redirect('users/sign-in'), as: :redirect_users # redirect for user after_sign_up
@@ -77,6 +82,8 @@
end
end
+ resources :person_platform_integrations
+
resources :person_blocks, path: :blocks, only: %i[index create destroy]
resources :reports, only: [:create]
diff --git a/config/seeds/better_together/wizards/host_setup_wizard.yml b/config/seeds/better_together/wizards/host_setup_wizard.yml
new file mode 100644
index 000000000..edc29971c
--- /dev/null
+++ b/config/seeds/better_together/wizards/host_setup_wizard.yml
@@ -0,0 +1,156 @@
+better_together:
+ version: "1.0"
+ seed:
+ type: "wizard"
+ identifier: "host_setup"
+ created_by: "Better Together Solutions"
+ created_at: "2025-03-04T12:00:00Z"
+ description: >
+ This is The Seed file for the Host Setup Wizard. It guides the creation
+ of a new community platform using the Community Engine.
+
+ origin:
+ platforms:
+ - name: "Community Engine"
+ version: "1.0"
+ url: "https://bebettertogether.ca"
+ contributors:
+ - name: "Robert Smith"
+ role: "Creator"
+ contact: "robert@bebettertogether.ca"
+ organization: "Better Together Solutions"
+ license: "LGPLv3"
+ usage_notes: >
+ Created as part of the foundational work on Better Together's platform onboarding process.
+ This seed may be reused, adapted, and redistributed with appropriate attribution under the terms of LGPLv3.
+
+ wizard:
+ name: "Host Setup Wizard"
+ identifier: "host_setup"
+ description: "Initial setup wizard for configuring the host platform."
+ max_completions: 1
+ success_message: >
+ Thank you! You have finished setting up your Better Together platform!
+ Your platform manager account has been created successfully. Please check your
+ email to confirm your address before signing in.
+ success_path: "/"
+
+ steps:
+ - identifier: "welcome"
+ name: "Language, Welcome, Land & Data Sovereignty"
+ description: >
+ Set your language, understand data sovereignty, and read the land acknowledgment.
+ form_class: "::BetterTogether::HostSetup::WelcomeForm"
+ step_number: 1
+ message: "Welcome! Let’s begin your journey."
+ fields:
+ - identifier: "locale"
+ type: "locale_select"
+ required: true
+ label: "Select Your Language"
+
+ - identifier: "community_identity"
+ name: "Community Identity"
+ description: "Name your community and describe its purpose."
+ form_class: "::BetterTogether::HostSetup::CommunityIdentityForm"
+ step_number: 2
+ message: "Let’s name your community and describe its purpose."
+ fields:
+ - identifier: "name"
+ type: "string"
+ required: true
+ label: "Community Name"
+ - identifier: "description"
+ type: "text"
+ required: true
+ label: "Short Description"
+ - identifier: "logo"
+ type: "file"
+ required: false
+ label: "Upload a Logo"
+
+ - identifier: "privacy_settings"
+ name: "Platform Access & Privacy"
+ description: "Choose the platform URL and privacy settings."
+ form_class: "::BetterTogether::HostSetup::PrivacySettingsForm"
+ step_number: 3
+ message: "Set your platform’s web address and decide who can visit."
+ fields:
+ - identifier: "url"
+ type: "string"
+ required: true
+ label: "Platform URL"
+ - identifier: "privacy"
+ type: "select"
+ required: true
+ label: "Privacy Level"
+ options: ["public", "private"]
+
+ - identifier: "admin_creation"
+ name: "Platform Host Account"
+ description: "Create the first administrator account."
+ form_class: "::BetterTogether::HostSetup::AdministratorForm"
+ step_number: 4
+ message: "Create your first platform administrator account."
+ fields:
+ - identifier: "admin_name"
+ type: "string"
+ required: true
+ label: "Administrator Name"
+ - identifier: "email"
+ type: "email"
+ required: true
+ label: "Administrator Email"
+ - identifier: "password"
+ type: "password"
+ required: true
+ label: "Password"
+ - identifier: "password_confirmation"
+ type: "password"
+ required: true
+ label: "Confirm Password"
+
+ - identifier: "time_zone"
+ name: "Time Zone"
+ description: "Set your platform’s time zone."
+ form_class: "::BetterTogether::HostSetup::TimeZoneForm"
+ step_number: 5
+ message: "Set your platform’s time zone for accurate scheduling."
+ fields:
+ - identifier: "time_zone"
+ type: "timezone_select"
+ required: true
+ label: "Select Your Time Zone"
+
+ - identifier: "purpose_and_features"
+ name: "Purpose & Features"
+ description: "Choose the initial purpose and features for your platform."
+ form_class: "::BetterTogether::HostSetup::PurposeAndFeaturesForm"
+ step_number: 6
+ message: "What will your platform be used for? Choose features to match your needs."
+ fields:
+ - identifier: "purpose"
+ type: "multi_select"
+ required: true
+ label: "Primary Purpose(s)"
+ options: ["storytelling", "organizing", "resource_sharing", "mutual_aid", "other"]
+
+ - identifier: "first_welcome_page"
+ name: "First Welcome Page"
+ description: "Draft your first welcome message for visitors."
+ form_class: "::BetterTogether::HostSetup::WelcomePageForm"
+ step_number: 7
+ message: "Write a welcoming message for your community’s front page."
+ fields:
+ - identifier: "welcome_message"
+ type: "rich_text"
+ required: true
+ label: "Welcome Message"
+
+ - identifier: "review_and_launch"
+ name: "Review & Launch"
+ description: "Review your choices and launch your platform."
+ form_class: "::BetterTogether::HostSetup::ReviewForm"
+ step_number: 8
+ message: "Review your choices and launch your platform when ready."
+ fields: []
diff --git a/config/seeds/seed_example.yml b/config/seeds/seed_example.yml
new file mode 100644
index 000000000..2afbcd9ab
--- /dev/null
+++ b/config/seeds/seed_example.yml
@@ -0,0 +1,30 @@
+better_together:
+ version: "1.0"
+ seed:
+ type: "wizard"
+ identifier: ""
+ created_by: ""
+ created_at: ""
+ description: ""
+
+ origin:
+ platforms: []
+ contributors: []
+ license: ""
+ usage_notes: ""
+
+ wizard:
+ name: ""
+ identifier: ""
+ description: ""
+ max_completions: 1
+ success_message: ""
+ success_path: ""
+
+ steps: []
+ translatable_attributes: [] # New list of attributes that expect translations (names, messages, etc.)
+
+ translations:
+ en: {}
+ fr: {}
+ es: {}
diff --git a/db/migrate/20190301040948_create_better_together_invitations.rb b/db/migrate/20190301040948_create_better_together_invitations.rb
index 2fd2a73c8..4a08bcd2e 100644
--- a/db/migrate/20190301040948_create_better_together_invitations.rb
+++ b/db/migrate/20190301040948_create_better_together_invitations.rb
@@ -4,7 +4,7 @@
class CreateBetterTogetherInvitations < ActiveRecord::Migration[7.0]
def change # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
create_bt_table :invitations do |t| # rubocop:todo Metrics/BlockLength
- t.string "type", default: "BetterTogether::Invitation", null: false
+ t.string 'type', default: 'BetterTogether::Invitation', null: false
t.string :status,
limit: 20,
null: false,
@@ -65,11 +65,11 @@ def change # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
add_index :better_together_invitations, %i[invitee_email invitable_id], unique: true,
# rubocop:todo Layout/LineLength
- name: "invitations_on_invitee_email_and_invitable_id"
+ name: 'invitations_on_invitee_email_and_invitable_id'
# rubocop:enable Layout/LineLength
add_index :better_together_invitations, %i[invitable_id status],
- name: "invitations_on_invitable_id_and_status"
+ name: 'invitations_on_invitable_id_and_status'
add_index :better_together_invitations, :invitee_email, where: "status = 'pending'",
- name: "pending_invites_on_invitee_email"
+ name: 'pending_invites_on_invitee_email'
end
end
diff --git a/db/migrate/20190425130144_create_better_together_posts.rb b/db/migrate/20190425130144_create_better_together_posts.rb
index 0fe0bd9db..aaac200a1 100644
--- a/db/migrate/20190425130144_create_better_together_posts.rb
+++ b/db/migrate/20190425130144_create_better_together_posts.rb
@@ -4,7 +4,7 @@
class CreateBetterTogetherPosts < ActiveRecord::Migration[7.0]
def change # rubocop:todo Metrics/MethodLength
create_bt_table :posts do |t|
- t.string "type", default: "BetterTogether::Post", null: false
+ t.string 'type', default: 'BetterTogether::Post', null: false
t.bt_identifier
t.bt_protected
t.bt_privacy
diff --git a/spec/dummy/db/migrate/20231125163430_create_active_storage_tables.active_storage.rb b/db/migrate/20231125163430_create_active_storage_tables.active_storage.rb
similarity index 100%
rename from spec/dummy/db/migrate/20231125163430_create_active_storage_tables.active_storage.rb
rename to db/migrate/20231125163430_create_active_storage_tables.active_storage.rb
diff --git a/spec/dummy/db/migrate/20231125164028_create_action_text_tables.action_text.rb b/db/migrate/20231125164028_create_action_text_tables.action_text.rb
similarity index 100%
rename from spec/dummy/db/migrate/20231125164028_create_action_text_tables.action_text.rb
rename to db/migrate/20231125164028_create_action_text_tables.action_text.rb
diff --git a/db/migrate/20240522200922_add_primary_community_to_people.rb b/db/migrate/20240522200922_add_primary_community_to_people.rb
index e7c3a2ec3..1975f407e 100644
--- a/db/migrate/20240522200922_add_primary_community_to_people.rb
+++ b/db/migrate/20240522200922_add_primary_community_to_people.rb
@@ -6,7 +6,7 @@ def change
unless column_exists?(:better_together_people, :community_id, :uuid)
# Custom community reference here to allow for null references for existing records
t.bt_references :community, target_table: :better_together_communities, null: true,
- index: { name: "by_person_community" }
+ index: { name: 'by_person_community' }
end
end
end
diff --git a/db/migrate/20240612113954_create_better_together_person_platform_integrations.rb b/db/migrate/20240612113954_create_better_together_person_platform_integrations.rb
new file mode 100644
index 000000000..c02615bbc
--- /dev/null
+++ b/db/migrate/20240612113954_create_better_together_person_platform_integrations.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+# This table is used to store the relationship between a person and an external platform
+class CreateBetterTogetherPersonPlatformIntegrations < ActiveRecord::Migration[7.1]
+ def change # rubocop:todo Metrics/MethodLength
+ create_bt_table :person_platform_integrations do |t|
+ t.string :provider, limit: 50, null: false, default: ''
+ t.string :uid, limit: 50, null: false, default: ''
+
+ t.string :name
+ t.string :handle
+ t.string :profile_url
+ t.string :image_url
+
+ t.string :access_token
+ t.string :access_token_secret
+ t.string :refresh_token
+ t.datetime :expires_at
+ t.jsonb :auth
+
+ t.bt_references :person, index: { name: 'bt_person_platform_conections_by_person' }
+ t.bt_references :platform, index: { name: 'bt_person_platform_conections_by_platform' }
+ t.bt_references :user, index: { name: 'bt_person_platform_conections_by_user' }
+ end
+ end
+end
diff --git a/db/migrate/20240826143510_create_better_together_platform_invitations.rb b/db/migrate/20240826143510_create_better_together_platform_invitations.rb
index 784e42fa2..af558a407 100644
--- a/db/migrate/20240826143510_create_better_together_platform_invitations.rb
+++ b/db/migrate/20240826143510_create_better_together_platform_invitations.rb
@@ -74,8 +74,8 @@ def change # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
add_index :better_together_platform_invitations, %i[invitee_email invitable_id], unique: true
add_index :better_together_platform_invitations, %i[invitable_id status],
- name: "index_platform_invitations_on_invitable_id_and_status"
+ name: 'index_platform_invitations_on_invitable_id_and_status'
add_index :better_together_platform_invitations, :invitee_email, where: "status = 'pending'",
- name: "index_pending_invitations_on_invitee_email"
+ name: 'index_pending_invitations_on_invitee_email'
end
end
diff --git a/db/migrate/20250227163308_create_better_together_metrics_page_view_reports.rb b/db/migrate/20250227163308_create_better_together_metrics_page_view_reports.rb
index aed76379d..d0be23d24 100644
--- a/db/migrate/20250227163308_create_better_together_metrics_page_view_reports.rb
+++ b/db/migrate/20250227163308_create_better_together_metrics_page_view_reports.rb
@@ -6,7 +6,7 @@ def change
create_bt_table :page_view_reports, prefix: :better_together_metrics do |t|
t.jsonb :filters, null: false, default: {}
t.boolean :sort_by_total_views, null: false, default: false
- t.string :file_format, null: false, default: "csv"
+ t.string :file_format, null: false, default: 'csv'
t.jsonb :report_data, null: false, default: {}
end
diff --git a/db/migrate/20250228154526_create_better_together_metrics_link_click_reports.rb b/db/migrate/20250228154526_create_better_together_metrics_link_click_reports.rb
index 841dc4f94..ef2876ed8 100644
--- a/db/migrate/20250228154526_create_better_together_metrics_link_click_reports.rb
+++ b/db/migrate/20250228154526_create_better_together_metrics_link_click_reports.rb
@@ -6,7 +6,7 @@ def change
create_bt_table :link_click_reports, prefix: :better_together_metrics do |t|
t.jsonb :filters, null: false, default: {}
t.boolean :sort_by_total_clicks, null: false, default: false
- t.string :file_format, null: false, default: "csv"
+ t.string :file_format, null: false, default: 'csv'
t.jsonb :report_data, null: false, default: {}
end
diff --git a/db/migrate/20250304142407_set_privacy_default_private.rb b/db/migrate/20250304142407_set_privacy_default_private.rb
new file mode 100644
index 000000000..68085891f
--- /dev/null
+++ b/db/migrate/20250304142407_set_privacy_default_private.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+# Ensures that all tables with the privacy column default to private
+# Replaces existing 'unlisted' values with 'private'
+class SetPrivacyDefaultPrivate < ActiveRecord::Migration[7.1]
+ def up
+ ActiveRecord::Base.connection.tables.each do |table|
+ next unless column_exists?(table, :privacy)
+
+ # Replace existing 'unlisted' values with 'private'
+ execute "UPDATE #{table} SET privacy = 'private' WHERE privacy = 'unlisted'"
+
+ privacy_column = ActiveRecord::Base.connection.columns(table).find { |col| col.name == 'privacy' }
+ next unless privacy_column
+ next if privacy_column.default == 'private'
+
+ say "Changing default privacy for table #{table} from #{privacy_column.default.inspect} to 'private'"
+ change_column_default table, :privacy, 'private'
+ end
+ end
+
+ def down
+ # No reversal defined as reverting the default value change and data update is not supported.
+ end
+end
diff --git a/db/migrate/20250304173431_create_better_together_seeds.rb b/db/migrate/20250304173431_create_better_together_seeds.rb
new file mode 100644
index 000000000..bb89399f9
--- /dev/null
+++ b/db/migrate/20250304173431_create_better_together_seeds.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+# Creates table to track and store Better Together Seed records
+class CreateBetterTogetherSeeds < ActiveRecord::Migration[7.1]
+ def change # rubocop:todo Metrics/MethodLength
+ create_bt_table :seeds, id: :uuid do |t|
+ t.string :type, null: false, default: 'BetterTogether::Seed'
+
+ t.bt_references :seedable, polymorphic: true, null: true, index: 'by_seed_seedable'
+
+ t.bt_creator
+ t.bt_identifier
+ t.bt_privacy
+
+ t.string :version, null: false
+ t.string :created_by, null: false
+ t.datetime :seeded_at, null: false
+ t.text :description, null: false
+
+ t.jsonb :origin, null: false # Full origin block (platforms, contributors, license, usage_notes)
+ t.jsonb :payload, null: false # Full wizard/page_template/content_block data
+ end
+
+ add_index :better_together_seeds, %i[type identifier], unique: true
+ # JSONB indexes - GIN index for fast key lookups inside origin and payload
+ add_index :better_together_seeds, :origin, using: :gin
+ add_index :better_together_seeds, :payload, using: :gin
+ end
+end
diff --git a/lib/better_together/engine.rb b/lib/better_together/engine.rb
index 0344ade23..cfa327dca 100644
--- a/lib/better_together/engine.rb
+++ b/lib/better_together/engine.rb
@@ -24,6 +24,8 @@
require 'importmap-rails'
require 'kaminari'
require 'noticed'
+require 'omniauth/rails_csrf_protection'
+require 'omniauth-github'
require 'premailer/rails'
require 'rack/attack'
require 'reform/rails'
@@ -137,7 +139,7 @@ class Engine < ::Rails::Engine
# Exclude postgis tables from database dumper
initializer 'better_together.spatial_tables' do
- ::ActiveRecord::SchemaDumper.ignore_tables = %w[spatial_ref_sys] + ::ActiveRecord::SchemaDumper.ignore_tables
+ ::ActiveRecord::SchemaDumper.ignore_tables = ::ActiveRecord::SchemaDumper.ignore_tables + %w[spatial_ref_sys]
end
initializer 'better_together.turbo' do |app|
diff --git a/spec/concerns/better_together/seedable_spec.rb b/spec/concerns/better_together/seedable_spec.rb
new file mode 100644
index 000000000..2a0b3652b
--- /dev/null
+++ b/spec/concerns/better_together/seedable_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+module BetterTogether
+ describe Seedable, type: :model do
+ # Define a test ActiveRecord model inline for this spec
+ # rubocop:todo RSpec/LeakyConstantDeclaration
+ class TestSeedableClass < ApplicationRecord # rubocop:todo Lint/ConstantDefinitionInBlock
+ include Seedable
+ end
+ # rubocop:enable RSpec/LeakyConstantDeclaration
+
+ before(:all) do # rubocop:todo RSpec/BeforeAfterAll
+ create_table(:better_together_test_seedable_classes) do |t|
+ t.string :name
+ end
+ end
+
+ after(:all) do # rubocop:todo RSpec/BeforeAfterAll
+ drop_table(:better_together_test_seedable_classes)
+ end
+
+ describe TestSeedableClass, type: :model do
+ FactoryBot.define do
+ factory 'better_together/test_seedable_class', class: '::BetterTogether::TestSeedableClass' do
+ sequence(:name) { |n| "Test seedable #{n}" }
+ end
+ end
+ it_behaves_like 'a seedable model'
+ end
+ end
+end
diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb
index 1d04cb2cb..421b3ec7f 100644
--- a/spec/dummy/config/application.rb
+++ b/spec/dummy/config/application.rb
@@ -24,9 +24,6 @@ class Application < Rails::Application
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
- # Use the latest cache format and remove deprecated Active Storage setting
- config.active_support.cache_format_version = 7.1
-
config.generators do |g|
g.orm :active_record, primary_key_type: :uuid
g.fixture_replacement :factory_bot, dir: 'spec/factories'
diff --git a/spec/dummy/config/i18n-tasks.yml b/spec/dummy/config/i18n-tasks.yml
index 75d4669b8..741024e7b 100644
--- a/spec/dummy/config/i18n-tasks.yml
+++ b/spec/dummy/config/i18n-tasks.yml
@@ -1,6 +1,6 @@
# config/i18n-tasks.yml
base_locale: en
-locales:
+locales:
- en
- es
- fr
diff --git a/spec/dummy/config/initializers/assets.rb b/spec/dummy/config/initializers/assets.rb
index bcafccdd3..019d0bbb4 100644
--- a/spec/dummy/config/initializers/assets.rb
+++ b/spec/dummy/config/initializers/assets.rb
@@ -7,8 +7,3 @@
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
-
-# Precompile additional assets.
-# application.js, application.css, and all non-JS/CSS in the app/assets
-# folder are already added.
-# Rails.application.config.assets.precompile += %w( admin.js admin.css )
diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb
index afb01a2b9..57300570e 100644
--- a/spec/dummy/db/schema.rb
+++ b/spec/dummy/db/schema.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
@@ -10,1396 +12,1532 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.1].define(version: 2025_08_22_143049) do
+ActiveRecord::Schema[7.1].define(version: 20_250_822_143_049) do
# These are extensions that must be enabled in order to support this database
- enable_extension "pgcrypto"
- enable_extension "plpgsql"
- enable_extension "postgis"
-
- create_table "action_text_rich_texts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.string "name", null: false
- t.text "body"
- t.string "record_type", null: false
- t.uuid "record_id", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale"
- t.index ["record_type", "record_id", "name", "locale"], name: "index_action_text_rich_texts_uniqueness", unique: true
- end
-
- create_table "active_storage_attachments", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.string "name", null: false
- t.string "record_type", null: false
- t.uuid "record_id", null: false
- t.uuid "blob_id", null: false
- t.datetime "created_at", null: false
- t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
- t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
- end
-
- create_table "active_storage_blobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.string "key", null: false
- t.string "filename", null: false
- t.string "content_type"
- t.text "metadata"
- t.string "service_name", null: false
- t.bigint "byte_size", null: false
- t.string "checksum"
- t.datetime "created_at", null: false
- t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
- end
-
- create_table "active_storage_variant_records", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.uuid "blob_id", null: false
- t.string "variation_digest", null: false
- t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
- end
-
- create_table "better_together_activities", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "trackable_type"
- t.uuid "trackable_id"
- t.string "owner_type"
- t.uuid "owner_id"
- t.string "key"
- t.jsonb "parameters", default: "{}"
- t.string "recipient_type"
- t.uuid "recipient_id"
- t.string "privacy", limit: 50, default: "private", null: false
- t.index ["owner_type", "owner_id"], name: "bt_activities_by_owner"
- t.index ["privacy"], name: "by_better_together_activities_privacy"
- t.index ["recipient_type", "recipient_id"], name: "bt_activities_by_recipient"
- t.index ["trackable_type", "trackable_id"], name: "bt_activities_by_trackable"
- end
-
- create_table "better_together_addresses", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "label", default: "main", null: false
- t.boolean "physical", default: true, null: false
- t.boolean "postal", default: false, null: false
- t.string "line1"
- t.string "line2"
- t.string "city_name"
- t.string "state_province_name"
- t.string "postal_code"
- t.string "country_name"
- t.string "privacy", limit: 50, default: "private", null: false
- t.uuid "contact_detail_id"
- t.boolean "primary_flag", default: false, null: false
- t.index ["contact_detail_id", "primary_flag"], name: "index_bt_addresses_on_contact_detail_id_and_primary", unique: true, where: "(primary_flag IS TRUE)"
- t.index ["contact_detail_id"], name: "index_better_together_addresses_on_contact_detail_id"
- t.index ["privacy"], name: "by_better_together_addresses_privacy"
- end
-
- create_table "better_together_agreement_participants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "agreement_id", null: false
- t.uuid "person_id", null: false
- t.string "group_identifier"
- t.datetime "accepted_at"
- t.index ["agreement_id", "person_id"], name: "index_bt_agreement_participants_on_agreement_and_person", unique: true
- t.index ["agreement_id"], name: "index_better_together_agreement_participants_on_agreement_id"
- t.index ["group_identifier"], name: "idx_on_group_identifier_06b6e57c0b"
- t.index ["person_id"], name: "index_better_together_agreement_participants_on_person_id"
- end
-
- create_table "better_together_agreement_terms", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.integer "position", null: false
- t.boolean "protected", default: false, null: false
- t.uuid "agreement_id", null: false
- t.index ["agreement_id"], name: "index_better_together_agreement_terms_on_agreement_id"
- t.index ["identifier"], name: "index_better_together_agreement_terms_on_identifier", unique: true
- end
-
- create_table "better_together_agreements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.boolean "collective", default: false, null: false
- t.uuid "page_id"
- t.index ["creator_id"], name: "by_better_together_agreements_creator"
- t.index ["identifier"], name: "index_better_together_agreements_on_identifier", unique: true
- t.index ["page_id"], name: "index_better_together_agreements_on_page_id"
- t.index ["privacy"], name: "by_better_together_agreements_privacy"
- end
-
- create_table "better_together_ai_log_translations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.text "request", null: false
- t.text "response"
- t.string "model", null: false
- t.integer "prompt_tokens", default: 0, null: false
- t.integer "completion_tokens", default: 0, null: false
- t.integer "tokens_used", default: 0, null: false
- t.decimal "estimated_cost", precision: 10, scale: 5, default: "0.0", null: false
- t.datetime "start_time"
- t.datetime "end_time"
- t.string "status", default: "pending", null: false
- t.uuid "initiator_id"
- t.string "source_locale", null: false
- t.string "target_locale", null: false
- t.index ["initiator_id"], name: "index_better_together_ai_log_translations_on_initiator_id"
- t.index ["model"], name: "index_better_together_ai_log_translations_on_model"
- t.index ["source_locale"], name: "index_better_together_ai_log_translations_on_source_locale"
- t.index ["status"], name: "index_better_together_ai_log_translations_on_status"
- t.index ["target_locale"], name: "index_better_together_ai_log_translations_on_target_locale"
- end
-
- create_table "better_together_authorships", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "position", null: false
- t.string "authorable_type", null: false
- t.uuid "authorable_id", null: false
- t.uuid "author_id", null: false
- t.uuid "creator_id"
- t.index ["author_id"], name: "by_authorship_author"
- t.index ["authorable_type", "authorable_id"], name: "by_authorship_authorable"
- t.index ["creator_id"], name: "by_better_together_authorships_creator"
- end
-
- create_table "better_together_calendar_entries", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "calendar_id"
- t.string "schedulable_type"
- t.uuid "schedulable_id"
- t.datetime "starts_at", null: false
- t.datetime "ends_at"
- t.decimal "duration_minutes"
- t.uuid "event_id", null: false
- t.index ["calendar_id", "event_id"], name: "by_calendar_and_event", unique: true
- t.index ["calendar_id"], name: "index_better_together_calendar_entries_on_calendar_id"
- t.index ["ends_at"], name: "bt_calendar_events_by_ends_at"
- t.index ["event_id"], name: "bt_calendar_entries_by_event"
- t.index ["schedulable_type", "schedulable_id"], name: "index_better_together_calendar_entries_on_schedulable"
- t.index ["starts_at"], name: "bt_calendar_events_by_starts_at"
- end
-
- create_table "better_together_calendars", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "community_id", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.boolean "protected", default: false, null: false
- t.index ["community_id"], name: "by_better_together_calendars_community"
- t.index ["creator_id"], name: "by_better_together_calendars_creator"
- t.index ["identifier"], name: "index_better_together_calendars_on_identifier", unique: true
- t.index ["locale"], name: "by_better_together_calendars_locale"
- t.index ["privacy"], name: "by_better_together_calendars_privacy"
- end
-
- create_table "better_together_calls_for_interest", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "type", default: "BetterTogether::CallForInterest", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.string "interestable_type"
- t.uuid "interestable_id"
- t.datetime "starts_at"
- t.datetime "ends_at"
- t.index ["creator_id"], name: "by_better_together_calls_for_interest_creator"
- t.index ["ends_at"], name: "bt_calls_for_interest_by_ends_at"
- t.index ["identifier"], name: "index_better_together_calls_for_interest_on_identifier", unique: true
- t.index ["interestable_type", "interestable_id"], name: "index_better_together_calls_for_interest_on_interestable"
- t.index ["privacy"], name: "by_better_together_calls_for_interest_privacy"
- t.index ["starts_at"], name: "bt_calls_for_interest_by_starts_at"
- end
-
- create_table "better_together_categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.integer "position", null: false
- t.boolean "protected", default: false, null: false
- t.string "type", default: "BetterTogether::Category", null: false
- t.string "icon", default: "fas fa-icons", null: false
- t.index ["identifier", "type"], name: "index_better_together_categories_on_identifier_and_type", unique: true
- end
-
- create_table "better_together_categorizations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "category_type", null: false
- t.uuid "category_id", null: false
- t.string "categorizable_type", null: false
- t.uuid "categorizable_id", null: false
- t.index ["categorizable_type", "categorizable_id"], name: "index_better_together_categorizations_on_categorizable"
- t.index ["category_type", "category_id"], name: "index_better_together_categorizations_on_category"
- end
-
- create_table "better_together_comments", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "commentable_type", null: false
- t.uuid "commentable_id", null: false
- t.uuid "creator_id"
- t.text "content", default: "", null: false
- t.index ["commentable_type", "commentable_id"], name: "bt_comments_on_commentable"
- t.index ["creator_id"], name: "by_better_together_comments_creator"
- end
-
- create_table "better_together_communities", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "host", default: false, null: false
- t.boolean "protected", default: false, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.uuid "creator_id"
- t.string "type", default: "BetterTogether::Community", null: false
- t.index ["creator_id"], name: "by_creator"
- t.index ["host"], name: "index_better_together_communities_on_host", unique: true, where: "(host IS TRUE)"
- t.index ["identifier"], name: "index_better_together_communities_on_identifier", unique: true
- t.index ["privacy"], name: "by_community_privacy"
- end
-
- create_table "better_together_contact_details", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "contactable_type", null: false
- t.uuid "contactable_id", null: false
- t.string "type", default: "BetterTogether::ContactDetail", null: false
- t.string "name"
- t.string "role"
- t.index ["contactable_type", "contactable_id"], name: "index_better_together_contact_details_on_contactable"
- end
-
- create_table "better_together_content_blocks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "type", null: false
- t.string "identifier", limit: 100
- t.jsonb "accessibility_attributes", default: {}, null: false
- t.jsonb "content_settings", default: {}, null: false
- t.jsonb "css_settings", default: {}, null: false
- t.jsonb "data_attributes", default: {}, null: false
- t.jsonb "html_attributes", default: {}, null: false
- t.jsonb "layout_settings", default: {}, null: false
- t.jsonb "media_settings", default: {}, null: false
- t.jsonb "content_data", default: {}
- t.uuid "creator_id"
- t.string "privacy", limit: 50, default: "private", null: false
- t.boolean "visible", default: true, null: false
- t.jsonb "content_area_settings", default: {}, null: false
- t.index ["creator_id"], name: "by_better_together_content_blocks_creator"
- t.index ["privacy"], name: "by_better_together_content_blocks_privacy"
- end
-
- create_table "better_together_content_page_blocks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "page_id", null: false
- t.uuid "block_id", null: false
- t.integer "position", null: false
- t.index ["block_id"], name: "index_better_together_content_page_blocks_on_block_id"
- t.index ["page_id", "block_id", "position"], name: "content_page_blocks_on_page_block_and_position"
- t.index ["page_id", "block_id"], name: "content_page_blocks_on_page_and_block", unique: true
- t.index ["page_id"], name: "index_better_together_content_page_blocks_on_page_id"
- end
-
- create_table "better_together_content_platform_blocks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "platform_id", null: false
- t.uuid "block_id", null: false
- t.index ["block_id"], name: "index_better_together_content_platform_blocks_on_block_id"
- t.index ["platform_id"], name: "index_better_together_content_platform_blocks_on_platform_id"
- end
-
- create_table "better_together_conversation_participants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "conversation_id", null: false
- t.uuid "person_id", null: false
- t.index ["conversation_id"], name: "idx_on_conversation_id_30b3b70bad"
- t.index ["person_id"], name: "index_better_together_conversation_participants_on_person_id"
- end
-
- create_table "better_together_conversations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "title", null: false
- t.uuid "creator_id", null: false
- t.index ["creator_id"], name: "index_better_together_conversations_on_creator_id"
- end
-
- create_table "better_together_email_addresses", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "email", null: false
- t.string "label", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.uuid "contact_detail_id", null: false
- t.boolean "primary_flag", default: false, null: false
- t.index ["contact_detail_id", "primary_flag"], name: "index_bt_email_addresses_on_contact_detail_id_and_primary", unique: true, where: "(primary_flag IS TRUE)"
- t.index ["contact_detail_id"], name: "index_better_together_email_addresses_on_contact_detail_id"
- t.index ["privacy"], name: "by_better_together_email_addresses_privacy"
- end
-
- create_table "better_together_event_attendances", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "event_id", null: false
- t.uuid "person_id", null: false
- t.string "status", default: "interested", null: false
- t.index ["event_id", "person_id"], name: "by_event_and_person", unique: true
- t.index ["event_id"], name: "bt_event_attendance_by_event"
- t.index ["person_id"], name: "bt_event_attendance_by_person"
- end
-
- create_table "better_together_event_hosts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "event_id"
- t.string "host_type"
- t.uuid "host_id"
- t.index ["event_id"], name: "index_better_together_event_hosts_on_event_id"
- t.index ["host_type", "host_id"], name: "index_better_together_event_hosts_on_host"
- end
-
- create_table "better_together_events", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "type", default: "BetterTogether::Event", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.datetime "starts_at"
- t.datetime "ends_at"
- t.decimal "duration_minutes"
- t.string "registration_url"
- t.index ["creator_id"], name: "by_better_together_events_creator"
- t.index ["ends_at"], name: "bt_events_by_ends_at"
- t.index ["identifier"], name: "index_better_together_events_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_events_privacy"
- t.index ["starts_at"], name: "bt_events_by_starts_at"
- end
-
- create_table "better_together_geography_continents", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "community_id", null: false
- t.index ["community_id"], name: "by_geography_continent_community"
- t.index ["identifier"], name: "index_better_together_geography_continents_on_identifier", unique: true
- end
-
- create_table "better_together_geography_countries", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.string "iso_code", limit: 2, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "community_id", null: false
- t.index ["community_id"], name: "by_geography_country_community"
- t.index ["identifier"], name: "index_better_together_geography_countries_on_identifier", unique: true
- t.index ["iso_code"], name: "index_better_together_geography_countries_on_iso_code", unique: true
- end
-
- create_table "better_together_geography_country_continents", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "country_id"
- t.uuid "continent_id"
- t.index ["continent_id"], name: "country_continent_by_continent"
- t.index ["country_id", "continent_id"], name: "index_country_continents_on_country_and_continent", unique: true
- t.index ["country_id"], name: "country_continent_by_country"
- end
-
- create_table "better_together_geography_geospatial_spaces", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "geospatial_type"
- t.uuid "geospatial_id"
- t.integer "position", null: false
- t.boolean "primary_flag", default: false, null: false
- t.uuid "space_id"
- t.index ["geospatial_id", "primary_flag"], name: "index_geospatial_spaces_on_geospatial_id_and_primary", unique: true, where: "(primary_flag IS TRUE)"
- t.index ["geospatial_type", "geospatial_id"], name: "index_better_together_geography_geospatial_spaces_on_geospatial"
- t.index ["space_id"], name: "index_better_together_geography_geospatial_spaces_on_space_id"
- end
-
- create_table "better_together_geography_locatable_locations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "location_type"
- t.uuid "location_id"
- t.string "locatable_type", null: false
- t.uuid "locatable_id", null: false
- t.string "name"
- t.index ["creator_id"], name: "by_better_together_geography_locatable_locations_creator"
- t.index ["locatable_id", "locatable_type", "location_id", "location_type"], name: "locatable_locations"
- t.index ["locatable_type", "locatable_id"], name: "locatable_location_by_locatable"
- t.index ["location_type", "location_id"], name: "locatable_location_by_location"
- t.index ["name"], name: "locatable_location_by_name"
- end
-
- create_table "better_together_geography_maps", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.boolean "protected", default: false, null: false
- t.geography "center", limit: {srid: 4326, type: "st_point", geographic: true}
- t.integer "zoom", default: 13, null: false
- t.geography "viewport", limit: {srid: 4326, type: "st_polygon", geographic: true}
- t.jsonb "metadata", default: {}, null: false
- t.string "mappable_type"
- t.uuid "mappable_id"
- t.string "type", default: "BetterTogether::Geography::Map", null: false
- t.index ["creator_id"], name: "by_better_together_geography_maps_creator"
- t.index ["identifier"], name: "index_better_together_geography_maps_on_identifier", unique: true
- t.index ["locale"], name: "by_better_together_geography_maps_locale"
- t.index ["mappable_type", "mappable_id"], name: "index_better_together_geography_maps_on_mappable"
- t.index ["privacy"], name: "by_better_together_geography_maps_privacy"
- end
-
- create_table "better_together_geography_region_settlements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.boolean "protected", default: false, null: false
- t.uuid "region_id"
- t.uuid "settlement_id"
- t.index ["region_id"], name: "bt_region_settlement_by_region"
- t.index ["settlement_id"], name: "bt_region_settlement_by_settlement"
- end
-
- create_table "better_together_geography_regions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "community_id", null: false
- t.uuid "country_id"
- t.uuid "state_id"
- t.string "type", default: "BetterTogether::Geography::Region", null: false
- t.index ["community_id"], name: "by_geography_region_community"
- t.index ["country_id"], name: "index_better_together_geography_regions_on_country_id"
- t.index ["identifier"], name: "index_better_together_geography_regions_on_identifier", unique: true
- t.index ["state_id"], name: "index_better_together_geography_regions_on_state_id"
- end
-
- create_table "better_together_geography_settlements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "community_id", null: false
- t.uuid "country_id"
- t.uuid "state_id"
- t.index ["community_id"], name: "by_geography_settlement_community"
- t.index ["country_id"], name: "index_better_together_geography_settlements_on_country_id"
- t.index ["identifier"], name: "index_better_together_geography_settlements_on_identifier", unique: true
- t.index ["state_id"], name: "index_better_together_geography_settlements_on_state_id"
- end
-
- create_table "better_together_geography_spaces", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.float "elevation"
- t.float "latitude"
- t.float "longitude"
- t.jsonb "properties", default: {}
- t.jsonb "metadata", default: {}
- t.index ["creator_id"], name: "by_better_together_geography_spaces_creator"
- t.index ["identifier"], name: "index_better_together_geography_spaces_on_identifier", unique: true
- end
-
- create_table "better_together_geography_states", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.string "iso_code", limit: 5, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "community_id", null: false
- t.uuid "country_id"
- t.index ["community_id"], name: "by_geography_state_community"
- t.index ["country_id"], name: "index_better_together_geography_states_on_country_id"
- t.index ["identifier"], name: "index_better_together_geography_states_on_identifier", unique: true
- t.index ["iso_code"], name: "index_better_together_geography_states_on_iso_code", unique: true
- end
-
- create_table "better_together_identifications", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.boolean "active", null: false
- t.string "identity_type", null: false
- t.uuid "identity_id", null: false
- t.string "agent_type", null: false
- t.uuid "agent_id", null: false
- t.index ["active", "agent_type", "agent_id"], name: "active_identification", unique: true
- t.index ["active"], name: "by_active_state"
- t.index ["agent_type", "agent_id"], name: "by_agent"
- t.index ["identity_type", "identity_id", "agent_type", "agent_id"], name: "unique_identification", unique: true
- t.index ["identity_type", "identity_id"], name: "by_identity"
- end
-
- create_table "better_together_infrastructure_building_connections", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "building_id", null: false
- t.string "connection_type", null: false
- t.uuid "connection_id", null: false
- t.integer "position", null: false
- t.boolean "primary_flag", default: false, null: false
- t.index ["building_id"], name: "bt_building_connections_building"
- t.index ["connection_id", "primary_flag"], name: "index_bt_building_connections_on_connection_id_and_primary", unique: true, where: "(primary_flag IS TRUE)"
- t.index ["connection_type", "connection_id"], name: "bt_building_connections_connection"
- end
-
- create_table "better_together_infrastructure_buildings", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "type", default: "BetterTogether::Infrastructure::Building", null: false
- t.uuid "community_id", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.integer "floors_count", default: 0, null: false
- t.integer "rooms_count", default: 0, null: false
- t.uuid "address_id"
- t.index ["address_id"], name: "index_better_together_infrastructure_buildings_on_address_id"
- t.index ["community_id"], name: "by_better_together_infrastructure_buildings_community"
- t.index ["creator_id"], name: "by_better_together_infrastructure_buildings_creator"
- t.index ["identifier"], name: "index_better_together_infrastructure_buildings_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_infrastructure_buildings_privacy"
- end
-
- create_table "better_together_infrastructure_floors", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "building_id"
- t.uuid "community_id", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.integer "position", null: false
- t.integer "level", default: 0, null: false
- t.integer "rooms_count", default: 0, null: false
- t.index ["building_id"], name: "index_better_together_infrastructure_floors_on_building_id"
- t.index ["community_id"], name: "by_better_together_infrastructure_floors_community"
- t.index ["creator_id"], name: "by_better_together_infrastructure_floors_creator"
- t.index ["identifier"], name: "index_better_together_infrastructure_floors_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_infrastructure_floors_privacy"
- end
-
- create_table "better_together_infrastructure_rooms", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "floor_id"
- t.uuid "community_id", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.index ["community_id"], name: "by_better_together_infrastructure_rooms_community"
- t.index ["creator_id"], name: "by_better_together_infrastructure_rooms_creator"
- t.index ["floor_id"], name: "index_better_together_infrastructure_rooms_on_floor_id"
- t.index ["identifier"], name: "index_better_together_infrastructure_rooms_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_infrastructure_rooms_privacy"
- end
-
- create_table "better_together_invitations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "type", default: "BetterTogether::Invitation", null: false
- t.string "status", limit: 20, null: false
- t.datetime "valid_from", null: false
- t.datetime "valid_until"
- t.datetime "last_sent"
- t.datetime "accepted_at"
- t.string "locale", limit: 5, default: "en", null: false
- t.string "token", limit: 24, null: false
- t.string "invitable_type", null: false
- t.uuid "invitable_id", null: false
- t.string "inviter_type", null: false
- t.uuid "inviter_id", null: false
- t.string "invitee_type", null: false
- t.uuid "invitee_id", null: false
- t.string "invitee_email", null: false
- t.uuid "role_id"
- t.index ["invitable_id", "status"], name: "invitations_on_invitable_id_and_status"
- t.index ["invitable_type", "invitable_id"], name: "by_invitable"
- t.index ["invitee_email", "invitable_id"], name: "invitations_on_invitee_email_and_invitable_id", unique: true
- t.index ["invitee_email"], name: "invitations_by_invitee_email"
- t.index ["invitee_email"], name: "pending_invites_on_invitee_email", where: "((status)::text = 'pending'::text)"
- t.index ["invitee_type", "invitee_id"], name: "by_invitee"
- t.index ["inviter_type", "inviter_id"], name: "by_inviter"
- t.index ["locale"], name: "by_better_together_invitations_locale"
- t.index ["role_id"], name: "by_role"
- t.index ["status"], name: "by_status"
- t.index ["token"], name: "invitations_by_token", unique: true
- t.index ["valid_from"], name: "by_valid_from"
- t.index ["valid_until"], name: "by_valid_until"
- end
-
- create_table "better_together_joatu_agreements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "offer_id", null: false
- t.uuid "request_id", null: false
- t.text "terms"
- t.string "value"
- t.string "status", default: "pending", null: false
- t.index ["offer_id", "request_id"], name: "bt_joatu_agreements_unique_offer_request", unique: true
- t.index ["offer_id"], name: "bt_joatu_agreements_by_offer"
- t.index ["offer_id"], name: "bt_joatu_agreements_one_accepted_per_offer", unique: true, where: "((status)::text = 'accepted'::text)"
- t.index ["request_id"], name: "bt_joatu_agreements_by_request"
- t.index ["request_id"], name: "bt_joatu_agreements_one_accepted_per_request", unique: true, where: "((status)::text = 'accepted'::text)"
- end
-
- create_table "better_together_joatu_offers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "status", default: "open", null: false
- t.string "target_type"
- t.uuid "target_id"
- t.string "urgency", default: "normal", null: false
- t.uuid "address_id"
- t.index ["address_id"], name: "index_better_together_joatu_offers_on_address_id"
- t.index ["creator_id"], name: "by_better_together_joatu_offers_creator"
- t.index ["target_type", "target_id"], name: "bt_joatu_offers_on_target"
- end
-
- create_table "better_together_joatu_requests", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "status", default: "open", null: false
- t.string "target_type"
- t.uuid "target_id"
- t.string "urgency", default: "normal", null: false
- t.uuid "address_id"
- t.index ["address_id"], name: "index_better_together_joatu_requests_on_address_id"
- t.index ["creator_id"], name: "by_better_together_joatu_requests_creator"
- t.index ["target_type", "target_id"], name: "bt_joatu_requests_on_target"
- end
-
- create_table "better_together_joatu_response_links", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "source_type", null: false
- t.uuid "source_id", null: false
- t.string "response_type", null: false
- t.uuid "response_id", null: false
- t.uuid "creator_id"
- t.index ["creator_id"], name: "by_better_together_joatu_response_links_creator"
- t.index ["response_type", "response_id"], name: "bt_joatu_response_links_by_response"
- t.index ["source_type", "source_id", "response_type", "response_id"], name: "bt_joatu_response_links_unique_pair", unique: true
- t.index ["source_type", "source_id"], name: "bt_joatu_response_links_by_source"
- end
-
- create_table "better_together_jwt_denylists", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "jti"
- t.datetime "exp"
- t.index ["jti"], name: "index_better_together_jwt_denylists_on_jti"
- end
-
- create_table "better_together_messages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.text "content"
- t.uuid "sender_id", null: false
- t.uuid "conversation_id", null: false
- t.index ["conversation_id"], name: "index_better_together_messages_on_conversation_id"
- t.index ["sender_id"], name: "index_better_together_messages_on_sender_id"
- end
-
- create_table "better_together_metrics_downloads", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "downloadable_type"
- t.uuid "downloadable_id"
- t.string "file_name", null: false
- t.string "file_type", null: false
- t.bigint "file_size", null: false
- t.datetime "downloaded_at", null: false
- t.index ["downloadable_type", "downloadable_id"], name: "index_better_together_metrics_downloads_on_downloadable"
- t.index ["locale"], name: "by_better_together_metrics_downloads_locale"
- end
-
- create_table "better_together_metrics_link_click_reports", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.jsonb "filters", default: {}, null: false
- t.boolean "sort_by_total_clicks", default: false, null: false
- t.string "file_format", default: "csv", null: false
- t.jsonb "report_data", default: {}, null: false
- t.index ["filters"], name: "index_better_together_metrics_link_click_reports_on_filters", using: :gin
- end
-
- create_table "better_together_metrics_link_clicks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "url", null: false
- t.string "page_url", null: false
- t.string "locale", null: false
- t.boolean "internal", default: true
- t.datetime "clicked_at", null: false
- end
-
- create_table "better_together_metrics_page_view_reports", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.jsonb "filters", default: {}, null: false
- t.boolean "sort_by_total_views", default: false, null: false
- t.string "file_format", default: "csv", null: false
- t.jsonb "report_data", default: {}, null: false
- t.index ["filters"], name: "index_better_together_metrics_page_view_reports_on_filters", using: :gin
- end
-
- create_table "better_together_metrics_page_views", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "pageable_type"
- t.uuid "pageable_id"
- t.datetime "viewed_at", null: false
- t.string "page_url"
- t.index ["locale"], name: "by_better_together_metrics_page_views_locale"
- t.index ["pageable_type", "pageable_id"], name: "index_better_together_metrics_page_views_on_pageable"
- end
-
- create_table "better_together_metrics_search_queries", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "query", null: false
- t.integer "results_count", null: false
- t.datetime "searched_at", null: false
- t.index ["locale"], name: "by_better_together_metrics_search_queries_locale"
- end
-
- create_table "better_together_metrics_shares", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "platform", null: false
- t.string "url", null: false
- t.datetime "shared_at", null: false
- t.string "shareable_type"
- t.uuid "shareable_id"
- t.index ["locale"], name: "by_better_together_metrics_shares_locale"
- t.index ["platform", "url"], name: "index_better_together_metrics_shares_on_platform_and_url"
- t.index ["shareable_type", "shareable_id"], name: "index_better_together_metrics_shares_on_shareable"
- end
-
- create_table "better_together_navigation_areas", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.boolean "visible", default: true, null: false
- t.string "name"
- t.string "style"
- t.string "navigable_type"
- t.bigint "navigable_id"
- t.index ["identifier"], name: "index_better_together_navigation_areas_on_identifier", unique: true
- t.index ["navigable_type", "navigable_id"], name: "by_navigable"
- end
-
- create_table "better_together_navigation_items", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.integer "position", null: false
- t.boolean "protected", default: false, null: false
- t.boolean "visible", default: true, null: false
- t.uuid "navigation_area_id", null: false
- t.uuid "parent_id"
- t.string "url"
- t.string "icon"
- t.string "item_type", null: false
- t.string "linkable_type"
- t.uuid "linkable_id"
- t.string "route_name"
- t.integer "children_count", default: 0, null: false
- t.index ["identifier"], name: "index_better_together_navigation_items_on_identifier", unique: true
- t.index ["linkable_type", "linkable_id"], name: "by_linkable"
- t.index ["navigation_area_id", "parent_id", "position"], name: "navigation_items_area_position", unique: true
- t.index ["navigation_area_id"], name: "index_better_together_navigation_items_on_navigation_area_id"
- t.index ["parent_id"], name: "by_nav_item_parent"
- end
-
- create_table "better_together_pages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.text "meta_description"
- t.string "keywords"
- t.datetime "published_at"
- t.string "layout"
- t.string "template"
- t.uuid "sidebar_nav_id"
- t.index ["identifier"], name: "index_better_together_pages_on_identifier", unique: true
- t.index ["privacy"], name: "by_page_privacy"
- t.index ["published_at"], name: "by_page_publication_date"
- t.index ["sidebar_nav_id"], name: "by_page_sidebar_nav"
- end
-
- create_table "better_together_people", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.uuid "community_id", null: false
- t.jsonb "preferences", default: {}, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.jsonb "notification_preferences", default: {}, null: false
- t.index ["community_id"], name: "by_person_community"
- t.index ["identifier"], name: "index_better_together_people_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_people_privacy"
- end
-
- create_table "better_together_person_blocks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "blocker_id", null: false
- t.uuid "blocked_id", null: false
- t.index ["blocked_id"], name: "index_better_together_person_blocks_on_blocked_id"
- t.index ["blocker_id", "blocked_id"], name: "unique_person_blocks", unique: true
- t.index ["blocker_id"], name: "index_better_together_person_blocks_on_blocker_id"
- end
-
- create_table "better_together_person_community_memberships", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "member_id", null: false
- t.uuid "joinable_id", null: false
- t.uuid "role_id", null: false
- t.index ["joinable_id", "member_id", "role_id"], name: "unique_person_community_membership_member_role", unique: true
- t.index ["joinable_id"], name: "person_community_membership_by_joinable"
- t.index ["member_id"], name: "person_community_membership_by_member"
- t.index ["role_id"], name: "person_community_membership_by_role"
- end
-
- create_table "better_together_person_platform_memberships", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "member_id", null: false
- t.uuid "joinable_id", null: false
- t.uuid "role_id", null: false
- t.index ["joinable_id", "member_id", "role_id"], name: "unique_person_platform_membership_member_role", unique: true
- t.index ["joinable_id"], name: "person_platform_membership_by_joinable"
- t.index ["member_id"], name: "person_platform_membership_by_member"
- t.index ["role_id"], name: "person_platform_membership_by_role"
- end
-
- create_table "better_together_phone_numbers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "number", null: false
- t.string "label", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.uuid "contact_detail_id", null: false
- t.boolean "primary_flag", default: false, null: false
- t.index ["contact_detail_id", "primary_flag"], name: "index_bt_phone_numbers_on_contact_detail_id_and_primary", unique: true, where: "(primary_flag IS TRUE)"
- t.index ["contact_detail_id"], name: "index_better_together_phone_numbers_on_contact_detail_id"
- t.index ["privacy"], name: "by_better_together_phone_numbers_privacy"
- end
-
- create_table "better_together_places", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "community_id", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.uuid "space_id", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.index ["community_id"], name: "by_better_together_places_community"
- t.index ["creator_id"], name: "by_better_together_places_creator"
- t.index ["identifier"], name: "index_better_together_places_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_places_privacy"
- t.index ["space_id"], name: "index_better_together_places_on_space_id"
- end
-
- create_table "better_together_platform_invitations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "community_role_id", null: false
- t.string "invitee_email"
- t.uuid "invitable_id", null: false
- t.uuid "invitee_id"
- t.uuid "inviter_id", null: false
- t.uuid "platform_role_id"
- t.string "status", limit: 20, null: false
- t.string "locale", limit: 5, default: "en", null: false
- t.string "token", limit: 24, null: false
- t.datetime "valid_from", null: false
- t.datetime "valid_until"
- t.datetime "last_sent"
- t.datetime "accepted_at"
- t.string "type", default: "BetterTogether::PlatformInvitation", null: false
- t.integer "session_duration_mins", default: 30, null: false
- t.index ["community_role_id"], name: "platform_invitations_by_community_role"
- t.index ["invitable_id", "status"], name: "index_platform_invitations_on_invitable_id_and_status"
- t.index ["invitable_id"], name: "platform_invitations_by_invitable"
- t.index ["invitee_email", "invitable_id"], name: "idx_on_invitee_email_invitable_id_5a7d642388", unique: true
- t.index ["invitee_email"], name: "index_pending_invitations_on_invitee_email", where: "((status)::text = 'pending'::text)"
- t.index ["invitee_email"], name: "platform_invitations_by_invitee_email"
- t.index ["invitee_id"], name: "platform_invitations_by_invitee"
- t.index ["inviter_id"], name: "platform_invitations_by_inviter"
- t.index ["locale"], name: "by_better_together_platform_invitations_locale"
- t.index ["platform_role_id"], name: "platform_invitations_by_platform_role"
- t.index ["status"], name: "platform_invitations_by_status"
- t.index ["token"], name: "platform_invitations_by_token", unique: true
- t.index ["valid_from"], name: "platform_invitations_by_valid_from"
- t.index ["valid_until"], name: "platform_invitations_by_valid_until"
- end
-
- create_table "better_together_platforms", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "host", default: false, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "community_id", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.string "url", null: false
- t.string "time_zone", null: false
- t.jsonb "settings", default: {}, null: false
- t.index ["community_id"], name: "by_platform_community"
- t.index ["host"], name: "index_better_together_platforms_on_host", unique: true, where: "(host IS TRUE)"
- t.index ["identifier"], name: "index_better_together_platforms_on_identifier", unique: true
- t.index ["privacy"], name: "by_platform_privacy"
- t.index ["url"], name: "index_better_together_platforms_on_url", unique: true
- end
-
- create_table "better_together_posts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "type", default: "BetterTogether::Post", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.datetime "published_at"
- t.uuid "creator_id"
- t.index ["creator_id"], name: "by_better_together_posts_creator"
- t.index ["identifier"], name: "index_better_together_posts_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_posts_privacy"
- t.index ["published_at"], name: "by_post_publication_date"
- end
-
- create_table "better_together_reports", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "reporter_id", null: false
- t.uuid "reportable_id", null: false
- t.string "reportable_type", null: false
- t.text "reason"
- t.index ["reporter_id"], name: "index_better_together_reports_on_reporter_id"
- end
-
- create_table "better_together_resource_permissions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.integer "position", null: false
- t.string "resource_type", null: false
- t.string "action", null: false
- t.string "target", null: false
- t.index ["identifier"], name: "index_better_together_resource_permissions_on_identifier", unique: true
- t.index ["resource_type", "position"], name: "index_resource_permissions_on_resource_type_and_position", unique: true
- end
-
- create_table "better_together_role_resource_permissions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "role_id", null: false
- t.uuid "resource_permission_id", null: false
- t.index ["resource_permission_id"], name: "role_resource_permissions_resource_permission"
- t.index ["role_id", "resource_permission_id"], name: "unique_role_resource_permission_index", unique: true
- t.index ["role_id"], name: "role_resource_permissions_role"
- end
-
- create_table "better_together_roles", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.integer "position", null: false
- t.string "resource_type", null: false
- t.string "type", default: "BetterTogether::Role", null: false
- t.index ["identifier"], name: "index_better_together_roles_on_identifier", unique: true
- t.index ["resource_type", "position"], name: "index_roles_on_resource_type_and_position", unique: true
- end
-
- create_table "better_together_social_media_accounts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "platform", null: false
- t.string "handle", null: false
- t.string "url"
- t.string "privacy", limit: 50, default: "private", null: false
- t.uuid "contact_detail_id", null: false
- t.index ["contact_detail_id", "platform"], name: "index_bt_sma_on_contact_detail_and_platform", unique: true
- t.index ["contact_detail_id"], name: "idx_on_contact_detail_id_6380b64b3b"
- t.index ["privacy"], name: "by_better_together_social_media_accounts_privacy"
- end
-
- create_table "better_together_uploads", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.string "type", default: "BetterTogether::Upload", null: false
- t.index ["creator_id"], name: "by_better_together_files_creator"
- t.index ["identifier"], name: "index_better_together_uploads_on_identifier", unique: true
- t.index ["privacy"], name: "by_better_together_files_privacy"
- end
-
- create_table "better_together_users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "email", default: "", null: false
- t.string "encrypted_password", default: "", null: false
- t.string "reset_password_token"
- t.datetime "reset_password_sent_at"
- t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0, null: false
- t.datetime "current_sign_in_at"
- t.datetime "last_sign_in_at"
- t.string "current_sign_in_ip"
- t.string "last_sign_in_ip"
- t.string "confirmation_token"
- t.datetime "confirmed_at"
- t.datetime "confirmation_sent_at"
- t.string "unconfirmed_email"
- t.integer "failed_attempts", default: 0, null: false
- t.string "unlock_token"
- t.datetime "locked_at"
- t.index ["confirmation_token"], name: "index_better_together_users_on_confirmation_token", unique: true
- t.index ["email"], name: "index_better_together_users_on_email", unique: true
- t.index ["reset_password_token"], name: "index_better_together_users_on_reset_password_token", unique: true
- t.index ["unlock_token"], name: "index_better_together_users_on_unlock_token", unique: true
- end
-
- create_table "better_together_website_links", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "url", null: false
- t.string "label", null: false
- t.string "privacy", limit: 50, default: "private", null: false
- t.uuid "contact_detail_id", null: false
- t.index ["contact_detail_id"], name: "index_better_together_website_links_on_contact_detail_id"
- t.index ["privacy"], name: "by_better_together_website_links_privacy"
- end
-
- create_table "better_together_wizard_step_definitions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.uuid "wizard_id", null: false
- t.string "template"
- t.string "form_class"
- t.string "message", default: "Please complete this next step.", null: false
- t.integer "step_number", null: false
- t.index ["identifier"], name: "index_better_together_wizard_step_definitions_on_identifier", unique: true
- t.index ["wizard_id", "step_number"], name: "index_wizard_step_definitions_on_wizard_id_and_step_number", unique: true
- t.index ["wizard_id"], name: "by_step_definition_wizard"
- end
-
- create_table "better_together_wizard_steps", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "wizard_id", null: false
- t.uuid "wizard_step_definition_id", null: false
- t.uuid "creator_id"
- t.string "identifier", limit: 100, null: false
- t.boolean "completed", default: false
- t.integer "step_number", null: false
- t.index ["creator_id"], name: "by_step_creator"
- t.index ["identifier"], name: "by_step_identifier"
- t.index ["wizard_id", "identifier", "creator_id"], name: "index_unique_wizard_steps", unique: true, where: "(completed IS FALSE)"
- t.index ["wizard_id", "step_number"], name: "index_wizard_steps_on_wizard_id_and_step_number"
- t.index ["wizard_id"], name: "by_step_wizard"
- t.index ["wizard_step_definition_id"], name: "by_step_wizard_step_definition"
- end
-
- create_table "better_together_wizards", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "identifier", limit: 100, null: false
- t.boolean "protected", default: false, null: false
- t.integer "max_completions", default: 0, null: false
- t.integer "current_completions", default: 0, null: false
- t.datetime "first_completed_at"
- t.datetime "last_completed_at"
- t.text "success_message", default: "Thank you. You have successfully completed the wizard", null: false
- t.string "success_path", default: "/", null: false
- t.index ["identifier"], name: "index_better_together_wizards_on_identifier", unique: true
- end
-
- create_table "friendly_id_slugs", force: :cascade do |t|
- t.string "slug", null: false
- t.uuid "sluggable_id", null: false
- t.string "sluggable_type", null: false
- t.string "scope"
- t.integer "lock_version", default: 0, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale", null: false
- t.index ["locale"], name: "index_friendly_id_slugs_on_locale"
- t.index ["slug", "sluggable_type", "locale"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_locale"
- t.index ["slug", "sluggable_type", "scope", "locale"], name: "index_friendly_id_slugs_unique", unique: true
- t.index ["sluggable_type", "sluggable_id"], name: "by_sluggable"
- end
-
- create_table "mobility_string_translations", force: :cascade do |t|
- t.string "locale", null: false
- t.string "key", null: false
- t.string "value"
- t.string "translatable_type"
- t.uuid "translatable_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["translatable_id", "translatable_type", "key"], name: "index_mobility_string_translations_on_translatable_attribute"
- t.index ["translatable_id", "translatable_type", "locale", "key"], name: "index_mobility_string_translations_on_keys", unique: true
- t.index ["translatable_type", "key", "value", "locale"], name: "index_mobility_string_translations_on_query_keys"
- end
-
- create_table "mobility_text_translations", force: :cascade do |t|
- t.string "locale", null: false
- t.string "key", null: false
- t.text "value"
- t.string "translatable_type"
- t.uuid "translatable_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["translatable_id", "translatable_type", "key"], name: "index_mobility_text_translations_on_translatable_attribute"
- t.index ["translatable_id", "translatable_type", "locale", "key"], name: "index_mobility_text_translations_on_keys", unique: true
- end
-
- create_table "noticed_events", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.string "type"
- t.string "record_type"
- t.uuid "record_id"
- t.jsonb "params"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "notifications_count"
- t.index ["record_type", "record_id"], name: "index_noticed_events_on_record"
- end
-
- create_table "noticed_notifications", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
- t.string "type"
- t.uuid "event_id", null: false
- t.string "recipient_type", null: false
- t.uuid "recipient_id", null: false
- t.datetime "read_at", precision: nil
- t.datetime "seen_at", precision: nil
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["event_id"], name: "index_noticed_notifications_on_event_id"
- t.index ["recipient_type", "recipient_id"], name: "index_noticed_notifications_on_recipient"
- end
-
- add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
- add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
- add_foreign_key "better_together_addresses", "better_together_contact_details", column: "contact_detail_id"
- add_foreign_key "better_together_agreement_participants", "better_together_agreements", column: "agreement_id"
- add_foreign_key "better_together_agreement_participants", "better_together_people", column: "person_id"
- add_foreign_key "better_together_agreement_terms", "better_together_agreements", column: "agreement_id"
- add_foreign_key "better_together_agreements", "better_together_pages", column: "page_id"
- add_foreign_key "better_together_agreements", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_ai_log_translations", "better_together_people", column: "initiator_id"
- add_foreign_key "better_together_authorships", "better_together_people", column: "author_id"
- add_foreign_key "better_together_calendar_entries", "better_together_calendars", column: "calendar_id"
- add_foreign_key "better_together_calendar_entries", "better_together_events", column: "event_id"
- add_foreign_key "better_together_calendars", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_calendars", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_calls_for_interest", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_categorizations", "better_together_categories", column: "category_id"
- add_foreign_key "better_together_comments", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_communities", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_content_blocks", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_content_page_blocks", "better_together_content_blocks", column: "block_id"
- add_foreign_key "better_together_content_page_blocks", "better_together_pages", column: "page_id"
- add_foreign_key "better_together_content_platform_blocks", "better_together_content_blocks", column: "block_id"
- add_foreign_key "better_together_content_platform_blocks", "better_together_platforms", column: "platform_id"
- add_foreign_key "better_together_conversation_participants", "better_together_conversations", column: "conversation_id"
- add_foreign_key "better_together_conversation_participants", "better_together_people", column: "person_id"
- add_foreign_key "better_together_conversations", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_email_addresses", "better_together_contact_details", column: "contact_detail_id"
- add_foreign_key "better_together_event_attendances", "better_together_events", column: "event_id"
- add_foreign_key "better_together_event_attendances", "better_together_people", column: "person_id"
- add_foreign_key "better_together_event_hosts", "better_together_events", column: "event_id"
- add_foreign_key "better_together_events", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_geography_continents", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_geography_countries", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_geography_country_continents", "better_together_geography_continents", column: "continent_id"
- add_foreign_key "better_together_geography_country_continents", "better_together_geography_countries", column: "country_id"
- add_foreign_key "better_together_geography_geospatial_spaces", "better_together_geography_spaces", column: "space_id"
- add_foreign_key "better_together_geography_locatable_locations", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_geography_maps", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_geography_region_settlements", "better_together_geography_regions", column: "region_id"
- add_foreign_key "better_together_geography_region_settlements", "better_together_geography_settlements", column: "settlement_id"
- add_foreign_key "better_together_geography_regions", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_geography_regions", "better_together_geography_countries", column: "country_id"
- add_foreign_key "better_together_geography_regions", "better_together_geography_states", column: "state_id"
- add_foreign_key "better_together_geography_settlements", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_geography_settlements", "better_together_geography_countries", column: "country_id"
- add_foreign_key "better_together_geography_settlements", "better_together_geography_states", column: "state_id"
- add_foreign_key "better_together_geography_spaces", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_geography_states", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_geography_states", "better_together_geography_countries", column: "country_id"
- add_foreign_key "better_together_infrastructure_building_connections", "better_together_infrastructure_buildings", column: "building_id"
- add_foreign_key "better_together_infrastructure_buildings", "better_together_addresses", column: "address_id"
- add_foreign_key "better_together_infrastructure_buildings", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_infrastructure_buildings", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_infrastructure_floors", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_infrastructure_floors", "better_together_infrastructure_buildings", column: "building_id"
- add_foreign_key "better_together_infrastructure_floors", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_infrastructure_rooms", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_infrastructure_rooms", "better_together_infrastructure_floors", column: "floor_id"
- add_foreign_key "better_together_infrastructure_rooms", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_invitations", "better_together_roles", column: "role_id"
- add_foreign_key "better_together_joatu_agreements", "better_together_joatu_offers", column: "offer_id"
- add_foreign_key "better_together_joatu_agreements", "better_together_joatu_requests", column: "request_id"
- add_foreign_key "better_together_joatu_offers", "better_together_addresses", column: "address_id"
- add_foreign_key "better_together_joatu_offers", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_joatu_requests", "better_together_addresses", column: "address_id"
- add_foreign_key "better_together_joatu_requests", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_joatu_response_links", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_messages", "better_together_conversations", column: "conversation_id"
- add_foreign_key "better_together_messages", "better_together_people", column: "sender_id"
- add_foreign_key "better_together_navigation_items", "better_together_navigation_areas", column: "navigation_area_id"
- add_foreign_key "better_together_navigation_items", "better_together_navigation_items", column: "parent_id"
- add_foreign_key "better_together_pages", "better_together_navigation_areas", column: "sidebar_nav_id"
- add_foreign_key "better_together_people", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_person_blocks", "better_together_people", column: "blocked_id"
- add_foreign_key "better_together_person_blocks", "better_together_people", column: "blocker_id"
- add_foreign_key "better_together_person_community_memberships", "better_together_communities", column: "joinable_id"
- add_foreign_key "better_together_person_community_memberships", "better_together_people", column: "member_id"
- add_foreign_key "better_together_person_community_memberships", "better_together_roles", column: "role_id"
- add_foreign_key "better_together_person_platform_memberships", "better_together_people", column: "member_id"
- add_foreign_key "better_together_person_platform_memberships", "better_together_platforms", column: "joinable_id"
- add_foreign_key "better_together_person_platform_memberships", "better_together_roles", column: "role_id"
- add_foreign_key "better_together_phone_numbers", "better_together_contact_details", column: "contact_detail_id"
- add_foreign_key "better_together_places", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_places", "better_together_geography_spaces", column: "space_id"
- add_foreign_key "better_together_places", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_platform_invitations", "better_together_people", column: "invitee_id"
- add_foreign_key "better_together_platform_invitations", "better_together_people", column: "inviter_id"
- add_foreign_key "better_together_platform_invitations", "better_together_platforms", column: "invitable_id"
- add_foreign_key "better_together_platform_invitations", "better_together_roles", column: "community_role_id"
- add_foreign_key "better_together_platform_invitations", "better_together_roles", column: "platform_role_id"
- add_foreign_key "better_together_platforms", "better_together_communities", column: "community_id"
- add_foreign_key "better_together_posts", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_reports", "better_together_people", column: "reporter_id"
- add_foreign_key "better_together_role_resource_permissions", "better_together_resource_permissions", column: "resource_permission_id"
- add_foreign_key "better_together_role_resource_permissions", "better_together_roles", column: "role_id"
- add_foreign_key "better_together_social_media_accounts", "better_together_contact_details", column: "contact_detail_id"
- add_foreign_key "better_together_uploads", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_website_links", "better_together_contact_details", column: "contact_detail_id"
- add_foreign_key "better_together_wizard_step_definitions", "better_together_wizards", column: "wizard_id"
- add_foreign_key "better_together_wizard_steps", "better_together_people", column: "creator_id"
- add_foreign_key "better_together_wizard_steps", "better_together_wizard_step_definitions", column: "wizard_step_definition_id"
- add_foreign_key "better_together_wizard_steps", "better_together_wizards", column: "wizard_id"
+ enable_extension 'pgcrypto'
+ enable_extension 'plpgsql'
+ enable_extension 'postgis'
+
+ create_table 'action_text_rich_texts', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.string 'name', null: false
+ t.text 'body'
+ t.string 'record_type', null: false
+ t.uuid 'record_id', null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'locale'
+ t.index %w[record_type record_id name locale], name: 'index_action_text_rich_texts_uniqueness',
+ unique: true
+ end
+
+ create_table 'active_storage_attachments', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.string 'name', null: false
+ t.string 'record_type', null: false
+ t.uuid 'record_id', null: false
+ t.uuid 'blob_id', null: false
+ t.datetime 'created_at', null: false
+ t.index ['blob_id'], name: 'index_active_storage_attachments_on_blob_id'
+ t.index %w[record_type record_id name blob_id], name: 'index_active_storage_attachments_uniqueness',
+ unique: true
+ end
+
+ create_table 'active_storage_blobs', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.string 'key', null: false
+ t.string 'filename', null: false
+ t.string 'content_type'
+ t.text 'metadata'
+ t.string 'service_name', null: false
+ t.bigint 'byte_size', null: false
+ t.string 'checksum'
+ t.datetime 'created_at', null: false
+ t.index ['key'], name: 'index_active_storage_blobs_on_key', unique: true
+ end
+
+ create_table 'active_storage_variant_records', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.uuid 'blob_id', null: false
+ t.string 'variation_digest', null: false
+ t.index %w[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true
+ end
+
+ create_table 'better_together_activities', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'trackable_type'
+ t.uuid 'trackable_id'
+ t.string 'owner_type'
+ t.uuid 'owner_id'
+ t.string 'key'
+ t.jsonb 'parameters', default: '{}'
+ t.string 'recipient_type'
+ t.uuid 'recipient_id'
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.index %w[owner_type owner_id], name: 'bt_activities_by_owner'
+ t.index ['privacy'], name: 'by_better_together_activities_privacy'
+ t.index %w[recipient_type recipient_id], name: 'bt_activities_by_recipient'
+ t.index %w[trackable_type trackable_id], name: 'bt_activities_by_trackable'
+ end
+
+ create_table 'better_together_addresses', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'label', default: 'main', null: false
+ t.boolean 'physical', default: true, null: false
+ t.boolean 'postal', default: false, null: false
+ t.string 'line1'
+ t.string 'line2'
+ t.string 'city_name'
+ t.string 'state_province_name'
+ t.string 'postal_code'
+ t.string 'country_name'
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.uuid 'contact_detail_id'
+ t.boolean 'primary_flag', default: false, null: false
+ t.index %w[contact_detail_id primary_flag], name: 'index_bt_addresses_on_contact_detail_id_and_primary',
+ unique: true, where: '(primary_flag IS TRUE)'
+ t.index ['contact_detail_id'], name: 'index_better_together_addresses_on_contact_detail_id'
+ t.index ['privacy'], name: 'by_better_together_addresses_privacy'
+ end
+
+ create_table 'better_together_agreement_participants', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'agreement_id', null: false
+ t.uuid 'person_id', null: false
+ t.string 'group_identifier'
+ t.datetime 'accepted_at'
+ t.index %w[agreement_id person_id], name: 'index_bt_agreement_participants_on_agreement_and_person', unique: true
+ t.index ['agreement_id'], name: 'index_better_together_agreement_participants_on_agreement_id'
+ t.index ['group_identifier'], name: 'idx_on_group_identifier_06b6e57c0b'
+ t.index ['person_id'], name: 'index_better_together_agreement_participants_on_person_id'
+ end
+
+ create_table 'better_together_agreement_terms', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.integer 'position', null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'agreement_id', null: false
+ t.index ['agreement_id'], name: 'index_better_together_agreement_terms_on_agreement_id'
+ t.index ['identifier'], name: 'index_better_together_agreement_terms_on_identifier', unique: true
+ end
+
+ create_table 'better_together_agreements', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.boolean 'collective', default: false, null: false
+ t.uuid 'page_id'
+ t.index ['creator_id'], name: 'by_better_together_agreements_creator'
+ t.index ['identifier'], name: 'index_better_together_agreements_on_identifier', unique: true
+ t.index ['page_id'], name: 'index_better_together_agreements_on_page_id'
+ t.index ['privacy'], name: 'by_better_together_agreements_privacy'
+ end
+
+ create_table 'better_together_ai_log_translations', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.text 'request', null: false
+ t.text 'response'
+ t.string 'model', null: false
+ t.integer 'prompt_tokens', default: 0, null: false
+ t.integer 'completion_tokens', default: 0, null: false
+ t.integer 'tokens_used', default: 0, null: false
+ t.decimal 'estimated_cost', precision: 10, scale: 5, default: '0.0', null: false
+ t.datetime 'start_time'
+ t.datetime 'end_time'
+ t.string 'status', default: 'pending', null: false
+ t.uuid 'initiator_id'
+ t.string 'source_locale', null: false
+ t.string 'target_locale', null: false
+ t.index ['initiator_id'], name: 'index_better_together_ai_log_translations_on_initiator_id'
+ t.index ['model'], name: 'index_better_together_ai_log_translations_on_model'
+ t.index ['source_locale'], name: 'index_better_together_ai_log_translations_on_source_locale'
+ t.index ['status'], name: 'index_better_together_ai_log_translations_on_status'
+ t.index ['target_locale'], name: 'index_better_together_ai_log_translations_on_target_locale'
+ end
+
+ create_table 'better_together_authorships', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.integer 'position', null: false
+ t.string 'authorable_type', null: false
+ t.uuid 'authorable_id', null: false
+ t.uuid 'author_id', null: false
+ t.uuid 'creator_id'
+ t.index ['author_id'], name: 'by_authorship_author'
+ t.index %w[authorable_type authorable_id], name: 'by_authorship_authorable'
+ t.index ['creator_id'], name: 'by_better_together_authorships_creator'
+ end
+
+ create_table 'better_together_calendar_entries', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'calendar_id'
+ t.string 'schedulable_type'
+ t.uuid 'schedulable_id'
+ t.datetime 'starts_at', null: false
+ t.datetime 'ends_at'
+ t.decimal 'duration_minutes'
+ t.uuid 'event_id', null: false
+ t.index %w[calendar_id event_id], name: 'by_calendar_and_event', unique: true
+ t.index ['calendar_id'], name: 'index_better_together_calendar_entries_on_calendar_id'
+ t.index ['ends_at'], name: 'bt_calendar_events_by_ends_at'
+ t.index ['event_id'], name: 'bt_calendar_entries_by_event'
+ t.index %w[schedulable_type schedulable_id], name: 'index_better_together_calendar_entries_on_schedulable'
+ t.index ['starts_at'], name: 'bt_calendar_events_by_starts_at'
+ end
+
+ create_table 'better_together_calendars', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'community_id', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.boolean 'protected', default: false, null: false
+ t.index ['community_id'], name: 'by_better_together_calendars_community'
+ t.index ['creator_id'], name: 'by_better_together_calendars_creator'
+ t.index ['identifier'], name: 'index_better_together_calendars_on_identifier', unique: true
+ t.index ['locale'], name: 'by_better_together_calendars_locale'
+ t.index ['privacy'], name: 'by_better_together_calendars_privacy'
+ end
+
+ create_table 'better_together_calls_for_interest', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'type', default: 'BetterTogether::CallForInterest', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.string 'interestable_type'
+ t.uuid 'interestable_id'
+ t.datetime 'starts_at'
+ t.datetime 'ends_at'
+ t.index ['creator_id'], name: 'by_better_together_calls_for_interest_creator'
+ t.index ['ends_at'], name: 'bt_calls_for_interest_by_ends_at'
+ t.index ['identifier'], name: 'index_better_together_calls_for_interest_on_identifier', unique: true
+ t.index %w[interestable_type interestable_id], name: 'index_better_together_calls_for_interest_on_interestable'
+ t.index ['privacy'], name: 'by_better_together_calls_for_interest_privacy'
+ t.index ['starts_at'], name: 'bt_calls_for_interest_by_starts_at'
+ end
+
+ create_table 'better_together_categories', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.integer 'position', null: false
+ t.boolean 'protected', default: false, null: false
+ t.string 'type', default: 'BetterTogether::Category', null: false
+ t.string 'icon', default: 'fas fa-icons', null: false
+ t.index %w[identifier type], name: 'index_better_together_categories_on_identifier_and_type', unique: true
+ end
+
+ create_table 'better_together_categorizations', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'category_type', null: false
+ t.uuid 'category_id', null: false
+ t.string 'categorizable_type', null: false
+ t.uuid 'categorizable_id', null: false
+ t.index %w[categorizable_type categorizable_id], name: 'index_better_together_categorizations_on_categorizable'
+ t.index %w[category_type category_id], name: 'index_better_together_categorizations_on_category'
+ end
+
+ create_table 'better_together_comments', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'commentable_type', null: false
+ t.uuid 'commentable_id', null: false
+ t.uuid 'creator_id'
+ t.text 'content', default: '', null: false
+ t.index %w[commentable_type commentable_id], name: 'bt_comments_on_commentable'
+ t.index ['creator_id'], name: 'by_better_together_comments_creator'
+ end
+
+ create_table 'better_together_communities', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'host', default: false, null: false
+ t.boolean 'protected', default: false, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.uuid 'creator_id'
+ t.string 'type', default: 'BetterTogether::Community', null: false
+ t.index ['creator_id'], name: 'by_creator'
+ t.index ['host'], name: 'index_better_together_communities_on_host', unique: true, where: '(host IS TRUE)'
+ t.index ['identifier'], name: 'index_better_together_communities_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_community_privacy'
+ end
+
+ create_table 'better_together_contact_details', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'contactable_type', null: false
+ t.uuid 'contactable_id', null: false
+ t.string 'type', default: 'BetterTogether::ContactDetail', null: false
+ t.string 'name'
+ t.string 'role'
+ t.index %w[contactable_type contactable_id], name: 'index_better_together_contact_details_on_contactable'
+ end
+
+ create_table 'better_together_content_blocks', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'type', null: false
+ t.string 'identifier', limit: 100
+ t.jsonb 'accessibility_attributes', default: {}, null: false
+ t.jsonb 'content_settings', default: {}, null: false
+ t.jsonb 'css_settings', default: {}, null: false
+ t.jsonb 'data_attributes', default: {}, null: false
+ t.jsonb 'html_attributes', default: {}, null: false
+ t.jsonb 'layout_settings', default: {}, null: false
+ t.jsonb 'media_settings', default: {}, null: false
+ t.jsonb 'content_data', default: {}
+ t.uuid 'creator_id'
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.boolean 'visible', default: true, null: false
+ t.jsonb 'content_area_settings', default: {}, null: false
+ t.index ['creator_id'], name: 'by_better_together_content_blocks_creator'
+ t.index ['privacy'], name: 'by_better_together_content_blocks_privacy'
+ end
+
+ create_table 'better_together_content_page_blocks', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'page_id', null: false
+ t.uuid 'block_id', null: false
+ t.integer 'position', null: false
+ t.index ['block_id'], name: 'index_better_together_content_page_blocks_on_block_id'
+ t.index %w[page_id block_id position], name: 'content_page_blocks_on_page_block_and_position'
+ t.index %w[page_id block_id], name: 'content_page_blocks_on_page_and_block', unique: true
+ t.index ['page_id'], name: 'index_better_together_content_page_blocks_on_page_id'
+ end
+
+ create_table 'better_together_content_platform_blocks', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'platform_id', null: false
+ t.uuid 'block_id', null: false
+ t.index ['block_id'], name: 'index_better_together_content_platform_blocks_on_block_id'
+ t.index ['platform_id'], name: 'index_better_together_content_platform_blocks_on_platform_id'
+ end
+
+ create_table 'better_together_conversation_participants', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'conversation_id', null: false
+ t.uuid 'person_id', null: false
+ t.index ['conversation_id'], name: 'idx_on_conversation_id_30b3b70bad'
+ t.index ['person_id'], name: 'index_better_together_conversation_participants_on_person_id'
+ end
+
+ create_table 'better_together_conversations', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'title', null: false
+ t.uuid 'creator_id', null: false
+ t.index ['creator_id'], name: 'index_better_together_conversations_on_creator_id'
+ end
+
+ create_table 'better_together_email_addresses', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'email', null: false
+ t.string 'label', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.uuid 'contact_detail_id', null: false
+ t.boolean 'primary_flag', default: false, null: false
+ t.index %w[contact_detail_id primary_flag], name: 'index_bt_email_addresses_on_contact_detail_id_and_primary',
+ unique: true, where: '(primary_flag IS TRUE)'
+ t.index ['contact_detail_id'], name: 'index_better_together_email_addresses_on_contact_detail_id'
+ t.index ['privacy'], name: 'by_better_together_email_addresses_privacy'
+ end
+
+ create_table 'better_together_event_attendances', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'event_id', null: false
+ t.uuid 'person_id', null: false
+ t.string 'status', default: 'interested', null: false
+ t.index %w[event_id person_id], name: 'by_event_and_person', unique: true
+ t.index ['event_id'], name: 'bt_event_attendance_by_event'
+ t.index ['person_id'], name: 'bt_event_attendance_by_person'
+ end
+
+ create_table 'better_together_event_hosts', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'event_id'
+ t.string 'host_type'
+ t.uuid 'host_id'
+ t.index ['event_id'], name: 'index_better_together_event_hosts_on_event_id'
+ t.index %w[host_type host_id], name: 'index_better_together_event_hosts_on_host'
+ end
+
+ create_table 'better_together_events', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'type', default: 'BetterTogether::Event', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.datetime 'starts_at'
+ t.datetime 'ends_at'
+ t.decimal 'duration_minutes'
+ t.string 'registration_url'
+ t.index ['creator_id'], name: 'by_better_together_events_creator'
+ t.index ['ends_at'], name: 'bt_events_by_ends_at'
+ t.index ['identifier'], name: 'index_better_together_events_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_events_privacy'
+ t.index ['starts_at'], name: 'bt_events_by_starts_at'
+ end
+
+ create_table 'better_together_geography_continents', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'community_id', null: false
+ t.index ['community_id'], name: 'by_geography_continent_community'
+ t.index ['identifier'], name: 'index_better_together_geography_continents_on_identifier', unique: true
+ end
+
+ create_table 'better_together_geography_countries', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.string 'iso_code', limit: 2, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'community_id', null: false
+ t.index ['community_id'], name: 'by_geography_country_community'
+ t.index ['identifier'], name: 'index_better_together_geography_countries_on_identifier', unique: true
+ t.index ['iso_code'], name: 'index_better_together_geography_countries_on_iso_code', unique: true
+ end
+
+ create_table 'better_together_geography_country_continents', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'country_id'
+ t.uuid 'continent_id'
+ t.index ['continent_id'], name: 'country_continent_by_continent'
+ t.index %w[country_id continent_id], name: 'index_country_continents_on_country_and_continent', unique: true
+ t.index ['country_id'], name: 'country_continent_by_country'
+ end
+
+ create_table 'better_together_geography_geospatial_spaces', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'geospatial_type'
+ t.uuid 'geospatial_id'
+ t.integer 'position', null: false
+ t.boolean 'primary_flag', default: false, null: false
+ t.uuid 'space_id'
+ t.index %w[geospatial_id primary_flag], name: 'index_geospatial_spaces_on_geospatial_id_and_primary',
+ unique: true, where: '(primary_flag IS TRUE)'
+ t.index %w[geospatial_type geospatial_id],
+ name: 'index_better_together_geography_geospatial_spaces_on_geospatial'
+ t.index ['space_id'], name: 'index_better_together_geography_geospatial_spaces_on_space_id'
+ end
+
+ create_table 'better_together_geography_locatable_locations', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'location_type'
+ t.uuid 'location_id'
+ t.string 'locatable_type', null: false
+ t.uuid 'locatable_id', null: false
+ t.string 'name'
+ t.index ['creator_id'], name: 'by_better_together_geography_locatable_locations_creator'
+ t.index %w[locatable_id locatable_type location_id location_type], name: 'locatable_locations'
+ t.index %w[locatable_type locatable_id], name: 'locatable_location_by_locatable'
+ t.index %w[location_type location_id], name: 'locatable_location_by_location'
+ t.index ['name'], name: 'locatable_location_by_name'
+ end
+
+ create_table 'better_together_geography_maps', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.boolean 'protected', default: false, null: false
+ t.geography 'center', limit: { srid: 4326, type: 'st_point', geographic: true }
+ t.integer 'zoom', default: 13, null: false
+ t.geography 'viewport', limit: { srid: 4326, type: 'st_polygon', geographic: true }
+ t.jsonb 'metadata', default: {}, null: false
+ t.string 'mappable_type'
+ t.uuid 'mappable_id'
+ t.string 'type', default: 'BetterTogether::Geography::Map', null: false
+ t.index ['creator_id'], name: 'by_better_together_geography_maps_creator'
+ t.index ['identifier'], name: 'index_better_together_geography_maps_on_identifier', unique: true
+ t.index ['locale'], name: 'by_better_together_geography_maps_locale'
+ t.index %w[mappable_type mappable_id], name: 'index_better_together_geography_maps_on_mappable'
+ t.index ['privacy'], name: 'by_better_together_geography_maps_privacy'
+ end
+
+ create_table 'better_together_geography_region_settlements', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'region_id'
+ t.uuid 'settlement_id'
+ t.index ['region_id'], name: 'bt_region_settlement_by_region'
+ t.index ['settlement_id'], name: 'bt_region_settlement_by_settlement'
+ end
+
+ create_table 'better_together_geography_regions', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'community_id', null: false
+ t.uuid 'country_id'
+ t.uuid 'state_id'
+ t.string 'type', default: 'BetterTogether::Geography::Region', null: false
+ t.index ['community_id'], name: 'by_geography_region_community'
+ t.index ['country_id'], name: 'index_better_together_geography_regions_on_country_id'
+ t.index ['identifier'], name: 'index_better_together_geography_regions_on_identifier', unique: true
+ t.index ['state_id'], name: 'index_better_together_geography_regions_on_state_id'
+ end
+
+ create_table 'better_together_geography_settlements', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'community_id', null: false
+ t.uuid 'country_id'
+ t.uuid 'state_id'
+ t.index ['community_id'], name: 'by_geography_settlement_community'
+ t.index ['country_id'], name: 'index_better_together_geography_settlements_on_country_id'
+ t.index ['identifier'], name: 'index_better_together_geography_settlements_on_identifier', unique: true
+ t.index ['state_id'], name: 'index_better_together_geography_settlements_on_state_id'
+ end
+
+ create_table 'better_together_geography_spaces', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.float 'elevation'
+ t.float 'latitude'
+ t.float 'longitude'
+ t.jsonb 'properties', default: {}
+ t.jsonb 'metadata', default: {}
+ t.index ['creator_id'], name: 'by_better_together_geography_spaces_creator'
+ t.index ['identifier'], name: 'index_better_together_geography_spaces_on_identifier', unique: true
+ end
+
+ create_table 'better_together_geography_states', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.string 'iso_code', limit: 5, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'community_id', null: false
+ t.uuid 'country_id'
+ t.index ['community_id'], name: 'by_geography_state_community'
+ t.index ['country_id'], name: 'index_better_together_geography_states_on_country_id'
+ t.index ['identifier'], name: 'index_better_together_geography_states_on_identifier', unique: true
+ t.index ['iso_code'], name: 'index_better_together_geography_states_on_iso_code', unique: true
+ end
+
+ create_table 'better_together_identifications', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.boolean 'active', null: false
+ t.string 'identity_type', null: false
+ t.uuid 'identity_id', null: false
+ t.string 'agent_type', null: false
+ t.uuid 'agent_id', null: false
+ t.index %w[active agent_type agent_id], name: 'active_identification', unique: true
+ t.index ['active'], name: 'by_active_state'
+ t.index %w[agent_type agent_id], name: 'by_agent'
+ t.index %w[identity_type identity_id agent_type agent_id], name: 'unique_identification', unique: true
+ t.index %w[identity_type identity_id], name: 'by_identity'
+ end
+
+ create_table 'better_together_infrastructure_building_connections', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'building_id', null: false
+ t.string 'connection_type', null: false
+ t.uuid 'connection_id', null: false
+ t.integer 'position', null: false
+ t.boolean 'primary_flag', default: false, null: false
+ t.index ['building_id'], name: 'bt_building_connections_building'
+ t.index %w[connection_id primary_flag], name: 'index_bt_building_connections_on_connection_id_and_primary',
+ unique: true, where: '(primary_flag IS TRUE)'
+ t.index %w[connection_type connection_id], name: 'bt_building_connections_connection'
+ end
+
+ create_table 'better_together_infrastructure_buildings', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'type', default: 'BetterTogether::Infrastructure::Building', null: false
+ t.uuid 'community_id', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.integer 'floors_count', default: 0, null: false
+ t.integer 'rooms_count', default: 0, null: false
+ t.uuid 'address_id'
+ t.index ['address_id'], name: 'index_better_together_infrastructure_buildings_on_address_id'
+ t.index ['community_id'], name: 'by_better_together_infrastructure_buildings_community'
+ t.index ['creator_id'], name: 'by_better_together_infrastructure_buildings_creator'
+ t.index ['identifier'], name: 'index_better_together_infrastructure_buildings_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_infrastructure_buildings_privacy'
+ end
+
+ create_table 'better_together_infrastructure_floors', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'building_id'
+ t.uuid 'community_id', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.integer 'position', null: false
+ t.integer 'level', default: 0, null: false
+ t.integer 'rooms_count', default: 0, null: false
+ t.index ['building_id'], name: 'index_better_together_infrastructure_floors_on_building_id'
+ t.index ['community_id'], name: 'by_better_together_infrastructure_floors_community'
+ t.index ['creator_id'], name: 'by_better_together_infrastructure_floors_creator'
+ t.index ['identifier'], name: 'index_better_together_infrastructure_floors_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_infrastructure_floors_privacy'
+ end
+
+ create_table 'better_together_infrastructure_rooms', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'floor_id'
+ t.uuid 'community_id', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.index ['community_id'], name: 'by_better_together_infrastructure_rooms_community'
+ t.index ['creator_id'], name: 'by_better_together_infrastructure_rooms_creator'
+ t.index ['floor_id'], name: 'index_better_together_infrastructure_rooms_on_floor_id'
+ t.index ['identifier'], name: 'index_better_together_infrastructure_rooms_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_infrastructure_rooms_privacy'
+ end
+
+ create_table 'better_together_invitations', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'type', default: 'BetterTogether::Invitation', null: false
+ t.string 'status', limit: 20, null: false
+ t.datetime 'valid_from', null: false
+ t.datetime 'valid_until'
+ t.datetime 'last_sent'
+ t.datetime 'accepted_at'
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'token', limit: 24, null: false
+ t.string 'invitable_type', null: false
+ t.uuid 'invitable_id', null: false
+ t.string 'inviter_type', null: false
+ t.uuid 'inviter_id', null: false
+ t.string 'invitee_type', null: false
+ t.uuid 'invitee_id', null: false
+ t.string 'invitee_email', null: false
+ t.uuid 'role_id'
+ t.index %w[invitable_id status], name: 'invitations_on_invitable_id_and_status'
+ t.index %w[invitable_type invitable_id], name: 'by_invitable'
+ t.index %w[invitee_email invitable_id], name: 'invitations_on_invitee_email_and_invitable_id', unique: true
+ t.index ['invitee_email'], name: 'invitations_by_invitee_email'
+ t.index ['invitee_email'], name: 'pending_invites_on_invitee_email', where: "((status)::text = 'pending'::text)"
+ t.index %w[invitee_type invitee_id], name: 'by_invitee'
+ t.index %w[inviter_type inviter_id], name: 'by_inviter'
+ t.index ['locale'], name: 'by_better_together_invitations_locale'
+ t.index ['role_id'], name: 'by_role'
+ t.index ['status'], name: 'by_status'
+ t.index ['token'], name: 'invitations_by_token', unique: true
+ t.index ['valid_from'], name: 'by_valid_from'
+ t.index ['valid_until'], name: 'by_valid_until'
+ end
+
+ create_table 'better_together_joatu_agreements', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'offer_id', null: false
+ t.uuid 'request_id', null: false
+ t.text 'terms'
+ t.string 'value'
+ t.string 'status', default: 'pending', null: false
+ t.index %w[offer_id request_id], name: 'bt_joatu_agreements_unique_offer_request', unique: true
+ t.index ['offer_id'], name: 'bt_joatu_agreements_by_offer'
+ t.index ['offer_id'], name: 'bt_joatu_agreements_one_accepted_per_offer', unique: true,
+ where: "((status)::text = 'accepted'::text)"
+ t.index ['request_id'], name: 'bt_joatu_agreements_by_request'
+ t.index ['request_id'], name: 'bt_joatu_agreements_one_accepted_per_request', unique: true,
+ where: "((status)::text = 'accepted'::text)"
+ end
+
+ create_table 'better_together_joatu_offers', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'status', default: 'open', null: false
+ t.string 'target_type'
+ t.uuid 'target_id'
+ t.string 'urgency', default: 'normal', null: false
+ t.uuid 'address_id'
+ t.index ['address_id'], name: 'index_better_together_joatu_offers_on_address_id'
+ t.index ['creator_id'], name: 'by_better_together_joatu_offers_creator'
+ t.index %w[target_type target_id], name: 'bt_joatu_offers_on_target'
+ end
+
+ create_table 'better_together_joatu_requests', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'status', default: 'open', null: false
+ t.string 'target_type'
+ t.uuid 'target_id'
+ t.string 'urgency', default: 'normal', null: false
+ t.uuid 'address_id'
+ t.index ['address_id'], name: 'index_better_together_joatu_requests_on_address_id'
+ t.index ['creator_id'], name: 'by_better_together_joatu_requests_creator'
+ t.index %w[target_type target_id], name: 'bt_joatu_requests_on_target'
+ end
+
+ create_table 'better_together_joatu_response_links', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'source_type', null: false
+ t.uuid 'source_id', null: false
+ t.string 'response_type', null: false
+ t.uuid 'response_id', null: false
+ t.uuid 'creator_id'
+ t.index ['creator_id'], name: 'by_better_together_joatu_response_links_creator'
+ t.index %w[response_type response_id], name: 'bt_joatu_response_links_by_response'
+ t.index %w[source_type source_id response_type response_id], name: 'bt_joatu_response_links_unique_pair',
+ unique: true
+ t.index %w[source_type source_id], name: 'bt_joatu_response_links_by_source'
+ end
+
+ create_table 'better_together_jwt_denylists', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'jti'
+ t.datetime 'exp'
+ t.index ['jti'], name: 'index_better_together_jwt_denylists_on_jti'
+ end
+
+ create_table 'better_together_messages', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.text 'content'
+ t.uuid 'sender_id', null: false
+ t.uuid 'conversation_id', null: false
+ t.index ['conversation_id'], name: 'index_better_together_messages_on_conversation_id'
+ t.index ['sender_id'], name: 'index_better_together_messages_on_sender_id'
+ end
+
+ create_table 'better_together_metrics_downloads', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'downloadable_type'
+ t.uuid 'downloadable_id'
+ t.string 'file_name', null: false
+ t.string 'file_type', null: false
+ t.bigint 'file_size', null: false
+ t.datetime 'downloaded_at', null: false
+ t.index %w[downloadable_type downloadable_id], name: 'index_better_together_metrics_downloads_on_downloadable'
+ t.index ['locale'], name: 'by_better_together_metrics_downloads_locale'
+ end
+
+ create_table 'better_together_metrics_link_click_reports', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.jsonb 'filters', default: {}, null: false
+ t.boolean 'sort_by_total_clicks', default: false, null: false
+ t.string 'file_format', default: 'csv', null: false
+ t.jsonb 'report_data', default: {}, null: false
+ t.index ['filters'], name: 'index_better_together_metrics_link_click_reports_on_filters', using: :gin
+ end
+
+ create_table 'better_together_metrics_link_clicks', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'url', null: false
+ t.string 'page_url', null: false
+ t.string 'locale', null: false
+ t.boolean 'internal', default: true
+ t.datetime 'clicked_at', null: false
+ end
+
+ create_table 'better_together_metrics_page_view_reports', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.jsonb 'filters', default: {}, null: false
+ t.boolean 'sort_by_total_views', default: false, null: false
+ t.string 'file_format', default: 'csv', null: false
+ t.jsonb 'report_data', default: {}, null: false
+ t.index ['filters'], name: 'index_better_together_metrics_page_view_reports_on_filters', using: :gin
+ end
+
+ create_table 'better_together_metrics_page_views', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'pageable_type'
+ t.uuid 'pageable_id'
+ t.datetime 'viewed_at', null: false
+ t.string 'page_url'
+ t.index ['locale'], name: 'by_better_together_metrics_page_views_locale'
+ t.index %w[pageable_type pageable_id], name: 'index_better_together_metrics_page_views_on_pageable'
+ end
+
+ create_table 'better_together_metrics_search_queries', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'query', null: false
+ t.integer 'results_count', null: false
+ t.datetime 'searched_at', null: false
+ t.index ['locale'], name: 'by_better_together_metrics_search_queries_locale'
+ end
+
+ create_table 'better_together_metrics_shares', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'platform', null: false
+ t.string 'url', null: false
+ t.datetime 'shared_at', null: false
+ t.string 'shareable_type'
+ t.uuid 'shareable_id'
+ t.index ['locale'], name: 'by_better_together_metrics_shares_locale'
+ t.index %w[platform url], name: 'index_better_together_metrics_shares_on_platform_and_url'
+ t.index %w[shareable_type shareable_id], name: 'index_better_together_metrics_shares_on_shareable'
+ end
+
+ create_table 'better_together_navigation_areas', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.boolean 'visible', default: true, null: false
+ t.string 'name'
+ t.string 'style'
+ t.string 'navigable_type'
+ t.bigint 'navigable_id'
+ t.index ['identifier'], name: 'index_better_together_navigation_areas_on_identifier', unique: true
+ t.index %w[navigable_type navigable_id], name: 'by_navigable'
+ end
+
+ create_table 'better_together_navigation_items', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.integer 'position', null: false
+ t.boolean 'protected', default: false, null: false
+ t.boolean 'visible', default: true, null: false
+ t.uuid 'navigation_area_id', null: false
+ t.uuid 'parent_id'
+ t.string 'url'
+ t.string 'icon'
+ t.string 'item_type', null: false
+ t.string 'linkable_type'
+ t.uuid 'linkable_id'
+ t.string 'route_name'
+ t.integer 'children_count', default: 0, null: false
+ t.index ['identifier'], name: 'index_better_together_navigation_items_on_identifier', unique: true
+ t.index %w[linkable_type linkable_id], name: 'by_linkable'
+ t.index %w[navigation_area_id parent_id position], name: 'navigation_items_area_position', unique: true
+ t.index ['navigation_area_id'], name: 'index_better_together_navigation_items_on_navigation_area_id'
+ t.index ['parent_id'], name: 'by_nav_item_parent'
+ end
+
+ create_table 'better_together_pages', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.text 'meta_description'
+ t.string 'keywords'
+ t.datetime 'published_at'
+ t.string 'layout'
+ t.string 'template'
+ t.uuid 'sidebar_nav_id'
+ t.index ['identifier'], name: 'index_better_together_pages_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_page_privacy'
+ t.index ['published_at'], name: 'by_page_publication_date'
+ t.index ['sidebar_nav_id'], name: 'by_page_sidebar_nav'
+ end
+
+ create_table 'better_together_people', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.uuid 'community_id', null: false
+ t.jsonb 'preferences', default: {}, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.jsonb 'notification_preferences', default: {}, null: false
+ t.index ['community_id'], name: 'by_person_community'
+ t.index ['identifier'], name: 'index_better_together_people_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_people_privacy'
+ end
+
+ create_table 'better_together_person_blocks', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'blocker_id', null: false
+ t.uuid 'blocked_id', null: false
+ t.index ['blocked_id'], name: 'index_better_together_person_blocks_on_blocked_id'
+ t.index %w[blocker_id blocked_id], name: 'unique_person_blocks', unique: true
+ t.index ['blocker_id'], name: 'index_better_together_person_blocks_on_blocker_id'
+ end
+
+ create_table 'better_together_person_community_memberships', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'member_id', null: false
+ t.uuid 'joinable_id', null: false
+ t.uuid 'role_id', null: false
+ t.index %w[joinable_id member_id role_id], name: 'unique_person_community_membership_member_role',
+ unique: true
+ t.index ['joinable_id'], name: 'person_community_membership_by_joinable'
+ t.index ['member_id'], name: 'person_community_membership_by_member'
+ t.index ['role_id'], name: 'person_community_membership_by_role'
+ end
+
+ create_table 'better_together_person_platform_integrations', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'provider', limit: 50, default: '', null: false
+ t.string 'uid', limit: 50, default: '', null: false
+ t.string 'name'
+ t.string 'handle'
+ t.string 'profile_url'
+ t.string 'image_url'
+ t.string 'access_token'
+ t.string 'access_token_secret'
+ t.string 'refresh_token'
+ t.datetime 'expires_at'
+ t.jsonb 'auth'
+ t.uuid 'person_id'
+ t.uuid 'platform_id'
+ t.uuid 'user_id'
+ t.index ['person_id'], name: 'bt_person_platform_conections_by_person'
+ t.index ['platform_id'], name: 'bt_person_platform_conections_by_platform'
+ t.index ['user_id'], name: 'bt_person_platform_conections_by_user'
+ end
+
+ create_table 'better_together_person_platform_memberships', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'member_id', null: false
+ t.uuid 'joinable_id', null: false
+ t.uuid 'role_id', null: false
+ t.index %w[joinable_id member_id role_id], name: 'unique_person_platform_membership_member_role', unique: true
+ t.index ['joinable_id'], name: 'person_platform_membership_by_joinable'
+ t.index ['member_id'], name: 'person_platform_membership_by_member'
+ t.index ['role_id'], name: 'person_platform_membership_by_role'
+ end
+
+ create_table 'better_together_phone_numbers', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'number', null: false
+ t.string 'label', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.uuid 'contact_detail_id', null: false
+ t.boolean 'primary_flag', default: false, null: false
+ t.index %w[contact_detail_id primary_flag], name: 'index_bt_phone_numbers_on_contact_detail_id_and_primary',
+ unique: true, where: '(primary_flag IS TRUE)'
+ t.index ['contact_detail_id'], name: 'index_better_together_phone_numbers_on_contact_detail_id'
+ t.index ['privacy'], name: 'by_better_together_phone_numbers_privacy'
+ end
+
+ create_table 'better_together_places', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'community_id', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.uuid 'space_id', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.index ['community_id'], name: 'by_better_together_places_community'
+ t.index ['creator_id'], name: 'by_better_together_places_creator'
+ t.index ['identifier'], name: 'index_better_together_places_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_places_privacy'
+ t.index ['space_id'], name: 'index_better_together_places_on_space_id'
+ end
+
+ create_table 'better_together_platform_invitations', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'community_role_id', null: false
+ t.string 'invitee_email'
+ t.uuid 'invitable_id', null: false
+ t.uuid 'invitee_id'
+ t.uuid 'inviter_id', null: false
+ t.uuid 'platform_role_id'
+ t.string 'status', limit: 20, null: false
+ t.string 'locale', limit: 5, default: 'en', null: false
+ t.string 'token', limit: 24, null: false
+ t.datetime 'valid_from', null: false
+ t.datetime 'valid_until'
+ t.datetime 'last_sent'
+ t.datetime 'accepted_at'
+ t.string 'type', default: 'BetterTogether::PlatformInvitation', null: false
+ t.integer 'session_duration_mins', default: 30, null: false
+ t.index ['community_role_id'], name: 'platform_invitations_by_community_role'
+ t.index %w[invitable_id status], name: 'index_platform_invitations_on_invitable_id_and_status'
+ t.index ['invitable_id'], name: 'platform_invitations_by_invitable'
+ t.index %w[invitee_email invitable_id], name: 'idx_on_invitee_email_invitable_id_5a7d642388', unique: true
+ t.index ['invitee_email'], name: 'index_pending_invitations_on_invitee_email',
+ where: "((status)::text = 'pending'::text)"
+ t.index ['invitee_email'], name: 'platform_invitations_by_invitee_email'
+ t.index ['invitee_id'], name: 'platform_invitations_by_invitee'
+ t.index ['inviter_id'], name: 'platform_invitations_by_inviter'
+ t.index ['locale'], name: 'by_better_together_platform_invitations_locale'
+ t.index ['platform_role_id'], name: 'platform_invitations_by_platform_role'
+ t.index ['status'], name: 'platform_invitations_by_status'
+ t.index ['token'], name: 'platform_invitations_by_token', unique: true
+ t.index ['valid_from'], name: 'platform_invitations_by_valid_from'
+ t.index ['valid_until'], name: 'platform_invitations_by_valid_until'
+ end
+
+ create_table 'better_together_platforms', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'host', default: false, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'community_id', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.string 'url', null: false
+ t.string 'time_zone', null: false
+ t.jsonb 'settings', default: {}, null: false
+ t.index ['community_id'], name: 'by_platform_community'
+ t.index ['host'], name: 'index_better_together_platforms_on_host', unique: true, where: '(host IS TRUE)'
+ t.index ['identifier'], name: 'index_better_together_platforms_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_platform_privacy'
+ t.index ['url'], name: 'index_better_together_platforms_on_url', unique: true
+ end
+
+ create_table 'better_together_posts', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'type', default: 'BetterTogether::Post', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.datetime 'published_at'
+ t.uuid 'creator_id'
+ t.index ['creator_id'], name: 'by_better_together_posts_creator'
+ t.index ['identifier'], name: 'index_better_together_posts_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_posts_privacy'
+ t.index ['published_at'], name: 'by_post_publication_date'
+ end
+
+ create_table 'better_together_reports', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'reporter_id', null: false
+ t.uuid 'reportable_id', null: false
+ t.string 'reportable_type', null: false
+ t.text 'reason'
+ t.index ['reporter_id'], name: 'index_better_together_reports_on_reporter_id'
+ end
+
+ create_table 'better_together_resource_permissions', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.integer 'position', null: false
+ t.string 'resource_type', null: false
+ t.string 'action', null: false
+ t.string 'target', null: false
+ t.index ['identifier'], name: 'index_better_together_resource_permissions_on_identifier', unique: true
+ t.index %w[resource_type position], name: 'index_resource_permissions_on_resource_type_and_position',
+ unique: true
+ end
+
+ create_table 'better_together_role_resource_permissions', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'role_id', null: false
+ t.uuid 'resource_permission_id', null: false
+ t.index ['resource_permission_id'], name: 'role_resource_permissions_resource_permission'
+ t.index %w[role_id resource_permission_id], name: 'unique_role_resource_permission_index', unique: true
+ t.index ['role_id'], name: 'role_resource_permissions_role'
+ end
+
+ create_table 'better_together_roles', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.integer 'position', null: false
+ t.string 'resource_type', null: false
+ t.string 'type', default: 'BetterTogether::Role', null: false
+ t.index ['identifier'], name: 'index_better_together_roles_on_identifier', unique: true
+ t.index %w[resource_type position], name: 'index_roles_on_resource_type_and_position', unique: true
+ end
+
+ create_table 'better_together_social_media_accounts', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'platform', null: false
+ t.string 'handle', null: false
+ t.string 'url'
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.uuid 'contact_detail_id', null: false
+ t.index %w[contact_detail_id platform], name: 'index_bt_sma_on_contact_detail_and_platform', unique: true
+ t.index ['contact_detail_id'], name: 'idx_on_contact_detail_id_6380b64b3b'
+ t.index ['privacy'], name: 'by_better_together_social_media_accounts_privacy'
+ end
+
+ create_table 'better_together_uploads', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.string 'type', default: 'BetterTogether::Upload', null: false
+ t.index ['creator_id'], name: 'by_better_together_files_creator'
+ t.index ['identifier'], name: 'index_better_together_uploads_on_identifier', unique: true
+ t.index ['privacy'], name: 'by_better_together_files_privacy'
+ end
+
+ create_table 'better_together_users', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'email', default: '', null: false
+ t.string 'encrypted_password', default: '', null: false
+ t.string 'reset_password_token'
+ t.datetime 'reset_password_sent_at'
+ t.datetime 'remember_created_at'
+ t.integer 'sign_in_count', default: 0, null: false
+ t.datetime 'current_sign_in_at'
+ t.datetime 'last_sign_in_at'
+ t.string 'current_sign_in_ip'
+ t.string 'last_sign_in_ip'
+ t.string 'confirmation_token'
+ t.datetime 'confirmed_at'
+ t.datetime 'confirmation_sent_at'
+ t.string 'unconfirmed_email'
+ t.integer 'failed_attempts', default: 0, null: false
+ t.string 'unlock_token'
+ t.datetime 'locked_at'
+ t.index ['confirmation_token'], name: 'index_better_together_users_on_confirmation_token', unique: true
+ t.index ['email'], name: 'index_better_together_users_on_email', unique: true
+ t.index ['reset_password_token'], name: 'index_better_together_users_on_reset_password_token', unique: true
+ t.index ['unlock_token'], name: 'index_better_together_users_on_unlock_token', unique: true
+ end
+
+ create_table 'better_together_website_links', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'url', null: false
+ t.string 'label', null: false
+ t.string 'privacy', limit: 50, default: 'private', null: false
+ t.uuid 'contact_detail_id', null: false
+ t.index ['contact_detail_id'], name: 'index_better_together_website_links_on_contact_detail_id'
+ t.index ['privacy'], name: 'by_better_together_website_links_privacy'
+ end
+
+ create_table 'better_together_wizard_step_definitions', id: :uuid, default: lambda {
+ 'gen_random_uuid()'
+ }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.uuid 'wizard_id', null: false
+ t.string 'template'
+ t.string 'form_class'
+ t.string 'message', default: 'Please complete this next step.', null: false
+ t.integer 'step_number', null: false
+ t.index ['identifier'], name: 'index_better_together_wizard_step_definitions_on_identifier', unique: true
+ t.index %w[wizard_id step_number], name: 'index_wizard_step_definitions_on_wizard_id_and_step_number',
+ unique: true
+ t.index ['wizard_id'], name: 'by_step_definition_wizard'
+ end
+
+ create_table 'better_together_wizard_steps', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.uuid 'wizard_id', null: false
+ t.uuid 'wizard_step_definition_id', null: false
+ t.uuid 'creator_id'
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'completed', default: false
+ t.integer 'step_number', null: false
+ t.index ['creator_id'], name: 'by_step_creator'
+ t.index ['identifier'], name: 'by_step_identifier'
+ t.index %w[wizard_id identifier creator_id], name: 'index_unique_wizard_steps', unique: true,
+ where: '(completed IS FALSE)'
+ t.index %w[wizard_id step_number], name: 'index_wizard_steps_on_wizard_id_and_step_number'
+ t.index ['wizard_id'], name: 'by_step_wizard'
+ t.index ['wizard_step_definition_id'], name: 'by_step_wizard_step_definition'
+ end
+
+ create_table 'better_together_wizards', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'identifier', limit: 100, null: false
+ t.boolean 'protected', default: false, null: false
+ t.integer 'max_completions', default: 0, null: false
+ t.integer 'current_completions', default: 0, null: false
+ t.datetime 'first_completed_at'
+ t.datetime 'last_completed_at'
+ t.text 'success_message', default: 'Thank you. You have successfully completed the wizard', null: false
+ t.string 'success_path', default: '/', null: false
+ t.index ['identifier'], name: 'index_better_together_wizards_on_identifier', unique: true
+ end
+
+ create_table 'friendly_id_slugs', force: :cascade do |t|
+ t.string 'slug', null: false
+ t.uuid 'sluggable_id', null: false
+ t.string 'sluggable_type', null: false
+ t.string 'scope'
+ t.integer 'lock_version', default: 0, null: false
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'locale', null: false
+ t.index ['locale'], name: 'index_friendly_id_slugs_on_locale'
+ t.index %w[slug sluggable_type locale], name: 'index_friendly_id_slugs_on_slug_and_sluggable_type_and_locale'
+ t.index %w[slug sluggable_type scope locale], name: 'index_friendly_id_slugs_unique', unique: true
+ t.index %w[sluggable_type sluggable_id], name: 'by_sluggable'
+ end
+
+ create_table 'mobility_string_translations', force: :cascade do |t|
+ t.string 'locale', null: false
+ t.string 'key', null: false
+ t.string 'value'
+ t.string 'translatable_type'
+ t.uuid 'translatable_id'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index %w[translatable_id translatable_type key],
+ name: 'index_mobility_string_translations_on_translatable_attribute'
+ t.index %w[translatable_id translatable_type locale key],
+ name: 'index_mobility_string_translations_on_keys', unique: true
+ t.index %w[translatable_type key value locale], name: 'index_mobility_string_translations_on_query_keys'
+ end
+
+ create_table 'mobility_text_translations', force: :cascade do |t|
+ t.string 'locale', null: false
+ t.string 'key', null: false
+ t.text 'value'
+ t.string 'translatable_type'
+ t.uuid 'translatable_id'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index %w[translatable_id translatable_type key],
+ name: 'index_mobility_text_translations_on_translatable_attribute'
+ t.index %w[translatable_id translatable_type locale key],
+ name: 'index_mobility_text_translations_on_keys', unique: true
+ end
+
+ create_table 'noticed_events', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.string 'type'
+ t.string 'record_type'
+ t.uuid 'record_id'
+ t.jsonb 'params'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.integer 'notifications_count'
+ t.index %w[record_type record_id], name: 'index_noticed_events_on_record'
+ end
+
+ create_table 'noticed_notifications', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t|
+ t.string 'type'
+ t.uuid 'event_id', null: false
+ t.string 'recipient_type', null: false
+ t.uuid 'recipient_id', null: false
+ t.datetime 'read_at', precision: nil
+ t.datetime 'seen_at', precision: nil
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index ['event_id'], name: 'index_noticed_notifications_on_event_id'
+ t.index %w[recipient_type recipient_id], name: 'index_noticed_notifications_on_recipient'
+ end
+
+ add_foreign_key 'active_storage_attachments', 'active_storage_blobs', column: 'blob_id'
+ add_foreign_key 'active_storage_variant_records', 'active_storage_blobs', column: 'blob_id'
+ add_foreign_key 'better_together_addresses', 'better_together_contact_details', column: 'contact_detail_id'
+ add_foreign_key 'better_together_agreement_participants', 'better_together_agreements', column: 'agreement_id'
+ add_foreign_key 'better_together_agreement_participants', 'better_together_people', column: 'person_id'
+ add_foreign_key 'better_together_agreement_terms', 'better_together_agreements', column: 'agreement_id'
+ add_foreign_key 'better_together_agreements', 'better_together_pages', column: 'page_id'
+ add_foreign_key 'better_together_agreements', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_ai_log_translations', 'better_together_people', column: 'initiator_id'
+ add_foreign_key 'better_together_authorships', 'better_together_people', column: 'author_id'
+ add_foreign_key 'better_together_calendar_entries', 'better_together_calendars', column: 'calendar_id'
+ add_foreign_key 'better_together_calendar_entries', 'better_together_events', column: 'event_id'
+ add_foreign_key 'better_together_calendars', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_calendars', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_calls_for_interest', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_categorizations', 'better_together_categories', column: 'category_id'
+ add_foreign_key 'better_together_comments', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_communities', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_content_blocks', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_content_page_blocks', 'better_together_content_blocks', column: 'block_id'
+ add_foreign_key 'better_together_content_page_blocks', 'better_together_pages', column: 'page_id'
+ add_foreign_key 'better_together_content_platform_blocks', 'better_together_content_blocks', column: 'block_id'
+ add_foreign_key 'better_together_content_platform_blocks', 'better_together_platforms', column: 'platform_id'
+ add_foreign_key 'better_together_conversation_participants', 'better_together_conversations',
+ column: 'conversation_id'
+ add_foreign_key 'better_together_conversation_participants', 'better_together_people', column: 'person_id'
+ add_foreign_key 'better_together_conversations', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_email_addresses', 'better_together_contact_details', column: 'contact_detail_id'
+ add_foreign_key 'better_together_event_attendances', 'better_together_events', column: 'event_id'
+ add_foreign_key 'better_together_event_attendances', 'better_together_people', column: 'person_id'
+ add_foreign_key 'better_together_event_hosts', 'better_together_events', column: 'event_id'
+ add_foreign_key 'better_together_events', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_geography_continents', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_geography_countries', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_geography_country_continents', 'better_together_geography_continents',
+ column: 'continent_id'
+ add_foreign_key 'better_together_geography_country_continents', 'better_together_geography_countries',
+ column: 'country_id'
+ add_foreign_key 'better_together_geography_geospatial_spaces', 'better_together_geography_spaces', column: 'space_id'
+ add_foreign_key 'better_together_geography_locatable_locations', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_geography_maps', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_geography_region_settlements', 'better_together_geography_regions',
+ column: 'region_id'
+ add_foreign_key 'better_together_geography_region_settlements', 'better_together_geography_settlements',
+ column: 'settlement_id'
+ add_foreign_key 'better_together_geography_regions', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_geography_regions', 'better_together_geography_countries', column: 'country_id'
+ add_foreign_key 'better_together_geography_regions', 'better_together_geography_states', column: 'state_id'
+ add_foreign_key 'better_together_geography_settlements', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_geography_settlements', 'better_together_geography_countries', column: 'country_id'
+ add_foreign_key 'better_together_geography_settlements', 'better_together_geography_states', column: 'state_id'
+ add_foreign_key 'better_together_geography_spaces', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_geography_states', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_geography_states', 'better_together_geography_countries', column: 'country_id'
+ add_foreign_key 'better_together_infrastructure_building_connections', 'better_together_infrastructure_buildings',
+ column: 'building_id'
+ add_foreign_key 'better_together_infrastructure_buildings', 'better_together_addresses', column: 'address_id'
+ add_foreign_key 'better_together_infrastructure_buildings', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_infrastructure_buildings', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_infrastructure_floors', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_infrastructure_floors', 'better_together_infrastructure_buildings',
+ column: 'building_id'
+ add_foreign_key 'better_together_infrastructure_floors', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_infrastructure_rooms', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_infrastructure_rooms', 'better_together_infrastructure_floors', column: 'floor_id'
+ add_foreign_key 'better_together_infrastructure_rooms', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_invitations', 'better_together_roles', column: 'role_id'
+ add_foreign_key 'better_together_joatu_agreements', 'better_together_joatu_offers', column: 'offer_id'
+ add_foreign_key 'better_together_joatu_agreements', 'better_together_joatu_requests', column: 'request_id'
+ add_foreign_key 'better_together_joatu_offers', 'better_together_addresses', column: 'address_id'
+ add_foreign_key 'better_together_joatu_offers', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_joatu_requests', 'better_together_addresses', column: 'address_id'
+ add_foreign_key 'better_together_joatu_requests', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_joatu_response_links', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_messages', 'better_together_conversations', column: 'conversation_id'
+ add_foreign_key 'better_together_messages', 'better_together_people', column: 'sender_id'
+ add_foreign_key 'better_together_navigation_items', 'better_together_navigation_areas', column: 'navigation_area_id'
+ add_foreign_key 'better_together_navigation_items', 'better_together_navigation_items', column: 'parent_id'
+ add_foreign_key 'better_together_pages', 'better_together_navigation_areas', column: 'sidebar_nav_id'
+ add_foreign_key 'better_together_people', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_person_blocks', 'better_together_people', column: 'blocked_id'
+ add_foreign_key 'better_together_person_blocks', 'better_together_people', column: 'blocker_id'
+ add_foreign_key 'better_together_person_community_memberships', 'better_together_communities', column: 'joinable_id'
+ add_foreign_key 'better_together_person_community_memberships', 'better_together_people', column: 'member_id'
+ add_foreign_key 'better_together_person_community_memberships', 'better_together_roles', column: 'role_id'
+ add_foreign_key 'better_together_person_platform_integrations', 'better_together_people', column: 'person_id'
+ add_foreign_key 'better_together_person_platform_integrations', 'better_together_platforms', column: 'platform_id'
+ add_foreign_key 'better_together_person_platform_integrations', 'better_together_users', column: 'user_id'
+ add_foreign_key 'better_together_person_platform_memberships', 'better_together_people', column: 'member_id'
+ add_foreign_key 'better_together_person_platform_memberships', 'better_together_platforms', column: 'joinable_id'
+ add_foreign_key 'better_together_person_platform_memberships', 'better_together_roles', column: 'role_id'
+ add_foreign_key 'better_together_phone_numbers', 'better_together_contact_details', column: 'contact_detail_id'
+ add_foreign_key 'better_together_places', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_places', 'better_together_geography_spaces', column: 'space_id'
+ add_foreign_key 'better_together_places', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_platform_invitations', 'better_together_people', column: 'invitee_id'
+ add_foreign_key 'better_together_platform_invitations', 'better_together_people', column: 'inviter_id'
+ add_foreign_key 'better_together_platform_invitations', 'better_together_platforms', column: 'invitable_id'
+ add_foreign_key 'better_together_platform_invitations', 'better_together_roles', column: 'community_role_id'
+ add_foreign_key 'better_together_platform_invitations', 'better_together_roles', column: 'platform_role_id'
+ add_foreign_key 'better_together_platforms', 'better_together_communities', column: 'community_id'
+ add_foreign_key 'better_together_posts', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_reports', 'better_together_people', column: 'reporter_id'
+ add_foreign_key 'better_together_role_resource_permissions', 'better_together_resource_permissions',
+ column: 'resource_permission_id'
+ add_foreign_key 'better_together_role_resource_permissions', 'better_together_roles', column: 'role_id'
+ add_foreign_key 'better_together_social_media_accounts', 'better_together_contact_details',
+ column: 'contact_detail_id'
+ add_foreign_key 'better_together_uploads', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_website_links', 'better_together_contact_details', column: 'contact_detail_id'
+ add_foreign_key 'better_together_wizard_step_definitions', 'better_together_wizards', column: 'wizard_id'
+ add_foreign_key 'better_together_wizard_steps', 'better_together_people', column: 'creator_id'
+ add_foreign_key 'better_together_wizard_steps', 'better_together_wizard_step_definitions',
+ column: 'wizard_step_definition_id'
+ add_foreign_key 'better_together_wizard_steps', 'better_together_wizards', column: 'wizard_id'
end
diff --git a/spec/factories/better_together/people.rb b/spec/factories/better_together/people.rb
index 769866e94..7ca0fa51b 100644
--- a/spec/factories/better_together/people.rb
+++ b/spec/factories/better_together/people.rb
@@ -4,7 +4,8 @@
module BetterTogether
FactoryBot.define do
- factory :better_together_person, class: Person, aliases: %i[person inviter invitee creator author] do
+ factory 'better_together/person', class: Person,
+ aliases: %i[better_together_person person inviter invitee creator author] do
id { Faker::Internet.uuid }
name { Faker::Name.name }
description { Faker::Lorem.paragraph(sentence_count: 3) }
diff --git a/spec/factories/better_together/person_platform_integrations.rb b/spec/factories/better_together/person_platform_integrations.rb
new file mode 100644
index 000000000..c8b2bc895
--- /dev/null
+++ b/spec/factories/better_together/person_platform_integrations.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :better_together_person_platform_integration,
+ class: 'BetterTogether::PersonPlatformIntegration',
+ aliases: %i[person_platform_integration] do
+ provider { 'MyString' }
+ uid { 'MyString' }
+ access_token { 'MyString' }
+ access_token_secret { 'MyString' }
+ profile_url { 'MyString' }
+ user
+ person { user.person }
+ end
+end
diff --git a/spec/factories/better_together/seeds.rb b/spec/factories/better_together/seeds.rb
new file mode 100644
index 000000000..e7389c842
--- /dev/null
+++ b/spec/factories/better_together/seeds.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :better_together_seed, class: 'BetterTogether::Seed' do
+ id { SecureRandom.uuid }
+ version { '1.0' }
+ created_by { 'Better Together Solutions' }
+ seeded_at { Time.current }
+ description { 'This is a generic seed for testing purposes.' }
+
+ origin do
+ {
+ 'contributors' => [
+ { 'name' => 'Test Contributor', 'role' => 'Tester', 'contact' => 'test@example.com',
+ 'organization' => 'Test Org' }
+ ],
+ 'platforms' => [
+ { 'name' => 'Community Engine', 'version' => '1.0', 'url' => 'https://bebettertogether.ca' }
+ ],
+ 'license' => 'LGPLv3',
+ 'usage_notes' => 'This seed is for test purposes only.'
+ }
+ end
+
+ payload do
+ {
+ version: '1.0',
+ generic_data: {
+ name: 'Generic Seed',
+ description: 'This is a placeholder seed.'
+ }
+ }
+ end
+ end
+end
diff --git a/spec/factories/better_together/users.rb b/spec/factories/better_together/users.rb
index ac65cd73d..f988e97c0 100644
--- a/spec/factories/better_together/users.rb
+++ b/spec/factories/better_together/users.rb
@@ -30,5 +30,12 @@
)
end
end
+
+ before :create do |user|
+ user.build_person_identification(
+ agent: user,
+ identity: create(:person)
+ )
+ end
end
end
diff --git a/spec/factories/better_together/wizard_step_definitions.rb b/spec/factories/better_together/wizard_step_definitions.rb
index 540dbefd1..2c7f8e52b 100644
--- a/spec/factories/better_together/wizard_step_definitions.rb
+++ b/spec/factories/better_together/wizard_step_definitions.rb
@@ -3,9 +3,9 @@
# spec/factories/wizard_step_definitions.rb
FactoryBot.define do
- factory :better_together_wizard_step_definition,
+ factory 'better_together/wizard_step_definition',
class: 'BetterTogether::WizardStepDefinition',
- aliases: %i[wizard_step_definition] do
+ aliases: %i[better_together_wizard_step_definition wizard_step_definition] do
id { SecureRandom.uuid }
wizard { create(:wizard) }
name { Faker::Lorem.unique.sentence(word_count: 3) }
@@ -14,7 +14,7 @@
template { "template_#{Faker::Lorem.word}" }
form_class { "FormClass#{Faker::Lorem.word}" }
message { 'Please complete this next step.' }
- step_number { Faker::Number.unique.between(from: 1, to: 50) }
+ step_number { Faker::Number.unique.between(from: 1, to: 500) }
protected { Faker::Boolean.boolean }
end
end
diff --git a/spec/factories/better_together/wizard_steps.rb b/spec/factories/better_together/wizard_steps.rb
index a2c7c71dd..99b736830 100644
--- a/spec/factories/better_together/wizard_steps.rb
+++ b/spec/factories/better_together/wizard_steps.rb
@@ -3,9 +3,9 @@
# spec/factories/wizard_steps.rb
FactoryBot.define do
- factory :better_together_wizard_step,
+ factory 'better_together/wizard_step',
class: 'BetterTogether::WizardStep',
- aliases: %i[wizard_step] do
+ aliases: %i[better_together_wizard_step wizard_step] do
id { SecureRandom.uuid }
wizard_step_definition
wizard { wizard_step_definition.wizard }
diff --git a/spec/factories/better_together/wizards.rb b/spec/factories/better_together/wizards.rb
index 59faf9513..33e00c0e7 100644
--- a/spec/factories/better_together/wizards.rb
+++ b/spec/factories/better_together/wizards.rb
@@ -3,9 +3,9 @@
# spec/factories/wizards.rb
FactoryBot.define do
- factory :better_together_wizard,
+ factory 'better_together/wizard',
class: 'BetterTogether::Wizard',
- aliases: %i[wizard] do
+ aliases: %i[better_together_wizard wizard] do
id { SecureRandom.uuid }
name { Faker::Lorem.sentence(word_count: 3) }
identifier { name.parameterize }
diff --git a/spec/features/setup_wizard_spec.rb b/spec/features/setup_wizard_spec.rb
index 92830e721..b47568127 100644
--- a/spec/features/setup_wizard_spec.rb
+++ b/spec/features/setup_wizard_spec.rb
@@ -12,6 +12,9 @@
# Start at the root and verify redirection to the wizard
visit '/'
+ expect(current_path).to eq(better_together.home_page_path(locale: I18n.locale))
+
+ visit better_together.new_user_session_path(locale: I18n.locale)
expect(current_path).to eq(better_together.setup_wizard_step_platform_details_path(locale: I18n.locale))
expect(page).to have_content("Please configure your platform's details below")
diff --git a/spec/helpers/better_together/person_platform_integrations_helper_spec.rb b/spec/helpers/better_together/person_platform_integrations_helper_spec.rb
new file mode 100644
index 000000000..4e37ccc97
--- /dev/null
+++ b/spec/helpers/better_together/person_platform_integrations_helper_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+# Specs in this file have access to a helper object that includes
+# the BetterTogether::PersonPlatformIntegrationsHelper. For example:
+#
+# describe BetterTogether::PersonPlatformIntegrationsHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# expect(helper.concat_strings("this","that")).to eq("this that")
+# end
+# end
+# end
+RSpec.describe BetterTogether::PersonPlatformIntegrationsHelper do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/helpers/better_together/seeds_helper_spec.rb b/spec/helpers/better_together/seeds_helper_spec.rb
new file mode 100644
index 000000000..e81117d91
--- /dev/null
+++ b/spec/helpers/better_together/seeds_helper_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+# Specs in this file have access to a helper object that includes
+# the SeedsHelper. For example:
+#
+# describe SeedsHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# expect(helper.concat_strings("this","that")).to eq("this that")
+# end
+# end
+# end
+module BetterTogether
+ RSpec.describe SeedsHelper do
+ pending "add some examples to (or delete) #{__FILE__}"
+ end
+end
diff --git a/spec/models/better_together/person_platform_integration_spec.rb b/spec/models/better_together/person_platform_integration_spec.rb
new file mode 100644
index 000000000..3ad0127eb
--- /dev/null
+++ b/spec/models/better_together/person_platform_integration_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe BetterTogether::PersonPlatformIntegration do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/better_together/person_spec.rb b/spec/models/better_together/person_spec.rb
index 60e42167b..3e173fdcc 100644
--- a/spec/models/better_together/person_spec.rb
+++ b/spec/models/better_together/person_spec.rb
@@ -15,7 +15,8 @@ module BetterTogether
it_behaves_like 'a friendly slugged record'
it_behaves_like 'an identity'
it_behaves_like 'has_id'
- # it_behaves_like 'an author model'
+ it_behaves_like 'an author model'
+ it_behaves_like 'a seedable model'
describe 'ActiveModel validations' do
it { is_expected.to validate_presence_of(:name) }
diff --git a/spec/models/better_together/seed_spec.rb b/spec/models/better_together/seed_spec.rb
new file mode 100644
index 000000000..f2cbff92f
--- /dev/null
+++ b/spec/models/better_together/seed_spec.rb
@@ -0,0 +1,199 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe BetterTogether::Seed do
+ subject(:seed) { build(:better_together_seed) }
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:type) }
+ it { is_expected.to validate_presence_of(:version) }
+ it { is_expected.to validate_presence_of(:created_by) }
+ it { is_expected.to validate_presence_of(:seeded_at) }
+ it { is_expected.to validate_presence_of(:description) }
+ it { is_expected.to validate_presence_of(:origin) }
+ it { is_expected.to validate_presence_of(:payload) }
+ end
+
+ describe '#export' do
+ it 'returns the complete structured seed data' do
+ expect(seed.export.keys.first).to eq('better_together')
+ end
+ end
+
+ describe '#export_yaml' do
+ it 'generates valid YAML' do
+ yaml = seed.export_yaml
+ expect(yaml).to include('better_together')
+ end
+ end
+
+ it 'returns the contributors from origin' do
+ expect(seed.contributors.first['name']).to eq('Test Contributor')
+ end
+
+ it 'returns the platforms from origin' do
+ expect(seed.platforms.first['name']).to eq('Community Engine')
+ end
+
+ describe 'scopes' do
+ before do
+ create(:better_together_seed, identifier: 'generic_seed')
+ create(:better_together_seed, identifier: 'home_page', type: 'BetterTogether::Seed')
+ end
+
+ it 'filters by type' do
+ expect(described_class.by_type('BetterTogether::Seed').count).to eq(2)
+ end
+
+ it 'filters by identifier' do
+ expect(described_class.by_identifier('home_page').count).to eq(1)
+ end
+ end
+
+ # -------------------------------------------------------------------
+ # Specs for .load_seed
+ # -------------------------------------------------------------------
+ describe '.load_seed' do
+ let(:valid_seed_data) do
+ {
+ 'better_together' => {
+ 'version' => '1.0',
+ 'seed' => {
+ 'type' => 'BetterTogether::Seed',
+ 'identifier' => 'from_test',
+ 'created_by' => 'Test Creator',
+ 'created_at' => '2025-03-04T12:00:00Z',
+ 'description' => 'A seed from tests',
+ 'origin' => {
+ 'contributors' => [],
+ 'platforms' => [],
+ 'license' => 'LGPLv3',
+ 'usage_notes' => 'Test usage only.'
+ }
+ },
+ 'payload_key' => 'payload_value'
+ }
+ }
+ end
+
+ let(:file_path) { '/fake/absolute/path/host_setup_wizard.yml' }
+
+ before do
+ # Default everything to false/unset, override if needed
+ allow(File).to receive(:exist?).and_return(false)
+ allow(YAML).to receive(:load_file).and_call_original
+ end
+
+ context 'when the source is a direct file path' do
+ # rubocop:todo RSpec/NestedGroups
+ context 'and the file exists' do # rubocop:todo RSpec/ContextWording, RSpec/NestedGroups
+ # rubocop:enable RSpec/NestedGroups
+ before do
+ allow(File).to receive(:exist?).with(file_path).and_return(true)
+ allow(YAML).to receive(:load_file).with(file_path).and_return(valid_seed_data)
+ end
+
+ it 'imports the seed and returns a BetterTogether::Seed record' do # rubocop:todo RSpec/MultipleExpectations
+ result = described_class.load_seed(file_path)
+ expect(result).to be_a(described_class)
+ expect(result.identifier).to eq('from_test')
+ expect(result.payload[:payload_key]).to eq('payload_value')
+ end
+ end
+
+ # rubocop:todo RSpec/NestedGroups
+ context 'but the file does not exist' do # rubocop:todo RSpec/ContextWording, RSpec/NestedGroups
+ # rubocop:enable RSpec/NestedGroups
+ it 'falls back to namespace logic and raises an error' do
+ expect do
+ described_class.load_seed(file_path)
+ end.to raise_error(RuntimeError, /Seed file not found for/)
+ end
+ end
+
+ context 'when YAML loading raises an error' do # rubocop:todo RSpec/NestedGroups
+ before do
+ allow(File).to receive(:exist?).with(file_path).and_return(true)
+ allow(YAML).to receive(:load_file).with(file_path).and_raise(StandardError, 'Bad YAML')
+ end
+
+ it 'raises a descriptive error' do
+ expect do
+ described_class.load_seed(file_path)
+ end.to raise_error(RuntimeError, /Error loading seed from file.*Bad YAML/)
+ end
+ end
+ end
+
+ context 'when the source is a namespace' do
+ let(:namespace) { 'better_together/wizards/host_setup_wizard' }
+ let(:full_path) { Rails.root.join('config', 'seeds', "#{namespace}.yml").to_s }
+
+ # rubocop:todo RSpec/NestedGroups
+ context 'and the file exists' do # rubocop:todo RSpec/ContextWording, RSpec/NestedGroups
+ # rubocop:enable RSpec/NestedGroups
+ before do
+ allow(File).to receive(:exist?).with(namespace).and_return(false)
+ allow(File).to receive(:exist?).with(full_path).and_return(true)
+ allow(YAML).to receive(:load_file).with(full_path).and_return(valid_seed_data)
+ end
+
+ it 'imports the seed from the namespace path' do # rubocop:todo RSpec/MultipleExpectations
+ result = described_class.load_seed(namespace)
+ expect(result).to be_a(described_class)
+ expect(result.identifier).to eq('from_test')
+ end
+ end
+
+ # rubocop:todo RSpec/NestedGroups
+ context 'but the file does not exist' do # rubocop:todo RSpec/ContextWording, RSpec/NestedGroups
+ # rubocop:enable RSpec/NestedGroups
+ before do
+ allow(File).to receive(:exist?).with(namespace).and_return(false)
+ allow(File).to receive(:exist?).with(full_path).and_return(false)
+ end
+
+ it 'raises a file-not-found error' do
+ expect do
+ described_class.load_seed(namespace)
+ end.to raise_error(RuntimeError, /Seed file not found for/)
+ end
+ end
+
+ context 'when YAML loading raises an error' do # rubocop:todo RSpec/NestedGroups
+ before do
+ allow(File).to receive(:exist?).with(namespace).and_return(false)
+ allow(File).to receive(:exist?).with(full_path).and_return(true)
+ allow(YAML).to receive(:load_file).with(full_path).and_raise(StandardError, 'YAML parse error')
+ end
+
+ it 'raises a descriptive error' do
+ expect do
+ described_class.load_seed(namespace)
+ end.to raise_error(RuntimeError, /Error loading seed from namespace.*YAML parse error/)
+ end
+ end
+ end
+ end
+
+ # -------------------------------------------------------------------
+ # Specs for Active Storage attachment
+ # -------------------------------------------------------------------
+ describe 'Active Storage YAML attachment' do
+ let(:seed) do
+ # create a valid, persisted seed so that we can test the attachment
+ create(:better_together_seed)
+ end
+
+ it 'attaches a YAML file after creation' do # rubocop:todo RSpec/NoExpectationExample
+ # seed.reload # Ensures the record reloads from the DB after the commit callback
+ # expect(seed.yaml_file).to be_attached
+
+ # # Optional: Check content type and file content
+ # expect(seed.yaml_file.content_type).to eq('text/yaml')
+ # downloaded_data = seed.yaml_file.download
+ # expect(downloaded_data).to include('better_together')
+ end
+ end
+end
diff --git a/spec/models/better_together/wizard_spec.rb b/spec/models/better_together/wizard_spec.rb
index fcb2e60f2..d16ec4534 100644
--- a/spec/models/better_together/wizard_spec.rb
+++ b/spec/models/better_together/wizard_spec.rb
@@ -14,6 +14,8 @@ module BetterTogether
end
end
+ it_behaves_like 'a seedable model'
+
describe 'ActiveRecord associations' do
it { is_expected.to have_many(:wizard_step_definitions).dependent(:destroy) }
it { is_expected.to have_many(:wizard_steps).dependent(:destroy) }
diff --git a/spec/models/better_together/wizard_step_definition_spec.rb b/spec/models/better_together/wizard_step_definition_spec.rb
index 48d90443e..98d6a95de 100644
--- a/spec/models/better_together/wizard_step_definition_spec.rb
+++ b/spec/models/better_together/wizard_step_definition_spec.rb
@@ -16,6 +16,8 @@ module BetterTogether
end
end
+ it_behaves_like 'a seedable model'
+
describe 'ActiveRecord associations' do
it { is_expected.to belong_to(:wizard) }
it { is_expected.to have_many(:wizard_steps) }
diff --git a/spec/models/better_together/wizard_step_spec.rb b/spec/models/better_together/wizard_step_spec.rb
index 2c5c65064..fb587a130 100644
--- a/spec/models/better_together/wizard_step_spec.rb
+++ b/spec/models/better_together/wizard_step_spec.rb
@@ -16,6 +16,8 @@ module BetterTogether
end
end
+ it_behaves_like 'a seedable model'
+
describe 'ActiveRecord associations' do
# it { is_expected.to belong_to(:wizard) }
it {
diff --git a/spec/requests/better_together/person_platform_integrations_spec.rb b/spec/requests/better_together/person_platform_integrations_spec.rb
new file mode 100644
index 000000000..769d9ed3d
--- /dev/null
+++ b/spec/requests/better_together/person_platform_integrations_spec.rb
@@ -0,0 +1,154 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+# This spec was generated by rspec-rails when you ran the scaffold generator.
+# It demonstrates how one might use RSpec to test the controller code that
+# was generated by Rails when you ran the scaffold generator.
+#
+# It assumes that the implementation code is generated by the rails scaffold
+# generator. If you are using any extension libraries to generate different
+# controller code, this generated spec may or may not pass.
+#
+# It only uses APIs available in rails and/or rspec-rails. There are a number
+# of tools you can use to make these specs even more expressive, but we're
+# sticking to rails and rspec-rails APIs to keep things simple and stable.
+
+RSpec.describe '/better_together/authorizations' do
+ # This should return the minimal set of attributes required to create a valid
+ # BetterTogether::PersonPlatformIntegration. As you add validations to BetterTogether::PersonPlatformIntegration,
+ # be sure to adjust the attributes here as well.
+ let(:valid_attributes) do
+ skip('Add a hash of attributes valid for your model')
+ end
+
+ let(:invalid_attributes) do
+ skip('Add a hash of attributes invalid for your model')
+ end
+
+ describe 'GET /index' do # rubocop:todo RSpec/RepeatedExampleGroupBody
+ it 'renders a successful response' do # rubocop:todo RSpec/NoExpectationExample
+ # BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # get person_platform_integrations_url
+ # expect(response).to be_successful
+ end
+ end
+
+ describe 'GET /show' do # rubocop:todo RSpec/RepeatedExampleGroupBody
+ it 'renders a successful response' do # rubocop:todo RSpec/NoExpectationExample
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # get person_platform_integration_url(authorization)
+ # expect(response).to be_successful
+ end
+ end
+
+ describe 'GET /new' do # rubocop:todo RSpec/RepeatedExampleGroupBody
+ it 'renders a successful response' do # rubocop:todo RSpec/NoExpectationExample
+ # get new_person_platform_integration_url
+ # expect(response).to be_successful
+ end
+ end
+
+ describe 'GET /edit' do # rubocop:todo RSpec/RepeatedExampleGroupBody
+ it 'renders a successful response' do # rubocop:todo RSpec/NoExpectationExample
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # get edit_person_platform_integration_url(authorization)
+ # expect(response).to be_successful
+ end
+ end
+
+ describe 'POST /create' do
+ context 'with valid parameters' do
+ # rubocop:todo RSpec/RepeatedExample
+ it 'creates a new BetterTogether::PersonPlatformIntegration' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect do
+ # post person_platform_integrations_url, params: { person_platform_integration: valid_attributes }
+ # end.to change(BetterTogether::PersonPlatformIntegration, :count).by(1)
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'redirects to the created person_platform_integration' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # post person_platform_integrations_url, params: { person_platform_integration: valid_attributes }
+ # expect(response).to
+ # redirect_to(person_platform_integration_url(BetterTogether::PersonPlatformIntegration.last))
+ end
+ # rubocop:enable RSpec/RepeatedExample
+ end
+
+ context 'with invalid parameters' do
+ # rubocop:todo RSpec/RepeatedExample
+ it 'does not create a new BetterTogether::PersonPlatformIntegration' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect do
+ # post person_platform_integrations_url, params: { person_platform_integration: invalid_attributes }
+ # end.to change(BetterTogether::PersonPlatformIntegration, :count).by(0)
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ # rubocop:todo RSpec/NoExpectationExample
+ it "renders a response with 422 status (i.e. to display the 'new' template)" do
+ # post person_platform_integrations_url, params: { person_platform_integration: invalid_attributes }
+ # expect(response).to have_http_status(:unprocessable_entity)
+ end
+ # rubocop:enable RSpec/NoExpectationExample
+ # rubocop:enable RSpec/RepeatedExample
+ end
+ end
+
+ describe 'PATCH /update' do
+ context 'with valid parameters' do
+ let(:new_attributes) do
+ skip('Add a hash of attributes valid for your model')
+ end
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'updates the requested person_platform_integration' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # patch person_platform_integration_url(authorization), params: { person_platform_integration: new_attributes }
+ # authorization.reload
+ # skip('Add assertions for updated state')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'redirects to the person_platform_integration' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # patch person_platform_integration_url(authorization), params: { person_platform_integration: new_attributes }
+ # authorization.reload
+ # expect(response).to redirect_to(person_platform_integration_url(authorization))
+ end
+ # rubocop:enable RSpec/RepeatedExample
+ end
+
+ context 'with invalid parameters' do
+ # rubocop:todo RSpec/NoExpectationExample
+ it "renders a response with 422 status (i.e. to display the 'edit' template)" do
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # patch person_platform_integration_url(authorization),
+ # params: { person_platform_integration: invalid_attributes }
+ # expect(response).to have_http_status(:unprocessable_entity)
+ end
+ # rubocop:enable RSpec/NoExpectationExample
+ end
+ end
+
+ describe 'DELETE /destroy' do
+ # rubocop:todo RSpec/RepeatedExample
+ it 'destroys the requested person_platform_integration' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # expect do
+ # delete person_platform_integration_url(authorization)
+ # end.to change(BetterTogether::PersonPlatformIntegration, :count).by(-1)
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'redirects to the person_platform_integrations list' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # authorization = BetterTogether::PersonPlatformIntegration.create! valid_attributes
+ # delete person_platform_integration_url(authorization)
+ # expect(response).to redirect_to(person_platform_integrations_url)
+ end
+ # rubocop:enable RSpec/RepeatedExample
+ end
+end
diff --git a/spec/routing/better_together/person_platform_integrations_routing_spec.rb b/spec/routing/better_together/person_platform_integrations_routing_spec.rb
new file mode 100644
index 000000000..c1047e2a5
--- /dev/null
+++ b/spec/routing/better_together/person_platform_integrations_routing_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe BetterTogether::PersonPlatformIntegrationsController do
+ describe 'routing' do
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #index' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(get: '/better_together/authorizations').to route_to('better_together/authorizations#index')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #new' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(get: '/better_together/authorizations/new').to route_to('better_together/authorizations#new')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #show' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(get: '/better_together/authorizations/1').to route_to('better_together/authorizations#show', id: '1')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #edit' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(get: '/better_together/authorizations/1/edit').toroute_to('better_together/authorizations#edit', id: '1')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #create' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(post: '/better_together/authorizations').to route_to('better_together/authorizations#create')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #update via PUT' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(put: '/better_together/authorizations/1').to route_to('better_together/authorizations#update', id: '1')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #update via PATCH' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(patch: '/better_together/authorizations/1').to route_to('better_together/authorizations#update', id: '1')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+
+ # rubocop:todo RSpec/RepeatedExample
+ it 'routes to #destroy' do # rubocop:todo RSpec/NoExpectationExample, RSpec/RepeatedExample
+ # expect(delete: '/better_together/authorizations/1').toroute_to('better_together/authorizations#destroy',id: '1')
+ end
+ # rubocop:enable RSpec/RepeatedExample
+ end
+end
diff --git a/spec/support/shared_examples/a_seedable_model.rb b/spec/support/shared_examples/a_seedable_model.rb
new file mode 100644
index 000000000..40bb36bae
--- /dev/null
+++ b/spec/support/shared_examples/a_seedable_model.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a seedable model' do
+ it 'includes the Seedable concern' do
+ expect(described_class.ancestors).to include(BetterTogether::Seedable)
+ end
+
+ describe 'Seedable instance methods' do
+ # Use create(...) so the record is persisted in the test database
+ let(:record) { create(described_class.name.underscore.to_sym) }
+
+ it 'responds to #plant' do
+ expect(record).to respond_to(:plant)
+ end
+
+ it 'responds to #export_as_seed' do
+ expect(record).to respond_to(:export_as_seed)
+ end
+
+ it 'responds to #export_as_seed_yaml' do
+ expect(record).to respond_to(:export_as_seed_yaml)
+ end
+
+ describe '#export_as_seed' do
+ it 'returns a hash with the default root key' do
+ seed_hash = record.export_as_seed
+ expect(seed_hash.keys).to include(BetterTogether::Seed::DEFAULT_ROOT_KEY)
+ end
+
+ it 'includes the record data under :record (or your chosen key)' do
+ seed_hash = record.export_as_seed
+ root_key = seed_hash.keys.first
+ expect(seed_hash[root_key]).to have_key(:record)
+ end
+ end
+
+ describe '#export_as_seed_yaml' do
+ it 'returns a valid YAML string' do # rubocop:todo RSpec/MultipleExpectations
+ yaml_str = record.export_as_seed_yaml
+ expect(yaml_str).to be_a(String)
+ expect(yaml_str).to include(BetterTogether::Seed::DEFAULT_ROOT_KEY.to_s)
+ end
+ end
+ end
+
+ describe 'Seedable class methods' do
+ let(:records) { build_list(described_class.name.underscore.to_sym, 3) }
+
+ it 'responds to .export_collection_as_seed' do
+ expect(described_class).to respond_to(:export_collection_as_seed)
+ end
+
+ it 'responds to .export_collection_as_seed_yaml' do
+ expect(described_class).to respond_to(:export_collection_as_seed_yaml)
+ end
+
+ describe '.export_collection_as_seed' do
+ it 'returns a hash with the default root key' do
+ collection_hash = described_class.export_collection_as_seed(records)
+ expect(collection_hash.keys).to include(BetterTogether::Seed::DEFAULT_ROOT_KEY)
+ end
+
+ it 'includes an array of records under :records' do # rubocop:todo RSpec/MultipleExpectations
+ collection_hash = described_class.export_collection_as_seed(records)
+ root_key = collection_hash.keys.first
+ expect(collection_hash[root_key]).to have_key(:records)
+ expect(collection_hash[root_key][:records]).to be_an(Array)
+ expect(collection_hash[root_key][:records].size).to eq(records.size)
+ end
+ end
+
+ describe '.export_collection_as_seed_yaml' do
+ it 'returns a valid YAML string' do # rubocop:todo RSpec/MultipleExpectations
+ yaml_str = described_class.export_collection_as_seed_yaml(records)
+ expect(yaml_str).to be_a(String)
+ expect(yaml_str).to include(BetterTogether::Seed::DEFAULT_ROOT_KEY.to_s)
+ end
+ end
+ end
+end
diff --git a/spec/views/better_together/person_platform_integrations/edit.html.erb_spec.rb b/spec/views/better_together/person_platform_integrations/edit.html.erb_spec.rb
new file mode 100644
index 000000000..0ec7fbfd1
--- /dev/null
+++ b/spec/views/better_together/person_platform_integrations/edit.html.erb_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'better_together/authorizations/edit' do
+ let(:person_platform_integration) do
+ create(:person_platform_integration)
+ end
+
+ before do
+ assign(:person_platform_integration, person_platform_integration)
+ end
+
+ it 'renders the edit person_platform_integration form' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+
+ # assert_select 'form[action=?][method=?]', person_platform_integration_path(person_platform_integration), 'post' do
+ # assert_select 'input[name=?]', 'person_platform_integration[provider]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[uid]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[access_token]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[access_secret]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[profile_url]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[user_id]'
+ # assert_select 'input[name=?]', 'person_platform_integration[person_id]'
+ # end
+ end
+end
diff --git a/spec/views/better_together/person_platform_integrations/index.html.erb_spec.rb b/spec/views/better_together/person_platform_integrations/index.html.erb_spec.rb
new file mode 100644
index 000000000..2c2211363
--- /dev/null
+++ b/spec/views/better_together/person_platform_integrations/index.html.erb_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'better_together/authorizations/index' do
+ before do
+ assign(:person_platform_integrations, create_list(:person_platform_integration, 3))
+ end
+
+ it 'renders a list of better_together/authorizations' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+ # cell_selector = Rails::VERSION::STRING >= '7' ? 'div>p' : 'tr>td'
+ # assert_select cell_selector, text: Regexp.new('Provider'.to_s), count: 2
+ # assert_select cell_selector, text: Regexp.new('Uid'.to_s), count: 2
+ # assert_select cell_selector, text: Regexp.new('Token'.to_s), count: 2
+ # assert_select cell_selector, text: Regexp.new('Secret'.to_s), count: 2
+ # assert_select cell_selector, text: Regexp.new('Profile Url'.to_s), count: 2
+ # assert_select cell_selector, text: Regexp.new(nil.to_s), count: 2
+ end
+end
diff --git a/spec/views/better_together/person_platform_integrations/new.html.erb_spec.rb b/spec/views/better_together/person_platform_integrations/new.html.erb_spec.rb
new file mode 100644
index 000000000..ea22b1842
--- /dev/null
+++ b/spec/views/better_together/person_platform_integrations/new.html.erb_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'better_together/authorizations/new' do
+ before do
+ assign(:person_platform_integration, create(:person_platform_integration))
+ end
+
+ it 'renders new person_platform_integration form' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+
+ # assert_select 'form[action=?][method=?]', person_platform_integrations_path, 'post' do
+ # assert_select 'input[name=?]', 'person_platform_integration[provider]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[uid]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[token]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[secret]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[profile_url]'
+
+ # assert_select 'input[name=?]', 'person_platform_integration[user_id]'
+ # end
+ end
+end
diff --git a/spec/views/better_together/person_platform_integrations/show.html.erb_spec.rb b/spec/views/better_together/person_platform_integrations/show.html.erb_spec.rb
new file mode 100644
index 000000000..2102b8627
--- /dev/null
+++ b/spec/views/better_together/person_platform_integrations/show.html.erb_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'better_together/authorizations/show' do
+ before do
+ assign(:person_platform_integration, create(:person_platform_integration))
+ end
+
+ it 'renders attributes in
' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+ # expect(rendered).to match(/Provider/)
+ # expect(rendered).to match(/Uid/)
+ # expect(rendered).to match(/Token/)
+ # expect(rendered).to match(/Secret/)
+ # expect(rendered).to match(/Profile Url/)
+ # expect(rendered).to match(//)
+ end
+end
diff --git a/spec/views/better_together/seeds/edit.html.erb_spec.rb b/spec/views/better_together/seeds/edit.html.erb_spec.rb
new file mode 100644
index 000000000..453c336b5
--- /dev/null
+++ b/spec/views/better_together/seeds/edit.html.erb_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'seeds/edit' do
+ let(:seed) do
+ create(:better_together_seed)
+ end
+
+ before do
+ assign(:seed, seed)
+ end
+
+ it 'renders the edit seed form' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+
+ # assert_select "form[action=?][method=?]", seed_path(seed), "post" do
+ # end
+ end
+end
diff --git a/spec/views/better_together/seeds/index.html.erb_spec.rb b/spec/views/better_together/seeds/index.html.erb_spec.rb
new file mode 100644
index 000000000..52f2ca336
--- /dev/null
+++ b/spec/views/better_together/seeds/index.html.erb_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'seeds/index' do
+ before do
+ assign(:seeds, [
+ create(:better_together_seed),
+ create(:better_together_seed)
+ ])
+ end
+
+ it 'renders a list of seeds' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+ # cell_selector = 'div>p'
+ end
+end
diff --git a/spec/views/better_together/seeds/new.html.erb_spec.rb b/spec/views/better_together/seeds/new.html.erb_spec.rb
new file mode 100644
index 000000000..c95369385
--- /dev/null
+++ b/spec/views/better_together/seeds/new.html.erb_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'seeds/new' do
+ before do
+ assign(:seed, build(:better_together_seed))
+ end
+
+ it 'renders new seed form' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+
+ # assert_select "form[action=?][method=?]", seeds_path, "post" do
+ # end
+ end
+end
diff --git a/spec/views/better_together/seeds/show.html.erb_spec.rb b/spec/views/better_together/seeds/show.html.erb_spec.rb
new file mode 100644
index 000000000..b87226fcb
--- /dev/null
+++ b/spec/views/better_together/seeds/show.html.erb_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'seeds/show' do
+ before do
+ assign(:seed, create(:better_together_seed))
+ end
+
+ it 'renders attributes in
' do # rubocop:todo RSpec/NoExpectationExample
+ # render
+ end
+end