feat(web): private club showcases with membership flow (v3.7.0, issue #110) #119
Closed
Toutsu
wants to merge 0 commits from
feat/issue-110-private-club-showcases into main
pull from: feat/issue-110-private-club-showcases
merge into: Toutsu:main
Toutsu:main
Toutsu:feature/telegram-game-card-fields
Toutsu:feature/issue-136-wizard-format-location
Toutsu:fix/issue-135-wizard-publish-schedule
Toutsu:fix/issue-133-on-conflict-inference
Toutsu:fix/issue-130-no-limit-complete
Toutsu:fix/issue-129-libgssapi
Toutsu:fix/issue-127-wizard-capacity-club
Toutsu:fix/issue-125-test-cleanup
Toutsu:fix/issue-123-no-limit-wizard
Toutsu:feat/issue-112-wizard-refactor
Toutsu:feat/issue-111-game-creation-wizard
Toutsu:fix/issue-110-showcase-500
Toutsu:codex/feature-issue-108-portfolio
Toutsu:feat/profile-design-system
Toutsu:codex/fix-public-pages-500
Toutsu:feature/issue-40-master-profiles
Toutsu:feature/issue-39-game-catalog
Toutsu:codex/feature/issue-38-public-club-pages
Toutsu:refactor/issue-37-platform-neutral-handlers
Toutsu:codex/fix-template-topic-release
Toutsu:refactor/issue-36-platform-migration
Toutsu:fix/discord-nullable-telegram-columns
Toutsu:fix/discord-dapper-aot-missing
Toutsu:fix/discord-console-logging-deferred
Toutsu:fix/discord-guildinteractionuser-permissions
Toutsu:fix/discord-count-bigint-cast
Toutsu:fix/discord-slash-commands-guild-context
Toutsu:fix/discord-slash-command-registration
Toutsu:feature/issue-35-identity-linking
Toutsu:fix/discord-oauth-diagnostics
Toutsu:feature/issue-34-discord-oauth-dashboard
Toutsu:test/issue-33-regression-tests
Toutsu:chore/issue-32-discord-compose-wiring
Toutsu:codex/issue-31-platform-messenger-scheduler
Toutsu:feature/discord-reschedule-voting
Toutsu:codex/feature-issue-29-discord-join-leave
Toutsu:feature/issue-28-discord-newsession-listsessions
Toutsu:feature/issue-27-discord-session-batch-renderer
Toutsu:feature/issue-26-discord-netcord-gateway
Toutsu:codex/refactor-issue-25-platform-neutral-join-leave
Toutsu:feature/dashboard-design-refresh
Toutsu:feature/issue-58-health-checks
Toutsu:feature/issue-23-platform-identity
Toutsu:fix/issue-60-add-license
Toutsu:feature/issue-57-postgresql-backup
Toutsu:feature/trivy-security-scan
Toutsu:codex/feature/issue-21-telegram-topics
Toutsu:feature/issue-20-rsvp-reminders
Toutsu:feature/issue-15-session-audit-log
Toutsu:feature/issue-19-batch-join-link
Toutsu:fix/navmenu-mobile-overlap
Toutsu:feature/new-logo
Toutsu:issue-47-navmenu-icon-fix
Toutsu:issue-15-session-audit-log
Toutsu:issue-14-attendance-stats
Toutsu:issue-22-neutral-rendering
Toutsu:codex/ftest-telegram-landing-smoke
Toutsu:feat/player-list-kick-waitlist
Toutsu:codex/co-gm-delegation
No Reviewers
Labels
Clear labels
area:bot
area:data
area:discord
area:infra
area:miniapp
area:platform
area:shared
area:web
in-progress
next-up
pending-approval
platform:discord
platform:multi
platform:telegram
priority:p0
priority:p0
priority:p1
priority:p2
priority:p3
security
type:bug
type:chore
type:feature
type:refactor
type:test
Telegram bot and worker logic
Database schema, migrations and persistence model
Discord bot service and Discord adapter
Infrastructure, runtime and deployment
Telegram Mini App dashboard
Platform-neutral abstractions and adapter boundaries
Shared domain and rendering contracts
Blazor web dashboard
В работе (issue взят агентом)
Recommended immediate backlog
Ждёт согласования плана решения
Discord-specific behavior or adapter work
Cross-platform or platform-neutral work
Telegram-specific behavior or adapter work
Critical priority
Блокирующий приоритет: задача должна быть выполнена до признания решения production-ready
High priority
Medium priority
Lower priority
Security-sensitive work
Bug fix or corrective work
Maintenance and supporting work
New product functionality
Structural change without direct feature growth
Testing and coverage work
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Toutsu/GmRelayBot#119
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "feat/issue-110-private-club-showcases"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implements Issue #110: game masters can now publish sessions exclusively to a club's private showcase, gated behind a member application and approval flow. Replaces the binary
is_publiccolumn with a 4-statepublication_modeenum, and adds aclub_membershipstable with a Pending/Active/Rejected/Left lifecycle.What's new
Data model (V030 migration)
club_membershipstable with status/role CHECK constraints, partial unique indexux_club_memberships_one_activeensuring only one Active row per (group, player).sessions.publication_modeVARCHAR(20) replacingis_public; CHECK constraint overNone/Catalog/ClubOnly/Both.ix_sessions_public_scheduleandix_sessions_showcaseagainst the new column.portfolio_games.publication_mode(defaultBoth) for parity with the upcoming portfolio feature.Domain
GmRelay.Shared.Domain.PublicationModeenum withToDatabaseValue/FromDatabaseValue/IsVisibleInCatalog/IsVisibleToClubMembers.Services
ISessionStoregains 12 membership/showcase methods.AuthorizedMembershipService(new) owns the membership flow with GM-only approve/reject authorization.SessionService: member-aware SQL forGetPublicClubBySlugAsync,GetPublicSessionAsync,GetPublicMasterProfileBySlugAsync, andGetPublicSessionsForMasterAsync—ClubOnlyrows are only visible to Active members of the group.AuthorizedSessionService:SetSessionPublic*/SetBatchPublic*renamed toSetSessionPublicationMode*/SetBatchPublicationMode*.UI
MyClubMemberships.razor—/profile/memberships(active, pending, history; leave/cancel buttons).ClubApplications.razor—/group/{GroupId}/applications(owner/co-GM only; approve/reject).PublicClub.razor— public/members-only sections with apply & login CTAs; passesviewerPlayerIdto the store.PublicMasterProfile.razor— same member-aware resolution.EditSession.razorandGroupDetails.razor— replaced the boolean toggle with a 4-state<select>.NavMenu.razor— new "Мои клубы" link, version bumped to v3.7.0.PublicLayout.razor— new "Клубы" link to/showcase.GroupDetails.razor— "Заявки участников (N)" card linking to the applications page when N > 0.Tests (493 total, all passing)
PublicationModeTests,ClubMembershipsTests,ClubShowcaseSourceTests,AuthorizedMembershipServiceTests.PublicClubPagesTests(filter clause and migration assertions),AuthorizedSessionServiceTests/AuthorizedPortfolioServiceTests(FakeSessionStore now matches the newISessionStoresurface),CampaignTemplatesNavigationTests(version assertion).Versioning
Directory.Build.props,compose.yaml,.gitea/workflows/deploy.yml,src/GmRelay.Web/Components/Layout/NavMenu.razorall bumped from3.6.0→3.7.0.Out of scope
SetSessionPublic*surface).publication_modefrom reviews (onlyportfolio_gameswas extended, as agreed in the issue).Manual verification
\d club_memberships,\d sessions(nois_public, haspublication_mode),\di ix_sessions_public_schedule(partial index onpublication_mode IN ('Catalog','Both'))./group/{id}→ 4-state selector for a session;/group/{id}/applicationsshows pending applications./club/{slug}→ "Подать заявку" with a message; after GM approval, the "Игры для участников клуба" section appears;ClubOnlysessions are visible only to approved members./club/{slug}never exposes the members-only list, and the public showcase filtersClubOnlyrows out./showcasefor any visitor never includesClubOnlysessions.grep -rn "is_public" src/— should be empty insessions(still present onmaster_profiles.is_publicfrom V028, which is intentional).🤖 Generated with Claude Code
Pull request closed