Commit Graph

262 Commits

Author SHA1 Message Date
Adrien Maston f6b9e765b8 Merge pull request #2619 from basecamp/style-devices-page
Style devices page
2026-03-03 12:20:09 +01:00
Adrien Maston 34ab9c6231 Update saas/app/views/devices/index.html.erb
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-03 12:14:28 +01:00
Jorge Manrubia f2f5254efa Merge pull request #2638 from dainmiller/doc-typos-readme-kamal
Fix small documentation typos
2026-03-03 11:24:00 +01:00
Andy Smith 9cd1167f85 Change exceeding and nearing limits to account for the 1000th card (#2345)
* Change exceeding and nearing limits to account for the 1000th card (instead of 1001)

* Add boundary condition tests for card limit checks

Tests now verify behavior at exactly the limit (1000 cards) and at the
nearing threshold (remaining = 100), covering the off-by-one fix.

---------

Co-authored-by: Jorge Manrubia <jorge@37signals.com>
2026-03-03 10:28:38 +01:00
Jorge Manrubia f6952187c7 Merge pull request #2508 from henrik/patch-1
billing.rb: destroy -> destroy!
2026-03-03 10:25:48 +01:00
Adrien Maston b8f7d5be2f Merge remote-tracking branch 'origin/style-devices-page' into style-devices-page
* origin/style-devices-page:
  Update saas/app/views/devices/index.html.erb
2026-03-02 10:21:14 +01:00
Adrien Maston 0caf9b057b Update empty state test 2026-03-02 10:20:58 +01:00
Adrien Maston fd13ffb5cc Update saas/app/views/devices/index.html.erb
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 10:17:36 +01:00
Dain Miller bdf4459716 Fix small documentation typos 2026-02-28 05:41:55 -05:00
Jay Ohms d758d9913e Hide the subscription panel in the mobile apps 2026-02-27 09:40:05 -05:00
Silvia Uberti 0a83a2db73 Restore sc-chi cache after maintenance.
This reverts commit 4d2e111b01.
2026-02-27 10:30:08 +01:00
Silvia Uberti 4d2e111b01 Temporarily disable sc-chi cache for maintenance. (#2618) 2026-02-27 10:14:50 +01:00
Adrien Maston 3cb5906023 Tweak buttons and let panel grow more 2026-02-26 19:50:23 +01:00
Adrien Maston 04f7c3b66d Change empty state message 2026-02-26 18:06:11 +01:00
Adrien Maston 6c9668d870 Style device list and empty state 2026-02-26 17:15:32 +01:00
Adrien Maston 0fc2ea4af0 Use public layout 2026-02-26 17:15:02 +01:00
Rosa Gutierrez 13268ef668 Add base_url to native push notification payload
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 6fb24118ea Use internal account ID as account_id and add account_slug
In native push payload, to be consistent about how we refer to
this in other endpoints.
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 5bea9633d0 Make APNS and FCM env vars available
To beta and production deploys.
2026-02-25 19:31:13 +01:00
Rosa Gutierrez abef50c503 Fix devices_path route helper in native devices partial
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 92cb749e16 Fix tests for renamed fixtures and new stacked notifications
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>
2026-02-25 19:31:13 +01:00
Fernando Olivares cefc20612a Add creator_familiar_name to push notification payload
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>
2026-02-25 19:31:13 +01:00
Fernando Olivares b1cdb72381 Add creator initials and avatar color to push notification payload
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>
2026-02-25 19:31:13 +01:00
Fernando Olivares 113e61d418 Add avatar_url so we always get an avatar even when the user hasn't set one 2026-02-25 19:31:13 +01:00
Rosa Gutierrez 6ec3cc6f2c Document --push flag for testing native push notifications
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 9c165e1e89 Don't read APNS_TEAM_ID from 1Password
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.
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 5ad1e8cee7 Simplify push.yml to only use B64 encryption keys
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez d1500ad4ec Rename apns-dev to push-dev and unify 1Password credentials
- 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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 126ccb5e3a Add integration test for notification delivery and simplify test helpers
- 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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 6b1598eebb Configure APNS and FCM encryption keys in Kamal secrets
Move encryption keys to base64 password fields for easier Kamal secret
management, and organize them at the root level.
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 7864748be9 Simplify PushTarget by removing template method pattern
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 0948533da7 Rename push to process on PushTarget for clearer semantics
"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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 3621df8f0f Consolidate push jobs into single Notification::PushJob
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 4f19c42958 Move category and high_priority to payload classes
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 9299300dbf Move push priority concerns from Event and Mention into Native push target 2026-02-25 19:31:13 +01:00
Rosa Gutierrez 34fd62faf1 Move devices table to saas database
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 1b53396050 Make devices controller untenanted with engine routes
- 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>
2026-02-25 19:31:13 +01:00
Fernando Olivares c7d0559191 Change priority notification level for mentions and assignments 2026-02-25 19:31:13 +01:00
Rosa Gutierrez ab6bc256eb Link devices to sessions for automatic cleanup on logout
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>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez b5205ce6b2 Rename Push to PushTarget for better readability
PushTarget#push reads more naturally than Push#push. The push target
is the thing that pushes notifications to a specific destination.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 06c9ece058 Move payload method to Notification and make accessors public
The notification now owns its payload via #payload method in Pushable,
allowing direct access like notification.payload.title. Push classes
simply use the notification's payload rather than building it themselves.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 05819f84a2 Refactor notification push system with registry pattern
Replace NotificationPusher with a cleaner architecture:

- Add Notification::Pushable concern with push target registry
- Add Notification::Push base class with template methods
- Add Notification::Push::Web for web push (OSS)
- Add Notification::Push::Native for native push (SaaS)
- Add Notification::WebPushJob and Notification::NativePushJob

Key design:
- Registry pattern: Notification.register_push_target(:web)
- Template method: push calls should_push? then perform_push
- Subclasses override should_push? (with super) and perform_push
- Each target handles its own job enqueueing

Also:
- Add Notification#pushable? for checking push eligibility
- Add Notification#identity delegation to user
- Reorganize tests to match new class structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Tidy up saas engine a bit more
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 555132bbef Change device ownership from User to Identity
Devices now belong to Identity instead of User, allowing a single
device registration to work across all accounts an identity has
access to.

- Move User::Devices to Identity::Devices
- Update DevicesController to use Current.identity
- Update NotificationPusher::Native to use user.identity.devices
- Clean up tests to use @identity directly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Fix reference to `user.devices`, left-over from the identity switch
2026-02-25 19:31:13 +01:00
Rosa Gutierrez d3cc79a5bc Simplify device routes and use ActiveRecord validations
- Use RESTful DELETE /devices/:id where :id can be token or database ID
- Remove redundant unregister collection route
- Remove old Users::DevicesController
- Return 404 when device not found instead of silently succeeding
- Return 422 for invalid platform via ActiveRecord validation
- Update action_push_native to main branch (includes validate: true on enum)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 9d32f3e845 Refactor devices controller and extract registration to model
- Remove Users namespace from DevicesController (now just DevicesController)
- Create ApplicationPushDevice model extending ActionPushNative::Device
- Move device registration logic (find_or_initialize + update) to model
- Update User::Devices concern to use ApplicationPushDevice
- Fix push notification tests (endpoint validation, job count expectations)
- Update push_config_test to use ActionPushNative.config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Fernando Olivares 7e0470a692 Send the URL instead of path in notifications 2026-02-25 19:31:13 +01:00
Fernando Olivares ade39b15ab Add title/body to android notifications too 2026-02-25 19:31:13 +01:00
Fernando Olivares 29d3960a3c Remove UUID requirement from push notification device registration
- Remove UUID column from devices table entirely
- Update unique index from (owner, uuid) to (owner, token)
- Simplify create action to just create device records
- Add token-based unregister route for API clients
- Consolidate error handling with rescue_from
- Update fixtures to remove uuid references

Devices are now identified by (owner, token) instead of UUID.
This simplifies the client-side registration flow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Fernando Olivares 7d04bb514f Add Firebase configuration
- Update local script to load Firebase key
- Configure Firebase projectId in push.yml
2026-02-25 19:31:13 +01:00
Fernando Olivares 55336873b2 Fix database issues and add APNS configuration
- Fix owner_id type to UUID in devices migration
- Fix NOT NULL crash in device registration
- Add APNS config and 1Password integration
- Add --apns flag to bin/dev for local development
- Clean up devices controller
2026-02-25 19:31:13 +01:00