Commit Graph

62 Commits

Author SHA1 Message Date
Mike Dalessio 9aa15e9fb2 Forbid comments on draft cards
- 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>
2026-01-23 11:28:26 -05:00
Mike Dalessio ffab4cad6f Update models, views, and fixtures for polymorphic reactions
- Reaction: belongs_to :reactable (polymorphic) instead of :comment
- Comment: has_many :reactions with as: :reactable
- Views: use reaction.reactable instead of reaction.comment
- Fixtures: use polymorphic syntax for reactable association

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 12:29:54 -05:00
Rosa Gutierrez 196d685f8d Implement authorization for Active Storage endpoints
Consider blobs attached to any public records accessible to anyone with
the URL.
2025-12-25 21:22:36 +01:00
Ítalo Matos fbc586646f Refactor: improve query scope composition with merge syntax (#2131)
* Refactor: improve query scope composition with merge syntax

Replace manual WHERE clause concatenation with Rails' merge method
for more elegant and maintainable scope composition across Card,
Comment, and Filter models. This approach better follows Rails
conventions and improves code readability.

* Extend scope composition improvements to Card::Closeable

Apply the same nested hash syntax pattern to closures table references
in order and where clauses.

* Remove unnecessary outer braces from where clause

---------

Co-authored-by: Jeremy Daer <jeremy@37signals.com>
2025-12-13 10:10:13 -08:00
Jeremy Daer 761d0b4a76 Speedy, auditable, deadlock-resistant storage tracking (#2026)
An append-only storage ledger replaces deadlock-prone synchronous
counter updates and drift-prone async updates.

All content storage (card images, card/comment/board description embeds)
is tracked. Account exports (which expire) and avatars are not tracked.

Storage is accounted for by Account and Board. Both consume the same
event stream independently: no bubble-up storage bumps triggering
deadlocks due to lock sequencing. Each calculates its own total from
the underlying ledger with independent cursors and materialization.

* Storage::Entry: Append-only ledger recording attach/detach/transfer
  events with delta bytes. Single event stream indexed for both
  Account and Board cursor queries.

* Storage::Total: Polymorphic snapshot cache with cursor (last_entry_id)
  tracking which entries have been materialized.

* Storage::Totaled concern: Provides bytes_used (fast snapshot) and
  bytes_used_exact (snapshot + pending) query modes, plus
  materialize_storage! to roll up pending entries.

* Storage::Tracked concern: For models owning attachments (Card,
  Comment, Board). Provides board_for_storage_tracking for models
  where board is determined differently (Board returns self).
  Handles board transfers by recording transfer_out/transfer_in entries.

* Storage::AttachmentTracking: Hooks ActiveStorage::Attachment lifecycle
  to record attach/detach entries. Handles ActionText::RichText embeds
  by traversing to the actual model. Snapshots context in before_destroy
  to handle cascading deletes where parent record may be gone by
  after_destroy_commit.

* MaterializeJob: Rolls up pending entries into snapshot. Concurrency
  limited per owner to prevent duplicate work.

* ReconcileJob: On-demand reconciliation against actual attachment
  storage for support/debugging. Compares ledger total to real bytes
  from card images, card embeds, comment embeds, and board embeds.

Usage:
* account.bytes_used / board.bytes_used: fast, slightly stale bytesize
* account.bytes_used_exact / board.bytes_used_exact: real-time bytesize
* Storage::Entry: audit trail for debugging and point-in-time queries
2025-12-10 16:04:30 -08:00
Mike Dalessio 79c9ea2ce1 Remove a bunch of N+1s
related to notification and comment rendering
2025-11-27 11:08:45 -05:00
Stanko K.R. 8fa9566c07 Update sign up 2025-11-17 09:12:40 -05:00
Donal McBreen fc56ad9d7c Combine uuid-old and uuid branch changes
- Switch to binary 16 for UUID keys
- Remove AccountScopedRecord base class, all model use binary uuids now
- Fix the search sql to serialize uuids properly
- Patch the MySQL schema dumper to output binary lengths
2025-11-17 09:12:34 -05:00
Mike Dalessio e4011ef211 Update primary keys on customer data to UUIDs
- schema changes to primary and foreign keys
- fixture changes
- customer data models subclass AccountScopedRecord
- import script updated
2025-11-17 09:12:30 -05:00
Donal McBreen e8abc66eba MySQL search
Add a single search_index table for full-text search of cards and
comments.

For the search there is a full-text index on the title and content
columns. The board_ids is also included in the table and accessible
board ids are pre-loaded and included in the search query. This allows
us to filter out inaccessible records before joining with other tables.

Right now the search is just using boolean search. This would give us
a bunch of syntax options
(see https://dev.mysql.com/doc/refman/8.4/en/fulltext-boolean.html)
except the search query filters those out.

I've removed the searchable_by method for now - everything is built
on the assumption that there's a single search index table and all data
must fit into it.

Queries are written in SQL, we don't have a SearchIndex ActiveRecord
model. That's because we'll likely want to shard the table and it will
be simpler to just keep with the raw SQL for that.

There's no stemming, highlighting or snippet extraction yet - we are
dumping the full description in the search results.

Data can be reindexed with the search:reindex rake task.
2025-11-17 09:12:17 -05:00
Stanko K.R. ba3f6b188e Add account_id to everything 2025-11-17 09:11:42 -05:00
Jorge Manrubia 03a345609e Baseline replacing collection with board across code 2025-11-05 13:31:54 +01:00
Stanko K.R. 10728e35ef Create scopes for filtering comment by user or system 2025-08-14 14:32:10 +02:00
Jorge Manrubia 8bb7783215 Extract "prompt generation" logic to models for events, comments and cards
So that we can reuse in other scenarios
2025-07-24 16:48:03 +02:00
Jason Zimdars 485e575c40 Merge branch 'main' into card-attachments
* main: (45 commits)
  Display tag counts in the filter menu
  Move Add Card button to header
  Re-write help content, try a modal-like display
  Move to internal registry
  Show date instead of time for notifications older than 1 day
  Ensure checks are visible for tags and assignments
  Adjust padding so card number isn't cut off
  Don't color the collection header in considering
  Golden cards bubble to the top of Considering, too
  Adjust card collection header when colored golden
  Allow cards in Considering to gilded
  Hide focus ring on new card titles and step inputs
  Add hover effect for comment edit button
  Add hover effect to overflow button
  Improve multi-account behavior of the PWA
  Remove unneeded *
  Rename test
  Review the code to move cards
  Update editor
  Generalize and delete mentions too
  ...
2025-07-08 16:04:14 -05:00
Jorge Manrubia cbeefc5b74 Remove unused code 2025-07-04 19:00:22 +02:00
Jorge Manrubia b8b4ef5463 Extract common concern to examine attachments 2025-07-04 17:53:37 +02:00
Jason Zimdars 0539d366d7 Display attachments in events for comments 2025-07-03 16:48:43 -05:00
Jorge Manrubia 0997b45e37 Make searchable work with multiple fields and index card descriptions as separated columns 2025-06-24 08:03:25 +02:00
Jorge Manrubia fa04016cbe Revert "Revert "Replace House with Lexical"" 2025-05-29 14:25:16 +02:00
Jorge Manrubia 08d8b2e5ff Revert "Replace House with Lexical" 2025-05-29 14:22:27 +02:00
Jorge Manrubia 10b2aad647 Replace House with lexical-powered actiontext 2025-05-23 11:41:08 +02:00
Jorge Manrubia 9d7438ba25 Use similarity searches and refined prompt 2025-05-16 13:29:18 +02:00
Jorge Manrubia 2b98db9e66 Flatten out comments and messages
https://37s.fizzy.37signals.com/collections/693169850/cards/999008989#comment_994777841
2025-04-29 19:21:18 +02:00
Jorge Manrubia 82885e453d Not needed anymore 2025-04-26 09:13:24 +02:00
Jorge Manrubia 905ccb9b4b Make comments the event's host 2025-04-24 13:45:48 +02:00
Jorge Manrubia edcc9e3279 Add mentionees as watchers 2025-04-23 12:38:06 +02:00
Jorge Manrubia 9b4fec936e Move mentions to comments
- It does not make sense to scan "event summaries" for notifications.
- Placing them at the message level prevents us from using the generic approach to extract the mentionable content
2025-04-22 16:17:37 +02:00
David Heinemeier Hansson 706178f3c4 Better naming 2025-04-12 13:33:54 +02:00
David Heinemeier Hansson d4a31fec6d Dont overload the main transaction
Even if we are going to get rid of this cleanup_events stuff.
2025-04-12 13:33:06 +02:00
David Heinemeier Hansson 2357c75063 Reads better with a verb first 2025-04-12 13:09:49 +02:00
David Heinemeier Hansson 0031ce34ea Correct order 2025-04-12 11:46:17 +02:00
David Heinemeier Hansson e4efe446e6 Simlpe callback is actually enough
Since the Comment already knows about the card.
2025-04-12 11:45:34 +02:00
David Heinemeier Hansson f2c2b0492e Have to solve this in an overhaul of events 2025-04-12 11:42:50 +02:00
David Heinemeier Hansson f5b30456a0 Comments arent part of event summaries any more 2025-04-12 11:42:41 +02:00
David Heinemeier Hansson 81a89dbda1 Comments should always have messages 2025-04-12 11:23:45 +02:00
David Heinemeier Hansson cef8899bda Comments are not currently used as notifiables 2025-04-12 11:18:59 +02:00
David Heinemeier Hansson 9f1c3ae046 Note my discontent 2025-04-12 11:17:01 +02:00
David Heinemeier Hansson 63c05220ce Clearer naming 2025-04-12 11:09:55 +02:00
David Heinemeier Hansson 27d90abbd6 Reduce the direct knowledge of comments inside the card 2025-04-12 11:04:16 +02:00
David Heinemeier Hansson b698eefa06 Messageables already have access to the card 2025-04-12 11:00:15 +02:00
David Heinemeier Hansson 60a0360203 Remove more activity scoring related to comments 2025-04-12 10:52:48 +02:00
David Heinemeier Hansson fb733b9a60 No more tracking commenting as an activity for sorting
We are doing away with all the automated activity scoring, but for now
lets just get rid of it for comments.
2025-04-12 10:50:25 +02:00
David Heinemeier Hansson 81f431d946 Comment-specific behavior needs to live in the comment
This really is a bit of a tangled mess. Everyone knows everything about
everyone else.
2025-04-12 10:39:56 +02:00
David Heinemeier Hansson 80bc1dd163 Reactions dont have any callbacks so can just be deleted 2025-04-12 10:15:38 +02:00
David Heinemeier Hansson f4ce57e308 Move comments under cards 2025-04-11 16:21:44 +02:00
David Heinemeier Hansson 64b529ce94 Fix indention 2025-04-11 16:12:18 +02:00
Jorge Manrubia 723e6d94f5 Rename bubbles => cards 2025-04-09 14:50:58 +02:00
Kevin McConnell 16a80ff3a6 More dynamic activity scores
This introduces a more dynamic system of activity scoring, to improve
the way bubbles "bubble up" due to their activity. There are a few
different parts we can tune here, and it's likely we'll need to make
adjustments once we get a feel for how this works in practice.

The basic idea here is:

- We assign points for certain types of event that happen on a bubble. A
  boost gets 1 point, a comment gets 10 points, and so on.
- These points decay over time, at a rate of 50% per day. So old
  activity is worth much less than new activity. Bubbles should rise up
  quickly when acted upon, bit will float back down if left idle.
- Some comments can score higher than others: the first comment from
  each person on a bubble is worth more (20) because it signals that
  more people are getting involved; and comments that follow a comment
  by a different author are also worth more (15) because that signals
  there's ongoing conversation between people, not just a series of
  notes being left by one individual.

In terms of implementation, we persist the score on the bubble
whenever it changes, but we handle the decay on the client side. That
allows us to cache the bubble representation without having to
continually change it while its activity decays.

We also keep a separate `activity_score_order` attribute on the model.
This can be used to sort the bubbles in order of "most active", without
having to think about the decay.
2025-03-05 17:16:31 +00:00
Jason Zimdars cd534391c1 Delete referenced events when deleting comments 2025-02-24 13:24:49 -06:00