Skip to content

Conversation

@olivaresf
Copy link
Contributor

@olivaresf olivaresf commented Jan 19, 2026

Enables native push notifications for iOS and Android on Fizzy-SaaS.

  • Adds the action_push_native gem (v0.3.0) to enable native mobile push notifications for iOS and Android devices
  • Sets up foundation for APNS (Apple Push Notification Service) and FCM (Firebase Cloud Messaging)

olivaresf and others added 30 commits January 14, 2026 14:38
Phase 1 of native push notifications implementation:

- Add action_push_native gem to Gemfile.saas for SaaS-only native push
- Add migration for action_push_native_devices table
- Create ApplicationPushNotification model in saas/app/models/
- Create ApplicationPushNotificationJob in saas/app/jobs/
- Create push.yml config in saas/config/ with APNs/FCM settings

The migration needs MySQL running to execute (SaaS mode uses MySQL).
Config placeholders (team_id, topic, project_id) need to be filled in.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Include the devices association in User model via the SaaS engine
to prepare for device registration functionality.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /users/devices routes for device registration
- Create DevicesController with index, create, destroy actions
- Add devices index view for managing registered devices
- Add native_devices partial to notification settings (SaaS only)
- Add skeleton controller tests for Phase 4 implementation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create NotificationPusher::Native concern for sending to native devices
- Prepend native concern via SaaS engine
- Add device fixtures for testing
- Add PushNotificationTestHelper for test assertions
- Implement full controller tests for device registration
- Add NotificationPusher model tests for native push logic

Native push notifications now send alongside web push when users
have registered mobile devices. Supports iOS (APNs) and Android (FCM)
with platform-specific features like time-sensitive delivery and
data-only messages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The schema version was set to the first migration's timestamp
(2026_01_14_203313) but already included the unique index from
the second migration (2026_01_15_000000). This updates the version
to correctly reflect all applied migrations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the push_to_web method which duplicated the base class's
push_to_user logic. Now directly calls push_to_user with a guard
for empty subscriptions, keeping the optimization while reducing
code duplication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Devices are now identified by (owner, uuid) instead of token alone.
This allows multiple users to have device records with the same push
token, with notifications correctly routed to the authenticated user.

Key changes:
- Add uuid column to action_push_native_devices
- Replace unique index on token with composite (owner_type, owner_id, uuid)
- Controller now looks up by user + uuid, updates token on registration
- Require uuid parameter in device registration API

This prevents potential token hijacking where one user could take over
another user's push notifications by registering their token.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Verifies that when a user has both web push subscriptions and native
devices registered, notifications are delivered to both channels.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace three separate migrations with one that creates the
action_push_native_devices table with the final schema:
- uuid column (not null)
- Composite unique index on (owner_type, owner_id, uuid)

This avoids unnecessary intermediate schema changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The _native_devices partial now lives in the SaaS engine and is only
rendered when Fizzy.saas? is true. This keeps SaaS-specific views
out of the self-hosted codebase entirely.

In self-hosted mode, the partial doesn't exist and the render call
is skipped via the conditional. If someone tried to render it directly,
Rails would raise ActionView::MissingTemplate.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clearer naming now that we have both web and native push delivery.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use find_or_initialize_by instead of find_or_create_by to avoid
inserting a record with only uuid before all required fields are set.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fizzy uses UUID primary keys, so the polymorphic owner reference
needs to specify type: :uuid to match.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Native push is disabled in local environments by default, but can now
be enabled by setting ENABLE_NATIVE_PUSH=true for testing the full
push notification flow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Usage: bin/dev --apns

This loads APNs credentials from 1Password and enables native push
delivery in development. Requires SaaS mode to be enabled.

Also updates apns-dev to export ENABLE_NATIVE_PUSH=true so that
loading credentials automatically enables push delivery.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Native push notifications require SaaS mode, so automatically enable
it when the --apns flag is used instead of showing an error.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@olivaresf olivaresf requested a review from rosa January 19, 2026 15:12
* origin/main: (96 commits)
  Fix notification broadcast test for turbo-rails 2.0.21
  Update `turbo-rails` to get latest Turbo version
  Remove reference to removed controller
  Fix bad formatting on bridge page title attr
  Use private functions for bridge components
  Setup focus handling on touch target's connect callback
  Setup proper focus handling for mobile on the card perma's board picker
  Move dialog focus handling into the dialog controller
  Create popup initial alignment classes
  Fix class typo
  Hide the board selector button if card is closed
  Align board and tag picker dialogs without using math
  Add dialog manager to card perma
  Fix "M" hotkey using stale user from fragment cache
  Solve problem when Action Text raises on missing attachables
  Solve problem when Action Text raises on missing attachables
  Completing a step removes stalled status from UI
  Bump Bootsnap to v1.21.1
  Add Enable all/Disable all buttons to webhook event selection
  Use correct class selectors to target cards with  background images
  ...
Sign up for free to 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.

1 participant