Prompt file imported from dwarwick/MusicSalesApp (
.github/prompts/plan-tipChargebackBlockAdminSubscriptionStatus.prompt.md). Copyright stays with the author.
Plan: Tip Chargeback Block + Admin Subscription Status
When a tipper files a chargeback, block them from tipping again by adding an IsTipBlocked flag to ApplicationUser. Send the tipper an email explaining the chargeback and the permanent tipping ban. Expose tip-block status and subscription status on the Admin Manage Users page, with the ability for admin to re-enable tipping.
Phase 1: Database & Model Changes
-
Add
IsTipBlockedandTipBlockedAttoApplicationUser— follows the exact pattern of existingIsSubscriptionBlocked/SubscriptionBlockedAtfields.- File: ApplicationUser.cs
-
Create EF migration for the two new columns.
Phase 2: Tip Chargeback Logic — Block Tipper & Send Email
-
Block tipper in
TryHandleTipChargebackAsync— after updating tip status to Chargeback, setuser.IsTipBlocked = trueanduser.TipBlockedAt = DateTime.UtcNowon theTipperUser. Follows the same pattern used inProcessSubscriptionChargebackAsyncwhereIsSubscriptionBlockedis set. (depends on step 1)- File: PayPalWebhookController.cs —
TryHandleTipChargebackAsyncmethod
- File: PayPalWebhookController.cs —
-
Send tipper chargeback email — new method
SendTipperChargebackEmailAsyncfollowing the pattern of existingSendSubscriberChargebackEmailAsync. Includes: chargeback notification, statement that tipping is permanently revoked, support contact. Called fromTryHandleTipChargebackAsyncfor ALL tip chargebacks (not just paid-out ones). (parallel with step 3) -
Add tip-block check in
ValidateTipAsync— after loading the user, checkuser.IsTipBlockedand return a rejection message. (depends on step 1)- File: TipService.cs —
ValidateTipAsyncmethod
- File: TipService.cs —
Phase 3: Admin Manage Users — Tip Block Status & Toggle
-
Add
IsTipBlocked/TipBlockedAttoUserViewModel— map inLoadUsersAsync, add_editIsTipBlockedfield, wire intoEditUser/SaveEdit. (depends on step 1) -
Add grid columns "Tip Blocked" and "Tip Blocked At" — badge template (Yes=red, No=gray), follows exact pattern of "Sub Blocked" column. (depends on step 6)
-
Add "Tip Blocked" checkbox in the edit modal — next to existing "Subscription Blocked" checkbox. (depends on step 6)
Phase 4: Admin Manage Users — Subscription Status Column
-
Add
SubscriptionStatusdisplay string toUserViewModel— derived at load time fromSubscriptionstable +IsSubscriptionBlocked:- If
IsSubscriptionBlocked→ "Blocked" (red badge) - Else if latest subscription is
ACTIVEand not expired → "Active" (green) - Else if latest subscription is
CANCELLED/SUSPENDED/EXPIRED→ "Cancelled" (yellow) - Else (no subscription) → "Not Subscribed" (gray)
- File: AdminUserManagement.razor.cs —
LoadUsersAsync
- If
-
Add "Sub Status" grid column — color-coded badge column placed near existing "Sub Blocked" column.
Phase 5: Tests & Verification
-
Update
AdminUserManagementTests— verify new columns render ("Tip Blocked", "Tip Blocked At", "Sub Status"). -
Add/update TipService tests — test
ValidateTipAsyncrejects whenIsTipBlocked = true.- File:
MusicSalesApp.Tests/Services/TipServiceTests.cs
- File:
-
Run all existing tests to catch regressions.
Verification
dotnet build MusicSalesApp.slnx— solution compilesdotnet test MusicSalesApp.slnx— all tests pass- Migration generates correctly with the two new columns
- Manual: Admin Manage Users page shows new "Tip Blocked", "Tip Blocked At", and "Sub Status" columns
- Manual: Edit modal allows toggling "Tip Blocked" and it persists on save
Decisions
IsTipBlocked/TipBlockedAtfollows the exact same model pattern asIsSubscriptionBlocked/SubscriptionBlockedAt- Subscription status is derived at query time (not a stored field) to avoid staleness
- "Blocked" status takes priority over actual subscription state
- The tipper email is sent for all tip chargebacks (not just ones already paid out — the existing creator email is only for paid-out tips)
- No additional constants needed in Common/Helpers since the tip-block message is a one-time validation string, not written/read in separate places
Further Considerations
- Should re-enabling tipping send an email to the user? Yes, I think it's good to notify the user when their tipping privileges are restored. I can add a new
SendTipReenabledEmailAsyncmethod following the pattern of the chargeback email, and call it fromSaveEditwhen an admin unchecks "Tip Blocked". The email would explain that their tipping privileges have been restored and they can tip again. - Should "Blocked" subscription status be a separate value in the grid vs the existing "Sub Blocked" column? My plan adds a new "Sub Status" column with derived status (which subsumes the info from "Sub Blocked"), but keeps the existing "Sub Blocked" column for backward compatibility. If you'd prefer to remove the redundancy, I can adjust. We do not need a redundant "Tip Blocked" column since the "Tip Blocked At" column already indicates if they are blocked (null = not blocked, timestamp = blocked).
We also need to update terms of service and the creator agreement to reflect the chargeback policy for subscriptions and tips. Ensure t he dates are updated in these documents.