The magic link verification endpoint now returns `requires_signup_completion`
to indicate whether the client needs to collect a name and complete signup.
The signup completion endpoint now supports JSON responses with the account ID.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This is so that native API clients can get the session record deleted
server-side. They still need to take care of clearing any cookies
they've set in web views.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* main: (127 commits)
Align board name start so it doesn't get too big
Clean up card/events header layout
Sync email to Stripe when user changes email address (#2432)
Fix IDOR in webhook activation endpoint (#2431)
Add card reactions to API docs and reactions_url to card JSON (#2427)
Remove unnecessary claude plan
Allow boosts on cards (#2411)
Revert "Fix notification click URL by using correct data property"
Add migration to remove draft cards from search index
Guard search indexing with searchable? check
Forbid comments on draft cards
prefactor: update search to use published cards
Fix notification click URL by using correct data property
Wait for service worker to be active before subscribing
Fix stuck state when permission granted but no subscription
Extract Card::Commentable
Include arm64 build in Docker workflow
Remove unnecessary `await` in push handler
Correctly initialise WebPush connection (#2417)
Update models, views, and fixtures for polymorphic reactions
...
The webhook activation controller was using account-scoped lookup
instead of board-scoped lookup, allowing users to reactivate webhooks
on boards they don't have access to.
This was an oversight when board-scoping was added to the main webhooks
controller - the activations controller was missed in that update.
The fix adds the BoardScoped concern to properly restrict webhook
activation to boards the user has explicit access to.
* Add reactions association to Card model
Adds `has_many :reactions` to Card, matching the implementation in Comment.
This allows cards to be reacted to directly with emoji reactions.
The association:
- Orders reactions chronologically
- Uses polymorphic `:reactable` interface
- Deletes reactions when card is destroyed
Includes test coverage for the new association.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add reactions UI to card detail view
- Create Cards::ReactionsController with turbo stream responses
- Add card reactions views (reactions list, new form, menu partial)
- Position reaction button flush-right when no reactions exist
- Show reactions on bottom-left when present, with button inline
- Handle narrow viewports by flowing button below meta section
- Add controller tests for card reactions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add boost count to card preview
Display reaction count alongside comment count on card tiles in board
columns. Introduces a .card__counts wrapper to group both counts with
proper positioning on all viewport sizes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Consolidate reaction views for cards and comments
Extract shared views to app/views/reactions/ using polymorphic routing.
Both card and comment reactions now render the same partials, with a
helper to compute the correct path prefix for nested routes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix emoji picker width in card reactions
Override .card .popup { inline-size: 260px } for the reaction popup
so the emoji grid displays without horizontal scrollbar.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Hide boost count where comment count is hidden
Add .card__boosts alongside .card__comments in:
- Tray view (display: none)
- Cards with background images (opacity toggle on hover)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix reactions button overlap with zoom button in card footer
When a card has a background image, the footer contains both a reactions
button and a zoom button. Previously they would overlap because the
reactions button was absolutely positioned to the bottom-right.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Tighten up previews
* Move card reactions from meta partial to container
Fixes two issues:
1. Reactions were duplicated each time a card was assigned because the
turbo stream replaced the meta div with the full perma/meta partial,
which included reactions outside the replaced element.
2. Draft cards incorrectly showed the boost button because the meta
partial was shared between published and draft containers.
Moving reactions to _container.html.erb (published cards only) fixes
both issues and keeps the meta partial focused on meta content.
Fixes https://app.fizzy.do/5986089/cards/3837
Fixes https://app.fizzy.do/5986089/cards/3835
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* WIP adjust perma page
* Position and style the footer
* Render the stamp in the card body instead of the footer
* Fix undefined local variable in public cards view
Changed `card` to `@card` when rendering the stamp partial.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Preload card reactions to avoid N+1 queries
Include reactions and their reacters in the preloaded scope, matching
what we already do for comments.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add model tests for card and comment reaction cleanup
Test that:
- Creating a card reaction touches the card's last_active_at
- Reactions are deleted when their parent comment is destroyed
- Reactions are deleted when their parent card is destroyed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Minor improvements to reactions code
- Use size instead of count in boosts partial to avoid extra SQL query
on already-loaded collection
- Add else clause to reaction_path_prefix_for to raise ArgumentError
for unknown reactable types instead of silently returning nil
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Bump specificity of reaction popup in the card perma
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Smith <andy@37signals.com>
- Add Card#commentable? method that returns true only for published cards.
- CardsController#create ensures that the card is commentable.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a SelfAssignmentsController to resolve the current user at request
time, avoiding the use of an incorrect user id baked into a cached URL.
ref: #2211 originally added the "M" hotkey
ref: https://app.fizzy.do/5986089/cards/3722
Skipping API responses, where we need absolute URLs, and those that are
intended for sharing or external use:
- account/join_codes/show.html.erb - Join code URL for sharing
- boards/edit/_publication.html.erb - Publication URL for sharing
- public/* views - Public page URLs and og:url meta tags
- pwa/manifest.json.erb - PWA manifest needs absolute URLs
For this, we had to replace `url_for` used with Active Storage variants
and previews with the specific path helper (for Active Storage
representations).
* Add self-service account deletion
* Disable access to cancelled accounts & implement Stripe interactions
* Add tests
* Fix failing tests
* Remove cancelled accounts from lists
* Fix incorrect redirect
* Use _path instead of _url for consistency
* Don't track how far the inicieration job got
We still want the step tracking so that the job can be interrupted. But, since the scope is idempotent, we don't need to track how far it got.
* Specify the exact time when the data will be deleted
* Fix crash due to unadvancable cursor
* Rename up_for_incineration to due_for_incineration
* Regenrate the schema
* Fix incorrect path check
* Migrate the SQLite schema
* Only show the cancel button on cancellable accounts
* Check that a subscirption method exists before calling it
* Ignore job failures due to missing records when an account gets deleted
* Skip sending notifications on cancelled accounts
* Use collbacks to integrate
* Add a blank line between queue_as and discard_on
* Break checks into methods
* Inline methods
* Rename Account::IncinerateJob
* Run migrations
* Migrate SQLite
In this case requests won't be performed from a secure context [1] and
the browser won't send the Sec-Fetch-Site header. This means non-GET
requests will be rejected because CSRF protection will fail.
With this change, we allow these requests with missing Sec-Fetch-Site
headers if:
- They happen over HTTP
- The app is not configured to force SSL
The Origin check happens in any case.
[1] https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts#potentially_trustworthy_origins
Use the more idiomatic ActiveRecord ids method instead of pluck(:id)
across controllers and models. The ids method is more readable and
explicitly conveys the intent to retrieve primary key values.
Changes:
- BoardsController#edit: Use @board.users.ids
- Board::Storage: Use cards.ids, Comment.where().ids, and ActionText::RichText.where().ids
- User::Accessor: Use account.boards.all_access.ids
This change improves code clarity while maintaining the same functionality.
We don't allow changing the status via this action, and it's confusing
and can lead to cases where someone can set someone's else card as
draft, effectively hiding it.