From c640a3157781918592e2198690a3c9e0af2d7f79 Mon Sep 17 00:00:00 2001 From: Francesc Leveque Date: Mon, 25 May 2026 12:57:52 +0200 Subject: [PATCH] RadarStore: persist DETS in the configured data_dir, not :priv_dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the radar PR shipped, every deploy wiped users' radar listings — they had to re-opt-in to repopulate. Portfolios survived because Pulse.Store reads `data_dir` from config and `config/runtime.exs` points that at `DATA_DIR=/app/data`, a Kamal-mounted volume. RadarStore was the odd one out: it called `:code.priv_dir(:pulse)` directly, which resolves inside the release directory — rebuilt per image, so the file was always empty after a deploy. Match the pattern used by `Pulse.Store`, `Pulse.Analytics`, and `Pulse.RadarAnalytics`: read `data_dir` from app env and join `radars.dets` onto it. In prod that resolves to `/app/data/radars.dets` (volume-backed); in dev it stays at `priv/data/radars.dets`; in test the data_dir is already overridden in `config/test.exs`. Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/pulse/radar_store.ex | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pulse/radar_store.ex b/lib/pulse/radar_store.ex index 0de101e..26ea24f 100644 --- a/lib/pulse/radar_store.ex +++ b/lib/pulse/radar_store.ex @@ -51,8 +51,13 @@ defmodule Pulse.RadarStore do @impl true def init(_opts) do - path = Path.join(:code.priv_dir(:pulse), "data/radars.dets") |> to_charlist() - File.mkdir_p!(Path.dirname(to_string(path))) + # Read from the configurable data_dir (overridden in prod via DATA_DIR + # → /app/data, a Kamal-mounted volume). Matches Pulse.Store / Analytics + # / RadarAnalytics — using :code.priv_dir/1 here meant every deploy + # wiped the file because release dirs are rebuilt per image. + data_dir = Application.get_env(:pulse, :data_dir, "priv/data") + File.mkdir_p!(data_dir) + path = Path.join(data_dir, "radars.dets") |> String.to_charlist() case :dets.open_file(@table, file: path, type: :set) do {:ok, table} ->