* main: (56 commits)
Update app/views/cards/container/_closure_buttons.html.erb
Update app/views/columns/show/_add_card_button.html.erb
Update app/views/events/index/_add_card_button.html.erb
Just return the object
Rename is-main-action to display-as-primary-action
Remove debug line
Rename show-label to display-title
Include path in web push payload for backwards compatibility
Add base_url to native push notification payload
Use internal account ID as `account_id` and add `account_slug`
Make APNS and FCM env vars available
Fix devices_path route helper in native devices partial
Fix tests for renamed fixtures and new stacked notifications
Add creator_familiar_name to push notification payload
Add creator initials and avatar color to push notification payload
Add avatar_url so we always get an avatar even when the user hasn't set one
Document --push flag for testing native push notifications
Don't read APNS_TEAM_ID from 1Password
Simplify push.yml to only use B64 encryption keys
Rename apns-dev to push-dev and unify 1Password credentials
...
Old service workers cached in browsers still read `data.path` from the
push notification payload. Include it alongside `data.url` so notification
clicks keep working until those service workers update.
Currently we only register the service worker in the notification
settings screen, so this won't happen very often. Once we introduce
offline mode, we'll register the service worker in more places, so we
should be able to remove this.
Include the server's base URL so native apps can identify which Fizzy
instance (SaaS or self-hosted) a notification originated from.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The manage devices link used `devices_path` but the route is defined in
the saas engine, so it needs `saas.devices_path`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clear assignee's existing notifications in setup since Notifier now
uses create_or_find_by instead of create, and reload the association
to avoid caching after destroy_all.
Update fixture references after rebase: use `logo_assignment_kevin`
as base notification and `logo_mentioned_david` for mention tests.
Update source to `logo_published` in tests that need generic card events.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Include the shortened familiar name format (e.g., "Salvador D.")
for display in iOS notification titles.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move avatar_background_color logic from helper to User::Avatar concern
so it can be accessed from models. Include creator_id, creator_initials,
and creator_avatar_color in native push notifications for local avatar
rendering on iOS.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
It's a public value like the APNs topic, so just fallback to this value
in push.yml. In this way we have one fewer field we need to maintain
consistently across multiple 1Password items.
- Rename script from apns-dev to push-dev (handles both APNs and FCM)
- Fetch credentials from Deploy/Fizzy Production (same as Kamal)
- Use _B64 env vars to avoid escaping issues with multiline keys
- Update bin/dev flag from --apns to --push
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
In-flight jobs queued before deploy would fail if the old class is
missing. This shim delegates to the new notification.push method.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive integration test covering card assignment, comments,
mentions, email bundling, and edge cases (system user, inactive user)
- Inline push notification test helpers into the only test that uses them
- Remove separate PushNotificationTestHelper module
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The web push payload sends the URL in data.url but the service
worker was looking for data.path, resulting in undefined URLs.
Also fix WebPush::Notification test to use url instead of path
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Each target now implements process directly with its own logic,
rather than using processable?/perform_push hooks. The pushable?
check is done once in Notification#push before iterating targets.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
"Push to target" reads naturally - we push the notification to the
target. "Target processes" also makes sense - the target receives
and handles the notification in its own way.
- Add class method PushTarget.process(notification) that instantiates
and calls the instance method
- Rename instance method from push to process
- Add private push_to helper in Pushable for readable iteration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace separate WebPushJob and NativePushJob with a single PushJob
that calls notification.push, which iterates over registered targets.
Each target handles its own delivery - Web pushes synchronously via
the pool, Native enqueues device-level jobs via deliver_later_to.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use polymorphism instead of case statements in Native push target:
- DefaultPayload#category returns "default", #high_priority? returns false
- EventPayload#category returns "assignment"/"comment"/"card" based on action
- MentionPayload#category returns "mention", #high_priority? returns true
This simplifies the Native push target by delegating source-specific
logic to the appropriate payload classes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use ActionPushNative's new on_load hook to configure the database connection,
following the same pattern as Active Storage and Action Text:
ActiveSupport.on_load(:action_push_native_record) do
connects_to database: { writing: :saas, reading: :saas }
end
This allows ApplicationPushDevice to inherit directly from ActionPushNative::Device
without needing an intermediate abstract class.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add disallow_account_scope to skip tenant requirement
- Move routes to saas/config/routes.rb (engine routes)
- Use saas.devices_path/saas.device_path for engine route helpers
- Update tests to work without tenant context
Devices belong to Identity (global), not Account, so they don't
need tenant context in the URL.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Devices should persist independently of sessions - when a session is
deleted, the device registration should remain valid.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidates the session reference and index cleanup into the original
CreateActionPushNativeDevices migration for a cleaner migration history.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The unique (owner_type, owner_id, token) index already serves queries
filtering by (owner_type, owner_id) via its leftmost prefix.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a session is destroyed (user logs out), all devices registered
to that session are automatically destroyed, preventing push
notifications from being sent to logged-out devices.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>