Uh oh!
There was an error while loading. Please reload this page.
Notifications module intial commit - #505
Merged
Merged
Conversation
Addresses follow-ups from PR BeamLabEU#499 review. maybe_set_folder/2 now verifies the target folder is in-scope before passing nil to Storage.move_file_to_folder/3. Previously the scope-bypass was load-bearing but implicit — a refactor of folder_uuid derivation could have silently turned it into "ignore scope entirely." Out-of-scope placements are now refused with a log line instead. Upload processing buffers results into :pending_batch and schedules a single commit via send_update_after after a 250ms debounce window. Dragging ten files onto a folder now triggers one reload_current_page and one combined flash ("10 new files uploaded") instead of ten serial reloads and overlapping flashes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces PhoenixKit.Notifications: a per-user inbox that fans out from
Activity.log/1 whenever an activity targets a user other than the actor.
Admins keep using /admin/activity for audit; they do not receive
notifications, so systems with many users do not drown the audit panel.
The V103 migration adds phoenix_kit_notifications with UUID v7 PKs,
cascading FKs to activities + users, per-row seen_at and dismissed_at,
a unique index on (activity_uuid, recipient_uuid), and a partial index
covering the "my undismissed inbox, newest first" read path.
The global notifications_enabled setting (default "true") gates
maybe_create_from_activity/1 so the whole feature can be turned off.
UI is two surfaces, both backed by a per-user PubSub topic
("phoenix_kit:notifications:<user_uuid>"):
- A sticky nested LiveView (PhoenixKitWeb.Live.NotificationsBell)
rendered from LayoutWrapper whenever a user is signed in. Shows the
bell + unread badge + dropdown with 10 most recent rows. Subscribes
to the per-user topic so badge and contents refresh live across
navigation.
- /notifications inbox (PhoenixKitWeb.Live.Users.Notifications) in the
authenticated live_session. Paginated list with Unread/All filter,
per-row mark-seen/dismiss, and bulk Mark all seen / Clear all.
"Seen" is only set on explicit action (clicking a row or Mark all seen).
Opening the bell dropdown does NOT auto-flag anything as seen.
Retention: PhoenixKit.Notifications.PruneWorker runs daily at 04:00,
keyed on the notifications_retention_days setting (falls back to
activity_retention_days, default 90). Cascading deletes also clean up
when the underlying activity is pruned.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>User-activity notifications are not what an admin bell slot should surface — the admin header is for platform-wide signals (PhoenixKit updates, system health) rather than a stream of end-user actions. The NotificationsBell LiveView stays available; parent apps embed it in their own user-facing header when they want it. The /notifications inbox page stays reachable by URL for any signed-in user. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The notifications feature is backend + an embeddable bell LiveView, not a PhoenixKit-owned page. Drops the /notifications route and its LiveView along with the Render/link fallback and the bell's "See all" link that pointed to it. Parent apps embed PhoenixKitWeb.Live.NotificationsBell wherever they have a user-facing header. Row clicks still mark seen + navigate when Render.render(n).link is set; when it's nil the dropdown just refreshes instead of falling back to a dead URL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each user can now mute notification types from the existing UserSettings
LiveComponent. Preferences persist in custom_fields.notification_preferences
so the system remembers them across sessions and restarts. No migration
needed; reuses the V18 JSONB column.
Types are the unit of toggling, not individual actions — three core types
(account, posts, comments) ship with PhoenixKit, and external modules
contribute more via the new optional notification_types/0 callback on
PhoenixKit.Module (mirrors integration_providers/0). Types.list/0 merges
core + discovered, so a new toggle appears in every user's UserSettings
automatically when a module ships one.
maybe_create_from_activity/1 grows one new branch before do_create: ask
Prefs.user_wants?/2 whether the recipient has the type enabled. The
filter fails open — unknown actions, missing prefs, or a failing user
lookup never silently drop a notification.
Render.render/1 also honors three conventional metadata keys —
notification_text, notification_icon, notification_link — before falling
back to the action lookup. This lets any Activity.log/1 caller ship
custom display from outside PhoenixKit without editing the Render module.
UserSettings gets a :notifications section (added to @default_sections)
that iterates Types.list/0 and renders a toggle per type. The existing
hidden-input-before-checkbox idiom and {:phoenix_kit_user_updated, user}
broadcast match the other sections.
AGENTS.md documents the new preferences UI, the notification_types/0
extension point, the metadata override, and a cheat sheet of the three
extension scenarios.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Upstream landed V103 (nested categories) in parallel on the same version slot, so our notifications-table migration moves up one. This is a pure rename: * module name PhoenixKit.Migrations.Postgres.V103 → V104 * file v103.ex → v104.ex * `COMMENT ON TABLE phoenix_kit IS '103'` → '104' on up * `COMMENT ON TABLE phoenix_kit IS '102'` → '103' on down (so the rollback stops at upstream's V103, not jumps past it) * postgres.ex @current_version 103 → 104 and the moduledoc heading * No schema changes Callers that already ran the old V103 locally (pre-upstream-sync) will see the migration system treat the DB as "at 103" and apply V104's DO block idempotently — the CREATE TABLE IF NOT EXISTS is safe either way. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ddon pushed a commit
that referenced
this pull request
Apr 24, 2026
- Per-user notifications driven by Activity.log fan-out; V104 migration, bell LiveView, Render, Types, Prefs, PruneWorker, UserSettings toggles (PR #505) - Admin sidebar dynamic_children_fn now accepts (scope, locale) in addition to (scope), backwards-compatible arity dispatch (PR #506) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ddon pushed a commit
that referenced
this pull request
Apr 24, 2026
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
timujinne added a commit
to timujinne/phoenix_kit
that referenced
this pull request
Apr 28, 2026
Brings in: - phoenix_kit_favicon component (PR BeamLabEU#504) - Per-user notifications module (V104) - dynamic_children/2 with locale (PR BeamLabEU#506) - arity-2 dynamic_children callbacks (PR BeamLabEU#505) - Bump to 1.7.101 - Claude review docs for PRs BeamLabEU#505/506
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.