Skip to content

feat: skipping section & event announcements rework#28

Merged
pmyagkov merged 16 commits intomasterfrom
feature/skipping-section
Mar 16, 2026
Merged

feat: skipping section & event announcements rework#28
pmyagkov merged 16 commits intomasterfrom
feature/skipping-section

Conversation

@pmyagkov
Copy link
Copy Markdown
Owner

Summary

  • Add "😢 Skipping" section to event announcements — users who click "I'm out" now appear in a dedicated section instead of being silently removed
  • Introduce event_announcements table to support multiple announcement messages per event (one per participant DM for private events)
  • Rework private event announcements: each participant receives a personal DM with their own keyboard (owner gets management buttons, others get join/leave only)
  • Fix pre-push hook to load nvm for correct node version (was using v20 instead of v22, causing native module failures)

Changes

Data model

  • event_participants.status column ('in' | 'out') — tracks who's playing vs skipping
  • event_announcements table — stores telegram message/chat IDs for each announcement message

Announcement format

  • "✋ Playing — N:" section shown when participants have status = 'in'
  • "😢 Skipping — N:" section shown when participants have status = 'out'
  • Empty event shows no participant sections

Button behavior

  • "I'm out" from registered user → marks as out, shows in Skipping
  • "I'm out" from unregistered user → creates with out status
  • "I'm in" from skipping user → "Welcome back! ✋", moves to Playing
  • Double "I'm out" → no-op with "You're already skipping"

Private events

  • announceEvent sends individual DMs to each participant + owner
  • Owner DM includes management buttons (+/- Participant, courts, finalize, cancel)
  • Adding a participant sends them a DM and creates event_announcements row
  • All DMs updated when any participant change happens

Test plan

  • 758 tests passing (77 files)
  • Typecheck clean
  • Lint clean
  • New integration tests for skipping flow (4 tests) and private DM flow (2 tests)
  • Updated existing tests for new assertion formats

🤖 Generated with Claude Code

pmyagkov and others added 10 commits March 9, 2026 15:07
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>
pmyagkov and others added 2 commits March 14, 2026 15:29
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>
pmyagkov and others added 3 commits March 16, 2026 12:38
- 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>
@pmyagkov pmyagkov merged commit 1fd16ba into master Mar 16, 2026
4 checks passed
@pmyagkov pmyagkov deleted the feature/skipping-section branch March 16, 2026 12:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant