Commit Graph

26 Commits

Author SHA1 Message Date
Toutsu 2819786f91 test(wizard): add wizard tests + refactor to IWizardDraftRepository
- Extract IWizardDraftRepository interface for testability (NSubstitute cannot
  mock sealed classes; the codebase uses fake-style doubles instead).
- Add step-transition, pool-slot, validation, cancel/back, and render-shape tests
  using FakeWizardDraftRepository and FakeWizardMessenger.
- Fix wizard payload persistence bug: HandleCallbackAsync and HandleTextAsync
  now call SavePayload after ApplyChoice/ApplyText mutations, so subsequent
  LoadPayload calls see the user's progress. Previously, local WizardPayload
  mutations were discarded and the wizard reset on every step.
- CommitCurrentPoolSlot now auto-creates a slot via EnsureCurrentPoolSlot when
  one is missing, so the PoolSlotCapacity → waitlist click is recoverable
  even if the user lands on the step without a slot.
2026-06-04 09:53:15 +03:00
Toutsu 4a04d7d723 refactor(wizard): make CreateSessionHandler wizard-driven and remove legacy parser 2026-06-04 09:00:37 +03:00
Toutsu 4d2aef637f fix(wizard): bind @PayloadJson parameter in UpsertAsync INSERT
The UpsertAsync SQL used @Payload (without 'Json' suffix) but the
WizardDraft POCO exposes the property as PayloadJson. Dapper.AOT
requires parameter names to match property names, so the parameter
went through unbinded and PostgreSQL rejected 'payload' as a column
reference. Without integration tests this went unnoticed; the new
WizardDraftRepositoryTests now exercise the path and surface it.
2026-06-04 08:13:10 +03:00
Toutsu c45c46abcf feat(wizard): add WizardDraftRepository (Dapper.AOT) 2026-06-04 08:01:46 +03:00
Toutsu 2c7495cd8d feat(wizard): add WizardPayload with AOT JSON source-gen 2026-06-04 07:59:13 +03:00
Toutsu d5fdc19016 feat(wizard): add WizardDraft POCO 2026-06-04 07:56:38 +03:00
Toutsu 6cb2fbe610 feat(web): add private club showcases with membership flow (v3.7.0)
PR Checks / test-and-build (pull_request) Successful in 7m28s
Implements Issue #110: game masters can now publish sessions
exclusively to a club's private showcase, gated behind a
member application and approval flow. Adds a 4-state
publication_mode (None/Catalog/ClubOnly/Both) replacing the
binary is_public, plus a club_memberships table with
Pending/Active/Rejected/Left lifecycle and partial unique
index ensuring a single Active row per (group, player).

Highlights
- V030 migration: club_memberships, publication_mode, drop
  is_public, recreate partial indexes, portfolio_games gains
  publication_mode.
- PublicationMode enum + extensions in GmRelay.Shared.
- ISessionStore gains 12 membership/showcase methods;
  AuthorizedMembershipService owns the membership flow with
  GM-only approve/reject authorization.
- PublicClub / PublicMasterProfile / PublicSession: member-
  aware queries (ClubOnly visible only to Active members).
- New pages: MyClubMemberships (/profile/memberships) and
  ClubApplications (/group/{id}/applications).
- GroupDetails and EditSession switch from a bool toggle to
  a 4-state publication_mode selector.
- NavMenu adds Moji kluby, PublicLayout adds Kluby.

Tests: 4 new test files (PublicationMode, ClubMemberships,
AuthorizedMembershipService, ClubShowcaseSource) + updates
to PublicClubPages, AuthorizedSessionService/Portfolio
service FakeSessionStore, CampaignTemplatesNavigation.
493 tests pass.

Bump version 3.6.0 -> 3.7.0 across Directory.Build.props,
compose.yaml, deploy.yml, NavMenu.razor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 11:09:22 +03:00
Toutsu a20da4b1a0 fix(data): serialize portfolio mutations before rows 2026-06-02 10:32:13 +03:00
Toutsu a28b75dd5b fix(data): align portfolio mutation lock order 2026-06-01 20:23:43 +03:00
Toutsu 3c1a98bcc4 fix(data): harden portfolio publication concurrency 2026-06-01 09:46:18 +03:00
Toutsu 0c1d3abd7e feat(web): add public master profiles
PR Checks / test-and-build (pull_request) Successful in 12m32s
Add sanitized public GM profiles with publication controls, public /gm/{slug} pages, and links from public game surfaces.

Bump version -> 3.5.0
2026-05-29 00:08:14 +03:00
Toutsu a63e3bef1e fix: финальные правки ревью для issue #39
PR Checks / test-and-build (pull_request) Successful in 13m16s
- PublicSession.razor: добавлена обработка ?register=1, AuthStateProvider,
  TryGetPlatformIdentity, кнопки записи для авторизованных/неавторизованных
  пользователей, отображение результата регистрации
- CreateSessionHandler: добавлен cover_image_url в INSERT SQL
- DiscordProjectStructureTests: версия 3.4.0 во всех проверках
- README.md: актуальная версия v3.4.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 17:00:33 +03:00
Toutsu 76c6818952 fix(shared): add missing Platform parameter in players upsert 2026-05-28 16:28:25 +03:00
Toutsu 633a020212 fix(shared): convert GameSystem to string in SQL, guard rollback after commit 2026-05-28 16:26:54 +03:00
Toutsu ab38238fe8 feat(shared): extend CreateSessionCommand with showcase metadata
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 16:20:44 +03:00
Toutsu 6d59737d07 feat(web): update public session detail with showcase fields
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 16:13:35 +03:00
Toutsu f94bea3e74 feat(shared): add GameSystem enum and Showcase DTOs
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 14:58:49 +03:00
Toutsu 542f15f2d6 refactor: extract remaining Telegram handlers to platform-neutral contracts
PR Checks / test-and-build (pull_request) Successful in 13m48s
- Extract CreateSessionHandler, ListSessionsHandler, DeleteSessionHandler,
  ExportCalendarHandler, HandleRescheduleTimeInputHandler,
  HandleRescheduleVoteHandler to GmRelay.Shared
- Add IPlatformMessenger methods: SendScheduleAsync, UpdateScheduleAsync,
  SendGroupMessageAsync with actions, CreateThreadAsync, DeleteThreadAsync
- Rewrite Telegram Bot wrappers as thin adapters delegating to shared handlers
- Rewrite DiscordRescheduleVoteHandler to use shared HandleRescheduleVoteHandler
- Update UpdateRouter with explicit type aliases for ambiguous handler names
- Add contract and source-inspection tests for extracted handlers
- Bump version 3.1.1 → 3.2.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:52:09 +03:00
Toutsu 040b0a3cdb refactor: завершить platform migration и удалить deprecated telegram_* scaffolding
PR Checks / test-and-build (pull_request) Failing after 13m15s
- Добавлены миграции V024 (backfill + deprecation comments + calendar_subscriptions platform identity) и V025 (backfill proposed_by_external_user_id)
- Все Bot handlers переведены с telegram_id/chat_id на platform + external_*
- Shared handlers очищены от COALESCE fallback с telegram_* колонками
- DiscordBot очищен от COALESCE fallback
- Web SessionService и CalendarSubscriptionService переведены на external_*
- HandleRsvpHandler: убран legacy UNION с gm_telegram_id, теперь только group_managers
- RescheduleVotingFinalizer: переведен на external_username/external_user_id
- Tests: добавлены asserts для V024/V025
- Версия обновлена до 3.1.0

Bump version → 3.1.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 16:41:15 +03:00
Toutsu 3447acd8c4 fix(discord): update sessions via interactions
Deploy Telegram Bot / build-and-push (push) Successful in 6m14s
Deploy Telegram Bot / scan-images (push) Successful in 3m12s
Deploy Telegram Bot / deploy (push) Successful in 31s
2026-05-26 14:24:06 +03:00
Toutsu 2a707e4825 feat(platform): route scheduler notifications through platform messenger
PR Checks / test-and-build (pull_request) Successful in 7m9s
2026-05-21 12:30:35 +03:00
Toutsu db9a931ed6 fix(shared): filter due proposals by source_platform to prevent cross-platform race
PR Checks / test-and-build (pull_request) Successful in 6m11s
Both Telegram and Discord deadline services were querying ALL due
proposals without filtering by source_platform. If the Telegram
service reached a Discord proposal first, it finalized the DB state
but skipped message handling. The Discord service then saw status
!= 'Voting' and never updated the Discord vote message.

Fix: GetDueProposalIdsAsync now accepts a sourcePlatform parameter
and filters at the DB level. Each service only processes its own
platform's proposals.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 12:48:25 +03:00
Toutsu fdfc73ae9c feat(discord): add reschedule vote button handler 2026-05-20 12:21:13 +03:00
Toutsu a13edf20af feat(shared): add RescheduleVotingFinalizer and ISystemClock 2026-05-20 11:54:53 +03:00
Toutsu fcd7de035f refactor(shared): extract reschedule voting types to Shared 2026-05-20 11:44:57 +03:00
Toutsu 39132be4e8 feat(discord): enable session join leave buttons
PR Checks / test-and-build (pull_request) Successful in 6m6s
Move neutral join/leave handlers into GmRelay.Shared so Telegram and Discord share capacity, waitlist, duplicate-click, and schedule-update behavior.

Add Discord component routing for join_session and leave_session buttons with deferred ephemeral replies and serialized schedule message updates.

Bump version to 2.5.0 and update Discord docs.

Refs #29
2026-05-19 14:13:48 +03:00