Stripe backend: voter limit + checkout session API - #4
Draft
ArendPeter wants to merge 9 commits into
Draft
ArendPeter wants to merge 9 commits into
ArendPeter wants to merge 9 commits into
Conversation
Per Equal-Vote#1590 the checkout flow moved to a cart model: one Checkout Session can carry multiple line items, so `product` now stores a JSON array of line items (each a full Stripe price_data snapshot tagged with its internal product type) instead of a single varchar product type. voter_count_granted stays the authoritative aggregate on the row, so sumVoterLimitPurchases no longer filters by product. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012e7hk5frznvBj8kbB3uu4M
Replaced 'product' and 'amount_cents' columns with 'line_items' column in the stripeCheckoutSessionsDB table.
…e & lock down voter_limit (issue Equal-Vote#1585) Task: Wire voter-limit resolution hierarchy, payment-required response & lock down voter_limit PRD: Phase 1 Payment System (Equal-Vote#1566), graduated from Equal-Vote#1568 Key decisions: - Voter limit now falls back to election.voter_limit (not sharedConfig.FREE_TIER_PRIVATE_VOTER_LIMIT) — override dict still wins when present, matching the issue spec - Limit-exceeded response is 402 with structured body (code, currentVoterLimit, requestedVoterCount, blockSize, pricePerBlockCents) — sent directly via res.json(), bypassing errorCatch middleware - editElectionController overwrites inputElection.voter_limit with req.election.voter_limit before calling updateElection(), discarding any client-submitted value - useFetch suppresses the generic snackbar for PAYMENT_REQUIRED and exposes latestErrorResponse ref so the caller can read the raw error body synchronously after makeRequest returns false - AddElectionRoll.tsx has a stub branch for code === 'PAYMENT_REQUIRED' (modal is separate ticket) - Mock ElectionsDB now sets voter_limit = pricingConfig.FREE_TIER_LIMIT in createElection(), matching the real implementation Files changed: - packages/backend/src/Controllers/Roll/addElectionRollController.ts - packages/backend/src/Controllers/Election/editElectionController.ts - packages/backend/src/Models/__mocks__/Elections.ts - packages/frontend/src/hooks/useFetch.ts - packages/frontend/src/components/Election/Admin/AddElectionRoll.tsx - packages/backend/src/test/voterLimitRoll.test.ts (new, 5 tests) Blockers/notes: - Branch is based on voter-limit-migration-1584 (PR Equal-Vote#1589) which must merge first - Payment modal (opened on PAYMENT_REQUIRED) is separate frontend work tracked elsewhere Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ripe session) — issue Equal-Vote#1586 Task: POST /API/Election/:id/CheckoutSession Key decisions: - Product catalog in Services/Stripe/catalog.ts: pure functions (validateCart, buildLineItems, computeTotals) — one entry (voter_limit_block), easily testable - StripeService wrapper + __mocks__ counterpart wired into ServiceLocator - Placeholder UUID written to DB first to get row ID for Stripe metadata; real session ID swapped in post-creation via new updateStripeSessionId() - Max voter_limit capped at 5000; 'pending' row inserted before Stripe call - Shared domain model updated: StripeCheckoutSessionProduct → 'voter_limit_block'; StripeCheckoutSessionLineItem.product renamed to .type (matches spec JSON) Files changed: - packages/backend/src/Services/Stripe/catalog.ts (new) - packages/backend/src/Services/Stripe/StripeService.ts (new) - packages/backend/src/Services/Stripe/__mocks__/StripeService.ts (new) - packages/backend/src/Controllers/Election/createCheckoutSessionController.ts (new) - packages/backend/src/test/checkoutSession.test.ts (new — 9 tests, all pass) - packages/backend/src/Models/StripeCheckoutSessions.ts (add updateStripeSessionId) - packages/backend/src/Models/__mocks__/StripeCheckoutSessions.ts (same) - packages/backend/src/ServiceLocator.ts (add stripeCheckoutSessionsDb, stripeService) - packages/backend/src/__mocks__/ServiceLocator.ts (same) - packages/backend/src/Controllers/Election/index.ts (re-export) - packages/backend/src/Routes/elections.routes.ts (add route) - packages/shared/src/domain_model/StripeCheckoutSession.ts (type fix) - packages/backend/package.json + package-lock.json (add stripe dependency) Builds on voter-limit-migration-1584 branch (merged in); requires STRIPE_SECRET_KEY. All 223 backend tests pass; tsc clean. Blockers: STRIPE_SECRET_KEY must be configured for production use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
# Conflicts: # package-lock.json
frontend/tsconfig.json has strict:false, which changes how tsc infers the callback param type in kysely's .select(eb => ...) here, causing "Untyped function calls may not accept type arguments" during the frontend build (which type-checks this file transitively via useAPI.ts's import of a backend controller). Co-Authored-By: Claude Sonnet 5 <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.
Human Summary
This change builds on the stripe database change in Equal-Vote#1589. It adds API support for checkout sessions.
Summary
sandcastle/issue-1585(voter-limit resolution hierarchy, payment-required response, and voter_limit lockdown) andsandcastle/issue-1586(Checkout Session creation endpoint — cart validation + Stripe session) intostripe-backend.StripeServiceand a productcatalogfor building Stripe line items, plus acreateCheckoutSessionControllerand route wiring.StripeCheckoutSessionsDB.sumVoterLimitPurchasesthat only surfaced when type-checked under the frontend's non-stricttsconfig.json(which transitively type-checks this backend file viauseAPI.ts).package-lock.jsonto reconcile dependency additions from both branches (addsstripe).Test plan
npm run build -w @equal-vote/star-vote-backendpassesnpm run build -w @equal-vote/star-vote-frontendpasses (including the transitive type-check of backend files)npm test -w @equal-vote/star-vote-backend— 228/228 tests pass