Skip to content

Commit 4fdf46c

Browse files
committed
Rewrite comments and docs to drop PR #1749 review-process references
Strip finding IDs (B1, M6, m2, ...), hypothetical-rename stories, and forward/backward "we used to X, now we Y" narrative from comments and docs. Replace with descriptions of what the code is and what it does.
1 parent dfc2ed2 commit 4fdf46c

14 files changed

Lines changed: 78 additions & 92 deletions

File tree

demo/test/demo_web/live/preferences_persistence_test.exs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,9 @@ defmodule DemoWeb.Live.PreferencesPersistenceTest do
66
interactions emit a `push_event` with the expected preference key and value
77
shape.
88
9-
Uses the M6/M7 seams:
10-
11-
* `Backpex.Preferences.LiveView.event_name/0` — wire event name.
12-
* `Backpex.Preferences.Keys.{order,filters,columns}/1` — canonical keys.
13-
14-
Never string-literal the event name or keys here; the whole point of the
15-
seams is that renaming them breaks the emitter and the test in lockstep.
9+
The wire event name comes from `Backpex.Preferences.LiveView.event_name/0`
10+
and the keys come from `Backpex.Preferences.Keys.{order,filters,columns}/1`,
11+
so the test reflects the same contract the emitter uses.
1612
"""
1713

1814
use DemoWeb.ConnCase, async: false
@@ -72,7 +68,7 @@ defmodule DemoWeb.Live.PreferencesPersistenceTest do
7268

7369
# The LiveResource emits several filter-persistence events over the mount
7470
# + change cycle. We care that at least one of them reflects the new
75-
# two-value set and carries the canonical filters key.
71+
# two-value set and carries the filters key.
7672
assert_push_event(view, @event_name, %{
7773
key: ^expected_key,
7874
value: %{"published" => ["published", "not_published"]}

guides/live_resource/user-preferences.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -439,13 +439,14 @@ All three keys route through whichever adapter you configured for
439439
`"resource.*"` — typically the Session adapter by default, or a per-user DB
440440
adapter once you wire one up.
441441

442-
### Before / after: migrating a custom macro
442+
### Replacing a hand-rolled persistence layer
443443

444-
Apps that previously rolled their own persistence (custom `init_order`
445-
callback backed by a DB table) can delete that scaffolding:
444+
If your app already persists ordering, filters, or column state through a
445+
custom `init_order` callback backed by a DB table, the `persist:` option
446+
replaces that scaffolding:
446447

447448
```elixir
448-
# Before
449+
# Hand-rolled
449450
use Backpex.LiveResource, adapter_config: [...]
450451

451452
def init_order(assigns), do: MyApp.OrderingSettings.fetch(assigns.current_user, __MODULE__)
@@ -456,7 +457,7 @@ end
456457
```
457458

458459
```elixir
459-
# After
460+
# With persist:
460461
use Backpex.LiveResource,
461462
adapter_config: [...],
462463
persist: [:order]

guides/upgrading/v0.19.md

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,16 @@ The `BackpexSidebarSections` hook has been replaced by `BackpexSidebar`, which n
9191
9292
This version introduces a unified preference system that eliminates UI flickering. User preferences (theme, sidebar state, column visibility, etc.) are now server-rendered from a configurable storage backend on every request.
9393

94-
Backpex ships with a Phoenix-session adapter out of the box (matches the legacy behavior — no action needed). Route individual prefixes to a per-user database adapter when you outgrow the ~4KB cookie ceiling or need preferences to follow a user across devices. See the [User Preferences guide](../live_resource/user-preferences.md) for adapter recipes and the opt-in persistence flag for ordering / filters / columns.
94+
Backpex ships with a Phoenix-session adapter out of the box, so no action is needed to keep preferences in the session. Route individual prefixes to a per-user database adapter when you outgrow the ~4KB cookie ceiling or need preferences to follow a user across devices. See the [User Preferences guide](../live_resource/user-preferences.md) for adapter recipes and the opt-in persistence flag for ordering / filters / columns.
9595

9696
### Preferences: adapter architecture
9797

98-
- **Terminology.** What was called "cookie-based preferences" is now just
99-
"preferences," because storage is pluggable (session, ETS, Ecto, ...). The
100-
JS property `BackpexPreferences.cookiePath` was renamed to `endpointPath`
101-
— internal to the hook; no change unless you called it directly.
102-
- **Default behavior is unchanged.** With no config, every key routes to
103-
`Backpex.Preferences.Adapters.Session` — identical to the pre-release
104-
branch. Existing apps keep working.
98+
- **Terminology.** Storage is pluggable (session, ETS, Ecto, ...), so the
99+
subsystem is called "preferences" rather than "cookie-based preferences."
100+
The JS property exposed to hooks is `BackpexPreferences.endpointPath`.
101+
- **Default behavior.** With no config, every key routes to
102+
`Backpex.Preferences.Adapters.Session`, so existing apps need no changes
103+
to keep working.
105104
- **Route a prefix to your database.** Implement
106105
`Backpex.Preferences.Adapter` and add the route:
107106

@@ -116,12 +115,9 @@ Backpex ships with a Phoenix-session adapter out of the box (matches the legacy
116115

117116
Full walkthrough (migration + schema + adapter module, two table shapes)
118117
in the [User Preferences guide](../live_resource/user-preferences.md).
119-
- **Per-resource module keys encoding changed.** The internal
120-
`resource.<Module>.<suffix>` key now uses `:` as a separator
121-
(`resource:<Module>:<suffix>`) so module-name dots don't create
122-
accidental path segments. Any values persisted under the previous shape
123-
are effectively invalid and will be ignored — no migration is required
124-
because the previous shape was only written on this unreleased branch.
118+
- **Per-resource module keys.** Internal
119+
`resource:<Module>:<suffix>` keys use `:` as a separator so module-name
120+
dots don't create accidental path segments.
125121
- **New `persist:` option on `use Backpex.LiveResource`.** Opt in to
126122
persisting ordering, filters, or column visibility through the
127123
preferences layer:
@@ -132,9 +128,8 @@ Backpex ships with a Phoenix-session adapter out of the box (matches the legacy
132128
persist: [:order, :filters, :columns]
133129
```
134130

135-
Not required, not a breaking change — default is `[]`, which preserves
136-
Backpex's URL-as-source-of-truth behavior for ordering and filters, and
137-
in-memory column visibility.
131+
Not required, not a breaking change — default is `[]`, which keeps
132+
ordering and filters in the URL and column visibility in-memory.
138133

139134
### Breaking Changes
140135

lib/backpex/preferences.ex

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ defmodule Backpex.Preferences do
1313
## Zero-config defaults
1414
1515
With no `:backpex, Backpex.Preferences` config set, every key routes to
16-
`Backpex.Preferences.Adapters.Session` — matches the legacy single-adapter
17-
behavior.
16+
`Backpex.Preferences.Adapters.Session`.
1817
1918
## Configuring per-prefix routing
2019
@@ -42,7 +41,7 @@ defmodule Backpex.Preferences do
4241
* `get_map/3` — read every value under a prefix as a nested map.
4342
* `put/4` — write from a LiveView socket or `%Plug.Conn{}`.
4443
* `put_batch/3` — dispatch a list of writes (best-effort, first-error-wins;
45-
see the function docs for the partial-success caveat).
44+
see the function docs for the partial-success semantics).
4645
"""
4746

4847
alias Backpex.Preferences.Adapters
@@ -57,9 +56,9 @@ defmodule Backpex.Preferences do
5756
Reads a preference. Falls back to `opts[:default]` when the value is
5857
missing or the adapter cannot identify the current user.
5958
60-
Accepts a `%Backpex.Preferences.Context{}` or a bare Phoenix session map
61-
the session-map form is kept for backward compatibility with the legacy
62-
`Preferences.get(session, key)` call sites.
59+
Accepts a `%Backpex.Preferences.Context{}` or a bare Phoenix session map.
60+
The session-map form is convenient for call sites that only have a
61+
session on hand.
6362
6463
## Options
6564
@@ -111,10 +110,10 @@ defmodule Backpex.Preferences do
111110
* `{:ok, value}` — the adapter returned a stored value.
112111
* `:error` — the adapter successfully determined nothing is stored
113112
(`{:ok, :not_found}` from the adapter), **or** the adapter returned
114-
`{:error, :unidentified}`. Per the
115-
`Backpex.Preferences.Adapter` behaviour, `:unidentified` on reads is
116-
defined as "treat as not found" — no warning is logged for that case
117-
because it is expected (anonymous visitors, background jobs, etc.).
113+
`{:error, :unidentified}`. The `Backpex.Preferences.Adapter`
114+
behaviour defines `:unidentified` on reads as "treat as not found",
115+
so no warning is logged for that case — it is expected (anonymous
116+
visitors, background jobs, etc.).
118117
* `{:error, reason}` — any other adapter failure (e.g. a raised
119118
exception swallowed by the dispatcher). A warning is also logged.
120119
@@ -138,7 +137,7 @@ defmodule Backpex.Preferences do
138137
{:ok, value}
139138

140139
{_module, {:error, :unidentified}} ->
141-
# Per the adapter behaviour, `:unidentified` on reads means "treat as
140+
# The adapter behaviour defines `:unidentified` on reads as "treat as
142141
# not found" — collapse to `:error` without logging. This matches the
143142
# expected path for anonymous visitors / background jobs that have no
144143
# resolved identity.
@@ -362,15 +361,17 @@ defmodule Backpex.Preferences do
362361
def resolve_identity(%Context{} = ctx), do: ctx
363362

364363
@doc """
365-
Legacy alias preserved for call sites that still reference the Phoenix
366-
session key directly. New code should read
367-
`Backpex.Preferences.Adapters.Session.session_key/0`.
364+
Returns the Phoenix session key used by the Session adapter.
365+
366+
Convenience passthrough to `Backpex.Preferences.Adapters.Session.session_key/0`.
368367
"""
369368
@spec session_key() :: String.t()
370369
def session_key, do: Adapters.Session.session_key()
371370

372371
@doc """
373-
Legacy alias for `Backpex.Preferences.Key.parse/1`.
372+
Splits a preference key into path segments.
373+
374+
Convenience passthrough to `Backpex.Preferences.Key.parse/1`.
374375
"""
375376
@spec parse_key(String.t()) :: [String.t()]
376377
def parse_key(key), do: Key.parse(key)

lib/backpex/preferences/adapters/session.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ defmodule Backpex.Preferences.Adapters.Session do
1414
## Write-path limitations
1515
1616
`put/4` returns `{:error, :requires_http}` for any source other than
17-
`:controller`. Writing to a Phoenix session outside an HTTP request cycle is
18-
not supported by `Plug.Session`. The dispatcher handles this by falling back
19-
to `push_event/3`, which round-trips the write through the browser and the
17+
`:controller`. `Plug.Session` cannot write to the Phoenix session outside
18+
an HTTP request cycle. The dispatcher handles this by falling back to
19+
`push_event/3`, which round-trips the write through the browser and the
2020
preferences controller.
2121
"""
2222

lib/backpex/preferences/context.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ defmodule Backpex.Preferences.Context do
1212
- `from_mount/2` — LiveView mount / on_mount hook (read path).
1313
- `from_conn/1` — Plug controller (write path over HTTP).
1414
- `from_socket/2` — server-side preference writes from a LiveView.
15-
- `coerce/1` — wraps a bare session map for backward compatibility with the
16-
legacy `Backpex.Preferences.get(session, key)` API.
15+
- `coerce/1` — wraps a bare session map so callers that only have a
16+
session on hand can still use the dispatcher.
1717
1818
## The `identity` field
1919
@@ -45,8 +45,7 @@ defmodule Backpex.Preferences.Context do
4545
@doc """
4646
Build a context for a read originating at LiveView mount.
4747
48-
`assigns` defaults to `%{}` for callers that only have a session (e.g. the
49-
legacy `Preferences.get(session, key)` path).
48+
`assigns` defaults to `%{}` for callers that only have a session on hand.
5049
"""
5150
@spec from_mount(map(), map()) :: t()
5251
def from_mount(session, assigns \\ %{}) when is_map(session) and is_map(assigns) do
@@ -79,8 +78,9 @@ defmodule Backpex.Preferences.Context do
7978
end
8079

8180
@doc """
82-
Wrap a bare session map (or pass through an existing context) so the legacy
83-
`Preferences.get(session, key)` call sites keep working.
81+
Wrap a bare session map (or pass through an existing context) so call
82+
sites that only have a session map can still call `Preferences.get/3` and
83+
friends.
8484
8585
Accepts:
8686

lib/backpex/preferences/keys.ex

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
defmodule Backpex.Preferences.Keys do
22
@moduledoc """
3-
Canonical names for all Backpex-managed preference keys.
3+
Names for every Backpex-managed preference key.
44
55
Every built-in preference (theme, sidebar state, per-resource column
6-
visibility, ...) is emitted through a function in this module rather than an
7-
inline string literal. This is the single seam for the key namespace: change
8-
a value here and every emission plus every test updates in lockstep.
9-
10-
Renaming `theme/0` from `"global.theme"` to `"global.color_scheme"` would
11-
otherwise pass the test suite while silently orphaning every user's stored
12-
preference. Routing every literal through this module makes that
13-
impossible — the tests break the moment the emitter does.
6+
visibility, ...) is produced by a function in this module rather than an
7+
inline string literal, so emitters and tests share a single source for
8+
the name.
149
1510
## Global keys
1611
@@ -26,18 +21,18 @@ defmodule Backpex.Preferences.Keys do
2621
## Per-resource keys
2722
2823
Per-resource preferences embed the LiveResource module name as a single
29-
atomic path segment using the colon-separated key form
30-
(`resource:<Module>:<suffix>`). Module names contain dots, so using the
31-
colon form keeps the module as one segment rather than splitting into
32-
several nested ones.
24+
path segment using the colon-separated key form
25+
(`resource:<Module>:<suffix>`). Module names contain dots, so the colon
26+
form keeps the module as one segment rather than splitting into several
27+
nested ones.
3328
3429
* `columns/1` — `"resource:<Module>:columns"`
3530
* `order/1` — `"resource:<Module>:order"`
3631
* `filters/1` — `"resource:<Module>:filters"`
3732
* `metrics_visible/1` — `"resource:<Module>:metrics_visible"`
3833
39-
Delegates construction to `Backpex.Preferences.Key.resource_key/2` so the
40-
encoding stays consistent with other callers of the key helpers.
34+
Key construction is delegated to `Backpex.Preferences.Key.resource_key/2`
35+
so the encoding stays consistent with other callers of the key helpers.
4136
"""
4237

4338
alias Backpex.Preferences.Key

lib/backpex/preferences/live_view.ex

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ defmodule Backpex.Preferences.LiveView do
22
@moduledoc """
33
LiveView-side helpers for the preferences subsystem.
44
5-
The only seam for emitting a preference-write push_event from a LiveView.
6-
Centralizes the wire event name so renaming the contract touches exactly
7-
one Elixir call site.
8-
9-
The event name itself is a browser contract — the `BackpexPreferences` JS
10-
hook listens for it and POSTs to the preferences controller. Treat it as
11-
a stable wire protocol; do not rename without a matching change in
12-
`assets/js/hooks/_preferences.js`. The current name is returned from
13-
`event_name/0`.
5+
Emits preference-write push_events from a LiveView and owns the wire event
6+
name that the `BackpexPreferences` JS hook listens for. The hook receives
7+
the event, POSTs to the preferences controller, and the controller
8+
persists through the configured adapter.
9+
10+
The event name is a browser contract — treat it as a stable wire protocol
11+
and keep it aligned with `assets/js/hooks/_preferences.js`. The name is
12+
returned from `event_name/0`.
1413
"""
1514

1615
alias Phoenix.LiveView

lib/backpex/preferences/router.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ defmodule Backpex.Preferences.Router do
3030
3131
When no `:adapters` config is set, the router falls back to a single
3232
`{:default, Backpex.Preferences.Adapters.Session, []}` route so the zero-
33-
config behavior matches the legacy single-adapter implementation.
33+
config behavior routes every key to the Session adapter.
3434
3535
## Prefix vs. key resolution
3636

test/controllers/preferences_controller_test.exs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,7 @@ defmodule Backpex.PreferencesControllerTest do
164164
assert stored["ok.before"] == "committed"
165165

166166
# Short-circuit: the entry after the failure was never dispatched, so
167-
# its ETS row was never written. Under the old Enum.reduce/3 it would
168-
# have been written and this assertion would fail.
167+
# its ETS row was never written.
169168
refute Map.has_key?(stored, "ok.after")
170169

171170
# Session-backed effects collected before the failure are never applied

0 commit comments

Comments
 (0)