feat: skipping section & event announcements rework#28
Merged
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New table to track multiple announcement messages per event. Includes migration, repo with CRUD operations, and unit tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- resolveEventByMessageId checks event_announcements first - announceEvent stores row in event_announcements table - refreshAnnouncement iterates all announcement rows - updateAnnouncementMessage delegates to refreshAnnouncement for private events - All callback handlers use resolver instead of direct findByMessageId Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add eventAnnouncementRepository to mock container - Update assertion format: "Participants —" → "✋ Playing —" - Remove "(nobody yet)" assertions (no longer shown) - Update leave tests: markAsOut instead of removeFromEvent - Fix BTN_LEAVE assertion: "👋 I'm out" → "😢 I'm out" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update announceEvent to send individual DMs to each participant - Add isOwner parameter to buildInlineKeyboard for per-user keyboards - Send DM to newly added participants via +participant wizard - Create event_announcements row for each sent DM - Update refreshAnnouncement to pass isOwner per announcement - Add integration tests for private event DM flow Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Husky v9 runs hooks via sh which defaults to node v20, but native modules (better-sqlite3) are compiled for v22. This caused ERR_DLOPEN_FAILED and all tests to fail during git push. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migration entries 0002/0003 had `when` timestamps earlier than 0000/0001, which may cause drizzle migrator to skip them when applying on a production dump that already has 0000/0001 recorded. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bump actions/checkout v4→v6, actions/setup-node v4→v6, codecov/codecov-action v4→v5 to resolve Node.js 20 deprecation warnings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Switch from bot.start() to @grammyjs/runner for concurrent update processing, enabling in-memory locks to actually prevent race conditions - Add per-user-per-event locking in handleJoin/handleLeave with composite key (eventId:userId) and "⏳ In progress" callback - Add descriptive callback texts: "Joined ✋", "Joined (×N) ✋", "Welcome back! ✋", "You're out 😢", "You're already skipping" - Optimize addToEvent to return participations via RETURNING clause, eliminating extra findEventParticipant query after insert - Add debug logging to EventLock and join/leave handlers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move getEventParticipants/notifyOwner and logging outside the lock in handleJoin and handleLeave so the lock is held for the minimum duration (only DB write + announcement update) - Add BotBlockedError to transport layer: sendMessage now maps GrammyError 403 → BotBlockedError, silently drops 429 with warning - Fix notifyOwner fallback: on BotBlockedError send the standard "I can't reach you" message to main chat instead of the original notification (was leaking owner-only messages to group on 429) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Transport: test 403 → BotBlockedError, 429 → silent return 0, 500 → rethrow - Business: test notifyOwner fallback sends standard "can't reach" message on BotBlockedError, and does NOT fallback on other errors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
event_announcementstable to support multiple announcement messages per event (one per participant DM for private events)Changes
Data model
event_participants.statuscolumn ('in' | 'out') — tracks who's playing vs skippingevent_announcementstable — stores telegram message/chat IDs for each announcement messageAnnouncement format
status = 'in'status = 'out'Button behavior
out, shows in SkippingoutstatusPrivate events
announceEventsends individual DMs to each participant + ownerevent_announcementsrowTest plan
🤖 Generated with Claude Code