Rebuilds search records for every published Card and every Comment on a
published Card. Intended for manual invocation after a search-index loss
event — not a recurring job.
Uses ActiveJob::Continuable so the work survives worker restarts and
resumes from the last-processed id. The job is idempotent.
Removes script/maintenance/reindex_stale_search_records.rb, which was
written against a different hypothesis (a date-cutoff backfill) and is
superseded by this unconditional repair job.
Account::Searchable#clear_search_records called
Search::Record.for(id).destroy_all which deleted every row in the
shard's table, wiping search records belonging to every other account
that happened to hash to the same shard.
ref: https://3.basecamp.com/2914079/buckets/27/card_tables/cards/9782824728
The data import path (Account::DataTransfer) uses insert_all! which
bypasses ActiveRecord callbacks, so imported cards and comments never
get search records created and are invisible to search and card-table
filtering.
This script reindexes all published cards and comments created before
a cutoff date (default 2026-04-01). The reindex method is an upsert
so already-indexed records get a harmless update.
Usage:
bin/rails runner script/maintenance/reindex_stale_search_records.rb
bin/rails runner script/maintenance/reindex_stale_search_records.rb 2026-01-01
Edge Rails introduced ActionText::Attachable#to_editor_content_attachment_partial_path
which defaults to to_partial_path ("users/user"). Override it in User::Mentionable to
delegate to to_attachable_partial_path ("users/attachable"), matching the existing
display rendering path.
Tag was never actually embedded as an action-text-attachment in
persisted rich text. It was only used in the Fizzy Do command prompt
input which was not stored. The data transfer tests happened to use Tag
as a convenient fixture — switch them to User, which is genuinely
attachable via mentions.
The tags prompt was added for the Fizzy Do command system, but became
dead code when commands were removed in 89af9066. The commands_prompt
was cleaned up but tags_prompt was missed.
Remove the Tag::Attachable concern, Prompts::TagsController, its views
and route, and the tags_prompt helper. Tag still includes
ActionText::Attachable directly, which is needed by the data transfer
system.
* Extract shared DnsTestHelper from duplicated stub_dns_resolution methods
* Fix flaky WebTest by stubbing DNS resolution for push subscription creation
* Update lexxy to 0.9.5.beta
* Fix syntax highlight controller for lexxy 0.9.5.beta
The highlightAll export was renamed to highlightCode.
---------
Co-authored-by: Mike Dalessio <mike@37signals.com>
Using fizzy.localhost causes CORS errors when using minio for Active
Storage because the minio endpoint is at minio.fizzy.localhost — a
sibling subdomain, not a subdomain of the app host. Switching to
app.fizzy.localhost makes both hosts subdomains of fizzy.localhost,
resolving the CORS issue. See #2814 for the related minio CORS fix.
fizzy.localhost will continue to work if people want to use it, but all
docs and scripts have been updated to point to app.fizzy.localhost.
ActiveStorage::Record and ApplicationRecord used separate connection
pools (from separate `connects_to` calls). This meant `belongs_to
touch: true` on attachments silently failed — the card couldn't join the
attachment's transaction to receive the deferred touch, so fragment
caches were never invalidated after image removal.
Fix by delegating `connection_pool` from ActiveStorage::Record to
ApplicationRecord so they share a single pool.
* Detect dependency requirement drift in bin/bundle-drift
The checker only compared resolved spec versions between Gemfile.lock
and Gemfile.saas.lock. When dependabot bumped solid_queue from ~> 1.3
to ~> 1.4, the forward command patched the resolved version but left
the stale dependency requirement. The checker didn't catch it because
both lockfiles resolved to the same version.
Now find_drift also compares dependency requirements for shared direct
dependencies, and forward patches the DEPENDENCIES section too.
Includes built-in self-test (bin/bundle-drift self-test).
* Sync solid_queue dependency requirement in Gemfile.saas.lock
Updates ~> 1.3 to ~> 1.4 to match Gemfile.lock.
Move MinIO from minio.localhost to minio.fizzy.localhost, which makes
it same-site with the app, so the CORS redirect succeeds.
The service worker fetches Active Storage URLs with `mode: "cors"` so
it can inspect response sizes for offline caching. Active Storage's
redirect controller returns a 302 to the MinIO presigned URL. When
that redirect crosses site boundaries (from fizzy.localhost to
minio.localhost), the browser sets the Origin header to "null" on the
redirected request per the Fetch spec, which fails the CORS check and
produces net::ERR_FAILED.
* Upgrade addressable from 2.8.9 to 2.9.0
Security release fixing ReDoS vulnerabilities in Addressable::Template#match.
No application impact — fizzy does not use Addressable::Template directly.
* dep: fix saas drift
* Add JSON API support for timezone update
* Simplify timezone controller to just head :no_content
* Use PUT instead of PATCH in timezone tests to match docs
* Use PATCH instead of PUT for timezone endpoint
Reverts tests to use patch and updates docs heading to PATCH
for consistency.
* Add JSON events API endpoint
* Add regression test for event particulars defaults
* Move JSON events API to a dedicated ActivitiesController
The events endpoint served both the HTML day timeline and the JSON API
feed, but the two paths shared no data or behavior — the HTML side uses
DayTimelinesScoped while the JSON side built its own query. Splitting
into ActivitiesController gives the API its own home at
GET /:account/activities.json without dragging in the timeline
before_actions.
Also preloads comment creator in Event.preloaded to avoid an N+1 when
rendering comment eventables in the JSON feed.
* Add board settings fields to board JSON responses
* Move public_description fields to board partial, gate on published
* Add index test for public_description fields on published boards
* Update app/views/boards/show.json.jbuilder
Prefer `unless` to `if !`
---------
Co-authored-by: Mike Dalessio <mike.dalessio@gmail.com>
* Document avatar removal API endpoint
* Document notification settings API endpoints
* Document access token list and delete API endpoints
* Document join code API endpoints
* Fix access token delete URL parameter name in docs
* Split docs/API.md into per-resource sections under docs/api/
* Move API endpoints index above authentication in docs/api/README.md
* Fix trailing comma in boards.md JSON example
* Fix trailing comma in cards.md, add Response label to identity.md, add Rich Text to endpoint index