Skip to content

Notifications module intial commit - #505

Merged
ddon merged 7 commits into
BeamLabEU:devfrom
alexdont:dev
Apr 24, 2026
Merged

Notifications module intial commit#505
ddon merged 7 commits into
BeamLabEU:devfrom
alexdont:dev

Conversation

@alexdont

Copy link
Copy Markdown
Contributor

No description provided.

Alexander Donand others added 7 commits April 21, 2026 20:31
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
ddon merged commit bdd6939 into BeamLabEU:devApr 24, 2026
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
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexdont@ddon