feat(payment): unified /payment hub with realtime PaymentHistory + Subscriptions#147
Merged
Merged
Conversation
…bscriptions Consolidates the scattered payment pages into ONE tabbed hub at /payment and makes the surfaces live via Supabase Realtime. Hub (src/app/payment/): - page.tsx + PaymentHubContent.tsx + SearchParamsReader.tsx — ProtectedRoute + DaisyUI tabs (Overview / Subscriptions), ?tab= deep-link, per-tab <h1> (Payments / Subscriptions), activeTab initialized synchronously from the URL so the correct heading paints on first render. Absorbs the former /payment/dashboard (PaymentQueuePanel + PaymentHistory) and /account/subscriptions (SubscriptionManager) content verbatim, gating intact. - Deletes the 4 old route files; /account nav buttons → /payment[?tab=subscriptions]. Realtime (src/hooks/, reuses the useConnections debounced-channel pattern): - usePaymentResultsRealtime + useSubscriptionsRealtime — subscribe to postgres_changes, debounce 1s, return 'connecting'|'live'|'error' for a status badge, inert when enabled=false (tests/stories). Unit-tested. - PaymentHistory + SubscriptionManager gain an optional `realtime` prop (default true): a stable refetch callback wired to the hook, a `realtime-status` connection badge, and a live `transaction-count`. Migration: adds payment_results + subscriptions to the supabase_realtime publication (idempotent-guarded, mirroring the messaging tables). WITHOUT this the channel subscribes but never receives events — verified live: the table was missing from the publication, added it, and the counter then updated 2→3 on a service-role insert with no reload. Applied to prod via the Management API. Tests: - Retargeted the 3 green tests to the hub: openSubscriptionsAs → /payment?tab=subscriptions; 02 route-render + 05 queue-panel gotos/headings. - Un-skipped 4 06-realtime tests (live transaction counter, payment-list live update, subscription status change, connection-status indicator) using new seedIsolatedPayment / openPaymentHubAs fixtures; guarded on getAdminClient(). - Regenerated docs/payment-e2e-skip-index.md (27 → 23 skips, reclassified). Verified: type-check, lint, validate:structure (110/110), 132 unit tests, and a live Playwright-MCP realtime check (counter 2→3 via a service-role insert). Co-Authored-By: Claude Opus 4.8 (1M context) <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.
What
Consolidates the scattered payment pages into one tabbed hub at
/paymentand makes the surfaces live via Supabase Realtime. Replaces/payment/dashboard+/account/subscriptions(both deleted).Hub (
src/app/payment/)page.tsx+PaymentHubContent.tsx+SearchParamsReader.tsx—ProtectedRoute+ DaisyUI tabs (Overview / Subscriptions),?tab=deep-linking, per-tab<h1>(Payments/Subscriptions),activeTabinitialized synchronously from the URL so the right heading paints on first render. Absorbs the former dashboard (PaymentQueuePanel + PaymentHistory) and subscriptions (SubscriptionManager) content verbatim; gating (ProtectedRoute, feature flags, not-configured alert) intact./accountnav buttons now point at/payment[?tab=subscriptions].Realtime (
src/hooks/, reuses theuseConnectionsdebounced-channel pattern)usePaymentResultsRealtime+useSubscriptionsRealtime— subscribe topostgres_changes, debounce 1s, return'connecting' | 'live' | 'error', fully inert whenenabled=false(tests/stories). Unit-tested (mock channel, status callback, debounce, cleanup, disabled path).PaymentHistory+SubscriptionManagergain an optionalrealtimeprop (defaulttrue): a stablerefetchwired to the hook, arealtime-statusconnection badge, and a livetransaction-count.Migration (root-cause fix)
Adds
payment_results+subscriptionsto thesupabase_realtimepublication (idempotent-guarded, mirroring the messaging tables). Without this the channel subscribes but never receives events — I verified this live: the tables were missing from the publication; after adding them, the counter updated 2 → 3 on a service-role insert with no reload. Applied to prod via the Management API.Tests
openSubscriptionsAs→/payment?tab=subscriptions;02route-render +05queue-panel gotos/headings). Per-tab h1 keeps theirlevel: 1heading anchors valid.06-realtimetests (live transaction counter, payment-list live update, subscription status change, connection-status indicator) using newseedIsolatedPayment/openPaymentHubAsfixtures; guarded ongetAdminClient().docs/payment-e2e-skip-index.md(27 → 23 skips, reclassified).Verification
type-check✅,lint✅,validate:structure110/110 ✅, 132 unit tests ✅/payment, service-role inserted a payment → counter + list updated 2 → 3 with no reload; confirmedrealtime-statusreads "Live". (Surfaced + fixed the missing publication membership; also noted the PWA service worker caches the initial history fetch — the realtime in-memory refetch path is unaffected.)🤖 Generated with Claude Code