Moving to github

This commit is contained in:
2026-03-28 19:24:29 -04:00
commit 036fa7ab33
302 changed files with 17838 additions and 0 deletions

11
db/cable_schema.rb Normal file
View File

@@ -0,0 +1,11 @@
ActiveRecord::Schema[7.1].define(version: 1) do
create_table "solid_cable_messages", force: :cascade do |t|
t.binary "channel", limit: 1024, null: false
t.binary "payload", limit: 536870912, null: false
t.datetime "created_at", null: false
t.integer "channel_hash", limit: 8, null: false
t.index ["channel"], name: "index_solid_cable_messages_on_channel"
t.index ["channel_hash"], name: "index_solid_cable_messages_on_channel_hash"
t.index ["created_at"], name: "index_solid_cable_messages_on_created_at"
end
end

12
db/cache_schema.rb Normal file
View File

@@ -0,0 +1,12 @@
ActiveRecord::Schema[7.2].define(version: 1) do
create_table "solid_cache_entries", force: :cascade do |t|
t.binary "key", limit: 1024, null: false
t.binary "value", limit: 536870912, null: false
t.datetime "created_at", null: false
t.integer "key_hash", limit: 8, null: false
t.integer "byte_size", limit: 4, null: false
t.index ["byte_size"], name: "index_solid_cache_entries_on_byte_size"
t.index ["key_hash", "byte_size"], name: "index_solid_cache_entries_on_key_hash_and_byte_size"
t.index ["key_hash"], name: "index_solid_cache_entries_on_key_hash", unique: true
end
end

View File

@@ -0,0 +1,29 @@
class CreateUsers < ActiveRecord::Migration[8.1]
def change
create_table :users do |t|
t.string :email, null: false
t.string :username, null: false
t.string :password_digest, null: false
t.text :bio
t.boolean :profile_public, default: false, null: false
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :username, unique: true
# Enable Row Level Security
enable_rls_on :users
end
private
def enable_rls_on(table_name)
execute <<-SQL
ALTER TABLE #{table_name} ENABLE ROW LEVEL SECURITY;
CREATE POLICY #{table_name}_isolation_policy ON #{table_name}
USING (id = current_setting('app.current_user_id', true)::bigint);
SQL
end
end

View File

@@ -0,0 +1,12 @@
class CreatePlatforms < ActiveRecord::Migration[8.1]
def change
create_table :platforms do |t|
t.string :name, null: false
t.string :abbreviation
t.string :manufacturer
t.timestamps
end
add_index :platforms, :name, unique: true
end
end

View File

@@ -0,0 +1,10 @@
class CreateGenres < ActiveRecord::Migration[8.1]
def change
create_table :genres do |t|
t.string :name, null: false
t.timestamps
end
add_index :genres, :name, unique: true
end
end

View File

@@ -0,0 +1,22 @@
class CreateApiTokens < ActiveRecord::Migration[8.1]
def change
create_table :api_tokens do |t|
t.references :user, null: false, foreign_key: true, index: true
t.string :token, null: false
t.string :name
t.datetime :last_used_at
t.datetime :expires_at
t.timestamps
end
add_index :api_tokens, :token, unique: true
# Enable Row Level Security
execute <<-SQL
ALTER TABLE api_tokens ENABLE ROW LEVEL SECURITY;
CREATE POLICY api_tokens_isolation_policy ON api_tokens
USING (user_id = current_setting('app.current_user_id', true)::bigint);
SQL
end
end

View File

@@ -0,0 +1,33 @@
class CreateGames < ActiveRecord::Migration[8.1]
def change
create_table :games do |t|
t.references :user, null: false, foreign_key: true, index: true
t.references :platform, null: false, foreign_key: true, index: true
t.string :title, null: false
t.string :format, null: false
t.date :date_added, null: false
t.string :completion_status
t.integer :user_rating
t.text :notes
t.string :condition
t.decimal :price_paid, precision: 10, scale: 2
t.string :location
t.string :digital_store
t.boolean :custom_entry, default: false, null: false
t.integer :igdb_id
t.timestamps
end
add_index :games, :title
add_index :games, :igdb_id
# Enable Row Level Security
execute <<-SQL
ALTER TABLE games ENABLE ROW LEVEL SECURITY;
CREATE POLICY games_isolation_policy ON games
USING (user_id = current_setting('app.current_user_id', true)::bigint);
SQL
end
end

View File

@@ -0,0 +1,12 @@
class CreateGameGenres < ActiveRecord::Migration[8.1]
def change
create_table :game_genres do |t|
t.references :game, null: false, foreign_key: true, index: true
t.references :genre, null: false, foreign_key: true, index: true
t.timestamps
end
add_index :game_genres, [ :game_id, :genre_id ], unique: true
end
end

View File

@@ -0,0 +1,23 @@
class CreateCollections < ActiveRecord::Migration[8.1]
def change
create_table :collections do |t|
t.references :user, null: false, foreign_key: true, index: true
t.string :name, null: false
t.text :description
t.integer :parent_collection_id
t.timestamps
end
add_index :collections, :parent_collection_id
add_foreign_key :collections, :collections, column: :parent_collection_id
# Enable Row Level Security
execute <<-SQL
ALTER TABLE collections ENABLE ROW LEVEL SECURITY;
CREATE POLICY collections_isolation_policy ON collections
USING (user_id = current_setting('app.current_user_id', true)::bigint);
SQL
end
end

View File

@@ -0,0 +1,13 @@
class CreateCollectionGames < ActiveRecord::Migration[8.1]
def change
create_table :collection_games do |t|
t.references :collection, null: false, foreign_key: true, index: true
t.references :game, null: false, foreign_key: true, index: true
t.integer :position
t.timestamps
end
add_index :collection_games, [ :collection_id, :game_id ], unique: true
end
end

View File

@@ -0,0 +1,28 @@
class CreateItems < ActiveRecord::Migration[8.1]
def change
create_table :items do |t|
t.references :user, null: false, foreign_key: true, index: true
t.string :name, null: false
t.string :item_type, null: false
t.references :platform, foreign_key: true, index: true
t.string :condition
t.decimal :price_paid, precision: 10, scale: 2
t.string :location
t.date :date_added, null: false
t.text :notes
t.integer :igdb_id
t.timestamps
end
add_index :items, :igdb_id
# Enable Row Level Security
execute <<-SQL
ALTER TABLE items ENABLE ROW LEVEL SECURITY;
CREATE POLICY items_isolation_policy ON items
USING (user_id = current_setting('app.current_user_id', true)::bigint);
SQL
end
end

View File

@@ -0,0 +1,6 @@
class AddPasswordResetToUsers < ActiveRecord::Migration[8.1]
def change
add_column :users, :password_reset_token, :string
add_column :users, :password_reset_sent_at, :datetime
end
end

View File

@@ -0,0 +1,5 @@
class RenameEncryptedPasswordToPasswordDigest < ActiveRecord::Migration[8.1]
def change
rename_column :users, :encrypted_password, :password_digest
end
end

View File

@@ -0,0 +1,20 @@
class CreateIgdbGames < ActiveRecord::Migration[8.1]
def change
create_table :igdb_games do |t|
t.bigint :igdb_id, null: false
t.string :name, null: false
t.string :slug
t.string :cover_url
t.text :summary
t.date :first_release_date
t.integer :match_count, default: 0, null: false
t.datetime :last_synced_at
t.timestamps
end
add_index :igdb_games, :igdb_id, unique: true
add_index :igdb_games, :name
add_index :igdb_games, :slug
end
end

View File

@@ -0,0 +1,14 @@
class CreateIgdbPlatformMappings < ActiveRecord::Migration[8.1]
def change
create_table :igdb_platform_mappings do |t|
t.references :platform, null: false, foreign_key: true, index: true
t.integer :igdb_platform_id, null: false
t.string :igdb_platform_name
t.timestamps
end
add_index :igdb_platform_mappings, :igdb_platform_id
add_index :igdb_platform_mappings, [ :platform_id, :igdb_platform_id ], unique: true, name: 'index_platform_mappings_unique'
end
end

View File

@@ -0,0 +1,8 @@
class AddIgdbSyncToUsers < ActiveRecord::Migration[8.1]
def change
add_column :users, :igdb_sync_enabled, :boolean, default: false, null: false
add_column :users, :igdb_last_synced_at, :datetime
add_index :users, :igdb_sync_enabled
end
end

View File

@@ -0,0 +1,9 @@
class AddIgdbMatchingToGames < ActiveRecord::Migration[8.1]
def change
add_column :games, :igdb_matched_at, :datetime
add_column :games, :igdb_match_status, :string
add_column :games, :igdb_match_confidence, :decimal, precision: 5, scale: 2
add_index :games, :igdb_match_status
end
end

View File

@@ -0,0 +1,22 @@
class CreateIgdbMatchSuggestions < ActiveRecord::Migration[8.1]
def change
create_table :igdb_match_suggestions do |t|
t.references :game, null: false, foreign_key: true, index: true
t.references :igdb_game, foreign_key: true, index: true
t.bigint :igdb_id, null: false
t.string :igdb_name, null: false
t.string :igdb_slug
t.string :igdb_cover_url
t.date :igdb_release_date
t.string :igdb_platform_name
t.decimal :confidence_score, precision: 5, scale: 2
t.string :status, default: 'pending', null: false # pending, approved, rejected
t.datetime :reviewed_at
t.timestamps
end
add_index :igdb_match_suggestions, :status
add_index :igdb_match_suggestions, [ :game_id, :igdb_id ], unique: true
end
end

View File

@@ -0,0 +1,5 @@
class AddSummaryToIgdbMatchSuggestions < ActiveRecord::Migration[8.1]
def change
add_column :igdb_match_suggestions, :igdb_summary, :text
end
end

View File

@@ -0,0 +1,5 @@
class AddGenresToIgdbMatchSuggestions < ActiveRecord::Migration[8.1]
def change
add_column :igdb_match_suggestions, :igdb_genres, :text, array: true, default: []
end
end

View File

@@ -0,0 +1,5 @@
class ChangeIgdbSyncEnabledDefaultToTrue < ActiveRecord::Migration[8.1]
def change
change_column_default :users, :igdb_sync_enabled, from: false, to: true
end
end

View File

@@ -0,0 +1,6 @@
class AddThemeToUsers < ActiveRecord::Migration[8.1]
def change
add_column :users, :theme, :string, default: "light", null: false
add_index :users, :theme
end
end

129
db/queue_schema.rb Normal file
View File

@@ -0,0 +1,129 @@
ActiveRecord::Schema[7.1].define(version: 1) do
create_table "solid_queue_blocked_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.string "concurrency_key", null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.index [ "concurrency_key", "priority", "job_id" ], name: "index_solid_queue_blocked_executions_for_release"
t.index [ "expires_at", "concurrency_key" ], name: "index_solid_queue_blocked_executions_for_maintenance"
t.index [ "job_id" ], name: "index_solid_queue_blocked_executions_on_job_id", unique: true
end
create_table "solid_queue_claimed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.bigint "process_id"
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_claimed_executions_on_job_id", unique: true
t.index [ "process_id", "job_id" ], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id"
end
create_table "solid_queue_failed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.text "error"
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_failed_executions_on_job_id", unique: true
end
create_table "solid_queue_jobs", force: :cascade do |t|
t.string "queue_name", null: false
t.string "class_name", null: false
t.text "arguments"
t.integer "priority", default: 0, null: false
t.string "active_job_id"
t.datetime "scheduled_at"
t.datetime "finished_at"
t.string "concurrency_key"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index [ "active_job_id" ], name: "index_solid_queue_jobs_on_active_job_id"
t.index [ "class_name" ], name: "index_solid_queue_jobs_on_class_name"
t.index [ "finished_at" ], name: "index_solid_queue_jobs_on_finished_at"
t.index [ "queue_name", "finished_at" ], name: "index_solid_queue_jobs_for_filtering"
t.index [ "scheduled_at", "finished_at" ], name: "index_solid_queue_jobs_for_alerting"
end
create_table "solid_queue_pauses", force: :cascade do |t|
t.string "queue_name", null: false
t.datetime "created_at", null: false
t.index [ "queue_name" ], name: "index_solid_queue_pauses_on_queue_name", unique: true
end
create_table "solid_queue_processes", force: :cascade do |t|
t.string "kind", null: false
t.datetime "last_heartbeat_at", null: false
t.bigint "supervisor_id"
t.integer "pid", null: false
t.string "hostname"
t.text "metadata"
t.datetime "created_at", null: false
t.string "name", null: false
t.index [ "last_heartbeat_at" ], name: "index_solid_queue_processes_on_last_heartbeat_at"
t.index [ "name", "supervisor_id" ], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true
t.index [ "supervisor_id" ], name: "index_solid_queue_processes_on_supervisor_id"
end
create_table "solid_queue_ready_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_ready_executions_on_job_id", unique: true
t.index [ "priority", "job_id" ], name: "index_solid_queue_poll_all"
t.index [ "queue_name", "priority", "job_id" ], name: "index_solid_queue_poll_by_queue"
end
create_table "solid_queue_recurring_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "task_key", null: false
t.datetime "run_at", null: false
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_recurring_executions_on_job_id", unique: true
t.index [ "task_key", "run_at" ], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true
end
create_table "solid_queue_recurring_tasks", force: :cascade do |t|
t.string "key", null: false
t.string "schedule", null: false
t.string "command", limit: 2048
t.string "class_name"
t.text "arguments"
t.string "queue_name"
t.integer "priority", default: 0
t.boolean "static", default: true, null: false
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index [ "key" ], name: "index_solid_queue_recurring_tasks_on_key", unique: true
t.index [ "static" ], name: "index_solid_queue_recurring_tasks_on_static"
end
create_table "solid_queue_scheduled_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "scheduled_at", null: false
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true
t.index [ "scheduled_at", "priority", "job_id" ], name: "index_solid_queue_dispatch_all"
end
create_table "solid_queue_semaphores", force: :cascade do |t|
t.string "key", null: false
t.integer "value", default: 1, null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index [ "expires_at" ], name: "index_solid_queue_semaphores_on_expires_at"
t.index [ "key", "value" ], name: "index_solid_queue_semaphores_on_key_and_value"
t.index [ "key" ], name: "index_solid_queue_semaphores_on_key", unique: true
end
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
end

331
db/schema.rb generated Normal file
View File

@@ -0,0 +1,331 @@
# 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.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.1].define(version: 2026_03_28_222034) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"
create_table "api_tokens", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "expires_at"
t.datetime "last_used_at"
t.string "name"
t.string "token", null: false
t.datetime "updated_at", null: false
t.bigint "user_id", null: false
t.index ["token"], name: "index_api_tokens_on_token", unique: true
t.index ["user_id"], name: "index_api_tokens_on_user_id"
end
create_table "collection_games", force: :cascade do |t|
t.bigint "collection_id", null: false
t.datetime "created_at", null: false
t.bigint "game_id", null: false
t.integer "position"
t.datetime "updated_at", null: false
t.index ["collection_id", "game_id"], name: "index_collection_games_on_collection_id_and_game_id", unique: true
t.index ["collection_id"], name: "index_collection_games_on_collection_id"
t.index ["game_id"], name: "index_collection_games_on_game_id"
end
create_table "collections", force: :cascade do |t|
t.datetime "created_at", null: false
t.text "description"
t.string "name", null: false
t.integer "parent_collection_id"
t.datetime "updated_at", null: false
t.bigint "user_id", null: false
t.index ["parent_collection_id"], name: "index_collections_on_parent_collection_id"
t.index ["user_id"], name: "index_collections_on_user_id"
end
create_table "game_genres", force: :cascade do |t|
t.datetime "created_at", null: false
t.bigint "game_id", null: false
t.bigint "genre_id", null: false
t.datetime "updated_at", null: false
t.index ["game_id", "genre_id"], name: "index_game_genres_on_game_id_and_genre_id", unique: true
t.index ["game_id"], name: "index_game_genres_on_game_id"
t.index ["genre_id"], name: "index_game_genres_on_genre_id"
end
create_table "games", force: :cascade do |t|
t.string "completion_status"
t.string "condition"
t.datetime "created_at", null: false
t.boolean "custom_entry", default: false, null: false
t.date "date_added", null: false
t.string "digital_store"
t.string "format", null: false
t.integer "igdb_id"
t.decimal "igdb_match_confidence", precision: 5, scale: 2
t.string "igdb_match_status"
t.datetime "igdb_matched_at"
t.string "location"
t.text "notes"
t.bigint "platform_id", null: false
t.decimal "price_paid", precision: 10, scale: 2
t.string "title", null: false
t.datetime "updated_at", null: false
t.bigint "user_id", null: false
t.integer "user_rating"
t.index ["igdb_id"], name: "index_games_on_igdb_id"
t.index ["igdb_match_status"], name: "index_games_on_igdb_match_status"
t.index ["platform_id"], name: "index_games_on_platform_id"
t.index ["title"], name: "index_games_on_title"
t.index ["user_id"], name: "index_games_on_user_id"
end
create_table "genres", force: :cascade do |t|
t.datetime "created_at", null: false
t.string "name", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_genres_on_name", unique: true
end
create_table "igdb_games", force: :cascade do |t|
t.string "cover_url"
t.datetime "created_at", null: false
t.date "first_release_date"
t.bigint "igdb_id", null: false
t.datetime "last_synced_at"
t.integer "match_count", default: 0, null: false
t.string "name", null: false
t.string "slug"
t.text "summary"
t.datetime "updated_at", null: false
t.index ["igdb_id"], name: "index_igdb_games_on_igdb_id", unique: true
t.index ["name"], name: "index_igdb_games_on_name"
t.index ["slug"], name: "index_igdb_games_on_slug"
end
create_table "igdb_match_suggestions", force: :cascade do |t|
t.decimal "confidence_score", precision: 5, scale: 2
t.datetime "created_at", null: false
t.bigint "game_id", null: false
t.string "igdb_cover_url"
t.bigint "igdb_game_id"
t.text "igdb_genres", default: [], array: true
t.bigint "igdb_id", null: false
t.string "igdb_name", null: false
t.string "igdb_platform_name"
t.date "igdb_release_date"
t.string "igdb_slug"
t.text "igdb_summary"
t.datetime "reviewed_at"
t.string "status", default: "pending", null: false
t.datetime "updated_at", null: false
t.index ["game_id", "igdb_id"], name: "index_igdb_match_suggestions_on_game_id_and_igdb_id", unique: true
t.index ["game_id"], name: "index_igdb_match_suggestions_on_game_id"
t.index ["igdb_game_id"], name: "index_igdb_match_suggestions_on_igdb_game_id"
t.index ["status"], name: "index_igdb_match_suggestions_on_status"
end
create_table "igdb_platform_mappings", force: :cascade do |t|
t.datetime "created_at", null: false
t.integer "igdb_platform_id", null: false
t.string "igdb_platform_name"
t.bigint "platform_id", null: false
t.datetime "updated_at", null: false
t.index ["igdb_platform_id"], name: "index_igdb_platform_mappings_on_igdb_platform_id"
t.index ["platform_id", "igdb_platform_id"], name: "index_platform_mappings_unique", unique: true
t.index ["platform_id"], name: "index_igdb_platform_mappings_on_platform_id"
end
create_table "items", force: :cascade do |t|
t.string "condition"
t.datetime "created_at", null: false
t.date "date_added", null: false
t.integer "igdb_id"
t.string "item_type", null: false
t.string "location"
t.string "name", null: false
t.text "notes"
t.bigint "platform_id"
t.decimal "price_paid", precision: 10, scale: 2
t.datetime "updated_at", null: false
t.bigint "user_id", null: false
t.index ["igdb_id"], name: "index_items_on_igdb_id"
t.index ["platform_id"], name: "index_items_on_platform_id"
t.index ["user_id"], name: "index_items_on_user_id"
end
create_table "platforms", force: :cascade do |t|
t.string "abbreviation"
t.datetime "created_at", null: false
t.string "manufacturer"
t.string "name", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_platforms_on_name", unique: true
end
create_table "solid_queue_blocked_executions", force: :cascade do |t|
t.string "concurrency_key", null: false
t.datetime "created_at", null: false
t.datetime "expires_at", null: false
t.bigint "job_id", null: false
t.integer "priority", default: 0, null: false
t.string "queue_name", null: false
t.index ["concurrency_key", "priority", "job_id"], name: "index_solid_queue_blocked_executions_for_release"
t.index ["expires_at", "concurrency_key"], name: "index_solid_queue_blocked_executions_for_maintenance"
t.index ["job_id"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true
end
create_table "solid_queue_claimed_executions", force: :cascade do |t|
t.datetime "created_at", null: false
t.bigint "job_id", null: false
t.bigint "process_id"
t.index ["job_id"], name: "index_solid_queue_claimed_executions_on_job_id", unique: true
t.index ["process_id", "job_id"], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id"
end
create_table "solid_queue_failed_executions", force: :cascade do |t|
t.datetime "created_at", null: false
t.text "error"
t.bigint "job_id", null: false
t.index ["job_id"], name: "index_solid_queue_failed_executions_on_job_id", unique: true
end
create_table "solid_queue_jobs", force: :cascade do |t|
t.string "active_job_id"
t.text "arguments"
t.string "class_name", null: false
t.string "concurrency_key"
t.datetime "created_at", null: false
t.datetime "finished_at"
t.integer "priority", default: 0, null: false
t.string "queue_name", null: false
t.datetime "scheduled_at"
t.datetime "updated_at", null: false
t.index ["active_job_id"], name: "index_solid_queue_jobs_on_active_job_id"
t.index ["class_name"], name: "index_solid_queue_jobs_on_class_name"
t.index ["finished_at"], name: "index_solid_queue_jobs_on_finished_at"
t.index ["queue_name", "finished_at"], name: "index_solid_queue_jobs_for_filtering"
t.index ["scheduled_at", "finished_at"], name: "index_solid_queue_jobs_for_alerting"
end
create_table "solid_queue_pauses", force: :cascade do |t|
t.datetime "created_at", null: false
t.string "queue_name", null: false
t.index ["queue_name"], name: "index_solid_queue_pauses_on_queue_name", unique: true
end
create_table "solid_queue_processes", force: :cascade do |t|
t.datetime "created_at", null: false
t.string "hostname"
t.string "kind", null: false
t.datetime "last_heartbeat_at", null: false
t.text "metadata"
t.string "name", null: false
t.integer "pid", null: false
t.bigint "supervisor_id"
t.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at"
t.index ["name", "supervisor_id"], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true
t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id"
end
create_table "solid_queue_ready_executions", force: :cascade do |t|
t.datetime "created_at", null: false
t.bigint "job_id", null: false
t.integer "priority", default: 0, null: false
t.string "queue_name", null: false
t.index ["job_id"], name: "index_solid_queue_ready_executions_on_job_id", unique: true
t.index ["priority", "job_id"], name: "index_solid_queue_poll_all"
t.index ["queue_name", "priority", "job_id"], name: "index_solid_queue_poll_by_queue"
end
create_table "solid_queue_recurring_executions", force: :cascade do |t|
t.datetime "created_at", null: false
t.bigint "job_id", null: false
t.datetime "run_at", null: false
t.string "task_key", null: false
t.index ["job_id"], name: "index_solid_queue_recurring_executions_on_job_id", unique: true
t.index ["task_key", "run_at"], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true
end
create_table "solid_queue_recurring_tasks", force: :cascade do |t|
t.text "arguments"
t.string "class_name"
t.string "command", limit: 2048
t.datetime "created_at", null: false
t.text "description"
t.string "key", null: false
t.integer "priority", default: 0
t.string "queue_name"
t.string "schedule", null: false
t.boolean "static", default: true, null: false
t.datetime "updated_at", null: false
t.index ["key"], name: "index_solid_queue_recurring_tasks_on_key", unique: true
t.index ["static"], name: "index_solid_queue_recurring_tasks_on_static"
end
create_table "solid_queue_scheduled_executions", force: :cascade do |t|
t.datetime "created_at", null: false
t.bigint "job_id", null: false
t.integer "priority", default: 0, null: false
t.string "queue_name", null: false
t.datetime "scheduled_at", null: false
t.index ["job_id"], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true
t.index ["scheduled_at", "priority", "job_id"], name: "index_solid_queue_dispatch_all"
end
create_table "solid_queue_semaphores", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "expires_at", null: false
t.string "key", null: false
t.datetime "updated_at", null: false
t.integer "value", default: 1, null: false
t.index ["expires_at"], name: "index_solid_queue_semaphores_on_expires_at"
t.index ["key", "value"], name: "index_solid_queue_semaphores_on_key_and_value"
t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true
end
create_table "users", force: :cascade do |t|
t.text "bio"
t.datetime "created_at", null: false
t.string "email", null: false
t.datetime "igdb_last_synced_at"
t.boolean "igdb_sync_enabled", default: true, null: false
t.string "password_digest", null: false
t.datetime "password_reset_sent_at"
t.string "password_reset_token"
t.boolean "profile_public", default: false, null: false
t.string "theme", default: "light", null: false
t.datetime "updated_at", null: false
t.string "username", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["igdb_sync_enabled"], name: "index_users_on_igdb_sync_enabled"
t.index ["theme"], name: "index_users_on_theme"
t.index ["username"], name: "index_users_on_username", unique: true
end
add_foreign_key "api_tokens", "users"
add_foreign_key "collection_games", "collections"
add_foreign_key "collection_games", "games"
add_foreign_key "collections", "collections", column: "parent_collection_id"
add_foreign_key "collections", "users"
add_foreign_key "game_genres", "games"
add_foreign_key "game_genres", "genres"
add_foreign_key "games", "platforms"
add_foreign_key "games", "users"
add_foreign_key "igdb_match_suggestions", "games"
add_foreign_key "igdb_match_suggestions", "igdb_games"
add_foreign_key "igdb_platform_mappings", "platforms"
add_foreign_key "items", "platforms"
add_foreign_key "items", "users"
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
end

345
db/seeds.rb Normal file
View File

@@ -0,0 +1,345 @@
puts "Seeding database..."
# Create Platforms
puts "Creating platforms..."
platforms_data = [
# Nintendo
{ name: "Nintendo Entertainment System", abbreviation: "NES", manufacturer: "Nintendo" },
{ name: "Super Nintendo Entertainment System", abbreviation: "SNES", manufacturer: "Nintendo" },
{ name: "Nintendo 64", abbreviation: "N64", manufacturer: "Nintendo" },
{ name: "GameCube", abbreviation: "GCN", manufacturer: "Nintendo" },
{ name: "Wii", abbreviation: "Wii", manufacturer: "Nintendo" },
{ name: "Wii U", abbreviation: "Wii U", manufacturer: "Nintendo" },
{ name: "Nintendo Switch", abbreviation: "Switch", manufacturer: "Nintendo" },
{ name: "Game Boy", abbreviation: "GB", manufacturer: "Nintendo" },
{ name: "Game Boy Color", abbreviation: "GBC", manufacturer: "Nintendo" },
{ name: "Game Boy Advance", abbreviation: "GBA", manufacturer: "Nintendo" },
{ name: "Nintendo DS", abbreviation: "DS", manufacturer: "Nintendo" },
{ name: "Nintendo 3DS", abbreviation: "3DS", manufacturer: "Nintendo" },
# Sony
{ name: "PlayStation", abbreviation: "PS1", manufacturer: "Sony" },
{ name: "PlayStation 2", abbreviation: "PS2", manufacturer: "Sony" },
{ name: "PlayStation 3", abbreviation: "PS3", manufacturer: "Sony" },
{ name: "PlayStation 4", abbreviation: "PS4", manufacturer: "Sony" },
{ name: "PlayStation 5", abbreviation: "PS5", manufacturer: "Sony" },
{ name: "PlayStation Portable", abbreviation: "PSP", manufacturer: "Sony" },
{ name: "PlayStation Vita", abbreviation: "PS Vita", manufacturer: "Sony" },
# Microsoft
{ name: "Xbox", abbreviation: "Xbox", manufacturer: "Microsoft" },
{ name: "Xbox 360", abbreviation: "X360", manufacturer: "Microsoft" },
{ name: "Xbox One", abbreviation: "XB1", manufacturer: "Microsoft" },
{ name: "Xbox Series X/S", abbreviation: "Series X/S", manufacturer: "Microsoft" },
# Sega
{ name: "Sega Genesis", abbreviation: "Genesis", manufacturer: "Sega" },
{ name: "Sega Saturn", abbreviation: "Saturn", manufacturer: "Sega" },
{ name: "Sega Dreamcast", abbreviation: "Dreamcast", manufacturer: "Sega" },
{ name: "Sega Game Gear", abbreviation: "Game Gear", manufacturer: "Sega" },
# Other
{ name: "PC", abbreviation: "PC", manufacturer: nil },
{ name: "Mobile (iOS)", abbreviation: "iOS", manufacturer: "Apple" },
{ name: "Mobile (Android)", abbreviation: "Android", manufacturer: "Google" },
{ name: "Arcade", abbreviation: "Arcade", manufacturer: nil }
]
platforms_data.each do |platform_data|
Platform.find_or_create_by!(name: platform_data[:name]) do |platform|
platform.abbreviation = platform_data[:abbreviation]
platform.manufacturer = platform_data[:manufacturer]
end
end
puts "Created #{Platform.count} platforms"
# Create Genres
puts "Creating genres..."
genres = [
"Action", "Adventure", "RPG", "JRPG", "Strategy", "Simulation",
"Platformer", "Fighting", "Racing", "Sports", "Puzzle", "Horror",
"Stealth", "Shooter", "FPS", "TPS", "Rhythm", "Visual Novel",
"Roguelike", "Metroidvania", "Sandbox", "MMO", "Turn-Based",
"Real-Time Strategy", "Tower Defense", "Card Game", "Party Game",
"Educational", "Survival", "Battle Royale"
]
genres.each do |genre_name|
Genre.find_or_create_by!(name: genre_name)
end
puts "Created #{Genre.count} genres"
# Create demo user and sample games for development
if Rails.env.development?
puts "Creating demo user..."
demo_user = User.find_or_create_by!(email: "demo@turbovault.com") do |user|
user.username = "demo"
user.password = "password123"
user.password_confirmation = "password123"
user.bio = "Demo user for TurboVault development"
user.profile_public = true
puts " ✓ Created demo user"
puts " Email: demo@turbovault.com"
puts " Password: password123"
end
if demo_user.persisted? && !demo_user.previously_new_record?
puts " ✓ Demo user already exists"
puts " Email: demo@turbovault.com"
puts " Password: password123"
end
# Create sample collections
puts "Creating sample collections for demo user..."
nintendo_collection = demo_user.collections.find_or_create_by!(name: "Nintendo Games") do |collection|
collection.description = "All my Nintendo platform games"
end
n64_collection = demo_user.collections.find_or_create_by!(name: "N64 Classics") do |collection|
collection.description = "Best games from the Nintendo 64 era"
collection.parent_collection = nintendo_collection
end
favorites_collection = demo_user.collections.find_or_create_by!(name: "All-Time Favorites") do |collection|
collection.description = "My absolute favorite games across all platforms"
end
backlog_collection = demo_user.collections.find_or_create_by!(name: "To Play") do |collection|
collection.description = "Games I still need to complete"
end
puts " ✓ Created #{demo_user.collections.count} collections"
# Only create games if demo user has none
if demo_user.games.empty?
puts "Creating sample games for demo user..."
# Find platforms
n64 = Platform.find_by(abbreviation: "N64")
ps5 = Platform.find_by(abbreviation: "PS5")
switch = Platform.find_by(abbreviation: "Switch")
snes = Platform.find_by(abbreviation: "SNES")
ps2 = Platform.find_by(abbreviation: "PS2")
pc = Platform.find_by(name: "PC")
# Find genres
action = Genre.find_by(name: "Action")
adventure = Genre.find_by(name: "Adventure")
rpg = Genre.find_by(name: "RPG")
jrpg = Genre.find_by(name: "JRPG")
platformer = Genre.find_by(name: "Platformer")
puzzle = Genre.find_by(name: "Puzzle")
shooter = Genre.find_by(name: "Shooter")
fps = Genre.find_by(name: "FPS")
simulation = Genre.find_by(name: "Simulation")
sample_games = [
{
title: "The Legend of Zelda: Ocarina of Time",
platform: n64,
genres: [ action, adventure ],
collections: [ nintendo_collection, n64_collection, favorites_collection ],
format: "physical",
condition: "cib",
completion_status: "completed",
user_rating: 5,
price_paid: 45.00,
location: "Shelf A - Row 2",
notes: "One of the best games ever made. Perfect condition with manual and box.",
date_added: 30.days.ago
},
{
title: "Super Mario 64",
platform: n64,
genres: [ platformer, adventure ],
collections: [ nintendo_collection, n64_collection, favorites_collection ],
format: "physical",
condition: "loose",
completion_status: "completed",
user_rating: 5,
price_paid: 30.00,
location: "Shelf A - Row 2",
date_added: 45.days.ago
},
{
title: "Elden Ring",
platform: ps5,
genres: [ action, rpg ],
collections: [ favorites_collection ],
format: "digital",
digital_store: "PlayStation Store",
completion_status: "currently_playing",
user_rating: 5,
price_paid: 59.99,
notes: "Amazing open world. Currently at 80 hours playtime.",
date_added: 10.days.ago
},
{
title: "The Legend of Zelda: Breath of the Wild",
platform: switch,
genres: [ action, adventure ],
collections: [ nintendo_collection, favorites_collection ],
format: "physical",
condition: "cib",
completion_status: "completed",
user_rating: 5,
price_paid: 60.00,
location: "Shelf B - Row 1",
date_added: 20.days.ago
},
{
title: "Super Metroid",
platform: snes,
genres: [ action, adventure, platformer ],
collections: [ nintendo_collection, favorites_collection ],
format: "physical",
condition: "loose",
completion_status: "completed",
user_rating: 5,
price_paid: 85.00,
location: "Shelf A - Row 1",
notes: "Classic Metroidvania. Still holds up today!",
date_added: 60.days.ago
},
{
title: "Final Fantasy VII",
platform: ps2,
genres: [ jrpg, rpg ],
collections: [ backlog_collection ],
format: "physical",
condition: "cib",
completion_status: "backlog",
user_rating: nil,
price_paid: 20.00,
location: "Shelf B - Row 3",
notes: "Need to replay this classic.",
date_added: 15.days.ago
},
{
title: "Hollow Knight",
platform: pc,
genres: [ action, platformer, adventure ],
collections: [ favorites_collection ],
format: "digital",
digital_store: "Steam",
completion_status: "on_hold",
user_rating: 5,
price_paid: 15.00,
notes: "Incredible art style and gameplay. Taking a break but will return.",
date_added: 25.days.ago
},
{
title: "Portal 2",
platform: pc,
genres: [ puzzle, fps ],
collections: [ favorites_collection ],
format: "digital",
digital_store: "Steam",
completion_status: "completed",
user_rating: 5,
price_paid: 9.99,
notes: "Perfect puzzle game. Co-op is fantastic.",
date_added: 50.days.ago
},
{
title: "Hades",
platform: switch,
genres: [ action, rpg ],
collections: [ nintendo_collection, favorites_collection ],
format: "digital",
digital_store: "Nintendo eShop",
completion_status: "completed",
user_rating: 5,
price_paid: 24.99,
notes: "Best roguelike I've ever played. Fantastic story and gameplay loop.",
date_added: 35.days.ago
},
{
title: "Cyberpunk 2077",
platform: ps5,
genres: [ action, rpg, shooter ],
collections: [ backlog_collection ],
format: "digital",
digital_store: "PlayStation Store",
completion_status: "backlog",
user_rating: nil,
price_paid: 29.99,
notes: "Heard it's much better now after patches. Need to start this.",
date_added: 5.days.ago
},
{
title: "GoldenEye 007",
platform: n64,
genres: [ fps, action ],
collections: [ nintendo_collection, n64_collection ],
format: "physical",
condition: "loose",
completion_status: "completed",
user_rating: 4,
price_paid: 35.00,
location: "Shelf A - Row 2",
notes: "Classic multiplayer. Still fun with friends.",
date_added: 40.days.ago
},
{
title: "Stardew Valley",
platform: switch,
genres: [ simulation ],
collections: [ nintendo_collection ],
format: "digital",
digital_store: "Nintendo eShop",
completion_status: "currently_playing",
user_rating: 5,
price_paid: 14.99,
notes: "Perfect game for relaxing. Over 100 hours in!",
date_added: 55.days.ago
}
]
sample_games.each do |game_data|
game = demo_user.games.create!(
title: game_data[:title],
platform: game_data[:platform],
format: game_data[:format],
condition: game_data[:condition],
completion_status: game_data[:completion_status],
user_rating: game_data[:user_rating],
price_paid: game_data[:price_paid],
location: game_data[:location],
digital_store: game_data[:digital_store],
notes: game_data[:notes],
date_added: game_data[:date_added] || Date.current
)
game.genres = game_data[:genres] if game_data[:genres]
game.collections = game_data[:collections] if game_data[:collections]
end
puts " ✓ Created #{demo_user.games.count} sample games"
puts " ✓ Games organized into collections"
else
puts " ✓ Demo user already has #{demo_user.games.count} games"
end
puts "\n" + "="*60
puts "Demo Account Ready!"
puts "="*60
puts "Email: demo@turbovault.com"
puts "Password: password123"
puts ""
puts "Quick Login: http://localhost:3000/login"
puts "="*60
end
puts "Seeding completed!"
puts "- #{Platform.count} platforms"
puts "- #{Genre.count} genres"
# Seed IGDB Platform Mappings
puts "\nSeeding IGDB platform mappings..."
IgdbPlatformMapping.seed_common_mappings!
puts " ✓ Created #{IgdbPlatformMapping.count} platform mappings"