diff --git a/AGENTS.md b/AGENTS.md index c81978f8..512747fc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,6 +45,7 @@ Most of the application logic lives in the **CoPlan Rails engine** (`engine/`), - Enums are stored as **strings** (not integers) — validated with constants and `inclusion:` validators - JSON columns for arrays/hashes (`tags`, `metadata`, `trigger_statuses`, `allowed_email_domains`) - No PG-only types (`citext`, `text[]`, `ON CONFLICT ... WHERE`) — use Rails validations and `json` columns +- **No foreign key constraints** — the ODS/Aurora `app` DB user lacks `REFERENCES` privilege. Use indexes on relationship columns instead of `add_foreign_key`. Referential integrity is enforced at the application layer via validations. - `Current.organization` and `Current.user` are set per-request for scoping ## Model Conventions diff --git a/config/initializers/coplan.rb b/config/initializers/coplan.rb index cd74e005..7b3c37eb 100644 --- a/config/initializers/coplan.rb +++ b/config/initializers/coplan.rb @@ -1,4 +1,6 @@ CoPlan.configure do |config| + config.sign_in_path = "/sign_in" + config.authenticate = ->(request) { user_id = request.session[:user_id] return nil unless user_id diff --git a/engine/app/controllers/coplan/application_controller.rb b/engine/app/controllers/coplan/application_controller.rb index bd15304c..0d9929b4 100644 --- a/engine/app/controllers/coplan/application_controller.rb +++ b/engine/app/controllers/coplan/application_controller.rb @@ -43,7 +43,11 @@ def authenticate_coplan_user! attrs = callback.call(request) unless attrs && attrs[:external_id].present? - head :unauthorized + if CoPlan.configuration.sign_in_path + redirect_to CoPlan.configuration.sign_in_path, alert: "Please sign in." + else + head :unauthorized + end return end diff --git a/engine/db/migrate/20260226200000_create_coplan_schema.rb b/engine/db/migrate/20260226200000_create_coplan_schema.rb index 3802d8d3..118ed31d 100644 --- a/engine/db/migrate/20260226200000_create_coplan_schema.rb +++ b/engine/db/migrate/20260226200000_create_coplan_schema.rb @@ -26,7 +26,6 @@ def change add_index :coplan_plans, :status add_index :coplan_plans, :updated_at add_index :coplan_plans, :created_by_user_id - add_foreign_key :coplan_plans, :coplan_users, column: :created_by_user_id create_table :coplan_plan_versions, id: { type: :string, limit: 36 } do |t| t.string :plan_id, limit: 36, null: false @@ -49,10 +48,7 @@ def change add_index :coplan_plan_versions, :plan_id add_index :coplan_plan_versions, [:plan_id, :revision], unique: true add_index :coplan_plan_versions, [:plan_id, :created_at] - add_foreign_key :coplan_plan_versions, :coplan_plans, column: :plan_id - - # Now that coplan_plan_versions exists, add the FK for current_plan_version_id - add_foreign_key :coplan_plans, :coplan_plan_versions, column: :current_plan_version_id + add_index :coplan_plans, :current_plan_version_id create_table :coplan_plan_collaborators, id: { type: :string, limit: 36 } do |t| t.string :plan_id, limit: 36, null: false @@ -66,9 +62,6 @@ def change add_index :coplan_plan_collaborators, :user_id add_index :coplan_plan_collaborators, :added_by_user_id add_index :coplan_plan_collaborators, [:plan_id, :user_id], unique: true - add_foreign_key :coplan_plan_collaborators, :coplan_plans, column: :plan_id - add_foreign_key :coplan_plan_collaborators, :coplan_users, column: :user_id - add_foreign_key :coplan_plan_collaborators, :coplan_users, column: :added_by_user_id create_table :coplan_comment_threads, id: { type: :string, limit: 36 } do |t| t.string :plan_id, limit: 36, null: false @@ -91,12 +84,11 @@ def change add_index :coplan_comment_threads, [:plan_id, :status] add_index :coplan_comment_threads, [:plan_id, :out_of_date] - add_foreign_key :coplan_comment_threads, :coplan_plans, column: :plan_id - add_foreign_key :coplan_comment_threads, :coplan_plan_versions, column: :plan_version_id - add_foreign_key :coplan_comment_threads, :coplan_plan_versions, column: :addressed_in_plan_version_id - add_foreign_key :coplan_comment_threads, :coplan_plan_versions, column: :out_of_date_since_version_id - add_foreign_key :coplan_comment_threads, :coplan_users, column: :created_by_user_id - add_foreign_key :coplan_comment_threads, :coplan_users, column: :resolved_by_user_id + add_index :coplan_comment_threads, :plan_version_id + add_index :coplan_comment_threads, :created_by_user_id + add_index :coplan_comment_threads, :resolved_by_user_id + add_index :coplan_comment_threads, :addressed_in_plan_version_id + add_index :coplan_comment_threads, :out_of_date_since_version_id create_table :coplan_comments, id: { type: :string, limit: 36 } do |t| t.string :comment_thread_id, limit: 36, null: false @@ -108,7 +100,6 @@ def change end add_index :coplan_comments, [:comment_thread_id, :created_at] - add_foreign_key :coplan_comments, :coplan_comment_threads, column: :comment_thread_id create_table :coplan_edit_leases, id: { type: :string, limit: 36 } do |t| t.string :plan_id, limit: 36, null: false @@ -121,7 +112,6 @@ def change end add_index :coplan_edit_leases, :plan_id, unique: true - add_foreign_key :coplan_edit_leases, :coplan_plans, column: :plan_id create_table :coplan_edit_sessions, id: { type: :string, limit: 36 } do |t| t.string :plan_id, limit: 36, null: false @@ -139,8 +129,7 @@ def change end add_index :coplan_edit_sessions, [:plan_id, :status] - add_foreign_key :coplan_edit_sessions, :coplan_plans, column: :plan_id - add_foreign_key :coplan_edit_sessions, :coplan_plan_versions, column: :plan_version_id + add_index :coplan_edit_sessions, :plan_version_id create_table :coplan_api_tokens, id: { type: :string, limit: 36 } do |t| t.string :user_id, limit: 36, null: false @@ -155,7 +144,6 @@ def change add_index :coplan_api_tokens, :user_id add_index :coplan_api_tokens, :token_digest, unique: true - add_foreign_key :coplan_api_tokens, :coplan_users, column: :user_id create_table :coplan_automated_plan_reviewers, id: { type: :string, limit: 36 } do |t| t.string :key, null: false diff --git a/engine/lib/coplan/configuration.rb b/engine/lib/coplan/configuration.rb index 0666a928..06002801 100644 --- a/engine/lib/coplan/configuration.rb +++ b/engine/lib/coplan/configuration.rb @@ -1,6 +1,6 @@ module CoPlan class Configuration - attr_accessor :authenticate + attr_accessor :authenticate, :sign_in_path attr_accessor :ai_base_url, :ai_api_key, :ai_model attr_accessor :error_reporter attr_accessor :notification_handler