From c8d672b078e5de4901ff72a986cae6d6eee95f1f Mon Sep 17 00:00:00 2001 From: Claude Sonnet 5 Date: Tue, 7 Jul 2026 12:04:28 +0000 Subject: [PATCH 1/2] feat: make DATABASE_URL configurable for dev and test envs Allow overriding the hardcoded Postgres config in dev/test via the DATABASE_URL environment variable, mirroring the existing prod behavior. Existing config/dev.exs and config/test.exs defaults are preserved when the variable is unset. Co-Authored-By: Claude Sonnet 5 --- README.md | 14 +++++++++++ config/runtime.exs | 6 +++++ test/config/runtime_test.exs | 46 ++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 test/config/runtime_test.exs diff --git a/README.md b/README.md index ba5d907..3b5cab9 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,20 @@ Edit `lib/bodhi/open_router.ex` and modify the `@default_model` attribute: See all available models at: https://openrouter.ai/models +## Database Configuration + +By default, `dev` and `test` connect to the Postgres instance defined in +`config/dev.exs` / `config/test.exs`. To point either environment at a +different database, set `DATABASE_URL` before starting the app or running +tests — it overrides the hardcoded defaults: + +```bash +export DATABASE_URL="ecto://USER:PASS@HOST/DATABASE" +``` + +Leave `DATABASE_URL` unset to keep using the defaults. In `prod`, +`DATABASE_URL` is required, as before. + ## Features ### Daily Dialog Summarization diff --git a/config/runtime.exs b/config/runtime.exs index 1f320e9..cd25887 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -31,6 +31,12 @@ config :telegex, config :posthog, api_key: "#{System.get_env("POSTHOG_KEY")}" +if config_env() in [:dev, :test] do + if database_url = System.get_env("DATABASE_URL") do + config :bodhi, Bodhi.Repo, url: database_url + end +end + if config_env() == :prod do database_url = System.get_env("DATABASE_URL") || diff --git a/test/config/runtime_test.exs b/test/config/runtime_test.exs new file mode 100644 index 0000000..a5c630c --- /dev/null +++ b/test/config/runtime_test.exs @@ -0,0 +1,46 @@ +defmodule Config.RuntimeTest do + use ExUnit.Case, async: false + + @runtime_config_path "config/runtime.exs" + + setup do + original_database_url = System.get_env("DATABASE_URL") + + on_exit(fn -> + case original_database_url do + nil -> System.delete_env("DATABASE_URL") + value -> System.put_env("DATABASE_URL", value) + end + end) + + :ok + end + + for env <- [:dev, :test] do + test "preserves the default Bodhi.Repo config for #{env} " <> + "when DATABASE_URL is unset" do + System.delete_env("DATABASE_URL") + + config = read_runtime_config(unquote(env)) + + assert config + |> Keyword.get(:bodhi, []) + |> Keyword.get(Bodhi.Repo) == nil + end + + test "overrides the Bodhi.Repo url for #{env} " <> + "when DATABASE_URL is set" do + database_url = "ecto://user:pass@host/#{unquote(env)}_db" + System.put_env("DATABASE_URL", database_url) + + config = read_runtime_config(unquote(env)) + + assert config + |> get_in([:bodhi, Bodhi.Repo, :url]) == database_url + end + end + + defp read_runtime_config(env) do + Config.Reader.read!(@runtime_config_path, env: env, target: :host) + end +end From 00c322a6938c4de1e11e2fdfcb36122a81ad0302 Mon Sep 17 00:00:00 2001 From: Claude Sonnet 5 Date: Tue, 7 Jul 2026 16:38:20 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20address=20PR=20review=20=E2=80=94=20?= =?UTF-8?q?document=20.env=20DATABASE=5FURL=20collision,=20test=20pool=20m?= =?UTF-8?q?erge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Callout the .env/compose.yml DATABASE_URL collision risk and the MIX_TEST_PARTITION caveat in the README, and add a test proving the compile-time pool_size/pool settings survive being merged with the DATABASE_URL runtime override. Co-Authored-By: Claude Sonnet 5 --- README.md | 14 ++++++++++++++ test/config/runtime_test.exs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/README.md b/README.md index 3b5cab9..4bea839 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,20 @@ export DATABASE_URL="ecto://USER:PASS@HOST/DATABASE" Leave `DATABASE_URL` unset to keep using the defaults. In `prod`, `DATABASE_URL` is required, as before. +> **Caution:** the root `.env` file (used by `compose.yml`) also defines a +> `DATABASE_URL`, pointing at the Docker-internal `postgres` hostname. That +> value is only reachable from inside the compose network. If you export +> `.env` into your shell (e.g. via `direnv` or `source .env`), a host-run +> `mix phx.server` / `mix test` will pick it up and try to connect to the +> unreachable `postgres` host instead of the exposed `localhost:5433` +> instance. Unset `DATABASE_URL` (or override it explicitly) before running +> Mix commands on the host. +> +> For `test`, setting `DATABASE_URL` replaces the whole `database` value, +> including the `MIX_TEST_PARTITION` suffix used for parallel CI test runs +> — don't combine a custom `DATABASE_URL` with partitioned test runs unless +> you account for that yourself. + ## Features ### Daily Dialog Summarization diff --git a/test/config/runtime_test.exs b/test/config/runtime_test.exs index a5c630c..0b83b04 100644 --- a/test/config/runtime_test.exs +++ b/test/config/runtime_test.exs @@ -38,9 +38,41 @@ defmodule Config.RuntimeTest do assert config |> get_in([:bodhi, Bodhi.Repo, :url]) == database_url end + + test "keeps the compile-time Bodhi.Repo pool settings for #{env} " <> + "once merged with the DATABASE_URL override" do + database_url = "ecto://user:pass@host/#{unquote(env)}_db" + System.put_env("DATABASE_URL", database_url) + + compile_time_config = read_compile_time_config(unquote(env)) + + merged_repo_config = + compile_time_config + |> Config.Reader.merge(read_runtime_config(unquote(env))) + |> get_in([:bodhi, Bodhi.Repo]) + + compile_time_repo_config = + get_in(compile_time_config, [:bodhi, Bodhi.Repo]) + + assert merged_repo_config[:url] == database_url + + assert merged_repo_config[:pool_size] == + compile_time_repo_config[:pool_size] + + assert merged_repo_config[:pool] == compile_time_repo_config[:pool] + end end defp read_runtime_config(env) do Config.Reader.read!(@runtime_config_path, env: env, target: :host) end + + defp read_compile_time_config(env) do + config = Config.Reader.read!("config/config.exs", env: env, target: :host) + + env_config = + Config.Reader.read!("config/#{env}.exs", env: env, target: :host) + + Config.Reader.merge(config, env_config) + end end